simplification.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /****************************************************************
  2. *
  3. * MODULE: v.generalize
  4. *
  5. * AUTHOR(S): Daniel Bundala
  6. *
  7. * PURPOSE: Module for line simplification and smoothing
  8. *
  9. * COPYRIGHT: (C) 2002-2005 by the GRASS Development Team
  10. *
  11. * This program is free software under the
  12. * GNU General Public License (>=v2).
  13. * Read the file COPYING that comes with GRASS
  14. * for details.
  15. *
  16. ****************************************************************/
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <grass/gis.h>
  20. #include <grass/vector.h>
  21. #include <grass/glocale.h>
  22. #include "point.h"
  23. #include "pq.h"
  24. #include "misc.h"
  25. int douglas_peucker(struct line_pnts *Points, double thresh, int with_z)
  26. {
  27. int *stack = G_malloc(sizeof(int) * Points->n_points * 2);
  28. if (!stack) {
  29. G_fatal_error(_("Out of memory"));
  30. return Points->n_points;
  31. }
  32. int *index = G_malloc(sizeof(int) * Points->n_points); /* Indices of points in output line */
  33. if (!index) {
  34. G_fatal_error(_("Out of memory"));
  35. G_free(stack);
  36. return Points->n_points;
  37. }
  38. int top = 2; /* first free slot in the stack */
  39. int icount = 1; /* number of indices stored */
  40. int i;
  41. thresh *= thresh;
  42. index[0] = 0; /* first point is always in output line */
  43. /* stack contains pairs of elements: (beginning, end) */
  44. stack[0] = 0;
  45. stack[1] = Points->n_points - 1;
  46. while (top > 0) { /*there are still segments to consider */
  47. /*Pop indices of the segment from the stack */
  48. int last = stack[--top];
  49. int first = stack[--top];
  50. double x1 = Points->x[first];
  51. double y1 = Points->y[first];
  52. double z1 = Points->z[first];
  53. double x2 = Points->x[last];
  54. double y2 = Points->y[last];
  55. double z2 = Points->z[last];
  56. int maxindex = -1;
  57. double maxdist = -1;
  58. int i;
  59. for (i = first + 1; i <= last - 1; i++) { /* Find the furthermost point between first, last */
  60. double px, py, pz, pdist;
  61. int status;
  62. double dist =
  63. dig_distance2_point_to_line(Points->x[i], Points->y[i],
  64. Points->z[i],
  65. x1, y1, z1, x2, y2, z2, with_z,
  66. &px, &py, &pz, &pdist, &status);
  67. if (maxindex == -1 || dist > maxdist) { /* update the furthermost point so far seen */
  68. maxindex = i;
  69. maxdist = dist;
  70. }
  71. }
  72. if (maxindex == -1 || maxdist <= thresh) { /* no points between or all point are inside the threshold */
  73. index[icount++] = last;
  74. }
  75. else {
  76. /* break line into two parts, the order of pushing is crucial! It gurantees, that we are going to the left */
  77. stack[top++] = maxindex;
  78. stack[top++] = last;
  79. stack[top++] = first;
  80. stack[top++] = maxindex;
  81. }
  82. }
  83. Points->n_points = icount;
  84. /* finally, select only points marked in the algorithm */
  85. for (i = 0; i < icount; i++) {
  86. Points->x[i] = Points->x[index[i]];
  87. Points->y[i] = Points->y[index[i]];
  88. Points->z[i] = Points->z[index[i]];
  89. }
  90. G_free(stack);
  91. G_free(index);
  92. return (Points->n_points);
  93. }
  94. int lang(struct line_pnts *Points, double thresh, int look_ahead, int with_z)
  95. {
  96. int count = 1; /* place where the next point will be added. i.e after the last point */
  97. int from = 0;
  98. int to = look_ahead;
  99. thresh *= thresh;
  100. while (from < Points->n_points - 1) { /* repeat until we reach the last point */
  101. int i;
  102. int found = 0; /* whether we have found the point outside the threshold */
  103. double x1 = Points->x[from];
  104. double y1 = Points->y[from];
  105. double z1 = Points->z[from];
  106. if (Points->n_points - 1 < to) { /* check that we are always in the line */
  107. to = Points->n_points - 1;
  108. }
  109. double x2 = Points->x[to];
  110. double y2 = Points->y[to];
  111. double z2 = Points->z[to];
  112. for (i = from + 1; i < to; i++) {
  113. double px, py, pz, pdist;
  114. int status;
  115. if (dig_distance2_point_to_line
  116. (Points->x[i], Points->y[i], Points->z[i], x1, y1, z1, x2, y2,
  117. z2, with_z, &px, &py, &pz, &pdist, &status) > thresh) {
  118. found = 1;
  119. break;
  120. }
  121. }
  122. if (found) {
  123. to--;
  124. }
  125. else {
  126. Points->x[count] = Points->x[to];
  127. Points->y[count] = Points->y[to];
  128. Points->z[count] = Points->z[to];
  129. count++;
  130. from = to;
  131. to += look_ahead;
  132. }
  133. }
  134. Points->n_points = count;
  135. return Points->n_points;
  136. }
  137. /* Eliminates all vertices which are close(r than eps) to each other */
  138. int vertex_reduction(struct line_pnts *Points, double eps, int with_z)
  139. {
  140. int start, i, count, n;
  141. n = Points->n_points;
  142. /* there's almost nothing to remove */
  143. if (n <= 2)
  144. return Points->n_points;
  145. count = 0;
  146. start = 0;
  147. eps *= eps;
  148. count = 1; /*we never remove the first point */
  149. for (i = 0; i < n - 1; i++) {
  150. double dx = Points->x[i] - Points->x[start];
  151. double dy = Points->y[i] - Points->y[start];
  152. double dz = Points->z[i] - Points->z[start];
  153. double dst = dx * dx + dy * dy;
  154. if (with_z) {
  155. dst += dz * dz;
  156. }
  157. if (dst > eps) {
  158. Points->x[count] = Points->x[i];
  159. Points->y[count] = Points->y[i];
  160. Points->z[count] = Points->z[i];
  161. count++;
  162. start = i;
  163. }
  164. }
  165. /* last point is also always preserved */
  166. Points->x[count] = Points->x[n - 1];
  167. Points->y[count] = Points->y[n - 1];
  168. Points->z[count] = Points->z[n - 1];
  169. count++;
  170. Points->n_points = count;
  171. return Points->n_points;
  172. }
  173. /*Reumann-Witkam algorithm
  174. * Returns number of points in the output line
  175. */
  176. int reumann_witkam(struct line_pnts *Points, double thresh, int with_z)
  177. {
  178. int i, count;
  179. POINT x0, x1, x2, sub, diff;
  180. double subd, diffd, sp, dist;
  181. int n;
  182. n = Points->n_points;
  183. if (n < 3)
  184. return n;
  185. thresh *= thresh;
  186. count = 1;
  187. point_assign(Points, 0, with_z, &x1, 0);
  188. point_assign(Points, 1, with_z, &x2, 0);
  189. point_subtract(x2, x1, &sub);
  190. subd = point_dist2(sub);
  191. for (i = 2; i < n; i++) {
  192. point_assign(Points, i, with_z, &x0, 0);
  193. point_subtract(x1, x0, &diff);
  194. diffd = point_dist2(diff);
  195. sp = point_dot(diff, sub);
  196. dist = (diffd * subd - sp * sp) / subd;
  197. /* if the point is out of the threshlod-sausage, store it and calculate
  198. * all variables which do not change for each line-point calculation */
  199. if (dist > thresh) {
  200. point_assign(Points, i - 1, with_z, &x1, 0);
  201. point_assign(Points, i, with_z, &x2, 0);
  202. point_subtract(x2, x1, &sub);
  203. subd = point_dist2(sub);
  204. Points->x[count] = x0.x;
  205. Points->y[count] = x0.y;
  206. Points->z[count] = x0.z;
  207. count++;
  208. }
  209. }
  210. Points->x[count] = Points->x[n - 1];
  211. Points->y[count] = Points->y[n - 1];
  212. Points->z[count] = Points->z[n - 1];
  213. Points->n_points = count + 1;
  214. return Points->n_points;
  215. }
  216. /* douglas-peucker algorithm which simplifies a line to a line with
  217. * at most reduction% of points.
  218. * returns the number of points in the output line. It is approx
  219. * reduction/100 * Points->n_points.
  220. */
  221. int douglas_peucker_reduction(struct line_pnts *Points, double thresh,
  222. double reduction, int with_z)
  223. {
  224. int i;
  225. int n = Points->n_points;
  226. /* the maximum number of points which may be
  227. * included in the output */
  228. int nexp = n * (reduction / (double)100.0);
  229. /* line too short */
  230. if (n < 3)
  231. return n;
  232. /* indicates which point were selected by the algorithm */
  233. int *sel;
  234. sel = G_calloc(sizeof(int), n);
  235. if (sel == NULL) {
  236. G_fatal_error(_("Out of memory"));
  237. return n;
  238. }
  239. /* array used for storing the indices of line segments+furthest point */
  240. int *index;
  241. index = G_malloc(sizeof(int) * 3 * n);
  242. if (index == NULL) {
  243. G_fatal_error(_("Out of memory"));
  244. G_free(sel);
  245. return n;
  246. }
  247. int indices;
  248. indices = 0;
  249. /* preserve first and last point */
  250. sel[0] = sel[n - 1] = 1;
  251. nexp -= 2;
  252. thresh *= thresh;
  253. double d;
  254. int mid = get_furthest(Points, 0, n - 1, with_z, &d);
  255. int em;
  256. /* priority queue of line segments,
  257. * key is the distance of the furthest point */
  258. binary_heap pq;
  259. if (!binary_heap_init(n, &pq)) {
  260. G_fatal_error(_("Out of memory"));
  261. G_free(sel);
  262. G_free(index);
  263. return n;
  264. }
  265. if (d > thresh) {
  266. index[0] = 0;
  267. index[1] = n - 1;
  268. index[2] = mid;
  269. binary_heap_push(d, 0, &pq);
  270. indices = 3;
  271. }
  272. /* while we can add new points and queue is non-empty */
  273. while (nexp > 0) {
  274. /* empty heap */
  275. if (!binary_heap_extract_max(&pq, &em))
  276. break;
  277. int left = index[em];
  278. int right = index[em + 1];
  279. int furt = index[em + 2];
  280. /*mark the furthest point */
  281. sel[furt] = 1;
  282. nexp--;
  283. /* consider left and right segment */
  284. mid = get_furthest(Points, left, furt, with_z, &d);
  285. if (d > thresh) {
  286. binary_heap_push(d, indices, &pq);
  287. index[indices++] = left;
  288. index[indices++] = furt;
  289. index[indices++] = mid;
  290. }
  291. mid = get_furthest(Points, furt, right, with_z, &d);
  292. if (d > thresh) {
  293. binary_heap_push(d, indices, &pq);
  294. index[indices++] = furt;
  295. index[indices++] = right;
  296. index[indices++] = mid;
  297. }
  298. }
  299. /* copy selected points */
  300. int selected = 0;
  301. for (i = 0; i < n; i++) {
  302. if (sel[i]) {
  303. Points->x[selected] = Points->x[i];
  304. Points->y[selected] = Points->y[i];
  305. Points->z[selected] = Points->z[i];
  306. selected++;
  307. }
  308. }
  309. G_free(sel);
  310. G_free(index);
  311. binary_heap_free(&pq);
  312. Points->n_points = selected;
  313. return Points->n_points;
  314. }