-
Notifications
You must be signed in to change notification settings - Fork 339
Expand file tree
/
Copy pathBasicDragger.java
More file actions
251 lines (223 loc) · 8.86 KB
/
BasicDragger.java
File metadata and controls
251 lines (223 loc) · 8.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/*
* Copyright (C) 2016 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package gov.nasa.worldwind.util;
import gov.nasa.worldwind.*;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.drag.*;
import gov.nasa.worldwind.event.*;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.globes.Globe;
import java.awt.*;
/**
* Interprets mouse input via the {@link DragSelectEvent} for notifying picked objects implementing the
* {@link Draggable} interface. This version uses the {@link Draggable} interface for dragging but retains the original
* behavior of the BasicDragger when the {@link gov.nasa.worldwind.pick.PickedObject} implements either the
* {@link Movable} or {@link Movable2} interface.
* <p>
* For objects not yet implementing the {@link Draggable} interface the legacy dragging functionality will be used.
*/
public class BasicDragger implements SelectListener
{
/**
* The {@link WorldWindow} this dragger will utilize for the {@link Globe}, {@link View}, and
* {@link SceneController} objects.
*/
protected WorldWindow wwd;
/**
* Indicates if the dragger is currently dragging.
*/
protected boolean dragging = false;
/**
* The {@link DragContext} for dragging operations. Initialized on {@link AVKey#DRAG_BEGIN}.
*/
protected DragContext dragContext;
/**
* Creates a dragging controller which converts {@link SelectEvent}s to the {@link Draggable} interface.
*
* @param wwd the {@link WorldWindow} this drag controller should be associated with.
*
* @throws IllegalArgumentException if the provided {@link WorldWindow} is null.
*/
public BasicDragger(WorldWindow wwd)
{
if (wwd == null)
{
String msg = Logging.getMessage("nullValue.WorldWindow");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
this.wwd = wwd;
}
/**
* Ignores the useTerrain argument as it has been deprecated and utilizes the single parameter constructor.
*
* @deprecated the useTerrain property has been deprecated in favor of the {@link Draggable} interface which allows
* the object to define the drag behavior.
*/
public BasicDragger(WorldWindow wwd, boolean useTerrain)
{
this(wwd);
}
/**
* Returns if the dragger is currently executing a dragging operation.
*
* @return <code>true</code> if a drag operation is executing.
*/
public boolean isDragging()
{
return this.dragging;
}
/**
*
* @return <code>false</code> as this functionality has been deprecated.
* @deprecated the {@link Draggable} provides the object being dragged complete control over the dragging behavior.
*/
public boolean isUseTerrain()
{
return false;
}
/**
* @param useTerrain
*
* @deprecated definition of dragging behavior now defined by the object in the {@link Draggable} interface.
*/
public void setUseTerrain(boolean useTerrain)
{
// ignored - functionality deprecated
}
@Override
public void selected(SelectEvent event)
{
if (event == null)
{
String msg = Logging.getMessage("nullValue.EventIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (event.getEventAction().equals(SelectEvent.DRAG_END))
{
if(this.dragContext != null)
{
this.dragContext.setDragState(AVKey.DRAG_ENDED);
this.fireDrag((DragSelectEvent) event);
this.dragContext = null;
}
this.dragging = false;
}
else if (event.getEventAction().equals(SelectEvent.DRAG))
{
if (this.dragContext == null)
this.dragContext = new DragContext();
this.dragContext.setPoint(event.getPickPoint());
this.dragContext.setPreviousPoint(((DragSelectEvent) event).getPreviousPickPoint());
this.dragContext.setView(this.wwd.getView());
this.dragContext.setGlobe(this.wwd.getModel().getGlobe());
this.dragContext.setSceneController(this.wwd.getSceneController());
if (this.dragging)
{
this.dragContext.setDragState(AVKey.DRAG_CHANGE);
this.fireDrag((DragSelectEvent) event);
}
else
{
this.dragContext.setDragState(AVKey.DRAG_BEGIN);
this.dragContext.setInitialPoint(((DragSelectEvent) event).getPreviousPickPoint());
this.dragging = true;
this.fireDrag((DragSelectEvent) event);
}
}
event.consume();
}
/**
* Propagates the {@link DragContext} to the picked object if it implements {@link Draggable},
* {@link Movable}, or {@link Movable2}.
*
* @param dragEvent the {@link DragContext} to deliver to the selected object.
*
* @throws IllegalArgumentException if the {@link DragContext} is null.
*/
protected void fireDrag(DragSelectEvent dragEvent)
{
if (dragEvent == null || dragEvent.getTopObject() == null)
{
String msg = Logging.getMessage("nullValue.ObjectIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
Object dragObject = dragEvent.getTopObject();
if (dragObject instanceof Draggable)
{
((Draggable) dragObject).drag(this.dragContext);
}
else if ((dragObject instanceof Movable2) || (dragObject instanceof Movable))
{
// Utilize the existing behavior
this.dragLegacy(dragEvent);
}
}
//////////////////////////////////////////////////////////
// Legacy Properties
//////////////////////////////////////////////////////////
protected Vec4 dragRefObjectPoint;
protected Point dragRefCursorPoint;
protected double dragRefAltitude;
/**
* Legacy drag approach, provided for objects not yet implementing the {@link Draggable} interface.
*
* @param event the current {@link SelectEvent}.
*/
protected void dragLegacy(SelectEvent event)
{
DragSelectEvent dragEvent = (DragSelectEvent) event;
Object dragObject = dragEvent.getTopObject();
if (dragObject == null)
return;
View view = wwd.getView();
Globe globe = wwd.getModel().getGlobe();
// Compute dragged object ref-point in model coordinates.
// Use the Icon and Annotation logic of elevation as offset above ground when below max elevation.
Position refPos = null;
if (dragObject instanceof Movable2)
refPos = ((Movable2) dragObject).getReferencePosition();
else if (dragObject instanceof Movable)
refPos = ((Movable) dragObject).getReferencePosition();
if (refPos == null)
return;
Vec4 refPoint = globe.computePointFromPosition(refPos);
if (this.dragContext.getDragState().equals(AVKey.DRAG_BEGIN)) // Dragging started
{
// Save initial reference points for object and cursor in screen coordinates
// Note: y is inverted for the object point.
this.dragRefObjectPoint = view.project(refPoint);
// Save cursor position
this.dragRefCursorPoint = dragEvent.getPreviousPickPoint();
// Save start altitude
this.dragRefAltitude = globe.computePositionFromPoint(refPoint).getElevation();
}
// Compute screen-coord delta since drag started.
int dx = dragEvent.getPickPoint().x - this.dragRefCursorPoint.x;
int dy = dragEvent.getPickPoint().y - this.dragRefCursorPoint.y;
// Find intersection of screen coord (refObjectPoint + delta) with globe.
double x = this.dragRefObjectPoint.x + dx;
double y = event.getMouseEvent().getComponent().getSize().height - this.dragRefObjectPoint.y + dy - 1;
Line ray = view.computeRayFromScreenPoint(x, y);
Position pickPos = null;
// Use intersection with sphere at reference altitude.
Intersection inters[] = globe.intersect(ray, this.dragRefAltitude);
if (inters != null)
pickPos = globe.computePositionFromPoint(inters[0].getIntersectionPoint());
if (pickPos != null)
{
// Intersection with globe. Move reference point to the intersection point,
// but maintain current altitude.
Position p = new Position(pickPos, refPos.getElevation());
if (dragObject instanceof Movable2)
((Movable2) dragObject).moveTo(globe, p);
else
((Movable) dragObject).moveTo(p);
}
}
}