outline.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #define OUTLINE
  2. #include <stdlib.h>
  3. #include <grass/gis.h>
  4. #include <grass/glocale.h>
  5. #include "globals.h"
  6. #include "local_proto.h"
  7. #define V Region.vertex /* converted vertex list */
  8. #define VN Region.vertex_npoints
  9. #define P Region.perimeter /* perimeter point list */
  10. #define PN Region.perimeter_npoints
  11. #define A Region.point
  12. #define AN Region.npoints
  13. #define extrema(x,y,z) (((x<y)&&(z<y))||((x>y)&&(z>y)))
  14. #define non_extrema(x,y,z) (((x<y)&&(y<z))||((x>y)&&(y>z)))
  15. int outline(void)
  16. {
  17. int first;
  18. int skip; /* boolean */
  19. int np; /* perimeter estimate */
  20. POINT tmp[MAX_VERTEX]; /* temp vertex list */
  21. int cur;
  22. int prev;
  23. int next;
  24. double tmp_n, tmp_e;
  25. POINT temp;
  26. /* convert alarm area points to data row/col verticies */
  27. Menu_msg("Preparing outline...");
  28. for (cur = 0; cur < AN; cur++) {
  29. temp.y = view_to_row(Region.view, A[cur].y);
  30. temp.x = view_to_col(Region.view, A[cur].x);
  31. tmp_n = row_to_northing(&(Region.view->cell.head), temp.y, 0.5);
  32. tmp_e = col_to_easting(&(Region.view->cell.head), temp.x, 0.5);
  33. tmp[cur].y = Rast_northing_to_row(tmp_n, &Band_cellhd);
  34. tmp[cur].x = Rast_easting_to_col(tmp_e, &Band_cellhd);
  35. }
  36. /* find first edge which is not horizontal */
  37. first = -1;
  38. prev = AN - 1;
  39. for (cur = 0; cur < AN; prev = cur++)
  40. if (tmp[cur].y != tmp[prev].y) {
  41. first = cur;
  42. break;
  43. }
  44. if (first < 0) {
  45. G_warning(_("Absurd polygon."));
  46. return (0);
  47. }
  48. /* copy tmp to vertex list collapsing adjacent horizontal edges */
  49. skip = 0;
  50. VN = 0;
  51. cur = first; /* stmt not necssary */
  52. do {
  53. if (signalflag.interrupt)
  54. return (0);
  55. if (!skip) {
  56. V[VN].x = tmp[cur].x;
  57. V[VN].y = tmp[cur].y;
  58. VN++;
  59. }
  60. prev = cur++;
  61. if (cur >= AN)
  62. cur = 0;
  63. if ((next = cur + 1) >= AN)
  64. next = 0;
  65. skip = ((tmp[prev].y == tmp[cur].y) && (tmp[next].y == tmp[cur].y));
  66. }
  67. while (cur != first);
  68. /* count points on the perimeter */
  69. np = 0;
  70. prev = VN - 1;
  71. for (cur = 0; cur < VN; prev = cur++)
  72. np += abs(V[prev].y - V[cur].y);
  73. /* allocate perimeter list */
  74. P = (POINT *) G_malloc(np * sizeof(POINT));
  75. if (!P) {
  76. G_warning(_("Outlined area is too large."));
  77. return (0);
  78. }
  79. /* store the perimeter points */
  80. PN = 0;
  81. prev = VN - 1;
  82. for (cur = 0; cur < VN; prev = cur++) {
  83. if (signalflag.interrupt)
  84. return (0);
  85. edge(V[prev].x, V[prev].y, V[cur].x, V[cur].y);
  86. }
  87. /*
  88. * now decide which verticies should be included
  89. * local extrema are excluded
  90. * local non-extrema are included
  91. * verticies of horizontal edges which are pseudo-extrema
  92. * are excluded.
  93. * one vertex of horizontal edges which are pseudo-non-extrema
  94. * are included.
  95. */
  96. prev = VN - 1;
  97. cur = 0;
  98. do {
  99. if (signalflag.interrupt)
  100. return (0);
  101. next = cur + 1;
  102. if (next >= VN)
  103. next = 0;
  104. if (extrema(V[prev].y, V[cur].y, V[next].y))
  105. skip = 1;
  106. else if (non_extrema(V[prev].y, V[cur].y, V[next].y))
  107. skip = 0;
  108. else {
  109. skip = 0;
  110. if (++next >= VN)
  111. next = 0;
  112. if (extrema(V[prev].y, V[cur].y, V[next].y))
  113. skip = 1;
  114. }
  115. if (!skip)
  116. edge_point(V[cur].x, V[cur].y);
  117. cur = next;
  118. prev = cur - 1;
  119. }
  120. while (cur != 0);
  121. /* sort the edge points by row and then by col */
  122. Menu_msg("Sorting...");
  123. qsort(P, (size_t) PN, sizeof(POINT), edge_order);
  124. Menu_msg("");
  125. return (1);
  126. }