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