snap.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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 optionaly 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. * \param[out] msgout file pointer where messages will be written or NULL
  60. *
  61. * \return void
  62. */
  63. /* As mentioned above, lines are not necessarily snapped to nearest vertex! For example:
  64. |
  65. | 1 line 3 is snapped to line 1,
  66. | then line 2 is not snapped to common node at lines 1 and 3,
  67. because it is already outside of threshold
  68. ----------- 3
  69. |
  70. | 2
  71. |
  72. */
  73. void
  74. Vect_snap_lines_list(struct Map_info *Map, struct ilist *List_lines,
  75. double thresh, struct Map_info *Err, FILE * msgout)
  76. {
  77. struct line_pnts *Points, *NPoints;
  78. struct line_cats *Cats;
  79. int line, ltype, line_idx;
  80. double thresh2;
  81. int printed;
  82. struct Node *RTree;
  83. int point; /* index in points array */
  84. int nanchors, ntosnap; /* number of anchors and number of points to be snapped */
  85. int nsnapped, ncreated; /* number of snapped verices, number of new vertices (on segments) */
  86. int apoints, npoints, nvertices; /* number of allocated points, registered points, vertices */
  87. XPNT *XPnts; /* Array of points */
  88. NEW *New = NULL; /* Array of new points */
  89. int anew = 0, nnew; /* allocated new points , number of new points */
  90. struct Rect rect;
  91. struct ilist *List;
  92. int *Index = NULL; /* indexes of anchors for vertices */
  93. int aindex = 0; /* allocated Index */
  94. int width = 26; /* fprintf width */
  95. if (List_lines->n_values < 1)
  96. return;
  97. Points = Vect_new_line_struct();
  98. NPoints = Vect_new_line_struct();
  99. Cats = Vect_new_cats_struct();
  100. List = Vect_new_list();
  101. RTree = RTreeNewIndex();
  102. thresh2 = thresh * thresh;
  103. /* Go through all lines in vector, and add each point to structure of points */
  104. apoints = 0;
  105. point = 1; /* index starts from 1 ! */
  106. nvertices = 0;
  107. XPnts = NULL;
  108. printed = 0;
  109. if (msgout)
  110. fprintf(msgout, "%s...", _("Registering points"));
  111. for (line_idx = 0; line_idx < List_lines->n_values; line_idx++) {
  112. int v;
  113. line = List_lines->value[line_idx];
  114. G_debug(3, "line = %d", line);
  115. if (!Vect_line_alive(Map, line))
  116. continue;
  117. ltype = Vect_read_line(Map, Points, Cats, line);
  118. for (v = 0; v < Points->n_points; v++) {
  119. G_debug(3, " vertex v = %d", v);
  120. nvertices++;
  121. /* Box */
  122. rect.boundary[0] = Points->x[v];
  123. rect.boundary[3] = Points->x[v];
  124. rect.boundary[1] = Points->y[v];
  125. rect.boundary[4] = Points->y[v];
  126. rect.boundary[2] = 0;
  127. rect.boundary[5] = 0;
  128. /* Already registered ? */
  129. Vect_reset_list(List);
  130. RTreeSearch(RTree, &rect, (void *)add_item, List);
  131. G_debug(3, "List : nvalues = %d", List->n_values);
  132. if (List->n_values == 0) { /* Not found */
  133. /* Add to tree and to structure */
  134. RTreeInsertRect(&rect, point, &RTree, 0);
  135. if ((point - 1) == apoints) {
  136. apoints += 10000;
  137. XPnts =
  138. (XPNT *) G_realloc(XPnts,
  139. (apoints + 1) * sizeof(XPNT));
  140. }
  141. XPnts[point].x = Points->x[v];
  142. XPnts[point].y = Points->y[v];
  143. XPnts[point].anchor = -1;
  144. point++;
  145. }
  146. }
  147. if (msgout && printed > 1000) {
  148. fprintf(msgout, "\r%s... %d", _("Registering points"), point - 1);
  149. fflush(msgout);
  150. printed = 0;
  151. }
  152. printed++;
  153. }
  154. npoints = point - 1;
  155. if (msgout) {
  156. fprintf(msgout,
  157. "\r \r");
  158. fprintf(msgout, "%-*s: %4d\n", width, _("All vertices"), nvertices);
  159. fprintf(msgout, "%-*s: %4d\n", width, _("Registered points"),
  160. npoints);
  161. }
  162. /* Go through all registered points and if not yet marked mark it as anchor and assign this anchor
  163. * to all not yet marked points in threshold */
  164. nanchors = ntosnap = 0;
  165. for (point = 1; point <= npoints; point++) {
  166. int i;
  167. G_debug(3, " point = %d", point);
  168. if (XPnts[point].anchor >= 0)
  169. continue;
  170. XPnts[point].anchor = 0; /* make it anchor */
  171. nanchors++;
  172. /* Find points in threshold */
  173. rect.boundary[0] = XPnts[point].x - thresh;
  174. rect.boundary[3] = XPnts[point].x + thresh;
  175. rect.boundary[1] = XPnts[point].y - thresh;
  176. rect.boundary[4] = XPnts[point].y + thresh;
  177. rect.boundary[2] = 0;
  178. rect.boundary[5] = 0;
  179. Vect_reset_list(List);
  180. RTreeSearch(RTree, &rect, (void *)add_item, List);
  181. G_debug(4, " %d points in threshold box", List->n_values);
  182. for (i = 0; i < List->n_values; i++) {
  183. int pointb;
  184. double dx, dy, dist2;
  185. pointb = List->value[i];
  186. if (pointb == point)
  187. continue;
  188. dx = XPnts[pointb].x - XPnts[point].x;
  189. dy = XPnts[pointb].y - XPnts[point].y;
  190. dist2 = dx * dx + dy * dy;
  191. if (dist2 <= thresh2) {
  192. XPnts[pointb].anchor = point;
  193. ntosnap++;
  194. }
  195. }
  196. }
  197. if (msgout) {
  198. fprintf(msgout, "%-*s: %4d\n", width, _("Nodes marked as anchor"),
  199. nanchors);
  200. fprintf(msgout, "%-*s: %4d\n", width, _("Nodes marked to be snapped"),
  201. ntosnap);
  202. }
  203. /* Go through all lines and:
  204. * 1) for all vertices: if not anchor snap it to its anchor
  205. * 2) for all segments: snap it to all anchors in threshold (except anchors of vertices of course) */
  206. printed = 0;
  207. nsnapped = ncreated = 0;
  208. if (msgout)
  209. fprintf(msgout, "%-*s: %4d", width, _("Snaps"), nsnapped + ncreated);
  210. for (line_idx = 0; line_idx < List_lines->n_values; line_idx++) {
  211. int v, spoint, anchor;
  212. int changed = 0;
  213. line = List_lines->value[line_idx];
  214. G_debug(3, "line = %d", line);
  215. if (!Vect_line_alive(Map, line))
  216. continue;
  217. ltype = Vect_read_line(Map, Points, Cats, line);
  218. if (Points->n_points >= aindex) {
  219. aindex = Points->n_points;
  220. Index = (int *)G_realloc(Index, aindex * sizeof(int));
  221. }
  222. /* Snap all vertices */
  223. for (v = 0; v < Points->n_points; v++) {
  224. /* Box */
  225. rect.boundary[0] = Points->x[v];
  226. rect.boundary[3] = Points->x[v];
  227. rect.boundary[1] = Points->y[v];
  228. rect.boundary[4] = Points->y[v];
  229. rect.boundary[2] = 0;
  230. rect.boundary[5] = 0;
  231. /* Find point ( should always find one point ) */
  232. Vect_reset_list(List);
  233. RTreeSearch(RTree, &rect, (void *)add_item, List);
  234. spoint = List->value[0];
  235. anchor = XPnts[spoint].anchor;
  236. if (anchor > 0) { /* to be snapped */
  237. Points->x[v] = XPnts[anchor].x;
  238. Points->y[v] = XPnts[anchor].y;
  239. nsnapped++;
  240. changed = 1;
  241. Index[v] = anchor; /* point on new location */
  242. }
  243. else {
  244. Index[v] = spoint; /* old point */
  245. }
  246. }
  247. /* New points */
  248. Vect_reset_line(NPoints);
  249. /* Snap all segments to anchors in threshold */
  250. for (v = 0; v < Points->n_points - 1; v++) {
  251. int i;
  252. double x1, x2, y1, y2, xmin, xmax, ymin, ymax;
  253. G_debug(3, " segment = %d end anchors : %d %d", v, Index[v],
  254. Index[v + 1]);
  255. x1 = Points->x[v];
  256. x2 = Points->x[v + 1];
  257. y1 = Points->y[v];
  258. y2 = Points->y[v + 1];
  259. Vect_append_point(NPoints, Points->x[v], Points->y[v],
  260. Points->z[v]);
  261. /* Box */
  262. if (x1 <= x2) {
  263. xmin = x1;
  264. xmax = x2;
  265. }
  266. else {
  267. xmin = x2;
  268. xmax = x1;
  269. }
  270. if (y1 <= y2) {
  271. ymin = y1;
  272. ymax = y2;
  273. }
  274. else {
  275. ymin = y2;
  276. ymax = y1;
  277. }
  278. rect.boundary[0] = xmin - thresh;
  279. rect.boundary[3] = xmax + thresh;
  280. rect.boundary[1] = ymin - thresh;
  281. rect.boundary[4] = ymax + thresh;
  282. rect.boundary[2] = 0;
  283. rect.boundary[5] = 0;
  284. /* Find points */
  285. Vect_reset_list(List);
  286. RTreeSearch(RTree, &rect, (void *)add_item, List);
  287. G_debug(3, " %d points in box", List->n_values);
  288. /* Snap to anchor in threshold different from end points */
  289. nnew = 0;
  290. for (i = 0; i < List->n_values; i++) {
  291. double dist2, along;
  292. spoint = List->value[i];
  293. G_debug(4, " spoint = %d anchor = %d", spoint,
  294. XPnts[spoint].anchor);
  295. if (spoint == Index[v] || spoint == Index[v + 1])
  296. continue; /* end point */
  297. if (XPnts[spoint].anchor > 0)
  298. continue; /* point is not anchor */
  299. /* Check the distance */
  300. dist2 =
  301. dig_distance2_point_to_line(XPnts[spoint].x,
  302. XPnts[spoint].y, 0, x1, y1, 0,
  303. x2, y2, 0, 0, NULL, NULL,
  304. NULL, &along, NULL);
  305. G_debug(4, " distance = %lf", sqrt(dist2));
  306. if (dist2 <= thresh2) {
  307. G_debug(4, " anchor in thresh, along = %lf", along);
  308. if (nnew == anew) {
  309. anew += 100;
  310. New = (NEW *) G_realloc(New, anew * sizeof(NEW));
  311. }
  312. New[nnew].anchor = spoint;
  313. New[nnew].along = along;
  314. nnew++;
  315. }
  316. }
  317. G_debug(3, " nnew = %d", nnew);
  318. /* insert new vertices */
  319. if (nnew > 0) {
  320. /* sort by distance along the segment */
  321. qsort(New, sizeof(char) * nnew, sizeof(NEW), sort_new);
  322. for (i = 0; i < nnew; i++) {
  323. anchor = New[i].anchor;
  324. /* Vect_line_insert_point ( Points, ++v, XPnts[anchor].x, XPnts[anchor].y, 0); */
  325. Vect_append_point(NPoints, XPnts[anchor].x,
  326. XPnts[anchor].y, 0);
  327. ncreated++;
  328. }
  329. changed = 1;
  330. }
  331. }
  332. /* append end point */
  333. v = Points->n_points - 1;
  334. Vect_append_point(NPoints, Points->x[v], Points->y[v], Points->z[v]);
  335. if (changed) { /* rewrite the line */
  336. Vect_line_prune(NPoints); /* remove duplicates */
  337. if (NPoints->n_points > 1 || ltype & GV_LINES) {
  338. Vect_rewrite_line(Map, line, ltype, NPoints, Cats);
  339. }
  340. else {
  341. Vect_delete_line(Map, line);
  342. }
  343. if (Err) {
  344. Vect_write_line(Err, ltype, Points, Cats);
  345. }
  346. }
  347. if (msgout && printed > 1000) {
  348. fprintf(msgout, "\r%s: %5d (line = %d)", _("Snaps"),
  349. nsnapped + ncreated, line);
  350. fflush(msgout);
  351. printed = 0;
  352. }
  353. printed++;
  354. } /* for each line */
  355. if (msgout) {
  356. fprintf(msgout, "\r%-*s: %4d\n", width, _("Snapped vertices"),
  357. nsnapped);
  358. fprintf(msgout, "%-*s: %4d\n", width, _("New vertices"), ncreated);
  359. }
  360. Vect_destroy_line_struct(Points);
  361. Vect_destroy_line_struct(NPoints);
  362. Vect_destroy_cats_struct(Cats);
  363. G_free(XPnts);
  364. G_free(Index);
  365. G_free(New);
  366. RTreeDestroyNode(RTree);
  367. }
  368. /* for qsort */
  369. static int sort_new(const void *pa, const void *pb)
  370. {
  371. NEW *p1 = (NEW *) pa;
  372. NEW *p2 = (NEW *) pb;
  373. if (p1->along < p2->along)
  374. return -1;
  375. if (p1->along > p2->along)
  376. return 1;
  377. return 1;
  378. }
  379. /*!
  380. * \brief Snap lines in vector map to existing vertex in threshold.
  381. *
  382. * For details see Vect_snap_lines_list()
  383. *
  384. * \param[in] Map input map where vertices will be snapped
  385. * \param[in] type type of lines to snap
  386. * \param[in] thresh threshold in which snap vertices
  387. * \param[out] Err vector map where lines representing snap are written or NULL
  388. * \param[out] msgout file pointer where messages will be written or NULL
  389. *
  390. * \return void
  391. */
  392. void
  393. Vect_snap_lines(struct Map_info *Map, int type, double thresh,
  394. struct Map_info *Err, FILE * msgout)
  395. {
  396. int line, nlines, ltype;
  397. struct ilist *List;
  398. List = Vect_new_list();
  399. nlines = Vect_get_num_lines(Map);
  400. for (line = 1; line <= nlines; line++) {
  401. G_debug(3, "line = %d", line);
  402. if (!Vect_line_alive(Map, line))
  403. continue;
  404. ltype = Vect_read_line(Map, NULL, NULL, line);
  405. if (!(ltype & type))
  406. continue;
  407. Vect_list_append(List, line);
  408. }
  409. Vect_snap_lines_list(Map, List, thresh, Err, msgout);
  410. Vect_destroy_list(List);
  411. return;
  412. }