Package artofillusion

Source Code of artofillusion.MoveScaleRotateObjectTool

/* Copyright (C) 2006-2009 by Peter Eastman

   This program is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
   Foundation; either version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but WITHOUT ANY
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
   PARTICULAR PURPOSE.  See the GNU General Public License for more details. */

package artofillusion;

import artofillusion.ui.*;
import artofillusion.ui.Compound3DManipulator.*;
import artofillusion.math.*;
import artofillusion.object.*;

import java.awt.event.*;
import java.awt.*;
import java.util.*;

import buoy.event.*;
import buoy.widget.*;

/**
* This editing tool presents a compound interface for moving, scaling, and rotating objects.
*/

public class MoveScaleRotateObjectTool extends EditingTool
{
  private boolean dragInProgress, draggingObjects;
  private ArrayList<ObjectInfo> objects;
  private CoordinateSystem originalCoords[];
  private Object3D originalObjects[];
  private ObjectInfo clickedObject;
  private Point clickPoint;
  private Vec3 rotationCenter[];
  private UndoRecord undo;
  private final Compound3DManipulator manipulator;
  private boolean tooltipsEnabled, tooltipsAdded, applyToChildren = true;
  private int scaleAround = POSITIONS_FIXED, rotateAround = PARENT_CENTER;

  private static BToolTip ROTATE_TIP = new BToolTip(Translate.text("moveScaleRotateObjectTool.rotateTipText"));
  private static BToolTip MOVE_TIP = new BToolTip(Translate.text("moveScaleRotateObjectTool.moveTipText"));
  private static BToolTip SCALE_TIP = new BToolTip(Translate.text("moveScaleRotateObjectTool.scaleTipText"));

  private static final int POSITIONS_FIXED = 0;
  private static final int POSITIONS_SCALE = 1;

  private static final int OBJECT_CENTER = 0;
  private static final int PARENT_CENTER = 1;
  private static final int SELECTION_CENTER = 2;

  public MoveScaleRotateObjectTool(LayoutWindow fr)
  {
    super(fr);
    initButton("moveScaleRotate");
    manipulator = new Compound3DManipulator();
    manipulator.addEventLink(HandlePressedEvent.class, this, "handlePressed");
    manipulator.addEventLink(HandleDraggedEvent.class, this, "handleDragged");
    manipulator.addEventLink(HandleReleasedEvent.class, this, "handleReleased");
  }

  public int whichClicks()
  {
    return OBJECT_CLICKS+ALL_CLICKS;
  }

  public boolean allowSelectionChanges()
  {
    return !dragInProgress;
  }

  public String getToolTipText()
  {
    return Translate.text("moveScaleRotateObjectTool.tipText");
  }

  /** Get the LayoutWindow to which this tool belongs. */

  public LayoutWindow getWindow()
  {
    return (LayoutWindow) theWindow;
  }

  public void drawOverlay(ViewerCanvas view)
  {
    BoundingBox selectionBounds = findSelectionBounds(view.getCamera());
    if (!dragInProgress && manipulator.getViewMode() == Compound3DManipulator.NPQ_MODE && selectionBounds != null)
    {
      // Calculate the axis directions.

      ObjectInfo firstObj = getWindow().getSelectedObjects().iterator().next();
      CoordinateSystem coords = firstObj.getCoords();
      manipulator.setNPQAxes(coords.getUpDirection().cross(coords.getZDirection()), coords.getUpDirection(), coords.getZDirection());
    }
    manipulator.draw(view, selectionBounds);
    if (!dragInProgress)
    {
      if (selectionBounds != null)
        theWindow.setHelpText(Translate.text("moveScaleRotateObjectTool.helpText"));
      else
        theWindow.setHelpText(Translate.text("moveScaleRotateObjectTool.errorText"));
    }
  }

  public void mousePressed(WidgetMouseEvent e, ViewerCanvas view)
  {
    BoundingBox selectionBounds = findSelectionBounds(view.getCamera());
    dragInProgress = false;
    draggingObjects = false;
    if (selectionBounds != null)
      dragInProgress = manipulator.mousePressed(e, view, selectionBounds);
  }

