All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mapfish.print.map.readers.WMTSMapReader Maven / Gradle / Ivy

/*
 * Copyright (C) 2013  Camptocamp
 *
 * This file is part of MapFish Print
 *
 * MapFish Print is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MapFish Print is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MapFish Print.  If not, see .
 */

package org.mapfish.print.map.readers;

import org.mapfish.print.RenderingContext;
import org.mapfish.print.Transformer;
import org.mapfish.print.map.ParallelMapTileLoader;
import org.mapfish.print.map.renderers.TileRenderer;
import org.mapfish.print.utils.PJsonArray;
import org.mapfish.print.utils.PJsonObject;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Support for the protocol using directly the content of a WMTS tiled layer, support REST or KVP.
 */
public class WMTSMapReader extends TileableMapReader {

    private static final String RESOLUTION = "resolution";
    private static final String TILE_SIZE = "tileSize";
    private static final String TOP_LEFT_CORNER = "topLeftCorner";
    private static final String MATRIX_SIZE = "matrixSize";
    private static final String RESOLUTIONS = "resolutions";
    private static final String MATRIX_IDS = "matrixIds";
    private static final String MATRIX_SET = "matrixSet";
    private static final String ZOOM_OFFSET = "zoomOffset";
    private static final String FORMAT_SUFFIX = "formatSuffix";
    private static final String EXTENSION = "extension";
    private static final String FORMAT = "format";
    private static final String TILE_ORIGIN = "tileOrigin";
    private static final String STYLE = "style";
    private static final String VERSION = "version";
    private static final String OPACITY = "opacity";
    private static final String TILE_FULL_EXTENT = "tileFullExtent";
    private static final String MAX_EXTENT = "maxExtent";
    private static final String REQUEST_ENCODING = "requestEncoding";
    private static final String DIMENSIONS = "dimensions";
    private static final String PARAMS = "params";
    private final WmtsCapabilitiesInfo capabilitiesInfo;

    public static class Factory implements MapReaderFactory {
        @Override
        public List create(String type, RenderingContext context,
                PJsonObject params) {
            return Collections.singletonList(new WMTSMapReader(params.getString("layer"), context, params));
        }
    }

    protected final String layer;
    @SuppressWarnings("unused")
    private final float opacity;
    private final String version;
    private final WMTSRequestEncoding requestEncoding;
    private final PJsonArray tileOrigin;
    private final String style;
    private final PJsonArray dimensions;
    private final PJsonObject dimensionsParams;
    private final String matrixSet;
    private final Integer zoomOffset;
    private final PJsonArray matrixIds;
    private final String formatSuffix;
    private final String format;
    private PJsonObject matrix; // the currently used matrix


