[9095] | 1 | package org.openstreetmap.gui.jmapviewer;
|
---|
| 2 |
|
---|
| 3 | // License: GPL. Copyright 2007 by Tim Haussmann
|
---|
| 4 |
|
---|
| 5 | /**
|
---|
| 6 | * This class implements the Mercator Projection as it is used by Openstreetmap
|
---|
| 7 | * (and google). It provides methods to translate coordinates from 'map space'
|
---|
| 8 | * into latitude and longitude (on the WGS84 ellipsoid) and vice versa. Map
|
---|
| 9 | * space is measured in pixels. The origin of the map space is the top left
|
---|
| 10 | * corner. The map space origin (0,0) has latitude ~85 and longitude -180
|
---|
| 11 | *
|
---|
| 12 | * @author Tim Haussmann
|
---|
| 13 | *
|
---|
| 14 | */
|
---|
| 15 |
|
---|
| 16 | public class OsmMercator {
|
---|
| 17 |
|
---|
| 18 | private static int TILE_SIZE = 256;
|
---|
| 19 | public static final double MAX_LAT = 85.05112877980659;
|
---|
| 20 | public static final double MIN_LAT = -85.05112877980659;
|
---|
| 21 |
|
---|
| 22 | public static double radius(int aZoomlevel) {
|
---|
[11376] | 23 | return (TILE_SIZE * (1 << aZoomlevel)) / (2.0 * Math.PI);
|
---|
[9095] | 24 | }
|
---|
| 25 |
|
---|
| 26 | /**
|
---|
| 27 | * Returns the absolut number of pixels in y or x, defined as: 2^Zoomlevel *
|
---|
| 28 | * TILE_WIDTH where TILE_WIDTH is the width of a tile in pixels
|
---|
| 29 | *
|
---|
| 30 | * @param aZoomlevel
|
---|
| 31 | * @return
|
---|
| 32 | */
|
---|
| 33 | public static int getMaxPixels(int aZoomlevel) {
|
---|
[11376] | 34 | return TILE_SIZE * (1 << aZoomlevel);
|
---|
[9095] | 35 | }
|
---|
| 36 |
|
---|
| 37 | public static int falseEasting(int aZoomlevel) {
|
---|
[11376] | 38 | return getMaxPixels(aZoomlevel) / 2;
|
---|
[9095] | 39 | }
|
---|
| 40 |
|
---|
| 41 | public static int falseNorthing(int aZoomlevel) {
|
---|
[11376] | 42 | return (-1 * getMaxPixels(aZoomlevel) / 2);
|
---|
[9095] | 43 | }
|
---|
| 44 |
|
---|
| 45 | /**
|
---|
| 46 | * Transform longitude to pixelspace
|
---|
| 47 | *
|
---|
| 48 | * @param aLongitude
|
---|
| 49 | * [-180..180]
|
---|
| 50 | * @return [0..2^Zoomlevel*TILE_SIZE[
|
---|
| 51 | */
|
---|
| 52 | public static int LonToX(double aLongitude, int aZoomlevel) {
|
---|
| 53 | double longitude = Math.toRadians(aLongitude);
|
---|
[11376] | 54 | int x = (int) ((radius(aZoomlevel) * longitude) + falseEasting(aZoomlevel));
|
---|
| 55 | x = Math.min(x, getMaxPixels(aZoomlevel) - 1);
|
---|
| 56 | return x;
|
---|
[9095] | 57 | }
|
---|
| 58 |
|
---|
| 59 | /**
|
---|
| 60 | * Transforms latitude to pixelspace
|
---|
| 61 | *
|
---|
| 62 | * @param aLat
|
---|
| 63 | * [-90...90]
|
---|
| 64 | * @return [0..2^Zoomlevel*TILE_SIZE[
|
---|
| 65 | */
|
---|
| 66 | public static int LatToY(double aLat, int aZoomlevel) {
|
---|
| 67 | if (aLat < MIN_LAT)
|
---|
| 68 | aLat = MIN_LAT;
|
---|
| 69 | else if (aLat > MAX_LAT)
|
---|
| 70 | aLat = MAX_LAT;
|
---|
| 71 | double latitude = Math.toRadians(aLat);
|
---|
[11376] | 72 | int y =
|
---|
| 73 | (int) (-1
|
---|
| 74 | * (radius(aZoomlevel) / 2.0 * Math.log((1.0 + Math.sin(latitude))
|
---|
| 75 | / (1.0 - Math.sin(latitude)))) - falseNorthing(aZoomlevel));
|
---|
| 76 | y = Math.min(y, getMaxPixels(aZoomlevel) - 1);
|
---|
| 77 | return y;
|
---|
[9095] | 78 | }
|
---|
| 79 |
|
---|
| 80 | /**
|
---|
| 81 | * Transforms pixel coordinate X to longitude
|
---|
| 82 | *
|
---|
| 83 | * @param aX
|
---|
| 84 | * [0..2^Zoomlevel*TILE_WIDTH[
|
---|
| 85 | * @return ]-180..180[
|
---|
| 86 | */
|
---|
| 87 | public static double XToLon(int aX, int aZoomlevel) {
|
---|
| 88 | aX -= falseEasting(aZoomlevel);
|
---|
| 89 | double longRadians = aX / radius(aZoomlevel);
|
---|
| 90 | double longDegrees = Math.toDegrees(longRadians);
|
---|
[11376] | 91 | return longDegrees;
|
---|
[9095] | 92 | }
|
---|
| 93 |
|
---|
| 94 | /**
|
---|
| 95 | * Transforms pixel coordinate Y to latitude
|
---|
| 96 | *
|
---|
| 97 | * @param aY
|
---|
| 98 | * [0..2^Zoomlevel*TILE_WIDTH[
|
---|
| 99 | * @return [MIN_LAT..MAX_LAT] is about [-85..85]
|
---|
| 100 | */
|
---|
| 101 | public static double YToLat(int aY, int aZoomlevel) {
|
---|
| 102 | aY += falseNorthing(aZoomlevel);
|
---|
[11376] | 103 | double latitude = (Math.PI / 2) - (2 * Math.atan(Math.exp(-1.0 * aY / radius(aZoomlevel))));
|
---|
[9095] | 104 | return -1 * Math.toDegrees(latitude);
|
---|
| 105 | }
|
---|
| 106 |
|
---|
| 107 | }
|
---|