001// License: GPL. For details, see Readme.txt file.
002package org.openstreetmap.gui.jmapviewer.tilesources;
003
004import java.awt.Point;
005
006import org.openstreetmap.gui.jmapviewer.Coordinate;
007import org.openstreetmap.gui.jmapviewer.OsmMercator;
008import org.openstreetmap.gui.jmapviewer.Projected;
009import org.openstreetmap.gui.jmapviewer.Tile;
010import org.openstreetmap.gui.jmapviewer.TileRange;
011import org.openstreetmap.gui.jmapviewer.TileXY;
012import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
013import org.openstreetmap.gui.jmapviewer.interfaces.IProjected;
014
015/**
016 * TMS tile source.
017 */
018public class TMSTileSource extends AbstractTMSTileSource {
019
020    protected int maxZoom;
021    protected int minZoom;
022    protected OsmMercator osmMercator;
023
024    /**
025     * Constructs a new {@code TMSTileSource}.
026     * @param info tile source information
027     */
028    public TMSTileSource(TileSourceInfo info) {
029        super(info);
030        minZoom = info.getMinZoom();
031        maxZoom = info.getMaxZoom();
032        this.osmMercator = new OsmMercator(this.getTileSize());
033    }
034
035    @Override
036    public int getMinZoom() {
037        return (minZoom == 0) ? super.getMinZoom() : minZoom;
038    }
039
040    @Override
041    public int getMaxZoom() {
042        return (maxZoom == 0) ? super.getMaxZoom() : maxZoom;
043    }
044
045    @Override
046    public double getDistance(double lat1, double lon1, double lat2, double lon2) {
047        return osmMercator.getDistance(lat1, lon1, lat2, lon2);
048    }
049
050    @Override
051    public Point latLonToXY(double lat, double lon, int zoom) {
052        return new Point(
053                (int) Math.round(osmMercator.lonToX(lon, zoom)),
054                (int) Math.round(osmMercator.latToY(lat, zoom))
055                );
056    }
057
058    @Override
059    public ICoordinate xyToLatLon(int x, int y, int zoom) {
060        return new Coordinate(
061                osmMercator.yToLat(y, zoom),
062                osmMercator.xToLon(x, zoom)
063                );
064    }
065
066    @Override
067    public TileXY latLonToTileXY(double lat, double lon, int zoom) {
068        return new TileXY(
069                osmMercator.lonToX(lon, zoom) / getTileSize(),
070                osmMercator.latToY(lat, zoom) / getTileSize()
071                );
072    }
073
074    @Override
075    public ICoordinate tileXYToLatLon(int x, int y, int zoom) {
076        return new Coordinate(
077                osmMercator.yToLat(y * getTileSize(), zoom),
078                osmMercator.xToLon(x * getTileSize(), zoom)
079                );
080    }
081
082    @Override
083    public IProjected tileXYtoProjected(int x, int y, int zoom) {
084        double mercatorWidth = 2 * Math.PI * OsmMercator.EARTH_RADIUS;
085        double f = mercatorWidth * getTileSize() / osmMercator.getMaxPixels(zoom);
086        return new Projected(f * x - mercatorWidth / 2, -(f * y - mercatorWidth / 2));
087    }
088
089    @Override
090    public TileXY projectedToTileXY(IProjected p, int zoom) {
091        double mercatorWidth = 2 * Math.PI * OsmMercator.EARTH_RADIUS;
092        double f = mercatorWidth * getTileSize() / osmMercator.getMaxPixels(zoom);
093        return new TileXY((p.getEast() + mercatorWidth / 2) / f, (-p.getNorth() + mercatorWidth / 2) / f);
094    }
095
096    @Override
097    public boolean isInside(Tile inner, Tile outer) {
098        int dz = inner.getZoom() - outer.getZoom();
099        if (dz < 0) return false;
100        return outer.getXtile() == inner.getXtile() >> dz &&
101                outer.getYtile() == inner.getYtile() >> dz;
102    }
103
104    @Override
105    public TileRange getCoveringTileRange(Tile tile, int newZoom) {
106        if (newZoom <= tile.getZoom()) {
107            int dz = tile.getZoom() - newZoom;
108            TileXY xy = new TileXY(tile.getXtile() >> dz, tile.getYtile() >> dz);
109            return new TileRange(xy, xy, newZoom);
110        } else {
111            int dz = newZoom - tile.getZoom();
112            TileXY t1 = new TileXY(tile.getXtile() << dz, tile.getYtile() << dz);
113            TileXY t2 = new TileXY(t1.getX() + (1 << dz) - 1, t1.getY() + (1 << dz) - 1);
114            return new TileRange(t1, t2, newZoom);
115        }
116    }
117
118    @Override
119    public String getServerCRS() {
120        return "EPSG:3857";
121    }
122}