package drawing3D; import java.awt.event.MouseEvent; import javax.swing.event.MouseInputListener; /** * A panel which draws 3D objects and allows the user to rotate the view of them * with the mouse. * * Use the field of this class called "viewer" to manipulate 3D objects. Upon * construction, an animation thread is started which redraws the 3D objects * frequently. * * @author Curran Kelleher * */ public class RotatableObject3DViewingPanel extends MinimalObject3DViewingPanel implements Runnable, MouseInputListener { private static final long serialVersionUID = 6264324613452387956L; /** * A boolean flag signaling whether or not the view should be animating. */ protected boolean animate = true; /** * When this is set to true, the animation thread is stopped permanently. */ public boolean stopThread = false; /** * The per-frame increment of the rotation angle about the X axis. */ protected double rotationIncrementX = 0; /** * The per-frame increment of the rotation angle about the Y axis. */ protected double rotationIncrementY = 0; /** * Temporary variable used when the mouse is being dragged to calculate what * the rotationIncrementX should be when the mouse is released. */ double tempRotationIncrementX = 0; /** * Temporary variable used when the mouse is being dragged to calculate what * the rotationIncrementY should be when the mouse is released. */ double tempRotationIncrementY = 0; /** * The angle of rotation in the "X" direction on the screen. */ protected double rotationStateX = 2.7; /** * The angle of rotation in the "Y" direction on the screen. */ protected double rotationStateY = 1; /** * Temporary variable used when the mouse is being dragged to calculate the * amount the mouse had moved since the last mouseMoved event. */ double oldMouseX = 0; /** * Temporary variable used when the mouse is being dragged to calculate the * amount the mouse had moved since the last mouseMoved event. */ double oldMouseY = 0; /** * The factor which converts pixels of mouse movement to angles of rotation. */ protected double mouseRotationFactor = 0.006; /** * Reset to System.currentTimeMillis() every time the mouse is dragged. If * the user has held the mouse still for a while (more than 400 ms) before * letting go, the the intention probably is to make it stay still after the * mouse is released, not set it spinning. This variable is used for * checking that. */ long lastTimeMouseWasDragged = 0; /** * Construct an empty RotatableObject3DViewingPanel. Use the field of this * class called "viewer" to manipulate 3D objects. Upon construction, an * animation thread is started which redraws the 3D objects frequently. * */ public RotatableObject3DViewingPanel() { super(); // add the mouse listener addMouseMotionListener(this); addMouseListener(this); (new Thread(this)).start(); } /** * Called to start the animation Thread. */ @SuppressWarnings("static-access") public void run() { while (!stopThread) { // only update the graph if the animate flag is true if (animate) { updateForEachFrame(); } try { Thread.currentThread().sleep(!animate ? 200 : 20); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * Called every frame. * */ protected void updateForEachFrame() { // update the rotation rotationStateX += rotationIncrementX; if (rotationStateX < 0) rotationStateX += 2 * Math.PI; else if (rotationStateX > 2 * Math.PI) rotationStateX -= 2 * Math.PI; rotationStateY += rotationIncrementY; if (rotationStateY < 0) rotationStateY += 2 * Math.PI; else if (rotationStateY > 2 * Math.PI) rotationStateY -= 2 * Math.PI; // set the rotation viewer.window.setRotation(rotationStateY, 0, rotationStateX); // draw the objects drawObjectsOnBufferImage(); // draw the buffered image to the screen repaint(); } public void mouseDragged(MouseEvent e) { rotationStateX += (tempRotationIncrementX = (oldMouseX - e.getX()) * mouseRotationFactor * ((rotationStateY < Math.PI) ? -1 : 1)); rotationStateY += (tempRotationIncrementY = (oldMouseY - e.getY()) * mouseRotationFactor); oldMouseX = e.getX(); oldMouseY = e.getY(); lastTimeMouseWasDragged = System.currentTimeMillis(); } public void mouseMoved(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { rotationIncrementX = rotationIncrementY = tempRotationIncrementX = tempRotationIncrementY = 0; oldMouseX = e.getX(); oldMouseY = e.getY(); } public void mouseReleased(MouseEvent e) { // if the user has held the mouse still for a while (more than 400 ms) // before letting go, the the intention probably is to make it stay // still after the mouse is released, not set it spinning if (System.currentTimeMillis() - lastTimeMouseWasDragged > 400) setRotationIncrementValues(0, 0); else setRotationIncrementValues(tempRotationIncrementX, tempRotationIncrementY); } /** * Sets the rotation increment values. This method is called when the mouse * is released. It sets the current rotation increment parameters to the * specified values. * * @param rotationIncrementX * the new rotation increment value for the "X" direction * @param rotationIncrementY * the new rotation increment value for the "Y" direction */ protected void setRotationIncrementValues(double rotationIncrementX, double rotationIncrementY) { this.rotationIncrementX = rotationIncrementX; this.rotationIncrementY = rotationIncrementY; } }