View Javadoc

1   /*
2    * $RCSfile: TranslateMouseBehavior.java,v $
3    * A modification of MouseTranslate.java *
4    *
5    * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * - Redistribution of source code must retain the above copyright
12   *   notice, this list of conditions and the following disclaimer.
13   *
14   * - Redistribution in binary form must reproduce the above copyright
15   *   notice, this list of conditions and the following disclaimer in
16   *   the documentation and/or other materials provided with the
17   *   distribution.
18   *
19   * Neither the name of Sun Microsystems, Inc. or the names of
20   * contributors may be used to endorse or promote products derived
21   * from this software without specific prior written permission.
22   *
23   * This software is provided "AS IS," without a warranty of any
24   * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
25   * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
26   * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
27   * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
28   * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
29   * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
30   * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
31   * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
32   * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
33   * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
34   * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
35   * POSSIBILITY OF SUCH DAMAGES.
36   *
37   * You acknowledge that this software is not designed, licensed or
38   * intended for use in the design, construction, operation or
39   * maintenance of any nuclear facility.
40   *
41   * $Revision: 1.1 $
42   * $Date: 2004/09/28 09:44:32 $
43   * $State: Exp $
44   */
45  /*
46   * Modified to translate with axis rotations taking into account. 
47   * Copyright (c) 2003 Delft University of Technology 
48   * Jaffalaan 5, 2628 BX Delft, the Netherlands All
49   * rights reserved.
50   */
51  package nl.tudelft.simulation.dsol.gui.animation3D.mouse;
52  
53  import java.awt.AWTEvent;
54  import java.awt.Component;
55  import java.awt.event.MouseEvent;
56  import java.util.Enumeration;
57  
58  import javax.media.j3d.Transform3D;
59  import javax.media.j3d.TransformGroup;
60  import javax.media.j3d.WakeupCriterion;
61  import javax.media.j3d.WakeupOnAWTEvent;
62  import javax.media.j3d.WakeupOnBehaviorPost;
63  import javax.vecmath.Vector3d;
64  
65  import com.sun.j3d.utils.behaviors.mouse.MouseBehavior;
66  import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback;
67  
68  /***
69   * Translation behavior defines how the camera is translated. Based on
70   * com.sun.j3d.utils.behaviors.mouse.MouseTranslate.
71   */
72  public class TranslateMouseBehavior extends MouseBehavior
73  {
74      /*** x translation factor */
75      private double xFactor = .02;
76  
77      /*** y translation factor */
78      private double yFactor = .02;
79  
80      /*** translation vector */
81      private Vector3d translation = new Vector3d();
82  
83      /*** mouse behavior callback */
84      private MouseBehaviorCallback callback = null;
85  
86      /*** rotation group around x-axis */
87      private TransformGroup rotateXGroup = null;
88  
89      /*** rotation group around y-axis */
90      private TransformGroup rotateYGroup = null;
91  
92      /*** rotation around x-axis */
93      private Transform3D rotateX = new Transform3D();
94  
95      /*** rotation around y-axis */
96      private Transform3D rotateY = new Transform3D();
97  
98      /***
99       * Creates a mouse translate behavior given the transform group.
100      * 
101      * @param transformGroup The transformGroup to operate on.
102      */
103     public TranslateMouseBehavior(final TransformGroup transformGroup)
104     {
105         super(transformGroup);
106     }
107 
108     /***
109      * Creates a default translate behavior.
110      */
111     public TranslateMouseBehavior()
112     {
113         super(0);
114     }
115 
116     /***
117      * Creates a translate behavior. Note that this behavior still needs a
118      * transform group to work on (use setTransformGroup(tg)) and the transform
119      * group must add this behavior.
120      * 
121      * @param flags flags
122      */
123     public TranslateMouseBehavior(final int flags)
124     {
125         super(flags);
126     }
127 
128     /***
129      * Creates a translate behavior that uses AWT listeners and behavior posts
130      * rather than WakeupOnAWTEvent. The behavior is added to the specified
131      * Component. A null component can be passed to specify the behavior should
132      * use listeners. Components can then be added to the behavior with the
133      * addListener(Component c) method.
134      * 
135      * @param c The Component to add the MouseListener and MouseMotionListener
136      *            to.
137      * @since Java 3D 1.2.1
138      */
139     public TranslateMouseBehavior(final Component c)
140     {
141         super(c, 0);
142     }
143 
144     /***
145      * Creates a translate behavior that uses AWT listeners and behavior posts
146      * rather than WakeupOnAWTEvent. The behaviors is added to the specified
147      * Component and works on the given TransformGroup. A null component can be
148      * passed to specify the behavior should use listeners. Components can then
149      * be added to the behavior with the addListener(Component c) method.
150      * 
151      * @param c The Component to add the MouseListener and MouseMotionListener
152      *            to.
153      * @param transformGroup The TransformGroup to operate on.
154      * @since Java 3D 1.2.1
155      */
156     public TranslateMouseBehavior(final Component c,
157             final TransformGroup transformGroup)
158     {
159         super(c, transformGroup);
160     }
161 
162     /***
163      * Creates a translate behavior that uses AWT listeners and behavior posts
164      * rather than WakeupOnAWTEvent. The behavior is added to the specified
165      * Component. A null component can be passed to specify the behavior should
166      * use listeners. Components can then be added to the behavior with the
167      * addListener(Component c) method. Note that this behavior still needs a
168      * transform group to work on (use setTransformGroup(tg)) and the transform
169      * group must add this behavior.
170      * 
171      * @param c The Component to add the MouseListener and MouseMotionListener
172      *            to.
173      * @param flags interesting flags (wakeup conditions).
174      * @since Java 3D 1.2.1
175      */
176     public TranslateMouseBehavior(final Component c, final int flags)
177     {
178         super(c, flags);
179     }
180 
181     /***
182      * @see javax.media.j3d.Behavior#initialize()
183      */
184     public void initialize()
185     {
186         super.initialize();
187         if ((flags & INVERT_INPUT) == INVERT_INPUT)
188         {
189             invert = true;
190             this.xFactor *= -1;
191             this.yFactor *= -1;
192         }
193     }
194 
195     /***
196      * @return the x-axis movement multipler.
197      */
198     public double getXFactor()
199     {
200         return this.xFactor;
201     }
202 
203     /***
204      * @return the y-axis movement multipler.
205      */
206     public double getYFactor()
207     {
208         return this.yFactor;
209     }
210 
211     /***
212      * Set the x-axis amd y-axis movement multipler with factor.
213      * 
214      * @param factor same factor for both x and y
215      */
216     public void setFactor(final double factor)
217     {
218         this.xFactor = factor;
219         this.yFactor = factor;
220     }
221 
222     /***
223      * Set the x-axis amd y-axis movement multipler with xFactor and yFactor
224      * respectively.
225      * 
226      * @param xFactor the xFactor
227      * @param yFactor the yFactor
228      */
229     public void setFactor(final double xFactor, final double yFactor)
230     {
231         this.xFactor = xFactor;
232         this.yFactor = yFactor;
233     }
234 
235     /***
236      * Set the rotation around the x-axis.
237      * 
238      * @param rotateXGroup rotation around x-axis.
239      */
240     public void setRotateXGroup(final TransformGroup rotateXGroup)
241     {
242         this.rotateXGroup = rotateXGroup;
243     }
244 
245     /***
246      * Set the rotation around the y-axis.
247      * 
248      * @param rotateYGroup rotation around y-axis.
249      */
250     public void setRotateYGroup(final TransformGroup rotateYGroup)
251     {
252         this.rotateYGroup = rotateYGroup;
253     }
254 
255     /***
256      * @see javax.media.j3d.Behavior#processStimulus(java.util.Enumeration)
257      */
258     public void processStimulus(final Enumeration criteria)
259     {
260         WakeupCriterion wakeup;
261         AWTEvent[] events;
262         MouseEvent evt;
263         // 	int id;
264         // 	int dx, dy;
265 
266         while (criteria.hasMoreElements())
267         {
268             wakeup = (WakeupCriterion) criteria.nextElement();
269 
270             if (wakeup instanceof WakeupOnAWTEvent)
271             {
272                 events = ((WakeupOnAWTEvent) wakeup).getAWTEvent();
273                 if (events.length > 0)
274                 {
275                     evt = (MouseEvent) events[events.length - 1];
276                     doProcess(evt);
277                 }
278             } else if (wakeup instanceof WakeupOnBehaviorPost)
279             {
280                 while (true)
281                 {
282                     // access to the queue must be synchronized
283                     synchronized (mouseq)
284                     {
285                         if (mouseq.isEmpty())
286                         {
287                             break;
288                         }
289                         evt = (MouseEvent) mouseq.remove(0);
290                         // consolodate MOUSE_DRAG events
291                         while ((evt.getID() == MouseEvent.MOUSE_DRAGGED)
292                                 && !mouseq.isEmpty()
293                                 && (((MouseEvent) mouseq.get(0)).getID() == MouseEvent.MOUSE_DRAGGED))
294                         {
295                             evt = (MouseEvent) mouseq.remove(0);
296                         }
297                     }
298                     doProcess(evt);
299                 }
300             }
301 
302         }
303         wakeupOn(mouseCriterion);
304     }
305 
306     /***
307      * @param evt mouse event
308      */
309     void doProcess(final MouseEvent evt)
310     {
311         int id;
312         int dx, dy;
313 
314         processMouseEvent(evt);
315 
316         if (((buttonPress) && ((flags & MANUAL_WAKEUP) == 0))
317                 || ((wakeUp) && ((flags & MANUAL_WAKEUP) != 0)))
318         {
319             id = evt.getID();
320             if ((id == MouseEvent.MOUSE_DRAGGED) && !evt.isAltDown()
321                     && evt.isMetaDown())
322             {
323 
324                 this.x = evt.getX();
325                 this.y = evt.getY();
326 
327                 dx = this.x - this.x_last;
328                 dy = this.y - this.y_last;
329 
330                 if ((!reset) && ((Math.abs(dy) < 50) && (Math.abs(dx) < 50)))
331                 {
332                     //System.out.println("dx " + dx + " dy " + dy);
333                     this.transformGroup.getTransform(this.currXform);
334 
335                     this.translation.x = dx * this.xFactor;
336                     this.translation.y = -dy * this.yFactor;
337                     this.translation.z = 0;
338 
339                     this.transformX.setZero();
340 
341                     // Now do some rotations around the x- and y-axis if these
342                     // are available.
343                     if ((this.rotateYGroup != null)
344                             && (this.rotateXGroup != null))
345                     {
346                         this.rotateYGroup.getTransform(this.rotateY);
347                         this.rotateXGroup.getTransform(this.rotateX);
348                         this.transformX.set(this.rotateY);
349                         this.transformX.mul(this.rotateX);
350 
351                         // transform the translation
352                         this.transformX.transform(this.translation);
353                     }
354                     this.transformX.set(this.translation);
355 
356                     if (this.invert)
357                     {
358                         this.currXform.mul(this.currXform, this.transformX);
359                     } else
360                     {
361                         this.currXform.mul(this.transformX, this.currXform);
362                     }
363 
364                     this.transformGroup.setTransform(this.currXform);
365 
366                     this.transformChanged(this.currXform);
367 
368                     if (this.callback != null)
369                     {
370                         this.callback
371                                 .transformChanged(
372                                         MouseBehaviorCallback.TRANSLATE,
373                                         this.currXform);
374                     }
375 
376                 } else
377                 {
378                     this.reset = false;
379                 }
380                 this.x_last = this.x;
381                 this.y_last = this.y;
382             } else if (id == MouseEvent.MOUSE_PRESSED)
383             {
384                 this.x_last = evt.getX();
385                 this.y_last = evt.getY();
386             }
387         }
388     }
389 
390     /***
391      * Users can overload this method which is called every time the Behavior
392      * updates the transform
393      * 
394      * Default implementation does nothing
395      * 
396      * @param transform the transform
397      */
398     public void transformChanged(final Transform3D transform)
399     {
400         // Nothing
401     }
402 
403     /***
404      * The transformChanged method in the callback class will be called every
405      * time the transform is updated
406      * 
407      * @param callback callback
408      */
409     public void setupCallback(final MouseBehaviorCallback callback)
410     {
411         this.callback = callback;
412     }
413 }