GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-36359e2344
Vlib/snap.c
Go to the documentation of this file.
1 /*!
2  * \file lib/vector/Vlib/snap.c
3  *
4  * \brief Vector library - Clean vector map (snap lines)
5  *
6  * Higher level functions for reading/writing/manipulating vectors.
7  *
8  * (C) 2001-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 Radim Blazek
14  * \author update to GRASS 7 Markus Metz
15  */
16 
17 #include <stdlib.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <math.h>
22 #include <grass/vector.h>
23 #include <grass/glocale.h>
24 #include <grass/kdtree.h>
25 
26 /* translate segment to box and back */
27 #define X1W 0x01 /* x1 is West, x2 East */
28 #define Y1S 0x02 /* y1 is South, y2 North */
29 #define Z1B 0x04 /* z1 is Bottom, z2 Top */
30 
31 /* Vertex */
32 typedef struct {
33  double x, y, z;
34  int anchor; /* 0 - anchor, do not snap this point, that means snap others to
35  this */
36  /* >0 - index of anchor to which snap this point */
37  /* -1 - init value */
38 } XPNT;
39 
40 typedef struct {
41  int anchor;
42  double along;
43 } NEW;
44 
45 /* for qsort */
46 static int sort_new(const void *pa, const void *pb)
47 {
48  NEW *p1 = (NEW *)pa;
49  NEW *p2 = (NEW *)pb;
50 
51  return (p1->along < p2->along ? -1 : (p1->along > p2->along));
52 
53  /*
54  if (p1->along < p2->along)
55  return -1;
56  if (p1->along > p2->along)
57  return 1;
58  return 1;
59  */
60 }
61 
62 typedef struct {
63  double x, y, z, along;
64 } NEW2;
65 
66 /* for qsort */
67 static int sort_new2(const void *pa, const void *pb)
68 {
69  NEW2 *p1 = (NEW2 *)pa;
70  NEW2 *p2 = (NEW2 *)pb;
71 
72  return (p1->along < p2->along ? -1 : (p1->along > p2->along));
73 }
74 
75 /* This function is called by RTreeSearch() to find a vertex */
76 static int find_item(int id, const struct RTree_Rect *rect UNUSED, void *list)
77 {
78  G_ilist_add((struct ilist *)list, id);
79  return 0;
80 }
81 
82 /* This function is called by RTreeSearch() to add selected node/line/area/isle
83  * to the list */
84 static int add_item(int id, const struct RTree_Rect *rect UNUSED, void *list)
85 {
86  G_ilist_add((struct ilist *)list, id);
87  return 1;
88 }
89 
90 /* This function is called by RTreeSearch() to add selected node/line/area/isle
91  * to the list */
92 static int find_item_box(int id, const struct RTree_Rect *rect, void *list)
93 {
94  struct bound_box box;
95 
96  box.W = rect->boundary[0];
97  box.S = rect->boundary[1];
98  box.B = rect->boundary[2];
99  box.E = rect->boundary[3];
100  box.N = rect->boundary[4];
101  box.T = rect->boundary[5];
102 
103  dig_boxlist_add((struct boxlist *)list, id, &box);
104 
105  return 0;
106 }
107 
108 /* This function is called by RTreeSearch() to add selected node/line/area/isle
109  * to the list */
110 static int add_item_box(int id, const struct RTree_Rect *rect, void *list)
111 {
112  struct bound_box box;
113 
114  box.W = rect->boundary[0];
115  box.S = rect->boundary[1];
116  box.B = rect->boundary[2];
117  box.E = rect->boundary[3];
118  box.N = rect->boundary[4];
119  box.T = rect->boundary[5];
120 
121  dig_boxlist_add((struct boxlist *)list, id, &box);
122 
123  return 1;
124 }
125 
126 static void Vect_snap_lines_list_rtree(struct Map_info *, const struct ilist *,
127  double, struct Map_info *);
128 
129 static void Vect_snap_lines_list_kdtree(struct Map_info *, const struct ilist *,
130  double, struct Map_info *);
131 
132 /*!
133  \brief Snap selected lines to existing vertex in threshold.
134 
135  Snap selected lines to existing vertices of other selected lines.
136  3D snapping is not supported.
137 
138  Lines showing how vertices were snapped may be optionally written to error
139  map. Input map must be opened on level 2 for update at least on
140  GV_BUILD_BASE.
141 
142  As mentioned above, lines are not necessarily snapped to nearest vertex! For
143  example: <pre>
144  |
145  | 1 line 3 is snapped to line 1,
146  | then line 2 is not snapped to common node at lines 1 and 3,
147  because it is already outside of threshold
148  ----------- 3
149 
150  |
151  | 2
152  |
153  </pre>
154 
155  The algorithm selects anchor vertices and snaps non-anchor vertices
156  to these anchors.
157  The distance between anchor vertices is always > threshold.
158  If there is more than one anchor vertex within threshold around a
159  non-anchor vertex, this vertex is snapped to the nearest anchor
160  vertex within threshold.
161 
162  \param Map input map where vertices will be snapped
163  \param List_lines list of lines to snap
164  \param thresh threshold in which snap vertices
165  \param[out] Err vector map where lines representing snap are written or NULL
166 
167  \return void
168  */
169 void Vect_snap_lines_list(struct Map_info *Map, const struct ilist *List_lines,
170  double thresh, struct Map_info *Err)
171 {
172  if (getenv("GRASS_VECTOR_LOWMEM"))
173  Vect_snap_lines_list_rtree(Map, List_lines, thresh, Err);
174  else
175  Vect_snap_lines_list_kdtree(Map, List_lines, thresh, Err);
176 }
177 
178 static void Vect_snap_lines_list_kdtree(struct Map_info *Map,
179  const struct ilist *List_lines,
180  double thresh, struct Map_info *Err)
181 {
182  struct line_pnts *Points, *NPoints;
183  struct line_cats *Cats;
184  int line, ltype, line_idx;
185  double thresh2;
186 
187  int point; /* index in points array */
188  int nsnapped, ncreated; /* number of snapped verices, number of new vertices
189  (on segments) */
190  int apoints, npoints; /* number of allocated points, registered points */
191  XPNT *XPnts; /* Array of points */
192  NEW *New = NULL; /* Array of new points */
193  int anew = 0, nnew; /* allocated new points, number of new points */
194  struct ilist *List;
195  int *Index = NULL; /* indexes of anchors for vertices */
196  int aindex = 0; /* allocated Index */
197 
198  struct kdtree *KDTree;
199  double c[2];
200  double *kdd;
201  int *kduid, kd_found;
202 
203  if (List_lines->n_values < 1)
204  return;
205 
206  Points = Vect_new_line_struct();
207  NPoints = Vect_new_line_struct();
208  Cats = Vect_new_cats_struct();
209  List = Vect_new_list();
210 
211  KDTree = kdtree_create(2, NULL);
212 
213  thresh2 = thresh * thresh;
214 
215  /* Go through all lines in vector, and add each point to structure of points
216  */
217  apoints = 0;
218  point = 1; /* index starts from 1 ! */
219  XPnts = NULL;
220 
221  G_important_message(_("Snap vertices Pass 1: select points"));
222  for (line_idx = 0; line_idx < List_lines->n_values; line_idx++) {
223  int v;
224 
225  G_percent(line_idx, List_lines->n_values, 2);
226 
227  line = List_lines->value[line_idx];
228 
229  G_debug(3, "line = %d", line);
230  if (!Vect_line_alive(Map, line))
231  continue;
232 
233  ltype = Vect_read_line(Map, Points, Cats, line);
234 
235  for (v = 0; v < Points->n_points; v++) {
236 
237  G_debug(3, " vertex v = %d", v);
238 
239  /* coords */
240  c[0] = Points->x[v];
241  c[1] = Points->y[v];
242 
243  if (kdtree_insert(KDTree, c, point, 0)) {
244  /* Add to structure */
245  if ((point - 1) == apoints) {
246  apoints += 10000;
247  XPnts =
248  (XPNT *)G_realloc(XPnts, (apoints + 1) * sizeof(XPNT));
249  }
250  XPnts[point].x = Points->x[v];
251  XPnts[point].y = Points->y[v];
252  XPnts[point].anchor = -1;
253  point++;
254  }
255  }
256  }
257  G_percent(line_idx, List_lines->n_values, 2); /* finish it */
258 
259  npoints = point - 1;
260 
261  /* Go through all registered points and if not yet marked mark it as anchor
262  * and assign this anchor to all not yet marked points in threshold */
263 
264  G_important_message(_("Snap vertices Pass 2: assign anchor vertices"));
265 
266  for (point = 1; point <= npoints; point++) {
267  int i;
268 
269  G_percent(point, npoints, 4);
270 
271  G_debug(3, " point = %d", point);
272 
273  if (XPnts[point].anchor >= 0)
274  continue;
275 
276  XPnts[point].anchor = 0; /* make it anchor */
277 
278  /* Find points in threshold */
279  c[0] = XPnts[point].x;
280  c[1] = XPnts[point].y;
281 
282  Vect_reset_list(List);
283  kd_found = kdtree_dnn(KDTree, c, &kduid, &kdd, thresh, &point);
284  G_debug(4, " %d points in threshold box", kd_found);
285 
286  for (i = 0; i < kd_found; i++) {
287  int pointb;
288  double dx, dy, dist2;
289 
290  pointb = kduid[i];
291  if (pointb == point)
292  continue;
293 
294  dx = XPnts[pointb].x - XPnts[point].x;
295  dy = XPnts[pointb].y - XPnts[point].y;
296  dist2 = dx * dx + dy * dy;
297 
298  if (dist2 > thresh2) /* outside threshold */
299  continue;
300 
301  /* doesn't have an anchor yet */
302  if (XPnts[pointb].anchor == -1) {
303  XPnts[pointb].anchor = point;
304  }
305  else if (XPnts[pointb].anchor >
306  0) { /* check distance to previously assigned anchor */
307  double dist2_a;
308 
309  dx = XPnts[XPnts[pointb].anchor].x - XPnts[pointb].x;
310  dy = XPnts[XPnts[pointb].anchor].y - XPnts[pointb].y;
311  dist2_a = dx * dx + dy * dy;
312 
313  /* replace old anchor */
314  if (dist2 < dist2_a) {
315  XPnts[pointb].anchor = point;
316  }
317  }
318  }
319  if (kd_found) {
320  G_free(kdd);
321  G_free(kduid);
322  }
323  }
324 
325  /* Go through all lines and:
326  * 1) for all vertices: if not anchor snap it to its anchor
327  * 2) for all segments: snap it to all anchors in threshold (except
328  * anchors of vertices of course) */
329 
330  nsnapped = ncreated = 0;
331 
332  G_important_message(_("Snap vertices Pass 3: snap to assigned points"));
333 
334  for (line_idx = 0; line_idx < List_lines->n_values; line_idx++) {
335  int v, spoint, anchor;
336  int changed = 0;
337  double kddist;
338 
339  G_percent(line_idx, List_lines->n_values, 2);
340 
341  line = List_lines->value[line_idx];
342 
343  G_debug(3, "line = %d", line);
344  if (!Vect_line_alive(Map, line))
345  continue;
346 
347  ltype = Vect_read_line(Map, Points, Cats, line);
348 
349  if (Points->n_points >= aindex) {
350  aindex = Points->n_points;
351  Index = (int *)G_realloc(Index, aindex * sizeof(int));
352  }
353 
354  /* Snap all vertices */
355  G_debug(3, "Snap all vertices");
356  for (v = 0; v < Points->n_points; v++) {
357  /* Box */
358  c[0] = Points->x[v];
359  c[1] = Points->y[v];
360 
361  /* Find point ( should always find one point ) */
362  Vect_reset_list(List);
363 
364  spoint = -1;
365  kdtree_knn(KDTree, c, &spoint, &kddist, 1, NULL);
366  if (spoint == -1)
367  G_fatal_error("Point not in KD Tree");
368 
369  anchor = XPnts[spoint].anchor;
370 
371  if (anchor > 0) { /* to be snapped */
372  Points->x[v] = XPnts[anchor].x;
373  Points->y[v] = XPnts[anchor].y;
374  nsnapped++;
375  changed = 1;
376  Index[v] = anchor; /* point on new location */
377  }
378  else {
379  Index[v] = spoint; /* old point */
380  }
381  }
382 
383  /* New points */
384  Vect_reset_line(NPoints);
385 
386  /* Snap all segments to anchors in threshold */
387  G_debug(3, "Snap all segments");
388  for (v = 0; v < Points->n_points - 1; v++) {
389  int i;
390  double x1, x2, y1, y2, xmin, xmax, ymin, ymax;
391  double rc[4];
392 
393  G_debug(3, " segment = %d end anchors : %d %d", v, Index[v],
394  Index[v + 1]);
395 
396  x1 = Points->x[v];
397  x2 = Points->x[v + 1];
398  y1 = Points->y[v];
399  y2 = Points->y[v + 1];
400 
401  Vect_append_point(NPoints, Points->x[v], Points->y[v],
402  Points->z[v]);
403 
404  /* Box */
405  if (x1 <= x2) {
406  xmin = x1;
407  xmax = x2;
408  }
409  else {
410  xmin = x2;
411  xmax = x1;
412  }
413  if (y1 <= y2) {
414  ymin = y1;
415  ymax = y2;
416  }
417  else {
418  ymin = y2;
419  ymax = y1;
420  }
421 
422  /* Find points */
423  Vect_reset_list(List);
424  G_debug(3, " search anchors for segment %g,%g to %g,%g", x1, y1,
425  x2, y2);
426  /* distance search: circle around midpoint encompassing
427  * endpoints
428  * box search: box encompassing endpoints,
429  * smaller than corresponding circle */
430  rc[0] = xmin - thresh * 2;
431  rc[1] = ymin - thresh * 2;
432  rc[2] = xmax + thresh * 2;
433  rc[3] = ymax + thresh * 2;
434 
435  kd_found = kdtree_rnn(KDTree, rc, &kduid, NULL);
436 
437  G_debug(3, " %d points in box", kd_found);
438 
439  /* Snap to anchor in threshold different from end points */
440  nnew = 0;
441  for (i = 0; i < kd_found; i++) {
442  double dist2, along;
443  int status;
444 
445  spoint = kduid[i];
446  G_debug(4, " spoint = %d anchor = %d", spoint,
447  XPnts[spoint].anchor);
448 
449  if (spoint == Index[v] || spoint == Index[v + 1])
450  continue; /* end point */
451  if (XPnts[spoint].anchor > 0)
452  continue; /* point is not anchor */
453 
454  /* Check the distance */
456  XPnts[spoint].x, XPnts[spoint].y, 0, x1, y1, 0, x2, y2, 0,
457  0, NULL, NULL, NULL, &along, &status);
458 
459  G_debug(4, " distance = %lf", sqrt(dist2));
460 
461  if (status == 0 && dist2 <= thresh2) {
462  G_debug(4, " anchor in thresh, along = %lf", along);
463 
464  if (nnew == anew) {
465  anew += 100;
466  New = (NEW *)G_realloc(New, anew * sizeof(NEW));
467  }
468  New[nnew].anchor = spoint;
469  New[nnew].along = along;
470  nnew++;
471  }
472  }
473  if (kd_found) {
474  G_free(kduid);
475  }
476  G_debug(3, " nnew = %d", nnew);
477  /* insert new vertices */
478  if (nnew > 0) {
479  /* sort by distance along the segment */
480  qsort(New, sizeof(char) * nnew, sizeof(NEW), sort_new);
481 
482  for (i = 0; i < nnew; i++) {
483  anchor = New[i].anchor;
484  /* Vect_line_insert_point ( Points, ++v, XPnts[anchor].x,
485  * XPnts[anchor].y, 0); */
486  Vect_append_point(NPoints, XPnts[anchor].x, XPnts[anchor].y,
487  0);
488  ncreated++;
489  }
490  changed = 1;
491  }
492  }
493 
494  /* append end point */
495  v = Points->n_points - 1;
496  Vect_append_point(NPoints, Points->x[v], Points->y[v], Points->z[v]);
497 
498  if (changed) { /* rewrite the line */
499  Vect_line_prune(NPoints); /* remove duplicates */
500  if (NPoints->n_points > 1 || !(ltype & GV_LINES)) {
501  Vect_rewrite_line(Map, line, ltype, NPoints, Cats);
502  }
503  else {
504  Vect_delete_line(Map, line);
505  }
506  if (Err) {
507  Vect_write_line(Err, ltype, Points, Cats);
508  }
509  }
510  } /* for each line */
511  G_percent(line_idx, List_lines->n_values, 2); /* finish it */
512 
513  Vect_destroy_line_struct(Points);
514  Vect_destroy_line_struct(NPoints);
516  G_free(XPnts);
517  G_free(Index);
518  G_free(New);
519  kdtree_destroy(KDTree);
520 
521  G_verbose_message(_("Snapped vertices: %d"), nsnapped);
522  G_verbose_message(_("New vertices: %d"), ncreated);
523 }
524 
525 static void Vect_snap_lines_list_rtree(struct Map_info *Map,
526  const struct ilist *List_lines,
527  double thresh, struct Map_info *Err)
528 {
529  struct line_pnts *Points, *NPoints;
530  struct line_cats *Cats;
531  int line, ltype, line_idx;
532  double thresh2;
533 
534  int point; /* index in points array */
535  int nsnapped, ncreated; /* number of snapped verices, number of new vertices
536  (on segments) */
537  int apoints, npoints; /* number of allocated points, registered points */
538  XPNT *XPnts; /* Array of points */
539  NEW *New = NULL; /* Array of new points */
540  int anew = 0, nnew; /* allocated new points , number of new points */
541  struct ilist *List;
542  int *Index = NULL; /* indexes of anchors for vertices */
543  int aindex = 0; /* allocated Index */
544 
545  struct RTree *RTree;
546  int rtreefd = -1;
547  static struct RTree_Rect rect;
548  static int rect_init = 0;
549 
550  if (!rect_init) {
551  rect.boundary = G_malloc(6 * sizeof(RectReal));
552  rect_init = 6;
553  }
554 
555  if (List_lines->n_values < 1)
556  return;
557 
558  Points = Vect_new_line_struct();
559  NPoints = Vect_new_line_struct();
560  Cats = Vect_new_cats_struct();
561  List = Vect_new_list();
562  if (getenv("GRASS_VECTOR_LOWMEM")) {
563  char *filename = G_tempfile();
564 
565  rtreefd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
566  remove(filename);
567  }
568  RTree = RTreeCreateTree(rtreefd, 0, 2);
569 
570  thresh2 = thresh * thresh;
571 
572  /* Go through all lines in vector, and add each point to structure of points
573  */
574  apoints = 0;
575  point = 1; /* index starts from 1 ! */
576  XPnts = NULL;
577 
578  G_important_message(_("Snap vertices Pass 1: select points"));
579  for (line_idx = 0; line_idx < List_lines->n_values; line_idx++) {
580  int v;
581 
582  G_percent(line_idx, List_lines->n_values, 2);
583 
584  line = List_lines->value[line_idx];
585 
586  G_debug(3, "line = %d", line);
587  if (!Vect_line_alive(Map, line))
588  continue;
589 
590  ltype = Vect_read_line(Map, Points, Cats, line);
591 
592  for (v = 0; v < Points->n_points; v++) {
593  G_debug(3, " vertex v = %d", v);
594 
595  /* Box */
596  rect.boundary[0] = Points->x[v];
597  rect.boundary[3] = Points->x[v];
598  rect.boundary[1] = Points->y[v];
599  rect.boundary[4] = Points->y[v];
600  rect.boundary[2] = 0;
601  rect.boundary[5] = 0;
602 
603  /* Already registered ? */
604  Vect_reset_list(List);
605  RTreeSearch(RTree, &rect, find_item, List);
606  G_debug(3, "List : nvalues = %d", List->n_values);
607 
608  if (List->n_values == 0) { /* Not found */
609  /* Add to tree and to structure */
610  RTreeInsertRect(&rect, point, RTree);
611  if ((point - 1) == apoints) {
612  apoints += 10000;
613  XPnts =
614  (XPNT *)G_realloc(XPnts, (apoints + 1) * sizeof(XPNT));
615  }
616  XPnts[point].x = Points->x[v];
617  XPnts[point].y = Points->y[v];
618  XPnts[point].anchor = -1;
619  point++;
620  }
621  }
622  }
623  G_percent(line_idx, List_lines->n_values, 2); /* finish it */
624 
625  npoints = point - 1;
626 
627  /* Go through all registered points and if not yet marked mark it as anchor
628  * and assign this anchor to all not yet marked points in threshold */
629 
630  G_important_message(_("Snap vertices Pass 2: assign anchor vertices"));
631 
632  for (point = 1; point <= npoints; point++) {
633  int i;
634 
635  G_percent(point, npoints, 4);
636 
637  G_debug(3, " point = %d", point);
638 
639  if (XPnts[point].anchor >= 0)
640  continue;
641 
642  XPnts[point].anchor = 0; /* make it anchor */
643 
644  /* Find points in threshold */
645  rect.boundary[0] = XPnts[point].x - thresh;
646  rect.boundary[3] = XPnts[point].x + thresh;
647  rect.boundary[1] = XPnts[point].y - thresh;
648  rect.boundary[4] = XPnts[point].y + thresh;
649  rect.boundary[2] = 0;
650  rect.boundary[5] = 0;
651 
652  Vect_reset_list(List);
653  RTreeSearch(RTree, &rect, add_item, List);
654  G_debug(4, " %d points in threshold box", List->n_values);
655 
656  for (i = 0; i < List->n_values; i++) {
657  int pointb;
658  double dx, dy, dist2;
659 
660  pointb = List->value[i];
661  if (pointb == point)
662  continue;
663 
664  dx = XPnts[pointb].x - XPnts[point].x;
665  dy = XPnts[pointb].y - XPnts[point].y;
666  dist2 = dx * dx + dy * dy;
667 
668  if (dist2 > thresh2) /* outside threshold */
669  continue;
670 
671  /* doesn't have an anchor yet */
672  if (XPnts[pointb].anchor == -1) {
673  XPnts[pointb].anchor = point;
674  }
675  else if (XPnts[pointb].anchor >
676  0) { /* check distance to previously assigned anchor */
677  double dist2_a;
678 
679  dx = XPnts[XPnts[pointb].anchor].x - XPnts[pointb].x;
680  dy = XPnts[XPnts[pointb].anchor].y - XPnts[pointb].y;
681  dist2_a = dx * dx + dy * dy;
682 
683  /* replace old anchor */
684  if (dist2 < dist2_a) {
685  XPnts[pointb].anchor = point;
686  }
687  }
688  }
689  }
690 
691  /* Go through all lines and:
692  * 1) for all vertices: if not anchor snap it to its anchor
693  * 2) for all segments: snap it to all anchors in threshold (except
694  * anchors of vertices of course) */
695 
696  nsnapped = ncreated = 0;
697 
698  G_important_message(_("Snap vertices Pass 3: snap to assigned points"));
699 
700  for (line_idx = 0; line_idx < List_lines->n_values; line_idx++) {
701  int v, spoint, anchor;
702  int changed = 0;
703 
704  G_percent(line_idx, List_lines->n_values, 2);
705 
706  line = List_lines->value[line_idx];
707 
708  G_debug(3, "line = %d", line);
709  if (!Vect_line_alive(Map, line))
710  continue;
711 
712  ltype = Vect_read_line(Map, Points, Cats, line);
713 
714  if (Points->n_points >= aindex) {
715  aindex = Points->n_points;
716  Index = (int *)G_realloc(Index, aindex * sizeof(int));
717  }
718 
719  /* Snap all vertices */
720  for (v = 0; v < Points->n_points; v++) {
721  /* Box */
722  rect.boundary[0] = Points->x[v];
723  rect.boundary[3] = Points->x[v];
724  rect.boundary[1] = Points->y[v];
725  rect.boundary[4] = Points->y[v];
726  rect.boundary[2] = 0;
727  rect.boundary[5] = 0;
728 
729  /* Find point ( should always find one point ) */
730  Vect_reset_list(List);
731 
732  RTreeSearch(RTree, &rect, add_item, List);
733 
734  spoint = List->value[0];
735  anchor = XPnts[spoint].anchor;
736 
737  if (anchor > 0) { /* to be snapped */
738  Points->x[v] = XPnts[anchor].x;
739  Points->y[v] = XPnts[anchor].y;
740  nsnapped++;
741  changed = 1;
742  Index[v] = anchor; /* point on new location */
743  }
744  else {
745  Index[v] = spoint; /* old point */
746  }
747  }
748 
749  /* New points */
750  Vect_reset_line(NPoints);
751 
752  /* Snap all segments to anchors in threshold */
753  for (v = 0; v < Points->n_points - 1; v++) {
754  int i;
755  double x1, x2, y1, y2, xmin, xmax, ymin, ymax;
756 
757  G_debug(3, " segment = %d end anchors : %d %d", v, Index[v],
758  Index[v + 1]);
759 
760  x1 = Points->x[v];
761  x2 = Points->x[v + 1];
762  y1 = Points->y[v];
763  y2 = Points->y[v + 1];
764 
765  Vect_append_point(NPoints, Points->x[v], Points->y[v],
766  Points->z[v]);
767 
768  /* Box */
769  if (x1 <= x2) {
770  xmin = x1;
771  xmax = x2;
772  }
773  else {
774  xmin = x2;
775  xmax = x1;
776  }
777  if (y1 <= y2) {
778  ymin = y1;
779  ymax = y2;
780  }
781  else {
782  ymin = y2;
783  ymax = y1;
784  }
785 
786  rect.boundary[0] = xmin - thresh;
787  rect.boundary[3] = xmax + thresh;
788  rect.boundary[1] = ymin - thresh;
789  rect.boundary[4] = ymax + thresh;
790  rect.boundary[2] = 0;
791  rect.boundary[5] = 0;
792 
793  /* Find points */
794  Vect_reset_list(List);
795  RTreeSearch(RTree, &rect, add_item, List);
796 
797  G_debug(3, " %d points in box", List->n_values);
798 
799  /* Snap to anchor in threshold different from end points */
800  nnew = 0;
801  for (i = 0; i < List->n_values; i++) {
802  double dist2, along;
803  int status;
804 
805  spoint = List->value[i];
806  G_debug(4, " spoint = %d anchor = %d", spoint,
807  XPnts[spoint].anchor);
808 
809  if (spoint == Index[v] || spoint == Index[v + 1])
810  continue; /* end point */
811  if (XPnts[spoint].anchor > 0)
812  continue; /* point is not anchor */
813 
814  /* Check the distance */
816  XPnts[spoint].x, XPnts[spoint].y, 0, x1, y1, 0, x2, y2, 0,
817  0, NULL, NULL, NULL, &along, &status);
818 
819  G_debug(4, " distance = %lf", sqrt(dist2));
820 
821  if (status == 0 && dist2 <= thresh2) {
822  G_debug(4, " anchor in thresh, along = %lf", along);
823 
824  if (nnew == anew) {
825  anew += 100;
826  New = (NEW *)G_realloc(New, anew * sizeof(NEW));
827  }
828  New[nnew].anchor = spoint;
829  New[nnew].along = along;
830  nnew++;
831  }
832  }
833  G_debug(3, " nnew = %d", nnew);
834  /* insert new vertices */
835  if (nnew > 0) {
836  /* sort by distance along the segment */
837  qsort(New, sizeof(char) * nnew, sizeof(NEW), sort_new);
838 
839  for (i = 0; i < nnew; i++) {
840  anchor = New[i].anchor;
841  /* Vect_line_insert_point ( Points, ++v, XPnts[anchor].x,
842  * XPnts[anchor].y, 0); */
843  Vect_append_point(NPoints, XPnts[anchor].x, XPnts[anchor].y,
844  0);
845  ncreated++;
846  }
847  changed = 1;
848  }
849  }
850 
851  /* append end point */
852  v = Points->n_points - 1;
853  Vect_append_point(NPoints, Points->x[v], Points->y[v], Points->z[v]);
854 
855  if (changed) { /* rewrite the line */
856  Vect_line_prune(NPoints); /* remove duplicates */
857  if (NPoints->n_points > 1 || !(ltype & GV_LINES)) {
858  Vect_rewrite_line(Map, line, ltype, NPoints, Cats);
859  }
860  else {
861  Vect_delete_line(Map, line);
862  }
863  if (Err) {
864  Vect_write_line(Err, ltype, Points, Cats);
865  }
866  }
867  } /* for each line */
868  G_percent(line_idx, List_lines->n_values, 2); /* finish it */
869 
870  Vect_destroy_line_struct(Points);
871  Vect_destroy_line_struct(NPoints);
873  G_free(XPnts);
874  G_free(Index);
875  G_free(New);
877  if (rtreefd >= 0)
878  close(rtreefd);
879 
880  G_verbose_message(_("Snapped vertices: %d"), nsnapped);
881  G_verbose_message(_("New vertices: %d"), ncreated);
882 }
883 
884 /*!
885  \brief Snap lines in vector map to existing vertex in threshold.
886 
887  For details see Vect_snap_lines_list()
888 
889  \param[in] Map input map where vertices will be snapped
890  \param[in] type type of lines to snap
891  \param[in] thresh threshold in which snap vertices
892  \param[out] Err vector map where lines representing snap are written or NULL
893 
894  \return void
895  */
896 void Vect_snap_lines(struct Map_info *Map, int type, double thresh,
897  struct Map_info *Err)
898 {
899  int line, nlines, ltype;
900  struct ilist *List;
901 
902  List = Vect_new_list();
903 
904  nlines = Vect_get_num_lines(Map);
905 
906  G_important_message(_("Reading features..."));
907  for (line = 1; line <= nlines; line++) {
908  G_debug(3, "line = %d", line);
909 
910  if (!Vect_line_alive(Map, line))
911  continue;
912 
913  ltype = Vect_read_line(Map, NULL, NULL, line);
914 
915  if (!(ltype & type))
916  continue;
917 
918  G_ilist_add(List, line);
919  }
920 
921  Vect_snap_lines_list(Map, List, thresh, Err);
922 
923  Vect_destroy_list(List);
924 
925  return;
926 }
927 
928 /*!
929  \brief Snap a line to reference lines in Map with threshold.
930 
931  3D snapping is supported. The line to snap and the reference lines
932  can but do not need to be in different vector maps.
933 
934  Vect_snap_line() uses less memory, but is slower than
935  Vect_snap_lines_list()
936 
937  For details on snapping, see Vect_snap_lines_list()
938 
939  \param[in] Map input map with reference lines
940  \param[in] reflist list of reference lines
941  \param[in,out] Points line points to snap
942  \param[in] thresh threshold in which to snap vertices
943  \param[in] with_z 2D or 3D snapping
944  \param[in,out] nsnapped number of snapped vertices
945  \param[in,out] ncreated number of new vertices (on segments)
946 
947  \return 1 if line was changed, otherwise 0
948  */
949 int Vect_snap_line(struct Map_info *Map, struct ilist *reflist,
950  struct line_pnts *Points, double thresh, int with_z,
951  int *nsnapped, int *ncreated)
952 {
953  struct line_pnts *LPoints, *NPoints;
954  struct line_cats *Cats;
955  int i, v, line, nlines;
956  int changed;
957  double thresh2;
958 
959  int point; /* index in points array */
960  int segment; /* index in segments array */
961  int asegments; /* number of allocated segments */
962  char *XSegs = NULL; /* Array of segments */
963  NEW2 *New = NULL; /* Array of new points */
964  int anew = 0, nnew; /* allocated new points , number of new points */
965  struct boxlist *List;
966 
967  struct RTree *pnt_tree, /* spatial index for reference points */
968  *seg_tree; /* spatial index for reference segments */
969  struct RTree_Rect rect;
970 
971  rect.boundary = G_malloc(6 * sizeof(RectReal));
972  rect.boundary[0] = 0;
973  rect.boundary[1] = 0;
974  rect.boundary[2] = 0;
975  rect.boundary[3] = 0;
976  rect.boundary[4] = 0;
977  rect.boundary[5] = 0;
978 
979  changed = 0;
980  if (nsnapped)
981  *nsnapped = 0;
982  if (ncreated)
983  *ncreated = 0;
984 
985  point = Points->n_points;
986  Vect_line_prune(Points);
987  if (point != Points->n_points)
988  changed = 1;
989 
990  nlines = reflist->n_values;
991  if (nlines < 1)
992  return changed;
993 
994  LPoints = Vect_new_line_struct();
995  NPoints = Vect_new_line_struct();
996  Cats = Vect_new_cats_struct();
997  List = Vect_new_boxlist(1);
998  with_z = (with_z != 0);
999  pnt_tree = RTreeCreateTree(-1, 0, 2 + with_z);
1000  RTreeSetOverflow(pnt_tree, 0);
1001  seg_tree = RTreeCreateTree(-1, 0, 2 + with_z);
1002  RTreeSetOverflow(seg_tree, 0);
1003 
1004  thresh2 = thresh * thresh;
1005 
1006  point = segment = 1; /* index starts from 1 ! */
1007  asegments = 0;
1008 
1009  /* Add all vertices and all segments of all reference lines
1010  * to spatial indices */
1011  nlines = reflist->n_values;
1012  for (i = 0; i < nlines; i++) {
1013 
1014  line = reflist->value[i];
1015 
1016  G_debug(3, "line = %d", line);
1017  if (!Vect_line_alive(Map, line))
1018  continue;
1019 
1020  Vect_read_line(Map, LPoints, Cats, line);
1021  Vect_line_prune(LPoints);
1022 
1023  for (v = 0; v < LPoints->n_points; v++) {
1024  G_debug(3, " vertex v = %d", v);
1025 
1026  /* Box */
1027  rect.boundary[0] = LPoints->x[v];
1028  rect.boundary[3] = LPoints->x[v];
1029  rect.boundary[1] = LPoints->y[v];
1030  rect.boundary[4] = LPoints->y[v];
1031  if (with_z) {
1032  rect.boundary[2] = LPoints->z[v];
1033  rect.boundary[5] = LPoints->z[v];
1034  }
1035 
1036  /* Already registered ? */
1037  Vect_reset_boxlist(List);
1038  RTreeSearch(pnt_tree, &rect, find_item_box, (void *)List);
1039  G_debug(3, "List : nvalues = %d", List->n_values);
1040 
1041  if (List->n_values == 0) { /* Not found */
1042 
1043  /* Add to points tree */
1044  RTreeInsertRect(&rect, point, pnt_tree);
1045 
1046  point++;
1047  }
1048 
1049  /* reference segments */
1050  if (v) {
1051  char sides = 0;
1052 
1053  /* Box */
1054  if (LPoints->x[v - 1] < LPoints->x[v]) {
1055  rect.boundary[0] = LPoints->x[v - 1];
1056  rect.boundary[3] = LPoints->x[v];
1057  sides |= X1W;
1058  }
1059  else {
1060  rect.boundary[0] = LPoints->x[v];
1061  rect.boundary[3] = LPoints->x[v - 1];
1062  }
1063  if (LPoints->y[v - 1] < LPoints->y[v]) {
1064  rect.boundary[1] = LPoints->y[v - 1];
1065  rect.boundary[4] = LPoints->y[v];
1066  sides |= Y1S;
1067  }
1068  else {
1069  rect.boundary[1] = LPoints->y[v];
1070  rect.boundary[4] = LPoints->y[v - 1];
1071  }
1072  if (LPoints->z[v - 1] < LPoints->z[v]) {
1073  rect.boundary[2] = LPoints->z[v - 1];
1074  rect.boundary[5] = LPoints->z[v];
1075  sides |= Z1B;
1076  }
1077  else {
1078  rect.boundary[2] = LPoints->z[v];
1079  rect.boundary[5] = LPoints->z[v - 1];
1080  }
1081 
1082  /* do not check for duplicates, too costly
1083  * because different segments can have identical boxes */
1084  RTreeInsertRect(&rect, segment, seg_tree);
1085 
1086  if ((segment - 1) == asegments) {
1087  asegments += 1000;
1088  XSegs = (char *)G_realloc(XSegs,
1089  (asegments + 1) * sizeof(char));
1090  }
1091  XSegs[segment] = sides;
1092  segment++;
1093  }
1094  }
1095  }
1096 
1097  /* go through all vertices of the line to snap */
1098  /* find nearest reference vertex */
1099  for (v = 0; v < Points->n_points; v++) {
1100  double dist2, tmpdist2;
1101  double x, y, z;
1102 
1103  dist2 = thresh2 + thresh2;
1104  x = Points->x[v];
1105  y = Points->y[v];
1106  z = Points->z[v];
1107 
1108  /* Box */
1109  rect.boundary[0] = Points->x[v] - thresh;
1110  rect.boundary[3] = Points->x[v] + thresh;
1111  rect.boundary[1] = Points->y[v] - thresh;
1112  rect.boundary[4] = Points->y[v] + thresh;
1113  if (with_z) {
1114  rect.boundary[2] = Points->z[v] - thresh;
1115  rect.boundary[5] = Points->z[v] + thresh;
1116  }
1117 
1118  Vect_reset_boxlist(List);
1119 
1120  RTreeSearch(pnt_tree, &rect, add_item_box, (void *)List);
1121 
1122  for (i = 0; i < List->n_values; i++) {
1123  double dx = List->box[i].E - Points->x[v];
1124  double dy = List->box[i].N - Points->y[v];
1125  double dz = 0;
1126 
1127  if (with_z)
1128  dz = List->box[i].T - Points->z[v];
1129 
1130  tmpdist2 = dx * dx + dy * dy + dz * dz;
1131 
1132  if (tmpdist2 < dist2) {
1133  dist2 = tmpdist2;
1134 
1135  x = List->box[i].E;
1136  y = List->box[i].N;
1137  z = List->box[i].T;
1138  }
1139  }
1140 
1141  if (dist2 <= thresh2 && dist2 > 0) {
1142  Points->x[v] = x;
1143  Points->y[v] = y;
1144  Points->z[v] = z;
1145 
1146  changed = 1;
1147  if (nsnapped)
1148  (*nsnapped)++;
1149  }
1150  }
1151 
1152  /* go through all vertices of the line to snap */
1153  /* find nearest reference segment */
1154  for (v = 0; v < Points->n_points; v++) {
1155  double dist2, tmpdist2;
1156  double x, y, z;
1157 
1158  dist2 = thresh2 + thresh2;
1159  x = Points->x[v];
1160  y = Points->y[v];
1161  z = Points->z[v];
1162 
1163  /* Box */
1164  rect.boundary[0] = Points->x[v] - thresh;
1165  rect.boundary[3] = Points->x[v] + thresh;
1166  rect.boundary[1] = Points->y[v] - thresh;
1167  rect.boundary[4] = Points->y[v] + thresh;
1168  if (with_z) {
1169  rect.boundary[2] = Points->z[v] - thresh;
1170  rect.boundary[5] = Points->z[v] + thresh;
1171  }
1172 
1173  Vect_reset_boxlist(List);
1174 
1175  RTreeSearch(seg_tree, &rect, add_item_box, (void *)List);
1176 
1177  for (i = 0; i < List->n_values; i++) {
1178  double x1, y1, z1, x2, y2, z2;
1179  double tmpx, tmpy, tmpz;
1180  int status;
1181 
1182  segment = List->id[i];
1183 
1184  if (XSegs[segment] & X1W) {
1185  x1 = List->box[i].W;
1186  x2 = List->box[i].E;
1187  }
1188  else {
1189  x1 = List->box[i].E;
1190  x2 = List->box[i].W;
1191  }
1192  if (XSegs[segment] & Y1S) {
1193  y1 = List->box[i].S;
1194  y2 = List->box[i].N;
1195  }
1196  else {
1197  y1 = List->box[i].N;
1198  y2 = List->box[i].S;
1199  }
1200  if (XSegs[segment] & Z1B) {
1201  z1 = List->box[i].B;
1202  z2 = List->box[i].T;
1203  }
1204  else {
1205  z1 = List->box[i].T;
1206  z2 = List->box[i].B;
1207  }
1208 
1209  /* Check the distance */
1210  tmpdist2 = dig_distance2_point_to_line(
1211  Points->x[v], Points->y[v], Points->z[v], x1, y1, z1, x2, y2,
1212  z2, with_z, &tmpx, &tmpy, &tmpz, NULL, &status);
1213 
1214  if (tmpdist2 < dist2 && status == 0) {
1215  dist2 = tmpdist2;
1216 
1217  x = tmpx;
1218  y = tmpy;
1219  z = tmpz;
1220  }
1221  }
1222 
1223  if (dist2 <= thresh2 && dist2 > 0) {
1224  Points->x[v] = x;
1225  Points->y[v] = y;
1226  Points->z[v] = z;
1227 
1228  changed = 1;
1229  if (nsnapped)
1230  (*nsnapped)++;
1231  }
1232  }
1233 
1234  RTreeDestroyTree(seg_tree);
1235  G_free(XSegs);
1236 
1237  /* go through all segments of the line to snap */
1238  /* find nearest reference vertex, add this vertex */
1239  for (v = 0; v < Points->n_points - 1; v++) {
1240  double x1, x2, y1, y2, z1, z2;
1241  double xmin, xmax, ymin, ymax, zmin, zmax;
1242 
1243  x1 = Points->x[v];
1244  x2 = Points->x[v + 1];
1245  y1 = Points->y[v];
1246  y2 = Points->y[v + 1];
1247  if (with_z) {
1248  z1 = Points->z[v];
1249  z2 = Points->z[v + 1];
1250  }
1251  else {
1252  z1 = z2 = 0;
1253  }
1254 
1255  Vect_append_point(NPoints, Points->x[v], Points->y[v], Points->z[v]);
1256 
1257  /* Box */
1258  if (x1 <= x2) {
1259  xmin = x1;
1260  xmax = x2;
1261  }
1262  else {
1263  xmin = x2;
1264  xmax = x1;
1265  }
1266  if (y1 <= y2) {
1267  ymin = y1;
1268  ymax = y2;
1269  }
1270  else {
1271  ymin = y2;
1272  ymax = y1;
1273  }
1274  if (z1 <= z2) {
1275  zmin = z1;
1276  zmax = z2;
1277  }
1278  else {
1279  zmin = z2;
1280  zmax = z1;
1281  }
1282 
1283  rect.boundary[0] = xmin - thresh;
1284  rect.boundary[3] = xmax + thresh;
1285  rect.boundary[1] = ymin - thresh;
1286  rect.boundary[4] = ymax + thresh;
1287  rect.boundary[2] = zmin - thresh;
1288  rect.boundary[5] = zmax + thresh;
1289 
1290  /* Find points */
1291  Vect_reset_boxlist(List);
1292  RTreeSearch(pnt_tree, &rect, add_item_box, (void *)List);
1293 
1294  G_debug(3, " %d points in box", List->n_values);
1295 
1296  /* Snap to vertex in threshold different from end points */
1297  nnew = 0;
1298  for (i = 0; i < List->n_values; i++) {
1299  double dist2, along;
1300  int status;
1301 
1302  if (!with_z)
1303  List->box[i].T = 0;
1304 
1305  if (Points->x[v] == List->box[i].E &&
1306  Points->y[v] == List->box[i].N &&
1307  Points->z[v] == List->box[i].T)
1308  continue; /* start point */
1309 
1310  if (Points->x[v + 1] == List->box[i].E &&
1311  Points->y[v + 1] == List->box[i].N &&
1312  Points->z[v + 1] == List->box[i].T)
1313  continue; /* end point */
1314 
1315  /* Check the distance */
1317  List->box[i].E, List->box[i].N, List->box[i].T, x1, y1, z1, x2,
1318  y2, z2, with_z, NULL, NULL, NULL, &along, &status);
1319 
1320  if (dist2 <= thresh2 && status == 0) {
1321  G_debug(4, " anchor in thresh, along = %lf", along);
1322 
1323  if (nnew == anew) {
1324  anew += 100;
1325  New = (NEW2 *)G_realloc(New, anew * sizeof(NEW2));
1326  }
1327  New[nnew].x = List->box[i].E;
1328  New[nnew].y = List->box[i].N;
1329  New[nnew].z = List->box[i].T;
1330  New[nnew].along = along;
1331  nnew++;
1332  }
1333  G_debug(3, "dist: %g, thresh: %g", dist2, thresh2);
1334  }
1335  G_debug(3, " nnew = %d", nnew);
1336  /* insert new vertices */
1337  if (nnew > 0) {
1338  /* sort by distance along the segment */
1339  qsort(New, nnew, sizeof(NEW2), sort_new2);
1340 
1341  for (i = 0; i < nnew; i++) {
1342  Vect_append_point(NPoints, New[i].x, New[i].y, New[i].z);
1343  if (ncreated)
1344  (*ncreated)++;
1345  }
1346  changed = 1;
1347  }
1348  }
1349 
1350  /* append end point */
1351  v = Points->n_points - 1;
1352  Vect_append_point(NPoints, Points->x[v], Points->y[v], Points->z[v]);
1353 
1354  if (Points->n_points != NPoints->n_points) {
1355  Vect_line_prune(NPoints); /* remove duplicates */
1356  Vect_reset_line(Points);
1357  Vect_append_points(Points, NPoints, GV_FORWARD);
1358  }
1359 
1360  Vect_destroy_line_struct(LPoints);
1361  Vect_destroy_line_struct(NPoints);
1363  Vect_destroy_boxlist(List);
1364  G_free(New);
1365  RTreeDestroyTree(pnt_tree);
1366  G_free(rect.boundary);
1367 
1368  return changed;
1369 }
#define X1W
Definition: Vlib/snap.c:27
void Vect_snap_lines_list(struct Map_info *Map, const struct ilist *List_lines, double thresh, struct Map_info *Err)
Snap selected lines to existing vertex in threshold.
Definition: Vlib/snap.c:169
#define Y1S
Definition: Vlib/snap.c:28
#define Z1B
Definition: Vlib/snap.c:29
void Vect_snap_lines(struct Map_info *Map, int type, double thresh, struct Map_info *Err)
Snap lines in vector map to existing vertex in threshold.
Definition: Vlib/snap.c:896
int Vect_snap_line(struct Map_info *Map, struct ilist *reflist, struct line_pnts *Points, double thresh, int with_z, int *nsnapped, int *ncreated)
Snap a line to reference lines in Map with threshold.
Definition: Vlib/snap.c:949
#define NULL
Definition: ccmath.h:32
void G_percent(long, long, int)
Print percent complete messages.
Definition: percent.c:61
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_realloc(p, n)
Definition: defs/gis.h:96
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition: defs/gis.h:94
void void G_verbose_message(const char *,...) __attribute__((format(printf
char * G_tempfile(void)
Returns a temporary file name.
Definition: tempfile.c:62
void void void G_important_message(const char *,...) __attribute__((format(printf
void G_ilist_add(struct ilist *, int)
Add item to ilist.
Definition: ilist.c:78
int G_debug(int, const char *,...) __attribute__((format(printf
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
Definition: line.c:77
off_t Vect_rewrite_line(struct Map_info *, off_t, int, const struct line_pnts *, const struct line_cats *)
Rewrites existing feature (topological level required)
int Vect_reset_boxlist(struct boxlist *)
Reset boxlist structure.
plus_t Vect_get_num_lines(struct Map_info *)
Fetch number of features (points, lines, boundaries, centroids) in vector map.
Definition: level_two.c:75
struct boxlist * Vect_new_boxlist(int)
Creates and initializes a struct boxlist.
void Vect_destroy_boxlist(struct boxlist *)
Frees all memory associated with a struct boxlist, including the struct itself.
void Vect_destroy_list(struct ilist *)
Frees all memory associated with a struct ilist, including the struct itself.
void Vect_destroy_cats_struct(struct line_cats *)
Frees all memory associated with line_cats structure, including the struct itself.
int Vect_read_line(struct Map_info *, struct line_pnts *, struct line_cats *, int)
Read vector feature (topological level required)
struct ilist * Vect_new_list(void)
Creates and initializes a struct ilist.
int Vect_line_alive(struct Map_info *, int)
Check if feature is alive or dead (topological level required)
int Vect_delete_line(struct Map_info *, off_t)
Delete existing feature (topological level required)
off_t Vect_write_line(struct Map_info *, int, const struct line_pnts *, const struct line_cats *)
Writes a new feature.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
Definition: line.c:45
void Vect_reset_line(struct line_pnts *)
Reset line.
Definition: line.c:129
int Vect_line_prune(struct line_pnts *)
Remove duplicate points, i.e. zero length segments.
Definition: line.c:279
struct line_cats * Vect_new_cats_struct(void)
Creates and initializes line_cats structure.
int Vect_reset_list(struct ilist *)
Reset ilist structure.
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
Definition: line.c:148
int Vect_append_points(struct line_pnts *, const struct line_pnts *, int)
Appends points to the end of a line.
Definition: line.c:335
#define GV_LINES
Definition: dig_defines.h:193
#define GV_FORWARD
Line direction indicator forward/backward.
Definition: dig_defines.h:179
double dig_distance2_point_to_line(double, double, double, double, double, double, double, double, double, int, double *, double *, double *, double *, int *)
int dig_boxlist_add(struct boxlist *, int, const struct bound_box *)
#define UNUSED
A macro for an attribute, if attached to a variable, indicating that the variable is not used.
Definition: gis.h:47
#define _(str)
Definition: glocale.h:10
int kdtree_rnn(struct kdtree *t, double *c, int **puid, int *skip)
Definition: kdtree.c:751
struct kdtree * kdtree_create(char ndims, int *btol)
Definition: kdtree.c:111
int kdtree_insert(struct kdtree *t, double *c, int uid, int dc)
Definition: kdtree.c:179
int kdtree_knn(struct kdtree *t, double *c, int *uid, double *d, int k, int *skip)
Definition: kdtree.c:512
void kdtree_destroy(struct kdtree *t)
Definition: kdtree.c:167
int kdtree_dnn(struct kdtree *t, double *c, int **puid, double **pd, double maxdist, int *skip)
Definition: kdtree.c:636
double RectReal
Definition: rtree.h:26
Vector map info.
Definition: dig_structs.h:1243
RectReal * boundary
Definition: rtree.h:55
Definition: rtree.h:123
Bounding box.
Definition: dig_structs.h:64
double W
West.
Definition: dig_structs.h:80
List of bounding boxes with id.
Definition: dig_structs.h:1723
List of integers.
Definition: gis.h:709
int n_values
Number of values in the list.
Definition: gis.h:717
int * value
Array of values.
Definition: gis.h:713
k-d tree
Definition: kdtree.h:80
Feature category info.
Definition: dig_structs.h:1677
Feature geometry info - coordinates.
Definition: dig_structs.h:1651
double * y
Array of Y coordinates.
Definition: dig_structs.h:1659
double * x
Array of X coordinates.
Definition: dig_structs.h:1655
int n_points
Number of points.
Definition: dig_structs.h:1667
double * z
Array of Z coordinates.
Definition: dig_structs.h:1663
Definition: manage.h:4
void RTreeSetOverflow(struct RTree *t, char overflow)
Enable/disable R*-tree forced reinsertion (overflow)
int RTreeInsertRect(struct RTree_Rect *r, int tid, struct RTree *t)
Insert an item into a R*-Tree.
void RTreeDestroyTree(struct RTree *t)
Destroy an R*-Tree.
int RTreeSearch(struct RTree *t, struct RTree_Rect *r, SearchHitCallback *shcb, void *cbarg)
Search an R*-Tree.
struct RTree * RTreeCreateTree(int fd, off_t rootpos, int ndims)
Create new empty R*-Tree.
#define x