GRASS GIS 8 Programmer's Manual 8.2.1(2023)-exported
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
11static 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
23static 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
54void 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}
void G_free(void *buf)
Free allocated memory.
Definition: alloc.c:149
#define NULL
Definition: ccmath.h:32
struct html_state html
void html_polygon(const struct path *p)
#define RAD_DEG
int count
char * G_store(const char *s)
Copy string to allocated memory.
Definition: strings.c:87
int num_pts
Definition: htmlmap.h:21
int MAX_POINTS
Definition: htmlmap.h:35
char * last_text
Definition: htmlmap.h:29
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
int count
Definition: path.h:18
struct vertex * vertices
Definition: path.h:17
double x
Definition: path.h:12
double y
Definition: path.h:12
#define x