Graphviz 14.1.3~dev.20260124.0732
Loading...
Searching...
No Matches
visibility.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 <pathplan/vis.h>
15#include <stdbool.h>
16#include <stdlib.h>
17#include <util/alloc.h>
18
19/* allocArray:
20 * Allocate a VxV array of COORD values.
21 * (array2 is a pointer to an array of pointers; the array is
22 * accessed in row-major order.)
23 * The values in the array are initialized to 0.
24 * Add extra rows.
25 */
26static array2 allocArray(int V, int extra)
27{
28 int i;
29
30 assert(V >= 0);
31 array2 arr = gv_calloc(V + extra, sizeof(COORD*));
32 COORD *p = gv_calloc((size_t)V * (size_t)V, sizeof(COORD));
33 for (i = 0; i < V; i++) {
34 arr[i] = p;
35 p += V;
36 }
37 for (i = V; i < V + extra; i++)
38 arr[i] = NULL;
39
40 return arr;
41}
42
43/* area2:
44 * Returns twice the area of triangle abc.
45 */
47{
48 return (a.y - b.y) * (c.x - b.x) - (c.y - b.y) * (a.x - b.x);
49}
50
51/* wind:
52 * Returns 1, 0, -1 if the points abc are counterclockwise,
53 * collinear, or clockwise.
54 */
56{
57 COORD w;
58
59 w = (a.y - b.y) * (c.x - b.x) - (c.y - b.y) * (a.x - b.x);
60 /* need to allow for small math errors. seen with "gcc -O2 -mcpu=i686 -ffast-math" */
61 return w > .0001 ? 1 : (w < -.0001 ? -1 : 0);
62}
63
64/* inBetween:
65 * Return true if c is in (a,b), assuming a,b,c are collinear.
66 */
67static bool inBetween(Ppoint_t a, Ppoint_t b, Ppoint_t c)
68{
69 if (a.x != b.x) /* not vertical */
70 return (a.x < c.x && c.x < b.x) || (b.x < c.x && c.x < a.x);
71 else
72 return (a.y < c.y && c.y < b.y) || (b.y < c.y && c.y < a.y);
73}
74
75/* intersect:
76 * Returns true if the segment [c,d] blocks a and b from seeing each other.
77 * More specifically, returns true iff c or d lies on (a,b) or the two
78 * segments intersect as open sets.
79 */
81{
82 int a_abc;
83 int a_abd;
84 int a_cda;
85 int a_cdb;
86
87 a_abc = wind(a, b, c);
88 if (a_abc == 0 && inBetween(a, b, c)) {
89 return true;
90 }
91 a_abd = wind(a, b, d);
92 if (a_abd == 0 && inBetween(a, b, d)) {
93 return true;
94 }
95 a_cda = wind(c, d, a);
96 a_cdb = wind(c, d, b);
97
98 /* True if c and d are on opposite sides of ab,
99 * and a and b are on opposite sides of cd.
100 */
101 return a_abc * a_abd < 0 && a_cda * a_cdb < 0;
102}
103
104/* in_cone:
105 * Returns true iff point b is in the cone a0,a1,a2
106 * NB: the cone is considered a closed set
107 */
108static bool in_cone(Ppoint_t a0, Ppoint_t a1, Ppoint_t a2, Ppoint_t b)
109{
110 int m = wind(b, a0, a1);
111 int p = wind(b, a1, a2);
112
113 if (wind(a0, a1, a2) > 0)
114 return m >= 0 && p >= 0; /* convex at a */
115 else
116 return m >= 0 || p >= 0; /* reflex at a */
117}
118
119/* dist2:
120 * Returns the square of the distance between points a and b.
121 */
123{
124 COORD delx = a.x - b.x;
125 COORD dely = a.y - b.y;
126
127 return delx * delx + dely * dely;
128}
129
130/* dist:
131 * Returns the distance between points a and b.
132 */
134{
135 return sqrt(dist2(a, b));
136}
137
138static bool inCone(int i, int j, Ppoint_t pts[], int nextPt[], int prevPt[])
139{
140 return in_cone(pts[prevPt[i]], pts[i], pts[nextPt[i]], pts[j]);
141}
142
143/* clear:
144 * Return true if no polygon line segment non-trivially intersects
145 * the segment [pti,ptj], ignoring segments in [start,end).
146 */
147static bool clear(Ppoint_t pti, Ppoint_t ptj,
148 int start, int end,
149 int V, Ppoint_t pts[], int nextPt[])
150{
151 int k;
152
153 for (k = 0; k < start; k++) {
154 if (intersect(pti, ptj, pts[k], pts[nextPt[k]]))
155 return false;
156 }
157 for (k = end; k < V; k++) {
158 if (intersect(pti, ptj, pts[k], pts[nextPt[k]]))
159 return false;
160 }
161 return true;
162}
163
164/* compVis:
165 * Compute visibility graph of vertices of polygons.
166 * Only do polygons from index startp to end.
167 * If two nodes cannot see each other, the matrix entry is 0.
168 * If two nodes can see each other, the matrix entry is the distance
169 * between them.
170 */
171static void compVis(vconfig_t * conf) {
172 int V = conf->N;
173 Ppoint_t *pts = conf->P;
174 int *nextPt = conf->next;
175 int *prevPt = conf->prev;
176 array2 wadj = conf->vis;
177 int j, i, previ;
178 COORD d;
179
180 for (i = 0; i < V; i++) {
181 /* add edge between i and previ.
182 * Note that this works for the cases of polygons of 1 and 2
183 * vertices, though needless work is done.
184 */
185 previ = prevPt[i];
186 d = dist(pts[i], pts[previ]);
187 wadj[i][previ] = d;
188 wadj[previ][i] = d;
189
190 /* Check remaining, earlier vertices */
191 if (previ == i - 1)
192 j = i - 2;
193 else
194 j = i - 1;
195 for (; j >= 0; j--) {
196 if (inCone(i, j, pts, nextPt, prevPt) &&
197 inCone(j, i, pts, nextPt, prevPt) &&
198 clear(pts[i], pts[j], V, V, V, pts, nextPt)) {
199 /* if i and j see each other, add edge */
200 d = dist(pts[i], pts[j]);
201 wadj[i][j] = d;
202 wadj[j][i] = d;
203 }
204 }
205 }
206}
207
208/* visibility:
209 * Given a vconfig_t conf, representing polygonal barriers,
210 * compute the visibility graph of the vertices of conf.
211 * The graph is stored in conf->vis.
212 */
214{
215 conf->vis = allocArray(conf->N, 2);
216 compVis(conf);
217}
218
219/* polyhit:
220 * Given a vconfig_t conf, as above, and a point,
221 * return the index of the polygon that contains
222 * the point, or else POLYID_NONE.
223 */
224static int polyhit(vconfig_t * conf, Ppoint_t p)
225{
226 int i;
228
229 for (i = 0; i < conf->Npoly; i++) {
230 poly.ps = &(conf->P[conf->start[i]]);
231 poly.pn = (size_t)(conf->start[i + 1] - conf->start[i]);
232 if (in_poly(poly, p))
233 return i;
234 }
235 return POLYID_NONE;
236}
237
238/* ptVis:
239 * Given a vconfig_t conf, representing polygonal barriers,
240 * and a point within one of the polygons, compute the point's
241 * visibility vector relative to the vertices of the remaining
242 * polygons, i.e., pretend the argument polygon is invisible.
243 *
244 * If pp is NIL, ptVis computes the visibility vector for p
245 * relative to all barrier vertices.
246 */
247COORD *ptVis(vconfig_t * conf, int pp, Ppoint_t p)
248{
249 const int V = conf->N;
250 Ppoint_t *pts = conf->P;
251 int *nextPt = conf->next;
252 int *prevPt = conf->prev;
253 int k;
254 int start, end;
255 Ppoint_t pk;
256 COORD d;
257
258 COORD *vadj = gv_calloc(V + 2, sizeof(COORD));
259
260 if (pp == POLYID_UNKNOWN)
261 pp = polyhit(conf, p);
262 if (pp >= 0) {
263 start = conf->start[pp];
264 end = conf->start[pp + 1];
265 } else {
266 start = V;
267 end = V;
268 }
269
270 for (k = 0; k < start; k++) {
271 pk = pts[k];
272 if (in_cone(pts[prevPt[k]], pk, pts[nextPt[k]], p) &&
273 clear(p, pk, start, end, V, pts, nextPt)) {
274 /* if p and pk see each other, add edge */
275 d = dist(p, pk);
276 vadj[k] = d;
277 } else
278 vadj[k] = 0;
279 }
280
281 for (k = start; k < end; k++)
282 vadj[k] = 0;
283
284 for (k = end; k < V; k++) {
285 pk = pts[k];
286 if (in_cone(pts[prevPt[k]], pk, pts[nextPt[k]], p) &&
287 clear(p, pk, start, end, V, pts, nextPt)) {
288 /* if p and pk see each other, add edge */
289 d = dist(p, pk);
290 vadj[k] = d;
291 } else
292 vadj[k] = 0;
293 }
294 vadj[V] = 0;
295 vadj[V + 1] = 0;
296
297 return vadj;
298
299}
300
301/* directVis:
302 * Given two points, return true if the points can directly see each other.
303 * If a point is associated with a polygon, the edges of the polygon
304 * are ignored when checking visibility.
305 */
306bool directVis(Ppoint_t p, int pp, Ppoint_t q, int qp, vconfig_t * conf)
307{
308 int V = conf->N;
309 Ppoint_t *pts = conf->P;
310 int *nextPt = conf->next;
311 int k;
312 int s1, e1;
313 int s2, e2;
314
315 if (pp < 0) {
316 s1 = 0;
317 e1 = 0;
318 if (qp < 0) {
319 s2 = 0;
320 e2 = 0;
321 } else {
322 s2 = conf->start[qp];
323 e2 = conf->start[qp + 1];
324 }
325 } else if (qp < 0) {
326 s1 = 0;
327 e1 = 0;
328 s2 = conf->start[pp];
329 e2 = conf->start[pp + 1];
330 } else if (pp <= qp) {
331 s1 = conf->start[pp];
332 e1 = conf->start[pp + 1];
333 s2 = conf->start[qp];
334 e2 = conf->start[qp + 1];
335 } else {
336 s1 = conf->start[qp];
337 e1 = conf->start[qp + 1];
338 s2 = conf->start[pp];
339 e2 = conf->start[pp + 1];
340 }
341
342 for (k = 0; k < s1; k++) {
343 if (intersect(p, q, pts[k], pts[nextPt[k]]))
344 return false;
345 }
346 for (k = e1; k < s2; k++) {
347 if (intersect(p, q, pts[k], pts[nextPt[k]]))
348 return false;
349 }
350 for (k = e2; k < V; k++) {
351 if (intersect(p, q, pts[k], pts[nextPt[k]]))
352 return false;
353 }
354 return true;
355}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define V
Definition gdefs.h:5
node NULL
Definition grammar.y:181
bool in_poly(const Ppoly_t poly, Ppoint_t q)
Definition inpoly.c:26
NEATOPROCS_API void s1(graph_t *, node_t *)
Definition stuff.c:651
double COORD
Definition pathutil.h:31
double x
Definition pathgeom.h:38
double y
Definition pathgeom.h:38
int N
Definition vis.h:31
Ppoint_t * P
Definition vis.h:32
int * start
Definition vis.h:33
int * next
Definition vis.h:34
array2 vis
Definition vis.h:38
int * prev
Definition vis.h:35
int Npoly
Definition vis.h:30
struct poly_s poly
COORD ** array2
Definition vis.h:25
static bool inCone(int i, int j, Ppoint_t pts[], int nextPt[], int prevPt[])
Definition visibility.c:138
COORD * ptVis(vconfig_t *conf, int pp, Ppoint_t p)
Definition visibility.c:247
static COORD dist(Ppoint_t a, Ppoint_t b)
Definition visibility.c:133
static bool inBetween(Ppoint_t a, Ppoint_t b, Ppoint_t c)
Definition visibility.c:67
int wind(Ppoint_t a, Ppoint_t b, Ppoint_t c)
Definition visibility.c:55
static bool clear(Ppoint_t pti, Ppoint_t ptj, int start, int end, int V, Ppoint_t pts[], int nextPt[])
Definition visibility.c:147
static bool intersect(Ppoint_t a, Ppoint_t b, Ppoint_t c, Ppoint_t d)
Definition visibility.c:80
void visibility(vconfig_t *conf)
Definition visibility.c:213
static array2 allocArray(int V, int extra)
Definition visibility.c:26
COORD area2(Ppoint_t a, Ppoint_t b, Ppoint_t c)
Definition visibility.c:46
static bool in_cone(Ppoint_t a0, Ppoint_t a1, Ppoint_t a2, Ppoint_t b)
Definition visibility.c:108
bool directVis(Ppoint_t p, int pp, Ppoint_t q, int qp, vconfig_t *conf)
Definition visibility.c:306
COORD dist2(Ppoint_t a, Ppoint_t b)
Definition visibility.c:122
static void compVis(vconfig_t *conf)
Definition visibility.c:171
static int polyhit(vconfig_t *conf, Ppoint_t p)
Definition visibility.c:224
#define POLYID_UNKNOWN
Definition vispath.h:51
#define POLYID_NONE
Definition vispath.h:50