Graphviz 12.0.1~dev.20240715.2254
Loading...
Searching...
No Matches
multispline.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 <assert.h>
12#include <cgraph/alloc.h>
13#include <float.h>
14#include <limits.h>
16#include <neatogen/delaunay.h>
17#include <neatogen/neatoprocs.h>
18#include <math.h>
19#include <stdbool.h>
20#include <stddef.h>
21
22static bool spline_merge(node_t * n)
23{
24 (void)n;
25 return false;
26}
27
28static bool swap_ends_p(edge_t * e)
29{
30 (void)e;
31 return false;
32}
33
35 .splineMerge = spline_merge};
36
37typedef struct {
38 int i, j;
39} ipair;
40
41typedef struct _tri {
43 struct _tri *nxttri;
45
46typedef struct {
47 Ppoly_t poly; /* base polygon used for routing an edge */
48 tri **triMap; /* triMap[j] is list of all opposite sides of
49 triangles containing vertex j, represented
50 as the indices of the two points in poly */
51} tripoly_t;
52
53/*
54 * Support for map from I x I -> I
55 */
56typedef struct {
57 Dtlink_t link; /* cdt data */
58 int a[2]; /* key */
59 int t;
60} item;
61
62static int cmpItem(void *item1, void *item2) {
63 const int *p1 = item1;
64 const int *p2 = item2;
65 if (p1[0] < p2[0]) return -1;
66 if (p1[0] > p2[0]) return 1;
67 if (p1[1] < p2[1]) return -1;
68 if (p1[1] > p2[1]) return 1;
69 return 0;
70}
71
72/* newItem:
73 */
74static void *newItem(item *objp, Dtdisc_t *disc) {
75 item *newp = gv_alloc(sizeof(item));
76
77 (void)disc;
78 newp->a[0] = objp->a[0];
79 newp->a[1] = objp->a[1];
80 newp->t = objp->t;
81
82 return newp;
83}
84
86 .key = offsetof(item, a),
87 .size = 2 * sizeof(int),
88 .link = offsetof(item, link),
89 .makef = (Dtmake_f)newItem,
90 .freef = free,
91 .comparf = cmpItem,
92};
93
94static void addMap(Dt_t * map, int a, int b, int t)
95{
96 item it;
97 int tmp;
98 if (a > b) {
99 tmp = a;
100 a = b;
101 b = tmp;
102 }
103 it.a[0] = a;
104 it.a[1] = b;
105 it.t = t;
106 dtinsert(map, &it);
107}
108
109/* mapSegToTri:
110 * Create mapping from indices of side endpoints to triangle id
111 * We use a set rather than a bag because the segments used for lookup
112 * will always be a side of a polygon and hence have a unique triangle.
113 */
115{
116 Dt_t *map = dtopen(&itemdisc, Dtoset);
117 int i, a, b, c;
118 int *ps = sf->faces;
119 for (i = 0; i < sf->nfaces; i++) {
120 a = *ps++;
121 b = *ps++;
122 c = *ps++;
123 addMap(map, a, b, i);
124 addMap(map, b, c, i);
125 addMap(map, c, a, i);
126 }
127 return map;
128}
129
130static int findMap(Dt_t * map, int a, int b)
131{
132 item it;
133 item *ip;
134 if (a > b) {
135 int tmp = a;
136 a = b;
137 b = tmp;
138 }
139 it.a[0] = a;
140 it.a[1] = b;
141 ip = dtsearch(map, &it);
142 assert(ip);
143 return ip->t;
144}
145
146/*
147 * Support for map from I -> I
148 */
149
150typedef struct {
151 Dtlink_t link; /* cdt data */
152 int i; /* key */
153 int j;
154} Ipair;
155
156static int cmpIpair(void *pair1, void *pair2) {
157 const int *p1 = pair1;
158 const int *p2 = pair2;
159 if (*p1 < *p2) {
160 return -1;
161 }
162 if (*p1 > *p2) {
163 return 1;
164 }
165 return 0;
166}
167
168static void *newIpair(Ipair *objp, Dtdisc_t *disc) {
169 Ipair *newp = gv_alloc(sizeof(Ipair));
170
171 (void)disc;
172 newp->i = objp->i;
173 newp->j = objp->j;
174
175 return newp;
176}
177
179 .key = offsetof(Ipair, i),
180 .size = sizeof(int),
181 .link = offsetof(Ipair, link),
182 .makef = (Dtmake_f)newIpair,
183 .freef = free,
184 .comparf = cmpIpair,
185};
186
187static void vmapAdd(Dt_t * map, int i, int j)
188{
189 Ipair obj;
190 obj.i = i;
191 obj.j = j;
192 dtinsert(map, &obj);
193}
194
195static int vMap(Dt_t * map, int i)
196{
197 Ipair *ip;
198 ip = dtmatch(map, &i);
199 return ip->j;
200}
201
202/* mapTri:
203 * Map vertex indices from router_t to tripoly_t coordinates.
204 */
205static void mapTri(Dt_t * map, tri * tp)
206{
207 for (; tp; tp = tp->nxttri) {
208 tp->v.i = vMap(map, tp->v.i);
209 tp->v.j = vMap(map, tp->v.j);
210 }
211}
212
213/* addTri:
214 */
215static tri *
216addTri(int i, int j, tri * oldp)
217{
218 tri *tp = gv_alloc(sizeof(tri));
219 tp->v.i = i;
220 tp->v.j = j;
221 tp->nxttri = oldp;
222 return tp;
223}
224
225/* bisect:
226 * Return the angle bisecting the angle pp--cp--np
227 */
228static double bisect(pointf pp, pointf cp, pointf np)
229{
230 double theta, phi;
231 theta = atan2(np.y - cp.y, np.x - cp.x);
232 phi = atan2(pp.y - cp.y, pp.x - cp.x);
233 return (theta + phi) / 2.0;
234}
235
236/* raySeg:
237 * Check if ray v->w intersects segment a--b.
238 */
239static int raySeg(pointf v, pointf w, pointf a, pointf b)
240{
241 int wa = wind(v, w, a);
242 int wb = wind(v, w, b);
243 if (wa == wb)
244 return 0;
245 if (wa == 0) {
246 return wind(v, b, w) * wind(v, b, a) >= 0;
247 } else {
248 return wind(v, a, w) * wind(v, a, b) >= 0;
249 }
250}
251
252/* raySegIntersect:
253 * Find the point p where ray v->w intersects segment ai-bi, if any.
254 * Return 1 on success, 0 on failure
255 */
256static int
258{
259 if (raySeg(v, w, a, b))
260 return line_intersect(v, w, a, b, p);
261 else
262 return 0;
263}
264
265/* triPoint:
266 * Given the triangle vertex v, and point w so that v->w points
267 * into the polygon, return where the ray v->w intersects the
268 * polygon. The search uses all of the opposite sides of triangles
269 * with v as vertex.
270 * Return 0 on success; 1 on failure.
271 */
272static int
273triPoint(tripoly_t * trip, int vx, pointf v, pointf w, pointf * ip)
274{
275 tri *tp;
276
277 for (tp = trip->triMap[vx]; tp; tp = tp->nxttri) {
279 (v, w, trip->poly.ps[tp->v.i], trip->poly.ps[tp->v.j], ip))
280 return 0;
281 }
282 return 1;
283}
284
285/* ctrlPtIdx:
286 * Find the index of v in the points polys->ps.
287 * We start at 1 since the point corresponding to 0
288 * will never be used as v.
289 */
290static int ctrlPtIdx(pointf v, Ppoly_t * polys)
291{
292 pointf w;
293 for (size_t i = 1; i < polys->pn; i++) {
294 w = polys->ps[i];
295 if (w.x == v.x && w.y == v.y) {
296 assert(i <= INT_MAX);
297 return (int)i;
298 }
299 }
300 return -1;
301}
302
303#define SEP 15
304
305/* mkCtrlPts:
306 * Generate mult points associated with v.
307 * The points will lie on the ray bisecting the angle prev--v--nxt.
308 * The first point will aways be v.
309 * The rest are positioned equally spaced with maximum spacing SEP.
310 * In addition, they all lie within the polygon trip->poly.
311 * Parameter s gives the index after which a vertex lies on the
312 * opposite side. This is necessary to get the "curvature" of the
313 * path correct.
314 */
315static pointf *mkCtrlPts(int s, int mult, pointf prev, pointf v,
316 pointf nxt, tripoly_t * trip)
317{
318 int idx = ctrlPtIdx(v, &trip->poly);
319 int i;
320 double d, sep, theta, sinTheta, cosTheta;
321 pointf q, w;
322
323 if (idx < 0)
324 return NULL;
325
326 pointf *ps = gv_calloc(mult, sizeof(pointf));
327 theta = bisect(prev, v, nxt);
328 sinTheta = sin(theta);
329 cosTheta = cos(theta);
330 w.x = v.x + 100 * cosTheta;
331 w.y = v.y + 100 * sinTheta;
332 if (idx > s) {
333 if (wind(prev, v, w) != 1) {
334 sinTheta *= -1;
335 cosTheta *= -1;
336 w.x = v.x + 100 * cosTheta;
337 w.y = v.y + 100 * sinTheta;
338 }
339 } else if (wind(prev, v, w) != -1) {
340 sinTheta *= -1;
341 cosTheta *= -1;
342 w.x = v.x + 100 * cosTheta;
343 w.y = v.y + 100 * sinTheta;
344 }
345
346 if (triPoint(trip, idx, v, w, &q)) {
347 return 0;
348 }
349
350 d = DIST(q, v);
351 if (d >= mult * SEP)
352 sep = SEP;
353 else
354 sep = d / mult;
355 if (idx < s) {
356 for (i = 0; i < mult; i++) {
357 ps[i].x = v.x + i * sep * cosTheta;
358 ps[i].y = v.y + i * sep * sinTheta;
359 }
360 } else {
361 for (i = 0; i < mult; i++) {
362 ps[mult - i - 1].x = v.x + i * sep * cosTheta;
363 ps[mult - i - 1].y = v.y + i * sep * sinTheta;
364 }
365 }
366 return ps;
367}
368
369/*
370 * Simple graph structure for recording the triangle graph.
371 */
372
373typedef struct {
374 size_t ne; // no. of edges.
375 int *edges; /* indices of edges adjacent to node. */
376 pointf ctr; /* center of triangle. */
377} tnode;
378
379typedef struct {
380 int t, h; /* indices of head and tail nodes */
381 ipair seg; /* indices of points forming shared segment */
382 double dist; /* length of edge; usually distance between centers */
383} tedge;
384
385typedef struct {
387 size_t nnodes; // number of nodes
389 int nedges; // number of edges
390} tgraph;
391
392struct router_s {
393 int pn; /* no. of points */
394 pointf *ps; /* all points in configuration */
395 int *obs; /* indices in obstacle i are obs[i]...obs[i+1]-1 */
396 int *tris; /* indices of triangle i are tris[3*i]...tris[3*i+2] */
397 Dt_t *trimap; /* map from obstacle side (a,b) to index of adj. triangle */
398 int tn; /* no. of nodes in tg */
399 tgraph *tg; /* graph of triangles */
400};
401
402/* triCenter:
403 * Given an array of points and 3 integer indices,
404 * compute and return the center of the triangle.
405 */
406static pointf triCenter(pointf * pts, int *idxs)
407{
408 pointf a = pts[*idxs++];
409 pointf b = pts[*idxs++];
410 pointf c = pts[*idxs++];
411 pointf p;
412 p.x = (a.x + b.x + c.x) / 3.0;
413 p.y = (a.y + b.y + c.y) / 3.0;
414 return p;
415}
416
417#define MARGIN 32
418
419/* bbox:
420 * Compute bounding box of polygons, and return it
421 * with an added margin of MARGIN.
422 * Store total number of points in *np.
423 */
424static boxf bbox(Ppoly_t** obsp, int npoly, int *np)
425{
426 boxf bb;
427 int i, cnt = 0;
428 pointf p;
429 Ppoly_t* obs;
430
431 bb.LL.x = bb.LL.y = DBL_MAX;
432 bb.UR.x = bb.UR.y = -DBL_MAX;
433
434 for (i = 0; i < npoly; i++) {
435 obs = *obsp++;
436 for (size_t j = 0; j < obs->pn; j++) {
437 p = obs->ps[j];
438 bb.LL.x = fmin(bb.LL.x, p.x);
439 bb.UR.x = fmax(bb.UR.x, p.x);
440 bb.LL.y = fmin(bb.LL.y, p.y);
441 bb.UR.y = fmax(bb.UR.y, p.y);
442 cnt++;
443 }
444 }
445
446 *np = cnt;
447
448 bb.LL.x -= MARGIN;
449 bb.LL.y -= MARGIN;
450 bb.UR.x += MARGIN;
451 bb.UR.y += MARGIN;
452
453 return bb;
454}
455
456static int *mkTriIndices(surface_t * sf)
457{
458 int *tris = gv_calloc(3 * sf->nfaces, sizeof(int));
459 memcpy(tris, sf->faces, 3 * sf->nfaces * sizeof(int));
460 return tris;
461}
462
463/* sharedEdge:
464 * Returns a pair of integer (x,y), x < y, where x and y are the
465 * indices of the two vertices of the shared edge.
466 */
467static ipair sharedEdge(int *p, int *q)
468{
469 ipair pt;
470 int tmp, p1, p2;
471 p1 = *p;
472 p2 = *(p + 1);
473 if (p1 == *q) {
474 if (p2 != *(q + 1) && p2 != *(q + 2)) {
475 p2 = *(p + 2);
476 }
477 } else if (p1 == *(q + 1)) {
478 if (p2 != *q && p2 != *(q + 2)) {
479 p2 = *(p + 2);
480 }
481 } else if (p1 == *(q + 2)) {
482 if (p2 != *q && p2 != *(q + 1)) {
483 p2 = *(p + 2);
484 }
485 } else {
486 p1 = *(p + 2);
487 }
488
489 if (p1 > p2) {
490 tmp = p1;
491 p1 = p2;
492 p2 = tmp;
493 }
494 pt.i = p1;
495 pt.j = p2;
496 return pt;
497}
498
499/* addTriEdge:
500 * Add an edge to g, with tail t, head h, and shared
501 * segment seg.
502 */
503static void addTriEdge(tgraph *g, int t, int h, ipair seg) {
504 g->edges = gv_recalloc(g->edges, g->nedges, g->nedges + 1,
505 sizeof(g->edges[0]));
506 tedge *ep = g->edges + g->nedges;
507 tnode *tp = g->nodes + t;
508 tnode *hp = g->nodes + h;
509
510 ep->t = t;
511 ep->h = h;
512 ep->dist = DIST(tp->ctr, hp->ctr);
513 ep->seg = seg;
514
515 tp->edges = gv_recalloc(tp->edges, tp->ne, tp->ne + 1,
516 sizeof(tp->edges[0]));
517 tp->edges[tp->ne++] = g->nedges;
518 hp->edges = gv_recalloc(hp->edges, hp->ne, hp->ne + 1,
519 sizeof(hp->edges[0]));
520 hp->edges[hp->ne++] = g->nedges;
521
522 g->nedges++;
523}
524
525static void freeTriGraph(tgraph * tg)
526{
527 for (size_t i = 0; i < tg->nnodes; ++i) {
528 free(tg->nodes[i].edges);
529 }
530 free(tg->nodes);
531 free(tg->edges);
532 free(tg);
533}
534
535/* mkTriGraph:
536 * Generate graph with triangles as nodes and an edge iff two triangles
537 * share an edge.
538 */
539static tgraph *mkTriGraph(surface_t *sf, pointf *pts) {
540 tnode *np;
541 int j, i, ne = 0;
542 int *jp;
543
544 /* ne is twice no. of edges */
545 for (i = 0; i < 3 * sf->nfaces; i++)
546 if (sf->neigh[i] != -1)
547 ne++;
548
549 tgraph *g = gv_alloc(sizeof(tgraph));
550
551 /* plus 2 for nodes added as endpoints of an edge */
552 g->nnodes = sf->nfaces + 2;
553 g->nodes = gv_calloc(g->nnodes, sizeof(tnode));
554
555 for (i = 0; i < sf->nfaces; i++) {
556 np = g->nodes + i;
557 np->ctr = triCenter(pts, sf->faces + 3 * i);
558 }
559
560 for (i = 0; i < sf->nfaces; i++) {
561 np = g->nodes + i;
562 jp = sf->neigh + 3 * i;
563 ne = 0;
564 while (ne < 3 && (j = *jp++) != -1) {
565 if (i < j) {
566 ipair seg =
567 sharedEdge(sf->faces + 3 * i, sf->faces + 3 * j);
568 addTriEdge(g, i, j, seg);
569 }
570 ne++;
571 }
572 }
573
574 return g;
575}
576
578{
579 free(rtr->ps);
580 free(rtr->obs);
581 free(rtr->tris);
582 dtclose(rtr->trimap);
583 freeTriGraph(rtr->tg);
584 free(rtr);
585}
586
587router_t *mkRouter(Ppoly_t** obsp, int npoly)
588{
589 router_t *rtr = gv_alloc(sizeof(router_t));
590 Ppoly_t* obs;
591 boxf bb;
592 int npts;
593 surface_t *sf;
594 /* points in obstacle i have indices obsi[i] through obsi[i+1]-1 in pts
595 */
596 int *obsi = gv_calloc(npoly + 1, sizeof(int));
597 int i, ix = 4, six = 0;
598
599 bb = bbox(obsp, npoly, &npts);
600 npts += 4; /* 4 points of bounding box */
601 pointf *pts = gv_calloc(npts, sizeof(pointf)); // all points are stored in pts
602 int *segs = gv_calloc(2 * npts, sizeof(int)); // indices of points forming segments
603
604 /* store bounding box in CCW order */
605 pts[0] = bb.LL;
606 pts[1].x = bb.UR.x;
607 pts[1].y = bb.LL.y;
608 pts[2] = bb.UR;
609 pts[3].x = bb.LL.x;
610 pts[3].y = bb.UR.y;
611 for (i = 1; i <= 4; i++) {
612 segs[six++] = i - 1;
613 if (i < 4)
614 segs[six++] = i;
615 else
616 segs[six++] = 0;
617 }
618
619 /* store obstacles in CW order and generate constraint segments */
620 for (i = 0; i < npoly; i++) {
621 obsi[i] = ix;
622 obs = *obsp++;
623 for (size_t j = 1; j <= obs->pn; j++) {
624 segs[six++] = ix;
625 if (j < obs->pn)
626 segs[six++] = ix + 1;
627 else
628 segs[six++] = obsi[i];
629 pts[ix++] = obs->ps[j - 1];
630 }
631 }
632 obsi[i] = ix;
633
634 /* copy points into coordinate arrays */
635 double *x = gv_calloc(npts, sizeof(double));
636 double *y = gv_calloc(npts, sizeof(double));
637 for (i = 0; i < npts; i++) {
638 x[i] = pts[i].x;
639 y[i] = pts[i].y;
640 }
641 sf = mkSurface(x, y, npts, segs, npts);
642 free(x);
643 free(y);
644 free(segs);
645
646 rtr->ps = pts;
647 rtr->pn = npts;
648 rtr->obs = obsi;
649 rtr->tris = mkTriIndices(sf);
650 rtr->trimap = mapSegToTri(sf);
651 rtr->tn = sf->nfaces;
652 rtr->tg = mkTriGraph(sf, pts);
653
654 freeSurface(sf);
655 return rtr;
656}
657
658/* finishEdge:
659 * Finish edge generation, clipping to nodes and adding arrowhead
660 * if necessary, and adding edge labels
661 */
662static void finishEdge(edge_t* e, Ppoly_t spl, int flip) {
663 if (flip) {
664 for (size_t j = 0; j < spl.pn / 2; j++) {
665 pointf tmp = spl.ps[spl.pn - 1 - j];
666 spl.ps[spl.pn - 1 - j] = spl.ps[j];
667 spl.ps[j] = tmp;
668 }
669 }
670 if (Verbose > 1)
671 fprintf(stderr, "spline %s %s\n", agnameof(agtail(e)), agnameof(aghead(e)));
672 clip_and_install(e, aghead(e), spl.ps, spl.pn, &sinfo);
673
674 addEdgeLabels(e);
675}
676
677#define EQPT(p,q) (((p).x==(q).x)&&((p).y==(q).y))
678
679/* tweakEnd:
680 * Hack because path routing doesn't know about the interiors
681 * of polygons. If the first or last segment of the shortest path
682 * lies along one of the polygon boundaries, the path may flip
683 * inside the polygon. To avoid this, we shift the point a bit.
684 *
685 * If the edge p(=poly.ps[s])-q of the shortest path is also an
686 * edge of the border polygon, move p slightly inside the polygon
687 * and return it. If prv and nxt are the two vertices adjacent to
688 * p in the polygon, let m be the midpoint of prv--nxt. We then
689 * move a tiny bit along the ray p->m.
690 *
691 * Otherwise, return p unchanged.
692 */
694 Ppoint_t prv, nxt, p;
695
696 p = poly.ps[s];
697 nxt = poly.ps[(s + 1) % poly.pn];
698 if (s == 0)
699 prv = poly.ps[poly.pn-1];
700 else
701 prv = poly.ps[s - 1];
702 if (EQPT(q, nxt) || EQPT(q, prv) ){
703 Ppoint_t m;
704 m.x = (nxt.x + prv.x)/2.0 - p.x;
705 m.y = (nxt.y + prv.y)/2.0 - p.y;
706 const double d = hypot(m.x, m.y);
707 p.x += 0.1*m.x/d;
708 p.y += 0.1*m.y/d;
709 }
710 return p;
711}
712
713static void tweakPath(Ppoly_t poly, size_t t, Ppolyline_t pl) {
714 pl.ps[0] = tweakEnd(poly, 0, pl.ps[1]);
715 pl.ps[pl.pn-1] = tweakEnd (poly, t, pl.ps[pl.pn-2]);
716}
717
718
719/* genroute:
720 * Generate splines for e and cohorts.
721 * Edges go from 0 to t.
722 * Return 0 on success.
723 */
724static int genroute(tripoly_t *trip, int t, edge_t *e, int doPolyline) {
725 pointf eps[2];
726 Pvector_t evs[2];
727 pointf **cpts = NULL; /* lists of control points */
729 Ppolyline_t pl, spl;
730 Ppolyline_t mmpl;
731 Pedge_t *medges = NULL;
732 int mult = ED_count(e);
733 node_t* head = aghead(e);
734 int rv = 0;
735
736 poly.ps = NULL;
737 pl.pn = 0;
738 eps[0].x = trip->poly.ps[0].x, eps[0].y = trip->poly.ps[0].y;
739 eps[1].x = trip->poly.ps[t].x, eps[1].y = trip->poly.ps[t].y;
740 if (Pshortestpath(&(trip->poly), eps, &pl) < 0) {
741 agwarningf("Could not create control points for multiple spline for edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
742 rv = 1;
743 goto finish;
744 }
745
746 if (pl.pn == 2) {
747 makeStraightEdge(agraphof(head), e, doPolyline, &sinfo);
748 goto finish;
749 }
750
751 evs[0].x = evs[0].y = 0;
752 evs[1].x = evs[1].y = 0;
753
754 if (mult == 1 || Concentrate) {
755 poly = trip->poly;
756 medges = gv_calloc(poly.pn, sizeof(Pedge_t));
757 for (size_t j = 0; j < poly.pn; j++) {
758 medges[j].a = poly.ps[j];
759 medges[j].b = poly.ps[(j + 1) % poly.pn];
760 }
761 assert(t >= 0);
762 tweakPath(poly, (size_t)t, pl);
763 if (Proutespline(medges, poly.pn, pl, evs, &spl) < 0) {
764 agwarningf("Could not create control points for multiple spline for edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
765 rv = 1;
766 goto finish;
767 }
768 finishEdge(e, spl, aghead(e) != head);
769 free(medges);
770
771 return 0;
772 }
773
774 const size_t pn = 2 * (pl.pn - 1);
775
776 cpts = gv_calloc(pl.pn - 2, sizeof(pointf *));
777 for (size_t i = 0; i + 2 < pl.pn; i++) {
778 cpts[i] =
779 mkCtrlPts(t, mult+1, pl.ps[i], pl.ps[i + 1], pl.ps[i + 2], trip);
780 if (!cpts[i]) {
781 agwarningf("Could not create control points for multiple spline for edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
782 rv = 1;
783 goto finish;
784 }
785 }
786
787 poly.ps = gv_calloc(pn, sizeof(pointf));
788 poly.pn = pn;
789
790 for (int i = 0; i < mult; i++) {
791 poly.ps[0] = eps[0];
792 for (size_t j = 1; j + 1 < pl.pn; j++) {
793 poly.ps[j] = cpts[j - 1][i];
794 }
795 poly.ps[pl.pn - 1] = eps[1];
796 for (size_t j = 1; j + 1 < pl.pn; j++) {
797 poly.ps[pn - j] = cpts[j - 1][i + 1];
798 }
799 if (Pshortestpath(&poly, eps, &mmpl) < 0) {
800 agwarningf("Could not create control points for multiple spline for edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
801 rv = 1;
802 goto finish;
803 }
804
805 if (doPolyline) {
806 make_polyline (mmpl, &spl);
807 }
808 else {
809 medges = gv_calloc(poly.pn, sizeof(Pedge_t));
810 for (size_t j = 0; j < poly.pn; j++) {
811 medges[j].a = poly.ps[j];
812 medges[j].b = poly.ps[(j + 1) % poly.pn];
813 }
814 tweakPath(poly, pl.pn - 1, mmpl);
815 if (Proutespline(medges, poly.pn, mmpl, evs, &spl) < 0) {
816 agwarningf("Could not create control points for multiple spline for edge (%s,%s)\n",
817 agnameof(agtail(e)), agnameof(aghead(e)));
818 rv = 1;
819 goto finish;
820 }
821 }
822 finishEdge(e, spl, aghead(e) != head);
823
824 e = ED_to_virt(e);
825 }
826
827finish :
828 if (cpts) {
829 for (size_t i = 0; i + 2 < pl.pn; i++)
830 free(cpts[i]);
831 free(cpts);
832 }
833 free(medges);
834 free(poly.ps);
835 return rv;
836}
837
838#define NSMALL -0.0000000001
839
840/* inCone:
841 * Returns true iff q is in the convex cone a-b-c
842 */
843static int
845{
846 return area2(q,a,b) >= NSMALL && area2(q,b,c) >= NSMALL;
847}
848
849static pointf north = {0, 1};
850static pointf northeast = {1, 1};
851static pointf east = {1, 0};
852static pointf southeast = {1, -1};
853static pointf south = {0, -1};
854static pointf southwest = {-1, -1};
855static pointf west = {-1, 0};
856static pointf northwest = {-1, 1};
857
858/* addEndpoint:
859 * Add node to graph representing spline end point p inside obstruction obs_id.
860 * For each side of obstruction, add edge from p to corresponding triangle.
861 * The node id of the new node in the graph is v_id.
862 * If p lies on the side of its node (sides != 0), we limit the triangles
863 * to those within 45 degrees of each side of the natural direction of p.
864 */
865static void addEndpoint(router_t * rtr, pointf p, node_t* v, int v_id, int sides)
866{
867 int obs_id = ND_lim(v);
868 int starti = rtr->obs[obs_id];
869 int endi = rtr->obs[obs_id + 1];
870 pointf* pts = rtr->ps;
871 int i, t;
872 pointf vr, v0, v1;
873
874 switch (sides) {
875 case TOP :
876 vr = add_pointf (p, north);
877 v0 = add_pointf (p, northwest);
878 v1 = add_pointf (p, northeast);
879 break;
880 case TOP|RIGHT :
881 vr = add_pointf (p, northeast);
882 v0 = add_pointf (p, north);
883 v1 = add_pointf (p, east);
884 break;
885 case RIGHT :
886 vr = add_pointf (p, east);
887 v0 = add_pointf (p, northeast);
888 v1 = add_pointf (p, southeast);
889 break;
890 case BOTTOM|RIGHT :
891 vr = add_pointf (p, southeast);
892 v0 = add_pointf (p, east);
893 v1 = add_pointf (p, south);
894 break;
895 case BOTTOM :
896 vr = add_pointf (p, south);
897 v0 = add_pointf (p, southeast);
898 v1 = add_pointf (p, southwest);
899 break;
900 case BOTTOM|LEFT :
901 vr = add_pointf (p, southwest);
902 v0 = add_pointf (p, south);
903 v1 = add_pointf (p, west);
904 break;
905 case LEFT :
906 vr = add_pointf (p, west);
907 v0 = add_pointf (p, southwest);
908 v1 = add_pointf (p, northwest);
909 break;
910 case TOP|LEFT :
911 vr = add_pointf (p, northwest);
912 v0 = add_pointf (p, west);
913 v1 = add_pointf (p, north);
914 break;
915 case 0 :
916 break;
917 default :
918 assert (0);
919 break;
920 }
921
922 rtr->tg->nodes[v_id].ne = 0;
923 rtr->tg->nodes[v_id].ctr = p;
924 for (i = starti; i < endi; i++) {
925 ipair seg;
926 seg.i = i;
927 if (i < endi - 1)
928 seg.j = i + 1;
929 else
930 seg.j = starti;
931 t = findMap(rtr->trimap, seg.i, seg.j);
932 if (sides && !inCone (v0, p, v1, pts[seg.i]) && !inCone (v0, p, v1, pts[seg.j]) && !raySeg(p,vr,pts[seg.i],pts[seg.j]))
933 continue;
934 addTriEdge(rtr->tg, v_id, t, seg);
935 }
936 assert(rtr->tg->nodes[v_id].ne > 0 && "no edges were added");
937}
938
939/* edgeToSeg:
940 * Given edge from i to j, find segment associated
941 * with the edge.
942 *
943 * This lookup could be made faster by modifying the
944 * shortest path algorithm to store the edges rather than
945 * the nodes.
946 */
947static ipair edgeToSeg(tgraph * tg, int i, int j)
948{
949 ipair ip = {0, 0};
950 tnode *np = tg->nodes + i;
951 tedge *ep;
952
953 for (size_t k = 0; k < np->ne; k++) {
954 ep = tg->edges + np->edges[k];
955 if (ep->t == j || ep->h == j)
956 return ep->seg;
957 }
958
959 assert(0);
960 return ip;
961}
962
963static void
965{
966 tri* tp;
967 tri* nxt;
968
969 free (trip->poly.ps);
970 for (size_t i = 0; i < trip->poly.pn; i++) {
971 for (tp = trip->triMap[i]; tp; tp = nxt) {
972 nxt = tp->nxttri;
973 free (tp);
974 }
975 }
976 free (trip->triMap);
977 free (trip);
978}
979
980/* Auxiliary data structure used to translate a path of rectangles
981 * into a polygon. Each side_t represents a vertex on one side of
982 * the polygon. v is the index of the vertex in the global router_t,
983 * and ts is a linked list of the indices of segments of sides opposite
984 * to v in some triangle on the path. These lists will be translated
985 * to polygon indices by mapTri, and stored in tripoly_t.triMap.
986 */
987typedef struct {
988 int v;
990} side_t;
991
992/* mkPoly:
993 * Construct simple polygon from shortest path from t to s in g.
994 * dad gives the indices of the triangles on path.
995 * sx used to store index of s in points.
996 * index of t is always 0
997 */
998static tripoly_t *mkPoly(router_t * rtr, int *dad, int s, int t,
999 pointf p_s, pointf p_t, int *sx)
1000{
1001 tripoly_t *ps;
1002 int nxt;
1003 ipair p;
1004 size_t nt = 0;
1005 int idx;
1006 int cnt1 = 0;
1007 int cnt2 = 0;
1008 pointf *pts;
1009 /* maps vertex index used in router_t to vertex index used in tripoly */
1010 Dt_t *vmap;
1011
1012 /* count number of triangles in path */
1013 for (nxt = dad[t]; nxt != s; nxt = dad[nxt]) {
1014 nt++;
1015 assert (nxt != dad[nxt] && "infinite loop due to 'nxt' not changing");
1016 }
1017
1018 side_t *side1 = gv_calloc(nt + 4, sizeof(side_t));
1019 side_t *side2 = gv_calloc(nt + 4, sizeof(side_t));
1020
1021 nxt = dad[t];
1022 p = edgeToSeg(rtr->tg, nxt, t);
1023 side1[cnt1].ts = addTri(-1, p.j, NULL);
1024 side1[cnt1++].v = p.i;
1025 side2[cnt2].ts = addTri(-1, p.i, NULL);
1026 side2[cnt2++].v = p.j;
1027
1028 t = nxt;
1029 for (nxt = dad[t]; nxt >= 0; nxt = dad[nxt]) {
1030 p = edgeToSeg(rtr->tg, t, nxt);
1031 if (p.i == side1[cnt1 - 1].v) {
1032 side1[cnt1 - 1].ts =
1033 addTri(side2[cnt2 - 1].v, p.j, side1[cnt1 - 1].ts);
1034 side2[cnt2 - 1].ts =
1035 addTri(side1[cnt1 - 1].v, p.j, side2[cnt2 - 1].ts);
1036 side2[cnt2].ts =
1037 addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL);
1038 side2[cnt2++].v = p.j;
1039 } else if (p.i == side2[cnt2 - 1].v) {
1040 side1[cnt1 - 1].ts =
1041 addTri(side2[cnt2 - 1].v, p.j, side1[cnt1 - 1].ts);
1042 side2[cnt2 - 1].ts =
1043 addTri(side1[cnt1 - 1].v, p.j, side2[cnt2 - 1].ts);
1044 side1[cnt1].ts =
1045 addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL);
1046 side1[cnt1++].v = p.j;
1047 } else if (p.j == side1[cnt1 - 1].v) {
1048 side1[cnt1 - 1].ts =
1049 addTri(side2[cnt2 - 1].v, p.i, side1[cnt1 - 1].ts);
1050 side2[cnt2 - 1].ts =
1051 addTri(side1[cnt1 - 1].v, p.i, side2[cnt2 - 1].ts);
1052 side2[cnt2].ts =
1053 addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL);
1054 side2[cnt2++].v = p.i;
1055 } else {
1056 side1[cnt1 - 1].ts =
1057 addTri(side2[cnt2 - 1].v, p.i, side1[cnt1 - 1].ts);
1058 side2[cnt2 - 1].ts =
1059 addTri(side1[cnt1 - 1].v, p.i, side2[cnt2 - 1].ts);
1060 side1[cnt1].ts =
1061 addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL);
1062 side1[cnt1++].v = p.i;
1063 }
1064 t = nxt;
1065 }
1066 side1[cnt1 - 1].ts = addTri(-2, side2[cnt2 - 1].v, side1[cnt1 - 1].ts);
1067 side2[cnt2 - 1].ts = addTri(-2, side1[cnt1 - 1].v, side2[cnt2 - 1].ts);
1068
1069 /* store points in pts starting with t in 0,
1070 * then side1, then s, then side2
1071 */
1072 vmap = dtopen(&ipairdisc, Dtoset);
1073 vmapAdd(vmap, -1, 0);
1074 vmapAdd(vmap, -2, cnt1 + 1);
1075 pointf *pps = pts = gv_calloc(nt + 4, sizeof(pointf));
1076 tri **trim = gv_calloc(nt + 4, sizeof(tri*));
1077 *pps++ = p_t;
1078 idx = 1;
1079 for (int i = 0; i < cnt1; i++) {
1080 vmapAdd(vmap, side1[i].v, idx);
1081 *pps++ = rtr->ps[side1[i].v];
1082 trim[idx++] = side1[i].ts;
1083 }
1084 *pps++ = p_s;
1085 idx++;
1086 for (int i = cnt2 - 1; i >= 0; i--) {
1087 vmapAdd(vmap, side2[i].v, idx);
1088 *pps++ = rtr->ps[side2[i].v];
1089 trim[idx++] = side2[i].ts;
1090 }
1091
1092 for (size_t i = 0; i < nt + 4; i++) {
1093 mapTri(vmap, trim[i]);
1094 }
1095
1096 ps = gv_alloc(sizeof(tripoly_t));
1097 ps->poly.pn = nt + 4; /* nt triangles gives nt+2 points plus s and t */
1098 ps->poly.ps = pts;
1099 ps->triMap = trim;
1100
1101 free (side1);
1102 free (side2);
1103 dtclose(vmap);
1104 *sx = cnt1 + 1; /* index of s in ps */
1105 return ps;
1106}
1107
1108/* resetGraph:
1109 * Remove edges and nodes added for current edge routing
1110 */
1111static void resetGraph(tgraph *g, int ncnt, int ecnt,
1112 size_t *original_edge_count) {
1113 int i;
1114 tnode *np = g->nodes;
1115 g->nedges = ecnt;
1116 for (i = 0; i < ncnt; i++) {
1117 np->ne = original_edge_count[i];
1118 np++;
1119 }
1120}
1121
1122#define PQTYPE int
1123#define PQVTYPE float
1124
1125#define PQ_TYPES
1126#include <neatogen/fPQ.h>
1127#undef PQ_TYPES
1128
1129typedef struct {
1130 PQ pq;
1132 int *idxs;
1133} PPQ;
1134
1135#define N_VAL(pq,n) ((PPQ*)pq)->vals[n]
1136#define N_IDX(pq,n) ((PPQ*)pq)->idxs[n]
1137
1138#define PQ_CODE
1139#include <neatogen/fPQ.h>
1140#undef PQ_CODE
1141
1142#define N_DAD(n) dad[n]
1143#define E_WT(e) (e->dist)
1144#define UNSEEN (-FLT_MAX)
1145
1146/* triPath:
1147 * Find the shortest path with lengths in g from
1148 * v0 to v1. The returned vector (dad) encodes the
1149 * shorted path from v1 to v0. That path is given by
1150 * v1, dad[v1], dad[dad[v1]], ..., v0.
1151 */
1152static int *
1153triPath(tgraph * g, int n, int v0, int v1, PQ * pq)
1154{
1155 int i, adjn;
1156 double d;
1157 tnode *np;
1158 tedge *e;
1159 int *dad = gv_calloc(n, sizeof(int));
1160
1161 for (i = 0; i < pq->PQsize; i++)
1162 N_VAL(pq, i) = UNSEEN;
1163
1164 PQinit(pq);
1165 N_DAD(v0) = -1;
1166 N_VAL(pq, v0) = 0;
1167 if (PQinsert(pq, v0))
1168 return NULL;
1169
1170 while ((i = PQremove(pq)) != -1) {
1171 N_VAL(pq, i) *= -1;
1172 if (i == v1)
1173 break;
1174 np = g->nodes + i;
1175 for (size_t j = 0; j < np->ne; j++) {
1176 e = g->edges + np->edges[j];
1177 if (e->t == i)
1178 adjn = e->h;
1179 else
1180 adjn = e->t;
1181 if (N_VAL(pq, adjn) < 0) {
1182 d = -(N_VAL(pq, i) + E_WT(e));
1183 if (N_VAL(pq, adjn) == UNSEEN) {
1184 N_VAL(pq, adjn) = d;
1185 N_DAD(adjn) = i;
1186 if (PQinsert(pq, adjn)) {
1187 free(dad);
1188 return NULL;
1189 }
1190 } else if (N_VAL(pq, adjn) < d) {
1191 PQupdate(pq, adjn, d);
1192 N_DAD(adjn) = i;
1193 }
1194 }
1195 }
1196 }
1197 return dad;
1198}
1199
1200/* makeMultiSpline:
1201 * FIX: we don't really use the shortest path provided by ED_path,
1202 * so avoid in neato spline code.
1203 * Return 0 on success.
1204 */
1205int makeMultiSpline(edge_t* e, router_t * rtr, int doPolyline) {
1206 Ppolyline_t line = ED_path(e);
1207 node_t *t = agtail(e);
1208 node_t *h = aghead(e);
1209 pointf t_p = line.ps[0];
1210 pointf h_p = line.ps[line.pn - 1];
1211 tripoly_t *poly;
1212 int idx;
1213 int *sp;
1214 int t_id = rtr->tn;
1215 int h_id = rtr->tn + 1;
1216 int ecnt = rtr->tg->nedges;
1217 PPQ pq;
1218 int ret;
1219
1220 // record the number of edges in each node, so we can drop the added ones
1221 // later
1222 size_t *original_edge_count = gv_calloc(rtr->tg->nnodes,
1223 sizeof(original_edge_count[0]));
1224 for (size_t i = 0; i < rtr->tg->nnodes; ++i)
1225 original_edge_count[i] = rtr->tg->nodes[i].ne;
1226
1227 /* Add endpoints to triangle graph */
1228 addEndpoint(rtr, t_p, t, t_id, ED_tail_port(e).side);
1229 addEndpoint(rtr, h_p, h, h_id, ED_head_port(e).side);
1230
1231 /* Initialize priority queue */
1232 PQgen(&pq.pq, rtr->tn + 2, -1);
1233 PQTYPE *idxs = gv_calloc(pq.pq.PQsize + 1, sizeof(PQTYPE));
1234 PQVTYPE *vals = gv_calloc(pq.pq.PQsize + 1, sizeof(PQVTYPE));
1235 vals[0] = 0;
1236 pq.vals = vals + 1;
1237 pq.idxs = idxs + 1;
1238
1239 /* Find shortest path of triangles */
1240 sp = triPath(rtr->tg, rtr->tn+2, h_id, t_id, (PQ *) & pq);
1241
1242 free(vals);
1243 free(idxs);
1244 PQfree(&(pq.pq), 0);
1245
1246 /* Use path of triangles to generate guiding polygon */
1247 if (sp) {
1248 poly = mkPoly(rtr, sp, h_id, t_id, h_p, t_p, &idx);
1249 free(sp);
1250
1251 /* Generate multiple splines using polygon */
1252 ret = genroute(poly, idx, e, doPolyline);
1253 freeTripoly (poly);
1254 }
1255 else ret = -1;
1256
1257 resetGraph(rtr->tg, rtr->tn, ecnt, original_edge_count);
1258 free(original_edge_count);
1259 return ret;
1260}
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
static void * gv_alloc(size_t size)
Definition alloc.h:47
void *(* Dtmake_f)(void *, Dtdisc_t *)
Definition cdt.h:50
#define dtmatch(d, o)
Definition cdt.h:192
#define dtsearch(d, o)
Definition cdt.h:191
#define dtinsert(d, o)
Definition cdt.h:193
CDT_API int dtclose(Dt_t *)
Definition dtclose.c:8
CDT_API Dtmethod_t * Dtoset
ordered set (self-adjusting tree)
Definition dttree.c:304
CDT_API Dt_t * dtopen(Dtdisc_t *, Dtmethod_t *)
Definition dtopen.c:9
#define LEFT
Definition const.h:120
#define RIGHT
Definition const.h:118
#define BOTTOM
Definition const.h:117
#define TOP
Definition const.h:119
surface_t * mkSurface(double *x, double *y, int n, int *segs, int nsegs)
Definition delaunay.c:762
void freeSurface(surface_t *s)
Definition delaunay.c:768
#define head
Definition dthdr.h:15
void PQinit(void)
Definition fPQ.c:44
static snode ** pq
Definition fPQ.c:19
void PQgen(int sz)
Definition fPQ.c:25
void PQfree(void)
Definition fPQ.c:36
snode * PQremove(void)
Definition fPQ.c:121
void PQupdate(snode *n, int d)
Definition fPQ.c:137
int line_intersect(pointf a, pointf b, pointf c, pointf d, pointf *p)
Definition geom.c:235
#define DIST(p, q)
Definition geom.h:62
static pointf add_pointf(pointf p, pointf q)
Definition geomprocs.h:63
bool Concentrate
Definition globals.h:61
static int Verbose
Definition gml2gv.c:22
void free(void *)
node NULL
Definition grammar.y:149
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:199
#define ED_count(e)
Definition types.h:580
#define agtail(e)
Definition cgraph.h:889
#define ED_path(e)
Definition types.h:593
#define aghead(e)
Definition cgraph.h:890
#define ED_head_port(e)
Definition types.h:588
#define ED_tail_port(e)
Definition types.h:597
#define ED_to_virt(e)
Definition types.h:599
void agwarningf(const char *fmt,...)
Definition agerror.c:173
#define ND_lim(n)
Definition types.h:504
Agraph_t * agraphof(void *obj)
Definition obj.c:184
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:158
static void freef(void *ident)
void PQinsert(Halfedge *he, Site *v, double offset)
Definition heap.c:42
$2 u p prev
Definition htmlparse.y:495
static int * ps
Definition lu.c:51
static tripoly_t * mkPoly(router_t *rtr, int *dad, int s, int t, pointf p_s, pointf p_t, int *sx)
static int findMap(Dt_t *map, int a, int b)
static void addMap(Dt_t *map, int a, int b, int t)
Definition multispline.c:94
static tgraph * mkTriGraph(surface_t *sf, pointf *pts)
static pointf southwest
static void mapTri(Dt_t *map, tri *tp)
#define PQVTYPE
router_t * mkRouter(Ppoly_t **obsp, int npoly)
static pointf northwest
static ipair sharedEdge(int *p, int *q)
struct _tri tri
static int raySegIntersect(pointf v, pointf w, pointf a, pointf b, pointf *p)
static int * mkTriIndices(surface_t *sf)
static void * newItem(item *objp, Dtdisc_t *disc)
Definition multispline.c:74
static bool swap_ends_p(edge_t *e)
Definition multispline.c:28
static bool spline_merge(node_t *n)
Definition multispline.c:22
void freeRouter(router_t *rtr)
static void * newIpair(Ipair *objp, Dtdisc_t *disc)
static void addTriEdge(tgraph *g, int t, int h, ipair seg)
#define N_DAD(n)
static int vMap(Dt_t *map, int i)
static void finishEdge(edge_t *e, Ppoly_t spl, int flip)
static pointf east
static int inCone(pointf a, pointf b, pointf c, pointf q)
static int cmpItem(void *item1, void *item2)
Definition multispline.c:62
static void resetGraph(tgraph *g, int ncnt, int ecnt, size_t *original_edge_count)
int makeMultiSpline(edge_t *e, router_t *rtr, int doPolyline)
static pointf * mkCtrlPts(int s, int mult, pointf prev, pointf v, pointf nxt, tripoly_t *trip)
static ipair edgeToSeg(tgraph *tg, int i, int j)
static tri * addTri(int i, int j, tri *oldp)
static void tweakPath(Ppoly_t poly, size_t t, Ppolyline_t pl)
#define NSMALL
static int genroute(tripoly_t *trip, int t, edge_t *e, int doPolyline)
static pointf triCenter(pointf *pts, int *idxs)
static pointf northeast
static Ppoint_t tweakEnd(Ppoly_t poly, size_t s, Ppoint_t q)
#define SEP
static pointf west
static int * triPath(tgraph *g, int n, int v0, int v1, PQ *pq)
#define E_WT(e)
static Dtdisc_t itemdisc
Definition multispline.c:85
static int cmpIpair(void *pair1, void *pair2)
static int raySeg(pointf v, pointf w, pointf a, pointf b)
static pointf southeast
#define UNSEEN
#define MARGIN
static pointf north
static Dt_t * mapSegToTri(surface_t *sf)
static Dtdisc_t ipairdisc
#define N_VAL(pq, n)
static splineInfo sinfo
Definition multispline.c:34
static void freeTriGraph(tgraph *tg)
static int triPoint(tripoly_t *trip, int vx, pointf v, pointf w, pointf *ip)
static int ctrlPtIdx(pointf v, Ppoly_t *polys)
static boxf bbox(Ppoly_t **obsp, int npoly, int *np)
static pointf south
static void vmapAdd(Dt_t *map, int i, int j)
static void addEndpoint(router_t *rtr, pointf p, node_t *v, int v_id, int sides)
#define PQTYPE
static double bisect(pointf pp, pointf cp, pointf np)
#define EQPT(p, q)
static void freeTripoly(tripoly_t *trip)
void make_polyline(Ppolyline_t line, Ppolyline_t *sline)
Definition util.c:59
int Proutespline(Pedge_t *barriers, size_t n_barriers, Ppolyline_t input_route, Pvector_t endpoint_slopes[2], Ppolyline_t *output_route)
Definition route.c:69
int Pshortestpath(Ppoly_t *boundary, Ppoint_t endpoints[2], Ppolyline_t *output_route)
Definition shortest.c:85
PATHUTIL_API int wind(Ppoint_t a, Ppoint_t b, Ppoint_t c)
Definition visibility.c:53
PATHUTIL_API COORD area2(Ppoint_t, Ppoint_t, Ppoint_t)
Definition visibility.c:44
void clip_and_install(edge_t *fe, node_t *hn, pointf *ps, size_t pn, splineInfo *info)
Definition splines.c:238
void makeStraightEdge(graph_t *g, edge_t *e, int edgetype, splineInfo *info)
Definition routespl.c:934
void addEdgeLabels(edge_t *e)
Definition splines.c:1328
static triangles_t tris
Definition shortest.c:57
Dtlink_t link
PQVTYPE * vals
int * idxs
Ppoint_t b
Definition pathgeom.h:53
Ppoint_t a
Definition pathgeom.h:53
size_t pn
Definition pathgeom.h:47
Ppoint_t * ps
Definition pathgeom.h:46
double x
Definition pathgeom.h:38
double y
Definition pathgeom.h:38
Definition cdt.h:104
int key
Definition cdt.h:89
struct _tri * nxttri
Definition multispline.c:43
ipair v
Definition multispline.c:42
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
int i
Definition multispline.c:38
int j
Definition multispline.c:38
Definition utils.c:748
node_t * t
Definition utils.c:751
int a[2]
Definition multispline.c:58
int t
Definition multispline.c:59
double x
Definition geom.h:29
double y
Definition geom.h:29
tgraph * tg
pointf * ps
Dt_t * trimap
int * tris
int * obs
tri * ts
bool(* swapEnds)(edge_t *e)
Definition types.h:67
int * faces
Definition delaunay.h:19
int nfaces
Definition delaunay.h:18
int * neigh
Definition delaunay.h:20
ipair seg
double dist
tnode * nodes
int nedges
size_t nnodes
tedge * edges
size_t ne
int * edges
pointf ctr
tri ** triMap
Definition multispline.c:48
Ppoly_t poly
Definition multispline.c:47
struct poly_s poly
Definition grammar.c:93