/src/MapServer/src/mapcontour.c
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * $Id: mapcontour.c 12629 2011-10-06 18:06:34Z aboudreault $ |
3 | | * |
4 | | * Project: MapServer |
5 | | * Purpose: Contour Layer |
6 | | * Author: Alan Boudreault (aboudreault@mapgears.com) |
7 | | * Author: Daniel Morissette (dmorissette@mapgears.com) |
8 | | * |
9 | | ********************************************************************** |
10 | | * Copyright (c) 2011, Alan Boudreault, MapGears |
11 | | * |
12 | | * Permission is hereby granted, free of charge, to any person obtaining a |
13 | | * copy of this software and associated documentation files (the "Software"), |
14 | | * to deal in the Software without restriction, including without limitation |
15 | | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
16 | | * and/or sell copies of the Software, and to permit persons to whom the |
17 | | * Software is furnished to do so, subject to the following conditions: |
18 | | * |
19 | | * The above copyright notice and this permission notice shall be included in |
20 | | * all copies of this Software or works derived from this Software. |
21 | | * |
22 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
23 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
24 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
25 | | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
26 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
27 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
28 | | * DEALINGS IN THE SOFTWARE. |
29 | | **********************************************************************/ |
30 | | |
31 | | #include "mapserver.h" |
32 | | #include "mapcopy.h" |
33 | | #include "mapresample.h" |
34 | | |
35 | | #include "ogr_api.h" |
36 | | #include "ogr_srs_api.h" |
37 | | #include "gdal.h" |
38 | | #include "gdal_alg.h" |
39 | | |
40 | | #include "mapows.h" |
41 | | #include "mapthread.h" |
42 | | #include "mapraster.h" |
43 | | #include "cpl_string.h" |
44 | | |
45 | 0 | #define GEO_TRANS(tr, x, y) ((tr)[0] + (tr)[1] * (x) + (tr)[2] * (y)) |
46 | | |
47 | | extern int InvGeoTransform(double *gt_in, double *gt_out); |
48 | | |
49 | | typedef struct { |
50 | | |
51 | | /* OGR DataSource */ |
52 | | layerObj ogrLayer; |
53 | | |
54 | | /* internal use */ |
55 | | GDALDatasetH hOrigDS; |
56 | | GDALDatasetH hDS; |
57 | | double *buffer; /* memory dataset buffer */ |
58 | | rectObj extent; /* original dataset extent */ |
59 | | OGRDataSourceH hOGRDS; |
60 | | double cellsize; |
61 | | |
62 | | } contourLayerInfo; |
63 | | |
64 | 0 | static int msContourLayerInitItemInfo(layerObj *layer) { |
65 | 0 | contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; |
66 | |
|
67 | 0 | if (clinfo == NULL) { |
68 | 0 | msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", |
69 | 0 | "msContourLayerInitItemInfo()"); |
70 | 0 | return MS_FAILURE; |
71 | 0 | } |
72 | | |
73 | 0 | return msLayerInitItemInfo(&clinfo->ogrLayer); |
74 | 0 | } |
75 | | |
76 | 0 | static void msContourLayerFreeItemInfo(layerObj *layer) { |
77 | 0 | contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; |
78 | |
|
79 | 0 | if (clinfo == NULL) { |
80 | 0 | msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", |
81 | 0 | "msContourLayerFreeItemInfo()"); |
82 | 0 | return; |
83 | 0 | } |
84 | | |
85 | 0 | msLayerFreeItemInfo(&clinfo->ogrLayer); |
86 | 0 | } |
87 | | |
88 | 0 | static void msContourLayerInfoInitialize(layerObj *layer) { |
89 | 0 | contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; |
90 | |
|
91 | 0 | if (clinfo != NULL) |
92 | 0 | return; |
93 | | |
94 | 0 | clinfo = (contourLayerInfo *)msSmallCalloc(1, sizeof(contourLayerInfo)); |
95 | 0 | layer->layerinfo = clinfo; |
96 | 0 | clinfo->hOrigDS = NULL; |
97 | 0 | clinfo->hDS = NULL; |
98 | 0 | clinfo->extent.minx = -1.0; |
99 | 0 | clinfo->extent.miny = -1.0; |
100 | 0 | clinfo->extent.maxx = -1.0; |
101 | 0 | clinfo->extent.maxy = -1.0; |
102 | |
|
103 | 0 | initLayer(&clinfo->ogrLayer, layer->map); |
104 | 0 | clinfo->ogrLayer.type = layer->type; |
105 | 0 | clinfo->ogrLayer.debug = layer->debug; |
106 | 0 | clinfo->ogrLayer.connectiontype = MS_OGR; |
107 | 0 | clinfo->ogrLayer.name = msStrdup(layer->name); |
108 | 0 | clinfo->ogrLayer.connection = |
109 | 0 | (char *)msSmallMalloc(strlen(clinfo->ogrLayer.name) + 13); |
110 | 0 | sprintf(clinfo->ogrLayer.connection, "__%s_CONTOUR__", clinfo->ogrLayer.name); |
111 | 0 | clinfo->ogrLayer.units = layer->units; |
112 | |
|
113 | 0 | if (msOWSLookupMetadata(&(layer->metadata), "OFG", "ID_type") == NULL) { |
114 | 0 | msInsertHashTable(&(layer->metadata), "gml_ID_type", "Integer"); |
115 | 0 | } |
116 | 0 | { |
117 | 0 | const char *elevItem = CSLFetchNameValue(layer->processing, "CONTOUR_ITEM"); |
118 | 0 | if (elevItem && strlen(elevItem) > 0) { |
119 | 0 | char szTmp[100]; |
120 | 0 | snprintf(szTmp, sizeof(szTmp), "%s_type", elevItem); |
121 | 0 | if (msOWSLookupMetadata(&(layer->metadata), "OFG", szTmp) == NULL) { |
122 | 0 | snprintf(szTmp, sizeof(szTmp), "gml_%s_type", elevItem); |
123 | 0 | msInsertHashTable(&(layer->metadata), szTmp, "Real"); |
124 | 0 | } |
125 | 0 | } |
126 | 0 | } |
127 | 0 | } |
128 | | |
129 | 0 | static void msContourLayerInfoFree(layerObj *layer) { |
130 | 0 | contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; |
131 | |
|
132 | 0 | if (clinfo == NULL) |
133 | 0 | return; |
134 | | |
135 | 0 | freeLayer(&clinfo->ogrLayer); |
136 | 0 | free(clinfo); |
137 | |
|
138 | 0 | layer->layerinfo = NULL; |
139 | 0 | } |
140 | | |
141 | 0 | static int msContourLayerReadRaster(layerObj *layer, rectObj rect) { |
142 | 0 | mapObj *map = layer->map; |
143 | 0 | char **bands; |
144 | 0 | int band = 1; |
145 | 0 | double adfGeoTransform[6], adfInvGeoTransform[6]; |
146 | 0 | double llx, lly, urx, ury; |
147 | 0 | rectObj copyRect, mapRect; |
148 | 0 | int dst_xsize, dst_ysize; |
149 | 0 | int virtual_grid_step_x, virtual_grid_step_y; |
150 | 0 | int src_xoff, src_yoff, src_xsize, src_ysize; |
151 | 0 | double map_cellsize_x, map_cellsize_y, dst_cellsize_x, dst_cellsize_y; |
152 | 0 | GDALRasterBandH hBand = NULL; |
153 | 0 | CPLErr eErr; |
154 | |
|
155 | 0 | contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; |
156 | |
|
157 | 0 | if (layer->debug) |
158 | 0 | msDebug("Entering msContourLayerReadRaster().\n"); |
159 | |
|
160 | 0 | if (clinfo == NULL || clinfo->hOrigDS == NULL) { |
161 | 0 | msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", |
162 | 0 | "msContourLayerReadRaster()"); |
163 | 0 | return MS_FAILURE; |
164 | 0 | } |
165 | | |
166 | 0 | bands = CSLTokenizeStringComplex( |
167 | 0 | CSLFetchNameValue(layer->processing, "BANDS"), " ,", FALSE, FALSE); |
168 | 0 | if (CSLCount(bands) > 0) { |
169 | 0 | band = atoi(bands[0]); |
170 | 0 | if (band < 1 || band > GDALGetRasterCount(clinfo->hOrigDS)) { |
171 | 0 | msSetError(MS_IMGERR, |
172 | 0 | "BANDS PROCESSING directive includes illegal band '%d', " |
173 | 0 | "should be from 1 to %d.", |
174 | 0 | "msContourLayerReadRaster()", band, |
175 | 0 | GDALGetRasterCount(clinfo->hOrigDS)); |
176 | 0 | CSLDestroy(bands); |
177 | 0 | return MS_FAILURE; |
178 | 0 | } |
179 | 0 | } |
180 | 0 | CSLDestroy(bands); |
181 | |
|
182 | 0 | hBand = GDALGetRasterBand(clinfo->hOrigDS, band); |
183 | 0 | if (hBand == NULL) { |
184 | 0 | msSetError(MS_IMGERR, "Band %d does not exist on dataset.", |
185 | 0 | "msContourLayerReadRaster()", band); |
186 | 0 | return MS_FAILURE; |
187 | 0 | } |
188 | | |
189 | 0 | if (layer->projection.numargs > 0 && |
190 | 0 | EQUAL(layer->projection.args[0], "auto")) { |
191 | 0 | const char *wkt; |
192 | 0 | wkt = GDALGetProjectionRef(clinfo->hOrigDS); |
193 | 0 | if (wkt != NULL && strlen(wkt) > 0) { |
194 | 0 | if (msOGCWKT2ProjectionObj(wkt, &(layer->projection), layer->debug) != |
195 | 0 | MS_SUCCESS) { |
196 | 0 | char msg[MESSAGELENGTH * 2]; |
197 | 0 | errorObj *ms_error = msGetErrorObj(); |
198 | |
|
199 | 0 | snprintf(msg, sizeof(msg), |
200 | 0 | "%s\n" |
201 | 0 | "PROJECTION AUTO cannot be used for this " |
202 | 0 | "GDAL raster (`%s').", |
203 | 0 | ms_error->message, layer->data); |
204 | 0 | msg[MESSAGELENGTH - 1] = '\0'; |
205 | |
|
206 | 0 | msSetError(MS_OGRERR, "%s", "msDrawRasterLayer()", msg); |
207 | 0 | return MS_FAILURE; |
208 | 0 | } |
209 | 0 | } |
210 | 0 | } |
211 | | |
212 | | /* |
213 | | * Compute the georeferenced window of overlap, and read the source data |
214 | | * downsampled to match output resolution, or at full resolution if |
215 | | * output resolution is lower than the source resolution. |
216 | | * |
217 | | * A large portion of this overlap calculation code was borrowed from |
218 | | * msDrawRasterLayerGDAL(). |
219 | | * Would be possible to move some of this to a reusable function? |
220 | | * |
221 | | * Note: This code works only if no reprojection is involved. It would |
222 | | * need rework to support cases where output projection differs from source |
223 | | * data file projection. |
224 | | */ |
225 | | |
226 | 0 | src_xsize = GDALGetRasterXSize(clinfo->hOrigDS); |
227 | 0 | src_ysize = GDALGetRasterYSize(clinfo->hOrigDS); |
228 | | |
229 | | /* set the Dataset extent */ |
230 | 0 | msGetGDALGeoTransform(clinfo->hOrigDS, map, layer, adfGeoTransform); |
231 | 0 | clinfo->extent.minx = adfGeoTransform[0]; |
232 | 0 | clinfo->extent.maxy = adfGeoTransform[3]; |
233 | 0 | clinfo->extent.maxx = adfGeoTransform[0] + src_xsize * adfGeoTransform[1]; |
234 | 0 | clinfo->extent.miny = adfGeoTransform[3] + src_ysize * adfGeoTransform[5]; |
235 | |
|
236 | 0 | if (layer->transform) { |
237 | 0 | if (layer->debug) |
238 | 0 | msDebug("msContourLayerReadRaster(): Entering transform.\n"); |
239 | |
|
240 | 0 | InvGeoTransform(adfGeoTransform, adfInvGeoTransform); |
241 | |
|
242 | 0 | mapRect = rect; |
243 | 0 | if (map->cellsize == 0) { |
244 | 0 | map->cellsize = msAdjustExtent(&mapRect, map->width, map->height); |
245 | 0 | } |
246 | 0 | map_cellsize_x = map_cellsize_y = map->cellsize; |
247 | | /* if necessary, project the searchrect to source coords */ |
248 | 0 | if (msProjectionsDiffer(&(map->projection), &(layer->projection))) { |
249 | 0 | if (msProjectRect(&map->projection, &layer->projection, &mapRect) != |
250 | 0 | MS_SUCCESS) { |
251 | 0 | msDebug("msContourLayerReadRaster(%s): unable to reproject map request " |
252 | 0 | "rectangle into layer projection, canceling.\n", |
253 | 0 | layer->name); |
254 | 0 | return MS_FAILURE; |
255 | 0 | } |
256 | | |
257 | 0 | map_cellsize_x = MS_CELLSIZE(mapRect.minx, mapRect.maxx, map->width); |
258 | 0 | map_cellsize_y = MS_CELLSIZE(mapRect.miny, mapRect.maxy, map->height); |
259 | | |
260 | | /* if the projection failed to project the extent requested, we need to |
261 | | calculate the cellsize to preserve the initial map cellsize ratio */ |
262 | 0 | if ((mapRect.minx < GEO_TRANS(adfGeoTransform, 0, src_ysize)) || |
263 | 0 | (mapRect.maxx > GEO_TRANS(adfGeoTransform, src_xsize, 0)) || |
264 | 0 | (mapRect.miny < GEO_TRANS(adfGeoTransform + 3, 0, src_ysize)) || |
265 | 0 | (mapRect.maxy > GEO_TRANS(adfGeoTransform + 3, src_xsize, 0))) { |
266 | |
|
267 | 0 | int src_unit, dst_unit; |
268 | 0 | src_unit = GetMapserverUnitUsingProj(&map->projection); |
269 | 0 | dst_unit = GetMapserverUnitUsingProj(&layer->projection); |
270 | 0 | if (src_unit == -1 || dst_unit == -1) { |
271 | 0 | msDebug("msContourLayerReadRaster(%s): unable to reproject map " |
272 | 0 | "request rectangle into layer projection, canceling.\n", |
273 | 0 | layer->name); |
274 | 0 | return MS_FAILURE; |
275 | 0 | } |
276 | | |
277 | 0 | map_cellsize_x = MS_CONVERT_UNIT( |
278 | 0 | src_unit, dst_unit, MS_CELLSIZE(rect.minx, rect.maxx, map->width)); |
279 | 0 | map_cellsize_y = MS_CONVERT_UNIT( |
280 | 0 | src_unit, dst_unit, MS_CELLSIZE(rect.miny, rect.maxy, map->height)); |
281 | 0 | } |
282 | 0 | } |
283 | | |
284 | 0 | if (map_cellsize_x == 0 || map_cellsize_y == 0) { |
285 | 0 | if (layer->debug) |
286 | 0 | msDebug("msContourLayerReadRaster(): Cellsize can't be 0.\n"); |
287 | 0 | return MS_FAILURE; |
288 | 0 | } |
289 | | |
290 | | /* Adjust MapServer pixel model to GDAL pixel model */ |
291 | 0 | mapRect.minx -= map_cellsize_x * 0.5; |
292 | 0 | mapRect.maxx += map_cellsize_x * 0.5; |
293 | 0 | mapRect.miny -= map_cellsize_y * 0.5; |
294 | 0 | mapRect.maxy += map_cellsize_y * 0.5; |
295 | | |
296 | | /* |
297 | | * If raw data cellsize (from geotransform) is larger than output |
298 | | * map_cellsize then we want to extract only enough data to match the output |
299 | | * map resolution which means that GDAL will automatically sample the data |
300 | | * on read. |
301 | | * |
302 | | * To prevent bad contour effects on tile edges, we adjust the target |
303 | | * cellsize to align the extracted window with a virtual grid based on the |
304 | | * origin of the raw data and a virtual grid step size corresponding to an |
305 | | * integer sampling step. |
306 | | * |
307 | | * If source data has a greater cellsize (i.e. lower res) that requested |
308 | | * output map then we use the raw data cellsize as target cellsize since |
309 | | * there is no point in interpolating the data for contours in this case. |
310 | | */ |
311 | |
|
312 | 0 | virtual_grid_step_x = (int)floor(map_cellsize_x / ABS(adfGeoTransform[1])); |
313 | 0 | if (virtual_grid_step_x < 1) |
314 | 0 | virtual_grid_step_x = |
315 | 0 | 1; /* Do not interpolate data if grid sampling step < 1 */ |
316 | |
|
317 | 0 | virtual_grid_step_y = (int)floor(map_cellsize_y / ABS(adfGeoTransform[5])); |
318 | 0 | if (virtual_grid_step_y < 1) |
319 | 0 | virtual_grid_step_y = |
320 | 0 | 1; /* Do not interpolate data if grid sampling step < 1 */ |
321 | | |
322 | | /* target cellsize is a multiple of raw data cellsize based on grid step*/ |
323 | 0 | dst_cellsize_x = ABS(adfGeoTransform[1]) * virtual_grid_step_x; |
324 | 0 | dst_cellsize_y = ABS(adfGeoTransform[5]) * virtual_grid_step_y; |
325 | | |
326 | | /* Compute overlap between source and target views */ |
327 | |
|
328 | 0 | copyRect = mapRect; |
329 | |
|
330 | 0 | if (copyRect.minx < GEO_TRANS(adfGeoTransform, 0, src_ysize)) |
331 | 0 | copyRect.minx = GEO_TRANS(adfGeoTransform, 0, src_ysize); |
332 | 0 | if (copyRect.maxx > GEO_TRANS(adfGeoTransform, src_xsize, 0)) |
333 | 0 | copyRect.maxx = GEO_TRANS(adfGeoTransform, src_xsize, 0); |
334 | 0 | if (copyRect.miny < GEO_TRANS(adfGeoTransform + 3, 0, src_ysize)) |
335 | 0 | copyRect.miny = GEO_TRANS(adfGeoTransform + 3, 0, src_ysize); |
336 | 0 | if (copyRect.maxy > GEO_TRANS(adfGeoTransform + 3, src_xsize, 0)) |
337 | 0 | copyRect.maxy = GEO_TRANS(adfGeoTransform + 3, src_xsize, 0); |
338 | |
|
339 | 0 | if (copyRect.minx >= copyRect.maxx || copyRect.miny >= copyRect.maxy) { |
340 | 0 | if (layer->debug) |
341 | 0 | msDebug("msContourLayerReadRaster(): No overlap.\n"); |
342 | 0 | return MS_SUCCESS; |
343 | 0 | } |
344 | | |
345 | | /* |
346 | | * Convert extraction window to raster coordinates |
347 | | */ |
348 | 0 | llx = GEO_TRANS(adfInvGeoTransform + 0, copyRect.minx, copyRect.miny); |
349 | 0 | lly = GEO_TRANS(adfInvGeoTransform + 3, copyRect.minx, copyRect.miny); |
350 | 0 | urx = GEO_TRANS(adfInvGeoTransform + 0, copyRect.maxx, copyRect.maxy); |
351 | 0 | ury = GEO_TRANS(adfInvGeoTransform + 3, copyRect.maxx, copyRect.maxy); |
352 | | |
353 | | /* |
354 | | * Align extraction window with virtual grid |
355 | | * (keep in mind raster coordinates origin is at upper-left) |
356 | | * We also add an extra buffer to fix tile boundarie issues when zoomed |
357 | | */ |
358 | 0 | llx = floor(llx / virtual_grid_step_x) * virtual_grid_step_x - |
359 | 0 | (virtual_grid_step_x * 5); |
360 | 0 | urx = ceil(urx / virtual_grid_step_x) * virtual_grid_step_x + |
361 | 0 | (virtual_grid_step_x * 5); |
362 | 0 | ury = floor(ury / virtual_grid_step_y) * virtual_grid_step_y - |
363 | 0 | (virtual_grid_step_x * 5); |
364 | 0 | lly = ceil(lly / virtual_grid_step_y) * virtual_grid_step_y + |
365 | 0 | (virtual_grid_step_x * 5); |
366 | |
|
367 | 0 | src_xoff = MS_MAX(0, (int)floor(llx + 0.5)); |
368 | 0 | src_yoff = MS_MAX(0, (int)floor(ury + 0.5)); |
369 | 0 | src_xsize = MS_MIN(MS_MAX(0, (int)(urx - llx + 0.5)), |
370 | 0 | GDALGetRasterXSize(clinfo->hOrigDS) - src_xoff); |
371 | 0 | src_ysize = MS_MIN(MS_MAX(0, (int)(lly - ury + 0.5)), |
372 | 0 | GDALGetRasterYSize(clinfo->hOrigDS) - src_yoff); |
373 | | |
374 | | /* Update the geographic extent (buffer added) */ |
375 | | /* TODO: a better way to go the geo_trans */ |
376 | 0 | copyRect.minx = GEO_TRANS(adfGeoTransform + 0, src_xoff, 0); |
377 | 0 | copyRect.maxx = GEO_TRANS(adfGeoTransform + 0, src_xoff + src_xsize, 0); |
378 | 0 | copyRect.miny = GEO_TRANS(adfGeoTransform + 3, 0, src_yoff + src_ysize); |
379 | 0 | copyRect.maxy = GEO_TRANS(adfGeoTransform + 3, 0, src_yoff); |
380 | | |
381 | | /* |
382 | | * If input window is to small then stop here |
383 | | */ |
384 | 0 | if (src_xsize < 2 || src_ysize < 2) { |
385 | 0 | if (layer->debug) |
386 | 0 | msDebug("msContourLayerReadRaster(): input window too small, or no " |
387 | 0 | "apparent overlap between map view and this window(1).\n"); |
388 | 0 | return MS_SUCCESS; |
389 | 0 | } |
390 | | |
391 | | /* Target buffer size */ |
392 | 0 | dst_xsize = (int)ceil((copyRect.maxx - copyRect.minx) / dst_cellsize_x); |
393 | 0 | dst_ysize = (int)ceil((copyRect.maxy - copyRect.miny) / dst_cellsize_y); |
394 | |
|
395 | 0 | if (dst_xsize == 0 || dst_ysize == 0) { |
396 | 0 | if (layer->debug) |
397 | 0 | msDebug("msContourLayerReadRaster(): no apparent overlap between map " |
398 | 0 | "view and this window(2).\n"); |
399 | 0 | return MS_SUCCESS; |
400 | 0 | } |
401 | | |
402 | 0 | if (layer->debug) |
403 | 0 | msDebug("msContourLayerReadRaster(): src=%d,%d,%d,%d, dst=%d,%d,%d,%d\n", |
404 | 0 | src_xoff, src_yoff, src_xsize, src_ysize, 0, 0, dst_xsize, |
405 | 0 | dst_ysize); |
406 | 0 | } else { |
407 | 0 | src_xoff = 0; |
408 | 0 | src_yoff = 0; |
409 | 0 | dst_xsize = src_xsize = MS_MIN(map->width, src_xsize); |
410 | 0 | dst_ysize = src_ysize = MS_MIN(map->height, src_ysize); |
411 | 0 | copyRect.minx = 0; |
412 | 0 | copyRect.miny = 0; |
413 | 0 | (void)copyRect.miny; |
414 | 0 | copyRect.maxx = map->width; |
415 | 0 | copyRect.maxy = map->height; |
416 | 0 | (void)copyRect.maxx; |
417 | 0 | dst_cellsize_y = dst_cellsize_x = 1; |
418 | 0 | } |
419 | | |
420 | | /* -------------------------------------------------------------------- */ |
421 | | /* Allocate buffer, and read data into it. */ |
422 | | /* -------------------------------------------------------------------- */ |
423 | | |
424 | 0 | clinfo->buffer = (double *)malloc(sizeof(double) * dst_xsize * dst_ysize); |
425 | 0 | if (clinfo->buffer == NULL) { |
426 | 0 | msSetError(MS_MEMERR, "Malloc(): Out of memory.", |
427 | 0 | "msContourLayerReadRaster()"); |
428 | 0 | return MS_FAILURE; |
429 | 0 | } |
430 | | |
431 | 0 | eErr = GDALRasterIO(hBand, GF_Read, src_xoff, src_yoff, src_xsize, src_ysize, |
432 | 0 | clinfo->buffer, dst_xsize, dst_ysize, GDT_Float64, 0, 0); |
433 | |
|
434 | 0 | if (eErr != CE_None) { |
435 | 0 | msSetError(MS_IOERR, "GDALRasterIO() failed: %s", |
436 | 0 | "msContourLayerReadRaster()", CPLGetLastErrorMsg()); |
437 | 0 | free(clinfo->buffer); |
438 | 0 | clinfo->buffer = NULL; |
439 | 0 | return MS_FAILURE; |
440 | 0 | } |
441 | | |
442 | 0 | GDALDriverH hMemDRV = GDALGetDriverByName("MEM"); |
443 | 0 | if (!hMemDRV) { |
444 | 0 | msSetError(MS_IOERR, "GDAL MEM driver not available", |
445 | 0 | "msContourLayerReadRaster()"); |
446 | 0 | free(clinfo->buffer); |
447 | 0 | clinfo->buffer = NULL; |
448 | 0 | return MS_FAILURE; |
449 | 0 | } |
450 | | |
451 | 0 | char pointer[64]; |
452 | 0 | memset(pointer, 0, sizeof(pointer)); |
453 | 0 | CPLPrintPointer(pointer, clinfo->buffer, sizeof(pointer)); |
454 | |
|
455 | 0 | clinfo->hDS = GDALCreate(hMemDRV, "", dst_xsize, dst_ysize, 0, 0, NULL); |
456 | 0 | if (clinfo->hDS == NULL) { |
457 | 0 | msSetError(MS_IMGERR, "Unable to create GDAL Memory dataset.", |
458 | 0 | "msContourLayerReadRaster()"); |
459 | 0 | free(clinfo->buffer); |
460 | 0 | clinfo->buffer = NULL; |
461 | 0 | return MS_FAILURE; |
462 | 0 | } |
463 | | |
464 | 0 | char **papszOptions = CSLSetNameValue(NULL, "DATAPOINTER", pointer); |
465 | 0 | eErr = GDALAddBand(clinfo->hDS, GDT_Float64, papszOptions); |
466 | 0 | CSLDestroy(papszOptions); |
467 | 0 | if (eErr != CE_None) { |
468 | 0 | msSetError(MS_IMGERR, "Unable to add band to GDAL Memory dataset.", |
469 | 0 | "msContourLayerReadRaster()"); |
470 | 0 | free(clinfo->buffer); |
471 | 0 | clinfo->buffer = NULL; |
472 | 0 | return MS_FAILURE; |
473 | 0 | } |
474 | | |
475 | 0 | { |
476 | | // Copy nodata value from source dataset to memory dataset |
477 | 0 | int bHasNoData = FALSE; |
478 | 0 | double dfNoDataValue = GDALGetRasterNoDataValue(hBand, &bHasNoData); |
479 | 0 | if (bHasNoData) { |
480 | 0 | GDALSetRasterNoDataValue(GDALGetRasterBand(clinfo->hDS, 1), |
481 | 0 | dfNoDataValue); |
482 | 0 | } |
483 | 0 | } |
484 | |
|
485 | 0 | adfGeoTransform[0] = copyRect.minx; |
486 | 0 | adfGeoTransform[1] = dst_cellsize_x; |
487 | 0 | adfGeoTransform[2] = 0; |
488 | 0 | adfGeoTransform[3] = copyRect.maxy; |
489 | 0 | adfGeoTransform[4] = 0; |
490 | 0 | adfGeoTransform[5] = -dst_cellsize_y; |
491 | |
|
492 | 0 | clinfo->cellsize = MS_MAX(dst_cellsize_x, dst_cellsize_y); |
493 | 0 | { |
494 | 0 | char buf[64]; |
495 | 0 | sprintf(buf, "%lf", clinfo->cellsize); |
496 | 0 | msInsertHashTable(&layer->metadata, "__data_cellsize__", buf); |
497 | 0 | } |
498 | |
|
499 | 0 | GDALSetGeoTransform(clinfo->hDS, adfGeoTransform); |
500 | 0 | return MS_SUCCESS; |
501 | 0 | } |
502 | | |
503 | 0 | static void msContourOGRCloseConnection(void *conn_handle) { |
504 | 0 | OGRDataSourceH hDS = (OGRDataSourceH)conn_handle; |
505 | |
|
506 | 0 | msAcquireLock(TLOCK_OGR); |
507 | 0 | OGR_DS_Destroy(hDS); |
508 | 0 | msReleaseLock(TLOCK_OGR); |
509 | 0 | } |
510 | | |
511 | | /* Function that parses multiple options in the a list. It also supports |
512 | | min/maxscaledenom checks. ie. "CONTOUR_INTERVAL=0,3842942:10" */ |
513 | 0 | static char *msContourGetOption(layerObj *layer, const char *name) { |
514 | 0 | int c, i, found = MS_FALSE; |
515 | 0 | char **values, **tmp, **options; |
516 | 0 | double maxscaledenom, minscaledenom; |
517 | 0 | char *value = NULL; |
518 | |
|
519 | 0 | options = CSLFetchNameValueMultiple(layer->processing, name); |
520 | 0 | c = CSLCount(options); |
521 | | |
522 | | /* First pass to find the value among options that have min/maxscaledenom */ |
523 | | /* specified */ |
524 | 0 | for (i = 0; i < c && found == MS_FALSE; ++i) { |
525 | 0 | values = CSLTokenizeStringComplex(options[i], ":", FALSE, FALSE); |
526 | 0 | if (CSLCount(values) == 2) { |
527 | 0 | tmp = CSLTokenizeStringComplex(values[0], ",", FALSE, FALSE); |
528 | 0 | if (CSLCount(tmp) == 2) { |
529 | 0 | minscaledenom = atof(tmp[0]); |
530 | 0 | maxscaledenom = atof(tmp[1]); |
531 | 0 | if (layer->map->scaledenom <= 0 || |
532 | 0 | (((maxscaledenom <= 0) || |
533 | 0 | (layer->map->scaledenom <= maxscaledenom)) && |
534 | 0 | ((minscaledenom <= 0) || |
535 | 0 | (layer->map->scaledenom > minscaledenom)))) { |
536 | 0 | value = msStrdup(values[1]); |
537 | 0 | found = MS_TRUE; |
538 | 0 | } |
539 | 0 | } |
540 | 0 | CSLDestroy(tmp); |
541 | 0 | } |
542 | 0 | CSLDestroy(values); |
543 | 0 | } |
544 | | |
545 | | /* Second pass to find the value among options that do NOT have */ |
546 | | /* min/maxscaledenom specified */ |
547 | 0 | for (i = 0; i < c && found == MS_FALSE; ++i) { |
548 | 0 | values = CSLTokenizeStringComplex(options[i], ":", FALSE, FALSE); |
549 | 0 | if (CSLCount(values) == 1) { |
550 | 0 | value = msStrdup(values[0]); |
551 | 0 | found = MS_TRUE; |
552 | 0 | } |
553 | 0 | CSLDestroy(values); |
554 | 0 | } |
555 | |
|
556 | 0 | CSLDestroy(options); |
557 | |
|
558 | 0 | return value; |
559 | 0 | } |
560 | | |
561 | 0 | static int msContourLayerGenerateContour(layerObj *layer) { |
562 | 0 | OGRSFDriverH hDriver; |
563 | 0 | OGRFieldDefnH hFld; |
564 | 0 | OGRLayerH hLayer; |
565 | 0 | const char *elevItem; |
566 | 0 | char *option; |
567 | 0 | double interval = 1.0, levels[1000]; |
568 | 0 | int levelCount = 0; |
569 | 0 | GDALRasterBandH hBand = NULL; |
570 | 0 | CPLErr eErr; |
571 | 0 | int bHasNoData = FALSE; |
572 | 0 | double dfNoDataValue; |
573 | |
|
574 | 0 | contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; |
575 | |
|
576 | 0 | OGRRegisterAll(); |
577 | |
|
578 | 0 | if (clinfo == NULL) { |
579 | 0 | msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", |
580 | 0 | "msContourLayerCreateOGRDataSource()"); |
581 | 0 | return MS_FAILURE; |
582 | 0 | } |
583 | | |
584 | 0 | if (!clinfo->hDS) { /* no overlap */ |
585 | 0 | return MS_SUCCESS; |
586 | 0 | } |
587 | | |
588 | 0 | hBand = GDALGetRasterBand(clinfo->hDS, 1); |
589 | 0 | if (hBand == NULL) { |
590 | 0 | msSetError(MS_IMGERR, "Band %d does not exist on dataset.", |
591 | 0 | "msContourLayerGenerateContour()", 1); |
592 | 0 | return MS_FAILURE; |
593 | 0 | } |
594 | | |
595 | | /* Create the OGR DataSource */ |
596 | 0 | hDriver = OGRGetDriverByName("Memory"); |
597 | 0 | if (hDriver == NULL) { |
598 | 0 | msSetError(MS_OGRERR, "Unable to get OGR driver 'Memory'.", |
599 | 0 | "msContourLayerCreateOGRDataSource()"); |
600 | 0 | return MS_FAILURE; |
601 | 0 | } |
602 | | |
603 | 0 | clinfo->hOGRDS = OGR_Dr_CreateDataSource(hDriver, "", NULL); |
604 | 0 | if (clinfo->hOGRDS == NULL) { |
605 | 0 | msSetError(MS_OGRERR, "Unable to create OGR DataSource.", |
606 | 0 | "msContourLayerCreateOGRDataSource()"); |
607 | 0 | return MS_FAILURE; |
608 | 0 | } |
609 | | |
610 | 0 | hLayer = OGR_DS_CreateLayer(clinfo->hOGRDS, clinfo->ogrLayer.name, NULL, |
611 | 0 | wkbLineString, NULL); |
612 | |
|
613 | 0 | hFld = OGR_Fld_Create("ID", OFTInteger); |
614 | 0 | OGR_Fld_SetWidth(hFld, 8); |
615 | 0 | OGR_L_CreateField(hLayer, hFld, FALSE); |
616 | 0 | OGR_Fld_Destroy(hFld); |
617 | | |
618 | | /* Check if we have a coutour item specified */ |
619 | 0 | elevItem = CSLFetchNameValue(layer->processing, "CONTOUR_ITEM"); |
620 | 0 | if (elevItem && strlen(elevItem) > 0) { |
621 | 0 | hFld = OGR_Fld_Create(elevItem, OFTReal); |
622 | 0 | OGR_Fld_SetWidth(hFld, 12); |
623 | 0 | OGR_Fld_SetPrecision(hFld, 3); |
624 | 0 | OGR_L_CreateField(hLayer, hFld, FALSE); |
625 | 0 | OGR_Fld_Destroy(hFld); |
626 | 0 | } else { |
627 | 0 | elevItem = NULL; |
628 | 0 | } |
629 | |
|
630 | 0 | option = msContourGetOption(layer, "CONTOUR_INTERVAL"); |
631 | 0 | if (option) { |
632 | 0 | interval = atof(option); |
633 | 0 | free(option); |
634 | 0 | } |
635 | |
|
636 | 0 | option = msContourGetOption(layer, "CONTOUR_LEVELS"); |
637 | 0 | if (option) { |
638 | 0 | int i, c; |
639 | 0 | char **levelsTmp; |
640 | 0 | levelsTmp = CSLTokenizeStringComplex(option, ",", FALSE, FALSE); |
641 | 0 | c = CSLCount(levelsTmp); |
642 | 0 | for (i = 0; i < c && i < (int)(sizeof(levels) / sizeof(double)); ++i) |
643 | 0 | levels[levelCount++] = atof(levelsTmp[i]); |
644 | |
|
645 | 0 | CSLDestroy(levelsTmp); |
646 | 0 | free(option); |
647 | 0 | } |
648 | |
|
649 | 0 | dfNoDataValue = GDALGetRasterNoDataValue(hBand, &bHasNoData); |
650 | |
|
651 | 0 | eErr = GDALContourGenerate( |
652 | 0 | hBand, interval, 0.0, levelCount, levels, bHasNoData, dfNoDataValue, |
653 | 0 | hLayer, OGR_FD_GetFieldIndex(OGR_L_GetLayerDefn(hLayer), "ID"), |
654 | 0 | (elevItem == NULL) |
655 | 0 | ? -1 |
656 | 0 | : OGR_FD_GetFieldIndex(OGR_L_GetLayerDefn(hLayer), elevItem), |
657 | 0 | NULL, NULL); |
658 | |
|
659 | 0 | if (eErr != CE_None) { |
660 | 0 | msSetError(MS_IOERR, "GDALContourGenerate() failed: %s", |
661 | 0 | "msContourLayerGenerateContour()", CPLGetLastErrorMsg()); |
662 | 0 | return MS_FAILURE; |
663 | 0 | } |
664 | | |
665 | 0 | msConnPoolRegister(&clinfo->ogrLayer, clinfo->hOGRDS, |
666 | 0 | msContourOGRCloseConnection); |
667 | |
|
668 | 0 | return MS_SUCCESS; |
669 | 0 | } |
670 | | |
671 | 0 | int msContourLayerOpen(layerObj *layer) { |
672 | 0 | char *decrypted_path; |
673 | 0 | char szPath[MS_MAXPATHLEN]; |
674 | 0 | contourLayerInfo *clinfo; |
675 | |
|
676 | 0 | if (layer->debug) |
677 | 0 | msDebug("Entering msContourLayerOpen().\n"); |
678 | | |
679 | | /* If we don't have info, initialize an empty one now */ |
680 | 0 | if (layer->layerinfo == NULL) |
681 | 0 | msContourLayerInfoInitialize(layer); |
682 | |
|
683 | 0 | clinfo = (contourLayerInfo *)layer->layerinfo; |
684 | 0 | if (layer->data == NULL && layer->tileindex == NULL) { |
685 | 0 | msSetError(MS_MISCERR, "Layer %s has neither DATA nor TILEINDEX defined.", |
686 | 0 | "msContourLayerOpen()", layer->name); |
687 | 0 | return MS_FAILURE; |
688 | 0 | } |
689 | | |
690 | 0 | if (layer->tileindex != NULL) { |
691 | 0 | char szTilename[MS_MAXPATHLEN]; |
692 | 0 | int status; |
693 | 0 | int tilelayerindex, tileitemindex, tilesrsindex; |
694 | 0 | rectObj searchrect; |
695 | 0 | layerObj *tlp; |
696 | 0 | shapeObj tshp; |
697 | 0 | char tilesrsname[1]; |
698 | |
|
699 | 0 | msInitShape(&tshp); |
700 | 0 | searchrect = layer->map->extent; |
701 | |
|
702 | 0 | status = msDrawRasterSetupTileLayer(layer->map, layer, &searchrect, |
703 | 0 | MS_FALSE, &tilelayerindex, |
704 | 0 | &tileitemindex, &tilesrsindex, &tlp); |
705 | 0 | if (status == MS_FAILURE) { |
706 | 0 | return MS_FAILURE; |
707 | 0 | } |
708 | | |
709 | 0 | status = msDrawRasterIterateTileIndex(layer, tlp, &tshp, tileitemindex, -1, |
710 | 0 | szTilename, sizeof(szTilename), |
711 | 0 | tilesrsname, sizeof(tilesrsname)); |
712 | 0 | if (status == MS_FAILURE || status == MS_DONE) { |
713 | 0 | if (status == MS_DONE) { |
714 | 0 | if (layer->debug) |
715 | 0 | msDebug("No raster matching filter.\n"); |
716 | 0 | } |
717 | 0 | msDrawRasterCleanupTileLayer(tlp, tilelayerindex); |
718 | 0 | return MS_FAILURE; |
719 | 0 | } |
720 | | |
721 | 0 | msDrawRasterCleanupTileLayer(tlp, tilelayerindex); |
722 | |
|
723 | 0 | msDrawRasterBuildRasterPath(layer->map, layer, szTilename, szPath); |
724 | 0 | decrypted_path = msStrdup(szPath); |
725 | | |
726 | | /* Cancel the time filter that might have been set on ours in case of */ |
727 | | /* a inline tileindex */ |
728 | 0 | msFreeExpression(&layer->filter); |
729 | 0 | msInitExpression(&layer->filter); |
730 | 0 | } else { |
731 | 0 | msTryBuildPath3(szPath, layer->map->mappath, layer->map->shapepath, |
732 | 0 | layer->data); |
733 | 0 | decrypted_path = msDecryptStringTokens(layer->map, szPath); |
734 | 0 | } |
735 | | |
736 | 0 | GDALAllRegister(); |
737 | | |
738 | | /* Open the original Dataset */ |
739 | |
|
740 | 0 | msAcquireLock(TLOCK_GDAL); |
741 | 0 | if (decrypted_path) { |
742 | 0 | clinfo->hOrigDS = GDALOpen(decrypted_path, GA_ReadOnly); |
743 | 0 | msFree(decrypted_path); |
744 | 0 | } else |
745 | 0 | clinfo->hOrigDS = NULL; |
746 | |
|
747 | 0 | msReleaseLock(TLOCK_GDAL); |
748 | |
|
749 | 0 | if (clinfo->hOrigDS == NULL) { |
750 | 0 | msSetError(MS_IMGERR, "Unable to open GDAL dataset.", |
751 | 0 | "msContourLayerOpen()"); |
752 | 0 | return MS_FAILURE; |
753 | 0 | } |
754 | | |
755 | | /* Open the raster source */ |
756 | 0 | if (msContourLayerReadRaster(layer, layer->map->extent) != MS_SUCCESS) |
757 | 0 | return MS_FAILURE; |
758 | | |
759 | | /* Generate Contour Dataset */ |
760 | 0 | if (msContourLayerGenerateContour(layer) != MS_SUCCESS) |
761 | 0 | return MS_FAILURE; |
762 | | |
763 | 0 | if (clinfo->hDS) { |
764 | 0 | GDALClose(clinfo->hDS); |
765 | 0 | clinfo->hDS = NULL; |
766 | 0 | free(clinfo->buffer); |
767 | 0 | } |
768 | | |
769 | | /* Open our virtual ogr layer */ |
770 | 0 | if (clinfo->hOGRDS && (msLayerOpen(&clinfo->ogrLayer) != MS_SUCCESS)) |
771 | 0 | return MS_FAILURE; |
772 | | |
773 | 0 | return MS_SUCCESS; |
774 | 0 | } |
775 | | |
776 | 0 | int msContourLayerIsOpen(layerObj *layer) { |
777 | 0 | if (layer->layerinfo) |
778 | 0 | return MS_TRUE; |
779 | 0 | return MS_FALSE; |
780 | 0 | } |
781 | | |
782 | 0 | int msContourLayerClose(layerObj *layer) { |
783 | 0 | contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; |
784 | |
|
785 | 0 | if (layer->debug) |
786 | 0 | msDebug("Entering msContourLayerClose().\n"); |
787 | |
|
788 | 0 | if (clinfo) { |
789 | 0 | if (clinfo->hOGRDS) |
790 | 0 | msConnPoolRelease(&clinfo->ogrLayer, clinfo->hOGRDS); |
791 | |
|
792 | 0 | msLayerClose(&clinfo->ogrLayer); |
793 | |
|
794 | 0 | if (clinfo->hDS) { |
795 | 0 | GDALClose(clinfo->hDS); |
796 | 0 | clinfo->hDS = NULL; |
797 | 0 | free(clinfo->buffer); |
798 | 0 | } |
799 | |
|
800 | 0 | if (clinfo->hOrigDS) { |
801 | 0 | GDALClose(clinfo->hOrigDS); |
802 | 0 | clinfo->hOrigDS = NULL; |
803 | 0 | } |
804 | |
|
805 | 0 | msContourLayerInfoFree(layer); |
806 | 0 | } |
807 | |
|
808 | 0 | return MS_SUCCESS; |
809 | 0 | } |
810 | | |
811 | 0 | int msContourLayerGetItems(layerObj *layer) { |
812 | 0 | const char *elevItem; |
813 | 0 | contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; |
814 | |
|
815 | 0 | if (clinfo == NULL) { |
816 | 0 | msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", |
817 | 0 | "msContourLayerGetItems()"); |
818 | 0 | return MS_FAILURE; |
819 | 0 | } |
820 | | |
821 | 0 | layer->numitems = 0; |
822 | 0 | layer->items = (char **)msSmallCalloc(sizeof(char *), 2); |
823 | |
|
824 | 0 | layer->items[layer->numitems++] = msStrdup("ID"); |
825 | 0 | elevItem = CSLFetchNameValue(layer->processing, "CONTOUR_ITEM"); |
826 | 0 | if (elevItem && strlen(elevItem) > 0) { |
827 | 0 | layer->items[layer->numitems++] = msStrdup(elevItem); |
828 | 0 | } |
829 | |
|
830 | 0 | return msLayerGetItems(&clinfo->ogrLayer); |
831 | 0 | } |
832 | | |
833 | 0 | int msContourLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery) { |
834 | 0 | int i; |
835 | 0 | rectObj newRect; |
836 | 0 | contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; |
837 | |
|
838 | 0 | if (layer->debug) |
839 | 0 | msDebug("Entering msContourLayerWhichShapes().\n"); |
840 | |
|
841 | 0 | if (clinfo == NULL) { |
842 | 0 | msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", |
843 | 0 | "msContourLayerWhichShapes()"); |
844 | 0 | return MS_FAILURE; |
845 | 0 | } |
846 | | |
847 | 0 | if (isQuery) { |
848 | 0 | newRect = layer->map->extent; |
849 | 0 | } else { |
850 | 0 | newRect = rect; |
851 | | /* if necessary, project the searchrect to source coords */ |
852 | 0 | if (msProjectionsDiffer(&(layer->map->projection), &(layer->projection))) { |
853 | 0 | if (msProjectRect(&layer->projection, &layer->map->projection, |
854 | 0 | &newRect) != MS_SUCCESS) { |
855 | 0 | msDebug("msContourLayerWhichShapes(%s): unable to reproject map " |
856 | 0 | "request rectangle into layer projection, canceling.\n", |
857 | 0 | layer->name); |
858 | 0 | return MS_FAILURE; |
859 | 0 | } |
860 | 0 | } |
861 | 0 | } |
862 | | |
863 | | /* regenerate the raster io */ |
864 | 0 | if (clinfo->hOGRDS) |
865 | 0 | msConnPoolRelease(&clinfo->ogrLayer, clinfo->hOGRDS); |
866 | |
|
867 | 0 | msLayerClose(&clinfo->ogrLayer); |
868 | | |
869 | | /* Open the raster source */ |
870 | 0 | if (msContourLayerReadRaster(layer, newRect) != MS_SUCCESS) |
871 | 0 | return MS_FAILURE; |
872 | | |
873 | | /* Generate Contour Dataset */ |
874 | 0 | if (msContourLayerGenerateContour(layer) != MS_SUCCESS) |
875 | 0 | return MS_FAILURE; |
876 | | |
877 | 0 | if (clinfo->hDS) { |
878 | 0 | GDALClose(clinfo->hDS); |
879 | 0 | clinfo->hDS = NULL; |
880 | 0 | free(clinfo->buffer); |
881 | 0 | } |
882 | |
|
883 | 0 | if (!clinfo->hOGRDS) /* no overlap */ |
884 | 0 | return MS_DONE; |
885 | | |
886 | | /* Open our virtual ogr layer */ |
887 | 0 | if (msLayerOpen(&clinfo->ogrLayer) != MS_SUCCESS) |
888 | 0 | return MS_FAILURE; |
889 | | |
890 | 0 | clinfo->ogrLayer.numitems = layer->numitems; |
891 | 0 | clinfo->ogrLayer.items = |
892 | 0 | (char **)msSmallMalloc(sizeof(char *) * layer->numitems); |
893 | 0 | for (i = 0; i < layer->numitems; ++i) { |
894 | 0 | clinfo->ogrLayer.items[i] = msStrdup(layer->items[i]); |
895 | 0 | } |
896 | |
|
897 | 0 | return msLayerWhichShapes(&clinfo->ogrLayer, rect, isQuery); |
898 | 0 | } |
899 | | |
900 | | int msContourLayerGetShape(layerObj *layer, shapeObj *shape, |
901 | 0 | resultObj *record) { |
902 | 0 | contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; |
903 | |
|
904 | 0 | if (layer->debug) |
905 | 0 | msDebug("Entering msContourLayerGetShape().\n"); |
906 | |
|
907 | 0 | if (clinfo == NULL) { |
908 | 0 | msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", |
909 | 0 | "msContourLayerGetShape()"); |
910 | 0 | return MS_FAILURE; |
911 | 0 | } |
912 | | |
913 | 0 | return msLayerGetShape(&clinfo->ogrLayer, shape, record); |
914 | 0 | } |
915 | | |
916 | 0 | int msContourLayerNextShape(layerObj *layer, shapeObj *shape) { |
917 | 0 | contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; |
918 | |
|
919 | 0 | if (layer->debug) |
920 | 0 | msDebug("Entering msContourLayerNextShape().\n"); |
921 | |
|
922 | 0 | if (clinfo == NULL) { |
923 | 0 | msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", |
924 | 0 | "msContourLayerNextShape()"); |
925 | 0 | return MS_FAILURE; |
926 | 0 | } |
927 | | |
928 | 0 | return msLayerNextShape(&clinfo->ogrLayer, shape); |
929 | 0 | } |
930 | | |
931 | | /************************************************************************/ |
932 | | /* msContourLayerGetExtent() */ |
933 | | /* Simple copy of the maprasterquery.c file. might change in the future */ |
934 | | /************************************************************************/ |
935 | | |
936 | 0 | int msContourLayerGetExtent(layerObj *layer, rectObj *extent) { |
937 | 0 | contourLayerInfo *clinfo = (contourLayerInfo *)layer->layerinfo; |
938 | |
|
939 | 0 | if (layer->debug) |
940 | 0 | msDebug("Entering msContourLayerGetExtent().\n"); |
941 | |
|
942 | 0 | if (clinfo == NULL) { |
943 | 0 | msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", |
944 | 0 | "msContourLayerGetExtent()"); |
945 | 0 | return MS_FAILURE; |
946 | 0 | } |
947 | | |
948 | 0 | MS_COPYRECT(extent, &clinfo->extent); |
949 | |
|
950 | 0 | return MS_SUCCESS; |
951 | 0 | } |
952 | | |
953 | | /************************************************************************/ |
954 | | /* msContourLayerSetTimeFilter() */ |
955 | | /* */ |
956 | | /* This function is actually just used in the context of */ |
957 | | /* setting a filter on the tileindex for time based queries. */ |
958 | | /* For instance via WMS requests. */ |
959 | | /* */ |
960 | | /* If a local shapefile tileindex is in use, we will set a */ |
961 | | /* backtics filter (shapefile compatible). If another layer is */ |
962 | | /* being used as the tileindex then we will forward the */ |
963 | | /* SetTimeFilter call to it. If there is no tileindex in */ |
964 | | /* place, we do nothing. */ |
965 | | /************************************************************************/ |
966 | | |
967 | | int msContourLayerSetTimeFilter(layerObj *layer, const char *timestring, |
968 | 0 | const char *timefield) { |
969 | 0 | int tilelayerindex; |
970 | |
|
971 | 0 | if (layer->debug) |
972 | 0 | msDebug("msContourLayerSetTimeFilter(%s,%s).\n", timestring, timefield); |
973 | | |
974 | | /* -------------------------------------------------------------------- */ |
975 | | /* If we don't have a tileindex the time filter has no effect. */ |
976 | | /* -------------------------------------------------------------------- */ |
977 | 0 | if (layer->tileindex == NULL) { |
978 | 0 | if (layer->debug) |
979 | 0 | msDebug("msContourLayerSetTimeFilter(): time filter without effect on " |
980 | 0 | "layers without tileindex.\n"); |
981 | 0 | return MS_SUCCESS; |
982 | 0 | } |
983 | | |
984 | | /* -------------------------------------------------------------------- */ |
985 | | /* Find the tileindex layer. */ |
986 | | /* -------------------------------------------------------------------- */ |
987 | 0 | tilelayerindex = msGetLayerIndex(layer->map, layer->tileindex); |
988 | | |
989 | | /* -------------------------------------------------------------------- */ |
990 | | /* If we are using a local shapefile as our tileindex (that is */ |
991 | | /* to say, the tileindex name is not of another layer), then we */ |
992 | | /* just install a backtics style filter on the current layer. */ |
993 | | /* -------------------------------------------------------------------- */ |
994 | 0 | if (tilelayerindex == -1) |
995 | 0 | return msLayerMakeBackticsTimeFilter(layer, timestring, timefield); |
996 | | |
997 | | /* -------------------------------------------------------------------- */ |
998 | | /* Otherwise we invoke the tileindex layers SetTimeFilter */ |
999 | | /* method. */ |
1000 | | /* -------------------------------------------------------------------- */ |
1001 | 0 | if (msCheckParentPointer(layer->map, "map") == MS_FAILURE) |
1002 | 0 | return MS_FAILURE; |
1003 | 0 | return msLayerSetTimeFilter(layer->GET_LAYER(map, tilelayerindex), timestring, |
1004 | 0 | timefield); |
1005 | 0 | } |
1006 | | |
1007 | | /************************************************************************/ |
1008 | | /* msRASTERLayerInitializeVirtualTable() */ |
1009 | | /************************************************************************/ |
1010 | | |
1011 | 0 | int msContourLayerInitializeVirtualTable(layerObj *layer) { |
1012 | 0 | assert(layer != NULL); |
1013 | 0 | assert(layer->vtable != NULL); |
1014 | | |
1015 | 0 | layer->vtable->LayerInitItemInfo = msContourLayerInitItemInfo; |
1016 | 0 | layer->vtable->LayerFreeItemInfo = msContourLayerFreeItemInfo; |
1017 | 0 | layer->vtable->LayerOpen = msContourLayerOpen; |
1018 | 0 | layer->vtable->LayerIsOpen = msContourLayerIsOpen; |
1019 | 0 | layer->vtable->LayerWhichShapes = msContourLayerWhichShapes; |
1020 | 0 | layer->vtable->LayerNextShape = msContourLayerNextShape; |
1021 | 0 | layer->vtable->LayerGetShape = msContourLayerGetShape; |
1022 | | /* layer->vtable->LayerGetShapeCount, use default */ |
1023 | 0 | layer->vtable->LayerClose = msContourLayerClose; |
1024 | 0 | layer->vtable->LayerGetItems = msContourLayerGetItems; |
1025 | 0 | layer->vtable->LayerGetExtent = msContourLayerGetExtent; |
1026 | | /* layer->vtable->LayerGetAutoStyle, use default */ |
1027 | | /* layer->vtable->LayerApplyFilterToLayer, use default */ |
1028 | | /*layer->vtable->LayerCloseConnection = msContourLayerClose;*/ |
1029 | | /* we use backtics for proper tileindex shapefile functioning */ |
1030 | 0 | layer->vtable->LayerSetTimeFilter = msContourLayerSetTimeFilter; |
1031 | | /* layer->vtable->LayerCreateItems, use default */ |
1032 | | /* layer->vtable->LayerGetNumFeatures, use default */ |
1033 | |
|
1034 | 0 | return MS_SUCCESS; |
1035 | 0 | } |