View Javadoc

    1   /*
    2    * $RCSfile: ZoomMouseBehavior.java,v $ A modification of MouseZoom.java *
    3    *
    4    * Copyright (c) 2004 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 are met: -
    8    * Redistribution of source code must retain the above copyright notice, this
    9    * list of conditions and the following disclaimer. - Redistribution in binary
    10   * form must reproduce the above copyright notice, this list of conditions and
    11   * the following disclaimer in the documentation and/or other materials provided
    12   * with the distribution.
    13   *
    14   * Neither the name of Sun Microsystems, Inc. or the names of contributors may
    15   * be used to endorse or promote products derived from this software without
    16   * specific prior written permission.
    17   *
    18   * This software is provided "AS IS," without a warranty of any kind. ALL
    19   * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
    20   * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
    21   * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS
    22   * LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A
    23   * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
    24   * IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT
    25   * OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
    26   * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
    27   * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS
    28   * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
    29   *
    30   * You acknowledge that this software is not designed, licensed or intended for
    31   * use in the design, construction, operation or maintenance of any nuclear
    32   * facility.
    33   *
    34   * $Revision: 1.5 $ $Date: 2004/12/16 13:18:56 $ $State: Exp $
    35   */
    36  /*
    37   * Modified to zoom along the rotated z-axis (actually move). Copyright (c)
    38   * 2002-2005 Delft University of Technology Jaffalaan 5, 2628 BX Delft, the
    39   * Netherlands All rights reserved.
    40   */
    41  package nl.tudelft.simulation.dsol.gui.animation3D.mouse;
    42
    43  import java.awt.AWTEvent;
    44  import java.awt.Component;
    45  import java.awt.event.MouseEvent;
    46  import java.util.Enumeration;
    47
    48  import javax.media.j3d.Transform3D;
    49  import javax.media.j3d.TransformGroup;
    50  import javax.media.j3d.WakeupCriterion;
    51  import javax.media.j3d.WakeupOnAWTEvent;
    52  import javax.media.j3d.WakeupOnBehaviorPost;
    53  import javax.vecmath.Vector3d;
    54
    55  import com.sun.j3d.utils.behaviors.mouse.MouseBehavior;
    56  import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback;
    57
    58  /***
    59   * ZoomMouseBehavior is a Java3D behavior object that lets users control the Z
    60   * axis translation of an object via a mouse drag motion with the second mouse
    61   * button. See MouseRotate for similar usage info. Based on
    62   * com.sun.j3d.utils.behaviors.mouse.MouseZoom.
    63   */
    64  public class ZoomMouseBehavior extends MouseBehavior
    65  {
    66  	/*** zoom factor */
    67  	private double zFactor = .04;
    68
    69  	/*** translation */
    70  	private Vector3d translation = new Vector3d();
    71
    72  	/*** callback */
    73  	private MouseBehaviorCallback callback = null;
    74
    75  	/*** rotation group around x-axis */
    76  	private TransformGroup rotateXGroup = null;
    77
    78  	/*** rotation group around y-axis */
    79  	private TransformGroup rotateYGroup = null;
    80
    81  	/*** rotation around x-axis */
    82  	private Transform3D rotateX = new Transform3D();
    83
    84  	/*** rotation around y-axis */
    85  	private Transform3D rotateY = new Transform3D();
    86
    87
    88  	/***
    89  	 * Creates a zoom behavior given the transform group.
    90  	 *
    91  	 * @param transformGroup The transformGroup to operate on.
    92  	 */
    93  	public ZoomMouseBehavior(final TransformGroup transformGroup)
    94  	{
    95  		super(transformGroup);
    96  	}
    97
    98  	/***
    99  	 * Creates a default mouse zoom behavior.
    100 	 */
    101 	public ZoomMouseBehavior()
    102 	{
    103 		super(0);
    104 	}
    105
    106 	/***
    107 	 * Creates a zoom behavior. Note that this behavior still needs a transform
    108 	 * group to work on (use setTransformGroup(tg)) and the transform group must
    109 	 * add this behavior.
    110 	 *
    111 	 * @param flags flags
    112 	 */
    113 	public ZoomMouseBehavior(final int flags)
    114 	{
    115 		super(flags);
    116 	}
    117
    118 	/***
    119 	 * Creates a zoom behavior that uses AWT listeners and behavior posts rather
    120 	 * than WakeupOnAWTEvent. The behavior is added to the specified Component.
    121 	 * A null component can be passed to specify the behavior should use
    122 	 * listeners. Components can then be added to the behavior with the
    123 	 * addListener(Component c) method.
    124 	 *
    125 	 * @param c The Component to add the MouseListener and MouseMotionListener
    126 	 *        to.
    127 	 * @since Java 3D 1.2.1
    128 	 */
    129 	public ZoomMouseBehavior(final Component c)
    130 	{
    131 		super(c, 0);
    132 	}
    133
    134 	/***
    135 	 * Creates a zoom behavior that uses AWT listeners and behavior posts rather
    136 	 * than WakeupOnAWTEvent. The behaviors is added to the specified Component
    137 	 * and works on the given TransformGroup.
    138 	 *
    139 	 * @param c The Component to add the MouseListener and MouseMotionListener
    140 	 *        to. A null component can be passed to specify the behavior should
    141 	 *        use listeners. Components can then be added to the behavior with
    142 	 *        the addListener(Component c) method.
    143 	 * @param transformGroup The TransformGroup to operate on.
    144 	 * @since Java 3D 1.2.1
    145 	 */
    146 	public ZoomMouseBehavior(final Component c,
    147 			final TransformGroup transformGroup)
    148 	{
    149 		super(c, transformGroup);
    150 	}
    151
    152 	/***
    153 	 * Creates a zoom behavior that uses AWT listeners and behavior posts rather
    154 	 * than WakeupOnAWTEvent. The behavior is added to the specified Component.
    155 	 * A null component can be passed to specify the behavior should use
    156 	 * listeners. Components can then be added to the behavior with the
    157 	 * addListener(Component c) method. Note that this behavior still needs a
    158 	 * transform group to work on (use setTransformGroup(tg)) and the transform
    159 	 * group must add this behavior.
    160 	 *
    161 	 * @param c The Component to add the MouseListener and MouseMotionListener
    162 	 *        to. A null component can be passed to specify the behavior should
    163 	 *        use listeners. Components can then be added to the behavior with
    164 	 *        the addListener(Component c) method.
    165 	 * @param flags interesting flags (wakeup conditions).
    166 	 * @since Java 3D 1.2.1
    167 	 */
    168 	public ZoomMouseBehavior(final Component c, final int flags)
    169 	{
    170 		super(c, flags);
    171 	}
    172
    173 	/***
    174 	 * @see javax.media.j3d.Behavior#initialize()
    175 	 */
    176 	public void initialize()
    177 	{
    178 		super.initialize();
    179 		if ((this.flags & INVERT_INPUT) == INVERT_INPUT)
    180 		{
    181 			this.zFactor *= -1;
    182 			this.invert = true;
    183 		}
    184 	}
    185
    186 	/***
    187 	 * @return the y-axis movement multipler.
    188 	 */
    189 	public double getFactor()
    190 	{
    191 		return this.zFactor;
    192 	}
    193
    194 	/***
    195 	 * Set the y-axis movement multipler with factor.
    196 	 *
    197 	 * @param factor the zoom factor
    198 	 */
    199 	public void setFactor(final double factor)
    200 	{
    201 		this.zFactor = factor;
    202 	}
    203
    204 	/***
    205 	 * Set the rotation around the x-axis.
    206 	 *
    207 	 * @param rotateXGroup rotation around x-axis.
    208 	 */
    209 	public void setRotateXGroup(final TransformGroup rotateXGroup)
    210 	{
    211 		this.rotateXGroup = rotateXGroup;
    212 	}
    213
    214 	/***
    215 	 * Set the rotation around the y-axis.
    216 	 *
    217 	 * @param rotateYGroup rotation around y-axis.
    218 	 */
    219 	public void setRotateYGroup(final TransformGroup rotateYGroup)
    220 	{
    221 		this.rotateYGroup = rotateYGroup;
    222 	}
    223
    224 	/***
    225 	 * @see javax.media.j3d.Behavior#processStimulus(java.util.Enumeration)
    226 	 */
    227 	public void processStimulus(final Enumeration criteria)
    228 	{
    229 		WakeupCriterion wakeup;
    230 		AWTEvent[] events;
    231 		MouseEvent evt;
    232 		// int id;
    233 		// int dx, dy;
    234
    235 		while (criteria.hasMoreElements())
    236 		{
    237 			wakeup = (WakeupCriterion) criteria.nextElement();
    238 			if (wakeup instanceof WakeupOnAWTEvent)
    239 			{
    240 				events = ((WakeupOnAWTEvent) wakeup).getAWTEvent();
    241 				if (events.length > 0)
    242 				{
    243 					evt = (MouseEvent) events[events.length - 1];
    244 					doProcess(evt);
    245 				}
    246 			} else if (wakeup instanceof WakeupOnBehaviorPost)
    247 			{
    248 				while (true)
    249 				{
    250 					synchronized (this.mouseq)
    251 					{
    252 						if (this.mouseq.isEmpty())
    253 						{
    254 							break;
    255 						}
    256 						evt = (MouseEvent) this.mouseq.remove(0);
    257 						// consolodate MOUSE_DRAG events
    258 						while ((evt.getID() == MouseEvent.MOUSE_DRAGGED)
    259 								&& !this.mouseq.isEmpty()
    260 								&& (((MouseEvent) this.mouseq.get(0)).getID() == MouseEvent.MOUSE_DRAGGED))
    261 						{
    262 							evt = (MouseEvent) this.mouseq.remove(0);
    263 						}
    264 					}
    265 					doProcess(evt);
    266 				}
    267 			}
    268
    269 		}
    270 		wakeupOn(this.mouseCriterion);
    271 	}
    272
    273 	/***
    274 	 * @param evt mouse event
    275 	 */
    276 	void doProcess(final MouseEvent evt)
    277 	{
    278 		int id;
    279 		int dy;
    280
    281 		processMouseEvent(evt);
    282
    283 		if (((this.buttonPress) && ((this.flags & MANUAL_WAKEUP) == 0))
    284 				|| ((this.wakeUp) && ((this.flags & MANUAL_WAKEUP) != 0)))
    285 		{
    286 			id = evt.getID();
    287 			if ((id == MouseEvent.MOUSE_DRAGGED) && evt.isAltDown()
    288 					&& !evt.isMetaDown())
    289 			{
    290
    291 				this.y = evt.getY();
    292
    293 				dy = this.y - this.y_last;
    294
    295 				if ((!this.reset) && ((Math.abs(dy) < 50)))
    296 				{
    297 					this.transformGroup.getTransform(this.currXform);
    298
    299 					this.translation.x = 0;
    300 					this.translation.y = 0;
    301 					this.translation.z = -dy * this.zFactor;
    302
    303 					this.transformX.setZero();
    304
    305 					// Now do some rotations around the x- and y-axis if these
    306 					// are available.
    307 					if ((this.rotateYGroup != null)
    308 							&& (this.rotateXGroup != null))
    309 					{
    310 						this.rotateYGroup.getTransform(this.rotateY);
    311 						this.rotateXGroup.getTransform(this.rotateX);
    312 						this.transformX.set(this.rotateY);
    313 						this.transformX.mul(this.rotateX);
    314
    315 						// transform the translation
    316 						this.transformX.transform(this.translation);
    317 					}
    318 					this.transformX.set(this.translation);
    319
    320 					if (this.invert)
    321 					{
    322 						this.currXform.mul(this.currXform, this.transformX);
    323 					} else
    324 					{
    325 						this.currXform.mul(this.transformX, this.currXform);
    326 					}
    327
    328 					this.transformGroup.setTransform(this.currXform);
    329
    330 					this.transformChanged(this.currXform);
    331
    332 					if (this.callback != null)
    333 					{
    334 						this.callback.transformChanged(
    335 								MouseBehaviorCallback.ZOOM, this.currXform);
    336 					}
    337
    338 				} else
    339 				{
    340 					this.reset = false;
    341 				}
    342
    343 				this.x_last = this.x;
    344 				this.y_last = this.y;
    345 			} else if (id == MouseEvent.MOUSE_PRESSED)
    346 			{
    347 				this.x_last = evt.getX();
    348 				this.y_last = evt.getY();
    349 			}
    350 		}
    351 	}
    352
    353 	/***
    354 	 * Users can overload this method which is called every time the Behavior
    355 	 * updates the transform
    356 	 *
    357 	 * Default implementation does nothing
    358 	 *
    359 	 * @param transform transform
    360 	 */
    361 	public void transformChanged(final Transform3D transform)
    362 	{
    363 		// nothing
    364 	}
    365
    366 	/***
    367 	 * The transformChanged method in the callback class will be called every
    368 	 * time the transform is updated
    369 	 *
    370 	 * @param callback callback
    371 	 */
    372 	public void setupCallback(final MouseBehaviorCallback callback)
    373 	{
    374 		this.callback = callback;
    375 	}
    376 }