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