Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
legal.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include <assert.h>
12#include <float.h>
13#include <math.h>
14#include <limits.h>
15#include <neatogen/neato.h>
16#include <pathplan/pathutil.h>
17#include <stddef.h>
18#include <util/alloc.h>
19#include <util/exit.h>
20
21#define SLOPE(p,q) ( ( ( p.y ) - ( q.y ) ) / ( ( p.x ) - ( q.x ) ) )
22
23#define EQ_PT(v,w) (((v).x == (w).x) && ((v).y == (w).y))
24
25#define after(v) (((v)==((v)->poly->finish))?((v)->poly->start):((v)+1))
26#define prior(v) (((v)==((v)->poly->start))?((v)->poly->finish):((v)-1))
27
28typedef struct active_edge active_edge;
29typedef struct polygon polygon;
30
31 typedef struct {
35 } vertex ;
36
37 struct polygon {
40 };
41
42 struct active_edge {
45 };
50 typedef struct {
52 } data ;
53
54static int sign(double v) {
55 if (v < 0)
56 return -1;
57 if (v > 0)
58 return 1;
59 return 0;
60}
61
62/* find the sign of the area of each of the triangles
63 formed by adding a vertex of m to l
64 also find the sign of their product */
65static void sgnarea(vertex *l, vertex *m, int i[])
66{
67 double a, b, c, d, e, f, g, h, t;
68 a = l->pos.x;
69 b = l->pos.y;
70 c = after(l)->pos.x - a;
71 d = after(l)->pos.y - b;
72 e = m->pos.x - a;
73 f = m->pos.y - b;
74 g = after(m)->pos.x - a;
75 h = after(m)->pos.y - b;
76 t = c * f - d * e;
77 i[0] = sign(t);
78 t = c * h - d * g;
79 i[1] = sign(t);
80 i[2] = i[0] * i[1];
81}
82
95static int between(double f, double g, double h) {
96 if (f < g) {
97 if (g < h) {
98 return 1;
99 }
100 if (g > h) {
101 return -1;
102 }
103 return 0;
104 }
105 if (f > g) {
106 if (g > h) {
107 return 1;
108 }
109 if (g < h) {
110 return -1;
111 }
112 return 0;
113 }
114 return 0;
115}
116
117/* determine if vertex i of line m is on line l */
118static int online(vertex *l, vertex *m, int i)
119{
120 pointf a, b, c;
121 a = l->pos;
122 b = after(l)->pos;
123 c = i == 0 ? m->pos : after(m)->pos;
124 return a.x == b.x
125 ? (a.x == c.x && -1 != between(a.y, c.y, b.y))
126 : between(a.x, c.x, b.x);
127}
128
129/* determine point of detected intersections */
130static int intpoint(vertex *l, vertex *m, double *x, double *y, int cond)
131{
132 pointf ls, le, ms, me, pt1, pt2;
133 double m1, m2, c1, c2;
134
135 if (cond <= 0)
136 return 0;
137 ls = l->pos;
138 le = after(l)->pos;
139 ms = m->pos;
140 me = after(m)->pos;
141
142 switch (cond) {
143
144 case 3: /* a simple intersection */
145 if (ls.x == le.x) {
146 *x = ls.x;
147 *y = me.y + SLOPE(ms, me) * (*x - me.x);
148 } else if (ms.x == me.x) {
149 *x = ms.x;
150 *y = le.y + SLOPE(ls, le) * (*x - le.x);
151 } else {
152 m1 = SLOPE(ms, me);
153 m2 = SLOPE(ls, le);
154 c1 = ms.y - m1 * ms.x;
155 c2 = ls.y - m2 * ls.x;
156 *x = (c2 - c1) / (m1 - m2);
157 *y = (m1 * c2 - c1 * m2) / (m1 - m2);
158 }
159 break;
160
161 case 2: /* the two lines have a common segment */
162 if (online(l, m, 0) == -1) { /* ms between ls and le */
163 pt1 = ms;
164 pt2 = online(m, l, 1) == -1
165 ? (online(m, l, 0) == -1 ? le : ls) : me;
166 } else if (online(l, m, 1) == -1) { /* me between ls and le */
167 pt1 = me;
168 pt2 = online(l, m, 0) == -1
169 ? (online(m, l, 0) == -1 ? le : ls) : ms;
170 } else {
171 /* may be degenerate? */
172 if (online(m, l, 0) != -1)
173 return 0;
174 pt1 = ls;
175 pt2 = le;
176 }
177
178 *x = (pt1.x + pt2.x) / 2;
179 *y = (pt1.y + pt2.y) / 2;
180 break;
181
182 case 1: /* a vertex of line m is on line l */
183 if ((ls.x - le.x) * (ms.y - ls.y) == (ls.y - le.y) * (ms.x - ls.x)) {
184 *x = ms.x;
185 *y = ms.y;
186 } else {
187 *x = me.x;
188 *y = me.y;
189 }
190 } /* end switch */
191 return 1;
192}
193
194static void
195putSeg (int i, vertex* v)
196{
197 fprintf(stderr, "seg#%d : (%.3f, %.3f) (%.3f, %.3f)\n",
198 i, v->pos.x, v->pos.y, after(v)->pos.x, after(v)->pos.y);
199}
200
201/* realIntersect:
202 * Return 1 if a real intersection has been found
203 */
204static int
205realIntersect (vertex *firstv, vertex *secondv, pointf p)
206{
207 pointf vft, vsd, avft, avsd;
208
209 vft = firstv->pos;
210 avft = after(firstv)->pos;
211 vsd = secondv->pos;
212 avsd = after(secondv)->pos;
213
214 if ((vft.x != avft.x && vsd.x != avsd.x) ||
215 (vft.x == avft.x && !EQ_PT(vft, p) && !EQ_PT(avft, p)) ||
216 (vsd.x == avsd.x && !EQ_PT(vsd, p) && !EQ_PT(avsd, p)))
217 {
218 if (Verbose > 1) {
219 fprintf(stderr, "\nintersection at %.3f %.3f\n",
220 p.x, p.y);
221 putSeg (1, firstv);
222 putSeg (2, secondv);
223 }
224 return 1;
225 }
226 else return 0;
227}
228
229/* find_intersection:
230 * detect whether segments l and m intersect
231 * Return 1 if found; 0 otherwise;
232 */
233static int find_intersection(vertex *l, vertex *m) {
234 double x, y;
235 pointf p;
236 int i[3];
237 sgnarea(l, m, i);
238
239 if (i[2] > 0)
240 return 0;
241
242 if (i[2] < 0) {
243 sgnarea(m, l, i);
244 if (i[2] > 0)
245 return 0;
246 if (!intpoint(l, m, &x, &y, i[2] < 0 ? 3 : online(m, l, abs(i[0]))))
247 return 0;
248 }
249
250 else if (!intpoint(l, m, &x, &y, i[0] == i[1] ?
251 2 * MAX(online(l, m, 0),
252 online(l, m, 1)) : online(l, m, abs(i[0]))))
253 return 0;
254
255 p.x = x;
256 p.y = y;
257 return realIntersect(l, m, p);
258}
259
260static int gt(const void *a, const void *b) {
261 const vertex *const *i = a;
262 const vertex *const *j = b;
263 if ((*i)->pos.x > (*j)->pos.x) {
264 return 1;
265 }
266 if ((*i)->pos.x < (*j)->pos.x) {
267 return -1;
268 }
269 if ((*i)->pos.y > (*j)->pos.y) {
270 return 1;
271 }
272 if ((*i)->pos.y < (*j)->pos.y) {
273 return -1;
274 }
275 return 0;
276}
277
278/* find_ints:
279 * Check for pairwise intersection of polygon sides
280 * Return 1 if intersection found, 0 for not found, -1 for error.
281 */
282static int find_ints(vertex vertex_list[], size_t nvertices) {
283 int j, k, found = 0;
285 active_edge *new, *tempa;
286 vertex *pt1, *pt2, *templ;
287
288 all.first = all.final = 0;
289 all.number = 0;
290
291 vertex **pvertex = gv_calloc(nvertices, sizeof(vertex*));
292
293 for (size_t i = 0; i < nvertices; i++)
294 pvertex[i] = vertex_list + i;
295
296/* sort vertices by x coordinate */
297 qsort(pvertex, nvertices, sizeof(vertex *), gt);
298
299/* walk through the vertices in order of increasing x coordinate */
300 for (size_t i = 0; i < nvertices; i++) {
301 pt1 = pvertex[i];
302 templ = pt2 = prior(pvertex[i]);
303 for (k = 0; k < 2; k++) { /* each vertex has 2 edges */
304 switch (gt(&pt1, &pt2)) {
305
306 case -1: /* forward edge, test and insert */
307
308 /* test */
309 for (tempa = all.first, j = 0; j < all.number;
310 j++, tempa = tempa->next) {
311 found = find_intersection(tempa->name, templ);
312 if (found)
313 goto finish;
314 }
315
316 new = gv_alloc(sizeof(active_edge));
317 if (all.number == 0) {
318 all.first = new;
319 new->last = 0;
320 } /* insert */
321 else {
322 all.final->next = new;
323 new->last = all.final;
324 }
325
326 new->name = templ;
327 new->next = 0;
328 templ->active = new;
329 all.final = new;
330 all.number++;
331
332 break; /* end of case -1 */
333
334 case 1: /* backward edge, delete */
335
336 if ((tempa = templ->active) == 0) {
337 agerrorf("trying to delete a non-line\n");
338 return -1;
339 }
340 if (all.number == 1)
341 all.final = all.first = 0; /* delete the line */
342 else if (tempa == all.first) {
343 all.first = all.first->next;
344 all.first->last = 0;
345 } else if (tempa == all.final) {
346 all.final = all.final->last;
347 all.final->next = 0;
348 } else {
349 tempa->last->next = tempa->next;
350 tempa->next->last = tempa->last;
351 }
352 free(tempa);
353 all.number--;
354 templ->active = 0;
355 break; /* end of case 1 */
356
357 default:
358 break; // same point; do nothing
359
360 } /* end switch */
361
362 pt2 = after(pvertex[i]);
363 templ = pvertex[i]; /*second neighbor */
364 } /* end k for loop */
365 } /* end i for loop */
366
367finish :
368 for (tempa = all.first, j = 0; j < all.number;
369 j++, tempa = new) {
370 new = tempa->next;
371 free (tempa);
372 }
373 free (pvertex);
374 return found;
375}
376
377#define INBOX(p,bb) ((p.x <= bb.UR.x) && (p.x >= bb.LL.x) && (p.y <= bb.UR.y) && (p.y >= bb.LL.y))
378#define NESTED(a,b) (INBOX(a.LL,b) && INBOX(a.UR,b))
379
380/* findInside:
381 * Check if one polygon is inside another. We know that each
382 * pair is either disjoint or one is inside the other.
383 * Return 1 if an intersection is found, 0 otherwise.
384 */
385static int
386findInside(Ppoly_t ** polys, int n_polys, polygon* polygon_list)
387{
388 int i, j;
389 pointf pt;
390 Ppoly_t* p1;
391 Ppoly_t* p2;
392
393 for (i = 0; i < n_polys; i++) {
394 p1 = polys[i];
395 pt = p1->ps[0];
396 for (j = i+1; j < n_polys; j++) {
397 p2 = polys[j];
398 if (NESTED(polygon_list[i].bb,polygon_list[j].bb)) {
399 if (in_poly(*p2, pt)) return 1;
400 }
401 else if (NESTED(polygon_list[j].bb,polygon_list[i].bb)) {
402 if (in_poly(*p1, p2->ps[0])) return 1;
403 }
404 }
405 }
406 return 0;
407}
408
409/* Plegal_arrangement:
410 * Check that none of the polygons overlap.
411 * Return 1 if okay; 0 otherwise.
412 */
413int Plegal_arrangement(Ppoly_t ** polys, int n_polys)
414{
415 int i, vno, found;
416 boxf bb;
417 double x, y;
418
419 polygon *polygon_list = gv_calloc(n_polys, sizeof(polygon));
420
421 size_t nverts;
422 for (nverts = 0, i = 0; i < n_polys; i++) {
423 nverts += polys[i]->pn;
424 }
425
426 vertex *vertex_list = gv_calloc(nverts, sizeof(vertex));
427
428 for (i = vno = 0; i < n_polys; i++) {
429 polygon_list[i].start = &vertex_list[vno];
430 bb.LL.x = bb.LL.y = DBL_MAX;
431 bb.UR.x = bb.UR.y = -DBL_MAX;
432 for (size_t j = 0; j < polys[i]->pn; j++) {
433 x = polys[i]->ps[j].x;
434 y = polys[i]->ps[j].y;
435 bb.LL.x = fmin(bb.LL.x,x);
436 bb.LL.y = fmin(bb.LL.y,y);
437 bb.UR.x = fmax(bb.UR.x,x);
438 bb.UR.y = fmax(bb.UR.y,y);
439 vertex_list[vno].pos.x = x;
440 vertex_list[vno].pos.y = y;
441 vertex_list[vno].poly = &polygon_list[i];
442 vertex_list[vno].active = 0;
443 vno++;
444 }
445 polygon_list[i].finish = &vertex_list[vno - 1];
446 polygon_list[i].bb = bb;
447 }
448
449 found = find_ints(vertex_list, nverts);
450 if (found < 0) {
451 free(polygon_list);
452 free(vertex_list);
453 return 0;
454 }
455
456 if (!found) {
457 found = findInside(polys, n_polys, polygon_list);
458 }
459 free(polygon_list);
460 free(vertex_list);
461
462 return !found;
463}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static void * gv_alloc(size_t size)
Definition alloc.h:47
#define le
Definition edges.h:25
static bool Verbose
Definition gml2gv.c:23
void free(void *)
void agerrorf(const char *fmt,...)
Definition agerror.c:165
bool in_poly(const Ppoly_t poly, Ppoint_t q)
Definition inpoly.c:24
static int between(double f, double g, double h)
Definition legal.c:95
static int intpoint(vertex *l, vertex *m, double *x, double *y, int cond)
Definition legal.c:130
static int realIntersect(vertex *firstv, vertex *secondv, pointf p)
Definition legal.c:205
static int find_ints(vertex vertex_list[], size_t nvertices)
Definition legal.c:282
static int gt(const void *a, const void *b)
Definition legal.c:260
static void sgnarea(vertex *l, vertex *m, int i[])
Definition legal.c:65
#define after(v)
Definition legal.c:25
int Plegal_arrangement(Ppoly_t **polys, int n_polys)
Definition legal.c:413
struct active_edge_list active_edge_list
static int sign(double v)
Definition legal.c:54
static int online(vertex *l, vertex *m, int i)
Definition legal.c:118
static int find_intersection(vertex *l, vertex *m)
Definition legal.c:233
#define SLOPE(p, q)
Definition legal.c:21
static void putSeg(int i, vertex *v)
Definition legal.c:195
static int findInside(Ppoly_t **polys, int n_polys, polygon *polygon_list)
Definition legal.c:386
#define NESTED(a, b)
Definition legal.c:378
#define prior(v)
Definition legal.c:26
#define EQ_PT(v, w)
Definition legal.c:23
static size_t nvertices
Definition site.c:20
size_t pn
Definition pathgeom.h:47
Ppoint_t * ps
Definition pathgeom.h:46
double x
Definition pathgeom.h:38
double y
Definition pathgeom.h:38
active_edge * final
Definition legal.c:47
active_edge * first
Definition legal.c:47
vertex * name
Definition legal.c:43
struct active_edge * next
Definition legal.c:44
struct active_edge * last
Definition legal.c:44
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
Definition legal.c:50
int ninters
Definition legal.c:51
double x
Definition geom.h:29
double y
Definition geom.h:29
vertex * finish
Definition legal.c:38
boxf bb
Definition legal.c:39
vertex * start
Definition legal.c:38
Definition legal.c:31
pointf pos
Definition legal.c:32
active_edge * active
Definition legal.c:34
polygon * poly
Definition legal.c:33
#define MAX(a, b)
Definition write.c:31