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