GoogleEarthLayer
1 import gov.nasa.worldwind.avlist.AVKey; 2 import gov.nasa.worldwind.avlist.AVList; 3 import gov.nasa.worldwind.avlist.AVListImpl; 4 import gov.nasa.worldwind.geom.Angle; 5 import gov.nasa.worldwind.geom.LatLon; 6 import gov.nasa.worldwind.layers.Mercator.BasicMercatorTiledImageLayer; 7 import gov.nasa.worldwind.layers.Mercator.MercatorSector; 8 import gov.nasa.worldwind.util.LevelSet; 9 import gov.nasa.worldwind.util.Tile; 10 import gov.nasa.worldwind.util.TileUrlBuilder; 11 12 import java.awt.image.BufferedImage; 13 import java.net.MalformedURLException; 14 import java.net.URL; 15 16 public class GoogleEarthLayer extends BasicMercatorTiledImageLayer { 17 public static enum Dataset { 18 AERIAL("Aerial", "a", ".jpg", 19 "http://khm%d.google.com/kh/v=57&x=%d&y=%d&z=%d&s=Galile"); 20 21 public final String label; 22 public final String dataset; 23 public final String formatSuffix; 24 public final String urlFormat; 25 26 private Dataset(String label, String dataset, String formatSuffix, 27 String urlFormat) { 28 this.label = label; 29 this.dataset = dataset; 30 this.formatSuffix = formatSuffix; 31 this.urlFormat = urlFormat; 32 } 33 } 34 35 private final Dataset dataset; 36 37 public GoogleEarthLayer() { 38 this(Dataset.AERIAL); 39 } 40 41 public GoogleEarthLayer(Dataset dataset) { 42 super(makeLevels(dataset)); 43 if (dataset == null) 44 throw new NullPointerException("Dataset cannot be null"); 45 this.dataset = dataset; 46 this.setValue(AVKey.DISPLAY_NAME, "Google Earth " + dataset.label); 47 this.setSplitScale(1.3); 48 } 49 50 protected static LevelSet makeLevels(Dataset dataset) { 51 AVList params = new AVListImpl(); 52 53 params.setValue(AVKey.TILE_WIDTH, 256); 54 params.setValue(AVKey.TILE_HEIGHT, 256); 55 params 56 .setValue(AVKey.DATA_CACHE_NAME, "Google Earth7 " 57 + dataset.label); 58 params.setValue(AVKey.SERVICE, 59 "http://kh0.google.com/kh?n=404&v=17&t=t"); 60 params.setValue(AVKey.DATASET_NAME, dataset.dataset); 61 params.setValue(AVKey.FORMAT_SUFFIX, dataset.formatSuffix); 62 params.setValue(AVKey.NUM_LEVELS, 16); 63 params.setValue(AVKey.NUM_EMPTY_LEVELS, 0); 64 params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, new LatLon(Angle 65 .fromDegrees(22.5d), Angle.fromDegrees(45d))); 66 params.setValue(AVKey.SECTOR, new MercatorSector(-1.0, 1.0, 67 Angle.NEG180, Angle.POS180)); 68 params.setValue(AVKey.TILE_URL_BUILDER, new URLBuilder(dataset)); 69 params.setValue(AVKey.DISPLAY_NAME, "Google Maps " + dataset.label); 70 71 return new LevelSet(params); 72 } 73 74 public static class URLBuilder implements TileUrlBuilder { 75 76 private Dataset dataset; 77 78 public URLBuilder(Dataset dataset) { 79 this.dataset = dataset; 80 } 81 82 public URL getURL(Tile tile, String imageFormat) 83 throws MalformedURLException { 84 LatLon center = tile.getSector().getCentroid(); 85 String urlString = computeTileUrl(dataset.urlFormat, center 86 .getLatitude().degrees, center.getLongitude().degrees, tile 87 .getLevelNumber() + 3); 88 System.out.println("Need:" + urlString); 89 URL url = new URL(urlString); 90 return url; 91 } 92 93 private static String computeTileUrl(String urlFormat, double lat, double lon, int zoom) { 94 95 if (lon > 180.0) { 96 lon -= 360.0; 97 } 98 99 lon = (180.0 + lon) / 360.0; 100 lat = 0.5 101 - Math.log(Math.tan((Math.PI / 4.0) 102 + ((Math.PI * lat) / (2.0 * 180.0)))) / (2.0 * Math.PI); 103 104 int scale = 1 << (int) zoom; 105 106 // can just truncate to integer, this looses the fractional 107 // "pixel offset" 108 int x = (int) (lon * scale); 109 int y = (int) (lat * scale); 110 return String.format(urlFormat, (int) (Math.random() * 4), x, y, zoom); 111 } 112 113 } 114 115 @Override 116 protected boolean isTileValid(BufferedImage image) { 117 // return false if the tile is white (this will mark the tile as absent) 118 boolean white = true; 119 // JPEG compression will cause white to be not quite white 120 String lowercaseFormat = getDataset().formatSuffix.toLowerCase(); 121 int threshold = lowercaseFormat.contains("jpg") 122 || lowercaseFormat.contains("jpeg") ? 200 : 250; 123 for (int x = 0; x < image.getWidth(); x++) { 124 for (int y = 0; y < image.getHeight(); y++) { 125 int rgb = image.getRGB(x, y); 126 white = isWhite(rgb, threshold); 127 if (!white) 128 break; 129 } 130 if (!white) 131 break; 132 } 133 return !white; 134 } 135 136 private boolean isWhite(int rgb, int threshold) { 137 int r = (rgb >> 16) & 0xff; 138 int g = (rgb >> 8) & 0xff; 139 int b = (rgb >> 0) & 0xff; 140 return r + b + g > threshold * 3; 141 } 142 143 public Dataset getDataset() { 144 return dataset; 145 } 146 }