001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.layer.imagery;
003
004import java.awt.geom.Point2D;
005import java.awt.geom.Rectangle2D;
006
007import org.openstreetmap.gui.jmapviewer.Tile;
008import org.openstreetmap.gui.jmapviewer.TileXY;
009import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
010import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
011import org.openstreetmap.josm.data.coor.LatLon;
012import org.openstreetmap.josm.data.projection.Projecting;
013import org.openstreetmap.josm.data.projection.ShiftedProjecting;
014import org.openstreetmap.josm.gui.MapView;
015import org.openstreetmap.josm.gui.MapViewState.MapViewPoint;
016
017/**
018 * This class handles tile coordinate management and computes their position in the map view.
019 * @author Michael Zangl
020 * @since 10651
021 */
022public class TileCoordinateConverter {
023    private final MapView mapView;
024    private final TileSourceDisplaySettings settings;
025    private final TileSource tileSource;
026
027    /**
028     * Create a new coordinate converter for the map view.
029     * @param mapView The map view.
030     * @param tileSource The tile source to use when converting coordinates.
031     * @param settings displacement settings.
032     */
033    public TileCoordinateConverter(MapView mapView, TileSource tileSource, TileSourceDisplaySettings settings) {
034        this.mapView = mapView;
035        this.tileSource = tileSource;
036        this.settings = settings;
037    }
038
039    private MapViewPoint pos(ICoordinate ll) {
040        return mapView.getState().getPointFor(new LatLon(ll)).add(settings.getDisplacement());
041    }
042
043    /**
044     * Gets the projecting instance to use to convert between latlon and eastnorth coordinates.
045     * @return The {@link Projecting} instance.
046     */
047    public Projecting getProjecting() {
048        return new ShiftedProjecting(mapView.getProjection(), settings.getDisplacement());
049    }
050
051    /**
052     * Gets the top left position of the tile inside the map view.
053     * @param tile The tile
054     * @return The positon.
055     */
056    public Point2D getPixelForTile(Tile tile) {
057        ICoordinate coord = tile.getTileSource().tileXYToLatLon(tile);
058        return pos(coord).getInView();
059    }
060
061    /**
062     * Gets the position of the tile inside the map view.
063     * @param tile The tile
064     * @return The positon.
065     */
066    public Rectangle2D getRectangleForTile(Tile tile) {
067        ICoordinate c1 = tile.getTileSource().tileXYToLatLon(tile);
068        ICoordinate c2 = tile.getTileSource().tileXYToLatLon(tile.getXtile() + 1, tile.getYtile() + 1, tile.getZoom());
069
070        return pos(c1).rectTo(pos(c2)).getInView();
071    }
072
073    /**
074     * Returns average number of screen pixels per tile pixel for current mapview
075     * @param zoom zoom level
076     * @return average number of screen pixels per tile pixel
077     */
078    public double getScaleFactor(int zoom) {
079        LatLon topLeft = mapView.getLatLon(0, 0);
080        LatLon botRight = mapView.getLatLon(mapView.getWidth(), mapView.getHeight());
081        TileXY t1 = tileSource.latLonToTileXY(topLeft.toCoordinate(), zoom);
082        TileXY t2 = tileSource.latLonToTileXY(botRight.toCoordinate(), zoom);
083
084        int screenPixels = mapView.getWidth()*mapView.getHeight();
085        double tilePixels = Math.abs((t2.getY()-t1.getY())*(t2.getX()-t1.getX())*tileSource.getTileSize()*tileSource.getTileSize());
086        if (screenPixels == 0 || tilePixels == 0) return 1;
087        return screenPixels/tilePixels;
088    }
089}