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