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 }