/src/MapServer/src/mapuvraster.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************** |
2 | | * $Id: mapuv.c 12629 2011-10-06 18:06:34Z aboudreault $ |
3 | | * |
4 | | * Project: MapServer |
5 | | * Purpose: UV Layer |
6 | | * Author: Alan Boudreault (aboudreault@mapgears.com) |
7 | | * |
8 | | ********************************************************************** |
9 | | * Copyright (c) 2011, Alan Boudreault, MapGears |
10 | | * |
11 | | * Permission is hereby granted, free of charge, to any person obtaining a |
12 | | * copy of this software and associated documentation files (the "Software"), |
13 | | * to deal in the Software without restriction, including without limitation |
14 | | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
15 | | * and/or sell copies of the Software, and to permit persons to whom the |
16 | | * Software is furnished to do so, subject to the following conditions: |
17 | | * |
18 | | * The above copyright notice and this permission notice shall be included in |
19 | | * all copies of this Software or works derived from this Software. |
20 | | * |
21 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
22 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
23 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
24 | | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
25 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
26 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
27 | | * DEALINGS IN THE SOFTWARE. |
28 | | **********************************************************************/ |
29 | | |
30 | | #include "mapserver.h" |
31 | | |
32 | | #include <assert.h> |
33 | | #include <math.h> |
34 | | #include <stdbool.h> |
35 | | #include "mapows.h" |
36 | | #include "mapresample.h" |
37 | | #include "mapthread.h" |
38 | | |
39 | | #include <cmath> |
40 | | #include <limits> |
41 | | |
42 | | #define MSUVRASTER_NUMITEMS 6 |
43 | 0 | #define MSUVRASTER_ANGLE "uv_angle" |
44 | 0 | #define MSUVRASTER_ANGLEINDEX -100 |
45 | 0 | #define MSUVRASTER_MINUS_ANGLE "uv_minus_angle" |
46 | 0 | #define MSUVRASTER_MINUSANGLEINDEX -101 |
47 | 0 | #define MSUVRASTER_LENGTH "uv_length" |
48 | 0 | #define MSUVRASTER_LENGTHINDEX -102 |
49 | 0 | #define MSUVRASTER_LENGTH_2 "uv_length_2" |
50 | 0 | #define MSUVRASTER_LENGTH2INDEX -103 |
51 | 0 | #define MSUVRASTER_U "u" |
52 | 0 | #define MSUVRASTER_UINDEX -104 |
53 | 0 | #define MSUVRASTER_V "v" |
54 | 0 | #define MSUVRASTER_VINDEX -105 |
55 | 0 | #define MSUVRASTER_LON "lon" |
56 | 0 | #define MSUVRASTER_LONINDEX -106 |
57 | 0 | #define MSUVRASTER_LAT "lat" |
58 | 0 | #define MSUVRASTER_LATINDEX -107 |
59 | | |
60 | | typedef struct { |
61 | | |
62 | | /* query cache results */ |
63 | | int query_results; |
64 | | |
65 | | int refcount; |
66 | | |
67 | | float *u; /* u values */ |
68 | | float *v; /* v values */ |
69 | | int width; |
70 | | int height; |
71 | | rectObj extent; |
72 | | int next_shape; |
73 | | |
74 | | /* To improve performance of GetShape() when queried on increasing shapeindex |
75 | | */ |
76 | | long last_queried_shapeindex; // value in [0, query_results[ range |
77 | | size_t last_raster_off; // value in [0, width*height[ range |
78 | | |
79 | | bool needsLonLat; |
80 | | reprojectionObj *reprojectorToLonLat; |
81 | | |
82 | | mapObj |
83 | | *mapToUseForWhichShapes; /* set if the map->extent and map->projection are |
84 | | valid in msUVRASTERLayerWhichShapes() */ |
85 | | |
86 | | } uvRasterLayerInfo; |
87 | | |
88 | | void msUVRASTERLayerUseMapExtentAndProjectionForNextWhichShapes(layerObj *layer, |
89 | 0 | mapObj *map) { |
90 | 0 | uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; |
91 | 0 | uvlinfo->mapToUseForWhichShapes = map; |
92 | 0 | } |
93 | | |
94 | 0 | static int msUVRASTERLayerInitItemInfo(layerObj *layer) { |
95 | 0 | uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; |
96 | 0 | int i; |
97 | 0 | int *itemindexes; |
98 | 0 | int failed = 0; |
99 | |
|
100 | 0 | if (layer->numitems == 0) |
101 | 0 | return MS_SUCCESS; |
102 | | |
103 | 0 | if (uvlinfo == NULL) { |
104 | 0 | msSetError(MS_MISCERR, "Assertion failed: GDAL layer not opened!!!", |
105 | 0 | "msUVRASTERLayerInitItemInfo()"); |
106 | 0 | return (MS_FAILURE); |
107 | 0 | } |
108 | | |
109 | 0 | if (layer->iteminfo) |
110 | 0 | free(layer->iteminfo); |
111 | |
|
112 | 0 | if ((layer->iteminfo = (int *)malloc(sizeof(int) * layer->numitems)) == |
113 | 0 | NULL) { |
114 | 0 | msSetError(MS_MEMERR, NULL, "msUVRASTERLayerInitItemInfo()"); |
115 | 0 | return (MS_FAILURE); |
116 | 0 | } |
117 | | |
118 | 0 | itemindexes = (int *)layer->iteminfo; |
119 | 0 | for (i = 0; i < layer->numitems; i++) { |
120 | | /* Special attribute names. */ |
121 | 0 | if (EQUAL(layer->items[i], MSUVRASTER_ANGLE)) |
122 | 0 | itemindexes[i] = MSUVRASTER_ANGLEINDEX; |
123 | 0 | else if (EQUAL(layer->items[i], MSUVRASTER_MINUS_ANGLE)) |
124 | 0 | itemindexes[i] = MSUVRASTER_MINUSANGLEINDEX; |
125 | 0 | else if (EQUAL(layer->items[i], MSUVRASTER_LENGTH)) |
126 | 0 | itemindexes[i] = MSUVRASTER_LENGTHINDEX; |
127 | 0 | else if (EQUAL(layer->items[i], MSUVRASTER_LENGTH_2)) |
128 | 0 | itemindexes[i] = MSUVRASTER_LENGTH2INDEX; |
129 | 0 | else if (EQUAL(layer->items[i], MSUVRASTER_U)) |
130 | 0 | itemindexes[i] = MSUVRASTER_UINDEX; |
131 | 0 | else if (EQUAL(layer->items[i], MSUVRASTER_V)) |
132 | 0 | itemindexes[i] = MSUVRASTER_VINDEX; |
133 | 0 | else if (EQUAL(layer->items[i], MSUVRASTER_LON)) { |
134 | 0 | uvlinfo->needsLonLat = true; |
135 | 0 | itemindexes[i] = MSUVRASTER_LONINDEX; |
136 | 0 | } else if (EQUAL(layer->items[i], MSUVRASTER_LAT)) { |
137 | 0 | uvlinfo->needsLonLat = true; |
138 | 0 | itemindexes[i] = MSUVRASTER_LATINDEX; |
139 | 0 | } else { |
140 | 0 | itemindexes[i] = -1; |
141 | 0 | msSetError(MS_MISCERR, "Invalid Field name: %s", |
142 | 0 | "msUVRASTERLayerInitItemInfo()", layer->items[i]); |
143 | 0 | failed = 1; |
144 | 0 | } |
145 | 0 | } |
146 | |
|
147 | 0 | return failed ? (MS_FAILURE) : (MS_SUCCESS); |
148 | 0 | } |
149 | | |
150 | 0 | void msUVRASTERLayerFreeItemInfo(layerObj *layer) { |
151 | 0 | if (layer->iteminfo) |
152 | 0 | free(layer->iteminfo); |
153 | 0 | layer->iteminfo = NULL; |
154 | 0 | } |
155 | | |
156 | 0 | static void msUVRasterLayerInfoInitialize(layerObj *layer) { |
157 | 0 | uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; |
158 | |
|
159 | 0 | if (uvlinfo != NULL) |
160 | 0 | return; |
161 | | |
162 | 0 | uvlinfo = (uvRasterLayerInfo *)msSmallCalloc(1, sizeof(uvRasterLayerInfo)); |
163 | 0 | layer->layerinfo = uvlinfo; |
164 | |
|
165 | 0 | uvlinfo->u = NULL; |
166 | 0 | uvlinfo->v = NULL; |
167 | 0 | uvlinfo->width = 0; |
168 | 0 | uvlinfo->height = 0; |
169 | | |
170 | | /* Set attribute type to Real, unless the user has explicitly set */ |
171 | | /* something else. */ |
172 | 0 | { |
173 | 0 | const char *const items[] = { |
174 | 0 | MSUVRASTER_ANGLE, MSUVRASTER_MINUS_ANGLE, MSUVRASTER_LENGTH, |
175 | 0 | MSUVRASTER_LENGTH_2, MSUVRASTER_U, MSUVRASTER_V, |
176 | 0 | }; |
177 | 0 | size_t i; |
178 | 0 | for (i = 0; i < sizeof(items) / sizeof(items[0]); ++i) { |
179 | 0 | char szTmp[100]; |
180 | 0 | snprintf(szTmp, sizeof(szTmp), "%s_type", items[i]); |
181 | 0 | if (msOWSLookupMetadata(&(layer->metadata), "OFG", szTmp) == NULL) { |
182 | 0 | snprintf(szTmp, sizeof(szTmp), "gml_%s_type", items[i]); |
183 | 0 | msInsertHashTable(&(layer->metadata), szTmp, "Real"); |
184 | 0 | } |
185 | 0 | } |
186 | 0 | } |
187 | 0 | } |
188 | | |
189 | | static void msUVRasterLayerInfoFree(layerObj *layer) |
190 | | |
191 | 0 | { |
192 | 0 | uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; |
193 | |
|
194 | 0 | if (uvlinfo == NULL) |
195 | 0 | return; |
196 | | |
197 | 0 | free(uvlinfo->u); |
198 | 0 | free(uvlinfo->v); |
199 | |
|
200 | 0 | if (uvlinfo->reprojectorToLonLat) { |
201 | 0 | msProjectDestroyReprojector(uvlinfo->reprojectorToLonLat); |
202 | 0 | } |
203 | |
|
204 | 0 | free(uvlinfo); |
205 | |
|
206 | 0 | layer->layerinfo = NULL; |
207 | 0 | } |
208 | | |
209 | 0 | int msUVRASTERLayerOpen(layerObj *layer) { |
210 | | /* If we don't have info, initialize an empty one now */ |
211 | 0 | if (layer->layerinfo == NULL) |
212 | 0 | msUVRasterLayerInfoInitialize(layer); |
213 | 0 | if (layer->layerinfo == NULL) |
214 | 0 | return MS_FAILURE; |
215 | | |
216 | 0 | uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; |
217 | |
|
218 | 0 | uvlinfo->refcount = uvlinfo->refcount + 1; |
219 | |
|
220 | 0 | return MS_SUCCESS; |
221 | 0 | } |
222 | | |
223 | 0 | int msUVRASTERLayerIsOpen(layerObj *layer) { |
224 | 0 | if (layer->layerinfo) |
225 | 0 | return MS_TRUE; |
226 | 0 | return MS_FALSE; |
227 | 0 | } |
228 | | |
229 | 0 | int msUVRASTERLayerClose(layerObj *layer) { |
230 | 0 | uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; |
231 | |
|
232 | 0 | if (uvlinfo != NULL) { |
233 | 0 | uvlinfo->refcount--; |
234 | |
|
235 | 0 | if (uvlinfo->refcount < 1) |
236 | 0 | msUVRasterLayerInfoFree(layer); |
237 | 0 | } |
238 | 0 | return MS_SUCCESS; |
239 | 0 | } |
240 | | |
241 | 0 | int msUVRASTERLayerGetItems(layerObj *layer) { |
242 | 0 | uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; |
243 | |
|
244 | 0 | if (uvlinfo == NULL) |
245 | 0 | return MS_FAILURE; |
246 | | |
247 | 0 | layer->numitems = 0; |
248 | 0 | layer->items = (char **)msSmallCalloc(sizeof(char *), 10); |
249 | |
|
250 | 0 | layer->items[layer->numitems++] = msStrdup(MSUVRASTER_ANGLE); |
251 | 0 | layer->items[layer->numitems++] = msStrdup(MSUVRASTER_MINUS_ANGLE); |
252 | 0 | layer->items[layer->numitems++] = msStrdup(MSUVRASTER_LENGTH); |
253 | 0 | layer->items[layer->numitems++] = msStrdup(MSUVRASTER_LENGTH_2); |
254 | 0 | layer->items[layer->numitems++] = msStrdup(MSUVRASTER_U); |
255 | 0 | layer->items[layer->numitems++] = msStrdup(MSUVRASTER_V); |
256 | 0 | layer->items[layer->numitems++] = msStrdup(MSUVRASTER_LON); |
257 | 0 | layer->items[layer->numitems++] = msStrdup(MSUVRASTER_LAT); |
258 | 0 | layer->items[layer->numitems] = NULL; |
259 | |
|
260 | 0 | return msUVRASTERLayerInitItemInfo(layer); |
261 | 0 | } |
262 | | |
263 | | /********************************************************************** |
264 | | * msUVRASTERGetValues() |
265 | | * |
266 | | * Special attribute names are used to return some UV params: uv_angle, |
267 | | * uv_length, u and v. |
268 | | **********************************************************************/ |
269 | | static char **msUVRASTERGetValues(layerObj *layer, float u, float v, |
270 | 0 | const pointObj *point) { |
271 | 0 | char **values; |
272 | 0 | int i = 0; |
273 | 0 | char tmp[100]; |
274 | 0 | float size_scale; |
275 | 0 | int *itemindexes = (int *)layer->iteminfo; |
276 | 0 | uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; |
277 | 0 | double lon = HUGE_VAL; |
278 | 0 | double lat = HUGE_VAL; |
279 | |
|
280 | 0 | if (layer->numitems == 0) |
281 | 0 | return (NULL); |
282 | | |
283 | 0 | if (!layer->iteminfo) { /* Should not happen... but just in case! */ |
284 | 0 | if (msUVRASTERLayerInitItemInfo(layer) != MS_SUCCESS) |
285 | 0 | return NULL; |
286 | 0 | itemindexes = (int *)layer->iteminfo; /* reassign after malloc */ |
287 | 0 | } |
288 | | |
289 | 0 | if ((values = (char **)malloc(sizeof(char *) * layer->numitems)) == NULL) { |
290 | 0 | msSetError(MS_MEMERR, NULL, "msUVRASTERGetValues()"); |
291 | 0 | return (NULL); |
292 | 0 | } |
293 | | |
294 | | /* -------------------------------------------------------------------- */ |
295 | | /* Determine desired size_scale. Default to 1 if not otherwise set */ |
296 | | /* -------------------------------------------------------------------- */ |
297 | 0 | size_scale = 1; |
298 | 0 | if (CSLFetchNameValue(layer->processing, "UV_SIZE_SCALE") != NULL) { |
299 | 0 | size_scale = atof(CSLFetchNameValue(layer->processing, "UV_SIZE_SCALE")); |
300 | 0 | } |
301 | |
|
302 | 0 | if (uvlinfo->needsLonLat) { |
303 | 0 | if (uvlinfo->reprojectorToLonLat == NULL) |
304 | 0 | uvlinfo->reprojectorToLonLat = |
305 | 0 | msProjectCreateReprojector(&layer->projection, NULL); |
306 | 0 | if (uvlinfo->reprojectorToLonLat) { |
307 | 0 | pointObj pointWrk = *point; |
308 | 0 | if (msProjectPointEx(uvlinfo->reprojectorToLonLat, &pointWrk) == |
309 | 0 | MS_SUCCESS) { |
310 | 0 | lon = pointWrk.x; |
311 | 0 | lat = pointWrk.y; |
312 | 0 | } |
313 | 0 | } |
314 | 0 | } |
315 | |
|
316 | 0 | for (i = 0; i < layer->numitems; i++) { |
317 | 0 | if (itemindexes[i] == MSUVRASTER_ANGLEINDEX) { |
318 | 0 | snprintf(tmp, 100, "%f", (atan2((double)v, (double)u) * 180 / MS_PI)); |
319 | 0 | values[i] = msStrdup(tmp); |
320 | 0 | } else if (itemindexes[i] == MSUVRASTER_MINUSANGLEINDEX) { |
321 | 0 | double minus_angle; |
322 | 0 | minus_angle = (atan2((double)v, (double)u) * 180 / MS_PI) + 180; |
323 | 0 | if (minus_angle >= 360) |
324 | 0 | minus_angle -= 360; |
325 | 0 | snprintf(tmp, 100, "%f", minus_angle); |
326 | 0 | values[i] = msStrdup(tmp); |
327 | 0 | } else if ((itemindexes[i] == MSUVRASTER_LENGTHINDEX) || |
328 | 0 | (itemindexes[i] == MSUVRASTER_LENGTH2INDEX)) { |
329 | 0 | float length = sqrt((u * u) + (v * v)) * size_scale; |
330 | |
|
331 | 0 | if (itemindexes[i] == MSUVRASTER_LENGTHINDEX) |
332 | 0 | snprintf(tmp, 100, "%f", length); |
333 | 0 | else |
334 | 0 | snprintf(tmp, 100, "%f", length / 2); |
335 | |
|
336 | 0 | values[i] = msStrdup(tmp); |
337 | 0 | } else if (itemindexes[i] == MSUVRASTER_UINDEX) { |
338 | 0 | snprintf(tmp, 100, "%f", u); |
339 | 0 | values[i] = msStrdup(tmp); |
340 | 0 | } else if (itemindexes[i] == MSUVRASTER_VINDEX) { |
341 | 0 | snprintf(tmp, 100, "%f", v); |
342 | 0 | values[i] = msStrdup(tmp); |
343 | 0 | } else if (itemindexes[i] == MSUVRASTER_LONINDEX) { |
344 | 0 | snprintf(tmp, sizeof(tmp), "%.18g", lon); |
345 | 0 | values[i] = msStrdup(tmp); |
346 | 0 | } else if (itemindexes[i] == MSUVRASTER_LATINDEX) { |
347 | 0 | snprintf(tmp, sizeof(tmp), "%.18g", lat); |
348 | 0 | values[i] = msStrdup(tmp); |
349 | 0 | } else { |
350 | 0 | values[i] = NULL; |
351 | 0 | } |
352 | 0 | } |
353 | |
|
354 | 0 | return values; |
355 | 0 | } |
356 | | |
357 | 0 | rectObj msUVRASTERGetSearchRect(layerObj *layer, mapObj *map) { |
358 | 0 | rectObj searchrect = map->extent; |
359 | 0 | int bDone = MS_FALSE; |
360 | | |
361 | | /* For UVRaster, it is important that the searchrect is not too large */ |
362 | | /* to avoid insufficient intermediate raster resolution, which could */ |
363 | | /* happen if we use the default code path, given potential reprojection */ |
364 | | /* issues when using a map extent that is not in the validity area of */ |
365 | | /* the layer projection. */ |
366 | 0 | if (!layer->projection.gt.need_geotransform && |
367 | 0 | !(msProjIsGeographicCRS(&(map->projection)) && |
368 | 0 | msProjIsGeographicCRS(&(layer->projection)))) { |
369 | 0 | rectObj layer_ori_extent; |
370 | |
|
371 | 0 | if (msLayerGetExtent(layer, &layer_ori_extent) == MS_SUCCESS) { |
372 | 0 | projectionObj map_proj; |
373 | |
|
374 | 0 | double map_extent_minx = map->extent.minx; |
375 | 0 | double map_extent_miny = map->extent.miny; |
376 | 0 | double map_extent_maxx = map->extent.maxx; |
377 | 0 | double map_extent_maxy = map->extent.maxy; |
378 | 0 | rectObj layer_extent = layer_ori_extent; |
379 | | |
380 | | /* Create a variant of map->projection without geotransform for */ |
381 | | /* conveniency */ |
382 | 0 | msInitProjection(&map_proj); |
383 | 0 | msCopyProjection(&map_proj, &map->projection); |
384 | 0 | map_proj.gt.need_geotransform = MS_FALSE; |
385 | 0 | if (map->projection.gt.need_geotransform) { |
386 | 0 | map_extent_minx = |
387 | 0 | map->projection.gt.geotransform[0] + |
388 | 0 | map->projection.gt.geotransform[1] * map->extent.minx + |
389 | 0 | map->projection.gt.geotransform[2] * map->extent.miny; |
390 | 0 | map_extent_miny = |
391 | 0 | map->projection.gt.geotransform[3] + |
392 | 0 | map->projection.gt.geotransform[4] * map->extent.minx + |
393 | 0 | map->projection.gt.geotransform[5] * map->extent.miny; |
394 | 0 | map_extent_maxx = |
395 | 0 | map->projection.gt.geotransform[0] + |
396 | 0 | map->projection.gt.geotransform[1] * map->extent.maxx + |
397 | 0 | map->projection.gt.geotransform[2] * map->extent.maxy; |
398 | 0 | map_extent_maxy = |
399 | 0 | map->projection.gt.geotransform[3] + |
400 | 0 | map->projection.gt.geotransform[4] * map->extent.maxx + |
401 | 0 | map->projection.gt.geotransform[5] * map->extent.maxy; |
402 | 0 | } |
403 | | |
404 | | /* Reproject layer extent to map projection */ |
405 | 0 | msProjectRect(&layer->projection, &map_proj, &layer_extent); |
406 | |
|
407 | 0 | if (layer_extent.minx <= map_extent_minx && |
408 | 0 | layer_extent.miny <= map_extent_miny && |
409 | 0 | layer_extent.maxx >= map_extent_maxx && |
410 | 0 | layer_extent.maxy >= map_extent_maxy) { |
411 | | /* do nothing special if area to map is inside layer extent */ |
412 | 0 | } else { |
413 | 0 | if (layer_extent.minx >= map_extent_minx && |
414 | 0 | layer_extent.maxx <= map_extent_maxx && |
415 | 0 | layer_extent.miny >= map_extent_miny && |
416 | 0 | layer_extent.maxy <= map_extent_maxy) { |
417 | | /* if the area to map is larger than the layer extent, then */ |
418 | | /* use full layer extent and add some margin to reflect the */ |
419 | | /* proportion of the useful area over the requested bbox */ |
420 | 0 | double extra_x = (map_extent_maxx - map_extent_minx) / |
421 | 0 | (layer_extent.maxx - layer_extent.minx) * |
422 | 0 | (layer_ori_extent.maxx - layer_ori_extent.minx); |
423 | 0 | double extra_y = (map_extent_maxy - map_extent_miny) / |
424 | 0 | (layer_extent.maxy - layer_extent.miny) * |
425 | 0 | (layer_ori_extent.maxy - layer_ori_extent.miny); |
426 | 0 | searchrect.minx = layer_ori_extent.minx - extra_x / 2; |
427 | 0 | searchrect.maxx = layer_ori_extent.maxx + extra_x / 2; |
428 | 0 | searchrect.miny = layer_ori_extent.miny - extra_y / 2; |
429 | 0 | searchrect.maxy = layer_ori_extent.maxy + extra_y / 2; |
430 | 0 | } else { |
431 | | /* otherwise clip the map extent with the reprojected layer */ |
432 | | /* extent */ |
433 | 0 | searchrect.minx = MS_MAX(map_extent_minx, layer_extent.minx); |
434 | 0 | searchrect.maxx = MS_MIN(map_extent_maxx, layer_extent.maxx); |
435 | 0 | searchrect.miny = MS_MAX(map_extent_miny, layer_extent.miny); |
436 | 0 | searchrect.maxy = MS_MIN(map_extent_maxy, layer_extent.maxy); |
437 | | /* and reproject into the layer projection */ |
438 | 0 | msProjectRect(&map_proj, &layer->projection, &searchrect); |
439 | 0 | } |
440 | 0 | bDone = MS_TRUE; |
441 | 0 | } |
442 | |
|
443 | 0 | msFreeProjection(&map_proj); |
444 | 0 | } |
445 | 0 | } |
446 | |
|
447 | 0 | if (!bDone) |
448 | 0 | msProjectRect(&map->projection, &layer->projection, |
449 | 0 | &searchrect); /* project the searchrect to source coords */ |
450 | |
|
451 | 0 | return searchrect; |
452 | 0 | } |
453 | | |
454 | 0 | int msUVRASTERLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { |
455 | 0 | uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; |
456 | 0 | imageObj *image_tmp; |
457 | 0 | outputFormatObj *outputformat = NULL; |
458 | 0 | mapObj *map_tmp; |
459 | 0 | double map_cellsize; |
460 | 0 | unsigned int spacing; |
461 | 0 | int width, height; |
462 | 0 | char **alteredProcessing = NULL, *saved_layer_mask; |
463 | 0 | char **savedProcessing = NULL; |
464 | 0 | int bHasLonWrap = MS_FALSE; |
465 | 0 | double dfLonWrap = 0.0; |
466 | 0 | rectObj oldLayerExtent; |
467 | 0 | char *oldLayerData = NULL; |
468 | 0 | projectionObj oldLayerProjection; |
469 | 0 | int ret; |
470 | |
|
471 | 0 | memset(&oldLayerExtent, 0, sizeof(oldLayerExtent)); |
472 | 0 | memset(&oldLayerProjection, 0, sizeof(oldLayerProjection)); |
473 | |
|
474 | 0 | if (layer->debug) |
475 | 0 | msDebug("Entering msUVRASTERLayerWhichShapes().\n"); |
476 | |
|
477 | 0 | if (uvlinfo == NULL) |
478 | 0 | return MS_FAILURE; |
479 | | |
480 | 0 | if (CSLFetchNameValue(layer->processing, "BANDS") == NULL) { |
481 | 0 | msSetError(MS_MISCERR, |
482 | 0 | "BANDS processing option is required for UV layer. You have to " |
483 | 0 | "specified 2 bands.", |
484 | 0 | "msUVRASTERLayerWhichShapes()"); |
485 | 0 | return MS_FAILURE; |
486 | 0 | } |
487 | | |
488 | | /* |
489 | | ** Allocate mapObj structure |
490 | | */ |
491 | 0 | map_tmp = (mapObj *)msSmallCalloc(sizeof(mapObj), 1); |
492 | 0 | if (initMap(map_tmp) == -1) { /* initialize this map */ |
493 | 0 | msFree(map_tmp); |
494 | 0 | return (MS_FAILURE); |
495 | 0 | } |
496 | | |
497 | | /* -------------------------------------------------------------------- */ |
498 | | /* Determine desired spacing. Default to 32 if not otherwise set */ |
499 | | /* -------------------------------------------------------------------- */ |
500 | 0 | spacing = 32; |
501 | 0 | if (CSLFetchNameValue(layer->processing, "UV_SPACING") != NULL) { |
502 | 0 | spacing = atoi(CSLFetchNameValue(layer->processing, "UV_SPACING")); |
503 | 0 | if (spacing == 0) |
504 | 0 | spacing = 32; |
505 | 0 | } |
506 | |
|
507 | 0 | width = (int)(layer->map->width / spacing); |
508 | 0 | height = (int)(layer->map->height / spacing); |
509 | | |
510 | | /* Initialize our dummy map */ |
511 | 0 | MS_INIT_COLOR(map_tmp->imagecolor, 255, 255, 255, 255); |
512 | 0 | map_tmp->resolution = layer->map->resolution; |
513 | 0 | map_tmp->defresolution = layer->map->defresolution; |
514 | |
|
515 | 0 | outputformat = (outputFormatObj *)msSmallCalloc(1, sizeof(outputFormatObj)); |
516 | 0 | outputformat->bands = 2; |
517 | 0 | outputformat->name = NULL; |
518 | 0 | outputformat->driver = NULL; |
519 | 0 | outputformat->refcount = 0; |
520 | 0 | outputformat->vtable = NULL; |
521 | 0 | outputformat->device = NULL; |
522 | 0 | outputformat->renderer = MS_RENDER_WITH_RAWDATA; |
523 | 0 | outputformat->imagemode = MS_IMAGEMODE_FLOAT32; |
524 | 0 | msAppendOutputFormat(map_tmp, outputformat); |
525 | |
|
526 | 0 | msCopyHashTable(&map_tmp->configoptions, &layer->map->configoptions); |
527 | 0 | map_tmp->mappath = msStrdup(layer->map->mappath); |
528 | 0 | map_tmp->shapepath = msStrdup(layer->map->shapepath); |
529 | 0 | map_tmp->gt.rotation_angle = 0.0; |
530 | | |
531 | | /* Custom msCopyProjection() that removes lon_wrap parameter */ |
532 | 0 | { |
533 | 0 | int i; |
534 | |
|
535 | 0 | map_tmp->projection.numargs = 0; |
536 | 0 | map_tmp->projection.gt = layer->projection.gt; |
537 | |
|
538 | 0 | for (i = 0; i < layer->projection.numargs; i++) { |
539 | 0 | if (strncmp(layer->projection.args[i], |
540 | 0 | "lon_wrap=", strlen("lon_wrap=")) == 0) { |
541 | 0 | bHasLonWrap = MS_TRUE; |
542 | 0 | dfLonWrap = atof(layer->projection.args[i] + strlen("lon_wrap=")); |
543 | 0 | } else { |
544 | 0 | map_tmp->projection.args[map_tmp->projection.numargs++] = |
545 | 0 | msStrdup(layer->projection.args[i]); |
546 | 0 | } |
547 | 0 | } |
548 | 0 | if (map_tmp->projection.numargs != 0) { |
549 | 0 | msProcessProjection(&(map_tmp->projection)); |
550 | 0 | } |
551 | |
|
552 | 0 | map_tmp->projection.wellknownprojection = |
553 | 0 | layer->projection.wellknownprojection; |
554 | 0 | } |
555 | | |
556 | | /* Very special case to improve quality for rasters referenced from lon=0 to |
557 | | * 360 */ |
558 | | /* We create a temporary VRT that swiches the 2 hemispheres, and then we */ |
559 | | /* modify the georeferencing to be in the more standard [-180, 180] range */ |
560 | | /* and we adjust the layer->data, extent and projection accordingly */ |
561 | 0 | if (layer->tileindex == NULL && uvlinfo->mapToUseForWhichShapes && |
562 | 0 | bHasLonWrap && dfLonWrap == 180.0) { |
563 | 0 | rectObj layerExtent; |
564 | 0 | msLayerGetExtent(layer, &layerExtent); |
565 | 0 | if (layerExtent.minx == 0 && layerExtent.maxx == 360) { |
566 | 0 | GDALDatasetH hDS = NULL; |
567 | 0 | char *decrypted_path; |
568 | |
|
569 | 0 | if (strncmp(layer->data, "<VRTDataset", strlen("<VRTDataset")) == 0) { |
570 | 0 | decrypted_path = msStrdup(layer->data); |
571 | 0 | } else { |
572 | 0 | char szPath[MS_MAXPATHLEN]; |
573 | 0 | msTryBuildPath3(szPath, layer->map->mappath, layer->map->shapepath, |
574 | 0 | layer->data); |
575 | 0 | decrypted_path = msDecryptStringTokens(layer->map, szPath); |
576 | 0 | } |
577 | |
|
578 | 0 | if (decrypted_path) { |
579 | 0 | char **connectionoptions; |
580 | 0 | GDALAllRegister(); |
581 | 0 | connectionoptions = |
582 | 0 | msGetStringListFromHashTable(&(layer->connectionoptions)); |
583 | 0 | hDS = GDALOpenEx(decrypted_path, GDAL_OF_RASTER, NULL, |
584 | 0 | (const char *const *)connectionoptions, NULL); |
585 | 0 | CSLDestroy(connectionoptions); |
586 | 0 | } |
587 | 0 | if (hDS != NULL) { |
588 | 0 | int iBand; |
589 | 0 | int nXSize = GDALGetRasterXSize(hDS); |
590 | 0 | int nYSize = GDALGetRasterYSize(hDS); |
591 | 0 | int nBands = GDALGetRasterCount(hDS); |
592 | 0 | int nMaxLen = 100 + nBands * (800 + 2 * strlen(decrypted_path)); |
593 | 0 | int nOffset = 0; |
594 | 0 | char *pszInlineVRT = static_cast<char *>(msSmallMalloc(nMaxLen)); |
595 | |
|
596 | 0 | snprintf(pszInlineVRT, nMaxLen, |
597 | 0 | "<VRTDataset rasterXSize=\"%d\" rasterYSize=\"%d\">", nXSize, |
598 | 0 | nYSize); |
599 | 0 | nOffset = strlen(pszInlineVRT); |
600 | 0 | for (iBand = 1; iBand <= nBands; iBand++) { |
601 | 0 | const char *pszDataType = "Byte"; |
602 | 0 | switch (GDALGetRasterDataType(GDALGetRasterBand(hDS, iBand))) { |
603 | 0 | case GDT_Byte: |
604 | 0 | pszDataType = "Byte"; |
605 | 0 | break; |
606 | 0 | case GDT_Int16: |
607 | 0 | pszDataType = "Int16"; |
608 | 0 | break; |
609 | 0 | case GDT_UInt16: |
610 | 0 | pszDataType = "UInt16"; |
611 | 0 | break; |
612 | 0 | case GDT_Int32: |
613 | 0 | pszDataType = "Int32"; |
614 | 0 | break; |
615 | 0 | case GDT_UInt32: |
616 | 0 | pszDataType = "UInt32"; |
617 | 0 | break; |
618 | 0 | case GDT_Float32: |
619 | 0 | pszDataType = "Float32"; |
620 | 0 | break; |
621 | 0 | case GDT_Float64: |
622 | 0 | pszDataType = "Float64"; |
623 | 0 | break; |
624 | 0 | default: |
625 | 0 | break; |
626 | 0 | } |
627 | | |
628 | 0 | snprintf(pszInlineVRT + nOffset, nMaxLen - nOffset, |
629 | 0 | " <VRTRasterBand dataType=\"%s\" band=\"%d\">" |
630 | 0 | " <SimpleSource>" |
631 | 0 | " <SourceFilename " |
632 | 0 | "relativeToVrt=\"1\"><![CDATA[%s]]></SourceFilename>" |
633 | 0 | " <SourceBand>%d</SourceBand>" |
634 | 0 | " <SrcRect xOff=\"%d\" yOff=\"%d\" xSize=\"%d\" " |
635 | 0 | "ySize=\"%d\"/>" |
636 | 0 | " <DstRect xOff=\"%d\" yOff=\"%d\" xSize=\"%d\" " |
637 | 0 | "ySize=\"%d\"/>" |
638 | 0 | " </SimpleSource>" |
639 | 0 | " <SimpleSource>" |
640 | 0 | " <SourceFilename " |
641 | 0 | "relativeToVrt=\"1\"><![CDATA[%s]]></SourceFilename>" |
642 | 0 | " <SourceBand>%d</SourceBand>" |
643 | 0 | " <SrcRect xOff=\"%d\" yOff=\"%d\" xSize=\"%d\" " |
644 | 0 | "ySize=\"%d\"/>" |
645 | 0 | " <DstRect xOff=\"%d\" yOff=\"%d\" xSize=\"%d\" " |
646 | 0 | "ySize=\"%d\"/>" |
647 | 0 | " </SimpleSource>" |
648 | 0 | " </VRTRasterBand>", |
649 | 0 | pszDataType, iBand, decrypted_path, iBand, nXSize / 2, 0, |
650 | 0 | nXSize - nXSize / 2, nYSize, 0, 0, nXSize - nXSize / 2, |
651 | 0 | nYSize, decrypted_path, iBand, 0, 0, nXSize / 2, nYSize, |
652 | 0 | nXSize - nXSize / 2, 0, nXSize / 2, nYSize); |
653 | |
|
654 | 0 | nOffset += strlen(pszInlineVRT + nOffset); |
655 | 0 | } |
656 | 0 | snprintf(pszInlineVRT + nOffset, nMaxLen - nOffset, "</VRTDataset>"); |
657 | |
|
658 | 0 | oldLayerExtent = layer->extent; |
659 | 0 | oldLayerData = layer->data; |
660 | 0 | oldLayerProjection = layer->projection; |
661 | 0 | layer->extent.minx = -180; |
662 | 0 | layer->extent.maxx = 180; |
663 | 0 | layer->data = pszInlineVRT; |
664 | 0 | layer->projection = map_tmp->projection; |
665 | | |
666 | | /* map_tmp->projection is actually layer->projection without lon_wrap */ |
667 | 0 | rect = uvlinfo->mapToUseForWhichShapes->extent; |
668 | 0 | msProjectRect(&uvlinfo->mapToUseForWhichShapes->projection, |
669 | 0 | &map_tmp->projection, &rect); |
670 | 0 | bHasLonWrap = MS_FALSE; |
671 | |
|
672 | 0 | GDALClose(hDS); |
673 | 0 | } |
674 | 0 | msFree(decrypted_path); |
675 | 0 | } |
676 | 0 | } |
677 | | |
678 | 0 | if (isQuery) { |
679 | | /* For query mode, use layer->map->extent reprojected rather than */ |
680 | | /* the provided rect. Generic query code will filter returned features. */ |
681 | 0 | rect = msUVRASTERGetSearchRect(layer, layer->map); |
682 | 0 | } |
683 | |
|
684 | 0 | map_cellsize = MS_MAX(MS_CELLSIZE(rect.minx, rect.maxx, layer->map->width), |
685 | 0 | MS_CELLSIZE(rect.miny, rect.maxy, layer->map->height)); |
686 | 0 | map_tmp->cellsize = map_cellsize * spacing; |
687 | 0 | map_tmp->extent.minx = |
688 | 0 | rect.minx - (0.5 * map_cellsize) + (0.5 * map_tmp->cellsize); |
689 | 0 | map_tmp->extent.miny = |
690 | 0 | rect.miny - (0.5 * map_cellsize) + (0.5 * map_tmp->cellsize); |
691 | 0 | map_tmp->extent.maxx = |
692 | 0 | map_tmp->extent.minx + ((width - 1) * map_tmp->cellsize); |
693 | 0 | map_tmp->extent.maxy = |
694 | 0 | map_tmp->extent.miny + ((height - 1) * map_tmp->cellsize); |
695 | |
|
696 | 0 | if (bHasLonWrap && dfLonWrap == 180.0) { |
697 | 0 | if (map_tmp->extent.minx >= 180) { |
698 | | /* Request on the right half of the shifted raster (= western hemisphere) |
699 | | */ |
700 | 0 | map_tmp->extent.minx -= 360; |
701 | 0 | map_tmp->extent.maxx -= 360; |
702 | 0 | } else if (map_tmp->extent.maxx >= 180.0) { |
703 | | /* Request spanning on the 2 hemispheres => drawing whole planet */ |
704 | | /* Take only into account vertical resolution, as horizontal one */ |
705 | | /* will be unreliable (assuming square pixels...) */ |
706 | 0 | map_cellsize = MS_CELLSIZE(rect.miny, rect.maxy, layer->map->height); |
707 | 0 | map_tmp->cellsize = map_cellsize * spacing; |
708 | |
|
709 | 0 | width = 360.0 / map_tmp->cellsize; |
710 | 0 | map_tmp->extent.minx = -180.0 + (0.5 * map_tmp->cellsize); |
711 | 0 | map_tmp->extent.maxx = 180.0 - (0.5 * map_tmp->cellsize); |
712 | 0 | } |
713 | 0 | } |
714 | |
|
715 | 0 | if (layer->debug) |
716 | 0 | msDebug( |
717 | 0 | "msUVRASTERLayerWhichShapes(): width: %d, height: %d, cellsize: %g\n", |
718 | 0 | width, height, map_tmp->cellsize); |
719 | |
|
720 | 0 | if (layer->debug == MS_DEBUGLEVEL_VVV) |
721 | 0 | msDebug("msUVRASTERLayerWhichShapes(): extent: %g %g %g %g\n", |
722 | 0 | map_tmp->extent.minx, map_tmp->extent.miny, map_tmp->extent.maxx, |
723 | 0 | map_tmp->extent.maxy); |
724 | | |
725 | | /* important to use that function, to compute map |
726 | | geotransform, used by the resampling*/ |
727 | 0 | msMapSetSize(map_tmp, width, height); |
728 | |
|
729 | 0 | if (layer->debug == MS_DEBUGLEVEL_VVV) |
730 | 0 | msDebug("msUVRASTERLayerWhichShapes(): geotransform: %g %g %g %g %g %g\n", |
731 | 0 | map_tmp->gt.geotransform[0], map_tmp->gt.geotransform[1], |
732 | 0 | map_tmp->gt.geotransform[2], map_tmp->gt.geotransform[3], |
733 | 0 | map_tmp->gt.geotransform[4], map_tmp->gt.geotransform[5]); |
734 | |
|
735 | 0 | uvlinfo->extent = map_tmp->extent; |
736 | |
|
737 | 0 | image_tmp = msImageCreate(width, height, map_tmp->outputformatlist[0], NULL, |
738 | 0 | NULL, map_tmp->resolution, map_tmp->defresolution, |
739 | 0 | &(map_tmp->imagecolor)); |
740 | | |
741 | | /* Default set to AVERAGE resampling */ |
742 | 0 | if (CSLFetchNameValue(layer->processing, "RESAMPLE") == NULL) { |
743 | 0 | alteredProcessing = CSLDuplicate(layer->processing); |
744 | 0 | alteredProcessing = |
745 | 0 | CSLSetNameValue(alteredProcessing, "RESAMPLE", "AVERAGE"); |
746 | 0 | savedProcessing = layer->processing; |
747 | 0 | layer->processing = alteredProcessing; |
748 | 0 | } |
749 | | |
750 | | /* disable masking at this level: we don't want to apply the mask at the |
751 | | * raster level, it will be applied with the correct cellsize and image size |
752 | | * in the vector rendering phase. |
753 | | */ |
754 | 0 | saved_layer_mask = layer->mask; |
755 | 0 | layer->mask = NULL; |
756 | 0 | ret = msDrawRasterLayerLow(map_tmp, layer, image_tmp, NULL); |
757 | | |
758 | | /* restore layer attributes if we went through the above on-the-fly VRT */ |
759 | 0 | if (oldLayerData) { |
760 | 0 | msFree(layer->data); |
761 | 0 | layer->data = oldLayerData; |
762 | 0 | layer->extent = oldLayerExtent; |
763 | 0 | layer->projection = oldLayerProjection; |
764 | 0 | } |
765 | | |
766 | | /* restore layer mask */ |
767 | 0 | layer->mask = saved_layer_mask; |
768 | | |
769 | | /* restore the saved processing */ |
770 | 0 | if (alteredProcessing != NULL) { |
771 | 0 | layer->processing = savedProcessing; |
772 | 0 | CSLDestroy(alteredProcessing); |
773 | 0 | } |
774 | |
|
775 | 0 | if (ret == MS_FAILURE) { |
776 | 0 | msSetError(MS_MISCERR, "Unable to draw raster data.", |
777 | 0 | "msUVRASTERLayerWhichShapes()"); |
778 | |
|
779 | 0 | msFreeMap(map_tmp); |
780 | 0 | msFreeImage(image_tmp); |
781 | |
|
782 | 0 | return MS_FAILURE; |
783 | 0 | } |
784 | | |
785 | | /* free old query arrays */ |
786 | 0 | free(uvlinfo->u); |
787 | 0 | free(uvlinfo->v); |
788 | | |
789 | | /* Update our uv layer structure */ |
790 | 0 | uvlinfo->width = width; |
791 | 0 | uvlinfo->height = height; |
792 | 0 | uvlinfo->query_results = 0; |
793 | |
|
794 | 0 | uvlinfo->last_queried_shapeindex = 0; |
795 | 0 | uvlinfo->last_raster_off = 0; |
796 | |
|
797 | 0 | uvlinfo->u = (float *)msSmallMalloc(sizeof(float *) * width * height); |
798 | 0 | uvlinfo->v = (float *)msSmallMalloc(sizeof(float *) * width * height); |
799 | |
|
800 | 0 | for (size_t off = 0; off < static_cast<size_t>(width) * height; ++off) { |
801 | | /* Ignore invalid pixels (at nodata), or (u,v)=(0,0) */ |
802 | 0 | if (MS_GET_BIT(image_tmp->img_mask, off)) { |
803 | 0 | uvlinfo->u[off] = image_tmp->img.raw_float[off]; |
804 | 0 | uvlinfo->v[off] = |
805 | 0 | image_tmp->img.raw_float[off + static_cast<size_t>(width) * height]; |
806 | 0 | if (!(uvlinfo->u[off] == 0 && uvlinfo->v[off] == 0)) { |
807 | 0 | uvlinfo->query_results++; |
808 | 0 | } else { |
809 | 0 | uvlinfo->u[off] = std::numeric_limits<float>::quiet_NaN(); |
810 | 0 | uvlinfo->v[off] = std::numeric_limits<float>::quiet_NaN(); |
811 | 0 | } |
812 | 0 | } else { |
813 | 0 | uvlinfo->u[off] = std::numeric_limits<float>::quiet_NaN(); |
814 | 0 | uvlinfo->v[off] = std::numeric_limits<float>::quiet_NaN(); |
815 | 0 | } |
816 | 0 | } |
817 | |
|
818 | 0 | msFreeImage(image_tmp); /* we do not need the imageObj anymore */ |
819 | 0 | msFreeMap(map_tmp); |
820 | |
|
821 | 0 | uvlinfo->next_shape = 0; |
822 | |
|
823 | 0 | return MS_SUCCESS; |
824 | 0 | } |
825 | | |
826 | | int msUVRASTERLayerGetShape(layerObj *layer, shapeObj *shape, |
827 | 0 | resultObj *record) { |
828 | 0 | uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; |
829 | 0 | lineObj line; |
830 | 0 | pointObj point; |
831 | 0 | const long shapeindex = record->shapeindex; |
832 | |
|
833 | 0 | msFreeShape(shape); |
834 | 0 | shape->type = MS_SHAPE_NULL; |
835 | |
|
836 | 0 | if (shapeindex < 0 || shapeindex >= uvlinfo->query_results) { |
837 | 0 | msSetError(MS_MISCERR, |
838 | 0 | "Out of range shape index requested. Requested %ld\n" |
839 | 0 | "but only %d shapes available.", |
840 | 0 | "msUVRASTERLayerGetShape()", shapeindex, uvlinfo->query_results); |
841 | 0 | return MS_FAILURE; |
842 | 0 | } |
843 | | |
844 | | /* loop to the next valid value */ |
845 | 0 | size_t raster_off = (shapeindex >= uvlinfo->last_queried_shapeindex) |
846 | 0 | ? uvlinfo->last_raster_off |
847 | 0 | : 0; |
848 | 0 | for (long curshapeindex = (shapeindex >= uvlinfo->last_queried_shapeindex) |
849 | 0 | ? uvlinfo->last_queried_shapeindex |
850 | 0 | : 0; |
851 | 0 | raster_off < static_cast<size_t>(uvlinfo->width) * uvlinfo->height; |
852 | 0 | ++raster_off) { |
853 | 0 | if (!std::isnan(uvlinfo->u[raster_off])) { |
854 | 0 | if (curshapeindex == shapeindex) { |
855 | 0 | uvlinfo->last_queried_shapeindex = shapeindex; |
856 | 0 | uvlinfo->last_raster_off = raster_off; |
857 | 0 | break; |
858 | 0 | } |
859 | 0 | ++curshapeindex; |
860 | 0 | } |
861 | 0 | } |
862 | 0 | assert(raster_off < static_cast<size_t>(uvlinfo->width) * uvlinfo->height); |
863 | | |
864 | 0 | const int x = static_cast<int>(raster_off % uvlinfo->width); |
865 | 0 | const int y = static_cast<int>(raster_off / uvlinfo->width); |
866 | 0 | point.x = Pix2Georef(x, 0, uvlinfo->width - 1, uvlinfo->extent.minx, |
867 | 0 | uvlinfo->extent.maxx, MS_FALSE); |
868 | 0 | point.y = Pix2Georef(y, 0, uvlinfo->height - 1, uvlinfo->extent.miny, |
869 | 0 | uvlinfo->extent.maxy, MS_TRUE); |
870 | 0 | if (layer->debug == MS_DEBUGLEVEL_VVV) |
871 | 0 | msDebug("msUVRASTERLayerWhichShapes(): shapeindex: %ld, x: %g, y: %g\n", |
872 | 0 | shapeindex, point.x, point.y); |
873 | |
|
874 | 0 | point.m = 0.0; |
875 | |
|
876 | 0 | shape->type = MS_SHAPE_POINT; |
877 | 0 | line.numpoints = 1; |
878 | 0 | line.point = &point; |
879 | 0 | msAddLine(shape, &line); |
880 | 0 | msComputeBounds(shape); |
881 | |
|
882 | 0 | shape->numvalues = layer->numitems; |
883 | 0 | shape->values = msUVRASTERGetValues(layer, uvlinfo->u[raster_off], |
884 | 0 | uvlinfo->v[raster_off], &point); |
885 | 0 | shape->index = shapeindex; |
886 | 0 | shape->resultindex = shapeindex; |
887 | |
|
888 | 0 | return MS_SUCCESS; |
889 | 0 | } |
890 | | |
891 | 0 | int msUVRASTERLayerNextShape(layerObj *layer, shapeObj *shape) { |
892 | 0 | uvRasterLayerInfo *uvlinfo = (uvRasterLayerInfo *)layer->layerinfo; |
893 | |
|
894 | 0 | if (uvlinfo->next_shape < 0 || |
895 | 0 | uvlinfo->next_shape >= uvlinfo->query_results) { |
896 | 0 | msFreeShape(shape); |
897 | 0 | shape->type = MS_SHAPE_NULL; |
898 | 0 | return MS_DONE; |
899 | 0 | } else { |
900 | 0 | resultObj record; |
901 | |
|
902 | 0 | record.shapeindex = uvlinfo->next_shape++; |
903 | 0 | record.tileindex = 0; |
904 | 0 | record.classindex = record.resultindex = -1; |
905 | |
|
906 | 0 | return msUVRASTERLayerGetShape(layer, shape, &record); |
907 | 0 | } |
908 | 0 | } |
909 | | |
910 | | /************************************************************************/ |
911 | | /* msUVRASTERLayerGetExtent() */ |
912 | | /* Simple copy of the maprasterquery.c file. might change in the future */ |
913 | | /************************************************************************/ |
914 | | |
915 | | int msUVRASTERLayerGetExtent(layerObj *layer, rectObj *extent) |
916 | | |
917 | 0 | { |
918 | 0 | char szPath[MS_MAXPATHLEN]; |
919 | 0 | mapObj *map = layer->map; |
920 | 0 | shapefileObj *tileshpfile; |
921 | |
|
922 | 0 | if ((!layer->data || strlen(layer->data) == 0) && layer->tileindex == NULL) { |
923 | | /* should we be issuing a specific error about not supporting |
924 | | extents for tileindexed raster layers? */ |
925 | 0 | return MS_FAILURE; |
926 | 0 | } |
927 | | |
928 | 0 | if (map == NULL) |
929 | 0 | return MS_FAILURE; |
930 | | |
931 | | /* If the layer use a tileindex, return the extent of the tileindex |
932 | | * shapefile/referenced layer */ |
933 | 0 | if (layer->tileindex) { |
934 | 0 | const int tilelayerindex = msGetLayerIndex(map, layer->tileindex); |
935 | 0 | if (tilelayerindex != -1) /* does the tileindex reference another layer */ |
936 | 0 | return msLayerGetExtent(GET_LAYER(map, tilelayerindex), extent); |
937 | 0 | else { |
938 | 0 | tileshpfile = (shapefileObj *)malloc(sizeof(shapefileObj)); |
939 | 0 | MS_CHECK_ALLOC(tileshpfile, sizeof(shapefileObj), MS_FAILURE); |
940 | |
|
941 | 0 | if (msShapefileOpen(tileshpfile, "rb", |
942 | 0 | msBuildPath3(szPath, map->mappath, map->shapepath, |
943 | 0 | layer->tileindex), |
944 | 0 | MS_TRUE) == -1) |
945 | 0 | if (msShapefileOpen(tileshpfile, "rb", |
946 | 0 | msBuildPath(szPath, map->mappath, layer->tileindex), |
947 | 0 | MS_TRUE) == -1) |
948 | 0 | return MS_FAILURE; |
949 | | |
950 | 0 | *extent = tileshpfile->bounds; |
951 | 0 | msShapefileClose(tileshpfile); |
952 | 0 | free(tileshpfile); |
953 | 0 | return MS_SUCCESS; |
954 | 0 | } |
955 | 0 | } |
956 | | |
957 | 0 | msTryBuildPath3(szPath, map->mappath, map->shapepath, layer->data); |
958 | 0 | char *decrypted_path = msDecryptStringTokens(map, szPath); |
959 | 0 | if (!decrypted_path) |
960 | 0 | return MS_FAILURE; |
961 | | |
962 | 0 | GDALAllRegister(); |
963 | |
|
964 | 0 | char **connectionoptions = |
965 | 0 | msGetStringListFromHashTable(&(layer->connectionoptions)); |
966 | 0 | GDALDatasetH hDS = GDALOpenEx(decrypted_path, GDAL_OF_RASTER, NULL, |
967 | 0 | (const char *const *)connectionoptions, NULL); |
968 | 0 | CSLDestroy(connectionoptions); |
969 | 0 | msFree(decrypted_path); |
970 | 0 | if (hDS == NULL) { |
971 | 0 | return MS_FAILURE; |
972 | 0 | } |
973 | | |
974 | 0 | const int nXSize = GDALGetRasterXSize(hDS); |
975 | 0 | const int nYSize = GDALGetRasterYSize(hDS); |
976 | 0 | double adfGeoTransform[6] = {0}; |
977 | 0 | const CPLErr eErr = GDALGetGeoTransform(hDS, adfGeoTransform); |
978 | 0 | GDALClose(hDS); |
979 | 0 | if (eErr != CE_None) { |
980 | 0 | return MS_FAILURE; |
981 | 0 | } |
982 | | |
983 | | /* If this appears to be an ungeoreferenced raster than flip it for |
984 | | mapservers purposes. */ |
985 | 0 | if (adfGeoTransform[5] == 1.0 && adfGeoTransform[3] == 0.0) { |
986 | 0 | adfGeoTransform[5] = -1.0; |
987 | 0 | adfGeoTransform[3] = nYSize; |
988 | 0 | } |
989 | |
|
990 | 0 | extent->minx = adfGeoTransform[0]; |
991 | 0 | extent->maxy = adfGeoTransform[3]; |
992 | |
|
993 | 0 | extent->maxx = adfGeoTransform[0] + nXSize * adfGeoTransform[1]; |
994 | 0 | extent->miny = adfGeoTransform[3] + nYSize * adfGeoTransform[5]; |
995 | |
|
996 | 0 | return MS_SUCCESS; |
997 | 0 | } |
998 | | |
999 | | /************************************************************************/ |
1000 | | /* msUVRASTERLayerSetTimeFilter() */ |
1001 | | /* */ |
1002 | | /* This function is actually just used in the context of */ |
1003 | | /* setting a filter on the tileindex for time based queries. */ |
1004 | | /* For instance via WMS requests. So it isn't really related */ |
1005 | | /* to the "raster query" support at all. */ |
1006 | | /* */ |
1007 | | /* If a local shapefile tileindex is in use, we will set a */ |
1008 | | /* backtics filter (shapefile compatible). If another layer is */ |
1009 | | /* being used as the tileindex then we will forward the */ |
1010 | | /* SetTimeFilter call to it. If there is no tileindex in */ |
1011 | | /* place, we do nothing. */ |
1012 | | /************************************************************************/ |
1013 | | |
1014 | | int msUVRASTERLayerSetTimeFilter(layerObj *layer, const char *timestring, |
1015 | 0 | const char *timefield) { |
1016 | 0 | int tilelayerindex; |
1017 | | |
1018 | | /* -------------------------------------------------------------------- */ |
1019 | | /* If we don't have a tileindex the time filter has no effect. */ |
1020 | | /* -------------------------------------------------------------------- */ |
1021 | 0 | if (layer->tileindex == NULL) |
1022 | 0 | return MS_SUCCESS; |
1023 | | |
1024 | | /* -------------------------------------------------------------------- */ |
1025 | | /* Find the tileindex layer. */ |
1026 | | /* -------------------------------------------------------------------- */ |
1027 | 0 | tilelayerindex = msGetLayerIndex(layer->map, layer->tileindex); |
1028 | | |
1029 | | /* -------------------------------------------------------------------- */ |
1030 | | /* If we are using a local shapefile as our tileindex (that is */ |
1031 | | /* to say, the tileindex name is not of another layer), then we */ |
1032 | | /* just install a backtics style filter on the raster layer. */ |
1033 | | /* This is propagated to the "working layer" created for the */ |
1034 | | /* tileindex by code in mapraster.c. */ |
1035 | | /* -------------------------------------------------------------------- */ |
1036 | 0 | if (tilelayerindex == -1) |
1037 | 0 | return msLayerMakeBackticsTimeFilter(layer, timestring, timefield); |
1038 | | |
1039 | | /* -------------------------------------------------------------------- */ |
1040 | | /* Otherwise we invoke the tileindex layers SetTimeFilter */ |
1041 | | /* method. */ |
1042 | | /* -------------------------------------------------------------------- */ |
1043 | 0 | if (msCheckParentPointer(layer->map, "map") == MS_FAILURE) |
1044 | 0 | return MS_FAILURE; |
1045 | 0 | return msLayerSetTimeFilter(layer->GET_LAYER(map, tilelayerindex), timestring, |
1046 | 0 | timefield); |
1047 | 0 | } |
1048 | | |
1049 | | /************************************************************************/ |
1050 | | /* msRASTERLayerInitializeVirtualTable() */ |
1051 | | /************************************************************************/ |
1052 | | |
1053 | 0 | int msUVRASTERLayerInitializeVirtualTable(layerObj *layer) { |
1054 | 0 | assert(layer != NULL); |
1055 | 0 | assert(layer->vtable != NULL); |
1056 | | |
1057 | 0 | layer->vtable->LayerInitItemInfo = msUVRASTERLayerInitItemInfo; |
1058 | 0 | layer->vtable->LayerFreeItemInfo = msUVRASTERLayerFreeItemInfo; |
1059 | 0 | layer->vtable->LayerOpen = msUVRASTERLayerOpen; |
1060 | 0 | layer->vtable->LayerIsOpen = msUVRASTERLayerIsOpen; |
1061 | 0 | layer->vtable->LayerWhichShapes = msUVRASTERLayerWhichShapes; |
1062 | 0 | layer->vtable->LayerNextShape = msUVRASTERLayerNextShape; |
1063 | 0 | layer->vtable->LayerGetShape = msUVRASTERLayerGetShape; |
1064 | | /* layer->vtable->LayerGetShapeCount, use default */ |
1065 | 0 | layer->vtable->LayerClose = msUVRASTERLayerClose; |
1066 | 0 | layer->vtable->LayerGetItems = msUVRASTERLayerGetItems; |
1067 | 0 | layer->vtable->LayerGetExtent = msUVRASTERLayerGetExtent; |
1068 | | /* layer->vtable->LayerGetAutoStyle, use default */ |
1069 | | /* layer->vtable->LayerApplyFilterToLayer, use default */ |
1070 | | /* layer->vtable->LayerCloseConnection = msUVRASTERLayerClose; */ |
1071 | | /* we use backtics for proper tileindex shapefile functioning */ |
1072 | 0 | layer->vtable->LayerSetTimeFilter = msUVRASTERLayerSetTimeFilter; |
1073 | | /* layer->vtable->LayerCreateItems, use default */ |
1074 | | /* layer->vtable->LayerGetNumFeatures, use default */ |
1075 | |
|
1076 | 0 | return MS_SUCCESS; |
1077 | 0 | } |