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