~ubuntu-branches/ubuntu/saucy/mapserver/saucy-security

« back to all changes in this revision

Viewing changes to maptile.c

  • Committer: Package Import Robot
  • Author(s): Francesco Paolo Lovergine
  • Date: 2011-12-23 14:02:06 UTC
  • mfrom: (26.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20111223140206-n3h9t2hsa8hyslmu
Tags: 6.0.1-2
Added missed stuff for libmapscript-perl.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/******************************************************************************
2
 
 * $Id$ 
 
2
 * $Id: maptile.c 11503 2011-04-07 19:56:16Z dmorissette $ 
3
3
 *
4
4
 * Project:  MapServer
5
5
 * Purpose:  MapServer Tile Access API
30
30
#include "maptile.h"
31
31
#include "mapproject.h"
32
32
 
 
33
static void msTileResetMetatileLevel(mapObj *map) {
 
34
  hashTableObj *meta = &(map->web.metadata); 
 
35
  const char *zero = "0";
 
36
  const char *value = NULL;
 
37
 
 
38
  /*  Is the tile_metatile_levetl set... */
 
39
  if((value = msLookupHashTable(meta, "tile_metatile_level")) != NULL) {
 
40
    msRemoveHashTable(meta, "tile_metatile_level");
 
41
    msInsertHashTable(meta, "tile_metatile_level", zero);
 
42
  }
 
43
  /* No tile_metatile_level value. */
 
44
  else {
 
45
    msInsertHashTable(meta, "tile_metatile_level", zero);
 
46
  }
 
47
}
 
48
 
 
49
/************************************************************************
 
50
 *                            msTileGetGMapCoords                       *
 
51
 ************************************************************************/
 
52
static int msTileGetGMapCoords(const char *coordstring, int *x, int *y, int *zoom) {
 
53
 
 
54
  int num_coords = 0;
 
55
  char **coords = NULL;
 
56
  
 
57
  if( coordstring ) {
 
58
    coords = msStringSplit(coordstring, ' ', &(num_coords));
 
59
    if( num_coords != 3 ) {
 
60
      msSetError(MS_WEBERR, "Invalid number of tile coordinates (should be three).", "msTileSetup()");
 
61
      return MS_FAILURE;
 
62
    }
 
63
  } 
 
64
  else {
 
65
    msSetError(MS_WEBERR, "Tile parameter not set.", "msTileSetup()");
 
66
    return MS_FAILURE;
 
67
  }
 
68
  
 
69
  if( x )
 
70
    *x = strtol(coords[0], NULL, 10);
 
71
  if( y )
 
72
    *y = strtol(coords[1], NULL, 10);
 
73
  if( zoom )
 
74
    *zoom = strtol(coords[2], NULL, 10);
 
75
 
 
76
  return MS_SUCCESS;
 
77
}
 
78
 
 
79
 
 
80
/************************************************************************
 
81
 *                            msTileSetParams                           *
 
82
 ************************************************************************/
 
83
static void msTileGetParams(mapObj *map, tileParams *params) {
 
84
 
 
85
  const char *value = NULL;
 
86
  hashTableObj *meta = &(map->web.metadata); 
 
87
  
 
88
  params->tile_size = SPHEREMERC_IMAGE_SIZE;
 
89
  
 
90
  /* Check for tile buffer, set to buffer==0 as default */
 
91
  if((value = msLookupHashTable(meta, "tile_map_edge_buffer")) != NULL) {
 
92
    params->map_edge_buffer = atoi(value);
 
93
    if(map->debug)
 
94
      msDebug("msTileSetParams(): tile_map_edge_buffer = %d\n", params->map_edge_buffer);
 
95
  }  
 
96
  else
 
97
    params->map_edge_buffer = 0;    
 
98
 
 
99
  /* Check for metatile size, set to tile==metatile as default */
 
100
  if((value = msLookupHashTable(meta, "tile_metatile_level")) != NULL) {
 
101
    params->metatile_level = atoi(value);
 
102
    /* Quietly force metatile_level to be sane */
 
103
    if( params->metatile_level < 0 ) 
 
104
      params->metatile_level = 0;
 
105
    if( params->metatile_level > 2 ) 
 
106
      params->metatile_level = 2;
 
107
    if(map->debug)
 
108
      msDebug("msTileSetParams(): tile_metatile_level = %d\n", params->metatile_level);
 
109
  }  
 
110
  else
 
111
    params->metatile_level = 0;
 
112
  
 
113
}
 
