View Javadoc

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