Worldwind public release 0.2.1
[worldwind-tracker.git] / gov / nasa / worldwind / geom / LatLon.java
blob761ed62ab91a2aa82275244e2f133f9606d4d83c
1 /*
2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
5 All Rights Reserved.
6 */
7 package gov.nasa.worldwind.geom;
9 import gov.nasa.worldwind.*;
11 /**
12 * Represents a point on the two-dimensional surface of a globe. Latitude is the degrees North and ranges between [-90,
13 * 90], while longitude refers to degrees East, and ranges between (-180, 180].
14 * <p/>
15 * Instances of <code>LatLon</code> are immutable.
17 * @author Tom Gaskins
18 * @version $Id: LatLon.java 2152 2007-06-26 20:34:22Z tgaskins $
20 public class LatLon
22 private final Angle latitude;
23 private final Angle longitude;
25 /**
26 * Factor method for obtaining a new <code>LatLon</code> from two angles expressed in radians.
28 * @param latitude in radians
29 * @param longitude in radians
30 * @return a new <code>LatLon</code> from the given angles, which are expressed as radians
32 public static LatLon fromRadians(double latitude, double longitude)
34 return new LatLon(Math.toDegrees(latitude), Math.toDegrees(longitude));
37 /**
38 * Factory method for obtaining a new <code>LatLon</code> from two angles expressed in degrees.
40 * @param latitude in degrees
41 * @param longitude in degrees
42 * @return a new <code>LatLon</code> from the given angles, which are expressed as degrees
44 public static LatLon fromDegrees(double latitude, double longitude)
46 return new LatLon(latitude, longitude);
49 private LatLon(double latitude, double longitude)
51 this.latitude = Angle.fromDegrees(latitude);
52 this.longitude = Angle.fromDegrees(longitude);
55 /**
56 * Contructs a new <code>LatLon</code> from two angles. Neither angle may be null.
58 * @param latitude
59 * @param longitude
60 * @throws IllegalArgumentException if <code>latitude</code> or <code>longitude</code> is null
62 public LatLon(Angle latitude, Angle longitude)
64 if (latitude == null || longitude == null)
66 String message = WorldWind.retrieveErrMsg("nullValue.LatitudeOrLongitudeIsNull");
67 WorldWind.logger().log(java.util.logging.Level.FINE, message);
68 throw new IllegalArgumentException(message);
71 this.latitude = latitude;
72 this.longitude = longitude;
75 /**
76 * Obtains the latitude of this <code>LatLon</code>.
78 * @return this <code>LatLon</code>'s latitude
80 public final Angle getLatitude()
82 return this.latitude;
85 /**
86 * Obtains the longitude of this <code>LatLon</code>.
88 * @return this <code>LatLon</code>'s longitude
90 public final Angle getLongitude()
92 return this.longitude;
95 public static LatLon interpolate(double t, LatLon begin, LatLon end)
97 if (begin == null || end == null)
99 String message = WorldWind.retrieveErrMsg("nullValue.LatitudeOrLongitudeIsNull");
100 WorldWind.logger().log(java.util.logging.Level.FINE, message);
101 throw new IllegalArgumentException(message);
104 if (t < 0)
105 return begin;
106 else if (t > 1)
107 return end;
108 Quaternion beginQuat = Quaternion.EulerToQuaternion(begin.getLongitude().getRadians(),
109 begin.getLatitude().getRadians(), 0);
110 Quaternion endQuat = Quaternion.EulerToQuaternion(end.getLongitude().getRadians(),
111 end.getLatitude().getRadians(), 0);
112 Quaternion q = Quaternion.Slerp(beginQuat, endQuat, t);
113 Vec4 v = Quaternion.QuaternionToEuler(q);
114 if (Double.isNaN(v.x) || Double.isNaN(v.y))
115 return null;
116 return LatLon.fromRadians(v.y, v.x);
120 * Computes the great circle angular distance between two locations
122 * @param begin LatLon of the first location
123 * @param end LatLon of the second location
124 * @return the angular distance between the two locations
126 public static Angle sphericalDistance(LatLon begin, LatLon end)
128 double radLatA = begin.getLatitude().radians;
129 double radLatB = end.getLatitude().radians;
130 double radLonA = begin.getLongitude().radians;
131 double radLonB = end.getLongitude().radians;
132 return Angle.fromRadians(
133 Math.acos(Math.cos(radLatA) * Math.cos(radLatB) * Math.cos(radLonA - radLonB)
134 + Math.sin(radLatA) * Math.sin(radLatB)));
137 public LatLon add(LatLon that)
139 if (that == null)
141 String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull");
142 WorldWind.logger().log(java.util.logging.Level.FINE, msg);
143 throw new IllegalArgumentException(msg);
146 Angle lat = Angle.normalizedLatitude(this.latitude.add(that.latitude));
147 Angle lon = Angle.normalizedLongitude(this.longitude.add(that.longitude));
149 return new LatLon(lat, lon);
152 public LatLon subtract(LatLon that)
154 if (that == null)
156 String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull");
157 WorldWind.logger().log(java.util.logging.Level.FINE, msg);
158 throw new IllegalArgumentException(msg);
161 Angle lat = Angle.normalizedLatitude(this.latitude.subtract(that.latitude));
162 Angle lon = Angle.normalizedLongitude(this.longitude.subtract(that.longitude));
164 return new LatLon(lat, lon);
167 public LatLon add(Position that)
169 if (that == null)
171 String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull");
172 WorldWind.logger().log(java.util.logging.Level.FINE, msg);
173 throw new IllegalArgumentException(msg);
176 Angle lat = Angle.normalizedLatitude(this.latitude.add(that.getLatitude()));
177 Angle lon = Angle.normalizedLongitude(this.longitude.add(that.getLongitude()));
179 return new LatLon(lat, lon);
182 public LatLon subtract(Position that)
184 if (that == null)
186 String msg = WorldWind.retrieveErrMsg("nullValue.AngleIsNull");
187 WorldWind.logger().log(java.util.logging.Level.FINE, msg);
188 throw new IllegalArgumentException(msg);
191 Angle lat = Angle.normalizedLatitude(this.latitude.subtract(that.getLatitude()));
192 Angle lon = Angle.normalizedLongitude(this.longitude.subtract(that.getLongitude()));
194 return new LatLon(lat, lon);
197 public static boolean positionsCrossLongitudeBoundary(Iterable<LatLon> positions)
199 if (positions == null)
201 String msg = WorldWind.retrieveErrMsg("nullValue.PositionsListIsNull");
202 WorldWind.logger().log(java.util.logging.Level.FINE, msg);
203 throw new IllegalArgumentException(msg);
206 LatLon pos = null;
207 for (LatLon posNext : positions)
209 if (pos != null)
211 // A segment cross the line if end pos have different longitude signs
212 // and are more than 180 degress longitude apart
213 if (Math.signum(pos.getLongitude().degrees) != Math.signum(posNext.getLongitude().degrees))
215 if (Math.abs(pos.getLongitude().degrees - posNext.getLongitude().degrees) > 180)
216 return true;
219 pos = posNext;
222 return false;
225 @Override
226 public String toString()
228 return "(" + this.latitude.toString() + ", " + this.longitude.toString() + ")";
231 @Override
232 public boolean equals(Object o)
234 if (this == o)
235 return true;
236 if (o == null || getClass() != o.getClass())
237 return false;
239 final gov.nasa.worldwind.geom.LatLon latLon = (gov.nasa.worldwind.geom.LatLon) o;
241 if (!latitude.equals(latLon.latitude))
242 return false;
243 //noinspection RedundantIfStatement
244 if (!longitude.equals(latLon.longitude))
245 return false;
247 return true;
250 @Override
251 public int hashCode()
253 int result;
254 result = latitude.hashCode();
255 result = 29 * result + longitude.hashCode();
256 return result;