tinyows 1.2.2
ows_bbox.c
Go to the documentation of this file.
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 <string.h>
29#include <math.h>
30
31#include "ows.h"
32
33
34/*
35 * Initialize a bbox structure
36 */
38{
39 ows_bbox *b;
40
41 b = malloc(sizeof(ows_bbox));
42 assert(b);
43
44 b->xmin = -DBL_MAX + 1;
45 b->ymin = -DBL_MAX + 1;
46 b->xmax = DBL_MAX - 1;
47 b->ymax = DBL_MAX - 1;
48
49 b->srs = ows_srs_init();
50
51 return b;
52}
53
54
55/*
56 * Free a bbox structure
57 */
59{
60 assert(b);
61
62 ows_srs_free(b->srs);
63 free(b);
64 b = NULL;
65}
66
67
68/*
69 * Set a given bbox with null area test
70 */
71bool ows_bbox_set(ows * o, ows_bbox * b, double xmin, double ymin, double xmax, double ymax, int srid)
72{
73 assert(o && b);
74
75 if (xmin >= xmax || ymin >= ymax) return false;
76
77 if ( fabs(xmin - DBL_MAX) < DBL_EPSILON
78 || fabs(ymin - DBL_MAX) < DBL_EPSILON
79 || fabs(xmax - DBL_MAX) < DBL_EPSILON
80 || fabs(ymax - DBL_MAX) < DBL_EPSILON) return false;
81
82 b->xmin = xmin;
83 b->xmax = xmax;
84 b->ymin = ymin;
85 b->ymax = ymax;
86
87 if (srid == 4326) return ows_srs_set_geobbox(o, b->srs);
88
89 return ows_srs_set_from_srid(o, b->srs, srid);
90}
91
92
93/*
94 * Set a given bbox from a string like 'xmin,ymin,xmax,ymax'
95 */
96bool ows_bbox_set_from_str(ows * o, ows_bbox * bb, const char *str, int srid,
97 bool honours_authority_axis_order_if_no_explicit_srs)
98{
99 double xmin, ymin, xmax, ymax;
100 buffer *b;
101 list *l;
102 bool ret;
103
104 assert(o && bb && str);
105
106 b = buffer_init();
107 buffer_add_str(b, str);
108 l = list_explode(',', b);
109 buffer_free(b);
110
111 /* srs is optional since WFS 1.1 */
112 if (l->size < 4 || l->size > 5) {
113 list_free(l);
114 return false;
115 }
116
117 xmin = strtod(l->first->value->buf, NULL);
118 ymin = strtod(l->first->next->value->buf, NULL);
119 xmax = strtod(l->first->next->next->value->buf, NULL);
120 ymax = strtod(l->first->next->next->next->value->buf, NULL);
121 /* FIXME error handling */
122
123 /* srs is optional since WFS 1.1 */
124 if (l->size == 5) {
125 ows_srs* s = ows_srs_init();
126 ret = ows_srs_set_from_srsname(o, s, l->last->value->buf);
127 if (ret)
128 {
129 srid = s->srid;
130 ret = ows_bbox_set(o, bb, xmin, ymin, xmax, ymax, srid);
131 ows_srs_free(bb->srs);
132 bb->srs = s;
133 } else {
134 ows_srs_free(s);
135 }
136
137 } else {
138 ret = ows_bbox_set(o, bb, xmin, ymin, xmax, ymax, srid);
139 bb->srs->honours_authority_axis_order = honours_authority_axis_order_if_no_explicit_srs;
140 }
141
142 list_free(l);
143
144 return ret;
145}
146
147
148/*
149 * Set a given bbox matching a feature collection's outerboundaries
150 * or a simple feature's outerboundaries
151 * Bbox is set from a list containing one or several layer names
152 * and optionnaly one or several WHERE SQL statement following each layer name
153 */
154ows_bbox *ows_bbox_boundaries(ows * o, list * from, list * where, ows_srs * srs)
155{
156 ows_bbox *bb;
157 buffer *sql;
158 list *geom;
159 list_node *ln_from, *ln_where, *ln_geom;
160 PGresult *res;
161
162 assert(o && from && where && srs);
163
164 bb = ows_bbox_init();
165
166 if (from->size != where->size) return bb;
167
168 sql = buffer_init();
169 /* Put into a buffer the SQL request calculating an extent */
170 buffer_add_str(sql, "SELECT ST_xmin(g.extent), ST_ymin(g.extent), ST_xmax(g.extent), ST_ymax(g.extent) FROM ");
171 buffer_add_str(sql, "(SELECT ST_Extent(foo.the_geom) as extent FROM ( ");
172
173 /* For each layer name or each geometry column, make an union between retrieved features */
174 for (ln_from = from->first, ln_where = where->first;
175 ln_from;
176 ln_from = ln_from->next, ln_where = ln_where->next) {
177
178 geom = ows_psql_geometry_column(o, ln_from->value);
179
180 for (ln_geom = geom->first ; ln_geom ; ln_geom = ln_geom->next) {
181 buffer_add_str(sql, " (SELECT ST_Transform(\"");
182 buffer_copy(sql, ln_geom->value);
183 buffer_add_str(sql, "\"::geometry, ");
184 buffer_add_int(sql, srs->srid);
185 buffer_add_str(sql, ") AS \"the_geom\" FROM \"");
186 buffer_copy(sql, ows_psql_schema_name(o, ln_from->value));
187 buffer_add_str(sql, "\".\"");
188 buffer_copy(sql, ows_psql_table_name(o, ln_from->value));
189 buffer_add_str(sql, "\" ");
190 buffer_copy(sql, ln_where->value);
191 buffer_add_str(sql, ")");
192
193 if (ln_geom->next) buffer_add_str(sql, " UNION ALL ");
194 }
195
196 if (ln_from->next) buffer_add_str(sql, " UNION ALL ");
197 }
198
199 buffer_add_str(sql, " ) AS foo) AS g");
200
201 res = ows_psql_exec(o, sql->buf);
202 buffer_free(sql);
203
204 if (PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != 4) {
205 PQclear(res);
206 return bb;
207 }
208
209 bb->xmin = strtod(PQgetvalue(res, 0, 0), NULL);
210 bb->ymin = strtod(PQgetvalue(res, 0, 1), NULL);
211 bb->xmax = strtod(PQgetvalue(res, 0, 2), NULL);
212 bb->ymax = strtod(PQgetvalue(res, 0, 3), NULL);
213 /* FIXME Error handling */
214
215 ows_srs_copy(bb->srs, srs);
216
217 PQclear(res);
218 return bb;
219}
220
221
222/*
223 * Transform a bbox from initial srid to another srid passed in parameter
224 */
225bool ows_bbox_transform(ows * o, ows_bbox * bb, int srid)
226{
227 buffer *sql;
228 PGresult *res;
229
230 assert(o && bb);
231
232 sql = buffer_init();
233 buffer_add_str(sql, "SELECT xmin(g), ymin(g), xmax(g), ymax(g) FROM (SELECT ST_Transform(");
234 ows_bbox_to_query(o, bb, sql);
235 buffer_add_str(sql, ")) AS g ) AS foo");
236
237 res = ows_psql_exec(o, sql->buf);
238 buffer_free(sql);
239
240 if (PQresultStatus(res) != PGRES_TUPLES_OK) {
241 PQclear(res);
242 return false;
243 }
244
245 bb->xmin = strtod(PQgetvalue(res, 0, 0), NULL);
246 bb->ymin = strtod(PQgetvalue(res, 0, 1), NULL);
247 bb->xmax = strtod(PQgetvalue(res, 0, 2), NULL);
248 bb->ymax = strtod(PQgetvalue(res, 0, 3), NULL);
249 /* FIXME Error Handling */
250
251 return ows_srs_set_from_srid(o, bb->srs, srid);
252}
253
254
255/*
256 * Transform a geobbox into a bbox
257 */
259{
260 assert(bb && geo);
261
262 if (geo->west < geo->east) {
263 bb->xmin = geo->west;
264 bb->xmax = geo->east;
265 } else {
266 bb->xmax = geo->west;
267 bb->xmin = geo->east;
268 }
269
270 if (geo->north < geo->south) {
271 bb->ymin = geo->north;
272 bb->ymax = geo->south;
273 } else {
274 bb->ymax = geo->north;
275 bb->ymin = geo->south;
276 }
277
278 return ows_srs_set_geobbox(o, bb->srs);
279}
280
281
282/*
283 * Convert a bbox to PostGIS query Polygon
284 */
285void ows_bbox_to_query(ows *o, ows_bbox *bbox, buffer *query)
286{
287 double x1, y1, x2, y2;
288
289 assert(o && bbox && query);
290
292 x1 = bbox->ymin;
293 y1 = bbox->xmin;
294 x2 = bbox->ymax;
295 y2 = bbox->xmax;
296 } else {
297 x1 = bbox->xmin;
298 y1 = bbox->ymin;
299 x2 = bbox->xmax;
300 y2 = bbox->ymax;
301 }
302
303 /* We use explicit POLYGON geometry rather than BBOX
304 related to precision handle (Float4 vs Double) */
305 buffer_add_str(query, "'SRID=");
306 buffer_add_int(query, bbox->srs->srid);
307 buffer_add_str(query, ";POLYGON((");
308 buffer_add_double(query, x1);
309 buffer_add_str(query, " ");
310 buffer_add_double(query, y1);
311 buffer_add_str(query, ",");
312 buffer_add_double(query, x1);
313 buffer_add_str(query, " ");
314 buffer_add_double(query, y2);
315 buffer_add_str(query, ",");
316 buffer_add_double(query, x2);
317 buffer_add_str(query, " ");
318 buffer_add_double(query, y2);
319 buffer_add_str(query, ",");
320 buffer_add_double(query, x2);
321 buffer_add_str(query, " ");
322 buffer_add_double(query, y1);
323 buffer_add_str(query, ",");
324 buffer_add_double(query, x1);
325 buffer_add_str(query, " ");
326 buffer_add_double(query, y1);
327 buffer_add_str(query, "))'::geometry");
328
329 /* FIXME what about geography ? */
330}
331
332
333#ifdef OWS_DEBUG
334/*
335 * Flush bbox value to a file (mainly to debug purpose)
336 */
337void ows_bbox_flush(const ows_bbox * b, FILE * output)
338{
339 assert(b);
340
341 fprintf(output, "[%g,%g,%g,%g]\n", b->xmin, b->ymin, b->xmax, b->ymax);
342 ows_srs_flush(b->srs, output);
343}
344#endif
PGresult * ows_psql_exec(ows *o, const char *sql)
Definition ows_psql.c:56
void buffer_copy(buffer *dest, const buffer *src)
Definition buffer.c:350
ows_srs * ows_srs_init()
Definition ows_srs.c:37
list * ows_psql_geometry_column(ows *o, buffer *layer_name)
Definition ows_psql.c:76
void list_free(list *l)
Definition list.c:54
void buffer_add_str(buffer *buf, const char *str)
Definition buffer.c:254
bool ows_srs_set_from_srsname(ows *o, ows_srs *s, const char *srsname)
Definition ows_srs.c:303
void ows_bbox_flush(const ows_bbox *b, FILE *output)
void buffer_add_double(buffer *buf, double f)
Definition buffer.c:158
bool ows_srs_set_from_srid(ows *o, ows_srs *s, int srid)
Definition ows_srs.c:251
void ows_srs_flush(ows_srs *c, FILE *output)
void buffer_free(buffer *buf)
Definition buffer.c:83
void buffer_add_int(buffer *buf, int i)
Definition buffer.c:173
bool ows_srs_set_geobbox(ows *o, ows_srs *s)
Definition ows_srs.c:232
void ows_srs_free(ows_srs *c)
Definition ows_srs.c:76
buffer * buffer_init()
Definition buffer.c:61
buffer * ows_psql_table_name(ows *o, buffer *layer_name)
Definition ows_psql.c:116
list * list_explode(char separator, const buffer *value)
Definition list.c:296
ows_srs * ows_srs_copy(ows_srs *d, ows_srs *s)
Definition ows_srs.c:56
buffer * ows_psql_schema_name(ows *o, buffer *layer_name)
Definition ows_psql.c:96
void ows_bbox_free(ows_bbox *b)
Definition ows_bbox.c:58
ows_bbox * ows_bbox_init()
Definition ows_bbox.c:37
bool ows_bbox_set_from_geobbox(ows *o, ows_bbox *bb, ows_geobbox *geo)
Definition ows_bbox.c:258
ows_bbox * ows_bbox_boundaries(ows *o, list *from, list *where, ows_srs *srs)
Definition ows_bbox.c:154
bool ows_bbox_transform(ows *o, ows_bbox *bb, int srid)
Definition ows_bbox.c:225
void ows_bbox_to_query(ows *o, ows_bbox *bbox, buffer *query)
Definition ows_bbox.c:285
bool ows_bbox_set_from_str(ows *o, ows_bbox *bb, const char *str, int srid, bool honours_authority_axis_order_if_no_explicit_srs)
Definition ows_bbox.c:96
bool ows_bbox_set(ows *o, ows_bbox *b, double xmin, double ymin, double xmax, double ymax, int srid)
Definition ows_bbox.c:71
struct List_node list_node
struct Buffer buffer
struct Ows ows
struct Ows_srs ows_srs
struct Ows_bbox ows_bbox
struct Ows_geobbox ows_geobbox
struct List list
char * buf
size to next realloc
Definition ows_struct.h:39
struct List_node * next
Definition ows_struct.h:45
buffer * value
Definition ows_struct.h:44
unsigned int size
Definition ows_struct.h:52
list_node * last
Definition ows_struct.h:51
list_node * first
Definition ows_struct.h:50
ows_srs * srs
Definition ows_struct.h:139
double xmax
Definition ows_struct.h:137
double ymin
Definition ows_struct.h:136
double ymax
Definition ows_struct.h:138
double xmin
Definition ows_struct.h:135
double east
Definition ows_struct.h:143
double south
Definition ows_struct.h:145
double north
Definition ows_struct.h:146
double west
Definition ows_struct.h:144
bool honours_authority_axis_order
Definition ows_struct.h:126
bool is_axis_order_gis_friendly
Definition ows_struct.h:118

Generated for tinyows by doxygen 1.13.2