2 Copyright (C) 2001, 2006 United States Government as represented by
3 the Administrator of the National Aeronautics and Space Administration.
6 package gov
.nasa
.worldwind
;
8 import gov
.nasa
.worldwind
.geom
.*;
9 import gov
.nasa
.worldwind
.geom
.Point
;
11 import javax
.media
.opengl
.*;
12 import javax
.media
.opengl
.glu
.*;
14 import java
.util
.logging
.Level
;
17 * @author Paul Collins
18 * @version $Id: AbstractView.java 1794 2007-05-08 22:07:21Z dcollins $
20 public abstract class AbstractView
extends WWObjectImpl
implements View
22 private static final Double DefaultFov
;
26 DefaultFov
= Configuration
.getDoubleValue(AVKey
.FOV
, 45d
);
29 // Current OpenGL viewing state.
30 private Matrix4 modelView
;
31 private Matrix4 projection
;
32 private Rectangle viewport
;
33 private Angle fieldOfView
= Angle
.fromDegrees(DefaultFov
);
34 // Current DrawContext state.
35 private Globe globe
= null;
36 private double verticalExaggeration
= -1;
37 // Cached viewing attribute computations.
38 private Point eye
= null;
39 private Point up
= null;
40 private Point forward
= null;
41 private Frustum frustumInModelCoords
= null;
42 private double pixelSizeScale
= -1;
43 private double horizonDistance
= -1;
45 private static final int[] matrixMode
= new int[1];
46 private static final int[] viewportArray
= new int[4];
48 public void apply(DrawContext dc
)
50 validateDrawContext(dc
);
51 this.globe
= dc
.getGlobe();
52 this.verticalExaggeration
= dc
.getVerticalExaggeration();
54 // Get the current OpenGL viewport state.
55 dc
.getGL().glGetIntegerv(GL
.GL_VIEWPORT
, viewportArray
, 0);
56 this.viewport
= new Rectangle(viewportArray
[0], viewportArray
[1], viewportArray
[2], viewportArray
[3]);
58 this.clearCachedAttributes();
62 protected abstract void doApply(DrawContext dc
);
64 private void clearCachedAttributes()
69 this.frustumInModelCoords
= null;
70 this.pixelSizeScale
= -1;
71 this.horizonDistance
= -1;
74 protected void applyMatrixState(DrawContext dc
, Matrix4 modelView
, Matrix4 projection
)
76 validateDrawContext(dc
);
77 if (modelView
== null)
79 String message
= WorldWind
.retrieveErrMsg("AbstractView.ModelViewIsNull");
80 WorldWind
.logger().log(Level
.FINE
, message
);
82 if (projection
== null)
84 String message
= WorldWind
.retrieveErrMsg("AbstractView.ProjectionIsNull");
85 WorldWind
.logger().log(Level
.FINE
, message
);
90 // Store the current matrix-mode state.
91 gl
.glGetIntegerv(GL
.GL_MATRIX_MODE
, matrixMode
, 0);
92 int newMatrixMode
= matrixMode
[0];
94 // Apply the model-view matrix to the current OpenGL context held by 'dc'.
95 if (newMatrixMode
!= GL
.GL_MODELVIEW
)
97 newMatrixMode
= GL
.GL_MODELVIEW
;
98 gl
.glMatrixMode(newMatrixMode
);
100 if (modelView
!= null)
101 gl
.glLoadMatrixd(modelView
.getEntries(), 0);
105 // Apply the projection matrix to the current OpenGL context held by 'dc'.
106 newMatrixMode
= GL
.GL_PROJECTION
;
107 gl
.glMatrixMode(newMatrixMode
);
108 if (projection
!= null)
109 gl
.glLoadMatrixd(projection
.getEntries(), 0);
113 // Restore matrix-mode state.
114 if (newMatrixMode
!= matrixMode
[0])
115 gl
.glMatrixMode(matrixMode
[0]);
117 this.modelView
= modelView
;
118 this.projection
= projection
;
121 protected void validateDrawContext(DrawContext dc
)
125 String message
= WorldWind
.retrieveErrMsg("nullValue.DrawContextIsNull");
126 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
127 throw new IllegalArgumentException(message
);
130 if (dc
.getGL() == null)
132 String message
= WorldWind
.retrieveErrMsg("AbstractView.DrawingContextGLIsNull");
133 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
134 throw new IllegalStateException(message
);
138 public Matrix4
getModelViewMatrix()
140 return this.modelView
;
143 public Matrix4
getProjectionMatrix()
145 return this.projection
;
148 public java
.awt
.Rectangle
getViewport()
150 return this.viewport
;
153 public Frustum
getFrustumInModelCoordinates()
155 if (this.frustumInModelCoords
== null)
157 // Compute the current model-view coordinate frustum.
158 Frustum frust
= this.getFrustum();
159 if (frust
!= null && this.modelView
!= null)
160 this.frustumInModelCoords
= frust
.getInverseTransformed(this.modelView
);
162 return this.frustumInModelCoords
;
165 public Angle
getFieldOfView()
167 return this.fieldOfView
;
170 public void setFieldOfView(Angle newFov
)
174 String message
= WorldWind
.retrieveErrMsg("nullValue.AngleIsNull");
175 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
176 throw new IllegalArgumentException(message
);
178 this.fieldOfView
= newFov
;
181 public void pushReferenceCenter(DrawContext dc
, Point referenceCenter
)
183 validateDrawContext(dc
);
184 if (referenceCenter
== null)
186 String message
= WorldWind
.retrieveErrMsg("nullValue.PointIsNull");
187 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
188 throw new IllegalArgumentException(message
);
191 Matrix4 newModelView
;
192 if (this.modelView
!= null)
194 newModelView
= new Matrix4(this.modelView
.getEntries());
195 Matrix4 reference
= new Matrix4();
196 reference
.translate(referenceCenter
);
197 newModelView
.multiply(reference
);
201 newModelView
= new Matrix4();
205 // Store the current matrix-mode state.
206 gl
.glGetIntegerv(GL
.GL_MATRIX_MODE
, matrixMode
, 0);
207 // Push and load a new model-view matrix to the current OpenGL context held by 'dc'.
208 if (matrixMode
[0] != GL
.GL_MODELVIEW
)
209 gl
.glMatrixMode(GL
.GL_MODELVIEW
);
211 gl
.glLoadMatrixd(newModelView
.getEntries(), 0);
212 // Restore matrix-mode state.
213 if (matrixMode
[0] != GL
.GL_MODELVIEW
)
214 gl
.glMatrixMode(matrixMode
[0]);
217 public void popReferenceCenter(DrawContext dc
)
219 validateDrawContext(dc
);
221 // Store the current matrix-mode state.
222 gl
.glGetIntegerv(GL
.GL_MATRIX_MODE
, matrixMode
, 0);
223 // Pop a model-view matrix off the current OpenGL context held by 'dc'.
224 if (matrixMode
[0] != GL
.GL_MODELVIEW
)
225 gl
.glMatrixMode(GL
.GL_MODELVIEW
);
227 // Restore matrix-mode state.
228 if (matrixMode
[0] != GL
.GL_MODELVIEW
)
229 gl
.glMatrixMode(matrixMode
[0]);
232 public Point
getEyePoint()
234 if (this.eye
== null)
237 if (this.modelView
!= null && (modelViewInv
= this.modelView
.getInverse()) != null)
238 this.eye
= modelViewInv
.transform(new Point(0, 0, 0, 1));
243 public Point
getUpVector()
248 if (this.modelView
!= null && (modelViewInv
= this.modelView
.getInverse()) != null)
249 this.up
= modelViewInv
.transform(new Point(0, 1, 0, 0));
254 public Point
getForwardVector()
256 if (this.forward
== null)
259 if (this.modelView
!= null && (modelViewInv
= this.modelView
.getInverse()) != null)
260 this.forward
= modelViewInv
.transform(new Point(0, 0, -1, 0));
265 // TODO: this should be expressed in OpenGL screen coordinates, not toolkit (e.g. AWT) coordinates
266 public Line
computeRayFromScreenPoint(double x
, double y
)
268 if (this.viewport
== null)
270 double yInv
= this.viewport
.height
- y
- 1; // TODO: should be computed by caller
271 Point a
= this.unProject(new Point(x
, yInv
, 0, 0));
272 Point b
= this.unProject(new Point(x
, yInv
, 1, 0));
273 if (a
== null || b
== null)
275 return new Line(a
, b
.subtract(a
).normalize());
278 // TODO: rename?, remove?
279 public Position
computePositionFromScreenPoint(double x
, double y
)
281 Line line
= this.computeRayFromScreenPoint(x
, y
);
284 if (this.globe
== null)
286 return this.globe
.getIntersectionPosition(line
);
289 public double computePixelSizeAtDistance(double distance
)
291 if (this.pixelSizeScale
< 0)
293 // Compute the current coefficient for computing the size of a pixel.
294 if (this.fieldOfView
!= null && this.viewport
.width
> 0)
295 this.pixelSizeScale
= 2 * fieldOfView
.tanHalfAngle() / (double) this.viewport
.width
;
296 else if (this.viewport
.width
> 0)
297 this.pixelSizeScale
= 1 / (double) this.viewport
.width
;
299 if (this.pixelSizeScale
< 0)
301 return this.pixelSizeScale
* Math
.abs(distance
);
304 public double computeHorizonDistance()
306 if (this.horizonDistance
< 0)
308 this.horizonDistance
= this.computeHorizonDistance(this.globe
, this.verticalExaggeration
,
311 return this.horizonDistance
;
314 protected double computeHorizonDistance(Globe globe
, double verticalExaggeration
, Point eyePoint
)
316 if (globe
== null || eyePoint
== null)
319 // Compute the current (approximate) distance from eye to globe horizon.
320 Position eyePosition
= globe
.computePositionFromPoint(eyePoint
);
321 double elevation
= verticalExaggeration
322 * globe
.getElevation(eyePosition
.getLatitude(), eyePosition
.getLongitude());
323 Point surface
= globe
.computePointFromPosition(eyePosition
.getLatitude(), eyePosition
.getLongitude(),
325 double altitude
= eyePoint
.length() - surface
.length();
326 double radius
= globe
.getMaximumRadius();
327 return Math
.sqrt(altitude
* (2 * radius
+ altitude
));
330 public Point
project(Point modelPoint
)
332 if (modelPoint
== null)
334 String message
= WorldWind
.retrieveErrMsg("nullValue.PointIsNull");
335 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
336 throw new IllegalArgumentException(message
);
338 if (this.modelView
== null || this.projection
== null || this.viewport
== null)
340 Point eyeCoord
= this.modelView
.transform(new Point(modelPoint
.x(), modelPoint
.y(), modelPoint
.z(), 1));
341 Point clipCoord
= this.projection
.transform(eyeCoord
);
342 if (clipCoord
.w() == 0)
344 Point normDeviceCoord
= new Point(clipCoord
.x() / clipCoord
.w(), clipCoord
.y() / clipCoord
.w(),
345 clipCoord
.z() / clipCoord
.w(), 0);
347 (normDeviceCoord
.x() + 1) * (this.viewport
.width
/ 2d
) + this.viewport
.x
,
348 (normDeviceCoord
.y() + 1) * (this.viewport
.height
/ 2d
) + this.viewport
.y
,
349 (normDeviceCoord
.z() + 1) / 2d
,
353 public Point
unProject(Point windowPoint
)
355 if (windowPoint
== null)
357 String message
= WorldWind
.retrieveErrMsg("nullValue.PointIsNull");
358 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
359 throw new IllegalArgumentException(message
);
362 if (this.modelView
== null || this.projection
== null || this.viewport
== null)
364 double[] projectionMatrix
= this.projection
.getEntries();
365 double[] modelViewMatrix
= this.modelView
.getEntries();
366 int[] viewport
= new int[] {this.viewport
.x
, this.viewport
.y
, this.viewport
.width
, this.viewport
.height
};
367 double[] modelPoint
= new double[3];
369 if (glu
.gluUnProject(windowPoint
.x(), windowPoint
.y(), windowPoint
.z(), modelViewMatrix
, 0, projectionMatrix
, 0,
370 viewport
, 0, modelPoint
, 0))
371 return new Point(modelPoint
[0], modelPoint
[1], modelPoint
[2], 0d
);
375 // TODO: uncomment this when Matrix4.getInverse() is fixed
376 // if (projection == null || modelView == null || viewport == null)
378 // Point ndCoord = new Point(
379 // 2 * (windowPoint.x() - viewport.getX()) / (double) viewport.width - 1,
380 // 2 * (windowPoint.y() - viewport.getY()) / (double) viewport.height - 1,
381 // 2 * windowPoint.z() - 1,
383 // Matrix m = new Matrix4(modelView.getEntries());
384 // m.multiply(projection);
385 // Point clipCoord = m.getInverse().transform(ndCoord);
386 // if (clipCoord.w() == 0)
388 // return new Point(clipCoord.x() / clipCoord.w(), clipCoord.y() / clipCoord.w(),
389 // clipCoord.z() / clipCoord.w(), 0);