| 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 | |
| 15 | #include "vis.h" |
| 16 | |
| 17 | #ifdef DMALLOC |
| 18 | #include "dmalloc.h" |
| 19 | #endif |
| 20 | |
| 21 | /* TRANSPARENT means router sees past colinear obstacles */ |
| 22 | #ifdef TRANSPARENT |
| 23 | #define INTERSECT(a,b,c,d,e) intersect1((a),(b),(c),(d),(e)) |
| 24 | #else |
| 25 | #define INTERSECT(a,b,c,d,e) intersect((a),(b),(c),(d)) |
| 26 | #endif |
| 27 | |
| 28 | /* allocArray: |
| 29 | * Allocate a VxV array of COORD values. |
| 30 | * (array2 is a pointer to an array of pointers; the array is |
| 31 | * accessed in row-major order.) |
| 32 | * The values in the array are initialized to 0. |
| 33 | * Add extra rows. |
| 34 | */ |
| 35 | static array2 allocArray(int V, int ) |
| 36 | { |
| 37 | int i; |
| 38 | array2 arr; |
| 39 | COORD *p; |
| 40 | |
| 41 | arr = (COORD **) malloc((V + extra) * sizeof(COORD *)); |
| 42 | p = (COORD *) calloc(V * V, sizeof(COORD)); |
| 43 | for (i = 0; i < V; i++) { |
| 44 | arr[i] = p; |
| 45 | p += V; |
| 46 | } |
| 47 | for (i = V; i < V + extra; i++) |
| 48 | arr[i] = (COORD *) 0; |
| 49 | |
| 50 | return arr; |
| 51 | } |
| 52 | |
| 53 | /* area2: |
| 54 | * Returns twice the area of triangle abc. |
| 55 | */ |
| 56 | COORD area2(Ppoint_t a, Ppoint_t b, Ppoint_t c) |
| 57 | { |
| 58 | return ((a.y - b.y) * (c.x - b.x) - (c.y - b.y) * (a.x - b.x)); |
| 59 | } |
| 60 | |
| 61 | /* wind: |
| 62 | * Returns 1, 0, -1 if the points abc are counterclockwise, |
| 63 | * collinear, or clockwise. |
| 64 | */ |
| 65 | int wind(Ppoint_t a, Ppoint_t b, Ppoint_t c) |
| 66 | { |
| 67 | COORD w; |
| 68 | |
| 69 | w = ((a.y - b.y) * (c.x - b.x) - (c.y - b.y) * (a.x - b.x)); |
| 70 | /* need to allow for small math errors. seen with "gcc -O2 -mcpu=i686 -ffast-math" */ |
| 71 | return (w > .0001) ? 1 : ((w < -.0001) ? -1 : 0); |
| 72 | } |
| 73 | |
| 74 | #if 0 /* NOT USED */ |
| 75 | /* open_intersect: |
| 76 | * Returns true iff segment ab intersects segment cd. |
| 77 | * NB: segments are considered open sets |
| 78 | */ |
| 79 | static int open_intersect(Ppoint_t a, Ppoint_t b, Ppoint_t c, Ppoint_t d) |
| 80 | { |
| 81 | return (((area2(a, b, c) > 0 && area2(a, b, d) < 0) || |
| 82 | (area2(a, b, c) < 0 && area2(a, b, d) > 0)) |
| 83 | && |
| 84 | ((area2(c, d, a) > 0 && area2(c, d, b) < 0) || |
| 85 | (area2(c, d, a) < 0 && area2(c, d, b) > 0))); |
| 86 | } |
| 87 | #endif |
| 88 | |
| 89 | /* inBetween: |
| 90 | * Return true if c is in (a,b), assuming a,b,c are collinear. |
| 91 | */ |
| 92 | int inBetween(Ppoint_t a, Ppoint_t b, Ppoint_t c) |
| 93 | { |
| 94 | if (a.x != b.x) /* not vertical */ |
| 95 | return (((a.x < c.x) && (c.x < b.x)) |
| 96 | || ((b.x < c.x) && (c.x < a.x))); |
| 97 | else |
| 98 | return (((a.y < c.y) && (c.y < b.y)) |
| 99 | || ((b.y < c.y) && (c.y < a.y))); |
| 100 | } |
| 101 | |
| 102 | /* TRANSPARENT means router sees past colinear obstacles */ |
| 103 | #ifdef TRANSPARENT |
| 104 | /* intersect1: |
| 105 | * Returns true if the polygon segment [q,n) blocks a and b from seeing |
| 106 | * each other. |
| 107 | * More specifically, returns true iff the two segments intersect as open |
| 108 | * sets, or if q lies on (a,b) and either n and p lie on |
| 109 | * different sides of (a,b), i.e., wind(a,b,n)*wind(a,b,p) < 0, or the polygon |
| 110 | * makes a left turn at q, i.e., wind(p,q,n) > 0. |
| 111 | * |
| 112 | * We are assuming the p,q,n are three consecutive vertices of a barrier |
| 113 | * polygon with the polygon interior to the right of p-q-n. |
| 114 | * |
| 115 | * Note that given the constraints of our problem, we could probably |
| 116 | * simplify this code even more. For example, if abq are collinear, but |
| 117 | * q is not in (a,b), we could return false since n will not be in (a,b) |
| 118 | * nor will the (a,b) intersect (q,n). |
| 119 | * |
| 120 | * Also note that we are computing w_abq twice in a tour of a polygon, |
| 121 | * once for each edge of which it is a vertex. |
| 122 | */ |
| 123 | static int intersect1(Ppoint_t a, Ppoint_t b, Ppoint_t q, Ppoint_t n, |
| 124 | Ppoint_t p) |
| 125 | { |
| 126 | int w_abq; |
| 127 | int w_abn; |
| 128 | int w_qna; |
| 129 | int w_qnb; |
| 130 | |
| 131 | w_abq = wind(a, b, q); |
| 132 | w_abn = wind(a, b, n); |
| 133 | |
| 134 | /* If q lies on (a,b),... */ |
| 135 | if ((w_abq == 0) && inBetween(a, b, q)) { |
| 136 | return ((w_abn * wind(a, b, p) < 0) || (wind(p, q, n) > 0)); |
| 137 | } else { |
| 138 | w_qna = wind(q, n, a); |
| 139 | w_qnb = wind(q, n, b); |
| 140 | /* True if q and n are on opposite sides of ab, |
| 141 | * and a and b are on opposite sides of qn. |
| 142 | */ |
| 143 | return (((w_abq * w_abn) < 0) && ((w_qna * w_qnb) < 0)); |
| 144 | } |
| 145 | } |
| 146 | #else |
| 147 | |
| 148 | /* intersect: |
| 149 | * Returns true if the segment [c,d] blocks a and b from seeing each other. |
| 150 | * More specifically, returns true iff c or d lies on (a,b) or the two |
| 151 | * segments intersect as open sets. |
| 152 | */ |
| 153 | int intersect(Ppoint_t a, Ppoint_t b, Ppoint_t c, Ppoint_t d) |
| 154 | { |
| 155 | int a_abc; |
| 156 | int a_abd; |
| 157 | int a_cda; |
| 158 | int a_cdb; |
| 159 | |
| 160 | a_abc = wind(a, b, c); |
| 161 | if ((a_abc == 0) && inBetween(a, b, c)) { |
| 162 | return 1; |
| 163 | } |
| 164 | a_abd = wind(a, b, d); |
| 165 | if ((a_abd == 0) && inBetween(a, b, d)) { |
| 166 | return 1; |
| 167 | } |
| 168 | a_cda = wind(c, d, a); |
| 169 | a_cdb = wind(c, d, b); |
| 170 | |
| 171 | /* True if c and d are on opposite sides of ab, |
| 172 | * and a and b are on opposite sides of cd. |
| 173 | */ |
| 174 | return (((a_abc * a_abd) < 0) && ((a_cda * a_cdb) < 0)); |
| 175 | } |
| 176 | #endif |
| 177 | |
| 178 | /* in_cone: |
| 179 | * Returns true iff point b is in the cone a0,a1,a2 |
| 180 | * NB: the cone is considered a closed set |
| 181 | */ |
| 182 | static int in_cone(Ppoint_t a0, Ppoint_t a1, Ppoint_t a2, Ppoint_t b) |
| 183 | { |
| 184 | int m = wind(b, a0, a1); |
| 185 | int p = wind(b, a1, a2); |
| 186 | |
| 187 | if (wind(a0, a1, a2) > 0) |
| 188 | return (m >= 0 && p >= 0); /* convex at a */ |
| 189 | else |
| 190 | return (m >= 0 || p >= 0); /* reflex at a */ |
| 191 | } |
| 192 | |
| 193 | #if 0 /* NOT USED */ |
| 194 | /* in_open_cone: |
| 195 | * Returns true iff point b is in the cone a0,a1,a2 |
| 196 | * NB: the cone is considered an open set |
| 197 | */ |
| 198 | static int in_open_cone(Ppoint_t a0, Ppoint_t a1, Ppoint_t a2, Ppoint_t b) |
| 199 | { |
| 200 | int m = wind(b, a0, a1); |
| 201 | int p = wind(b, a1, a2); |
| 202 | |
| 203 | if (wind(a0, a1, a2) >= 0) |
| 204 | return (m > 0 && p > 0); /* convex at a */ |
| 205 | else |
| 206 | return (m > 0 || p > 0); /* reflex at a */ |
| 207 | } |
| 208 | #endif |
| 209 | |
| 210 | /* dist2: |
| 211 | * Returns the square of the distance between points a and b. |
| 212 | */ |
| 213 | COORD dist2(Ppoint_t a, Ppoint_t b) |
| 214 | { |
| 215 | COORD delx = a.x - b.x; |
| 216 | COORD dely = a.y - b.y; |
| 217 | |
| 218 | return (delx * delx + dely * dely); |
| 219 | } |
| 220 | |
| 221 | /* dist: |
| 222 | * Returns the distance between points a and b. |
| 223 | */ |
| 224 | static COORD dist(Ppoint_t a, Ppoint_t b) |
| 225 | { |
| 226 | return sqrt(dist2(a, b)); |
| 227 | } |
| 228 | |
| 229 | static int inCone(int i, int j, Ppoint_t pts[], int nextPt[], int prevPt[]) |
| 230 | { |
| 231 | return in_cone(pts[prevPt[i]], pts[i], pts[nextPt[i]], pts[j]); |
| 232 | } |
| 233 | |
| 234 | /* clear: |
| 235 | * Return true if no polygon line segment non-trivially intersects |
| 236 | * the segment [pti,ptj], ignoring segments in [start,end). |
| 237 | */ |
| 238 | static int clear(Ppoint_t pti, Ppoint_t ptj, |
| 239 | int start, int end, |
| 240 | int V, Ppoint_t pts[], int nextPt[], int prevPt[]) |
| 241 | { |
| 242 | int k; |
| 243 | |
| 244 | for (k = 0; k < start; k++) { |
| 245 | if (INTERSECT(pti, ptj, pts[k], pts[nextPt[k]], pts[prevPt[k]])) |
| 246 | return 0; |
| 247 | } |
| 248 | for (k = end; k < V; k++) { |
| 249 | if (INTERSECT(pti, ptj, pts[k], pts[nextPt[k]], pts[prevPt[k]])) |
| 250 | return 0; |
| 251 | } |
| 252 | return 1; |
| 253 | } |
| 254 | |
| 255 | /* compVis: |
| 256 | * Compute visibility graph of vertices of polygons. |
| 257 | * Only do polygons from index startp to end. |
| 258 | * If two nodes cannot see each other, the matrix entry is 0. |
| 259 | * If two nodes can see each other, the matrix entry is the distance |
| 260 | * between them. |
| 261 | */ |
| 262 | static void compVis(vconfig_t * conf, int start) |
| 263 | { |
| 264 | int V = conf->N; |
| 265 | Ppoint_t *pts = conf->P; |
| 266 | int *nextPt = conf->next; |
| 267 | int *prevPt = conf->prev; |
| 268 | array2 wadj = conf->vis; |
| 269 | int j, i, previ; |
| 270 | COORD d; |
| 271 | |
| 272 | for (i = start; i < V; i++) { |
| 273 | /* add edge between i and previ. |
| 274 | * Note that this works for the cases of polygons of 1 and 2 |
| 275 | * vertices, though needless work is done. |
| 276 | */ |
| 277 | previ = prevPt[i]; |
| 278 | d = dist(pts[i], pts[previ]); |
| 279 | wadj[i][previ] = d; |
| 280 | wadj[previ][i] = d; |
| 281 | |
| 282 | /* Check remaining, earlier vertices */ |
| 283 | if (previ == i - 1) |
| 284 | j = i - 2; |
| 285 | else |
| 286 | j = i - 1; |
| 287 | for (; j >= 0; j--) { |
| 288 | if (inCone(i, j, pts, nextPt, prevPt) && |
| 289 | inCone(j, i, pts, nextPt, prevPt) && |
| 290 | clear(pts[i], pts[j], V, V, V, pts, nextPt, prevPt)) { |
| 291 | /* if i and j see each other, add edge */ |
| 292 | d = dist(pts[i], pts[j]); |
| 293 | wadj[i][j] = d; |
| 294 | wadj[j][i] = d; |
| 295 | } |
| 296 | } |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | /* visibility: |
| 301 | * Given a vconfig_t conf, representing polygonal barriers, |
| 302 | * compute the visibility graph of the vertices of conf. |
| 303 | * The graph is stored in conf->vis. |
| 304 | */ |
| 305 | void visibility(vconfig_t * conf) |
| 306 | { |
| 307 | conf->vis = allocArray(conf->N, 2); |
| 308 | compVis(conf, 0); |
| 309 | } |
| 310 | |
| 311 | /* polyhit: |
| 312 | * Given a vconfig_t conf, as above, and a point, |
| 313 | * return the index of the polygon that contains |
| 314 | * the point, or else POLYID_NONE. |
| 315 | */ |
| 316 | static int polyhit(vconfig_t * conf, Ppoint_t p) |
| 317 | { |
| 318 | int i; |
| 319 | Ppoly_t poly; |
| 320 | |
| 321 | for (i = 0; i < conf->Npoly; i++) { |
| 322 | poly.ps = &(conf->P[conf->start[i]]); |
| 323 | poly.pn = conf->start[i + 1] - conf->start[i]; |
| 324 | if (in_poly(poly, p)) |
| 325 | return i; |
| 326 | } |
| 327 | return POLYID_NONE; |
| 328 | } |
| 329 | |
| 330 | /* ptVis: |
| 331 | * Given a vconfig_t conf, representing polygonal barriers, |
| 332 | * and a point within one of the polygons, compute the point's |
| 333 | * visibility vector relative to the vertices of the remaining |
| 334 | * polygons, i.e., pretend the argument polygon is invisible. |
| 335 | * |
| 336 | * If pp is NIL, ptVis computes the visibility vector for p |
| 337 | * relative to all barrier vertices. |
| 338 | */ |
| 339 | COORD *ptVis(vconfig_t * conf, int pp, Ppoint_t p) |
| 340 | { |
| 341 | int V = conf->N; |
| 342 | Ppoint_t *pts = conf->P; |
| 343 | int *nextPt = conf->next; |
| 344 | int *prevPt = conf->prev; |
| 345 | int k; |
| 346 | int start, end; |
| 347 | COORD *vadj; |
| 348 | Ppoint_t pk; |
| 349 | COORD d; |
| 350 | |
| 351 | vadj = (COORD *) malloc((V + 2) * sizeof(COORD)); |
| 352 | |
| 353 | |
| 354 | if (pp == POLYID_UNKNOWN) |
| 355 | pp = polyhit(conf, p); |
| 356 | if (pp >= 0) { |
| 357 | start = conf->start[pp]; |
| 358 | end = conf->start[pp + 1]; |
| 359 | } else { |
| 360 | start = V; |
| 361 | end = V; |
| 362 | } |
| 363 | |
| 364 | for (k = 0; k < start; k++) { |
| 365 | pk = pts[k]; |
| 366 | if (in_cone(pts[prevPt[k]], pk, pts[nextPt[k]], p) && |
| 367 | clear(p, pk, start, end, V, pts, nextPt, prevPt)) { |
| 368 | /* if p and pk see each other, add edge */ |
| 369 | d = dist(p, pk); |
| 370 | vadj[k] = d; |
| 371 | } else |
| 372 | vadj[k] = 0; |
| 373 | } |
| 374 | |
| 375 | for (k = start; k < end; k++) |
| 376 | vadj[k] = 0; |
| 377 | |
| 378 | for (k = end; k < V; k++) { |
| 379 | pk = pts[k]; |
| 380 | if (in_cone(pts[prevPt[k]], pk, pts[nextPt[k]], p) && |
| 381 | clear(p, pk, start, end, V, pts, nextPt, prevPt)) { |
| 382 | /* if p and pk see each other, add edge */ |
| 383 | d = dist(p, pk); |
| 384 | vadj[k] = d; |
| 385 | } else |
| 386 | vadj[k] = 0; |
| 387 | } |
| 388 | vadj[V] = 0; |
| 389 | vadj[V + 1] = 0; |
| 390 | |
| 391 | return vadj; |
| 392 | |
| 393 | } |
| 394 | |
| 395 | /* directVis: |
| 396 | * Given two points, return true if the points can directly see each other. |
| 397 | * If a point is associated with a polygon, the edges of the polygon |
| 398 | * are ignored when checking visibility. |
| 399 | */ |
| 400 | int directVis(Ppoint_t p, int pp, Ppoint_t q, int qp, vconfig_t * conf) |
| 401 | { |
| 402 | int V = conf->N; |
| 403 | Ppoint_t *pts = conf->P; |
| 404 | int *nextPt = conf->next; |
| 405 | /* int* prevPt = conf->prev; */ |
| 406 | int k; |
| 407 | int s1, e1; |
| 408 | int s2, e2; |
| 409 | |
| 410 | if (pp < 0) { |
| 411 | s1 = 0; |
| 412 | e1 = 0; |
| 413 | if (qp < 0) { |
| 414 | s2 = 0; |
| 415 | e2 = 0; |
| 416 | } else { |
| 417 | s2 = conf->start[qp]; |
| 418 | e2 = conf->start[qp + 1]; |
| 419 | } |
| 420 | } else if (qp < 0) { |
| 421 | s1 = 0; |
| 422 | e1 = 0; |
| 423 | s2 = conf->start[pp]; |
| 424 | e2 = conf->start[pp + 1]; |
| 425 | } else if (pp <= qp) { |
| 426 | s1 = conf->start[pp]; |
| 427 | e1 = conf->start[pp + 1]; |
| 428 | s2 = conf->start[qp]; |
| 429 | e2 = conf->start[qp + 1]; |
| 430 | } else { |
| 431 | s1 = conf->start[qp]; |
| 432 | e1 = conf->start[qp + 1]; |
| 433 | s2 = conf->start[pp]; |
| 434 | e2 = conf->start[pp + 1]; |
| 435 | } |
| 436 | |
| 437 | for (k = 0; k < s1; k++) { |
| 438 | if (INTERSECT(p, q, pts[k], pts[nextPt[k]], pts[prevPt[k]])) |
| 439 | return 0; |
| 440 | } |
| 441 | for (k = e1; k < s2; k++) { |
| 442 | if (INTERSECT(p, q, pts[k], pts[nextPt[k]], pts[prevPt[k]])) |
| 443 | return 0; |
| 444 | } |
| 445 | for (k = e2; k < V; k++) { |
| 446 | if (INTERSECT(p, q, pts[k], pts[nextPt[k]], pts[prevPt[k]])) |
| 447 | return 0; |
| 448 | } |
| 449 | return 1; |
| 450 | } |
| 451 | |