gov.nasa.worldwind.awt.AbstractViewInputHandler 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.awt;
import gov.nasa.worldwind.*;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.pick.PickedObjectList;
import gov.nasa.worldwind.util.Logging;
import gov.nasa.worldwind.view.orbit.OrbitView;
import java.awt.*;
import java.awt.event.*;
/**
* @author dcollins
* @version $Id: AbstractViewInputHandler.java 2251 2014-08-21 21:17:46Z dcollins $
*/
public abstract class AbstractViewInputHandler implements ViewInputHandler, java.beans.PropertyChangeListener
{
protected WorldWindow wwd;
protected ViewInputAttributes attributes;
protected ViewInputAttributes.ActionAttributesMap mouseActionMap;
protected ViewInputAttributes.ActionAttributesMap keyActionMap;
protected ViewInputAttributes.DeviceModifierMap keyModsActionMap;
protected ViewInputAttributes.DeviceModifierMap mouseModsActionMap;
protected ViewInputAttributes.DeviceModifierMap mouseWheelModsActionMap;
// Optional behaviors.
protected boolean enableSmoothing;
protected boolean lockHeading;
protected boolean stopOnFocusLost;
// AWT event support.
protected boolean wwdFocusOwner;
protected Point mouseDownPoint;
protected Point lastMousePoint;
protected Point mousePoint;
protected Position selectedPosition;
protected Matrix mouseDownModelview;
protected Matrix mouseDownProjection;
protected Rectangle mouseDownViewport;
protected KeyEventState keyEventState = new KeyEventState();
// Input transformation coefficients.
protected double dragSlopeFactor = DEFAULT_DRAG_SLOPE_FACTOR;
// Per-frame input event timing support.
protected long perFrameInputInterval = DEFAULT_PER_FRAME_INPUT_INTERVAL;
protected long lastPerFrameInputTime;
protected static final double DEFAULT_DRAG_SLOPE_FACTOR = 0.002;
protected static final long DEFAULT_PER_FRAME_INPUT_INTERVAL = 100L; // 35L; // perform per frame input every N ms
// These constants are used by the device input handling routines to determine whether or not to
// (1) generate view change events based on the current device state, or
// (2) query whether or not events would be generated from the current device state.
protected static final String GENERATE_EVENTS = "GenerateEvents";
protected static final String QUERY_EVENTS = "QueryEvents";
// These constants define scaling functions for transforming raw input into a range of values. The scale functions
// are interpreted as follows:
// EYE_ALTITUDE: distance from eye to ground, divided by 3 * globe's radius and clamped to range [0, 1]
// ZOOM: distance from eye to view center point, divided by 3 * globe's radius and clamped to range [0, 1]
// EYE_ALTITUDE_EXP or ZOOM_EXP: function placed in an exponential function in the range [0, 1]
protected static final String SCALE_FUNC_EYE_ALTITUDE = "ScaleFuncEyeAltitude";
protected static final String SCALE_FUNC_EYE_ALTITUDE_EXP = "ScaleFuncEyeAltitudeExp";
protected static final String SCALE_FUNC_ZOOM = "ScaleFuncZoom";
protected static final String SCALE_FUNC_ZOOM_EXP = "ScaleFuncZoomExp";
protected int[] modifierList =
{
KeyEvent.ALT_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK,
KeyEvent.ALT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK,
KeyEvent.ALT_DOWN_MASK | KeyEvent.META_DOWN_MASK,
KeyEvent.SHIFT_DOWN_MASK,
KeyEvent.CTRL_DOWN_MASK,
KeyEvent.META_DOWN_MASK,
KeyEvent.ALT_DOWN_MASK,
0
};
protected final int NUM_MODIFIERS = 8;
public AbstractViewInputHandler()
{
this.enableSmoothing = true;
this.lockHeading = true;
this.stopOnFocusLost = true;
this.attributes = new ViewInputAttributes();
// Actions for the pointer device
this.mouseActionMap = this.attributes.getActionMap(ViewInputAttributes.DEVICE_MOUSE);
this.keyActionMap = this.attributes.getActionMap(ViewInputAttributes.DEVICE_KEYBOARD);
this.keyModsActionMap = this.attributes.getModifierActionMap(ViewInputAttributes.DEVICE_KEYBOARD);
this.mouseModsActionMap = this.attributes.getModifierActionMap(ViewInputAttributes.DEVICE_MOUSE);
this.mouseWheelModsActionMap =
this.attributes.getModifierActionMap(ViewInputAttributes.DEVICE_MOUSE_WHEEL);
}
/**
* Return the WorldWindow
this ViewInputHandler is listening to for input events, and will modify in
* response to those events
*
* @return the WorldWindow
this ViewInputHandler is listening to, and will modify in response to
* events.
*/
public WorldWindow getWorldWindow()
{
return this.wwd;
}
/**
* Sets the WorldWindow
this ViewInputHandler should listen to for input events, and should modify in
* response to those events. If the parameter newWorldWindow
is null, then this ViewInputHandler
* will do nothing.
*
* @param newWorldWindow the WorldWindow
to listen on, and modify in response to events.
*/
public void setWorldWindow(WorldWindow newWorldWindow)
{
if (newWorldWindow == this.wwd)
return;
if (this.wwd != null)
{
//this.wwd.removeRenderingListener(this);
this.wwd.getSceneController().removePropertyChangeListener(this);
}
this.wwd = newWorldWindow;
if (this.wwd != null)
{
//this.wwd.addRenderingListener(this);
this.wwd.getSceneController().addPropertyChangeListener(this);
}
}
/**
* Returns the values that are used to transform raw input events into view movments.
*
* @return values that are be used to transform raw input into view movement.
*/
public ViewInputAttributes getAttributes()
{
return this.attributes;
}
/**
* Sets the values that will be used to transform raw input events into view movements. ViewInputAttributes
* define a calibration value for each combination of device and action, and a general sensitivity value
* for each device.
*
* @param attributes values that will be used to transform raw input into view movement.
*
* @throws IllegalArgumentException if attributes
is null.
*
* @see ViewInputAttributes
*/
public void setAttributes(ViewInputAttributes attributes)
{
if (attributes == null)
{
String message = Logging.getMessage("nullValue.AttributesIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.attributes = attributes;
}
/**
* Returns whether the ViewInputHandler will smooth view movements in response to input events.
*
* @return true if the view will movements are smoothed; false otherwise.
*/
public boolean isEnableSmoothing()
{
return this.enableSmoothing;
}
/**
* Sets whether the ViewInputHandler should smooth view movements in response to input events. A value of true
* will cause the ViewInputHandler to delegate decisions about whether to smooth a certain input event to its
* {@link ViewInputAttributes}. A value of false will disable all smoothing.
*
* @param enable true to smooth view movements; false otherwise.
*/
public void setEnableSmoothing(boolean enable)
{
this.enableSmoothing = enable;
}
/**
* Returns whether the view's heading should stay the same unless explicitly changed.
*
* @return true if the view's heading will stay the same unless explicity changed; false otherwise.
*/
public boolean isLockHeading()
{
return this.lockHeading;
}
/**
* Sets whether the view's heading should stay the same unless explicitly changed. For example, moving forward
* along a great arc would suggest a change in position and heading. If the heading had been locked, the
* ViewInputHandler will move forward in a way that doesn't change the heading.
*
* @param lock true if the view's heading should stay the same unless explicity changed; false otherwise.
*/
public void setLockHeading(boolean lock)
{
this.lockHeading = lock;
}
/**
* Returns whether the view will stop when the WorldWindow looses focus.
*
* @return true if the view will stop when the WorldWindow looses focus; false otherwise.
*/
public boolean isStopOnFocusLost()
{
return this.stopOnFocusLost;
}
/**
* Sets whether the view should stop when the WorldWindow looses focus.
*
* @param stop true if the view should stop when the WorldWindow looses focus; false otherwise.
*/
public void setStopOnFocusLost(boolean stop)
{
this.stopOnFocusLost = stop;
}
/**
* Returns the factor
that dampens view movement when the user pans drags the cursor in a way that could
* cause an abrupt transition.
*
* @return factor dampening view movement when a mouse drag event would cause an abrupt transition.
* @see #setDragSlopeFactor
*/
public double getDragSlopeFactor()
{
return this.dragSlopeFactor;
}
/**
* Sets the factor
that dampens view movement when a mouse drag event would cause an abrupt
* transition. The drag slope is the ratio of screen pixels to Cartesian distance moved, measured by the previous
* and current mouse points. As drag slope gets larger, it becomes more difficult to operate the view. This
* typically happens while dragging over and around the horizon, where movement of a few pixels can cause the view
* to move many kilometers. This factor
is the amount of damping applied to the view movement in such
* cases. Setting factor
to zero will disable this behavior, while setting factor
to a
* positive value may dampen the effects of mouse dragging.
*
* @param factor dampening view movement when a mouse drag event would cause an abrupt transition. Must be greater
* than or equal to zero.
*
* @throws IllegalArgumentException if factor
is less than zero.
*/
public void setDragSlopeFactor(double factor)
{
if (factor < 0)
{
String message = Logging.getMessage("generic.ArgumentOutOfRange", "factor < 0");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.dragSlopeFactor = factor;
}
protected long getPerFrameInputInterval()
{
return this.perFrameInputInterval;
}
protected void setPerFrameInputInterval(long milliseconds)
{
this.perFrameInputInterval = milliseconds;
}
protected View getView()
{
return (this.wwd != null) ? this.wwd.getView() : null;
}
//**************************************************************//
//******************** AWT Event Support *********************//
//**************************************************************//
protected boolean isWorldWindowFocusOwner()
{
return this.wwdFocusOwner;
}
protected void setWorldWindowFocusOwner(boolean focusOwner)
{
this.wwdFocusOwner = focusOwner;
}
protected Point getMousePoint()
{
return this.mousePoint;
}
protected Point getLastMousePoint()
{
return this.lastMousePoint;
}
protected void updateMousePoint(MouseEvent e)
{
this.lastMousePoint = this.mousePoint;
this.mousePoint = new Point(e.getPoint());
}
protected Position getSelectedPosition()
{
return this.selectedPosition;
}
protected void setSelectedPosition(Position position)
{
this.selectedPosition = position;
}
protected Position computeSelectedPosition()
{
PickedObjectList pickedObjects = this.wwd.getObjectsAtCurrentPosition();
if (pickedObjects != null)
{
if (pickedObjects.getTerrainObject() != null)
{
return pickedObjects.getTerrainObject().getPosition();
}
}
return null;
}
//**************************************************************//
//******************** View Change Events ********************//
//**************************************************************//
protected void onStopView()
{
View view = this.getView();
if (view == null) // include this test to ensure any derived implementation performs it
{
return;
}
view.stopMovement();
}
//**************************************************************//
//******************** Key Events ****************************//
//**************************************************************//
public void keyTyped(KeyEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
return;
}
this.keyEventState.keyTyped(e);
}
public void keyPressed(KeyEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
return;
}
this.keyEventState.keyPressed(e);
this.handleKeyPressed(e);
}
public void keyReleased(KeyEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
return;
}
this.keyEventState.keyReleased(e);
this.handleKeyReleased(e);
}
@SuppressWarnings({"UnusedDeclaration"})
protected void handleKeyPressed(KeyEvent e)
{
// Determine whether or not the current key state would have generated a view change event.
// If so, issue a repaint event to give the per-frame input a chance to run.
if (this.handlePerFrameKeyState(this.keyEventState, QUERY_EVENTS))
{
View view = this.getView();
if (view != null)
{
view.firePropertyChange(AVKey.VIEW, null, view);
}
}
}
@SuppressWarnings({"UnusedDeclaration"})
protected void handleKeyReleased(KeyEvent e)
{
}
//**************************************************************//
//******************** Mouse Events **************************//
//**************************************************************//
public void mouseClicked(MouseEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
return;
}
this.handleMouseClicked(e);
}
public void mousePressed(MouseEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
return;
}
this.keyEventState.mousePressed(e);
this.setMouseDownPoint(e.getPoint());
this.setSelectedPosition(this.computeSelectedPosition());
this.setMouseDownView(this.getView());
this.updateMousePoint(e);
this.handleMousePressed(e);
}
public void mouseReleased(MouseEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
return;
}
this.keyEventState.mouseReleased(e);
this.setMouseDownPoint(null);
this.setSelectedPosition(null);
this.setMouseDownView(null);
this.handleMouseReleased(e);
}
public void mouseEntered(MouseEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
//noinspection UnnecessaryReturnStatement
return;
}
}
public void mouseExited(MouseEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
//noinspection UnnecessaryReturnStatement
return;
}
}
@SuppressWarnings({"UnusedDeclaration"})
protected void handleMouseClicked(MouseEvent e)
{
}
@SuppressWarnings({"UnusedDeclaration"})
protected void handleMousePressed(MouseEvent e)
{
// Determine whether or not the current key state would have generated a view change event.
// If so, issue a repaint event to give the per-frame input a chance to run.
if (this.handlePerFrameMouseState(this.keyEventState, QUERY_EVENTS))
{
View view = this.getView();
if (view != null)
{
view.firePropertyChange(AVKey.VIEW, null, view);
}
}
}
@SuppressWarnings({"UnusedDeclaration"})
protected void handleMouseReleased(MouseEvent e)
{
}
//**************************************************************//
//******************** Mouse Motion Events *******************//
//**************************************************************//
public void mouseDragged(MouseEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
return;
}
this.updateMousePoint(e);
this.handleMouseDragged(e);
}
public void mouseMoved(MouseEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
return;
}
this.updateMousePoint(e);
this.handleMouseMoved(e);
}
@SuppressWarnings({"UnusedDeclaration"})
protected void handleMouseDragged(MouseEvent e)
{
}
@SuppressWarnings({"UnusedDeclaration"})
protected void handleMouseMoved(MouseEvent e)
{
}
//**************************************************************//
//******************** Mouse Wheel Events ********************//
//**************************************************************//
public void mouseWheelMoved(MouseWheelEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
return;
}
this.handleMouseWheelMoved(e);
}
@SuppressWarnings({"UnusedDeclaration"})
protected void handleMouseWheelMoved(MouseWheelEvent e)
{
}
//**************************************************************//
//******************** Focus Events **************************//
//**************************************************************//
public void focusGained(FocusEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
return;
}
this.setWorldWindowFocusOwner(true);
this.handleFocusGained(e);
}
public void focusLost(FocusEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
return;
}
this.keyEventState.clearKeyState();
this.setWorldWindowFocusOwner(false);
this.handleFocusLost(e);
}
@SuppressWarnings({"UnusedDeclaration"})
protected void handleFocusGained(FocusEvent e)
{
}
@SuppressWarnings({"UnusedDeclaration"})
protected void handleFocusLost(FocusEvent e)
{
if (this.isStopOnFocusLost())
this.onStopView();
}
protected boolean handlePerFrameEvents (String action) {
// pcm - do we really want short-circuit eval here?
return (handlePerFrameKeyState(this.keyEventState, action) ||
handlePerFrameMouseState(this.keyEventState, action) ||
handlePerFrameAnimation(action));
}
public void apply()
{
// Process per-frame input only when the World Window is the focus owner.
if (!this.isWorldWindowFocusOwner()) {
return;
}
// Throttle the interval at which we process per-frame input, which is usually invoked each frame. This helps
// balance the input response of high and low framerate applications.
long now = System.currentTimeMillis();
long interval = now - lastPerFrameInputTime;
if (interval >= this.getPerFrameInputInterval()) {
if (handlePerFrameEvents(GENERATE_EVENTS)) {
getWorldWindow().redraw();
}
lastPerFrameInputTime = now;
} else {
// Determine whether or not the current key state would have generated a view change event. If so, issue
// a repaint event to give the per-frame input a chance to run again.
if (handlePerFrameEvents(QUERY_EVENTS)) {
getWorldWindow().redraw();
}
}
}
public void viewApplied()
{
}
// Interpret the current key state according to the specified target. If the target is KEY_POLL_GENERATE_EVENTS,
// then the the key state will generate any appropriate view change events. If the target is KEY_POLL_QUERY_EVENTS,
// then the key state will not generate events, and this will return whether or not any view change events would
// have been generated.
protected boolean handlePerFrameKeyState(KeyEventState keys, String target)
{
return false;
}
protected boolean handlePerFrameMouseState(KeyEventState keys, String target)
{
return false;
}
protected boolean handlePerFrameAnimation(String target)
{
return false;
}
//**************************************************************//
//******************** Property Change Events ****************//
//**************************************************************//
public void propertyChange(java.beans.PropertyChangeEvent e)
{
if (this.wwd == null) // include this test to ensure any derived implementation performs it
{
return;
}
if (e == null) // include this test to ensure any derived implementation performs it
{
return;
}
this.handlePropertyChange(e);
}
@SuppressWarnings({"UnusedDeclaration"})
protected void handlePropertyChange(java.beans.PropertyChangeEvent e)
{
}
//**************************************************************//
//******************** Raw Input Transformation **************//
//**************************************************************//
// Translates raw user input into a change in value, according to the specified device and action attributes.
// The input is scaled by the action attribute range (depending on eye position), then scaled by the device
// sensitivity.
protected double rawInputToChangeInValue(double rawInput,
ViewInputAttributes.DeviceAttributes deviceAttributes, ViewInputAttributes.ActionAttributes actionAttributes,
String scaleFunc)
{
double value = rawInput;
double[] range = actionAttributes.getValues();
value *= this.getScaledValue(range[0], range[1], scaleFunc);
value *= deviceAttributes.getSensitivity();
return value;
}
protected double getScaledValue(double minValue, double maxValue, String scaleFunc)
{
if (scaleFunc == null)
{
return minValue;
}
double t = 0.0;
if (scaleFunc.startsWith(SCALE_FUNC_EYE_ALTITUDE))
{
t = this.evaluateScaleFuncEyeAltitude();
}
else if (scaleFunc.startsWith(SCALE_FUNC_ZOOM))
{
t = this.evaluateScaleFuncZoom();
}
if (scaleFunc.toLowerCase().endsWith("exp"))
{
t = Math.pow(2.0, t) - 1.0;
}
return minValue * (1.0 - t) + maxValue * t;
}
protected double evaluateScaleFuncEyeAltitude()
{
View view = this.getView();
if (view == null)
{
return 0.0;
}
Position eyePos = view.getEyePosition();
double radius = this.wwd.getModel().getGlobe().getRadius();
double surfaceElevation = this.wwd.getModel().getGlobe().getElevation(eyePos.getLatitude(), eyePos.getLongitude());
double t = (eyePos.getElevation() - surfaceElevation) / (3.0 * radius);
return (t < 0 ? 0 : (t > 1 ? 1 : t));
}
protected double evaluateScaleFuncZoom()
{
View view = this.getView();
if (view == null)
{
return 0.0;
}
if (view instanceof OrbitView)
{
double radius = this.wwd.getModel().getGlobe().getRadius();
double t = ((OrbitView) view).getZoom() / (3.0 * radius);
return (t < 0 ? 0 : (t > 1 ? 1 : t));
}
return 0.0;
}
protected double getScaleValueElevation(
ViewInputAttributes.DeviceAttributes deviceAttributes, ViewInputAttributes.ActionAttributes actionAttributes)
{
View view = this.getView();
if (view == null)
{
return 0.0;
}
double[] range = actionAttributes.getValues();
Position eyePos = view.getEyePosition();
double radius = this.wwd.getModel().getGlobe().getRadius();
double surfaceElevation = this.wwd.getModel().getGlobe().getElevation(eyePos.getLatitude(),
eyePos.getLongitude());
double t = getScaleValue(range[0], range[1],
eyePos.getElevation() - surfaceElevation, 3.0 * radius, true);
t *= deviceAttributes.getSensitivity();
return t;
}
protected double getScaleValue(double minValue, double maxValue,
double value, double range, boolean isExp)
{
double t = value / range;
t = t < 0 ? 0 : (t > 1 ? 1 : t);
if (isExp)
{
t = Math.pow(2.0, t) - 1.0;
}
return(minValue * (1.0 - t) + maxValue * t);
}
//**************************************************************//
//******************** Utility Methods ***********************//
//**************************************************************//
protected Vec4 computeSelectedPointAt(Point point)
{
if (this.getSelectedPosition() == null)
{
return null;
}
View view = this.getView();
if (view == null)
{
return null;
}
// Reject a selected position if its elevation is above the eye elevation. When that happens, the user is
// essentially dragging along the inside of a sphere, and the effects of dragging are reversed. To the user
// this behavior appears unpredictable.
double elevation = this.getSelectedPosition().getElevation();
if (view.getEyePosition().getElevation() <= elevation)
{
return null;
}
// Intersect with a somewhat larger or smaller Globe which will pass through the selected point, but has the
// same proportions as the actual Globe. This will simulate dragging the selected position more accurately.
Line ray = view.computeRayFromScreenPoint(point.getX(), point.getY());
Intersection[] intersections = this.wwd.getModel().getGlobe().intersect(ray, elevation);
if (intersections == null || intersections.length == 0)
{
return null;
}
return ray.nearestIntersectionPoint(intersections);
}
protected LatLon getChangeInLocation(Point point1, Point point2, Vec4 vec1, Vec4 vec2)
{
// Modify the distance we'll actually travel based on the slope of world distance travelled to screen
// distance travelled . A large slope means the user made a small change in screen space which resulted
// in a large change in world space. We want to reduce the impact of that change to something reasonable.
double dragSlope = this.computeDragSlope(point1, point2, vec1, vec2);
double dragSlopeFactor = this.getDragSlopeFactor();
double scale = 1.0 / (1.0 + dragSlopeFactor * dragSlope * dragSlope);
Position pos1 = this.wwd.getModel().getGlobe().computePositionFromPoint(vec1);
Position pos2 = this.wwd.getModel().getGlobe().computePositionFromPoint(vec2);
LatLon adjustedLocation = LatLon.interpolateGreatCircle(scale, pos1, pos2);
// Return the distance to travel in angular degrees.
return pos1.subtract(adjustedLocation);
}
public double computeDragSlope(Point point1, Point point2, Vec4 vec1, Vec4 vec2)
{
View view = this.getView();
if (view == null)
{
return 0.0;
}
// Compute the screen space distance between point1 and point2.
double dx = point2.getX() - point1.getX();
double dy = point2.getY() - point1.getY();
double pixelDistance = Math.sqrt(dx * dx + dy * dy);
// Determine the distance from the eye to the point on the forward vector closest to vec1 and vec2
double d = view.getEyePoint().distanceTo3(vec1);
// Compute the size of a screen pixel at the nearest of the two distances.
double pixelSize = view.computePixelSizeAtDistance(d);
// Return the ratio of world distance to screen distance.
double slope = vec1.distanceTo3(vec2) / (pixelDistance * pixelSize);
if (slope < 1.0)
slope = 1.0;
return slope - 1.0;
}
protected static Point constrainToSourceBounds(Point point, Object source)
{
if (point == null)
return null;
if (!(source instanceof Component))
return point;
Component c = (Component) source;
int x = (int) point.getX();
if (x < 0)
x = 0;
if (x > c.getWidth())
x = c.getWidth();
int y = (int) point.getY();
if (y < 0)
y = 0;
if (y > c.getHeight())
y = c.getHeight();
return new Point(x, y);
}
public Point getMouseDownPoint()
{
return mouseDownPoint;
}
public void setMouseDownPoint(Point mouseDownPoint)
{
this.mouseDownPoint = mouseDownPoint;
}
protected void setMouseDownView(View mouseDownView)
{
if (mouseDownView != null)
{
this.mouseDownModelview = mouseDownView.getModelviewMatrix();
this.mouseDownProjection = mouseDownView.getProjectionMatrix();
this.mouseDownViewport = mouseDownView.getViewport();
}
else
{
this.mouseDownModelview = null;
this.mouseDownProjection = null;
this.mouseDownViewport = null;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy