package de.danielbasedow.prospecter.core.geo;
import net.sf.jsi.Rectangle;
/**
* Represents an area on earth centered at a coordinate and extending distance meters to the north, south, west and
* east. It is not a circle but more of a square. This means matched results can be up to 40% further away than the
* specified distance (worst case if match is in one of the corners NW, NE, SE, SW).
*/
public class GeoPerimeter {
public static final double EQUATORIAL_RADIUS = 6378137;
public static final double POLAR_RADIUS = 6356752.3;
private final double latitude;
private final double longitude;
private final int distance;
private final double north;
private final double south;
private final double east;
private final double west;
/**
* @param latitude latitude of center
* @param longitude longitude of center
* @param distance in meters
*/
public GeoPerimeter(double latitude, double longitude, int distance) {
this.latitude = Math.toRadians(latitude);
this.longitude = Math.toRadians(longitude);
this.distance = distance;
double r = getRadiusAtLatitude(this.latitude);
double pr = r * Math.cos(this.latitude);
south = Math.toDegrees(this.latitude - distance / r);
north = Math.toDegrees(this.latitude + distance / r);
west = Math.toDegrees(this.longitude - distance / pr);
east = Math.toDegrees(this.longitude + distance / pr);
}
/**
* Get the the northern limit based on center latitude and distance
*
* @return northern limit converted to integer
*/
public float getNorth() {
return (float) north;
}
/**
* Get the the southern limit based on center latitude and distance
*
* @return southern limit converted to integer
*/
public float getSouth() {
return (float) south;
}
/**
* Get the the eastern limit based on center longitude and distance
*
* @return eastern limit
*/
public float getEast() {
return (float) east;
}
/**
* Get the the western limit based on center longitude and distance
*
* @return western limit
*/
public float getWest() {
return (float) west;
}
/**
* tests whether the box spans the 180° longitude.
*
* @return true if eastern limit lies in western hemisphere and western limit in eastern hemisphere
*/
public boolean spans180Longitude() {
if (getEast() > 180) {
return true;
} else if (getWest() < -180) {
return true;
}
return false;
}
/**
* Mirrors the perimeter into fake space. Used to mirror perimeter boxes that span hemisphere at 180 longitude.
*
* @return additional perimeter for indexing
*/
public GeoPerimeter mirrorInFakeSpace() {
if (longitude > 0) {
return new GeoPerimeter(Math.toDegrees(latitude), Math.toDegrees(longitude) - 360, distance);
} else {
return new GeoPerimeter(Math.toDegrees(latitude), Math.toDegrees(longitude) + 360, distance);
}
}
private double getRadiusAtLatitude(double latitude) {
double a = EQUATORIAL_RADIUS * EQUATORIAL_RADIUS * Math.cos(latitude);
double b = POLAR_RADIUS * POLAR_RADIUS * Math.sin(latitude);
double c = EQUATORIAL_RADIUS * Math.cos(latitude);
double d = POLAR_RADIUS * Math.sin(latitude);
return Math.sqrt((a * a + b * b) / (c * c + d * d));
}
public Rectangle getRectangle() {
return new Rectangle(getWest(), getSouth(), getEast(), getNorth());
}
}