snap.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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-2008 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. *
  17. * \date 2001
  18. */
  19. #include <stdlib.h>
  20. #include <math.h>
  21. #include <grass/gis.h>
  22. #include <grass/Vect.h>
  23. #include <grass/glocale.h>
  24. /* function prototypes */
  25. static int sort_new(const void *pa, const void *pb);
  26. /* Vertex */
  27. typedef struct
  28. {
  29. double x, y;
  30. int anchor; /* 0 - anchor, do not snap this point, that means snap others to this */
  31. /* >0 - index of anchor to which snap this point */
  32. /* -1 - init value */
  33. } XPNT;
  34. typedef struct
  35. {
  36. int anchor;
  37. double along;
  38. } NEW;
  39. /* This function is called by RTreeSearch() to add selected node/line/area/isle to thelist */
  40. int add_item(int id, struct ilist *list)
  41. {
  42. dig_list_add(list, id);
  43. return 1;
  44. }
  45. /*!
  46. * \brief Snap selected lines to existing vertex in threshold.
  47. *
  48. * Snap selected lines to existing vertices.
  49. *
  50. * \warning Lines are not necessarily snapped to nearest vertex, but to vertex in threshold!
  51. *
  52. * Lines showing how vertices were snapped may be optionally written to error map.
  53. * Input map must be opened on level 2 for update at least on GV_BUILD_BASE.
  54. *
  55. * \param[in] Map input map where vertices will be snapped
  56. * \param[in] List_lines list of lines to snap
  57. * \param[in] thresh threshold in which snap vertices
  58. * \param[out] Err vector map where lines representing snap are written or NULL
  59. *
  60. * \return void
  61. */
  62. /* As mentioned above, lines are not necessarily snapped to nearest vertex! For example:
  63. |
  64. | 1 line 3 is snapped to line 1,
  65. | then line 2 is not snapped to common node at lines 1 and 3,
  66. because it is already outside of threshold
  67. ----------- 3
  68. |
  69. | 2
  70. |
  71. */
  72. void
  73. Vect_snap_lines_list(struct Map_info *Map, struct ilist *List_lines,
  74. double thresh, struct Map_info *Err)
  75. {
  76. struct line_pnts *Points, *NPoints;
  77. struct line_cats *Cats;
  78. int line, ltype, line_idx;
  79. double thresh2;
  80. struct Node *RTree;
  81. int point; /* index in points array */
  82. int nanchors, ntosnap; /* number of anchors and number of points to be snapped */
  83. int nsnapped, ncreated; /* number of snapped verices, number of new vertices (on segments) */
  84. int apoints, npoints, nvertices; /* number of allocated points, registered points, vertices */
  85. XPNT *XPnts; /* Array of points */
  86. NEW *New = NULL; /* Array of new points */
  87. int anew = 0, nnew; /* allocated new points , number of new points */
  88. struct Rect rect;
  89. struct ilist *List;
  90. int *Index = NULL; /* indexes of anchors for vertices */
  91. int aindex = 0; /* allocated Index */
  92. if (List_lines->n_values < 1)
  93. return;
  94. Points = Vect_new_line_struct();
  95. NPoints = Vect_new_line_struct();
  96. Cats = Vect_new_cats_struct();
  97. List = Vect_new_list();
  98. RTree = RTreeNewIndex();
  99. thresh2 = thresh * thresh;
  100. /* Go through all lines in vector, and add each point to structure of points */
  101. apoints = 0;
  102. point = 1; /* index starts from 1 ! */
  103. nvertices = 0;
  104. XPnts = NULL;
  105. for (line_idx = 0; line_idx < List_lines->n_values; line_idx++) {
  106. int v;
  107. line = List_lines->value[line_idx];
  108. G_debug(3, "line = %d", line);
  109. if (!Vect_line_alive(Map, line))
  110. continue;
  111. ltype = Vect_read_line(Map, Points, Cats, line);
  112. for (v = 0; v < Points->n_points; v++) {
  113. G_debug(3, " vertex v = %d", v);
  114. nvertices++;
  115. /* Box */
  116. rect.boundary[0] = Points->x[v];
  117. rect.boundary[3] = Points->x[v];
  118. rect.boundary[1] = Points->y[v];
  119. rect.boundary[4] = Points->y[v];
  120. rect.boundary[2] = 0;
  121. rect.boundary[5] = 0;
  122. /* Already registered ? */
  123. Vect_reset_list(List);
  124. RTreeSearch(RTree, &rect, (void *)add_item, List);
  125. G_debug(3, "List : nvalues = %d", List->n_values);
  126. if (List->n_values == 0) { /* Not found */
  127. /* Add to tree and to structure */
  128. RTreeInsertRect(&rect, point, &RTree, 0);
  129. if ((point - 1) == apoints) {
  130. apoints += 10000;
  131. XPnts =
  132. (XPNT *) G_realloc(XPnts,
  133. (apoints + 1) * sizeof(XPNT));
  134. }
  135. XPnts[point].x = Points->x[v];
  136. XPnts[point].y = Points->y[v];
  137. XPnts[point].anchor = -1;
  138. point++;
  139. }
  140. }
  141. }
  142. npoints = point - 1;
  143. /* Go through all registered points and if not yet marked mark it as anchor and assign this anchor
  144. * to all not yet marked points in threshold */
  145. nanchors = ntosnap = 0;
  146. for (point = 1; point <= npoints; point++) {
  147. int i;
  148. G_debug(3, " point = %d", point);
  149. if (XPnts[point].anchor >= 0)
  150. continue;
  151. XPnts[point].anchor = 0; /* make it anchor */
  152. nanchors++;
  153. /* Find points in threshold */
  154. rect.boundary[0] = XPnts[point].x - thresh;
  155. rect.boundary[3] = XPnts[point].x + thresh;
  156. rect.boundary[1] = XPnts[point].y - thresh;
  157. rect.boundary[4] = XPnts[point].y + thresh;
  158. rect.boundary[2] = 0;
  159. rect.boundary[5] = 0;
  160. Vect_reset_list(List);
  161. RTreeSearch(RTree, &rect, (void *)add_item, List);
  162. G_debug(4, " %d points in threshold box", List->n_values);
  163. for (i = 0; i < List->n_values; i++) {
  164. int pointb;
  165. double dx, dy, dist2;
  166. pointb = List->value[i];
  167. if (pointb == point)
  168. continue;
  169. dx = XPnts[pointb].x - XPnts[point].x;
  170. dy = XPnts[pointb].y - XPnts[point].y;
  171. dist2 = dx * dx + dy * dy;
  172. if (dist2 <= thresh2) {
  173. XPnts[pointb].anchor = point;
  174. ntosnap++;
  175. }
  176. }
  177. }
  178. /* Go through all lines and:
  179. * 1) for all vertices: if not anchor snap it to its anchor
  180. * 2) for all segments: snap it to all anchors in threshold (except anchors of vertices of course) */
  181. nsnapped = ncreated = 0;
  182. for (line_idx = 0; line_idx < List_lines->n_values; line_idx++) {
  183. int v, spoint, anchor;
  184. int changed = 0;
  185. line = List_lines->value[line_idx];
  186. G_debug(3, "line = %d", line);
  187. if (!Vect_line_alive(Map, line))
  188. continue;
  189. ltype = Vect_read_line(Map, Points, Cats, line);
  190. if (Points->n_points >= aindex) {
  191. aindex = Points->n_points;
  192. Index = (int *)G_realloc(Index, aindex * sizeof(int));
  193. }
  194. /* Snap all vertices */
  195. for (v = 0; v < Points->n_points; v++) {
  196. /* Box */
  197. rect.boundary[0] = Points->x[v];
  198. rect.boundary[3] = Points->x[v];
  199. rect.boundary[1] = Points->y[v];
  200. rect.boundary[4] = Points->y[v];
  201. rect.boundary[2] = 0;
  202. rect.boundary[5] = 0;
  203. /* Find point ( should always find one point ) */
  204. Vect_reset_list(List);
  205. RTreeSearch(RTree, &rect, (void *)add_item, List);
  206. spoint = List->value[0];
  207. anchor = XPnts[spoint].anchor;
  208. if (anchor > 0) { /* to be snapped */
  209. Points->x[v] = XPnts[anchor].x;
  210. Points->y[v] = XPnts[anchor].y;
  211. nsnapped++;
  212. changed = 1;
  213. Index[v] = anchor; /* point on new location */
  214. }
  215. else {
  216. Index[v] = spoint; /* old point */
  217. }
  218. }
  219. /* New points */
  220. Vect_reset_line(NPoints);
  221. /* Snap all segments to anchors in threshold */
  222. for (v = 0; v < Points->n_points - 1; v++) {
  223. int i;
  224. double x1, x2, y1, y2, xmin, xmax, ymin, ymax;
  225. G_debug(3, " segment = %d end anchors : %d %d", v, Index[v],
  226. Index[v + 1]);
  227. x1 = Points->x[v];
  228. x2 = Points->x[v + 1];
  229. y1 = Points->y[v];
  230. y2 = Points->y[v + 1];
  231. Vect_append_point(NPoints, Points->x[v], Points->y[v],
  232. Points->z[v]);
  233. /* Box */
  234. if (x1 <= x2) {
  235. xmin = x1;
  236. xmax = x2;
  237. }
  238. else {
  239. xmin = x2;
  240. xmax = x1;
  241. }
  242. if (y1 <= y2) {
  243. ymin = y1;
  244. ymax = y2;
  245. }
  246. else {
  247. ymin = y2;
  248. ymax = y1;
  249. }
  250. rect.boundary[0] = xmin - thresh;
  251. rect.boundary[3] = xmax + thresh;
  252. rect.boundary[1] = ymin - thresh;
  253. rect.boundary[4] = ymax + thresh;
  254. rect.boundary[2] = 0;
  255. rect.boundary[5] = 0;
  256. /* Find points */
  257. Vect_reset_list(List);
  258. RTreeSearch(RTree, &rect, (void *)add_item, List);
  259. G_debug(3, " %d points in box", List->n_values);
  260. /* Snap to anchor in threshold different from end points */
  261. nnew = 0;
  262. for (i = 0; i < List->n_values; i++) {
  263. double dist2, along;
  264. spoint = List->value[i];
  265. G_debug(4, " spoint = %d anchor = %d", spoint,
  266. XPnts[spoint].anchor);
  267. if (spoint == Index[v] || spoint == Index[v + 1])
  268. continue; /* end point */
  269. if (XPnts[spoint].anchor > 0)
  270. continue; /* point is not anchor */
  271. /* Check the distance */
  272. dist2 =
  273. dig_distance2_point_to_line(XPnts[spoint].x,
  274. XPnts[spoint].y, 0, x1, y1, 0,
  275. x2, y2, 0, 0, NULL, NULL,
  276. NULL, &along, NULL);
  277. G_debug(4, " distance = %lf", sqrt(dist2));
  278. if (dist2 <= thresh2) {
  279. G_debug(4, " anchor in thresh, along = %lf", along);
  280. if (nnew == anew) {
  281. anew += 100;
  282. New = (NEW *) G_realloc(New, anew * sizeof(NEW));
  283. }
  284. New[nnew].anchor = spoint;
  285. New[nnew].along = along;
  286. nnew++;
  287. }
  288. }
  289. G_debug(3, " nnew = %d", nnew);
  290. /* insert new vertices */
  291. if (nnew > 0) {
  292. /* sort by distance along the segment */
  293. qsort(New, sizeof(char) * nnew, sizeof(NEW), sort_new);
  294. for (i = 0; i < nnew; i++) {
  295. anchor = New[i].anchor;
  296. /* Vect_line_insert_point ( Points, ++v, XPnts[anchor].x, XPnts[anchor].y, 0); */
  297. Vect_append_point(NPoints, XPnts[anchor].x,
  298. XPnts[anchor].y, 0);
  299. ncreated++;
  300. }
  301. changed = 1;
  302. }
  303. }
  304. /* append end point */
  305. v = Points->n_points - 1;
  306. Vect_append_point(NPoints, Points->x[v], Points->y[v], Points->z[v]);
  307. if (changed) { /* rewrite the line */
  308. Vect_line_prune(NPoints); /* remove duplicates */
  309. if (NPoints->n_points > 1 || ltype & GV_LINES) {
  310. Vect_rewrite_line(Map, line, ltype, NPoints, Cats);
  311. }
  312. else {
  313. Vect_delete_line(Map, line);
  314. }
  315. if (Err) {
  316. Vect_write_line(Err, ltype, Points, Cats);
  317. }
  318. }
  319. } /* for each line */
  320. Vect_destroy_line_struct(Points);
  321. Vect_destroy_line_struct(NPoints);
  322. Vect_destroy_cats_struct(Cats);
  323. G_free(XPnts);
  324. G_free(Index);
  325. G_free(New);
  326. RTreeDestroyNode(RTree);
  327. }
  328. /* for qsort */
  329. static int sort_new(const void *pa, const void *pb)
  330. {
  331. NEW *p1 = (NEW *) pa;
  332. NEW *p2 = (NEW *) pb;
  333. if (p1->along < p2->along)
  334. return -1;
  335. if (p1->along > p2->along)
  336. return 1;
  337. return 1;
  338. }
  339. /*!
  340. * \brief Snap lines in vector map to existing vertex in threshold.
  341. *
  342. * For details see Vect_snap_lines_list()
  343. *
  344. * \param[in] Map input map where vertices will be snapped
  345. * \param[in] type type of lines to snap
  346. * \param[in] thresh threshold in which snap vertices
  347. * \param[out] Err vector map where lines representing snap are written or NULL
  348. *
  349. * \return void
  350. */
  351. void
  352. Vect_snap_lines(struct Map_info *Map, int type, double thresh,
  353. struct Map_info *Err)
  354. {
  355. int line, nlines, ltype;
  356. struct ilist *List;
  357. List = Vect_new_list();
  358. nlines = Vect_get_num_lines(Map);
  359. for (line = 1; line <= nlines; line++) {
  360. G_debug(3, "line = %d", line);
  361. if (!Vect_line_alive(Map, line))
  362. continue;
  363. ltype = Vect_read_line(Map, NULL, NULL, line);
  364. if (!(ltype & type))
  365. continue;
  366. Vect_list_append(List, line);
  367. }
  368. Vect_snap_lines_list(Map, List, thresh, Err);
  369. Vect_destroy_list(List);
  370. return;
  371. }