1
/******************************************************************************
5
* Purpose: MapCache tile caching grid support file
6
* Author: Thomas Bonfort and the MapServer team.
8
******************************************************************************
9
* Copyright (c) 1996-2011 Regents of the University of Minnesota.
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:
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.
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
*****************************************************************************/
32
#include <apr_strings.h>
34
* allocate and initialize a new tileset
36
mapcache_grid* mapcache_grid_create(apr_pool_t *pool)
38
mapcache_grid* grid = (mapcache_grid*)apr_pcalloc(pool, sizeof(mapcache_grid));
39
grid->metadata = apr_table_make(pool,3);
40
grid->srs_aliases = apr_array_make(pool,0,sizeof(char*));
41
grid->unit = MAPCACHE_UNIT_METERS;
42
grid->origin = MAPCACHE_GRID_ORIGIN_BOTTOM_LEFT;
48
* \brief compute the extent of a given tile in the grid given its x, y, and z.
49
* \returns \extent the tile's extent
51
void mapcache_grid_get_extent(mapcache_context *ctx, mapcache_grid *grid,
52
int x, int y, int z, mapcache_extent *bbox)
54
double res = grid->levels[z]->resolution;
55
switch(grid->origin) {
56
case MAPCACHE_GRID_ORIGIN_BOTTOM_LEFT:
57
bbox->minx = grid->extent.minx + (res * x * grid->tile_sx);
58
bbox->miny = grid->extent.miny + (res * y * grid->tile_sy);
59
bbox->maxx = grid->extent.minx + (res * (x + 1) * grid->tile_sx);
60
bbox->maxy = grid->extent.miny + (res * (y + 1) * grid->tile_sy);
62
case MAPCACHE_GRID_ORIGIN_TOP_LEFT:
63
bbox->minx = grid->extent.minx + (res * x * grid->tile_sx);
64
bbox->miny = grid->extent.maxy - (res * (y+1) * grid->tile_sy);
65
bbox->maxx = grid->extent.minx + (res * (x + 1) * grid->tile_sx);
66
bbox->maxy = grid->extent.maxy - (res * y * grid->tile_sy);
68
case MAPCACHE_GRID_ORIGIN_BOTTOM_RIGHT:
69
case MAPCACHE_GRID_ORIGIN_TOP_RIGHT:
70
ctx->set_error(ctx,500,"grid origin not implemented");
74
const char* mapcache_grid_get_crs(mapcache_context *ctx, mapcache_grid *grid)
78
/*locate the number after epsg: in the grd srs*/
79
epsgnum = strchr(grid->srs,':');
86
return apr_psprintf(ctx->pool,"urn:ogc:def:crs:EPSG:6.3:%s",epsgnum);
89
const char* mapcache_grid_get_srs(mapcache_context *ctx, mapcache_grid *grid)
91
return (const char*)grid->srs;
94
void mapcache_grid_compute_limits(const mapcache_grid *grid, const mapcache_extent *extent, mapcache_extent_i *limits, int tolerance)
97
double epsilon = 0.0000001;
98
for(i=0; i<grid->nlevels; i++) {
99
mapcache_grid_level *level = grid->levels[i];
100
double unitheight = grid->tile_sy * level->resolution;
101
double unitwidth = grid->tile_sx * level->resolution;
103
switch(grid->origin) {
104
case MAPCACHE_GRID_ORIGIN_BOTTOM_LEFT:
105
limits[i].minx = floor((extent->minx - grid->extent.minx) / unitwidth + epsilon) - tolerance;
106
limits[i].maxx = ceil((extent->maxx - grid->extent.minx) / unitwidth - epsilon) + tolerance;
107
limits[i].miny = floor((extent->miny - grid->extent.miny) / unitheight + epsilon) - tolerance;
108
limits[i].maxy = ceil((extent->maxy - grid->extent.miny) / unitheight - epsilon) + tolerance;
110
case MAPCACHE_GRID_ORIGIN_TOP_LEFT:
111
limits[i].minx = floor((extent->minx - grid->extent.minx) / unitwidth + epsilon) - tolerance;
112
limits[i].maxx = ceil((extent->maxx - grid->extent.minx) / unitwidth - epsilon) + tolerance;
113
limits[i].miny = floor((grid->extent.maxy - extent->maxy) / unitheight + epsilon) - tolerance;
114
//limits[i].maxy = level->maxy - floor((extent->miny - grid->extent.miny) / unitheight + epsilon) + tolerance;
115
limits[i].maxy = ceil((grid->extent.maxy - extent->miny) / unitheight - epsilon) + tolerance;
116
//printf("%d: %d %d %d %d\n",i,limits[i].minx,limits[i].miny,limits[i].maxx,limits[i].maxy);
118
case MAPCACHE_GRID_ORIGIN_TOP_RIGHT:
119
case MAPCACHE_GRID_ORIGIN_BOTTOM_RIGHT:
120
break; /* not implemented */
122
// to avoid requesting out-of-range tiles
123
if (limits[i].minx < 0) limits[i].minx = 0;
124
if (limits[i].maxx > level->maxx) limits[i].maxx = level->maxx;
125
if (limits[i].miny < 0) limits[i].miny = 0;
126
if (limits[i].maxy > level->maxy) limits[i].maxy = level->maxy;
131
double mapcache_grid_get_resolution(mapcache_extent *bbox, int sx, int sy)
133
double rx = mapcache_grid_get_horizontal_resolution(bbox,sx);
134
double ry = mapcache_grid_get_vertical_resolution(bbox,sy);
135
return MAPCACHE_MAX(rx,ry);
139
double mapcache_grid_get_horizontal_resolution(mapcache_extent *bbox, int width)
141
return (bbox->maxx - bbox->minx) / (double)width;
144
double mapcache_grid_get_vertical_resolution(mapcache_extent *bbox, int height)
146
return (bbox->maxy - bbox->miny) / (double)height;
149
int mapcache_grid_get_level(mapcache_context *ctx, mapcache_grid *grid, double *resolution, int *level)
151
double max_diff = *resolution / (double)MAPCACHE_MAX(grid->tile_sx, grid->tile_sy);
153
for(i=0; i<grid->nlevels; i++) {
154
if(fabs(grid->levels[i]->resolution - *resolution) < max_diff) {
155
*resolution = grid->levels[i]->resolution;
157
return MAPCACHE_SUCCESS;
160
return MAPCACHE_FAILURE;
163
void mapcache_grid_get_closest_level(mapcache_context *ctx, mapcache_grid_link *grid_link, double resolution, int *level)
165
double dst = fabs(grid_link->grid->levels[grid_link->minz]->resolution - resolution);
169
for(i=grid_link->minz + 1; i<grid_link->maxz; i++) {
170
double curdst = fabs(grid_link->grid->levels[i]->resolution - resolution);
179
* update the tile by setting it's x,y,z value given a bbox.
180
* will return MAPCACHE_TILESET_WRONG_RESOLUTION or MAPCACHE_TILESET_WRONG_EXTENT
181
* if the bbox does not correspond to the tileset's configuration
183
int mapcache_grid_get_cell(mapcache_context *ctx, mapcache_grid *grid, mapcache_extent *bbox,
184
int *x, int *y, int *z)
186
double res = mapcache_grid_get_resolution(bbox,grid->tile_sx,grid->tile_sy);
187
if(MAPCACHE_SUCCESS != mapcache_grid_get_level(ctx, grid, &res, z))
188
return MAPCACHE_FAILURE;
190
switch(grid->origin) {
191
case MAPCACHE_GRID_ORIGIN_BOTTOM_LEFT:
192
*x = (int)(((bbox->minx - grid->extent.minx) / (res * grid->tile_sx)) + 0.5);
193
*y = (int)(((bbox->miny - grid->extent.miny) / (res * grid->tile_sy)) + 0.5);
195
if((fabs(bbox->minx - (*x * res * grid->tile_sx) - grid->extent.minx ) / res > 1) ||
196
(fabs(bbox->miny - (*y * res * grid->tile_sy) - grid->extent.miny ) / res > 1)) {
197
return MAPCACHE_FAILURE;
200
case MAPCACHE_GRID_ORIGIN_TOP_LEFT:
201
*x = (int)(((bbox->minx - grid->extent.minx) / (res * grid->tile_sx)) + 0.5);
202
*y = (int)(((grid->extent.maxy - bbox->maxy) / (res * grid->tile_sy)) + 0.5);
204
if((fabs(bbox->minx - (*x * res * grid->tile_sx) - grid->extent.minx ) / res > 1) ||
205
(fabs(bbox->maxy - (grid->extent.maxy - (*y * res * grid->tile_sy)) ) / res > 1)) {
206
return MAPCACHE_FAILURE;
209
case MAPCACHE_GRID_ORIGIN_BOTTOM_RIGHT:
210
case MAPCACHE_GRID_ORIGIN_TOP_RIGHT:
211
return MAPCACHE_FAILURE;
213
return MAPCACHE_SUCCESS;
217
void mapcache_grid_get_xy(mapcache_context *ctx, mapcache_grid *grid, double dx, double dy,
218
int z, int *x, int *y)
222
if(z>=grid->nlevels) {
223
ctx->set_error(ctx,500,"####BUG##### requesting invalid level");
227
res = grid->levels[z]->resolution;
228
switch(grid->origin) {
229
case MAPCACHE_GRID_ORIGIN_BOTTOM_LEFT:
230
*x = (int)((dx - grid->extent.minx) / (res * grid->tile_sx));
231
*y = (int)((dy - grid->extent.miny) / (res * grid->tile_sy));
233
case MAPCACHE_GRID_ORIGIN_TOP_LEFT:
234
*x = (int)((dx - grid->extent.minx) / (res * grid->tile_sx));
235
*y = (int)((grid->extent.maxy - dy) / (res * grid->tile_sy));
237
case MAPCACHE_GRID_ORIGIN_BOTTOM_RIGHT:
238
case MAPCACHE_GRID_ORIGIN_TOP_RIGHT:
239
ctx->set_error(ctx,500,"####BUG##### origin not implemented");
243
/* vim: ts=2 sts=2 et sw=2