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 package nl.tudelft.simulation.dsol.gui.animation3D.mouse;
42
43 import java.awt.AWTEvent;
44 import java.awt.Component;
45 import java.awt.event.MouseEvent;
46 import java.util.Enumeration;
47
48 import javax.media.j3d.Transform3D;
49 import javax.media.j3d.TransformGroup;
50 import javax.media.j3d.WakeupCriterion;
51 import javax.media.j3d.WakeupOnAWTEvent;
52 import javax.media.j3d.WakeupOnBehaviorPost;
53 import javax.vecmath.Vector3d;
54
55 import com.sun.j3d.utils.behaviors.mouse.MouseBehavior;
56 import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback;
57
58 /***
59 * ZoomMouseBehavior is a Java3D behavior object that lets users control the Z
60 * axis translation of an object via a mouse drag motion with the second mouse
61 * button. See MouseRotate for similar usage info. Based on
62 * com.sun.j3d.utils.behaviors.mouse.MouseZoom.
63 */
64 public class ZoomMouseBehavior extends MouseBehavior
65 {
66 /*** zoom factor */
67 private double zFactor = .04;
68
69 /*** translation */
70 private Vector3d translation = new Vector3d();
71
72 /*** callback */
73 private MouseBehaviorCallback callback = null;
74
75 /*** rotation group around x-axis */
76 private TransformGroup rotateXGroup = null;
77
78 /*** rotation group around y-axis */
79 private TransformGroup rotateYGroup = null;
80
81 /*** rotation around x-axis */
82 private Transform3D rotateX = new Transform3D();
83
84 /*** rotation around y-axis */
85 private Transform3D rotateY = new Transform3D();
86
87
88 /***
89 * Creates a zoom behavior given the transform group.
90 *
91 * @param transformGroup The transformGroup to operate on.
92 */
93 public ZoomMouseBehavior(final TransformGroup transformGroup)
94 {
95 super(transformGroup);
96 }
97
98 /***
99 * Creates a default mouse zoom behavior.
100 */
101 public ZoomMouseBehavior()
102 {
103 super(0);
104 }
105
106 /***
107 * Creates a zoom behavior. Note that this behavior still needs a transform
108 * group to work on (use setTransformGroup(tg)) and the transform group must
109 * add this behavior.
110 *
111 * @param flags flags
112 */
113 public ZoomMouseBehavior(final int flags)
114 {
115 super(flags);
116 }
117
118 /***
119 * Creates a zoom behavior that uses AWT listeners and behavior posts rather
120 * than WakeupOnAWTEvent. The behavior is added to the specified Component.
121 * A null component can be passed to specify the behavior should use
122 * listeners. Components can then be added to the behavior with the
123 * addListener(Component c) method.
124 *
125 * @param c The Component to add the MouseListener and MouseMotionListener
126 * to.
127 * @since Java 3D 1.2.1
128 */
129 public ZoomMouseBehavior(final Component c)
130 {
131 super(c, 0);
132 }
133
134 /***
135 * Creates a zoom behavior that uses AWT listeners and behavior posts rather
136 * than WakeupOnAWTEvent. The behaviors is added to the specified Component
137 * and works on the given TransformGroup.
138 *
139 * @param c The Component to add the MouseListener and MouseMotionListener
140 * to. A null component can be passed to specify the behavior should
141 * use listeners. Components can then be added to the behavior with
142 * the addListener(Component c) method.
143 * @param transformGroup The TransformGroup to operate on.
144 * @since Java 3D 1.2.1
145 */
146 public ZoomMouseBehavior(final Component c,
147 final TransformGroup transformGroup)
148 {
149 super(c, transformGroup);
150 }
151
152 /***
153 * Creates a zoom behavior that uses AWT listeners and behavior posts rather
154 * than WakeupOnAWTEvent. The behavior is added to the specified Component.
155 * A null component can be passed to specify the behavior should use
156 * listeners. Components can then be added to the behavior with the
157 * addListener(Component c) method. Note that this behavior still needs a
158 * transform group to work on (use setTransformGroup(tg)) and the transform
159 * group must add this behavior.
160 *
161 * @param c The Component to add the MouseListener and MouseMotionListener
162 * to. A null component can be passed to specify the behavior should
163 * use listeners. Components can then be added to the behavior with
164 * the addListener(Component c) method.
165 * @param flags interesting flags (wakeup conditions).
166 * @since Java 3D 1.2.1
167 */
168 public ZoomMouseBehavior(final Component c, final int flags)
169 {
170 super(c, flags);
171 }
172
173 /***
174 * @see javax.media.j3d.Behavior#initialize()
175 */
176 public void initialize()
177 {
178 super.initialize();
179 if ((this.flags & INVERT_INPUT) == INVERT_INPUT)
180 {
181 this.zFactor *= -1;
182 this.invert = true;
183 }
184 }
185
186 /***
187 * @return the y-axis movement multipler.
188 */
189 public double getFactor()
190 {
191 return this.zFactor;
192 }
193
194 /***
195 * Set the y-axis movement multipler with factor.
196 *
197 * @param factor the zoom factor
198 */
199 public void setFactor(final double factor)
200 {
201 this.zFactor = factor;
202 }
203
204 /***
205 * Set the rotation around the x-axis.
206 *
207 * @param rotateXGroup rotation around x-axis.
208 */
209 public void setRotateXGroup(final TransformGroup rotateXGroup)
210 {
211 this.rotateXGroup = rotateXGroup;
212 }
213
214 /***
215 * Set the rotation around the y-axis.
216 *
217 * @param rotateYGroup rotation around y-axis.
218 */
219 public void setRotateYGroup(final TransformGroup rotateYGroup)
220 {
221 this.rotateYGroup = rotateYGroup;
222 }
223
224 /***
225 * @see javax.media.j3d.Behavior#processStimulus(java.util.Enumeration)
226 */
227 public void processStimulus(final Enumeration criteria)
228 {
229 WakeupCriterion wakeup;
230 AWTEvent[] events;
231 MouseEvent evt;
232
233
234
235 while (criteria.hasMoreElements())
236 {
237 wakeup = (WakeupCriterion) criteria.nextElement();
238 if (wakeup instanceof WakeupOnAWTEvent)
239 {
240 events = ((WakeupOnAWTEvent) wakeup).getAWTEvent();
241 if (events.length > 0)
242 {
243 evt = (MouseEvent) events[events.length - 1];
244 doProcess(evt);
245 }
246 } else if (wakeup instanceof WakeupOnBehaviorPost)
247 {
248 while (true)
249 {
250 synchronized (this.mouseq)
251 {
252 if (this.mouseq.isEmpty())
253 {
254 break;
255 }
256 evt = (MouseEvent) this.mouseq.remove(0);
257
258 while ((evt.getID() == MouseEvent.MOUSE_DRAGGED)
259 && !this.mouseq.isEmpty()
260 && (((MouseEvent) this.mouseq.get(0)).getID() == MouseEvent.MOUSE_DRAGGED))
261 {
262 evt = (MouseEvent) this.mouseq.remove(0);
263 }
264 }
265 doProcess(evt);
266 }
267 }
268
269 }
270 wakeupOn(this.mouseCriterion);
271 }
272
273 /***
274 * @param evt mouse event
275 */
276 void doProcess(final MouseEvent evt)
277 {
278 int id;
279 int dy;
280
281 processMouseEvent(evt);
282
283 if (((this.buttonPress) && ((this.flags & MANUAL_WAKEUP) == 0))
284 || ((this.wakeUp) && ((this.flags & MANUAL_WAKEUP) != 0)))
285 {
286 id = evt.getID();
287 if ((id == MouseEvent.MOUSE_DRAGGED) && evt.isAltDown()
288 && !evt.isMetaDown())
289 {
290
291 this.y = evt.getY();
292
293 dy = this.y - this.y_last;
294
295 if ((!this.reset) && ((Math.abs(dy) < 50)))
296 {
297 this.transformGroup.getTransform(this.currXform);
298
299 this.translation.x = 0;
300 this.translation.y = 0;
301 this.translation.z = -dy * this.zFactor;
302
303 this.transformX.setZero();
304
305
306
307 if ((this.rotateYGroup != null)
308 && (this.rotateXGroup != null))
309 {
310 this.rotateYGroup.getTransform(this.rotateY);
311 this.rotateXGroup.getTransform(this.rotateX);
312 this.transformX.set(this.rotateY);
313 this.transformX.mul(this.rotateX);
314
315
316 this.transformX.transform(this.translation);
317 }
318 this.transformX.set(this.translation);
319
320 if (this.invert)
321 {
322 this.currXform.mul(this.currXform, this.transformX);
323 } else
324 {
325 this.currXform.mul(this.transformX, this.currXform);
326 }
327
328 this.transformGroup.setTransform(this.currXform);
329
330 this.transformChanged(this.currXform);
331
332 if (this.callback != null)
333 {
334 this.callback.transformChanged(
335 MouseBehaviorCallback.ZOOM, this.currXform);
336 }
337
338 } else
339 {
340 this.reset = false;
341 }
342
343 this.x_last = this.x;
344 this.y_last = this.y;
345 } else if (id == MouseEvent.MOUSE_PRESSED)
346 {
347 this.x_last = evt.getX();
348 this.y_last = evt.getY();
349 }
350 }
351 }
352
353 /***
354 * Users can overload this method which is called every time the Behavior
355 * updates the transform
356 *
357 * Default implementation does nothing
358 *
359 * @param transform transform
360 */
361 public void transformChanged(final Transform3D transform)
362 {
363
364 }
365
366 /***
367 * The transformChanged method in the callback class will be called every
368 * time the transform is updated
369 *
370 * @param callback callback
371 */
372 public void setupCallback(final MouseBehaviorCallback callback)
373 {
374 this.callback = callback;
375 }
376 }