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
.*;
10 import javax
.media
.opengl
.*;
11 import javax
.media
.opengl
.glu
.*;
12 import java
.util
.logging
.Level
;
15 * @author Paul Collins
16 * @version $Id: AbstractView.java 2126 2007-06-21 21:00:42Z dcollins $
18 public abstract class AbstractView
extends WWObjectImpl
implements View
21 private boolean isInitialized
= false;
22 private final double[] matrixArray
= new double[32];
23 private final double[] vecArray
= new double[4];
24 private final int[] viewportArray
= new int[4];
26 // ============== Viewing State ======================= //
27 // ============== Viewing State ======================= //
28 // ============== Viewing State ======================= //
30 // Current OpenGL viewing state.
31 private Matrix modelView
;
32 private Matrix projection
;
33 private java
.awt
.Rectangle viewport
;
35 public void apply(DrawContext dc
)
39 String message
= WorldWind
.retrieveErrMsg("nullValue.DrawContextIsNull");
40 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
41 throw new IllegalArgumentException(message
);
44 if (dc
.getGL() == null)
46 String message
= WorldWind
.retrieveErrMsg("AbstractView.DrawingContextGLIsNull");
47 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
48 throw new IllegalStateException(message
);
51 if (dc
.getGlobe() == null)
53 String message
= WorldWind
.retrieveErrMsg("layers.AbstractLayer.NoGlobeSpecifiedInDrawingContext");
54 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
55 throw new IllegalStateException(message
);
58 if (this.isViewUpdateable(dc
))
59 this.updateViewingState(dc
);
64 public boolean isViewUpdateable(DrawContext dc
)
68 String message
= WorldWind
.retrieveErrMsg("nullValue.DrawContextIsNull");
69 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
70 throw new IllegalArgumentException(message
);
73 return !dc
.isPickingMode();
76 private void updateViewingState(DrawContext dc
)
78 this.clearAttributes();
79 this.drawContext
= dc
;
81 // Get the current OpenGL viewport state.
82 dc
.getGL().glGetIntegerv(GL
.GL_VIEWPORT
, this.viewportArray
, 0);
83 this.viewport
= new java
.awt
.Rectangle(
84 this.viewportArray
[0],
85 this.viewportArray
[1],
86 this.viewportArray
[2],
87 this.viewportArray
[3]);
89 if (!this.isInitialized
)
91 this.isInitialized
= true;
93 this.updateStateIterators(dc
);
96 protected void loadModelViewProjection(DrawContext dc
, Matrix modelView
, Matrix projection
)
100 String message
= WorldWind
.retrieveErrMsg("nullValue.DrawContextIsNull");
101 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
102 throw new IllegalArgumentException(message
);
105 if (dc
.getGL() == null)
107 String message
= WorldWind
.retrieveErrMsg("AbstractView.DrawingContextGLIsNull");
108 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
109 throw new IllegalStateException(message
);
112 if (modelView
== null)
114 String message
= WorldWind
.retrieveErrMsg("AbstractView.ModelViewIsNull");
115 WorldWind
.logger().log(Level
.FINE
, message
);
118 if (projection
== null)
120 String message
= WorldWind
.retrieveErrMsg("AbstractView.ProjectionIsNull");
121 WorldWind
.logger().log(Level
.FINE
, message
);
124 this.modelView
= modelView
;
125 this.projection
= projection
;
128 // Store the current matrix-mode state.
129 final int matrixMode
= this.getMatrixMode(gl
);
131 // Apply the model-view matrix to the current OpenGL context held by 'dc'.
132 this.modelView
.toArray(this.matrixArray
, 0, false);
133 gl
.glMatrixMode(GL
.GL_MODELVIEW
);
134 gl
.glLoadMatrixd(this.matrixArray
, 0);
136 // Apply the projection matrix to the current OpenGL context held by 'dc'.
137 this.projection
.toArray(this.matrixArray
, 0, false);
138 gl
.glMatrixMode(GL
.GL_PROJECTION
);
139 gl
.glLoadMatrixd(this.matrixArray
, 0);
141 // Restore matrix-mode state.
142 gl
.glMatrixMode(matrixMode
);
145 protected abstract void doApply(DrawContext dc
);
147 public Matrix
pushReferenceCenter(DrawContext dc
, Vec4 referenceCenter
)
151 String message
= WorldWind
.retrieveErrMsg("nullValue.DrawContextIsNull");
152 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
153 throw new IllegalArgumentException(message
);
156 if (dc
.getGL() == null)
158 String message
= WorldWind
.retrieveErrMsg("AbstractView.DrawingContextGLIsNull");
159 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
160 throw new IllegalStateException(message
);
163 if (referenceCenter
== null)
165 String message
= WorldWind
.retrieveErrMsg("nullValue.PointIsNull");
166 WorldWind
.logger().log(Level
.FINE
, message
);
167 throw new IllegalArgumentException(message
);
170 // Compute a new model-view matrix with origin at referenceCenter.
171 Matrix matrix
= null;
172 if (this.modelView
!= null)
173 matrix
= this.modelView
.multiply(Matrix
.fromTranslation(referenceCenter
));
176 // Store the current matrix-mode state.
177 final int matrixMode
= this.getMatrixMode(gl
);
179 if (matrixMode
!= GL
.GL_MODELVIEW
)
180 gl
.glMatrixMode(GL
.GL_MODELVIEW
);
182 // Push and load a new model-view matrix to the current OpenGL context held by 'dc'.
186 matrix
.toArray(this.matrixArray
, 0, false);
187 gl
.glLoadMatrixd(this.matrixArray
, 0);
190 // Restore matrix-mode state.
191 if (matrixMode
!= GL
.GL_MODELVIEW
)
192 gl
.glMatrixMode(matrixMode
);
197 public void popReferenceCenter(DrawContext dc
)
201 String message
= WorldWind
.retrieveErrMsg("nullValue.DrawContextIsNull");
202 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
203 throw new IllegalArgumentException(message
);
206 if (dc
.getGL() == null)
208 String message
= WorldWind
.retrieveErrMsg("AbstractView.DrawingContextGLIsNull");
209 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
210 throw new IllegalStateException(message
);
214 // Store the current matrix-mode state.
215 final int matrixMode
= this.getMatrixMode(gl
);
217 // Pop a model-view matrix off the current OpenGL context held by 'dc'.
218 if (matrixMode
!= GL
.GL_MODELVIEW
)
219 gl
.glMatrixMode(GL
.GL_MODELVIEW
);
221 // Pop the top model-view matrix.
224 // Restore matrix-mode state.
225 if (matrixMode
!= GL
.GL_MODELVIEW
)
226 gl
.glMatrixMode(matrixMode
);
229 private final int[] matrixModeArray
= new int[1];
231 private int getMatrixMode(GL gl
)
233 gl
.glGetIntegerv(GL
.GL_MATRIX_MODE
, this.matrixModeArray
, 0);
234 return this.matrixModeArray
[0];
237 // ============== Runtime Initialization ======================= //
238 // ============== Runtime Initialization ======================= //
239 // ============== Runtime Initialization ======================= //
241 private void initialize(DrawContext dc
)
243 this.fieldOfView
= getInitialFieldOfView(dc
, this.fieldOfView
);
244 this.doInitialize(dc
);
247 protected void doInitialize(DrawContext dc
)
251 protected static Angle
getInitialFieldOfView(DrawContext dc
, Angle clientValue
)
253 // Use value specified by client.
254 if (clientValue
!= null)
257 // Use value from configuration.
258 Double configValue
= Configuration
.getDoubleValue(AVKey
.FOV
);
259 if (configValue
!= null)
260 return Angle
.fromDegrees(configValue
);
263 return Angle
.fromDegrees(45.0);
266 protected static Angle
getInitialLatitude(DrawContext dc
, Angle clientValue
)
268 // Use value specified by client.
269 if (clientValue
!= null)
272 // Use value from configuration.
273 Double configValue
= Configuration
.getDoubleValue(AVKey
.INITIAL_LATITUDE
);
274 if (configValue
!= null)
275 return Angle
.fromDegrees(configValue
);
281 protected static Angle
getInitialLongitude(DrawContext dc
, Angle clientValue
)
283 // Use value specified by client.
284 if (clientValue
!= null)
287 // Use value from configuration.
288 Double configValue
= Configuration
.getDoubleValue(AVKey
.INITIAL_LONGITUDE
);
289 if (configValue
!= null)
290 return Angle
.fromDegrees(configValue
);
292 // Use longitude of system time-zone.
293 java
.util
.TimeZone tz
= java
.util
.Calendar
.getInstance().getTimeZone();
295 return Angle
.fromDegrees(180.0 * tz
.getOffset(System
.currentTimeMillis()) / (12.0 * 3.6e6
));
301 protected static Angle
getInitialHeading(DrawContext dc
, Angle clientValue
)
303 // Use value specified by client.
304 if (clientValue
!= null)
307 // Use value from configuration.
308 Double configValue
= Configuration
.getDoubleValue("null");
309 if (configValue
!= null)
310 return Angle
.fromDegrees(configValue
);
316 protected static Angle
getInitialPitch(DrawContext dc
, Angle clientValue
)
318 // Use value specified by client.
319 if (clientValue
!= null)
322 // Use value from configuration.
323 Double configValue
= Configuration
.getDoubleValue("null");
324 if (configValue
!= null)
325 return Angle
.fromDegrees(configValue
);
331 protected static double getInitialAltitude(DrawContext dc
, double clientValue
)
333 // Use value specified by client.
334 if (clientValue
>= 0.0)
337 // Use value from configuration.
338 Double configValue
= Configuration
.getDoubleValue("null");
339 if (configValue
!= null)
342 // Use globe radius with coefficient.
343 if (dc
!= null && dc
.getGlobe() != null)
344 return 3.0 * dc
.getGlobe().getRadius();
350 // ============== Attribute Accessors ======================= //
351 // ============== Attribute Accessors ======================= //
352 // ============== Attribute Accessors ======================= //
354 // Current DrawContext state.
355 private DrawContext drawContext
= null;
356 // Cached viewing attribute computations.
357 private Vec4 eye
= null;
358 private Vec4 up
= null;
359 private Vec4 forward
= null;
360 private Frustum frustumInModelCoords
= null;
361 private Angle fieldOfView
= null;
362 private double pixelSizeScale
= -1;
363 private double horizonDistance
= -1;
365 private void clearAttributes()
367 this.drawContext
= null;
371 this.frustumInModelCoords
= null;
372 this.pixelSizeScale
= -1;
373 this.horizonDistance
= -1;
376 protected DrawContext
getDrawContext()
378 return this.drawContext
;
381 public Matrix
getModelViewMatrix()
383 return this.modelView
;
386 public Matrix
getProjectionMatrix()
388 return this.projection
;
391 public java
.awt
.Rectangle
getViewport()
393 return new java
.awt
.Rectangle(this.viewport
);
396 public Frustum
getFrustumInModelCoordinates()
398 if (this.frustumInModelCoords
== null)
400 // Compute the current model-view coordinate frustum.
401 Frustum frust
= this.getFrustum();
402 if (frust
!= null && this.modelView
!= null)
403 this.frustumInModelCoords
= frust
.transformBy(this.modelView
.getTranspose());
405 return this.frustumInModelCoords
;
408 public Angle
getFieldOfView()
410 return this.fieldOfView
;
413 public void setFieldOfView(Angle newFov
)
417 String message
= WorldWind
.retrieveErrMsg("nullValue.AngleIsNull");
418 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
419 throw new IllegalArgumentException(message
);
421 this.fieldOfView
= newFov
;
424 public Vec4
getEyePoint()
426 if (this.eye
== null)
429 if (this.modelView
!= null && (modelViewInv
= this.modelView
.getInverse()) != null)
430 this.eye
= Vec4
.UNIT_W
.transformBy4(modelViewInv
);
435 public Vec4
getUpVector()
440 if (this.modelView
!= null && (modelViewInv
= this.modelView
.getInverse()) != null)
441 this.up
= Vec4
.UNIT_Y
.transformBy4(modelViewInv
);
446 public Vec4
getForwardVector()
448 if (this.forward
== null)
451 if (this.modelView
!= null && (modelViewInv
= this.modelView
.getInverse()) != null)
452 this.forward
= Vec4
.UNIT_NEGATIVE_Z
.transformBy4(modelViewInv
);
457 // ============== State Iterators ======================= //
458 // ============== State Iterators ======================= //
459 // ============== State Iterators ======================= //
461 private ViewStateIterator viewStateIterator
= null;
463 public void iterateOver(ViewStateIterator viewStateIterator
)
465 if (viewStateIterator
== null)
467 this.stopIterating();
471 this.viewStateIterator
= viewStateIterator
.coalesceWith(this, this.viewStateIterator
);
472 this.firePropertyChange(AVKey
.VIEW
, null, this);
475 public boolean isIterating()
477 return this.viewStateIterator
!= null;
480 public void stopIterating()
482 this.viewStateIterator
= null;
485 private void updateStateIterators(DrawContext dc
)
487 if (!this.isIterating())
490 if (this.viewStateIterator
.hasNextState(this))
492 this.viewStateIterator
.nextState(this);
493 this.firePropertyChange(AVKey
.VIEW
, null, this);
497 this.stopIterating();
501 // ============== Utilities ======================= //
502 // ============== Utilities ======================= //
503 // ============== Utilities ======================= //
506 private final GLU glu
= new GLU();
508 // TODO: this should be expressed in OpenGL screen coordinates, not toolkit (e.g. AWT) coordinates
509 public Line
computeRayFromScreenPoint(double x
, double y
)
511 if (this.viewport
== null)
513 double invY
= this.viewport
.height
- y
- 1; // TODO: should be computed by caller
514 Vec4 a
= this.unProject(new Vec4(x
, invY
, 0, 0));
515 Vec4 b
= this.unProject(new Vec4(x
, invY
, 1, 0));
516 if (a
== null || b
== null)
518 return new Line(a
, b
.subtract3(a
).normalize3());
521 public Position
computePositionFromScreenPoint(double x
, double y
)
523 Line line
= this.computeRayFromScreenPoint(x
, y
);
527 if (this.drawContext
== null)
530 Globe globe
= this.drawContext
.getGlobe();
534 return globe
.getIntersectionPosition(line
);
537 public double computePixelSizeAtDistance(double distance
)
539 if (this.pixelSizeScale
< 0)
541 // Compute the current coefficient for computing the size of a pixel.
542 if (this.fieldOfView
!= null && this.viewport
.width
> 0)
543 this.pixelSizeScale
= 2 * this.fieldOfView
.tanHalfAngle() / (double) this.viewport
.width
;
544 else if (this.viewport
.width
> 0)
545 this.pixelSizeScale
= 1 / (double) this.viewport
.width
;
547 if (this.pixelSizeScale
< 0)
549 return this.pixelSizeScale
* Math
.abs(distance
);
552 public double computeHorizonDistance()
554 if (this.horizonDistance
< 0)
556 if (this.drawContext
== null)
557 return this.horizonDistance
;
559 Globe globe
= this.drawContext
.getGlobe();
561 return this.horizonDistance
;
563 this.horizonDistance
= this.computeHorizonDistance(globe
, this.drawContext
.getVerticalExaggeration(),
566 return this.horizonDistance
;
569 protected double computeHorizonDistance(Globe globe
, double verticalExaggeration
, Vec4 eyeVec
)
571 if (globe
== null || eyeVec
== null)
574 // Compute the current (approximate) distance from eye to globe horizon.
575 Position eyePosition
= globe
.computePositionFromPoint(eyeVec
);
576 double elevation
= verticalExaggeration
577 * globe
.getElevation(eyePosition
.getLatitude(), eyePosition
.getLongitude());
578 Vec4 surface
= globe
.computePointFromPosition(eyePosition
.getLatitude(), eyePosition
.getLongitude(),
580 double altitude
= eyeVec
.getLength3() - surface
.getLength3();
581 double radius
= globe
.getMaximumRadius();
582 return Math
.sqrt(altitude
* (2 * radius
+ altitude
));
585 public Vec4
project(Vec4 modelPoint
)
587 if (modelPoint
== null)
589 String message
= WorldWind
.retrieveErrMsg("nullValue.PointIsNull");
590 WorldWind
.logger().log(Level
.FINE
, message
);
591 throw new IllegalArgumentException(message
);
594 if (this.modelView
== null || this.projection
== null || this.viewport
== null)
597 this.modelView
.toArray(this.matrixArray
, 0, false);
598 this.projection
.toArray(this.matrixArray
, 16, false);
600 if (!this.glu
.gluProject(
601 modelPoint
.x
, modelPoint
.y
, modelPoint
.z
,
603 this.matrixArray
, 16,
604 this.viewportArray
, 0,
610 return Vec4
.fromArray3(this.vecArray
, 0);
613 public Vec4
unProject(Vec4 windowPoint
)
615 if (windowPoint
== null)
617 String message
= WorldWind
.retrieveErrMsg("nullValue.PointIsNull");
618 WorldWind
.logger().log(Level
.FINE
, message
);
619 throw new IllegalArgumentException(message
);
622 if (this.modelView
== null || this.projection
== null || this.viewport
== null)
625 this.modelView
.toArray(this.matrixArray
, 0, false);
626 this.projection
.toArray(this.matrixArray
, 16, false);
628 if (!this.glu
.gluUnProject(
629 windowPoint
.x
, windowPoint
.y
, windowPoint
.z
,
631 this.matrixArray
, 16,
632 this.viewportArray
, 0,
638 return Vec4
.fromArray3(this.vecArray
, 0);