Graphviz 13.0.0~dev.20250210.0415
Loading...
Searching...
No Matches
trapezoid.c
Go to the documentation of this file.
1
9/*************************************************************************
10 * Copyright (c) 2011 AT&T Intellectual Property
11 * All rights reserved. This program and the accompanying materials
12 * are made available under the terms of the Eclipse Public License v1.0
13 * which accompanies this distribution, and is available at
14 * https://www.eclipse.org/legal/epl-v10.html
15 *
16 * Contributors: Details at https://graphviz.org
17 *************************************************************************/
18
19
20#include "config.h"
21#include <string.h>
22#include <assert.h>
23#include <stdbool.h>
24#include <stdio.h>
25#include <math.h>
26#include <common/geom.h>
27#include <common/types.h>
28#include <ortho/trap.h>
29#include <util/alloc.h>
30#include <util/gv_math.h>
31
32/* Node types */
33
34#define T_X 1
35#define T_Y 2
36#define T_SINK 3
37
38#define FIRSTPT 1 /* checking whether pt. is inserted */
39#define LASTPT 2
40
41#define S_LEFT 1 /* for merge-direction */
42#define S_RIGHT 2
43
44#define INF 1<<30
45
46#define CROSS(v0, v1, v2) (((v1).x - (v0).x)*((v2).y - (v0).y) - \
47 ((v1).y - (v0).y)*((v2).x - (v0).x))
48
49typedef struct {
50 int nodetype; /* Y-node or S-node */
51 int segnum;
53 int trnum;
54 int parent; /* doubly linked DAG */
55 int left, right; /* children */
56} qnode_t;
57
59typedef struct {
60 size_t length;
62} qnodes_t;
63
64/* Return a new node to be added into the query tree */
65static int newnode(qnodes_t *qs) {
66 qs->data = gv_recalloc(qs->data, qs->length, qs->length + 1, sizeof(qnode_t));
67 ++qs->length;
68 return qs->length - 1;
69}
70
71/* Return a free trapezoid */
72static int newtrap(traps_t *tr) {
73 tr->data = gv_recalloc(tr->data, tr->length, tr->length + 1, sizeof(trap_t));
74 ++tr->length;
75 return tr->length - 1;
76}
77
78/* Return the maximum of the two points into the yval structure */
79static void _max (pointf *yval, pointf *v0, pointf *v1)
80{
81 if (v0->y > v1->y + C_EPS)
82 *yval = *v0;
83 else if (FP_EQUAL(v0->y, v1->y))
84 {
85 if (v0->x > v1->x + C_EPS)
86 *yval = *v0;
87 else
88 *yval = *v1;
89 }
90 else
91 *yval = *v1;
92}
93
94/* Return the minimum of the two points into the yval structure */
95static void _min (pointf *yval, pointf *v0, pointf *v1)
96{
97 if (v0->y < v1->y - C_EPS)
98 *yval = *v0;
99 else if (FP_EQUAL(v0->y, v1->y))
100 {
101 if (v0->x < v1->x)
102 *yval = *v0;
103 else
104 *yval = *v1;
105 }
106 else
107 *yval = *v1;
108}
109
111{
112 if (v0->y > v1->y + C_EPS)
113 return true;
114 else if (v0->y < v1->y - C_EPS)
115 return false;
116 else
117 return v0->x >= v1->x;
118}
119
120static bool _less_than (pointf *v0, pointf *v1)
121{
122 return !_greater_than_equal_to(v0, v1);
123}
124
125/* Initialize the query structure (Q) and the trapezoid table (T)
126 * when the first segment is added to start the trapezoidation. The
127 * query-tree starts out with 4 trapezoids, one S-node and 2 Y-nodes
128 *
129 * 4
130 * -----------------------------------
131 * \
132 * 1 \ 2
133 * \
134 * -----------------------------------
135 * 3
136 */
137
138static int
139init_query_structure(int segnum, segment_t *seg, traps_t *tr, qnodes_t *qs) {
140 int i1, root;
141 int t1, t2, t3, t4;
142 segment_t *s = &seg[segnum];
143
144 i1 = newnode(qs);
145 qs->data[i1].nodetype = T_Y;
146 _max(&qs->data[i1].yval, &s->v0, &s->v1); /* root */
147 root = i1;
148
149 int i2 = newnode(qs);
150 qs->data[i1].right = i2;
151 qs->data[i2].nodetype = T_SINK;
152 qs->data[i2].parent = i1;
153
154 int i3 = newnode(qs);
155 qs->data[i1].left = i3;
156 qs->data[i3].nodetype = T_Y;
157 _min(&qs->data[i3].yval, &s->v0, &s->v1); /* root */
158 qs->data[i3].parent = i1;
159
160 int i4 = newnode(qs);
161 qs->data[i3].left = i4;
162 qs->data[i4].nodetype = T_SINK;
163 qs->data[i4].parent = i3;
164
165 int i5 = newnode(qs);
166 qs->data[i3].right = i5;
167 qs->data[i5].nodetype = T_X;
168 qs->data[i5].segnum = segnum;
169 qs->data[i5].parent = i3;
170
171 int i6 = newnode(qs);
172 qs->data[i5].left = i6;
173 qs->data[i6].nodetype = T_SINK;
174 qs->data[i6].parent = i5;
175
176 int i7 = newnode(qs);
177 qs->data[i5].right = i7;
178 qs->data[i7].nodetype = T_SINK;
179 qs->data[i7].parent = i5;
180
181 t1 = newtrap(tr); /* middle left */
182 t2 = newtrap(tr); /* middle right */
183 t3 = newtrap(tr); /* bottom-most */
184 t4 = newtrap(tr); /* topmost */
185
186 tr->data[t1].hi = qs->data[i1].yval;
187 tr->data[t2].hi = qs->data[i1].yval;
188 tr->data[t4].lo = qs->data[i1].yval;
189 tr->data[t1].lo = qs->data[i3].yval;
190 tr->data[t2].lo = qs->data[i3].yval;
191 tr->data[t3].hi = qs->data[i3].yval;
192 tr->data[t4].hi.y = (double)(INF);
193 tr->data[t4].hi.x = (double)(INF);
194 tr->data[t3].lo.y = (double)-1 * (INF);
195 tr->data[t3].lo.x = (double)-1 * (INF);
196 tr->data[t1].rseg = segnum;
197 tr->data[t2].lseg = segnum;
198 tr->data[t1].u0 = t4;
199 tr->data[t2].u0 = t4;
200 tr->data[t1].d0 = t3;
201 tr->data[t2].d0 = t3;
202 tr->data[t4].d0 = t1;
203 tr->data[t3].u0 = t1;
204 tr->data[t4].d1 = t2;
205 tr->data[t3].u1 = t2;
206
207 tr->data[t1].sink = i6;
208 tr->data[t2].sink = i7;
209 tr->data[t3].sink = i4;
210 tr->data[t4].sink = i2;
211
212 tr->data[t1].state = ST_VALID;
213 tr->data[t2].state = ST_VALID;
214 tr->data[t3].state = ST_VALID;
215 tr->data[t4].state = ST_VALID;
216
217 qs->data[i2].trnum = t4;
218 qs->data[i4].trnum = t3;
219 qs->data[i6].trnum = t1;
220 qs->data[i7].trnum = t2;
221
222 s->is_inserted = true;
223 return root;
224}
225
226/* Return true if the vertex v is to the left of line segment no.
227 * segnum. Takes care of the degenerate cases when both the vertices
228 * have the same y--cood, etc.
229 */
230static bool
231is_left_of (int segnum, segment_t* seg, pointf *v)
232{
233 segment_t *s = &seg[segnum];
234 double area;
235
236 if (_greater_than(&s->v1, &s->v0)) /* seg. going upwards */
237 {
238 if (FP_EQUAL(s->v1.y, v->y))
239 {
240 if (v->x < s->v1.x)
241 area = 1.0;
242 else
243 area = -1.0;
244 }
245 else if (FP_EQUAL(s->v0.y, v->y))
246 {
247 if (v->x < s->v0.x)
248 area = 1.0;
249 else
250 area = -1.0;
251 }
252 else
253 area = CROSS(s->v0, s->v1, *v);
254 }
255 else /* v0 > v1 */
256 {
257 if (FP_EQUAL(s->v1.y, v->y))
258 {
259 if (v->x < s->v1.x)
260 area = 1.0;
261 else
262 area = -1.0;
263 }
264 else if (FP_EQUAL(s->v0.y, v->y))
265 {
266 if (v->x < s->v0.x)
267 area = 1.0;
268 else
269 area = -1.0;
270 }
271 else
272 area = CROSS(s->v1, s->v0, (*v));
273 }
274
275 return area > 0.0;
276}
277
278/* Returns true if the corresponding endpoint of the given segment is */
279/* already inserted into the segment tree. Use the simple test of */
280/* whether the segment which shares this endpoint is already inserted */
281static bool inserted (int segnum, segment_t* seg, int whichpt)
282{
283 if (whichpt == FIRSTPT)
284 return seg[seg[segnum].prev].is_inserted;
285 else
286 return seg[seg[segnum].next].is_inserted;
287}
288
289/* This is query routine which determines which trapezoid does the
290 * point v lie in. The return value is the trapezoid number.
291 */
292static int
293locate_endpoint (pointf *v, pointf *vo, int r, segment_t* seg, qnodes_t* qs)
294{
295 qnode_t *rptr = &qs->data[r];
296
297 switch (rptr->nodetype) {
298 case T_SINK:
299 return rptr->trnum;
300
301 case T_Y:
302 if (_greater_than(v, &rptr->yval)) /* above */
303 return locate_endpoint(v, vo, rptr->right, seg, qs);
304 else if (_equal_to(v, &rptr->yval)) /* the point is already */
305 { /* inserted. */
306 if (_greater_than(vo, &rptr->yval)) /* above */
307 return locate_endpoint(v, vo, rptr->right, seg, qs);
308 else
309 return locate_endpoint(v, vo, rptr->left, seg, qs); /* below */
310 }
311 else
312 return locate_endpoint(v, vo, rptr->left, seg, qs); /* below */
313
314 case T_X:
315 if (_equal_to(v, &seg[rptr->segnum].v0) ||
316 _equal_to(v, &seg[rptr->segnum].v1))
317 {
318 if (FP_EQUAL(v->y, vo->y)) /* horizontal segment */
319 {
320 if (vo->x < v->x)
321 return locate_endpoint(v, vo, rptr->left, seg, qs); /* left */
322 else
323 return locate_endpoint(v, vo, rptr->right, seg, qs); /* right */
324 }
325
326 else if (is_left_of(rptr->segnum, seg, vo))
327 return locate_endpoint(v, vo, rptr->left, seg, qs); /* left */
328 else
329 return locate_endpoint(v, vo, rptr->right, seg, qs); /* right */
330 }
331 else if (is_left_of(rptr->segnum, seg, v))
332 return locate_endpoint(v, vo, rptr->left, seg, qs); /* left */
333 else
334 return locate_endpoint(v, vo, rptr->right, seg, qs); /* right */
335
336 default:
337 fprintf(stderr, "unexpected case in locate_endpoint\n");
338 assert (0);
339 break;
340 }
341 return 1; /* stop warning */
342}
343
344/* Thread in the segment into the existing trapezoidation. The
345 * limiting trapezoids are given by tfirst and tlast (which are the
346 * trapezoids containing the two endpoints of the segment. Merges all
347 * possible trapezoids which flank this segment and have been recently
348 * divided because of its insertion
349 */
350static void
351merge_trapezoids(int segnum, int tfirst, int tlast, int side, traps_t *tr,
352 qnodes_t* qs)
353{
354 int t;
355
356 /* First merge polys on the LHS */
357 t = tfirst;
358 while (t > 0 && _greater_than_equal_to(&tr->data[t].lo, &tr->data[tlast].lo))
359 {
360 int tnext, ptnext;
361 bool cond;
362 if (side == S_LEFT)
363 cond = ((tnext = tr->data[t].d0) > 0 && tr->data[tnext].rseg == segnum) ||
364 ((tnext = tr->data[t].d1) > 0 && tr->data[tnext].rseg == segnum);
365 else
366 cond = ((tnext = tr->data[t].d0) > 0 && tr->data[tnext].lseg == segnum) ||
367 ((tnext = tr->data[t].d1) > 0 && tr->data[tnext].lseg == segnum);
368
369 if (cond)
370 {
371 if (tr->data[t].lseg == tr->data[tnext].lseg &&
372 tr->data[t].rseg == tr->data[tnext].rseg) /* good neighbours */
373 { /* merge them */
374 /* Use the upper node as the new node i.e. t */
375
376 ptnext = qs->data[tr->data[tnext].sink].parent;
377
378 if (qs->data[ptnext].left == tr->data[tnext].sink)
379 qs->data[ptnext].left = tr->data[t].sink;
380 else
381 qs->data[ptnext].right = tr->data[t].sink; /* redirect parent */
382
383
384 /* Change the upper neighbours of the lower trapezoids */
385
386 if ((tr->data[t].d0 = tr->data[tnext].d0) > 0) {
387 if (tr->data[tr->data[t].d0].u0 == tnext)
388 tr->data[tr->data[t].d0].u0 = t;
389 else if (tr->data[tr->data[t].d0].u1 == tnext)
390 tr->data[tr->data[t].d0].u1 = t;
391 }
392
393 if ((tr->data[t].d1 = tr->data[tnext].d1) > 0) {
394 if (tr->data[tr->data[t].d1].u0 == tnext)
395 tr->data[tr->data[t].d1].u0 = t;
396 else if (tr->data[tr->data[t].d1].u1 == tnext)
397 tr->data[tr->data[t].d1].u1 = t;
398 }
399
400 tr->data[t].lo = tr->data[tnext].lo;
401 tr->data[tnext].state = ST_INVALID; /* invalidate the lower */
402 /* trapezium */
403 }
404 else /* not good neighbours */
405 t = tnext;
406 }
407 else /* do not satisfy the outer if */
408 t = tnext;
409
410 } /* end-while */
411
412}
413
414static void update_trapezoid(segment_t *s, segment_t *seg, traps_t *tr, int t, int tn)
415{
416 if (tr->data[t].u0 > 0 && tr->data[t].u1 > 0)
417 { /* continuation of a chain from abv. */
418 if (tr->data[t].usave > 0) /* three upper neighbours */
419 {
420 if (tr->data[t].uside == S_LEFT)
421 {
422 tr->data[tn].u0 = tr->data[t].u1;
423 tr->data[t].u1 = -1;
424 tr->data[tn].u1 = tr->data[t].usave;
425
426 tr->data[tr->data[t].u0].d0 = t;
427 tr->data[tr->data[tn].u0].d0 = tn;
428 tr->data[tr->data[tn].u1].d0 = tn;
429 }
430 else /* intersects in the right */
431 {
432 tr->data[tn].u1 = -1;
433 tr->data[tn].u0 = tr->data[t].u1;
434 tr->data[t].u1 = tr->data[t].u0;
435 tr->data[t].u0 = tr->data[t].usave;
436
437 tr->data[tr->data[t].u0].d0 = t;
438 tr->data[tr->data[t].u1].d0 = t;
439 tr->data[tr->data[tn].u0].d0 = tn;
440 }
441
442 tr->data[t].usave = 0;
443 tr->data[tn].usave = 0;
444 }
445 else /* No usave.... simple case */
446 {
447 tr->data[tn].u0 = tr->data[t].u1;
448 tr->data[t].u1 = -1;
449 tr->data[tn].u1 = -1;
450 tr->data[tr->data[tn].u0].d0 = tn;
451 }
452 }
453 else
454 { /* fresh seg. or upward cusp */
455 int tmp_u = tr->data[t].u0;
456 int td0, td1;
457 if ((td0 = tr->data[tmp_u].d0) > 0 && (td1 = tr->data[tmp_u].d1) > 0)
458 { /* upward cusp */
459 if (tr->data[td0].rseg > 0 && !is_left_of(tr->data[td0].rseg, seg, &s->v1))
460 {
461 tr->data[t].u0 = -1;
462 tr->data[t].u1 = -1;
463 tr->data[tn].u1 = -1;
464 tr->data[tr->data[tn].u0].d1 = tn;
465 }
466 else /* cusp going leftwards */
467 {
468 tr->data[tn].u0 = -1;
469 tr->data[tn].u1 = -1;
470 tr->data[t].u1 = -1;
471 tr->data[tr->data[t].u0].d0 = t;
472 }
473 }
474 else /* fresh segment */
475 {
476 tr->data[tr->data[t].u0].d0 = t;
477 tr->data[tr->data[t].u0].d1 = tn;
478 }
479 }
480}
481
482/* Add in the new segment into the trapezoidation and update Q and T
483 * structures. First locate the two endpoints of the segment in the
484 * Q-structure. Then start from the topmost trapezoid and go down to
485 * the lower trapezoid dividing all the trapezoids in between .
486 */
487static void add_segment(int segnum, segment_t *seg, traps_t *tr, qnodes_t *qs) {
488 segment_t s;
489 int tu, tl, sk, tfirst, tlast;
490 int tfirstr = 0, tlastr = 0, tfirstl = 0, tlastl = 0;
491 int i1, i2, t, tn;
492 int tribot = 0;
493 bool is_swapped;
494 int tmptriseg;
495
496 s = seg[segnum];
497 if (_greater_than(&s.v1, &s.v0)) /* Get higher vertex in v0 */
498 {
499 SWAP(&s.v0, &s.v1);
500 SWAP(&s.root0, &s.root1);
501 is_swapped = true;
502 }
503 else is_swapped = false;
504
505 if (!inserted(segnum, seg, is_swapped ? LASTPT : FIRSTPT))
506 /* insert v0 in the tree */
507 {
508 int tmp_d;
509
510 tu = locate_endpoint(&s.v0, &s.v1, s.root0, seg, qs);
511 tl = newtrap(tr); /* tl is the new lower trapezoid */
512 tr->data[tl].state = ST_VALID;
513 tr->data[tl] = tr->data[tu];
514 tr->data[tu].lo.y = s.v0.y;
515 tr->data[tl].hi.y = s.v0.y;
516 tr->data[tu].lo.x = s.v0.x;
517 tr->data[tl].hi.x = s.v0.x;
518 tr->data[tu].d0 = tl;
519 tr->data[tu].d1 = 0;
520 tr->data[tl].u0 = tu;
521 tr->data[tl].u1 = 0;
522
523 if ((tmp_d = tr->data[tl].d0) > 0 && tr->data[tmp_d].u0 == tu)
524 tr->data[tmp_d].u0 = tl;
525 if ((tmp_d = tr->data[tl].d0) > 0 && tr->data[tmp_d].u1 == tu)
526 tr->data[tmp_d].u1 = tl;
527
528 if ((tmp_d = tr->data[tl].d1) > 0 && tr->data[tmp_d].u0 == tu)
529 tr->data[tmp_d].u0 = tl;
530 if ((tmp_d = tr->data[tl].d1) > 0 && tr->data[tmp_d].u1 == tu)
531 tr->data[tmp_d].u1 = tl;
532
533 /* Now update the query structure and obtain the sinks for the */
534 /* two trapezoids */
535
536 i1 = newnode(qs); /* Upper trapezoid sink */
537 i2 = newnode(qs); /* Lower trapezoid sink */
538 sk = tr->data[tu].sink;
539
540 qs->data[sk].nodetype = T_Y;
541 qs->data[sk].yval = s.v0;
542 qs->data[sk].segnum = segnum; /* not really reqd ... maybe later */
543 qs->data[sk].left = i2;
544 qs->data[sk].right = i1;
545
546 qs->data[i1].nodetype = T_SINK;
547 qs->data[i1].trnum = tu;
548 qs->data[i1].parent = sk;
549
550 qs->data[i2].nodetype = T_SINK;
551 qs->data[i2].trnum = tl;
552 qs->data[i2].parent = sk;
553
554 tr->data[tu].sink = i1;
555 tr->data[tl].sink = i2;
556 tfirst = tl;
557 }
558 else /* v0 already present */
559 { /* Get the topmost intersecting trapezoid */
560 tfirst = locate_endpoint(&s.v0, &s.v1, s.root0, seg, qs);
561 }
562
563
564 if (!inserted(segnum, seg, is_swapped ? FIRSTPT : LASTPT))
565 /* insert v1 in the tree */
566 {
567 int tmp_d;
568
569 tu = locate_endpoint(&s.v1, &s.v0, s.root1, seg, qs);
570
571 tl = newtrap(tr); /* tl is the new lower trapezoid */
572 tr->data[tl].state = ST_VALID;
573 tr->data[tl] = tr->data[tu];
574 tr->data[tu].lo.y = tr->data[tl].hi.y = s.v1.y;
575 tr->data[tu].lo.x = tr->data[tl].hi.x = s.v1.x;
576 tr->data[tu].d0 = tl;
577 tr->data[tu].d1 = 0;
578 tr->data[tl].u0 = tu;
579 tr->data[tl].u1 = 0;
580
581 if ((tmp_d = tr->data[tl].d0) > 0 && tr->data[tmp_d].u0 == tu)
582 tr->data[tmp_d].u0 = tl;
583 if ((tmp_d = tr->data[tl].d0) > 0 && tr->data[tmp_d].u1 == tu)
584 tr->data[tmp_d].u1 = tl;
585
586 if ((tmp_d = tr->data[tl].d1) > 0 && tr->data[tmp_d].u0 == tu)
587 tr->data[tmp_d].u0 = tl;
588 if ((tmp_d = tr->data[tl].d1) > 0 && tr->data[tmp_d].u1 == tu)
589 tr->data[tmp_d].u1 = tl;
590
591 /* Now update the query structure and obtain the sinks for the */
592 /* two trapezoids */
593
594 i1 = newnode(qs); /* Upper trapezoid sink */
595 i2 = newnode(qs); /* Lower trapezoid sink */
596 sk = tr->data[tu].sink;
597
598 qs->data[sk].nodetype = T_Y;
599 qs->data[sk].yval = s.v1;
600 qs->data[sk].segnum = segnum; /* not really reqd ... maybe later */
601 qs->data[sk].left = i2;
602 qs->data[sk].right = i1;
603
604 qs->data[i1].nodetype = T_SINK;
605 qs->data[i1].trnum = tu;
606 qs->data[i1].parent = sk;
607
608 qs->data[i2].nodetype = T_SINK;
609 qs->data[i2].trnum = tl;
610 qs->data[i2].parent = sk;
611
612 tr->data[tu].sink = i1;
613 tr->data[tl].sink = i2;
614 tlast = tu;
615 }
616 else /* v1 already present */
617 { /* Get the lowermost intersecting trapezoid */
618 tlast = locate_endpoint(&s.v1, &s.v0, s.root1, seg, qs);
619 tribot = 1;
620 }
621
622 /* Thread the segment into the query tree creating a new X-node */
623 /* First, split all the trapezoids which are intersected by s into */
624 /* two */
625
626 t = tfirst; /* topmost trapezoid */
627
628 while (t > 0 && _greater_than_equal_to(&tr->data[t].lo, &tr->data[tlast].lo))
629 /* traverse from top to bot */
630 {
631 int t_sav, tn_sav;
632 sk = tr->data[t].sink;
633 i1 = newnode(qs); /* left trapezoid sink */
634 i2 = newnode(qs); /* right trapezoid sink */
635
636 qs->data[sk].nodetype = T_X;
637 qs->data[sk].segnum = segnum;
638 qs->data[sk].left = i1;
639 qs->data[sk].right = i2;
640
641 qs->data[i1].nodetype = T_SINK; /* left trapezoid (use existing one) */
642 qs->data[i1].trnum = t;
643 qs->data[i1].parent = sk;
644
645 qs->data[i2].nodetype = T_SINK; /* right trapezoid (allocate new) */
646 qs->data[i2].trnum = tn = newtrap(tr);
647 tr->data[tn].state = ST_VALID;
648 qs->data[i2].parent = sk;
649
650 if (t == tfirst)
651 tfirstr = tn;
652 if (_equal_to(&tr->data[t].lo, &tr->data[tlast].lo))
653 tlastr = tn;
654
655 tr->data[tn] = tr->data[t];
656 tr->data[t].sink = i1;
657 tr->data[tn].sink = i2;
658 t_sav = t;
659 tn_sav = tn;
660
661 /* error */
662
663 if (tr->data[t].d0 <= 0 && tr->data[t].d1 <= 0) /* case cannot arise */
664 {
665 fprintf(stderr, "add_segment: error\n");
666 break;
667 }
668
669 /* only one trapezoid below. partition t into two and make the */
670 /* two resulting trapezoids t and tn as the upper neighbours of */
671 /* the sole lower trapezoid */
672
673 else if (tr->data[t].d0 > 0 && tr->data[t].d1 <= 0)
674 { /* Only one trapezoid below */
675 update_trapezoid(&s, seg, tr, t, tn);
676
677 if (FP_EQUAL(tr->data[t].lo.y, tr->data[tlast].lo.y) &&
678 FP_EQUAL(tr->data[t].lo.x, tr->data[tlast].lo.x) && tribot)
679 { /* bottom forms a triangle */
680
681 if (is_swapped)
682 tmptriseg = seg[segnum].prev;
683 else
684 tmptriseg = seg[segnum].next;
685
686 if (tmptriseg > 0 && is_left_of(tmptriseg, seg, &s.v0))
687 {
688 /* L-R downward cusp */
689 tr->data[tr->data[t].d0].u0 = t;
690 tr->data[tn].d0 = -1;
691 tr->data[tn].d1 = -1;
692 }
693 else
694 {
695 /* R-L downward cusp */
696 tr->data[tr->data[tn].d0].u1 = tn;
697 tr->data[t].d0 = -1;
698 tr->data[t].d1 = -1;
699 }
700 }
701 else
702 {
703 if (tr->data[tr->data[t].d0].u0 > 0 && tr->data[tr->data[t].d0].u1 > 0)
704 {
705 if (tr->data[tr->data[t].d0].u0 == t) /* passes through LHS */
706 {
707 tr->data[tr->data[t].d0].usave = tr->data[tr->data[t].d0].u1;
708 tr->data[tr->data[t].d0].uside = S_LEFT;
709 }
710 else
711 {
712 tr->data[tr->data[t].d0].usave = tr->data[tr->data[t].d0].u0;
713 tr->data[tr->data[t].d0].uside = S_RIGHT;
714 }
715 }
716 tr->data[tr->data[t].d0].u0 = t;
717 tr->data[tr->data[t].d0].u1 = tn;
718 }
719
720 t = tr->data[t].d0;
721 }
722
723
724 else if (tr->data[t].d0 <= 0 && tr->data[t].d1 > 0)
725 { /* Only one trapezoid below */
726 update_trapezoid(&s, seg, tr, t, tn);
727
728 if (FP_EQUAL(tr->data[t].lo.y, tr->data[tlast].lo.y) &&
729 FP_EQUAL(tr->data[t].lo.x, tr->data[tlast].lo.x) && tribot)
730 { /* bottom forms a triangle */
731
732 if (is_swapped)
733 tmptriseg = seg[segnum].prev;
734 else
735 tmptriseg = seg[segnum].next;
736
737 if (tmptriseg > 0 && is_left_of(tmptriseg, seg, &s.v0))
738 {
739 /* L-R downward cusp */
740 tr->data[tr->data[t].d1].u0 = t;
741 tr->data[tn].d0 = -1;
742 tr->data[tn].d1 = -1;
743 }
744 else
745 {
746 /* R-L downward cusp */
747 tr->data[tr->data[tn].d1].u1 = tn;
748 tr->data[t].d0 = -1;
749 tr->data[t].d1 = -1;
750 }
751 }
752 else
753 {
754 if (tr->data[tr->data[t].d1].u0 > 0 && tr->data[tr->data[t].d1].u1 > 0)
755 {
756 if (tr->data[tr->data[t].d1].u0 == t) /* passes through LHS */
757 {
758 tr->data[tr->data[t].d1].usave = tr->data[tr->data[t].d1].u1;
759 tr->data[tr->data[t].d1].uside = S_LEFT;
760 }
761 else
762 {
763 tr->data[tr->data[t].d1].usave = tr->data[tr->data[t].d1].u0;
764 tr->data[tr->data[t].d1].uside = S_RIGHT;
765 }
766 }
767 tr->data[tr->data[t].d1].u0 = t;
768 tr->data[tr->data[t].d1].u1 = tn;
769 }
770
771 t = tr->data[t].d1;
772 }
773
774 /* two trapezoids below. Find out which one is intersected by */
775 /* this segment and proceed down that one */
776
777 else
778 {
779 double y0, yt;
780 pointf tmppt;
781 int tnext;
782 bool i_d0, i_d1;
783
784 i_d0 = i_d1 = false;
785 if (FP_EQUAL(tr->data[t].lo.y, s.v0.y))
786 {
787 if (tr->data[t].lo.x > s.v0.x)
788 i_d0 = true;
789 else
790 i_d1 = true;
791 }
792 else
793 {
794 tmppt.y = y0 = tr->data[t].lo.y;
795 yt = (y0 - s.v0.y)/(s.v1.y - s.v0.y);
796 tmppt.x = s.v0.x + yt * (s.v1.x - s.v0.x);
797
798 if (_less_than(&tmppt, &tr->data[t].lo))
799 i_d0 = true;
800 else
801 i_d1 = true;
802 }
803
804 /* check continuity from the top so that the lower-neighbour */
805 /* values are properly filled for the upper trapezoid */
806
807 update_trapezoid(&s, seg, tr, t, tn);
808
809 if (FP_EQUAL(tr->data[t].lo.y, tr->data[tlast].lo.y) &&
810 FP_EQUAL(tr->data[t].lo.x, tr->data[tlast].lo.x) && tribot)
811 {
812 /* this case arises only at the lowest trapezoid.. i.e.
813 tlast, if the lower endpoint of the segment is
814 already inserted in the structure */
815
816 tr->data[tr->data[t].d0].u0 = t;
817 tr->data[tr->data[t].d0].u1 = -1;
818 tr->data[tr->data[t].d1].u0 = tn;
819 tr->data[tr->data[t].d1].u1 = -1;
820
821 tr->data[tn].d0 = tr->data[t].d1;
822 tr->data[t].d1 = -1;
823 tr->data[tn].d1 = -1;
824
825 tnext = tr->data[t].d1;
826 }
827 else if (i_d0)
828 /* intersecting d0 */
829 {
830 tr->data[tr->data[t].d0].u0 = t;
831 tr->data[tr->data[t].d0].u1 = tn;
832 tr->data[tr->data[t].d1].u0 = tn;
833 tr->data[tr->data[t].d1].u1 = -1;
834
835 /* new code to determine the bottom neighbours of the */
836 /* newly partitioned trapezoid */
837
838 tr->data[t].d1 = -1;
839
840 tnext = tr->data[t].d0;
841 }
842 else /* intersecting d1 */
843 {
844 tr->data[tr->data[t].d0].u0 = t;
845 tr->data[tr->data[t].d0].u1 = -1;
846 tr->data[tr->data[t].d1].u0 = t;
847 tr->data[tr->data[t].d1].u1 = tn;
848
849 /* new code to determine the bottom neighbours of the */
850 /* newly partitioned trapezoid */
851
852 tr->data[tn].d0 = tr->data[t].d1;
853 tr->data[tn].d1 = -1;
854
855 tnext = tr->data[t].d1;
856 }
857
858 t = tnext;
859 }
860
861 tr->data[t_sav].rseg = segnum;
862 tr->data[tn_sav].lseg = segnum;
863 } /* end-while */
864
865 /* Now combine those trapezoids which share common segments. We can */
866 /* use the pointers to the parent to connect these together. This */
867 /* works only because all these new trapezoids have been formed */
868 /* due to splitting by the segment, and hence have only one parent */
869
870 tfirstl = tfirst;
871 tlastl = tlast;
872 merge_trapezoids(segnum, tfirstl, tlastl, S_LEFT, tr, qs);
873 merge_trapezoids(segnum, tfirstr, tlastr, S_RIGHT, tr, qs);
874
875 seg[segnum].is_inserted = true;
876}
877
878/* Update the roots stored for each of the endpoints of the segment.
879 * This is done to speed up the location-query for the endpoint when
880 * the segment is inserted into the trapezoidation subsequently
881 */
882static void
883find_new_roots(int segnum, segment_t *seg, traps_t *tr, qnodes_t *qs) {
884 segment_t *s = &seg[segnum];
885
886 if (s->is_inserted) return;
887
888 s->root0 = locate_endpoint(&s->v0, &s->v1, s->root0, seg, qs);
889 s->root0 = tr->data[s->root0].sink;
890
891 s->root1 = locate_endpoint(&s->v1, &s->v0, s->root1, seg, qs);
892 s->root1 = tr->data[s->root1].sink;
893}
894
895/* Get log*n for given n */
896static int math_logstar_n(int n)
897{
898 int i;
899 double v;
900
901 for (i = 0, v = (double) n; v >= 1; i++)
902 v = log2(v);
903
904 return i - 1;
905}
906
907static int math_N(int n, int h)
908{
909 int i;
910 double v;
911
912 for (i = 0, v = (double) n; i < h; i++)
913 v = log2(v);
914
915 return (int) ceil((double) 1.0*n/v);
916}
917
918/* Main routine to perform trapezoidation */
919traps_t construct_trapezoids(int nseg, segment_t *seg, int *permute) {
920 int i;
921 int root, h;
922 int segi = 1;
923
924 // We will append later nodes by expanding this on-demand. First node is a
925 // sentinel.
926 qnodes_t qs = {.length = 1, .data = gv_calloc(1, sizeof(qnode_t))};
927
928 // First trapezoid is reserved as a sentinel. We will append later
929 // trapezoids by expanding this on-demand.
930 traps_t tr = {.length = 1, .data = gv_calloc(1, sizeof(trap_t))};
931
932 /* Add the first segment and get the query structure and trapezoid */
933 /* list initialised */
934
935 root = init_query_structure(permute[segi++], seg, &tr, &qs);
936
937 for (i = 1; i <= nseg; i++)
938 seg[i].root0 = seg[i].root1 = root;
939
940 for (h = 1; h <= math_logstar_n(nseg); h++) {
941 for (i = math_N(nseg, h -1) + 1; i <= math_N(nseg, h); i++)
942 add_segment(permute[segi++], seg, &tr, &qs);
943
944 /* Find a new root for each of the segment endpoints */
945 for (i = 1; i <= nseg; i++)
946 find_new_roots(i, seg, &tr, &qs);
947 }
948
949 for (i = math_N(nseg, math_logstar_n(nseg)) + 1; i <= nseg; i++)
950 add_segment(permute[segi++], seg, &tr, &qs);
951
952 free(qs.data);
953 return tr;
954}
Memory allocation wrappers that exit on failure.
static void * gv_recalloc(void *ptr, size_t old_nmemb, size_t new_nmemb, size_t size)
Definition alloc.h:73
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define right(i)
Definition closest.c:79
geometric types and macros (e.g. points and boxes)
void free(void *)
Arithmetic helper functions.
#define SWAP(a, b)
Definition gv_math.h:130
double x
Definition geom.h:29
double y
Definition geom.h:29
int segnum
Definition trapezoid.c:51
int right
Definition trapezoid.c:55
int trnum
Definition trapezoid.c:53
int nodetype
Definition trapezoid.c:50
int parent
Definition trapezoid.c:54
pointf yval
Definition trapezoid.c:52
int left
Definition trapezoid.c:55
an array of qnodes
Definition trapezoid.c:59
size_t length
Definition trapezoid.c:60
qnode_t * data
Definition trapezoid.c:61
pointf v0
Definition trap.h:27
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
trapezoid elements and utilities for partition.c
#define ST_INVALID
Definition trap.h:54
#define _equal_to(v0, v1)
Definition trap.h:80
#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
#define ST_VALID
Definition trap.h:53
#define T_Y
Definition trapezoid.c:35
static bool _less_than(pointf *v0, pointf *v1)
Definition trapezoid.c:120
#define INF
Definition trapezoid.c:44
#define S_LEFT
Definition trapezoid.c:41
static void merge_trapezoids(int segnum, int tfirst, int tlast, int side, traps_t *tr, qnodes_t *qs)
Definition trapezoid.c:351
static void _max(pointf *yval, pointf *v0, pointf *v1)
Definition trapezoid.c:79
static int newnode(qnodes_t *qs)
Definition trapezoid.c:65
#define T_X
Definition trapezoid.c:34
static int math_logstar_n(int n)
Definition trapezoid.c:896
static int math_N(int n, int h)
Definition trapezoid.c:907
static void update_trapezoid(segment_t *s, segment_t *seg, traps_t *tr, int t, int tn)
Definition trapezoid.c:414
#define FIRSTPT
Definition trapezoid.c:38
#define LASTPT
Definition trapezoid.c:39
static bool _greater_than_equal_to(pointf *v0, pointf *v1)
Definition trapezoid.c:110
#define CROSS(v0, v1, v2)
Definition trapezoid.c:46
static void find_new_roots(int segnum, segment_t *seg, traps_t *tr, qnodes_t *qs)
Definition trapezoid.c:883
static int newtrap(traps_t *tr)
Definition trapezoid.c:72
traps_t construct_trapezoids(int nseg, segment_t *seg, int *permute)
Definition trapezoid.c:919
#define S_RIGHT
Definition trapezoid.c:42
static int init_query_structure(int segnum, segment_t *seg, traps_t *tr, qnodes_t *qs)
Definition trapezoid.c:139
static bool inserted(int segnum, segment_t *seg, int whichpt)
Definition trapezoid.c:281
static bool is_left_of(int segnum, segment_t *seg, pointf *v)
Definition trapezoid.c:231
static int locate_endpoint(pointf *v, pointf *vo, int r, segment_t *seg, qnodes_t *qs)
Definition trapezoid.c:293
static void add_segment(int segnum, segment_t *seg, traps_t *tr, qnodes_t *qs)
Definition trapezoid.c:487
static void _min(pointf *yval, pointf *v0, pointf *v1)
Definition trapezoid.c:95
#define T_SINK
Definition trapezoid.c:36
graphs, nodes and edges info: Agraphinfo_t, Agnodeinfo_t and Agedgeinfo_t
Definition grammar.c:93