/*
Copyright (C) 2001, 2006 United States Government
as represented by the Administrator of the
National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.geom;
import gov.nasa.worldwind.util.Logging;
/**
* @author tag
* @version $Id: Position.java 5250 2008-05-01 15:33:31Z dcollins $
*/
public class Position
{
private final Angle latitude;
private final Angle longitude;
private final double elevation;
public static final Position ZERO = new Position(Angle.ZERO, Angle.ZERO, 0d);
public static Position fromRadians(double latitude, double longitude, double elevation)
{
return new Position(Angle.fromRadians(latitude), Angle.fromRadians(longitude), elevation);
}
public static Position fromDegrees(double latitude, double longitude, double elevation)
{
return new Position(Angle.fromDegrees(latitude), Angle.fromDegrees(longitude), elevation);
}
public Position(Angle latitude, Angle longitude, double elevation)
{
if (latitude == null || longitude == null)
{
String message = Logging.getMessage("nullValue.LatitudeOrLongitudeIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.latitude = latitude;
this.longitude = longitude;
this.elevation = elevation;
}
public Position(LatLon latLon, double elevation)
{
if (latLon == null)
{
String message = Logging.getMessage("nullValue.LatLonIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.latitude = latLon.getLatitude();
this.longitude = latLon.getLongitude();
this.elevation = elevation;
}
/**
* Obtains the latitude of this position
*
* @return this position's latitude
*/
public final Angle getLatitude()
{
return this.latitude;
}
/**
* Obtains the longitude of this position
*
* @return this position's longitude
*/
public final Angle getLongitude()
{
return this.longitude;
}
public LatLon getLatLon()
{
return new LatLon(this.getLatitude(), this.getLongitude());
}
public Position add(Position that)
{
Angle lat = Angle.normalizedLatitude(this.latitude.add(that.latitude));
Angle lon = Angle.normalizedLongitude(this.longitude.add(that.longitude));
return new Position(lat, lon, this.elevation + that.elevation);
}
public Position subtract(Position that)
{
Angle lat = Angle.normalizedLatitude(this.latitude.subtract(that.latitude));
Angle lon = Angle.normalizedLongitude(this.longitude.subtract(that.longitude));
return new Position(lat, lon, this.elevation - that.elevation);
}
public static Position interpolate(double amount, Position value1, Position value2)
{
if (value1 == null || value2 == null)
{
String message = Logging.getMessage("nullValue.PositionIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (amount < 0)
return value1;
else if (amount > 1)
return value2;
Quaternion beginQuat = Quaternion.fromLatLon(value1.getLatitude(), value1.getLongitude());
Quaternion endQuat = Quaternion.fromLatLon(value2.getLatitude(), value2.getLongitude());
Quaternion quaternion = Quaternion.slerp(amount, beginQuat, endQuat);
LatLon latLon = quaternion.getLatLon();
if (latLon == null)
return null;
return new Position(latLon, amount * value2.getElevation() + (1 - amount) * value1.getElevation());
}
/**
* Obtains the elevation of this position
*
* @return this position's elevation
*/
public final double getElevation()
{
return this.elevation;
}
public String toString()
{
return "(" + this.latitude.toString() + ", " + this.longitude.toString() + ", " + this.elevation + ")";
}
public static boolean positionsCrossDateLine(Iterable<Position> positions)
{
if (positions == null)
{
String msg = Logging.getMessage("nullValue.PositionsListIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
Position pos = null;
for (Position posNext : positions)
{
if (pos != null)
{
// A segment cross the line if end pos have different longitude signs
// and are more than 180 degress longitude apart
if (Math.signum(pos.getLongitude().degrees) != Math.signum(posNext.getLongitude().degrees))
{
double delta = Math.abs(pos.getLongitude().degrees - posNext.getLongitude().degrees);
if (delta > 180 && delta < 360)
return true;
}
}
pos = posNext;
}
return false;
}
}