|
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 00015 #include "vis.h" 00016 00017 #ifdef DMALLOC 00018 #include "dmalloc.h" 00019 #endif 00020 00021 /* TRANSPARENT means router sees past colinear obstacles */ 00022 #ifdef TRANSPARENT 00023 #define INTERSECT(a,b,c,d,e) intersect1((a),(b),(c),(d),(e)) 00024 #else 00025 #define INTERSECT(a,b,c,d,e) intersect((a),(b),(c),(d)) 00026 #endif 00027 00028 /* allocArray: 00029 * Allocate a VxV array of COORD values. 00030 * (array2 is a pointer to an array of pointers; the array is 00031 * accessed in row-major order.) 00032 * The values in the array are initialized to 0. 00033 * Add extra rows. 00034 */ 00035 static array2 allocArray(int V, int extra) 00036 { 00037 int i; 00038 array2 arr; 00039 COORD *p; 00040 00041 arr = (COORD **) malloc((V + extra) * sizeof(COORD *)); 00042 p = (COORD *) calloc(V * V, sizeof(COORD)); 00043 for (i = 0; i < V; i++) { 00044 arr[i] = p; 00045 p += V; 00046 } 00047 for (i = V; i < V + extra; i++) 00048 arr[i] = (COORD *) 0; 00049 00050 return arr; 00051 } 00052 00053 /* area2: 00054 * Returns twice the area of triangle abc. 00055 */ 00056 COORD area2(Ppoint_t a, Ppoint_t b, Ppoint_t c) 00057 { 00058 return ((a.y - b.y) * (c.x - b.x) - (c.y - b.y) * (a.x - b.x)); 00059 } 00060 00061 /* wind: 00062 * Returns 1, 0, -1 if the points abc are counterclockwise, 00063 * collinear, or clockwise. 00064 */ 00065 int wind(Ppoint_t a, Ppoint_t b, Ppoint_t c) 00066 { 00067 COORD w; 00068 00069 w = ((a.y - b.y) * (c.x - b.x) - (c.y - b.y) * (a.x - b.x)); 00070 /* need to allow for small math errors. seen with "gcc -O2 -mcpu=i686 -ffast-math" */ 00071 return (w > .0001) ? 1 : ((w < -.0001) ? -1 : 0); 00072 } 00073 00074 #if 0 /* NOT USED */ 00075 /* open_intersect: 00076 * Returns true iff segment ab intersects segment cd. 00077 * NB: segments are considered open sets 00078 */ 00079 static int open_intersect(Ppoint_t a, Ppoint_t b, Ppoint_t c, Ppoint_t d) 00080 { 00081 return (((area2(a, b, c) > 0 && area2(a, b, d) < 0) || 00082 (area2(a, b, c) < 0 && area2(a, b, d) > 0)) 00083 && 00084 ((area2(c, d, a) > 0 && area2(c, d, b) < 0) || 00085 (area2(c, d, a) < 0 && area2(c, d, b) > 0))); 00086 } 00087 #endif 00088 00089 /* inBetween: 00090 * Return true if c is in (a,b), assuming a,b,c are collinear. 00091 */ 00092 int inBetween(Ppoint_t a, Ppoint_t b, Ppoint_t c) 00093 { 00094 if (a.x != b.x) /* not vertical */ 00095 return (((a.x < c.x) && (c.x < b.x)) 00096 || ((b.x < c.x) && (c.x < a.x))); 00097 else 00098 return (((a.y < c.y) && (c.y < b.y)) 00099 || ((b.y < c.y) && (c.y < a.y))); 00100 } 00101 00102 /* TRANSPARENT means router sees past colinear obstacles */ 00103 #ifdef TRANSPARENT 00104 /* intersect1: 00105 * Returns true if the polygon segment [q,n) blocks a and b from seeing 00106 * each other. 00107 * More specifically, returns true iff the two segments intersect as open 00108 * sets, or if q lies on (a,b) and either n and p lie on 00109 * different sides of (a,b), i.e., wind(a,b,n)*wind(a,b,p) < 0, or the polygon 00110 * makes a left turn at q, i.e., wind(p,q,n) > 0. 00111 * 00112 * We are assuming the p,q,n are three consecutive vertices of a barrier 00113 * polygon with the polygon interior to the right of p-q-n. 00114 * 00115 * Note that given the constraints of our problem, we could probably 00116 * simplify this code even more. For example, if abq are collinear, but 00117 * q is not in (a,b), we could return false since n will not be in (a,b) 00118 * nor will the (a,b) intersect (q,n). 00119 * 00120 * Also note that we are computing w_abq twice in a tour of a polygon, 00121 * once for each edge of which it is a vertex. 00122 */ 00123 static int intersect1(Ppoint_t a, Ppoint_t b, Ppoint_t q, Ppoint_t n, 00124 Ppoint_t p) 00125 { 00126 int w_abq; 00127 int w_abn; 00128 int w_qna; 00129 int w_qnb; 00130 00131 w_abq = wind(a, b, q); 00132 w_abn = wind(a, b, n); 00133 00134 /* If q lies on (a,b),... */ 00135 if ((w_abq == 0) && inBetween(a, b, q)) { 00136 return ((w_abn * wind(a, b, p) < 0) || (wind(p, q, n) > 0)); 00137 } else { 00138 w_qna = wind(q, n, a); 00139 w_qnb = wind(q, n, b); 00140 /* True if q and n are on opposite sides of ab, 00141 * and a and b are on opposite sides of qn. 00142 */ 00143 return (((w_abq * w_abn) < 0) && ((w_qna * w_qnb) < 0)); 00144 } 00145 } 00146 #else 00147 00148 /* intersect: 00149 * Returns true if the segment [c,d] blocks a and b from seeing each other. 00150 * More specifically, returns true iff c or d lies on (a,b) or the two 00151 * segments intersect as open sets. 00152 */ 00153 int intersect(Ppoint_t a, Ppoint_t b, Ppoint_t c, Ppoint_t d) 00154 { 00155 int a_abc; 00156 int a_abd; 00157 int a_cda; 00158 int a_cdb; 00159 00160 a_abc = wind(a, b, c); 00161 if ((a_abc == 0) && inBetween(a, b, c)) { 00162 return 1; 00163 } 00164 a_abd = wind(a, b, d); 00165 if ((a_abd == 0) && inBetween(a, b, d)) { 00166 return 1; 00167 } 00168 a_cda = wind(c, d, a); 00169 a_cdb = wind(c, d, b); 00170 00171 /* True if c and d are on opposite sides of ab, 00172 * and a and b are on opposite sides of cd. 00173 */ 00174 return (((a_abc * a_abd) < 0) && ((a_cda * a_cdb) < 0)); 00175 } 00176 #endif 00177 00178 /* in_cone: 00179 * Returns true iff point b is in the cone a0,a1,a2 00180 * NB: the cone is considered a closed set 00181 */ 00182 static int in_cone(Ppoint_t a0, Ppoint_t a1, Ppoint_t a2, Ppoint_t b) 00183 { 00184 int m = wind(b, a0, a1); 00185 int p = wind(b, a1, a2); 00186 00187 if (wind(a0, a1, a2) > 0) 00188 return (m >= 0 && p >= 0); /* convex at a */ 00189 else 00190 return (m >= 0 || p >= 0); /* reflex at a */ 00191 } 00192 00193 #if 0 /* NOT USED */ 00194 /* in_open_cone: 00195 * Returns true iff point b is in the cone a0,a1,a2 00196 * NB: the cone is considered an open set 00197 */ 00198 static int in_open_cone(Ppoint_t a0, Ppoint_t a1, Ppoint_t a2, Ppoint_t b) 00199 { 00200 int m = wind(b, a0, a1); 00201 int p = wind(b, a1, a2); 00202 00203 if (wind(a0, a1, a2) >= 0) 00204 return (m > 0 && p > 0); /* convex at a */ 00205 else 00206 return (m > 0 || p > 0); /* reflex at a */ 00207 } 00208 #endif 00209 00210 /* dist2: 00211 * Returns the square of the distance between points a and b. 00212 */ 00213 COORD dist2(Ppoint_t a, Ppoint_t b) 00214 { 00215 COORD delx = a.x - b.x; 00216 COORD dely = a.y - b.y; 00217 00218 return (delx * delx + dely * dely); 00219 } 00220 00221 /* dist: 00222 * Returns the distance between points a and b. 00223 */ 00224 static COORD dist(Ppoint_t a, Ppoint_t b) 00225 { 00226 return sqrt(dist2(a, b)); 00227 } 00228 00229 static int inCone(int i, int j, Ppoint_t pts[], int nextPt[], int prevPt[]) 00230 { 00231 return in_cone(pts[prevPt[i]], pts[i], pts[nextPt[i]], pts[j]); 00232 } 00233 00234 /* clear: 00235 * Return true if no polygon line segment non-trivially intersects 00236 * the segment [pti,ptj], ignoring segments in [start,end). 00237 */ 00238 static int clear(Ppoint_t pti, Ppoint_t ptj, 00239 int start, int end, 00240 int V, Ppoint_t pts[], int nextPt[], int prevPt[]) 00241 { 00242 int k; 00243 00244 for (k = 0; k < start; k++) { 00245 if (INTERSECT(pti, ptj, pts[k], pts[nextPt[k]], pts[prevPt[k]])) 00246 return 0; 00247 } 00248 for (k = end; k < V; k++) { 00249 if (INTERSECT(pti, ptj, pts[k], pts[nextPt[k]], pts[prevPt[k]])) 00250 return 0; 00251 } 00252 return 1; 00253 } 00254 00255 /* compVis: 00256 * Compute visibility graph of vertices of polygons. 00257 * Only do polygons from index startp to end. 00258 * If two nodes cannot see each other, the matrix entry is 0. 00259 * If two nodes can see each other, the matrix entry is the distance 00260 * between them. 00261 */ 00262 static void compVis(vconfig_t * conf, int start) 00263 { 00264 int V = conf->N; 00265 Ppoint_t *pts = conf->P; 00266 int *nextPt = conf->next; 00267 int *prevPt = conf->prev; 00268 array2 wadj = conf->vis; 00269 int j, i, previ; 00270 COORD d; 00271 00272 for (i = start; i < V; i++) { 00273 /* add edge between i and previ. 00274 * Note that this works for the cases of polygons of 1 and 2 00275 * vertices, though needless work is done. 00276 */ 00277 previ = prevPt[i]; 00278 d = dist(pts[i], pts[previ]); 00279 wadj[i][previ] = d; 00280 wadj[previ][i] = d; 00281 00282 /* Check remaining, earlier vertices */ 00283 if (previ == i - 1) 00284 j = i - 2; 00285 else 00286 j = i - 1; 00287 for (; j >= 0; j--) { 00288 if (inCone(i, j, pts, nextPt, prevPt) && 00289 inCone(j, i, pts, nextPt, prevPt) && 00290 clear(pts[i], pts[j], V, V, V, pts, nextPt, prevPt)) { 00291 /* if i and j see each other, add edge */ 00292 d = dist(pts[i], pts[j]); 00293 wadj[i][j] = d; 00294 wadj[j][i] = d; 00295 } 00296 } 00297 } 00298 } 00299 00300 /* visibility: 00301 * Given a vconfig_t conf, representing polygonal barriers, 00302 * compute the visibility graph of the vertices of conf. 00303 * The graph is stored in conf->vis. 00304 */ 00305 void visibility(vconfig_t * conf) 00306 { 00307 conf->vis = allocArray(conf->N, 2); 00308 compVis(conf, 0); 00309 } 00310 00311 /* polyhit: 00312 * Given a vconfig_t conf, as above, and a point, 00313 * return the index of the polygon that contains 00314 * the point, or else POLYID_NONE. 00315 */ 00316 static int polyhit(vconfig_t * conf, Ppoint_t p) 00317 { 00318 int i; 00319 Ppoly_t poly; 00320 00321 for (i = 0; i < conf->Npoly; i++) { 00322 poly.ps = &(conf->P[conf->start[i]]); 00323 poly.pn = conf->start[i + 1] - conf->start[i]; 00324 if (in_poly(poly, p)) 00325 return i; 00326 } 00327 return POLYID_NONE; 00328 } 00329 00330 /* ptVis: 00331 * Given a vconfig_t conf, representing polygonal barriers, 00332 * and a point within one of the polygons, compute the point's 00333 * visibility vector relative to the vertices of the remaining 00334 * polygons, i.e., pretend the argument polygon is invisible. 00335 * 00336 * If pp is NIL, ptVis computes the visibility vector for p 00337 * relative to all barrier vertices. 00338 */ 00339 COORD *ptVis(vconfig_t * conf, int pp, Ppoint_t p) 00340 { 00341 int V = conf->N; 00342 Ppoint_t *pts = conf->P; 00343 int *nextPt = conf->next; 00344 int *prevPt = conf->prev; 00345 int k; 00346 int start, end; 00347 COORD *vadj; 00348 Ppoint_t pk; 00349 COORD d; 00350 00351 vadj = (COORD *) malloc((V + 2) * sizeof(COORD)); 00352 00353 00354 if (pp == POLYID_UNKNOWN) 00355 pp = polyhit(conf, p); 00356 if (pp >= 0) { 00357 start = conf->start[pp]; 00358 end = conf->start[pp + 1]; 00359 } else { 00360 start = V; 00361 end = V; 00362 } 00363 00364 for (k = 0; k < start; k++) { 00365 pk = pts[k]; 00366 if (in_cone(pts[prevPt[k]], pk, pts[nextPt[k]], p) && 00367 clear(p, pk, start, end, V, pts, nextPt, prevPt)) { 00368 /* if p and pk see each other, add edge */ 00369 d = dist(p, pk); 00370 vadj[k] = d; 00371 } else 00372 vadj[k] = 0; 00373 } 00374 00375 for (k = start; k < end; k++) 00376 vadj[k] = 0; 00377 00378 for (k = end; k < V; k++) { 00379 pk = pts[k]; 00380 if (in_cone(pts[prevPt[k]], pk, pts[nextPt[k]], p) && 00381 clear(p, pk, start, end, V, pts, nextPt, prevPt)) { 00382 /* if p and pk see each other, add edge */ 00383 d = dist(p, pk); 00384 vadj[k] = d; 00385 } else 00386 vadj[k] = 0; 00387 } 00388 vadj[V] = 0; 00389 vadj[V + 1] = 0; 00390 00391 return vadj; 00392 00393 } 00394 00395 /* directVis: 00396 * Given two points, return true if the points can directly see each other. 00397 * If a point is associated with a polygon, the edges of the polygon 00398 * are ignored when checking visibility. 00399 */ 00400 int directVis(Ppoint_t p, int pp, Ppoint_t q, int qp, vconfig_t * conf) 00401 { 00402 int V = conf->N; 00403 Ppoint_t *pts = conf->P; 00404 int *nextPt = conf->next; 00405 /* int* prevPt = conf->prev; */ 00406 int k; 00407 int s1, e1; 00408 int s2, e2; 00409 00410 if (pp < 0) { 00411 s1 = 0; 00412 e1 = 0; 00413 if (qp < 0) { 00414 s2 = 0; 00415 e2 = 0; 00416 } else { 00417 s2 = conf->start[qp]; 00418 e2 = conf->start[qp + 1]; 00419 } 00420 } else if (qp < 0) { 00421 s1 = 0; 00422 e1 = 0; 00423 s2 = conf->start[pp]; 00424 e2 = conf->start[pp + 1]; 00425 } else if (pp <= qp) { 00426 s1 = conf->start[pp]; 00427 e1 = conf->start[pp + 1]; 00428 s2 = conf->start[qp]; 00429 e2 = conf->start[qp + 1]; 00430 } else { 00431 s1 = conf->start[qp]; 00432 e1 = conf->start[qp + 1]; 00433 s2 = conf->start[pp]; 00434 e2 = conf->start[pp + 1]; 00435 } 00436 00437 for (k = 0; k < s1; k++) { 00438 if (INTERSECT(p, q, pts[k], pts[nextPt[k]], pts[prevPt[k]])) 00439 return 0; 00440 } 00441 for (k = e1; k < s2; k++) { 00442 if (INTERSECT(p, q, pts[k], pts[nextPt[k]], pts[prevPt[k]])) 00443 return 0; 00444 } 00445 for (k = e2; k < V; k++) { 00446 if (INTERSECT(p, q, pts[k], pts[nextPt[k]], pts[prevPt[k]])) 00447 return 0; 00448 } 00449 return 1; 00450 }
1.7.5