package org.syzygy.gps;
import java.io.IOException;
/**
* This class was written by Stephen Crane (jscrane@gmail.com)
* and is released under the terms of the GNU GPL
* (http://www.gnu.org/licenses/gpl.html).
*/
public abstract class CoordinateMapper
{
private final int tileSize;
private final int maxZoom;
private final MercatorProjection projection;
private MapCache maps;
protected CoordinateMapper(int tileSize, int maxZoom)
{
this.tileSize = tileSize;
this.maxZoom = maxZoom;
this.projection = new MercatorProjection(tileSize, maxZoom);
}
public void setMapCache(MapCache maps)
{
this.maps = maps;
}
public int getScreenY(Tile tile, double latitude, int height)
{
double y = projection.mapLatitude(latitude, tile.getZoom());
return (int) ((y - tile.getTileY()) * (double) height);
}
public int getScreenX(Tile tile, double longitude, int width)
{
double x = projection.mapLongitude(longitude, tile.getZoom());
return (int) ((x - tile.getTileX()) * (double) width);
}
public double getLatitude(double y, int zoom)
{
return projection.getLatitude(y, zoom);
}
public double getLongitude(double x, int zoom)
{
return projection.getLongitude(x, zoom);
}
public int getMaxZoom()
{
return maxZoom;
}
public int getTileSize()
{
return tileSize;
}
protected abstract Tile makeTile(int tileX, int tileY, int zoom);
public abstract String getName();
public Tile getTile(double latitude, double longitude, int zoom)
{
return makeTile((int) Math.floor(projection.mapLongitude(longitude, zoom)), (int) Math.floor(projection.mapLatitude(latitude, zoom)), zoom);
}
public Tile getTile(String s)
{
int start = 0, end = s.indexOf('_');
int x = new Integer(s.substring(start, end)).intValue();
start = end + 1;
end = s.indexOf('_', start);
int y = new Integer(s.substring(start, end)).intValue();
int zoom = new Integer(s.substring(end + 1)).intValue();
return makeTile(x, y, zoom);
}
public double getLongitudinalDistance(Tile lastTile)
{
int x = lastTile.getTileX(), zoom = lastTile.getZoom();
double dlon = projection.getLongitude(x + 1, zoom) - projection.getLongitude(x, zoom);
double lat = projection.getLatitude(lastTile.getTileY(), zoom);
return projection.getLongitudinalDistance(lat, dlon);
}
public double getLatitudinalDistance(Tile lastTile)
{
int y = lastTile.getTileY(), zoom = lastTile.getZoom();
double dlat = projection.getLatitude(y, zoom) - projection.getLatitude(y + 1, zoom);
return projection.getLatitudinalDistance(dlat);
}
public abstract class Tile
{
private final int zoom;
private final int tileX;
private final int tileY;
protected Tile(int tileX, int tileY, int zoom)
{
this.zoom = zoom;
this.tileY = tileY;
this.tileX = tileX;
}
public boolean equals(Object o)
{
if (!(o instanceof Tile))
return false;
Tile t = (Tile) o;
return t.getTileX() == getTileX() && t.getTileY() == getTileY() && t.getZoom() == getZoom();
}
public int getTileX()
{
return tileX;
}
public int getTileY()
{
return tileY;
}
public int getZoom()
{
return zoom;
}
public abstract String getURL();
public String toString()
{
return getTileX() + "_" + getTileY() + "_" + getZoom();
}
public Tile zoomOut()
{
if (getZoom() == 0)
return this;
return makeTile(getTileX() / 2, getTileY() / 2, getZoom() - 1);
}
public Tile zoomIn(int dx, int dy)
{
if (getZoom() == getMaxZoom())
return this;
return makeTile(getTileX() * 2 + dx, getTileY() * 2 + dy, getZoom() + 1);
}
public Tile pan(int x, int y)
{
return makeTile(getTileX() + x, getTileY() + y, getZoom());
}
public byte[] getMap() throws IOException
{
byte[] mapData = maps.get(this);
if (mapData == null)
mapData = maps.fetch(this);
if (mapData == null)
mapData = zoomOut().getMap();
return mapData;
}
}
}