📄 viewinputhandler.java
字号:
/* Copyright (C) 2001, 2006 United States Government as represented bythe 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.event.*;import gov.nasa.worldwind.geom.*;import gov.nasa.worldwind.pick.*;import gov.nasa.worldwind.util.Logging;import gov.nasa.worldwind.view.*;import java.awt.*;import java.awt.event.*;/** * @author dcollins * @version $Id: ViewInputHandler.java 9881 2009-04-02 16:43:28Z dcollins $ */public class ViewInputHandler implements KeyListener, MouseListener, MouseMotionListener, MouseWheelListener, FocusListener, RenderingListener, java.beans.PropertyChangeListener{ private WorldWindow wwd; private ViewInputAttributes attributes; // Optional behaviors. private boolean enableSmoothing; private boolean lockHeading; private boolean stopOnFocusLost; private Position selectedPosition; // AWT event support. private boolean wwdFocusOwner; private Point lastMousePoint; private Point mousePoint; private KeyEventState keyEventState = new KeyEventState(); private OrbitViewInputSupport orbitViewInputSupport = new OrbitViewInputSupport(); // Input transformation coefficients. private double dragSlopeFactor = DEFAULT_DRAG_SLOPE_FACTOR; // Per-frame input event timing support. private long lastPerFrameInputTime; private static final double DEFAULT_DRAG_SLOPE_FACTOR = 0.002; private static final long DEFAULT_PER_FRAME_INPUT_DELAY = 35L; // 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"; public ViewInputHandler() { this.enableSmoothing = true; this.lockHeading = true; this.stopOnFocusLost = true; this.attributes = new ViewInputAttributes(); } /** * Return the <code>WorldWindow</code> this ViewInputHandler is listening to for input events, and will modify in * response to those events * * @return the <code>WorldWindow</code> this ViewInputHandler is listening to, and will modify in response to * events. */ public WorldWindow getWorldWindow() { return this.wwd; } /** * Sets the <code>WorldWindow</code> this ViewInputHandler should listen to for input events, and should modify in * response to those events. If the parameter <code>newWorldWindow</code> is null, then this ViewInputHandler * will do nothing. * * @param newWorldWindow the <code>WorldWindow</code> 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 <code>attributes</code> 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 <code>factor</code> 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 <code>factor</code> 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 <code>factor</code> is the amount of damping applied to the view movement in such * cases. Setting <code>factor</code> to zero will disable this behavior, while setting <code>factor</code> 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 <code>factor</code> 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 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) { PickedObject top = pickedObjects.getTopPickedObject(); if (top != null && top.isTerrain()) { return top.getPosition(); } } return null; } //**************************************************************// //******************** View Change Events ********************// //**************************************************************// protected void onFocusView(Position focalPosition, ViewInputAttributes.ActionAttributes actionAttribs) { View view = this.getView(); if (view == null) // include this test to ensure any derived implementation performs it { return; } if (view instanceof OrbitView) { if (view.hasStateIterator()) view.stopStateIterators(); // We're treating a speed parameter as smoothing here. A greater speed results in greater smoothing and // slower response. Therefore the min speed used at lower altitudes ought to be *greater* than the max // speed used at higher altitudes. double[] values = actionAttribs.getValues(); double smoothing = this.getScaledValue(values[0], values[1], SCALE_FUNC_ZOOM); if (!actionAttribs.isEnableSmoothing()) smoothing = 0.0; this.orbitViewInputSupport.setCenterTarget((OrbitView) view, null); this.orbitViewInputSupport.setCenterSmoothing(smoothing); this.orbitViewInputSupport.setCenterTarget((OrbitView) view, focalPosition); view.firePropertyChange(AVKey.VIEW, null, view); } } protected void onPanViewAbsolute(Angle latitudeChange, Angle longitudeChange, ViewInputAttributes.ActionAttributes actionAttribs) { View view = this.getView(); if (view == null) // include this test to ensure any derived implementation performs it { return; } if (latitudeChange.equals(Angle.ZERO) && longitudeChange.equals(Angle.ZERO)) { return; } if (view instanceof OrbitView) { Position newPosition = ((OrbitView) view).getCenterPosition().add(new Position( latitudeChange, longitudeChange, 0.0)); this.setCenterPosition((OrbitView) view, newPosition, actionAttribs); } } protected void onPanViewRelative(Angle forwardChange, Angle sideChange, ViewInputAttributes.ActionAttributes actionAttribs) { View view = this.getView(); if (view == null) // include this test to ensure any derived implementation performs it { return; } if (forwardChange.equals(Angle.ZERO) && sideChange.equals(Angle.ZERO)) { return; } if (view instanceof OrbitView) { double sinHeading = ((OrbitView) view).getHeading().sin(); double cosHeading = ((OrbitView) view).getHeading().cos(); double latChange = cosHeading * forwardChange.getDegrees() - sinHeading * sideChange.getDegrees(); double lonChange = sinHeading * forwardChange.getDegrees() + cosHeading * sideChange.getDegrees(); Position newPosition = ((OrbitView) view).getCenterPosition().add( Position.fromDegrees(latChange, lonChange, 0.0)); this.setCenterPosition((OrbitView) view, newPosition, actionAttribs); } } protected void onResetHeading() {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -