/src/MapServer/src/mapobject.c
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * $Id$ |
3 | | * |
4 | | * Project: MapServer |
5 | | * Purpose: Functions for operating on a mapObj that don't belong in a |
6 | | * more specific file such as mapfile.c, or mapdraw.c. |
7 | | * Author: Frank Warmerdam, warmerdam@pobox.com |
8 | | * |
9 | | ****************************************************************************** |
10 | | * Copyright (c) 2004, Frank Warmerdam |
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 |
23 | | * OR 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 "mapows.h" |
33 | | |
34 | | #include "gdal.h" |
35 | | #include "cpl_conv.h" |
36 | | |
37 | | void freeWeb(webObj *web); |
38 | | void freeScalebar(scalebarObj *scalebar); |
39 | | void freeReferenceMap(referenceMapObj *ref); |
40 | | void freeLegend(legendObj *legend); |
41 | | |
42 | | /************************************************************************/ |
43 | | /* msNewMapObj() */ |
44 | | /* */ |
45 | | /* Create a new initialized map object. */ |
46 | | /************************************************************************/ |
47 | | |
48 | 0 | mapObj *msNewMapObj() { |
49 | 0 | mapObj *map = NULL; |
50 | | |
51 | | /* create an empty map, no layers etc... */ |
52 | 0 | map = (mapObj *)calloc(1, sizeof(mapObj)); |
53 | |
|
54 | 0 | if (!map) { |
55 | 0 | msSetError(MS_MEMERR, NULL, "msCreateMap()"); |
56 | 0 | return NULL; |
57 | 0 | } |
58 | | |
59 | 0 | if (initMap(map) == -1) { |
60 | 0 | msFreeMap(map); |
61 | 0 | return NULL; |
62 | 0 | } |
63 | | |
64 | 0 | if (msPostMapParseOutputFormatSetup(map) == MS_FAILURE) { |
65 | 0 | msFreeMap(map); |
66 | 0 | return NULL; |
67 | 0 | } |
68 | | |
69 | 0 | return map; |
70 | 0 | } |
71 | | |
72 | | /************************************************************************/ |
73 | | /* msFreeMap() */ |
74 | | /************************************************************************/ |
75 | | |
76 | 22.8k | void msFreeMap(mapObj *map) { |
77 | 22.8k | int i; |
78 | | |
79 | 22.8k | if (!map) |
80 | 11.2k | return; |
81 | | |
82 | | /* printf("msFreeMap(): maybe freeing map at %p count=%d.\n",map, |
83 | | * map->refcount); */ |
84 | 11.6k | if (MS_REFCNT_DECR_IS_NOT_ZERO(map)) { |
85 | 0 | return; |
86 | 0 | } |
87 | 11.6k | if (map->debug >= MS_DEBUGLEVEL_VV) |
88 | 1 | msDebug("msFreeMap(): freeing map at %p.\n", map); |
89 | | |
90 | 11.6k | msCloseConnections(map); |
91 | | |
92 | 11.6k | msFree(map->name); |
93 | 11.6k | msFree(map->shapepath); |
94 | 11.6k | msFree(map->mappath); |
95 | | |
96 | 11.6k | msFreeProjection(&(map->projection)); |
97 | 11.6k | msFreeProjection(&(map->latlon)); |
98 | 11.6k | msProjectionContextReleaseToPool(map->projContext); |
99 | | |
100 | 11.6k | msFreeLabelCache(&(map->labelcache)); |
101 | | |
102 | 11.6k | msFree(map->imagetype); |
103 | | |
104 | 11.6k | msFreeFontSet(&(map->fontset)); |
105 | | |
106 | 11.6k | msFreeSymbolSet(&map->symbolset); /* free symbols */ |
107 | 11.6k | msFree(map->symbolset.filename); |
108 | | |
109 | 11.6k | freeWeb(&(map->web)); |
110 | | |
111 | 11.6k | freeScalebar(&(map->scalebar)); |
112 | 11.6k | freeReferenceMap(&(map->reference)); |
113 | 11.6k | freeLegend(&(map->legend)); |
114 | | |
115 | 319k | for (i = 0; i < map->maxlayers; i++) { |
116 | 307k | if (GET_LAYER(map, i) != NULL) { |
117 | 30.8k | GET_LAYER(map, i)->map = NULL; |
118 | 30.8k | if (freeLayer((GET_LAYER(map, i))) == MS_SUCCESS) |
119 | 30.8k | free(GET_LAYER(map, i)); |
120 | 30.8k | } |
121 | 307k | } |
122 | 11.6k | msFree(map->layers); |
123 | | |
124 | 11.6k | if (map->layerorder) |
125 | 4.78k | free(map->layerorder); |
126 | | |
127 | 11.6k | msFree(map->templatepattern); |
128 | 11.6k | msFree(map->datapattern); |
129 | 11.6k | msFreeHashItems(&(map->configoptions)); |
130 | 11.6k | if (map->outputformat && map->outputformat->refcount > 0 && |
131 | 1.18k | --map->outputformat->refcount < 1) |
132 | 0 | msFreeOutputFormat(map->outputformat); |
133 | | |
134 | 12.7k | for (i = 0; i < map->numoutputformats; i++) { |
135 | 1.18k | if (map->outputformatlist[i]->refcount > 0 && |
136 | 1.18k | --map->outputformatlist[i]->refcount < 1) |
137 | 1.18k | msFreeOutputFormat(map->outputformatlist[i]); |
138 | 1.18k | } |
139 | 11.6k | if (map->outputformatlist != NULL) |
140 | 1.18k | msFree(map->outputformatlist); |
141 | | |
142 | 11.6k | msFreeQuery(&(map->query)); |
143 | | |
144 | | #ifdef USE_V8_MAPSCRIPT |
145 | | if (map->v8context) |
146 | | msV8FreeContext(map); |
147 | | #endif |
148 | | |
149 | 11.6k | msFree(map); |
150 | 11.6k | } |
151 | | |
152 | | /************************************************************************/ |
153 | | /* msGetConfigOption() */ |
154 | | /************************************************************************/ |
155 | | |
156 | | const char *msGetConfigOption(mapObj *map, const char *key) |
157 | | |
158 | 0 | { |
159 | 0 | return msLookupHashTable(&(map->configoptions), key); |
160 | 0 | } |
161 | | |
162 | | /************************************************************************/ |
163 | | /* msSetConfigOption() */ |
164 | | /************************************************************************/ |
165 | | |
166 | | int msSetConfigOption(mapObj *map, const char *key, const char *value) |
167 | | |
168 | 4.81k | { |
169 | | /* We have special "early" handling of this so that it will be */ |
170 | | /* in effect when the projection blocks are parsed and pj_init is called. */ |
171 | 4.81k | if (strcasecmp(key, "PROJ_DATA") == 0 || strcasecmp(key, "PROJ_LIB") == 0) { |
172 | | /* value may be relative to map path */ |
173 | 539 | msSetPROJ_DATA(value, map->mappath); |
174 | 539 | } |
175 | | |
176 | | /* Same for MS_ERRORFILE, we want it to kick in as early as possible |
177 | | * to catch parsing errors. |
178 | | * Value can be relative to mapfile, unless it's already absolute |
179 | | */ |
180 | 4.81k | if (strcasecmp(key, "MS_ERRORFILE") == 0) { |
181 | 296 | if (msSetErrorFile(value, map->mappath) != MS_SUCCESS) |
182 | 3 | return MS_FAILURE; |
183 | 296 | } |
184 | | |
185 | 4.80k | if (msLookupHashTable(&(map->configoptions), key) != NULL) |
186 | 2.28k | msRemoveHashTable(&(map->configoptions), key); |
187 | 4.80k | msInsertHashTable(&(map->configoptions), key, value); |
188 | | |
189 | 4.80k | return MS_SUCCESS; |
190 | 4.81k | } |
191 | | |
192 | | /************************************************************************/ |
193 | | /* msTestConfigOption() */ |
194 | | /************************************************************************/ |
195 | | |
196 | | int msTestConfigOption(mapObj *map, const char *key, int default_result) |
197 | | |
198 | 0 | { |
199 | 0 | const char *result = msGetConfigOption(map, key); |
200 | |
|
201 | 0 | if (result == NULL) |
202 | 0 | return default_result; |
203 | | |
204 | 0 | if (strcasecmp(result, "YES") == 0 || strcasecmp(result, "ON") == 0 || |
205 | 0 | strcasecmp(result, "TRUE") == 0) |
206 | 0 | return MS_TRUE; |
207 | 0 | else |
208 | 0 | return MS_FALSE; |
209 | 0 | } |
210 | | |
211 | | /************************************************************************/ |
212 | | /* msApplyMapConfigOptions() */ |
213 | | /************************************************************************/ |
214 | | |
215 | | void msApplyMapConfigOptions(mapObj *map) |
216 | | |
217 | 1.18k | { |
218 | 1.18k | const char *key; |
219 | | |
220 | 3.05k | for (key = msFirstKeyFromHashTable(&(map->configoptions)); key != NULL; |
221 | 1.86k | key = msNextKeyFromHashTable(&(map->configoptions), key)) { |
222 | 1.86k | const char *value = msLookupHashTable(&(map->configoptions), key); |
223 | 1.86k | if (strcasecmp(key, "PROJ_DATA") == 0 || strcasecmp(key, "PROJ_LIB") == 0) { |
224 | 25 | msSetPROJ_DATA(value, map->mappath); |
225 | 1.84k | } else if (strcasecmp(key, "MS_ERRORFILE") == 0) { |
226 | 0 | msSetErrorFile(value, map->mappath); |
227 | 1.84k | } else { |
228 | 1.84k | CPLSetConfigOption(key, value); |
229 | 1.84k | } |
230 | 1.86k | } |
231 | 1.18k | } |
232 | | |
233 | | /************************************************************************/ |
234 | | /* msMapIgnoreMissingData() */ |
235 | | /************************************************************************/ |
236 | | |
237 | 0 | int msMapIgnoreMissingData(mapObj *map) { |
238 | 0 | const char *result = msGetConfigOption(map, "ON_MISSING_DATA"); |
239 | 0 | const int default_result = |
240 | 0 | #ifndef IGNORE_MISSING_DATA |
241 | 0 | MS_MISSING_DATA_FAIL; |
242 | | #else |
243 | | MS_MISSING_DATA_LOG; |
244 | | #endif |
245 | |
|
246 | 0 | if (result == NULL) |
247 | 0 | return default_result; |
248 | | |
249 | 0 | if (strcasecmp(result, "FAIL") == 0) |
250 | 0 | return MS_MISSING_DATA_FAIL; |
251 | 0 | else if (strcasecmp(result, "LOG") == 0) |
252 | 0 | return MS_MISSING_DATA_LOG; |
253 | 0 | else if (strcasecmp(result, "IGNORE") == 0) |
254 | 0 | return MS_MISSING_DATA_IGNORE; |
255 | | |
256 | 0 | return default_result; |
257 | 0 | } |
258 | | |
259 | | /************************************************************************/ |
260 | | /* msMapSetExtent() */ |
261 | | /************************************************************************/ |
262 | | |
263 | | int msMapSetExtent(mapObj *map, double minx, double miny, double maxx, |
264 | 0 | double maxy) { |
265 | |
|
266 | 0 | map->extent.minx = minx; |
267 | 0 | map->extent.miny = miny; |
268 | 0 | map->extent.maxx = maxx; |
269 | 0 | map->extent.maxy = maxy; |
270 | |
|
271 | 0 | if (!MS_VALID_EXTENT(map->extent)) { |
272 | 0 | msSetError(MS_MISCERR, |
273 | 0 | "Given map extent is invalid. Check that it " |
274 | 0 | "is in the form: minx, miny, maxx, maxy", |
275 | 0 | "setExtent()"); |
276 | 0 | return MS_FAILURE; |
277 | 0 | } |
278 | | |
279 | 0 | map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height); |
280 | | |
281 | | /* if the map size is also set, recompute scale, ignore errors? */ |
282 | 0 | if (map->width != -1 || map->height != -1) |
283 | 0 | msCalculateScale(map->extent, map->units, map->width, map->height, |
284 | 0 | map->resolution, &(map->scaledenom)); |
285 | |
|
286 | 0 | return msMapComputeGeotransform(map); |
287 | 0 | } |
288 | | |
289 | | /************************************************************************/ |
290 | | /* msMapOffsetExtent() */ |
291 | | /************************************************************************/ |
292 | | |
293 | 0 | int msMapOffsetExtent(mapObj *map, double x, double y) { |
294 | 0 | return msMapSetExtent(map, map->extent.minx + x, map->extent.miny + y, |
295 | 0 | map->extent.maxx + x, map->extent.maxy + y); |
296 | 0 | } |
297 | | |
298 | | /************************************************************************/ |
299 | | /* msMapScaleExtent() */ |
300 | | /************************************************************************/ |
301 | | |
302 | | int msMapScaleExtent(mapObj *map, double zoomfactor, double minscaledenom, |
303 | 0 | double maxscaledenom) { |
304 | 0 | double geo_width, geo_height, center_x, center_y, md; |
305 | |
|
306 | 0 | if (zoomfactor <= 0.0) { |
307 | 0 | msSetError(MS_MISCERR, "The given zoomfactor is invalid", |
308 | 0 | "msMapScaleExtent()"); |
309 | 0 | } |
310 | |
|
311 | 0 | geo_width = map->extent.maxx - map->extent.minx; |
312 | 0 | geo_height = map->extent.maxy - map->extent.miny; |
313 | |
|
314 | 0 | center_x = map->extent.minx + geo_width * 0.5; |
315 | 0 | center_y = map->extent.miny + geo_height * 0.5; |
316 | |
|
317 | 0 | geo_width *= zoomfactor; |
318 | |
|
319 | 0 | if (minscaledenom > 0 || maxscaledenom > 0) { |
320 | | /* ensure we are within the valid scale domain */ |
321 | 0 | md = (map->width - 1) / |
322 | 0 | (map->resolution * msInchesPerUnit(map->units, center_y)); |
323 | 0 | if (minscaledenom > 0 && geo_width < minscaledenom * md) |
324 | 0 | geo_width = minscaledenom * md; |
325 | 0 | if (maxscaledenom > 0 && geo_width > maxscaledenom * md) |
326 | 0 | geo_width = maxscaledenom * md; |
327 | 0 | } |
328 | |
|
329 | 0 | geo_width *= 0.5; |
330 | 0 | geo_height = geo_width * map->height / map->width; |
331 | |
|
332 | 0 | return msMapSetExtent(map, center_x - geo_width, center_y - geo_height, |
333 | 0 | center_x + geo_width, center_y + geo_height); |
334 | 0 | } |
335 | | |
336 | | /************************************************************************/ |
337 | | /* msMapSetCenter() */ |
338 | | /************************************************************************/ |
339 | | |
340 | 0 | int msMapSetCenter(mapObj *map, pointObj *center) { |
341 | 0 | return msMapOffsetExtent( |
342 | 0 | map, center->x - (map->extent.minx + map->extent.maxx) * 0.5, |
343 | 0 | center->y - (map->extent.miny + map->extent.maxy) * 0.5); |
344 | 0 | } |
345 | | |
346 | | /************************************************************************/ |
347 | | /* msMapSetRotation() */ |
348 | | /************************************************************************/ |
349 | | |
350 | | int msMapSetRotation(mapObj *map, double rotation_angle) |
351 | | |
352 | 499 | { |
353 | 499 | map->gt.rotation_angle = rotation_angle; |
354 | 499 | if (map->gt.rotation_angle != 0.0) |
355 | 154 | map->gt.need_geotransform = MS_TRUE; |
356 | 345 | else |
357 | 345 | map->gt.need_geotransform = MS_FALSE; |
358 | | |
359 | 499 | return msMapComputeGeotransform(map); |
360 | 499 | } |
361 | | |
362 | | /************************************************************************/ |
363 | | /* msMapSetSize() */ |
364 | | /************************************************************************/ |
365 | | |
366 | | int msMapSetSize(mapObj *map, int width, int height) |
367 | | |
368 | 0 | { |
369 | 0 | map->width = width; |
370 | 0 | map->height = height; |
371 | |
|
372 | 0 | return msMapComputeGeotransform(map); /* like SetRotation -- sean */ |
373 | 0 | } |
374 | | |
375 | | /************************************************************************/ |
376 | | /* msMapComputeGeotransform() */ |
377 | | /************************************************************************/ |
378 | | |
379 | | extern int InvGeoTransform(double *gt_in, double *gt_out); |
380 | | |
381 | | int msMapComputeGeotransformEx(mapObj *map, double resolutionX, |
382 | | double resolutionY) |
383 | | |
384 | 430 | { |
385 | 430 | double rot_angle; |
386 | 430 | double geo_width, geo_height, center_x, center_y; |
387 | | |
388 | 430 | map->saved_extent = map->extent; |
389 | | |
390 | 430 | rot_angle = map->gt.rotation_angle * MS_PI / 180.0; |
391 | | |
392 | 430 | geo_width = map->extent.maxx - map->extent.minx; |
393 | 430 | geo_height = map->extent.maxy - map->extent.miny; |
394 | | |
395 | 430 | center_x = map->extent.minx + geo_width * 0.5; |
396 | 430 | center_y = map->extent.miny + geo_height * 0.5; |
397 | | |
398 | | /* |
399 | | ** Per bug 1916 we have to adjust for the fact that map extents |
400 | | ** are based on the center of the edge pixels, not the outer |
401 | | ** edges as is expected in a geotransform. |
402 | | */ |
403 | 430 | map->gt.geotransform[1] = cos(rot_angle) * resolutionX; |
404 | 430 | map->gt.geotransform[2] = sin(rot_angle) * resolutionY; |
405 | 430 | map->gt.geotransform[0] = center_x - |
406 | 430 | (map->width * 0.5) * map->gt.geotransform[1] - |
407 | 430 | (map->height * 0.5) * map->gt.geotransform[2]; |
408 | | |
409 | 430 | map->gt.geotransform[4] = sin(rot_angle) * resolutionX; |
410 | 430 | map->gt.geotransform[5] = -cos(rot_angle) * resolutionY; |
411 | 430 | map->gt.geotransform[3] = center_y - |
412 | 430 | (map->width * 0.5) * map->gt.geotransform[4] - |
413 | 430 | (map->height * 0.5) * map->gt.geotransform[5]; |
414 | | |
415 | 430 | if (InvGeoTransform(map->gt.geotransform, map->gt.invgeotransform)) |
416 | 430 | return MS_SUCCESS; |
417 | 0 | else |
418 | 0 | return MS_FAILURE; |
419 | 430 | } |
420 | | |
421 | | int msMapComputeGeotransform(mapObj *map) |
422 | | |
423 | 1.68k | { |
424 | | /* Do we have all required parameters? */ |
425 | 1.68k | if (map->extent.minx == map->extent.maxx || map->width <= 1 || |
426 | 436 | map->height <= 1) |
427 | 1.25k | return MS_FAILURE; |
428 | | |
429 | 430 | const double geo_width = map->extent.maxx - map->extent.minx; |
430 | 430 | const double geo_height = map->extent.maxy - map->extent.miny; |
431 | 430 | return msMapComputeGeotransformEx(map, geo_width / (map->width - 1), |
432 | 430 | geo_height / (map->height - 1)); |
433 | 1.68k | } |
434 | | |
435 | | /************************************************************************/ |
436 | | /* msMapPixelToGeoref() */ |
437 | | /************************************************************************/ |
438 | | |
439 | | void msMapPixelToGeoref(mapObj *map, double *x, double *y) |
440 | | |
441 | 0 | { |
442 | 0 | (void)map; |
443 | 0 | (void)x; |
444 | 0 | (void)y; |
445 | 0 | msSetError(MS_MISCERR, NULL, "msMapPixelToGeoref() not yet implemented"); |
446 | 0 | } |
447 | | |
448 | | /************************************************************************/ |
449 | | /* msMapGeorefToPixel() */ |
450 | | /************************************************************************/ |
451 | | |
452 | | void msMapGeorefToPixel(mapObj *map, double *x, double *y) |
453 | | |
454 | 0 | { |
455 | 0 | (void)map; |
456 | 0 | (void)x; |
457 | 0 | (void)y; |
458 | 0 | msSetError(MS_MISCERR, NULL, "msMapGeorefToPixel() not yet implemented"); |
459 | 0 | } |
460 | | |
461 | | /************************************************************************/ |
462 | | /* msMapSetFakedExtent() */ |
463 | | /************************************************************************/ |
464 | | |
465 | | int msMapSetFakedExtent(mapObj *map) |
466 | | |
467 | 0 | { |
468 | 0 | int i; |
469 | | /* -------------------------------------------------------------------- */ |
470 | | /* Remember the original map extents so we can restore them */ |
471 | | /* later. */ |
472 | | /* -------------------------------------------------------------------- */ |
473 | 0 | map->saved_extent = map->extent; |
474 | | |
475 | | /* -------------------------------------------------------------------- */ |
476 | | /* Set extents such that the bottom left corner is 0,0 and the */ |
477 | | /* top right is width,height. Note this is upside down from */ |
478 | | /* the normal sense of pixel/line coordinates, but we do this */ |
479 | | /* so that the normal "extent" concept of coordinates */ |
480 | | /* increasing to the right, and up is maintained (like in */ |
481 | | /* georeferenced coordinate systems). */ |
482 | | /* -------------------------------------------------------------------- */ |
483 | 0 | map->extent.minx = 0; |
484 | 0 | map->extent.maxx = map->width; |
485 | 0 | map->extent.miny = 0; |
486 | 0 | map->extent.maxy = map->height; |
487 | 0 | map->cellsize = 1.0; |
488 | | |
489 | | /* -------------------------------------------------------------------- */ |
490 | | /* When we copy the geotransform into the projection object we */ |
491 | | /* have to flip it to account for the preceding upside-down */ |
492 | | /* coordinate system. */ |
493 | | /* -------------------------------------------------------------------- */ |
494 | 0 | map->projection.gt = map->gt; |
495 | |
|
496 | 0 | map->projection.gt.geotransform[0] += map->height * map->gt.geotransform[2]; |
497 | 0 | map->projection.gt.geotransform[3] += map->height * map->gt.geotransform[5]; |
498 | |
|
499 | 0 | map->projection.gt.geotransform[2] *= -1; |
500 | 0 | map->projection.gt.geotransform[5] *= -1; |
501 | |
|
502 | 0 | for (i = 0; i < map->numlayers; i++) |
503 | 0 | GET_LAYER(map, i)->project = MS_TRUE; |
504 | |
|
505 | 0 | return InvGeoTransform(map->projection.gt.geotransform, |
506 | 0 | map->projection.gt.invgeotransform); |
507 | 0 | } |
508 | | |
509 | | /************************************************************************/ |
510 | | /* msMapRestoreRealExtent() */ |
511 | | /************************************************************************/ |
512 | | |
513 | | int msMapRestoreRealExtent(mapObj *map) |
514 | | |
515 | 0 | { |
516 | 0 | map->projection.gt.need_geotransform = MS_FALSE; |
517 | 0 | map->extent = map->saved_extent; |
518 | 0 | map->cellsize = msAdjustExtent(&(map->extent), map->width, map->height); |
519 | |
|
520 | 0 | return MS_SUCCESS; |
521 | 0 | } |
522 | | |
523 | | /************************************************************************/ |
524 | | /* msInsertLayer() */ |
525 | | /************************************************************************/ |
526 | | /* Returns the index at which the layer was inserted |
527 | | */ |
528 | | |
529 | 0 | int msInsertLayer(mapObj *map, layerObj *layer, int nIndex) { |
530 | 0 | if (!layer) { |
531 | 0 | msSetError(MS_CHILDERR, "Can't insert a NULL Layer", "msInsertLayer()"); |
532 | 0 | return -1; |
533 | 0 | } |
534 | | |
535 | | /* Ensure there is room for a new layer */ |
536 | 0 | if (map->numlayers == map->maxlayers) { |
537 | 0 | if (msGrowMapLayers(map) == NULL) |
538 | 0 | return -1; |
539 | 0 | } |
540 | | |
541 | | /* msGrowMapLayers allocates the new layer which we don't need to do since we |
542 | | have 1 that we are inserting not sure if it is possible for this to be non |
543 | | null otherwise, but better to check since this function replaces the value |
544 | | */ |
545 | 0 | if (map->layers[map->numlayers] != NULL) |
546 | 0 | free(map->layers[map->numlayers]); |
547 | | |
548 | | /* Catch attempt to insert past end of layers array */ |
549 | 0 | if (nIndex >= map->numlayers) { |
550 | 0 | msSetError(MS_CHILDERR, "Cannot insert layer beyond index %d", |
551 | 0 | "msInsertLayer()", map->numlayers - 1); |
552 | 0 | return -1; |
553 | 0 | } else if (nIndex < 0) { /* Insert at the end by default */ |
554 | 0 | map->layerorder[map->numlayers] = map->numlayers; |
555 | 0 | GET_LAYER(map, map->numlayers) = layer; |
556 | 0 | GET_LAYER(map, map->numlayers)->index = map->numlayers; |
557 | 0 | GET_LAYER(map, map->numlayers)->map = map; |
558 | 0 | MS_REFCNT_INCR(layer); |
559 | 0 | map->numlayers++; |
560 | 0 | return map->numlayers - 1; |
561 | 0 | } else { |
562 | | /* Move existing layers at the specified nIndex or greater */ |
563 | | /* to an index one higher */ |
564 | 0 | int i; |
565 | 0 | for (i = map->numlayers; i > nIndex; i--) { |
566 | 0 | GET_LAYER(map, i) = GET_LAYER(map, i - 1); |
567 | 0 | GET_LAYER(map, i)->index = i; |
568 | 0 | } |
569 | | |
570 | | /* assign new layer to specified index */ |
571 | 0 | GET_LAYER(map, nIndex) = layer; |
572 | 0 | GET_LAYER(map, nIndex)->index = nIndex; |
573 | 0 | GET_LAYER(map, nIndex)->map = map; |
574 | | |
575 | | /* adjust layers drawing order */ |
576 | 0 | for (i = map->numlayers; i > nIndex; i--) { |
577 | 0 | map->layerorder[i] = map->layerorder[i - 1]; |
578 | 0 | if (map->layerorder[i] >= nIndex) |
579 | 0 | map->layerorder[i]++; |
580 | 0 | } |
581 | 0 | for (i = 0; i < nIndex; i++) { |
582 | 0 | if (map->layerorder[i] >= nIndex) |
583 | 0 | map->layerorder[i]++; |
584 | 0 | } |
585 | 0 | map->layerorder[nIndex] = nIndex; |
586 | | |
587 | | /* increment number of layers and return */ |
588 | 0 | MS_REFCNT_INCR(layer); |
589 | 0 | map->numlayers++; |
590 | 0 | return nIndex; |
591 | 0 | } |
592 | 0 | } |
593 | | |
594 | | /************************************************************************/ |
595 | | /* msRemoveLayer() */ |
596 | | /************************************************************************/ |
597 | 0 | layerObj *msRemoveLayer(mapObj *map, int nIndex) { |
598 | 0 | int i; |
599 | 0 | int order_index; |
600 | 0 | layerObj *layer; |
601 | |
|
602 | 0 | if (nIndex < 0 || nIndex >= map->numlayers) { |
603 | 0 | msSetError(MS_CHILDERR, "Cannot remove Layer, invalid index %d", |
604 | 0 | "msRemoveLayer()", nIndex); |
605 | 0 | return NULL; |
606 | 0 | } else { |
607 | 0 | layer = GET_LAYER(map, nIndex); |
608 | | /* msCopyLayer(layer, (GET_LAYER(map, nIndex))); */ |
609 | | |
610 | | /* Iteratively copy the higher index layers down one index */ |
611 | 0 | for (i = nIndex; i < map->numlayers - 1; i++) { |
612 | | /* freeLayer((GET_LAYER(map, i))); */ |
613 | | /* initLayer((GET_LAYER(map, i)), map); */ |
614 | | /* msCopyLayer(GET_LAYER(map, i), GET_LAYER(map, i+1)); */ |
615 | 0 | GET_LAYER(map, i) = GET_LAYER(map, i + 1); |
616 | 0 | GET_LAYER(map, i)->index = i; |
617 | 0 | } |
618 | | /* Free the extra layer at the end */ |
619 | | /* freeLayer((GET_LAYER(map, map->numlayers-1))); */ |
620 | 0 | GET_LAYER(map, map->numlayers - 1) = NULL; |
621 | | |
622 | | /* Adjust drawing order */ |
623 | 0 | order_index = 0; |
624 | 0 | for (i = 0; i < map->numlayers; i++) { |
625 | 0 | if (map->layerorder[i] > nIndex) |
626 | 0 | map->layerorder[i]--; |
627 | 0 | if (map->layerorder[i] == nIndex) { |
628 | 0 | order_index = i; |
629 | 0 | break; |
630 | 0 | } |
631 | 0 | } |
632 | 0 | for (i = order_index; i < map->numlayers - 1; i++) { |
633 | 0 | map->layerorder[i] = map->layerorder[i + 1]; |
634 | 0 | if (map->layerorder[i] > nIndex) |
635 | 0 | map->layerorder[i]--; |
636 | 0 | } |
637 | | |
638 | | /* decrement number of layers and return copy of removed layer */ |
639 | 0 | map->numlayers--; |
640 | 0 | layer->map = NULL; |
641 | 0 | MS_REFCNT_DECR(layer); |
642 | 0 | return layer; |
643 | 0 | } |
644 | 0 | } |
645 | | |
646 | | /* |
647 | | ** Move the layer's order for drawing purpose. Moving it up here |
648 | | ** will have the effect of drawing the layer earlier. |
649 | | */ |
650 | 0 | int msMoveLayerUp(mapObj *map, int nLayerIndex) { |
651 | 0 | int iCurrentIndex = -1; |
652 | 0 | if (map && nLayerIndex < map->numlayers && nLayerIndex >= 0) { |
653 | 0 | for (int i = 0; i < map->numlayers; i++) { |
654 | 0 | if (map->layerorder[i] == nLayerIndex) { |
655 | 0 | iCurrentIndex = i; |
656 | 0 | break; |
657 | 0 | } |
658 | 0 | } |
659 | 0 | if (iCurrentIndex >= 0) { |
660 | | /* we do not need to promote if it is the first one. */ |
661 | 0 | if (iCurrentIndex == 0) |
662 | 0 | return MS_FAILURE; |
663 | | |
664 | 0 | map->layerorder[iCurrentIndex] = map->layerorder[iCurrentIndex - 1]; |
665 | 0 | map->layerorder[iCurrentIndex - 1] = nLayerIndex; |
666 | |
|
667 | 0 | return MS_SUCCESS; |
668 | 0 | } |
669 | 0 | } |
670 | 0 | msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveLayerUp()", nLayerIndex); |
671 | 0 | return MS_FAILURE; |
672 | 0 | } |
673 | | |
674 | | /* |
675 | | ** Move the layer's order for drawing purpose. Moving it down here |
676 | | ** will have the effect of drawing the layer later. |
677 | | */ |
678 | 0 | int msMoveLayerDown(mapObj *map, int nLayerIndex) { |
679 | 0 | int iCurrentIndex = -1; |
680 | 0 | if (map && nLayerIndex < map->numlayers && nLayerIndex >= 0) { |
681 | 0 | for (int i = 0; i < map->numlayers; i++) { |
682 | 0 | if (map->layerorder[i] == nLayerIndex) { |
683 | 0 | iCurrentIndex = i; |
684 | 0 | break; |
685 | 0 | } |
686 | 0 | } |
687 | 0 | if (iCurrentIndex >= 0) { |
688 | | /* we do not need to demote if it is the last one. */ |
689 | 0 | if (iCurrentIndex == map->numlayers - 1) |
690 | 0 | return MS_FAILURE; |
691 | | |
692 | 0 | map->layerorder[iCurrentIndex] = map->layerorder[iCurrentIndex + 1]; |
693 | 0 | map->layerorder[iCurrentIndex + 1] = nLayerIndex; |
694 | |
|
695 | 0 | return MS_SUCCESS; |
696 | 0 | } |
697 | 0 | } |
698 | 0 | msSetError(MS_CHILDERR, "Invalid index: %d", "msMoveLayerDown()", |
699 | 0 | nLayerIndex); |
700 | 0 | return MS_FAILURE; |
701 | 0 | } |
702 | | |
703 | | /* |
704 | | ** Set the array used for the drawing order. The array passed must contain |
705 | | ** all the layer's index ordered by the drawing priority. |
706 | | ** Ex : for 3 layers in the map file, if |
707 | | ** panIndexes[0] = 2 |
708 | | ** panIndexes[1] = 0 |
709 | | ** panIndexes[2] = 1 |
710 | | ** will set the darwing order to layer 2, layer 0, |
711 | | ** and then layer 1. |
712 | | ** |
713 | | ** Note : It is assumed that the index panIndexes has the same number of |
714 | | ** of elements as the number of layers in the map. |
715 | | ** Return TRUE on success else FALSE. |
716 | | */ |
717 | 0 | int msSetLayersdrawingOrder(mapObj *self, int *panIndexes) { |
718 | 0 | if (self && panIndexes) { |
719 | 0 | const int nElements = self->numlayers; |
720 | 0 | for (int i = 0; i < nElements; i++) { |
721 | 0 | int bFound = 0; |
722 | 0 | for (int j = 0; j < nElements; j++) { |
723 | 0 | if (panIndexes[j] == i) { |
724 | 0 | bFound = 1; |
725 | 0 | break; |
726 | 0 | } |
727 | 0 | } |
728 | 0 | if (!bFound) |
729 | 0 | return 0; |
730 | 0 | } |
731 | | /* -------------------------------------------------------------------- */ |
732 | | /* At this point the array is valid so update the layers order array.*/ |
733 | | /* -------------------------------------------------------------------- */ |
734 | 0 | for (int i = 0; i < nElements; i++) { |
735 | 0 | self->layerorder[i] = panIndexes[i]; |
736 | 0 | } |
737 | 0 | return 1; |
738 | 0 | } |
739 | 0 | return 0; |
740 | 0 | } |
741 | | |
742 | | /* ========================================================================= |
743 | | msMapLoadOWSParameters |
744 | | |
745 | | Function to support mapscript mapObj::loadOWSParameters |
746 | | ========================================================================= */ |
747 | | |
748 | | int msMapLoadOWSParameters(mapObj *map, cgiRequestObj *request, |
749 | 0 | const char *wmtver) { |
750 | 0 | #ifdef USE_WMS_SVR |
751 | 0 | int version; |
752 | 0 | char *wms_exception_format = NULL; |
753 | 0 | const char *wms_request = NULL; |
754 | 0 | int result, i = 0; |
755 | 0 | owsRequestObj ows_request; |
756 | |
|
757 | 0 | msOWSInitRequestObj(&ows_request); |
758 | |
|
759 | 0 | version = msOWSParseVersionString(wmtver); |
760 | 0 | for (i = 0; i < request->NumParams; i++) { |
761 | 0 | if (strcasecmp(request->ParamNames[i], "EXCEPTIONS") == 0) |
762 | 0 | wms_exception_format = request->ParamValues[i]; |
763 | 0 | else if (strcasecmp(request->ParamNames[i], "REQUEST") == 0) |
764 | 0 | wms_request = request->ParamValues[i]; |
765 | 0 | } |
766 | |
|
767 | 0 | msOWSRequestLayersEnabled(map, "M", wms_request, &ows_request); |
768 | |
|
769 | 0 | result = msWMSLoadGetMapParams( |
770 | 0 | map, version, request->ParamNames, request->ParamValues, |
771 | 0 | request->NumParams, wms_exception_format, wms_request, &ows_request); |
772 | |
|
773 | 0 | msOWSClearRequestObj(&ows_request); |
774 | |
|
775 | 0 | return result; |
776 | |
|
777 | | #else |
778 | | msSetError(MS_WMSERR, "WMS server support is not available.", |
779 | | "msMapLoadOWSParameters()"); |
780 | | return MS_FAILURE; |
781 | | #endif |
782 | 0 | } |