GRASS 8 Programmer's Manual 8.6.0dev(2026)-ddeab64dbf
Loading...
Searching...
No Matches
dgraph.c
Go to the documentation of this file.
1/*!
2 \file lib/vector/Vlib/dgraph.c
3
4 \brief Vector library - intersection (lower level functions)
5
6 Higher level functions for reading/writing/manipulating vectors.
7
8 (C) 2008-2009 by the GRASS Development Team
9
10 This program is free software under the GNU General Public License
11 (>=v2). Read the file COPYING that comes with GRASS for details.
12
13 \author Rewritten by Rosen Matev (Google Summer of Code 2008)
14 */
15
16#include <stdlib.h>
17#include <string.h>
18#include <math.h>
19#include <grass/gis.h>
20#include <grass/vector.h>
21#include <grass/glocale.h>
22#include "dgraph.h"
23#include "e_intersect.h"
24
25#define LENGTH(DX, DY) (sqrt((DX * DX) + (DY * DY)))
26#define PI M_PI
27
28struct intersection_point {
29 double x;
30 double y;
31 int group; /* IPs with very similar dist will be in the same group */
32};
33
34struct seg_intersection {
35 int with; /* second segment */
36 int ip; /* index of the IP */
37 double dist; /* distance from first point of first segment to intersection
38 point (IP) */
39};
40
41struct seg_intersection_list {
42 int count;
43 int allocated;
44 struct seg_intersection *a;
45};
46
47struct seg_intersections {
48 int ipcount;
49 int ipallocated;
50 struct intersection_point *ip;
51 int ilcount;
52 struct seg_intersection_list *il;
53 int group_count;
54};
55
56struct seg_intersections *create_si_struct(int segments_count)
57{
58 struct seg_intersections *si;
59
60 int i;
61
62 si = G_malloc(sizeof(struct seg_intersections));
63 si->ipcount = 0;
64 si->ipallocated = segments_count + 16;
65 si->ip = G_malloc((si->ipallocated) * sizeof(struct intersection_point));
66 si->ilcount = segments_count;
67 si->il = G_malloc(segments_count * sizeof(struct seg_intersection_list));
68 for (i = 0; i < segments_count; i++) {
69 si->il[i].count = 0;
70 si->il[i].allocated = 0;
71 si->il[i].a = NULL;
72 }
73
74 return si;
75}
76
77void destroy_si_struct(struct seg_intersections *si)
78{
79 int i;
80
81 for (i = 0; i < si->ilcount; i++)
82 G_free(si->il[i].a);
83 G_free(si->il);
84 G_free(si->ip);
85 G_free(si);
86
87 return;
88}
89
90/* internal use */
91void add_ipoint1(struct seg_intersection_list *il, int with, double dist,
92 int ip)
93{
94 struct seg_intersection *s;
95
96 if (il->count == il->allocated) {
97 il->allocated += 4;
98 il->a =
99 G_realloc(il->a, (il->allocated) * sizeof(struct seg_intersection));
100 }
101 s = &(il->a[il->count]);
102 s->with = with;
103 s->ip = ip;
104 s->dist = dist;
105 il->count++;
106
107 return;
108}
109
110/* adds intersection point to the structure */
111void add_ipoint(const struct line_pnts *Points, int first_seg, int second_seg,
112 double x, double y, struct seg_intersections *si)
113{
114 struct intersection_point *t;
115
116 int ip;
117
118 G_debug(4, "add_ipoint()");
119
120 if (si->ipcount == si->ipallocated) {
121 si->ipallocated += 16;
122 si->ip = G_realloc(si->ip, (si->ipallocated) *
123 sizeof(struct intersection_point));
124 }
125 ip = si->ipcount;
126 t = &(si->ip[ip]);
127 t->x = x;
128 t->y = y;
129 t->group = -1;
130 si->ipcount++;
131
133 LENGTH((Points->x[first_seg] - x), (Points->y[first_seg] - y)),
134 ip);
135 if (second_seg >= 0)
137 &(si->il[second_seg]), first_seg,
138 LENGTH((Points->x[second_seg] - x), (Points->y[second_seg] - y)),
139 ip);
140}
141
142void sort_intersection_list(struct seg_intersection_list *il)
143{
144 int n, i, j, min;
145 struct seg_intersection t;
146
147 G_debug(4, "sort_intersection_list()");
148
149 n = il->count;
150 G_debug(4, " n=%d", n);
151 for (i = 0; i < n - 1; i++) {
152 min = i;
153 for (j = i + 1; j < n; j++) {
154 if (il->a[j].dist < il->a[min].dist) {
155 min = j;
156 }
157 }
158 if (min != i) {
159 t = il->a[i];
160 il->a[i] = il->a[min];
161 il->a[min] = t;
162 }
163 }
164
165 return;
166}
167
168int compare(const void *a, const void *b)
169{
170 struct intersection_point *aa, *bb;
171
172 aa = *((struct intersection_point **)a);
173 bb = *((struct intersection_point **)b);
174
175 if (aa->x < bb->x)
176 return -1;
177 else if (aa->x > bb->x)
178 return 1;
179 else
180 return (aa->y < bb->y) ? -1 : ((aa->y > bb->y) ? 1 : 0);
181}
182
183/* O(Points->n_points) time */
184double get_epsilon(struct line_pnts *Points)
185{
186 int i, np;
187
188 double min, t;
189
190 double *x, *y;
191
192 np = Points->n_points;
193 x = Points->x;
194 y = Points->y;
195
196 min = MAX(fabs(x[1] - x[0]), fabs(y[1] - y[0]));
197 for (i = 1; i <= np - 2; i++) {
198 t = MAX(fabs(x[i + 1] - x[i]), fabs(y[i + 1] - y[i]));
199 if ((t > 0) && (t < min)) {
200 min = t;
201 }
202 }
203
204 /* ??? is 0.001 ok ??? */
205 return min * 0.000001;
206}
207
208/* currently O(n*n); future implementation O(nlogn) */
209struct seg_intersections *find_all_intersections(const struct line_pnts *Points)
210{
211 int i, j, np;
212 int group, t;
213 int looped;
214
215 /* double EPSILON = 0.00000001; */
216 double EPSILON = GRASS_EPSILON;
217 double *x, *y;
218 double x1, y1, x2, y2;
219 int res;
220
221 /*int res2
222 double x1_, y1_, x2_, y2_, z1_, z2_; */
223 struct seg_intersections *si;
224 struct seg_intersection_list *il;
225 struct intersection_point **sorted;
226
227 G_debug(3, "find_all_intersections()");
228
229 np = Points->n_points;
230 x = Points->x;
231 y = Points->y;
232
233 si = create_si_struct(np - 1);
234
235 looped = ((x[0] == x[np - 1]) && (y[0] == y[np - 1]));
236 G_debug(3, " looped=%d", looped);
237
238 G_debug(3, " finding intersections...");
239 for (i = 0; i < np - 1; i++) {
240 for (j = i + 1; j < np - 1; j++) {
241 G_debug(4, " checking %d-%d %d-%d", i, i + 1, j, j + 1);
242 /*res = segment_intersection_2d_e(x[i], y[i], x[i+1], y[i+1], x[j],
243 * y[j], x[j+1], y[j+1], &x1, &y1, &x2, &y2); */
244 res = segment_intersection_2d(x[i], y[i], x[i + 1], y[i + 1], x[j],
245 y[j], x[j + 1], y[j + 1], &x1, &y1,
246 &x2, &y2);
247
248 /* res2 = segment_intersection_2d_e(x[i], y[i], x[i+1],
249 y[i+1], x[j], y[j], x[j+1], y[j+1], &x1_, &y1_, &x2_, &y2_); if
250 ((res != res2) || ((res != 0) && (x1!=x1_ || y1!=y1_)) ) {
251 G_debug(1, "exact=%d orig=%d", res, res2);
252 segment_intersection_2d_test(x[i], y[i], x[i+1], y[i+1], x[j],
253 y[j], x[j+1], y[j+1], &x1, &y1, &x2, &y2);
254 }
255 */
256 G_debug(4, " intersection type = %d", res);
257 if (res == 1) {
258 add_ipoint(Points, i, j, x1, y1, si);
259 }
260 else if ((res >= 2) && (res <= 5)) {
261 add_ipoint(Points, i, j, x1, y1, si);
262 add_ipoint(Points, i, j, x2, y2, si);
263 }
264 }
265 }
266 if (!looped) {
267 /* these are not really intersection points */
268 add_ipoint(Points, 0, -1, Points->x[0], Points->y[0], si);
269 add_ipoint(Points, np - 2, -1, Points->x[np - 1], Points->y[np - 1],
270 si);
271 }
272 G_debug(3, " finding intersections...done");
273
274 G_debug(3, " postprocessing...");
275 if (si->ipallocated > si->ipcount) {
276 si->ipallocated = si->ipcount;
277 si->ip = G_realloc(si->ip,
278 (si->ipcount) * sizeof(struct intersection_point));
279 }
280 for (i = 0; i < si->ilcount; i++) {
281 il = &(si->il[i]);
282 if (il->allocated > il->count) {
283 il->allocated = il->count;
284 il->a =
285 G_realloc(il->a, (il->count) * sizeof(struct seg_intersection));
286 }
287
288 if (il->count > 0) {
290 /* is it ok to use qsort here ? */
291 }
292 }
293
294 /* si->ip will not be reallocated any more so we can use pointers */
295 sorted = G_malloc((si->ipcount) * sizeof(struct intersection_point *));
296 for (i = 0; i < si->ipcount; i++)
297 sorted[i] = &(si->ip[i]);
298
299 qsort(sorted, si->ipcount, sizeof(struct intersection_point *), compare);
300
301 /* assign groups */
302 group = 0; /* next available group number */
303 for (i = 0; i < si->ipcount; i++) {
304
305 t = group;
306 for (j = i - 1; j >= 0; j--) {
307 if (!FEQUAL(sorted[j]->x, sorted[i]->x, EPSILON))
308 /* if (!almost_equal(sorted[j]->x, sorted[i]->x, 16))
309 */
310 break;
311 if (FEQUAL(sorted[j]->y, sorted[i]->y, EPSILON)) {
312 /* if (almost_equal(sorted[j]->y, sorted[i]->y, 16))
313 * { */
314 t = sorted[j]->group;
315 break;
316 }
317 }
318 G_debug(4, " group=%d, ip=%d", t,
319 (int)(sorted[i] - &(si->ip[0])));
320 sorted[i]->group = t;
321 if (t == group)
322 group++;
323 }
324 si->group_count = group;
325
326 G_debug(3, " postprocessing...done");
327
328 /* output contents of si */
329 for (i = 0; i < si->ilcount; i++) {
330 G_debug(4, "%d-%d :", i, i + 1);
331 for (j = 0; j < si->il[i].count; j++) {
332 G_debug(4, " %d-%d, group=%d", si->il[i].a[j].with,
333 si->il[i].a[j].with + 1, si->ip[si->il[i].a[j].ip].group);
334 G_debug(4, " dist=%.18f", si->il[i].a[j].dist);
335 G_debug(4, " x=%.18f, y=%.18f",
336 si->ip[si->il[i].a[j].ip].x, si->ip[si->il[i].a[j].ip].y);
337 }
338 }
339 G_free(sorted);
340
341 return si;
342}
343
344/* create's graph with n vertices and allocates memory for e edges */
345/* trying to add more than e edges, produces fatal error */
346struct planar_graph *pg_create_struct(int n, int e)
347{
348 struct planar_graph *pg;
349
350 pg = G_malloc(sizeof(struct planar_graph));
351 pg->vcount = n;
352 pg->v = G_malloc(n * sizeof(struct pg_vertex));
353 memset(pg->v, 0, n * sizeof(struct pg_vertex));
354 pg->ecount = 0;
355 pg->eallocated = MAX(e, 0);
356 pg->e = NULL;
357 pg->e = G_malloc(e * sizeof(struct pg_edge));
358
359 return pg;
360}
361
363{
364 int i;
365
366 for (i = 0; i < pg->vcount; i++) {
367 G_free(pg->v[i].edges);
368 G_free(pg->v[i].angles);
369 }
370 G_free(pg->v);
371 G_free(pg->e);
372 G_free(pg);
373}
374
375/* v1 and v2 must be valid */
376int pg_existsedge(struct planar_graph *pg, int v1, int v2)
377{
378 struct pg_vertex *v;
379 struct pg_edge *e;
380 int i, ecount;
381
382 if (pg->v[v1].ecount <= pg->v[v2].ecount)
383 v = &(pg->v[v1]);
384 else
385 v = &(pg->v[v2]);
386
387 ecount = v->ecount;
388 for (i = 0; i < ecount; i++) {
389 e = v->edges[i];
390 if (((e->v1 == v1) && (e->v2 == v2)) ||
391 ((e->v1 == v2) && (e->v2 == v1)))
392 return 1;
393 }
394
395 return 0;
396}
397
398/* for internal use */
399void pg_addedge1(struct pg_vertex *v, struct pg_edge *e)
400{
401 if (v->ecount == v->eallocated) {
402 v->eallocated += 4;
403 v->edges =
404 G_realloc(v->edges, (v->eallocated) * sizeof(struct pg_edge *));
405 }
406 v->edges[v->ecount] = e;
407 v->ecount++;
408}
409
410void pg_addedge(struct planar_graph *pg, int v1, int v2)
411{
412 struct pg_edge *e;
413
414 G_debug(4, "pg_addedge(), v1=%d, v2=%d", v1, v2);
415
416 if ((v1 == v2) || (v1 < 0) || (v1 >= pg->vcount) || (v2 < 0) ||
417 (v2 >= pg->vcount)) {
418 G_fatal_error(" pg_addedge(), v1 and/or v2 is invalid");
419 return;
420 }
421
422 if (pg_existsedge(pg, v1, v2))
423 return;
424
425 if (pg->ecount == pg->eallocated) {
426 G_fatal_error(_("Trying to add more edges to the planar_graph "
427 "than the initial allocation size allows"));
428 }
429 e = &(pg->e[pg->ecount]);
430 e->v1 = v1;
431 e->v2 = v2;
432 e->winding_left =
433 0; /* winding is undefined if the corresponding side is not visited */
434 e->winding_right = 0;
435 e->visited_left = 0;
436 e->visited_right = 0;
437 pg->ecount++;
438 pg_addedge1(&(pg->v[v1]), e);
439 pg_addedge1(&(pg->v[v2]), e);
440
441 return;
442}
443
444struct planar_graph *pg_create(const struct line_pnts *Points)
445{
446 struct seg_intersections *si;
447 struct planar_graph *pg;
448 struct intersection_point *ip;
449 struct pg_vertex *vert;
450 struct pg_edge *edge;
451
452 int i, j, t, v;
453
454 G_debug(3, "pg_create()");
455
456 si = find_all_intersections(Points);
457 pg = pg_create_struct(si->group_count, 2 * (si->ipcount));
458
459 /* set vertices info */
460 for (i = 0; i < si->ipcount; i++) {
461 ip = &(si->ip[i]);
462 t = ip->group;
463 pg->v[t].x = ip->x;
464 pg->v[t].y = ip->y;
465 }
466
467 /* add all edges */
468 for (i = 0; i < si->ilcount; i++) {
469 v = si->ip[si->il[i].a[0].ip].group;
470 for (j = 1; j < si->il[i].count; j++) {
471 t = si->ip[si->il[i].a[j].ip].group;
472 if (t != v) {
473 pg_addedge(pg, v, t); /* edge direction is v ---> t */
474 v = t;
475 }
476 }
477 }
478
479 /* precalculate angles with 0x */
480 for (i = 0; i < pg->vcount; i++) {
481 vert = &(pg->v[i]);
482 vert->angles = G_malloc((vert->ecount) * sizeof(double));
483 for (j = 0; j < vert->ecount; j++) {
484 edge = vert->edges[j];
485 t = (edge->v1 != i) ? (edge->v1) : (edge->v2);
486 vert->angles[j] = atan2(pg->v[t].y - vert->y, pg->v[t].x - vert->x);
487 }
488 }
489
491 /*
492 I'm not sure if shrinking of the allocated memory always preserves it's
493 physical place. That's why I don't want to do this: if (pg->ecount <
494 pg->eallocated) { pg->eallocated = pg->ecount; pg->e = G_realloc(pg->e,
495 (pg->ecount)*sizeof(struct pg_edge));
496 }
497 */
498
499 /* very time consuming */
500 /*
501 for (i = 0; i < pg->vcount; i++) {
502 if (pg->v[i].ecount < pg->v[i].eallocated) {
503 pg->v[i].eallocated = pg->v[i].ecount;
504 pg->v[i].edges = G_realloc(pg->v[i].edges,
505 (pg->v[i].ecount)*sizeof(struct pg_edges));
506 }
507 }
508 */
509
510 /* output pg */
511 for (i = 0; i < pg->vcount; i++) {
512 G_debug(4, " vertex %d (%g, %g)", i, pg->v[i].x, pg->v[i].y);
513 for (j = 0; j < pg->v[i].ecount; j++) {
514 G_debug(4, " edge %d-%d", pg->v[i].edges[j]->v1,
515 pg->v[i].edges[j]->v2);
516 }
517 }
518
519 return pg;
520}
#define EPSILON
#define NULL
Definition ccmath.h:32
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:147
#define G_realloc(p, n)
Definition defs/gis.h:141
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition defs/gis.h:139
int G_debug(int, const char *,...) __attribute__((format(printf
void add_ipoint1(struct seg_intersection_list *il, int with, double dist, int ip)
Definition dgraph.c:91
#define LENGTH(DX, DY)
Definition dgraph.c:25
struct seg_intersections * create_si_struct(int segments_count)
Definition dgraph.c:56
void add_ipoint(const struct line_pnts *Points, int first_seg, int second_seg, double x, double y, struct seg_intersections *si)
Definition dgraph.c:111
int pg_existsedge(struct planar_graph *pg, int v1, int v2)
Definition dgraph.c:376
void sort_intersection_list(struct seg_intersection_list *il)
Definition dgraph.c:142
void pg_addedge(struct planar_graph *pg, int v1, int v2)
Definition dgraph.c:410
double get_epsilon(struct line_pnts *Points)
Definition dgraph.c:184
struct planar_graph * pg_create_struct(int n, int e)
Definition dgraph.c:346
void destroy_si_struct(struct seg_intersections *si)
Definition dgraph.c:77
int compare(const void *a, const void *b)
Definition dgraph.c:168
void pg_destroy_struct(struct planar_graph *pg)
Definition dgraph.c:362
struct seg_intersections * find_all_intersections(const struct line_pnts *Points)
Definition dgraph.c:209
struct planar_graph * pg_create(const struct line_pnts *Points)
Definition dgraph.c:444
void pg_addedge1(struct pg_vertex *v, struct pg_edge *e)
Definition dgraph.c:399
#define min(x, y)
Definition draw2.c:29
int segment_intersection_2d(double ax1, double ay1, double ax2, double ay2, double bx1, double by1, double bx2, double by2, double *x1, double *y1, double *x2, double *y2)
#define FEQUAL(X, Y, TOL)
Definition e_intersect.h:5
#define GRASS_EPSILON
Definition gis.h:178
#define MAX(a, b)
Definition gis.h:148
#define _(str)
Definition glocale.h:10
int count
double b
Definition r_raster.c:39
double t
Definition r_raster.c:39
Feature geometry info - coordinates.
double * y
Array of Y coordinates.
double * x
Array of X coordinates.
int n_points
Number of points.
char winding_left
Definition dgraph.h:11
int v1
Definition dgraph.h:7
int v2
Definition dgraph.h:8
char winding_right
Definition dgraph.h:12
char visited_right
Definition dgraph.h:10
char visited_left
Definition dgraph.h:9
int ecount
Definition dgraph.h:18
struct pg_edge ** edges
Definition dgraph.h:20
int eallocated
Definition dgraph.h:19
int ecount
Definition dgraph.h:27
struct pg_edge * e
Definition dgraph.h:29
int eallocated
Definition dgraph.h:28
struct pg_vertex * v
Definition dgraph.h:26
int vcount
Definition dgraph.h:25
#define x