/** * 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. * @param tileSize the tile size * @return the pixel X coordinate of the longitude value. */ public static double longitudeToPixelX(double longitude, byte zoomLevel, int tileSize) { long mapSize = getMapSize(zoomLevel, tileSize); return (longitude + 180) / 360 * mapSize; }
@Test public void getMapSizeTest() { for (int tileSize : TILE_SIZES) { for (byte zoomLevel = ZOOM_LEVEL_MIN; zoomLevel <= ZOOM_LEVEL_MAX; ++zoomLevel) { long factor = Math.round(MercatorProjection.zoomLevelToScaleFactor(zoomLevel)); Assert.assertEquals(tileSize * factor, MercatorProjection.getMapSize(zoomLevel, tileSize)); Assert.assertEquals(MercatorProjection.getMapSizeWithScaleFactor(MercatorProjection.zoomLevelToScaleFactor(zoomLevel), tileSize), MercatorProjection.getMapSize(zoomLevel, tileSize)); } verifyInvalidGetMapSize((byte) -1, tileSize); } }
/** * 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, byte zoomLevel, int tileSize) { double sinLatitude = Math.sin(latitude * (Math.PI / 180)); long mapSize = getMapSize(zoomLevel, tileSize); // FIXME improve this formula so that it works correctly without the clipping double pixelY = (0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI)) * mapSize; return Math.min(Math.max(0, pixelY), mapSize); }
@Test public void tileXToLongitudeTest() { for (int tileSize : TILE_SIZES) { for (byte zoomLevel = ZOOM_LEVEL_MIN; zoomLevel <= ZOOM_LEVEL_MAX; ++zoomLevel) { double longitude = MercatorProjection.tileXToLongitude(0, zoomLevel); Assert.assertEquals(LatLongUtils.LONGITUDE_MIN, longitude, 0); longitude = MercatorProjection.tileXToLongitudeWithScaleFactor(0, MercatorProjection.zoomLevelToScaleFactor(zoomLevel)); Assert.assertEquals(LatLongUtils.LONGITUDE_MIN, longitude, 0); long tileX = MercatorProjection.getMapSize(zoomLevel, tileSize) / tileSize; longitude = MercatorProjection.tileXToLongitude(tileX, zoomLevel); Assert.assertEquals(LatLongUtils.LONGITUDE_MAX, longitude, 0); tileX = MercatorProjection.getMapSizeWithScaleFactor(MercatorProjection.zoomLevelToScaleFactor(zoomLevel), tileSize) / tileSize; longitude = MercatorProjection.tileXToLongitudeWithScaleFactor(tileX, MercatorProjection.zoomLevelToScaleFactor(zoomLevel)); Assert.assertEquals(LatLongUtils.LONGITUDE_MAX, longitude, 0); } } }
/** * 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, byte zoomLevel) { return pixelYToLatitude(tileY * DUMMY_TILE_SIZE, getMapSize(zoomLevel, DUMMY_TILE_SIZE)); }
@Test public void tileYToLatitudeTest() { for (int tileSize : TILE_SIZES) { for (byte zoomLevel = ZOOM_LEVEL_MIN; zoomLevel <= ZOOM_LEVEL_MAX; ++zoomLevel) { double latitude = MercatorProjection.tileYToLatitude(0, zoomLevel); Assert.assertEquals(MercatorProjection.LATITUDE_MAX, latitude, 0); latitude = MercatorProjection.tileYToLatitudeWithScaleFactor(0, MercatorProjection.zoomLevelToScaleFactor(zoomLevel)); Assert.assertEquals(MercatorProjection.LATITUDE_MAX, latitude, 0); long tileY = MercatorProjection.getMapSize(zoomLevel, tileSize) / tileSize; latitude = MercatorProjection.tileYToLatitude(tileY, zoomLevel); Assert.assertEquals(MercatorProjection.LATITUDE_MIN, latitude, 0); tileY = MercatorProjection.getMapSizeWithScaleFactor(MercatorProjection.zoomLevelToScaleFactor(zoomLevel), tileSize) / tileSize; latitude = MercatorProjection.tileYToLatitudeWithScaleFactor(tileY, MercatorProjection.zoomLevelToScaleFactor(zoomLevel)); Assert.assertEquals(MercatorProjection.LATITUDE_MIN, latitude, 0); } } }
/** * 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, byte zoomLevel) { return pixelXToLongitude(tileX * DUMMY_TILE_SIZE, getMapSize(zoomLevel, DUMMY_TILE_SIZE)); }
private static double deltaLat(double deltaPixel, double lat, byte zoom, int tileSize) { long mapSize = MercatorProjection.getMapSize(zoom, tileSize); double pixelY = MercatorProjection.latitudeToPixelY(lat, mapSize); double lat2 = MercatorProjection.pixelYToLatitude(pixelY + deltaPixel, mapSize); return Math.abs(lat2 - lat); }
public static Point getTopLeftPoint(MapPosition mapPosition, Dimension canvasDimension, int tileSize) { LatLong centerPoint = mapPosition.latLong; int halfCanvasWidth = canvasDimension.width / 2; int halfCanvasHeight = canvasDimension.height / 2; long mapSize = MercatorProjection.getMapSize(mapPosition.zoomLevel, tileSize); double pixelX = Math.round(MercatorProjection.longitudeToPixelX(centerPoint.longitude, mapSize)); double pixelY = Math.round(MercatorProjection.latitudeToPixelY(centerPoint.latitude, mapSize)); return new Point((long) pixelX - halfCanvasWidth, (long) pixelY - halfCanvasHeight); }
/** * @return the non-negative radius of this circle in pixels. */ protected int getRadiusInPixels(double latitude, byte zoomLevel) { return (int) MercatorProjection.metersToPixels(this.radius, latitude, MercatorProjection.getMapSize(zoomLevel, displayModel.getTileSize())); }
void startAnimationMove(LatLong latLong) { // TODO is this properly synchronized? mapSize = MercatorProjection.getMapSize(zoomLevel, displayModel.getTileSize()); targetPixelX = MercatorProjection.longitudeToPixelX(latLong.longitude, mapSize); targetPixelY = MercatorProjection.latitudeToPixelY(latLong.latitude, mapSize); moveSteps = DEFAULT_MOVE_STEPS; synchronized (this) { notify(); } }
/** * The pivot point is the point the map zooms around. If the map zooms around its center null is returned, otherwise * the zoom-specific x/y pixel coordinates for the MercatorProjection (note: not the x/y coordinates for the map * view or the frame buffer, the MapViewPosition knows nothing about them). * * @param zoomLevel the zoomlevel to compute the x/y coordinates for * @return the x/y coordinates of the map pivot point if set or null otherwise. */ public synchronized Point getPivotXY(byte zoomLevel) { if (this.pivot != null) { return MercatorProjection.getPixel(this.pivot, MercatorProjection.getMapSize(zoomLevel, displayModel.getTileSize())); } return null; }
public static BoundingBox getBoundingBox(MapPosition mapPosition, Dimension canvasDimension, int tileSize) { long mapSize = MercatorProjection.getMapSize(mapPosition.zoomLevel, tileSize); double pixelX = MercatorProjection.longitudeToPixelX(mapPosition.latLong.longitude, mapSize); double pixelY = MercatorProjection.latitudeToPixelY(mapPosition.latLong.latitude, mapSize); int halfCanvasWidth = canvasDimension.width / 2; int halfCanvasHeight = canvasDimension.height / 2; double pixelXMin = Math.max(0, pixelX - halfCanvasWidth); double pixelYMin = Math.max(0, pixelY - halfCanvasHeight); double pixelXMax = Math.min(mapSize, pixelX + halfCanvasWidth); double pixelYMax = Math.min(mapSize, pixelY + halfCanvasHeight); double minLatitude = MercatorProjection.pixelYToLatitude(pixelYMax, mapSize); double minLongitude = MercatorProjection.pixelXToLongitude(pixelXMin, mapSize); double maxLatitude = MercatorProjection.pixelYToLatitude(pixelYMin, mapSize); double maxLongitude = MercatorProjection.pixelXToLongitude(pixelXMax, mapSize); return new BoundingBox(minLatitude, minLongitude, maxLatitude, maxLongitude); }
private static double calculatePriority(Tile tile, MapPosition mapPosition, int tileSize) { double tileLatitude = MercatorProjection.tileYToLatitude(tile.tileY, tile.zoomLevel); double tileLongitude = MercatorProjection.tileXToLongitude(tile.tileX, tile.zoomLevel); int halfTileSize = tileSize / 2; long mapSize = MercatorProjection.getMapSize(mapPosition.zoomLevel, tileSize); double tilePixelX = MercatorProjection.longitudeToPixelX(tileLongitude, mapSize) + halfTileSize; double tilePixelY = MercatorProjection.latitudeToPixelY(tileLatitude, mapSize) + halfTileSize; LatLong latLong = mapPosition.latLong; double mapPixelX = MercatorProjection.longitudeToPixelX(latLong.longitude, mapSize); double mapPixelY = MercatorProjection.latitudeToPixelY(latLong.latitude, mapSize); double diffPixel = Math.hypot(tilePixelX - mapPixelX, tilePixelY - mapPixelY); int diffZoom = Math.abs(tile.zoomLevel - mapPosition.zoomLevel); return diffPixel + PENALTY_PER_ZOOM_LEVEL * tileSize * diffZoom; }
private static void verifyInvalidGetMapSize(byte zoomLevel, int tileSize) { try { MercatorProjection.getMapSize(zoomLevel, tileSize); Assert.fail("zoomLevel: " + zoomLevel); } catch (IllegalArgumentException e) { Assert.assertTrue(true); } }
@Test public void metersToPixelTest() { for (int tileSize : TILE_SIZES) { Assert.assertTrue(MercatorProjection.metersToPixels(10, 10.0, MercatorProjection.getMapSize((byte) 1, tileSize)) < 1); Assert.assertTrue(MercatorProjection.metersToPixels((int) (40 * 10e7), 10.0, MercatorProjection.getMapSize((byte) 1, tileSize)) > 1); Assert.assertTrue(MercatorProjection.metersToPixels(10, 10.0, MercatorProjection.getMapSize((byte) 20, tileSize)) > 1); Assert.assertTrue(MercatorProjection.metersToPixels(10, 89.0, MercatorProjection.getMapSize((byte) 1, tileSize)) < 1); Assert.assertTrue(MercatorProjection.metersToPixels((int) (40 * 10e3), 50, MercatorProjection.getMapSize((byte) 10, tileSize)) > 1); } }
private static void verifyInvalidPixelXToLongitude(double pixelX, byte zoomLevel, int tileSize) { try { MercatorProjection.pixelXToLongitude(pixelX, MercatorProjection.getMapSize(zoomLevel, tileSize)); Assert.fail("pixelX: " + pixelX + ", zoomLevel: " + zoomLevel); } catch (IllegalArgumentException e) { Assert.assertTrue(true); } }
private static void verifyInvalidPixelYToLatitude(double pixelY, byte zoomLevel, int tileSize) { try { MercatorProjection.pixelYToLatitude(pixelY, MercatorProjection.getMapSize(zoomLevel, tileSize)); Assert.fail("pixelY: " + pixelY + ", zoomLevel: " + zoomLevel); } catch (IllegalArgumentException e) { Assert.assertTrue(true); } }
@Override public synchronized void draw(BoundingBox boundingBox, byte zoomLevel, Canvas canvas, Point topLeftPoint) { if (this.latLong == null || this.bitmap == null || this.bitmap.isDestroyed()) { return; } long mapSize = MercatorProjection.getMapSize(zoomLevel, this.displayModel.getTileSize()); double pixelX = MercatorProjection.longitudeToPixelX(this.latLong.longitude, mapSize); double pixelY = MercatorProjection.latitudeToPixelY(this.latLong.latitude, mapSize); int halfBitmapWidth = this.bitmap.getWidth() / 2; int halfBitmapHeight = this.bitmap.getHeight() / 2; int left = (int) (pixelX - topLeftPoint.x - halfBitmapWidth + this.horizontalOffset); int top = (int) (pixelY - topLeftPoint.y - halfBitmapHeight + this.verticalOffset); int right = left + this.bitmap.getWidth(); int bottom = top + this.bitmap.getHeight(); Rectangle bitmapRectangle = new Rectangle(left, top, right, bottom); Rectangle canvasRectangle = new Rectangle(0, 0, canvas.getWidth(), canvas.getHeight()); if (!canvasRectangle.intersects(bitmapRectangle)) { return; } canvas.drawBitmap(this.bitmap, left, top); }
@Test public void moveCenterTest() { MapViewPosition mapViewPosition = new MapViewPosition(new FixedTileSizeDisplayModel(256)); mapViewPosition.moveCenter( MercatorProjection.getMapSize((byte) 0, new FixedTileSizeDisplayModel(256).getTileSize()) / -360d, 0); MapPosition mapPosition = mapViewPosition.getMapPosition(); Assert.assertEquals(0, mapPosition.latLong.latitude, 0); Assert.assertEquals(1, mapPosition.latLong.longitude, 1.0E-14); Assert.assertEquals(0, mapPosition.zoomLevel); }