001 package org.openstreetmap.gui.jmapviewer.tilesources; 002 003 import java.util.Random; 004 005 import org.openstreetmap.gui.jmapviewer.OsmMercator; 006 007 public class ScanexTileSource extends AbstractTMSTileSource { 008 private static String API_KEY = "4018C5A9AECAD8868ED5DEB2E41D09F7"; 009 010 private enum ScanexLayer { 011 IRS("irs", "/TileSender.ashx?ModeKey=tile&MapName=F7B8CF651682420FA1749D894C8AD0F6&LayerName=BAC78D764F0443BD9AF93E7A998C9F5B"), 012 SPOT("spot", "/TileSender.ashx?ModeKey=tile&MapName=F7B8CF651682420FA1749D894C8AD0F6&LayerName=F51CE95441284AF6B2FC319B609C7DEC"); 013 014 private String name; 015 private String uri; 016 017 ScanexLayer(String name, String uri) { 018 this.name = name; 019 this.uri = uri; 020 } 021 public String getName() { 022 return name; 023 } 024 public String getUri() { 025 return uri; 026 } 027 } 028 029 /* IRS by default */ 030 private ScanexLayer Layer = ScanexLayer.IRS; 031 032 public ScanexTileSource(String url) { 033 super("Scanex " + url, "http://maps.kosmosnimki.ru"); 034 035 for (ScanexLayer layer : ScanexLayer.values()) { 036 if (url.equalsIgnoreCase(layer.getName())) { 037 this.Layer = layer; 038 break; 039 } 040 } 041 } 042 043 @Override 044 public int getMaxZoom() { 045 return 14; 046 } 047 048 @Override 049 public String getExtension() { 050 return("jpeg"); 051 } 052 053 @Override 054 public String getTilePath(int zoom, int tilex, int tiley) { 055 int tmp = (int)Math.pow(2.0, zoom - 1); 056 057 tilex = tilex - tmp; 058 tiley = tmp - tiley - 1; 059 060 return this.Layer.getUri() + "&apikey=" + API_KEY + "&x=" + tilex + "&y=" + tiley + "&z=" + zoom; 061 } 062 063 public TileUpdate getTileUpdate() { 064 return TileUpdate.IfNoneMatch; 065 } 066 067 private static double RADIUS_E = 6378137; /* radius of Earth at equator, m */ 068 private static double EQUATOR = 40075016.68557849; /* equator length, m */ 069 private static double E = 0.0818191908426; /* eccentricity of Earth's ellipsoid */ 070 071 @Override 072 public double latToTileY(double lat, int zoom) { 073 double tmp = Math.tan(Math.PI/4 * (1 + lat/90)); 074 double pow = Math.pow(Math.tan(Math.PI/4 + Math.asin(E * Math.sin(Math.toRadians(lat)))/2), E); 075 076 return (EQUATOR/2 - (RADIUS_E * Math.log(tmp/pow))) * Math.pow(2.0, zoom) / EQUATOR; 077 } 078 079 @Override 080 public double lonToTileX(double lon, int zoom) { 081 return (RADIUS_E * lon * Math.PI / (90*EQUATOR) + 1) * Math.pow(2.0, zoom - 1); 082 } 083 084 /* 085 * To solve inverse formula latitude = f(y) we use 086 * Newton's method. We cache previous calculated latitude, 087 * because new one is usually close to the old one. In case 088 * if solution gets out of bounds, we reset to a new random 089 * value. 090 */ 091 private double cached_lat = 0; 092 093 @Override 094 public double tileYToLat(int y, int zoom) { 095 Random r= new Random(); 096 double lat0, lat; 097 098 lat = cached_lat; 099 do { 100 lat0 = lat; 101 lat = lat - Math.toDegrees(NextTerm(Math.toRadians(lat), y, zoom)); 102 if (lat > OsmMercator.MAX_LAT || lat < OsmMercator.MIN_LAT) { 103 lat = OsmMercator.MIN_LAT + 104 (double )r.nextInt((int )(OsmMercator.MAX_LAT - 105 OsmMercator.MIN_LAT)); 106 } 107 } while ((Math.abs(lat0 - lat) > 0.000001)); 108 109 cached_lat = lat; 110 111 return (lat); 112 } 113 114 /* Next term in Newton's polynomial */ 115 private double NextTerm(double lat, double y, int zoom) { 116 double sinl=Math.sin(lat); 117 double cosl=Math.cos(lat); 118 double ec, f, df; 119 120 zoom = (int )Math.pow(2.0, zoom - 1); 121 ec = Math.exp((1 - y/zoom)*Math.PI); 122 123 f = (Math.tan(Math.PI/4+lat/2) - 124 ec * Math.pow(Math.tan(Math.PI/4 + Math.asin(E * sinl)/2), E)); 125 df = 1/(1 - sinl) - ec * E * cosl/((1 - E * sinl) * 126 (Math.sqrt (1 - E * E * sinl * sinl))); 127 128 return (f/df); 129 } 130 131 @Override 132 public double tileXToLon(int x, int zoom) { 133 return (x / Math.pow(2.0, zoom - 1) - 1) * (90*EQUATOR) / RADIUS_E / Math.PI; 134 } 135 }