Graphviz  2.29.20120524.0446
lib/pathplan/visibility.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 
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 }