Graphviz 14.1.3~dev.20260124.0732
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 "config.h"
12
13#include <assert.h>
14#include <float.h>
15#include <math.h>
16#include <limits.h>
17#include <neatogen/neato.h>
18#include <pathplan/pathutil.h>
19#include <stdbool.h>
20#include <stddef.h>
21#include <util/alloc.h>
22#include <util/exit.h>
23#include <util/list.h>
24
25#define SLOPE(p,q) ( ( ( p.y ) - ( q.y ) ) / ( ( p.x ) - ( q.x ) ) )
26
27#define EQ_PT(v,w) (((v).x == (w).x) && ((v).y == (w).y))
28
29#define after(v) (((v)==((v)->poly->finish))?((v)->poly->start):((v)+1))
30#define prior(v) (((v)==((v)->poly->start))?((v)->poly->finish):((v)-1))
31
32typedef struct polygon polygon;
33
34 typedef struct vertex {
37 struct vertex *active;
39
40 struct polygon {
43 };
44
45static int sign(double v) {
46 if (v < 0)
47 return -1;
48 if (v > 0)
49 return 1;
50 return 0;
51}
52
53/* find the sign of the area of each of the triangles
54 formed by adding a vertex of m to l
55 also find the sign of their product */
56static void sgnarea(vertex *l, vertex *m, int i[])
57{
58 double a, b, c, d, e, f, g, h, t;
59 a = l->pos.x;
60 b = l->pos.y;
61 c = after(l)->pos.x - a;
62 d = after(l)->pos.y - b;
63 e = m->pos.x - a;
64 f = m->pos.y - b;
65 g = after(m)->pos.x - a;
66 h = after(m)->pos.y - b;
67 t = c * f - d * e;
68 i[0] = sign(t);
69 t = c * h - d * g;
70 i[1] = sign(t);
71 i[2] = i[0] * i[1];
72}
73
86static int between(double f, double g, double h) {
87 if (f < g) {
88 if (g < h) {
89 return 1;
90 }
91 if (g > h) {
92 return -1;
93 }
94 return 0;
95 }
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 return 0;
106}
107
108/* determine if vertex i of line m is on line l */
109static int online(vertex *l, vertex *m, int i)
110{
111 pointf a, b, c;
112 a = l->pos;
113 b = after(l)->pos;
114 c = i == 0 ? m->pos : after(m)->pos;
115 return a.x == b.x
116 ? (a.x == c.x && -1 != between(a.y, c.y, b.y))
117 : between(a.x, c.x, b.x);
118}
119
120/* determine point of detected intersections */
121static int intpoint(vertex *l, vertex *m, double *x, double *y, int cond)
122{
123 pointf ls, le, ms, me, pt1, pt2;
124 double m1, m2, c1, c2;
125
126 if (cond <= 0)
127 return 0;
128 ls = l->pos;
129 le = after(l)->pos;
130 ms = m->pos;
131 me = after(m)->pos;
132
133 switch (cond) {
134
135 case 3: /* a simple intersection */
136 if (ls.x == le.x) {
137 *x = ls.x;
138 *y = me.y + SLOPE(ms, me) * (*x - me.x);
139 } else if (ms.x == me.x) {
140 *x = ms.x;
141 *y = le.y + SLOPE(ls, le) * (*x - le.x);
142 } else {
143 m1 = SLOPE(ms, me);
144 m2 = SLOPE(ls, le);
145 c1 = ms.y - m1 * ms.x;
146 c2 = ls.y - m2 * ls.x;
147 *x = (c2 - c1) / (m1 - m2);
148 *y = (m1 * c2 - c1 * m2) / (m1 - m2);
149 }
150 break;
151
152 case 2: /* the two lines have a common segment */
153 if (online(l, m, 0) == -1) { /* ms between ls and le */
154 pt1 = ms;
155 pt2 = online(m, l, 1) == -1
156 ? (online(m, l, 0) == -1 ? le : ls) : me;
157 } else if (online(l, m, 1) == -1) { /* me between ls and le */
158 pt1 = me;
159 pt2 = online(l, m, 0) == -1
160 ? (online(m, l, 0) == -1 ? le : ls) : ms;
161 } else {
162 /* may be degenerate? */
163 if (online(m, l, 0) != -1)
164 return 0;
165 pt1 = ls;
166 pt2 = le;
167 }
168
169 *x = (pt1.x + pt2.x) / 2;
170 *y = (pt1.y + pt2.y) / 2;
171 break;
172
173 case 1: /* a vertex of line m is on line l */
174 if ((ls.x - le.x) * (ms.y - ls.y) == (ls.y - le.y) * (ms.x - ls.x)) {
175 *x = ms.x;
176 *y = ms.y;
177 } else {
178 *x = me.x;
179 *y = me.y;
180 }
181 } /* end switch */
182 return 1;
183}
184
185static void
186putSeg (int i, vertex* v)
187{
188 fprintf(stderr, "seg#%d : (%.3f, %.3f) (%.3f, %.3f)\n",
189 i, v->pos.x, v->pos.y, after(v)->pos.x, after(v)->pos.y);
190}
191
193static bool realIntersect(vertex *firstv, vertex *secondv, pointf p) {
194 const pointf vft = firstv->pos;
195 const pointf avft = after(firstv)->pos;
196 const pointf vsd = secondv->pos;
197 const pointf avsd = after(secondv)->pos;
198
199 if ((vft.x != avft.x && vsd.x != avsd.x) ||
200 (vft.x == avft.x && !EQ_PT(vft, p) && !EQ_PT(avft, p)) ||
201 (vsd.x == avsd.x && !EQ_PT(vsd, p) && !EQ_PT(avsd, p)))
202 {
203 if (Verbose > 1) {
204 fprintf(stderr, "\nintersection at %.3f %.3f\n",
205 p.x, p.y);
206 putSeg (1, firstv);
207 putSeg (2, secondv);
208 }
209 return true;
210 }
211 return false;
212}
213
214/* detect whether segments l and m intersect
215 * Return true if found; false otherwise;
216 */
217static bool find_intersection(vertex *l, vertex *m) {
218 double x, y;
219 int i[3];
220 sgnarea(l, m, i);
221
222 if (i[2] > 0)
223 return false;
224
225 if (i[2] < 0) {
226 sgnarea(m, l, i);
227 if (i[2] > 0)
228 return false;
229 if (!intpoint(l, m, &x, &y, i[2] < 0 ? 3 : online(m, l, abs(i[0]))))
230 return false;
231 }
232
233 else if (!intpoint(l, m, &x, &y, i[0] == i[1] ?
234 2 * MAX(online(l, m, 0),
235 online(l, m, 1)) : online(l, m, abs(i[0]))))
236 return false;
237
238 return realIntersect(l, m, (pointf){.x = x, .y = y});
239}
240
241static int gt(const void *a, const void *b) {
242 const vertex *const *i = a;
243 const vertex *const *j = b;
244 if ((*i)->pos.x > (*j)->pos.x) {
245 return 1;
246 }
247 if ((*i)->pos.x < (*j)->pos.x) {
248 return -1;
249 }
250 if ((*i)->pos.y > (*j)->pos.y) {
251 return 1;
252 }
253 if ((*i)->pos.y < (*j)->pos.y) {
254 return -1;
255 }
256 return 0;
257}
258
259/* Check for pairwise intersection of polygon sides
260 * Return 1 if intersection found, 0 for not found, -1 for error.
261 */
262static int find_ints(vertex vertex_list[], size_t nvertices) {
263 int found = 0;
264 LIST(vertex *) all = {0};
265 vertex *tempa;
266
267 vertex **pvertex = gv_calloc(nvertices, sizeof(vertex*));
268
269 for (size_t i = 0; i < nvertices; i++)
270 pvertex[i] = vertex_list + i;
271
272/* sort vertices by x coordinate */
273 qsort(pvertex, nvertices, sizeof(vertex *), gt);
274
275/* walk through the vertices in order of increasing x coordinate */
276 for (size_t i = 0; i < nvertices; i++) {
277 vertex *const pt1 = pvertex[i];
278 vertex *pt2 = prior(pvertex[i]);
279 vertex *templ = pt2;
280 for (int k = 0; k < 2; k++) { // each vertex has 2 edges
281 switch (gt(&pt1, &pt2)) {
282
283 case -1: /* forward edge, test and insert */
284
285 /* test */
286 for (size_t j = 0; j < LIST_SIZE(&all); ++j) {
287 tempa = LIST_GET(&all, j);
288 found = find_intersection(tempa, templ);
289 if (found)
290 goto finish;
291 }
292
293 LIST_APPEND(&all, templ);
294 templ->active = templ;
295 break;
296
297 case 1: /* backward edge, delete */
298
299 if ((tempa = templ->active) == 0) {
300 agerrorf("trying to delete a non-line\n");
301 return -1;
302 }
303 LIST_REMOVE(&all, tempa);
304 templ->active = 0;
305 break;
306
307 default:
308 break; // same point; do nothing
309
310 }
311
312 pt2 = after(pvertex[i]);
313 templ = pvertex[i]; /*second neighbor */
314 }
315 }
316
317finish :
318 LIST_FREE(&all);
319 free (pvertex);
320 return found;
321}
322
323#define INBOX(p,bb) ((p.x <= bb.UR.x) && (p.x >= bb.LL.x) && (p.y <= bb.UR.y) && (p.y >= bb.LL.y))
324#define NESTED(a,b) (INBOX(a.LL,b) && INBOX(a.UR,b))
325
326/* Check if one polygon is inside another. We know that each
327 * pair is either disjoint or one is inside the other.
328 * Return 1 if an intersection is found, 0 otherwise.
329 */
330static int
331findInside(Ppoly_t ** polys, int n_polys, polygon* polygon_list)
332{
333 int i, j;
334 pointf pt;
335 Ppoly_t* p1;
336 Ppoly_t* p2;
337
338 for (i = 0; i < n_polys; i++) {
339 p1 = polys[i];
340 pt = p1->ps[0];
341 for (j = i+1; j < n_polys; j++) {
342 p2 = polys[j];
343 if (NESTED(polygon_list[i].bb,polygon_list[j].bb)) {
344 if (in_poly(*p2, pt)) return 1;
345 }
346 else if (NESTED(polygon_list[j].bb,polygon_list[i].bb)) {
347 if (in_poly(*p1, p2->ps[0])) return 1;
348 }
349 }
350 }
351 return 0;
352}
353
354/* Check that none of the polygons overlap.
355 * Return 1 if okay; 0 otherwise.
356 */
357int Plegal_arrangement(Ppoly_t ** polys, int n_polys)
358{
359 int i, vno, found;
360 boxf bb;
361 double x, y;
362
363 polygon *polygon_list = gv_calloc(n_polys, sizeof(polygon));
364
365 size_t nverts;
366 for (nverts = 0, i = 0; i < n_polys; i++) {
367 nverts += polys[i]->pn;
368 }
369
370 vertex *vertex_list = gv_calloc(nverts, sizeof(vertex));
371
372 for (i = vno = 0; i < n_polys; i++) {
373 polygon_list[i].start = &vertex_list[vno];
374 bb.LL.x = bb.LL.y = DBL_MAX;
375 bb.UR.x = bb.UR.y = -DBL_MAX;
376 for (size_t j = 0; j < polys[i]->pn; j++) {
377 x = polys[i]->ps[j].x;
378 y = polys[i]->ps[j].y;
379 bb.LL.x = fmin(bb.LL.x,x);
380 bb.LL.y = fmin(bb.LL.y,y);
381 bb.UR.x = fmax(bb.UR.x,x);
382 bb.UR.y = fmax(bb.UR.y,y);
383 vertex_list[vno].pos.x = x;
384 vertex_list[vno].pos.y = y;
385 vertex_list[vno].poly = &polygon_list[i];
386 vertex_list[vno].active = 0;
387 vno++;
388 }
389 polygon_list[i].finish = &vertex_list[vno - 1];
390 polygon_list[i].bb = bb;
391 }
392
393 found = find_ints(vertex_list, nverts);
394 if (found < 0) {
395 free(polygon_list);
396 free(vertex_list);
397 return 0;
398 }
399
400 if (!found) {
401 found = findInside(polys, n_polys, polygon_list);
402 }
403 free(polygon_list);
404 free(vertex_list);
405
406 return !found;
407}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define MAX(a, b)
Definition arith.h:33
#define le
Definition edges.h:29
static bool Verbose
Definition gml2gv.c:26
void free(void *)
void agerrorf(const char *fmt,...)
Definition agerror.c:167
bool in_poly(const Ppoly_t poly, Ppoint_t q)
Definition inpoly.c:26
static int between(double f, double g, double h)
Definition legal.c:86
static int intpoint(vertex *l, vertex *m, double *x, double *y, int cond)
Definition legal.c:121
static int find_ints(vertex vertex_list[], size_t nvertices)
Definition legal.c:262
static int gt(const void *a, const void *b)
Definition legal.c:241
static void sgnarea(vertex *l, vertex *m, int i[])
Definition legal.c:56
#define after(v)
Definition legal.c:29
static bool find_intersection(vertex *l, vertex *m)
Definition legal.c:217
int Plegal_arrangement(Ppoly_t **polys, int n_polys)
Definition legal.c:357
static bool realIntersect(vertex *firstv, vertex *secondv, pointf p)
return true if a real intersection has been found
Definition legal.c:193
static int sign(double v)
Definition legal.c:45
static int online(vertex *l, vertex *m, int i)
Definition legal.c:109
#define SLOPE(p, q)
Definition legal.c:25
struct vertex vertex
static void putSeg(int i, vertex *v)
Definition legal.c:186
static int findInside(Ppoly_t **polys, int n_polys, polygon *polygon_list)
Definition legal.c:331
#define NESTED(a, b)
Definition legal.c:324
#define prior(v)
Definition legal.c:30
#define EQ_PT(v, w)
Definition legal.c:27
type-generic dynamically expanding list
#define LIST(type)
Definition list.h:55
#define LIST_SIZE(list)
Definition list.h:80
#define LIST_APPEND(list, item)
Definition list.h:120
#define LIST_FREE(list)
Definition list.h:370
#define LIST_REMOVE(list, item)
Definition list.h:218
#define LIST_GET(list, index)
Definition list.h:155
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
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
double x
Definition geom.h:29
double y
Definition geom.h:29
vertex * finish
Definition legal.c:41
boxf bb
Definition legal.c:42
vertex * start
Definition legal.c:41
Definition legal.c:34
pointf pos
Definition legal.c:35
polygon * poly
Definition legal.c:36
struct vertex * active
Definition legal.c:37