View Javadoc

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