2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
7 package gov
.nasa
.worldwind
.awt
;
9 import gov
.nasa
.worldwind
.*;
10 import gov
.nasa
.worldwind
.geom
.*;
12 import javax
.swing
.event
.*;
13 import java
.awt
.event
.*;
15 import java
.util
.logging
.Level
;
19 * @version $Id: AWTInputHandler.java 1820 2007-05-10 16:05:29Z dcollins $
21 @SuppressWarnings({"UnnecessaryReturnStatement"})
22 public class AWTInputHandler
extends AVListImpl
23 implements KeyListener
, MouseListener
, MouseMotionListener
, MouseWheelListener
, InputHandler
25 private WorldWindow worldWindow
= null;
26 private final EventListenerList eventListeners
= new EventListenerList();
27 private Position previousPickPosition
= null;
28 private PickedObjectList lastPickedObjects
= null;
29 private PickedObjectList hoverObjects
;
30 private boolean isHovering
= false;
31 private javax
.swing
.Timer hoverTimer
= new javax
.swing
.Timer(600, new ActionListener()
33 public void actionPerformed(ActionEvent actionEvent
)
35 if (AWTInputHandler
.this.hoverMatches())
37 AWTInputHandler
.this.isHovering
= true;
38 AWTInputHandler
.this.callSelectListeners(new SelectEvent(AWTInputHandler
.this.worldWindow
,
39 SelectEvent
.HOVER
, null, AWTInputHandler
.this.hoverObjects
));
40 AWTInputHandler
.this.hoverTimer
.stop();
44 // Current AWT mouse state.
45 private java
.awt
.Point lastMousePoint
= new java
.awt
.Point();
46 // private volatile int mouseClickButton;
47 // private volatile int mouseClickCount;
48 // private final int mouseClickCoalesceTime = 350;
49 // Repeating AWT key timer. Used to simulate keyboard polling.
50 private final Integer
[] POLLED_KEYS
=
52 KeyEvent
.VK_LEFT
, KeyEvent
.VK_RIGHT
,
53 KeyEvent
.VK_UP
, KeyEvent
.VK_DOWN
, KeyEvent
.VK_PAGE_UP
,
54 KeyEvent
.VK_PAGE_DOWN
, KeyEvent
.VK_ADD
, KeyEvent
.VK_EQUALS
,
55 KeyEvent
.VK_SUBTRACT
, KeyEvent
.VK_MINUS
57 private KeyPollTimer keyPollTimer
= new KeyPollTimer(25, Arrays
.asList(POLLED_KEYS
),
60 public void actionPerformed(ActionEvent actionEvent
)
62 if (actionEvent
== null)
64 Object source
= actionEvent
.getSource();
65 if (source
!= null && source
instanceof Integer
)
66 AWTInputHandler
.this.keysPolled((Integer
) source
, actionEvent
.getModifiers());
69 // Value interpolation timer. Smooths responses to certain input events.
70 private InterpolatorTimer interpolatorTimer
= new InterpolatorTimer(15);
71 private java
.beans
.PropertyChangeListener viewPropertyListener
= null;
72 private InterpolatorTimer
.ViewProperties viewTarget
= null;
73 private boolean smoothViewChange
= true;
74 // View LatLon properties.
75 private final double viewLatLonMinChangeFactor
= 0.00001;
76 private final double viewLatLonMaxChangeFactor
= 0.2;
77 private final double viewLatLonErrorThresold
= 0.000000001;
78 private final double viewLatLonStepCoefficient
= 0.6;
79 private final double viewLatLonCenterStepCoefficient
= 0.1;
80 // View heading and pitch (angle) properties.
81 private final double viewAngleChangeFactor
= 0.25;
82 private final double viewAngleErrorThreshold
= 0.0001;
83 private final double viewAngleStepCoefficient
= 0.3;
84 private final double viewAngleResetStepCoefficient
= 0.1;
85 // View zoom properties.
86 private final double viewZoomChangeFactor
= 0.05;
87 private final double viewZoomErrorThreshold
= 0.001;
88 private final double viewZoomStepCoefficient
= 0.1;
90 public void setEventSource(WorldWindow newWorldWindow
)
92 if (newWorldWindow
!= null && !(newWorldWindow
instanceof java
.awt
.Component
))
94 String message
= WorldWind
.retrieveErrMsg("awt.AWTInputHandler.EventSourceNotAComponent");
95 WorldWind
.logger().log(Level
.FINER
, message
);
96 throw new IllegalArgumentException(message
);
99 if (newWorldWindow
== this.worldWindow
)
102 if (this.worldWindow
!= null)
104 java
.awt
.Component c
= (java
.awt
.Component
) this.worldWindow
;
105 c
.removeKeyListener(this);
106 c
.removeMouseMotionListener(this);
107 c
.removeMouseListener(this);
108 c
.removeMouseWheelListener(this);
110 if (this.keyPollTimer
!= null)
111 c
.removeKeyListener(this.keyPollTimer
);
114 this.worldWindow
= newWorldWindow
;
116 if (this.worldWindow
== null)
119 java
.awt
.Component c
= (java
.awt
.Component
) this.worldWindow
;
120 c
.addKeyListener(this);
121 c
.addMouseMotionListener(this);
122 c
.addMouseListener(this);
123 c
.addMouseWheelListener(this);
125 if (this.keyPollTimer
!= null)
126 c
.addKeyListener(this.keyPollTimer
);
129 public WorldWindow
getEventSource()
131 return this.worldWindow
;
134 public void setHoverDelay(int delay
)
136 this.hoverTimer
.setDelay(delay
);
139 public int getHoverDelay()
141 return this.hoverTimer
.getDelay();
144 public void keyTyped(KeyEvent keyEvent
)
146 if (this.worldWindow
== null) // include this test to ensure any derived implementation performs it
150 public void keyPressed(KeyEvent keyEvent
)
152 if (this.worldWindow
== null) // include this test to ensure any derived implementation performs it
156 public void keyReleased(KeyEvent keyEvent
)
158 if (this.worldWindow
== null)
161 if (keyEvent
== null)
164 View view
= this.worldWindow
.getView();
168 int keyCode
= keyEvent
.getKeyCode();
169 if (keyCode
== KeyEvent
.VK_SPACE
)
171 this.interpolatorTimer
.stop();
173 else if (keyCode
== KeyEvent
.VK_N
)
175 InterpolatorTimer
.ViewProperties newProps
= new InterpolatorTimer
.ViewProperties();
176 newProps
.heading
= Angle
.fromDegrees(0);
177 this.setViewProperties(view
, newProps
, this.viewAngleResetStepCoefficient
, this.viewAngleErrorThreshold
,
180 else if (keyCode
== KeyEvent
.VK_R
)
182 InterpolatorTimer
.ViewProperties newProps
= new InterpolatorTimer
.ViewProperties();
183 newProps
.heading
= Angle
.fromDegrees(0);
184 newProps
.pitch
= Angle
.fromDegrees(0);
185 this.setViewProperties(view
, newProps
, this.viewAngleResetStepCoefficient
, this.viewAngleErrorThreshold
,
190 public void keysPolled(int keyCode
, int modifiers
)
192 if (this.worldWindow
== null)
195 View view
= this.worldWindow
.getView();
199 int slowMask
= (modifiers
& InputEvent
.ALT_DOWN_MASK
);
200 boolean slow
= slowMask
!= 0x0;
202 if (areModifiersExactly(modifiers
, slowMask
))
204 double sinHeading
= view
.getHeading().sin();
205 double cosHeading
= view
.getHeading().cos();
206 double latFactor
= 0;
207 double lonFactor
= 0;
208 if (keyCode
== KeyEvent
.VK_LEFT
)
210 latFactor
= sinHeading
;
211 lonFactor
= -cosHeading
;
213 else if (keyCode
== KeyEvent
.VK_RIGHT
)
215 latFactor
= -sinHeading
;
216 lonFactor
= cosHeading
;
218 else if (keyCode
== KeyEvent
.VK_UP
)
220 latFactor
= cosHeading
;
221 lonFactor
= sinHeading
;
223 else if (keyCode
== KeyEvent
.VK_DOWN
)
225 latFactor
= -cosHeading
;
226 lonFactor
= -sinHeading
;
228 if (latFactor
!= 0 || lonFactor
!= 0)
230 Globe globe
= this.worldWindow
.getModel().getGlobe();
233 LatLon latLonChange
= this.computeViewLatLonChange(view
, globe
, 10 * latFactor
, 10 * lonFactor
,
235 this.setViewLatLon(view
, this.computeNewViewLatLon(view
, latLonChange
.getLatitude(),
236 latLonChange
.getLongitude()));
242 double headingFactor
= 0;
243 double pitchFactor
= 0;
244 if (areModifiersExactly(modifiers
, slowMask
))
246 if (keyCode
== KeyEvent
.VK_PAGE_DOWN
)
248 else if (keyCode
== KeyEvent
.VK_PAGE_UP
)
251 else if (areModifiersExactly(modifiers
, InputEvent
.SHIFT_DOWN_MASK
| slowMask
))
253 if (keyCode
== KeyEvent
.VK_LEFT
)
255 else if (keyCode
== KeyEvent
.VK_RIGHT
)
257 else if (keyCode
== KeyEvent
.VK_UP
)
259 else if (keyCode
== KeyEvent
.VK_DOWN
)
262 if (headingFactor
!= 0)
264 this.setViewAngle(view
, this.computeNewViewHeading(view
,
265 this.computeViewAngleChange(4 * headingFactor
, slow
)), null);
268 else if (pitchFactor
!= 0)
270 this.setViewAngle(view
, null, this.computeNewViewPitch(view
,
271 this.computeViewAngleChange(4 * pitchFactor
, slow
)));
275 double zoomFactor
= 0;
276 if (areModifiersExactly(modifiers
, slowMask
))
278 if (keyCode
== KeyEvent
.VK_ADD
||
279 keyCode
== KeyEvent
.VK_EQUALS
)
281 else if (keyCode
== KeyEvent
.VK_SUBTRACT
||
282 keyCode
== KeyEvent
.VK_MINUS
)
285 else if (areModifiersExactly(modifiers
, InputEvent
.CTRL_DOWN_MASK
| slowMask
)
286 || areModifiersExactly(modifiers
, InputEvent
.META_DOWN_MASK
| slowMask
))
288 if (keyCode
== KeyEvent
.VK_UP
)
290 else if (keyCode
== KeyEvent
.VK_DOWN
)
295 this.setViewZoom(view
, this.computeNewViewZoom(view
, this.computeZoomViewChange(zoomFactor
, slow
)));
300 public void mouseClicked(final MouseEvent mouseEvent
)
302 if (this.worldWindow
== null) // include this test to ensure any subsequent implementation performs it
305 if (mouseEvent
== null)
308 View view
= this.worldWindow
.getView();
312 // int button = mouseEvent.getButton();
313 // if (this.mouseClickButton != button)
314 // this.mouseClickCount = 1;
316 // this.mouseClickCount = mouseEvent.getClickCount();
317 // this.mouseClickButton = button;
318 // if (this.mouseClickCount == 1)
320 // javax.swing.Timer clickTimer = new javax.swing.Timer(this.mouseClickCoalesceTime, new ActionListener()
322 // public void actionPerformed(ActionEvent evt)
324 // AWTInputHandler.this.mouseClickedCoalesced(mouseEvent, AWTInputHandler.this.mouseClickCount);
327 // clickTimer.setRepeats(false);
328 // clickTimer.start();
331 // if ( (null != this.lastPickedObjects)
332 // && (null != this.lastPickedObjects.getTopObject())
333 // && this.lastPickedObjects.getTopObject().isTerrain())
336 if (this.lastPickedObjects
!= null && this.lastPickedObjects
.size() > 0)
338 PickedObject top
= this.lastPickedObjects
.getTopObject();
339 if (top
!= null && top
.isTerrain())
341 InterpolatorTimer
.ViewProperties newProps
= new InterpolatorTimer
.ViewProperties();
342 Position position
= top
.getPosition();
343 newProps
.latLon
= new LatLon(position
.getLatitude(), position
.getLongitude());
344 this.setViewProperties(view
, newProps
, this.viewLatLonCenterStepCoefficient
,
345 this.viewLatLonErrorThresold
, true);
349 // Something is under the cursor, so it's deemed "selected".
351 if (MouseEvent
.BUTTON1
== mouseEvent
.getButton())
353 if (mouseEvent
.getClickCount() % 2 == 1)
355 this.callSelectListeners(new SelectEvent(this.worldWindow
, SelectEvent
.LEFT_CLICK
,
356 mouseEvent
, this.lastPickedObjects
));
360 this.callSelectListeners(new SelectEvent(this.worldWindow
, SelectEvent
.LEFT_DOUBLE_CLICK
,
361 mouseEvent
, this.lastPickedObjects
));
364 else if (MouseEvent
.BUTTON3
== mouseEvent
.getButton())
366 this.callSelectListeners(new SelectEvent(this.worldWindow
, SelectEvent
.RIGHT_CLICK
,
367 mouseEvent
, this.lastPickedObjects
));
370 view
.firePropertyChange(AVKey
.VIEW
, null, view
);
374 public void mousePressed(MouseEvent mouseEvent
)
376 if (this.worldWindow
== null)
382 public void mouseReleased(MouseEvent mouseEvent
)
384 if (this.worldWindow
== null)
390 public void mouseEntered(MouseEvent mouseEvent
)
392 if (this.worldWindow
== null)
398 public void mouseExited(MouseEvent mouseEvent
)
400 if (this.worldWindow
== null)
406 public void mouseDragged(MouseEvent mouseEvent
)
408 if (this.worldWindow
== null)
411 if (mouseEvent
== null)
414 View view
= this.worldWindow
.getView();
418 if (this.worldWindow
.getModel() == null)
421 java
.awt
.Point mouseMove
= new java
.awt
.Point(mouseEvent
.getPoint().x
- this.lastMousePoint
.x
,
422 mouseEvent
.getPoint().y
- this.lastMousePoint
.y
);
424 if (areModifiersExactly(mouseEvent
, InputEvent
.BUTTON1_DOWN_MASK
))
426 LatLon latLonChange
= null;
428 Position prev
= view
.computePositionFromScreenPoint(this.lastMousePoint
.x
, this.lastMousePoint
.y
);
429 Position cur
= view
.computePositionFromScreenPoint(mouseEvent
.getPoint().x
, mouseEvent
.getPoint().y
);
430 if (prev
!= null && cur
!= null)
432 latLonChange
= new LatLon(prev
.getLatitude().subtract(cur
.getLatitude()),
433 prev
.getLongitude().subtract(cur
.getLongitude()));
437 Globe globe
= this.worldWindow
.getModel().getGlobe();
440 double sinHeading
= view
.getHeading().sin();
441 double cosHeading
= view
.getHeading().cos();
442 double latFactor
= cosHeading
* mouseMove
.y
+ sinHeading
* mouseMove
.x
;
443 double lonFactor
= sinHeading
* mouseMove
.y
- cosHeading
* mouseMove
.x
;
444 latLonChange
= this.computeViewLatLonChange(view
, globe
, latFactor
, lonFactor
, false);
448 if (latLonChange
!= null)
450 this.setViewLatLon(view
, this.computeNewViewLatLon(view
, latLonChange
.getLatitude(),
451 latLonChange
.getLongitude()));
454 else if (areModifiersExactly(mouseEvent
, InputEvent
.BUTTON3_DOWN_MASK
)
455 || areModifiersExactly(mouseEvent
, InputEvent
.BUTTON1_DOWN_MASK
| InputEvent
.CTRL_DOWN_MASK
))
457 double headingDirection
= 1;
458 Object source
= mouseEvent
.getSource();
459 if (source
!= null && source
instanceof java
.awt
.Component
)
461 java
.awt
.Component component
= (java
.awt
.Component
) source
;
462 if (mouseEvent
.getPoint().y
< component
.getHeight() / 2)
463 headingDirection
= -1;
465 this.setViewAngle(view
,
466 this.computeNewViewHeading(view
, this.computeViewAngleChange(headingDirection
* mouseMove
.x
, false)),
467 this.computeNewViewPitch(view
, this.computeViewAngleChange(mouseMove
.y
, false)));
470 this.lastMousePoint
= mouseEvent
.getPoint();
473 public void mouseMoved(MouseEvent mouseEvent
)
475 if (this.worldWindow
== null)
478 if (mouseEvent
== null)
481 this.lastMousePoint
= mouseEvent
.getPoint();
483 View view
= this.worldWindow
.getView();
487 // Forward event to mouseDragged() for OS X.
488 // if (areModifiersExactly(mouseEvent, InputEvent.CTRL_DOWN_MASK))
490 // this.mouseDragged(mouseEvent);
493 Model model
= this.worldWindow
.getModel();
497 Globe globe
= model
.getGlobe();
501 this.lastPickedObjects
= this.worldWindow
.pick(mouseEvent
.getPoint());
502 PickedObject top
= null;
503 if (this.lastPickedObjects
!= null && this.lastPickedObjects
.size() > 0)
504 top
= this.lastPickedObjects
.getTopObject();
506 PickedObjectList selected
= null;
507 if (!(top
== null || top
.isTerrain())) // if not terrain
508 selected
= this.lastPickedObjects
;
510 this.callSelectListeners(new SelectEvent(this.worldWindow
, SelectEvent
.ROLLOVER
, mouseEvent
, selected
));
515 if (null != top
&& top
.hasPosition())
516 p
= top
.getPosition();
517 else if (this.lastPickedObjects
!= null && this.lastPickedObjects
.getTerrainObject() != null)
518 p
= this.lastPickedObjects
.getTerrainObject().getPosition();
520 this.callPositionListeners(new PositionEvent(this.worldWindow
, mouseEvent
, this.previousPickPosition
, p
));
521 this.previousPickPosition
= p
;
524 public void mouseWheelMoved(MouseWheelEvent mouseWheelEvent
)
526 if (this.worldWindow
== null)
529 if (mouseWheelEvent
== null)
532 View view
= this.worldWindow
.getView();
536 int wheelRotation
= mouseWheelEvent
.getWheelRotation();
537 double wheelDirection
= Math
.signum(wheelRotation
);
538 this.setViewZoom(view
, this.computeNewViewZoom(view
, this.computeZoomViewChange(wheelDirection
, false)));
541 private static boolean areModifiersExactly(InputEvent inputEvent
, int mask
)
543 return areModifiersExactly(inputEvent
.getModifiersEx(), mask
);
546 private static boolean areModifiersExactly(int modifiersEx
, int mask
)
548 return modifiersEx
== mask
;
551 private boolean isPickListEmpty(PickedObjectList pickList
)
553 return pickList
== null || pickList
.size() < 1;
556 private void doHover(boolean reset
)
558 if (!(this.isPickListEmpty(this.hoverObjects
) || this.isPickListEmpty(this.lastPickedObjects
)))
560 PickedObject hover
= this.hoverObjects
.getTopObject();
561 PickedObject last
= this.lastPickedObjects
.getTopObject();
563 if (hover
!= null && last
!= null && hover
.getObject().equals(last
.getObject()))
565 return; // object picked is the hover object. don't do anything but wait for the timer to expire.
574 if ((null != this.lastPickedObjects
)
575 && (null != this.lastPickedObjects
.getTopObject())
576 && this.lastPickedObjects
.getTopObject().isTerrain())
579 this.hoverObjects
= this.lastPickedObjects
;
580 this.hoverTimer
.restart();
583 private void cancelHover()
587 this.callSelectListeners(new SelectEvent(this.worldWindow
, SelectEvent
.HOVER
, null, null));
590 this.isHovering
= false;
591 this.hoverObjects
= null;
592 this.hoverTimer
.stop();
595 private boolean hoverMatches()
597 if (this.isPickListEmpty(this.lastPickedObjects
) || this.isPickListEmpty(this.hoverObjects
))
600 PickedObject lastTop
= this.lastPickedObjects
.getTopObject();
602 if (null != lastTop
&& lastTop
.isTerrain())
605 PickedObject newTop
= this.hoverObjects
.getTopObject();
606 //noinspection SimplifiableIfStatement
607 if (lastTop
== null || newTop
== null || lastTop
.getObject() == null || newTop
.getObject() == null)
610 return lastTop
.getObject().equals(newTop
.getObject());
613 public void addSelectListener(SelectListener listener
)
615 this.eventListeners
.add(SelectListener
.class, listener
);
618 public void removeSelectListener(SelectListener listener
)
620 this.eventListeners
.remove(SelectListener
.class, listener
);
623 public void addPositionListener(PositionListener listener
)
625 this.eventListeners
.add(PositionListener
.class, listener
);
628 public void removePositionListener(PositionListener listener
)
630 this.eventListeners
.remove(PositionListener
.class, listener
);
633 private void callSelectListeners(SelectEvent event
)
635 for (SelectListener listener
: this.eventListeners
.getListeners(SelectListener
.class))
637 listener
.selected(event
);
641 private void callPositionListeners(PositionEvent event
)
643 for (PositionListener listener
: this.eventListeners
.getListeners(PositionListener
.class))
645 listener
.moved(event
);
649 private void setViewProperties(final View view
, InterpolatorTimer
.ViewProperties newProperties
,
650 double stepCoefficient
, double errorThreshold
, boolean forceSmooth
)
654 String message
= WorldWind
.retrieveErrMsg("nullValue.ViewIsNull");
655 WorldWind
.logger().log(Level
.FINE
, message
);
656 throw new IllegalArgumentException(message
);
658 if (newProperties
== null)
660 String message
= WorldWind
.retrieveErrMsg("awt.InterpolatorTimer.ViewPropertiesIsNull");
661 WorldWind
.logger().log(Level
.FINE
, message
);
662 throw new IllegalArgumentException(message
);
665 if (forceSmooth
|| this.smoothViewChange
)
667 if (this.viewPropertyListener
== null)
669 this.viewPropertyListener
= new java
.beans
.PropertyChangeListener()
671 public void propertyChange(java
.beans
.PropertyChangeEvent evt
)
673 Object newValue
= evt
.getNewValue();
674 if (newValue
== null)
676 AWTInputHandler
.this.viewTarget
= null;
678 else if (newValue
instanceof InterpolatorTimer
.ViewProperties
)
680 InterpolatorTimer
.ViewProperties viewProps
= (InterpolatorTimer
.ViewProperties
) newValue
;
681 if (viewProps
.latLon
!= null)
682 view
.goToLatLon(viewProps
.latLon
);
683 if (viewProps
.heading
!= null)
684 view
.setHeading(viewProps
.heading
);
685 if (viewProps
.pitch
!= null)
686 view
.setPitch(viewProps
.pitch
);
687 if (viewProps
.zoom
!= null)
688 view
.setZoom(viewProps
.zoom
);
689 view
.firePropertyChange(AVKey
.VIEW
, null, view
);
694 InterpolatorTimer
.ViewProperties begin
= new InterpolatorTimer
.ViewProperties();
695 if (newProperties
.latLon
!= null)
696 begin
.latLon
= new LatLon(view
.getPosition().getLatitude(), view
.getPosition().getLongitude());
697 if (newProperties
.heading
!= null)
698 begin
.heading
= view
.getHeading();
699 if (newProperties
.pitch
!= null)
700 begin
.pitch
= view
.getPitch();
701 if (newProperties
.zoom
!= null)
702 begin
.zoom
= view
.getZoom();
703 this.viewTarget
= newProperties
;
704 this.interpolatorTimer
.start(stepCoefficient
, errorThreshold
, begin
, newProperties
,
705 this.viewPropertyListener
);
709 this.viewTarget
= null;
710 this.interpolatorTimer
.stop();
711 if (newProperties
.latLon
!= null)
712 view
.goToLatLon(newProperties
.latLon
);
713 if (newProperties
.heading
!= null)
714 view
.setHeading(newProperties
.heading
);
715 if (newProperties
.pitch
!= null)
716 view
.setPitch(newProperties
.pitch
);
717 if (newProperties
.zoom
!= null)
718 view
.setZoom(newProperties
.zoom
);
719 view
.firePropertyChange(AVKey
.VIEW
, null, view
);
723 private void setViewLatLon(final View view
, LatLon newLatLon
)
725 if (newLatLon
== null)
727 String message
= WorldWind
.retrieveErrMsg("nullValue.LatLonIsNull");
728 WorldWind
.logger().log(Level
.FINE
, message
);
729 throw new IllegalArgumentException(message
);
731 this.viewTarget
= new InterpolatorTimer
.ViewProperties();
732 this.viewTarget
.latLon
= newLatLon
;
733 this.setViewProperties(view
, this.viewTarget
, this.viewLatLonStepCoefficient
, this.viewLatLonErrorThresold
,
737 private LatLon
computeNewViewLatLon(View view
, Angle latChange
, Angle lonChange
)
741 if (this.viewTarget
!= null && this.viewTarget
.latLon
!= null)
743 latDegrees
= this.viewTarget
.latLon
.getLatitude().getDegrees();
744 lonDegrees
= this.viewTarget
.latLon
.getLongitude().getDegrees();
748 latDegrees
= view
.getPosition().getLatitude().getDegrees();
749 lonDegrees
= view
.getPosition().getLongitude().getDegrees();
751 latDegrees
= latDegrees
+ latChange
.getDegrees();
752 lonDegrees
= lonDegrees
+ lonChange
.getDegrees();
753 if (latDegrees
< -90)
755 else if (latDegrees
> 90)
757 if (lonDegrees
< -180)
758 lonDegrees
= lonDegrees
+ 360;
759 else if (lonDegrees
> 180)
760 lonDegrees
= lonDegrees
- 360;
761 return LatLon
.fromDegrees(latDegrees
, lonDegrees
);
764 private LatLon
computeViewLatLonChange(View view
, Globe globe
, double latFactor
, double lonFactor
, boolean slow
)
766 Point eye
= view
.getEyePoint();
770 double normAlt
= clamp((eye
.length() / globe
.getMaximumRadius()) - 1, 0, 1);
771 double factor
= ((1 - normAlt
) * this.viewLatLonMinChangeFactor
+ normAlt
* this.viewLatLonMaxChangeFactor
)
772 * (slow ?
2.5e-1 : 1);
773 return LatLon
.fromDegrees(latFactor
* factor
, lonFactor
* factor
);
776 private void setViewAngle(final View view
, Angle newHeading
, Angle newPitch
)
778 if (newHeading
== null && newPitch
== null)
780 String message
= WorldWind
.retrieveErrMsg("nullValue.AngleIsNull");
781 WorldWind
.logger().log(Level
.FINE
, message
);
782 throw new IllegalArgumentException(message
);
784 this.viewTarget
= new InterpolatorTimer
.ViewProperties();
785 this.viewTarget
.heading
= newHeading
;
786 this.viewTarget
.pitch
= newPitch
;
787 this.setViewProperties(view
, this.viewTarget
, this.viewAngleStepCoefficient
, this.viewAngleErrorThreshold
,
791 private Angle
computeNewViewHeading(View view
, Angle change
)
794 if (this.viewTarget
!= null && this.viewTarget
.heading
!= null)
795 degrees
= this.viewTarget
.heading
.getDegrees();
797 degrees
= view
.getHeading().getDegrees();
798 degrees
= degrees
+ change
.getDegrees();
800 degrees
= degrees
+ 360;
801 else if (degrees
> 360)
802 degrees
= degrees
- 360;
803 return Angle
.fromDegrees(degrees
);
806 private Angle
computeViewAngleChange(double factor
, boolean slow
)
808 return Angle
.fromDegrees(factor
* this.viewAngleChangeFactor
* (slow ?
2.5e-1 : 1));
811 private Angle
computeNewViewPitch(View view
, Angle change
)
814 if (this.viewTarget
!= null && this.viewTarget
.pitch
!= null)
815 degrees
= this.viewTarget
.pitch
.getDegrees();
817 degrees
= view
.getPitch().getDegrees();
818 degrees
= degrees
+ change
.getDegrees();
819 Angle
[] constraints
= view
.getPitchConstraints();
820 return Angle
.fromDegrees(clamp(degrees
, constraints
[0].getDegrees(), constraints
[1].getDegrees()));
823 private void setViewZoom(final View view
, double newZoom
)
825 this.viewTarget
= new InterpolatorTimer
.ViewProperties();
826 this.viewTarget
.zoom
= newZoom
;
827 this.setViewProperties(view
, this.viewTarget
, this.viewZoomStepCoefficient
, this.viewZoomErrorThreshold
,
831 private double computeNewViewZoom(View view
, double change
)
834 if (this.viewTarget
!= null && this.viewTarget
.zoom
!= null)
835 logZoom
= Math
.log(this.viewTarget
.zoom
);
837 logZoom
= Math
.log(view
.getZoom());
838 logZoom
= logZoom
+ change
;
839 double[] constraints
= view
.getZoomConstraints();
840 return clamp(Math
.exp(logZoom
), constraints
[0], constraints
[1]);
843 private double computeZoomViewChange(double factor
, boolean slow
)
845 return factor
* this.viewZoomChangeFactor
* (slow ?
2.5e-1 : 1);
848 private static double clamp(double x
, double min
, double max
)
850 return x
< min ? min
: (x
> max ? max
: x
);