114
 
 
115
/************************************************************************
 
116
 *                            msTileExtractSubTile                      *
 
117
 *                                                                      * 
 
118
 ************************************************************************/
 
119
static imageObj* msTileExtractSubTile(const mapservObj *msObj, const imageObj *img) {
 
120
 
 
121
  int width, height, mini, minj, maxi, maxj;
 
122
  int zoom = 2;
 
123
  imageObj* imgOut = NULL;
 
124
  tileParams params;
 
125
  rendererVTableObj *renderer;
 
126
  rasterBufferObj imgBuffer;
 
127
  
 
128
  if( !MS_RENDERER_PLUGIN(msObj->map->outputformat) 
 
129
                  || msObj->map->outputformat->renderer != img->format->renderer ||
 
130
                  ! MS_MAP_RENDERER(msObj->map)->supports_pixel_buffer ) {
 
131
          msSetError(MS_MISCERR,"unsupported or mixed renderers","msTileExtractSubTile()");
 
132
          return NULL;
 
133
  }
 
134
  renderer = MS_MAP_RENDERER(msObj->map);
 
135
  
 
136
  if (renderer->getRasterBufferHandle((imageObj*)img,&imgBuffer) != MS_SUCCESS) {
 
137
          return NULL;
 
138
  }
 
139
  
 
140
 
 
141
  /*
 
142
  ** Load the metatiling information from the map file.
 
143
  */
 
144
  msTileGetParams(msObj->map, &params);
 
145
 
 
146
  /*
 
147
  ** Initialize values for the metatile clip area.
 
148
  */
 
149
  width = img->width - 2*params.map_edge_buffer;
 
150
  height = img->height - 2*params.map_edge_buffer;
 
151
  mini = params.map_edge_buffer;
 
152
  minj = params.map_edge_buffer;
 
153
  maxi = img->width - params.map_edge_buffer - 1;
 
154
  maxj = img->height - params.map_edge_buffer - 1;
 
155
 
 
156
  if( msObj->TileMode == TILE_GMAP ) {
 
157
    int x, y, zoom;
 
158
    
 
159
    if( msObj->TileCoords ) {
 
160
      if( msTileGetGMapCoords(msObj->TileCoords, &x, &y, &zoom) == MS_FAILURE )
 
161
        return NULL;
 
162
    } 
 
163
    else {
 
164
      msSetError(MS_WEBERR, "Tile parameter not set.", "msTileSetup()");
 
165
      return NULL;
 
166
    }    
 
167
 
 
168
    if(msObj->map->debug)
 
169
      msDebug("msTileExtractSubTile(): gmaps coords (x: %d, y: %d)\n",x,y);
 
170
 
 
171
    /*
 
172
    ** The bottom N bits of the coordinates give us the subtile
 
173
    ** location relative to the metatile.
 
174
    */
 
175
    x = (0xffff ^ (0xffff << params.metatile_level)) & x;
 
176
    y = (0xffff ^ (0xffff << params.metatile_level)) & y;
 
177
 
 
178
    if(msObj->map->debug)
 
179
      msDebug("msTileExtractSubTile(): gmaps image coords (x: %d, y: %d)\n",x,y);
 
180
    
 
181
    mini = mini + x * params.tile_size;
 
182
    minj = minj + y * params.tile_size;
 
183
 
 
184
  }
 
185
  else if( msObj->TileMode == TILE_VE ) {
 
186
    int tsize;
 
187
    int i = 0;
 
188
    char j = 0;
 
189
  
 
190
    if( strlen( msObj->TileCoords ) - params.metatile_level < 0 ) {
 
191
      return(NULL);
 
192
    }
 
193
  
 
194
    /* 
 
195
    ** Process the last elements of the VE coordinate string to place the
 
196
    ** requested tile in the context of the metatile
 
197
    */
 
198
    for( i = strlen( msObj->TileCoords ) - params.metatile_level; 
 
199
         i < strlen( msObj->TileCoords ); 
 
200
         i++ ) 
 
201
    {
 
202
      j = msObj->TileCoords[i];
 
203
      tsize = width / zoom;
 
204
      if( j == '1' || j == '3' ) mini += tsize;
 
205
      if( j == '2' || j == '3' ) minj += tsize;
 
206
      zoom *= 2;
 
207
    }
 
208
  }
 
209
  else {
 
210
    return(NULL); /* Huh? Should have a mode. */
 
211
  }
 
212
  
 
213
  imgOut = msImageCreate(params.tile_size, params.tile_size, msObj->map->outputformat, NULL, NULL, msObj->map->resolution, msObj->map->defresolution, NULL);
 
214
  
 
215
  if( imgOut == NULL ) {
 
216
    return NULL;
 
217
  }
 
218
  
 
219
  if(msObj->map->debug)
 
220
    msDebug("msTileExtractSubTile(): extracting (%d x %d) tile, top corner (%d, %d)\n",params.tile_size,params.tile_size,mini,minj);
 
221
  
 
222
  
 
223
  
 
224
  renderer->mergeRasterBuffer(imgOut,&imgBuffer,1.0,mini, minj,0, 0,params.tile_size, params.tile_size);
 
225
 
 
226
  return imgOut;
 
227
}
 
228
 
 
229
 
33
230
/************************************************************************
34
231
 *                            msTileSetup                               *
35
232
 *                                                                      * 
40
237
#ifdef USE_TILE_API 
41
238
 
42
239
  char *outProjStr = NULL;
 
240
  tileParams params;
 
241
  
 
242
  /*
 
243
  ** Load the metatiling information from the map file.
 
244
  */
 
245
  msTileGetParams(msObj->map, &params);
43
246
 
44
247
  /* 
45
248
  ** Ensure all the LAYERs have a projection. 
54
257
  if( msObj->TileMode == TILE_GMAP || msObj->TileMode == TILE_VE ) {
55
258
    outProjStr = SPHEREMERC_PROJ4;
56
259
  } else {
57
 
    return(MS_FAILURE); /* Huh? No mode? */
 
260
    return MS_FAILURE; /* Huh? No mode? */
58
261
  }
59
262
  if( msLoadProjectionString(&(msObj->map->projection), outProjStr) != 0 ) {
60
263
    msSetError(MS_CGIERR, "Unable to load projection string.", "msTileSetup()");
61
 
    return(MS_FAILURE);
 
264
    return MS_FAILURE;
62
265
  }
63
266
  
64
267
  /*
66
269
  */
67
270
  if( msObj->TileMode == TILE_GMAP ) {
68
271
 
69
 
    int num_coords = 0;
70
 
    char **coords = NULL;
71
272
    int x, y, zoom;
72
273
    double zoomfactor;
73
274
    
74
275
    if( msObj->TileCoords ) {
75
 
      coords = msStringSplit(msObj->TileCoords, ' ', &(num_coords));
76
 
      if( num_coords != 3 ) {
77
 
        msSetError(MS_WEBERR, "Invalid number of tile coordinates (should be three).", "msTileSetup()");
78
 
        return(MS_FAILURE);
79
 
      }
 
276
      if( msTileGetGMapCoords(msObj->TileCoords, &x, &y, &zoom) == MS_FAILURE )
 
277
        return MS_FAILURE;
80
278
    } 
81
279
    else {
82
280
      msSetError(MS_WEBERR, "Tile parameter not set.", "msTileSetup()");
83
 
      return(MS_FAILURE);
84
 
    }
85
 
    
86
 
    x = strtol(coords[0], NULL, 10);
87
 
    y = strtol(coords[1], NULL, 10);
88
 
    zoom = strtol(coords[2], NULL, 10);
89
 
 
 
281
      return MS_FAILURE;
 
282
    }
 
283
    
 
284
    if( params.metatile_level >= zoom ) {
 
285
      msTileResetMetatileLevel(msObj->map);
 
286
    }
 
287
    
90
288
    zoomfactor = pow(2.0, (double)zoom);
91
289
    
92
290
    /*
109
307
      return(MS_FAILURE);
110
308
    }
111
309
 
 
310
    if( params.metatile_level >= strlen(msObj->TileCoords) ) {
 
311
      msTileResetMetatileLevel(msObj->map);
 
312
    }
 
313
 
112
314
  }
113
315
  else {
114
316
    return(MS_FAILURE); /* Huh? Should have a mode. */
121
323
#endif
122
324
}
123
325
 
 
326
 
 
327
 
124
328
/************************************************************************
125
329
 *                            msTileSetExtent                           *
126
330
 *                                                                      * 
131
335
#ifdef USE_TILE_API 
132
336
  
133
337
  mapObj *map = msObj->map;
134
 
  double        dx, dy;
 
338
  double        dx, dy, buffer;
 
339
  tileParams params;
 
340
  
 
341
  /* Read the tile-mode map file parameters */
 
342
  msTileGetParams(msObj->map, &params);
135
343
 
136
344
  if( msObj->TileMode == TILE_GMAP ) {
137
 
 
138
 
    int num_coords = 0;
139
 
    char **coords = NULL;
140
345
    int x, y, zoom;
141
346
    double zoomfactor, tilesize, xmin, xmax, ymin, ymax;
142
347
    
143
348
    if( msObj->TileCoords ) {
144
 
      coords = msStringSplit(msObj->TileCoords, ' ', &(num_coords));
145
 
      if( num_coords != 3 ) {
146
 
        msSetError(MS_WEBERR, "Invalid number of tile coordinates (should be three).", "msTileSetExtent()");
147
 
        return(MS_FAILURE);
148
 
      }
 
349
      if( msTileGetGMapCoords(msObj->TileCoords, &x, &y, &zoom) == MS_FAILURE )
 
350
        return MS_FAILURE;
149
351
    } 
150
352
    else {
151
353
      msSetError(MS_WEBERR, "Tile parameter not set.", "msTileSetup()");
152
 
      return(MS_FAILURE);
 
354
      return MS_FAILURE;
153
355
    }    
154
356
 
155
 
    x = strtol(coords[0], NULL, 10);
156
 
    y = strtol(coords[1], NULL, 10);
157
 
    zoom = strtol(coords[2], NULL, 10);
 
357
    if(map->debug)
 
358
      msDebug("msTileSetExtent(): gmaps coords (x: %d, y: %d, z: %d)\n",x,y,zoom);
 
359
 
 
360
    /*
 
361
    ** If we are metatiling, adjust the zoom level appropriately,
 
362
    ** then scale back the x/y coordinates to match the new level.
 
363
    */
 
364
    if( params.metatile_level > 0 ) {
 
365
      zoom = zoom - params.metatile_level;
 
366
      x = x >> params.metatile_level;
 
367
      y = y >> params.metatile_level;
 
368
    }
 
369
 
 
370
    if(map->debug)
 
371
      msDebug("msTileSetExtent(): gmaps metacoords (x: %d, y: %d, z: %d)\n",x,y,zoom);
158
372
 
159
373
    zoomfactor = pow(2.0, (double)zoom);
160
374
    
161
375
    /*
162
 
     * Calculate the ground extents of the tile request.
163
 
     */
 
376
    ** Calculate the ground extents of the tile request.
 
377
    */
164
378
    /* printf("X: %i  Y: %i  Z: %i\n",x,y,zoom); */
165
379
    tilesize = SPHEREMERC_GROUND_SIZE / zoomfactor;
166
380
    xmin = (x * tilesize) - (SPHEREMERC_GROUND_SIZE / 2.0);
185
399
    int i = 0;
186
400
    char j = 0;
187
401
    
188
 
    for( i = 0; i < strlen( msObj->TileCoords ); i++ ) {
 
402
    /* 
 
403
    ** Walk down the VE URL string, adjusting the extent each time.
 
404
    ** For meta-tiling cases, we stop early, to draw a larger image.
 
405
    */
 
406
    for( i = 0; i < strlen( msObj->TileCoords ) - params.metatile_level; i++ ) {
189
407
      j = msObj->TileCoords[i];
190
408
      tsize = SPHEREMERC_GROUND_SIZE / zoom;
191
409
      if( j == '1' || j == '3' ) minx += tsize;
204
422
  else {
205
423
    return(MS_FAILURE); /* Huh? Should have a mode. */
206
424
  }
 
425
 
 
426
  /* 
 
427
  ** Set the output tile size.
 
428
  */
 
429
  msObj->ImgCols = SPHEREMERC_IMAGE_SIZE << params.metatile_level;
 
430
  msObj->ImgRows = SPHEREMERC_IMAGE_SIZE << params.metatile_level;
 
431
  map->width = SPHEREMERC_IMAGE_SIZE << params.metatile_level;
 
432
  map->height = SPHEREMERC_IMAGE_SIZE << params.metatile_level;
 
433
 
 
434
  if(map->debug)
 
435
    msDebug("msTileSetExtent(): base image size (%d x %d)\n",map->width,map->height);
 
436
 
 
437
  /*
 
438
  ** Add the gutters
 
439
  ** First calculate ground units in the buffer at current extent 
 
440
  */
 
441
  buffer = params.map_edge_buffer * (map->extent.maxx - map->extent.minx) / (double)map->width;
 
442
  /* 
 
443
  ** Then adjust the map extents out by that amount 
 
444
  */
 
445
  map->extent.minx -= buffer;
 
446
  map->extent.maxx += buffer;
 
447
  map->extent.miny -= buffer;
 
448
  map->extent.maxy += buffer;
 
449
  /* 
 
450
  ** Finally adjust the map image size by the pixel buffer 
 
451
  */
 
452
  map->width += 2 * params.map_edge_buffer;
 
453
  map->height += 2 * params.map_edge_buffer;
 
454
  msObj->ImgCols += 2 * params.map_edge_buffer;
 
455
  msObj->ImgRows += 2 * params.map_edge_buffer;
 
456
 
 
457
  if(map->debug)
 
458
    msDebug("msTileSetExtent(): buffered image size (%d x %d)\n",map->width,map->height);
207
459
  
208
460
  /* 
209
461
  ** Adjust the extents inwards by 1/2 pixel so they are from
216
468
  dy = (map->extent.maxy - map->extent.miny) / map->height;
217
469
  map->extent.miny += dy*0.5;
218
470
  map->extent.maxy -= dy*0.5;
219
 
  
 
471
 
220
472
  /* 
221
 
  ** Set the output tile size.
 
473
  ** Ensure the labelcache buffer is greater than the tile buffer. 
222
474
  */
223
 
  msObj->ImgCols = SPHEREMERC_IMAGE_SIZE;
224
 
  msObj->ImgRows = SPHEREMERC_IMAGE_SIZE;
225
 
  map->width = SPHEREMERC_IMAGE_SIZE;
226
 
  map->height = SPHEREMERC_IMAGE_SIZE;
227
 
 
 
475
  if( params.map_edge_buffer > 0 ) {
 
476
    const char *value;
 
477
    hashTableObj *meta = &(map->web.metadata); 
 
478
    char tilebufferstr[64];
 
479
 
 
480
    /* Write the tile buffer to a string */
 
481
    snprintf(tilebufferstr, sizeof(tilebufferstr), "-%d", params.map_edge_buffer);
 
482
 
 
483
    /* Hm, the labelcache buffer is set... */
 
484
    if((value = msLookupHashTable(meta, "labelcache_map_edge_buffer")) != NULL) {
 
485
      /* If it's too small, replace with a bigger one */
 
486
      if( params.map_edge_buffer > abs(atoi(value)) ) {
 
487
        msRemoveHashTable(meta, "labelcache_map_edge_buffer");
 
488
        msInsertHashTable(meta, "labelcache_map_edge_buffer", tilebufferstr);
 
489
      }
 
490
    }
 
491
    /* No labelcache buffer value? Then we use the tile buffer. */
 
492
    else {
 
493
      msInsertHashTable(meta, "labelcache_map_edge_buffer", tilebufferstr);
 
494
    }
 
495
  }
 
496
  
228
497
  if(map->debug) {
229
498
    msDebug( "msTileSetExtent (%f, %f) (%f, %f)\n", map->extent.minx, map->extent.miny, map->extent.maxx, map->extent.maxy);
230
499
  }
280
549
  return(MS_SUCCESS);
281
550
}
282
551
 
 
552
/************************************************************************
 
553
 *                            msDrawTile                                *
 
554
 *                                                                      * 
 
555
 *   Draw the tile once with gutters, metatiling and buffers, then      *
 
556
 *   clip out the final tile.                                           *
 
557
 *   WARNING: Call msTileSetExtent() first or this will be a pointless  *
 
558
 *   fucnction call.                                                    *
 
559
 ************************************************************************/
 
560
 
 
561
imageObj* msTileDraw(mapservObj *msObj)
 
562
{
 
563
  imageObj *img;
 
564
  tileParams params;
 
565
  msTileGetParams(msObj->map, &params);
 
566
  img = msDrawMap(msObj->map, MS_FALSE);
 
567
  if( img == NULL )
 
568
    return NULL;
 
569
  if( params.metatile_level > 0 || params.map_edge_buffer > 0 )
 
570
  {
 
571
    imageObj *tmp = msTileExtractSubTile(msObj, img);
 
572
    msFreeImage(img);
 
573
    if( tmp == NULL )
 
574
      return NULL;
 
575
    img = tmp;
 
576
  }
 
577
  return img;
 
578
}
283
579