Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tools/tool.h"
Toshihiro Shimizu 890ddd
#include "tools/toolutils.h"
Toshihiro Shimizu 890ddd
#include "tools/cursors.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tstrokeutil.h"
Toshihiro Shimizu 890ddd
#include "tmathutil.h"
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/tobjecthandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshlevelhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobject.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
#include "tcolorstyles.h"
Toshihiro Shimizu 890ddd
#include "tsimplecolorstyles.h"
Toshihiro Shimizu 890ddd
#include "tstrokeoutline.h"
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace ToolUtils;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const int MY_ERROR = -1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// Iron
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// index must be between 0 and controlPointCount-1
Toshihiro Shimizu 890ddd
inline bool isIncluded(int index, int left, int rigth)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (left < rigth) {
Toshihiro Shimizu 890ddd
		return left <= index && index <= rigth;
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		return left <= index || index <= rigth;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// IronTool
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class IronTool : public TTool
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TStroke *m_strokeRef, *m_oldStroke;
Toshihiro Shimizu 890ddd
	TUndo *m_undo;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	DoublePair m_range;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool m_draw;
Toshihiro Shimizu 890ddd
	bool m_dragged;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TThickPoint m_cursor;
Toshihiro Shimizu 890ddd
	int m_selectedStroke;
Toshihiro Shimizu 890ddd
	TPointD m_beginPoint;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int m_cpIndexMin, m_cpIndexMax;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool m_active;
Toshihiro Shimizu 890ddd
	int m_cursorId;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	IronTool()
Toshihiro Shimizu 890ddd
		: TTool("T_Iron"), m_strokeRef(0), m_draw(false), m_active(false), m_dragged(false), m_undo(0), m_cpIndexMin(-1), m_cpIndexMax(-1), m_oldStroke(0), m_cursorId(ToolCursor::IronCursor)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		bind(TTool::Vectors);
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
		if (m_draw && (TVectorImageP)getImage(false)) {
Toshihiro Shimizu 890ddd
			glColor3d(1, 0, 1);
Toshihiro Shimizu 890ddd
			if (m_cursor.thick > 0)
Toshihiro Shimizu 890ddd
				tglDrawCircle(m_cursor, m_cursor.thick);
Toshihiro Shimizu 890ddd
			tglDrawCircle(m_cursor, m_cursor.thick + 4 * getPixelSize());
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void leftButtonDown(const TPointD &pos, const TMouseEvent &)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (m_active)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		assert(m_undo == 0);
Toshihiro Shimizu 890ddd
		m_active = false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TVectorImageP vi = TImageP(getImage(true));
Toshihiro Shimizu 890ddd
		if (!vi)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// select nearest stroke and finds its parameter
Toshihiro Shimizu 890ddd
		double dist;
Toshihiro Shimizu 890ddd
		UINT stroke;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!vi->getNearestStroke(pos, m_range.first, stroke, dist)) {
Toshihiro Shimizu 890ddd
			m_strokeRef = 0;
Toshihiro Shimizu 890ddd
			m_selectedStroke = MY_ERROR;
Toshihiro Shimizu 890ddd
			m_draw = false;
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			m_draw = true;
Toshihiro Shimizu 890ddd
			m_active = true;
Toshihiro Shimizu 890ddd
			m_strokeRef = vi->getStroke(stroke);
Toshihiro Shimizu 890ddd
			m_selectedStroke = stroke;
Toshihiro Shimizu 890ddd
			m_beginPoint = m_strokeRef->getPoint(m_range.first);
Toshihiro Shimizu 890ddd
			m_oldStroke = new TStroke(*vi->getStroke(stroke));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_range.second = m_range.first;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (TTool::getApplication()->getCurrentObject()->isSpline())
Toshihiro Shimizu 890ddd
				m_undo = new UndoPath(getXsheet()->getStageObject(getObjectId())->getSpline());
Toshihiro Shimizu 890ddd
			else {
Toshihiro Shimizu 890ddd
				TXshSimpleLevel *sl = TTool::getApplication()->getCurrentLevel()->getSimpleLevel();
Toshihiro Shimizu 890ddd
				assert(sl);
Toshihiro Shimizu 890ddd
				TFrameId id = getCurrentFid();
Toshihiro Shimizu 890ddd
				m_undo = new UndoModifyStrokeAndPaint(sl, id, stroke);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_strokeRef)
Toshihiro Shimizu 890ddd
			m_cpIndexMin = m_strokeRef->getControlPointCount();
Toshihiro Shimizu 890ddd
		m_cpIndexMax = -1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		invalidate();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void leftButtonDrag(const TPointD &pos, const TMouseEvent &e)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TVectorImageP vi(getImage(true));
Toshihiro Shimizu 890ddd
		if (!m_active || !vi || !m_strokeRef) {
Toshihiro Shimizu 890ddd
			delete m_undo;
Toshihiro Shimizu 890ddd
			m_undo = 0;
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_range.second = m_strokeRef->getW(pos);
Toshihiro Shimizu 890ddd
		m_cursor = m_strokeRef->getThickPoint(m_range.second);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double v0 = tmin(m_range.first, m_range.second);
Toshihiro Shimizu 890ddd
		double v1 = tmax(m_range.first, m_range.second);
Toshihiro Shimizu 890ddd
		const double eps = 0.005;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (v1 - v0 < eps && !(m_strokeRef->isSelfLoop() && 1 - (v1 - v0) < eps)) {
Toshihiro Shimizu 890ddd
			invalidate();
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TPointD point2 = m_strokeRef->getPoint(m_range.second);
Toshihiro Shimizu 890ddd
		double tdist2 = tdistance2(m_beginPoint, point2);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double pixelSize = getPixelSize();
Toshihiro Shimizu 890ddd
		if (tdist2 < 100 * pixelSize * pixelSize) {
Toshihiro Shimizu 890ddd
			invalidate();
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double draggedStrokeLen = m_strokeRef->getLength(v0, v1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double totalStrokeLen = m_strokeRef->getLength();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool direction = !m_strokeRef->isSelfLoop() ||
Toshihiro Shimizu 890ddd
						 draggedStrokeLen < totalStrokeLen - draggedStrokeLen;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!direction) {
Toshihiro Shimizu 890ddd
			draggedStrokeLen = totalStrokeLen - draggedStrokeLen;
Toshihiro Shimizu 890ddd
			tswap(v0, v1);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// se la lunghezza della parte di stroke tra i due punti di inizio e fine drag
Toshihiro Shimizu 890ddd
		// e' piu' del quadruplo della distanza tra i due punti, allora non si fa nulla perche'
Toshihiro Shimizu 890ddd
		// molto probabilmente si sta facendo drag tra due punti vicini di una curva piu' lunga
Toshihiro Shimizu 890ddd
		if ((draggedStrokeLen * draggedStrokeLen) > 16.0 * tdist2) {
Toshihiro Shimizu 890ddd
			m_beginPoint = point2;
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int i;
Toshihiro Shimizu 890ddd
		int maxCP = m_strokeRef->getControlPointCount() - 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//iCP0 is the control point index before v0 (or just on v0)
Toshihiro Shimizu 890ddd
		int iCP0 = (int)(maxCP * v0);
Toshihiro Shimizu 890ddd
		int iCP1 = m_strokeRef->getControlPointIndexAfterParameter(v1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (iCP0 > maxCP) {
Toshihiro Shimizu 890ddd
			if (!direction)
Toshihiro Shimizu 890ddd
				iCP0 = maxCP;
Toshihiro Shimizu 890ddd
			else {
Toshihiro Shimizu 890ddd
				invalidate();
Toshihiro Shimizu 890ddd
				return;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (iCP1 > maxCP)
Toshihiro Shimizu 890ddd
			iCP1 = maxCP;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (direction && (iCP1 - iCP0) < 2) {
Toshihiro Shimizu 890ddd
			invalidate();
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!direction && maxCP + 1 - (iCP1 - iCP0) < 3) {
Toshihiro Shimizu 890ddd
			invalidate();
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//*********************************************** point of no return **************************
Toshihiro Shimizu 890ddd
		m_dragged = true;
Toshihiro Shimizu 890ddd
		m_beginPoint = point2;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!m_strokeRef->isSelfLoop()) {
Toshihiro Shimizu 890ddd
			if (m_cpIndexMin > iCP0)
Toshihiro Shimizu 890ddd
				m_cpIndexMin = iCP0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (m_cpIndexMax < iCP1)
Toshihiro Shimizu 890ddd
				m_cpIndexMax = iCP1;
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			if (m_cpIndexMin == m_strokeRef->getControlPointCount() && m_cpIndexMax == -1) {
Toshihiro Shimizu 890ddd
				m_cpIndexMin = iCP0;
Toshihiro Shimizu 890ddd
				m_cpIndexMax = iCP1;
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				if (isIncluded(iCP0, m_cpIndexMin, m_cpIndexMax)) {
Toshihiro Shimizu 890ddd
					if (!isIncluded(iCP1, m_cpIndexMin, m_cpIndexMax)) {
Toshihiro Shimizu 890ddd
						m_cpIndexMax = iCP1;
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				} else if (isIncluded(iCP1, m_cpIndexMin, m_cpIndexMax)) {
Toshihiro Shimizu 890ddd
					assert(!isIncluded(iCP0, m_cpIndexMin, m_cpIndexMax));
Toshihiro Shimizu 890ddd
					m_cpIndexMin = iCP0;
Toshihiro Shimizu 890ddd
				} else {
Toshihiro Shimizu 890ddd
					int sgn = tsign(m_range.second - m_range.first);
Toshihiro Shimizu 890ddd
					if (!direction)
Toshihiro Shimizu 890ddd
						sgn = -sgn;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					switch (sgn) {
Toshihiro Shimizu 890ddd
					case 1:
Toshihiro Shimizu 890ddd
						m_cpIndexMax = iCP1;
Toshihiro Shimizu 890ddd
						break;
Toshihiro Shimizu 890ddd
					case -1:
Toshihiro Shimizu 890ddd
						m_cpIndexMin = iCP0;
Toshihiro Shimizu 890ddd
						break;
Toshihiro Shimizu 890ddd
					case 0:
Toshihiro Shimizu 890ddd
						assert(0);
Toshihiro Shimizu 890ddd
					default:
Toshihiro Shimizu 890ddd
						assert(0);
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_range.first = m_range.second;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		assert(m_cpIndexMin != m_cpIndexMax);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		v0 = m_strokeRef->getParameterAtControlPoint(iCP0);
Toshihiro Shimizu 890ddd
		v1 = m_strokeRef->getParameterAtControlPoint(iCP1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//double smoothFactor = getApplication()->getVectorToolsParameters().getToolSize();
Toshihiro Shimizu 890ddd
		//smoothFactor *= 0.01;
Toshihiro Shimizu 890ddd
		//smoothFactor = (smoothFactor*smoothFactor*smoothFactor)*0.7;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const double smoothFactor = 0.08;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double wDistance = (direction) ? v1 - v0 : 1 - (v0 - v1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double smoothFP = smoothFactor / wDistance;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TPointD pf0 = m_strokeRef->getControlPoint(iCP0) * smoothFP;
Toshihiro Shimizu 890ddd
		TPointD pf1 = m_strokeRef->getControlPoint(iCP1) * smoothFP;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TPointD appDPoint;
Toshihiro Shimizu 890ddd
		TThickPoint appThickPoint;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double oppSmoothFactor = 1.0 - smoothFactor;
Toshihiro Shimizu 890ddd
		double vp, v1vp, vpv0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		i = (iCP0 == maxCP || (iCP0 == 0 && !direction)) ? 1 : iCP0 + 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (; i != iCP1;) {
Toshihiro Shimizu 890ddd
			vp = m_strokeRef->getParameterAtControlPoint(i);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			appThickPoint = m_strokeRef->getControlPoint(i);
Toshihiro Shimizu 890ddd
			appDPoint = appThickPoint;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			v1vp = v1 - vp;
Toshihiro Shimizu 890ddd
			if (v1vp < 0) {
Toshihiro Shimizu 890ddd
				if (!direction)
Toshihiro Shimizu 890ddd
					v1vp += 1;
Toshihiro Shimizu 890ddd
				else
Toshihiro Shimizu 890ddd
					assert(0);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			vpv0 = vp - v0;
Toshihiro Shimizu 890ddd
			if (vpv0 < 0) {
Toshihiro Shimizu 890ddd
				if (!direction)
Toshihiro Shimizu 890ddd
					vpv0 += 1;
Toshihiro Shimizu 890ddd
				else
Toshihiro Shimizu 890ddd
					assert(0);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			assert(isAlmostZero(v1vp + vpv0 - wDistance));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			assert(isAlmostZero((smoothFP * v1vp + smoothFP * vpv0) + oppSmoothFactor - 1.0));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_strokeRef->setControlPoint(i, TThickPoint(
Toshihiro Shimizu 890ddd
												pf0 * v1vp +
Toshihiro Shimizu 890ddd
													pf1 * vpv0 +
Toshihiro Shimizu 890ddd
													appDPoint * oppSmoothFactor,
Toshihiro Shimizu 890ddd
												appThickPoint.thick));
Toshihiro Shimizu 890ddd
			// this is like
Toshihiro Shimizu 890ddd
			//
Toshihiro Shimizu 890ddd
			// averageP = ( p0*(v1-vp)/(v1-v0) + p1*(vp-v0)/(v1-v0));
Toshihiro Shimizu 890ddd
			// newCP(i) = oldCP(i)*(1-smoothFactor) + averageP*smoothFactor
Toshihiro Shimizu 890ddd
			//
Toshihiro Shimizu 890ddd
			// but faster
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			i++;
Toshihiro Shimizu 890ddd
			if (i == maxCP + 1) {
Toshihiro Shimizu 890ddd
				m_strokeRef->setControlPoint(0, m_strokeRef->getControlPoint(maxCP));
Toshihiro Shimizu 890ddd
				i = 1;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_strokeRef->invalidate();
Toshihiro Shimizu 890ddd
		invalidate();
Toshihiro Shimizu 890ddd
		notifyImageChanged();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void leftButtonUp(const TPointD &pos, const TMouseEvent &)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (!m_active)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_active = false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		invalidate();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TVectorImageP vi(getImage(true));
Toshihiro Shimizu 890ddd
		if (!vi || !m_strokeRef || !m_dragged) {
Toshihiro Shimizu 890ddd
			delete m_undo;
Toshihiro Shimizu 890ddd
			m_undo = 0;
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		QMutexLocker lock(vi->getMutex());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//TStroke *oldStroke = new TStroke(*(vi->getStroke(m_selectedStroke)));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		UINT cpCount = m_strokeRef->getControlPointCount();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_cpIndexMin &= ~1; // nearest even value less or equal to m_cpIndexMin
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_cpIndexMax & 1) //odd
Toshihiro Shimizu 890ddd
			m_cpIndexMax++;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int i = 0;
Toshihiro Shimizu 890ddd
		UINT count = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if ((m_cpIndexMin == 0 && (UINT)m_cpIndexMax == cpCount - 1) ||
Toshihiro Shimizu 890ddd
			(m_cpIndexMin == m_cpIndexMax && m_strokeRef->isSelfLoop())) {
Toshihiro Shimizu 890ddd
			/*
Toshihiro Shimizu 890ddd
      e' meglio rilevarli i corners.
Toshihiro Shimizu 890ddd
      Tanto se hai appiattito abbastanza, se ne vanno da soli,
Toshihiro Shimizu 890ddd
      senza lasciare ingrati compiti alla reuceControlPoints
Toshihiro Shimizu 890ddd
      Altrimenti non si fa altro che aumentarli i punti di controllo
Toshihiro Shimizu 890ddd
      */
Toshihiro Shimizu 890ddd
			vector<int> corners;</int>
Toshihiro Shimizu 890ddd
			corners.push_back(0);
Toshihiro Shimizu 890ddd
			detectCorners(m_strokeRef, 45, corners);
Toshihiro Shimizu 890ddd
			corners.push_back(m_strokeRef->getChunkCount());
Toshihiro Shimizu 890ddd
			m_strokeRef->reduceControlPoints(2.0 * getPixelSize(), corners);
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			if (m_cpIndexMin < m_cpIndexMax) {
Toshihiro Shimizu 890ddd
				vector<tthickpoint> hitPoints(m_cpIndexMax - m_cpIndexMin + 1);</tthickpoint>
Toshihiro Shimizu 890ddd
				count = 0;
Toshihiro Shimizu 890ddd
				for (i = m_cpIndexMin; i <= m_cpIndexMax; i++) {
Toshihiro Shimizu 890ddd
					hitPoints[count++] = m_strokeRef->getControlPoint(i);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
				TStroke *newStroke = new TStroke(hitPoints);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				vector<int> corners;</int>
Toshihiro Shimizu 890ddd
				corners.push_back(0);
Toshihiro Shimizu 890ddd
				detectCorners(newStroke, 45, corners);
Toshihiro Shimizu 890ddd
				corners.push_back(newStroke->getChunkCount());
Toshihiro Shimizu 890ddd
				newStroke->reduceControlPoints(2.0 * getPixelSize(), corners);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				hitPoints.resize(m_cpIndexMin + newStroke->getControlPointCount() + cpCount - 1 - m_cpIndexMax);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				count = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				for (i = 0; i < m_cpIndexMin; i++) {
Toshihiro Shimizu 890ddd
					hitPoints[count++] = m_strokeRef->getControlPoint(i);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				for (i = 0; i < newStroke->getControlPointCount(); i++) {
Toshihiro Shimizu 890ddd
					hitPoints[count++] = newStroke->getControlPoint(i);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				for (i = m_cpIndexMax + 1; i < (int)cpCount; i++) {
Toshihiro Shimizu 890ddd
					hitPoints[count++] = m_strokeRef->getControlPoint(i);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				m_strokeRef->reshape(&hitPoints[0], hitPoints.size());
Toshihiro Shimizu 890ddd
				delete newStroke;
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				assert(m_cpIndexMin != m_cpIndexMax);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				vector<tthickpoint> hitPoints(cpCount - m_cpIndexMin);</tthickpoint>
Toshihiro Shimizu 890ddd
				count = 0;
Toshihiro Shimizu 890ddd
				for (i = m_cpIndexMin; i < (int)cpCount; i++) {
Toshihiro Shimizu 890ddd
					hitPoints[count++] = m_strokeRef->getControlPoint(i);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
				TStroke *newStroke1 = new TStroke(hitPoints);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				vector<int> corners;</int>
Toshihiro Shimizu 890ddd
				corners.push_back(0);
Toshihiro Shimizu 890ddd
				detectCorners(newStroke1, 45, corners);
Toshihiro Shimizu 890ddd
				corners.push_back(newStroke1->getChunkCount());
Toshihiro Shimizu 890ddd
				newStroke1->reduceControlPoints(2.0 * getPixelSize(), corners);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				hitPoints.resize(m_cpIndexMax + 1);
Toshihiro Shimizu 890ddd
				count = 0;
Toshihiro Shimizu 890ddd
				for (i = 0; i <= m_cpIndexMax; i++) {
Toshihiro Shimizu 890ddd
					hitPoints[count++] = m_strokeRef->getControlPoint(i);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
				TStroke *newStroke2 = new TStroke(hitPoints);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				corners.clear();
Toshihiro Shimizu 890ddd
				corners.push_back(0);
Toshihiro Shimizu 890ddd
				detectCorners(newStroke2, 45, corners);
Toshihiro Shimizu 890ddd
				corners.push_back(newStroke2->getChunkCount());
Toshihiro Shimizu 890ddd
				newStroke2->reduceControlPoints(2.0 * getPixelSize(), corners);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				hitPoints.resize(
Toshihiro Shimizu 890ddd
					newStroke1->getControlPointCount() +
Toshihiro Shimizu 890ddd
					newStroke2->getControlPointCount() +
Toshihiro Shimizu 890ddd
					m_cpIndexMin - m_cpIndexMax - 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				count = 0;
Toshihiro Shimizu 890ddd
				for (i = 0; i < newStroke2->getControlPointCount(); i++) {
Toshihiro Shimizu 890ddd
					hitPoints[count++] = newStroke2->getControlPoint(i);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
				for (i = m_cpIndexMax + 1; i < m_cpIndexMin; i++) {
Toshihiro Shimizu 890ddd
					hitPoints[count++] = m_strokeRef->getControlPoint(i);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
				for (i = 0; i < newStroke1->getControlPointCount(); i++) {
Toshihiro Shimizu 890ddd
					hitPoints[count++] = newStroke1->getControlPoint(i);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				m_strokeRef->reshape(&hitPoints[0], hitPoints.size());
Toshihiro Shimizu 890ddd
				delete newStroke1;
Toshihiro Shimizu 890ddd
				delete newStroke2;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		invalidate();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_dragged = false;
Toshihiro Shimizu 890ddd
		assert(m_undo);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		assert(m_oldStroke);
Toshihiro Shimizu 890ddd
		vi->notifyChangedStrokes(m_selectedStroke, m_oldStroke);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TUndoManager::manager()->add(m_undo);
Toshihiro Shimizu 890ddd
		m_undo = 0;
Toshihiro Shimizu 890ddd
		delete m_oldStroke;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void invalidateCursorArea()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		double r = m_cursor.thick + 6;
Toshihiro Shimizu 890ddd
		TPointD d(r, r);
Toshihiro Shimizu 890ddd
		invalidate(TRectD(m_cursor - d, m_cursor + d));
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_draw = false;
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
			m_draw = true;
Toshihiro Shimizu 890ddd
			TStroke *strokeRef = vi->getStroke(stroke);
Toshihiro Shimizu 890ddd
			m_cursor = strokeRef->getThickPoint(pW);
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			m_draw = false;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		invalidate();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool moveCursor(const TPointD &pos)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void onActivate()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		//      getApplication()->editImageOrSpline();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void onLeave()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_draw = false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int getCursorId() const { return m_cursorId; }
Toshihiro Shimizu 890ddd
	void onEnter()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_draw = true;
Toshihiro Shimizu 890ddd
		if ((TVectorImageP)getImage(false))
Toshihiro Shimizu 890ddd
			m_cursorId = ToolCursor::IronCursor;
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			m_cursorId = ToolCursor::CURSOR_NO;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} ironTool;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void drawPoint(const TPointD &p, double pixelSize)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double sizeX = pixelSize;
Toshihiro Shimizu 890ddd
	double sizeY = pixelSize;
Toshihiro Shimizu 890ddd
	glBegin(GL_QUADS);
Toshihiro Shimizu 890ddd
	glVertex2d(p.x - sizeX, p.y - sizeY);
Toshihiro Shimizu 890ddd
	glVertex2d(p.x - sizeX, p.y + sizeY);
Toshihiro Shimizu 890ddd
	glVertex2d(p.x + sizeX, p.y + sizeY);
Toshihiro Shimizu 890ddd
	glVertex2d(p.x + sizeX, p.y - sizeY);
Toshihiro Shimizu 890ddd
	glEnd();
Toshihiro Shimizu 890ddd
	return;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void drawControlPoints(const TStroke *&stroke, double pixelSize)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int n = stroke->getChunkCount();
Toshihiro Shimizu 890ddd
	int i = 0;
Toshihiro Shimizu 890ddd
	for (i = 0; i < n; ++i) {
Toshihiro Shimizu 890ddd
		const TThickQuadratic *chunk = stroke->getChunk(i);
Toshihiro Shimizu 890ddd
		TPointD p0 = chunk->getP0();
Toshihiro Shimizu 890ddd
		TPointD p1 = chunk->getP1();
Toshihiro Shimizu 890ddd
		glColor3d(1.0, 0.0, 0.0);
Toshihiro Shimizu 890ddd
		drawPoint(p0, pixelSize);
Toshihiro Shimizu 890ddd
		glColor3d(1.0, 1.0, 1.0);
Toshihiro Shimizu 890ddd
		drawPoint(p1, pixelSize);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	const TThickQuadratic *chunk = stroke->getChunk(n - 1);
Toshihiro Shimizu 890ddd
	glColor3d(1.0, 0.0, 0.0);
Toshihiro Shimizu 890ddd
	TPointD p2 = chunk->getP2();
Toshihiro Shimizu 890ddd
	drawPoint(p2, pixelSize);
Toshihiro Shimizu 890ddd
	return;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
// end solo per debug
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//TTool *getIronTool() {return &ironTool;}