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