gv_quick.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*!
  2. \file lib/ogsf/gv_quick.c
  3. \brief OGSF library -
  4. GRASS OpenGL gsurf OGSF Library
  5. Trying some stuff to draw a quick version of a vector map, to represent
  6. it when doing interactive translations.
  7. (C) 1999-2008 by the GRASS Development Team
  8. This program is free software under the
  9. GNU General Public License (>=v2).
  10. Read the file COPYING that comes with GRASS
  11. for details.
  12. \author Bill Brown, USACERL (December 1993)
  13. \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
  14. */
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <grass/gis.h>
  18. #include <grass/ogsf.h>
  19. #include "rowcol.h"
  20. /*!
  21. \brief target number of desired points to represent entire file
  22. */
  23. #define TFAST_PTS 800
  24. /*!
  25. \brief max number of lines desired
  26. */
  27. #define MFAST_LNS 400
  28. static geoline *copy_line(geoline *);
  29. static geoline *thin_line(geoline *, float);
  30. /*!
  31. \brief Copy line
  32. \param gln source line (geoline)
  33. \return pointer to geoline struct
  34. \return on failure
  35. */
  36. static geoline *copy_line(geoline * gln)
  37. {
  38. geoline *newln;
  39. int i, np;
  40. newln = (geoline *) G_malloc(sizeof(geoline)); /* G_fatal_error */
  41. if (!newln) {
  42. return (NULL);
  43. }
  44. np = newln->npts = gln->npts;
  45. if (2 == (newln->dims = gln->dims)) {
  46. newln->p2 = (Point2 *) G_calloc(np, sizeof(Point2)); /* G_fatal_error */
  47. if (!newln->p2) {
  48. return (NULL);
  49. }
  50. for (i = 0; i < np; i++) {
  51. newln->p2[i][X] = gln->p2[i][X];
  52. newln->p2[i][Y] = gln->p2[i][Y];
  53. }
  54. }
  55. else {
  56. newln->p3 = (Point3 *) G_calloc(np, sizeof(Point3)); /* G_fatal_error */
  57. if (!newln->p3) {
  58. return (NULL);
  59. }
  60. for (i = 0; i < np; i++) {
  61. newln->p3[i][X] = gln->p3[i][X];
  62. newln->p3[i][Y] = gln->p3[i][Y];
  63. newln->p3[i][Z] = gln->p3[i][Z];
  64. }
  65. }
  66. newln->next = NULL;
  67. return (newln);
  68. }
  69. /*!
  70. \brief Thin line
  71. For now, just eliminate points at regular interval
  72. \param gln line (geoline)
  73. \param factor
  74. \return pointer to geoline struct
  75. \return NULL on failure
  76. */
  77. static geoline *thin_line(geoline * gln, float factor)
  78. {
  79. geoline *newln;
  80. int i, nextp, targp;
  81. newln = (geoline *) G_malloc(sizeof(geoline)); /* G_fatal_error */
  82. if (!newln) {
  83. return (NULL);
  84. }
  85. targp = (int)(gln->npts / factor);
  86. if (targp < 2) {
  87. targp = 2;
  88. }
  89. newln->npts = targp;
  90. if (2 == (newln->dims = gln->dims)) {
  91. newln->p2 = (Point2 *) G_calloc(targp, sizeof(Point2)); /* G_fatal_error */
  92. if (!newln->p2) {
  93. return (NULL);
  94. }
  95. for (i = 0; i < targp; i++) {
  96. if (i == targp - 1) {
  97. nextp = gln->npts - 1; /* avoid rounding error */
  98. }
  99. else {
  100. nextp = (int)((i * (gln->npts - 1)) / (targp - 1));
  101. }
  102. newln->p2[i][X] = gln->p2[nextp][X];
  103. newln->p2[i][Y] = gln->p2[nextp][Y];
  104. }
  105. }
  106. else {
  107. newln->p3 = (Point3 *) G_calloc(targp, sizeof(Point3)); /* G_fatal_error */
  108. if (!newln->p3) {
  109. return (NULL);
  110. }
  111. for (i = 0; i < targp; i++) {
  112. if (i == targp - 1) {
  113. nextp = gln->npts - 1; /* avoid rounding error */
  114. }
  115. else {
  116. nextp = (int)((i * (gln->npts - 1)) / (targp - 1));
  117. }
  118. newln->p3[i][X] = gln->p3[nextp][X];
  119. newln->p3[i][Y] = gln->p3[nextp][Y];
  120. newln->p3[i][Z] = gln->p3[nextp][Z];
  121. }
  122. }
  123. newln->next = NULL;
  124. return (newln);
  125. }
  126. /*!
  127. \brief Get line width
  128. \param gln line (geoline)
  129. \return line width
  130. */
  131. float gv_line_length(geoline * gln)
  132. {
  133. int n;
  134. float length = 0.0;
  135. for (n = 0; n < gln->npts - 1; n++) {
  136. if (gln->p2) {
  137. length += GS_P2distance(gln->p2[n + 1], gln->p2[n]);
  138. }
  139. else {
  140. length += GS_distance(gln->p3[n + 1], gln->p3[n]);
  141. }
  142. }
  143. return (length);
  144. }
  145. /*!
  146. \brief Get number of line vertices
  147. \param gln line (geoline)
  148. \return number of vertices
  149. */
  150. int gln_num_points(geoline * gln)
  151. {
  152. int np = 0;
  153. geoline *tln;
  154. for (tln = gln; tln; tln = tln->next) {
  155. np += tln->npts;
  156. }
  157. return (np);
  158. }
  159. /*!
  160. \brief Get number of points in vector
  161. \param gv vector (geovect)
  162. \return number of points
  163. */
  164. int gv_num_points(geovect * gv)
  165. {
  166. return (gln_num_points(gv->lines));
  167. }
  168. /*!
  169. \brief Decimate line
  170. strategy here: if line has more than average number of points, decimate
  171. by eliminating points, otherwise decimate by eliminating shorter lines
  172. \param gv vector (geovect)
  173. \return
  174. */
  175. int gv_decimate_lines(geovect * gv)
  176. {
  177. int T_pts, A_ppl, N_s;
  178. float decim_factor, slength[MFAST_LNS], T_slength, A_slength;
  179. geoline *gln, *prev;
  180. /* should check if already exists & free if != gv->lines */
  181. if (TFAST_PTS > (T_pts = gv_num_points(gv))) {
  182. gv->fastlines = gv->lines;
  183. return (1);
  184. }
  185. N_s = 0;
  186. T_slength = 0.0;
  187. decim_factor = T_pts / TFAST_PTS;
  188. A_ppl = T_pts / gv->n_lines; /* (int) Average points per line */
  189. prev = NULL;
  190. for (gln = gv->lines; gln; gln = gln->next) {
  191. if (gln->npts > A_ppl) {
  192. if (prev) {
  193. prev->next = thin_line(gln, decim_factor);
  194. prev = prev->next;
  195. }
  196. else {
  197. prev = gv->fastlines = thin_line(gln, decim_factor);
  198. }
  199. }
  200. else if (N_s < MFAST_LNS) {
  201. T_slength += slength[N_s++] = gv_line_length(gln);
  202. }
  203. }
  204. A_slength = T_slength / N_s;
  205. N_s = 0;
  206. for (gln = gv->lines; gln; gln = gln->next) {
  207. if (gln->npts <= A_ppl) {
  208. if (N_s < MFAST_LNS) {
  209. if (slength[N_s++] > A_slength) {
  210. if (prev) {
  211. prev->next = copy_line(gln);
  212. prev = prev->next;
  213. }
  214. else {
  215. prev = gv->fastlines = copy_line(gln);
  216. }
  217. }
  218. }
  219. }
  220. }
  221. G_debug(3, "Decimated lines have %d points.",
  222. gln_num_points(gv->fastlines));
  223. return (1);
  224. }