polygon.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #include <grass/gis.h>
  5. #include "driverlib.h"
  6. #include "htmlmap.h"
  7. #define RAD_DEG M_R2D
  8. static void delete_point(int *x, int *y, int count)
  9. {
  10. int i;
  11. for (i = 0; i < count; i++) {
  12. x[i] = x[i + 1];
  13. y[i] = y[i + 1];
  14. }
  15. }
  16. static double find_azimuth(double x1, double y1, double x2, double y2)
  17. {
  18. double xx, yy;
  19. xx = x1 - x2;
  20. yy = y1 - y2;
  21. if (x1 == x2) {
  22. return (y2 > y1) ? 90.0 : 270.0;
  23. }
  24. else {
  25. if (y2 < y1) {
  26. if (x2 > x1) {
  27. return 360.0 + (RAD_DEG * atan(yy / xx));
  28. }
  29. else {
  30. return 180.0 + (RAD_DEG * atan(yy / xx));
  31. }
  32. }
  33. else {
  34. if (x2 > x1) {
  35. return (RAD_DEG * atan(yy / xx));
  36. }
  37. else {
  38. return 180.0 + (RAD_DEG * atan(yy / xx));
  39. }
  40. }
  41. }
  42. }
  43. void html_polygon(const struct path *p)
  44. {
  45. int n = p->count;
  46. struct MapPoly *new;
  47. int i;
  48. int delta_x, delta_y;
  49. int min_x, max_x, min_y, max_y;
  50. double min_azimuth = 1.0;
  51. double azimuth1, azimuth2, diff1, diff2;
  52. int *x = G_malloc(n * sizeof(int));
  53. int *y = G_malloc(n * sizeof(int));
  54. for (i = 0; i < n; i++) {
  55. x[i] = (int) floor(p->vertices[i].x + 0.5);
  56. y[i] = (int) floor(p->vertices[i].y + 0.5);
  57. }
  58. /*
  59. * remove points that have adjacent duplicates or have differences of
  60. * less the the minimum allowed. remove end points that are same as
  61. * the begin point (ending point = starting point is added
  62. * during Graph_Clse)
  63. */
  64. i = 0;
  65. while (i < (n - 1)) {
  66. delta_x = x[i] - x[i + 1];
  67. if (delta_x < 0)
  68. delta_x = -delta_x;
  69. delta_y = y[i] - y[i + 1];
  70. if (delta_y < 0)
  71. delta_y = -delta_y;
  72. if ((x[i] == x[i + 1] && y[i] == y[i + 1]) ||
  73. (delta_x <= html.MINIMUM_DIST && delta_y <= html.MINIMUM_DIST)) {
  74. delete_point(&x[i + 1], &y[i + 1], n - i - 1);
  75. --n;
  76. }
  77. else {
  78. ++i;
  79. }
  80. }
  81. /* perform same checks for last point & first point */
  82. while (1) {
  83. delta_x = x[0] - x[n - 1];
  84. if (delta_x < 0)
  85. delta_x = -delta_x;
  86. delta_y = y[0] - y[n - 1];
  87. if (delta_y < 0)
  88. delta_y = -delta_y;
  89. if ((x[0] == x[n - 1] && y[0] == y[n - 1]) ||
  90. (delta_x <= html.MINIMUM_DIST && delta_y <= html.MINIMUM_DIST)) {
  91. --n;
  92. }
  93. else {
  94. break;
  95. }
  96. }
  97. /*
  98. * if a polygon has either x or y extents less than the bounding box
  99. * minimum, ignore it
  100. *
  101. */
  102. min_x = max_x = x[0];
  103. min_y = max_y = y[0];
  104. for (i = 0; i < n; i++) {
  105. if (x[i] < min_x)
  106. min_x = x[i];
  107. if (x[i] > max_x)
  108. max_x = x[i];
  109. if (y[i] < min_y)
  110. min_y = y[i];
  111. if (y[i] > max_y)
  112. max_y = y[i];
  113. }
  114. delta_x = max_x - min_x;
  115. delta_y = max_y - min_y;
  116. if (delta_x < html.BBOX_MINIMUM || delta_y < html.BBOX_MINIMUM) {
  117. n = 0;
  118. }
  119. /*
  120. * remove points in excess of MAX_POINTS vertices
  121. */
  122. while (n > html.MAX_POINTS) {
  123. for (i = 0; i < (n - 2); i++) {
  124. /*
  125. * see if middle point can be removed, by checking if the
  126. * relative bearing to the middle is less than our current tolerance
  127. */
  128. azimuth1 = find_azimuth((double)x[i], (double)y[i],
  129. (double)x[i + 1], (double)y[i + 1]);
  130. azimuth2 = find_azimuth((double)x[i], (double)y[i],
  131. (double)x[i + 2], (double)y[i + 2]);
  132. diff1 = fmod(fabs((azimuth2 + 360.0) - azimuth1), 360.0);
  133. diff2 = fmod(fabs((azimuth1 + 360.0) - azimuth2), 360.0);
  134. if (diff1 <= min_azimuth || diff2 <= min_azimuth) {
  135. delete_point(&x[i + 1], &y[i + 1], n - i - 1);
  136. --n;
  137. ++i;
  138. /* either stop deleting points because we're less than 100,
  139. or keep deleting points with the same difference as this
  140. one (which might make a smaller polygon yet).
  141. if (n <= 100) {
  142. break;
  143. }
  144. */
  145. }
  146. }
  147. /* increase minimum azimuth difference for next round */
  148. min_azimuth += 1.0;
  149. }
  150. /*
  151. * copy remaining points into a new MapPoly
  152. */
  153. if (n >= 3) {
  154. new = (struct MapPoly *)G_malloc(sizeof(struct MapPoly));
  155. /* grab the last text string written as url */
  156. new->url = G_store(html.last_text);
  157. /* hook up new MapPoly into list */
  158. new->next_poly = NULL;
  159. *html.tail = new;
  160. html.tail = &(new->next_poly);
  161. new->num_pts = n;
  162. new->x_pts = x;
  163. new->y_pts = y;
  164. }
  165. else {
  166. G_free(x);
  167. G_free(y);
  168. }
  169. }