diff --git a/mapwms.cpp b/mapwms.cpp index b7a84d8ec8..95e03dd678 100644 --- a/mapwms.cpp +++ b/mapwms.cpp @@ -867,6 +867,7 @@ int msWMSLoadGetMapParams(mapObj *map, int nVersion, const char *request = NULL; int status = 0; const char *layerlimit = NULL; + bool tiled = false; const char *sldenabled=NULL; const char *sld_url=NULL; @@ -1172,6 +1173,10 @@ int msWMSLoadGetMapParams(mapObj *map, int nVersion, else if (strcasecmp(names[i], "BBOX_PIXEL_IS_POINT") == 0) { bbox_pixel_is_point = (strcasecmp(values[i], "TRUE") == 0); } + /* Vendor specific TILED (WMS-C) */ + else if (strcasecmp(names[i], "TILED") == 0) { + tiled = (strcasecmp(values[i], "TRUE") == 0); + } /* Vendor-specific FILTER, added in RFC-118 */ else if (strcasecmp(names[i], "FILTER") == 0) { filter = values[i]; @@ -1239,6 +1244,50 @@ int msWMSLoadGetMapParams(mapObj *map, int nVersion, adjust_extent = true; } + if (tiled) { + const char *value; + hashTableObj *meta = &(map->web.metadata); + int map_edge_buffer = 0; + + if ((value = msLookupHashTable(meta, "tile_map_edge_buffer")) != NULL) { + map_edge_buffer = atoi(value); + } + if (map_edge_buffer > 0) { + /* adjust bbox and width and height to the buffer */ + const double buffer_x = map_edge_buffer * (map->extent.maxx - map->extent.minx) / (double)map->width; + const double buffer_y = map_edge_buffer * (map->extent.maxy - map->extent.miny) / (double)map->height; + + // TODO: we should probably clamp the extent to avoid going outside of -180,-90,180,90 for geographic CRS for example + map->extent.minx -= buffer_x; + map->extent.maxx += buffer_x; + map->extent.miny -= buffer_y; + map->extent.maxy += buffer_y; + + map->width += 2 * map_edge_buffer; + map->height += 2 * map_edge_buffer; + + if( map_edge_buffer > 0 ) { + char tilebufferstr[64]; + + /* Write the tile buffer to a string */ + snprintf(tilebufferstr, sizeof(tilebufferstr), "-%d", map_edge_buffer); + + /* Hm, the labelcache buffer is set... */ + if((value = msLookupHashTable(meta, "labelcache_map_edge_buffer")) != NULL) { + /* If it's too small, replace with a bigger one */ + if( map_edge_buffer > abs(atoi(value)) ) { + msRemoveHashTable(meta, "labelcache_map_edge_buffer"); + msInsertHashTable(meta, "labelcache_map_edge_buffer", tilebufferstr); + } + } + /* No labelcache buffer value? Then we use the tile buffer. */ + else { + msInsertHashTable(meta, "labelcache_map_edge_buffer", tilebufferstr); + } + } + } + } + /* ** If any select layers have a default time, we will apply the default ** time value even if no TIME request was in the url. @@ -3718,6 +3767,46 @@ int msWMSGetMap(mapObj *map, int nVersion, char **names, char **values, int nume img = msDrawMap(map, drawquerymap); } +/* see if we have tiled = true and a buffer */ + /* if so, clip the image */ + for (int i=0; iweb.metadata); + const char *value; + + if ((value = msLookupHashTable(meta, "tile_map_edge_buffer")) != NULL) { + const int map_edge_buffer = atoi(value); + if ( map_edge_buffer > 0 ) { + /* we have to clip the image */ + + // TODO: we could probably avoid the use of an intermediate image + // by playing with the rasterBufferObj's data->rgb.pixels and data->rgb.row_stride values. + rendererVTableObj* renderer = MS_MAP_RENDERER(map); + rasterBufferObj imgBuffer; + if( renderer->getRasterBufferHandle((imageObj*)img,&imgBuffer) != MS_SUCCESS ) + { + msFreeImage(img); + return MS_FAILURE; + } + + int width = map->width - map_edge_buffer - map_edge_buffer; + int height = map->height - map_edge_buffer - map_edge_buffer; + imageObj* tmp = msImageCreate( width, height, map->outputformat, NULL, NULL, map->resolution, map->defresolution, NULL); + + if((MS_FAILURE == renderer->mergeRasterBuffer(tmp,&imgBuffer,1.0,map_edge_buffer, map_edge_buffer,0, 0, width, height ))) { + msFreeImage(tmp); + msFreeImage(img); + img = NULL; + } else { + msFreeImage(img); + img = tmp; + } + } + } + break; + } + } + if (img == NULL) return msWMSException(map, nVersion, NULL, wms_exception_format); diff --git a/msautotest/wxs/expected/wms_tiled_tiled_disabled.png b/msautotest/wxs/expected/wms_tiled_tiled_disabled.png new file mode 100644 index 0000000000..18005ce3f0 Binary files /dev/null and b/msautotest/wxs/expected/wms_tiled_tiled_disabled.png differ diff --git a/msautotest/wxs/expected/wms_tiled_tiled_enabled.png b/msautotest/wxs/expected/wms_tiled_tiled_enabled.png new file mode 100644 index 0000000000..ae3e2f6066 Binary files /dev/null and b/msautotest/wxs/expected/wms_tiled_tiled_enabled.png differ diff --git a/msautotest/wxs/wms_tiled.map b/msautotest/wxs/wms_tiled.map new file mode 100644 index 0000000000..379449f87a --- /dev/null +++ b/msautotest/wxs/wms_tiled.map @@ -0,0 +1,80 @@ +# +# Test WMS-C TILED=TRUE +# +# REQUIRES: INPUT=GDAL OUTPUT=PNG SUPPORTS=WMS + +# RUN_PARMS: wms_tiled_tiled_disabled.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=44.1,-65.755,47.3,-58.375&WIDTH=400&HEIGHT=400&LAYERS=popplace&STYLES=&FORMAT=image%2Fpng" > [RESULT_DEMIME] + +# RUN_PARMS: wms_tiled_tiled_enabled.png [MAPSERV] QUERY_STRING="map=[MAPFILE]&VERSION=1.3.0&REQUEST=GetMap&CRS=EPSG%3A4326&BBOX=44.1,-65.755,47.3,-58.375&WIDTH=400&HEIGHT=400&LAYERS=popplace&STYLES=&FORMAT=image%2Fpng&TILED=TRUE" > [RESULT_DEMIME] + +MAP + +NAME WMS_TILED +STATUS ON +SIZE 400 300 +UNITS DD +IMAGECOLOR 255 255 255 +SHAPEPATH ./data +SYMBOLSET etc/symbols.sym +FONTSET etc/fonts.txt + +OUTPUTFORMAT + NAME GDPNG + DRIVER "GD/PNG" + MIMETYPE "image/png" + EXTENSION "png" +END + + +# +# Start of web interface definition +# +WEB + + IMAGEPATH "/tmp/ms_tmp/" + IMAGEURL "/ms_tmp/" + + METADATA + "wms_title" "Test simple wms" + "wms_onlineresource" "http://localhost/path/to/wms_simple?" + "wms_srs" "EPSG:42304 EPSG:42101 EPSG:4269 EPSG:4326" + "ows_schemas_location" "http://ogc.dmsolutions.ca" + "wms_sld_enabled" "false" + "ows_enable_request" "*" + "tile_map_edge_buffer" "50" + END +END + +PROJECTION + "init=epsg:4326" +END + + +# +# Start of layer definitions +# + + +LAYER + NAME popplace + DATA popplace + METADATA + "wms_title" "popplace" + "wms_description" "Cities of I.P.E." + END + TYPE POINT + STATUS ON + PROJECTION + "init=./data/epsg2:42304" + END + DUMP TRUE + CLASS + SYMBOL 2 + SIZE 40 + NAME "Cities" + COLOR 0 0 0 + END +END # Layer + + +END # Map File