Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "skeletonsubtools.h"
Toshihiro Shimizu 890ddd
#include "skeletontool.h"
Toshihiro Shimizu 890ddd
#include "tools/toolhandle.h"
Toshihiro Shimizu 890ddd
#include "tools/toolutils.h"
Toshihiro Shimizu 890ddd
#include "toonz/tscenehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tobjecthandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tframehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcolumnhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txsheethandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshlevelhandle.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/toonzscene.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshsimplelevel.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobjecttree.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobjectcmd.h"
Toshihiro Shimizu 890ddd
#include "toonz/tpinnedrangeset.h"
Toshihiro Shimizu 890ddd
#include "toonz/stage.h"
Toshihiro Shimizu 890ddd
#include "toonz/hook.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshcell.h"
Toshihiro Shimizu 890ddd
#include "toonz/skeleton.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/stageobjectutil.h"
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
#include "tconvert.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <tsystem.h></tsystem.h>
Toshihiro Shimizu 890ddd
#include <math.h></math.h>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace SkeletonSubtools;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// DragCenterTool
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
DragCenterTool::DragCenterTool(SkeletonTool *tool)
Shinya Kitaoka 120a6e
    : DragTool(tool)
Shinya Kitaoka 120a6e
    , m_objId(TTool::getApplication()->getCurrentObject()->getObjectId())
Shinya Kitaoka 120a6e
    , m_frame(TTool::getApplication()->getCurrentFrame()->getFrame()) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DragCenterTool::leftButtonDown(const TPointD &pos, const TMouseEvent &) {
Shinya Kitaoka 120a6e
  TXsheet *xsh = TTool::getApplication()->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
  m_center = m_oldCenter = xsh->getCenter(m_objId, m_frame);
Shinya Kitaoka 120a6e
  m_firstPos             = pos;
Shinya Kitaoka 120a6e
  m_affine               = xsh->getPlacement(m_objId, m_frame).inv() *
Shinya Kitaoka 120a6e
             xsh->getParentPlacement(m_objId, m_frame);
Shinya Kitaoka 120a6e
  m_affine.a13 = m_affine.a23 = 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DragCenterTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &) {
Shinya Kitaoka 120a6e
  double factor = 1.0 / Stage::inch;
Shinya Kitaoka 120a6e
  m_center      = m_oldCenter + (m_affine * (pos - m_firstPos)) * factor;
Shinya Kitaoka 120a6e
  TTool::getApplication()->getCurrentXsheet()->getXsheet()->setCenter(
Shinya Kitaoka 120a6e
      m_objId, m_frame, m_center);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DragCenterTool::leftButtonUp(const TPointD &pos, const TMouseEvent &) {
Shinya Kitaoka 120a6e
  UndoStageObjectCenterMove *undo =
Shinya Kitaoka 120a6e
      new UndoStageObjectCenterMove(m_objId, m_frame, m_oldCenter, m_center);
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  undo->setObjectHandle(app->getCurrentObject());
Shinya Kitaoka 120a6e
  undo->setXsheetHandle(app->getCurrentXsheet());
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(undo);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// DragChannelTool
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
DragChannelTool::DragChannelTool(SkeletonTool *tool, TStageObject::Channel a0)
Shinya Kitaoka 120a6e
    : DragTool(tool) {
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  m_before.setFrameHandle(app->getCurrentFrame());
Shinya Kitaoka 120a6e
  m_before.setObjectHandle(app->getCurrentObject());
Shinya Kitaoka 120a6e
  m_before.setXsheetHandle(app->getCurrentXsheet());
Shinya Kitaoka 120a6e
  m_before.add(a0);
Shinya Kitaoka 120a6e
  if (tool->isGlobalKeyframesEnabled()) {
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_Angle);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_X);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_Y);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_Z);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_SO);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_ScaleX);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_ScaleY);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_Scale);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_Path);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_ShearX);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_ShearY);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_after   = m_before;
Shinya Kitaoka 120a6e
  m_dragged = false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DragChannelTool::DragChannelTool(SkeletonTool *tool, TStageObject::Channel a0,
Shinya Kitaoka 120a6e
                                 TStageObject::Channel a1)
Shinya Kitaoka 120a6e
    : DragTool(tool) {
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  m_before.setFrameHandle(app->getCurrentFrame());
Shinya Kitaoka 120a6e
  m_before.setObjectHandle(app->getCurrentObject());
Shinya Kitaoka 120a6e
  m_before.setXsheetHandle(app->getCurrentXsheet());
Shinya Kitaoka 120a6e
  m_before.add(a0);
Shinya Kitaoka 120a6e
  m_before.add(a1);
Shinya Kitaoka 120a6e
  if (tool->isGlobalKeyframesEnabled()) {
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_Angle);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_X);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_Y);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_Z);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_SO);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_ScaleX);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_ScaleY);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_Scale);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_Path);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_ShearX);
Shinya Kitaoka 120a6e
    m_before.add(TStageObject::T_ShearY);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_after   = m_before;
