Coverage Report

Created: 2025-06-13 06:29

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