-use absolute x/y position and scale in MapPosition

- scale calculations look much nicer now, better always
   use 'double' unless you are sure about precision required
- finally got rid of zoomLevel relative coordinates
- cleanup MapPosition and MercatorProjection API functions
This commit is contained in:
Hannes Janetzek
2013-04-07 15:58:45 +02:00
parent a6a729244f
commit 8e01dce85e
29 changed files with 658 additions and 710 deletions

View File

@@ -15,78 +15,73 @@
*/
package org.oscim.core;
import org.oscim.utils.FastMath;
/** A MapPosition Container. */
public class MapPosition {
public final static int MAX_ZOOMLEVEL = 20;
public final static int MIN_ZOOMLEVEL = 2;
public double lon;
public double lat;
/** projected position x 0..1 */
public double x;
/** projected position y 0..1 */
public double y;
/** absolute scale */
public double scale;
public double absX;
public double absY;
public double absScale;
public float scale;
/** rotation angle */
public float angle;
/** perspective tile */
public float tilt;
// map center in tile coordinates of current zoom-level
public double x;
public double y;
// to be removed
// FastMath.log2((int) scale)
public int zoomLevel;
public MapPosition() {
this.zoomLevel = (byte) 1;
this.scale = 1;
this.lat = 0;
this.lon = 0;
this.x = 0.5;
this.y = 0.5;
this.zoomLevel = 1;
this.angle = 0;
this.x = MercatorProjection.longitudeToPixelX(this.lon, zoomLevel);
this.y = MercatorProjection.latitudeToPixelY(this.lat, zoomLevel);
}
/**
* @param geoPoint
* the map position.
* @param zoomLevel
* the zoom level.
* @param scale
* ...
*/
public MapPosition(GeoPoint geoPoint, byte zoomLevel, float scale) {
public void setZoomLevel(int zoomLevel) {
this.zoomLevel = zoomLevel;
this.scale = scale;
this.lat = geoPoint.getLatitude();
this.lon = geoPoint.getLongitude();
this.angle = 0;
this.x = MercatorProjection.longitudeToPixelX(this.lon, zoomLevel);
this.y = MercatorProjection.latitudeToPixelY(this.lat, zoomLevel);
this.scale = 1 << zoomLevel;
}
public MapPosition(double latitude, double longitude, int zoomLevel, float scale,
float angle) {
this.zoomLevel = zoomLevel;
public void setScale(double scale) {
this.zoomLevel = FastMath.log2((int) scale);
this.scale = scale;
this.lat = latitude;
this.lon = longitude;
this.angle = angle;
this.x = MercatorProjection.longitudeToPixelX(longitude, zoomLevel);
this.y = MercatorProjection.latitudeToPixelY(latitude, zoomLevel);
}
public void setPosition(GeoPoint geoPoint){
setPosition(geoPoint.getLatitude(), geoPoint.getLongitude());
}
public void setPosition(double latitude, double longitude) {
latitude = MercatorProjection.limitLatitude(latitude);
longitude = MercatorProjection.limitLongitude(longitude);
this.x = MercatorProjection.longitudeToX(longitude);
this.y = MercatorProjection.latitudeToY(latitude);
}
public void copy(MapPosition other) {
this.zoomLevel = other.zoomLevel;
this.scale = other.scale;
this.lat = other.lat;
this.lon = other.lon;
this.angle = other.angle;
this.scale = other.scale;
this.x = other.x;
this.y = other.y;
}
public void setFromLatLon(double latitude, double longitude, int zoomLevel){
this.zoomLevel = zoomLevel;
this.x = MercatorProjection.longitudeToPixelX(longitude, zoomLevel);
this.y = MercatorProjection.latitudeToPixelY(latitude, zoomLevel);
public double getZoomScale() {
return scale / (1 << zoomLevel);
}
public GeoPoint getGeoPoint() {
return new GeoPoint(MercatorProjection.toLatitude(y),
MercatorProjection.toLongitude(x));
}
@Override
@@ -94,11 +89,11 @@ public class MapPosition {
StringBuilder builder = new StringBuilder();
builder.append("MapPosition [");
builder.append("lat=");
builder.append(this.lat);
builder.append(MercatorProjection.toLatitude(y));
builder.append(", lon=");
builder.append(this.lon);
builder.append(MercatorProjection.toLongitude(x));
builder.append(", zoomLevel=");
builder.append(this.zoomLevel);
builder.append(zoomLevel);
builder.append("]");
return builder.toString();
}

View File

@@ -15,7 +15,6 @@
*/
package org.oscim.core;
/**
* An implementation of the spherical Mercator projection.
*/
@@ -61,28 +60,6 @@ public final class MercatorProjection {
/ ((long) Tile.TILE_SIZE << zoomLevel);
}
/**
* Converts a latitude coordinate (in degrees) to a pixel Y coordinate at a
* certain zoom level.
*
* @param latitude
* the latitude coordinate that should be converted.
* @param zoomLevel
* the zoom level at which the coordinate should be converted.
* @return the pixel Y coordinate of the latitude value.
*/
public static double latitudeToPixelY(double latitude, int zoomLevel) {
double sinLatitude = Math.sin(latitude * (Math.PI / 180));
return (0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI))
* ((long) Tile.TILE_SIZE << zoomLevel);
}
public static double latitudeToPixelY(MapPosition mapPosition) {
double sinLatitude = Math.sin(mapPosition.lat * (Math.PI / 180));
return (0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI))
* ((long) Tile.TILE_SIZE << mapPosition.zoomLevel);
}
/**
* Projects a longitude coordinate (in degrees) to the range [0.0,1.0]
*
@@ -95,18 +72,23 @@ public final class MercatorProjection {
return 0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);
}
public static double toLatitude(double y) {
return 90 - 360 * Math.atan(Math.exp((y - 0.5) * (2 * Math.PI))) / Math.PI;
}
/**
* Converts a latitude coordinate (in degrees) to a tile Y number at a
* certain zoom level.
* Projects a longitude coordinate (in degrees) to the range [0.0,1.0]
*
* @param latitude
* the latitude coordinate that should be converted.
* @param zoomLevel
* the zoom level at which the coordinate should be converted.
* @return the tile Y number of the latitude value.
* @param longitude
* the longitude coordinate that should be converted.
* @return the position .
*/
public static long latitudeToTileY(double latitude, int zoomLevel) {
return pixelYToTileY(latitudeToPixelY(latitude, zoomLevel), zoomLevel);
public static double longitudeToX(double longitude) {
return (longitude + 180) / 360;
}
public static double toLongitude(double x) {
return 360 * (x - 0.5);
}
/**
@@ -135,51 +117,6 @@ public final class MercatorProjection {
return Math.max(Math.min(longitude - 360, LONGITUDE_MAX), LONGITUDE_MIN);
return longitude;
}
/**
* Converts a longitude coordinate (in degrees) to a pixel X coordinate at a
* certain zoom level.
*
* @param longitude
* the longitude coordinate that should be converted.
* @param zoomLevel
* the zoom level at which the coordinate should be converted.
* @return the pixel X coordinate of the longitude value.
*/
public static double longitudeToPixelX(double longitude,int zoomLevel) {
return (longitude + 180) / 360 * ((long) Tile.TILE_SIZE << zoomLevel);
}
public static double longitudeToPixelX(MapPosition mapPosition) {
return (mapPosition.lon + 180) / 360
* ((long) Tile.TILE_SIZE << mapPosition.zoomLevel);
}
/**
* Projects a longitude coordinate (in degrees) to the range [0.0,1.0]
*
* @param longitude
* the longitude coordinate that should be converted.
* @return the position .
*/
public static double longitudeToX(double longitude) {
return (longitude + 180) / 360;
}
/**
* Converts a longitude coordinate (in degrees) to the tile X number at a
* certain zoom level.
*
* @param longitude
* the longitude coordinate that should be converted.
* @param zoomLevel
* the zoom level at which the coordinate should be converted.
* @return the tile X number of the longitude value.
*/
public static long longitudeToTileX(double longitude, int zoomLevel) {
return pixelXToTileX(longitudeToPixelX(longitude, zoomLevel), zoomLevel);
}
/**
@@ -196,25 +133,18 @@ public final class MercatorProjection {
return 360 * ((pixelX / ((long) Tile.TILE_SIZE << zoomLevel)) - 0.5);
}
public static double toLongitude(double pixelX) {
return 360 * (pixelX - 0.5);
}
public static double toLongitude(double pixelX, double scale) {
return 360 * ((pixelX / scale) - 0.5);
}
/**
* Converts a pixel X coordinate to the tile X number.
* Converts a longitude coordinate (in degrees) to a pixel X coordinate at a
* certain zoom level.
*
* @param pixelX
* the pixel X coordinate that should be converted.
* @param longitude
* the longitude coordinate that should be converted.
* @param zoomLevel
* the zoom level at which the coordinate should be converted.
* @return the tile X number.
* @return the pixel X coordinate of the longitude value.
*/
public static int pixelXToTileX(double pixelX, int zoomLevel) {
return (int) Math.min(Math.max(pixelX / Tile.TILE_SIZE, 0),
Math.pow(2, zoomLevel) - 1);
public static double longitudeToPixelX(double longitude, int zoomLevel) {
return (longitude + 180) / 360 * ((long) Tile.TILE_SIZE << zoomLevel);
}
/**
@@ -232,69 +162,22 @@ public final class MercatorProjection {
return 90 - 360 * Math.atan(Math.exp(-y * (2 * Math.PI))) / Math.PI;
}
public static double toLatitude(double pixelY) {
double y = 0.5 - pixelY;
return 90 - 360 * Math.atan(Math.exp(-y * (2 * Math.PI))) / Math.PI;
}
public static double toLatitude(double pixelY, double scale) {
double y = 0.5 - pixelY / scale;
return 90 - 360 * Math.atan(Math.exp(-y * (2 * Math.PI))) / Math.PI;
}
/**
* Converts a pixel Y coordinate to the tile Y number.
* Converts a latitude coordinate (in degrees) to a pixel Y coordinate at a
* certain zoom level.
*
* @param pixelY
* the pixel Y coordinate that should be converted.
* @param latitude
* the latitude coordinate that should be converted.
* @param zoomLevel
* the zoom level at which the coordinate should be converted.
* @return the tile Y number.
* @return the pixel Y coordinate of the latitude value.
*/
public static int pixelYToTileY(double pixelY, int zoomLevel) {
return (int) Math.min(Math.max(pixelY / Tile.TILE_SIZE, 0),
Math.pow(2, zoomLevel) - 1);
}
/**
* Converts a tile X number at a certain zoom level to a longitude
* coordinate.
*
* @param tileX
* the tile X number that should be converted.
* @param zoomLevel
* the zoom level at which the number should be converted.
* @return the longitude value of the tile X number.
*/
public static double tileXToLongitude(long tileX, int zoomLevel) {
return pixelXToLongitude(tileX * Tile.TILE_SIZE, zoomLevel);
}
/**
* Converts a tile Y number at a certain zoom level to a latitude
* coordinate.
*
* @param tileY
* the tile Y number that should be converted.
* @param zoomLevel
* the zoom level at which the number should be converted.
* @return the latitude value of the tile Y number.
*/
public static double tileYToLatitude(long tileY, int zoomLevel) {
return pixelYToLatitude(tileY * Tile.TILE_SIZE, zoomLevel);
public static double latitudeToPixelY(double latitude, int zoomLevel) {
double sinLatitude = Math.sin(latitude * (Math.PI / 180));
return (0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI))
* ((long) Tile.TILE_SIZE << zoomLevel);
}
private MercatorProjection() {
throw new IllegalStateException();
}
// public static Point projectPoint(GeoPoint geopoint, int z, Point reuse) {
// Point out = reuse == null ? new Point() : reuse;
//
// out.x = (int) MercatorProjection.longitudeToPixelX(geopoint.getLongitude(), z);
// out.y = (int) MercatorProjection.latitudeToPixelY(geopoint.getLatitude(), z);
//
// return out;
// }
}

View File

@@ -41,15 +41,6 @@ public class Tile {
*/
public final byte zoomLevel;
/**
* the pixel X coordinate of the upper left corner of this tile.
*/
public final long pixelX;
/**
* the pixel Y coordinate of the upper left corner of this tile.
*/
public final long pixelY;
/**
* @param tileX
* the X number of the tile.
@@ -61,8 +52,6 @@ public class Tile {
public Tile(int tileX, int tileY, byte zoomLevel) {
this.tileX = tileX;
this.tileY = tileY;
this.pixelX = this.tileX * TILE_SIZE;
this.pixelY = this.tileY * TILE_SIZE;
this.zoomLevel = zoomLevel;
}