/Common/src/main/java/au/gov/ga/worldwind/common/view/orbit/BaseOrbitView.java
Java | 528 lines | 416 code | 71 blank | 41 comment | 66 complexity | a7281c4bf00e2b003105a63c58058e2d MD5 | raw file
Possible License(s): BSD-3-Clause
- /*******************************************************************************
- * Copyright 2012 Geoscience Australia
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- ******************************************************************************/
- package au.gov.ga.worldwind.common.view.orbit;
- import gov.nasa.worldwind.Configuration;
- import gov.nasa.worldwind.WorldWind;
- import gov.nasa.worldwind.avlist.AVKey;
- import gov.nasa.worldwind.awt.ViewInputHandler;
- import gov.nasa.worldwind.geom.Angle;
- import gov.nasa.worldwind.geom.Frustum;
- import gov.nasa.worldwind.geom.Matrix;
- import gov.nasa.worldwind.geom.Position;
- import gov.nasa.worldwind.geom.Vec4;
- import gov.nasa.worldwind.render.DrawContext;
- import gov.nasa.worldwind.util.Logging;
- import gov.nasa.worldwind.view.ViewPropertyLimits;
- import gov.nasa.worldwind.view.orbit.BasicOrbitViewLimits;
- import gov.nasa.worldwind.view.orbit.OrbitView;
- import gov.nasa.worldwind.view.orbit.OrbitViewLimits;
- import javax.media.opengl.GL;
- /**
- * Better {@link OrbitView} implementation.
- *
- * @author Michael de Hoog (michael.dehoog@ga.gov.au)
- */
- public class BaseOrbitView extends AbstractView implements OrbitView
- {
- protected final static double DEFAULT_MIN_ELEVATION = 0;
- protected final static double DEFAULT_MAX_ELEVATION = 4000000;
- protected final static Angle DEFAULT_MIN_PITCH = Angle.fromDegrees(0);
- protected final static Angle DEFAULT_MAX_PITCH = Angle.fromDegrees(120);
- protected final IViewState state;
- protected OrbitViewLimits viewLimits;
- protected boolean outOfFocus = false;
- protected final BaseOrbitViewCollisionSupport collisionSupport = new BaseOrbitViewCollisionSupport();
- protected boolean resolvingCollisions;
- protected Position appliedEyePosition;
- protected Vec4 appliedEyePoint;
- protected Position unsetEyePosition;
- public BaseOrbitView()
- {
- this.state = createViewState();
- this.viewInputHandler = createViewInputHandler();
- this.viewLimits = createOrbitViewLimits();
- this.collisionSupport.setCollisionThreshold(COLLISION_THRESHOLD);
- this.collisionSupport.setNumIterations(COLLISION_NUM_ITERATIONS);
- loadConfigurationValues();
- }
- protected IViewState createViewState()
- {
- return new ViewState();
- }
- protected ViewInputHandler createViewInputHandler()
- {
- return (ViewInputHandler) WorldWind.createConfigurationComponent(AVKey.VIEW_INPUT_HANDLER_CLASS_NAME);
- }
- protected OrbitViewLimits createOrbitViewLimits()
- {
- OrbitViewLimits viewLimits = new BasicOrbitViewLimits();
- viewLimits.setPitchLimits(DEFAULT_MIN_PITCH, DEFAULT_MAX_PITCH);
- viewLimits.setEyeElevationLimits(DEFAULT_MIN_ELEVATION, DEFAULT_MAX_ELEVATION);
- return viewLimits;
- }
- protected void loadConfigurationValues()
- {
- Position center = getCenterPosition();
- Double initLat = Configuration.getDoubleValue(AVKey.INITIAL_LATITUDE);
- Double initLon = Configuration.getDoubleValue(AVKey.INITIAL_LONGITUDE);
- double initElev = center.getElevation();
- // Set center latitude and longitude. Do not change center elevation.
- if (initLat != null && initLon != null)
- {
- setCenterPosition(Position.fromDegrees(initLat, initLon, initElev));
- }
- else if (initLat != null)
- {
- setCenterPosition(Position.fromDegrees(initLat, center.getLongitude().degrees, initElev));
- }
- else if (initLon != null)
- {
- setCenterPosition(Position.fromDegrees(center.getLatitude().degrees, initLon, initElev));
- }
- Double initHeading = Configuration.getDoubleValue(AVKey.INITIAL_HEADING);
- if (initHeading != null)
- {
- setHeading(Angle.fromDegrees(initHeading));
- }
- Double initPitch = Configuration.getDoubleValue(AVKey.INITIAL_PITCH);
- if (initPitch != null)
- {
- setPitch(Angle.fromDegrees(initPitch));
- }
- Double initAltitude = Configuration.getDoubleValue(AVKey.INITIAL_ALTITUDE);
- if (initAltitude != null)
- {
- setZoom(initAltitude);
- }
- Double initFov = Configuration.getDoubleValue(AVKey.FOV);
- if (initFov != null)
- {
- setFieldOfView(Angle.fromDegrees(initFov));
- }
- }
- public IViewState getState()
- {
- return state;
- }
- @Override
- public Position getEyePosition()
- {
- if (appliedEyePosition != null)
- {
- return appliedEyePosition;
- }
- return getCurrentEyePosition();
- }
- @Override
- public Vec4 getEyePoint()
- {
- if (appliedEyePoint != null)
- {
- return appliedEyePoint;
- }
- return getCurrentEyePoint();
- }
- @Override
- public Vec4 getUpVector()
- {
- if (globe == null)
- {
- return Vec4.ZERO;
- }
- return state.getUp(globe);
- }
- @Override
- public Vec4 getForwardVector()
- {
- if (globe == null)
- {
- return Vec4.ZERO;
- }
- return state.getForward(globe);
- }
- @Override
- public Vec4 getCenterPoint()
- {
- if (globe == null)
- {
- return Vec4.ZERO;
- }
- return state.getCenterPoint(globe);
- }
- @Override
- public Position getCenterPosition()
- {
- return state.getCenter();
- }
- @Override
- public void setCenterPosition(Position center)
- {
- state.setCenter(center);
- resolveCollisionsWithPitch();
- markOutOfFocus();
- }
- @Override
- public Vec4 getCurrentEyePoint()
- {
- if (globe == null)
- {
- return Vec4.ZERO;
- }
- return state.getEyePoint(globe);
- }
- @Override
- public Position getCurrentEyePosition()
- {
- if (globe == null)
- {
- if (unsetEyePosition != null)
- {
- return unsetEyePosition;
- }
- return Position.ZERO;
- }
- return state.getEye(globe);
- }
- @Override
- public void setOrientation(Position eyePosition, Position centerPosition)
- {
- setCenterPosition(centerPosition);
- setEyePosition(eyePosition);
- }
- @Override
- public void setEyePosition(Position eyePosition)
- {
- if (globe == null)
- {
- unsetEyePosition = eyePosition;
- return;
- }
- unsetEyePosition = null;
- state.setEye(eyePosition, globe);
- resolveCollisionsWithPitch();
- markOutOfFocus();
- }
- @Override
- public double getZoom()
- {
- return state.getZoom();
- }
- @Override
- public void setZoom(double zoom)
- {
- state.setZoom(zoom);
- resolveCollisionsWithPitch();
- markOutOfFocus();
- }
- @Override
- public Angle getHeading()
- {
- return state.getHeading();
- }
- @Override
- public void setHeading(Angle heading)
- {
- state.setHeading(heading);
- resolveCollisionsWithPitch();
- focusOnViewportCenter();
- }
- @Override
- public Angle getPitch()
- {
- return state.getPitch();
- }
- @Override
- public void setPitch(Angle pitch)
- {
- state.setPitch(pitch);
- resolveCollisionsWithPitch();
- focusOnViewportCenter();
- }
- @Override
- public Angle getRoll()
- {
- return state.getRoll();
- }
- @Override
- public void setRoll(Angle roll)
- {
- state.setRoll(roll);
- focusOnViewportCenter();
- }
- protected void resolveCollisionsWithPitch()
- {
- if (this.dc == null)
- {
- return;
- }
- if (!isDetectCollisions() || resolvingCollisions)
- {
- return;
- }
- resolvingCollisions = true;
- // Compute the near distance corresponding to the current set of values.
- // If there is no collision, 'newPitch' will be null. Otherwise it will contain a value
- // that will resolve the collision.
- double nearDistance = this.computeNearDistance(this.getCurrentEyePosition());
- Angle newPitch = this.collisionSupport.computePitchToResolveCollision(this, nearDistance, this.dc);
- if (newPitch != null)
- {
- setPitch(newPitch);
- flagHadCollisions();
- }
- resolvingCollisions = false;
- }
- protected void flagHadCollisions()
- {
- this.hadCollisions = true;
- }
- @Override
- public ViewPropertyLimits getViewPropertyLimits()
- {
- return viewLimits;
- }
- @Override
- public OrbitViewLimits getOrbitViewLimits()
- {
- return viewLimits;
- }
- @Override
- public void setOrbitViewLimits(OrbitViewLimits limits)
- {
- this.viewLimits = limits;
- }
- protected void markOutOfFocus()
- {
- outOfFocus = true;
- }
- @Override
- public boolean canFocusOnViewportCenter()
- {
- if (this.dc == null || this.globe == null)
- {
- //cannot focus on viewport center until the view has been applied at least once
- return false;
- }
- if (this.isAnimating())
- {
- //don't change the viewport center (rotation point) while the user is in the middle of changing the view
- return false;
- }
- if (Math.abs(this.getPitch().degrees) >= 90)
- {
- //don't try and focus on the viewport center if the user is pitched below the surface
- return false;
- }
- if (this.dc.getViewportCenterPosition() == null)
- {
- //cannot focus on a null point!
- return false;
- }
- return true;
- }
- @Override
- public void focusOnViewportCenter()
- {
- if (!canFocusOnViewportCenter())
- {
- return;
- }
- if (!outOfFocus)
- {
- return;
- }
- outOfFocus = false;
- //calculate the center point in cartesian space
- Position viewportCenter = this.dc.getViewportCenterPosition();
- double elevation = this.globe.getElevation(viewportCenter.latitude, viewportCenter.longitude);
- Position viewportExaggerated = new Position(viewportCenter, elevation * dc.getVerticalExaggeration());
- Vec4 viewportCenterPoint = this.globe.computePointFromPosition(viewportExaggerated);
- //find a point along the forward vector so the view doesn't appear to change, only the distance from the center point
- Vec4 eyePoint = getCurrentEyePoint();
- Vec4 forward = getForwardVector();
- double distance = eyePoint.distanceTo3(viewportCenterPoint);
- Vec4 newCenterPoint = Vec4.fromLine3(eyePoint, distance, forward);
- state.setCenter(globe.computePositionFromPoint(newCenterPoint));
- state.setZoom(distance);
- }
- @Override
- public void stopMovementOnCenter()
- {
- firePropertyChange(CENTER_STOPPED, null, null);
- }
- @Override
- protected void doApply(DrawContext dc)
- {
- if (dc == null)
- {
- String message = Logging.getMessage("nullValue.DrawContextIsNull"); //$NON-NLS-1$
- Logging.logger().severe(message);
- throw new IllegalArgumentException(message);
- }
- if (dc.getGL() == null)
- {
- String message = Logging.getMessage("nullValue.DrawingContextGLIsNull"); //$NON-NLS-1$
- Logging.logger().severe(message);
- throw new IllegalArgumentException(message);
- }
- if (dc.getGlobe() == null)
- {
- String message = Logging.getMessage("nullValue.DrawingContextGlobeIsNull"); //$NON-NLS-1$
- Logging.logger().severe(message);
- throw new IllegalArgumentException(message);
- }
- if (unsetEyePosition != null)
- {
- setEyePosition(unsetEyePosition);
- }
- beforeComputeMatrices();
- //========== modelview matrix state ==========//
- // Compute the current modelview matrix.
- this.modelview = computeModelView();
- if (this.modelview == null)
- {
- this.modelview = Matrix.IDENTITY;
- }
- // Compute the current inverse-modelview matrix.
- this.modelviewInv = this.modelview.getInverse();
- if (this.modelviewInv == null)
- {
- this.modelviewInv = Matrix.IDENTITY;
- }
- //========== projection matrix state ==========//
- // Get the current OpenGL viewport state.
- this.viewport = computeViewport(dc);
- // Compute the current clip plane distances.
- this.nearClipDistance = this.computeNearClipDistance();
- this.farClipDistance = this.computeFarClipDistance();
- // Compute the current projection matrix.
- this.projection = computeProjection(this.fieldOfView, this.nearClipDistance, this.farClipDistance);
- // Compute the current frustum.
- this.frustum = computeFrustum(this.nearClipDistance, this.farClipDistance);
- //========== load GL matrix state ==========//
- loadGLViewState(dc, this.modelview, this.projection);
- afterDoApply();
- }
- protected void afterDoApply()
- {
- // Establish frame-specific values.
- this.horizonDistance = this.computeHorizonDistance();
- this.appliedEyePosition = getCurrentEyePosition();
- this.appliedEyePoint = getCurrentEyePoint();
- // Clear cached computations.
- this.lastFrustumInModelCoords = null;
- }
- protected void beforeComputeMatrices()
- {
- }
- protected java.awt.Rectangle computeViewport(DrawContext dc)
- {
- int[] viewportArray = new int[4];
- this.dc.getGL().glGetIntegerv(GL.GL_VIEWPORT, viewportArray, 0);
- return new java.awt.Rectangle(viewportArray[0], viewportArray[1], viewportArray[2], viewportArray[3]);
- }
- protected Matrix computeModelView()
- {
- if (globe == null)
- {
- return Matrix.IDENTITY;
- }
- return state.getTransform(globe);
- }
- protected Matrix computeProjection(Angle horizontalFieldOfView, double nearDistance, double farDistance)
- {
- double viewportWidth = this.viewport.width <= 0.0 ? 1.0 : this.viewport.width;
- double viewportHeight = this.viewport.height <= 0.0 ? 1.0 : this.viewport.height;
- return Matrix.fromPerspective(horizontalFieldOfView, viewportWidth, viewportHeight, nearDistance, farDistance);
- }
- protected Frustum computeFrustum(double nearDistance, double farDistance)
- {
- int viewportWidth = this.viewport.width <= 0.0 ? 1 : (int) this.viewport.width;
- int viewportHeight = this.viewport.height <= 0.0 ? 1 : (int) this.viewport.height;
- return Frustum.fromPerspective(this.fieldOfView, viewportWidth, viewportHeight, nearDistance, farDistance);
- }
- }