|
Graphviz
2.31.20130617.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 #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 }
1.7.5