Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "controlpointselection.h"
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "tmathutil.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tools/toolhandle.h"
Toshihiro Shimizu 890ddd
#include "tools/toolutils.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
using namespace ToolUtils;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool isLinearPoint(const TPointD &p0, const TPointD &p1, const TPointD &p2)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return (tdistance(p0, p1) < 0.02) && (tdistance(p1, p2) < 0.02);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Ritorna \b true se il punto \b p1 e' una cuspide.
Toshihiro Shimizu 890ddd
bool isCuspPoint(const TPointD &p0, const TPointD &p1, const TPointD &p2)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TPointD p0_p1(p0 - p1), p2_p1(p2 - p1);
Toshihiro Shimizu 890ddd
	double n1 = norm(p0_p1), n2 = norm(p2_p1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Partial linear points are ALWAYS cusps (since directions from them are
Toshihiro Shimizu 890ddd
	//determined by neighbours, not by the points themselves)
Toshihiro Shimizu 890ddd
	if ((n1 < 0.02) || (n2 < 0.02))
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	p0_p1 = p0_p1 * (1.0 / n1);
Toshihiro Shimizu 890ddd
	p2_p1 = p2_p1 * (1.0 / n2);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return (p0_p1 * p2_p1 > 0) || (fabs(cross(p0_p1, p2_p1)) > 0.09); //more than 5° is yes
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Distance-based check. Unscalable...
Toshihiro Shimizu 890ddd
	//return !areAlmostEqual(tdistance(p0,p2),tdistance(p0,p1)+tdistance(p1,p2),2);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TThickPoint computeLinearPoint(const TThickPoint &p1, const TThickPoint &p2, double factor, bool isIn)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TThickPoint p = p2 - p1;
Toshihiro Shimizu 890ddd
	TThickPoint v = p * (1 / norm(p));
Toshihiro Shimizu 890ddd
	if (isIn)
Toshihiro Shimizu 890ddd
		return p2 - factor * v;
Toshihiro Shimizu 890ddd
	return p1 + factor * v;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
/*! Insert a point in the most long chunk between chunk \b indexA and chunk \b indexB. */
Toshihiro Shimizu 890ddd
void insertPoint(TStroke *stroke, int indexA, int indexB)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(stroke);
Toshihiro Shimizu 890ddd
	int j = 0;
Toshihiro Shimizu 890ddd
	int chunkCount = indexB - indexA;
Toshihiro Shimizu 890ddd
	if (chunkCount % 2 == 0)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	double length = 0;
Toshihiro Shimizu 890ddd
	double firstW, lastW;
Toshihiro Shimizu 890ddd
	for (j = indexA; j < indexB; j++) {
Toshihiro Shimizu 890ddd
		//cerco il chunk piu' lungo
Toshihiro Shimizu 890ddd
		double w0 = stroke->getW(stroke->getChunk(j)->getP0());
Toshihiro Shimizu 890ddd
		double w1;
Toshihiro Shimizu 890ddd
		if (j == stroke->getChunkCount() - 1)
Toshihiro Shimizu 890ddd
			w1 = 1;
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			w1 = stroke->getW(stroke->getChunk(j)->getP2());
Toshihiro Shimizu 890ddd
		double length0 = stroke->getLength(w0);
Toshihiro Shimizu 890ddd
		double length1 = stroke->getLength(w1);
Toshihiro Shimizu 890ddd
		if (length < length1 - length0) {
Toshihiro Shimizu 890ddd
			firstW = w0;
Toshihiro Shimizu 890ddd
			lastW = w1;
Toshihiro Shimizu 890ddd
			length = length1 - length0;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	stroke->insertControlPoints((firstW + lastW) * 0.5);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} //namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// ControlPointEditorStroke
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ControlPointEditorStroke *ControlPointEditorStroke::clone() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	ControlPointEditorStroke *controlPointEditorStroke = new ControlPointEditorStroke();
Toshihiro Shimizu 890ddd
	controlPointEditorStroke->setStroke(m_vi->clone(), m_strokeIndex);
Toshihiro Shimizu 890ddd
	return controlPointEditorStroke;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int ControlPointEditorStroke::nextIndex(int index) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int cpCount = m_controlPoints.size();
Toshihiro Shimizu 890ddd
	if (++index < cpCount)
Toshihiro Shimizu 890ddd
		return index;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (isSelfLoop()) {
Toshihiro Shimizu 890ddd
		index %= cpCount;
Toshihiro Shimizu 890ddd
		return (index < 0) ? index + cpCount : index;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return -1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int ControlPointEditorStroke::prevIndex(int index) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int cpCount = m_controlPoints.size();
Toshihiro Shimizu 890ddd
	if (--index >= 0)
Toshihiro Shimizu 890ddd
		return index;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (isSelfLoop()) {
Toshihiro Shimizu 890ddd
		index %= cpCount;
Toshihiro Shimizu 890ddd
		return (index < 0) ? index + cpCount : index;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return -1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::adjustChunkParity()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	int firstChunk;
Toshihiro Shimizu 890ddd
	int secondChunk = stroke->getChunkCount();
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = stroke->getChunkCount() - 1; i > 0; i--) {
Toshihiro Shimizu 890ddd
		if (tdistance(stroke->getChunk(i - 1)->getP0(), stroke->getChunk(i)->getP2()) < 0.5)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		TPointD p0 = stroke->getChunk(i - 1)->getP1();
Toshihiro Shimizu 890ddd
		TPointD p1 = stroke->getChunk(i - 1)->getP2();
Toshihiro Shimizu 890ddd
		TPointD p2 = stroke->getChunk(i)->getP1();
Toshihiro Shimizu 890ddd
		if (isCuspPoint(p0, p1, p2) || isLinearPoint(p0, p1, p2)) {
Toshihiro Shimizu 890ddd
			firstChunk = i;
Toshihiro Shimizu 890ddd
			insertPoint(stroke, firstChunk, secondChunk);
Toshihiro Shimizu 890ddd
			secondChunk = firstChunk;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	insertPoint(stroke, 0, secondChunk);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::resetControlPoints()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	m_controlPoints.clear();
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	int cpCount = stroke->getControlPointCount();
Toshihiro Shimizu 890ddd
	if (cpCount == 3) {
Toshihiro Shimizu 890ddd
		const TThickQuadratic *chunk = stroke->getChunk(0);
Toshihiro Shimizu 890ddd
		if (chunk->getP0() == chunk->getP1() && chunk->getP0() == chunk->getP2()) //E' un punto
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			m_controlPoints.push_back(ControlPoint(0, TPointD(0.0, 0.0), TPointD(0.0, 0.0), true));
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	for (i = 0; i < cpCount; i = i + 4) {
Toshihiro Shimizu 890ddd
		TThickPoint speedIn, speedOut;
Toshihiro Shimizu 890ddd
		bool isPickOut = false;
Toshihiro Shimizu 890ddd
		TThickPoint p = stroke->getControlPoint(i);
Toshihiro Shimizu 890ddd
		TThickPoint precP = stroke->getControlPoint(i - 1);
Toshihiro Shimizu 890ddd
		TThickPoint nextP = stroke->getControlPoint(i + 1);
Toshihiro Shimizu 890ddd
		if (0 < i && i < cpCount - 1) //calcola speedIn e speedOut
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			speedIn = p - precP;
Toshihiro Shimizu 890ddd
			speedOut = nextP - p;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		if (i == 0) //calcola solo lo speedOut
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			speedOut = nextP - p;
Toshihiro Shimizu 890ddd
			if (isSelfLoop())
Toshihiro Shimizu 890ddd
				speedIn = p - stroke->getControlPoint(cpCount - 2);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		if (i == cpCount - 1) //calcola solo lo speedIn
Toshihiro Shimizu 890ddd
			speedIn = p - precP;
Toshihiro Shimizu 890ddd
		if (i == cpCount - 1 && isSelfLoop())
Toshihiro Shimizu 890ddd
			break; // Se lo stroke e' selfLoop inserisco solo il primo dei due punti coincidenti
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool isCusp = ((i != 0 && i != cpCount - 1) || (isSelfLoop() && i == 0)) ? isCuspPoint(precP, p, nextP) : true;
Toshihiro Shimizu 890ddd
		m_controlPoints.push_back(ControlPoint(i, speedIn, speedOut, isCusp));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TThickPoint ControlPointEditorStroke::getPureDependentPoint(int index) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return TThickPoint();
Toshihiro Shimizu 890ddd
	bool selfLoop = isSelfLoop();
Toshihiro Shimizu 890ddd
	int cpCount = selfLoop ? m_controlPoints.size() + 1 : m_controlPoints.size();
Toshihiro Shimizu 890ddd
	int nextIndex = (selfLoop && index == cpCount - 2) ? 0 : index + 1;
Toshihiro Shimizu 890ddd
	int pointIndex = m_controlPoints[index].m_pointIndex;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TThickPoint oldP(stroke->getControlPoint(pointIndex + 2));
Toshihiro Shimizu 890ddd
	TPointD oldSpeedOutP = stroke->getControlPoint(pointIndex + 1);
Toshihiro Shimizu 890ddd
	TPointD oldSpeedInP = stroke->getControlPoint(pointIndex + 3);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double dist = tdistance(oldSpeedOutP, oldSpeedInP);
Toshihiro Shimizu 890ddd
	double t = (dist > 1e-4) ? tdistance(oldSpeedInP, convert(oldP)) / dist : 0.5;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD speedOutPoint(getSpeedOutPoint(index));
Toshihiro Shimizu 890ddd
	TPointD nextSpeedInPoint(getSpeedInPoint(nextIndex));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return TThickPoint((1 - t) * nextSpeedInPoint + t * speedOutPoint, oldP.thick);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//return TThickPoint(0.5 * (speedOutPoint + nextSpeedInPoint), oldThick);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::getDependentPoints(
Toshihiro Shimizu 890ddd
	int index, std::vector<std::pair<int, tthickpoint="">> &points) const</std::pair<int,>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int cpCount = m_controlPoints.size();
Toshihiro Shimizu 890ddd
	if (index == cpCount && isSelfLoop()) //strange, but was treated...
Toshihiro Shimizu 890ddd
		index = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (index == 0 && cpCount == 1) {
Toshihiro Shimizu 890ddd
		//Single point case
Toshihiro Shimizu 890ddd
		TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
		TThickPoint pos(stroke->getControlPoint(m_controlPoints[0].m_pointIndex));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		points.push_back(std::make_pair(1, pos));
Toshihiro Shimizu 890ddd
		points.push_back(std::make_pair(2, pos));
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int prev = prevIndex(index);
Toshihiro Shimizu 890ddd
	if (prev >= 0) {
Toshihiro Shimizu 890ddd
		int prevPointIndex = m_controlPoints[prev].m_pointIndex;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (isSpeedOutLinear(prev))
Toshihiro Shimizu 890ddd
			points.push_back(std::make_pair(prevPointIndex + 1, getSpeedOutPoint(prev)));
Toshihiro Shimizu 890ddd
		points.push_back(std::make_pair(prevPointIndex + 2, getPureDependentPoint(prev)));
Toshihiro Shimizu 890ddd
		points.push_back(std::make_pair(prevPointIndex + 3, getSpeedInPoint(index)));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int next = nextIndex(index);
Toshihiro Shimizu 890ddd
	if (next >= 0) {
Toshihiro Shimizu 890ddd
		int pointIndex = m_controlPoints[index].m_pointIndex;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		points.push_back(std::make_pair(pointIndex + 1, getSpeedOutPoint(index)));
Toshihiro Shimizu 890ddd
		points.push_back(std::make_pair(pointIndex + 2, getPureDependentPoint(index)));
Toshihiro Shimizu 890ddd
		if (isSpeedInLinear(next))
Toshihiro Shimizu 890ddd
			points.push_back(std::make_pair(pointIndex + 3, getSpeedInPoint(next)));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::updatePoints()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	bool selfLoop = isSelfLoop();
Toshihiro Shimizu 890ddd
	//Se e' rimasto un unico punto non ha senso che la stroke sia selfloop
Toshihiro Shimizu 890ddd
	if (selfLoop && m_controlPoints.size() == 1) {
Toshihiro Shimizu 890ddd
		stroke->setSelfLoop(false);
Toshihiro Shimizu 890ddd
		selfLoop = false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Se e' self loop  devo aggiungere un punto in piu' al cpCount
Shinya Kitaoka 3bfa54
	std::vector<tthickpoint> points;</tthickpoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int cpCount = selfLoop ? m_controlPoints.size() + 1 : m_controlPoints.size();
Toshihiro Shimizu 890ddd
	if (cpCount == 1)
Toshihiro Shimizu 890ddd
		//Single point case
Toshihiro Shimizu 890ddd
		points.resize(3, getControlPoint(0));
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		std::vector<std::pair<int, tthickpoint="">> dependentPoints;</std::pair<int,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		points.push_back(getControlPoint(0));
Toshihiro Shimizu 890ddd
		points.push_back(getSpeedOutPoint(0));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int i, pointIndex, currPointIndex = m_controlPoints[0].m_pointIndex + 1;
Toshihiro Shimizu 890ddd
		for (i = 1; i < cpCount; ++i) {
Toshihiro Shimizu 890ddd
			bool isLastSelfLoopPoint = (selfLoop && i == cpCount - 1);
Toshihiro Shimizu 890ddd
			int index = isLastSelfLoopPoint ? 0 : i;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TThickPoint p = getControlPoint(index);
Toshihiro Shimizu 890ddd
			pointIndex = isLastSelfLoopPoint ? getStroke()->getControlPointCount() : m_controlPoints[index].m_pointIndex;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			dependentPoints.clear();
Toshihiro Shimizu 890ddd
			getDependentPoints(index, dependentPoints);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			int j;
Toshihiro Shimizu 890ddd
			for (j = 0; j < (int)dependentPoints.size() && dependentPoints[j].first < pointIndex; j++) {
Toshihiro Shimizu 890ddd
				if (currPointIndex < dependentPoints[j].first) {
Toshihiro Shimizu 890ddd
					currPointIndex = dependentPoints[j].first;
Toshihiro Shimizu 890ddd
					points.push_back(dependentPoints[j].second);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			points.push_back(p);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			for (; j < (int)dependentPoints.size(); j++) {
Toshihiro Shimizu 890ddd
				if (currPointIndex < dependentPoints[j].first) {
Toshihiro Shimizu 890ddd
					currPointIndex = dependentPoints[j].first;
Toshihiro Shimizu 890ddd
					points.push_back(dependentPoints[j].second);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	stroke->reshape(&points[0], points.size());
Toshihiro Shimizu 890ddd
	m_vi->notifyChangedStrokes(m_strokeIndex);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::updateDependentPoint(int index)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 3bfa54
	std::vector<std::pair<int, tthickpoint="">> points;</std::pair<int,>
Toshihiro Shimizu 890ddd
	getDependentPoints(index, points);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < (int)points.size(); i++)
Toshihiro Shimizu 890ddd
		stroke->setControlPoint(points[i].first, points[i].second);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_vi->notifyChangedStrokes(m_strokeIndex);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::moveSpeedOut(int index, const TPointD &delta, double minDistance)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//If the next cp has linear speed in, it must be recomputed
Toshihiro Shimizu 890ddd
	bool selfLoop = isSelfLoop();
Toshihiro Shimizu 890ddd
	int cpCount = selfLoop ? m_controlPoints.size() + 1 : m_controlPoints.size();
Toshihiro Shimizu 890ddd
	int nextIndex = (selfLoop && index == cpCount - 2) ? 0 : index + 1;
Toshihiro Shimizu 890ddd
	if (m_controlPoints[nextIndex].m_isCusp && isSpeedInLinear(nextIndex))
Toshihiro Shimizu 890ddd
		setLinearSpeedIn(nextIndex, true, false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Update the speedOut
Toshihiro Shimizu 890ddd
	m_controlPoints[index].m_speedOut += delta;
Toshihiro Shimizu 890ddd
	TPointD newP = m_controlPoints[index].m_speedOut;
Toshihiro Shimizu 890ddd
	if (areAlmostEqual(newP.x, 0, minDistance) && areAlmostEqual(newP.y, 0, minDistance)) //Setto a linear
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		setLinearSpeedOut(index);
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (!m_controlPoints[index].m_isCusp && !isSpeedInLinear(index)) {
Toshihiro Shimizu 890ddd
		//Devo ricalcolare lo SpeedIn
Toshihiro Shimizu 890ddd
		TPointD v(m_controlPoints[index].m_speedOut * (1.0 / norm(m_controlPoints[index].m_speedOut)));
Toshihiro Shimizu 890ddd
		m_controlPoints[index].m_speedIn = TThickPoint(
Toshihiro Shimizu 890ddd
			v * norm(m_controlPoints[index].m_speedIn),
Toshihiro Shimizu 890ddd
			m_controlPoints[index].m_speedIn.thick);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::moveSpeedIn(int index, const TPointD &delta, double minDistance)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//If the prev cp has linear speed out, it must be recomputed
Toshihiro Shimizu 890ddd
	bool selfLoop = isSelfLoop();
Toshihiro Shimizu 890ddd
	int cpCount = selfLoop ? m_controlPoints.size() + 1 : m_controlPoints.size();
Toshihiro Shimizu 890ddd
	int prevIndex = (selfLoop && index == 0) ? cpCount - 2 : index - 1;
Toshihiro Shimizu 890ddd
	if (m_controlPoints[prevIndex].m_isCusp && isSpeedOutLinear(prevIndex))
Toshihiro Shimizu 890ddd
		setLinearSpeedOut(prevIndex, true, false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Update the speedOut
Toshihiro Shimizu 890ddd
	m_controlPoints[index].m_speedIn -= delta;
Toshihiro Shimizu 890ddd
	TPointD newP = m_controlPoints[index].m_speedIn;
Toshihiro Shimizu 890ddd
	if (areAlmostEqual(newP.x, 0, minDistance) && areAlmostEqual(newP.y, 0, minDistance)) //Setto a linear
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		setLinearSpeedIn(index);
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (!m_controlPoints[index].m_isCusp && !isSpeedOutLinear(index)) {
Toshihiro Shimizu 890ddd
		//Devo ricalcolare lo SpeedOut
Toshihiro Shimizu 890ddd
		TPointD v(m_controlPoints[index].m_speedIn * (1.0 / norm(m_controlPoints[index].m_speedIn)));
Toshihiro Shimizu 890ddd
		m_controlPoints[index].m_speedOut = TThickPoint(
Toshihiro Shimizu 890ddd
			v * norm(m_controlPoints[index].m_speedOut),
Toshihiro Shimizu 890ddd
			m_controlPoints[index].m_speedOut.thick);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::moveSingleControlPoint(int index, const TPointD &delta)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int pointIndex = m_controlPoints[index].m_pointIndex;
Toshihiro Shimizu 890ddd
	assert(stroke && 0 <= pointIndex && pointIndex < stroke->getControlPointCount());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool selfLoop = isSelfLoop();
Toshihiro Shimizu 890ddd
	int cpCount = selfLoop ? m_controlPoints.size() + 1 : m_controlPoints.size();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TThickPoint p = stroke->getControlPoint(pointIndex);
Toshihiro Shimizu 890ddd
	p = TThickPoint(p + delta, p.thick);
Toshihiro Shimizu 890ddd
	stroke->setControlPoint(pointIndex, p);
Toshihiro Shimizu 890ddd
	if (pointIndex == 0 && selfLoop)
Toshihiro Shimizu 890ddd
		stroke->setControlPoint(stroke->getControlPointCount() - 1, p);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Directions must be recalculated in the linear cases
Toshihiro Shimizu 890ddd
	if ((selfLoop || index > 0) && isSpeedInLinear(index)) {
Toshihiro Shimizu 890ddd
		setLinearSpeedIn(index, true, false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Furthermore, if the NEIGHBOUR point is linear, it has to be
Toshihiro Shimizu 890ddd
		//recalculated too
Toshihiro Shimizu 890ddd
		int prevIndex = (selfLoop && index == 0) ? cpCount - 2 : index - 1;
Toshihiro Shimizu 890ddd
		if (m_controlPoints[prevIndex].m_isCusp && isSpeedOutLinear(prevIndex))
Toshihiro Shimizu 890ddd
			setLinearSpeedOut(prevIndex, true, false);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if ((selfLoop || index < cpCount - 1) && isSpeedOutLinear(index)) {
Toshihiro Shimizu 890ddd
		setLinearSpeedOut(index, true, false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int nextIndex = (selfLoop && index == cpCount - 2) ? 0 : index + 1;
Toshihiro Shimizu 890ddd
		if (m_controlPoints[nextIndex].m_isCusp && isSpeedInLinear(nextIndex))
Toshihiro Shimizu 890ddd
			setLinearSpeedIn(nextIndex, true, false);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::setStroke(const TVectorImageP &vi, int strokeIndex)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_strokeIndex = strokeIndex;
Toshihiro Shimizu 890ddd
	m_vi = vi;
Toshihiro Shimizu 890ddd
	if (!vi || strokeIndex == -1) {
Toshihiro Shimizu 890ddd
		m_controlPoints.clear();
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	const TThickQuadratic *chunk = stroke->getChunk(0);
Toshihiro Shimizu 890ddd
	if (stroke->getControlPointCount() == 3 && chunk->getP0() == chunk->getP1() && chunk->getP0() == chunk->getP2()) {
Toshihiro Shimizu 890ddd
		resetControlPoints();
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	adjustChunkParity();
Toshihiro Shimizu 890ddd
	resetControlPoints();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TThickPoint ControlPointEditorStroke::getControlPoint(int index) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	assert(stroke && 0 <= index && index < (int)m_controlPoints.size());
Toshihiro Shimizu 890ddd
	return stroke->getControlPoint(m_controlPoints[index].m_pointIndex);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int ControlPointEditorStroke::getIndexPointInStroke(int index) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_controlPoints[index].m_pointIndex;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TThickPoint ControlPointEditorStroke::getSpeedInPoint(int index) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	assert(stroke && 0 <= index && index < (int)m_controlPoints.size());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ControlPoint cp = m_controlPoints[index];
Toshihiro Shimizu 890ddd
	return stroke->getControlPoint(cp.m_pointIndex) - cp.m_speedIn;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TThickPoint ControlPointEditorStroke::getSpeedOutPoint(int index) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	assert(stroke && 0 <= index && index < (int)m_controlPoints.size());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ControlPoint cp = m_controlPoints[index];
Toshihiro Shimizu 890ddd
	return stroke->getControlPoint(cp.m_pointIndex) + cp.m_speedOut;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool ControlPointEditorStroke::isCusp(int index) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	assert(stroke && 0 <= index && index < (int)getControlPointCount());
Toshihiro Shimizu 890ddd
	return m_controlPoints[index].m_isCusp;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::setCusp(int index, bool isCusp, bool setSpeedIn)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_controlPoints[index].m_isCusp = isCusp;
Toshihiro Shimizu 890ddd
	if (isCusp == true)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	moveSpeed(index, TPointD(0.0, 0.0), setSpeedIn, 0.0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool ControlPointEditorStroke::isSpeedInLinear(int index) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(index < (int)m_controlPoints.size());
Toshihiro Shimizu 890ddd
	return (fabs(m_controlPoints[index].m_speedIn.x) <= 0.02) && (fabs(m_controlPoints[index].m_speedIn.y) <= 0.02);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool ControlPointEditorStroke::isSpeedOutLinear(int index) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(index < (int)m_controlPoints.size());
Toshihiro Shimizu 890ddd
	return (fabs(m_controlPoints[index].m_speedOut.x) <= 0.02) && (fabs(m_controlPoints[index].m_speedOut.y) <= 0.02);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::setLinearSpeedIn(int index, bool linear, bool updatePoints)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke || m_controlPoints.size() == 1)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	int pointIndex = m_controlPoints[index].m_pointIndex;
Toshihiro Shimizu 890ddd
	if (pointIndex == 0) {
Toshihiro Shimizu 890ddd
		if (isSelfLoop())
Toshihiro Shimizu 890ddd
			pointIndex = stroke->getControlPointCount() - 1;
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	int precIndex = (index == 0 && isSelfLoop()) ? m_controlPoints.size() - 1 : index - 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TThickPoint point = stroke->getControlPoint(pointIndex);
Toshihiro Shimizu 890ddd
	TThickPoint precPoint = (pointIndex > 2) ? stroke->getControlPoint(pointIndex - 3) : TThickPoint();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (linear) {
Toshihiro Shimizu 890ddd
		TThickPoint p(point - precPoint);
Toshihiro Shimizu 890ddd
		double n = norm(p);
Toshihiro Shimizu 890ddd
		TThickPoint speedIn = (n != 0.0) ? (0.01 / n) * p : TThickPoint(0.001, 0.001, 0.0);
Toshihiro Shimizu 890ddd
		m_controlPoints[index].m_speedIn = speedIn;
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		TThickPoint newPrec2 = (precPoint + point) * 0.5;
Toshihiro Shimizu 890ddd
		TThickPoint speedIn = (point - newPrec2) * 0.5;
Toshihiro Shimizu 890ddd
		m_controlPoints[index].m_speedIn = speedIn;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (updatePoints)
Toshihiro Shimizu 890ddd
		updateDependentPoint(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::setLinearSpeedOut(int index, bool linear, bool updatePoints)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke || m_controlPoints.size() == 1)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	int cpCount = stroke->getControlPointCount();
Toshihiro Shimizu 890ddd
	int pointIndex = m_controlPoints[index].m_pointIndex;
Toshihiro Shimizu 890ddd
	if (pointIndex == cpCount - 1) {
Toshihiro Shimizu 890ddd
		if (isSelfLoop())
Toshihiro Shimizu 890ddd
			pointIndex = 0;
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	int nextIndex = (index == m_controlPoints.size() - 1 && isSelfLoop()) ? 0 : index + 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TThickPoint point = stroke->getControlPoint(pointIndex);
Toshihiro Shimizu 890ddd
	TThickPoint nextPoint = (pointIndex < cpCount - 3) ? stroke->getControlPoint(pointIndex + 3) : TThickPoint();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (linear) {
Toshihiro Shimizu 890ddd
		TThickPoint p(nextPoint - point);
Toshihiro Shimizu 890ddd
		double n = norm(p);
Toshihiro Shimizu 890ddd
		TThickPoint speedOut = (n != 0.0) ? (0.01 / n) * p : TThickPoint(0.001, 0.001, 0.0);
Toshihiro Shimizu 890ddd
		m_controlPoints[index].m_speedOut = speedOut;
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		TThickPoint newNext2 = (nextPoint + point) * 0.5;
Toshihiro Shimizu 890ddd
		TThickPoint speedOut = (newNext2 - point) * 0.5;
Toshihiro Shimizu 890ddd
		m_controlPoints[index].m_speedOut = speedOut;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (updatePoints)
Toshihiro Shimizu 890ddd
		updateDependentPoint(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool ControlPointEditorStroke::setLinear(int index, bool isLinear, bool updatePoints)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	bool movePrec = (!isSelfLoop()) ? index > 0 : true;
Toshihiro Shimizu 890ddd
	bool moveNext = (!isSelfLoop()) ? (index < getControlPointCount() - 1) : true;
Toshihiro Shimizu 890ddd
	if (isLinear != isSpeedInLinear(index))
Toshihiro Shimizu 890ddd
		setLinearSpeedIn(index, isLinear, updatePoints);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		movePrec = false;
Toshihiro Shimizu 890ddd
	if (isLinear != isSpeedOutLinear(index))
Toshihiro Shimizu 890ddd
		setLinearSpeedOut(index, isLinear, updatePoints);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		moveNext = false;
Toshihiro Shimizu 890ddd
	bool ret = moveNext || movePrec;
Toshihiro Shimizu 890ddd
	if (ret)
Toshihiro Shimizu 890ddd
		m_controlPoints[index].m_isCusp = true;
Toshihiro Shimizu 890ddd
	return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool ControlPointEditorStroke::setControlPointsLinear(std::set<int> points, bool isLinear)</int>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::set<int>::iterator it;</int>
Toshihiro Shimizu 890ddd
	bool isChanged = false;
Toshihiro Shimizu 890ddd
	for (it = points.begin(); it != points.end(); it++)
Toshihiro Shimizu 890ddd
		isChanged = setLinear(*it, isLinear, false) || isChanged;
Toshihiro Shimizu 890ddd
	for (it = points.begin(); it != points.end(); it++)
Toshihiro Shimizu 890ddd
		updateDependentPoint(*it);
Toshihiro Shimizu 890ddd
	return isChanged;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::moveControlPoint(int index, const TPointD &delta)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	assert(stroke && 0 <= index && index < (int)getControlPointCount());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	moveSingleControlPoint(index, delta);
Toshihiro Shimizu 890ddd
	updateDependentPoint(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int ControlPointEditorStroke::addControlPoint(const TPointD &pos)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return -1;
Toshihiro Shimizu 890ddd
	double d = 0.01;
Toshihiro Shimizu 890ddd
	int indexAtPos;
Toshihiro Shimizu 890ddd
	int cpCount = stroke->getControlPointCount();
Toshihiro Shimizu 890ddd
	if (cpCount <= 3) //e' un unico chunk e in questo caso rappresenta un punto
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		getPointTypeAt(pos, d, indexAtPos);
Toshihiro Shimizu 890ddd
		return indexAtPos;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double w = stroke->getW(pos);
Toshihiro Shimizu 890ddd
	int pointIndex = stroke->getControlPointIndexAfterParameter(w);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int i, index;
Toshihiro Shimizu 890ddd
	for (i = 0; i < getControlPointCount(); i++) {
Toshihiro Shimizu 890ddd
		// Cerco il ControlPoint corrispondente all'indice pointIndex. OSS.: Effettuo il
Toshihiro Shimizu 890ddd
		// controllo da zero a getControlPointCount()-1 per gestire il caso del selfLoop
Toshihiro Shimizu 890ddd
		if (pointIndex == m_controlPoints[i].m_pointIndex + 1 ||
Toshihiro Shimizu 890ddd
			pointIndex == m_controlPoints[i].m_pointIndex + 2 ||
Toshihiro Shimizu 890ddd
			pointIndex == m_controlPoints[i].m_pointIndex + 3 ||
Toshihiro Shimizu 890ddd
			pointIndex == m_controlPoints[i].m_pointIndex + 4)
Toshihiro Shimizu 890ddd
			index = i;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ControlPoint precCp = m_controlPoints[index];
Toshihiro Shimizu 890ddd
	assert(precCp.m_pointIndex >= 0);
Shinya Kitaoka 3bfa54
	std::vector<tthickpoint> points;</tthickpoint>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (i = 0; i < cpCount; i++) {
Toshihiro Shimizu 890ddd
		if (i != precCp.m_pointIndex + 1 && i != precCp.m_pointIndex + 2 && i != precCp.m_pointIndex + 3)
Toshihiro Shimizu 890ddd
			points.push_back(stroke->getControlPoint(i));
Toshihiro Shimizu 890ddd
		if (i == precCp.m_pointIndex + 2) {
Toshihiro Shimizu 890ddd
			bool isBeforePointLinear = isSpeedOutLinear(index);
Toshihiro Shimizu 890ddd
			int nextIndex = (isSelfLoop() && index == m_controlPoints.size() - 1) ? 0 : index + 1;
Toshihiro Shimizu 890ddd
			bool isNextPointLinear = nextIndex < (int)m_controlPoints.size() && isSpeedInLinear(nextIndex);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TThickPoint a0 = stroke->getControlPoint(precCp.m_pointIndex);
Toshihiro Shimizu 890ddd
			TThickPoint a1 = stroke->getControlPoint(precCp.m_pointIndex + 1);
Toshihiro Shimizu 890ddd
			TThickPoint a2 = stroke->getControlPoint(precCp.m_pointIndex + 2);
Toshihiro Shimizu 890ddd
			TThickPoint a3 = stroke->getControlPoint(precCp.m_pointIndex + 3);
Toshihiro Shimizu 890ddd
			TThickPoint a4 = stroke->getControlPoint(precCp.m_pointIndex + 4);
Toshihiro Shimizu 890ddd
			double dist2 = tdistance2(pos, TPointD(a2));
Toshihiro Shimizu 890ddd
			TThickPoint d0, d1, d2, d3, d4, d5, d6;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (isBeforePointLinear && isNextPointLinear) {
Toshihiro Shimizu 890ddd
				// Se sono entrambi i punti lineari  inserisco un punto lineare
Toshihiro Shimizu 890ddd
				d0 = a1;
Toshihiro Shimizu 890ddd
				d3 = stroke->getThickPoint(w);
Toshihiro Shimizu 890ddd
				d6 = a3;
Toshihiro Shimizu 890ddd
				d2 = computeLinearPoint(d0, d3, 0.01, true);  //SpeedIn
Toshihiro Shimizu 890ddd
				d4 = computeLinearPoint(d3, d6, 0.01, false); //SpeedOut
Toshihiro Shimizu 890ddd
				d1 = 0.5 * (d0 + d2);
Toshihiro Shimizu 890ddd
				d5 = 0.5 * (d4 + d6);
Toshihiro Shimizu 890ddd
			} else if (dist2 < 32) {
Toshihiro Shimizu 890ddd
				// Sono molto vicino al punto che non viene visualizzato
Toshihiro Shimizu 890ddd
				TThickPoint b0 = 0.5 * (a0 + a1);
Toshihiro Shimizu 890ddd
				TThickPoint b1 = 0.5 * (a2 + a1);
Toshihiro Shimizu 890ddd
				TThickPoint c0 = 0.5 * (b0 + b1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				TThickPoint b2 = 0.5 * (a2 + a3);
Toshihiro Shimizu 890ddd
				TThickPoint b3 = 0.5 * (a3 + a4);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				TThickPoint c1 = 0.5 * (b2 + b3);
Toshihiro Shimizu 890ddd
				d0 = b0;
Toshihiro Shimizu 890ddd
				d1 = c0;
Toshihiro Shimizu 890ddd
				d2 = b1;
Toshihiro Shimizu 890ddd
				d3 = a2;
Toshihiro Shimizu 890ddd
				d4 = b2;
Toshihiro Shimizu 890ddd
				d5 = c1;
Toshihiro Shimizu 890ddd
				d6 = b3;
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				bool isInFirstChunk = true;
Toshihiro Shimizu 890ddd
				if (pointIndex > precCp.m_pointIndex + 2) {
Toshihiro Shimizu 890ddd
					// nel caso in cui sono nel secondo chunk scambio i punti
Toshihiro Shimizu 890ddd
					a0 = a4;
Toshihiro Shimizu 890ddd
					tswap(a1, a3);
Toshihiro Shimizu 890ddd
					isInFirstChunk = false;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				double w0 = (isSelfLoop() && precCp.m_pointIndex + 4 == cpCount - 1 && !isInFirstChunk) ? 1 : stroke->getW(a0);
Toshihiro Shimizu 890ddd
				double w1 = stroke->getW(a2);
Toshihiro Shimizu 890ddd
				double t = (w - w0) / (w1 - w0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				TThickPoint p = stroke->getThickPoint(w);
Toshihiro Shimizu 890ddd
				TThickPoint b0 = TThickPoint((1 - t) * a0 + t * a1, (1 - t) * a0.thick + t * a1.thick);
Toshihiro Shimizu 890ddd
				TThickPoint b1 = TThickPoint((1 - t) * a1 + t * a2, (1 - t) * a1.thick + t * a2.thick);
Toshihiro Shimizu 890ddd
				TThickPoint c0 = TThickPoint(0.5 * a0 + 0.5 * b0, (1 - t) * a0.thick + t * b0.thick);
Toshihiro Shimizu 890ddd
				TThickPoint c1 = TThickPoint(0.5 * b0 + 0.5 * p, (1 - t) * b0.thick + t * p.thick);
Toshihiro Shimizu 890ddd
				TThickPoint c2 = TThickPoint(0.5 * c0 + 0.5 * c1, (1 - t) * c0.thick + t * c1.thick);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				d0 = (isInFirstChunk) ? c0 : a3;
Toshihiro Shimizu 890ddd
				d1 = (isInFirstChunk) ? c2 : a2;
Toshihiro Shimizu 890ddd
				d2 = (isInFirstChunk) ? c1 : b1;
Toshihiro Shimizu 890ddd
				d3 = p;
Toshihiro Shimizu 890ddd
				d4 = (isInFirstChunk) ? b1 : c1;
Toshihiro Shimizu 890ddd
				d5 = (isInFirstChunk) ? a2 : c2;
Toshihiro Shimizu 890ddd
				d6 = (isInFirstChunk) ? a3 : c0;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			if (isBeforePointLinear && !isNextPointLinear)
Toshihiro Shimizu 890ddd
				d1 = computeLinearPoint(d0, d2, 0.01, false);
Toshihiro Shimizu 890ddd
			else if (isNextPointLinear && !isBeforePointLinear)
Toshihiro Shimizu 890ddd
				d5 = computeLinearPoint(d4, d6, 0.01, true);
Toshihiro Shimizu 890ddd
			points.push_back(d0);
Toshihiro Shimizu 890ddd
			points.push_back(d1);
Toshihiro Shimizu 890ddd
			points.push_back(d2);
Toshihiro Shimizu 890ddd
			points.push_back(d3);
Toshihiro Shimizu 890ddd
			points.push_back(d4);
Toshihiro Shimizu 890ddd
			points.push_back(d5);
Toshihiro Shimizu 890ddd
			points.push_back(d6);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	stroke->reshape(&points[0], points.size());
Toshihiro Shimizu 890ddd
	resetControlPoints();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	getPointTypeAt(pos, d, indexAtPos);
Toshihiro Shimizu 890ddd
	return indexAtPos;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::deleteControlPoint(int index)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(stroke && 0 <= index && index < (int)getControlPointCount());
Toshihiro Shimizu 890ddd
	//E' un unico chunk e in questo caso rappresenta un punto
Toshihiro Shimizu 890ddd
	if (stroke->getControlPointCount() <= 3 || (isSelfLoop() && stroke->getControlPointCount() <= 5)) {
Toshihiro Shimizu 890ddd
		m_controlPoints.clear();
Toshihiro Shimizu 890ddd
		m_vi->deleteStroke(m_strokeIndex);
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QList<int> newPointsIndex;</int>
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < (int)getControlPointCount() - 1; i++)
Toshihiro Shimizu 890ddd
		newPointsIndex.push_back(m_controlPoints[i].m_pointIndex);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_controlPoints.removeAt(index);
Toshihiro Shimizu 890ddd
	updatePoints();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Aggiorno gli indici dei punti nella stroke
Toshihiro Shimizu 890ddd
	assert((int)newPointsIndex.size() == (int)getControlPointCount());
Toshihiro Shimizu 890ddd
	for (i = 0; i < (int)getControlPointCount(); i++)
Toshihiro Shimizu 890ddd
		m_controlPoints[i].m_pointIndex = newPointsIndex.at(i);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int prev = prevIndex(index);
Toshihiro Shimizu 890ddd
	if (prev >= 0 && isSpeedOutLinear(prev)) {
Toshihiro Shimizu 890ddd
		setLinearSpeedOut(prev);
Toshihiro Shimizu 890ddd
		updateDependentPoint(prev);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (index < (int)m_controlPoints.size() && isSpeedInLinear(index)) {
Toshihiro Shimizu 890ddd
		setLinearSpeedIn(index);
Toshihiro Shimizu 890ddd
		updateDependentPoint(index);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::moveSpeed(int index, const TPointD &delta, bool isIn, double minDistance)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!isIn)
Toshihiro Shimizu 890ddd
		moveSpeedOut(index, delta, minDistance);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		moveSpeedIn(index, delta, minDistance);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	updateDependentPoint(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointEditorStroke::moveSegment(int beforeIndex, int nextIndex, const TPointD &delta, const TPointD &pos)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int cpCount = getControlPointCount();
Toshihiro Shimizu 890ddd
	//Verifiche per il caso in cui lo stroke e' selfLoop
Toshihiro Shimizu 890ddd
	if (isSelfLoop() && beforeIndex == 0 && nextIndex == cpCount - 1)
Toshihiro Shimizu 890ddd
		tswap(beforeIndex, nextIndex);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int beforePointIndex = m_controlPoints[beforeIndex].m_pointIndex;
Toshihiro Shimizu 890ddd
	int nextPointIndex = (isSelfLoop() && nextIndex == 0) ? stroke->getControlPointCount() - 1 : m_controlPoints[nextIndex].m_pointIndex;
Toshihiro Shimizu 890ddd
	double w = stroke->getW(pos);
Toshihiro Shimizu 890ddd
	double w0 = stroke->getParameterAtControlPoint(beforePointIndex);
Toshihiro Shimizu 890ddd
	double w4 = stroke->getParameterAtControlPoint(nextPointIndex);
Toshihiro Shimizu 890ddd
	assert(w0 <= w && w <= w4);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double t = 1;
Toshihiro Shimizu 890ddd
	double s = 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (isSpeedOutLinear(beforeIndex)) {
Toshihiro Shimizu 890ddd
		m_controlPoints[beforeIndex].m_speedOut = (stroke->getControlPoint(nextPointIndex) - stroke->getControlPoint(beforePointIndex)) * 0.3;
Toshihiro Shimizu 890ddd
		if (!isSpeedInLinear(beforeIndex))
Toshihiro Shimizu 890ddd
			m_controlPoints[beforeIndex].m_isCusp = true;
Toshihiro Shimizu 890ddd
	} else if (!isSpeedOutLinear(beforeIndex) && !isSpeedInLinear(beforeIndex) && !isCusp(beforeIndex)) {
Toshihiro Shimizu 890ddd
		t = 1 - abs(w - w0) / abs(w4 - w0);
Toshihiro Shimizu 890ddd
		moveSingleControlPoint(beforeIndex, t * delta);
Toshihiro Shimizu 890ddd
		t = 1 - t;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (isSpeedInLinear(nextIndex)) {
Toshihiro Shimizu 890ddd
		m_controlPoints[nextIndex].m_speedIn = (stroke->getControlPoint(nextPointIndex) - stroke->getControlPoint(beforePointIndex)) * 0.3;
Toshihiro Shimizu 890ddd
		if (!isSpeedOutLinear(nextIndex))
Toshihiro Shimizu 890ddd
			m_controlPoints[nextIndex].m_isCusp = true;
Toshihiro Shimizu 890ddd
	} else if (!isSpeedInLinear(nextIndex) && !isSpeedOutLinear(nextIndex) && !isCusp(nextIndex)) {
Toshihiro Shimizu 890ddd
		s = 1 - abs(w4 - w) / abs(w4 - w0);
Toshihiro Shimizu 890ddd
		moveSingleControlPoint(nextIndex, s * delta);
Toshihiro Shimizu 890ddd
		s = 1 - s;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	moveSpeedOut(beforeIndex, delta * s, 0);
Toshihiro Shimizu 890ddd
	//updateDependentPoint(beforeIndex);
Toshihiro Shimizu 890ddd
	moveSpeedIn(nextIndex, delta * t, 0);
Toshihiro Shimizu 890ddd
	//updateDependentPoint(nextIndex);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	updatePoints();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ControlPointEditorStroke::PointType ControlPointEditorStroke::getPointTypeAt(const TPointD &pos,
Toshihiro Shimizu 890ddd
																			 double &distance2, int &index) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *stroke = getStroke();
Toshihiro Shimizu 890ddd
	if (!stroke)
Toshihiro Shimizu 890ddd
		return NONE;
Toshihiro Shimizu 890ddd
	double w = stroke->getW(pos);
Toshihiro Shimizu 890ddd
	TPointD p = stroke->getPoint(w);
Toshihiro Shimizu 890ddd
	double strokeDistance = tdistance2(p, pos);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int precPointIndex = -1;
Toshihiro Shimizu 890ddd
	double minPrecDistance = 0;
Toshihiro Shimizu 890ddd
	double minDistance2 = distance2;
Toshihiro Shimizu 890ddd
	index = -1;
Toshihiro Shimizu 890ddd
	PointType type = NONE;
Toshihiro Shimizu 890ddd
	int cpCount = m_controlPoints.size();
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < cpCount; i++) {
Toshihiro Shimizu 890ddd
		ControlPoint cPoint = m_controlPoints[i];
Toshihiro Shimizu 890ddd
		TPointD point = stroke->getControlPoint(cPoint.m_pointIndex);
Toshihiro Shimizu 890ddd
		double cpDistance2 = tdistance2(pos, point);
Toshihiro Shimizu 890ddd
		double distanceIn2 = !isSpeedInLinear(i) ? tdistance2(pos, point - cPoint.m_speedIn) : cpDistance2 + 1;
Toshihiro Shimizu 890ddd
		double distanceOut2 = !isSpeedOutLinear(i) ? tdistance2(pos, point + cPoint.m_speedOut) : cpDistance2 + 1;
Toshihiro Shimizu 890ddd
		if (i == 0 && !isSelfLoop())
Shinya Kitaoka 12c444
			distanceIn2 = std::max(cpDistance2, distanceOut2) + 1;
Toshihiro Shimizu 890ddd
		if (i == cpCount - 1 && !isSelfLoop())
Shinya Kitaoka 12c444
			distanceOut2 = std::max(cpDistance2, distanceIn2) + 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (cpDistance2 < distanceIn2 && cpDistance2 < distanceOut2 && (cpDistance2 < minDistance2 || index < 0)) {
Toshihiro Shimizu 890ddd
			minDistance2 = cpDistance2;
Toshihiro Shimizu 890ddd
			index = i;
Toshihiro Shimizu 890ddd
			type = CONTROL_POINT;
Toshihiro Shimizu 890ddd
		} else if (distanceIn2 < cpDistance2 && distanceIn2 < distanceOut2 && (distanceIn2 < minDistance2 || index < 0)) {
Toshihiro Shimizu 890ddd
			minDistance2 = distanceIn2;
Toshihiro Shimizu 890ddd
			index = i;
Toshihiro Shimizu 890ddd
			type = SPEED_IN;
Toshihiro Shimizu 890ddd
		} else if (distanceOut2 < cpDistance2 && distanceOut2 < distanceIn2 && (distanceOut2 < minDistance2 || index < 0)) {
Toshihiro Shimizu 890ddd
			minDistance2 = distanceOut2;
Toshihiro Shimizu 890ddd
			index = i;
Toshihiro Shimizu 890ddd
			type = SPEED_OUT;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double cpw = stroke->getParameterAtControlPoint(m_controlPoints[i].m_pointIndex);
Toshihiro Shimizu 890ddd
		if (w <= cpw)
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
		double precDistance = w - cpw;
Toshihiro Shimizu 890ddd
		if (precPointIndex < 0 || precDistance < minPrecDistance) {
Toshihiro Shimizu 890ddd
			precPointIndex = i;
Toshihiro Shimizu 890ddd
			minPrecDistance = precDistance;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (minDistance2 < distance2)
Toshihiro Shimizu 890ddd
		distance2 = minDistance2;
Toshihiro Shimizu 890ddd
	else if (strokeDistance > distance2) {
Toshihiro Shimizu 890ddd
		distance2 = strokeDistance;
Toshihiro Shimizu 890ddd
		index = -1;
Toshihiro Shimizu 890ddd
		type = NONE;
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		distance2 = minPrecDistance;
Toshihiro Shimizu 890ddd
		index = precPointIndex;
Toshihiro Shimizu 890ddd
		type = SEGMENT;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return type;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// ControlPointSelection
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool ControlPointSelection::isSelected(int index) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_selectedPoints.find(index) != m_selectedPoints.end();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointSelection::select(int index)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_selectedPoints.insert(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointSelection::unselect(int index)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_selectedPoints.erase(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointSelection::addMenuItems(QMenu *menu)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int currentStrokeIndex = m_controlPointEditorStroke->getStrokeIndex();
Toshihiro Shimizu 890ddd
	if (isEmpty() || currentStrokeIndex == -1 ||
Toshihiro Shimizu 890ddd
		(m_controlPointEditorStroke && m_controlPointEditorStroke->getControlPointCount() <= 1))
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	QAction *linear = menu->addAction(tr("Set Linear Control Point"));
Toshihiro Shimizu 890ddd
	QAction *unlinear = menu->addAction(tr("Set Nonlinear Control Point"));
Toshihiro Shimizu 890ddd
	menu->addSeparator();
Toshihiro Shimizu 890ddd
	bool ret = connect(linear, SIGNAL(triggered()), this, SLOT(setLinear()));
Toshihiro Shimizu 890ddd
	ret = ret && connect(unlinear, SIGNAL(triggered()), this, SLOT(setUnlinear()));
Toshihiro Shimizu 890ddd
	assert(ret);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointSelection::setLinear()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TTool *tool = TTool::getApplication()->getCurrentTool()->getTool();
Toshihiro Shimizu 890ddd
	int currentStrokeIndex = m_controlPointEditorStroke->getStrokeIndex();
Toshihiro Shimizu 890ddd
	TVectorImageP vi(tool->getImage(false));
Toshihiro Shimizu 890ddd
	if (!vi || isEmpty() || currentStrokeIndex == -1)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	TUndo *undo;
Toshihiro Shimizu 890ddd
	if (tool->getApplication()->getCurrentObject()->isSpline())
Toshihiro Shimizu 890ddd
		undo = new UndoPath(tool->getXsheet()->getStageObject(tool->getObjectId())->getSpline());
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		TXshSimpleLevel *level = tool->getApplication()->getCurrentLevel()->getSimpleLevel();
Toshihiro Shimizu 890ddd
		UndoControlPointEditor *cpEditorUndo = new UndoControlPointEditor(level, tool->getCurrentFid());
Toshihiro Shimizu 890ddd
		cpEditorUndo->addOldStroke(currentStrokeIndex, vi->getVIStroke(currentStrokeIndex));
Toshihiro Shimizu 890ddd
		undo = cpEditorUndo;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (m_controlPointEditorStroke->getControlPointCount() == 0)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isChanged = m_controlPointEditorStroke->setControlPointsLinear(m_selectedPoints, true);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!isChanged)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	TUndoManager::manager()->add(undo);
Toshihiro Shimizu 890ddd
	tool->notifyImageChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointSelection::setUnlinear()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TTool *tool = TTool::getApplication()->getCurrentTool()->getTool();
Toshihiro Shimizu 890ddd
	int currentStrokeIndex = m_controlPointEditorStroke->getStrokeIndex();
Toshihiro Shimizu 890ddd
	TVectorImageP vi(tool->getImage(false));
Toshihiro Shimizu 890ddd
	if (!vi || isEmpty() || currentStrokeIndex == -1)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TUndo *undo;
Toshihiro Shimizu 890ddd
	if (tool->getApplication()->getCurrentObject()->isSpline())
Toshihiro Shimizu 890ddd
		undo = new UndoPath(tool->getXsheet()->getStageObject(tool->getObjectId())->getSpline());
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		TXshSimpleLevel *level = tool->getApplication()->getCurrentLevel()->getSimpleLevel();
Toshihiro Shimizu 890ddd
		UndoControlPointEditor *cpEditorUndo = new UndoControlPointEditor(level, tool->getCurrentFid());
Toshihiro Shimizu 890ddd
		cpEditorUndo->addOldStroke(currentStrokeIndex, vi->getVIStroke(currentStrokeIndex));
Toshihiro Shimizu 890ddd
		undo = cpEditorUndo;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (m_controlPointEditorStroke->getControlPointCount() == 0)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isChanged = m_controlPointEditorStroke->setControlPointsLinear(m_selectedPoints, false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!isChanged)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	TUndoManager::manager()->add(undo);
Toshihiro Shimizu 890ddd
	tool->notifyImageChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointSelection::deleteControlPoints()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TTool *tool = TTool::getApplication()->getCurrentTool()->getTool();
Toshihiro Shimizu 890ddd
	TVectorImageP vi(tool->getImage(false));
Toshihiro Shimizu 890ddd
	int currentStrokeIndex = m_controlPointEditorStroke->getStrokeIndex();
Toshihiro Shimizu 890ddd
	if (!vi || isEmpty() || currentStrokeIndex == -1)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Inizializzo l'UNDO
Toshihiro Shimizu 890ddd
	TUndo *undo;
Toshihiro Shimizu 890ddd
	bool isCurrentObjectSpline = tool->getApplication()->getCurrentObject()->isSpline();
Toshihiro Shimizu 890ddd
	if (isCurrentObjectSpline)
Toshihiro Shimizu 890ddd
		undo = new UndoPath(tool->getXsheet()->getStageObject(tool->getObjectId())->getSpline());
Toshihiro Shimizu 890ddd
	else {
Toshihiro Shimizu 890ddd
		TXshSimpleLevel *level = tool->getApplication()->getCurrentLevel()->getSimpleLevel();
Toshihiro Shimizu 890ddd
		UndoControlPointEditor *cpEditorUndo = new UndoControlPointEditor(level, tool->getCurrentFid());
Toshihiro Shimizu 890ddd
		cpEditorUndo->addOldStroke(currentStrokeIndex, vi->getVIStroke(currentStrokeIndex));
Toshihiro Shimizu 890ddd
		undo = cpEditorUndo;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = m_controlPointEditorStroke->getControlPointCount() - 1; i >= 0; i--)
Toshihiro Shimizu 890ddd
		if (isSelected(i))
Toshihiro Shimizu 890ddd
			m_controlPointEditorStroke->deleteControlPoint(i);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_controlPointEditorStroke->getControlPointCount() == 0) {
Toshihiro Shimizu 890ddd
		m_controlPointEditorStroke->setStroke((TVectorImage *)0, -1);
Toshihiro Shimizu 890ddd
		if (!isCurrentObjectSpline) {
Toshihiro Shimizu 890ddd
			UndoControlPointEditor *cpEditorUndo = dynamic_cast<undocontrolpointeditor *="">(undo);</undocontrolpointeditor>
Toshihiro Shimizu 890ddd
			if (cpEditorUndo)
Toshihiro Shimizu 890ddd
				cpEditorUndo->isStrokeDelete(true);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//La spline non puo' essere cancellata completamente!!!
Toshihiro Shimizu 890ddd
	if (vi->getStrokeCount() == 0) {
Toshihiro Shimizu 890ddd
		if (TTool::getApplication()->getCurrentObject()->isSpline()) {
Toshihiro Shimizu 890ddd
			std::vector<tpointd> points;</tpointd>
Toshihiro Shimizu 890ddd
			double d = 10;
Toshihiro Shimizu 890ddd
			points.push_back(TPointD(-d, 0));
Toshihiro Shimizu 890ddd
			points.push_back(TPointD(0, 0));
Toshihiro Shimizu 890ddd
			points.push_back(TPointD(d, 0));
Toshihiro Shimizu 890ddd
			TStroke *stroke = new TStroke(points);
Toshihiro Shimizu 890ddd
			vi->addStroke(stroke, false);
Toshihiro Shimizu 890ddd
			m_controlPointEditorStroke->setStrokeIndex(0);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	tool->notifyImageChanged();
Toshihiro Shimizu 890ddd
	selectNone();
Toshihiro Shimizu 890ddd
	//Registro l'UNDO
Toshihiro Shimizu 890ddd
	TUndoManager::manager()->add(undo);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ControlPointSelection::enableCommands()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	enableCommand(this, "MI_Clear", &ControlPointSelection::deleteControlPoints);
Toshihiro Shimizu 890ddd
}