Graphviz 13.1.3~dev.20250813.1130
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/prisize_t.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
50#ifndef HAVE_SRAND48
51#define srand48 srand
52#endif
53#ifdef _WIN32
54extern double drand48(void);
55#endif
56
57typedef struct {
58 int vnum;
59 int next; /* Circularly linked list */
60 int prev; /* describing the monotone */
61 int marked; /* polygon */
63
64typedef struct {
66 int vnext[4]; /* next vertices for the 4 chains */
67 int vpos[4]; /* position of v in the 4 chains */
70
71static int chain_idx;
72static size_t mon_idx;
73 /* Table to hold all the monotone */
74 /* polygons . Each monotone polygon */
75 /* is a circularly linked list */
77 /* chain init. information. This */
78 /* is used to decide which */
79 /* monotone polygon to split if */
80 /* there are several other */
81 /* polygons touching at the same */
82 /* vertex */
84 /* contains position of any vertex in */
85 /* the monotone chain for the polygon */
86static int* mon;
87
88/* return a new mon structure from the table */
89#define newmon() (++mon_idx)
90/* return a new chain element from the table */
91#define new_chain_element() (++chain_idx)
92
93static void
94convert (boxf bb, int flip, int ccw, pointf* pts)
95{
96 pts[0] = bb.LL;
97 pts[2] = bb.UR;
98 if (ccw) {
99 pts[1].x = bb.UR.x;
100 pts[1].y = bb.LL.y;
101 pts[3].x = bb.LL.x;
102 pts[3].y = bb.UR.y;
103 }
104 else {
105 pts[1].x = bb.LL.x;
106 pts[1].y = bb.UR.y;
107 pts[3].x = bb.UR.x;
108 pts[3].y = bb.LL.y;
109 }
110 if (flip) {
111 int i;
112 for (i = 0; i < NPOINTS; i++) {
113 pts[i] = perp(pts[i]);
114 }
115 }
116}
117
118static int
119store (segment_t* seg, int first, pointf* pts)
120{
121 int i, last = first + NPOINTS - 1;
122 int j = 0;
123
124 for (i = first; i <= last; i++, j++) {
125 if (i == first) {
126 seg[i].next = first+1;
127 seg[i].prev = last;
128 }
129 else if (i == last) {
130 seg[i].next = first;
131 seg[i].prev = last-1;
132 }
133 else {
134 seg[i].next = i+1;
135 seg[i].prev = i-1;
136 }
137 seg[i].is_inserted = false;
138 seg[seg[i].prev].v1 = seg[i].v0 = pts[j];
139 }
140 return (last+1);
141}
142
143static void genSegments(cell *cells, size_t ncells, boxf bb, segment_t *seg,
144 int flip) {
145 int i = 1;
146 pointf pts[4];
147
148 convert (bb, flip, 1, pts);
149 i = store (seg, i, pts);
150 for (size_t j = 0; j < ncells; j++) {
151 convert (cells[j].bb, flip, 0, pts);
152 i = store (seg, i, pts);
153 }
154}
155
156/* Generate a random permutation of the segments 1..n */
157static void generateRandomOrdering(size_t n, int *permute) {
158 for (size_t i = 0; i < n; i++) {
159 assert(i < INT_MAX);
160 permute[i] = (int)i + 1;
161 }
162
163 for (size_t i = 0; i < n; i++) {
164 const size_t j = (size_t)((double)i + drand48() * (double)(n - i));
165 if (j != i) {
166 SWAP(&permute[i], &permute[j]);
167 }
168 }
169}
170
171/* Function returns true if the trapezoid lies inside the polygon */
172static bool
174{
175 int rseg = t->rseg;
176
177 if (!t->is_valid)
178 return false;
179
180 if (t->lseg <= 0 || t->rseg <= 0)
181 return false;
182
183 if ((!is_valid_trap(t->u0) && !is_valid_trap(t->u1)) || (!is_valid_trap(t->d0) && !is_valid_trap(t->d1))) // triangle
184 return greater_than(seg[rseg].v1, seg[rseg].v0);
185
186 return false;
187}
188
189static double
190get_angle (pointf *vp0, pointf *vpnext, pointf *vp1)
191{
192 pointf v0, v1;
193
194 v0.x = vpnext->x - vp0->x;
195 v0.y = vpnext->y - vp0->y;
196
197 v1.x = vp1->x - vp0->x;
198 v1.y = vp1->y - vp0->y;
199
200 if (CROSS_SINE(v0, v1) >= 0) /* sine is positive */
201 return DOT(v0, v1)/LENGTH(v0)/LENGTH(v1);
202 else
203 return -1.0 * DOT(v0, v1)/LENGTH(v0)/LENGTH(v1) - 2;
204}
205
206/* (v0, v1) is the new diagonal to be added to the polygon. Find which */
207/* chain to use and return the positions of v0 and v1 in p and q */
208static void
209get_vertex_positions (int v0, int v1, int *ip, int *iq)
210{
211 vertexchain_t *vp0, *vp1;
212 int i;
213 double angle, temp;
214 int tp = 0, tq = 0;
215
216 vp0 = &vert[v0];
217 vp1 = &vert[v1];
218
219 /* p is identified as follows. Scan from (v0, v1) rightwards till */
220 /* you hit the first segment starting from v0. That chain is the */
221 /* chain of our interest */
222
223 angle = -4.0;
224 for (i = 0; i < 4; i++)
225 {
226 if (vp0->vnext[i] <= 0)
227 continue;
228 if ((temp = get_angle(&vp0->pt, &(vert[vp0->vnext[i]].pt),
229 &vp1->pt)) > angle)
230 {
231 angle = temp;
232 tp = i;
233 }
234 }
235
236 *ip = tp;
237
238 /* Do similar actions for q */
239
240 angle = -4.0;
241 for (i = 0; i < 4; i++)
242 {
243 if (vp1->vnext[i] <= 0)
244 continue;
245 if ((temp = get_angle(&vp1->pt, &(vert[vp1->vnext[i]].pt),
246 &vp0->pt)) > angle)
247 {
248 angle = temp;
249 tq = i;
250 }
251 }
252
253 *iq = tq;
254}
255
256/* v0 and v1 are specified in anti-clockwise order with respect to
257 * the current monotone polygon mcur. Split the current polygon into
258 * two polygons using the diagonal (v0, v1)
259 */
260static size_t make_new_monotone_poly(size_t mcur, int v0, int v1) {
261 int p, q, ip, iq;
262 const size_t 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 = %" PRISIZE_T ", (v0, v1) = (%d, %d)\n",
308 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, size_t mcur,
320 size_t trnum, size_t from, int flip, int dir) {
321 size_t mnew;
322 int v0, v1;
323
324 if (!is_valid_trap(trnum) || bitarray_get(*visited, trnum))
325 return;
326
327 trap_t *t = traps_at(tr, trnum);
328
329 bitarray_set(visited, 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 (!is_valid_trap(t->u0) && !is_valid_trap(t->u1)) {
359 if (is_valid_trap(t->d0) && is_valid_trap(t->d1)) { // downward opening triangle
360 v0 = traps_get(tr, t->d1).lseg;
361 v1 = t->lseg;
362 if (from == t->d1)
363 {
364 mnew = make_new_monotone_poly(mcur, v1, v0);
365 traverse_polygon(visited, decomp, seg, tr, mcur, t->d1, trnum, flip, TR_FROM_UP);
366 traverse_polygon(visited, decomp, seg, tr, mnew, t->d0, trnum, flip, TR_FROM_UP);
367 }
368 else
369 {
370 mnew = make_new_monotone_poly(mcur, v0, v1);
371 traverse_polygon (visited, decomp, seg, tr, mcur, t->d0, trnum, flip, TR_FROM_UP);
372 traverse_polygon (visited, decomp, seg, tr, mnew, t->d1, trnum, flip, TR_FROM_UP);
373 }
374 }
375 else
376 {
377 /* Just traverse all neighbours */
378 traverse_polygon(visited, decomp, seg, tr, mcur, t->u0, trnum, flip, TR_FROM_DN);
379 traverse_polygon(visited, decomp, seg, tr, mcur, t->u1, trnum, flip, TR_FROM_DN);
380 traverse_polygon(visited, decomp, seg, tr, mcur, t->d0, trnum, flip, TR_FROM_UP);
381 traverse_polygon(visited, decomp, seg, tr, mcur, t->d1, trnum, flip, TR_FROM_UP);
382 }
383 }
384
385 else if (!is_valid_trap(t->d0) && !is_valid_trap(t->d1)) {
386 if (is_valid_trap(t->u0) && is_valid_trap(t->u1)) { // upward opening triangle
387 v0 = t->rseg;
388 v1 = traps_get(tr, t->u0).rseg;
389 if (from == t->u1)
390 {
391 mnew = make_new_monotone_poly(mcur, v1, v0);
392 traverse_polygon(visited, decomp, seg, tr, mcur, t->u1, trnum, flip, TR_FROM_DN);
393 traverse_polygon(visited, decomp, seg, tr, mnew, t->u0, trnum, flip, TR_FROM_DN);
394 }
395 else
396 {
397 mnew = make_new_monotone_poly(mcur, v0, v1);
398 traverse_polygon(visited, decomp, seg, tr, mcur, t->u0, trnum, flip, TR_FROM_DN);
399 traverse_polygon(visited, decomp, seg, tr, mnew, t->u1, trnum, flip, TR_FROM_DN);
400 }
401 }
402 else
403 {
404 /* Just traverse all neighbours */
405 traverse_polygon(visited, decomp, seg, tr, mcur, t->u0, trnum, flip, TR_FROM_DN);
406 traverse_polygon(visited, decomp, seg, tr, mcur, t->u1, trnum, flip, TR_FROM_DN);
407 traverse_polygon(visited, decomp, seg, tr, mcur, t->d0, trnum, flip, TR_FROM_UP);
408 traverse_polygon(visited, decomp, seg, tr, mcur, t->d1, trnum, flip, TR_FROM_UP);
409 }
410 }
411
412 else if (is_valid_trap(t->u0) && is_valid_trap(t->u1)) {
413 if (is_valid_trap(t->d0) && is_valid_trap(t->d1)) { // downward + upward cusps
414 v0 = traps_get(tr, t->d1).lseg;
415 v1 = traps_get(tr, t->u0).rseg;
416 if ((dir == TR_FROM_DN && t->d1 == from) ||
417 (dir == TR_FROM_UP && t->u1 == from))
418 {
419 mnew = make_new_monotone_poly(mcur, v1, v0);
420 traverse_polygon(visited, decomp, seg, tr, mcur, t->u1, trnum, flip, TR_FROM_DN);
421 traverse_polygon(visited, decomp, seg, tr, mcur, t->d1, trnum, flip, TR_FROM_UP);
422 traverse_polygon(visited, decomp, seg, tr, mnew, t->u0, trnum, flip, TR_FROM_DN);
423 traverse_polygon(visited, decomp, seg, tr, mnew, t->d0, trnum, flip, TR_FROM_UP);
424 }
425 else
426 {
427 mnew = make_new_monotone_poly(mcur, v0, v1);
428 traverse_polygon(visited, decomp, seg, tr, mcur, t->u0, trnum, flip, TR_FROM_DN);
429 traverse_polygon(visited, decomp, seg, tr, mcur, t->d0, trnum, flip, TR_FROM_UP);
430 traverse_polygon(visited, decomp, seg, tr, mnew, t->u1, trnum, flip, TR_FROM_DN);
431 traverse_polygon(visited, decomp, seg, tr, mnew, t->d1, trnum, flip, TR_FROM_UP);
432 }
433 }
434 else /* only downward cusp */
435 {
436 if (equal_to(t->lo, seg[t->lseg].v1)) {
437 v0 = traps_get(tr, t->u0).rseg;
438 v1 = seg[t->lseg].next;
439
440 if (dir == TR_FROM_UP && t->u0 == from)
441 {
442 mnew = make_new_monotone_poly(mcur, v1, v0);
443 traverse_polygon(visited, decomp, seg, tr, mcur, t->u0, trnum, flip, TR_FROM_DN);
444 traverse_polygon(visited, decomp, seg, tr, mnew, t->d0, trnum, flip, TR_FROM_UP);
445 traverse_polygon(visited, decomp, seg, tr, mnew, t->u1, trnum, flip, TR_FROM_DN);
446 traverse_polygon(visited, decomp, seg, tr, mnew, t->d1, trnum, flip, TR_FROM_UP);
447 }
448 else
449 {
450 mnew = make_new_monotone_poly(mcur, v0, v1);
451 traverse_polygon(visited, decomp, seg, tr, mcur, t->u1, trnum, flip, TR_FROM_DN);
452 traverse_polygon(visited, decomp, seg, tr, mcur, t->d0, trnum, flip, TR_FROM_UP);
453 traverse_polygon(visited, decomp, seg, tr, mcur, t->d1, trnum, flip, TR_FROM_UP);
454 traverse_polygon(visited, decomp, seg, tr, mnew, t->u0, trnum, flip, TR_FROM_DN);
455 }
456 }
457 else
458 {
459 v0 = t->rseg;
460 v1 = traps_get(tr, t->u0).rseg;
461 if (dir == TR_FROM_UP && t->u1 == from)
462 {
463 mnew = make_new_monotone_poly(mcur, v1, v0);
464 traverse_polygon(visited, decomp, seg, tr, mcur, t->u1, trnum, flip, TR_FROM_DN);
465 traverse_polygon(visited, decomp, seg, tr, mnew, t->d1, trnum, flip, TR_FROM_UP);
466 traverse_polygon(visited, decomp, seg, tr, mnew, t->d0, trnum, flip, TR_FROM_UP);
467 traverse_polygon(visited, decomp, seg, tr, mnew, t->u0, trnum, flip, TR_FROM_DN);
468 }
469 else
470 {
471 mnew = make_new_monotone_poly(mcur, v0, v1);
472 traverse_polygon(visited, decomp, seg, tr, mcur, t->u0, trnum, flip, TR_FROM_DN);
473 traverse_polygon(visited, decomp, seg, tr, mcur, t->d0, trnum, flip, TR_FROM_UP);
474 traverse_polygon(visited, decomp, seg, tr, mcur, t->d1, trnum, flip, TR_FROM_UP);
475 traverse_polygon(visited, decomp, seg, tr, mnew, t->u1, trnum, flip, TR_FROM_DN);
476 }
477 }
478 }
479 }
480 else if (is_valid_trap(t->u0) || is_valid_trap(t->u1)) { // no downward cusp
481 if (is_valid_trap(t->d0) && is_valid_trap(t->d1)) { // only upward cusp
482 if (equal_to(t->hi, seg[t->lseg].v0)) {
483 v0 = traps_get(tr, t->d1).lseg;
484 v1 = t->lseg;
485 if (!(dir == TR_FROM_DN && t->d0 == from))
486 {
487 mnew = make_new_monotone_poly(mcur, v1, v0);
488 traverse_polygon(visited, decomp, seg, tr, mcur, t->u1, trnum, flip, TR_FROM_DN);
489 traverse_polygon(visited, decomp, seg, tr, mcur, t->d1, trnum, flip, TR_FROM_UP);
490 traverse_polygon(visited, decomp, seg, tr, mcur, t->u0, trnum, flip, TR_FROM_DN);
491 traverse_polygon(visited, decomp, seg, tr, mnew, t->d0, trnum, flip, TR_FROM_UP);
492 }
493 else
494 {
495 mnew = make_new_monotone_poly(mcur, v0, v1);
496 traverse_polygon(visited, decomp, seg, tr, mcur, t->d0, trnum, flip, TR_FROM_UP);
497 traverse_polygon(visited, decomp, seg, tr, mnew, t->u0, trnum, flip, TR_FROM_DN);
498 traverse_polygon(visited, decomp, seg, tr, mnew, t->u1, trnum, flip, TR_FROM_DN);
499 traverse_polygon(visited, decomp, seg, tr, mnew, t->d1, trnum, flip, TR_FROM_UP);
500 }
501 }
502 else
503 {
504 v0 = traps_get(tr, t->d1).lseg;
505 v1 = seg[t->rseg].next;
506
507 if (dir == TR_FROM_DN && t->d1 == from)
508 {
509 mnew = make_new_monotone_poly(mcur, v1, v0);
510 traverse_polygon(visited, decomp, seg, tr, mcur, t->d1, trnum, flip, TR_FROM_UP);
511 traverse_polygon(visited, decomp, seg, tr, mnew, t->u1, trnum, flip, TR_FROM_DN);
512 traverse_polygon(visited, decomp, seg, tr, mnew, t->u0, trnum, flip, TR_FROM_DN);
513 traverse_polygon(visited, decomp, seg, tr, mnew, t->d0, trnum, flip, TR_FROM_UP);
514 }
515 else
516 {
517 mnew = make_new_monotone_poly(mcur, v0, v1);
518 traverse_polygon(visited, decomp, seg, tr, mcur, t->u0, trnum, flip, TR_FROM_DN);
519 traverse_polygon(visited, decomp, seg, tr, mcur, t->d0, trnum, flip, TR_FROM_UP);
520 traverse_polygon(visited, decomp, seg, tr, mcur, t->u1, trnum, flip, TR_FROM_DN);
521 traverse_polygon(visited, decomp, seg, tr, mnew, t->d1, trnum, flip, TR_FROM_UP);
522 }
523 }
524 }
525 else /* no cusp */
526 {
527 if (equal_to(t->hi, seg[t->lseg].v0) && equal_to(t->lo, seg[t->rseg].v0)) {
528 v0 = t->rseg;
529 v1 = t->lseg;
530 if (dir == TR_FROM_UP)
531 {
532 mnew = make_new_monotone_poly(mcur, v1, v0);
533 traverse_polygon(visited, decomp, seg, tr, mcur, t->u0, trnum, flip, TR_FROM_DN);
534 traverse_polygon(visited, decomp, seg, tr, mcur, t->u1, trnum, flip, TR_FROM_DN);
535 traverse_polygon(visited, decomp, seg, tr, mnew, t->d1, trnum, flip, TR_FROM_UP);
536 traverse_polygon(visited, decomp, seg, tr, mnew, t->d0, trnum, flip, TR_FROM_UP);
537 }
538 else
539 {
540 mnew = make_new_monotone_poly(mcur, v0, v1);
541 traverse_polygon(visited, decomp, seg, tr, mcur, t->d1, trnum, flip, TR_FROM_UP);
542 traverse_polygon(visited, decomp, seg, tr, mcur, t->d0, trnum, flip, TR_FROM_UP);
543 traverse_polygon(visited, decomp, seg, tr, mnew, t->u0, trnum, flip, TR_FROM_DN);
544 traverse_polygon(visited, decomp, seg, tr, mnew, t->u1, trnum, flip, TR_FROM_DN);
545 }
546 }
547 else if (equal_to(t->hi, seg[t->rseg].v1) &&
548 equal_to(t->lo, seg[t->lseg].v1)) {
549 v0 = seg[t->rseg].next;
550 v1 = seg[t->lseg].next;
551
552 if (dir == TR_FROM_UP)
553 {
554 mnew = make_new_monotone_poly(mcur, v1, v0);
555 traverse_polygon(visited, decomp, seg, tr, mcur, t->u0, trnum, flip, TR_FROM_DN);
556 traverse_polygon(visited, decomp, seg, tr, mcur, t->u1, trnum, flip, TR_FROM_DN);
557 traverse_polygon(visited, decomp, seg, tr, mnew, t->d1, trnum, flip, TR_FROM_UP);
558 traverse_polygon(visited, decomp, seg, tr, mnew, t->d0, trnum, flip, TR_FROM_UP);
559 }
560 else
561 {
562 mnew = make_new_monotone_poly(mcur, v0, v1);
563 traverse_polygon(visited, decomp, seg, tr, mcur, t->d1, trnum, flip, TR_FROM_UP);
564 traverse_polygon(visited, decomp, seg, tr, mcur, t->d0, trnum, flip, TR_FROM_UP);
565 traverse_polygon(visited, decomp, seg, tr, mnew, t->u0, trnum, flip, TR_FROM_DN);
566 traverse_polygon(visited, decomp, seg, tr, mnew, t->u1, trnum, flip, TR_FROM_DN);
567 }
568 }
569 else /* no split possible */
570 {
571 traverse_polygon(visited, decomp, seg, tr, mcur, t->u0, trnum, flip, TR_FROM_DN);
572 traverse_polygon(visited, decomp, seg, tr, mcur, t->d0, trnum, flip, TR_FROM_UP);
573 traverse_polygon(visited, decomp, seg, tr, mcur, t->u1, trnum, flip, TR_FROM_DN);
574 traverse_polygon(visited, decomp, seg, tr, mcur, t->d1, trnum, flip, TR_FROM_UP);
575 }
576 }
577 }
578}
579
580static void
581monotonate_trapezoids(int nsegs, segment_t *seg, traps_t *tr,
582 int flip, boxes_t *decomp) {
583 int i;
584 bitarray_t visited = bitarray_new(traps_size(tr));
585
586 mchain = gv_calloc(traps_size(tr), sizeof(monchain_t));
587 vert = gv_calloc(nsegs + 1, sizeof(vertexchain_t));
588 mon = gv_calloc(nsegs, sizeof(int));
589
590 /* First locate a trapezoid which lies inside the polygon */
591 /* and which is triangular */
592 size_t j;
593 for (j = 0; j < traps_size(tr); j++)
594 if (inside_polygon(traps_at(tr, j), seg)) break;
595 const size_t tr_start = j;
596
597 /* Initialise the mon data-structure and start spanning all the */
598 /* trapezoids within the polygon */
599
600 for (i = 1; i <= nsegs; i++) {
601 mchain[i].prev = seg[i].prev;
602 mchain[i].next = seg[i].next;
603 mchain[i].vnum = i;
604 vert[i].pt = seg[i].v0;
605 vert[i].vnext[0] = seg[i].next; /* next vertex */
606 vert[i].vpos[0] = i; /* locn. of next vertex */
607 vert[i].nextfree = 1;
608 }
609
610 chain_idx = nsegs;
611 mon_idx = 0;
612 mon[0] = 1; /* position of any vertex in the first */
613 /* chain */
614
615 /* traverse the polygon */
616 if (is_valid_trap(traps_get(tr, tr_start).u0))
617 traverse_polygon(&visited, decomp, seg, tr, 0, tr_start,
618 traps_get(tr, tr_start).u0, flip, TR_FROM_UP);
619 else if (is_valid_trap(traps_get(tr, tr_start).d0))
620 traverse_polygon(&visited, decomp, seg, tr, 0, tr_start,
621 traps_get(tr, tr_start).d0, flip, TR_FROM_DN);
622
623 bitarray_reset(&visited);
624 free (mchain);
625 free (vert);
626 free (mon);
627}
628
629static bool rectIntersect(boxf *d, const boxf r0, const boxf r1) {
630 double t = fmax(r0.LL.x, r1.LL.x);
631 d->UR.x = fmin(r0.UR.x, r1.UR.x);
632 d->LL.x = t;
633
634 t = fmax(r0.LL.y, r1.LL.y);
635 d->UR.y = fmin(r0.UR.y, r1.UR.y);
636 d->LL.y = t;
637
638 return !(d->LL.x >= d->UR.x || d->LL.y >= d->UR.y);
639}
640
641#if DEBUG > 1
642static void
643dumpTrap (trap_t* tr, int n)
644{
645 int i;
646 for (i = 1; i <= n; i++) {
647 tr++;
648 fprintf(stderr, "%d : %d %d (%f,%f) (%f,%f) %" PRISIZE_T " %" PRISIZE_T
649 " %" PRISIZE_T " %" PRISIZE_T "\n", i, tr->lseg, tr->rseg,
650 tr->hi.x, tr->hi.y, tr->lo.x, tr->lo.y, tr->u0, tr->u1, tr->d0,
651 tr->d1);
652 fprintf(stderr, " %" PRISIZE_T " %" PRISIZE_T " %d %s\n", tr->sink,
653 tr->usave, tr->uside, tr->is_valid ? "valid" : "invalid");
654 }
655 fprintf (stderr, "====\n");
656}
657
658static void
659dumpSegs (segment_t* sg, int n)
660{
661 int i;
662 for (i = 1; i <= n; i++) {
663 sg++;
664 fprintf(stderr, "%d : (%f,%f) (%f,%f) %d %" PRISIZE_T " %" PRISIZE_T
665 " %d %d\n", i, sg->v0.x, sg->v0.y, sg->v1.x, sg->v1.y,
666 (int)sg->is_inserted, sg->root0, sg->root1, sg->next, sg->prev);
667 }
668 fprintf (stderr, "====\n");
669}
670#endif
671
672boxf *partition(cell *cells, size_t ncells, size_t *nrects, boxf bb) {
673 const size_t nsegs = 4 * (ncells + 1);
674 segment_t* segs = gv_calloc(nsegs + 1, sizeof(segment_t));
675 int* permute = gv_calloc(nsegs, sizeof(int));
676
677 if (DEBUG) {
678 fprintf(stderr, "cells = %" PRISIZE_T " segs = %" PRISIZE_T
679 " traps = dynamic\n", ncells, nsegs);
680 }
681 genSegments(cells, ncells, bb, segs, 0);
682 if (DEBUG) {
683 fprintf(stderr, "%" PRISIZE_T "\n\n", ncells + 1);
684 for (size_t i = 1; i <= nsegs; i++) {
685 if (i%4 == 1) fprintf(stderr, "4\n");
686 fprintf (stderr, "%f %f\n", segs[i].v0.x, segs[i].v0.y);
687 if (i%4 == 0) fprintf(stderr, "\n");
688 }
689 }
690 srand48(173);
691 generateRandomOrdering(nsegs, permute);
692 assert(nsegs <= INT_MAX);
693 traps_t hor_traps = construct_trapezoids((int)nsegs, segs, permute);
694 if (DEBUG) {
695 fprintf(stderr, "hor traps = %" PRISIZE_T "\n", traps_size(&hor_traps));
696 }
697 boxes_t hor_decomp = {0};
698 monotonate_trapezoids((int)nsegs, segs, &hor_traps, 0, &hor_decomp);
699 traps_free(&hor_traps);
700
701 genSegments(cells, ncells, bb, segs, 1);
702 generateRandomOrdering(nsegs, permute);
703 traps_t ver_traps = construct_trapezoids((int)nsegs, segs, permute);
704 if (DEBUG) {
705 fprintf(stderr, "ver traps = %" PRISIZE_T "\n", traps_size(&ver_traps));
706 }
707 boxes_t vert_decomp = {0};
708 monotonate_trapezoids((int)nsegs, segs, &ver_traps, 1, &vert_decomp);
709 traps_free(&ver_traps);
710
711 boxes_t rs = {0};
712 for (size_t i = 0; i < boxes_size(&vert_decomp); ++i)
713 for (size_t j = 0; j < boxes_size(&hor_decomp); ++j) {
714 boxf newbox = {0};
715 if (rectIntersect(&newbox, boxes_get(&vert_decomp, i),
716 boxes_get(&hor_decomp, j)))
717 boxes_append(&rs, newbox);
718 }
719
720 free (segs);
721 free (permute);
722 boxes_free(&hor_decomp);
723 boxes_free(&vert_decomp);
724 *nrects = boxes_size(&rs);
725 return boxes_detach(&rs);
726}
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:1548
geometric functions (e.g. on points and boxes)
static pointf perp(pointf p)
Definition geomprocs.h:146
void free(void *)
Arithmetic helper functions.
#define SWAP(a, b)
Definition gv_math.h:131
static void get_vertex_positions(int v0, int v1, int *ip, int *iq)
Definition partition.c:209
boxf * partition(cell *cells, size_t ncells, size_t *nrects, boxf bb)
partitions space around cells (nodes) into rectangular tiles
Definition partition.c:672
static size_t mon_idx
Definition partition.c:72
#define NPOINTS
Definition partition.c:32
static void genSegments(cell *cells, size_t ncells, boxf bb, segment_t *seg, int flip)
Definition partition.c:143
#define newmon()
Definition partition.c:89
#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:94
static double get_angle(pointf *vp0, pointf *vpnext, pointf *vp1)
Definition partition.c:190
#define srand48
Definition partition.c:51
static int chain_idx
Definition partition.c:71
static void generateRandomOrdering(size_t n, int *permute)
Definition partition.c:157
static size_t make_new_monotone_poly(size_t mcur, int v0, int v1)
Definition partition.c:260
#define LENGTH(v0)
Definition partition.c:48
static int * mon
Definition partition.c:86
static monchain_t * mchain
Definition partition.c:76
static bool rectIntersect(boxf *d, const boxf r0, const boxf r1)
Definition partition.c:629
static void monotonate_trapezoids(int nsegs, segment_t *seg, traps_t *tr, int flip, boxes_t *decomp)
Definition partition.c:581
#define new_chain_element()
Definition partition.c:91
#define TR_FROM_UP
Definition partition.c:34
static bool inside_polygon(trap_t *t, segment_t *seg)
Definition partition.c:173
#define DEBUG
Definition partition.c:29
#define CROSS_SINE(v0, v1)
Definition partition.c:47
static int store(segment_t *seg, int first, pointf *pts)
Definition partition.c:119
static vertexchain_t * vert
Definition partition.c:83
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)
Definition partition.c:318
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
int vpos[4]
Definition partition.c:67
int vnext[4]
Definition partition.c:66
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:868
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
an array of trapezoids
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