/* * <copyright> * Copyright 2013 BBN Technologies * </copyright> */ package com.bbn.openmap.dataAccess.mapTile; import java.awt.geom.Point2D; import com.bbn.openmap.proj.Mercator; import com.bbn.openmap.proj.Projection; import com.bbn.openmap.proj.coords.LatLonPoint; /** * An abstraction of MapTileCoordinateTransform that combines the identical * methods of OSM and TMS MapTileCoordinateTransforms. * * @author dietrick */ public abstract class AbstractMapTileCoordinateTransform implements MapTileCoordinateTransform { int tileSize = TILE_SIZE; /** * The zoom level tile size is used by the factory to determine when it * needs to get tiles for a different zoom level. The default value is 350. * That is, when the factory is figuring out what zoom level to use, if the * pixel size of a tile is greater than or equal to 350 x 350, it decides to * check the next zoom level for retrieving tiles. This is used instead of * just comparing projection scales. */ int DEFAULT_ZOOM_LEVEL_TILE_SIZE = 350; /* * (non-Javadoc) * * @see * com.bbn.openmap.dataAccess.mapTile.MapTileCoordinateTransform#latLonToTileUV * (java.awt.geom.Point2D, int) */ public Point2D latLonToTileUV(Point2D latlon, int zoom) { return latLonToTileUV(latlon, zoom, null); } /* * (non-Javadoc) * * @see * com.bbn.openmap.dataAccess.mapTile.MapTileCoordinateTransform#tileUVToLatLon * (java.awt.geom.Point2D, int) */ public Point2D tileUVToLatLon(Point2D tileUV, int zoom) { return tileUVToLatLon(tileUV, zoom, null); } /** * Return a scale value for the transforming projection, given a discrete * zoom level. * * @param zoom level * @return scale value. */ public float getScaleForZoom(int zoom) { Projection proj = new Mercator(new LatLonPoint.Double(), 1000000, TILE_SIZE, TILE_SIZE); return getScaleForZoomAndProjection(proj, zoom); } /** * Get the scale value for a Projection and discrete zoom level. * * @param proj the projection to use for scale calculations. * @param zoom the discrete zoom level. * @return scale value for the given projection. */ public float getScaleForZoomAndProjection(Projection proj, int zoom) { MapTileCoordinateTransform mtct = new OSMMapTileCoordinateTransform(); Point2D originLLUL = mtct.tileUVToLatLon(new Point2D.Double(0.0, 0.0), zoom); Point2D originLLLR = mtct.tileUVToLatLon(new Point2D.Double(1.0, 1.0), zoom); return proj.getScale(originLLUL, originLLLR, UVUL, UVLR); } /** * Given a projection, figure out the appropriate zoom level for it. Right * now, 0 is totally zoomed with one tile for the entire earth. But we don't * return 0, we start at 1. OM can't handle one tile that covers the entire * earth because of the restriction for handling OMGraphics to less than * half of the earth. * * @param proj * @return the zoom level. */ public int getZoomLevelForProj(Projection proj) { return getZoomLevelForProj(proj, DEFAULT_ZOOM_LEVEL_TILE_SIZE); } /** * Given a projection, figure out the appropriate zoom level for it. Right * now, 0 is totally zoomed with one tile for the entire earth. But we don't * return 0, we start at 1. OM can't handle one tile that covers the entire * earth because of the restriction for handling OMGraphics to less than * half of the earth. * * @param proj * @param zoomLevelTileSize used for determining zoom levels, a kind of * buffer around true zoom levels since the OpenMap layers scale * images. * @return the zoom level. */ public int getZoomLevelForProj(Projection proj, int zoomLevelTileSize) { int low = 1; int high = 20; int ret = low; for (int currentZoom = low; currentZoom <= high; currentZoom++) { // nearest tile to center Point2D nttc = latLonToTileUV(proj.getCenter(), currentZoom); double nttcX = Math.floor(nttc.getX()); double nttcY = Math.floor(nttc.getY()); Point2D originLLUL = tileUVToLatLon(new Point2D.Double(nttcX, nttcY), currentZoom); Point2D originLLLR = tileUVToLatLon(new Point2D.Double(nttcX + 1, nttcY + 1), currentZoom); Point2D projUVUL = proj.forward(originLLUL); Point2D projLLLR = proj.forward(originLLLR); if (Math.abs(projUVUL.getX() - projLLLR.getX()) <= zoomLevelTileSize) { return currentZoom; } /* * Used to try to do this with scale comparisons, now just look at * tile sizes. float diff = currentScale - scales[currentZoom]; if * (diff > 0) { return currentZoom + 1; } */ } return ret; } /** * Creates an array of scale values for different zoom levels. Make sure you * don't reference the array outside of 0 and high zoom levels. There will * be a high zoom level number of items in the array. * * @param proj * @param highZoomLevel * @return array, initialized for the low zoom level index to the high zoom * level index. */ public float[] getScalesForZoomLevels(Projection proj, int highZoomLevel) { float[] ret = new float[highZoomLevel + 1]; for (int i = 0; i <= highZoomLevel; i++) { ret[i] = getScaleForZoomAndProjection(proj, i); } return ret; } /** * Returns the tile size of the transform. */ public int getTileSize() { return tileSize; } }