2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
7 package gov
.nasa
.worldwind
.geom
;
9 import gov
.nasa
.worldwind
.util
.Logging
;
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].
15 * Instances of <code>LatLon</code> are immutable.
18 * @version $Id: LatLon.java 2567 2007-08-16 22:27:38Z tgaskins $
22 private final Angle latitude
;
23 private final Angle longitude
;
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
));
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
);
56 * Contructs a new <code>LatLon</code> from two angles. Neither angle may be null.
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
= Logging
.getMessage("nullValue.LatitudeOrLongitudeIsNull");
67 Logging
.logger().severe(message
);
68 throw new IllegalArgumentException(message
);
71 this.latitude
= latitude
;
72 this.longitude
= longitude
;
76 * Obtains the latitude of this <code>LatLon</code>.
78 * @return this <code>LatLon</code>'s latitude
80 public final Angle
getLatitude()
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 amount
, LatLon value1
, LatLon value2
)
97 if ((value1
== null) || (value2
== null))
99 String message
= Logging
.getMessage("nullValue.LatLonIsNull");
100 Logging
.logger().severe(message
);
101 throw new IllegalArgumentException(message
);
109 Quaternion beginQuat
= Quaternion
.fromRotationYPR(value1
.getLongitude(), value1
.getLatitude(), Angle
.ZERO
);
110 Quaternion endQuat
= Quaternion
.fromRotationYPR(value2
.getLongitude(), value2
.getLatitude(), Angle
.ZERO
);
111 Quaternion quaternion
= Quaternion
.slerp(amount
, beginQuat
, endQuat
);
113 Angle lat
= quaternion
.getRotationY();
114 Angle lon
= quaternion
.getRotationX();
115 if ((lat
== null) || (lon
== null))
118 return new LatLon(lat
, lon
);
122 * Computes the great circle angular distance between two locations
124 * @param begin LatLon of the first location
125 * @param end LatLon of the second location
126 * @return the angular distance between the two locations
128 public static Angle
sphericalDistance(LatLon begin
, LatLon end
)
130 // TODO: Perhaps use more accurate formula described here: http://en.wikipedia.org/wiki/Great-circle_distance
131 double radLatA
= begin
.getLatitude().radians
;
132 double radLatB
= end
.getLatitude().radians
;
133 double radLonA
= begin
.getLongitude().radians
;
134 double radLonB
= end
.getLongitude().radians
;
135 return Angle
.fromRadians(
136 Math
.acos(Math
.cos(radLatA
) * Math
.cos(radLatB
) * Math
.cos(radLonA
- radLonB
)
137 + Math
.sin(radLatA
) * Math
.sin(radLatB
)));
140 private static final double HALF_PI
= Math
.PI
/ 2d
;
142 public static Angle
azimuth(LatLon p1
, LatLon p2
)
144 double lat1
= p1
.getLatitude().radians
;
145 double lon1
= p1
.getLongitude().radians
;
146 double lat2
= p2
.getLatitude().radians
;
147 double lon2
= p2
.getLongitude().radians
;
149 if (lat1
== lat2
&& lon1
== lon2
)
153 return lat1
> lat2 ? Angle
.POS180
: Angle
.ZERO
;
155 double c
= Math
.acos(Math
.cos(lat1
) * Math
.cos(lat2
) * Math
.cos(lon2
- lon1
) + Math
.sin(lat1
) * Math
.sin(lat2
));
156 double A
= Math
.asin(Math
.cos(lat2
) * Math
.sin(lon2
- lon1
) / c
);
160 else if (lon2
< lon1
)
163 return Angle
.fromRadians(A
);
166 public static LatLon
endPosition(LatLon p
, double azimuth
, double pathLength
)
168 double a
= Math
.acos(Math
.cos(pathLength
) * Math
.cos(HALF_PI
- p
.getLatitude().radians
)
169 + Math
.sin(HALF_PI
- p
.getLatitude().radians
) * Math
.sin(pathLength
) * Math
.cos(azimuth
));
171 double B
= Math
.asin(Math
.sin(pathLength
) * Math
.sin(azimuth
) / Math
.sin(a
));
173 return new LatLon(Angle
.fromRadians(HALF_PI
- a
).normalizedLatitude(),
174 Angle
.fromRadians(B
+ p
.getLongitude().radians
).normalizedLongitude());
177 public LatLon
add(LatLon that
)
181 String msg
= Logging
.getMessage("nullValue.AngleIsNull");
182 Logging
.logger().severe(msg
);
183 throw new IllegalArgumentException(msg
);
186 Angle lat
= Angle
.normalizedLatitude(this.latitude
.add(that
.latitude
));
187 Angle lon
= Angle
.normalizedLongitude(this.longitude
.add(that
.longitude
));
189 return new LatLon(lat
, lon
);
192 public LatLon
subtract(LatLon that
)
196 String msg
= Logging
.getMessage("nullValue.AngleIsNull");
197 Logging
.logger().severe(msg
);
198 throw new IllegalArgumentException(msg
);
201 Angle lat
= Angle
.normalizedLatitude(this.latitude
.subtract(that
.latitude
));
202 Angle lon
= Angle
.normalizedLongitude(this.longitude
.subtract(that
.longitude
));
204 return new LatLon(lat
, lon
);
207 public LatLon
add(Position that
)
211 String msg
= Logging
.getMessage("nullValue.AngleIsNull");
212 Logging
.logger().severe(msg
);
213 throw new IllegalArgumentException(msg
);
216 Angle lat
= Angle
.normalizedLatitude(this.latitude
.add(that
.getLatitude()));
217 Angle lon
= Angle
.normalizedLongitude(this.longitude
.add(that
.getLongitude()));
219 return new LatLon(lat
, lon
);
222 public LatLon
subtract(Position that
)
226 String msg
= Logging
.getMessage("nullValue.AngleIsNull");
227 Logging
.logger().severe(msg
);
228 throw new IllegalArgumentException(msg
);
231 Angle lat
= Angle
.normalizedLatitude(this.latitude
.subtract(that
.getLatitude()));
232 Angle lon
= Angle
.normalizedLongitude(this.longitude
.subtract(that
.getLongitude()));
234 return new LatLon(lat
, lon
);
237 public static boolean positionsCrossDateLine(Iterable
<LatLon
> positions
)
239 if (positions
== null)
241 String msg
= Logging
.getMessage("nullValue.PositionsListIsNull");
242 Logging
.logger().severe(msg
);
243 throw new IllegalArgumentException(msg
);
247 for (LatLon posNext
: positions
)
251 // A segment cross the line if end pos have different longitude signs
252 // and are more than 180 degress longitude apart
253 if (Math
.signum(pos
.getLongitude().degrees
) != Math
.signum(posNext
.getLongitude().degrees
))
255 if (Math
.abs(pos
.getLongitude().degrees
- posNext
.getLongitude().degrees
) > 180)
265 public static boolean positionsCrossLongitudeBoundary(LatLon p1
, LatLon p2
)
267 if (p1
== null || p2
== null)
269 String msg
= Logging
.getMessage("nullValue.PositionsListIsNull");
270 Logging
.logger().severe(msg
);
271 throw new IllegalArgumentException(msg
);
274 // A segment cross the line if end pos have different longitude signs
275 // and are more than 180 degress longitude apart
276 if (Math
.signum(p1
.getLongitude().degrees
) != Math
.signum(p2
.getLongitude().degrees
))
278 if (Math
.abs(p1
.getLongitude().degrees
- p2
.getLongitude().degrees
) > 180)
286 public String
toString()
288 return "(" + this.latitude
.toString() + ", " + this.longitude
.toString() + ")";
292 public boolean equals(Object o
)
296 if (o
== null || getClass() != o
.getClass())
299 final gov
.nasa
.worldwind
.geom
.LatLon latLon
= (gov
.nasa
.worldwind
.geom
.LatLon
) o
;
301 if (!latitude
.equals(latLon
.latitude
))
303 //noinspection RedundantIfStatement
304 if (!longitude
.equals(latLon
.longitude
))
311 public int hashCode()
314 result
= latitude
.hashCode();
315 result
= 29 * result
+ longitude
.hashCode();