net.sf.marineapi.nmea.util.Position Maven / Gradle / Ivy
Show all versions of org.everit.osgi.bundles.net.sf.marineapi Show documentation
/*
* Position.java
* Copyright (C) 2010 Kimmo Tuukkanen
*
* This file is part of Java Marine API.
*
*
* Java Marine API is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Java Marine API 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Java Marine API. If not, see .
*/
package net.sf.marineapi.nmea.util;
/**
* Represents a geographic position. Default datum is WGS84 as generally in NMEA
* 0183. Notice that datum is only informative and it does not affect
* calculations or handling of other values.
*
* @author Kimmo Tuukkanen
*/
public class Position {
// latitude degrees
private double latitude;
// longitude degrees
private double longitude;
// altitude
private double altitude = 0.0;
// datum/coordinate system
private Datum datum = Datum.WGS84;
/**
* Creates a new instance of Position. Notice that altitude defaults to -0.0
* and may be set later.
*
* @param lat Latitude degrees
* @param lon Longitude degrees
* @see #setAltitude(double)
*/
public Position(double lat, double lon) {
setLatitude(lat);
setLongitude(lon);
}
/**
* Creates a new instance of position with latitude, longitude and altitude.
*
* @param lat Latitude degrees
* @param lon Longitude degrees
* @param alt Altitude value, in meters.
*/
public Position(double lat, double lon, double alt) {
this(lat, lon);
this.altitude = alt;
}
/**
* Creates new instance of Position with latitude, longitude and datum.
* Notice that altitude defaults to -0.0 and may be set later.
*
* @param lat Latitude degrees
* @param lon Longitude degrees
* @param datum Datum to set
* @see #setAltitude(double)
*/
public Position(double lat, double lon, Datum datum) {
this(lat, lon);
this.datum = datum;
}
/**
* Creates new instance of Position with latitude, longitude, altitude and
* datum.
*
* @param lat Latitude degrees
* @param lon Longitude degrees
* @param datum Datum to set
*/
public Position(double lat, double lon, double alt, Datum datum) {
this(lat, lon, alt);
this.datum = datum;
}
/**
* Calculates distance to specified Position
.
*
* The Distance is calculated using the Haversine
* formula. Implementation is based on example found at codecodex.com.
*
* Earth radius earth
* radius used in calculation is 6366.70702
km, based on
* the assumption that 1 degrees is exactly 60 NM.
*
* @param pos Position to which the distance is calculated.
* @return Distance to popos
in meters.
*/
public double distanceTo(Position pos) {
return haversine(getLatitude(), getLongitude(), pos.getLatitude(),
pos.getLongitude());
}
/**
* Gets the position altitude from mean sea level. Notice that most
* sentences with position don't provide this value. When missing, the
* default value in Position
is 0.0.
*
* @return Altitude value in meters
*/
public double getAltitude() {
return altitude;
}
/**
* Gets the datum, i.e. the coordinate system used to define geographic
* position. Default is {@link Datum#WGS84}, unless datum is specified in
* the constructor. Notice also that datum cannot be set afterwards.
*
* @return Datum enum
*/
public Datum getDatum() {
return datum;
}
/**
* Get latitude value of Position
*
* @return latitude degrees
*/
public double getLatitude() {
return this.latitude;
}
/**
* Get the hemisphere of latitude, North or South.
*
* @return CompassPoint.NORTH or CompassPoint.SOUTH
*/
public CompassPoint getLatitudeHemisphere() {
return isLatitudeNorth() ? CompassPoint.NORTH : CompassPoint.SOUTH;
}
/**
* Get longitude value of Position
*
* @return longitude degrees
*/
public double getLongitude() {
return this.longitude;
}
/**
* Get the hemisphere of longitude, East or West.
*
* @return CompassPoint.EAST or CompassPoint.WEST
*/
public CompassPoint getLongitudeHemisphere() {
return isLongitudeEast() ? CompassPoint.EAST : CompassPoint.WEST;
}
/**
* Tells if the latitude is on northern hemisphere.
*
* @return true if northern, otherwise false (south).
*/
public boolean isLatitudeNorth() {
return getLatitude() >= 0.0;
}
/**
* Tells if the longitude is on eastern hemisphere.
*
* @return true if eastern, otherwise false (west).
*/
public boolean isLongitudeEast() {
return getLongitude() >= 0.0;
}
/**
* Sets the altitude of position above or below mean sea level. Defaults to
* zero (-0.0).
*
* @param altitude Altitude value to set, in meters.
*/
public void setAltitude(double altitude) {
this.altitude = altitude;
}
/**
* Set the latitude degrees of Position
*
* @param latitude the latitude to set
* @throws IllegalArgumentException If specified latitude value is out of
* range 0..90 degrees.
*/
public void setLatitude(double latitude) {
if (latitude < -90 || latitude > 90) {
throw new IllegalArgumentException(
"Latitude out of bounds -90..90 degrees");
}
this.latitude = latitude;
}
/**
* Set the longitude degrees of Position
*
* @param longitude the longitude to set
* @throws IllegalArgumentException If specified longitude value is out of
* range 0..180 degrees.
*/
public void setLongitude(double longitude) {
if (longitude < -180 || longitude > 180) {
throw new IllegalArgumentException(
"Longitude out of bounds -180..180 degrees");
}
this.longitude = longitude;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
sb.append(String.format("%02.04f", Math.abs(getLatitude())));
sb.append(" ");
sb.append(getLatitudeHemisphere().toChar());
sb.append(", ");
sb.append(String.format("%03.04f", Math.abs(getLongitude())));
sb.append(" ");
sb.append(getLongitudeHemisphere().toChar());
sb.append(", ");
sb.append(getAltitude());
sb.append(" m]");
return sb.toString();
}
/**
* Convenience method for creating a waypoint based in the Position.
*
* @param id Waypoint ID or name
* @return the created Waypoint
*/
public Waypoint toWaypoint(String id) {
return new Waypoint(id, getLatitude(), getLongitude());
}
/**
* Haversine formulae, implementation based on example at codecodex.
*
* @param lat1 Origin latitude
* @param lon1 Origin longitude
* @param lat2 Destination latitude
* @param lon2 Destination longitude
* @return Distance in meters
*/
private double haversine(double lat1, double lon1, double lat2, double lon2) {
// Mean earth radius (IUGG) = 6371.009
// Meridional earth radius = 6367.4491
// Earth radius by assumption that 1 degree equals exactly 60 NM:
// 1.852 * 60 * 360 / (2 * Pi) = 6366.7 km
final double earthRadius = 6366.70702;
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lon2 - lon1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
* Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return (earthRadius * c * 1000);
}
}