1 /*
2 * $RCSfile: MouseTranslate.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 * MouseTranslate is a Java3D behavior object that lets users control the
58 * translation (X, Y) of an object via a mouse drag motion with the third
59 * mouse button (alt-click on PC). See MouseRotate for similar usage info.
60 */
61
62 public class MouseTranslate extends MouseBehavior {
63
64 double x_factor = .02;
65 double y_factor = .02;
66 Vector3d translation = new Vector3d();
67
68 private MouseBehaviorCallback callback = null;
69
70 /**
71 * Creates a mouse translate behavior given the transform group.
72 * @param transformGroup The transformGroup to operate on.
73 */
74 public MouseTranslate(TransformGroup transformGroup) {
75 super(transformGroup);
76 }
77
78 /**
79 * Creates a default translate behavior.
80 */
81 public MouseTranslate(){
82 super(0);
83 }
84
85 /**
86 * Creates a translate behavior.
87 * Note that this behavior still needs a transform
88 * group to work on (use setTransformGroup(tg)) and
89 * the transform group must add this behavior.
90 * @param flags
91 */
92 public MouseTranslate(int flags) {
93 super(flags);
94 }
95
96 /**
97 * Creates a translate behavior that uses AWT listeners and behavior
98 * posts rather than WakeupOnAWTEvent. The behavior is added to the
99 * specified Component. A null component can be passed to specify
100 * the behavior should use listeners. Components can then be added
101 * to the behavior with the addListener(Component c) method.
102 * @param c The Component to add the MouseListener
103 * and MouseMotionListener to.
104 * @since Java 3D 1.2.1
105 */
106 public MouseTranslate(Component c) {
107 super(c, 0);
108 }
109
110 /**
111 * Creates a translate behavior that uses AWT listeners and behavior
112 * posts rather than WakeupOnAWTEvent. The behaviors is added to
113 * the specified Component and works on the given TransformGroup.
114 * A null component can be passed to specify the behavior should use
115 * listeners. Components can then be added to the behavior with the
116 * addListener(Component c) method.
117 * @param c The Component to add the MouseListener and
118 * MouseMotionListener to.
119 * @param transformGroup The TransformGroup to operate on.
120 * @since Java 3D 1.2.1
121 */
122 public MouseTranslate(Component c, TransformGroup transformGroup) {
123 super(c, transformGroup);
124 }
125
126 /**
127 * Creates a translate behavior that uses AWT listeners and behavior
128 * posts rather than WakeupOnAWTEvent. The behavior is added to the
129 * specified Component. A null component can be passed to specify
130 * the behavior should use listeners. Components can then be added to
131 * the behavior with the addListener(Component c) method.
132 * Note that this behavior still needs a transform
133 * group to work on (use setTransformGroup(tg)) and the transform
134 * group must add this behavior.
135 * @param flags interesting flags (wakeup conditions).
136 * @since Java 3D 1.2.1
137 */
138 public MouseTranslate(Component c, int flags) {
139 super(c, flags);
140 }
141
142 public void initialize() {
143 super.initialize();
144 if ((flags & INVERT_INPUT) == INVERT_INPUT) {
145 invert = true;
146 x_factor *= -1;
147 y_factor *= -1;
148 }
149 }
150
151 /**
152 * Return the x-axis movement multipler.
153 **/
154 public double getXFactor() {
155 return x_factor;
156 }
157
158 /**
159 * Return the y-axis movement multipler.
160 **/
161 public double getYFactor() {
162 return y_factor;
163 }
164
165 /**
166 * Set the x-axis amd y-axis movement multipler with factor.
167 **/
168 public void setFactor( double factor) {
169 x_factor = y_factor = factor;
170 }
171
172 /**
173 * Set the x-axis amd y-axis movement multipler with xFactor and yFactor
174 * respectively.
175 **/
176 public void setFactor( double xFactor, double yFactor) {
177 x_factor = xFactor;
178 y_factor = yFactor;
179 }
180
181 public void processStimulus (Enumeration criteria) {
182 WakeupCriterion wakeup;
183 AWTEvent[] events;
184 MouseEvent evt;
185 // int id;
186 // int dx, dy;
187
188 while (criteria.hasMoreElements()) {
189 wakeup = (WakeupCriterion) criteria.nextElement();
190
191 if (wakeup instanceof WakeupOnAWTEvent) {
192 events = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
193 if (events.length > 0) {
194 evt = (MouseEvent) events[events.length-1];
195 doProcess(evt);
196 }
197 }
198
199 else if (wakeup instanceof WakeupOnBehaviorPost) {
200 while (true) {
201 // access to the queue must be synchronized
202 synchronized (mouseq) {
203 if (mouseq.isEmpty()) break;
204 evt = (MouseEvent)mouseq.remove(0);
205 // consolodate MOUSE_DRAG events
206 while ((evt.getID() == MouseEvent.MOUSE_DRAGGED) &&
207 !mouseq.isEmpty() &&
208 (((MouseEvent)mouseq.get(0)).getID() ==
209 MouseEvent.MOUSE_DRAGGED)) {
210 evt = (MouseEvent)mouseq.remove(0);
211 }
212 }
213 doProcess(evt);
214 }
215 }
216
217 }
218 wakeupOn(mouseCriterion);
219 }
220
221 void doProcess(MouseEvent evt) {
222 int id;
223 int dx, dy;
224
225 processMouseEvent(evt);
226
227 if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) ||
228 ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))){
229 id = evt.getID();
230 if ((id == MouseEvent.MOUSE_DRAGGED) &&
231 !evt.isAltDown() && !evt.isMetaDown()) {
232
233 x = evt.getX();
234 y = evt.getY();
235
236 dx = x - x_last;
237 dy = y - y_last;
238
239 if ((!reset) && ((Math.abs(dy) < 50) && (Math.abs(dx) < 50))) {
240 //System.out.println("dx " + dx + " dy " + dy);
241 transformGroup.getTransform(currXform);
242
243
244 // System.err.println("currXform is \n"+currXform);
245 Transform3D origCurrentXform = new Transform3D(currXform);
246
247 Transform3D ltvw = new Transform3D();
248 transformGroup.getLocalToVworld(ltvw);
249 // System.err.println("ltvw is \n"+ltvw);
250 Matrix3d mat = new Matrix3d();
251 ltvw.getRotationScale(mat);
252 Transform3D rot = new Transform3D();
253 rot.set(mat);
254 // x_factor = y_factor = 1/ltvw.getScale();
255
256 // currXform.mulInverse(origCurrentXform);
257 // currXform.mul(rot);
258
259
260 // System.err.println("after mul. currXform is \n"+currXform);
261 // Transform3D scale = new Transform3D();
262 // scale.setScale(ltvw.getScale());
263 // scale.invert();
264 // rot.mul(scale);
265
266
267
268 translation.x = dx*x_factor;
269 translation.y = -dy*y_factor;
270
271
272 // Vector3d translationOut = new Vector3d();
273 // rot.transform(translation, translationOut);
274
275 transformX.set(translation);
276
277 if (invert) {
278 currXform.mul(currXform, transformX);
279 } else {
280 currXform.mul(transformX, currXform);
281 }
282
283 // currXform.mulInverse(rot);
284 // currXform.mul(origCurrentXform);
285 transformGroup.setTransform(currXform);
286
287 transformChanged( currXform );
288
289 if (callback!=null)
290 callback.transformChanged( MouseBehaviorCallback.TRANSLATE,
291 currXform );
292
293 }
294 else {
295 reset = false;
296 }
297 x_last = x;
298 y_last = y;
299 }
300 else if (id == MouseEvent.MOUSE_PRESSED) {
301 x_last = evt.getX();
302 y_last = evt.getY();
303 }
304 }
305 }
306
307 /**
308 * Users can overload this method which is called every time
309 * the Behavior updates the transform
310 *
311 * Default implementation does nothing
312 */
313 public void transformChanged( Transform3D transform ) {
314 }
315
316 /**
317 * The transformChanged method in the callback class will
318 * be called every time the transform is updated
319 */
320 public void setupCallback( MouseBehaviorCallback callback ) {
321 this.callback = callback;
322 }
323 }
324