package com.bbn.openmap.proj.coords; import java.awt.geom.Point2D; /** * Convert between mercator uv coordinates that are used for map tiles and * lat/lon degrees. Setting the zoom level sets the number of expected pixels in * the Mercator uv projection in both directions. */ public abstract class MercatorUVGCT extends AbstractGCT implements GeoCoordTransformation { int zoomLevel; protected MercatorUVGCT(int zoomLevel) { this.zoomLevel = zoomLevel; } public abstract Point2D forward(double lat, double lon, Point2D ret); public abstract LatLonPoint inverse(double uvx, double uvy, LatLonPoint ret); public int getZoomLevel() { return zoomLevel; } public void setZoomLevel(int zoomLevel) { this.zoomLevel = zoomLevel; } public static class OSM extends MercatorUVGCT { public OSM(int zoomLevel) { super(zoomLevel); } public Point2D forward(double lat, double lon, Point2D ret) { if (ret == null) { ret = new Point2D.Double(); } ret.setLocation(((lon + 180.0) / 360.0 * Math.pow(2.0, zoomLevel)), ((1.0 - Math.log(Math.tan(lat * Math.PI / 180.0) + (1.0 / Math.cos(lat * Math.PI / 180.0))) / Math.PI) / 2.0 * (Math.pow(2.0, zoomLevel)))); return ret; } public LatLonPoint inverse(double uvx, double uvy, LatLonPoint ret) { if (ret == null) { ret = new LatLonPoint.Double(); } ret.setLocation(360.0 / Math.pow(2.0, zoomLevel) * uvx - 180.0, -90.0 + 360.0 / Math.PI * Math.atan(Math.exp((-2.0 * Math.PI * uvy) / Math.pow(2.0, zoomLevel) + Math.PI))); return ret; } } public static class TMS extends MercatorUVGCT { public TMS(int zoomLevel) { super(zoomLevel); } public Point2D forward(double lat, double lon, Point2D ret) { if (ret == null) { ret = new Point2D.Double(); } ret.setLocation(((lon + 180.0) / 360.0 * Math.pow(2, zoomLevel)), Math.pow(2.0, zoomLevel) - ((1.0 - Math.log(Math.tan(lat * Math.PI / 180.0) + (1.0 / Math.cos(lat * Math.PI / 180.0))) / Math.PI) / 2.0 * (Math.pow(2.0, zoomLevel)))); return ret; } public LatLonPoint inverse(double uvx, double uvy, LatLonPoint ret) { if (ret == null) { ret = new LatLonPoint.Double(); } ret.setLocation(360 / Math.pow(2, zoomLevel) * uvx - 180.0, -90.0 + 360.0 / Math.PI * Math.atan(Math.exp((-2.0 * Math.PI * (-(uvy - Math.pow(2.0, zoomLevel)))) / Math.pow(2.0, zoomLevel) + Math.PI))); return ret; } } }