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 }