Graphviz 16.1.1~dev.20261023.1344
Loading...
Searching...
No Matches
partition.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12#include <common/boxes.h>
13#include <common/geomprocs.h>
14#include <math.h>
15#include <ortho/partition.h>
16#include <ortho/trap.h>
17#include <stdbool.h>
18#include <stdint.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <util/alloc.h>
22#include <util/bitarray.h>
23#include <util/gv_math.h>
24#include <util/list.h>
25#include <util/prisize_t.h>
26#include <util/random.h>
27
28#ifndef DEBUG
29#define DEBUG 0
30#endif
31
32#define NPOINTS 4 /* only rectangles */
33
34#define TR_FROM_UP 1 /* for traverse-direction */
35#define TR_FROM_DN 2
36
37#define SP_SIMPLE_LRUP 1 /* for splitting trapezoids */
38#define SP_SIMPLE_LRDN 2
39#define SP_2UP_2DN 3
40#define SP_2UP_LEFT 4
41#define SP_2UP_RIGHT 5
42#define SP_2DN_LEFT 6
43#define SP_2DN_RIGHT 7
44#define SP_NOSPLIT -1
45
46#define DOT(v0, v1) ((v0).x * (v1).x + (v0).y * (v1).y)
47#define CROSS_SINE(v0, v1) ((v0).x * (v1).y - (v1).x * (v0).y)
48#define LENGTH(v0) hypot((v0).x, (v0).y)
49
50typedef struct {
51 size_t vnum;
53 size_t next;
54 size_t prev;
56
57typedef struct {
58 size_t next;
59 size_t pos;
60} vertex_t;
61
62typedef struct {
66
67static size_t chain_idx;
68static size_t mon_idx;
69/* contains position of any vertex in */
70/* the monotone chain for the polygon */
71static size_t *mon;
72
73/* return a new mon structure from the table */
74#define newmon() (++mon_idx)
75/* return a new chain element from the table */
76#define new_chain_element() (++chain_idx)
77
78static void convert(boxf bb, int flip, int ccw, pointf *pts) {
79 pts[0] = bb.LL;
80 pts[2] = bb.UR;
81 if (ccw) {
82 pts[1].x = bb.UR.x;
83 pts[1].y = bb.LL.y;
84 pts[3].x = bb.LL.x;
85 pts[3].y = bb.UR.y;
86 } else {
87 pts[1].x = bb.LL.x;
88 pts[1].y = bb.UR.y;
89 pts[3].x = bb.UR.x;
90 pts[3].y = bb.LL.y;
91 }
92 if (flip) {
93 int i;
94 for (i = 0; i < NPOINTS; i++) {
95 pts[i] = perp(pts[i]);
96 }
97 }
98}
99
100static size_t store(segment_t *seg, size_t first, pointf *pts) {
101 const size_t last = first + NPOINTS - 1;
102
103 for (size_t i = first, j = 0; i <= last; i++, j++) {
104 if (i == first) {
105 seg[i].next = first + 1;
106 seg[i].prev = last;
107 } else if (i == last) {
108 seg[i].next = first;
109 seg[i].prev = last - 1;
110 } else {
111 seg[i].next = i + 1;
112 seg[i].prev = i - 1;
113 }
114 seg[i].is_inserted = false;
115 seg[seg[i].prev].v1 = seg[i].v0 = pts[j];
116 }
117 return (last + 1);
118}
119
120static void genSegments(cell *cells, size_t ncells, boxf bb, segment_t *seg,
121 int flip) {
122 size_t i = 1;
123 pointf pts[4];
124
125 convert(bb, flip, 1, pts);
126 i = store(seg, i, pts);
127 for (size_t j = 0; j < ncells; j++) {
128 convert(cells[j].bb, flip, 0, pts);
129 i = store(seg, i, pts);
130 }
131}
132
133/* Generate a random permutation of the segments 1..n */
134static size_t *generateRandomOrdering(size_t n) {
135 size_t *const permute = gv_permutation(n);
136
137 // make indexing 1-based
138 for (size_t i = 0; i < n; i++) {
139 ++permute[i];
140 }
141
142 return permute;
143}
144
145/* Function returns true if the trapezoid lies inside the polygon */
146static bool inside_polygon(trap_t *t, segment_t *seg) {
147 size_t rseg = t->rseg;
148
149 if (!t->is_valid)
150 return false;
151
152 if (t->lseg == 0 || t->rseg == 0)
153 return false;
154
155 if ((!is_valid_trap(t->u0) && !is_valid_trap(t->u1)) ||
156 (!is_valid_trap(t->d0) && !is_valid_trap(t->d1))) // triangle
157 return greater_than(seg[rseg].v1, seg[rseg].v0);
158
159 return false;
160}
161
162static double get_angle(pointf vp0, pointf vpnext, pointf vp1) {
163 const pointf v0 = sub_pointf(vpnext, vp0);
164 const pointf v1 = sub_pointf(vp1, vp0);
165
166 if (CROSS_SINE(v0, v1) >= 0) /* sine is positive */
167 return DOT(v0, v1) / LENGTH(v0) / LENGTH(v1);
168 return -1.0 * DOT(v0, v1) / LENGTH(v0) / LENGTH(v1) - 2;
169}
170
175static void get_vertex_positions(const vertexchain_t *vert, size_t v0,
176 size_t v1, size_t *ip, size_t *iq) {
177 double angle, temp;
178
179 const vertexchain_t *const vp0 = &vert[v0];
180 const vertexchain_t *const vp1 = &vert[v1];
181
182 /* p is identified as follows. Scan from (v0, v1) rightwards till */
183 /* you hit the first segment starting from v0. That chain is the */
184 /* chain of our interest */
185
186 angle = -4.0;
187 *ip = 0;
188 for (size_t i = 0; i < LIST_SIZE(&vp0->vertex); i++) {
189 const size_t next = LIST_GET(&vp0->vertex, i).next;
190 if (next == 0)
191 continue;
192 if ((temp = get_angle(vp0->pt, vert[next].pt, vp1->pt)) > angle) {
193 angle = temp;
194 *ip = i;
195 }
196 }
197
198 /* Do similar actions for q */
199
200 angle = -4.0;
201 *iq = 0;
202 for (size_t i = 0; i < LIST_SIZE(&vp1->vertex); i++) {
203 const size_t next = LIST_GET(&vp1->vertex, i).next;
204 if (next == 0)
205 continue;
206 if ((temp = get_angle(vp1->pt, vert[next].pt, vp0->pt)) > angle) {
207 angle = temp;
208 *iq = i;
209 }
210 }
211}
212
213/* v0 and v1 are specified in anti-clockwise order with respect to
214 * the current monotone polygon mcur. Split the current polygon into
215 * two polygons using the diagonal (v0, v1)
216 *
217 * @param vert Chain initial information
218 * @param chain Monotone polygon chain to operate on
219 */
221 size_t mcur, size_t v0, size_t v1) {
222 size_t ip, iq;
223 const size_t mnew = newmon();
224 vertexchain_t *vp0, *vp1;
225
226 vp0 = &vert[v0];
227 vp1 = &vert[v1];
228
229 get_vertex_positions(vert, v0, v1, &ip, &iq);
230
231 // if a vertex has no chain yet, synthesize a zeroed element
232 if (ip == 0 && LIST_IS_EMPTY(&vp0->vertex)) {
233 LIST_APPEND(&vp0->vertex, (vertex_t){0});
234 }
235 if (iq == 0 && LIST_IS_EMPTY(&vp1->vertex)) {
236 LIST_APPEND(&vp1->vertex, (vertex_t){0});
237 }
238
239 const size_t p = LIST_GET(&vp0->vertex, ip).pos;
240 const size_t q = LIST_GET(&vp1->vertex, iq).pos;
241
242 /* At this stage, we have got the positions of v0 and v1 in the */
243 /* desired chain. Now modify the linked lists */
244
245 const size_t i = new_chain_element(); // for the new list
246 const size_t j = new_chain_element();
247
248 chain[i].vnum = v0;
249 chain[j].vnum = v1;
250
251 chain[i].next = chain[p].next;
252 chain[chain[p].next].prev = i;
253 chain[i].prev = j;
254 chain[j].next = i;
255 chain[j].prev = chain[q].prev;
256 chain[chain[q].prev].next = j;
257
258 chain[p].next = q;
259 chain[q].prev = p;
260
261 LIST_AT(&vp0->vertex, ip)->next = v1;
262
263 LIST_APPEND(&vp0->vertex,
264 (vertex_t){.next = chain[chain[i].next].vnum, .pos = i});
265 LIST_APPEND(&vp1->vertex, (vertex_t){.next = v0, .pos = j});
266
267#if DEBUG > 0
268 fprintf(stderr,
269 "make_poly: mcur = %" PRISIZE_T ", (v0, v1) = (%" PRISIZE_T
270 ", %" PRISIZE_T ")\n",
271 mcur, v0, v1);
272 fprintf(stderr, "next posns = (p, q) = (%" PRISIZE_T ", %" PRISIZE_T ")\n", p,
273 q);
274#endif
275
276 mon[mcur] = p;
277 mon[mnew] = i;
278 return mnew;
279}
280
285static void traverse_polygon(vertexchain_t *vert, bitarray_t *visited,
286 boxes_t *decomp, segment_t *seg, traps_t *tr,
287 size_t mcur, size_t trnum, size_t from, int flip,
288 int dir, monchain_t *chain) {
289 size_t mnew;
290
291 if (!is_valid_trap(trnum) || bitarray_get(*visited, trnum))
292 return;
293
294 trap_t *t = LIST_AT(tr, trnum);
295
296 bitarray_set(visited, trnum, true);
297
298 if (t->hi.y > t->lo.y + C_EPS &&
299 fp_equal(seg[t->lseg].v0.x, seg[t->lseg].v1.x) &&
300 fp_equal(seg[t->rseg].v0.x, seg[t->rseg].v1.x)) {
301 boxf newbox = {0};
302 if (flip) {
303 newbox.LL.x = t->lo.y;
304 newbox.LL.y = -seg[t->rseg].v0.x;
305 newbox.UR.x = t->hi.y;
306 newbox.UR.y = -seg[t->lseg].v0.x;
307 } else {
308 newbox.LL.x = seg[t->lseg].v0.x;
309 newbox.LL.y = t->lo.y;
310 newbox.UR.x = seg[t->rseg].v0.x;
311 newbox.UR.y = t->hi.y;
312 }
313 LIST_APPEND(decomp, newbox);
314 }
315
316 /* We have much more information available here. */
317 /* rseg: goes upwards */
318 /* lseg: goes downwards */
319
320 /* Initially assume that dir = TR_FROM_DN (from the left) */
321 /* Switch v0 and v1 if necessary afterwards */
322
323 /* special cases for triangles with cusps at the opposite ends. */
324 /* take care of this first */
325 if (!is_valid_trap(t->u0) && !is_valid_trap(t->u1)) {
326 if (is_valid_trap(t->d0) &&
327 is_valid_trap(t->d1)) { // downward opening triangle
328 const size_t v0 = LIST_GET(tr, t->d1).lseg;
329 const size_t v1 = t->lseg;
330 if (from == t->d1) {
331 mnew = make_new_monotone_poly(vert, chain, mcur, v1, v0);
332 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d1, trnum,
333 flip, TR_FROM_UP, chain);
334 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d0, trnum,
335 flip, TR_FROM_UP, chain);
336 } else {
337 mnew = make_new_monotone_poly(vert, chain, mcur, v0, v1);
338 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d0, trnum,
339 flip, TR_FROM_UP, chain);
340 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d1, trnum,
341 flip, TR_FROM_UP, chain);
342 }
343 } else {
344 /* Just traverse all neighbours */
345 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u0, trnum, flip,
346 TR_FROM_DN, chain);
347 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u1, trnum, flip,
348 TR_FROM_DN, chain);
349 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d0, trnum, flip,
350 TR_FROM_UP, chain);
351 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d1, trnum, flip,
352 TR_FROM_UP, chain);
353 }
354 }
355
356 else if (!is_valid_trap(t->d0) && !is_valid_trap(t->d1)) {
357 if (is_valid_trap(t->u0) &&
358 is_valid_trap(t->u1)) { // upward opening triangle
359 const size_t v0 = t->rseg;
360 const size_t v1 = LIST_GET(tr, t->u0).rseg;
361 if (from == t->u1) {
362 mnew = make_new_monotone_poly(vert, chain, mcur, v1, v0);
363 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u1, trnum,
364 flip, TR_FROM_DN, chain);
365 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u0, trnum,
366 flip, TR_FROM_DN, chain);
367 } else {
368 mnew = make_new_monotone_poly(vert, chain, mcur, v0, v1);
369 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u0, trnum,
370 flip, TR_FROM_DN, chain);
371 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u1, trnum,
372 flip, TR_FROM_DN, chain);
373 }
374 } else {
375 /* Just traverse all neighbours */
376 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u0, trnum, flip,
377 TR_FROM_DN, chain);
378 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u1, trnum, flip,
379 TR_FROM_DN, chain);
380 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d0, trnum, flip,
381 TR_FROM_UP, chain);
382 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d1, trnum, flip,
383 TR_FROM_UP, chain);
384 }
385 }
386
387 else if (is_valid_trap(t->u0) && is_valid_trap(t->u1)) {
388 if (is_valid_trap(t->d0) &&
389 is_valid_trap(t->d1)) { // downward + upward cusps
390 const size_t v0 = LIST_GET(tr, t->d1).lseg;
391 const size_t v1 = LIST_GET(tr, t->u0).rseg;
392 if ((dir == TR_FROM_DN && t->d1 == from) ||
393 (dir == TR_FROM_UP && t->u1 == from)) {
394 mnew = make_new_monotone_poly(vert, chain, mcur, v1, v0);
395 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u1, trnum,
396 flip, TR_FROM_DN, chain);
397 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d1, trnum,
398 flip, TR_FROM_UP, chain);
399 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u0, trnum,
400 flip, TR_FROM_DN, chain);
401 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d0, trnum,
402 flip, TR_FROM_UP, chain);
403 } else {
404 mnew = make_new_monotone_poly(vert, chain, mcur, v0, v1);
405 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u0, trnum,
406 flip, TR_FROM_DN, chain);
407 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d0, trnum,
408 flip, TR_FROM_UP, chain);
409 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u1, trnum,
410 flip, TR_FROM_DN, chain);
411 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d1, trnum,
412 flip, TR_FROM_UP, chain);
413 }
414 } else /* only downward cusp */
415 {
416 if (equal_to(t->lo, seg[t->lseg].v1)) {
417 const size_t v0 = LIST_GET(tr, t->u0).rseg;
418 const size_t v1 = seg[t->lseg].next;
419
420 if (dir == TR_FROM_UP && t->u0 == from) {
421 mnew = make_new_monotone_poly(vert, chain, mcur, v1, v0);
422 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u0, trnum,
423 flip, TR_FROM_DN, chain);
424 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d0, trnum,
425 flip, TR_FROM_UP, chain);
426 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u1, trnum,
427 flip, TR_FROM_DN, chain);
428 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d1, trnum,
429 flip, TR_FROM_UP, chain);
430 } else {
431 mnew = make_new_monotone_poly(vert, chain, mcur, v0, v1);
432 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u1, trnum,
433 flip, TR_FROM_DN, chain);
434 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d0, trnum,
435 flip, TR_FROM_UP, chain);
436 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d1, trnum,
437 flip, TR_FROM_UP, chain);
438 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u0, trnum,
439 flip, TR_FROM_DN, chain);
440 }
441 } else {
442 const size_t v0 = t->rseg;
443 const size_t v1 = LIST_GET(tr, t->u0).rseg;
444 if (dir == TR_FROM_UP && t->u1 == from) {
445 mnew = make_new_monotone_poly(vert, chain, mcur, v1, v0);
446 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u1, trnum,
447 flip, TR_FROM_DN, chain);
448 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d1, trnum,
449 flip, TR_FROM_UP, chain);
450 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d0, trnum,
451 flip, TR_FROM_UP, chain);
452 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u0, trnum,
453 flip, TR_FROM_DN, chain);
454 } else {
455 mnew = make_new_monotone_poly(vert, chain, mcur, v0, v1);
456 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u0, trnum,
457 flip, TR_FROM_DN, chain);
458 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d0, trnum,
459 flip, TR_FROM_UP, chain);
460 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d1, trnum,
461 flip, TR_FROM_UP, chain);
462 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u1, trnum,
463 flip, TR_FROM_DN, chain);
464 }
465 }
466 }
467 } else if (is_valid_trap(t->u0) || is_valid_trap(t->u1)) { // no downward cusp
468 if (is_valid_trap(t->d0) && is_valid_trap(t->d1)) { // only upward cusp
469 if (equal_to(t->hi, seg[t->lseg].v0)) {
470 const size_t v0 = LIST_GET(tr, t->d1).lseg;
471 const size_t v1 = t->lseg;
472 if (!(dir == TR_FROM_DN && t->d0 == from)) {
473 mnew = make_new_monotone_poly(vert, chain, mcur, v1, v0);
474 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u1, trnum,
475 flip, TR_FROM_DN, chain);
476 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d1, trnum,
477 flip, TR_FROM_UP, chain);
478 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u0, trnum,
479 flip, TR_FROM_DN, chain);
480 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d0, trnum,
481 flip, TR_FROM_UP, chain);
482 } else {
483 mnew = make_new_monotone_poly(vert, chain, mcur, v0, v1);
484 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d0, trnum,
485 flip, TR_FROM_UP, chain);
486 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u0, trnum,
487 flip, TR_FROM_DN, chain);
488 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u1, trnum,
489 flip, TR_FROM_DN, chain);
490 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d1, trnum,
491 flip, TR_FROM_UP, chain);
492 }
493 } else {
494 const size_t v0 = LIST_GET(tr, t->d1).lseg;
495 const size_t v1 = seg[t->rseg].next;
496
497 if (dir == TR_FROM_DN && t->d1 == from) {
498 mnew = make_new_monotone_poly(vert, chain, mcur, v1, v0);
499 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d1, trnum,
500 flip, TR_FROM_UP, chain);
501 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u1, trnum,
502 flip, TR_FROM_DN, chain);
503 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u0, trnum,
504 flip, TR_FROM_DN, chain);
505 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d0, trnum,
506 flip, TR_FROM_UP, chain);
507 } else {
508 mnew = make_new_monotone_poly(vert, chain, mcur, v0, v1);
509 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u0, trnum,
510 flip, TR_FROM_DN, chain);
511 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d0, trnum,
512 flip, TR_FROM_UP, chain);
513 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u1, trnum,
514 flip, TR_FROM_DN, chain);
515 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d1, trnum,
516 flip, TR_FROM_UP, chain);
517 }
518 }
519 } else /* no cusp */
520 {
521 if (equal_to(t->hi, seg[t->lseg].v0) &&
522 equal_to(t->lo, seg[t->rseg].v0)) {
523 const size_t v0 = t->rseg;
524 const size_t v1 = t->lseg;
525 if (dir == TR_FROM_UP) {
526 mnew = make_new_monotone_poly(vert, chain, mcur, v1, v0);
527 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u0, trnum,
528 flip, TR_FROM_DN, chain);
529 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u1, trnum,
530 flip, TR_FROM_DN, chain);
531 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d1, trnum,
532 flip, TR_FROM_UP, chain);
533 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d0, trnum,
534 flip, TR_FROM_UP, chain);
535 } else {
536 mnew = make_new_monotone_poly(vert, chain, mcur, v0, v1);
537 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d1, trnum,
538 flip, TR_FROM_UP, chain);
539 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d0, trnum,
540 flip, TR_FROM_UP, chain);
541 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u0, trnum,
542 flip, TR_FROM_DN, chain);
543 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u1, trnum,
544 flip, TR_FROM_DN, chain);
545 }
546 } else if (equal_to(t->hi, seg[t->rseg].v1) &&
547 equal_to(t->lo, seg[t->lseg].v1)) {
548 const size_t v0 = seg[t->rseg].next;
549 const size_t v1 = seg[t->lseg].next;
550
551 if (dir == TR_FROM_UP) {
552 mnew = make_new_monotone_poly(vert, chain, mcur, v1, v0);
553 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u0, trnum,
554 flip, TR_FROM_DN, chain);
555 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u1, trnum,
556 flip, TR_FROM_DN, chain);
557 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d1, trnum,
558 flip, TR_FROM_UP, chain);
559 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->d0, trnum,
560 flip, TR_FROM_UP, chain);
561 } else {
562 mnew = make_new_monotone_poly(vert, chain, mcur, v0, v1);
563 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d1, trnum,
564 flip, TR_FROM_UP, chain);
565 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d0, trnum,
566 flip, TR_FROM_UP, chain);
567 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u0, trnum,
568 flip, TR_FROM_DN, chain);
569 traverse_polygon(vert, visited, decomp, seg, tr, mnew, t->u1, trnum,
570 flip, TR_FROM_DN, chain);
571 }
572 } else /* no split possible */
573 {
574 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u0, trnum,
575 flip, TR_FROM_DN, chain);
576 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d0, trnum,
577 flip, TR_FROM_UP, chain);
578 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->u1, trnum,
579 flip, TR_FROM_DN, chain);
580 traverse_polygon(vert, visited, decomp, seg, tr, mcur, t->d1, trnum,
581 flip, TR_FROM_UP, chain);
582 }
583 }
584 }
585}
586
587static void monotonate_trapezoids(size_t nsegs, segment_t *seg, traps_t *tr,
588 int flip, boxes_t *decomp) {
589 bitarray_t visited = bitarray_new(LIST_SIZE(tr));
590
591 // Table to hold all the monotone polygons. Each monotone polygon is a
592 // circularly linked list
593 monchain_t *const mchain = gv_calloc(LIST_SIZE(tr), sizeof(monchain_t));
594
595 // Chain initial information. This is used to decide which monotone polygon
596 // to split if there are several other polygons touching the same vertex.
597 vertexchain_t *const vert = gv_calloc(nsegs + 1, sizeof(vertexchain_t));
598
599 mon = gv_calloc(nsegs, sizeof(size_t));
600
601 /* First locate a trapezoid which lies inside the polygon */
602 /* and which is triangular */
603 size_t j;
604 for (j = 0; j < LIST_SIZE(tr); j++)
605 if (inside_polygon(LIST_AT(tr, j), seg))
606 break;
607 const size_t tr_start = j;
608
609 /* Initialise the mon data-structure and start spanning all the */
610 /* trapezoids within the polygon */
611
612 for (size_t i = 1; i <= nsegs; i++) {
613 mchain[i].prev = seg[i].prev;
614 mchain[i].next = seg[i].next;
615 mchain[i].vnum = i;
616 vert[i].pt = seg[i].v0;
617 LIST_APPEND(&vert[i].vertex, (vertex_t){
618 .next = seg[i].next, // next vertex
619 .pos = i // locn. of next vertex
620 });
621 }
622
623 chain_idx = nsegs;
624 mon_idx = 0;
625 mon[0] = 1; /* position of any vertex in the first */
626 /* chain */
627
628 /* traverse the polygon */
629 if (is_valid_trap(LIST_GET(tr, tr_start).u0))
630 traverse_polygon(vert, &visited, decomp, seg, tr, 0, tr_start,
631 LIST_GET(tr, tr_start).u0, flip, TR_FROM_UP, mchain);
632 else if (is_valid_trap(LIST_GET(tr, tr_start).d0))
633 traverse_polygon(vert, &visited, decomp, seg, tr, 0, tr_start,
634 LIST_GET(tr, tr_start).d0, flip, TR_FROM_DN, mchain);
635
636 bitarray_reset(&visited);
637 free(mchain);
638 for (size_t i = 0; i < nsegs + 1; ++i) {
639 LIST_FREE(&vert[i].vertex);
640 }
641 free(vert);
642 free(mon);
643}
644
645static bool rectIntersect(boxf *d, const boxf r0, const boxf r1) {
646 double t = fmax(r0.LL.x, r1.LL.x);
647 d->UR.x = fmin(r0.UR.x, r1.UR.x);
648 d->LL.x = t;
649
650 t = fmax(r0.LL.y, r1.LL.y);
651 d->UR.y = fmin(r0.UR.y, r1.UR.y);
652 d->LL.y = t;
653
654 return !(d->LL.x >= d->UR.x || d->LL.y >= d->UR.y);
655}
656
657boxes_t partition(cell *cells, size_t ncells, boxf bb) {
658 const size_t nsegs = 4 * (ncells + 1);
659 segment_t *segs = gv_calloc(nsegs + 1, sizeof(segment_t));
660
661 if (DEBUG) {
662 fprintf(stderr,
663 "cells = %" PRISIZE_T " segs = %" PRISIZE_T " traps = dynamic\n",
664 ncells, nsegs);
665 }
666 genSegments(cells, ncells, bb, segs, 0);
667 if (DEBUG) {
668 fprintf(stderr, "%" PRISIZE_T "\n\n", ncells + 1);
669 for (size_t i = 1; i <= nsegs; i++) {
670 if (i % 4 == 1)
671 fprintf(stderr, "4\n");
672 fprintf(stderr, "%f %f\n", segs[i].v0.x, segs[i].v0.y);
673 if (i % 4 == 0)
674 fprintf(stderr, "\n");
675 }
676 }
677 size_t *permute = generateRandomOrdering(nsegs);
678 traps_t hor_traps = construct_trapezoids(nsegs, segs, permute);
679 free(permute);
680 if (DEBUG) {
681 fprintf(stderr, "hor traps = %" PRISIZE_T "\n", LIST_SIZE(&hor_traps));
682 }
683 if (LIST_SIZE(&hor_traps) == 0) {
684 free(segs);
685 fprintf(stderr, "horizontal trapezoid construction failed\n");
686 return (boxes_t){0};
687 }
688 boxes_t hor_decomp = {0};
689 monotonate_trapezoids(nsegs, segs, &hor_traps, 0, &hor_decomp);
690 LIST_FREE(&hor_traps);
691
692 genSegments(cells, ncells, bb, segs, 1);
693 permute = generateRandomOrdering(nsegs);
694 traps_t ver_traps = construct_trapezoids(nsegs, segs, permute);
695 free(permute);
696 if (DEBUG) {
697 fprintf(stderr, "ver traps = %" PRISIZE_T "\n", LIST_SIZE(&ver_traps));
698 }
699 if (LIST_SIZE(&ver_traps) == 0) {
700 LIST_FREE(&hor_decomp);
701 free(segs);
702 fprintf(stderr, "vertical trapezoid construction failed\n");
703 return (boxes_t){0};
704 }
705 boxes_t vert_decomp = {0};
706 monotonate_trapezoids(nsegs, segs, &ver_traps, 1, &vert_decomp);
707 LIST_FREE(&ver_traps);
708
709 boxes_t rs = {0};
710 for (size_t i = 0; i < LIST_SIZE(&vert_decomp); ++i)
711 for (size_t j = 0; j < LIST_SIZE(&hor_decomp); ++j) {
712 boxf newbox = {0};
713 if (rectIntersect(&newbox, LIST_GET(&vert_decomp, i),
714 LIST_GET(&hor_decomp, j)))
715 LIST_APPEND(&rs, newbox);
716 }
717
718 free(segs);
719 LIST_FREE(&hor_decomp);
720 LIST_FREE(&vert_decomp);
721 return rs;
722}
static agxbuf last
last message
Definition agerror.c:31
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
API for compacted arrays of booleans.
static bitarray_t bitarray_new(size_t size_bits)
create an array of the given element length
Definition bitarray.h:47
static bool bitarray_get(bitarray_t self, size_t index)
get the value of the given element
Definition bitarray.h:65
static void bitarray_set(bitarray_t *self, size_t index, bool value)
set or clear the value of the given element
Definition bitarray.h:80
static void bitarray_reset(bitarray_t *self)
free underlying resources and leave a bit array empty
Definition bitarray.h:114
geometric functions (e.g. on points and boxes)
static WUR pointf perp(pointf p)
Definition geomprocs.h:140
static WUR pointf sub_pointf(pointf p, pointf q)
Definition geomprocs.h:96
void free(void *)
Arithmetic helper functions.
type-generic dynamically expanding list
#define LIST_AT(list, index)
Definition list.h:210
#define LIST_APPEND(list,...)
Definition list.h:151
#define LIST(type)
Definition list.h:66
#define LIST_SIZE(list)
Definition list.h:92
#define LIST_FREE(list)
Definition list.h:413
#define LIST_IS_EMPTY(list)
Definition list.h:102
#define LIST_GET(list, index)
Definition list.h:197
static size_t mon_idx
Definition partition.c:68
#define NPOINTS
Definition partition.c:32
static void genSegments(cell *cells, size_t ncells, boxf bb, segment_t *seg, int flip)
Definition partition.c:120
static size_t * generateRandomOrdering(size_t n)
Definition partition.c:134
#define newmon()
Definition partition.c:74
#define TR_FROM_DN
Definition partition.c:35
#define DOT(v0, v1)
Definition partition.c:46
static void convert(boxf bb, int flip, int ccw, pointf *pts)
Definition partition.c:78
static void get_vertex_positions(const vertexchain_t *vert, size_t v0, size_t v1, size_t *ip, size_t *iq)
Definition partition.c:175
static double get_angle(pointf vp0, pointf vpnext, pointf vp1)
Definition partition.c:162
static void traverse_polygon(vertexchain_t *vert, bitarray_t *visited, boxes_t *decomp, segment_t *seg, traps_t *tr, size_t mcur, size_t trnum, size_t from, int flip, int dir, monchain_t *chain)
Definition partition.c:285
static size_t make_new_monotone_poly(vertexchain_t *vert, monchain_t *chain, size_t mcur, size_t v0, size_t v1)
Definition partition.c:220
#define LENGTH(v0)
Definition partition.c:48
static size_t store(segment_t *seg, size_t first, pointf *pts)
Definition partition.c:100
static bool rectIntersect(boxf *d, const boxf r0, const boxf r1)
Definition partition.c:645
#define new_chain_element()
Definition partition.c:76
boxes_t partition(cell *cells, size_t ncells, boxf bb)
partitions space around cells (nodes) into rectangular tiles
Definition partition.c:657
#define TR_FROM_UP
Definition partition.c:34
static size_t chain_idx
Definition partition.c:67
static bool inside_polygon(trap_t *t, segment_t *seg)
Definition partition.c:146
static size_t * mon
Definition partition.c:71
static void monotonate_trapezoids(size_t nsegs, segment_t *seg, traps_t *tr, int flip, boxes_t *decomp)
Definition partition.c:587
#define DEBUG
Definition partition.c:29
#define CROSS_SINE(v0, v1)
Definition partition.c:47
function partition, subroutine of mkMaze
#define PRISIZE_T
Definition prisize_t.h:25
size_t * gv_permutation(size_t bound)
Definition random.c:15
random number generation
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
result of partitioning available space, part of maze
Definition grid.h:33
size_t prev
Definition partition.c:54
size_t next
circularly linked list describing the monotone polygon
Definition partition.c:53
size_t vnum
Definition partition.c:51
double x
Definition geom.h:29
double y
Definition geom.h:29
size_t next
next logical segment
Definition trap.h:33
pointf v0
Definition trap.h:30
pointf v1
Definition trap.h:30
bool is_inserted
Definition trap.h:31
size_t prev
previous segment
Definition trap.h:34
Definition trap.h:40
size_t d1
Definition trap.h:44
pointf lo
Definition trap.h:42
size_t d0
Definition trap.h:44
size_t rseg
two adjoining segments
Definition trap.h:41
size_t u1
Definition trap.h:43
pointf hi
Definition trap.h:42
size_t lseg
Definition trap.h:41
size_t u0
Definition trap.h:43
bool is_valid
Definition trap.h:48
size_t next
next vertex in the chain
Definition partition.c:58
size_t pos
position of vertex in the chain
Definition partition.c:59
Definition legal.c:34
trapezoid elements and utilities for partition.c
static bool is_valid_trap(size_t index)
Definition trap.h:56
static bool equal_to(pointf v0, pointf v1)
Definition trap.h:88
static bool greater_than(pointf v0, pointf v1)
Definition trap.h:92
traps_t construct_trapezoids(size_t, segment_t *, size_t *)
Definition trapezoid.c:861
#define C_EPS
Definition trap.h:63
static bool fp_equal(double s, double t)
Definition trap.h:69
int ccw(Ppoint_t p1, Ppoint_t p2, Ppoint_t p3)
are the given points counter-clockwise, clockwise, or co-linear?
Definition triang.c:25