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
.globes
;
9 import gov
.nasa
.worldwind
.WWObjectImpl
;
10 import gov
.nasa
.worldwind
.geom
.*;
11 import gov
.nasa
.worldwind
.util
.Logging
;
15 * @version $Id: EllipsoidalGlobe.java 2570 2007-08-16 22:31:33Z tgaskins $
17 public class EllipsoidalGlobe
extends WWObjectImpl
implements Globe
19 private final double equatorialRadius
;
20 private final double polarRadius
;
21 private final double es
;
22 private final Vec4 center
;
24 private final ElevationModel elevationModel
;
26 public EllipsoidalGlobe(double equatorialRadius
, double polarRadius
, double es
, ElevationModel em
)
30 String msg
= Logging
.getMessage("nullValue.ElevationModelIsNull");
31 Logging
.logger().severe(msg
);
32 throw new IllegalArgumentException(msg
);
35 this.equatorialRadius
= equatorialRadius
;
36 this.polarRadius
= polarRadius
;
37 this.es
= es
; // assume it's consistent with the two radii
38 this.center
= Vec4
.ZERO
;
39 this.elevationModel
= em
;
42 public final double getRadius()
44 return this.equatorialRadius
;
47 public final double getEquatorialRadius()
49 return this.equatorialRadius
;
52 public final double getPolarRadius()
54 return this.polarRadius
;
57 public double getMaximumRadius()
59 return this.equatorialRadius
;
62 public double getRadiusAt(Angle latitude
, Angle longitude
)
64 if (latitude
== null || longitude
== null)
66 String msg
= Logging
.getMessage("nullValue.AngleIsNull");
67 Logging
.logger().severe(msg
);
68 throw new IllegalArgumentException(msg
);
71 return this.computePointFromPosition(latitude
, longitude
, 0d
).getLength3();
74 public double getRadiusAt(LatLon latLon
)
78 String msg
= Logging
.getMessage("nullValue.LatLonIsNull");
79 Logging
.logger().severe(msg
);
80 throw new IllegalArgumentException(msg
);
83 return this.computePointFromPosition(latLon
.getLatitude(), latLon
.getLongitude(), 0d
).getLength3();
86 public double getEccentricitySquared()
91 public final double getDiameter()
93 return this.equatorialRadius
* 2;
96 public final Vec4
getCenter()
101 public double getMaxElevation()
103 return this.elevationModel
.getMaximumElevation();
106 public double getMinElevation()
108 return this.elevationModel
.getMinimumElevation();
111 public final Extent
getExtent()
116 public boolean intersects(Frustum frustum
)
120 String message
= Logging
.getMessage("nullValue.FrustumIsNull");
121 Logging
.logger().severe(message
);
122 throw new IllegalArgumentException(message
);
125 return frustum
.intersects(this);
128 public Intersection
[] intersect(Line line
)
130 return this.intersect(line
, this.equatorialRadius
, this.polarRadius
);
133 public Intersection
[] intersect(Line line
, double altitude
)
135 return this.intersect(line
, this.equatorialRadius
+ altitude
, this.polarRadius
+ altitude
);
138 private Intersection
[] intersect(Line line
, double equRadius
, double polRadius
)
142 String message
= Logging
.getMessage("nullValue.LineIsNull");
143 Logging
.logger().severe(message
);
144 throw new IllegalArgumentException(message
);
147 // Taken from Lengyel, 2Ed., Section 5.2.3, page 148.
148 double m
= equRadius
/ polRadius
;
149 double n
= 1d
; //this.equatorialRadius / this.equatorialRadius;
153 double vx
= line
.getDirection().x
;
154 double vy
= line
.getDirection().y
;
155 double vz
= line
.getDirection().z
;
156 double sx
= line
.getOrigin().x
;
157 double sy
= line
.getOrigin().y
;
158 double sz
= line
.getOrigin().z
;
160 double a
= vx
* vx
+ m2
* vy
* vy
+ n2
* vz
* vz
;
161 double b
= 2d
* (sx
* vx
+ m2
* sy
* vy
+ n2
* sz
* vz
);
162 double c
= sx
* sx
+ m2
* sy
* sy
+ n2
* sz
* sz
- equRadius
* polRadius
;
164 double discriminant
= discriminant(a
, b
, c
);
165 if (discriminant
< 0)
168 double discriminantRoot
= Math
.sqrt(discriminant
);
169 if (discriminant
== 0)
171 Vec4 p
= line
.getPointAt((-b
- discriminantRoot
) / (2 * a
));
172 return new Intersection
[] {new Intersection(p
, true)};
174 else // (discriminant > 0)
176 Vec4 near
= line
.getPointAt((-b
- discriminantRoot
) / (2 * a
));
177 Vec4 far
= line
.getPointAt((-b
+ discriminantRoot
) / (2 * a
));
178 return new Intersection
[] {new Intersection(near
, false), new Intersection(far
, false)};
182 static private double discriminant(double a
, double b
, double c
)
184 return b
* b
- 4 * a
* c
;
187 public boolean intersects(Line line
)
191 String msg
= Logging
.getMessage("nullValue.LineIsNull");
192 Logging
.logger().severe(msg
);
193 throw new IllegalArgumentException(msg
);
196 return line
.distanceTo(this.center
) <= this.equatorialRadius
;
199 public boolean intersects(Plane plane
)
203 String msg
= Logging
.getMessage("nullValue.PlaneIsNull");
204 Logging
.logger().severe(msg
);
205 throw new IllegalArgumentException(msg
);
208 double dq1
= plane
.dot(this.center
);
209 return dq1
<= this.equatorialRadius
;
212 public Vec4
computeSurfaceNormalAtPoint(Vec4 p
)
216 String msg
= Logging
.getMessage("nullValue.PointIsNull");
217 Logging
.logger().severe(msg
);
218 throw new IllegalArgumentException(msg
);
221 p
= p
.subtract3(this.center
);
224 p
.x
/ (this.equatorialRadius
* this.equatorialRadius
),
225 p
.y
/ (this.polarRadius
* this.polarRadius
),
226 p
.z
/ (this.equatorialRadius
* this.equatorialRadius
)).normalize3();
229 public final ElevationModel
getElevationModel()
231 return this.elevationModel
;
234 public final double getElevation(Angle latitude
, Angle longitude
)
236 if (latitude
== null || longitude
== null)
238 String message
= Logging
.getMessage("nullValue.LatitudeOrLongitudeIsNull");
239 Logging
.logger().severe(message
);
240 throw new IllegalArgumentException(message
);
243 return this.elevationModel
!= null ?
this.elevationModel
.getElevation(latitude
, longitude
) : 0;
246 public final Vec4
computePointFromPosition(Position position
)
248 if (position
== null)
250 String message
= Logging
.getMessage("nullValue.PositionIsNull");
251 Logging
.logger().severe(message
);
252 throw new IllegalArgumentException(message
);
255 return this.geodeticToCartesian(position
.getLatitude(), position
.getLongitude(), position
.getElevation());
258 public final Vec4
computePointFromPosition(Angle latitude
, Angle longitude
, double metersElevation
)
260 if (latitude
== null || longitude
== null)
262 String message
= Logging
.getMessage("nullValue.LatitudeOrLongitudeIsNull");
263 Logging
.logger().severe(message
);
264 throw new IllegalArgumentException(message
);
267 return this.geodeticToCartesian(latitude
, longitude
, metersElevation
);
270 public final Position
computePositionFromPoint(Vec4 point
)
274 String message
= Logging
.getMessage("nullValue.PointIsNull");
275 Logging
.logger().severe(message
);
276 throw new IllegalArgumentException(message
);
279 return this.cartesianToGeodetic(point
);
282 public final Position
getIntersectionPosition(Line line
)
286 String msg
= Logging
.getMessage("nullValue.LineIsNull");
287 Logging
.logger().severe(msg
);
288 throw new IllegalArgumentException(msg
);
291 Intersection
[] intersections
= this.intersect(line
);
292 if (intersections
== null)
295 return this.computePositionFromPoint(intersections
[0].getIntersectionPoint());
298 // The code below maps latitude / longitude position to globe-centered Cartesian coordinates.
299 // The Y axis points to the north pole. The Z axis points to the intersection of the prime
300 // meridian and the equator, in the equatorial plane. The X axis completes a right-handed
301 // coordinate system, and is 90 degrees east of the Z axis and also in the equatorial plane.
303 private Vec4
geodeticToCartesian(Angle latitude
, Angle longitude
, double metersElevation
)
305 if (latitude
== null || longitude
== null)
307 String message
= Logging
.getMessage("nullValue.LatitudeOrLongitudeIsNull");
308 Logging
.logger().severe(message
);
309 throw new IllegalArgumentException(message
);
312 double cosLat
= latitude
.cos();
313 double sinLat
= latitude
.sin();
315 double rpm
= // getRadius (in meters) of vertical in prime meridian
316 this.equatorialRadius
/ Math
.sqrt(1.0 - this.es
* sinLat
* sinLat
);
318 double x
= (rpm
+ metersElevation
) * cosLat
* longitude
.sin();
319 double y
= (rpm
* (1.0 - this.es
) + metersElevation
) * sinLat
;
320 double z
= (rpm
+ metersElevation
) * cosLat
* longitude
.cos();
322 return new Vec4(x
, y
, z
);
325 private Position
cartesianToGeodetic(Vec4 cart
)
329 String message
= Logging
.getMessage("nullValue.PointIsNull");
330 Logging
.logger().severe(message
);
331 throw new IllegalArgumentException(message
);
336 // Direct transformation from geocentric to geodetic ccordinates,
337 // Journal of Geodesy (2002) 76:451-454
338 double ra2
= 1 / (this.equatorialRadius
* equatorialRadius
);
341 //noinspection SuspiciousNameCombination
347 double XXpYY
= X
* X
+ Y
* Y
;
348 double sqrtXXpYY
= Math
.sqrt(XXpYY
);
349 double p
= XXpYY
* ra2
;
350 double q
= Z
* Z
* (1 - e2
) * ra2
;
351 double r
= 1 / 6.0 * (p
+ q
- e4
);
352 double s
= e4
* p
* q
/ (4 * r
* r
* r
);
353 double t
= Math
.pow(1 + s
+ Math
.sqrt(s
* (2 + s
)), 1 / 3.0);
354 double u
= r
* (1 + t
+ 1 / t
);
355 double v
= Math
.sqrt(u
* u
+ e4
* q
);
356 double w
= e2
* (u
+ v
- q
) / (2 * v
);
357 double k
= Math
.sqrt(u
+ v
+ w
* w
) - w
;
358 double D
= k
* sqrtXXpYY
/ (k
+ e2
);
359 double lon
= 2 * Math
.atan2(Y
, X
+ sqrtXXpYY
);
360 double sqrtDDpZZ
= Math
.sqrt(D
* D
+ Z
* Z
);
361 double lat
= 2 * Math
.atan2(Z
, D
+ sqrtDDpZZ
);
362 double elevation
= (k
+ e2
- 1) * sqrtDDpZZ
/ k
;
364 return Position
.fromRadians(lat
, lon
, elevation
);
367 public boolean equals(Object o
)
371 if (o
== null || getClass() != o
.getClass())
374 EllipsoidalGlobe that
= (EllipsoidalGlobe
) o
;
376 if (Double
.compare(that
.equatorialRadius
, equatorialRadius
) != 0)
378 if (Double
.compare(that
.es
, es
) != 0)
380 if (Double
.compare(that
.polarRadius
, polarRadius
) != 0)
382 if (center
!= null ?
!center
.equals(that
.center
) : that
.center
!= null)
384 //noinspection RedundantIfStatement
385 if (elevationModel
!= null ?
!elevationModel
.equals(that
.elevationModel
) : that
.elevationModel
!= null)
391 public int hashCode()
395 temp
= equatorialRadius
!= +0.0d ? Double
.doubleToLongBits(equatorialRadius
) : 0L;
396 result
= (int) (temp ^
(temp
>>> 32));
397 temp
= polarRadius
!= +0.0d ? Double
.doubleToLongBits(polarRadius
) : 0L;
398 result
= 31 * result
+ (int) (temp ^
(temp
>>> 32));
399 temp
= es
!= +0.0d ? Double
.doubleToLongBits(es
) : 0L;
400 result
= 31 * result
+ (int) (temp ^
(temp
>>> 32));
401 result
= 31 * result
+ (center
!= null ? center
.hashCode() : 0);
402 result
= 31 * result
+ (elevationModel
!= null ? elevationModel
.hashCode() : 0);