Graphviz  2.29.20120524.0446
lib/neatogen/multispline.c
Go to the documentation of this file.
00001 /* $Id$Revision: */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 #include <multispline.h>
00015 #include <delaunay.h>
00016 #include <neatoprocs.h>
00017 #include <math.h>
00018 
00019 
00020 static boolean spline_merge(node_t * n)
00021 {
00022     return FALSE;
00023 }
00024 
00025 static boolean swap_ends_p(edge_t * e)
00026 {
00027     return FALSE;
00028 }
00029 
00030 static splineInfo sinfo = { swap_ends_p, spline_merge };
00031 
00032 typedef struct {
00033     int i, j;
00034 } ipair;
00035 
00036 typedef struct _tri {
00037     ipair v;
00038     struct _tri *nxttri;
00039 } tri;
00040 
00041 typedef struct {
00042     Ppoly_t poly;       /* base polygon used for routing an edge */
00043     tri **triMap;       /* triMap[j] is list of all opposite sides of 
00044                            triangles containing vertex j, represented
00045                            as the indices of the two points in poly */
00046 } tripoly_t;
00047 
00048 /*
00049  * Support for map from I x I -> I
00050  */
00051 typedef struct {
00052     Dtlink_t link;              /* cdt data */
00053     int a[2];                   /* key */
00054     int t;
00055 } item;
00056 
00057 static int cmpItem(Dt_t * d, int p1[], int p2[], Dtdisc_t * disc)
00058 {
00059     NOTUSED(d);
00060     NOTUSED(disc);
00061 
00062     if (p1[0] < p2[0])
00063         return -1;
00064     else if (p1[0] > p2[0])
00065         return 1;
00066     else if (p1[1] < p2[1])
00067         return -1;
00068     else if (p1[1] > p2[1])
00069         return 1;
00070     else
00071         return 0;
00072 }
00073 
00074 /* newItem:
00075  */
00076 static void *newItem(Dt_t * d, item * objp, Dtdisc_t * disc)
00077 {
00078     item *newp = NEW(item);
00079 
00080     NOTUSED(disc);
00081     newp->a[0] = objp->a[0];
00082     newp->a[1] = objp->a[1];
00083     newp->t = objp->t;
00084 
00085     return newp;
00086 }
00087 
00088 static void freeItem(Dt_t * d, item * obj, Dtdisc_t * disc)
00089 {
00090     free(obj);
00091 }
00092 
00093 static Dtdisc_t itemdisc = {
00094     offsetof(item, a),
00095     2 * sizeof(int),
00096     offsetof(item, link),
00097     (Dtmake_f) newItem,
00098     (Dtfree_f) freeItem,
00099     (Dtcompar_f) cmpItem,
00100     NIL(Dthash_f),
00101     NIL(Dtmemory_f),
00102     NIL(Dtevent_f)
00103 };
00104 
00105 static void addMap(Dt_t * map, int a, int b, int t)
00106 {
00107     item it;
00108     int tmp;
00109     if (a > b) {
00110         tmp = a;
00111         a = b;
00112         b = tmp;
00113     }
00114     it.a[0] = a;
00115     it.a[1] = b;
00116     it.t = t;
00117     dtinsert(map, &it);
00118 }
00119 
00120 /* mapSegToTri:
00121  * Create mapping from indices of side endpoints to triangle id 
00122  * We use a set rather than a bag because the segments used for lookup
00123  * will always be a side of a polygon and hence have a unique triangle.
00124  */
00125 static Dt_t *mapSegToTri(surface_t * sf)
00126 {
00127     Dt_t *map = dtopen(&itemdisc, Dtoset);
00128     int i, a, b, c;
00129     int *ps = sf->faces;
00130     for (i = 0; i < sf->nfaces; i++) {
00131         a = *ps++;
00132         b = *ps++;
00133         c = *ps++;
00134         addMap(map, a, b, i);
00135         addMap(map, b, c, i);
00136         addMap(map, c, a, i);
00137     }
00138     return map;
00139 }
00140 
00141 static int findMap(Dt_t * map, int a, int b)
00142 {
00143     item it;
00144     item *ip;
00145     if (a > b) {
00146         int tmp = a;
00147         a = b;
00148         b = tmp;
00149     }
00150     it.a[0] = a;
00151     it.a[1] = b;
00152     ip = (item *) dtsearch(map, &it);
00153     assert(ip);
00154     return ip->t;
00155 }
00156 
00157 /*
00158  * Support for map from I -> I
00159  */
00160 
00161 typedef struct {
00162     Dtlink_t link;              /* cdt data */
00163     int i;                      /* key */
00164     int j;
00165 } Ipair;
00166 
00167 static int cmpIpair(Dt_t * d, int *p1, int *p2, Dtdisc_t * disc)
00168 {
00169     NOTUSED(d);
00170     NOTUSED(disc);
00171 
00172     return (*p1 - *p2);
00173 }
00174 
00175 static void *newIpair(Dt_t * d, Ipair * objp, Dtdisc_t * disc)
00176 {
00177     Ipair *newp = NEW(Ipair);
00178 
00179     NOTUSED(disc);
00180     newp->i = objp->i;
00181     newp->j = objp->j;
00182 
00183     return newp;
00184 }
00185 
00186 static void freeIpair(Dt_t * d, Ipair * obj, Dtdisc_t * disc)
00187 {
00188     free(obj);
00189 }
00190 
00191 static Dtdisc_t ipairdisc = {
00192     offsetof(Ipair, i),
00193     sizeof(int),
00194     offsetof(Ipair, link),
00195     (Dtmake_f) newIpair,
00196     (Dtfree_f) freeIpair,
00197     (Dtcompar_f) cmpIpair,
00198     NIL(Dthash_f),
00199     NIL(Dtmemory_f),
00200     NIL(Dtevent_f)
00201 };
00202 
00203 static void vmapAdd(Dt_t * map, int i, int j)
00204 {
00205     Ipair obj;
00206     obj.i = i;
00207     obj.j = j;
00208     dtinsert(map, &obj);
00209 }
00210 
00211 static int vMap(Dt_t * map, int i)
00212 {
00213     Ipair *ip;
00214     ip = (Ipair *) dtmatch(map, &i);
00215     return ip->j;
00216 }
00217 
00218 /* mapTri:
00219  * Map vertex indices from router_t to tripoly_t coordinates.
00220  */
00221 static void mapTri(Dt_t * map, tri * tp)
00222 {
00223     for (; tp; tp = tp->nxttri) {
00224         tp->v.i = vMap(map, tp->v.i);
00225         tp->v.j = vMap(map, tp->v.j);
00226     }
00227 }
00228 
00229 /* addTri:
00230  */
00231 static tri *
00232 addTri(int i, int j, tri * oldp)
00233 {
00234     tri *tp = NEW(tri);
00235     tp->v.i = i;
00236     tp->v.j = j;
00237     tp->nxttri = oldp;
00238     return tp;
00239 }
00240 
00241 /* bisect:
00242  * Return the angle bisecting the angle pp--cp--np
00243  */
00244 static double bisect(pointf pp, pointf cp, pointf np)
00245 {
00246     double theta, phi;
00247     theta = atan2(np.y - cp.y, np.x - cp.x);
00248     phi = atan2(pp.y - cp.y, pp.x - cp.x);
00249     return (theta + phi) / 2.0;
00250 }
00251 
00252 /* raySeg:
00253  * Check if ray v->w intersects segment a--b.
00254  */
00255 static int raySeg(pointf v, pointf w, pointf a, pointf b)
00256 {
00257     int wa = wind(v, w, a);
00258     int wb = wind(v, w, b);
00259     if (wa == wb)
00260         return 0;
00261     if (wa == 0) {
00262         return (wind(v, b, w) * wind(v, b, a) >= 0);
00263     } else {
00264         return (wind(v, a, w) * wind(v, a, b) >= 0);
00265     }
00266 }
00267 
00268 /* raySegIntersect:
00269  * Find the point p where ray v->w intersects segment ai-bi, if any.
00270  * Return 1 on success, 0 on failure
00271  */
00272 static int
00273 raySegIntersect(pointf v, pointf w, pointf a, pointf b, pointf * p)
00274 {
00275     if (raySeg(v, w, a, b))
00276         return line_intersect(v, w, a, b, p);
00277     else
00278         return 0;
00279 }
00280 
00281 #ifdef DEVDBG
00282 #include <psdbg.c>
00283 #endif
00284 
00285 /* triPoint:
00286  * Given the triangle vertex v, and point w so that v->w points
00287  * into the polygon, return where the ray v->w intersects the
00288  * polygon. The search uses all of the opposite sides of triangles
00289  * with v as vertex.
00290  * Return 0 on success; 1 on failure.
00291  */
00292 static int
00293 triPoint(tripoly_t * trip, int vx, pointf v, pointf w, pointf * ip)
00294 {
00295     tri *tp;
00296 
00297     for (tp = trip->triMap[vx]; tp; tp = tp->nxttri) {
00298         if (raySegIntersect
00299             (v, w, trip->poly.ps[tp->v.i], trip->poly.ps[tp->v.j], ip))
00300             return 0;
00301     }
00302 #ifdef DEVDBG
00303     psInit();
00304     psComment ("Failure in triPoint");
00305     psColor("0 0 1");
00306     psSeg (v, w);
00307     for (tp = trip->triMap[vx]; tp; tp = tp->nxttri) {
00308         psTri(v, trip->poly.ps[tp->v.i], trip->poly.ps[tp->v.j]);
00309     }
00310     psOut(stderr);
00311 #endif
00312     return 1;
00313 }
00314 
00315 /* ctrlPtIdx:
00316  * Find the index of v in the points polys->ps.
00317  * We start at 1 since the point corresponding to 0 
00318  * will never be used as v.
00319  */
00320 static int ctrlPtIdx(pointf v, Ppoly_t * polys)
00321 {
00322     pointf w;
00323     int i;
00324     for (i = 1; i < polys->pn; i++) {
00325         w = polys->ps[i];
00326         if ((w.x == v.x) && (w.y == v.y))
00327             return i;
00328     }
00329     return -1;
00330 }
00331 
00332 #define SEP 15
00333 
00334 /* mkCtrlPts:
00335  * Generate mult points associated with v.
00336  * The points will lie on the ray bisecting the angle prev--v--nxt.
00337  * The first point will aways be v.
00338  * The rest are positioned equally spaced with maximum spacing SEP.
00339  * In addition, they all lie within the polygon trip->poly.
00340  * Parameter s gives the index after which a vertex lies on the
00341  * opposite side. This is necessary to get the "curvature" of the
00342  * path correct.
00343  */
00344 static pointf *mkCtrlPts(int s, int mult, pointf prev, pointf v,
00345                            pointf nxt, tripoly_t * trip)
00346 {
00347     pointf *ps;
00348     int idx = ctrlPtIdx(v, &(trip->poly));
00349     int i;
00350     double d, sep, theta, sinTheta, cosTheta;
00351     pointf q, w;
00352 
00353     if (idx < 0)
00354         return NULL;
00355 
00356     ps = N_GNEW(mult, pointf);
00357     theta = bisect(prev, v, nxt);
00358     sinTheta = sin(theta);
00359     cosTheta = cos(theta);
00360     w.x = v.x + 100 * cosTheta;
00361     w.y = v.y + 100 * sinTheta;
00362     if (idx > s) {
00363         if (wind(prev, v, w) != 1) {
00364             sinTheta *= -1;
00365             cosTheta *= -1;
00366             w.x = v.x + 100 * cosTheta;
00367             w.y = v.y + 100 * sinTheta;
00368         }
00369     } else if (wind(prev, v, w) != -1) {
00370         sinTheta *= -1;
00371         cosTheta *= -1;
00372         w.x = v.x + 100 * cosTheta;
00373         w.y = v.y + 100 * sinTheta;
00374     }
00375 
00376     if (triPoint(trip, idx, v, w, &q)) {
00377         return 0;
00378     }
00379 
00380     d = DIST(q, v);
00381     if (d >= mult * SEP)
00382         sep = SEP;
00383     else
00384         sep = d / mult;
00385     if (idx < s) {
00386         for (i = 0; i < mult; i++) {
00387             ps[i].x = v.x + i * sep * cosTheta;
00388             ps[i].y = v.y + i * sep * sinTheta;
00389         }
00390     } else {
00391         for (i = 0; i < mult; i++) {
00392             ps[mult - i - 1].x = v.x + i * sep * cosTheta;
00393             ps[mult - i - 1].y = v.y + i * sep * sinTheta;
00394         }
00395     }
00396     return ps;
00397 }
00398 
00399 /*
00400  * Simple graph structure for recording the triangle graph.
00401  */
00402 
00403 typedef struct {
00404     int ne;         /* no. of edges. */
00405     int *edges;     /* indices of edges adjacent to node. */
00406     pointf ctr;     /* center of triangle. */
00407 } tnode;
00408 
00409 typedef struct {
00410     int t, h;       /* indices of head and tail nodes */
00411     ipair seg;      /* indices of points forming shared segment */
00412     double dist;    /* length of edge; usually distance between centers */
00413 } tedge;
00414 
00415 typedef struct {
00416     tnode *nodes;
00417     tedge *edges;
00418     int nedges;    /* no. of edges; no. of nodes is stored in router_t */
00419 } tgraph;
00420 
00421 struct router_s {
00422     int pn;     /* no. of points */
00423     pointf *ps; /* all points in configuration */
00424     int *obs;   /* indices in obstacle i are obs[i]...obs[i+1]-1 */
00425     int *tris;  /* indices of triangle i are tris[3*i]...tris[3*i+2] */
00426     Dt_t *trimap; /* map from obstacle side (a,b) to index of adj. triangle */
00427     int tn;       /* no. of nodes in tg */
00428     tgraph *tg;   /* graph of triangles */
00429 };
00430 
00431 /* triCenter:
00432  * Given an array of points and 3 integer indices,
00433  * compute and return the center of the triangle.
00434  */
00435 static pointf triCenter(pointf * pts, int *idxs)
00436 {
00437     pointf a = pts[*idxs++];
00438     pointf b = pts[*idxs++];
00439     pointf c = pts[*idxs++];
00440     pointf p;
00441     p.x = (a.x + b.x + c.x) / 3.0;
00442     p.y = (a.y + b.y + c.y) / 3.0;
00443     return p;
00444 }
00445 
00446 #define MARGIN 32
00447 
00448 /* bbox:
00449  * Compute bounding box of polygons, and return it
00450  * with an added margin of MARGIN.
00451  * Store total number of points in *np.
00452  */
00453 static boxf bbox(Ppoly_t** obsp, int npoly, int *np)
00454 {
00455     boxf bb;
00456     int i, j, cnt = 0;
00457     pointf p;
00458     Ppoly_t* obs;
00459 
00460     bb.LL.x = bb.LL.y = MAXDOUBLE;
00461     bb.UR.x = bb.UR.y = -MAXDOUBLE;
00462 
00463     for (i = 0; i < npoly; i++) {
00464         obs = *obsp++;
00465         for (j = 0; j < obs->pn; j++) {
00466             p = obs->ps[j];
00467             if (p.x < bb.LL.x)
00468                 bb.LL.x = p.x;
00469             if (p.x > bb.UR.x)
00470                 bb.UR.x = p.x;
00471             if (p.y < bb.LL.y)
00472                 bb.LL.y = p.y;
00473             if (p.y > bb.UR.y)
00474                 bb.UR.y = p.y;
00475             cnt++;
00476         }
00477     }
00478 
00479     *np = cnt;
00480 
00481     bb.LL.x -= MARGIN;
00482     bb.LL.y -= MARGIN;
00483     bb.UR.x += MARGIN;
00484     bb.UR.y += MARGIN;
00485 
00486     return bb;
00487 }
00488 
00489 static int *mkTriIndices(surface_t * sf)
00490 {
00491     int *tris = N_GNEW(3 * sf->nfaces, int);
00492     memcpy(tris, sf->faces, 3 * sf->nfaces * sizeof(int));
00493     return tris;
00494 }
00495 
00496 /* degT:
00497  * Given a pointer to an array of 3 integers, return
00498  * the number not equal to -1
00499  */
00500 static int degT(int *ip)
00501 {
00502     ip++;
00503     if (*ip++ == -1)
00504         return 1;
00505     if (*ip == -1)
00506         return 2;
00507     else
00508         return 3;
00509 }
00510 
00511 /* sharedEdge:
00512  * Returns a pair of integer (x,y), x < y, where x and y are the
00513  * indices of the two vertices of the shared edge.
00514  */
00515 static ipair sharedEdge(int *p, int *q)
00516 {
00517     ipair pt;
00518     int tmp, p1, p2;
00519     p1 = *p;
00520     p2 = *(p + 1);
00521     if (p1 == *q) {
00522         if ((p2 != *(q + 1)) && (p2 != *(q + 2))) {
00523             p2 = *(p + 2);
00524         }
00525     } else if (p1 == *(q + 1)) {
00526         if ((p2 != *q) && (p2 != *(q + 2))) {
00527             p2 = *(p + 2);
00528         }
00529     } else if (p1 == *(q + 2)) {
00530         if ((p2 != *q) && (p2 != *(q + 1))) {
00531             p2 = *(p + 2);
00532         }
00533     } else {
00534         p1 = *(p + 2);
00535     }
00536 
00537     if (p1 > p2) {
00538         tmp = p1;
00539         p1 = p2;
00540         p2 = tmp;
00541     }
00542     pt.i = p1;
00543     pt.j = p2;
00544     return pt;
00545 }
00546 
00547 /* addTriEdge:
00548  * Add an edge to g, with tail t, head h, distance d, and shared
00549  * segment seg.
00550  */
00551 static void addTriEdge(tgraph * g, int t, int h, double d, ipair seg)
00552 {
00553     tedge *ep = g->edges + g->nedges;
00554     tnode *tp = g->nodes + t;
00555     tnode *hp = g->nodes + h;
00556 
00557     ep->t = t;
00558     ep->h = h;
00559     ep->dist = DIST(tp->ctr, hp->ctr);
00560     ep->seg = seg;
00561 
00562     tp->edges[tp->ne++] = g->nedges;
00563     hp->edges[hp->ne++] = g->nedges;
00564 
00565     g->nedges++;
00566 }
00567 
00568 static void freeTriGraph(tgraph * tg)
00569 {
00570     free(tg->nodes->edges);
00571     free(tg->nodes);
00572     free(tg->edges);
00573     free(tg);
00574 }
00575 
00576 /* mkTriGraph:
00577  * Generate graph with triangles as nodes and an edge iff two triangles
00578  * share an edge.
00579  */
00580 static tgraph *mkTriGraph(surface_t * sf, int maxv, pointf * pts)
00581 {
00582     tgraph *g;
00583     tnode *np;
00584     int j, i, ne = 0;
00585     int *edgei;
00586     int *jp;
00587 
00588     /* ne is twice no. of edges */
00589     for (i = 0; i < 3 * sf->nfaces; i++)
00590         if (sf->neigh[i] != -1)
00591             ne++;
00592 
00593     g = GNEW(tgraph);
00594 
00595     /* plus 2 for nodes added as endpoints of an edge */
00596     g->nodes = N_GNEW(sf->nfaces + 2, tnode);
00597 
00598     /* allow 1 possible extra edge per triangle, plus 
00599      * obstacles can have at most maxv triangles touching 
00600      */
00601     edgei = N_GNEW(sf->nfaces + ne + 2 * maxv, int);
00602     g->edges = N_GNEW(ne/2 + 2 * maxv, tedge);
00603     g->nedges = 0;
00604 
00605     for (i = 0; i < sf->nfaces; i++) {
00606         np = g->nodes + i;
00607         np->ne = 0;
00608         np->edges = edgei;
00609         np->ctr = triCenter(pts, sf->faces + 3 * i);
00610         edgei += degT(sf->neigh + 3 * i) + 1;
00611     }
00612     /* initialize variable nodes */
00613     np = g->nodes + i;
00614     np->ne = 0;
00615     np->edges = edgei;
00616     np++;
00617     np->ne = 0;
00618     np->edges = edgei + maxv;
00619 
00620     for (i = 0; i < sf->nfaces; i++) {
00621         np = g->nodes + i;
00622         jp = sf->neigh + 3 * i;
00623         ne = 0;
00624         while ((ne < 3) && ((j = *jp++) != -1)) {
00625             if (i < j) {
00626                 double dist = DIST(np->ctr, (g->nodes + j)->ctr);
00627                 ipair seg =
00628                     sharedEdge(sf->faces + 3 * i, sf->faces + 3 * j);
00629                 addTriEdge(g, i, j, dist, seg);
00630             }
00631             ne++;
00632         }
00633     }
00634 
00635     return g;
00636 }
00637 
00638 void freeRouter(router_t * rtr)
00639 {
00640     free(rtr->ps);
00641     free(rtr->obs);
00642     free(rtr->tris);
00643     dtclose(rtr->trimap);
00644     freeTriGraph(rtr->tg);
00645     free(rtr);
00646 }
00647 
00648 #ifdef DEVDBG
00649 static void
00650 prTriPoly (tripoly_t *poly, int si, int ei)
00651 {
00652     FILE* fp = fopen ("dumppoly","w");
00653     
00654     psInit();
00655     psPoly (&(poly->poly));
00656     psPoint (poly->poly.ps[si]);
00657     psPoint (poly->poly.ps[ei]);
00658     psOut(fp);
00659     fclose(fp);
00660 }
00661 
00662 static void
00663 prTriGraph (router_t* rtr, int n)
00664 {
00665     FILE* fp = fopen ("dump","w");
00666     int i;
00667     pointf* pts = rtr->ps;
00668     tnode* nodes = rtr->tg->nodes;
00669     char buf[BUFSIZ];
00670     
00671     psInit();
00672     for (i=0;i < rtr->tn; i++) {
00673         pointf a = pts[rtr->tris[3*i]];
00674         pointf b = pts[rtr->tris[3*i+1]];
00675         pointf c = pts[rtr->tris[3*i+2]];
00676         psTri (a, b,c);
00677         sprintf (buf, "%d", i);
00678         psTxt (buf, nodes[i].ctr);
00679     }
00680     for (i=rtr->tn;i < n; i++) {
00681         sprintf (buf, "%d", i);
00682         psTxt (buf, nodes[i].ctr);
00683     }
00684     psColor ("1 0 0");
00685     for (i=0;i < rtr->tg->nedges; i++) {
00686         tedge* e = rtr->tg->edges+i;
00687         psSeg (nodes[e->t].ctr, nodes[e->h].ctr);
00688     }
00689     psOut(fp);
00690     fclose(fp);
00691 }
00692 #endif
00693 
00694 router_t *mkRouter(Ppoly_t** obsp, int npoly)
00695 {
00696     router_t *rtr = NEW(router_t);
00697     Ppoly_t* obs;
00698     boxf bb;
00699     pointf *pts;
00700     int npts;
00701     surface_t *sf;
00702     int *segs;
00703     double *x;
00704     double *y;
00705     int maxv = 4; /* default max. no. of vertices in an obstacle; set below */
00706     /* points in obstacle i have indices obsi[i] through obsi[i+1]-1 in pts
00707      */
00708     int *obsi = N_NEW(npoly + 1, int);
00709     int i, j, ix = 4, six = 0;
00710 
00711     bb = bbox(obsp, npoly, &npts);
00712     npts += 4;                  /* 4 points of bounding box */
00713     pts = N_GNEW(npts, pointf); /* all points are stored in pts */
00714     segs = N_GNEW(2 * npts, int);       /* indices of points forming segments */
00715 
00716     /* store bounding box in CCW order */
00717     pts[0] = bb.LL;
00718     pts[1].x = bb.UR.x;
00719     pts[1].y = bb.LL.y;
00720     pts[2] = bb.UR;
00721     pts[3].x = bb.LL.x;
00722     pts[3].y = bb.UR.y;
00723     for (i = 1; i <= 4; i++) {
00724         segs[six++] = i - 1;
00725         if (i < 4)
00726             segs[six++] = i;
00727         else
00728             segs[six++] = 0;
00729     }
00730 
00731     /* store obstacles in CW order and generate constraint segments */
00732     for (i = 0; i < npoly; i++) {
00733         obsi[i] = ix;
00734         obs = *obsp++;
00735         for (j = 1; j <= obs->pn; j++) {
00736             segs[six++] = ix;
00737             if (j < obs->pn)
00738                 segs[six++] = ix + 1;
00739             else
00740                 segs[six++] = obsi[i];
00741             pts[ix++] = obs->ps[j - 1];
00742         }
00743         if (obs->pn > maxv)
00744             maxv = obs->pn;
00745     }
00746     obsi[i] = ix;
00747 
00748     /* copy points into coordinate arrays */
00749     x = N_GNEW(npts, double);
00750     y = N_GNEW(npts, double);
00751     for (i = 0; i < npts; i++) {
00752         x[i] = pts[i].x;
00753         y[i] = pts[i].y;
00754     }
00755     sf = mkSurface(x, y, npts, segs, npts);
00756     free(x);
00757     free(y);
00758     free(segs);
00759 
00760     rtr->ps = pts;
00761     rtr->pn = npts;
00762     rtr->obs = obsi;
00763     rtr->tris = mkTriIndices(sf);
00764     rtr->trimap = mapSegToTri(sf);
00765     rtr->tn = sf->nfaces;
00766     rtr->tg = mkTriGraph(sf, maxv, pts);
00767 
00768     freeSurface(sf);
00769     return rtr;
00770 }
00771 
00772 /* finishEdge:
00773  * Finish edge generation, clipping to nodes and adding arrowhead
00774  * if necessary, and adding edge labels
00775  */
00776 static void
00777 finishEdge (graph_t* g, edge_t* e, Ppoly_t spl, int flip, pointf p, pointf q)
00778 {
00779     int j;
00780     pointf *spline = N_GNEW(spl.pn, pointf);
00781     pointf p1, q1;
00782 
00783     if (flip) {
00784         for (j = 0; j < spl.pn; j++) {
00785             spline[spl.pn - 1 - j] = spl.ps[j];
00786         }
00787         p1 = q;
00788         q1 = p;
00789     }
00790     else {
00791         for (j = 0; j < spl.pn; j++) {
00792             spline[j] = spl.ps[j];
00793         }
00794         p1 = p;
00795         q1 = q;
00796     }
00797     if (Verbose > 1)
00798         fprintf(stderr, "spline %s %s\n", agnameof(agtail(e)), agnameof(aghead(e)));
00799     clip_and_install(e, aghead(e), spline, spl.pn, &sinfo);
00800     free(spline);
00801 
00802     addEdgeLabels(g, e, p1, q1);
00803 }
00804 
00805 #define EQPT(p,q) (((p).x==(q).x)&&((p).y==(q).y))
00806 
00807 /* tweakEnd:
00808  * Hack because path routing doesn't know about the interiors
00809  * of polygons. If the first or last segment of the shortest path
00810  * lies along one of the polygon boundaries, the path may flip
00811  * inside the polygon. To avoid this, we shift the point a bit.
00812  *
00813  * If the edge p(=poly.ps[s])-q of the shortest path is also an
00814  * edge of the border polygon, move p slightly inside the polygon
00815  * and return it. If prv and nxt are the two vertices adjacent to
00816  * p in the polygon, let m be the midpoint of prv--nxt. We then
00817  * move a tiny bit along the ray p->m.
00818  *
00819  * Otherwise, return p unchanged.
00820  */
00821 static Ppoint_t
00822 tweakEnd (Ppoly_t poly, int s, Ppolyline_t pl, Ppoint_t q)
00823 {
00824     Ppoint_t prv, nxt, p;
00825 
00826     p = poly.ps[s];
00827     nxt = poly.ps[(s + 1) % poly.pn];
00828     if (s == 0)
00829         prv = poly.ps[poly.pn-1];
00830     else
00831         prv = poly.ps[s - 1];
00832     if (EQPT(q, nxt) || EQPT(q, prv) ){
00833         Ppoint_t m;
00834         double d;
00835         m.x = (nxt.x + prv.x)/2.0 - p.x;
00836         m.y = (nxt.y + prv.y)/2.0 - p.y;
00837         d = LEN(m.x,m.y);
00838         p.x += 0.1*m.x/d;
00839         p.y += 0.1*m.y/d;
00840     }
00841     return p;
00842 }
00843 
00844 static void
00845 tweakPath (Ppoly_t poly, int s, int t, Ppolyline_t pl)
00846 {
00847     pl.ps[0] = tweakEnd (poly, s, pl, pl.ps[1]);
00848     pl.ps[pl.pn-1] = tweakEnd (poly, t, pl, pl.ps[pl.pn-2]);
00849 }
00850 
00851 
00852 /* genroute:
00853  * Generate splines for e and cohorts.
00854  * Edges go from s to t.
00855  * Return 0 on success.
00856  */
00857 static int 
00858 genroute(graph_t* g, tripoly_t * trip, int s, int t, edge_t * e, int doPolyline)
00859 {
00860     pointf eps[2];
00861     Pvector_t evs[2];
00862     pointf **cpts = NULL;               /* lists of control points */
00863     Ppoly_t poly;
00864     Ppolyline_t pl, spl;
00865     int i, j;
00866     Ppolyline_t mmpl;
00867     Pedge_t *medges = N_GNEW(trip->poly.pn, Pedge_t);
00868     int pn;
00869     int mult = ED_count(e);
00870     node_t* head = aghead(e);
00871     int rv = 0;
00872 
00873     poly.ps = NULL;
00874     pl.pn = 0;
00875     eps[0].x = trip->poly.ps[s].x, eps[0].y = trip->poly.ps[s].y;
00876     eps[1].x = trip->poly.ps[t].x, eps[1].y = trip->poly.ps[t].y;
00877     if (Pshortestpath(&(trip->poly), eps, &pl) < 0) {
00878         agerr(AGWARN, "Could not create control points for multiple spline for edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
00879         rv = 1;
00880         goto finish;
00881     }
00882 
00883     if (pl.pn == 2) {
00884         makeStraightEdge(agraphof(head), e, doPolyline);
00885         goto finish;
00886     }
00887 
00888     evs[0].x = evs[0].y = 0;
00889     evs[1].x = evs[1].y = 0;
00890 
00891     if ((mult == 1) || Concentrate) {
00892         poly = trip->poly;
00893         for (j = 0; j < poly.pn; j++) {
00894             medges[j].a = poly.ps[j];
00895             medges[j].b = poly.ps[(j + 1) % poly.pn];
00896         }
00897         tweakPath (poly, s, t, pl);
00898         if (Proutespline(medges, poly.pn, pl, evs, &spl) < 0) {
00899             agerr(AGWARN, "Could not create control points for multiple spline for edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
00900             rv = 1;
00901             goto finish;
00902         }
00903         finishEdge (g, e, spl, aghead(e) != head, eps[0], eps[1]);
00904         free(medges);
00905 
00906         return 0;
00907     }
00908     
00909     pn = 2 * (pl.pn - 1);
00910 
00911     cpts = N_NEW(pl.pn - 2, pointf *);
00912     for (i = 0; i < pl.pn - 2; i++) {
00913         cpts[i] =
00914             mkCtrlPts(t, mult+1, pl.ps[i], pl.ps[i + 1], pl.ps[i + 2], trip);
00915         if (!cpts[i]) {
00916             agerr(AGWARN, "Could not create control points for multiple spline for edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
00917             rv = 1;
00918             goto finish;
00919         }
00920     }
00921 
00922     poly.ps = N_GNEW(pn, pointf);
00923     poly.pn = pn;
00924 
00925     for (i = 0; i < mult; i++) {
00926         poly.ps[0] = eps[0];
00927         for (j = 1; j < pl.pn - 1; j++) {
00928             poly.ps[j] = cpts[j - 1][i];
00929         }
00930         poly.ps[pl.pn - 1] = eps[1];
00931         for (j = 1; j < pl.pn - 1; j++) {
00932             poly.ps[pn - j] = cpts[j - 1][i + 1];
00933         }
00934         if (Pshortestpath(&poly, eps, &mmpl) < 0) {
00935             agerr(AGWARN, "Could not create control points for multiple spline for edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
00936             rv = 1;
00937             goto finish;
00938         }
00939 
00940         if (doPolyline) {
00941             make_polyline (mmpl, &spl);
00942         }
00943         else {
00944             for (j = 0; j < poly.pn; j++) {
00945                 medges[j].a = poly.ps[j];
00946                 medges[j].b = poly.ps[(j + 1) % poly.pn];
00947             }
00948             tweakPath (poly, 0, pl.pn-1, mmpl);
00949             if (Proutespline(medges, poly.pn, mmpl, evs, &spl) < 0) {
00950                 agerr(AGWARN, "Could not create control points for multiple spline for edge (%s,%s)\n", 
00951                     agnameof(agtail(e)), agnameof(aghead(e)));
00952                 rv = 1;
00953                 goto finish;
00954             }
00955         }
00956         finishEdge (g, e, spl, aghead(e) != head, eps[0], eps[1]);
00957 
00958         e = ED_to_virt(e);
00959     }
00960 
00961 finish :
00962     if (cpts) {
00963         for (i = 0; i < pl.pn - 2; i++)
00964             free(cpts[i]);
00965         free(cpts);
00966     }
00967     free(medges);
00968     free(poly.ps);
00969     return rv;
00970 }
00971 
00972 #define NSMALL -0.0000000001
00973 
00974 /* inCone:
00975  * Returns true iff q is in the convex cone a-b-c
00976  */
00977 static int
00978 inCone (pointf a, pointf b, pointf c, pointf q)
00979 {
00980     return ((area2(q,a,b) >= NSMALL) && (area2(q,b,c) >= NSMALL));
00981 }
00982 
00983 static pointf north = {0, 1};
00984 static pointf northeast = {1, 1};
00985 static pointf east = {1, 0};
00986 static pointf southeast = {1, -1};
00987 static pointf south = {0, -1};
00988 static pointf southwest = {-1, -1};
00989 static pointf west = {-1, 0};
00990 static pointf northwest = {-1, 1};
00991 
00992 /* addEndpoint:
00993  * Add node to graph representing spline end point p inside obstruction obs_id.
00994  * For each side of obstruction, add edge from p to corresponding triangle.
00995  * The node id of the new node in the graph is v_id.
00996  * If p lies on the side of its node (sides != 0), we limit the triangles
00997  * to those within 45 degrees of each side of the natural direction of p.
00998  */
00999 static void addEndpoint(router_t * rtr, pointf p, node_t* v, int v_id, int sides)
01000 {
01001     int obs_id = ND_lim(v);
01002     int starti = rtr->obs[obs_id];
01003     int endi = rtr->obs[obs_id + 1];
01004     pointf* pts = rtr->ps;
01005     int i, t;
01006     double d;
01007     pointf vr, v0, v1;
01008 
01009     switch (sides) {
01010     case TOP :
01011         vr = add_pointf (p, north);
01012         v0 = add_pointf (p, northwest);
01013         v1 = add_pointf (p, northeast);
01014         break;
01015     case TOP|RIGHT :
01016         vr = add_pointf (p, northeast);
01017         v0 = add_pointf (p, north);
01018         v1 = add_pointf (p, east);
01019         break;
01020     case RIGHT :
01021         vr = add_pointf (p, east);
01022         v0 = add_pointf (p, northeast);
01023         v1 = add_pointf (p, southeast);
01024         break;
01025     case BOTTOM|RIGHT :
01026         vr = add_pointf (p, southeast);
01027         v0 = add_pointf (p, east);
01028         v1 = add_pointf (p, south);
01029         break;
01030     case BOTTOM :
01031         vr = add_pointf (p, south);
01032         v0 = add_pointf (p, southeast);
01033         v1 = add_pointf (p, southwest);
01034         break;
01035     case BOTTOM|LEFT :
01036         vr = add_pointf (p, southwest);
01037         v0 = add_pointf (p, south);
01038         v1 = add_pointf (p, west);
01039         break;
01040     case LEFT :
01041         vr = add_pointf (p, west);
01042         v0 = add_pointf (p, southwest);
01043         v1 = add_pointf (p, northwest);
01044         break;
01045     case TOP|LEFT :
01046         vr = add_pointf (p, northwest);
01047         v0 = add_pointf (p, west);
01048         v1 = add_pointf (p, north);
01049         break;
01050     case 0 :
01051         break;
01052     default :
01053         assert (0);
01054         break;
01055     }
01056 
01057     rtr->tg->nodes[v_id].ne = 0;
01058     rtr->tg->nodes[v_id].ctr = p;
01059     for (i = starti; i < endi; i++) {
01060         ipair seg;
01061         seg.i = i;
01062         if (i < endi - 1)
01063             seg.j = i + 1;
01064         else
01065             seg.j = starti;
01066         t = findMap(rtr->trimap, seg.i, seg.j);
01067         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]))
01068             continue;
01069         d = DIST(p, (rtr->tg->nodes + t)->ctr);
01070         addTriEdge(rtr->tg, v_id, t, d, seg);
01071     }
01072 }
01073 
01074 /* edgeToSeg:
01075  * Given edge from i to j, find segment associated
01076  * with the edge.
01077  *
01078  * This lookup could be made faster by modifying the 
01079  * shortest path algorithm to store the edges rather than
01080  * the nodes.
01081  */
01082 static ipair edgeToSeg(tgraph * tg, int i, int j)
01083 {
01084     ipair ip;
01085     tnode *np = tg->nodes + i;
01086     tedge *ep;
01087 
01088     for (i = 0; i < np->ne; i++) {
01089         ep = tg->edges + np->edges[i];
01090         if ((ep->t == j) || (ep->h == j))
01091             return (ep->seg);
01092     }
01093 
01094     assert(0);
01095     return ip;
01096 }
01097 
01098 static void
01099 freeTripoly (tripoly_t* trip)
01100 {
01101     int i;
01102     tri* tp;
01103     tri* nxt;
01104 
01105     free (trip->poly.ps);
01106     for (i = 0; i < trip->poly.pn; i++) {
01107         for (tp = trip->triMap[i]; tp; tp = nxt) {
01108             nxt = tp->nxttri;
01109             free (tp);
01110         }
01111     }
01112     free (trip->triMap);
01113     free (trip);
01114 }
01115 
01116 /* Auxiliary data structure used to translate a path of rectangles
01117  * into a polygon. Each side_t represents a vertex on one side of
01118  * the polygon. v is the index of the vertex in the global router_t,
01119  * and ts is a linked list of the indices of segments of sides opposite
01120  * to v in some triangle on the path. These lists will be translated
01121  * to polygon indices by mapTri, and stored in tripoly_t.triMap.
01122  */
01123 typedef struct {
01124     int v;
01125     tri *ts;
01126 } side_t;
01127 
01128 /* mkPoly:
01129  * Construct simple polygon from shortest path from t to s in g.
01130  * dad gives the indices of the triangles on path.
01131  * sx used to store index of s in points.
01132  * index of t is always 0
01133  */
01134 static tripoly_t *mkPoly(router_t * rtr, int *dad, int s, int t,
01135                          pointf p_s, pointf p_t, int *sx)
01136 {
01137     tripoly_t *ps;
01138     int nxt;
01139     ipair p;
01140     int nt = 0;
01141     side_t *side1;
01142     side_t *side2;
01143     int i, idx;
01144     int cnt1 = 0;
01145     int cnt2 = 0;
01146     pointf *pts;
01147     pointf *pps;
01148     /* maps vertex index used in router_t to vertex index used in tripoly */
01149     Dt_t *vmap;
01150     tri **trim;
01151 
01152     /* count number of triangles in path */
01153     for (nxt = dad[t]; nxt != s; nxt = dad[nxt])
01154         nt++;
01155 
01156     side1 = N_NEW(nt + 4, side_t);
01157     side2 = N_NEW(nt + 4, side_t);
01158 
01159     nxt = dad[t];
01160     p = edgeToSeg(rtr->tg, nxt, t);
01161     side1[cnt1].ts = addTri(-1, p.j, NULL);
01162     side1[cnt1++].v = p.i;
01163     side2[cnt2].ts = addTri(-1, p.i, NULL);
01164     side2[cnt2++].v = p.j;
01165 
01166     t = nxt;
01167     for (nxt = dad[t]; nxt >= 0; nxt = dad[nxt]) {
01168         p = edgeToSeg(rtr->tg, t, nxt);
01169         if (p.i == side1[cnt1 - 1].v) {
01170             side1[cnt1 - 1].ts =
01171                 addTri(side2[cnt2 - 1].v, p.j, side1[cnt1 - 1].ts);
01172             side2[cnt2 - 1].ts =
01173                 addTri(side1[cnt1 - 1].v, p.j, side2[cnt2 - 1].ts);
01174             side2[cnt2].ts =
01175                 addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL);
01176             side2[cnt2++].v = p.j;
01177         } else if (p.i == side2[cnt2 - 1].v) {
01178             side1[cnt1 - 1].ts =
01179                 addTri(side2[cnt2 - 1].v, p.j, side1[cnt1 - 1].ts);
01180             side2[cnt2 - 1].ts =
01181                 addTri(side1[cnt1 - 1].v, p.j, side2[cnt2 - 1].ts);
01182             side1[cnt1].ts =
01183                 addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL);
01184             side1[cnt1++].v = p.j;
01185         } else if (p.j == side1[cnt1 - 1].v) {
01186             side1[cnt1 - 1].ts =
01187                 addTri(side2[cnt2 - 1].v, p.i, side1[cnt1 - 1].ts);
01188             side2[cnt2 - 1].ts =
01189                 addTri(side1[cnt1 - 1].v, p.i, side2[cnt2 - 1].ts);
01190             side2[cnt2].ts =
01191                 addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL);
01192             side2[cnt2++].v = p.i;
01193         } else {
01194             side1[cnt1 - 1].ts =
01195                 addTri(side2[cnt2 - 1].v, p.i, side1[cnt1 - 1].ts);
01196             side2[cnt2 - 1].ts =
01197                 addTri(side1[cnt1 - 1].v, p.i, side2[cnt2 - 1].ts);
01198             side1[cnt1].ts =
01199                 addTri(side2[cnt2 - 1].v, side1[cnt1 - 1].v, NULL);
01200             side1[cnt1++].v = p.i;
01201         }
01202         t = nxt;
01203     }
01204     side1[cnt1 - 1].ts = addTri(-2, side2[cnt2 - 1].v, side1[cnt1 - 1].ts);
01205     side2[cnt2 - 1].ts = addTri(-2, side1[cnt1 - 1].v, side2[cnt2 - 1].ts);
01206 
01207     /* store points in pts starting with t in 0, 
01208      * then side1, then s, then side2 
01209      */
01210     vmap = dtopen(&ipairdisc, Dtoset);
01211     vmapAdd(vmap, -1, 0);
01212     vmapAdd(vmap, -2, cnt1 + 1);
01213     pps = pts = N_GNEW(nt + 4, pointf);
01214     trim = N_NEW(nt + 4, tri *);
01215     *pps++ = p_t;
01216     idx = 1;
01217     for (i = 0; i < cnt1; i++) {
01218         vmapAdd(vmap, side1[i].v, idx);
01219         *pps++ = rtr->ps[side1[i].v];
01220         trim[idx++] = side1[i].ts;
01221     }
01222     *pps++ = p_s;
01223     idx++;
01224     for (i = cnt2 - 1; i >= 0; i--) {
01225         vmapAdd(vmap, side2[i].v, idx);
01226         *pps++ = rtr->ps[side2[i].v];
01227         trim[idx++] = side2[i].ts;
01228     }
01229 
01230     for (i = 0; i < nt + 4; i++) {
01231         mapTri(vmap, trim[i]);
01232     }
01233 
01234     ps = NEW(tripoly_t);
01235     ps->poly.pn = nt + 4;  /* nt triangles gives nt+2 points plus s and t */
01236     ps->poly.ps = pts;
01237     ps->triMap = trim;
01238 
01239     free (side1);
01240     free (side2);
01241     dtclose(vmap);
01242     *sx = cnt1 + 1;             /* index of s in ps */
01243     return ps;
01244 }
01245 
01246 /* resetGraph:
01247  * Remove edges and nodes added for current edge routing
01248  */
01249 static void resetGraph(tgraph * g, int ncnt, int ecnt)
01250 {
01251     int i;
01252     tnode *np = g->nodes;
01253     g->nedges = ecnt;
01254     for (i = 0; i < ncnt; i++) {
01255         if (np->edges + np->ne == (np + 1)->edges)
01256             np->ne--;
01257         np++;
01258     }
01259 }
01260 
01261 #define PQTYPE int
01262 #define PQVTYPE float
01263 
01264 #define PQ_TYPES
01265 #include <fPQ.h>
01266 #undef PQ_TYPES
01267 
01268 typedef struct {
01269     PQ pq;
01270     PQVTYPE *vals;
01271     int *idxs;
01272 } PPQ;
01273 
01274 #define N_VAL(pq,n) ((PPQ*)pq)->vals[n]
01275 #define N_IDX(pq,n) ((PPQ*)pq)->idxs[n]
01276 
01277 #define PQ_CODE
01278 #include <fPQ.h>
01279 #undef PQ_CODE
01280 
01281 #define N_DAD(n) dad[n]
01282 #define E_WT(e) (e->dist)
01283 #define UNSEEN -MAXFLOAT
01284 
01285 /* triPath:
01286  * Find the shortest path with lengths in g from
01287  * v0 to v1. The returned vector (dad) encodes the
01288  * shorted path from v1 to v0. That path is given by
01289  * v1, dad[v1], dad[dad[v1]], ..., v0.
01290  */
01291 static int *
01292 triPath(tgraph * g, int n, int v0, int v1, PQ * pq)
01293 {
01294     int i, j, adjn;
01295     double d;
01296     tnode *np;
01297     tedge *e;
01298     int *dad = N_NEW(n, int);
01299 
01300     for (i = 0; i < pq->PQsize; i++)
01301         N_VAL(pq, i) = UNSEEN;
01302 
01303     PQinit(pq);
01304     N_DAD(v0) = -1;
01305     N_VAL(pq, v0) = 0;
01306     if (PQinsert(pq, v0))
01307         return NULL;
01308 
01309     while ((i = PQremove(pq)) != -1) {
01310         N_VAL(pq, i) *= -1;
01311         if (i == v1)
01312             break;
01313         np = g->nodes + i;
01314         for (j = 0; j < np->ne; j++) {
01315             e = g->edges + np->edges[j];
01316             if (e->t == i)
01317                 adjn = e->h;
01318             else
01319                 adjn = e->t;
01320             if (N_VAL(pq, adjn) < 0) {
01321                 d = -(N_VAL(pq, i) + E_WT(e));
01322                 if (N_VAL(pq, adjn) == UNSEEN) {
01323                     N_VAL(pq, adjn) = d;
01324                     N_DAD(adjn) = i;
01325                     if (PQinsert(pq, adjn)) return NULL;
01326                 } else if (N_VAL(pq, adjn) < d) {
01327                     PQupdate(pq, adjn, d);
01328                     N_DAD(adjn) = i;
01329                 }
01330             }
01331         }
01332     }
01333     return dad;
01334 }
01335 
01336 /* makeMultiSpline:
01337  * FIX: we don't really use the shortest path provided by ED_path,
01338  * so avoid in neato spline code.
01339  * Return 0 on success.
01340  */
01341 int makeMultiSpline(graph_t* g,  edge_t* e, router_t * rtr, int doPolyline)
01342 {
01343     Ppolyline_t line = ED_path(e);
01344     node_t *t = agtail(e);
01345     node_t *h = aghead(e);
01346     pointf t_p = line.ps[0];
01347     pointf h_p = line.ps[line.pn - 1];
01348     tripoly_t *poly;
01349     int idx;
01350     int *sp;
01351     int t_id = rtr->tn;
01352     int h_id = rtr->tn + 1;
01353     int ecnt = rtr->tg->nedges;
01354     PPQ pq;
01355     PQTYPE *idxs;
01356     PQVTYPE *vals;
01357     int ret;
01358 
01359         /* Add endpoints to triangle graph */
01360     addEndpoint(rtr, t_p, t, t_id, ED_tail_port(e).side);
01361     addEndpoint(rtr, h_p, h, h_id, ED_head_port(e).side);
01362 
01363         /* Initialize priority queue */
01364     PQgen(&pq.pq, rtr->tn + 2, -1);
01365     idxs = N_GNEW(pq.pq.PQsize + 1, PQTYPE);
01366     vals = N_GNEW(pq.pq.PQsize + 1, PQVTYPE);
01367     vals[0] = 0;
01368     pq.vals = vals + 1;
01369     pq.idxs = idxs + 1;
01370 
01371         /* Find shortest path of triangles */
01372     sp = triPath(rtr->tg, rtr->tn+2, h_id, t_id, (PQ *) & pq);
01373 
01374     free(vals);
01375     free(idxs);
01376     PQfree(&(pq.pq), 0);
01377 
01378         /* Use path of triangles to generate guiding polygon */
01379     if (sp) {
01380         poly = mkPoly(rtr, sp, h_id, t_id, h_p, t_p, &idx);
01381         free(sp);
01382 
01383         /* Generate multiple splines using polygon */
01384         ret = genroute(g, poly, 0, idx, e, doPolyline);
01385         freeTripoly (poly);
01386     }
01387     else ret = -1;
01388 
01389     resetGraph(rtr->tg, rtr->tn, ecnt);
01390     return ret;
01391 }