/** * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * @author Arne Kepp, OpenGeo, Copyright 2009 */ package org.geowebcache.grid; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.geowebcache.config.XMLConfiguration; import org.geowebcache.layer.TileLayerDispatcher; public class GridSetBroker { private static Log log = LogFactory.getLog(GridSetBroker.class); public final GridSet WORLD_EPSG4326; public final GridSet WORLD_EPSG3857; private Map<String, GridSet> gridSets; private Set<String> embeddedGridSets; public GridSetBroker(boolean useEPSG900913, boolean useGWC11xNames) { gridSets = new HashMap<String, GridSet>(); String unprojectedName = "GlobalCRS84Geometric"; String mercatorName = "GoogleMapsCompatible"; if (useGWC11xNames) { unprojectedName = "EPSG:4326"; if (useEPSG900913) { mercatorName = "EPSG:900913"; } else { mercatorName = "EPSG:3857"; } } log.debug("Adding " + unprojectedName); WORLD_EPSG4326 = GridSetFactory.createGridSet(unprojectedName, SRS.getEPSG4326(), BoundingBox.WORLD4326, false, GridSetFactory.DEFAULT_LEVELS, null, GridSetFactory.DEFAULT_PIXEL_SIZE_METER, 256, 256, true); WORLD_EPSG4326.setDescription("A default WGS84 tile matrix set where the first zoom level " + "covers the world with two tiles on the horizonal axis and one tile " + "over the vertical axis and each subsequent zoom level is calculated by half " + "the resolution of its previous one."); gridSets.put(WORLD_EPSG4326.getName(), WORLD_EPSG4326); final SRS googleMapsCompatibleSRS = useEPSG900913 ? SRS.getEPSG900913() : SRS.getEPSG3857(); log.debug("Adding " + googleMapsCompatibleSRS + " grid set for Spherical Mercator / GoogleMapsCompatible"); WORLD_EPSG3857 = GridSetFactory.createGridSet(mercatorName, googleMapsCompatibleSRS, BoundingBox.WORLD3857, false, commonPractice900913Resolutions(), null, 1.0D, GridSetFactory.DEFAULT_PIXEL_SIZE_METER, null, 256, 256, false); WORLD_EPSG3857 .setDescription("This well-known scale set has been defined to be compatible with Google Maps and" + " Microsoft Live Map projections and zoom levels. Level 0 allows representing the whole " + "world in a single 256x256 pixels. The next level represents the whole world in 2x2 tiles " + "of 256x256 pixels and so on in powers of 2. Scale denominator is only accurate near the equator."); gridSets.put(WORLD_EPSG3857.getName(), WORLD_EPSG3857); // log.debug("Adding WMTS 1.0 GoogleMapsCompatible Gridset"); // GridSet googleMapsCompatible = GridSetFactory.createGridSet("GoogleMapsCompatible", // googleMapsCompatibleSRS, BoundingBox.WORLD3857, false, // googleMapsCompatibleResolutions(), null, 1.0D, // GridSetFactory.DEFAULT_PIXEL_SIZE_METER, null, 256, 256, false); // // googleMapsCompatible // .setDescription("This well-known scale set has been defined to be compatible with Google Maps and" // + // " Microsoft Live Map projections and zoom levels. Level 0 allows representing the whole " // + // "world in a single 256x256 pixels. The next level represents the whole world in 2x2 tiles " // + // "of 256x256 pixels and so on in powers of 2. Scale denominator is only accurate near the equator."); // // gridSets.put(googleMapsCompatible.getName(), googleMapsCompatible); log.debug("Adding GlobalCRS84Pixel"); GridSet GlobalCRS84Pixel = GridSetFactory.createGridSet("GlobalCRS84Pixel", SRS.getEPSG4326(), BoundingBox.WORLD4326, true, scalesCRS84PixelResolutions(), null, null, GridSetFactory.DEFAULT_PIXEL_SIZE_METER, null, 256, 256, true); GlobalCRS84Pixel .setDescription("This well-known scale set has been defined for global cartographic products. " + "Rounded pixel sizes have been chosen for intuitive cartographic representation of raster data. " + "Some values have been chosen to coincide with original pixel size of commonly used global" + "products like STRM (1\" and 3\"), GTOPO (30\") or ETOPO (2' and 5'). Scale denominator" + "and approximated pixel size in meters are only accurate near the equator."); gridSets.put(GlobalCRS84Pixel.getName(), GlobalCRS84Pixel); log.debug("Adding GlobalCRS84Scale"); GridSet GlobalCRS84Scale = GridSetFactory.createGridSet("GlobalCRS84Scale", SRS.getEPSG4326(), BoundingBox.WORLD4326, true, null, scalesCRS84ScaleDenominators(), null, GridSetFactory.DEFAULT_PIXEL_SIZE_METER, null, 256, 256, true); GlobalCRS84Scale .setDescription("This well-known scale set has been defined for global cartographic products. " + "Rounded scales have been chosen for intuitive cartographic representation of vector data. " + "Scale denominator is only accurate near the equator."); gridSets.put(GlobalCRS84Scale.getName(), GlobalCRS84Scale); log.debug("Adding GoogleCRS84Quad"); GridSet GoogleCRS84Quad = GridSetFactory.createGridSet("GoogleCRS84Quad", SRS.getEPSG4326(), BoundingBox.WORLD4326, true, null, scalesCRS84QuadScaleDenominators(), null, GridSetFactory.DEFAULT_PIXEL_SIZE_METER, null, 256, 256, true); GoogleCRS84Quad .setDescription("This well-known scale set has been defined to allow quadtree " + "pyramids in CRS84. Level 0 allows representing the whole world " + "in a single 256x256 pixels (where the first 64 and last 64 lines " + "of the tile are left blank). The next level represents the whole world in 2x2" + " tiles of 256x256 pixels and so on in powers of 2. Scale denominator is only accurate near the equator."); gridSets.put(GoogleCRS84Quad.getName(), GoogleCRS84Quad); embeddedGridSets = Collections.unmodifiableSet(new HashSet<String>(gridSets.keySet())); } public GridSet get(String gridSetId) { return gridSets.get(gridSetId); } /** * @return the names of the gridsets that are internally defined */ public Set<String> getEmbeddedNames() { return embeddedGridSets; } public Set<String> getNames() { return new TreeSet<String>(gridSets.keySet()); } public List<GridSet> getGridSets() { return new ArrayList<GridSet>(gridSets.values()); } public void put(GridSet gridSet) { if (gridSets.containsKey(gridSet.getName())) { log.warn("Duplicate grid set " + gridSet.getName() + ", " + "removing previous instance, but it may still be referenced by layers."); gridSets.remove(gridSet.getName()); } log.debug("Adding " + gridSet.getName()); gridSets.put(gridSet.getName(), gridSet); } /** * Blindly removes a gridset from this gridset broker. * <p> * This method doesn't check whether there's any layer referencing the gridset nor removes it * from the {@link XMLConfiguration}. For such a thing, check * {@link TileLayerDispatcher#removeGridset(String)}, which cascades to this method. * </p> * * @param gridSetName * @return */ public GridSet remove(final String gridSetName) { GridSet removed = gridSets.remove(gridSetName); return removed; } private double[] scalesCRS84PixelResolutions() { double[] scalesCRS84Pixel = new double[18]; scalesCRS84Pixel[0] = 2; scalesCRS84Pixel[1] = 1; scalesCRS84Pixel[2] = 0.5; // 30 scalesCRS84Pixel[3] = scalesCRS84Pixel[2] * (2.0 / 3.0); // 20 scalesCRS84Pixel[4] = scalesCRS84Pixel[2] / 3.0; // 10 scalesCRS84Pixel[5] = scalesCRS84Pixel[4] / 2.0; // 5 scalesCRS84Pixel[6] = scalesCRS84Pixel[4] / 5.0; // 2 scalesCRS84Pixel[7] = scalesCRS84Pixel[4] / 10.0; // 1 scalesCRS84Pixel[8] = (5.0 / 6.0) * 1E-2; // 30'' = 8.33E-3 scalesCRS84Pixel[9] = scalesCRS84Pixel[8] / 2.0; // 15'' scalesCRS84Pixel[10] = scalesCRS84Pixel[9] / 3.0; // 5'' scalesCRS84Pixel[11] = scalesCRS84Pixel[9] / 5.0; // 3'' scalesCRS84Pixel[12] = scalesCRS84Pixel[11] / 3.0; // 1'' scalesCRS84Pixel[13] = scalesCRS84Pixel[12] / 2.0; // 0.5'' scalesCRS84Pixel[14] = scalesCRS84Pixel[13] * (3.0 / 5.0); // 0.3'' scalesCRS84Pixel[15] = scalesCRS84Pixel[14] / 3.0; // 0.1'' scalesCRS84Pixel[16] = scalesCRS84Pixel[15] * (3.0 / 10.0); // 0.03'' scalesCRS84Pixel[17] = scalesCRS84Pixel[16] / 3.0; // 0.01'' return scalesCRS84Pixel; } private double[] scalesCRS84ScaleDenominators() { // double[] scalesCRS84Pixel = { 1.25764139776733, 0.628820698883665, 0.251528279553466, // 0.125764139776733, 6.28820698883665E-2, 2.51528279553466E-2, 1.25764139776733E-2, // 6.28820698883665E-3, 2.51528279553466E-3, 1.25764139776733E-3, 6.28820698883665E-4, // 2.51528279553466E-4, 1.25764139776733E-4, 6.28820698883665E-5, 2.51528279553466E-5, // 1.25764139776733E-5, 6.28820698883665E-6, 2.51528279553466E-6, 1.25764139776733E-6, // 6.28820698883665E-7, 2.51528279553466E-7 }; // // return scalesCRS84Pixel; double[] scalesCRS84Pixel = { 500E6, 250E6, 100E6, 50E6, 25E6, 10E6, 5E6, 2.5E6, 1E6, 500E3, 250E3, 100E3, 50E3, 25E3, 10E3, 5E3, 2.5E3, 1000, 500, 250, 100 }; return scalesCRS84Pixel; } private double[] scalesCRS84QuadScaleDenominators() { double[] scalesCRS84QuadScaleResolutions = { 559082264.0287178, 279541132.0143589, 139770566.0071794, 69885283.00358972, 34942641.50179486, 17471320.75089743, 8735660.375448715, 4367830.187724357, 2183915.093862179, 1091957.546931089, 545978.7734655447, 272989.3867327723, 136494.6933663862, 68247.34668319309, 34123.67334159654, 17061.83667079827, 8530.918335399136, 4265.459167699568, 2132.729583849784 }; return scalesCRS84QuadScaleResolutions; } private double[] googleMapsCompatibleResolutions() { double[] scalesCRS84QuadScaleResolutions = { // 156543.0339280410, // 78271.51696402048, // 39135.75848201023, // 19567.87924100512, // 9783.939620502561, // 4891.969810251280, // 2445.984905125640, // 1222.992452562820, // 611.4962262814100, // 305.7481131407048, // 152.8740565703525, // 76.43702828517624, // 38.21851414258813, // 19.10925707129406, // 9.554628535647032, // 4.777314267823516, // 2.388657133911758, // 1.194328566955879, // 0.5971642834779395, // 0.29858214173896974, // 0.14929107086948487 }; return scalesCRS84QuadScaleResolutions; } private double[] commonPractice900913Resolutions() { return new double[] { // 156543.03390625, 78271.516953125, 39135.7584765625, 19567.87923828125, 9783.939619140625, 4891.9698095703125, 2445.9849047851562, 1222.9924523925781, 611.4962261962891, 305.74811309814453, 152.87405654907226, 76.43702827453613, 38.218514137268066, 19.109257068634033, 9.554628534317017, 4.777314267158508, 2.388657133579254, 1.194328566789627, 0.5971642833948135, 0.29858214169740677, 0.14929107084870338, 0.07464553542435169, 0.037322767712175846, 0.018661383856087923, 0.009330691928043961, 0.004665345964021981, 0.0023326729820109904, 0.0011663364910054952, 5.831682455027476E-4, 2.915841227513738E-4, 1.457920613756869E-4 }; } }