    private WMTSMapReader(String layer, RenderingContext context, PJsonObject params) {
        super(context, params);
        this.layer = layer;
        if (!context.getConfig().isIgnoreCapabilities()) {
            this.capabilitiesInfo = WMTSServiceInfo.getLayerInfo(baseUrl, layer, context);
        } else {
            this.capabilitiesInfo = null;
        }
        // Optional (but mandatory if matrixIds is not provided)
        PJsonArray maxExtent = params.optJSONArray(TILE_FULL_EXTENT, params.optJSONArray(MAX_EXTENT));
        // Optional (but mandatory if matrixIds is not provided)
        PJsonArray tileSize = params.optJSONArray(TILE_SIZE);
        opacity = params.optFloat(OPACITY, 1.0F);
        version = params.optString(VERSION, "1.0.0");
        requestEncoding = WMTSRequestEncoding.valueOf(params.optString(REQUEST_ENCODING, WMTSRequestEncoding.REST.name()));

        // Optional (but mandatory if matrixIds is not provided)
        tileOrigin = params.optJSONArray(TILE_ORIGIN);
        style = params.optString(STYLE, "");
        // Optional
        dimensions = params.optJSONArray(DIMENSIONS);
        // Optional
        dimensionsParams = params.optJSONObject(PARAMS);
        matrixSet = params.getString(MATRIX_SET);
        // Optional (but mandatory if matrixIds is not provided)
        zoomOffset = params.optInt(ZOOM_OFFSET);
        // Optional
        matrixIds = params.optJSONArray(MATRIX_IDS);
        // Optional (but mandatory if matrixIds is not provided)
        formatSuffix = params.optString(FORMAT_SUFFIX, params.optString(EXTENSION));

        // Optional (but mandatory if matrixIds is provided and requestEncoding is KVP)
        format = params.optString(FORMAT);

        if (tileOrigin == null && matrixIds == null) {
            throw new IllegalArgumentException("Either "+TILE_ORIGIN+" or "+MATRIX_IDS+" is required.");
        }
        if (zoomOffset == null && matrixIds == null) {
            throw new IllegalArgumentException("Either "+ZOOM_OFFSET+" or "+MATRIX_IDS+" is required.");
        }
        if (formatSuffix == null && matrixIds == null) {
            throw new IllegalArgumentException("Either "+EXTENSION+" (or "+FORMAT_SUFFIX+") or "+MATRIX_IDS+" is required.");
        }
        if (matrixIds == null) {
            tileCacheLayerInfo = new WMTSLayerInfo(params.getJSONArray(RESOLUTIONS), tileSize.getInt(0), tileSize.getInt(1), maxExtent.getFloat(0), maxExtent.getFloat(1), maxExtent.getFloat(2), maxExtent.getFloat(3), formatSuffix);
        }
    }
    @Override
    protected TileRenderer.Format getFormat() {
        return TileRenderer.Format.BITMAP;
    }
    @Override
    protected void addCommonQueryParams(Map> result, Transformer transformer, String srs, boolean first) {
        //not much query params for this protocol...
    }
    @Override
    protected void renderTiles(TileRenderer formatter, Transformer transformer, URI commonUri, ParallelMapTileLoader parallelMapTileLoader) throws IOException, URISyntaxException {
        if (matrixIds != null) {
            double diff = Double.POSITIVE_INFINITY;
            double targetResolution = transformer.getGeoW() / transformer.getStraightBitmapW();
            for (int i = 0 ; i < matrixIds.size() ; i++) {
                PJsonObject matrixId = matrixIds.getJSONObject(i);
                float resolution = matrixId.getFloat(RESOLUTION);
                double delta = Math.abs(1 - resolution / targetResolution);
                if (delta < diff) {
                    diff = delta;
                    matrix = matrixId;
                }
            }
            float resolution = matrix.getFloat(RESOLUTION);
            PJsonArray tileSize = matrix.getJSONArray(TILE_SIZE);
            PJsonArray topLeftCorner = matrix.getJSONArray(TOP_LEFT_CORNER);
            PJsonArray matrixSize = matrix.getJSONArray(MATRIX_SIZE);
            tileCacheLayerInfo = new TileCacheLayerInfo(
                    String.valueOf(resolution),
                    tileSize.getInt(0), tileSize.getInt(1),
                    topLeftCorner.getFloat(0),
                    topLeftCorner.getFloat(1) - tileSize.getInt(1) * matrixSize.getInt(1) * resolution,
                    topLeftCorner.getFloat(0) + tileSize.getInt(0) * matrixSize.getInt(0) * resolution,
                    topLeftCorner.getFloat(1),
                    format);
        }
        super.renderTiles(formatter, transformer, commonUri, parallelMapTileLoader);
    }
    @Override
    protected URI getTileUri(URI commonUri, Transformer transformer, double minGeoX, double minGeoY, double maxGeoX, double maxGeoY, long w, long h) throws URISyntaxException, UnsupportedEncodingException {
        if (matrixIds != null) {
            PJsonArray topLeftCorner = matrix.getJSONArray(TOP_LEFT_CORNER);
            float factor = 1 / (matrix.getFloat(RESOLUTION) * w);
            int row = (int) Math.round((topLeftCorner.getDouble(1) - maxGeoY) * factor);
            int col = (int) Math.round((minGeoX - topLeftCorner.getDouble(0)) * factor);
            if (WMTSRequestEncoding.REST == requestEncoding) {
                String path = commonUri.getPath();
                for (int i = 0 ; i < dimensions.size() ; i++) {
                    String d = dimensions.getString(i);
                    path = path.replace("{" + d + "}", dimensionsParams.getString(d.toUpperCase()));
                }
                path = path.replace("{TileMatrixSet}", matrixSet);
                path = path.replace("{TileMatrix}", matrix.getString("identifier"));
                path = path.replace("{TileRow}", String.valueOf(row));
                path = path.replace("{TileCol}", String.valueOf(col));

                return new URI(commonUri.getScheme(), commonUri.getUserInfo(), commonUri.getHost(), commonUri.getPort(),
                        path, commonUri.getQuery(), commonUri.getFragment());
            }
            else {
                String query = "SERVICE=WMTS";
                query += "&REQUEST=GetTile";
                query += "&VERSION=" + version;
                query += "&LAYER=" + layer;
                query += "&STYLE=" + style;
                query += "&TILEMATRIXSET=" + matrixSet;
                query += "&TILEMATRIX=" + matrix.getString("identifier");
                query += "&TILEROW=" + row;
                query += "&TILECOL=" + col;
                query += "&FORMAT=" + format;
                if (dimensions != null) {
                    for (int i = 0 ; i < dimensions.size() ; i++) {
                        String d = dimensions.getString(i);
                        query += "&" + d + "=" + dimensionsParams.getString(d.toUpperCase());
                    }
                }
                return new URI(commonUri.getScheme(), commonUri.getUserInfo(), commonUri.getHost(), commonUri.getPort(),
                        commonUri.getPath(), query, commonUri.getFragment());
            }
        }
        else {
            double targetResolution = (maxGeoX - minGeoX) / w;
            WMTSLayerInfo.ResolutionInfo resolution = tileCacheLayerInfo.getNearestResolution(targetResolution);

            int col = (int) Math.round(Math.floor(((maxGeoX + minGeoX)/2-tileOrigin.getDouble(0)) / (resolution.value * w)));
            int row = (int) Math.round(Math.floor((tileOrigin.getDouble(1)-(maxGeoY + minGeoY)/2) / (resolution.value * h)));

            StringBuilder path = new StringBuilder();
            if (!commonUri.getPath().endsWith("/")) {
                path.append('/');
            }
            if (requestEncoding == WMTSRequestEncoding.REST) {
                path.append(version);
                path.append('/').append(layer);
                path.append('/').append(style);
                // Add dimensions
                if (dimensions != null) {
                    for (int i = 0; i< dimensions.size(); i++) {
                        path.append('/').append(dimensionsParams.getString(dimensions.getString(i)));
                    }
                }
                path.append('/').append(matrixSet);
                path.append('/').append(resolution.index + zoomOffset);
                path.append('/').append(row);
                path.append('/').append(col);

                path.append('.').append(tileCacheLayerInfo.getExtension());

                return new URI(commonUri.getScheme(), commonUri.getUserInfo(), commonUri.getHost(), commonUri.getPort(), commonUri.getPath() + path, commonUri.getQuery(), commonUri.getFragment());
            }
            else {
                String query = "SERVICE=WMTS";
                query += "&REQUEST=GetTile";
                query += "&VERSION=" + version;
                query += "&LAYER=" + layer;
                query += "&STYLE=" + style;
                query += "&TILEMATRIXSET=" + matrixSet;
                String tileMatrix = ""+(resolution.index + zoomOffset);
                if (capabilitiesInfo != null && capabilitiesInfo.getTileMatrices().containsKey(matrixSet)) {
                    final WMTSServiceInfo.TileMatrixSet tileMatrixSet = capabilitiesInfo.getTileMatrices().get(matrixSet);
                    if (!tileMatrixSet.limits.containsKey(tileMatrix)) {
                        // try to find a tileMatrix from capabilities that seems to match parameters
                        final WMTSServiceInfo.TileMatrixLimit limit = tileMatrixSet.limits.get(matrixSet + ":" + tileMatrix);
                        if (limit != null) {
                            tileMatrix = limit.id;
                        } else {
                            for (WMTSServiceInfo.TileMatrixLimit l : tileMatrixSet.limits.values()) {
                                if (l.id.endsWith(":"+tileMatrix)) {
                                    tileMatrix = l.id;
                                    break;
                                }
                            }
                        }
                    }
                }
                query += "&TILEMATRIX=" + tileMatrix;
                query += "&TILEROW=" + row;
                query += "&TILECOL=" + col;
                query += "&FORMAT=" + (formatSuffix.equals("png") ? "image/png" : "image/jpeg");
                if (dimensions != null) {
                    for (int i = 0 ; i < dimensions.size() ; i++) {
                        String d = dimensions.getString(i);
                        query += "&" + d + "=" + dimensionsParams.getString(d.toUpperCase());
                    }
                }
                return new URI(commonUri.getScheme(), commonUri.getUserInfo(), commonUri.getHost(), commonUri.getPort(),
                        commonUri.getPath(), query, commonUri.getFragment());
            }
        }
    }
    @Override
    public boolean testMerge(MapReader other) {
        return false;
    }
    @Override
    public boolean canMerge(MapReader other) {
        return false;
    }
    @Override
    public String toString() {
        return layer;
    }

    private enum WMTSRequestEncoding {
        KVP, REST
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy