gov.nasa.worldwind.view.ViewUtil 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.View;
import gov.nasa.worldwind.animation.*;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.util.Logging;
import com.jogamp.opengl.glu.GLU;
import com.jogamp.opengl.glu.gl2.GLUgl2;
import java.awt.*;
/**
* @author jym
* @version $Id: ViewUtil.java 1933 2014-04-14 22:54:19Z dcollins $
*/
public class ViewUtil
{
public static class ViewState
{
protected Position position;
protected Angle heading;
protected Angle pitch;
protected Angle roll;
public ViewState(Position position, Angle heading, Angle pitch, Angle roll)
{
this.position = position;
this.heading = heading;
this.pitch = pitch;
this.roll = roll;
}
public Position getPosition()
{
return (position);
}
public void setPosition(Position position)
{
this.position = position;
}
public Angle getRoll()
{
return (roll);
}
public void setRoll(Angle roll)
{
this.roll = roll;
}
public Angle getPitch()
{
return (pitch);
}
public void setPitch(Angle pitch)
{
this.pitch = pitch;
}
public Angle getHeading()
{
return (heading);
}
public void setHeading(Angle heading)
{
this.heading = heading;
}
}
/**
* Create an animator to animate heading.
*
* @param view View to animate
* @param begin starting heading
* @param end final heading
*
* @return An Animator to animate heading.
*/
public static AngleAnimator createHeadingAnimator(View view, Angle begin, Angle end)
{
if (begin == null || end == null)
{
String message = Logging.getMessage("nullValue.AngleIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
final long MIN_LENGTH_MILLIS = 500;
final long MAX_LENGTH_MILLIS = 3000;
long lengthMillis = AnimationSupport.getScaledTimeMillisecs(
begin, end, Angle.POS180,
MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS);
return new AngleAnimator(new ScheduledInterpolator(lengthMillis),
begin, end, new ViewPropertyAccessor.HeadingAccessor(view));
}
/**
* Create an animator to animate pitch.
*
* @param view View to animate
* @param begin starting pitch
* @param end final pitch
*
* @return An Animator to animate pitch.
*/
public static AngleAnimator createPitchAnimator(View view, Angle begin, Angle end)
{
if (begin == null || end == null)
{
String message = Logging.getMessage("nullValue.AngleIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
final long MIN_LENGTH_MILLIS = 500;
final long MAX_LENGTH_MILLIS = 3000;
long lengthMillis = AnimationSupport.getScaledTimeMillisecs(
begin, end, Angle.POS180,
MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS);
return new AngleAnimator(new ScheduledInterpolator(lengthMillis),
begin, end, new ViewPropertyAccessor.PitchAccessor(view));
}
/**
* Create an animator to animate roll.
*
* @param view View to animate
* @param begin starting roll
* @param end final roll
*
* @return An Animator to animate roll.
*/
public static AngleAnimator createRollAnimator(View view, Angle begin, Angle end)
{
if (begin == null || end == null)
{
String message = Logging.getMessage("nullValue.AngleIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
final long MIN_LENGTH_MILLIS = 500;
final long MAX_LENGTH_MILLIS = 3000;
long lengthMillis = AnimationSupport.getScaledTimeMillisecs(
begin, end, Angle.POS180,
MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS);
return new AngleAnimator(new ScheduledInterpolator(lengthMillis),
begin, end, new ViewPropertyAccessor.RollAccessor(view));
}
/**
* Create an animator to animate heading, pitch, and roll.
*
* @param view View to animate
* @param beginHeading staring heading
* @param endHeading final heading
* @param beginPitch starting pitch
* @param endPitch final pitch
* @param beginRoll starting roll
* @param endRoll final roll
*
* @return A CompoundAnimator to animate heading, pitch, and roll.
*/
public static CompoundAnimator createHeadingPitchRollAnimator(View view, Angle beginHeading, Angle endHeading,
Angle beginPitch, Angle endPitch, Angle beginRoll, Angle endRoll)
{
if (beginHeading == null || endHeading == null || beginPitch == null || endPitch == null || beginRoll == null
|| endRoll == null)
{
String message = Logging.getMessage("nullValue.AngleIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
final long MIN_LENGTH_MILLIS = 500;
final long MAX_LENGTH_MILLIS = 3000;
long headingLengthMillis = AnimationSupport.getScaledTimeMillisecs(
beginHeading, endHeading, Angle.POS180,
MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS);
long pitchLengthMillis = AnimationSupport.getScaledTimeMillisecs(
beginPitch, endPitch, Angle.POS90,
MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS / 2L);
long rollLengthMillis = AnimationSupport.getScaledTimeMillisecs(
beginRoll, endRoll, Angle.POS90,
MIN_LENGTH_MILLIS, MAX_LENGTH_MILLIS / 2L);
long lengthMillis = headingLengthMillis + pitchLengthMillis + rollLengthMillis;
AngleAnimator headingAnimator = createHeadingAnimator(view, beginHeading, endHeading);
AngleAnimator pitchAnimator = createPitchAnimator(view, beginPitch, endPitch);
AngleAnimator rollAnimator = createRollAnimator(view, beginRoll, endRoll);
CompoundAnimator headingPitchAnimator = new CompoundAnimator(new ScheduledInterpolator(lengthMillis),
headingAnimator, pitchAnimator, rollAnimator);
return (headingPitchAnimator);
}
public static PositionAnimator createEyePositionAnimator(
View view, long timeToMove, Position begin, Position end)
{
return new PositionAnimator(new ScheduledInterpolator(timeToMove),
begin, end, ViewPropertyAccessor.createEyePositionAccessor(view));
}
public static Point subtract(Point a, Point b)
{
if (a == null || b == null)
return null;
return new Point((int) (a.getX() - b.getX()), (int) (a.getY() - b.getY()));
}
public static Matrix computeTransformMatrix(Globe globe, Position position, Angle heading, Angle pitch, Angle roll)
{
if (heading == null)
{
String message = Logging.getMessage("nullValue.HeadingIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (pitch == null)
{
String message = Logging.getMessage("nullValue.PitchIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
// To get a yaw-pitch-roll transform, do the view transform in reverse (i.e. roll-pitch-yaw)
Matrix transform = Matrix.IDENTITY;
transform = transform.multiply(Matrix.fromAxisAngle(roll, 0, 0, 1));
transform = transform.multiply(Matrix.fromAxisAngle(pitch, -1, 0, 0));
transform = transform.multiply(Matrix.fromAxisAngle(heading, 0, 0, 1));
transform = transform.multiply(computePositionTransform(globe, position));
return transform;
}
public static Matrix computePositionTransform(Globe globe, Position center)
{
if (globe == null)
{
String message = Logging.getMessage("nullValue.GlobeIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (center == null)
{
String message = Logging.getMessage("nullValue.CenterIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
// The view eye position will be the same as the center position.
// This is only the case without any zoom, heading, and pitch.
Vec4 eyePoint = globe.computePointFromPosition(center);
// The view forward direction will be colinear with the
// geoid surface normal at the center position.
Vec4 normal = globe.computeSurfaceNormalAtLocation(center.getLatitude(), center.getLongitude());
Vec4 lookAtPoint = eyePoint.subtract3(normal);
// The up direction will be pointing towards the north pole.
Vec4 north = globe.computeNorthPointingTangentAtLocation(center.getLatitude(), center.getLongitude());
// Creates a viewing matrix looking from eyePoint towards lookAtPoint,
// with the given up direction. The forward, right, and up vectors
// contained in the matrix are guaranteed to be orthogonal. This means
// that the Matrix's up may not be equivalent to the specified up vector
// here (though it will point in the same general direction).
// In this case, the forward direction would not be affected.
return Matrix.fromViewLookAt(eyePoint, lookAtPoint, north);
}
public static Matrix computeModelViewMatrix(Globe globe, Vec4 eyePoint, Vec4 centerPoint, Vec4 up)
{
if (globe == null)
{
String message = Logging.getMessage("nullValue.GlobeIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (eyePoint == null)
{
String message = "nullValue.EyePointIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (centerPoint == null)
{
String message = "nullValue.CenterPointIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (up == null)
{
String message = "nullValue.UpIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
Matrix modelview = Matrix.fromViewLookAt(eyePoint, centerPoint, up);
return (modelview);
}
public static Vec4 getUpVector(Globe globe, Vec4 lookAtPoint)
{
return globe.computeSurfaceNormalAtPoint(lookAtPoint);
}
public static ViewState computeViewState(Globe globe, Vec4 eyePoint, Vec4 centerPoint, Vec4 up)
{
if (globe == null)
{
String message = Logging.getMessage("nullValue.GlobeIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (eyePoint == null)
{
String message = "nullValue.EyePointIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (centerPoint == null)
{
String message = "nullValue.CenterPointIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (up == null)
{
up = ViewUtil.getUpVector(globe, centerPoint);
}
Matrix modelview = Matrix.fromViewLookAt(eyePoint, centerPoint, up);
return ViewUtil.computeModelCoordinates(globe, modelview, centerPoint,
eyePoint);
}
public static ViewState computeModelCoordinates(Globe globe, Matrix modelTransform, Vec4 centerPoint,
Vec4 eyePoint)
{
if (globe == null)
{
String message = Logging.getMessage("nullValue.GlobeIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (modelTransform == null)
{
String message = "nullValue.ModelTransformIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
// Compute the center position.
Position centerPos = globe.computePositionFromPoint(centerPoint);
// Compute the center position transform.
Matrix centerTransform = ViewUtil.computePositionTransform(globe, centerPos);
Matrix centerTransformInv = centerTransform.getInverse();
if (centerTransformInv == null)
{
String message = Logging.getMessage("generic.NoninvertibleMatrix");
Logging.logger().severe(message);
throw new IllegalStateException(message);
}
// Compute the heading-pitch-zoom transform.
Matrix hpzTransform = modelTransform.multiply(centerTransformInv);
// Extract the heading, pitch, and zoom values from the transform.
Angle heading = ViewUtil.computeHeading(hpzTransform);
Angle pitch = ViewUtil.computePitch(hpzTransform);
if (heading == null || pitch == null)
return null;
Position viewPosition = globe.computePositionFromPoint(eyePoint);
return new ViewState(viewPosition, heading, pitch, Angle.ZERO);
}
public static Angle computeHeading(Matrix headingPitchZoomTransform)
{
if (headingPitchZoomTransform == null)
{
String message = "nullValue.HeadingPitchZoomTransformTransformIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
return headingPitchZoomTransform.getRotationZ();
}
public static Angle computePitch(Matrix transform)
{
if (transform == null)
{
String message = "nullValue.HeadingPitchZoomTransformTransformIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
Angle a = transform.getRotationX();
if (a != null)
a = a.multiply(-1.0);
return a;
}
public static Angle computeRoll(Matrix transform)
{
if (transform == null)
{
String message = "nullValue.HeadingPitchZoomTransformTransformIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
return transform.getRotationY();
}
public static Position computePosition(Globe globe, Matrix transform)
{
if (transform == null)
{
String message = "nullValue.HeadingPitchZoomTransformTransformIsNull";
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
Vec4 v = transform.getTranslation();
Position p = globe.computePositionFromPoint(v);
return p != null ? p : Position.ZERO;
}
public static boolean validateViewState(ViewState viewState)
{
return (viewState != null
&& viewState.position != null
&& viewState.position.getLatitude().degrees >= -90
&& viewState.position.getLatitude().degrees <= 90
&& viewState.heading != null
&& viewState.pitch != null
&& viewState.pitch.degrees >= 0
&& viewState.pitch.degrees <= 90);
}
public static Position normalizedEyePosition(Position unnormalizedPosition)
{
if (unnormalizedPosition == null)
{
String message = Logging.getMessage("nullValue.PositionIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
return new Position(
Angle.normalizedLatitude(unnormalizedPosition.getLatitude()),
Angle.normalizedLongitude(unnormalizedPosition.getLongitude()),
unnormalizedPosition.getElevation());
}
public static Angle normalizedHeading(Angle unnormalizedHeading)
{
if (unnormalizedHeading == null)
{
String message = Logging.getMessage("nullValue.AngleIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
double degrees = unnormalizedHeading.degrees;
double heading = degrees % 360;
return Angle.fromDegrees(heading > 180 ? heading - 360 : (heading < -180 ? 360 + heading : heading));
}
public static Angle normalizedPitch(Angle unnormalizedPitch)
{
if (unnormalizedPitch == null)
{
String message = Logging.getMessage("nullValue.AngleIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
// Normalize pitch to the range [-180, 180].
double degrees = unnormalizedPitch.degrees;
double pitch = degrees % 360;
return Angle.fromDegrees(pitch > 180 ? pitch - 360 : (pitch < -180 ? 360 + pitch : pitch));
}
public static Angle normalizedRoll(Angle unnormalizedRoll)
{
if (unnormalizedRoll == null)
{
String message = Logging.getMessage("nullValue.AngleIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
double degrees = unnormalizedRoll.degrees;
double roll = degrees % 360;
return Angle.fromDegrees(roll > 180 ? roll - 360 : (roll < -180 ? 360 + roll : roll));
}
public static Line computeRayFromScreenPoint(View view, double x, double y,
Matrix modelview, Matrix projection, java.awt.Rectangle viewport)
{
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);
}
// Compute a ray originating from the view, and passing through the screen point (x, y).
//
// Taken from the "OpenGL Technical FAQ & Troubleshooting Guide",
// section 20.010 "How can I know which primitive a user has selected with the mouse?"
//
// http://www.opengl.org/resources/faq/technical/selection.htm#sele0010
Matrix modelViewInv = modelview.getInverse();
if (modelViewInv == null)
return null;
Vec4 eye = Vec4.UNIT_W.transformBy4(modelViewInv);
if (eye == null)
return null;
double yInGLCoords = viewport.height - y - 1;
Vec4 a = view.unProject(new Vec4(x, yInGLCoords, 0, 0));
Vec4 b = view.unProject(new Vec4(x, yInGLCoords, 1, 0));
if (a == null || b == null)
return null;
return new Line(eye, b.subtract3(a).normalize3());
}
public static double computePixelSizeAtDistance(double distance, Angle fieldOfView, java.awt.Rectangle viewport)
{
if (fieldOfView == null)
{
String message = Logging.getMessage("nullValue.AngleIsNull");
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);
}
// If the viewport width is zero, than replace it with 1, which effectively ignores the viewport width.
double viewportWidth = viewport.getWidth();
double pixelSizeScale = 2 * fieldOfView.tanHalfAngle() / (viewportWidth <= 0 ? 1d : viewportWidth);
return Math.abs(distance) * pixelSizeScale;
}
public static double computeHorizonDistance(Globe globe, double elevation)
{
if (globe == null)
{
String message = Logging.getMessage("nullValue.GlobeIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (elevation <= 0)
return 0;
double radius = globe.getMaximumRadius();
return Math.sqrt(elevation * (2 * radius + elevation));
}
/**
* Computes a View's vertical field-of-view given a View's horizontal field-of-view and the viewport window
* dimensions.
*
* @param horizontalFieldOfView the angle between the view frustum's left and right clipping planes.
* @param viewport the viewport dimensions, in window coordinates (screen pixels).
*
* @return the angle between the view frustum's bottom and top clipping planes.
*
* @throws IllegalArgumentException if the horitontal-field-of-view is null, or if the viewport rectangle is null.
*/
public static Angle computeVerticalFieldOfView(Angle horizontalFieldOfView, java.awt.Rectangle viewport)
{
if (horizontalFieldOfView == null)
{
String message = Logging.getMessage("nullValue.FOVIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (viewport == null)
{
String message = Logging.getMessage("nullValue.ViewportIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
// Taken form "Mathematics for 3D Game Programming and Computer Graphics", page 114.
double aspectRatio = viewport.getHeight() / viewport.getWidth();
double distanceToNearPlane = 1d / horizontalFieldOfView.tanHalfAngle();
double verticalFieldOfViewRadians = 2d * Math.atan(aspectRatio / distanceToNearPlane);
return Angle.fromRadians(verticalFieldOfViewRadians);
}
public static double computeElevationAboveSurface(DrawContext dc, Position position)
{
if (dc == null)
{
String message = Logging.getMessage("nullValue.DrawContextIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
Globe globe = dc.getGlobe();
if (globe == null)
{
String message = Logging.getMessage("nullValue.DrawingContextGlobeIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (position == null)
{
String message = Logging.getMessage("nullValue.Vec4IsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
Position surfacePosition = null;
// Look for the surface geometry point at 'position'.
Vec4 pointOnGlobe = dc.getPointOnTerrain(position.getLatitude(), position.getLongitude());
if (pointOnGlobe != null)
surfacePosition = globe.computePositionFromPoint(pointOnGlobe);
// Fallback to using globe elevation values.
if (surfacePosition == null)
surfacePosition = new Position(
position,
globe.getElevation(position.getLatitude(), position.getLongitude()) * dc.getVerticalExaggeration());
return position.getElevation() - surfacePosition.getElevation();
}
/**
* Computes the maximum near clip distance for a perspective projection that avoids clipping an object at a given
* distance from the eye point. The given distance should specify the smallest distance between the eye and the
* object being viewed, but may be an approximation if an exact clip distance is not required.
*
* @param fieldOfView The viewport rectangle, in OpenGL screen coordinates.
* @param distanceToObject The distance from the perspective eye point to the nearest object, in model coordinates.
*
* @return The maximum near clip distance, in model coordinates.
*
* @throws IllegalArgumentException if the field of view is null, or if the distance is negative.
*/
public static double computePerspectiveNearDistance(Angle fieldOfView, double distanceToObject)
{
if (fieldOfView == null)
{
String msg = Logging.getMessage("nullValue.FOVIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (distanceToObject < 0)
{
String msg = Logging.getMessage("generic.DistanceLessThanZero");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
double tanHalfFov = fieldOfView.tanHalfAngle();
return distanceToObject / (2 * Math.sqrt(2 * tanHalfFov * tanHalfFov + 1));
}
/**
* Computes the near clip distance that corresponds to a specified far clip distance and a resolution at the far
* clip distance. This returns zero if either the distance or the resolution are zero.
*
* @param farDistance The far clip distance, in model coordinates.
* @param farResolution The depth resolution at the far clip plane, in model coordinates.
* @param depthBits The number of bitplanes in the depth buffer. This is typically 16, 24, or 32 for OpenGL
* depth buffers.
*
* @return The near clip distance, in model coordinates.
*
* @throws IllegalArgumentException if either the distance or the resolution are negative, or if the depthBits is
* less than one.
*/
public static double computePerspectiveNearDistance(double farDistance, double farResolution, int depthBits)
{
if (farDistance < 0)
{
String msg = Logging.getMessage("generic.DistanceLessThanZero");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (farResolution < 0)
{
String msg = Logging.getMessage("generic.ResolutionLessThanZero");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (depthBits < 1)
{
String msg = Logging.getMessage("generic.DepthBitsLessThanOne");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (farDistance == 0 || farResolution == 0)
{
return 0;
}
double maxDepthValue = (1L << depthBits) - 1L;
return farDistance / (maxDepthValue / (1 - farResolution / farDistance) - maxDepthValue + 1);
}
/**
* Transforms a point in model coordinates to a point in screen coordinates. The returned x and y coordinates are
* relative to the screen's lower left hand screen corner, and the returned z coordinate defines the point's depth
* in screen coordinates (in the range [0, 1]). This returns null if the specified combination of modelview matrix,
* projection matrix, and viewport cannot produce a transformation.
*
* @param modelPoint the point in model coordinates to transform into window coordinates.
* @param modelview the modelview matrix.
* @param projection the projection matrix.
* @param viewport the viewport rectangle.
*
* @return the point in window coordinates, or null if the point cannot be transformed.
*
* @throws IllegalArgumentException if any of the model point, modelview matrix, projection matrix, or viewport
* rectangle are null.
*/
public static Vec4 project(Vec4 modelPoint, Matrix modelview, Matrix projection, java.awt.Rectangle viewport)
{
if (modelPoint == null)
{
String message = Logging.getMessage("nullValue.PointIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (modelview == null)
{
String message = Logging.getMessage("nullValue.ModelViewIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (projection == null)
{
String message = Logging.getMessage("nullValue.ProjectionIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (viewport == null)
{
String message = Logging.getMessage("nullValue.ViewportIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
GLU glu = new GLUgl2();
// 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 (!glu.gluProject(
modelPoint.x, modelPoint.y, modelPoint.z,
modelviewArray, 0,
projectionArray, 0,
viewportArray, 0,
result, 0))
{
return null;
}
return Vec4.fromArray3(result, 0);
}
/**
* Transforms a point in screen coordinates to a point in model coordinates. The input x and y are relative to the
* screen's lower left hand screen corner, while the z-value denotes the point's depth in screen coordinates (in the
* range [0, 1]). This returns null if the specified combination of modelview matrix, projection matrix, and
* viewport cannot produce a transformation.
*
* @param windowPoint the point in screen coordinates to transform into model coordinates.
* @param modelview the modelview matrix.
* @param projection the projection matrix.
* @param viewport the viewport rectangle.
*
* @return the point in model coordinates, or null if the point cannot be transformed.
*
* @throws IllegalArgumentException if any of the model point, modelview matrix, projection matrix, or viewport
* rectangle are null.
*/
public static 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)
{
String message = Logging.getMessage("nullValue.ModelViewIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (projection == null)
{
String message = Logging.getMessage("nullValue.ProjectionIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (viewport == null)
{
String message = Logging.getMessage("nullValue.ViewportIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
GLU glu = new GLUgl2();
// GLU expects matrices as column-major arrays.
double[] modelviewArray = modelview.toArray(new double[16], 0, false);
double[] projectionArray = projection.toArray(new double[16], 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 (!glu.gluUnProject(
windowPoint.x, windowPoint.y, windowPoint.z,
modelviewArray, 0,
projectionArray, 0,
viewportArray, 0,
result, 0))
{
return null;
}
return Vec4.fromArray3(result, 0);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy