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