// **********************************************************************
//
// <copyright>
//
// BBN Technologies
// 10 Moulton Street
// Cambridge, MA 02138
// (617) 873-8000
//
// Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
package com.jwetherell.openmap.common;
public class LatLonPoint {
public final static double NORTH_POLE = 90.0;
public final static double SOUTH_POLE = -NORTH_POLE;
public final static double DATELINE = 180.0;
public final static double LON_RANGE = 360.0;
public final static double EQUIVALENT_TOLERANCE = 0.00001;
protected double lat;
protected double lon;
protected transient double radLat;
protected transient double radLon;
/**
* Default constructor, values set to 0, 0.
*/
public LatLonPoint() {
}
/**
* Set the latitude, longitude for this point in decimal degrees.
*
* @param lat
* latitude
* @param lon
* longitude.
*/
public LatLonPoint(double lat, double lon) {
setLatLon(lat, lon, false);
}
/**
* Set the latitude, longitude for this point, with the option of noting
* whether the values are in degrees or radians.
*
* @param lat
* latitude
* @param lon
* longitude.
* @param isRadians
* true of values are radians.
*/
public LatLonPoint(double lat, double lon, boolean isRadian) {
setLatLon(lat, lon, isRadian);
}
/**
* Create Double version from another LatLonPoint.
*
* @param llp
*/
public LatLonPoint(LatLonPoint llp) {
setLatLon(llp.getY(), llp.getX(), false);
}
/**
* Point2D method, inheriting signature!!
*
* @param x
* longitude value in decimal degrees.
* @param y
* latitude value in decimal degrees.
*/
public void setLocation(double x, double y) {
setLatLon(y, x, false);
}
/**
* Set latitude and longitude.
*
* @param lat
* latitude in decimal degrees.
* @param lon
* longitude in decimal degrees.
*/
public void setLatLon(double lat, double lon) {
setLatLon(lat, lon, false);
}
/**
* Set latitude and longitude.
*
* @param lat
* latitude.
* @param lon
* longitude.
* @param isRadians
* true if lat/lon values are radians.
*/
public void setLatLon(double lat, double lon, boolean isRadians) {
if (isRadians) {
radLat = lat;
radLon = lon;
this.lat = ProjMath.radToDeg(lat);
this.lon = ProjMath.radToDeg(lon);
} else {
this.lat = normalizeLatitude(lat);
this.lon = wrapLongitude(lon);
radLat = ProjMath.degToRad(lat);
radLon = ProjMath.degToRad(lon);
}
}
/**
* @return longitude in decimal degrees.
*/
public double getX() {
return lon;
}
/**
* @return latitude in decimal degrees.
*/
public double getY() {
return lat;
}
/**
* @return float latitude in decimal degrees.
*/
public float getLatitude() {
return (float) lat;
}
/**
* @return float longitude in decimal degrees.
*/
public float getLongitude() {
return (float) lon;
}
/**
* @return radian longitude.
*/
public double getRadLon() {
return radLon;
}
/**
* @return radian latitude.
*/
public double getRadLat() {
return radLat;
}
/**
* Set latitude.
*
* @param lat
* latitude in decimal degrees
*/
public void setLatitude(double lat) {
this.lat = normalizeLatitude(lat);
radLat = ProjMath.degToRad(lat);
}
/**
* Set longitude.
*
* @param lon
* longitude in decimal degrees
*/
public void setLongitude(double lon) {
this.lon = wrapLongitude(lon);
radLon = ProjMath.degToRad(lon);
}
/**
* Set location values from another lat/lon point.
*
* @param llp
*/
public void setLatLon(LatLonPoint llp) {
setLatLon(llp.getY(), llp.getX(), false);
}
/**
* Ensure latitude is between the poles.
*
* @param lat
* @return
*/
public final static float normalizeLatitude(float lat) {
return (float) normalizeLatitude((double) lat);
}
/**
* Sets latitude to something sane.
*
* @param lat
* latitude in decimal degrees
* @return float normalized latitude in decimal degrees (−90° ≤
* φ ≤ 90°)
*/
public final static double normalizeLatitude(double lat) {
if (lat > NORTH_POLE) {
lat = NORTH_POLE;
}
if (lat < SOUTH_POLE) {
lat = SOUTH_POLE;
}
return lat;
}
/**
* Ensure the longitude is between the date line.
*
* @param lon
* @return
*/
public final static float wrapLongitude(float lon) {
return (float) wrapLongitude((double) lon);
}
/**
* Sets longitude to something sane.
*
* @param lon
* longitude in decimal degrees
* @return float wrapped longitude in decimal degrees (−180° ≤
* λ ≤ 180°)
*/
public final static double wrapLongitude(double lon) {
if ((lon < -DATELINE) || (lon > DATELINE)) {
lon += DATELINE;
lon = lon % LON_RANGE;
lon = (lon < 0) ? DATELINE + lon : -DATELINE + lon;
}
return lon;
}
/**
* Check if latitude is bogus. Latitude is invalid if lat > 90° or if
* lat < −90°.
*
* @param lat
* latitude in decimal degrees
* @return boolean true if latitude is invalid
*/
public static boolean isInvalidLatitude(double lat) {
return ((lat > NORTH_POLE) || (lat < SOUTH_POLE));
}
/**
* Check if longitude is bogus. Longitude is invalid if lon > 180° or
* if lon < −180°.
*
* @param lon
* longitude in decimal degrees
* @return boolean true if longitude is invalid
*/
public static boolean isInvalidLongitude(double lon) {
return ((lon < -DATELINE) || (lon > DATELINE));
}
/**
* Determines whether two LatLonPoints are equal.
*
* @param obj
* Object
* @return Whether the two points are equal up to a tolerance of 10 <sup>-5
* </sup> degrees in latitude and longitude.
*/
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final LatLonPoint pt = (LatLonPoint) obj;
return (MoreMath.approximately_equal(getY(), pt.getY(), EQUIVALENT_TOLERANCE) && MoreMath.approximately_equal(getX(), pt.getX(), EQUIVALENT_TOLERANCE));
}
/**
* Find the distance to another LatLonPoint, based on a earth spherical
* model.
*
* @param toPoint
* LatLonPoint
* @return distance, in radians. You can use an com.bbn.openmap.proj.Length
* to convert the radians to other units.
*/
public double distance(LatLonPoint toPoint) {
return GreatCircle.sphericalDistance(getRadLat(), getRadLon(), toPoint.getRadLat(), toPoint.getRadLon());
}
/**
* Find the azimuth to another point, based on the spherical earth model.
*
* @param toPoint
* LatLonPoint
* @return the azimuth `Az' east of north from this point bearing toward the
* one provided as an argument.(-PI <= Az <= PI).
*
*/
public double azimuth(LatLonPoint toPoint) {
return GreatCircle.sphericalAzimuth(getRadLat(), getRadLon(), toPoint.getRadLat(), toPoint.getRadLon());
}
/**
* Get a new LatLonPoint a distance and azimuth from another point, based on
* the spherical earth model.
*
* @param distance
* radians
* @param azimuth
* radians
* @return
*/
public LatLonPoint getPoint(double distance, double azimuth) {
return GreatCircle.sphericalBetween(getRadLat(), getRadLon(), distance, azimuth);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return "Lat=" + lat + ", Lon=" + lon;
}
}