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) {
|
---|
23 | return (TILE_SIZE * (1 << aZoomlevel)) / (2.0 * Math.PI);
|
---|
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) {
|
---|
34 | return TILE_SIZE * (1 << aZoomlevel);
|
---|
35 | }
|
---|
36 |
|
---|
37 | public static int falseEasting(int aZoomlevel) {
|
---|
38 | return getMaxPixels(aZoomlevel) / 2;
|
---|
39 | }
|
---|
40 |
|
---|
41 | public static int falseNorthing(int aZoomlevel) {
|
---|
42 | return (-1 * getMaxPixels(aZoomlevel) / 2);
|
---|
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);
|
---|
54 | int x = (int) ((radius(aZoomlevel) * longitude) + falseEasting(aZoomlevel));
|
---|
55 | x = Math.min(x, getMaxPixels(aZoomlevel) - 1);
|
---|
56 | return x;
|
---|
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);
|
---|
72 | int y = (int) (-1
|
---|
73 | * (radius(aZoomlevel) / 2.0 * Math.log((1.0 + Math.sin(latitude)) / (1.0 - Math.sin(latitude)))) - falseNorthing(aZoomlevel));
|
---|
74 | y = Math.min(y, getMaxPixels(aZoomlevel) - 1);
|
---|
75 | return y;
|
---|
76 | }
|
---|
77 |
|
---|
78 | /**
|
---|
79 | * Transforms pixel coordinate X to longitude
|
---|
80 | *
|
---|
81 | * @param aX
|
---|
82 | * [0..2^Zoomlevel*TILE_WIDTH[
|
---|
83 | * @return ]-180..180[
|
---|
84 | */
|
---|
85 | public static double XToLon(int aX, int aZoomlevel) {
|
---|
86 | aX -= falseEasting(aZoomlevel);
|
---|
87 | double longRadians = aX / radius(aZoomlevel);
|
---|
88 | double longDegrees = Math.toDegrees(longRadians);
|
---|
89 | return longDegrees;
|
---|
90 | }
|
---|
91 |
|
---|
92 | /**
|
---|
93 | * Transforms pixel coordinate Y to latitude
|
---|
94 | *
|
---|
95 | * @param aY
|
---|
96 | * [0..2^Zoomlevel*TILE_WIDTH[
|
---|
97 | * @return [MIN_LAT..MAX_LAT] is about [-85..85]
|
---|
98 | */
|
---|
99 | public static double YToLat(int aY, int aZoomlevel) {
|
---|
100 | aY += falseNorthing(aZoomlevel);
|
---|
101 | double latitude = (Math.PI / 2) - (2 * Math.atan(Math.exp(-1.0 * aY / radius(aZoomlevel))));
|
---|
102 | return -1 * Math.toDegrees(latitude);
|
---|
103 | }
|
---|
104 |
|
---|
105 | }
|
---|