  public void mousePressedOnObject(WidgetMouseEvent e, ViewerCanvas view, int obj)
  {
    draggingObjects = true;
    BoundingBox selectionBounds = findSelectionBounds(view.getCamera());
    Rectangle screenBounds = manipulator.findScreenBounds(selectionBounds, view.getCamera());
    handlePressed(manipulator.new HandlePressedEvent(view, Compound3DManipulator.MOVE, Compound3DManipulator.ALL, screenBounds, selectionBounds, e));
    clickedObject = view.getScene().getObject(obj);
    clickPoint = e.getPoint();
  }

  public void mouseDragged(WidgetMouseEvent e, ViewerCanvas view)
  {
    if (draggingObjects)
    {
      BoundingBox selectionBounds = findSelectionBounds(view.getCamera());
      Rectangle screenBounds = manipulator.findScreenBounds(selectionBounds, view.getCamera());
      Point dragPoint = e.getPoint();
      int dx = dragPoint.x - clickPoint.x;
      int dy = dragPoint.y - clickPoint.y;
      if (e.isShiftDown() && !e.isControlDown())
        {
          if (Math.abs(dx) > Math.abs(dy))
            dy = 0;
          else
            dx = 0;
        }
      Vec3 v;
      if (e.isControlDown())
        v = view.getCamera().getCameraCoordinates().getZDirection().times(-dy*0.01);
      else
        v = view.getCamera().findDragVector(clickedObject.getCoords().getOrigin(), dx, dy);
      handleDragged(manipulator.new HandleDraggedEvent(view, Compound3DManipulator.MOVE, Compound3DManipulator.ALL, screenBounds, selectionBounds, e, Mat4.translation(v.x, v.y, v.z)));
    }
    else
      manipulator.mouseDragged(e, view);
  }

  public void mouseReleased(WidgetMouseEvent e, ViewerCanvas view)
  {
    if (draggingObjects)
      handleReleased(null);
    else
      manipulator.mouseReleased(e, view);
  }

  protected void handlePressed(HandlePressedEvent ev)
  {
    objects = new ArrayList<ObjectInfo>();
    int sel[];
    if (applyToChildren)
      sel = getWindow().getSelectionWithChildren();
    else
      sel = getWindow().getSelectedIndices();
    for (int i = 0; i < sel.length; i++)
      objects.add(theWindow.getScene().getObject(sel[i]));
    originalCoords = new CoordinateSystem[objects.size()];
    for (int i = 0; i < originalCoords.length; i++)
      originalCoords[i] = objects.get(i).getCoords();
    if (ev.getHandleType() == Compound3DManipulator.SCALE)
    {
      originalObjects = new Object3D[objects.size()];
      for (int i = 0; i < originalObjects.length; i++)
        originalObjects[i] = objects.get(i).getObject();
    }
    if (ev.getHandleType() == Compound3DManipulator.ROTATE)
    {
      manipulator.setRotateAroundSelectionCenter(rotateAround == SELECTION_CENTER);
      rotationCenter = new Vec3[objects.size()];
      for (int i = 0; i < rotationCenter.length; i++)
        {
          ObjectInfo parent = objects.get(i);
          if (rotateAround == SELECTION_CENTER)
              rotationCenter[i] = new Vec3();
          else
            rotationCenter[i] = originalCoords[i].getOrigin();
          if (rotateAround == PARENT_CENTER)
            while (parent.getParent() != null)
              {
                parent = parent.getParent();
                if (parent.selected)
                  rotationCenter[i] = parent.getCoords().getOrigin();
              }
        }
    }
  }

