|
Graphviz
2.29.20120524.0446
|
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 }
1.7.5