snap.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /*!
  2. * \file 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
  11. * GNU General Public License (>=v2).
  12. * Read the file COPYING that comes with GRASS
  13. * for details.
  14. *
  15. * \author Radim Blazek
  16. * update to GRASS 7 Markus Metz
  17. *
  18. * \date 2009
  19. */
  20. #include <stdlib.h>
  21. #include <math.h>
  22. #include <grass/gis.h>
  23. #include <grass/Vect.h>
  24. #include <grass/glocale.h>
  25. #include <grass/vect/rbtree.h>
  26. /* function prototypes */
  27. static int sort_new(const void *pa, const void *pb);
  28. /* Vertex */
  29. typedef struct
  30. {
  31. double x, y;
  32. double anchor_x, anchor_y;
  33. int anchor; /* 0 - anchor, do not snap this point, that means snap others to this */
  34. /* >0 - index of anchor to which snap this point */
  35. /* -1 - init value */
  36. } XPNT;
  37. typedef struct
  38. {
  39. double anchor_x, anchor_y;
  40. int anchor;
  41. double along;
  42. } NEW;
  43. /* This function is called by RTreeSearch() to add selected node/line/area/isle to thelist */
  44. int add_item(int id, struct ilist *list)
  45. {
  46. dig_list_add(list, id);
  47. return 1;
  48. }
  49. /* function used by binary tree to compare items */
  50. int compare_snappnts(const void *Xpnta, const void *Xpntb)
  51. {
  52. XPNT *a, *b;
  53. a = (XPNT *)Xpnta;
  54. b = (XPNT *)Xpntb;
  55. if (a->x > b->x)
  56. return 1;
  57. else if (a->x < b->x)
  58. return -1;
  59. else {
  60. if (a->y > b->y)
  61. return 1;
  62. else if (a->y < b->y)
  63. return -1;
  64. else
  65. return 0;
  66. }
  67. G_warning("Break polygons: Bug in binary tree!");
  68. return 1;
  69. }
  70. /*!
  71. * \brief Snap selected lines to existing vertex in threshold.
  72. *
  73. * Snap selected lines to existing vertices.
  74. *
  75. * \warning Lines are not necessarily snapped to nearest vertex, but to vertex in threshold!
  76. *
  77. * Lines showing how vertices were snapped may be optionally written to error map.
  78. * Input map must be opened on level 2 for update at least on GV_BUILD_BASE.
  79. *
  80. * \param[in] Map input map where vertices will be snapped
  81. * \param[in] List_lines list of lines to snap
  82. * \param[in] thresh threshold in which snap vertices
  83. * \param[out] Err vector map where lines representing snap are written or NULL
  84. *
  85. * \return void
  86. */
  87. /* As mentioned above, lines are not necessarily snapped to nearest vertex! For example:
  88. |
  89. | 1 line 3 is snapped to line 1,
  90. | then line 2 is not snapped to common node at lines 1 and 3,
  91. because it is already outside of threshold
  92. ----------- 3
  93. |
  94. | 2
  95. |
  96. The algorithm selects anchor vertices and snaps non-anchor vertices
  97. to these anchors.
  98. The distance between anchor vertices is always > threshold.
  99. If there is more than one anchor vertex within threshold around a
  100. non-anchor vertex, this vertex is snapped to the nearest anchor
  101. vertex within threshold.
  102. */
  103. void
  104. Vect_snap_lines_list(struct Map_info *Map, struct ilist *List_lines,
  105. double thresh, struct Map_info *Err)
  106. {
  107. struct line_pnts *Points, *NPoints;
  108. struct line_cats *Cats;
  109. int line, ltype, line_idx;
  110. double thresh2;
  111. double xmin, xmax, ymin, ymax;
  112. struct RB_TREE *RBTree;
  113. struct RB_TRAV RBTrav1, RBTrav2;
  114. int point; /* index in points array */
  115. int nanchors, ntosnap; /* number of anchors and number of points to be snapped */
  116. int nsnapped, ncreated; /* number of snapped verices, number of new vertices (on segments) */
  117. int apoints, npoints, nvertices; /* number of allocated points, registered points, vertices */
  118. XPNT *XPnt_found, *XPnt_found2, XPnt_search; /* snap points */
  119. NEW *New = NULL; /* Array of new points */
  120. int anew = 0, nnew; /* allocated new points , number of new points */
  121. if (List_lines->n_values < 1)
  122. return;
  123. Points = Vect_new_line_struct();
  124. NPoints = Vect_new_line_struct();
  125. Cats = Vect_new_cats_struct();
  126. RBTree = rbtree_create(compare_snappnts, sizeof(XPNT));
  127. thresh2 = thresh * thresh;
  128. /* Go through all lines in vector, and add each point to search tree
  129. * points are kept sorted in search tree first by x, then by y */
  130. apoints = 0;
  131. point = 1; /* index starts from 1 ! */
  132. nvertices = 0;
  133. G_verbose_message(_("Snap vertices Pass 1: select points"));
  134. for (line_idx = 0; line_idx < List_lines->n_values; line_idx++) {
  135. int v;
  136. G_percent(line_idx, List_lines->n_values, 2);
  137. line = List_lines->value[line_idx];
  138. G_debug(3, "line = %d", line);
  139. if (!Vect_line_alive(Map, line))
  140. continue;
  141. ltype = Vect_read_line(Map, Points, Cats, line);
  142. for (v = 0; v < Points->n_points; v++) {
  143. G_debug(3, " vertex v = %d", v);
  144. nvertices++;
  145. XPnt_search.x = Points->x[v];
  146. XPnt_search.y = Points->y[v];
  147. /* Already registered ? */
  148. XPnt_found = rbtree_find(RBTree, &XPnt_search);
  149. if (XPnt_found == NULL) { /* Not found */
  150. /* Add to tree */
  151. XPnt_search.anchor = -1;
  152. XPnt_search.anchor_x = Points->x[v];
  153. XPnt_search.anchor_y = Points->y[v];
  154. rbtree_insert(RBTree, &XPnt_search);
  155. point++;
  156. }
  157. }
  158. } /* end of points selection */
  159. G_percent(line_idx, List_lines->n_values, 2); /* finish it */
  160. npoints = point - 1;
  161. /* Go through all registered points and if not yet marked,
  162. * mark it as anchor and assign this anchor to all not yet marked
  163. * points within threshold.
  164. * Update anchor for marked points if new anchor is closer. */
  165. G_verbose_message(_("Snap vertices Pass 2: assign anchor vertices"));
  166. nanchors = ntosnap = 0;
  167. rbtree_init_trav(&RBTrav1, RBTree);
  168. rbtree_init_trav(&RBTrav2, RBTree);
  169. point = 1;
  170. /* XPnts in the old version were not sorted, this causes subtle differences */
  171. while ((XPnt_found = rbtree_traverse(&RBTrav1)) != NULL) {
  172. double dx, dy, dist2;
  173. G_percent(point, npoints, 2);
  174. G_debug(3, " point = %d", point);
  175. point++;
  176. if (XPnt_found->anchor >= 0)
  177. continue;
  178. XPnt_found->anchor = 0; /* make it anchor */
  179. nanchors++;
  180. /* Find points in threshold */
  181. xmin = XPnt_found->x - thresh;
  182. xmax = XPnt_found->x + thresh;
  183. ymin = XPnt_found->y - thresh;
  184. ymax = XPnt_found->y + thresh;
  185. XPnt_search.x = xmin;
  186. XPnt_search.y = ymin;
  187. /* traverse search tree from start point onwards */
  188. rbtree_init_trav(&RBTrav2, RBTree);
  189. while ((XPnt_found2 = rbtree_traverse_start(&RBTrav2, &XPnt_search)) != NULL) {
  190. if (XPnt_found2->x > xmax)
  191. break; /* outside x search limit */
  192. /* not an anchor, and within y search limits */
  193. if (XPnt_found2->anchor != 0 &&
  194. XPnt_found2->y >= ymin && XPnt_found2->y <= ymax) {
  195. dx = XPnt_found2->x - XPnt_found->x;
  196. dy = XPnt_found2->y - XPnt_found->y;
  197. if (dx == 0 && dy == 0) /* XPnt_found2 == XPnt_found */
  198. continue;
  199. dist2 = dx * dx + dy * dy;
  200. if (dist2 > thresh2) /* outside threshold */
  201. continue;
  202. /* doesn't have an anchor yet */
  203. if (XPnt_found2->anchor == -1) {
  204. XPnt_found2->anchor = 1;
  205. XPnt_found2->anchor_x = XPnt_found->x;
  206. XPnt_found2->anchor_y = XPnt_found->y;
  207. ntosnap++;
  208. }
  209. else { /* check distance to previously assigned anchor */
  210. double dist2_a;
  211. dx = XPnt_found2->anchor_x - XPnt_found2->x;
  212. dy = XPnt_found2->anchor_y - XPnt_found2->y;
  213. dist2_a = dx * dx + dy * dy;
  214. /* replace old anchor */
  215. if (dist2 < dist2_a) {
  216. XPnt_found2->anchor_x = XPnt_found->x;
  217. XPnt_found2->anchor_y = XPnt_found->y;
  218. }
  219. }
  220. }
  221. }
  222. } /* end of anchor assignment */
  223. /* Go through all lines and:
  224. * 1) for all vertices: if not anchor snap it to its anchor
  225. * 2) for all segments: snap it to all anchors in threshold (except anchors of vertices of course) */
  226. nsnapped = ncreated = 0;
  227. G_verbose_message(_("Snap vertices Pass 3: snap to assigned points"));
  228. for (line_idx = 0; line_idx < List_lines->n_values; line_idx++) {
  229. int v;
  230. int changed = 0;
  231. G_percent(line_idx, List_lines->n_values, 2);
  232. line = List_lines->value[line_idx];
  233. G_debug(3, "line = %d", line);
  234. if (!Vect_line_alive(Map, line))
  235. continue;
  236. ltype = Vect_read_line(Map, Points, Cats, line);
  237. /* Snap all vertices */
  238. G_debug(2, "snap vertices");
  239. for (v = 0; v < Points->n_points; v++) {
  240. /* Find point ( should always find one point ) */
  241. XPnt_search.x = Points->x[v];
  242. XPnt_search.y = Points->y[v];
  243. XPnt_found = rbtree_find(RBTree, &XPnt_search);
  244. if (XPnt_found == NULL)
  245. G_fatal_error("Snap lines: could not find vertex");
  246. if (XPnt_found->anchor > 0) { /* to be snapped */
  247. Points->x[v] = XPnt_found->anchor_x;
  248. Points->y[v] = XPnt_found->anchor_y;
  249. nsnapped++;
  250. changed = 1;
  251. }
  252. }
  253. /* New points */
  254. Vect_reset_line(NPoints);
  255. /* Snap all segments to anchors in threshold */
  256. G_debug(2, "snap segments");
  257. for (v = 0; v < Points->n_points - 1; v++) {
  258. int i;
  259. double x1, x2, y1, y2;
  260. double dist2, along;
  261. int status;
  262. x1 = Points->x[v];
  263. x2 = Points->x[v + 1];
  264. y1 = Points->y[v];
  265. y2 = Points->y[v + 1];
  266. Vect_append_point(NPoints, Points->x[v], Points->y[v],
  267. Points->z[v]);
  268. /* Search limits */
  269. xmin = (x1 < x2 ? x1 : x2) - thresh;
  270. xmax = (x1 > x2 ? x1 : x2) + thresh;
  271. ymin = (y1 < y2 ? y1 : y2) - thresh;
  272. ymax = (y1 > y2 ? y1 : y2) + thresh;
  273. XPnt_search.x = xmin;
  274. XPnt_search.y = ymin;
  275. /* Find points within search limits */
  276. nnew = 0;
  277. rbtree_init_trav(&RBTrav2, RBTree);
  278. G_debug(3, "snap segment");
  279. while ((XPnt_found2 = rbtree_traverse_start(&RBTrav2, &XPnt_search)) != NULL) {
  280. if (XPnt_found2->x > xmax)
  281. break; /* outside x search limit */
  282. /* found point must be within y search limits */
  283. if (XPnt_found2->y < ymin || XPnt_found2->y > ymax)
  284. continue;
  285. /* found point must be anchor */
  286. if (XPnt_found2->anchor > 0)
  287. continue; /* point is not anchor */
  288. /* found point must not be end point */
  289. if ((XPnt_found2->x == x1 && XPnt_found2->y == y1) ||
  290. (XPnt_found2->x == x2 && XPnt_found2->y == y2))
  291. continue; /* end point */
  292. /* Check the distance */
  293. dist2 =
  294. dig_distance2_point_to_line(XPnt_found2->x,
  295. XPnt_found2->y, 0, x1, y1, 0,
  296. x2, y2, 0, 0, NULL, NULL,
  297. NULL, &along, &status);
  298. G_debug(4, " distance = %lf", sqrt(dist2));
  299. /* status == 0 if point is w/in segment space
  300. * avoids messy lines and boundaries */
  301. if (status == 0 && dist2 <= thresh2) {
  302. G_debug(4, " anchor in thresh, along = %lf", along);
  303. if (nnew == anew) {
  304. anew += 100;
  305. New = (NEW *) G_realloc(New, anew * sizeof(NEW));
  306. }
  307. New[nnew].anchor_x = XPnt_found2->x;
  308. New[nnew].anchor_y = XPnt_found2->y;
  309. New[nnew].along = along;
  310. nnew++;
  311. }
  312. }
  313. G_debug(3, " nnew = %d", nnew);
  314. /* insert new vertices */
  315. if (nnew > 0) {
  316. /* sort by distance along the segment */
  317. qsort(New, sizeof(char) * nnew, sizeof(NEW), sort_new);
  318. for (i = 0; i < nnew; i++) {
  319. Vect_append_point(NPoints, New[i].anchor_x,
  320. New[i].anchor_y, 0);
  321. ncreated++;
  322. }
  323. changed = 1;
  324. }
  325. }
  326. /* append end point */
  327. v = Points->n_points - 1;
  328. Vect_append_point(NPoints, Points->x[v], Points->y[v], Points->z[v]);
  329. if (changed) { /* rewrite the line */
  330. Vect_line_prune(NPoints); /* remove duplicates */
  331. if (NPoints->n_points > 1 || ltype & GV_LINES) {
  332. Vect_rewrite_line(Map, line, ltype, NPoints, Cats);
  333. }
  334. else {
  335. Vect_delete_line(Map, line);
  336. }
  337. if (Err) {
  338. Vect_write_line(Err, ltype, Points, Cats);
  339. }
  340. }
  341. } /* for each line */
  342. G_percent(line_idx, List_lines->n_values, 2); /* finish it */
  343. Vect_destroy_line_struct(Points);
  344. Vect_destroy_line_struct(NPoints);
  345. Vect_destroy_cats_struct(Cats);
  346. G_free(New);
  347. rbtree_destroy(RBTree);
  348. G_verbose_message(_("Snapped vertices: %d"), nsnapped);
  349. G_verbose_message(_("New vertices: %d"), ncreated);
  350. }
  351. /* for qsort */
  352. static int sort_new(const void *pa, const void *pb)
  353. {
  354. NEW *p1 = (NEW *) pa;
  355. NEW *p2 = (NEW *) pb;
  356. if (p1->along < p2->along)
  357. return -1;
  358. if (p1->along > p2->along)
  359. return 1;
  360. return 1;
  361. }
  362. /*!
  363. * \brief Snap lines in vector map to existing vertex in threshold.
  364. *
  365. * For details see Vect_snap_lines_list()
  366. *
  367. * \param[in] Map input map where vertices will be snapped
  368. * \param[in] type type of lines to snap
  369. * \param[in] thresh threshold in which snap vertices
  370. * \param[out] Err vector map where lines representing snap are written or NULL
  371. *
  372. * \return void
  373. */
  374. void
  375. Vect_snap_lines(struct Map_info *Map, int type, double thresh,
  376. struct Map_info *Err)
  377. {
  378. int line, nlines, ltype;
  379. struct ilist *List;
  380. List = Vect_new_list();
  381. nlines = Vect_get_num_lines(Map);
  382. for (line = 1; line <= nlines; line++) {
  383. G_debug(3, "line = %d", line);
  384. if (!Vect_line_alive(Map, line))
  385. continue;
  386. ltype = Vect_read_line(Map, NULL, NULL, line);
  387. if (!(ltype & type))
  388. continue;
  389. Vect_list_append(List, line);
  390. }
  391. Vect_snap_lines_list(Map, List, thresh, Err);
  392. Vect_destroy_list(List);
  393. return;
  394. }