/*
* Copyright (C) 2014 Alec Dhuse
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package co.foldingmap.map.tile;
import co.foldingmap.map.vector.Coordinate;
/**
* A convenience class for keeping an x, y, zoom triple information.
*
* @author Alec
*/
public class TileReference {
private int x, y, zoom;
public TileReference(int x, int y, int zoom) {
this.x = x;
this.y = y;
this.zoom = zoom;
}
/**
* Returns if this object is equal to another.
*
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof TileReference) {
return (this.hashCode() == obj.hashCode());
} else {
return false;
}
}
/**
* Returns the hash of this object
*
* @return
*/
@Override
public int hashCode() {
int hash = 7;
hash = 10 * hash + this.x;
hash = 100 * hash + this.y;
hash = 10000 * hash + this.zoom;
return hash;
}
/**
* Creates a Coordinate Object to represent the north-west corner of this tile.
*
* @return
*/
public Coordinate getCoordinate() {
Coordinate upperLeft;
upperLeft = new Coordinate(0, getLatitude(), getLongitude());
return upperLeft;
}
/**
* Returns the Latitude for the northern boundary of the tile.
*
* @return
*/
public float getLatitude() {
double latDeg, latRad, n;
n = Math.pow(2, zoom);
latRad = Math.atan(Math.sinh(Math.PI * (1 - 2 * y / n)));
latDeg = latRad * 180.0 / Math.PI;
return (float) latDeg;
}
/**
* Returns the Longitude for the western boundary of the tile.
*
* @return
*/
public float getLongitude() {
double lonDeg, n;
n = Math.pow(2, zoom);
lonDeg = x / n * 360.0 - 180.0;
return (float) lonDeg;
}
/**
* Returns the tile reference for the given offsets.
*
* @param xOffset
* @param yOffset
* @return
*/
public TileReference getTileOffset(int xOffset, int yOffset) {
int newX, newY;
newX = x + xOffset;
newY = y + yOffset;
// If x is a negative number wrap
if (newX < 0) newX = (int) (Math.pow(2, zoom) - 1);
//If y is negative, set it to 0
if (newY < 0) newY = 0;
return new TileReference(newX, newY, zoom);
}
/**
* Returns the TileReference that corresponds to the Latitude and Longitude
* given.
*
* @param latitude
* @param longitude
* @param zoomLevel Tile Zoom Level
* @return
*/
public static TileReference getTileReference(double latitude, double longitude, int zoomLevel) {
int n, xTile, yTile;
double latRadians;
TileReference tileRef;
latRadians = Coordinate.getLatitudeInRadians(latitude);
n = (int) Math.pow(2, zoomLevel);
xTile = (int) (((longitude + 180.0) / 360.0) * n);
if (latitude >= 85.0511f) {
yTile = 0;
} else {
yTile = (int) Math.abs(Math.floor( (1 - Math.log(Math.tan(latRadians) + 1 / Math.cos(latRadians)) / Math.PI) / 2 * (1<<zoomLevel) ) );
}
tileRef = new TileReference(xTile, yTile, zoomLevel);
return tileRef;
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
/**
* Returns the zoom value of this TileReference.
*
* @return
*/
public int getZoom() {
return this.zoom;
}
/**
* Increments the X value of this Tile Reference.
*/
public void incrementX() {
//Check to see if incrementing X would put it beyond the number of X tiles.
if ((x + 1) < Math.pow(2, zoom)) {
this.x++;
}
}
/**
* Increments the Y value of this Tile Reference.
*/
public void incrementY() {
//Check to see if incrementing Y would put it beyond the number of y tiles.
if ((y + 1) < Math.pow(2, zoom)) {
this.y++;
}
}
@Override
public String toString() {
return Integer.toString(zoom) + "," + Integer.toString(x) + "," + Integer.toString(y);
}
}