  protected void handleDragged(HandleDraggedEvent ev)
  {
    if (undo == null)
    {
      undo = new UndoRecord(theWindow, false);
      for (int i = 0; i < originalCoords.length; i++)
      {
        originalCoords[i] = originalCoords[i].duplicate();
        undo.addCommand(UndoRecord.COPY_COORDS, new Object[] {objects.get(i).getCoords(), originalCoords[i]});
        if (ev.getHandleType() == Compound3DManipulator.SCALE)
        {
          originalObjects[i] = originalObjects[i].duplicate();
          undo.addCommand(UndoRecord.COPY_OBJECT, new Object[] {objects.get(i).getObject(), originalObjects[i]});
        }
      }
    }
    transformObjects(ev);
    theWindow.updateImage();
    if (ev.getHandleType() == Compound3DManipulator.MOVE)
    {
      Vec3 drag = ev.getTransform().times(new Vec3());
      theWindow.setHelpText(Translate.text("reshapeMeshTool.dragText",
          Math.round(drag.x*1e5)/1e5+", "+Math.round(drag.y*1e5)/1e5+", "+Math.round(drag.z*1e5)/1e5));
    }
    else if (ev.getHandleType() == Compound3DManipulator.ROTATE)
      theWindow.setHelpText(Translate.text("rotateMeshTool.dragText", Double.toString(Math.round(ev.getRotationAngle()*1e5*180.0/Math.PI)/1e5)));
    else if (ev.getAxis() == Compound3DManipulator.UV && !ev.getMouseEvent().isShiftDown())
      theWindow.setHelpText(Translate.text("scaleMeshTool.dragText", Math.round(ev.getPrimaryScale()*1e5)/1e5+", "+Math.round(ev.getSecondaryScale()*1e5)/1e5));
    else
      theWindow.setHelpText(Translate.text("scaleMeshTool.dragText", Double.toString(Math.round(ev.getPrimaryScale()*1e5)/1e5)));
  }

  protected void handleReleased(HandleReleasedEvent ev)
  {
    if (undo != null)
      theWindow.setUndoRecord(undo);
    theWindow.updateImage();
    undo = null;
    rotationCenter = null;
    dragInProgress = false;
  }

  /**
   * Apply a transformation to the objects.
   */

  private void transformObjects(HandleDraggedEvent ev)
  {
    for (int i = 0; i < objects.size(); i++)
    {
      Mat4 transform = ev.getTransform();
      if (ev.getHandleType() == Compound3DManipulator.SCALE)
      {
        if (scaleAround == POSITIONS_SCALE)
        {
          // Scale the positions.

          CoordinateSystem coords = originalCoords[i].duplicate();
          coords.transformOrigin(transform);
          objects.get(i).getCoords().copyCoords(coords);
        }

        // Work out the scale factors for the size.

        double xscale = 1.0, yscale = 1.0, zscale = 1.0;
        Vec3 xdir = originalCoords[i].fromLocal().timesDirection(transform.timesDirection(new Vec3(1.0, 0.0, 0.0)));
        Vec3 ydir = originalCoords[i].fromLocal().timesDirection(transform.timesDirection(new Vec3(0.0, 1.0, 0.0)));
        Vec3 zdir = originalCoords[i].fromLocal().timesDirection(transform.timesDirection(new Vec3(0.0, 0.0, 1.0)));
        xdir.normalize();
        ydir.normalize();
        zdir.normalize();
        if (ev.getMouseEvent().isShiftDown())
        {
          xscale = yscale = zscale = ev.getPrimaryScale();
        }
        else if (ev.getAxis() == Compound3DManipulator.UV)
        {
          Vec3 uDir = manipulator.getAxisDirection(Compound3DManipulator.U, ev.getView());
          Vec3 vDir = manipulator.getAxisDirection(Compound3DManipulator.V, ev.getView());
          double xudot = Math.abs(xdir.dot(uDir));
          double yudot = Math.abs(ydir.dot(uDir));
          double zudot = Math.abs(zdir.dot(uDir));
          double xvdot = Math.abs(xdir.dot(vDir));
          double yvdot = Math.abs(ydir.dot(vDir));
          double zvdot = Math.abs(zdir.dot(vDir));
          if (xudot >= yudot && xudot >= zudot)
          {
            xscale = ev.getPrimaryScale();
            if (yvdot >= zvdot)
              yscale = ev.getSecondaryScale();
            else
              zscale = ev.getSecondaryScale();
          }
          else if (yudot >= xudot && yudot >= zudot)
          {
            yscale = ev.getPrimaryScale();
            if (xvdot >= zvdot)
              xscale = ev.getSecondaryScale();
            else
              zscale = ev.getSecondaryScale();
          }
          else
          {
            zscale = ev.getPrimaryScale();
            if (xvdot >= yvdot)
              xscale = ev.getSecondaryScale();
            else
              yscale = ev.getSecondaryScale();
          }
        }
        else
        {
          Vec3 scaleDir = manipulator.getAxisDirection(ev.getAxis(), ev.getView());
          double xdot = Math.abs(xdir.dot(scaleDir));
          double ydot = Math.abs(ydir.dot(scaleDir));
          double zdot = Math.abs(zdir.dot(scaleDir));
          if (xdot >= ydot && xdot >= zdot)
            xscale = ev.getPrimaryScale();
          else if (ydot >= xdot && ydot >= zdot)
            yscale = ev.getPrimaryScale();
          else
            zscale = ev.getPrimaryScale();
        }
        Vec3 size = originalObjects[i].getBounds().getSize();
        size.x *= xscale;
        size.y *= yscale;
        size.z *= zscale;
        objects.get(i).getObject().setSize(size.x, size.y, size.z);
        getWindow().getScene().objectModified(objects.get(i).getObject());
      }
      else
      {
        if (ev.getHandleType() == Compound3DManipulator.ROTATE)
        {
          Vec3 center = rotationCenter[i];
          transform = Mat4.translation(center.x, center.y, center.z).times(transform.times(Mat4.translation(-center.x, -center.y, -center.z)));
        }
        CoordinateSystem coords = originalCoords[i].duplicate();
        coords.transformCoordinates(transform);
        objects.get(i).getCoords().copyCoords(coords);
      }
    }
  }

  public void keyPressed(KeyPressedEvent e, ViewerCanvas view)
  {
    if (e.getKeyCode() == KeyEvent.VK_W && e.getModifiersEx() == 0)
    {
      // Change the axis mode.

      ViewMode mode = manipulator.getViewMode();
      if (mode == Compound3DManipulator.XYZ_MODE)
        manipulator.setViewMode(Compound3DManipulator.UV_MODE);
      else if (mode == Compound3DManipulator.UV_MODE)
        manipulator.setViewMode(Compound3DManipulator.NPQ_MODE);
      else
        manipulator.setViewMode(Compound3DManipulator.XYZ_MODE);
      theWindow.updateImage();
      return;
    }
    if (e.getKeyCode() == KeyEvent.VK_F1)
    {
      // Enable tooltips.

      tooltipsEnabled = !tooltipsEnabled;
      if (tooltipsEnabled && !tooltipsAdded)
      {
        ViewerCanvas allViews[] = ((MeshEditorWindow) theWindow).getAllViews();
        for (int i = 0; i < allViews.length; i++)
          allViews[i].addEventLink(ToolTipEvent.class, this, "showToolTip");
        tooltipsAdded = true;
      }
      if (!tooltipsEnabled)
        BToolTip.hide();
      return;
    }

    // Handle arrow keys.  This is equivalent to dragging the first selected object by one pixel.

    double dx, dy;
    int key = e.getKeyCode();
    if (key == KeyPressedEvent.VK_UP)
    {
      dx = 0;
      dy = -1;
    }
    else if (key == KeyPressedEvent.VK_DOWN)
    {
      dx = 0;
      dy = 1;
    }
    else if (key == KeyPressedEvent.VK_LEFT)
    {
      dx = -1;
      dy = 0;
    }
    else if (key == KeyPressedEvent.VK_RIGHT)
    {
      dx = 1;
      dy = 0;
    }
    else
      return;
    e.consume();
    int sel[];
    if (applyToChildren)
      sel = getWindow().getSelectionWithChildren();
    else
      sel = getWindow().getSelectedIndices();
    if (sel.length == 0)
      return// No objects are selected.
    if (view.getSnapToGrid())
    {
      double scale = view.getGridSpacing()*view.getScale();
      if (!e.isAltDown())
        scale /= view.getSnapToSubdivisions();
      dx *= scale;
      dy *= scale;
    }
    else if (e.isAltDown())
    {
      dx *= 10;
      dy *= 10;
    }
    Camera cam = view.getCamera();
    CoordinateSystem cameraCoords = cam.getCameraCoordinates();
    Scene theScene = theWindow.getScene();
    Vec3 v;
    if (e.isControlDown())
      v = cameraCoords.getZDirection().times(-dy*0.01);
    else
    {
      Vec3 origin = theScene.getObject(sel[0]).getCoords().getOrigin();
      if (Math.abs(origin.minus(cameraCoords.getOrigin()).dot(cameraCoords.getZDirection())) < 1e-10)
      {
        // The object being moved is in the plane of the camera, so use a slightly
        // different point to avoid dividing by zero.

        origin = origin.plus(cameraCoords.getZDirection().times(cam.getClipDistance()));
      }
      v = cam.findDragVector(origin, dx, dy);
    }
    theWindow.setUndoRecord(undo = new UndoRecord(getWindow(), false));
    ArrayList<ObjectInfo> toMove = new ArrayList<ObjectInfo>();
    for (int i = 0; i < sel.length; i++)
      toMove.add(theScene.getObject(sel[i]));
    for (int i = 0; i < toMove.size(); i++)
    {
      CoordinateSystem c = toMove.get(i).getCoords();
      undo.addCommand(UndoRecord.COPY_COORDS, new Object [] {c, c.duplicate()});
      c.setOrigin(c.getOrigin().plus(v));
    }
    theWindow.getScene().applyTracksAfterModification(toMove);
    theWindow.updateImage();
    undo = null;
  }

  private void showToolTip(ToolTipEvent ev)
  {
    if (!tooltipsEnabled)
      return;
    ViewerCanvas view = (ViewerCanvas) ev.getWidget();
    HandleType type = manipulator.getHandleTypeAtLocation(ev.getPoint(), view, findSelectionBounds(view.getCamera()));
    if (type == Compound3DManipulator.MOVE)
      MOVE_TIP.processEvent(ev);
    else if (type == Compound3DManipulator.ROTATE)
      ROTATE_TIP.processEvent(ev);
    else if (type == Compound3DManipulator.SCALE)
      SCALE_TIP.processEvent(ev);
    else
      BToolTip.hide();
  }

  /**
   * This method returns a bounding box for the selected objects in view coordinates,
   * or null if nothing is selected.
   */

  protected BoundingBox findSelectionBounds(Camera cam)
  {
    boolean anything = false;
    BoundingBox bounds = null;
    for (ObjectInfo info : getWindow().getSelectedObjects())
    {
      BoundingBox objBounds = info.getBounds().transformAndOutset(info.getCoords().fromLocal());
      if (!anything)
        bounds = objBounds;
      else
        bounds = bounds.merge(objBounds);
      anything = true;
    }
    return (bounds == null ? null : bounds.transformAndOutset(cam.getWorldToView()));
  }

  public void iconDoubleClicked()
  {
    BCheckBox childrenBox = new BCheckBox(Translate.text("applyToUnselectedChildren"), applyToChildren);
    BComboBox centerChoice = new BComboBox(new String [] {
      Translate.text("individualObjectCenters"),
      Translate.text("parentObject"),
      Translate.text("centerOfSelection")
    });
    centerChoice.setSelectedIndex(rotateAround);
    RowContainer rotateRow = new RowContainer();
    rotateRow.add(Translate.label("rotateAround"));
    rotateRow.add(centerChoice);
    BComboBox scaleChoice = new BComboBox(new String [] {
      Translate.text("remainFixed"),
      Translate.text("scaleWithObjects")
    });
    scaleChoice.setSelectedIndex(scaleAround);
    RowContainer scaleRow = new RowContainer();
    scaleRow.add(Translate.label("objectPositions"));
    scaleRow.add(scaleChoice);
    ComponentsDialog dlg = new ComponentsDialog(theFrame, Translate.text("moveRotateResizeToolTitle"),
                new Widget [] {childrenBox, rotateRow, scaleRow}, new String [] {null, null, null});
    if (!dlg.clickedOk())
      return;
    applyToChildren = childrenBox.getState();
    rotateAround = centerChoice.getSelectedIndex();
    scaleAround = scaleChoice.getSelectedIndex();
  }
}
TOP

Related Classes of artofillusion.MoveScaleRotateObjectTool

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.