Shinya Kitaoka 120a6e
  m_dragged = false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DragChannelTool::start() {
Shinya Kitaoka 120a6e
  m_before.updateValues();
Shinya Kitaoka 120a6e
  m_after = m_before;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPointD DragChannelTool::getCenter() {
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  TStageObjectId objId    = app->getCurrentObject()->getObjectId();
Shinya Kitaoka 120a6e
  int frame               = app->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
  TXsheet *xsh            = app->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
  return xsh->getParentPlacement(objId, frame).inv() *
Shinya Kitaoka 120a6e
         xsh->getPlacement(objId, frame) *
Shinya Kitaoka 120a6e
         (Stage::inch * xsh->getCenter(objId, frame));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DragChannelTool::leftButtonUp(const TPointD &pos, const TMouseEvent &) {
Shinya Kitaoka 120a6e
  if (m_dragged) {
Shinya Kitaoka 120a6e
    if (getTool()->isGlobalKeyframesEnabled()) m_after.setGlobalKeyframe();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TTool::Application *app   = TTool::getApplication();
Shinya Kitaoka 120a6e
    UndoStageObjectMove *undo = new UndoStageObjectMove(m_before, m_after);
Shinya Kitaoka 120a6e
    undo->setObjectHandle(app->getCurrentObject());
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo);
Shinya Kitaoka 120a6e
    app->getCurrentScene()->setDirtyFlag(true);
Shinya Kitaoka 120a6e
    app->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
    app->getCurrentObject()->notifyObjectIdChanged(
Shinya Kitaoka 120a6e
        false);  // Keyframes navigator reads this
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_dragged = false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// DragPositionTool
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
DragPositionTool::DragPositionTool(SkeletonTool *tool)
Shinya Kitaoka 120a6e
    : DragChannelTool(tool, TStageObject::T_X, TStageObject::T_Y) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DragPositionTool::leftButtonDown(const TPointD &pos, const TMouseEvent &) {
Shinya Kitaoka 120a6e
  start();
Shinya Kitaoka 120a6e
  m_firstPos = pos;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DragPositionTool::leftButtonDrag(const TPointD &pos,
Shinya Kitaoka 120a6e
                                      const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  TPointD delta = pos - m_firstPos;
Shinya Kitaoka 120a6e
  if (e.isShiftPressed()) {
Shinya Kitaoka 120a6e
    if (fabs(delta.x) > fabs(delta.y))
Shinya Kitaoka 120a6e
      delta.y = 0;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      delta.x = 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  double factor = 1.0 / Stage::inch;
Shinya Kitaoka 120a6e
  setValues(getOldValue(0) + delta.x * factor,
Shinya Kitaoka 120a6e
            getOldValue(1) + delta.y * factor);
Shinya Kitaoka 120a6e
  m_dragged = true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// DragRotationTool
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
DragRotationTool::DragRotationTool(SkeletonTool *tool, bool snapped)
Shinya Kitaoka 120a6e
    : DragChannelTool(tool, TStageObject::T_Angle), m_snapped(snapped) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DragRotationTool::leftButtonDown(const TPointD &pos, const TMouseEvent &) {
Shinya Kitaoka 120a6e
  m_lastPos = pos;
Shinya Kitaoka 120a6e
  m_center  = getCenter();
Shinya Kitaoka 120a6e
  start();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DragRotationTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &) {
Shinya Kitaoka 120a6e
  TPointD a = m_center - m_lastPos;
Shinya Kitaoka 120a6e
  TPointD b = m_center - pos;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double a0 = norm2(pos - m_lastPos);
Shinya Kitaoka 120a6e
  if (a0 < 2 && !m_dragged) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double a2 = norm2(a), b2 = norm2(b);
Shinya Kitaoka 120a6e
  const double eps = 1e-1;
Shinya Kitaoka 120a6e
  if (a2 < eps || b2 < eps) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double dang = asin(cross(a, b) / sqrt(a2 * b2)) * M_180_PI;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_snapped) {
Shinya Kitaoka 120a6e
    if (fabs(dang) < 2) return;
Shinya Kitaoka 120a6e
    m_snapped = false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  setValue(getValue(0) + dang);
Shinya Kitaoka 120a6e
  m_dragged = true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_lastPos = pos;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// ParentChangeTool
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ParentChangeTool::ParentChangeTool(SkeletonTool *tool, TTool::Viewer *viewer)
Shinya Kitaoka 120a6e
    : DragTool(tool)
Shinya Kitaoka 120a6e
    , m_viewer(viewer)
Shinya Kitaoka 120a6e
    , m_index(-1)
Shinya Kitaoka 120a6e
    , m_snapped(true)
Shinya Kitaoka 120a6e
    , m_pixelSize(tool->getPixelSize()) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ParentChangeTool::leftButtonDown(const TPointD &pos,
Shinya Kitaoka 120a6e
                                      const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  TXsheet *xsh            = app->getCurrentScene()->getScene()->getXsheet();
Shinya Kitaoka 120a6e
  // colonna, id e frame corrente
Shinya Kitaoka 120a6e
  int currentColumnIndex = app->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
  int currentFrame       = app->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
  TStageObjectId id      = TStageObjectId::ColumnId(currentColumnIndex);
Shinya Kitaoka 120a6e
  TStageObject *obj      = xsh->getStageObject(id);
Shinya Kitaoka 120a6e
  obj->getCenterAndOffset(m_oldCenter, m_oldOffset);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // trovo il centro della colonna corrente
Shinya Kitaoka 120a6e
  TAffine aff    = xsh->getPlacement(id, currentFrame);
Shinya Kitaoka 120a6e
  TPointD center = Stage::inch * xsh->getCenter(id, currentFrame);
Shinya Kitaoka 120a6e
  m_center       = aff * center;
Shinya Kitaoka 120a6e
  // mi serve in coordinate assolute (per questo non uso direttamente pos)
Shinya Kitaoka 120a6e
  m_lastPos  = m_viewer->winToWorld(e.m_pos);
Shinya Kitaoka 120a6e
  m_lastPos2 = pos;
Shinya Kitaoka 120a6e
  // if(m_mode==1) getTool()->setParentProbe(pos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // cerco centri e hooks di tutte le altre colonne (non discendenti)
Shinya Kitaoka 120a6e
  int nextName = 10000;
Shinya Kitaoka 120a6e
  for (int col = 0; col < xsh->getColumnCount(); col++) {
Shinya Kitaoka 120a6e
    TXshCell cell = xsh->getCell(currentFrame, col);
Shinya Kitaoka 120a6e
    if (cell.isEmpty()) continue;
Shinya Kitaoka 120a6e
    TStageObjectId colId = TStageObjectId::ColumnId(col);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // se colId e' un discendente di id non e' un candidato a diventare
Shinya Kitaoka 120a6e
    // il padre di id.
Shinya Kitaoka 120a6e
    TStageObjectId tmpId = colId;
Shinya Kitaoka 120a6e
    while (tmpId.isColumn() && tmpId != id)
Shinya Kitaoka 120a6e
      tmpId = xsh->getStageObjectParent(tmpId);
Shinya Kitaoka 120a6e
    if (tmpId == id) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // registro alcune informazioni relative a colId:
Shinya Kitaoka 120a6e
    // placement, bbox, centro, hooks, name, ecc.
Shinya Kitaoka 120a6e
    Element element;
Shinya Kitaoka 120a6e
    element.m_columnIndex   = col;
Shinya Kitaoka 120a6e
    TImageP img             = cell.getImage(false);
Shinya Kitaoka 120a6e
    if (img) element.m_bbox = img->getBBox();
Shinya Kitaoka 120a6e
    element.m_aff           = xsh->getPlacement(colId, currentFrame);
Shinya Kitaoka 120a6e
    Peer peer;
Shinya Kitaoka 120a6e
    peer.m_columnIndex = col;
Shinya Kitaoka 120a6e
    peer.m_handle      = 0;
Shinya Kitaoka 120a6e
    peer.m_name        = nextName++;
Shinya Kitaoka 120a6e
    peer.m_pos =
Shinya Kitaoka 120a6e
        element.m_aff * (Stage::inch * xsh->getCenter(colId, currentFrame));
Shinya Kitaoka 120a6e
    element.m_peers.push_back(peer);
Shinya Kitaoka 120a6e
    TXshLevel *xl = cell.m_level.getPointer();
Shinya Kitaoka 120a6e
    if (xl) {
Shinya Kitaoka 120a6e
      HookSet *hookSet     = xl->getHookSet();
Shinya Kitaoka 120a6e
      TStageObject *pegbar = xsh->getStageObject(colId);
Shinya Kitaoka 120a6e
      if (hookSet && pegbar) {
Shinya Kitaoka 120a6e
        for (int i = 0; i < hookSet->getHookCount(); i++) {
Shinya Kitaoka 120a6e
          if (!hookSet->getHook(i)) continue;
Shinya Kitaoka 120a6e
          peer.m_handle = 1 + i;
Shinya Kitaoka 120a6e
          peer.m_pos =
Shinya Kitaoka 120a6e
              element.m_aff * hookSet->getHook(i)->getAPos(cell.m_frameId);
Shinya Kitaoka 120a6e
          peer.m_name = nextName++;
Shinya Kitaoka 120a6e
          element.m_peers.push_back(peer);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_elements[col] = element;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // m_newParentCenter = TPointD();
Shinya Kitaoka 120a6e
  m_firstWinPos = e.m_pos;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_affine = xsh->getParentPlacement(id, currentFrame).inv();
Shinya Kitaoka 120a6e
  m_objId  = id;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ParentChangeTool::leftButtonDrag(const TPointD &pos,
Shinya Kitaoka 120a6e
                                      const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  if (m_snapped && norm2(e.m_pos - m_firstWinPos) > 200) {
Shinya Kitaoka 120a6e
    TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
    int currentColumnIndex  = app->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
    TStageObjectId objId    = TStageObjectId::ColumnId(currentColumnIndex);
Shinya Kitaoka 120a6e
    TStageObjectCmd::setParent(objId, TStageObjectId::NoneId, "",
Shinya Kitaoka 120a6e
                               app->getCurrentXsheet());
Shinya Kitaoka 120a6e
    m_snapped = false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_snapped) return;
Shinya Kitaoka 120a6e
  getTool()->setParentProbe(getTool()->getCurrentColumnParentMatrix() * pos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_index = m_viewer->posToColumnIndex(e.m_pos, m_pixelSize * 5, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_lastPos = m_viewer->winToWorld(e.m_pos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_handle = -1;
Shinya Kitaoka 120a6e
  if (m_index >= 0) {
Shinya Kitaoka 120a6e
    double minDist2 = 0;
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)m_elements[m_index].m_peers.size(); i++) {
Shinya Kitaoka 120a6e
      TPointD targetPos = m_elements[m_index].m_peers[i].m_pos;
Shinya Kitaoka 120a6e
      double dist2      = norm2(targetPos - m_lastPos);
Shinya Kitaoka 120a6e
      if (m_handle < 0 || dist2 < minDist2) {
Shinya Kitaoka 120a6e
        minDist2 = dist2;
Shinya Kitaoka 120a6e
        m_handle = m_elements[m_index].m_peers[i].m_handle;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ParentChangeTool::leftButtonUp(const TPointD &pos, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  int currentColumnIndex  = app->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
  int currentFrame        = app->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
  TXsheet *xsh            = app->getCurrentScene()->getScene()->getXsheet();
Shinya Kitaoka 120a6e
  TStageObjectId objId    = TStageObjectId::ColumnId(currentColumnIndex);
Shinya Kitaoka 120a6e
  getTool()->resetParentProbe();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_snapped) {
Shinya Kitaoka 120a6e
    xsh->getStageObject(objId)->setCenterAndOffset(m_oldCenter, m_oldOffset);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (getTool()->getMagicLinkCount() > 0) {
Shinya Kitaoka 120a6e
    MagicLink magicLink = getTool()->getMagicLink(0);
Shinya Kitaoka 120a6e
    HookData h0         = magicLink.m_h0;
Shinya Kitaoka 120a6e
    HookData h1         = magicLink.m_h1;
Shinya Kitaoka 120a6e
    TStageObject *obj   = xsh->getStageObject(objId);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int parentColumnIndex    = h1.m_columnIndex;
Shinya Kitaoka 120a6e
    TStageObjectId parentId  = TStageObjectId::ColumnId(parentColumnIndex);
Shinya Kitaoka 120a6e
    std::string parentHandle = h1.getHandle();
Shinya Kitaoka 120a6e
    std::string handle       = "";
Shinya Kitaoka 120a6e
    if (h0.m_columnIndex < 0) {
Shinya Kitaoka 120a6e
      handle = obj->getHandle();
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      handle = h0.getHandle();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // TUndoManager *undoManager = TUndoManager::manager();
Shinya Kitaoka 120a6e
    // undoManager->beginBlock();
Shinya Kitaoka 120a6e
    // TStageObjectCmd::resetPosition(id, app->getCurrentXsheet());
Shinya Kitaoka 120a6e
    TStageObjectCmd::setHandle(objId, handle, app->getCurrentXsheet());
Shinya Kitaoka 120a6e
    TStageObjectCmd::setParent(objId, parentId, parentHandle,
Shinya Kitaoka 120a6e
                               app->getCurrentXsheet());
Shinya Kitaoka 120a6e
    // undoManager->endBlock();
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    TStageObjectCmd::setParent(objId, TStageObjectId::NoneId, "",
Shinya Kitaoka 120a6e
                               app->getCurrentXsheet());
Shinya Kitaoka 120a6e
    xsh->getStageObject(objId)->setCenterAndOffset(m_oldCenter, m_oldOffset);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ParentChangeTool::draw() { getTool()->drawHooks(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// IKTool helper functions
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class Graph {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  typedef std::set<int> Links;</int>
Shinya Kitaoka 120a6e
  typedef Links::const_iterator LinkIter;
Shinya Kitaoka 120a6e
  typedef std::map<int, links=""> Nodes;</int,>
Shinya Kitaoka 120a6e
  typedef Nodes::const_iterator NodeIter;
Shinya Kitaoka 120a6e
  typedef std::map<int, int=""> LeaveTable;</int,>
Shinya Kitaoka 120a6e
  typedef LeaveTable::const_iterator LeaveIter;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Graph() {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int touch(int id) {
Shinya Kitaoka 120a6e
    if (m_nodes.count(id) == 0) m_nodes[id] = Links();
Shinya Kitaoka 120a6e
    return id;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  bool isNode(int id) const { return m_nodes.count(id) > 0; }
Shinya Kitaoka 120a6e
  int getNodeCount() const { return (int)m_nodes.size(); }
Shinya Kitaoka 120a6e
  void link(int a, int b) {
Shinya Kitaoka 120a6e
    touch(a);
Shinya Kitaoka 120a6e
    touch(b);
Shinya Kitaoka 120a6e
    m_nodes[a].insert(b);
Shinya Kitaoka 120a6e
    m_nodes[b].insert(a);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  bool areLinked(int a, int b) const {
Shinya Kitaoka 120a6e
    NodeIter it = m_nodes.find(a);
Shinya Kitaoka 120a6e
    return it == m_nodes.end() ? false : it->second.count(b);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  const Links &getLinks(int id) const {
Shinya Kitaoka 120a6e
    static const Links empty;
Shinya Kitaoka 120a6e
    NodeIter it = m_nodes.find(id);
Shinya Kitaoka 120a6e
    return it == m_nodes.end() ? empty : it->second;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int getLinkCount(int id) const { return (int)getLinks(id).size(); }
Shinya Kitaoka 120a6e
  int getFirstLink(int id) const {
Shinya Kitaoka 120a6e
    const Links &links = getLinks(id);
Shinya Kitaoka 120a6e
    return links.empty() ? -1 : *(links.begin());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  NodeIter begin() const { return m_nodes.begin(); }
Shinya Kitaoka 120a6e
  NodeIter end() const { return m_nodes.end(); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool isLeave(int id) const { return m_leaves.count(id); }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  enum LeaveType {
Shinya Kitaoka 120a6e
    PINNED     = 0x1,
Shinya Kitaoka 120a6e
    TEMP       = 0x2,
Shinya Kitaoka 120a6e
    CHILD_END  = 0x4,
Shinya Kitaoka 120a6e
    PARENT_END = 0x8
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
  int getLeaveType(int id) const {
Shinya Kitaoka 120a6e
    LeaveIter it = m_leaves.find(id);
Shinya Kitaoka 120a6e
    return it == m_leaves.end() ? 0 : it->second;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  void setLeaveType(int id, int type) { m_leaves[id] = type; }
Shinya Kitaoka 120a6e
  void remove(int id) {
Shinya Kitaoka 120a6e
    NodeIter it = m_nodes.find(id);
Shinya Kitaoka 120a6e
    if (it != m_nodes.end()) {
Shinya Kitaoka 120a6e
      for (LinkIter j = it->second.begin(); j != it->second.end(); ++j)
Shinya Kitaoka 120a6e
        m_nodes[*j].erase(id);
Shinya Kitaoka 120a6e
      m_nodes.erase(it->first);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  void clear() {
Shinya Kitaoka 120a6e
    m_nodes.clear();
Shinya Kitaoka 120a6e
    m_leaves.clear();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  Nodes m_nodes;
Shinya Kitaoka 120a6e
  std::map<int, int=""> m_leaves;</int,>
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool hasPinned(const Skeleton::Bone *bone, const Skeleton::Bone *prevBone) {
Shinya Kitaoka 120a6e
  if (!bone) return false;
Shinya Kitaoka 120a6e
  bool isHandle = prevBone == 0;
Shinya Kitaoka 120a6e
  bool isChild  = prevBone != 0 && prevBone == bone->getParent();
Shinya Kitaoka 120a6e
  if (bone->getPinnedStatus() != Skeleton::Bone::FREE) return true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (bone->getParent() && bone->getParent() != prevBone &&
Shinya Kitaoka 120a6e
      hasPinned(bone->getParent(), bone))
Shinya Kitaoka 120a6e
    return true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int i = 0; i < bone->getChildCount(); i++)
Shinya Kitaoka 120a6e
    if (bone->getChild(i) != prevBone)
Shinya Kitaoka 120a6e
      if (hasPinned(bone->getChild(i), bone)) return true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// create the tree from the skeleton. the tree contains the active chain only
Toshihiro Shimizu 890ddd
// i.e. the nodes bounded by the pinned nodes and the handle
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool addToActiveChain(Graph &tree, const Skeleton::Bone *bone,
Shinya Kitaoka 120a6e
                      const Skeleton::Bone *prevBone) {
Shinya Kitaoka 120a6e
  if (!bone) return false;
Shinya Kitaoka 120a6e
  bool isHandle    = prevBone == 0;
Shinya Kitaoka 120a6e
  bool isChild     = prevBone != 0 && prevBone == bone->getParent();
Shinya Kitaoka 120a6e
  bool isParent    = prevBone != 0 && prevBone->getParent() == bone;
Shinya Kitaoka 120a6e
  int pinnedStatus = bone->getPinnedStatus();
Shinya Kitaoka 120a6e
  bool isFree      = pinnedStatus == Skeleton::Bone::FREE;
Shinya Kitaoka 120a6e
  // bool isPinned = pinnedStatus == Skeleton::Bone::PINNED;
Shinya Kitaoka 120a6e
  bool isTempPinned = pinnedStatus == Skeleton::Bone::TEMP_PINNED;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool propagate = false;
Shinya Kitaoka 120a6e
  if (!isChild && isFree)
Shinya Kitaoka 120a6e
    if (bone->getParent())
Shinya Kitaoka 120a6e
      propagate |= addToActiveChain(tree, bone->getParent(), bone);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<int> children;</int>
Shinya Kitaoka 120a6e
  if (isHandle || isFree)
Shinya Kitaoka 120a6e
    for (int i = 0; i < bone->getChildCount(); i++)
Shinya Kitaoka 120a6e
      if (bone->getChild(i) != prevBone)
Shinya Kitaoka 120a6e
        propagate |= addToActiveChain(tree, bone->getChild(i), bone);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool insert = false;
Shinya Kitaoka 120a6e
  if (isHandle)  // the handle must be added anyway
Shinya Kitaoka 120a6e
    insert = true;
Shinya Kitaoka 120a6e
  else if (isChild)  // add child if it's pinned or if some gran-child has been
Shinya Kitaoka 120a6e
                     // added
Shinya Kitaoka 120a6e
    insert = !isFree || propagate;
Shinya Kitaoka 120a6e
  else if (isTempPinned) {
Shinya Kitaoka 120a6e
    // parent temp pinned are normally added, but if another branch is pinned we
Shinya Kitaoka 120a6e
    // are not
Shinya Kitaoka 120a6e
    // able to handle the configuration: then consider it as pinned
Shinya Kitaoka 120a6e
    bool locked = false;
Shinya Kitaoka 120a6e
    // if(bone->getParent()) locked |= hasPinned(bone->getParent(), bone);
Shinya Kitaoka 120a6e
    for (int i = 0; i < bone->getChildCount() && !locked; i++)
Shinya Kitaoka 120a6e
      if (bone->getChild(i) != prevBone)
Shinya Kitaoka 120a6e
        locked |= hasPinned(bone->getChild(i), bone);
Shinya Kitaoka 120a6e
    insert = !locked;
Shinya Kitaoka 120a6e
  } else  // add parent if free and grand-parent or some other child has been
Shinya Kitaoka 120a6e
          // added; don't add pinned parent
Shinya Kitaoka 120a6e
    insert = isFree && propagate;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (insert) {
Shinya Kitaoka 120a6e
    int index = tree.touch(bone->getColumnIndex());
Shinya Kitaoka 120a6e
    if (!isFree)
Shinya Kitaoka 120a6e
      tree.setLeaveType(index, isTempPinned ? 2 : 1);
Shinya Kitaoka 120a6e
    else if (!isChild && bone->getParent() &&
Shinya Kitaoka 120a6e
             !tree.isNode(bone->getParent()->getColumnIndex())) {
Shinya Kitaoka 120a6e
      // the parent has not been added. it was locked => this node act as pinned
Shinya Kitaoka 120a6e
      tree.setLeaveType(index, 2);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (prevBone) tree.link(prevBone->getColumnIndex(), index);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return isHandle || !isFree || propagate;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// IKToolUndo
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace SkeletonSubtools {
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
class IKToolUndo : public TUndo {
Shinya Kitaoka 120a6e
  struct Node {
Shinya Kitaoka 120a6e
    TStageObjectId m_id;
Shinya Kitaoka 120a6e
    double m_oldAngle, m_newAngle;
Shinya Kitaoka 120a6e
    bool m_wasKeyframe;
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
  std::vector<node> m_nodes;</node>
Shinya Kitaoka 120a6e
  TStageObjectId m_firstFootId;
Shinya Kitaoka 120a6e
  TAffine m_oldFootPlacement, m_newFootPlacement;
Shinya Kitaoka 120a6e
  int m_frame;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  IKToolUndo() {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void setFirstFootId(const TStageObjectId &firstFootId) {
Shinya Kitaoka 120a6e
    m_firstFootId = firstFootId;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  void setFirstFootOldPlacement(const TAffine &oldPlacement) {
Shinya Kitaoka 120a6e
    m_oldFootPlacement = oldPlacement;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  void setFirstFootNewPlacement(const TAffine &newPlacement) {
Shinya Kitaoka 120a6e
    m_newFootPlacement = newPlacement;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void addNode(const TStageObjectId &id) {
Shinya Kitaoka 120a6e
    m_nodes.push_back(Node());
Shinya Kitaoka 120a6e
    m_nodes.back().m_id = id;
Shinya Kitaoka 120a6e
    TXsheet *xsh = TTool::getApplication()->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
    int frame    = TTool::getApplication()->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
    TDoubleParam *param =
Shinya Kitaoka 120a6e
        xsh->getStageObject(id)->getParam(TStageObject::T_Angle);
Shinya Kitaoka 120a6e
    m_nodes.back().m_oldAngle    = param->getValue(frame);
Shinya Kitaoka 120a6e
    m_nodes.back().m_wasKeyframe = param->isKeyframe(frame);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void onAdd() override {
Shinya Kitaoka 120a6e
    TXsheet *xsh = TTool::getApplication()->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
    m_frame      = TTool::getApplication()->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)m_nodes.size(); i++) {
Shinya Kitaoka 120a6e
      TDoubleParam *param =
Shinya Kitaoka 120a6e
          xsh->getStageObject(m_nodes[i].m_id)->getParam(TStageObject::T_Angle);
Shinya Kitaoka 120a6e
      m_nodes[i].m_newAngle = param->getValue(m_frame);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void setFootPlacement(const TAffine &placement) const {
Shinya Kitaoka 120a6e
    if (!m_firstFootId.isColumn()) return;
Shinya Kitaoka 120a6e
    TXsheet *xsh = TTool::getApplication()->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
    TStageObject *obj         = xsh->getStageObject(m_firstFootId);
Shinya Kitaoka 120a6e
    TPinnedRangeSet *rangeSet = obj->getPinnedRangeSet();
Shinya Kitaoka 120a6e
    rangeSet->setPlacement(placement);
Shinya Kitaoka 120a6e
    while (obj->getParent().isColumn())
Shinya Kitaoka 120a6e
      obj = xsh->getStageObject(obj->getParent());
Shinya Kitaoka 120a6e
    obj->invalidate();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    TXsheet *xsh = TTool::getApplication()->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)m_nodes.size(); i++) {
Shinya Kitaoka 120a6e
      TDoubleParam *param =
Shinya Kitaoka 120a6e
          xsh->getStageObject(m_nodes[i].m_id)->getParam(TStageObject::T_Angle);
Shinya Kitaoka 120a6e
      if (m_nodes[i].m_wasKeyframe)
Shinya Kitaoka 120a6e
        param->setValue(m_frame, m_nodes[i].m_oldAngle);
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        param->deleteKeyframe(m_frame);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (m_firstFootId.isColumn()) setFootPlacement(m_oldFootPlacement);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
    TTool::getApplication()->getCurrentObject()->notifyObjectIdChanged(false);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    TXsheet *xsh = TTool::getApplication()->getCurrentXsheet()->getXsheet();
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)m_nodes.size(); i++) {
Shinya Kitaoka 120a6e
      TDoubleParam *param =
Shinya Kitaoka 120a6e
          xsh->getStageObject(m_nodes[i].m_id)->getParam(TStageObject::T_Angle);
Shinya Kitaoka 120a6e
      param->setValue(m_frame, m_nodes[i].m_newAngle);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (m_firstFootId.isColumn()) setFootPlacement(m_newFootPlacement);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
    TTool::getApplication()->getCurrentObject()->notifyObjectIdChanged(false);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  int getSize() const override {
Shinya Kitaoka 120a6e
    return sizeof(*this) + (int)m_nodes.size() * sizeof(Node);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Shinya Kitaoka 120a6e
}  // namespace SkeletonSubtools
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// IKTool
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
IKTool::IKTool(SkeletonTool *tool, TTool::Viewer *viewer, Skeleton *skeleton,
Shinya Kitaoka 120a6e
               int columnIndex)
Shinya Kitaoka 120a6e
    : DragTool(tool)
Shinya Kitaoka 120a6e
    , m_viewer(viewer)
Shinya Kitaoka 120a6e
    , m_skeleton(skeleton)
Shinya Kitaoka 120a6e
    , m_pos()
Shinya Kitaoka 120a6e
    , m_columnIndex(columnIndex)
Shinya Kitaoka 120a6e
    , m_valid(false)
Shinya Kitaoka 120a6e
    , m_IHateIK(false)
Shinya Kitaoka 120a6e
    , m_foot(0)
Shinya Kitaoka 120a6e
    , m_firstFoot(0)
Shinya Kitaoka 120a6e
    , m_undo(0) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
IKTool::~IKTool() { delete m_skeleton; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool IKTool::isParentOf(int columnIndex, int childColumnIndex) const {
Shinya Kitaoka 120a6e
  Skeleton::Bone *bone = m_skeleton->getBoneByColumnIndex(columnIndex);
Shinya Kitaoka 120a6e
  Skeleton::Bone *childBone =
Shinya Kitaoka 120a6e
      m_skeleton->getBoneByColumnIndex(childColumnIndex);
Shinya Kitaoka 120a6e
  return bone && childBone && childBone->getParent() == bone;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void IKTool::initEngine(const TPointD &pos) {
Shinya Kitaoka 120a6e
  m_valid = false;
Shinya Kitaoka 120a6e
  m_engine.clear();
Shinya Kitaoka 120a6e
  m_joints.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // m_skeleton->getRootBone()->getStageObject()->setStatus(TStageObject::IK);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // build the active chain (bounded by m_columnIndex and pinned nodes)
Shinya Kitaoka 120a6e
  Graph chain;
Shinya Kitaoka 120a6e
  addToActiveChain(chain, m_skeleton->getBoneByColumnIndex(m_columnIndex), 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // mark leaves as child_end or parent_end: a leave is child/parent_end iff
Shinya Kitaoka 120a6e
  // all its link are parent/child
Shinya Kitaoka 120a6e
  for (Graph::NodeIter it = chain.begin(); it != chain.end(); ++it)
Shinya Kitaoka 120a6e
    if (chain.getLeaveType(it->first) & (Graph::PINNED | Graph::TEMP)) {
Shinya Kitaoka 120a6e
      int type = 0;
Shinya Kitaoka 120a6e
      for (Graph::LinkIter j = it->second.begin(); j != it->second.end(); ++j) {
Shinya Kitaoka 120a6e
        int f =
Shinya Kitaoka 120a6e
            isParentOf(*j, it->first) ? Graph::CHILD_END : Graph::PARENT_END;
Shinya Kitaoka 120a6e
        if (type == 0)
Shinya Kitaoka 120a6e
          type = f;
Shinya Kitaoka 120a6e
        else if (type != f) {
Shinya Kitaoka 120a6e
          type = 0;
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      chain.setLeaveType(it->first, chain.getLeaveType(it->first) | type);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // search the foot (i.e. the pinned node). if there are no pinned node find
Shinya Kitaoka 120a6e
  // the first
Shinya Kitaoka 120a6e
  // temp-pinned
Shinya Kitaoka 120a6e
  int foot = -1;
Shinya Kitaoka 120a6e
  for (Graph::NodeIter it = chain.begin(); it != chain.end(); ++it)
Shinya Kitaoka 120a6e
    if (chain.isLeave(it->first)) {
Shinya Kitaoka 120a6e
      if ((chain.getLeaveType(it->first) & Graph::PINNED) != 0 || foot < 0)
Shinya Kitaoka 120a6e
        foot = it->first;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  if (foot < 0 || !chain.isNode(foot)) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // If the chain descend from the foot then the whole foot should be still
Shinya Kitaoka 120a6e
  // (e.g. no rotation)
Shinya Kitaoka 120a6e
  // => chop the foot
Shinya Kitaoka 120a6e
  if (chain.getLinkCount(foot) == 1 &&
Shinya Kitaoka 120a6e
      (chain.getLeaveType(foot) & Graph::PINNED)) {
Shinya Kitaoka 120a6e
    int nextNode = chain.getFirstLink(foot);
Shinya Kitaoka 120a6e
    if (isParentOf(foot, nextNode)) {
Shinya Kitaoka 120a6e
      chain.remove(foot);
Shinya Kitaoka 120a6e
      foot = nextNode;
Shinya Kitaoka 120a6e
      chain.setLeaveType(foot, 3);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // if the handle is a terminal node (i.e. just one link) and the next node is
Shinya Kitaoka 120a6e
  // a child
Shinya Kitaoka 120a6e
  // move the handle to the next node
Shinya Kitaoka 120a6e
  int handle = m_columnIndex;
Shinya Kitaoka 120a6e
  if (chain.getLinkCount(handle) == 1) {
Shinya Kitaoka 120a6e
    int nextNode = chain.getFirstLink(handle);
Shinya Kitaoka 120a6e
    if (isParentOf(handle, nextNode)) {
Shinya Kitaoka 120a6e
      chain.remove(handle);
Shinya Kitaoka 120a6e
      handle = nextNode;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // "reverse" the tree to suit the IKEngine convention
Shinya Kitaoka 120a6e
  std::vector<std::pair<int, *="" skeleton::bone="">> stack;</std::pair<int,>
Shinya Kitaoka 120a6e
  std::vector<int> done;</int>
Shinya Kitaoka 120a6e
  stack.push_back(std::make_pair(foot, (Skeleton::Bone *)0));
Shinya Kitaoka 120a6e
  while (!stack.empty()) {
Shinya Kitaoka 120a6e
    Skeleton::Bone *bone = m_skeleton->getBoneByColumnIndex(stack.back().first);
Shinya Kitaoka 120a6e
    Skeleton::Bone *prev = stack.back().second;
Shinya Kitaoka 120a6e
    Skeleton::Bone *prev2 = prev;
Shinya Kitaoka 120a6e
    stack.pop_back();
Shinya Kitaoka 120a6e
    for (;;) {
Shinya Kitaoka 120a6e
      int id = bone->getColumnIndex();
Shinya Kitaoka 120a6e
      done.push_back(id);
Shinya Kitaoka 120a6e
      double sign = 1;
Shinya Kitaoka 120a6e
      if (prev) {
Shinya Kitaoka 120a6e
        if (prev->getParent() == bone) sign = -1;
Shinya Kitaoka 120a6e
      } else if (done.size() == 1) {
Shinya Kitaoka 120a6e
        if (chain.getLeaveType(id) & Graph::CHILD_END) sign = -1;
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        if (chain.getLeaveType(id) & Graph::PARENT_END) sign = -1;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      Graph::Links links = chain.getLinks(bone->getColumnIndex());
Shinya Kitaoka 120a6e
      for (int i = 0; i < (int)done.size(); i++) links.erase(done[i]);
Shinya Kitaoka 120a6e
      if (links.size() == 0) {
Shinya Kitaoka 120a6e
        // terminal point
Shinya Kitaoka 120a6e
        m_joints.push_back(Joint(bone, prev, sign));
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        Graph::LinkIter it   = links.begin();
Shinya Kitaoka 120a6e
        Skeleton::Bone *next = m_skeleton->getBoneByColumnIndex(*it++);
Shinya Kitaoka 120a6e
        for (; it != links.end(); ++it)
Shinya Kitaoka 120a6e
          stack.push_back(std::make_pair(*it, prev));
Shinya Kitaoka 120a6e
        if (links.size() > 1 || (prev && next && (prev->getParent() == bone &&
Shinya Kitaoka 120a6e
                                                  next->getParent() == bone))) {
Shinya Kitaoka 120a6e
          bone = next;
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          m_joints.push_back(Joint(bone, prev, sign));
Shinya Kitaoka 120a6e
          prev = bone;
Shinya Kitaoka 120a6e
          bone = next;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // if(m_joints.size()>=2 && m_joints[1].m_prevBone == m_joints[0].m_bone)
Shinya Kitaoka 120a6e
  //  m_joints[0].m_sign = m_joints[1].m_sign;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // feed the engine
Shinya Kitaoka 120a6e
  m_engine.setRoot(m_joints[0].m_bone->getCenter());
Shinya Kitaoka 120a6e
  for (int i = 1; i < (int)m_joints.size(); i++) {
Shinya Kitaoka 120a6e
    int parent = -1;
Shinya Kitaoka 120a6e
    for (int j = 0; j < i; j++)
Shinya Kitaoka 120a6e
      if (m_joints[j].m_bone == m_joints[i].m_prevBone) {
Shinya Kitaoka 120a6e
        parent = j;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    if (parent < 0) {
Shinya Kitaoka 120a6e
      assert(0);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_engine.addJoint(m_joints[i].m_bone->getCenter(), parent);
Shinya Kitaoka 120a6e
    if (m_joints[i].m_bone->getPinnedStatus() != Skeleton::Bone::FREE)
Shinya Kitaoka 120a6e
      m_engine.lock(i);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // add the handle
Shinya Kitaoka 120a6e
  bool handleFound = false;
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)m_joints.size(); i++)
Shinya Kitaoka 120a6e
    if (m_joints[i].m_bone->getColumnIndex() == handle) {
Shinya Kitaoka 120a6e
      m_engine.addJoint(pos, i);
Shinya Kitaoka 120a6e
      handleFound = true;
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  if (!handleFound) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  setAngleOffsets();
Shinya Kitaoka 120a6e
  computeIHateIK();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_valid = true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TODO cambiare questo nome; aggiungere due righe di spiegazione
Shinya Kitaoka 120a6e
void IKTool::computeIHateIK() {
Shinya Kitaoka 120a6e
  std::vector<tstageobject *=""> objs;</tstageobject>
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_skeleton->getBoneCount(); i++)
Shinya Kitaoka 120a6e
    objs.push_back(m_skeleton->getBone(i)->getStageObject());
Shinya Kitaoka 120a6e
  int n     = (int)objs.size();
Shinya Kitaoka 120a6e
  int frame = TTool::getApplication()->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
  m_foot = m_firstFoot = 0;
Shinya Kitaoka 120a6e
  m_IHateIK            = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < n && !objs[i]->getPinnedRangeSet()->isPinned(frame); i++) {
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (i == n) return;
Shinya Kitaoka 120a6e
  m_foot = objs[i];
Shinya Kitaoka 120a6e
  const TPinnedRangeSet::Range *range =
Shinya Kitaoka 120a6e
      m_foot->getPinnedRangeSet()->getRange(frame);
Shinya Kitaoka 120a6e
  if (!range || range->first != frame) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_IHateIK      = true;
Shinya Kitaoka 120a6e
  int firstFrame = frame - 1;
Shinya Kitaoka 120a6e
  m_firstFoot    = m_foot;
Shinya Kitaoka 120a6e
  for (;;) {
Shinya Kitaoka 120a6e
    for (i = 0; i < n && !objs[i]->getPinnedRangeSet()->isPinned(firstFrame);
Shinya Kitaoka 120a6e
         i++) {
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (i == n) break;
Shinya Kitaoka 120a6e
    m_firstFoot = objs[i];
Shinya Kitaoka 120a6e
    range       = m_firstFoot->getPinnedRangeSet()->getRange(firstFrame);
Shinya Kitaoka 120a6e
    if (!range) break;
Shinya Kitaoka 120a6e
    firstFrame = range->first - 1;
Shinya Kitaoka 120a6e
    if (firstFrame < 0) break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_footPlacement      = m_foot->getPlacement(frame);
Shinya Kitaoka 120a6e
  m_firstFootPlacement = m_firstFoot->getPinnedRangeSet()->getPlacement();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void IKTool::setAngleOffsets() {
Shinya Kitaoka 120a6e
  int frame = TTool::getApplication()->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)m_joints.size(); i++) {
Shinya Kitaoka 120a6e
    double angle = m_joints[i].m_bone->getStageObject()->getParam(
Shinya Kitaoka 120a6e
        TStageObject::T_Angle, frame);
Shinya Kitaoka 120a6e
    double theta0             = angle * M_PI_180;
Shinya Kitaoka 120a6e
    double theta1             = m_joints[i].m_sign * m_engine.getJointAngle(i);
Shinya Kitaoka 120a6e
    m_joints[i].m_angleOffset = theta1 - theta0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void IKTool::storeOldValues() {
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)m_joints.size(); i++) {
Shinya Kitaoka 120a6e
    TStageObjectValues values(m_joints[i].m_bone->getStageObject()->getId(),
Shinya Kitaoka 120a6e
                              TStageObject::T_Angle);
Shinya Kitaoka 120a6e
    if (getTool()->isGlobalKeyframesEnabled()) {
Shinya Kitaoka 120a6e
      values.add(TStageObject::T_X);
Shinya Kitaoka 120a6e
      values.add(TStageObject::T_Y);
Shinya Kitaoka 120a6e
      values.add(TStageObject::T_Z);
Shinya Kitaoka 120a6e
      values.add(TStageObject::T_SO);
Shinya Kitaoka 120a6e
      values.add(TStageObject::T_ScaleX);
Shinya Kitaoka 120a6e
      values.add(TStageObject::T_ScaleY);
Shinya Kitaoka 120a6e
      values.add(TStageObject::T_Scale);
Shinya Kitaoka 120a6e
      values.add(TStageObject::T_Path);
Shinya Kitaoka 120a6e
      values.add(TStageObject::T_ShearX);
Shinya Kitaoka 120a6e
      values.add(TStageObject::T_ShearY);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
    values.setFrameHandle(app->getCurrentFrame());
Shinya Kitaoka 120a6e
    values.setXsheetHandle(app->getCurrentXsheet());
Shinya Kitaoka 120a6e
    values.updateValues();
Shinya Kitaoka 120a6e
    m_joints[i].m_oldValues = values;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void IKTool::apply() {
Shinya Kitaoka 120a6e
  if (!m_valid) return;
Shinya Kitaoka 120a6e
  TStageObject *rootObj = m_skeleton->getRootBone()->getStageObject();
Shinya Kitaoka 120a6e
  if (!m_undo) {
Shinya Kitaoka 120a6e
    m_undo = new IKToolUndo();
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)m_joints.size(); i++)
Shinya Kitaoka 120a6e
      m_undo->addNode(m_joints[i].m_bone->getStageObject()->getId());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_IHateIK && m_firstFoot) {
Shinya Kitaoka 120a6e
      m_undo->setFirstFootId(m_firstFoot->getId());
Shinya Kitaoka 120a6e
      m_undo->setFirstFootOldPlacement(
Shinya Kitaoka 120a6e
          m_firstFoot->getPinnedRangeSet()->getPlacement());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int frame = TTool::getApplication()->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)m_joints.size(); i++) {
Shinya Kitaoka 120a6e
    TStageObject *obj   = m_joints[i].m_bone->getStageObject();
Shinya Kitaoka 120a6e
    TDoubleParam *param = obj->getParam(TStageObject::T_Angle);
Shinya Kitaoka 120a6e
    double theta        = m_joints[i].m_sign * m_engine.getJointAngle(i) -
Shinya Kitaoka 120a6e
                   m_joints[i].m_angleOffset;
Shinya Kitaoka 120a6e
    theta *= M_180_PI;
Shinya Kitaoka 120a6e
    double oldTheta = param->getValue(frame);
Shinya Kitaoka 120a6e
    double delta    = theta - oldTheta;
Shinya Kitaoka 120a6e
    if (fabs(delta) > 180) theta += (theta < oldTheta ? 1 : -1) * 360;
Shinya Kitaoka 120a6e
    param->setValue(frame, theta);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_skeleton->getRootBone()->getStageObject()->invalidate();
Shinya Kitaoka 120a6e
  if (m_IHateIK) {
Shinya Kitaoka 120a6e
    TStageObject *rootObj = m_skeleton->getRootBone()->getStageObject();
Shinya Kitaoka 120a6e
    rootObj->setStatus(TStageObject::XY);
Shinya Kitaoka 120a6e
    rootObj->invalidate();
Shinya Kitaoka 120a6e
    TAffine rootBasePlacement = rootObj->getPlacement(frame);
Shinya Kitaoka 120a6e
    rootObj->setStatus(TStageObject::IK);
Shinya Kitaoka 120a6e
    rootObj->invalidate();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPinnedRangeSet *rangeSet = m_firstFoot->getPinnedRangeSet();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TAffine oldFootPlacement = m_foot->getPlacement(frame);
Shinya Kitaoka 120a6e
    TAffine relativeOldFootPlacement =
Shinya Kitaoka 120a6e
        rootBasePlacement.inv() * oldFootPlacement;
Shinya Kitaoka 120a6e
    TAffine correction = rootBasePlacement.inv() * m_footPlacement *
Shinya Kitaoka 120a6e
                         oldFootPlacement.inv() * rootBasePlacement;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    rangeSet->setPlacement(correction * rangeSet->getPlacement());
Shinya Kitaoka 120a6e
    rootObj->invalidate();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TAffine currentFootPlacement = m_foot->getPlacement(frame);
Shinya Kitaoka 120a6e
    TAffine check                = m_footPlacement.inv() * currentFootPlacement;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert(check.isIdentity(0.01));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void IKTool::leftButtonDown(const TPointD &p, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  TPointD pos = m_viewer->winToWorld(e.m_pos);
Shinya Kitaoka 120a6e
  m_pos       = pos;
Shinya Kitaoka 120a6e
  initEngine(pos);
Shinya Kitaoka 120a6e
  storeOldValues();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void IKTool::leftButtonDrag(const TPointD &p, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  if (!m_valid) return;
Shinya Kitaoka 120a6e
  if (m_engine.getJointCount() > 0) {
Shinya Kitaoka 120a6e
    TPointD tmp = m_viewer->winToWorld(e.m_pos);
Shinya Kitaoka 120a6e
    m_engine.drag(tmp);
Shinya Kitaoka 120a6e
    apply();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void IKTool::leftButtonUp(const TPointD &p, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  if (m_undo) {
Shinya Kitaoka 120a6e
    if (m_IHateIK && m_firstFoot)
Shinya Kitaoka 120a6e
      m_undo->setFirstFootNewPlacement(
Shinya Kitaoka 120a6e
          m_firstFoot->getPinnedRangeSet()->getPlacement());
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(m_undo);
Shinya Kitaoka 120a6e
    m_undo = 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_valid = false;
Shinya Kitaoka 120a6e
  m_engine.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void IKTool::draw() {
Shinya Kitaoka 120a6e
  int err = glGetError();
Shinya Kitaoka 120a6e
  assert(err == GL_NO_ERROR);
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  int frame               = app->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double unit =
Shinya Kitaoka 120a6e
      TTool::getApplication()->getCurrentTool()->getTool()->getPixelSize();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_engine.getJointCount() > 0) {
Shinya Kitaoka 120a6e
    glColor3d(1, 0, 1);
Shinya Kitaoka 120a6e
    for (int i = 0; i < m_engine.getJointCount(); i++) {
Shinya Kitaoka 120a6e
      TPointD pa = m_engine.getJoint(i);
Shinya Kitaoka 120a6e
      tglDrawDisk(pa, 5 * unit);
Shinya Kitaoka 120a6e
      if (i > 0) {
Shinya Kitaoka 120a6e
        int j = m_engine.getJointParent(i);
Shinya Kitaoka 120a6e
        tglDrawSegment(pa, m_engine.getJoint(j));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// ChangeDrawingTool
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class ChangeDrawingUndo : public TUndo {
Shinya Kitaoka 120a6e
  int m_row, m_col;
Shinya Kitaoka 120a6e
  TFrameId m_oldFid, m_newFid;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  ChangeDrawingUndo(int row, int col) : m_row(row), m_col(col) {
Shinya Kitaoka 120a6e
    m_oldFid = getDrawing();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TFrameId getDrawing() const {
Shinya Kitaoka 120a6e
    TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
    TXsheet *xsh            = app->getCurrentScene()->getScene()->getXsheet();
Shinya Kitaoka 120a6e
    TXshCell cell           = xsh->getCell(m_row, m_col);
Shinya Kitaoka 120a6e
    return cell.m_frameId;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void setDrawing(const TFrameId &fid) const {
Shinya Kitaoka 120a6e
    TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
    TXsheet *xsh            = app->getCurrentScene()->getScene()->getXsheet();
Shinya Kitaoka 120a6e
    TXshCell cell           = xsh->getCell(m_row, m_col);
Shinya Kitaoka 120a6e
    cell.m_frameId          = fid;
Shinya Kitaoka 120a6e
    xsh->setCell(m_row, m_col, cell);
Shinya Kitaoka 120a6e
    TStageObject *pegbar = xsh->getStageObject(TStageObjectId::ColumnId(m_col));
Shinya Kitaoka 120a6e
    pegbar->setOffset(pegbar->getOffset());
Shinya Kitaoka 120a6e
    // solo per invalidare l'imp. TODO da fare meglio
Shinya Kitaoka 120a6e
    // l'idea e' che cambiando drawing corrente, se ci sono hook la posizione
Shinya Kitaoka 120a6e
    // della pegbar (o delle pegbar figlie) puo' cambiare
Shinya Kitaoka 120a6e
    app->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void onAdd() override { m_newFid = getDrawing(); }
Shinya Kitaoka 473e70
  void undo() const override { setDrawing(m_oldFid); }
Shinya Kitaoka 473e70
  void redo() const override { setDrawing(m_newFid); }
Shinya Kitaoka 473e70
  int getSize() const override { return sizeof(*this); }
Shinya Kitaoka 120a6e
  TFrameId getOldDrawing() const { return m_oldFid; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ChangeDrawingTool::ChangeDrawingTool(SkeletonTool *tool, int dir)
Shinya Kitaoka 120a6e
    : DragTool(tool), m_oldY(0), m_dir(dir), m_undo(0) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChangeDrawingTool::leftButtonDown(const TPointD &, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  m_oldY                  = e.m_pos.y;
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  int row                 = app->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
  int col                 = app->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
  m_undo                  = new ChangeDrawingUndo(row, col);
Shinya Kitaoka 120a6e
  if (m_dir > 0)
Shinya Kitaoka 120a6e
    changeDrawing(1);
Shinya Kitaoka 120a6e
  else if (m_dir < 0)
Shinya Kitaoka 120a6e
    changeDrawing(-1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChangeDrawingTool::leftButtonDrag(const TPointD &, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  if (m_dir != 0) return;
Shinya Kitaoka 120a6e
  int delta     = e.m_pos.y - m_oldY;
Shinya Kitaoka 120a6e
  int h         = 5;
Shinya Kitaoka 120a6e
  int increment = delta > 0 ? delta / h : -(-delta) / h;
Shinya Kitaoka 120a6e
  if (increment == 0) return;
Shinya Kitaoka 120a6e
  changeDrawing(-increment);
Shinya Kitaoka 120a6e
  m_oldY += h * increment;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ChangeDrawingTool::leftButtonUp(const TPointD &, const TMouseEvent &e) {
Shinya Kitaoka 120a6e
  ChangeDrawingUndo *u = dynamic_cast<changedrawingundo *="">(m_undo);</changedrawingundo>
Shinya Kitaoka 120a6e
  if (u) {
Shinya Kitaoka 120a6e
    if (u->getOldDrawing() != u->getDrawing())
Shinya Kitaoka 120a6e
      TUndoManager::manager()->add(u);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      delete u;
Shinya Kitaoka 120a6e
    m_undo = 0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// cambia il frame della cella corrente, scorrendo (in maniera
Toshihiro Shimizu 890ddd
// ciclica) i drawings del livello
Toshihiro Shimizu 890ddd
// ritorna true se ci riesce
Shinya Kitaoka 120a6e
bool ChangeDrawingTool::changeDrawing(int delta) {
Shinya Kitaoka 120a6e
  TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
  TXsheet *xsh            = app->getCurrentScene()->getScene()->getXsheet();
Shinya Kitaoka 120a6e
  int row                 = app->getCurrentFrame()->getFrame();
Shinya Kitaoka 120a6e
  int col                 = app->getCurrentColumn()->getColumnIndex();
Shinya Kitaoka 120a6e
  TXshCell cell           = xsh->getCell(row, col);
Shinya Kitaoka 120a6e
  if (!cell.m_level || !cell.m_level->getSimpleLevel()) return false;
Shinya Kitaoka 120a6e
  std::vector<tframeid> fids;</tframeid>
Shinya Kitaoka 120a6e
  cell.m_level->getSimpleLevel()->getFids(fids);
Shinya Kitaoka 120a6e
  int n = fids.size();
Shinya Kitaoka 120a6e
  if (n < 2) return false;
Shinya Kitaoka 120a6e
  std::vector<tframeid>::iterator it;</tframeid>
Shinya Kitaoka 120a6e
  it = std::find(fids.begin(), fids.end(), cell.m_frameId);
Shinya Kitaoka 120a6e
  if (it == fids.end()) return false;
Shinya Kitaoka 120a6e
  int index = std::distance(fids.begin(), it);
Shinya Kitaoka 120a6e
  while (delta < 0) delta += n;
Shinya Kitaoka 120a6e
  index = (index + delta) % n;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ChangeDrawingUndo *u = dynamic_cast<changedrawingundo *="">(m_undo);</changedrawingundo>
Shinya Kitaoka 120a6e
  if (u) u->setDrawing(fids[index]);
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
CommandHandler::CommandHandler() : m_skeleton(0), m_tempPinnedSet(0) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
CommandHandler::~CommandHandler() { delete m_skeleton; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void CommandHandler::setSkeleton(Skeleton *skeleton) {
Shinya Kitaoka 120a6e
  if (m_skeleton != skeleton) {
Shinya Kitaoka 120a6e
    delete m_skeleton;
Shinya Kitaoka 120a6e
    m_skeleton = skeleton;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void CommandHandler::clearPinnedRanges() {
Shinya Kitaoka 120a6e
  if (m_skeleton) {
Shinya Kitaoka 120a6e
    TTool::Application *app = TTool::getApplication();
Shinya Kitaoka 120a6e
    m_skeleton->clearAllPinnedRanges();
Shinya Kitaoka 120a6e
    app->getCurrentScene()->setDirtyFlag(true);
Shinya Kitaoka 120a6e
    app->getCurrentXsheet()->notifyXsheetChanged();
Shinya Kitaoka 120a6e
    m_skeleton->getRootBone()->getStageObject()->setStatus(TStageObject::XY);
Shinya Kitaoka 120a6e
    delete m_skeleton;
Shinya Kitaoka 120a6e
    m_skeleton = 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (m_tempPinnedSet) m_tempPinnedSet->clear();
Toshihiro Shimizu 890ddd
}