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