Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tools/tool.h"
Toshihiro Shimizu 890ddd
#include "tools/toolutils.h"
Toshihiro Shimizu 890ddd
#include "toonz/txsheethandle.h"
Toshihiro Shimizu 890ddd
#include "tools/toolhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tframehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcolumnhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshlevelhandle.h"
Toshihiro Shimizu 890ddd
#include "tools/strokeselection.h"
Toshihiro Shimizu 890ddd
#include "tools/tool.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tmathutil.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tools/cursors.h"
Toshihiro Shimizu 890ddd
#include "tundo.h"
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "tthreadmessage.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonzqt/imageutils.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/tselectionhandle.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace ToolUtils;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// UndoCutter
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class UndoCutter : public ToolUtils::TToolUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int m_newStrokeId1;
Toshihiro Shimizu 890ddd
	int m_newStrokeId2;
Toshihiro Shimizu 890ddd
	int m_pos;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	VIStroke *m_oldStroke;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 3bfa54
	std::vector<tfilledregioninf> *m_fillInformation;</tfilledregioninf>
Shinya Kitaoka 3bfa54
	std::vector<doublepair> *m_sortedWRanges;</doublepair>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int m_row;
Toshihiro Shimizu 890ddd
	int m_column;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	UndoCutter(TXshSimpleLevel *level,
Toshihiro Shimizu 890ddd
			   const TFrameId &frameId,
Toshihiro Shimizu 890ddd
			   VIStroke *oldStroke,
Toshihiro Shimizu 890ddd
			   int pos,
Toshihiro Shimizu 890ddd
			   int newStrokeId1,
Toshihiro Shimizu 890ddd
			   int newStrokeId2,
Shinya Kitaoka 3bfa54
			   std::vector<tfilledregioninf> *fillInformation,</tfilledregioninf>
Shinya Kitaoka 3bfa54
			   std::vector<doublepair> *sortedWRanges)</doublepair>
Toshihiro Shimizu 890ddd
		: TToolUndo(level, frameId), m_oldStroke(oldStroke), m_newStrokeId1(newStrokeId1), m_newStrokeId2(newStrokeId2), m_pos(pos), m_fillInformation(fillInformation), m_sortedWRanges(sortedWRanges)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TTool::Application *app = TTool::getApplication();
