// License: WTFPL. For details, see LICENSE file. package iodb; import static org.openstreetmap.josm.tools.I18n.tr; import java.text.MessageFormat; import java.util.List; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.coor.EastNorth; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.imagery.OffsetBookmark; import org.openstreetmap.josm.data.projection.Projection; import org.openstreetmap.josm.gui.MapView; import org.openstreetmap.josm.gui.layer.AbstractTileSourceLayer; /** * Some common static methods for querying and processing imagery layers. * * @author Zverik * @license WTFPL */ public final class ImageryOffsetTools { /** * A title for all dialogs created in this plugin. */ public static final String DIALOG_TITLE = tr("Imagery Offset Database"); private ImageryOffsetTools() { // Hide default constructor for utilities classes } /** * Returns the topmost visible imagery layer. * @return the layer, or null if it hasn't been found. */ public static AbstractTileSourceLayer getTopImageryLayer() { if (Main.map == null || Main.map.mapView == null) return null; List<AbstractTileSourceLayer> layers = Main.getLayerManager().getLayersOfType(AbstractTileSourceLayer.class); for (AbstractTileSourceLayer layer : layers) { String url = layer.getInfo().getUrl(); if (layer.isVisible() && url != null && !url.contains("gps-")) { return layer; } } return null; } /** * Calculates the center of a visible map area. * @return the center point, or (0; 0) if there's no map on the screen. */ public static LatLon getMapCenter() { Projection proj = Main.getProjection(); return Main.map == null || Main.map.mapView == null ? new LatLon(0, 0) : proj.eastNorth2latlon(Main.map.mapView.getCenter()); } /** * Calculates an imagery layer offset. * @param center The center of a visible map area. * @return Coordinates of a point on the imagery which correspond to the * center point on the map. * @see #applyLayerOffset */ public static LatLon getLayerOffset(AbstractTileSourceLayer layer, LatLon center) { Projection proj = Main.getProjection(); EastNorth offsetCenter = Main.map.mapView.getCenter(); EastNorth centerOffset = offsetCenter.add(-layer.getDisplaySettings().getDx(), -layer.getDisplaySettings().getDy()); LatLon offsetLL = proj.eastNorth2latlon(centerOffset); return offsetLL; } /** * Applies the offset to the imagery layer. * @see #calculateOffset(iodb.ImageryOffset) * @see #getLayerOffset */ public static void applyLayerOffset(AbstractTileSourceLayer layer, ImageryOffset offset) { OffsetBookmark bookmark = calculateOffset(offset); layer.getDisplaySettings().setOffsetBookmark(bookmark); } /** * Calculate dx and dy for imagery offset. * @return An array of [dx, dy]. * @see #applyLayerOffset */ public static OffsetBookmark calculateOffset(ImageryOffset offset) { Projection proj = Main.getProjection(); EastNorth center = proj.latlon2eastNorth(offset.getPosition()); EastNorth offsetPos = proj.latlon2eastNorth(offset.getImageryPos()); EastNorth offsetXY = new EastNorth(center.getX() - offsetPos.getX(), center.getY() - offsetPos.getY()); OffsetBookmark b = new OffsetBookmark(proj.toCode(), offset.getImagery(), "Autogenerated", offsetXY.getX(), offsetXY.getY(), offset.getPosition().lon(), offset.getPosition().lat()); return b; } /** * Generate unique imagery identifier based on its type and URL. * @param layer imagery layer. * @return imagery id. */ public static String getImageryID(AbstractTileSourceLayer layer) { return layer == null ? null : ImageryIdGenerator.getImageryID(layer.getInfo().getUrl(), layer.getInfo().getImageryType()); } // Following three methods were snatched from TMSLayer private static double latToTileY(double lat, int zoom) { double l = lat / 180 * Math.PI; double pf = Math.log(Math.tan(l) + (1 / Math.cos(l))); return Math.pow(2.0, zoom - 1) * (Math.PI - pf) / Math.PI; } private static double lonToTileX(double lon, int zoom) { return Math.pow(2.0, zoom - 3) * (lon + 180.0) / 45.0; } public static int getCurrentZoom() { if (Main.map == null || Main.map.mapView == null) { return 1; } MapView mv = Main.map.mapView; LatLon topLeft = mv.getLatLon(0, 0); LatLon botRight = mv.getLatLon(mv.getWidth(), mv.getHeight()); double x1 = lonToTileX(topLeft.lon(), 1); double y1 = latToTileY(topLeft.lat(), 1); double x2 = lonToTileX(botRight.lon(), 1); double y2 = latToTileY(botRight.lat(), 1); int screenPixels = mv.getWidth() * mv.getHeight(); double tilePixels = Math.abs((y2 - y1) * (x2 - x1) * 256 * 256); if (screenPixels == 0 || tilePixels == 0) { return 1; } double factor = screenPixels / tilePixels; double result = Math.log(factor) / Math.log(2) / 2 + 1; int intResult = (int) Math.floor(result); return intResult; } /** * Converts distance in meters to a human-readable string. */ public static String formatDistance(double d) { // CHECKSTYLE.OFF: SingleSpaceSeparator if (d < 0.0095) return formatDistance(d * 1000, tr("mm"), true); if (d < 0.095) return formatDistance(d * 100, tr("cm"), true); if (d < 0.95) return formatDistance(d * 100, tr("cm"), false); if (d < 9.5) return formatDistance(d, tr("m"), true); if (d < 950) return formatDistance(d, tr("m"), false); if (d < 9500) return formatDistance(d / 1000, tr("km"), true); if (d < 1e6) return formatDistance(d / 1000, tr("km"), false); // CHECKSTYLE.ON: SingleSpaceSeparator return "\u221E"; } /** * Constructs a distance string. * @param d Distance. * @param si Units of measure for distance. * @param floating Whether a floating point is needed. * @return A formatted string. */ private static String formatDistance(double d, String si, boolean floating) { return MessageFormat.format(floating ? "{0,number,0.0} {1}" : "{0,number,0} {1}", d, si); } }