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