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