Graphviz  2.31.20130617.0446
lib/neatogen/legal.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 #include "neato.h"
00015 #include "pathutil.h"
00016 #include <setjmp.h>
00017 
00018 static jmp_buf jbuf;
00019 
00020 #define MAXINTS  10000          /* modify this line to reflect the max no. of 
00021                                    intersections you want reported -- 50000 seems to break the program */
00022 
00023 #define SLOPE(p,q) ( ( ( p.y ) - ( q.y ) ) / ( ( p.x ) - ( q.x ) ) )
00024 
00025 #define EQ_PT(v,w) (((v).x == (w).x) && ((v).y == (w).y))
00026 
00027 #define after(v) (((v)==((v)->poly->finish))?((v)->poly->start):((v)+1))
00028 #define prior(v) (((v)==((v)->poly->start))?((v)->poly->finish):((v)-1))
00029 
00030 typedef struct active_edge active_edge;
00031 typedef struct polygon polygon;
00032 
00033     typedef struct {
00034         pointf pos;
00035         polygon *poly;
00036         active_edge *active;
00037     } vertex ;
00038 
00039     struct polygon {
00040         vertex *start, *finish;
00041         boxf bb;
00042     };
00043 
00044     typedef struct {
00045         vertex *firstv, *secondv;
00046 #ifdef RECORD_INTERSECTS
00047         polygon *firstp, *secondp;
00048 #endif
00049         double x, y;
00050     } intersection ;
00051 
00052     struct active_edge {
00053         vertex *name;
00054         struct active_edge *next, *last;
00055     };
00056     typedef struct active_edge_list {
00057         active_edge *first, *final;
00058         int number;
00059     } active_edge_list ;
00060     typedef struct {
00061         int nvertices, npolygons, ninters;
00062     } data ;
00063 
00064 
00065 /* find the sign of the area of each of the triangles
00066     formed by adding a vertex of m to l  
00067     also find the sign of their product  */
00068 static void sgnarea(vertex *l, vertex *m, int i[])
00069 {
00070     double a, b, c, d, e, f, g, h, t;
00071     a = l->pos.x;
00072     b = l->pos.y;
00073     c = after(l)->pos.x - a;
00074     d = after(l)->pos.y - b;
00075     e = m->pos.x - a;
00076     f = m->pos.y - b;
00077     g = after(m)->pos.x - a;
00078     h = after(m)->pos.y - b;
00079     t = (c * f) - (d * e);
00080     i[0] = ((t == 0) ? 0 : (t > 0 ? 1 : -1));
00081     t = (c * h) - (d * g);
00082     i[1] = ((t == 0) ? 0 : (t > 0 ? 1 : -1));
00083     i[2] = i[0] * i[1];
00084 }
00085 
00086 /* determine if g lies between f and h      */
00087 static int between(double f, double g, double h)
00088 {
00089     if ((f == g) || (g == h))
00090         return (0);
00091     return ((f < g) ? (g < h ? 1 : -1) : (h < g ? 1 : -1));
00092 }
00093 
00094 /* determine if vertex i of line m is on line l     */
00095 static int online(vertex *l, vertex *m, int i)
00096 {
00097     pointf a, b, c;
00098     a = l->pos;
00099     b = after(l)->pos;
00100     c = (i == 0) ? m->pos : after(m)->pos;
00101     return ((a.x == b.x) ? ((a.x == c.x)
00102                             && (-1 !=
00103                                 between(a.y, c.y, b.y))) : between(a.x,
00104                                                                    c.x,
00105                                                                    b.x));
00106 }
00107 
00108 /* determine point of detected intersections  */
00109 static int intpoint(vertex *l, vertex *m, double *x, double *y, int cond)
00110 {
00111     pointf ls, le, ms, me, pt1, pt2;
00112     double m1, m2, c1, c2;
00113 
00114     if (cond <= 0)
00115         return (0);
00116     ls = l->pos;
00117     le = after(l)->pos;
00118     ms = m->pos;
00119     me = after(m)->pos;
00120 
00121     switch (cond) {
00122 
00123     case 3:                     /* a simple intersection        */
00124         if (ls.x == le.x) {
00125             *x = ls.x;
00126             *y = me.y + SLOPE(ms, me) * (*x - me.x);
00127         } else if (ms.x == me.x) {
00128             *x = ms.x;
00129             *y = le.y + SLOPE(ls, le) * (*x - le.x);
00130         } else {
00131             m1 = SLOPE(ms, me);
00132             m2 = SLOPE(ls, le);
00133             c1 = ms.y - (m1 * ms.x);
00134             c2 = ls.y - (m2 * ls.x);
00135             *x = (c2 - c1) / (m1 - m2);
00136             *y = ((m1 * c2) - (c1 * m2)) / (m1 - m2);
00137         }
00138         break;
00139 
00140     case 2:                     /*     the two lines  have a common segment  */
00141         if (online(l, m, 0) == -1) {    /* ms between ls and le */
00142             pt1 = ms;
00143             pt2 =
00144                 (online(m, l, 1) ==
00145                  -1) ? ((online(m, l, 0) == -1) ? le : ls) : me;
00146         } else if (online(l, m, 1) == -1) {     /* me between ls and le */
00147             pt1 = me;
00148             pt2 =
00149                 (online(l, m, 0) ==
00150                  -1) ? ((online(m, l, 0) == -1) ? le : ls) : ms;
00151         } else {
00152             /* may be degenerate? */
00153             if (online(m, l, 0) != -1)
00154                 return 0;
00155             pt1 = ls;
00156             pt2 = le;
00157         }
00158 
00159         *x = (pt1.x + pt2.x) / 2;
00160         *y = (pt1.y + pt2.y) / 2;
00161         break;
00162 
00163     case 1:                     /* a vertex of line m is on line l */
00164         if ((ls.x - le.x) * (ms.y - ls.y) == (ls.y - le.y) * (ms.x - ls.x)) {
00165             *x = ms.x;
00166             *y = ms.y;
00167         } else {
00168             *x = me.x;
00169             *y = me.y;
00170         }
00171     }                           /* end switch  */
00172     return (1);
00173 }
00174 
00175 static void
00176 putSeg (int i, vertex* v)
00177 {
00178     fprintf(stderr, "seg#%d : (%.3f, %.3f) (%.3f, %.3f)\n",
00179         i, v->pos.x, v->pos.y, after(v)->pos.x, after(v)->pos.y);
00180 }
00181 
00182 /* realIntersect:
00183  * Return 1 if a real inatersection has been found
00184  */
00185 static int
00186 realIntersect (vertex *firstv, vertex *secondv, pointf p)
00187 {
00188     pointf vft, vsd, avft, avsd;
00189 
00190     vft = firstv->pos;
00191     avft = after(firstv)->pos;
00192     vsd = secondv->pos;
00193     avsd = after(secondv)->pos;
00194 
00195     if (((vft.x != avft.x) && (vsd.x != avsd.x)) ||
00196         ((vft.x == avft.x) &&
00197          !EQ_PT(vft, p) &&
00198          !EQ_PT(avft, p)) ||
00199         ((vsd.x == avsd.x) &&
00200          !EQ_PT(vsd, p) && !EQ_PT(avsd, p))) 
00201     {
00202         if (Verbose > 1) {
00203                 fprintf(stderr, "\nintersection at %.3f %.3f\n",
00204                         p.x, p.y);
00205                 putSeg (1, firstv);
00206                 putSeg (2, secondv);
00207         }
00208         return 1;
00209     }
00210     else return 0;
00211 }
00212 
00213 /* find_intersection:
00214  * detect whether segments l and m intersect      
00215  * Return 1 if found; 0 otherwise;
00216  */
00217 static int find_intersection(vertex *l,
00218                   vertex *m,
00219                   intersection* ilist, data *input)
00220 {
00221     double x, y;
00222     pointf p;
00223         int i[3];
00224     sgnarea(l, m, i);
00225 
00226     if (i[2] > 0)
00227         return 0;
00228 
00229     if (i[2] < 0) {
00230         sgnarea(m, l, i);
00231         if (i[2] > 0)
00232             return 0;
00233         if (!intpoint
00234             (l, m, &x, &y, (i[2] < 0) ? 3 : online(m, l, ABS(i[0]))))
00235             return 0;
00236     }
00237 
00238     else if (!intpoint(l, m, &x, &y, (i[0] == i[1]) ?
00239                        2 * MAX(online(l, m, 0),
00240                                online(l, m, 1)) : online(l, m, ABS(i[0]))))
00241         return 0;
00242 
00243 #ifdef RECORD_INTERSECTS
00244     if (input->ninters >= MAXINTS) {
00245         agerr(AGERR, "using too many intersections\n");
00246         exit(1);
00247     }
00248 
00249     ilist[input->ninters].firstv = l;
00250     ilist[input->ninters].secondv = m;
00251     ilist[input->ninters].firstp = l->poly;
00252     ilist[input->ninters].secondp = m->poly;
00253     ilist[input->ninters].x = x;
00254     ilist[input->ninters].y = y;
00255     input->ninters++;
00256 #endif
00257     p.x = x;
00258     p.y = y;
00259     return realIntersect(l, m, p);
00260 }
00261 
00262 static int gt(vertex **i, vertex **j)
00263 {
00264     /* i > j if i.x > j.x or i.x = j.x and i.y > j.y  */
00265     double t;
00266     if ((t = (*i)->pos.x - (*j)->pos.x) != 0.)
00267         return ((t > 0.) ? 1 : -1);
00268     if ((t = (*i)->pos.y - (*j)->pos.y) == 0.)
00269         return (0);
00270     else
00271         return ((t > 0.) ? 1 : -1);
00272 }
00273 
00274 /* find_ints:
00275  * Check for pairwise intersection of polygon sides
00276  * Return 1 if intersection found, 0 otherwise.
00277  */
00278 static int
00279 find_ints(vertex vertex_list[],
00280           polygon polygon_list[],
00281           data *input, intersection ilist[])
00282 {
00283     int i, j, k, found = 0;
00284     active_edge_list all;
00285     active_edge *new, *tempa;
00286     vertex *pt1, *pt2, *templ, **pvertex;
00287 
00288     input->ninters = 0;
00289     all.first = all.final = 0;
00290     all.number = 0;
00291 
00292     pvertex = N_GNEW(input->nvertices, vertex *);
00293 
00294     for (i = 0; i < input->nvertices; i++)
00295         pvertex[i] = vertex_list + i;
00296 
00297 /* sort vertices by x coordinate        */
00298     qsort(pvertex, input->nvertices, sizeof(vertex *),
00299           (int (*)(const void *, const void *))gt);
00300 
00301 /* walk through the vertices in order of increasing x coordinate        */
00302     for (i = 0; i < input->nvertices; i++) {
00303         pt1 = pvertex[i];
00304         templ = pt2 = prior(pvertex[i]);
00305         for (k = 0; k < 2; k++) {       /* each vertex has 2 edges */
00306             switch (gt(&pt1, &pt2)) {
00307 
00308             case -1:            /* forward edge, test and insert      */
00309 
00310                  /* test */
00311                 for (tempa = all.first, j = 0; j < all.number;
00312                      j++, tempa = tempa->next) {
00313                     found = find_intersection(tempa->name, templ, ilist, input);
00314                     if (found)
00315                         goto finish;
00316                 }
00317 
00318                 new = GNEW(active_edge);
00319                 if (all.number == 0) {
00320                     all.first = new;
00321                     new->last = 0;
00322                 } /* insert */
00323                 else {
00324                     all.final->next = new;
00325                     new->last = all.final;
00326                 }
00327 
00328                 new->name = templ;
00329                 new->next = 0;
00330                 templ->active = new;
00331                 all.final = new;
00332                 all.number++;
00333 
00334                 break;          /* end of case -1       */
00335 
00336             case 1:             /* backward edge, delete        */
00337 
00338                 if ((tempa = templ->active) == 0) {
00339                     agerr(AGERR, "trying to delete a non-line\n");
00340                     longjmp(jbuf, 1);
00341                 }
00342                 if (all.number == 1)
00343                     all.final = all.first = 0;  /* delete the line */
00344                 else if (tempa == all.first) {
00345                     all.first = all.first->next;
00346                     all.first->last = 0;
00347                 } else if (tempa == all.final) {
00348                     all.final = all.final->last;
00349                     all.final->next = 0;
00350                 } else {
00351                     tempa->last->next = tempa->next;
00352                     tempa->next->last = tempa->last;
00353                 }
00354                 free((char *) tempa);
00355                 all.number--;
00356                 templ->active = 0;
00357                 break;          /* end of case 1        */
00358 
00359             }                   /* end switch   */
00360 
00361             pt2 = after(pvertex[i]);
00362             templ = pvertex[i]; /*second neighbor */
00363         }                       /* end k for loop       */
00364     }                           /* end i for loop       */
00365 
00366 finish :
00367     for (tempa = all.first, j = 0; j < all.number;
00368                      j++, tempa = new) {
00369         new = tempa->next;
00370         free (tempa);
00371     }
00372     free (pvertex);
00373     return found;
00374 }
00375 
00376 #define INBOX(p,bb) ((p.x <= bb.UR.x) && (p.x >= bb.LL.x) && (p.y <= bb.UR.y) && (p.y >= bb.LL.y))
00377 #define NESTED(a,b) (INBOX(a.LL,b) && INBOX(a.UR,b))
00378 
00379 /* findInside:
00380  * Check if one polygon is inside another. We know that each
00381  * pair is either disjoint or one is inside the other.
00382  * Return 1 if an intersection is found, 0 otherwise.
00383  */
00384 static int
00385 findInside(Ppoly_t ** polys, int n_polys, polygon* polygon_list)
00386 {
00387     int i, j;
00388     pointf pt;
00389     Ppoly_t* p1;
00390     Ppoly_t* p2;
00391 
00392     for (i = 0; i < n_polys; i++) {
00393         p1 = polys[i];
00394         pt = p1->ps[0];
00395         for (j = i+1; j < n_polys; j++) {
00396             p2 = polys[j];
00397             if (NESTED(polygon_list[i].bb,polygon_list[j].bb)) {
00398                 if (in_poly(*p2, pt)) return 1;
00399             }
00400             else if (NESTED(polygon_list[j].bb,polygon_list[i].bb)) {
00401                 if (in_poly(*p1, p2->ps[0])) return 1;
00402             }
00403         }
00404     }
00405     return 0;
00406 }
00407 
00408 /* Plegal_arrangement:
00409  * Check that none of the polygons overlap.
00410  * Return 1 if okay; 0 otherwise.
00411  */
00412 int Plegal_arrangement(Ppoly_t ** polys, int n_polys)
00413 {
00414     int i, j, vno, nverts, found;
00415     vertex *vertex_list;
00416     polygon *polygon_list;
00417     data input;
00418     intersection ilist[MAXINTS];
00419     boxf bb;
00420     double x, y;
00421 
00422     polygon_list = N_GNEW(n_polys, polygon);
00423 
00424     for (i = nverts = 0; i < n_polys; i++)
00425         nverts += polys[i]->pn;
00426 
00427     vertex_list = N_GNEW(nverts, vertex);
00428 
00429     for (i = vno = 0; i < n_polys; i++) {
00430         polygon_list[i].start = &vertex_list[vno];
00431         bb.LL.x = bb.LL.y = MAXDOUBLE;
00432         bb.UR.x = bb.UR.y = -MAXDOUBLE;
00433         for (j = 0; j < polys[i]->pn; j++) {
00434             x = polys[i]->ps[j].x;
00435             y = polys[i]->ps[j].y;
00436             bb.LL.x = MIN(bb.LL.x,x);
00437             bb.LL.y = MIN(bb.LL.y,y);
00438             bb.UR.x = MAX(bb.UR.x,x);
00439             bb.UR.y = MAX(bb.UR.y,y);
00440             vertex_list[vno].pos.x = x;
00441             vertex_list[vno].pos.y = y;
00442             vertex_list[vno].poly = &polygon_list[i];
00443             vertex_list[vno].active = 0;
00444             vno++;
00445         }
00446         polygon_list[i].finish = &vertex_list[vno - 1];
00447         polygon_list[i].bb = bb;
00448     }
00449 
00450     input.nvertices = nverts;
00451     input.npolygons = n_polys;
00452 
00453     if (setjmp(jbuf)) {
00454         free(polygon_list);
00455         free(vertex_list);
00456         return 0;
00457     }
00458     found = find_ints(vertex_list, polygon_list, &input, ilist);
00459 
00460     if (!found) {
00461         found = findInside(polys, n_polys, polygon_list);
00462     }
00463     free(polygon_list);
00464     free(vertex_list);
00465 
00466     return !found;
00467 }