View Javadoc

1   /*
2    * $RCSfile: ZoomMouseBehavior.java,v $ A modification of MouseZoom.java *
3    * 
4    * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved.
5    * 
6    * Redistribution and use in source and binary forms, with or without
7    * modification, are permitted provided that the following conditions are met: -
8    * Redistribution of source code must retain the above copyright notice, this
9    * list of conditions and the following disclaimer. - Redistribution in binary
10   * form must reproduce the above copyright notice, this list of conditions and
11   * the following disclaimer in the documentation and/or other materials provided
12   * with the distribution.
13   * 
14   * Neither the name of Sun Microsystems, Inc. or the names of contributors may
15   * be used to endorse or promote products derived from this software without
16   * specific prior written permission.
17   * 
18   * This software is provided "AS IS," without a warranty of any kind. ALL
19   * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
20   * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
21   * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS
22   * LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A
23   * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
24   * IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT
25   * OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
26   * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
27   * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS
28   * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
29   * 
30   * You acknowledge that this software is not designed, licensed or intended for
31   * use in the design, construction, operation or maintenance of any nuclear
32   * facility.
33   * 
34   * $Revision: 1.5 $ $Date: 2004/12/16 13:18:56 $ $State: Exp $
35   */
36  /*
37   * Modified to zoom along the rotated z-axis (actually move). Copyright (c)
38   * 2002-2005 Delft University of Technology Jaffalaan 5, 2628 BX Delft, the
39   * Netherlands All rights reserved.
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 		// int id;
233 		// int dx, dy;
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 						// consolodate MOUSE_DRAG events
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 					// Now do some rotations around the x- and y-axis if these
306 					// are available.
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 						// transform the translation
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 		// nothing
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 }