~ubuntu-branches/ubuntu/trusty/mapcache/trusty

« back to all changes in this revision

Viewing changes to lib/grid.c

  • Committer: Package Import Robot
  • Author(s): Bas Couwenberg
  • Date: 2013-09-11 19:16:06 UTC
  • Revision ID: package-import@ubuntu.com-20130911191606-9aydo919w4dgjx9v
Tags: upstream-1.2.0
ImportĀ upstreamĀ versionĀ 1.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************************************
 
2
 * $Id$
 
3
 *
 
4
 * Project:  MapServer
 
5
 * Purpose:  MapCache tile caching grid support file
 
6
 * Author:   Thomas Bonfort and the MapServer team.
 
7
 *
 
8
 ******************************************************************************
 
9
 * Copyright (c) 1996-2011 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
#include "mapcache.h"
 
31
#include <math.h>
 
32
#include <apr_strings.h>
 
33
/*
 
34
 * allocate and initialize a new tileset
 
35
 */
 
36
mapcache_grid* mapcache_grid_create(apr_pool_t *pool)
 
37
{
 
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;
 
43
  return grid;
 
44
}
 
45
 
 
46
 
 
47
/**
 
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
 
50
 */
 
51
void mapcache_grid_get_extent(mapcache_context *ctx, mapcache_grid *grid,
 
52
                              int x, int y, int z, mapcache_extent *bbox)
 
53
{
 
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);
 
61
      break;
 
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);
 
67
      break;
 
68
    case MAPCACHE_GRID_ORIGIN_BOTTOM_RIGHT:
 
69
    case MAPCACHE_GRID_ORIGIN_TOP_RIGHT:
 
70
      ctx->set_error(ctx,500,"grid origin not implemented");
 
71
  }
 
72
}
 
73
 
 
74
const char* mapcache_grid_get_crs(mapcache_context *ctx, mapcache_grid *grid)
 
75
{
 
76
  char *epsgnum;
 
77
 
 
78
  /*locate the number after epsg: in the grd srs*/
 
79
  epsgnum = strchr(grid->srs,':');
 
80
  if(!epsgnum) {
 
81
    epsgnum = grid->srs;
 
82
  } else {
 
83
    epsgnum++;
 
84
  }
 
85
 
 
86
  return apr_psprintf(ctx->pool,"urn:ogc:def:crs:EPSG:6.3:%s",epsgnum);
 
87
}
 
88
 
 
89
const char* mapcache_grid_get_srs(mapcache_context *ctx, mapcache_grid *grid)
 
90
{
 
91
  return (const char*)grid->srs;
 
92
}
 
93
 
 
94
void mapcache_grid_compute_limits(const mapcache_grid *grid, const mapcache_extent *extent, mapcache_extent_i *limits, int tolerance)
 
95
{
 
96
  int i;
 
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;
 
102
 
 
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;
 
109
        break;
 
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);
 
117
        break;
 
118
      case MAPCACHE_GRID_ORIGIN_TOP_RIGHT:
 
119
      case MAPCACHE_GRID_ORIGIN_BOTTOM_RIGHT:
 
120
        break; /* not implemented */
 
121
    }
 
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;
 
127
 
 
128
  }
 
129
}
 
130
 
 
131
double mapcache_grid_get_resolution(mapcache_extent *bbox, int sx, int sy)
 
132
{
 
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);
 
136
}
 
137
 
 
138
 
 
139
double mapcache_grid_get_horizontal_resolution(mapcache_extent *bbox, int width)
 
140
{
 
141
  return (bbox->maxx - bbox->minx) / (double)width;
 
142
}
 
143
 
 
144
double mapcache_grid_get_vertical_resolution(mapcache_extent *bbox, int height)
 
145
{
 
146
  return (bbox->maxy - bbox->miny) / (double)height;
 
147
}
 
148
 
 
149
int mapcache_grid_get_level(mapcache_context *ctx, mapcache_grid *grid, double *resolution, int *level)
 
150
{
 
151
  double max_diff = *resolution / (double)MAPCACHE_MAX(grid->tile_sx, grid->tile_sy);
 
152
  int i;
 
153
  for(i=0; i<grid->nlevels; i++) {
 
154
    if(fabs(grid->levels[i]->resolution - *resolution) < max_diff) {
 
155
      *resolution = grid->levels[i]->resolution;
 
156
      *level = i;
 
157
      return MAPCACHE_SUCCESS;
 
158
    }
 
159
  }
 
160
  return MAPCACHE_FAILURE;
 
161
}
 
162
 
 
163
void mapcache_grid_get_closest_level(mapcache_context *ctx, mapcache_grid_link *grid_link, double resolution, int *level)
 
164
{
 
165
  double dst = fabs(grid_link->grid->levels[grid_link->minz]->resolution - resolution);
 
166
  int i;
 
167
  *level = 0;
 
168
 
 
169
  for(i=grid_link->minz + 1; i<grid_link->maxz; i++) {
 
170
    double curdst = fabs(grid_link->grid->levels[i]->resolution - resolution);
 
171
    if( curdst < dst) {
 
172
      dst = curdst;
 
173
      *level = i;
 
174
    }
 
175
  }
 
176
}
 
177
 
 
178
/*
 
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
 
182
 */
 
183
int mapcache_grid_get_cell(mapcache_context *ctx, mapcache_grid *grid, mapcache_extent *bbox,
 
184
                           int *x, int *y, int *z)
 
185
{
 
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;
 
189
 
 
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);
 
194
 
 
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;
 
198
      }
 
199
      break;
 
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);
 
203
 
 
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;
 
207
      }
 
208
      break;
 
209
    case MAPCACHE_GRID_ORIGIN_BOTTOM_RIGHT:
 
210
    case MAPCACHE_GRID_ORIGIN_TOP_RIGHT:
 
211
      return MAPCACHE_FAILURE;
 
212
  }
 
213
  return MAPCACHE_SUCCESS;
 
214
}
 
215
 
 
216
 
 
217
void mapcache_grid_get_xy(mapcache_context *ctx, mapcache_grid *grid, double dx, double dy,
 
218
                          int z, int *x, int *y)
 
219
{
 
220
  double res;
 
221
#ifdef DEBUG
 
222
  if(z>=grid->nlevels) {
 
223
    ctx->set_error(ctx,500,"####BUG##### requesting invalid level");
 
224
    return;
 
225
  }
 
226
#endif
 
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));
 
232
      break;
 
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));
 
236
      break;
 
237
    case MAPCACHE_GRID_ORIGIN_BOTTOM_RIGHT:
 
238
    case MAPCACHE_GRID_ORIGIN_TOP_RIGHT:
 
239
      ctx->set_error(ctx,500,"####BUG##### origin not implemented");
 
240
      return;
 
241
  }
 
242
}
 
243
/* vim: ts=2 sts=2 et sw=2
 
244
*/