001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.layer; 003 004import java.io.IOException; 005import java.util.Set; 006 007import org.apache.commons.jcs.access.CacheAccess; 008import org.openstreetmap.gui.jmapviewer.TileXY; 009import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; 010import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader; 011import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource; 012import org.openstreetmap.josm.Main; 013import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry; 014import org.openstreetmap.josm.data.coor.LatLon; 015import org.openstreetmap.josm.data.imagery.ImageryInfo; 016import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType; 017import org.openstreetmap.josm.data.imagery.WMSCachedTileLoader; 018import org.openstreetmap.josm.data.imagery.WMTSTileSource; 019import org.openstreetmap.josm.data.preferences.BooleanProperty; 020import org.openstreetmap.josm.data.projection.Projection; 021import org.openstreetmap.josm.gui.MapView; 022 023/** 024 * WMTS layer based on AbstractTileSourceLayer. Overrides few methods to align WMTS to Tile based computations 025 * but most magic is done within WMTSTileSource class. 026 * 027 * Full specification of the protocol available at: 028 * http://www.opengeospatial.org/standards/wmts 029 * 030 * @author Wiktor Niesiobędzki 031 * 032 */ 033public class WMTSLayer extends AbstractCachedTileSourceLayer { 034 /** 035 * default setting of autozoom per layer 036 */ 037 public static final BooleanProperty PROP_DEFAULT_AUTOZOOM = new BooleanProperty("imagery.wmts.default_autozoom", true); 038 private static final String CACHE_REGION_NAME = "WMTS"; 039 040 041 /** 042 * Creates WMTS layer from ImageryInfo 043 * @param info Imagery Info describing the layer 044 */ 045 public WMTSLayer(ImageryInfo info) { 046 super(info); 047 autoZoom = PROP_DEFAULT_AUTOZOOM.get(); 048 } 049 050 @Override 051 protected AbstractTMSTileSource getTileSource(ImageryInfo info) { 052 try { 053 if (info.getImageryType() == ImageryType.WMTS && info.getUrl() != null) { 054 WMTSTileSource.checkUrl(info.getUrl()); 055 WMTSTileSource tileSource = new WMTSTileSource(info); 056 info.setAttribution(tileSource); 057 return tileSource; 058 } 059 return null; 060 } catch (IOException e) { 061 Main.warn(e); 062 throw new IllegalArgumentException(e); 063 } 064 } 065 066 /** 067 * @param zoom level of the tile 068 * @return how many pixels of the screen occupies one pixel of the tile 069 */ 070 private double getTileToScreenRatio(int zoom) { 071 MapView mv = Main.map.mapView; 072 LatLon topLeft = mv.getLatLon(0, 0); 073 LatLon botLeft = mv.getLatLon(0, tileSource.getTileSize()); 074 075 TileXY topLeftTile = tileSource.latLonToTileXY(topLeft.toCoordinate(), zoom); 076 077 ICoordinate north = tileSource.tileXYToLatLon(topLeftTile.getXIndex(), topLeftTile.getYIndex(), zoom); 078 ICoordinate south = tileSource.tileXYToLatLon(topLeftTile.getXIndex(), topLeftTile.getYIndex() + 1, zoom); 079 080 return Math.abs((north.getLat() - south.getLat()) / (topLeft.lat() - botLeft.lat())); 081 } 082 083 @Override 084 protected int getBestZoom() { 085 if (!Main.isDisplayingMapView()) return 1; 086 087 for (int i = getMinZoomLvl() + 1; i <= getMaxZoomLvl(); i++) { 088 double ret = getTileToScreenRatio(i); 089 if (ret < 1) { 090 return i - 1; 091 } 092 } 093 return getMaxZoomLvl(); 094 } 095 096 @Override 097 public boolean isProjectionSupported(Projection proj) { 098 Set<String> supportedProjections = ((WMTSTileSource) tileSource).getSupportedProjections(); 099 return supportedProjections.contains(proj.toCode()); 100 } 101 102 @Override 103 public String nameSupportedProjections() { 104 StringBuilder ret = new StringBuilder(); 105 for (String e: ((WMTSTileSource) tileSource).getSupportedProjections()) { 106 ret.append(e).append(", "); 107 } 108 return ret.length() > 2 ? ret.substring(0, ret.length()-2) : ret.toString(); 109 } 110 111 @Override 112 public void projectionChanged(Projection oldValue, Projection newValue) { 113 super.projectionChanged(oldValue, newValue); 114 ((WMTSTileSource) tileSource).initProjection(newValue); 115 } 116 117 @Override 118 protected Class<? extends TileLoader> getTileLoaderClass() { 119 return WMSCachedTileLoader.class; 120 } 121 122 @Override 123 protected String getCacheName() { 124 return CACHE_REGION_NAME; 125 } 126 127 /** 128 * @return cache region for WMTS layer 129 */ 130 public static CacheAccess<String, BufferedImageCacheEntry> getCache() { 131 return AbstractCachedTileSourceLayer.getCache(CACHE_REGION_NAME); 132 } 133}