From 18a8b292d2440cba44d9383069daa28f1ebb2f6d Mon Sep 17 00:00:00 2001 From: Hannes Janetzek Date: Wed, 10 Apr 2013 21:40:07 +0200 Subject: [PATCH] use MapPosition.scale: get rid of zoomLevel relative functions in MercatorProjection --- src/org/oscim/core/MercatorProjection.java | 83 ++++--------------- .../oscim/database/mapfile/Projection.java | 68 +++++++++++++-- src/org/oscim/overlay/ItemizedOverlay.java | 36 ++++---- src/org/oscim/overlay/PathOverlay.java | 12 ++- 4 files changed, 104 insertions(+), 95 deletions(-) diff --git a/src/org/oscim/core/MercatorProjection.java b/src/org/oscim/core/MercatorProjection.java index 60142b1f..cda4b800 100644 --- a/src/org/oscim/core/MercatorProjection.java +++ b/src/org/oscim/core/MercatorProjection.java @@ -51,13 +51,13 @@ public final class MercatorProjection { * @param latitude * the latitude coordinate at which the resolution should be * calculated. - * @param zoomLevel - * the zoom level at which the resolution should be calculated. + * @param scale + * the map scale at which the resolution should be calculated. * @return the ground resolution at the given latitude and zoom level. */ - public static double calculateGroundResolution(double latitude, int zoomLevel) { + public static double calculateGroundResolution(double latitude, double scale) { return Math.cos(latitude * (Math.PI / 180)) * EARTH_CIRCUMFERENCE - / ((long) Tile.SIZE << zoomLevel); + / (Tile.SIZE * scale); } /** @@ -84,11 +84,23 @@ public final class MercatorProjection { * @return the position . */ public static double longitudeToX(double longitude) { - return (longitude + 180) / 360; + return (longitude + 180.0) / 360.0; } public static double toLongitude(double x) { - return 360 * (x - 0.5); + return 360.0 * (x - 0.5); + } + + public static PointD project(GeoPoint p, PointD reuse) { + if (reuse == null) + reuse = new PointD(); + + reuse.x = ((p.longitudeE6 / 1E6) + 180.0) / 360.0; + + double sinLatitude = Math.sin((p.latitudeE6 / 1E6) * (Math.PI / 180.0)); + reuse.y = 0.5 - Math.log((1.0 + sinLatitude) / (1.0 - sinLatitude)) / (4.0 * Math.PI); + + return reuse; } /** @@ -119,65 +131,6 @@ public final class MercatorProjection { return longitude; } - /** - * Converts a pixel X coordinate at a certain zoom level to a longitude - * coordinate. - * - * @param pixelX - * the pixel X coordinate that should be converted. - * @param zoomLevel - * the zoom level at which the coordinate should be converted. - * @return the longitude value of the pixel X coordinate. - */ - public static double pixelXToLongitude(double pixelX, int zoomLevel) { - return 360 * ((pixelX / ((long) Tile.SIZE << zoomLevel)) - 0.5); - } - - /** - * 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.SIZE << zoomLevel); - } - - /** - * Converts a pixel Y coordinate at a certain zoom level to a latitude - * coordinate. - * - * @param pixelY - * the pixel Y coordinate that should be converted. - * @param zoomLevel - * the zoom level at which the coordinate should be converted. - * @return the latitude value of the pixel Y coordinate. - */ - public static double pixelYToLatitude(double pixelY, int zoomLevel) { - double y = 0.5 - (pixelY / ((long) Tile.SIZE << zoomLevel)); - return 90 - 360 * Math.atan(Math.exp(-y * (2 * Math.PI))) / Math.PI; - } - - /** - * 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.SIZE << zoomLevel); - } - private MercatorProjection() { } } diff --git a/src/org/oscim/database/mapfile/Projection.java b/src/org/oscim/database/mapfile/Projection.java index 991c4faa..0d48fedb 100644 --- a/src/org/oscim/database/mapfile/Projection.java +++ b/src/org/oscim/database/mapfile/Projection.java @@ -14,7 +14,6 @@ */ package org.oscim.database.mapfile; -import org.oscim.core.MercatorProjection; import org.oscim.core.Tile; public class Projection { @@ -31,7 +30,7 @@ public class Projection { * @return the longitude value of the tile X number. */ public static double tileXToLongitude(long tileX, int zoomLevel) { - return MercatorProjection.pixelXToLongitude(tileX * Tile.SIZE, zoomLevel); + return pixelXToLongitude(tileX * Tile.SIZE, zoomLevel); } /** @@ -45,7 +44,7 @@ public class Projection { * @return the latitude value of the tile Y number. */ public static double tileYToLatitude(long tileY, int zoomLevel) { - return MercatorProjection.pixelYToLatitude(tileY * Tile.SIZE, zoomLevel); + return pixelYToLatitude(tileY * Tile.SIZE, zoomLevel); } /** @@ -59,7 +58,7 @@ public class Projection { * @return the tile Y number of the latitude value. */ public static long latitudeToTileY(double latitude, int zoomLevel) { - return pixelYToTileY(MercatorProjection.latitudeToPixelY(latitude, zoomLevel), zoomLevel); + return pixelYToTileY(latitudeToPixelY(latitude, zoomLevel), zoomLevel); } /** @@ -73,7 +72,7 @@ public class Projection { * @return the tile X number of the longitude value. */ public static long longitudeToTileX(double longitude, int zoomLevel) { - return pixelXToTileX(MercatorProjection.longitudeToPixelX(longitude, zoomLevel), zoomLevel); + return pixelXToTileX(longitudeToPixelX(longitude, zoomLevel), zoomLevel); } /** @@ -102,6 +101,65 @@ public class Projection { return (int) Math.min(Math.max(pixelY / Tile.SIZE, 0), Math.pow(2, zoomLevel) - 1); } + + /** + * Converts a pixel X coordinate at a certain zoom level to a longitude + * coordinate. + * + * @param pixelX + * the pixel X coordinate that should be converted. + * @param zoomLevel + * the zoom level at which the coordinate should be converted. + * @return the longitude value of the pixel X coordinate. + */ + public static double pixelXToLongitude(double pixelX, int zoomLevel) { + return 360 * ((pixelX / ((long) Tile.SIZE << zoomLevel)) - 0.5); + } + + /** + * 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.SIZE << zoomLevel); + } + + /** + * Converts a pixel Y coordinate at a certain zoom level to a latitude + * coordinate. + * + * @param pixelY + * the pixel Y coordinate that should be converted. + * @param zoomLevel + * the zoom level at which the coordinate should be converted. + * @return the latitude value of the pixel Y coordinate. + */ + public static double pixelYToLatitude(double pixelY, int zoomLevel) { + double y = 0.5 - (pixelY / ((long) Tile.SIZE << zoomLevel)); + return 90 - 360 * Math.atan(Math.exp(-y * (2 * Math.PI))) / Math.PI; + } + + /** + * 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.SIZE << zoomLevel); + } private Projection(){ } diff --git a/src/org/oscim/overlay/ItemizedOverlay.java b/src/org/oscim/overlay/ItemizedOverlay.java index d378dbe9..e4f7f70e 100644 --- a/src/org/oscim/overlay/ItemizedOverlay.java +++ b/src/org/oscim/overlay/ItemizedOverlay.java @@ -21,15 +21,14 @@ package org.oscim.overlay; // - and to make this work for multiple overlays // a global scenegraph is probably required. -import org.oscim.core.GeoPoint; import org.oscim.core.MapPosition; import org.oscim.core.MercatorProjection; +import org.oscim.core.PointD; import org.oscim.core.Tile; import org.oscim.overlay.OverlayItem.HotspotPlace; import org.oscim.renderer.GLRenderer.Matrices; import org.oscim.renderer.layer.SymbolLayer; import org.oscim.renderer.overlays.BasicOverlay; -import org.oscim.utils.FastMath; import org.oscim.view.MapView; import android.content.res.Resources; @@ -73,8 +72,9 @@ public abstract class ItemizedOverlay extends Overlay private int mSize; - // pre-projected points to zoomlovel 18 - private static final byte MAX_ZOOM = 18; + // pre-projected points to zoomlevel 20 + private static final byte MAX_ZOOM = 20; + private final double MAX_SCALE; class ItemOverlay extends BasicOverlay { @@ -97,12 +97,7 @@ public abstract class ItemizedOverlay extends Overlay mUpdate = false; - //int mx = (int) curPos.x; - //int my = (int) curPos.y; - - //int z = curPos.zoomLevel; - - int z = FastMath.log2((int) curPos.scale); + int z = curPos.zoomLevel; int diff = MAX_ZOOM - z; int mx = (int) (curPos.x * (Tile.SIZE << z)); @@ -177,14 +172,7 @@ public abstract class ItemizedOverlay extends Overlay // updateMapPosition(); mMapPosition.copy(curPos); - //mMapPosition.x = curPos.x; - //mMapPosition.y = curPos.y; - //mMapPosition.zoomLevel = curPos.zoomLevel; - //mMapPosition.scale = curPos.scale; - //mMapPosition.angle = curPos.angle; - - // items are placed relative to scale == 1 - // mMapPosition.scale = 1; + // items are placed relative to zoomLevel mMapPosition.scale = 1 << z; layers.clear(); @@ -251,8 +239,12 @@ public abstract class ItemizedOverlay extends Overlay this.mDefaultMarker = pDefaultMarker; mLayer = new ItemOverlay(mapView); + + MAX_SCALE = (1 << MAX_ZOOM) * Tile.SIZE; } + private final PointD mMapPoint = new PointD(); + /** * Utility method to perform all processing on a new ItemizedOverlay. * Subclasses provide Items through the createItem(int) method. The subclass @@ -286,9 +278,11 @@ public abstract class ItemizedOverlay extends Overlay it.item = createItem(a); // pre-project points - GeoPoint p = it.item.mGeoPoint; - it.px = (int) MercatorProjection.longitudeToPixelX(p.getLongitude(), MAX_ZOOM); - it.py = (int) MercatorProjection.latitudeToPixelY(p.getLatitude(), MAX_ZOOM); + MercatorProjection.project(it.item.mGeoPoint, mMapPoint); + it.px = (int) (mMapPoint.x * MAX_SCALE); + it.py = (int) (mMapPoint.y * MAX_SCALE); + // it.px = (int) MercatorProjection.longitudeToPixelX(p.getLongitude(), MAX_ZOOM); + // it.py = (int) MercatorProjection.latitudeToPixelY(p.getLatitude(), MAX_ZOOM); } mUpdate = true; } diff --git a/src/org/oscim/overlay/PathOverlay.java b/src/org/oscim/overlay/PathOverlay.java index a3317905..a83f5149 100644 --- a/src/org/oscim/overlay/PathOverlay.java +++ b/src/org/oscim/overlay/PathOverlay.java @@ -22,6 +22,7 @@ import java.util.List; import org.oscim.core.GeoPoint; import org.oscim.core.MapPosition; import org.oscim.core.MercatorProjection; +import org.oscim.core.PointD; import org.oscim.core.Tile; import org.oscim.renderer.GLRenderer.Matrices; import org.oscim.renderer.layer.Layer; @@ -48,10 +49,12 @@ public class PathOverlay extends Overlay { class RenderPath extends BasicOverlay { private static final byte MAX_ZOOM = 20; + private final double MAX_SCALE; private static final int MIN_DIST = 4; // pre-projected points to zoomlovel 20 private int[] mPreprojected; + private final PointD mMapPoint; // projected points private float[] mPPoints; @@ -68,6 +71,8 @@ public class PathOverlay extends Overlay { mLine = new Line(Color.BLUE, 3.0f, Cap.BUTT); mIndex = new short[1]; mPPoints = new float[1]; + mMapPoint = new PointD(); + MAX_SCALE = (1 << MAX_ZOOM) * Tile.SIZE; } // note: this is called from GL-Thread. so check your syncs! @@ -99,10 +104,9 @@ public class PathOverlay extends Overlay { for (int i = 0, j = 0; i < size; i++, j += 2) { GeoPoint p = geopoints.get(i); - points[j + 0] = (int) MercatorProjection.longitudeToPixelX( - p.getLongitude(), MAX_ZOOM); - points[j + 1] = (int) MercatorProjection.latitudeToPixelY( - p.getLatitude(), MAX_ZOOM); + MercatorProjection.project(p, mMapPoint); + points[j + 0] = (int) (mMapPoint.x * MAX_SCALE); + points[j + 1] = (int) (mMapPoint.y * MAX_SCALE); } } }