1 /******************************************************************************
2 * $Id$
3 *
4 * Project: MapServer
5 * Purpose: Implementation of the union layer data provider (RFC-68).
6 * Author: Tamas Szekeres (szekerest@gmail.com).
7 *
8 ******************************************************************************
9 * Copyright (c) 1996-2005 Regents of the University of Minnesota.
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
22 * OR 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 #define _CRT_SECURE_NO_WARNINGS 1
31
32 /* $Id$ */
33 #include <assert.h>
34 #include "mapserver.h"
35
36
37
38 #define MSUNION_NUMITEMS 3
39 #define MSUNION_SOURCELAYERNAME "Union_SourceLayerName"
40 #define MSUNION_SOURCELAYERNAMEINDEX -100
41 #define MSUNION_SOURCELAYERGROUP "Union_SourceLayerGroup"
42 #define MSUNION_SOURCELAYERGROUPINDEX -101
43 #define MSUNION_SOURCELAYERVISIBLE "Union_SourceLayerVisible"
44 #define MSUNION_SOURCELAYERVISIBLEINDEX -102
45
46 typedef struct {
47 int layerIndex; /* current source layer index */
48 int classIndex; /* current class index */
49 char* classText; /* current class text (autostyle) */
50 int layerCount; /* number of the source layers */
51 layerObj* layers; /* structure to the source layers */
52 int *status; /* the layer status */
53 int *classgroup; /* current array of the valid classes */
54 int nclasses; /* number of the valid classes */
55 reprojectionObj* reprojectorSrcLayerToLayer;
56 int reprojectorCurSrcLayer;
57 } msUnionLayerInfo;
58
59 /* Close the the combined layer */
msUnionLayerClose(layerObj * layer)60 int msUnionLayerClose(layerObj *layer)
61 {
62 int i;
63 msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo;
64
65 if (!layerinfo)
66 return MS_SUCCESS;
67
68 if (!layer->map)
69 return MS_FAILURE;
70
71 msProjectDestroyReprojector(layerinfo->reprojectorSrcLayerToLayer);
72 for (i = 0; i < layerinfo->layerCount; i++) {
73 msLayerClose(&layerinfo->layers[i]);
74 freeLayer(&layerinfo->layers[i]);
75 }
76 msFree(layerinfo->layers);
77 msFree(layerinfo->status);
78 msFree(layerinfo->classgroup);
79 msFree(layerinfo->classText);
80 msFree(layerinfo);
81 layer->layerinfo = NULL;
82
83 return MS_SUCCESS;
84 }
85
isScaleInRange(mapObj * map,layerObj * layer)86 int isScaleInRange(mapObj* map, layerObj *layer)
87 {
88 if(map->scaledenom > 0) {
89 int i;
90 /* layer scale boundaries should be checked first */
91 if((layer->maxscaledenom > 0) && (map->scaledenom > layer->maxscaledenom))
92 return MS_FALSE;
93
94 if((layer->minscaledenom > 0) && (map->scaledenom <= layer->minscaledenom))
95 return MS_FALSE;
96
97 /* now check class scale boundaries (all layers *must* pass these tests) */
98 if(layer->numclasses > 0) {
99 for(i=0; i<layer->numclasses; i++) {
100 if((layer->class[i]->maxscaledenom > 0) && (map->scaledenom > layer->class[i]->maxscaledenom))
101 continue; /* can skip this one, next class */
102 if((layer->class[i]->minscaledenom > 0) && (map->scaledenom <= layer->class[i]->minscaledenom))
103 continue; /* can skip this one, next class */
104
105 break; /* can't skip this class (or layer for that matter) */
106 }
107 if(i == layer->numclasses)
108 return MS_FALSE;
109
110 }
111
112 if (layer->maxscaledenom <= 0 && layer->minscaledenom <= 0) {
113 if((layer->maxgeowidth > 0) && ((map->extent.maxx - map->extent.minx) > layer->maxgeowidth))
114 return MS_FALSE;
115
116 if((layer->mingeowidth > 0) && ((map->extent.maxx - map->extent.minx) < layer->mingeowidth))
117 return MS_FALSE;
118 }
119 }
120 return MS_TRUE;
121 }
122
msUnionLayerOpen(layerObj * layer)123 int msUnionLayerOpen(layerObj *layer)
124 {
125 msUnionLayerInfo *layerinfo;
126 char **layerNames;
127 mapObj* map;
128 int i;
129 int layerCount;
130 const char* pkey;
131 int status_check;
132 int scale_check;
133
134 if (layer->layerinfo != NULL) {
135 return MS_SUCCESS; /* Nothing to do... layer is already opened */
136 }
137
138 if (!layer->connection) {
139 msSetError(MS_MISCERR, "The CONNECTION option is not specified for layer: %s", "msUnionLayerOpen()", layer->name);
140 return MS_FAILURE;
141 }
142
143 if (!layer->map) {
144 msSetError(MS_MISCERR, "No map assigned to this layer: %s", "msUnionLayerOpen()", layer->name);
145 return MS_FAILURE;
146 }
147
148 map = layer->map;
149
150 layerinfo =(msUnionLayerInfo*)calloc(1, sizeof(msUnionLayerInfo));
151 MS_CHECK_ALLOC(layerinfo, sizeof(msUnionLayerInfo), MS_FAILURE);
152
153 layer->layerinfo = layerinfo;
154 layerinfo->layerIndex = 0;
155
156 layerinfo->classgroup = NULL;
157 layerinfo->nclasses = 0;
158
159 layerinfo->layerCount = 0;
160
161 layerinfo->classText = NULL;
162 layerinfo->reprojectorCurSrcLayer = -1;
163
164 pkey = msLayerGetProcessingKey(layer, "UNION_STATUS_CHECK");
165 if(pkey && strcasecmp(pkey, "true") == 0)
166 status_check = MS_TRUE;
167 else
168 status_check = MS_FALSE;
169
170 pkey = msLayerGetProcessingKey(layer, "UNION_SCALE_CHECK");
171 if(pkey && strcasecmp(pkey, "false") == 0)
172 scale_check = MS_FALSE;
173 else
174 scale_check = MS_TRUE;
175
176 pkey = msLayerGetProcessingKey(layer, "UNION_SRCLAYER_CLOSE_CONNECTION");
177
178 layerNames = msStringSplit(layer->connection, ',', &layerCount);
179
180 if (layerCount == 0) {
181 msSetError(MS_MISCERR, "No source layers specified in layer: %s", "msUnionLayerOpen()", layer->name);
182 if(layerNames)
183 msFreeCharArray(layerNames, layerinfo->layerCount);
184 msUnionLayerClose(layer);
185 return MS_FAILURE;
186 }
187
188 layerinfo->layers =(layerObj*)malloc(layerCount * sizeof(layerObj));
189 MS_CHECK_ALLOC(layerinfo->layers, layerCount * sizeof(layerObj), MS_FAILURE);
190
191 layerinfo->status =(int*)malloc(layerCount * sizeof(int));
192 MS_CHECK_ALLOC(layerinfo->status, layerCount * sizeof(int), MS_FAILURE);
193
194 for(i=0; i < layerCount; i++) {
195 int layerindex = msGetLayerIndex(map, layerNames[i]);
196 if (layerindex >= 0 && layerindex < map->numlayers) {
197 layerObj* srclayer = map->layers[layerindex];
198
199 if (srclayer->type != layer->type) {
200 msSetError(MS_MISCERR, "The type of the source layer doesn't match with the union layer: %s", "msUnionLayerOpen()", srclayer->name);
201 if(layerNames)
202 msFreeCharArray(layerNames, layerinfo->layerCount);
203 msUnionLayerClose(layer);
204 return MS_FAILURE;
205 }
206
207 /* we need to create a new layer in order make the singlepass query to work */
208 if(initLayer(&layerinfo->layers[i], map) == -1) {
209 msSetError(MS_MISCERR, "Cannot initialize source layer: %s", "msUnionLayerOpen()", srclayer->name);
210 if(layerNames)
211 msFreeCharArray(layerNames, layerinfo->layerCount);
212 msUnionLayerClose(layer);
213 return MS_FAILURE;
214 }
215
216 ++layerinfo->layerCount;
217
218 if (msCopyLayer(&layerinfo->layers[i], srclayer) != MS_SUCCESS) {
219 msSetError(MS_MISCERR, "Cannot copy source layer: %s", "msUnionLayerOpen()", srclayer->name);
220 if(layerNames)
221 msFreeCharArray(layerNames, layerinfo->layerCount);
222 msUnionLayerClose(layer);
223 return MS_FAILURE;
224 }
225
226 if (pkey) {
227 /* override connection flag */
228 msLayerSetProcessingKey(&layerinfo->layers[i], "CLOSE_CONNECTION", pkey);
229 }
230
231 /* check is we should skip this source (status check) */
232 if (status_check && layerinfo->layers[i].status == MS_OFF) {
233 layerinfo->status[i] = MS_DONE;
234 continue;
235 }
236
237 /* check is we should skip this source (scale check) */
238 if (scale_check && isScaleInRange(map, &layerinfo->layers[i]) == MS_FALSE) {
239 layerinfo->status[i] = MS_DONE;
240 continue;
241 }
242
243 layerinfo->status[i] = msLayerOpen(&layerinfo->layers[i]);
244 if (layerinfo->status[i] != MS_SUCCESS) {
245 if(layerNames)
246 msFreeCharArray(layerNames, layerinfo->layerCount);
247 msUnionLayerClose(layer);
248 return MS_FAILURE;
249 }
250 } else {
251 msSetError(MS_MISCERR, "Invalid layer: %s", "msUnionLayerOpen()", layerNames[i]);
252 if(layerNames)
253 msFreeCharArray(layerNames, layerinfo->layerCount);
254 msUnionLayerClose(layer);
255 return MS_FAILURE;
256 }
257 }
258
259 if(layerNames)
260 msFreeCharArray(layerNames, layerinfo->layerCount);
261
262 return MS_SUCCESS;
263 }
264
265 /* Return MS_TRUE if layer is open, MS_FALSE otherwise. */
msUnionLayerIsOpen(layerObj * layer)266 int msUnionLayerIsOpen(layerObj *layer)
267 {
268 if (layer->layerinfo)
269 return(MS_TRUE);
270 else
271 return(MS_FALSE);
272 }
273
274 /* Free the itemindexes array in a layer. */
msUnionLayerFreeItemInfo(layerObj * layer)275 void msUnionLayerFreeItemInfo(layerObj *layer)
276 {
277 int i;
278 msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo;
279
280 if (!layerinfo || !layer->map)
281 return;
282
283 msFree(layer->iteminfo);
284
285 layer->iteminfo = NULL;
286
287 for (i = 0; i < layerinfo->layerCount; i++) {
288 msLayerFreeItemInfo(&layerinfo->layers[i]);
289 if(layerinfo->layers[i].items) {
290 /* need to remove the source layer items */
291 msFreeCharArray(layerinfo->layers[i].items, layerinfo->layers[i].numitems);
292 layerinfo->layers[i].items = NULL;
293 layerinfo->layers[i].numitems = 0;
294 }
295 }
296 }
297
298 /* clean up expression tokens */
msUnionLayerFreeExpressionTokens(layerObj * layer)299 void msUnionLayerFreeExpressionTokens(layerObj *layer)
300 {
301 int i,j;
302 msFreeExpressionTokens(&(layer->filter));
303 msFreeExpressionTokens(&(layer->cluster.group));
304 msFreeExpressionTokens(&(layer->cluster.filter));
305 for(i=0; i<layer->numclasses; i++) {
306 msFreeExpressionTokens(&(layer->class[i]->expression));
307 msFreeExpressionTokens(&(layer->class[i]->text));
308 for(j=0; j<layer->class[i]->numstyles; j++)
309 msFreeExpressionTokens(&(layer->class[i]->styles[j]->_geomtransform));
310 }
311 }
312
313 /* allocate the iteminfo index array - same order as the item list */
msUnionLayerInitItemInfo(layerObj * layer)314 int msUnionLayerInitItemInfo(layerObj *layer)
315 {
316 int i, numitems;
317 int *itemindexes;
318 char* itemlist = NULL;
319
320 msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo;
321
322 if(layer->numitems == 0) {
323 return MS_SUCCESS;
324 }
325
326 if (!layerinfo || !layer->map)
327 return MS_FAILURE;
328
329 /* Cleanup any previous item selection */
330 msUnionLayerFreeItemInfo(layer);
331
332 layer->iteminfo = (int *) malloc(sizeof(int) * layer->numitems);
333 MS_CHECK_ALLOC(layer->iteminfo, sizeof(int) * layer->numitems, MS_FAILURE);
334
335 itemindexes = (int*)layer->iteminfo;
336
337 /* check whether we require attributes from the source layers also */
338 numitems = 0;
339 for (i = 0; i < layer->numitems; i++) {
340 if (EQUAL(layer->items[i], MSUNION_SOURCELAYERNAME))
341 itemindexes[i] = MSUNION_SOURCELAYERNAMEINDEX;
342 else if (EQUAL(layer->items[i], MSUNION_SOURCELAYERGROUP))
343 itemindexes[i] = MSUNION_SOURCELAYERGROUPINDEX;
344 else if (EQUAL(layer->items[i], MSUNION_SOURCELAYERVISIBLE))
345 itemindexes[i] = MSUNION_SOURCELAYERVISIBLEINDEX;
346 else {
347 itemindexes[i] = numitems++;
348 if (itemlist) {
349 itemlist = msStringConcatenate(itemlist, ",");
350 itemlist = msStringConcatenate(itemlist, layer->items[i]);
351 } else {
352 itemlist = msStrdup(layer->items[i]);
353 }
354 }
355 }
356
357 for (i = 0; i < layerinfo->layerCount; i++) {
358 layerObj* srclayer = &layerinfo->layers[i];
359
360 if (layerinfo->status[i] != MS_SUCCESS)
361 continue; /* skip empty layers */
362
363 msUnionLayerFreeExpressionTokens(srclayer);
364
365 if (itemlist) {
366 /* get items requested by the union layer plus the required items */
367 msLayerSetProcessingKey(srclayer, "ITEMS", itemlist);
368 if (msLayerWhichItems(srclayer, MS_TRUE, NULL) != MS_SUCCESS) {
369 msFree(itemlist);
370 return MS_FAILURE;
371 }
372 } else {
373 /* get only the required items */
374 if (msLayerWhichItems(srclayer, MS_FALSE, NULL) != MS_SUCCESS)
375 return MS_FAILURE;
376 }
377 }
378
379 msFree(itemlist);
380 return MS_SUCCESS;
381 }
382
msUnionLayerWhichShapes(layerObj * layer,rectObj rect,int isQuery)383 int msUnionLayerWhichShapes(layerObj *layer, rectObj rect, int isQuery)
384 {
385 int i;
386 layerObj* srclayer;
387 rectObj srcRect;
388 msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo;
389
390 if (!layerinfo || !layer->map)
391 return MS_FAILURE;
392
393 for (i = 0; i < layerinfo->layerCount; i++) {
394 layerObj* srclayer = &layerinfo->layers[i];
395
396 if (layerinfo->status[i] != MS_SUCCESS)
397 continue; /* skip empty layers */
398
399 if (layer->styleitem && layer->numitems == 0) {
400 /* need to initialize items */
401 msUnionLayerFreeExpressionTokens(srclayer);
402
403 /* get only the required items */
404 if (msLayerWhichItems(srclayer, MS_FALSE, NULL) != MS_SUCCESS)
405 return MS_FAILURE;
406 }
407
408 srcRect = rect;
409
410 if(srclayer->transform == MS_TRUE && srclayer->project && layer->transform == MS_TRUE && layer->project &&msProjectionsDiffer(&(srclayer->projection), &(layer->projection)))
411 msProjectRect(&layer->projection, &srclayer->projection, &srcRect); /* project the searchrect to source coords */
412
413 layerinfo->status[i] = msLayerWhichShapes(srclayer, srcRect, isQuery);
414 if (layerinfo->status[i] == MS_FAILURE)
415 return MS_FAILURE;
416 }
417
418 layerinfo->layerIndex = 0;
419 srclayer = &layerinfo->layers[0];
420
421 msFree(layerinfo->classgroup);
422
423 layerinfo->classgroup = NULL;
424 layerinfo->nclasses = 0;
425
426 if (srclayer->classgroup && srclayer->numclasses > 0)
427 layerinfo->classgroup = msAllocateValidClassGroups(srclayer, &layerinfo->nclasses);
428
429 return MS_SUCCESS;
430 }
431
BuildFeatureAttributes(layerObj * layer,layerObj * srclayer,shapeObj * shape)432 static int BuildFeatureAttributes(layerObj *layer, layerObj* srclayer, shapeObj *shape)
433 {
434 int i;
435 char **values;
436 int* itemindexes = layer->iteminfo;
437
438 values = malloc(sizeof(char*) * (layer->numitems));
439 MS_CHECK_ALLOC(values, layer->numitems * sizeof(char*), MS_FAILURE);;
440
441 for (i = 0; i < layer->numitems; i++) {
442 if (itemindexes[i] == MSUNION_SOURCELAYERNAMEINDEX)
443 values[i] = msStrdup(srclayer->name);
444 else if (itemindexes[i] == MSUNION_SOURCELAYERGROUPINDEX)
445 values[i] = msStrdup(srclayer->group);
446 else if (itemindexes[i] == MSUNION_SOURCELAYERVISIBLEINDEX) {
447 if (srclayer->status == MS_OFF)
448 values[i] = msStrdup("0");
449 else
450 values[i] = msStrdup("1");
451 } else if (shape->values[itemindexes[i]])
452 values[i] = msStrdup(shape->values[itemindexes[i]]);
453 else
454 values[i] = msStrdup("");
455 }
456
457 if (shape->values)
458 msFreeCharArray(shape->values, shape->numvalues);
459
460 shape->values = values;
461 shape->numvalues = layer->numitems;
462
463 return MS_SUCCESS;
464 }
465
466 /* find the next shape with the appropriate shape type */
467 /* also, load in the attribute data */
468 /* MS_DONE => no more data */
msUnionLayerNextShape(layerObj * layer,shapeObj * shape)469 int msUnionLayerNextShape(layerObj *layer, shapeObj *shape)
470 {
471 int rv;
472 layerObj* srclayer;
473 msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo;
474
475 if (!layerinfo || !layer->map)
476 return MS_FAILURE;
477
478 if (layerinfo->layerIndex < 0 || layerinfo->layerIndex >= layerinfo->layerCount)
479 return MS_FAILURE;
480
481 rv = MS_DONE;
482
483 while (layerinfo->layerIndex < layerinfo->layerCount) {
484 srclayer = &layerinfo->layers[layerinfo->layerIndex];
485 if (layerinfo->status[layerinfo->layerIndex] == MS_SUCCESS) {
486 while ((rv = srclayer->vtable->LayerNextShape(srclayer, shape)) == MS_SUCCESS) {
487 if(layer->styleitem) {
488 /* need to retrieve the source layer classindex if styleitem AUTO is set */
489 layerinfo->classIndex = msShapeGetClass(srclayer, layer->map, shape, layerinfo->classgroup, layerinfo->nclasses);
490 if(layerinfo->classIndex < 0 || layerinfo->classIndex >= srclayer->numclasses) {
491 /* this shape is not visible, skip it */
492 msFreeShape(shape);
493 if (rv == MS_SUCCESS)
494 continue;
495 else
496 break;
497 }
498 if(srclayer->styleitem && strcasecmp(srclayer->styleitem, "AUTO") != 0) {
499 /* Generic feature style handling as per RFC-61 */
500 msLayerGetFeatureStyle(layer->map, srclayer, srclayer->class[layerinfo->classIndex], shape);
501 }
502 /* set up annotation */
503 msFree(layerinfo->classText);
504 layerinfo->classText = NULL;
505 if(srclayer->class[layerinfo->classIndex]->numlabels > 0) {
506 /* pull text from the first label only */
507 if(msGetLabelStatus(layer->map,layer,shape,srclayer->class[layerinfo->classIndex]->labels[0]) == MS_ON) {
508 layerinfo->classText = msShapeGetLabelAnnotation(layer,shape,srclayer->class[layerinfo->classIndex]->labels[0]);
509 }
510 }
511 }
512
513 /* reproject to the target layer */
514 if( layerinfo->reprojectorCurSrcLayer != layerinfo->layerIndex )
515 {
516 msProjectDestroyReprojector(layerinfo->reprojectorSrcLayerToLayer);
517 layerinfo->reprojectorSrcLayerToLayer = NULL;
518 layerinfo->reprojectorCurSrcLayer = layerinfo->layerIndex;
519 if(srclayer->project && msProjectionsDiffer(&(srclayer->projection), &(layer->projection)))
520 layerinfo->reprojectorSrcLayerToLayer = msProjectCreateReprojector(&(srclayer->projection), &(layer->projection));
521 else
522 srclayer->project = MS_FALSE;
523 }
524 if(layerinfo->reprojectorSrcLayerToLayer)
525 msProjectShapeEx(layerinfo->reprojectorSrcLayerToLayer, shape);
526
527 /* update the layer styles with the bound values */
528 if(msBindLayerToShape(srclayer, shape, MS_FALSE) != MS_SUCCESS)
529 return MS_FAILURE;
530
531 shape->tileindex = layerinfo->layerIndex;
532
533 /* construct the item array */
534 if (layer->iteminfo)
535 rv = BuildFeatureAttributes(layer, srclayer, shape);
536
537 /* check the layer filter condition */
538 if(layer->filter.string != NULL && layer->numitems > 0 && layer->iteminfo) {
539 if (layer->filter.type == MS_EXPRESSION && layer->filter.tokens == NULL)
540 msTokenizeExpression(&(layer->filter), layer->items, &(layer->numitems));
541
542 if (!msEvalExpression(layer, shape, &(layer->filter), layer->filteritemindex)) {
543 /* this shape is filtered */
544 msFreeShape(shape);
545 continue;
546 }
547 }
548
549 return rv;
550 }
551 }
552
553 ++layerinfo->layerIndex;
554 if (layerinfo->layerIndex == layerinfo->layerCount) {
555 layerinfo->layerIndex = 0;
556 return MS_DONE;
557 }
558
559 /* allocate the classgroups for the next layer */
560 msFree(layerinfo->classgroup);
561
562 layerinfo->classgroup = NULL;
563 layerinfo->nclasses = 0;
564
565 if (srclayer->classgroup && srclayer->numclasses > 0)
566 layerinfo->classgroup = msAllocateValidClassGroups(srclayer, &layerinfo->nclasses);
567 }
568
569 return rv;
570 }
571
572 /* Random access of the feature. */
msUnionLayerGetShape(layerObj * layer,shapeObj * shape,resultObj * record)573 int msUnionLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record)
574 {
575 int rv;
576 layerObj* srclayer;
577 long tile = record->tileindex;
578 msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo;
579
580 if (!layerinfo || !layer->map)
581 return MS_FAILURE;
582
583 if (tile < 0 || tile >= layerinfo->layerCount) {
584 msSetError(MS_MISCERR, "Invalid tile index: %s", "msUnionLayerGetShape()", layer->name);
585 return MS_FAILURE;
586 }
587
588 srclayer = &layerinfo->layers[tile];
589 record->tileindex = 0;
590 rv = srclayer->vtable->LayerGetShape(srclayer, shape, record);
591 record->tileindex = tile;
592
593 if (rv == MS_SUCCESS) {
594 /* reproject to the target layer */
595 if( layerinfo->reprojectorCurSrcLayer != tile )
596 {
597 msProjectDestroyReprojector(layerinfo->reprojectorSrcLayerToLayer);
598 layerinfo->reprojectorSrcLayerToLayer = NULL;
599 layerinfo->reprojectorCurSrcLayer = tile;
600 if(srclayer->project && msProjectionsDiffer(&(srclayer->projection), &(layer->projection)))
601 layerinfo->reprojectorSrcLayerToLayer = msProjectCreateReprojector(&(srclayer->projection), &(layer->projection));
602 else
603 srclayer->project = MS_FALSE;
604 }
605 if(layerinfo->reprojectorSrcLayerToLayer)
606 msProjectShapeEx(layerinfo->reprojectorSrcLayerToLayer, shape);
607
608 shape->tileindex = tile;
609
610 /* construct the item array */
611 if (layer->iteminfo)
612 rv = BuildFeatureAttributes(layer, srclayer, shape);
613 }
614
615 return rv;
616 }
617
618 /* Query for the items collection */
msUnionLayerGetItems(layerObj * layer)619 int msUnionLayerGetItems(layerObj *layer)
620 {
621 /* we support certain built in attributes */
622 layer->numitems = 2;
623 layer->items = malloc(sizeof(char*) * (layer->numitems));
624 MS_CHECK_ALLOC(layer->items, layer->numitems * sizeof(char*), MS_FAILURE);
625 layer->items[0] = msStrdup(MSUNION_SOURCELAYERNAME);
626 layer->items[1] = msStrdup(MSUNION_SOURCELAYERGROUP);
627
628 return msUnionLayerInitItemInfo(layer);
629 }
630
msUnionLayerGetNumFeatures(layerObj * layer)631 int msUnionLayerGetNumFeatures(layerObj *layer)
632 {
633 int i, c, numFeatures;
634 msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo;
635
636 if (!layerinfo || !layer->map)
637 return 0;
638
639 numFeatures = 0;
640
641 for (i = 0; i < layerinfo->layerCount; i++) {
642 if (layerinfo->status[i] != MS_SUCCESS)
643 continue; /* skip empty layers */
644
645 c = msLayerGetNumFeatures(&layerinfo->layers[i]);
646 if (c > 0)
647 numFeatures += c;
648 }
649
650 return numFeatures;
651 }
652
msUnionLayerGetAutoStyle(mapObj * map,layerObj * layer,classObj * c,shapeObj * shape)653 static int msUnionLayerGetAutoStyle(mapObj *map, layerObj *layer, classObj *c, shapeObj* shape)
654 {
655 layerObj* srclayer;
656 msUnionLayerInfo* layerinfo = (msUnionLayerInfo*)layer->layerinfo;
657
658 if (!layerinfo || !layer->map)
659 return MS_FAILURE;
660
661 if (shape->tileindex < 0 || shape->tileindex >= layerinfo->layerCount) {
662 msSetError(MS_MISCERR, "Invalid tile index: %s", "msUnionLayerGetAutoStyle()", layer->name);
663 return MS_FAILURE;
664 }
665
666 srclayer = &layerinfo->layers[shape->tileindex];
667
668 if(srclayer->styleitem && strcasecmp(srclayer->styleitem, "AUTO") == 0) {
669 int rv;
670 int tileindex = shape->tileindex;
671 shape->tileindex = 0;
672 rv = msLayerGetAutoStyle(map, srclayer, c, shape);
673 shape->tileindex = tileindex;
674 return rv;
675 } else {
676 int i,j;
677 classObj* src = srclayer->class[layerinfo->classIndex];
678 /* copy the style from the current class index */
679 /* free any previous styles on the dst layer */
680
681 resetClassStyle(c);
682
683 for (i = 0; i < src->numstyles; i++) {
684 if (msMaybeAllocateClassStyle(c, i))
685 return MS_FAILURE;
686
687 if (msCopyStyle(c->styles[i], src->styles[i]) != MS_SUCCESS) {
688 msSetError(MS_MEMERR, "Failed to copy style.", "msUnionLayerGetAutoStyle()");
689 return MS_FAILURE;
690 }
691 /* remove the bindings on the style */
692 for(j=0; j<MS_STYLE_BINDING_LENGTH; j++) {
693 msFree(c->styles[i]->bindings[j].item);
694 c->styles[i]->bindings[j].item = NULL;
695 }
696 c->styles[i]->numbindings = 0;
697 }
698
699 for (i = 0; i < src->numlabels; i++) {
700 // RFC77 TODO: allocation need to be done, but is the right way (from mapcopy.c)?
701 if (msGrowClassLabels(c) == NULL)
702 return MS_FAILURE;
703 initLabel(c->labels[i]);
704
705 if (msCopyLabel(c->labels[i], src->labels[i]) != MS_SUCCESS) {
706 msSetError(MS_MEMERR, "Failed to copy label.", "msUnionLayerGetAutoStyle()");
707 return MS_FAILURE;
708 }
709
710 /* remove the bindings on the label */
711 for(j=0; j<MS_LABEL_BINDING_LENGTH; j++) {
712 msFree(c->labels[i]->bindings[j].item);
713 c->labels[i]->bindings[j].item = NULL;
714 }
715 c->labels[i]->numbindings = 0;
716 }
717 c->numlabels = src->numlabels;
718
719 c->layer = layer;
720 c->text.string = layerinfo->classText;
721 layerinfo->classText = NULL;
722 }
723 return MS_SUCCESS;
724 }
725
msUnionLayerCopyVirtualTable(layerVTableObj * vtable)726 int msUnionLayerCopyVirtualTable(layerVTableObj* vtable)
727 {
728 vtable->LayerInitItemInfo = msUnionLayerInitItemInfo;
729 vtable->LayerFreeItemInfo = msUnionLayerFreeItemInfo;
730 vtable->LayerOpen = msUnionLayerOpen;
731 vtable->LayerIsOpen = msUnionLayerIsOpen;
732 vtable->LayerWhichShapes = msUnionLayerWhichShapes;
733 vtable->LayerNextShape = msUnionLayerNextShape;
734 vtable->LayerGetShape = msUnionLayerGetShape;
735 /* layer->vtable->LayerGetShapeCount, use default */
736 vtable->LayerClose = msUnionLayerClose;
737
738 vtable->LayerGetItems = msUnionLayerGetItems;
739 vtable->LayerCloseConnection = msUnionLayerClose;
740 vtable->LayerGetAutoStyle = msUnionLayerGetAutoStyle;
741
742 vtable->LayerGetNumFeatures = msUnionLayerGetNumFeatures;
743
744 return MS_SUCCESS;
745 }
746
msUnionLayerInitializeVirtualTable(layerObj * layer)747 int msUnionLayerInitializeVirtualTable(layerObj *layer)
748 {
749 assert(layer != NULL);
750 assert(layer->vtable != NULL);
751
752 return msUnionLayerCopyVirtualTable(layer->vtable);
753 }
754