View Javadoc

1   /*
2    * $RCSfile: MouseRotate.java,v $
3    *
4    * Copyright (c) 2006 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
8    * are met:
9    *
10   * - Redistribution of source code must retain the above copyright
11   *   notice, this list of conditions and the following disclaimer.
12   *
13   * - Redistribution in binary form must reproduce the above copyright
14   *   notice, this list of conditions and the following disclaimer in
15   *   the documentation and/or other materials provided with the
16   *   distribution.
17   *
18   * Neither the name of Sun Microsystems, Inc. or the names of
19   * contributors may be used to endorse or promote products derived
20   * from this software without specific prior written permission.
21   *
22   * This software is provided "AS IS," without a warranty of any
23   * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
24   * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
25   * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
26   * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
27   * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
28   * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
29   * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
30   * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
31   * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
32   * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
33   * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
34   * POSSIBILITY OF SUCH DAMAGES.
35   *
36   * You acknowledge that this software is not designed, licensed or
37   * intended for use in the design, construction, operation or
38   * maintenance of any nuclear facility.
39   *
40   * $Revision: 1.1 $
41   * $Date: 2009/04/08 06:31:15 $
42   * $State: Exp $
43   */
44  
45  package edu.uci.ics.jung.visualization3d.control;
46  
47  import java.awt.*;
48  import java.awt.event.*;
49  import java.util.*;
50  import javax.media.j3d.*;
51  import javax.vecmath.*;
52  
53  import com.sun.j3d.utils.behaviors.mouse.MouseBehavior;
54  import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback;
55  
56  /**
57   * MouseRotate is a Java3D behavior object that lets users control the 
58   * rotation of an object via a mouse.
59   * <p>
60   * To use this utility, first create a transform group that this 
61   * rotate behavior will operate on. Then,
62   *<blockquote><pre>
63   * 
64   *   MouseRotate behavior = new MouseRotate();
65   *   behavior.setTransformGroup(objTrans);
66   *   objTrans.addChild(behavior);
67   *   behavior.setSchedulingBounds(bounds);
68   *
69   *</pre></blockquote>
70   * The above code will add the rotate behavior to the transform
71   * group. The user can rotate any object attached to the objTrans.
72   */
73  
74  public class MouseRotate extends MouseBehavior {
75  	double x_angle, y_angle;
76  	double x_factor = .03;
77  	double y_factor = .03;
78  
79  	private MouseBehaviorCallback callback = null;
80  
81  	/**
82  	 * Creates a rotate behavior given the transform group.
83  	 * @param transformGroup The transformGroup to operate on.
84  	 */
85  	public MouseRotate(TransformGroup transformGroup) {
86  		super(transformGroup);
87  	}
88  
89  	/**
90  	 * Creates a default mouse rotate behavior.
91  	 **/
92  	public MouseRotate() {
93  		super(0);
94  	}
95  
96  	/**
97  	 * Creates a rotate behavior.
98  	 * Note that this behavior still needs a transform
99  	 * group to work on (use setTransformGroup(tg)) and
100 	 * the transform group must add this behavior.
101 	 * @param flags interesting flags (wakeup conditions).
102 	 */
103 	public MouseRotate(int flags) {
104 		super(flags);
105 	}
106 
107 	/**
108 	 * Creates a rotate behavior that uses AWT listeners and behavior
109 	 * posts rather than WakeupOnAWTEvent.  The behavior is added to the
110 	 * specified Component. A null component can be passed to specify
111 	 * the behavior should use listeners.  Components can then be added
112 	 * to the behavior with the addListener(Component c) method.
113 	 * @param c The Component to add the MouseListener
114 	 * and MouseMotionListener to.
115 	 * @since Java 3D 1.2.1
116 	 */
117 	public MouseRotate(Component c) {
118 		super(c, 0);
119 	}
120 
121 	/**
122 	 * Creates a rotate behavior that uses AWT listeners and behavior
123 	 * posts rather than WakeupOnAWTEvent.  The behaviors is added to
124 	 * the specified Component and works on the given TransformGroup.
125 	 * A null component can be passed to specify the behavior should use
126 	 * listeners.  Components can then be added to the behavior with the
127 	 * addListener(Component c) method.
128 	 * @param c The Component to add the MouseListener and
129 	 * MouseMotionListener to.
130 	 * @param transformGroup The TransformGroup to operate on.
131 	 * @since Java 3D 1.2.1
132 	 */
133 	public MouseRotate(Component c, TransformGroup transformGroup) {
134 		super(c, transformGroup);
135 	}
136 
137 	/**
138 	 * Creates a rotate behavior that uses AWT listeners and behavior
139 	 * posts rather than WakeupOnAWTEvent.  The behavior is added to the
140 	 * specified Component.  A null component can be passed to specify
141 	 * the behavior should use listeners.  Components can then be added to
142 	 * the behavior with the addListener(Component c) method.
143 	 * Note that this behavior still needs a transform
144 	 * group to work on (use setTransformGroup(tg)) and the transform
145 	 * group must add this behavior.
146 	 * @param flags interesting flags (wakeup conditions).
147 	 * @since Java 3D 1.2.1
148 	 */
149 	public MouseRotate(Component c, int flags) {
150 		super(c, flags);
151 	}
152 
153 	public void initialize() {
154 		super.initialize();
155 		x_angle = 0;
156 		y_angle = 0;
157 		if ((flags & INVERT_INPUT) == INVERT_INPUT) {
158 			invert = true;
159 			x_factor *= -1;
160 			y_factor *= -1;
161 		}
162 	}
163 
164 	/**
165 	 * Return the x-axis movement multipler.
166 	 **/
167 	public double getXFactor() {
168 		return x_factor;
169 	}
170 
171 	/**
172 	 * Return the y-axis movement multipler.
173 	 **/
174 	public double getYFactor() {
175 		return y_factor;
176 	}
177 
178 
179 	/**
180 	 * Set the x-axis amd y-axis movement multipler with factor.
181 	 **/
182 	public void setFactor( double factor) {
183 		x_factor = y_factor = factor;
184 	}
185 
186 	/**
187 	 * Set the x-axis amd y-axis movement multipler with xFactor and yFactor
188 	 * respectively.
189 	 **/
190 	public void setFactor( double xFactor, double yFactor) {
191 		x_factor = xFactor;
192 		y_factor = yFactor;    
193 	}
194 
195 	public void processStimulus (Enumeration criteria) {
196 		WakeupCriterion wakeup;
197 		AWTEvent[] events;
198 		MouseEvent evt;
199 //		int id;
200 //		int dx, dy;
201 
202 		while (criteria.hasMoreElements()) {
203 			wakeup = (WakeupCriterion) criteria.nextElement();
204 			if (wakeup instanceof WakeupOnAWTEvent) {
205 				events = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
206 				if (events.length > 0) {
207 					evt = (MouseEvent) events[events.length-1];
208 					doProcess(evt);
209 				}
210 			}
211 
212 			else if (wakeup instanceof WakeupOnBehaviorPost) {
213 				while (true) {
214 					// access to the queue must be synchronized
215 					synchronized (mouseq) {
216 						if (mouseq.isEmpty()) break;
217 						evt = (MouseEvent)mouseq.remove(0);
218 						// consolidate MOUSE_DRAG events
219 						while ((evt.getID() == MouseEvent.MOUSE_DRAGGED) &&
220 								!mouseq.isEmpty() &&
221 								(((MouseEvent)mouseq.get(0)).getID() ==
222 									MouseEvent.MOUSE_DRAGGED)) {
223 							evt = (MouseEvent)mouseq.remove(0);
224 						}
225 					}
226 					doProcess(evt);
227 				}
228 			}
229 
230 		}
231 		wakeupOn (mouseCriterion);
232 	}
233 
234 	void doProcess(MouseEvent evt) {
235 		int id;
236 		int dx, dy;
237 
238 		processMouseEvent(evt);
239 		if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) ||
240 				((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))) {
241 			id = evt.getID();
242 			if ((id == MouseEvent.MOUSE_DRAGGED) && 
243 					!evt.isMetaDown() && ! evt.isAltDown() && evt.isShiftDown()){
244 				x = evt.getX();
245 				y = evt.getY();
246 
247 				dx = x - x_last;
248 				dy = y - y_last;
249 
250 				if (!reset){	    
251 					x_angle = dy * y_factor;
252 					y_angle = dx * x_factor;
253 
254 					transformX.rotX(x_angle);
255 					transformY.rotY(y_angle);
256 
257 					transformGroup.getTransform(currXform);
258 
259 					Matrix4d mat = new Matrix4d();
260 					// Remember old matrix
261 					currXform.get(mat);
262 
263 					// Translate to origin
264 					currXform.setTranslation(new Vector3d(0.0,0.0,0.0));
265 					if (invert) {
266 						currXform.mul(currXform, transformX);
267 						currXform.mul(currXform, transformY);
268 					} else {
269 						currXform.mul(transformX, currXform);
270 						currXform.mul(transformY, currXform);
271 					}
272 
273 					// Set old translation back
274 					Vector3d translation = new 
275 					Vector3d(mat.m03, mat.m13, mat.m23);
276 					currXform.setTranslation(translation);
277 
278 					// Update xform
279 					transformGroup.setTransform(currXform);
280 
281 					transformChanged( currXform );
282 
283 					if (callback!=null)
284 						callback.transformChanged( MouseBehaviorCallback.ROTATE,
285 								currXform );
286 				}
287 				else {
288 					reset = false;
289 				}
290 
291 				x_last = x;
292 				y_last = y;
293 			}
294 			else if (id == MouseEvent.MOUSE_PRESSED) {
295 				x_last = evt.getX();
296 				y_last = evt.getY();
297 			}
298 		}
299 	}
300 
301 	/**
302 	 * Users can overload this method  which is called every time
303 	 * the Behavior updates the transform
304 	 *
305 	 * Default implementation does nothing
306 	 */
307 	public void transformChanged( Transform3D transform ) {
308 	}
309 
310 
311 	/**
312 	 * The transformChanged method in the callback class will
313 	 * be called every time the transform is updated
314 	 */
315 	public void setupCallback( MouseBehaviorCallback callback ) {
316 		this.callback = callback;
317 	}
318 }