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