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

gov.nasa.worldwind.view.BasicView 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;

import gov.nasa.worldwind.*;
import gov.nasa.worldwind.animation.Animator;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.awt.ViewInputHandler;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.util.*;

import com.jogamp.opengl.GL2;

/**
 * A base class from which {@link View} implementations can be derived. Currently {@link
 * gov.nasa.worldwind.view.firstperson.BasicFlyView} and {@link gov.nasa.worldwind.view.orbit.BasicOrbitView} are both
 * derived from {@link BasicView} {@link BasicView} models the view in terms of a geographic position, and a pitch,
 * heading, and roll. It provides a mapping from that geocentric view model to a 3D graphics modelview matrix. BasicView
 * also manages the projection matrix via a {@link Frustum}.
 * 

* The view model is based on * * @author jym * @version $Id: BasicView.java 2204 2014-08-07 23:35:03Z dcollins $ */ public class BasicView extends WWObjectImpl implements View { /** The field of view in degrees. */ protected Angle fieldOfView = Angle.fromDegrees(45); // Provide reasonable default values for the near and far clip distances. By default, BasicView automatically // updates these values each frame based on the current eye position relative to the surface. These default values // are provided for two reasons: // * The view can provide a reasonable value to the application until the first frame. // * Subclass implementations which may override the automatic update of clipping plane distances have reasonable // default values to fall back on. protected double nearClipDistance = MINIMUM_NEAR_DISTANCE; protected double farClipDistance = MINIMUM_FAR_DISTANCE; protected Matrix modelview = Matrix.IDENTITY; protected Matrix modelviewInv = Matrix.IDENTITY; protected Matrix projection = Matrix.IDENTITY; protected java.awt.Rectangle viewport = new java.awt.Rectangle(); protected Frustum frustum = new Frustum(); protected Frustum lastFrustumInModelCoords = null; protected ViewPropertyLimits viewLimits; protected DrawContext dc; protected boolean detectCollisions = true; protected boolean hadCollisions; protected ViewInputHandler viewInputHandler; protected Globe globe; protected Position eyePosition = Position.ZERO; protected double horizonDistance; protected Angle roll = Angle.fromDegrees(0.0); protected Angle pitch = Angle.fromDegrees(0.0); protected Angle heading = Angle.fromDegrees(0.0); protected Position lastEyePosition = null; protected Vec4 lastEyePoint = null; protected Vec4 lastUpVector = null; protected Vec4 lastForwardVector = null; /** * Identifier for the modelview matrix state. This number is incremented when one of the fields that affects the * modelview matrix is set. */ protected long viewStateID; // TODO: make configurable protected static final double MINIMUM_NEAR_DISTANCE = 1; protected static final double MINIMUM_FAR_DISTANCE = 1000; /** * The views's default worst-case depth resolution, in meters. May be specified in the World Wind configuration file * as the gov.nasa.worldwind.avkey.DepthResolution property. The default if not specified in the * configuration is 3.0 meters. */ protected static final double DEFAULT_DEPTH_RESOLUTION = Configuration.getDoubleValue(AVKey.DEPTH_RESOLUTION, 3.0); protected static final double COLLISION_THRESHOLD = 10; protected static final int COLLISION_NUM_ITERATIONS = 4; /** Construct a BasicView */ public BasicView() { } public Globe getGlobe() { return this.globe; } /** * Set the globe associated with this view. Note that the globe is reset each frame. * * @param globe New globe. */ public void setGlobe(Globe globe) { this.globe = globe; } public DrawContext getDC() { return (this.dc); } public ViewInputHandler getViewInputHandler() { return viewInputHandler; } public void setViewInputHandler(ViewInputHandler viewInputHandler) { this.viewInputHandler = viewInputHandler; } public boolean isDetectCollisions() { return this.detectCollisions; } public void setDetectCollisions(boolean detectCollisions) { this.detectCollisions = detectCollisions; } public boolean hadCollisions() { boolean result = this.hadCollisions; this.hadCollisions = false; return result; } public void copyViewState(View view) { this.globe = view.getGlobe(); Vec4 center = view.getCenterPoint(); if (center == null) { Vec4 eyePoint = view.getCurrentEyePoint(); center = eyePoint.add3(view.getForwardVector()); } setOrientation(view.getCurrentEyePosition(), globe.computePositionFromPoint(center)); } public void apply(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 IllegalStateException(message); } if (dc.getGlobe() == null) { String message = Logging.getMessage("layers.AbstractLayer.NoGlobeSpecifiedInDrawingContext"); Logging.logger().severe(message); throw new IllegalStateException(message); } if (this.viewInputHandler != null) this.viewInputHandler.apply(); doApply(dc); if (this.viewInputHandler != null) this.viewInputHandler.viewApplied(); } protected void doApply(DrawContext dc) { } public void stopMovement() { this.firePropertyChange(VIEW_STOPPED, null, this); } public java.awt.Rectangle getViewport() { // java.awt.Rectangle is mutable, so we defensively copy the viewport. return new java.awt.Rectangle(this.viewport); } public Frustum getFrustum() { return this.frustum; } public Frustum getFrustumInModelCoordinates() { if (this.lastFrustumInModelCoords == null) { Matrix modelviewTranspose = this.modelview.getTranspose(); if (modelviewTranspose != null) this.lastFrustumInModelCoords = this.frustum.transformBy(modelviewTranspose); else this.lastFrustumInModelCoords = this.frustum; } return this.lastFrustumInModelCoords; } public void setFieldOfView(Angle fieldOfView) { if (fieldOfView == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.fieldOfView = fieldOfView; } public double getNearClipDistance() { return this.nearClipDistance; } protected void setNearClipDistance(double clipDistance) { this.nearClipDistance = clipDistance; } public double getFarClipDistance() { return this.farClipDistance; } protected void setFarClipDistance(double clipDistance) { this.farClipDistance = clipDistance; } public Matrix getModelviewMatrix() { return this.modelview; } /** {@inheritDoc} */ public long getViewStateID() { return this.viewStateID; } public Angle getFieldOfView() { return this.fieldOfView; } public Vec4 project(Vec4 modelPoint) { if (modelPoint == null) { String message = Logging.getMessage("nullValue.Vec4IsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } return this.project(modelPoint, this.modelview, this.projection, this.viewport); } public Vec4 unProject(Vec4 windowPoint) { if (windowPoint == null) { String message = Logging.getMessage("nullValue.Vec4IsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } return unProject(windowPoint, this.modelview, this.projection, this.viewport); } public Vec4 getEyePoint() { if (this.lastEyePoint == null) this.lastEyePoint = Vec4.UNIT_W.transformBy4(this.modelviewInv); return this.lastEyePoint; } public Vec4 getCenterPoint() { Vec4 eyePoint = this.getEyePoint(); Intersection[] intersection = this.globe.intersect(new Line(eyePoint, this.getForwardVector()), 0); if (intersection == null) { return null; } else { return (intersection[0].getIntersectionPoint()); } } public Position getCenterPosition() { Vec4 eyePoint = this.getEyePoint(); Intersection[] intersection = this.globe.intersect(new Line(eyePoint, this.getForwardVector()), 0); Position pos = this.globe.computePositionFromPoint(intersection[0].getIntersectionPoint()); return (pos); } public Vec4 getCurrentEyePoint() { if (this.globe != null) { Matrix modelview = ViewUtil.computeTransformMatrix(this.globe, this.eyePosition, this.heading, this.pitch, this.roll); if (modelview != null) { Matrix modelviewInv = modelview.getInverse(); if (modelviewInv != null) { return Vec4.UNIT_W.transformBy4(modelviewInv); } } } return Vec4.ZERO; } public Position getCurrentEyePosition() { // This method is intended to compute the eye position from this view's current parameters. It can be called // without having previously applied this view in apply(). if (this.globe != null) { Matrix modelview = ViewUtil.computeTransformMatrix(this.globe, this.eyePosition, this.heading, this.pitch, this.roll); if (modelview != null) { Matrix modelviewInv = modelview.getInverse(); if (modelviewInv != null) { Vec4 eyePoint = Vec4.UNIT_W.transformBy4(modelviewInv); return this.globe.computePositionFromPoint(eyePoint); } } } return Position.ZERO; } public Position getEyePosition() { return this.lastEyePosition; } public void setEyePosition(Position eyePosition) { if (eyePosition == null) { String message = Logging.getMessage("nullValue.PositionIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.eyePosition = eyePosition; this.updateModelViewStateID(); //resolveCollisionsWithCenterPosition(); } public Angle getHeading() { return this.heading; } 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 = heading; this.updateModelViewStateID(); //resolveCollisionsWithPitch(); } public Angle getPitch() { return this.pitch; } public void setPitch(Angle pitch) { if (pitch == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.pitch = pitch; this.updateModelViewStateID(); //resolveCollisionsWithPitch(); } public void setRoll(Angle roll) { if (roll == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } this.roll = ViewUtil.normalizedRoll(roll); this.updateModelViewStateID(); } public Angle getRoll() { return this.roll; } public Vec4 getUpVector() { if (this.lastUpVector == null) this.lastUpVector = Vec4.UNIT_Y.transformBy4(this.modelviewInv); return this.lastUpVector; } public Vec4 getForwardVector() { if (this.lastForwardVector == null) this.lastForwardVector = Vec4.UNIT_NEGATIVE_Z.transformBy4(this.modelviewInv); return this.lastForwardVector; } /** * Returns the most up-to-date forward vector. Unlike {@link #getForwardVector()}, this method will return the * View's immediate forward vector. * * @return Vec4 of the forward axis. */ public Vec4 getCurrentForwardVector() { if (this.globe != null) { Matrix modelview = ViewUtil.computeTransformMatrix(this.globe, this.eyePosition, this.heading, this.pitch, this.roll); if (modelview != null) { Matrix modelviewInv = modelview.getInverse(); if (modelviewInv != null) { return Vec4.UNIT_NEGATIVE_Z.transformBy4(modelviewInv); } } } return null; } protected void setViewState(ViewUtil.ViewState modelCoords) { if (modelCoords != null) { if (modelCoords.getPosition() != null) { this.eyePosition = ViewUtil.normalizedEyePosition(modelCoords.getPosition()); } if (modelCoords.getHeading() != null) { this.heading = ViewUtil.normalizedHeading(modelCoords.getHeading()); } if (modelCoords.getPitch() != null) { this.pitch = ViewUtil.normalizedPitch(modelCoords.getPitch()); } if (modelCoords.getRoll() != null) { this.roll = ViewUtil.normalizedRoll(modelCoords.getRoll()); } } } public void setOrientation(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 modelCoords = ViewUtil.computeViewState( this.globe, newEyePoint, newCenterPoint, up); setViewState(modelCoords); this.updateModelViewStateID(); } public void stopAnimations() { viewInputHandler.stopAnimators(); } public boolean isAnimating() { return viewInputHandler.isAnimating(); } public void goTo(Position position, double distance) { viewInputHandler.goTo(position, distance); } public Line computeRayFromScreenPoint(double x, double y) { return ViewUtil.computeRayFromScreenPoint(this, x, y, this.modelview, this.projection, this.viewport); } public Position computePositionFromScreenPoint(double x, double y) { if (this.globe != null) { Line ray = computeRayFromScreenPoint(x, y); if (ray != null) return this.globe.getIntersectionPosition(ray); } return null; } public double computePixelSizeAtDistance(double distance) { return ViewUtil.computePixelSizeAtDistance(distance, this.fieldOfView, this.viewport); } protected Position computeEyePositionFromModelview() { if (this.globe != null) { Vec4 eyePoint = Vec4.UNIT_W.transformBy4(this.modelviewInv); return this.globe.computePositionFromPoint(eyePoint); } return Position.ZERO; } public double getHorizonDistance() { return this.horizonDistance; } protected double computeHorizonDistance() { return this.computeHorizonDistance(computeEyePositionFromModelview()); } protected double computeHorizonDistance(Position eyePosition) { if (this.globe != null && eyePosition != null) { double elevation = eyePosition.getElevation(); double elevationAboveSurface = ViewUtil.computeElevationAboveSurface(this.dc, eyePosition); return ViewUtil.computeHorizonDistance(this.globe, Math.max(elevation, elevationAboveSurface)); } return 0; } public ViewPropertyLimits getViewPropertyLimits() { return this.viewLimits; } protected double computeNearClipDistance() { return computeNearDistance(getCurrentEyePosition()); } protected double computeFarClipDistance() { return computeFarDistance(getCurrentEyePosition()); } protected double computeNearDistance(Position eyePosition) { // Compute the near clip distance in order to achieve a desired depth resolution at the far clip distance. This // computed distance is limited such that it does not intersect the terrain when possible and is never less than // a predetermined minimum (usually one). The computed near distance automatically scales with the resolution of // the OpenGL depth buffer. int depthBits = this.dc.getGLRuntimeCapabilities().getDepthBits(); double nearDistance = ViewUtil.computePerspectiveNearDistance(this.farClipDistance, DEFAULT_DEPTH_RESOLUTION, depthBits); // Prevent the near clip plane from intersecting the terrain. if (eyePosition != null && this.dc != null) { double distanceToSurface = ViewUtil.computeElevationAboveSurface(this.dc, eyePosition); if (distanceToSurface > 0) { double maxNearDistance = ViewUtil.computePerspectiveNearDistance(this.fieldOfView, distanceToSurface); if (nearDistance > maxNearDistance) nearDistance = maxNearDistance; } else { nearDistance = MINIMUM_NEAR_DISTANCE; } } // Prevent the near clip plane from becoming unnecessarily small. A very small clip plane is not useful for // rendering the World Wind scene, and significantly reduces the depth precision in the majority of the scene. if (nearDistance < MINIMUM_NEAR_DISTANCE) nearDistance = MINIMUM_NEAR_DISTANCE; return nearDistance; } protected double computeFarDistance(Position eyePosition) { double far = 0; if (eyePosition != null) { far = computeHorizonDistance(eyePosition); } return far < MINIMUM_FAR_DISTANCE ? MINIMUM_FAR_DISTANCE : far; } public Matrix getProjectionMatrix() { return this.projection; } public String getRestorableState() { RestorableSupport rs = RestorableSupport.newRestorableSupport(); // Creating a new RestorableSupport failed. RestorableSupport logged the problem, so just return null. if (rs == null) return null; this.doGetRestorableState(rs, null); return rs.getStateAsXml(); } public void restoreState(String stateInXml) { if (stateInXml == null) { String message = Logging.getMessage("nullValue.StringIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } RestorableSupport rs; try { rs = RestorableSupport.parse(stateInXml); } catch (Exception e) { // Parsing the document specified by stateInXml failed. String message = Logging.getMessage("generic.ExceptionAttemptingToParseStateXml", stateInXml); Logging.logger().severe(message); throw new IllegalArgumentException(message, e); } this.doRestoreState(rs, null); } /** * Update the modelview state identifier. This method should be called whenever one of the fields that affects the * modelview matrix is changed. */ protected void updateModelViewStateID() { this.viewStateID++; } //**************************************************************// //******************** Restorable State ***********************// //**************************************************************// protected void doGetRestorableState(RestorableSupport rs, RestorableSupport.StateObject context) { this.getViewPropertyLimits().getRestorableState(rs, rs.addStateObject(context, "viewPropertyLimits")); rs.addStateValueAsBoolean(context, "detectCollisions", this.isDetectCollisions()); if (this.getFieldOfView() != null) rs.addStateValueAsDouble(context, "fieldOfView", this.getFieldOfView().getDegrees()); rs.addStateValueAsDouble(context, "nearClipDistance", this.getNearClipDistance()); rs.addStateValueAsDouble(context, "farClipDistance", this.getFarClipDistance()); if (this.getEyePosition() != null) rs.addStateValueAsPosition(context, "eyePosition", this.getEyePosition()); if (this.getHeading() != null) rs.addStateValueAsDouble(context, "heading", this.getHeading().getDegrees()); if (this.getPitch() != null) rs.addStateValueAsDouble(context, "pitch", this.getPitch().getDegrees()); } protected void doRestoreState(RestorableSupport rs, RestorableSupport.StateObject context) { // Restore the property limits and collision detection flags before restoring the view's position and // orientation. This has the effect of ensuring that the view's position and orientation are consistent with the // current property limits and the current surface collision state. RestorableSupport.StateObject so = rs.getStateObject(context, "viewPropertyLimits"); if (so != null) this.getViewPropertyLimits().restoreState(rs, so); Boolean b = rs.getStateValueAsBoolean(context, "detectCollisions"); if (b != null) this.setDetectCollisions(b); Double d = rs.getStateValueAsDouble(context, "fieldOfView"); if (d != null) this.setFieldOfView(Angle.fromDegrees(d)); d = rs.getStateValueAsDouble(context, "nearClipDistance"); if (d != null) this.setNearClipDistance(d); d = rs.getStateValueAsDouble(context, "farClipDistance"); if (d != null) this.setFarClipDistance(d); Position p = rs.getStateValueAsPosition(context, "eyePosition"); if (p != null) this.setEyePosition(p); d = rs.getStateValueAsDouble(context, "heading"); if (d != null) this.setHeading(Angle.fromDegrees(d)); d = rs.getStateValueAsDouble(context, "pitch"); if (d != null) this.setPitch(Angle.fromDegrees(d)); } public Matrix pushReferenceCenter(DrawContext dc, Vec4 referenceCenter) { 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 IllegalStateException(message); } if (referenceCenter == null) { String message = Logging.getMessage("nullValue.PointIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } Matrix modelview = getModelviewMatrix(); // Compute a new model-view matrix with origin at referenceCenter. Matrix matrix = null; if (modelview != null) matrix = modelview.multiply(Matrix.fromTranslation(referenceCenter)); GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. // Store the current matrix-mode state. OGLStackHandler ogsh = new OGLStackHandler(); try { ogsh.pushAttrib(gl, GL2.GL_TRANSFORM_BIT); gl.glMatrixMode(GL2.GL_MODELVIEW); // Push and load a new model-view matrix to the current OpenGL context held by 'dc'. gl.glPushMatrix(); if (matrix != null) { double[] matrixArray = new double[16]; matrix.toArray(matrixArray, 0, false); gl.glLoadMatrixd(matrixArray, 0); } } finally { ogsh.pop(gl); } return matrix; } public Matrix setReferenceCenter(DrawContext dc, Vec4 referenceCenter) { 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 IllegalStateException(message); } if (referenceCenter == null) { String message = Logging.getMessage("nullValue.PointIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } Matrix modelview = getModelviewMatrix(); // Compute a new model-view matrix with origin at referenceCenter. Matrix matrix = null; if (modelview != null) matrix = modelview.multiply(Matrix.fromTranslation(referenceCenter)); if (matrix == null) return null; GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. gl.glMatrixMode(GL2.GL_MODELVIEW); double[] matrixArray = new double[16]; matrix.toArray(matrixArray, 0, false); gl.glLoadMatrixd(matrixArray, 0); return matrix; } /** * Removes the model-view matrix on top of the matrix stack, and restores the original matrix. * * @param dc the current World Wind drawing context on which the original matrix will be restored. * * @throws IllegalArgumentException if dc is null, or if the Globe or GL * instances in dc are null. */ public void popReferenceCenter(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 IllegalStateException(message); } GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. // Store the current matrix-mode state. OGLStackHandler ogsh = new OGLStackHandler(); try { ogsh.pushAttrib(gl, GL2.GL_TRANSFORM_BIT); gl.glMatrixMode(GL2.GL_MODELVIEW); // Pop the top model-view matrix. gl.glPopMatrix(); } finally { ogsh.pop(gl); } } /** * Transforms the specified object coordinates into window coordinates using the given modelview and projection * matrices, and viewport. * * @param point The object coordinate to transform * @param modelview The modelview matrix * @param projection The projection matrix * @param viewport The viewport * * @return the transformed coordinates */ public Vec4 project(Vec4 point, Matrix modelview, Matrix projection, java.awt.Rectangle viewport) { if (point == null) { String message = Logging.getMessage("nullValue.PointIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (modelview == null || projection == null) { String message = Logging.getMessage("nullValue.MatrixIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (viewport == null) { String message = Logging.getMessage("nullValue.RectangleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } // GLU expects matrices as column-major arrays. double[] modelviewArray = new double[16]; double[] projectionArray = new double[16]; modelview.toArray(modelviewArray, 0, false); projection.toArray(projectionArray, 0, false); // GLU expects the viewport as a four-component array. int[] viewportArray = new int[] {viewport.x, viewport.y, viewport.width, viewport.height}; double[] result = new double[3]; if (!this.dc.getGLU().gluProject( point.x, point.y, point.z, modelviewArray, 0, projectionArray, 0, viewportArray, 0, result, 0)) { return null; } return Vec4.fromArray3(result, 0); } /** * Maps the given window coordinates into model coordinates using the given matrices and viewport. * * @param windowPoint the window point * @param modelview the modelview matrix * @param projection the projection matrix * @param viewport the window viewport * * @return the unprojected point */ public Vec4 unProject(Vec4 windowPoint, Matrix modelview, Matrix projection, java.awt.Rectangle viewport) { if (windowPoint == null) { String message = Logging.getMessage("nullValue.PointIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (modelview == null || projection == null) { String message = Logging.getMessage("nullValue.MatrixIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (viewport == null) { String message = Logging.getMessage("nullValue.RectangleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } // GLU expects matrices as column-major arrays. double[] modelviewArray = new double[16]; double[] projectionArray = new double[16]; modelview.toArray(modelviewArray, 0, false); projection.toArray(projectionArray, 0, false); // GLU expects the viewport as a four-component array. int[] viewportArray = new int[] {viewport.x, viewport.y, viewport.width, viewport.height}; double[] result = new double[3]; if (!this.dc.getGLU().gluUnProject( windowPoint.x, windowPoint.y, windowPoint.z, modelviewArray, 0, projectionArray, 0, viewportArray, 0, result, 0)) { return null; } return Vec4.fromArray3(result, 0); } /** * Sets the the opengl modelview and projection matrices to the given matrices. * * @param dc the drawing context * @param modelview the modelview matrix * @param projection the projection matrix */ public static void loadGLViewState(DrawContext dc, Matrix modelview, Matrix projection) { 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 IllegalStateException(message); } if (modelview == null) { Logging.logger().fine("nullValue.ModelViewIsNull"); } if (projection == null) { Logging.logger().fine("nullValue.ProjectionIsNull"); } double[] matrixArray = new double[16]; GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility. // Store the current matrix-mode state. OGLStackHandler ogsh = new OGLStackHandler(); try { ogsh.pushAttrib(gl, GL2.GL_TRANSFORM_BIT); // Apply the model-view matrix to the current OpenGL context. gl.glMatrixMode(GL2.GL_MODELVIEW); if (modelview != null) { modelview.toArray(matrixArray, 0, false); gl.glLoadMatrixd(matrixArray, 0); } else { gl.glLoadIdentity(); } // Apply the projection matrix to the current OpenGL context. gl.glMatrixMode(GL2.GL_PROJECTION); if (projection != null) { projection.toArray(matrixArray, 0, false); gl.glLoadMatrixd(matrixArray, 0); } else { gl.glLoadIdentity(); } } finally { ogsh.pop(gl); } } /** * Add an animator to the this View. The View does not start the animator. * * @param animator the {@link gov.nasa.worldwind.animation.Animator} to be added */ public void addAnimator(Animator animator) { viewInputHandler.addAnimator(animator); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy