Search code examples
gisopenlayers-3geoserverwms

Openlayers3: tile grid incorrect with pixelratio=3 using Geoserver/Geowebcache as backend


I'm developing a small webmap using Openlayers3 and geoserver/geowebcache as backend.

My goal is to support browsers/displays with pixelratio=1, pixelratio=2 and pixelratio=3.

For that I defined in geoserver backend 3 gridsets with tiles sizes 256x256, 512x512 and 768x768. I assume that:

  • pixelratio=1 requires a gridset with tiles sizes 256x256
  • pixelratio=2 requires a gridset with tiles sizes 512x512
  • pixelratio=3 requires a gridset with tiles sizes 768x768

Now, my code is working only for pixelratio=1 and pixelratio=2. But if pixelratio=3 geowebcache returns a error:

geowebcache-cache-result:MISS
geowebcache-miss-reason:request does not align to grid(s) 'grid_512' 'grid_768' 'grid_256'

If pixelratio=3 Openlayers generates such a URL:

http://localhost:8082/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image%2Fpng&TRANSPARENT=false&layers=mfn_mwb17%3Amfn_mwb17_0_basemap&TILED=true&WIDTH=768&HEIGHT=768&SRS=EPSG%3A32632&STYLES=&FORMAT_OPTIONS=dpi%3A270&BBOX=536964.8438079988%2C5280880.182948656%2C537609.9638079988%2C5281525.3029486565

Openalayers changes the tiles sizes to 768x768 and DPI to 270 but apparently does not calculate correctly the grid.

The demo map in Geoserver (based on Openlayers2) works with all 3 grid sets.

I'm using geoserver 2.10 and google chrome. This is my code so far. Resolutions and bounds are the same for all 3 grid sets in backend. Any help is appreciated:

<html>
<head>
    <title>WMS Tiles</title>
    <link rel="stylesheet" href="https://openlayers.org/en/v3.19.1/css/ol.css" type="text/css">
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
    <script src="https://openlayers.org/en/v3.19.1/build/ol.js"></script>
</head>
<body>
<div id="map" class="map"></div>
<script>
    console.log("DOMContentLoaded");
    try {
        var config = {
            "bounds": {
                "left": 536319.7238079988,
                "bottom": 5278944.822948656,
                "right": 540150.3790103362,
                "top": 5282223.663765706
            }
        };

        var bounds = [config.bounds.left, config.bounds.bottom, config.bounds.right, config.bounds.top];
        var resolutions = [2.5199999999999996,
            1.2599999999999998,
            0.6299999999999999,
            0.31499999999999995,
            0.15749999999999997,
            0.07874999999999999,
            0.03937499999999999
        ];

        var projection = new ol.proj.Projection({
            code: 'EPSG:32632'
        });

        var params = {
            'VERSION': '1.1.1',
            'layers': "mfn_mwb17:mfn_mwb17_0_basemap",
            'TILED': true,
            'TRANSPARENT': false
        };

        var tileGrid = new ol.tilegrid.TileGrid({
            extent: bounds,
            resolutions: resolutions,
            origin: [config.bounds.left, config.bounds.bottom],
            tileSize: [256, 256]
        });
        var view = new ol.View({
            zoom: 0,
            center: ol.extent.getCenter(bounds),
            projection: projection,
            resolutions: resolutions
        });

        var map = new ol.Map({
            controls: ol.control.defaults(
                {
                    rotate: false,
                    attributionOptions: {
                        collapsible: false
                    }
                }
            ),
            view: view,
            layers: [
                new ol.layer.Tile({
                    source: new ol.source.TileWMS({
                        url: "http://localhost:8082/wms",
                        params: params,
                        tileGrid: tileGrid,
                        serverType: 'geoserver'
                    }),
                    projection: projection,
                    extend: bounds
                })
            ],
            target: 'map'
        });
        console.log("no error");
    } catch (error) {
        console.log("error");
        console.log(error);
    }
</script>
</body>
</html>

Solution

  • There are a few issues with your code that might be the culprit:

    1. projection must be configured on the ol.source.TileWMS instance, not on ol.layer.Tile.
    2. To limit the extent of ol.layer.Tile, use the extent option, not extend.

    Fixing the above two might make your application work, but there are caveats:

    When you want to ensure that cached tiles are always used, you have to limit your application to certain pixel ratios. In your case 1, 2 and 3. When using ol.source.TileWMS with the option serverType: 'geoserver' configured, requests will always be made using the exact device pixel ratio, which can also be 1.33, 1.5, 6, or many other different values that you do not have tiles for.

    To fix this, you will want to configure your source with a tilePixelRatio instead, and not use the serverType option - if you continue to use WMS. The tilePixelRatio could be calculated like this:

    var tilePixelRatio = 1;
    if (ol.has.DEVICE_PIXEL_RATIO > 2.5) {
      tilePixelRatio = 3;
    } else if (ol.has.DEVICE_PIXEL_RATIO > 1.5) {
      tilePixelRatio = 2;
    }
    

    I would recommend to use TMS or WMTS instead. For TMS, things would look like this:

    var layerName = 'mfn_mwb17:mfn_mwb17_0_basemap';
    var gridset = 'grid_' + (tilePixelRatio * 256);
    var layer = new ol.layer.Tile({
      extent: bounds,
      source: new ol.source.XYZ({
        projection: 'EPSG:32632',
        tileGrid: tileGrid,
        tilePixelRatio: tilePixelRatio,
        url: '/geoserver/gwc/service/tms/1.0.0/' + layerName +
            '@' + gridset + '@png/{z}/{x}/{-y}.png'
      })
    });
    

    The above assumes your gridsets are named grid_256, grid_512 and grid_768, and all use the same tile matrix set. So they only differ in tile width and height in pixels (256, 512 and 768).