1
/* $Id: multispline.c,v 1.18 2009/08/11 21:21:20 erg Exp $Revision: */
2
/* vim:set shiftwidth=4 ts=8: */
4
/**********************************************************
5
* This software is part of the graphviz package *
6
* http://www.graphviz.org/ *
8
* Copyright (c) 1994-2004 AT&T Corp. *
9
* and is licensed under the *
10
* Common Public License, Version 1.0 *
13
* Information and Software Systems Research *
14
* AT&T Research, Florham Park NJ *
15
**********************************************************/
17
#include <multispline.h>
19
#include <neatoprocs.h>
23
static boolean spline_merge(node_t * n)
28
static boolean swap_ends_p(edge_t * e)
33
static splineInfo sinfo = { swap_ends_p, spline_merge };
45
Ppoly_t poly; /* base polygon used for routing an edge */
46
tri **triMap; /* triMap[j] is list of all opposite sides of
47
triangles containing vertex j, represented
48
as the indices of the two points in poly */
52
* Support for map from I x I -> I
55
Dtlink_t link; /* cdt data */
60
static int cmpItem(Dt_t * d, int p1[], int p2[], Dtdisc_t * disc)
67
else if (p1[0] > p2[0])
69
else if (p1[1] < p2[1])
71
else if (p1[1] > p2[1])
79
static void *newItem(Dt_t * d, item * objp, Dtdisc_t * disc)
81
item *newp = NEW(item);
84
newp->a[0] = objp->a[0];
85
newp->a[1] = objp->a[1];
91
static void freeItem(Dt_t * d, item * obj, Dtdisc_t * disc)
96
static Dtdisc_t itemdisc = {
102
(Dtcompar_f) cmpItem,
108
static void addMap(Dt_t * map, int a, int b, int t)
124
* Create mapping from indices of side endpoints to triangle id
125
* We use a set rather than a bag because the segments used for lookup
126
* will always be a side of a polygon and hence have a unique triangle.
128
static Dt_t *mapSegToTri(surface_t * sf)
130
Dt_t *map = dtopen(&itemdisc, Dtoset);
133
for (i = 0; i < sf->nfaces; i++) {
137
addMap(map, a, b, i);
138
addMap(map, b, c, i);
139
addMap(map, c, a, i);
144
static int findMap(Dt_t * map, int a, int b)
155
ip = (item *) dtsearch(map, &it);
161
* Support for map from I -> I
165
Dtlink_t link; /* cdt data */
170
static int cmpIpair(Dt_t * d, int *p1, int *p2, Dtdisc_t * disc)
178
static void *newIpair(Dt_t * d, Ipair * objp, Dtdisc_t * disc)
180
Ipair *newp = NEW(Ipair);
189
static void freeIpair(Dt_t * d, Ipair * obj, Dtdisc_t * disc)
194
static Dtdisc_t ipairdisc = {
197
offsetof(Ipair, link),
199
(Dtfree_f) freeIpair,
200
(Dtcompar_f) cmpIpair,
206
static void vmapAdd(Dt_t * map, int i, int j)
214
static int vMap(Dt_t * map, int i)
217
ip = (Ipair *) dtmatch(map, &i);
222
* Map vertex indices from router_t to tripoly_t coordinates.
224
static void mapTri(Dt_t * map, tri * tp)
226
for (; tp; tp = tp->nxttri) {
227
tp->v.i = vMap(map, tp->v.i);
228
tp->v.j = vMap(map, tp->v.j);
235
addTri(int i, int j, tri * oldp)
245
* Return the angle bisecting the angle pp--cp--np
247
static double bisect(pointf pp, pointf cp, pointf np)
250
theta = atan2(np.y - cp.y, np.x - cp.x);
251
phi = atan2(pp.y - cp.y, pp.x - cp.x);
252
return (theta + phi) / 2.0;
256
* Check if ray v->w intersects segment a--b.
258
static int raySeg(pointf v, pointf w, pointf a, pointf b)
260
int wa = wind(v, w, a);
261
int wb = wind(v, w, b);
265
return (wind(v, b, w) * wind(v, b, a) >= 0);
267
return (wind(v, a, w) * wind(v, a, b) >= 0);
272
* Find the point p where ray v->w intersects segment ai-bi, if any.
273
* Return 1 on success, 0 on failure
276
raySegIntersect(pointf v, pointf w, pointf a, pointf b, pointf * p)
278
if (raySeg(v, w, a, b))
279
return line_intersect(v, w, a, b, p);
285
* Given the triangle vertex v, and point w so that v->w points
286
* into the polygon, return where the ray v->w intersects the
287
* polygon. The search uses all of the opposite sides of triangles
289
* Return 0 on success; 1 on failure.
292
triPoint(tripoly_t * trip, int vx, pointf v, pointf w, pointf * ip)
296
for (tp = trip->triMap[vx]; tp; tp = tp->nxttri) {
298
(v, w, trip->poly.ps[tp->v.i], trip->poly.ps[tp->v.j], ip))
302
fprintf(stderr, "%%Failure in triPoint\n");
303
fprintf(stderr, "0 0 1 setrgbcolor\n");
305
for (tp = trip->triMap[vx]; tp; tp = tp->nxttri) {
306
drawTri(v, trip->poly.ps[tp->v.i], trip->poly.ps[tp->v.j]);
314
* Find the index of v in the points polys->ps.
315
* We start at 1 since the point corresponding to 0
316
* will never be used as v.
318
static int ctrlPtIdx(pointf v, Ppoly_t * polys)
322
for (i = 1; i < polys->pn; i++) {
324
if ((w.x == v.x) && (w.y == v.y))
333
* Generate mult points associated with v.
334
* The points will lie on the ray bisecting the angle prev--v--nxt.
335
* The first point will aways be v.
336
* The rest are positioned equally spaced with maximum spacing SEP.
337
* In addition, they all lie within the polygon trip->poly.
338
* Parameter s gives the index after which a vertex likes on the
339
* opposite side. This is necessary to get the "curvature" of the
342
static pointf *mkCtrlPts(int s, int mult, pointf prev, pointf v,
343
pointf nxt, tripoly_t * trip)
346
int idx = ctrlPtIdx(v, &(trip->poly));
348
double d, sep, theta, sinTheta, cosTheta;
354
ps = N_GNEW(mult, pointf);
355
theta = bisect(prev, v, nxt);
356
sinTheta = sin(theta);
357
cosTheta = cos(theta);
358
w.x = v.x + 100 * cosTheta;
359
w.y = v.y + 100 * sinTheta;
360
if ((idx > s) && (wind(prev, v, w) != 1)) {
363
w.x = v.x + 100 * cosTheta;
364
w.y = v.y + 100 * sinTheta;
365
} else if (wind(prev, v, w) != -1) {
368
w.x = v.x + 100 * cosTheta;
369
w.y = v.y + 100 * sinTheta;
372
if (triPoint(trip, idx, v, w, &q)) {
382
for (i = 0; i < mult; i++) {
383
ps[i].x = v.x + i * sep * cosTheta;
384
ps[i].y = v.y + i * sep * sinTheta;
387
for (i = 0; i < mult; i++) {
388
ps[mult - i - 1].x = v.x + i * sep * cosTheta;
389
ps[mult - i - 1].y = v.y + i * sep * sinTheta;
396
* Simple graph structure for recording the triangle graph.
400
int ne; /* no. of edges. */
401
int *edges; /* indices of edges adjacent to node. */
402
pointf ctr; /* center of triangle. */
406
int t, h; /* indices of head and tail nodes */
407
ipair seg; /* indices of points forming shared segment */
408
double dist; /* length of edge; usually distance between centers */
414
int nedges; /* no. of edges; no. of nodes is stored in router_t */
418
int pn; /* no. of points */
419
pointf *ps; /* all points in configuration */
420
int *obs; /* indices in obstacle i are obs[i]...obs[i+1]-1 */
421
int *tris; /* indices of triangle i are tris[3*i]...tris[3*i+2] */
422
Dt_t *trimap; /* map from obstacle side (a,b) to index of adj. triangle */
423
int tn; /* no. of nodes in tg */
424
tgraph *tg; /* graph of triangles */
428
* Given an array of points and 3 integer indices,
429
* compute and return the center of the triangle.
431
static pointf triCenter(pointf * pts, int *idxs)
433
pointf a = pts[*idxs++];
434
pointf b = pts[*idxs++];
435
pointf c = pts[*idxs++];
437
p.x = (a.x + b.x + c.x) / 3.0;
438
p.y = (a.y + b.y + c.y) / 3.0;
445
* Compute bounding box of polygons, and return it
446
* with an added margin of MARGIN.
447
* Store total number of points in *np.
449
static boxf bbox(Ppoly_t** obsp, int npoly, int *np)
456
bb.LL.x = bb.LL.y = MAXDOUBLE;
457
bb.UR.x = bb.UR.y = -MAXDOUBLE;
459
for (i = 0; i < npoly; i++) {
461
for (j = 0; j < obs->pn; j++) {
485
static int *mkTriIndices(surface_t * sf)
487
int *tris = N_GNEW(3 * sf->nfaces, int);
488
memcpy(tris, sf->faces, 3 * sf->nfaces * sizeof(int));
493
* Given a pointer to an array of 3 integers, return
494
* the number not equal to -1
496
static int degT(int *ip)
508
* Returns a pair of integer (x,y), x < y, where x and y are the
509
* indices of the two vertices of the shared edge.
511
static ipair sharedEdge(int *p, int *q)
518
if ((p2 != *(q + 1)) && (p2 != *(q + 2))) {
521
} else if (p1 == *(q + 1)) {
522
if ((p2 != *q) && (p2 != *(q + 2))) {
525
} else if (p1 == *(q + 2)) {
526
if ((p2 != *q) && (p2 != *(q + 1))) {
544
* Add an edge to g, with tail t, head h, distance d, and shared
547
static void addTriEdge(tgraph * g, int t, int h, double d, ipair seg)
549
tedge *ep = g->edges + g->nedges;
550
tnode *tp = g->nodes + t;
551
tnode *hp = g->nodes + h;
555
ep->dist = DIST(tp->ctr, hp->ctr);
558
tp->edges[tp->ne++] = g->nedges;
559
hp->edges[hp->ne++] = g->nedges;
564
static void freeTriGraph(tgraph * tg)
566
free(tg->nodes->edges);
573
* Generate graph with triangles as nodes and an edge iff two triangles
576
static tgraph *mkTriGraph(surface_t * sf, int maxv, pointf * pts)
584
/* ne is twice no. of edges */
585
for (i = 0; i < 3 * sf->nfaces; i++)
586
if (sf->neigh[i] != -1)
591
/* plus 2 for nodes added as endpoints of an edge */
592
g->nodes = N_GNEW(sf->nfaces + 2, tnode);
594
/* allow 1 possible extra edge per triangle, plus
595
* obstacles can have at most maxv triangles touching
597
edgei = N_GNEW(sf->nfaces + ne + 2 * maxv, int);
598
g->edges = N_GNEW(ne/2 + 2 * maxv, tedge);
601
for (i = 0; i < sf->nfaces; i++) {
605
np->ctr = triCenter(pts, sf->faces + 3 * i);
606
edgei += degT(sf->neigh + 3 * i) + 1;
608
/* initialize variable nodes */
614
np->edges = edgei + maxv;
616
for (i = 0; i < sf->nfaces; i++) {
618
jp = sf->neigh + 3 * i;
620
while ((ne < 3) && ((j = *jp++) != -1)) {
622
double dist = DIST(np->ctr, (g->nodes + j)->ctr);
624
sharedEdge(sf->faces + 3 * i, sf->faces + 3 * j);
625
addTriEdge(g, i, j, dist, seg);
634
void freeRouter(router_t * rtr)
639
dtclose(rtr->trimap);
640
freeTriGraph(rtr->tg);
647
prTriGraph (router_t* rtr, int n)
649
FILE* fp = fopen ("dump","w");
651
pointf* pts = rtr->ps;
652
tnode* nodes = rtr->tg->nodes;
656
for (i=0;i < rtr->tn; i++) {
657
pointf a = pts[rtr->tris[3*i]];
658
pointf b = pts[rtr->tris[3*i+1]];
659
pointf c = pts[rtr->tris[3*i+2]];
661
sprintf (buf, "%d", i);
662
psTxt (buf, nodes[i].ctr);
664
for (i=rtr->tn;i < n; i++) {
665
psTxt (buf, nodes[i].ctr);
668
for (i=0;i < rtr->tg->nedges; i++) {
669
tedge* e = rtr->tg->edges+i;
670
psSeg (nodes[e->t].ctr, nodes[e->h].ctr);
677
router_t *mkRouter(Ppoly_t** obsp, int npoly)
679
router_t *rtr = NEW(router_t);
688
int maxv = 4; /* default max. no. of vertices in an obstacle; set below */
689
/* points in obstacle i have indices obsi[i] through obsi[i+1]-1 in pts
691
int *obsi = N_NEW(npoly + 1, int);
692
int i, j, ix = 4, six = 0;
694
bb = bbox(obsp, npoly, &npts);
695
npts += 4; /* 4 points of bounding box */
696
pts = N_GNEW(npts, pointf); /* all points are stored in pts */
697
segs = N_GNEW(2 * npts, int); /* indices of points forming segments */
699
/* store bounding box in CCW order */
706
for (i = 1; i <= 4; i++) {
714
/* store obstacles in CW order and generate constraint segments */
715
for (i = 0; i < npoly; i++) {
718
for (j = 1; j <= obs->pn; j++) {
721
segs[six++] = ix + 1;
723
segs[six++] = obsi[i];
724
pts[ix++] = obs->ps[j - 1];
731
/* copy points into coordinate arrays */
732
x = N_GNEW(npts, double);
733
y = N_GNEW(npts, double);
734
for (i = 0; i < npts; i++) {
738
sf = mkSurface(x, y, npts, segs, npts);
746
rtr->tris = mkTriIndices(sf);
747
rtr->trimap = mapSegToTri(sf);
748
rtr->tn = sf->nfaces;
749
rtr->tg = mkTriGraph(sf, maxv, pts);
756
* Finish edge generation, clipping to nodes and adding arrowhead
757
* if necessary, and adding edge labels
760
finishEdge (graph_t* g, edge_t* e, Ppoly_t spl, int flip, pointf p, pointf q)
763
pointf *spline = N_GNEW(spl.pn, pointf);
767
for (j = 0; j < spl.pn; j++) {
768
spline[spl.pn - 1 - j] = spl.ps[j];
774
for (j = 0; j < spl.pn; j++) {
775
spline[j] = spl.ps[j];
781
fprintf(stderr, "spline %s %s\n", agnameof(agtail(e)), agnameof(aghead(e)));
782
clip_and_install(e, aghead(e), spline, spl.pn, &sinfo);
785
addEdgeLabels(g, e, p1, q1);
788
#define EQPT(p,q) (((p).x==(q).x)&&((p).y==(q).y))
791
* Hack because path routing doesn't know about the interiors
792
* of polygons. If the first or last segment of the shortest path
793
* lies along one of the polygon boundaries, the path may flip
794
* inside the polygon. To avoid this, we shift the point a bit.
796
* If the edge p(=poly.ps[s])-q of the shortest path is also an
797
* edge of the border polygon, move p slightly inside the polygon
798
* and return it. If prv and nxt are the two vertices adjacent to
799
* p in the polygon, let m be the midpoint of prv--nxt. We then
800
* move a tiny bit along the ray p->m.
802
* Otherwise, return p unchanged.
805
tweakEnd (Ppoly_t poly, int s, Ppolyline_t pl, Ppoint_t q)
807
Ppoint_t prv, nxt, p;
810
nxt = poly.ps[(s + 1) % poly.pn];
812
prv = poly.ps[poly.pn-1];
814
prv = poly.ps[s - 1];
815
if (EQPT(q, nxt) || EQPT(q, prv) ){
818
m.x = (nxt.x + prv.x)/2.0 - p.x;
819
m.y = (nxt.y + prv.y)/2.0 - p.y;
828
tweakPath (Ppoly_t poly, int s, int t, Ppolyline_t pl)
830
pl.ps[0] = tweakEnd (poly, s, pl, pl.ps[1]);
831
pl.ps[pl.pn-1] = tweakEnd (poly, t, pl, pl.ps[pl.pn-2]);
836
* Generate splines for e and cohorts.
837
* Edges go from s to t.
838
* Return 0 on success.
841
genroute(graph_t* g, tripoly_t * trip, int s, int t, edge_t * e, int doPolyline)
845
pointf **cpts; /* lists of control points */
850
Pedge_t *medges = N_GNEW(trip->poly.pn, Pedge_t);
852
int mult = ED_count(e);
853
node_t* head = aghead(e);
855
eps[0].x = trip->poly.ps[s].x, eps[0].y = trip->poly.ps[s].y;
856
eps[1].x = trip->poly.ps[t].x, eps[1].y = trip->poly.ps[t].y;
857
Pshortestpath(&(trip->poly), eps, &pl);
860
makeStraightEdge(agraphof(head), e, doPolyline);
864
evs[0].x = evs[0].y = 0;
865
evs[1].x = evs[1].y = 0;
867
if ((mult == 1) || Concentrate) {
869
for (j = 0; j < poly.pn; j++) {
870
medges[j].a = poly.ps[j];
871
medges[j].b = poly.ps[(j + 1) % poly.pn];
873
tweakPath (poly, s, t, pl);
874
Proutespline(medges, poly.pn, pl, evs, &spl);
875
finishEdge (g, e, spl, aghead(e) != head, eps[0], eps[1]);
881
pn = 2 * (pl.pn - 1);
883
cpts = N_NEW(pl.pn - 2, pointf *);
884
for (i = 0; i < pl.pn - 2; i++) {
886
mkCtrlPts(t, mult+1, pl.ps[i], pl.ps[i + 1], pl.ps[i + 2], trip);
888
agerr(AGWARN, "Could not create control points for multiple spline for edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
893
poly.ps = N_GNEW(pn, pointf);
896
for (i = 0; i < mult; i++) {
898
for (j = 1; j < pl.pn - 1; j++) {
899
poly.ps[j] = cpts[j - 1][i];
901
poly.ps[pl.pn - 1] = eps[1];
902
for (j = 1; j < pl.pn - 1; j++) {
903
poly.ps[pn - j] = cpts[j - 1][i + 1];
905
Pshortestpath(&poly, eps, &mmpl);
908
make_polyline (mmpl, &spl);
911
for (j = 0; j < poly.pn; j++) {
912
medges[j].a = poly.ps[j];
913
medges[j].b = poly.ps[(j + 1) % poly.pn];
915
tweakPath (poly, 0, pl.pn-1, mmpl);
916
Proutespline(medges, poly.pn, mmpl, evs, &spl);
918
finishEdge (g, e, spl, aghead(e) != head, eps[0], eps[1]);
923
for (i = 0; i < pl.pn - 2; i++)
931
#define NSMALL -0.0000000001
934
* Returns true iff q is in the convex cone a-b-c
937
inCone (pointf a, pointf b, pointf c, pointf q)
939
return ((area2(q,a,b) >= NSMALL) && (area2(q,b,c) >= NSMALL));
942
static pointf north = {0, 1};
943
static pointf northeast = {1, 1};
944
static pointf east = {1, 0};
945
static pointf southeast = {1, -1};
946
static pointf south = {0, -1};
947
static pointf southwest = {-1, -1};
948
static pointf west = {-1, 0};
949
static pointf northwest = {-1, 1};
952
* Add node to graph representing spline end point p inside obstruction obs_id.
953
* For each side of obstruction, add edge from p to corresponding triangle.
954
* The node id of the new node in the graph is v_id.
955
* If p lies on the side of its node (sides != 0), we limit the triangles
956
* to those within 45 degrees of each side of the natural direction of p.
958
static void addEndpoint(router_t * rtr, pointf p, node_t* v, int v_id, int sides)
960
int obs_id = ND_lim(v);
961
int starti = rtr->obs[obs_id];
962
int endi = rtr->obs[obs_id + 1];
963
pointf* pts = rtr->ps;
970
vr = add_pointf (p, north);
971
v0 = add_pointf (p, northwest);
972
v1 = add_pointf (p, northeast);
975
vr = add_pointf (p, northeast);
976
v0 = add_pointf (p, north);
977
v1 = add_pointf (p, east);
980
vr = add_pointf (p, east);
981
v0 = add_pointf (p, northeast);
982
v1 = add_pointf (p, southeast);
985
vr = add_pointf (p, southeast);
986
v0 = add_pointf (p, east);
987
v1 = add_pointf (p, south);
990
vr = add_pointf (p, south);
991
v0 = add_pointf (p, southeast);
992
v1 = add_pointf (p, southwest);
995
vr = add_pointf (p, southwest);
996
v0 = add_pointf (p, south);
997
v1 = add_pointf (p, west);
1000
vr = add_pointf (p, west);
1001
v0 = add_pointf (p, southwest);
1002
v1 = add_pointf (p, northwest);
1005
vr = add_pointf (p, northwest);
1006
v0 = add_pointf (p, west);
1007
v1 = add_pointf (p, north);
1016
rtr->tg->nodes[v_id].ne = 0;
1017
rtr->tg->nodes[v_id].ctr = p;
1018
for (i = starti; i < endi; i++) {
1025
t = findMap(rtr->trimap, seg.i, seg.j);
1026
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]))
1028
d = DIST(p, (rtr->tg->nodes + t)->ctr);
1029
addTriEdge(rtr->tg, v_id, t, d, seg);
1034
* Given edge from i to j, find segment associated
1037
* This lookup could be made faster by modifying the
1038
* shortest path algorithm to store the edges rather than
1041
static ipair edgeToSeg(tgraph * tg, int i, int j)
1044
tnode *np = tg->nodes + i;
1047
for (i = 0; i < np->ne; i++) {
1048
ep = tg->edges + np->edges[i];
1049
if ((ep->t == j) || (ep->h == j))
1058
freeTripoly (tripoly_t* trip)
1064
free (trip->poly.ps);
1065
for (i = 0; i < trip->poly.pn; i++) {
1066
for (tp = trip->triMap[i]; tp; tp = nxt) {
1071
free (trip->triMap);
1075
/* Auxiliary data structure used to translate a path of rectangles
1076
* into a polygon. Each side_t represents a vertex on one side of
1077
* the polygon. v is the index of the vertex in the global router_t,
1078
* and ts is a linked list of the indices of segments of sides opposite
1079
* to v in some triangle on the path. These lists will be translated
1080
* to polygon indices by mapTri, and stored in tripoly_t.triMap.
1088
* Construct simple polygon from shortest path from t to s in g.
1089
* dad gives the indices of the triangles on path.
1090
* sx used to store index of s in points.
1091
* index of t is always 0
1093
static tripoly_t *mkPoly(router_t * rtr, int *dad, int s, int t,
1094
pointf p_s, pointf p_t, int *sx)
1107
/* maps vertex index used in router_t to vertex index used in tripoly */
1111
/* count number of triangles in path */
1112
for (nxt = dad[t]; nxt != s; nxt = dad[nxt])
1115
side1 = N_NEW(nt + 4, side_t);
1116
side2 = N_NEW(nt + 4, side_t);
1119
p = edgeToSeg(rtr->tg, nxt, t);
1120
side1[cnt1].ts = addTri(-1, p.j, NULL);
1121
side1[cnt1++].v = p.i;
1122
side2[cnt2].ts = addTri(-1, p.i, NULL);
1123
side2[cnt2++].v = p.j;
1126
for (nxt = dad[t]; nxt >= 0; nxt = dad[nxt]) {
1127
p = edgeToSeg(rtr->tg, t, nxt);
1128
if (p.i == side1[cnt1 - 1].v) {
1129
side1[cnt1 - 1].ts =
1130
addTri(side2[cnt2 - 1].v, p.j, side1[cnt1 - 1].ts);
1131
side2[cnt2 - 1].ts =
1132
addTri(side1[cnt1 - 1].v, p.j, side2[cnt2 - 1].ts);
1134
addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL);
1135
side2[cnt2++].v = p.j;
1136
} else if (p.i == side2[cnt2 - 1].v) {
1137
side1[cnt1 - 1].ts =
1138
addTri(side2[cnt2 - 1].v, p.j, side1[cnt1 - 1].ts);
1139
side2[cnt2 - 1].ts =
1140
addTri(side1[cnt1 - 1].v, p.j, side2[cnt2 - 1].ts);
1142
addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL);
1143
side1[cnt1++].v = p.j;
1144
} else if (p.j == side1[cnt1 - 1].v) {
1145
side1[cnt1 - 1].ts =
1146
addTri(side2[cnt2 - 1].v, p.i, side1[cnt1 - 1].ts);
1147
side2[cnt2 - 1].ts =
1148
addTri(side1[cnt1 - 1].v, p.i, side2[cnt2 - 1].ts);
1150
addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL);
1151
side2[cnt2++].v = p.i;
1153
side1[cnt1 - 1].ts =
1154
addTri(side2[cnt2 - 1].v, p.i, side1[cnt1 - 1].ts);
1155
side2[cnt2 - 1].ts =
1156
addTri(side1[cnt1 - 1].v, p.i, side2[cnt2 - 1].ts);
1158
addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL);
1159
side1[cnt1++].v = p.i;
1163
side1[cnt1 - 1].ts = addTri(-2, side2[cnt2 - 1].v, side1[cnt1 - 1].ts);
1164
side2[cnt2 - 1].ts = addTri(-2, side1[cnt1 - 1].v, side2[cnt2 - 1].ts);
1166
/* store points in pts starting with t in 0,
1167
* then side1, then s, then side2
1169
vmap = dtopen(&ipairdisc, Dtoset);
1170
vmapAdd(vmap, -1, 0);
1171
vmapAdd(vmap, -2, cnt1 + 1);
1172
pps = pts = N_GNEW(nt + 4, pointf);
1173
trim = N_NEW(nt + 4, tri *);
1176
for (i = 0; i < cnt1; i++) {
1177
vmapAdd(vmap, side1[i].v, idx);
1178
*pps++ = rtr->ps[side1[i].v];
1179
trim[idx++] = side1[i].ts;
1183
for (i = cnt2 - 1; i >= 0; i--) {
1184
vmapAdd(vmap, side2[i].v, idx);
1185
*pps++ = rtr->ps[side2[i].v];
1186
trim[idx++] = side2[i].ts;
1189
for (i = 0; i < nt + 4; i++) {
1190
mapTri(vmap, trim[i]);
1193
ps = NEW(tripoly_t);
1194
ps->poly.pn = nt + 4; /* nt triangles gives nt+2 points plus s and t */
1201
*sx = cnt1 + 1; /* index of s in ps */
1206
* Remove edges and nodes added for current edge routing
1208
static void resetGraph(tgraph * g, int ncnt, int ecnt)
1211
tnode *np = g->nodes;
1213
for (i = 0; i < ncnt; i++) {
1214
if (np->edges + np->ne == (np + 1)->edges)
1221
#define PQVTYPE float
1233
#define N_VAL(pq,n) ((PPQ*)pq)->vals[n]
1234
#define N_IDX(pq,n) ((PPQ*)pq)->idxs[n]
1240
#define N_DAD(n) dad[n]
1241
#define E_WT(e) (e->dist)
1242
#define UNSEEN -MAXFLOAT
1245
* Find the shortest path with lengths in g from
1246
* v0 to v1. The returned vector (dad) encodes the
1247
* shorted path from v1 to v0. That path is given by
1248
* v1, dad[v1], dad[dad[v1]], ..., v0.
1251
triPath(tgraph * g, int n, int v0, int v1, PQ * pq)
1257
int *dad = N_NEW(n, int);
1259
for (i = 0; i < pq->PQsize; i++)
1260
N_VAL(pq, i) = UNSEEN;
1267
while ((i = PQremove(pq)) != -1) {
1272
for (j = 0; j < np->ne; j++) {
1273
e = g->edges + np->edges[j];
1278
if (N_VAL(pq, adjn) < 0) {
1279
d = -(N_VAL(pq, i) + E_WT(e));
1280
if (N_VAL(pq, adjn) == UNSEEN) {
1281
N_VAL(pq, adjn) = d;
1284
} else if (N_VAL(pq, adjn) < d) {
1285
PQupdate(pq, adjn, d);
1295
* FIX: we don't really use the shortest path provided by ED_path,
1296
* so avoid in neato spline code.
1297
* Return 0 on success.
1299
int makeMultiSpline(graph_t* g, edge_t* e, router_t * rtr, int doPolyline)
1301
Ppolyline_t line = ED_path(e);
1302
node_t *t = agtail(e);
1303
node_t *h = aghead(e);
1304
pointf t_p = line.ps[0];
1305
pointf h_p = line.ps[line.pn - 1];
1310
int h_id = rtr->tn + 1;
1311
int ecnt = rtr->tg->nedges;
1317
/* Add endpoints to triangle graph */
1318
addEndpoint(rtr, t_p, t, t_id, ED_tail_port(e).side);
1319
addEndpoint(rtr, h_p, h, h_id, ED_head_port(e).side);
1321
/* Initialize priority queue */
1322
PQgen(&pq.pq, rtr->tn + 2, -1);
1323
idxs = N_GNEW(pq.pq.PQsize + 1, PQTYPE);
1324
vals = N_GNEW(pq.pq.PQsize + 1, PQVTYPE);
1329
/* Find shortest path of triangles */
1330
sp = triPath(rtr->tg, rtr->tn+2, h_id, t_id, (PQ *) & pq);
1334
PQfree(&(pq.pq), 0);
1336
/* Use path of triangles to generate guiding polygon */
1337
poly = mkPoly(rtr, sp, h_id, t_id, h_p, t_p, &idx);
1340
/* Generate multiple splines using polygon */
1341
ret = genroute(g, poly, 0, idx, e, doPolyline);
1344
resetGraph(rtr->tg, rtr->tn, ecnt);