1 /*
2 Copyright (c) <2007-2012> <Barbara Philippot - Olivier Courtin>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 IN THE SOFTWARE.
21 */
22
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <assert.h>
27 #include <float.h>
28 #include <math.h>
29 #include <string.h>
30
31 #include "ows.h"
32
33
34 /*
35 * Initialize a geobbox structure
36 */
ows_geobbox_init()37 ows_geobbox *ows_geobbox_init()
38 {
39 ows_geobbox *g;
40
41 g = malloc(sizeof(ows_geobbox));
42 assert(g != NULL);
43
44 g->west = DBL_MIN;
45 g->east = DBL_MIN;
46 g->south = DBL_MIN;
47 g->north = DBL_MIN;
48
49 return g;
50 }
51
52
53 /*
54 * Clone a geobbox
55 */
ows_geobbox_copy(ows_geobbox * g)56 ows_geobbox *ows_geobbox_copy(ows_geobbox *g)
57 {
58 ows_geobbox *c;
59
60 assert(g);
61 c = malloc(sizeof(g));
62 return memcpy(c, g, sizeof(g));
63 }
64
65
66 /*
67 * Free a geobbox structure
68 */
ows_geobbox_free(ows_geobbox * g)69 void ows_geobbox_free(ows_geobbox *g)
70 {
71 assert(g);
72 free(g);
73 g = NULL;
74 }
75
76
77 /*
78 * Set a given geobbox with null area and earth limits tests
79 */
ows_geobbox_set(ows * o,ows_geobbox * g,double west,double east,double south,double north)80 bool ows_geobbox_set(ows * o, ows_geobbox * g, double west, double east, double south, double north)
81 {
82 double geom_tolerance = 0.01;
83
84 assert(g);
85
86 if (south + geom_tolerance < -90.0 || south - geom_tolerance > 90.0 ||
87 north + geom_tolerance < -90.0 || north - geom_tolerance > 90.0 ||
88 east + geom_tolerance < -180.0 || east - geom_tolerance > 180.0 ||
89 west + geom_tolerance < -180.0 || west - geom_tolerance > 180.0)
90 return false;
91
92 if (fabs(south - north) < DBL_EPSILON || fabs(east - west) < DBL_EPSILON)
93 return false;
94
95 /* TODO add a test to see if north is northern than south and so forth... */
96 g->west = west;
97 g->east = east;
98 g->south = south;
99 g->north = north;
100
101 return true;
102 }
103
104
105 /*
106 * Set a given geobbox from a bbox
107 */
ows_geobbox_set_from_bbox(ows * o,ows_geobbox * g,ows_bbox * bb)108 bool ows_geobbox_set_from_bbox(ows * o, ows_geobbox * g, ows_bbox * bb)
109 {
110 double west, east, south, north;
111
112 assert(g);
113 assert(bb);
114
115 if (bb->ymin < 0.0 && bb->ymax < 0.0) {
116 south = bb->ymax;
117 north = bb->ymin;
118 west = bb->xmax;
119 east = bb->xmin;
120 } else {
121 south = bb->ymin;
122 north = bb->ymax;
123 west = bb->xmin;
124 east = bb->xmax;
125 }
126
127 return ows_geobbox_set(o, g, west, east, south, north);
128 }
129
130
131 /*
132 * Set a given geobbox from a string like 'xmin,ymin,xmax,ymax'
133 */
ows_geobbox_set_from_str(ows * o,ows_geobbox * g,char * str)134 ows_geobbox *ows_geobbox_set_from_str(ows * o, ows_geobbox * g, char *str)
135 {
136 ows_bbox *bb;
137
138 assert(g);
139 assert(str);
140
141 bb = ows_bbox_init();
142 ows_bbox_set_from_str(o, bb, str, 4326);
143 ows_geobbox_set_from_bbox(o, g, bb);
144 ows_bbox_free(bb);
145
146 return g;
147 }
148
149
150 /*
151 * Set a geobbox matching a layer's extent
152 */
ows_geobbox_compute(ows * o,buffer * layer_name)153 ows_geobbox *ows_geobbox_compute(ows * o, buffer * layer_name)
154 {
155 double xmin, ymin, xmax, ymax;
156 buffer *sql;
157 PGresult *res;
158 ows_geobbox *g;
159 ows_bbox *bb;
160 list *geom;
161 list_node *ln;
162 bool first = true;
163
164 assert(o);
165 assert(layer_name);
166
167 sql = buffer_init();
168
169 geom = ows_psql_geometry_column(o, layer_name);
170 assert(geom);
171
172 g = ows_geobbox_init();
173 xmin = ymin = xmax = ymax = 0.0;
174
175 for (ln = geom->first; ln ; ln = ln->next) {
176 buffer_add_str(sql, "SELECT ST_xmin(g), ST_ymin(g), ST_xmax(g), ST_ymax(g) FROM ");
177 if (o->estimated_extent) {
178 buffer_add_str(sql, "(SELECT ST_Transform(ST_SetSRID(ST_Estimated_Extent('");
179 buffer_copy(sql, ows_psql_schema_name(o, layer_name));
180 buffer_add_str(sql, "','");
181 buffer_copy(sql, ows_psql_table_name(o, layer_name));
182 buffer_add_str(sql, "','");
183 buffer_copy(sql, ln->value);
184 buffer_add_str(sql, "'), (SELECT ST_SRID(\"");
185 buffer_copy(sql, ln->value);
186 buffer_add_str(sql, "\") FROM \"");
187 buffer_copy(sql, ows_psql_schema_name(o, layer_name));
188 buffer_add_str(sql, "\".\"");
189 buffer_copy(sql, ows_psql_table_name(o, layer_name));
190 buffer_add_str(sql, "\" LIMIT 1)) ,4326) AS g) AS foo");
191 } else {
192 buffer_add_str(sql, "(SELECT ST_Transform(ST_SetSRID(ST_Extent(\"");
193 buffer_copy(sql, ln->value);
194 buffer_add_str(sql, "\"), (SELECT ST_SRID(\"");
195 buffer_copy(sql, ln->value);
196 buffer_add_str(sql, "\") FROM \"");
197 buffer_copy(sql, ows_psql_schema_name(o, layer_name));
198 buffer_add_str(sql, "\".\"");
199 buffer_copy(sql, ows_psql_table_name(o, layer_name));
200 buffer_add_str(sql, "\" LIMIT 1)), 4326) AS g ");
201 buffer_add_str(sql, " FROM \"");
202 buffer_copy(sql, ows_psql_schema_name(o, layer_name));
203 buffer_add_str(sql, "\".\"");
204 buffer_copy(sql, ows_psql_table_name(o, layer_name));
205 buffer_add_str(sql, "\" ) AS foo");
206 }
207
208 res = ows_psql_exec(o, sql->buf);
209 buffer_empty(sql);
210 if (PQresultStatus(res) != PGRES_TUPLES_OK) {
211 PQclear(res);
212 buffer_free(sql);
213 return g;
214 }
215
216 if (first || atof(PQgetvalue(res, 0, 0)) < xmin) xmin = atof(PQgetvalue(res, 0, 0));
217 if (first || atof(PQgetvalue(res, 0, 1)) < ymin) ymin = atof(PQgetvalue(res, 0, 1));
218 if (first || atof(PQgetvalue(res, 0, 2)) > xmax) xmax = atof(PQgetvalue(res, 0, 2));
219 if (first || atof(PQgetvalue(res, 0, 3)) > ymax) ymax = atof(PQgetvalue(res, 0, 3));
220
221 first = false;
222 PQclear(res);
223 }
224
225 buffer_free(sql);
226
227 bb = ows_bbox_init();
228 ows_bbox_set(o, bb, xmin, ymin, xmax, ymax, 4326);
229 ows_geobbox_set_from_bbox(o, g, bb);
230 ows_bbox_free(bb);
231
232 return g;
233 }
234
235
236 #ifdef OWS_DEBUG
237 /*
238 * Flush bbox value to a file (mainly to debug purpose)
239 */
ows_geobbox_flush(const ows_geobbox * g,FILE * output)240 void ows_geobbox_flush(const ows_geobbox * g, FILE * output)
241 {
242 assert(g);
243 assert(output);
244
245 fprintf(output, "[W:%f,E:%f,S:%f,N:%f]\n", g->west, g->east, g->south, g->north);
246 }
247 #endif
248
249
250 /*
251 * vim: expandtab sw=4 ts=4
252 */
253