All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.nasa.worldwind.view.firstperson.BasicFlyView Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */
package gov.nasa.worldwind.view.firstperson;

import gov.nasa.worldwind.Configuration;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.util.Logging;
import gov.nasa.worldwind.view.*;

import com.jogamp.opengl.GL;

/**
 * This is a basic view that implements a yaw-pitch-roll model that can be applied to first-person style view
 * applications (such as flight simulation).
 * 

* Note that the pitch angle is defined as normal to the ground plane, not parallel as in most body axis * representations. This is to be consistent with the definition of pitch within WorldWind. Applications will need to * correct for pitch values by adding 90 degrees when commanding pitch (i.e. to get a horizontal view, enter 90 degrees * pitch. To get straight down, enter 0 degrees). * * @author jym * @author M. Duquette * @version $Id: BasicFlyView.java 1933 2014-04-14 22:54:19Z dcollins $ */ public class BasicFlyView extends BasicView { protected final static double DEFAULT_MIN_ELEVATION = 0; protected final static double DEFAULT_MAX_ELEVATION = 4000000; protected final static Angle DEFAULT_MIN_PITCH = Angle.ZERO; protected final static Angle DEFAULT_MAX_PITCH = Angle.fromDegrees(180); public BasicFlyView() { this.viewInputHandler = new FlyViewInputHandler(); this.viewLimits = new FlyViewLimits(); this.viewLimits.setPitchLimits(DEFAULT_MIN_PITCH, DEFAULT_MAX_PITCH); this.viewLimits.setEyeElevationLimits(DEFAULT_MIN_ELEVATION, DEFAULT_MAX_ELEVATION); loadConfigurationValues(); } protected void loadConfigurationValues() { Double initLat = Configuration.getDoubleValue(AVKey.INITIAL_LATITUDE); Double initLon = Configuration.getDoubleValue(AVKey.INITIAL_LONGITUDE); double initElev = 50000.0; // Set center latitude and longitude. Do not change center elevation. Double initAltitude = Configuration.getDoubleValue(AVKey.INITIAL_ALTITUDE); if (initAltitude != null) initElev = initAltitude; if (initLat != null && initLon != null) { initElev = ((FlyViewLimits) viewLimits).limitEyeElevation(initElev); setEyePosition(Position.fromDegrees(initLat, initLon, initElev)); } // Set only center latitude. Do not change center longitude or center elevation. else if (initLat != null) setEyePosition(Position.fromDegrees(initLat, this.eyePosition.getLongitude().degrees, initElev)); // Set only center longitude. Do not center latitude or center elevation. else if (initLon != null) setEyePosition(Position.fromDegrees(this.eyePosition.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 initFov = Configuration.getDoubleValue(AVKey.FOV); if (initFov != null) setFieldOfView(Angle.fromDegrees(initFov)); } @Override public void setEyePosition(Position eyePosition) { if (eyePosition == null) { String message = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (this.getGlobe() != null) { double elevation = ((FlyViewLimits) this.viewLimits).limitEyeElevation( eyePosition, this.getGlobe()); LatLon location = BasicViewPropertyLimits.limitEyePositionLocation( eyePosition.getLatitude(), eyePosition.getLongitude(), this.viewLimits); this.eyePosition = new Position(location, elevation); } else { LatLon location = BasicViewPropertyLimits.limitEyePositionLocation( eyePosition.getLatitude(), eyePosition.getLongitude(), this.viewLimits); this.eyePosition = new Position(location, eyePosition.getElevation()); this.eyePosition = eyePosition; } this.updateModelViewStateID(); } public Matrix getModelViewMatrix(Position eyePosition, Position centerPosition) { if (eyePosition == null || centerPosition == null) { String message = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (this.globe == null) { String message = Logging.getMessage("nullValue.DrawingContextGlobeIsNull"); Logging.logger().severe(message); throw new IllegalStateException(message); } Vec4 newEyePoint = this.globe.computePointFromPosition(eyePosition); Vec4 newCenterPoint = this.globe.computePointFromPosition(centerPosition); if (newEyePoint == null || newCenterPoint == null) { String message = Logging.getMessage("View.ErrorSettingOrientation", eyePosition, centerPosition); Logging.logger().severe(message); throw new IllegalArgumentException(message); } // If eye lat/lon != center lat/lon, then the surface normal at the center point will be a good value // for the up direction. Vec4 up = this.globe.computeSurfaceNormalAtPoint(newCenterPoint); // Otherwise, estimate the up direction by using the *current* heading with the new center position. Vec4 forward = newCenterPoint.subtract3(newEyePoint).normalize3(); if (forward.cross3(up).getLength3() < 0.001) { Matrix modelview = ViewUtil.computeTransformMatrix(this.globe, eyePosition, this.heading, Angle.ZERO, Angle.ZERO); if (modelview != null) { Matrix modelviewInv = modelview.getInverse(); if (modelviewInv != null) { up = Vec4.UNIT_Y.transformBy4(modelviewInv); } } } if (up == null) { String message = Logging.getMessage("View.ErrorSettingOrientation", eyePosition, centerPosition); Logging.logger().severe(message); throw new IllegalArgumentException(message); } Matrix modelViewMatrix = ViewUtil.computeModelViewMatrix(this.globe, newEyePoint, newCenterPoint, up); return (modelViewMatrix); } public ViewUtil.ViewState getViewState(Position eyePosition, Position centerPosition) { if (eyePosition == null || centerPosition == null) { String message = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (this.globe == null) { String message = Logging.getMessage("nullValue.DrawingContextGlobeIsNull"); Logging.logger().severe(message); throw new IllegalStateException(message); } Vec4 newEyePoint = this.globe.computePointFromPosition(eyePosition); Vec4 newCenterPoint = this.globe.computePointFromPosition(centerPosition); if (newEyePoint == null || newCenterPoint == null) { String message = Logging.getMessage("View.ErrorSettingOrientation", eyePosition, centerPosition); Logging.logger().severe(message); throw new IllegalArgumentException(message); } // If eye lat/lon != center lat/lon, then the surface normal at the center point will be a good value // for the up direction. Vec4 up = this.globe.computeSurfaceNormalAtPoint(newCenterPoint); // Otherwise, estimate the up direction by using the *current* heading with the new center position. Vec4 forward = newCenterPoint.subtract3(newEyePoint).normalize3(); if (forward.cross3(up).getLength3() < 0.001) { Matrix modelview = ViewUtil.computeTransformMatrix(this.globe, eyePosition, this.heading, Angle.ZERO, Angle.ZERO); if (modelview != null) { Matrix modelviewInv = modelview.getInverse(); if (modelviewInv != null) up = Vec4.UNIT_Y.transformBy4(modelviewInv); } } if (up == null) { String message = Logging.getMessage("View.ErrorSettingOrientation", eyePosition, centerPosition); Logging.logger().severe(message); throw new IllegalArgumentException(message); } ViewUtil.ViewState viewState = ViewUtil.computeViewState(this.globe, newEyePoint, newCenterPoint, up); return (viewState); } @Override protected void doApply(DrawContext dc) { if (dc == null) { String message = Logging.getMessage("nullValue.DrawContextIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (dc.getGL() == null) { String message = Logging.getMessage("nullValue.DrawingContextGLIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (dc.getGlobe() == null) { String message = Logging.getMessage("nullValue.DrawingContextGlobeIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } // Update DrawContext and Globe references. this.dc = dc; this.globe = this.dc.getGlobe(); //========== modelview matrix state ==========// // Compute the current modelview matrix. this.modelview = ViewUtil.computeTransformMatrix(this.globe, this.eyePosition, this.heading, this.pitch, this.roll); 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. int[] viewportArray = new int[4]; this.dc.getGL().glGetIntegerv(GL.GL_VIEWPORT, viewportArray, 0); this.viewport = new java.awt.Rectangle(viewportArray[0], viewportArray[1], viewportArray[2], viewportArray[3]); // Compute the current clip plane distances. The near distance depends on the far distance, so we must compute // the far distance first. this.farClipDistance = this.computeFarClipDistance(); this.nearClipDistance = this.computeNearClipDistance(); // Compute the current viewport dimensions. double viewportWidth = this.viewport.getWidth() <= 0.0 ? 1.0 : this.viewport.getWidth(); double viewportHeight = this.viewport.getHeight() <= 0.0 ? 1.0 : this.viewport.getHeight(); // Compute the current projection matrix. this.projection = Matrix.fromPerspective(this.fieldOfView, viewportWidth, viewportHeight, this.nearClipDistance, this.farClipDistance); // Compute the current frustum. this.frustum = Frustum.fromPerspective(this.fieldOfView, (int) viewportWidth, (int) viewportHeight, this.nearClipDistance, this.farClipDistance); //========== load GL matrix state ==========// loadGLViewState(dc, this.modelview, this.projection); //========== after apply (GL matrix state) ==========// afterDoApply(); } protected void afterDoApply() { // Establish frame-specific values. this.lastEyePosition = this.computeEyePositionFromModelview(); this.horizonDistance = this.computeHorizonDistance(); // Clear cached computations. this.lastEyePoint = null; this.lastUpVector = null; this.lastForwardVector = null; this.lastFrustumInModelCoords = null; } @Override protected void setViewState(ViewUtil.ViewState viewState) { if (viewState == null) { String message = Logging.getMessage("nullValue.ViewStateIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (viewState.getPosition() != null) { Position eyePos = ViewUtil.normalizedEyePosition(viewState.getPosition()); LatLon limitedLocation = BasicViewPropertyLimits.limitEyePositionLocation( this.eyePosition.getLatitude(), this.eyePosition.getLongitude(), this.getViewPropertyLimits()); this.eyePosition = new Position(limitedLocation, eyePos.getElevation()); } this.setHeading(viewState.getHeading()); this.setPitch(viewState.getPitch()); this.setRoll(viewState.getRoll()); } @Override public void setHeading(Angle heading) { if (heading == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.heading = ViewUtil.normalizedHeading(heading); this.heading = BasicViewPropertyLimits.limitHeading(this.heading, this.getViewPropertyLimits()); this.updateModelViewStateID(); } @Override public void setPitch(Angle pitch) { if (pitch == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.pitch = ViewUtil.normalizedPitch(pitch); this.pitch = BasicViewPropertyLimits.limitPitch(this.pitch, this.getViewPropertyLimits()); this.updateModelViewStateID(); } public void setViewPropertyLimits(ViewPropertyLimits limits) { this.viewLimits = limits; this.setViewState(new ViewUtil.ViewState(this.getEyePosition(), this.getHeading(), this.getPitch(), Angle.ZERO)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy