package org.geotools.tile.nasa; import java.net.URI; import java.util.SortedSet; import java.util.TreeSet; import javax.swing.Icon; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.renderer.lite.RendererUtilities; import org.geotools.tile.TileMapInfo; import org.geotools.tile.ZoomLevel; import org.jdom.Element; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Envelope; public class QuadTileMapInfo implements TileMapInfo { Element quad; /** Accessor used to grab content (& name) */ Accessor accessor; QuadTileMapInfo( Element quadTileSet ){ quad = quadTileSet; accessor = Accessor.create( quad ); if( accessor == null ){ throw new NullPointerException("Could not access this QuadTileMap"); } } QuadTileMapInfo( Element quadTileSet, Accessor accessor ){ quad = quadTileSet; this.accessor = accessor; } /** * Unique identifier for data source */ public URI getIdentifier() { return accessor.getIdentifier(); } /** * Grab the set of zoom levels. * <p> * Zoom levels are defined by: * <ul> * <ll>BoundingBox * <li>LevelZeroTileSizeDegrees * <li>NumberLevels * </ul> */ public SortedSet getZoomLevels() { double angle = getLevelZeroTileSizeDegrees(); Envelope bbox = getBounds(); int tileSize = getTextureSizePixels(); int rows = (int) (bbox.getHeight() / angle); int cols = (int) (bbox.getWidth() / angle); double scale; try { int midx = cols/2; int midy = rows/2; double x1 = bbox.getMinX() + ((double)midx)*angle; double x2 = x1 + angle; double y1 = bbox.getMinY() + ((double)midy)*angle; double y2 = y1 + angle; Envelope centerTile = new Envelope( x1, x2, y1, y2 ); CoordinateReferenceSystem crs = getCRS(); scale = RendererUtilities.calculateScale( centerTile, crs, 512, 512, 72.0 ); } catch (Exception e) { // Backup HACK double miles = 49.0 * angle; // 49 miles per deegree double inches = 63360 * miles; double pixels = inches / 72; // 72 DPI scale = pixels * 512; } ZoomLevel levelZero = new ZoomLevel(scale, rows, cols); int numberOfLevels = getNumberLevels(); return levels( levelZero, numberOfLevels ); } /** Create a set of zoom levels, starting from levelZero */ private static SortedSet levels( ZoomLevel levelZero, int numberOfLevels ){ SortedSet set = new TreeSet(); set.add( levelZero ); for( int zoom = 1; zoom <= numberOfLevels; zoom++ ){ set.add(levelZero.zoom( zoom )); } return set; } private double getLevelZeroTileSizeDegrees(){ Element imageAccessor = quad.getChild("ImageAccessor"); String text = imageAccessor.getChildText("LevelZeroTileSizeDegrees"); return Double.parseDouble( text ); } private int getNumberLevels(){ Element imageAccessor = quad.getChild("ImageAccessor"); String text = imageAccessor.getChildText("NumberLevels"); return Integer.parseInt( text ); } private int getTextureSizePixels(){ Element imageAccessor = quad.getChild("ImageAccessor"); String text = imageAccessor.getChildText("TextureSizePixels"); return Integer.parseInt( text ); } private int getImageTileService(){ Element imageAccessor = quad.getChild("ImageAccessor"); String text = imageAccessor.getChildText("ImageTileService"); return Integer.parseInt( text ); } public Envelope getBounds() { Element boundingBox = quad.getChild("BoundingBox"); double north = bound( boundingBox.getChild("North")); double south = bound( boundingBox.getChild("South")); double east = bound( boundingBox.getChild("East")); double west = bound( boundingBox.getChild("West")); return new ReferencedEnvelope( west, east, south, north, getCRS() ); } static double bound( Element direction ){ String value = direction.getChildText("Value"); return Double.parseDouble( value ); } public CoordinateReferenceSystem getCRS() { // TODO: account for <DistanceAboveSurface>0</DistanceAboveSurface> // TODO: model as perfect sphere return DefaultGeographicCRS.WGS84; } public String getDescription() { String basicDescription = quad.getChildText("Description"); String extendedDescription = LayerSetParser.description( quad ); if( extendedDescription != null ){ return basicDescription + "\n" + extendedDescription; } else { return basicDescription; } } /** * Icon (if avialable) will be in ExtendedInformation/ToolBarImage */ public Icon getIcon() { return LayerSetParser.infoIcon( quad ); } public String[] getKeywords() { return new String[]{ "TileMap" }; } public String getName() { return accessor.getName(); } /** * Currently world wind schema; suspect this should be * "TileMap" to allow geotools recognizers to function. */ public URI getSchema() { return WorldWindTileServiceInfo.SCHEMA; } public String getTitle() { return quad.getChildText("Name"); } }