simplification.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  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 seg1, seg2;
  179. int i, count;
  180. POINT x0, x1, x2, sub, diff;
  181. double subd, diffd, sp, dist;
  182. int n;
  183. n = Points->n_points;
  184. if (n < 3)
  185. return n;
  186. thresh *= thresh;
  187. seg1 = 0;
  188. seg2 = 1;
  189. count = 1;
  190. point_assign(Points, 0, with_z, &x1);
  191. point_assign(Points, 1, with_z, &x2);
  192. point_subtract(x2, x1, &sub);
  193. subd = point_dist2(sub);
  194. for (i = 2; i < n; i++) {
  195. point_assign(Points, i, with_z, &x0);
  196. point_subtract(x1, x0, &diff);
  197. diffd = point_dist2(diff);
  198. sp = point_dot(diff, sub);
  199. dist = (diffd * subd - sp * sp) / subd;
  200. /* if the point is out of the threshlod-sausage, store it and calculate
  201. * all variables which do not change for each line-point calculation */
  202. if (dist > thresh) {
  203. point_assign(Points, i - 1, with_z, &x1);
  204. point_assign(Points, i, with_z, &x2);
  205. point_subtract(x2, x1, &sub);
  206. subd = point_dist2(sub);
  207. Points->x[count] = x0.x;
  208. Points->y[count] = x0.y;
  209. Points->z[count] = x0.z;
  210. count++;
  211. }
  212. }
  213. Points->x[count] = Points->x[n - 1];
  214. Points->y[count] = Points->y[n - 1];
  215. Points->z[count] = Points->z[n - 1];
  216. Points->n_points = count + 1;
  217. return Points->n_points;
  218. }
  219. /* douglas-peucker algorithm which simplifies a line to a line with
  220. * at most reduction% of points.
  221. * returns the number of points in the output line. It is approx
  222. * reduction/100 * Points->n_points.
  223. */
  224. int douglas_peucker_reduction(struct line_pnts *Points, double thresh,
  225. double reduction, int with_z)
  226. {
  227. int i;
  228. int n = Points->n_points;
  229. /* the maximum number of points which may be
  230. * included in the output */
  231. int nexp = n * (reduction / (double)100.0);
  232. /* line too short */
  233. if (n < 3)
  234. return n;
  235. /* indicates which point were selected by the algorithm */
  236. int *sel;
  237. sel = G_calloc(sizeof(int), n);
  238. if (sel == NULL) {
  239. G_fatal_error(_("Out of memory"));
  240. return n;
  241. }
  242. /* array used for storing the indices of line segments+furthest point */
  243. int *index;
  244. index = G_malloc(sizeof(int) * 3 * n);
  245. if (index == NULL) {
  246. G_fatal_error(_("Out of memory"));
  247. G_free(sel);
  248. return n;
  249. }
  250. int indices;
  251. indices = 0;
  252. /* preserve first and last point */
  253. sel[0] = sel[n - 1] = 1;
  254. nexp -= 2;
  255. thresh *= thresh;
  256. double d;
  257. int mid = get_furthest(Points, 0, n - 1, with_z, &d);
  258. int em;
  259. /* priority queue of line segments,
  260. * key is the distance of the furthest point */
  261. binary_heap pq;
  262. if (!binary_heap_init(n, &pq)) {
  263. G_fatal_error(_("Out of memory"));
  264. G_free(sel);
  265. G_free(index);
  266. return n;
  267. }
  268. if (d > thresh) {
  269. index[0] = 0;
  270. index[1] = n - 1;
  271. index[2] = mid;
  272. binary_heap_push(d, 0, &pq);
  273. indices = 3;
  274. }
  275. /* while we can add new points and queue is non-empty */
  276. while (nexp > 0) {
  277. /* empty heap */
  278. if (!binary_heap_extract_max(&pq, &em))
  279. break;
  280. int left = index[em];
  281. int right = index[em + 1];
  282. int furt = index[em + 2];
  283. /*mark the furthest point */
  284. sel[furt] = 1;
  285. nexp--;
  286. /* consider left and right segment */
  287. mid = get_furthest(Points, left, furt, with_z, &d);
  288. if (d > thresh) {
  289. binary_heap_push(d, indices, &pq);
  290. index[indices++] = left;
  291. index[indices++] = furt;
  292. index[indices++] = mid;
  293. }
  294. mid = get_furthest(Points, furt, right, with_z, &d);
  295. if (d > thresh) {
  296. binary_heap_push(d, indices, &pq);
  297. index[indices++] = furt;
  298. index[indices++] = right;
  299. index[indices++] = mid;
  300. }
  301. }
  302. /* copy selected points */
  303. int selected = 0;
  304. for (i = 0; i < n; i++) {
  305. if (sel[i]) {
  306. Points->x[selected] = Points->x[i];
  307. Points->y[selected] = Points->y[i];
  308. Points->z[selected] = Points->z[i];
  309. selected++;
  310. }
  311. }
  312. G_free(sel);
  313. G_free(index);
  314. binary_heap_free(&pq);
  315. Points->n_points = selected;
  316. return Points->n_points;
  317. }