Toshihiro Shimizu 890ddd
		if (app) {
Toshihiro Shimizu 890ddd
			m_row = app->getCurrentFrame()->getFrame();
Toshihiro Shimizu 890ddd
			m_column = app->getCurrentColumn()->getColumnIndex();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	~UndoCutter()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		deleteVIStroke(m_oldStroke);
Toshihiro Shimizu 890ddd
		delete m_sortedWRanges;
Toshihiro Shimizu 890ddd
		delete m_fillInformation;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void undo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TTool::Application *app = TTool::getApplication();
Toshihiro Shimizu 890ddd
		if (!app)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		if (dynamic_cast<strokeselection *="">(TTool::getApplication()->getCurrentSelection()->getSelection()))</strokeselection>
Toshihiro Shimizu 890ddd
			TTool::getApplication()->getCurrentSelection()->setSelection(0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (app->getCurrentFrame()->isEditingScene()) {
Toshihiro Shimizu 890ddd
			app->getCurrentColumn()->setColumnIndex(m_column);
Toshihiro Shimizu 890ddd
			app->getCurrentFrame()->setFrame(m_row);
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			app->getCurrentFrame()->setFid(m_frameId);
Toshihiro Shimizu 890ddd
		TVectorImageP image = m_level->getFrame(m_frameId, true);
Toshihiro Shimizu 890ddd
		assert(!!image);
Toshihiro Shimizu 890ddd
		if (!image)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		QMutexLocker lock(image->getMutex());
Toshihiro Shimizu 890ddd
		VIStroke *stroke;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		stroke = image->getStrokeById(m_newStrokeId1);
Toshihiro Shimizu 890ddd
		if (stroke)
Toshihiro Shimizu 890ddd
			image->deleteStroke(stroke);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		stroke = image->getStrokeById(m_newStrokeId2);
Toshihiro Shimizu 890ddd
		if (stroke)
Toshihiro Shimizu 890ddd
			image->deleteStroke(stroke);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		stroke = cloneVIStroke(m_oldStroke);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		image->insertStrokeAt(stroke, m_pos);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		UINT size = m_fillInformation->size();
Toshihiro Shimizu 890ddd
		if (!size) {
Toshihiro Shimizu 890ddd
			app->getCurrentXsheet()->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
			notifyImageChanged();
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		image->findRegions();
Toshihiro Shimizu 890ddd
		TRegion *reg;
Toshihiro Shimizu 890ddd
		for (UINT i = 0; i < size; i++) {
Toshihiro Shimizu 890ddd
			reg = image->getRegion((*m_fillInformation)[i].m_regionId);
Toshihiro Shimizu 890ddd
			assert(reg);
Toshihiro Shimizu 890ddd
			if (reg)
Toshihiro Shimizu 890ddd
				reg->setStyle((*m_fillInformation)[i].m_styleId);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		app->getCurrentXsheet()->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
		notifyImageChanged();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void redo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TTool::Application *app = TTool::getApplication();
Toshihiro Shimizu 890ddd
		if (!app)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		if (app->getCurrentFrame()->isEditingScene()) {
Toshihiro Shimizu 890ddd
			app->getCurrentColumn()->setColumnIndex(m_column);
Toshihiro Shimizu 890ddd
			app->getCurrentFrame()->setFrame(m_row);
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			app->getCurrentFrame()->setFid(m_frameId);
Toshihiro Shimizu 890ddd
		TVectorImageP image = m_level->getFrame(m_frameId, true);
Toshihiro Shimizu 890ddd
		assert(!!image);
Toshihiro Shimizu 890ddd
		if (!image)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		QMutexLocker lock(image->getMutex());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool isSelfLoop = image->getStroke(m_pos)->isSelfLoop();
Toshihiro Shimizu 890ddd
		image->splitStroke(m_pos, *m_sortedWRanges);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		image->getStroke(m_pos)->setId(m_newStrokeId1);
Toshihiro Shimizu 890ddd
		if (!isSelfLoop && m_sortedWRanges->size() == 2)
Toshihiro Shimizu 890ddd
			image->getStroke(m_pos + 1)->setId(m_newStrokeId2);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		app->getCurrentXsheet()->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
		notifyImageChanged();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int getSize() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return sizeof(*this) + m_fillInformation->capacity() * sizeof(TFilledRegionInf) + 500;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QString getToolName()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return QString("Cutter Tool");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// CutterTool
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class CutterTool : public TTool
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	bool m_mouseDown;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD m_vTan;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TThickPoint m_cursor;
Toshihiro Shimizu 890ddd
	TPointD m_speed;
Toshihiro Shimizu 890ddd
	int m_cursorId;
Toshihiro Shimizu 890ddd
	double m_pW;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	CutterTool()
Toshihiro Shimizu 890ddd
		: TTool("T_Cutter"), m_mouseDown(false), m_cursorId(ToolCursor::CutterCursor)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		bind(TTool::VectorImage);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ToolType getToolType() const { return TTool::LevelWriteTool; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void draw()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		//TAffine viewMatrix = getViewer()->getViewMatrix();
Toshihiro Shimizu 890ddd
		//glPushMatrix();
Toshihiro Shimizu 890ddd
		//tglMultMatrix(viewMatrix);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const double pixelSize = getPixelSize();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double len = m_cursor.thick + 15 * pixelSize;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_speed != TPointD(0, 0)) {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TPointD v = m_speed;
Toshihiro Shimizu 890ddd
			TPointD p = (TPointD)m_cursor;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			v = rotate90(v);
Toshihiro Shimizu 890ddd
			v = normalize(v);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			v = v * (len);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			tglColor(TPixelD(0.1, 0.9, 0.1));
Toshihiro Shimizu 890ddd
			tglDrawSegment(p - v, p + v);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		//glPopMatrix();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void leftButtonDown(const TPointD &pos, const TMouseEvent &)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TVectorImageP vi = TImageP(getImage(true));
Toshihiro Shimizu 890ddd
		if (!vi)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		QMutexLocker sl(vi->getMutex());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double dist, pW;
Toshihiro Shimizu 890ddd
		UINT strokeIndex;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TStroke *strokeRef;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (vi->getNearestStroke(pos, pW, strokeIndex, dist) && pW >= 0 && pW <= 1) {
Toshihiro Shimizu 890ddd
			double w;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			strokeRef = vi->getStroke(strokeIndex);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double hitPointLen = strokeRef->getLength(pW);
Toshihiro Shimizu 890ddd
			double totalLen = strokeRef->getLength();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double len = hitPointLen;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (!strokeRef->isSelfLoop()) {
Toshihiro Shimizu 890ddd
				if (len < TConsts::epsilon)
Toshihiro Shimizu 890ddd
					w = 0;
Toshihiro Shimizu 890ddd
				else
Toshihiro Shimizu 890ddd
					w = strokeRef->getParameterAtLength(len);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (len > totalLen - TConsts::epsilon)
Toshihiro Shimizu 890ddd
					w = 1;
Toshihiro Shimizu 890ddd
				else
Toshihiro Shimizu 890ddd
					w = strokeRef->getParameterAtLength(len);
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				if (len < 0)
Toshihiro Shimizu 890ddd
					len += totalLen;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (len > totalLen)
Toshihiro Shimizu 890ddd
					len -= totalLen;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				w = strokeRef->getParameterAtLength(len);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2148c8
			std::vector<doublepair> *sortedWRanges = new std::vector<doublepair>;</doublepair></doublepair>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (strokeRef->isSelfLoop()) {
Shinya Kitaoka 2148c8
				sortedWRanges->push_back(std::make_pair(0, w));
Shinya Kitaoka 2148c8
				sortedWRanges->push_back(std::make_pair(w, 1));
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				if (w == 0 || w == 1)
Shinya Kitaoka 2148c8
					sortedWRanges->push_back(std::make_pair(0, 1));
Toshihiro Shimizu 890ddd
				else {
Shinya Kitaoka 2148c8
					sortedWRanges->push_back(std::make_pair(0, w));
Shinya Kitaoka 2148c8
					sortedWRanges->push_back(std::make_pair(w, 1));
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 2148c8
			std::vector<tfilledregioninf> *fillInformation = new std::vector<tfilledregioninf>;</tfilledregioninf></tfilledregioninf>
Toshihiro Shimizu 890ddd
			ImageUtils::getFillingInformationOverlappingArea(vi, *fillInformation, strokeRef->getBBox());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			VIStroke *oldStroke = cloneVIStroke(vi->getVIStroke(strokeIndex));
Toshihiro Shimizu 890ddd
			bool isSelfLoop = vi->getStroke(strokeIndex)->isSelfLoop();
Toshihiro Shimizu 890ddd
			vi->splitStroke(strokeIndex, *sortedWRanges);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TUndo *nundo;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TXshSimpleLevel *sl = TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
Toshihiro Shimizu 890ddd
			assert(sl);
Toshihiro Shimizu 890ddd
			TFrameId id = getCurrentFid();
Toshihiro Shimizu 890ddd
			if (isSelfLoop || sortedWRanges->size() == 1) {
Toshihiro Shimizu 890ddd
				nundo = new UndoCutter(sl, id, oldStroke, strokeIndex, vi->getStroke(strokeIndex)->getId(), -1, fillInformation, sortedWRanges);
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				assert(strokeIndex + 1 < vi->getStrokeCount());
Toshihiro Shimizu 890ddd
				nundo = new UndoCutter(sl, id, oldStroke, strokeIndex, vi->getStroke(strokeIndex)->getId(), vi->getStroke(strokeIndex + 1)->getId(), fillInformation, sortedWRanges);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TUndoManager::manager()->add(nundo);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			invalidate();
Toshihiro Shimizu 890ddd
			notifyImageChanged();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		invalidate();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void mouseMove(const TPointD &pos, const TMouseEvent &e)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TVectorImageP vi = TImageP(getImage(true));
Toshihiro Shimizu 890ddd
		if (!vi) {
Toshihiro Shimizu 890ddd
			m_speed = TPointD(0, 0);
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// select nearest stroke and finds its parameter
Toshihiro Shimizu 890ddd
		double dist, pW;
Toshihiro Shimizu 890ddd
		UINT stroke;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (vi->getNearestStroke(pos, pW, stroke, dist)) {
Toshihiro Shimizu 890ddd
			TStroke *strokeRef = vi->getStroke(stroke);
Toshihiro Shimizu 890ddd
			m_speed = strokeRef->getSpeed(pW);
Toshihiro Shimizu 890ddd
			m_cursor = strokeRef->getThickPoint(pW);
Toshihiro Shimizu 890ddd
			m_pW = pW;
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			m_speed = TPointD(0, 0);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		invalidate();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void onLeave()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_speed = TPointD(0, 0);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void onActivate()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void onEnter()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if ((TVectorImageP)getImage(false))
Toshihiro Shimizu 890ddd
			m_cursorId = ToolCursor::CutterCursor;
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			m_cursorId = ToolCursor::CURSOR_NO;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int getCursorId() const { return m_cursorId; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} cutterTool;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
} // namespace
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//TTool *getCutterTool() {return &cutterTool;}