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 }