001// License: GPL. For details, see Readme.txt file. 002package org.openstreetmap.gui.jmapviewer.tilesources; 003 004import java.awt.Point; 005import java.io.IOException; 006import java.util.HashMap; 007import java.util.List; 008import java.util.Map; 009import java.util.Map.Entry; 010 011import org.openstreetmap.gui.jmapviewer.Coordinate; 012import org.openstreetmap.gui.jmapviewer.OsmMercator; 013import org.openstreetmap.gui.jmapviewer.Tile; 014import org.openstreetmap.gui.jmapviewer.TileXY; 015import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; 016 017/** 018 * Class generalizing all tile based tile sources 019 * 020 * @author Wiktor Niesiobędzki 021 * 022 */ 023public abstract class AbstractTMSTileSource extends AbstractTileSource { 024 025 protected String name; 026 protected String baseUrl; 027 protected String id; 028 private final Map<String, String> noTileHeaders; 029 private final Map<String, String> metadataHeaders; 030 protected int tileSize; 031 protected OsmMercator osmMercator; 032 033 /** 034 * Creates an instance based on TileSource information 035 * 036 * @param info description of the Tile Source 037 */ 038 public AbstractTMSTileSource(TileSourceInfo info) { 039 this.name = info.getName(); 040 this.baseUrl = info.getUrl(); 041 if (baseUrl != null && baseUrl.endsWith("/")) { 042 baseUrl = baseUrl.substring(0, baseUrl.length()-1); 043 } 044 this.id = info.getUrl(); 045 this.noTileHeaders = info.getNoTileHeaders(); 046 this.metadataHeaders = info.getMetadataHeaders(); 047 this.tileSize = info.getTileSize(); 048 this.osmMercator = new OsmMercator(this.tileSize); 049 } 050 051 /** 052 * @return default tile size to use, when not set in Imagery Preferences 053 */ 054 @Override 055 public int getDefaultTileSize() { 056 return OsmMercator.DEFAUL_TILE_SIZE; 057 } 058 059 @Override 060 public String getName() { 061 return name; 062 } 063 064 @Override 065 public String getId() { 066 return id; 067 } 068 069 @Override 070 public int getMaxZoom() { 071 return 21; 072 } 073 074 @Override 075 public int getMinZoom() { 076 return 0; 077 } 078 079 /** 080 * @return image extension, used for URL creation 081 */ 082 public String getExtension() { 083 return "png"; 084 } 085 086 /** 087 * @param zoom level of the tile 088 * @param tilex tile number in x axis 089 * @param tiley tile number in y axis 090 * @return String containg path part of URL of the tile 091 * @throws IOException when subclass cannot return the tile URL 092 */ 093 public String getTilePath(int zoom, int tilex, int tiley) throws IOException { 094 return "/" + zoom + "/" + tilex + "/" + tiley + "." + getExtension(); 095 } 096 097 /** 098 * @return Base part of the URL of the tile source 099 */ 100 public String getBaseUrl() { 101 return this.baseUrl; 102 } 103 104 @Override 105 public String getTileUrl(int zoom, int tilex, int tiley) throws IOException { 106 return this.getBaseUrl() + getTilePath(zoom, tilex, tiley); 107 } 108 109 @Override 110 public String toString() { 111 return getName(); 112 } 113 114 /* 115 * Most tilesources use OsmMercator projection. 116 */ 117 @Override 118 public int getTileSize() { 119 if (tileSize <= 0) { 120 return getDefaultTileSize(); 121 } 122 return tileSize; 123 } 124 125 @Override 126 public double getDistance(double lat1, double lon1, double lat2, double lon2) { 127 return osmMercator.getDistance(lat1, lon1, lat2, lon2); 128 } 129 130 @Override 131 public Point latLonToXY(double lat, double lon, int zoom) { 132 return new Point( 133 (int) osmMercator.lonToX(lon, zoom), 134 (int) osmMercator.latToY(lat, zoom) 135 ); 136 } 137 138 @Override 139 public Point latLonToXY(ICoordinate point, int zoom) { 140 return latLonToXY(point.getLat(), point.getLon(), zoom); 141 } 142 143 @Override 144 public ICoordinate xyToLatLon(Point point, int zoom) { 145 return xyToLatLon(point.x, point.y, zoom); 146 } 147 148 @Override 149 public ICoordinate xyToLatLon(int x, int y, int zoom) { 150 return new Coordinate( 151 osmMercator.yToLat(y, zoom), 152 osmMercator.xToLon(x, zoom) 153 ); 154 } 155 156 @Override 157 public TileXY latLonToTileXY(double lat, double lon, int zoom) { 158 return new TileXY( 159 osmMercator.lonToX(lon, zoom) / tileSize, 160 osmMercator.latToY(lat, zoom) / tileSize 161 ); 162 } 163 164 @Override 165 public TileXY latLonToTileXY(ICoordinate point, int zoom) { 166 return latLonToTileXY(point.getLat(), point.getLon(), zoom); 167 } 168 169 @Override 170 public ICoordinate tileXYToLatLon(TileXY xy, int zoom) { 171 return tileXYToLatLon(xy.getXIndex(), xy.getYIndex(), zoom); 172 } 173 174 @Override 175 public ICoordinate tileXYToLatLon(Tile tile) { 176 return tileXYToLatLon(tile.getXtile(), tile.getYtile(), tile.getZoom()); 177 } 178 179 @Override 180 public ICoordinate tileXYToLatLon(int x, int y, int zoom) { 181 return new Coordinate( 182 osmMercator.yToLat(y * tileSize, zoom), 183 osmMercator.xToLon(x * tileSize, zoom) 184 ); 185 } 186 187 @Override 188 public int getTileXMax(int zoom) { 189 return getTileMax(zoom); 190 } 191 192 @Override 193 public int getTileXMin(int zoom) { 194 return 0; 195 } 196 197 @Override 198 public int getTileYMax(int zoom) { 199 return getTileMax(zoom); 200 } 201 202 @Override 203 public int getTileYMin(int zoom) { 204 return 0; 205 } 206 207 @Override 208 public boolean isNoTileAtZoom(Map<String, List<String>> headers, int statusCode, byte[] content) { 209 if (noTileHeaders != null && headers != null) { 210 for (Entry<String, String> searchEntry: noTileHeaders.entrySet()) { 211 List<String> headerVals = headers.get(searchEntry.getKey()); 212 if (headerVals != null) { 213 for (String headerValue: headerVals) { 214 if (headerValue.matches(searchEntry.getValue())) { 215 return true; 216 } 217 } 218 } 219 } 220 } 221 return super.isNoTileAtZoom(headers, statusCode, content); 222 } 223 224 @Override 225 public Map<String, String> getMetadata(Map<String, List<String>> headers) { 226 Map<String, String> ret = new HashMap<>(); 227 if (metadataHeaders != null && headers != null) { 228 for (Entry<String, String> searchEntry: metadataHeaders.entrySet()) { 229 List<String> headerVals = headers.get(searchEntry.getKey()); 230 if (headerVals != null) { 231 for (String headerValue: headerVals) { 232 ret.put(searchEntry.getValue(), headerValue); 233 } 234 } 235 } 236 } 237 return ret; 238 } 239 240 @Override 241 public String getTileId(int zoom, int tilex, int tiley) { 242 return this.baseUrl + "/" + zoom + "/" + tilex + "/" + tiley; 243 } 244 245 private static int getTileMax(int zoom) { 246 return (int) Math.pow(2.0, zoom) - 1; 247 } 248}