Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tools/tool.h"
Toshihiro Shimizu 890ddd
#include "tools/toolutils.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tstrokeutil.h"
Toshihiro Shimizu 890ddd
#include "tstrokedeformations.h"
Toshihiro Shimizu 890ddd
#include "tmathutil.h"
Toshihiro Shimizu 890ddd
#include "tools/cursors.h"
Toshihiro Shimizu 890ddd
#include "drawutil.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
//=============================================================================
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const UINT MAX_SAMPLE = 2;
Toshihiro Shimizu 890ddd
const int MY_ERROR = -1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const double c_LenghtOfBenderRegion = 10.0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const int IS_BEGIN = 0;
Toshihiro Shimizu 890ddd
const int IS_END = 1;
Toshihiro Shimizu 890ddd
const int IS_ALL = 2;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
double _extractFirst(DoublePair val)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return val.first;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
double _extractSecond(DoublePair val)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return val.second;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool strokeIsConnected(const TStroke &s, double toll = TConsts::epsilon)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	bool out = true;
Toshihiro Shimizu 890ddd
	int count = s.getChunkCount();
Toshihiro Shimizu 890ddd
	long double toll2 = sq(TConsts::epsilon);
Toshihiro Shimizu 890ddd
	if (count > 0) {
Toshihiro Shimizu 890ddd
		const TThickQuadratic *refTQ = s.getChunk(0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (int i = 1; i < count; ++i) {
Toshihiro Shimizu 890ddd
			if (out &&
Toshihiro Shimizu 890ddd
				tdistance2(refTQ->getP2(), s.getChunk(i)->getP0()) > toll2)
Toshihiro Shimizu 890ddd
				out = false;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return out;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool strokeIsConnected(const TStroke *s, double toll = TConsts::epsilon)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(s);
Toshihiro Shimizu 890ddd
	return strokeIsConnected(*s, toll);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
Extract an value of a pair.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 3bfa54
void extract(const std::vector<doublepair> &s, ArrayOfDouble &d, bool isFirstOrSecond = true)</doublepair>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (isFirstOrSecond)
Toshihiro Shimizu 890ddd
		std::transform(s.begin(), s.end(), back_inserter(d), _extractFirst);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		std::transform(s.begin(), s.end(), back_inserter(d), _extractSecond);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
double retrieveInitLength(double strokeLength, int beginEndOrAll)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double initLength = MY_ERROR;
Toshihiro Shimizu 890ddd
	switch (beginEndOrAll) {
Toshihiro Shimizu 890ddd
	case IS_BEGIN:
Toshihiro Shimizu 890ddd
		initLength = 0.0;
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
	case IS_END:
Toshihiro Shimizu 890ddd
		initLength = strokeLength;
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
	case IS_ALL:
Toshihiro Shimizu 890ddd
		initLength = strokeLength * 0.5;
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return initLength;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool isOdd(UINT val)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return val & 1 ? true : false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool isEven(UINT val)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return !isOdd(val);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 3bfa54
void clearPointerMap(std::map<tstroke *,="" std::vector<int=""> *> &corners)</tstroke>
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 3bfa54
	std::map<tstroke *,="" std::vector<int=""> *>::iterator it = corners.begin();</tstroke>
Toshihiro Shimizu 890ddd
	for (; it != corners.end(); ++it) {
Toshihiro Shimizu 890ddd
		delete it->second;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
// Bender Tool
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class BenderTool : public TTool
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
	TUndo *m_undo;
Toshihiro Shimizu 890ddd
	bool m_atLeastOneIsChanged;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 3bfa54
	std::vector<bool> m_directionIsChanged;</bool>
Shinya Kitaoka 3bfa54
	std::vector<tpointd> m_accumulator;</tpointd>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void increaseCP(TStroke *, int);
Toshihiro Shimizu 890ddd
	bool m_active;
Toshihiro Shimizu 890ddd
	int m_cursor;
Toshihiro Shimizu 890ddd
	enum PNT_SELECTED {
Toshihiro Shimizu 890ddd
		BNDR_NULL = 0,
Toshihiro Shimizu 890ddd
		BNDR_P0 = 1,
Toshihiro Shimizu 890ddd
		BNDR_P1 = 2
Toshihiro Shimizu 890ddd
	};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	struct benderStrokeInfo {
Toshihiro Shimizu 890ddd
		TStroke *m_stroke;
Toshihiro Shimizu 890ddd
		DoublePair m_extremes;
Toshihiro Shimizu 890ddd
		int m_isBeginEndOrAll;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		benderStrokeInfo(TStroke *stroke,
Toshihiro Shimizu 890ddd
						 DoublePair &info,
Toshihiro Shimizu 890ddd
						 int isBeginEndOrAll)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			m_stroke = stroke;
Toshihiro Shimizu 890ddd
			m_extremes = info;
Toshihiro Shimizu 890ddd
			m_isBeginEndOrAll = isBeginEndOrAll;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	};
Toshihiro Shimizu 890ddd
	std::vector<benderstrokeinfo> m_info;</benderstrokeinfo>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// contains information about stroke which have
Toshihiro Shimizu 890ddd
	//  intersection with benderSegment
Shinya Kitaoka 3bfa54
	std::map<tstroke *,="" arrayofstroke=""> m_metaStroke;</tstroke>
Shinya Kitaoka 3bfa54
	std::map<tstroke *,="" std::vector<int=""> *> m_hitStrokeCorners;</tstroke>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool m_showTangents;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// value selected
Toshihiro Shimizu 890ddd
	int m_buttonDownCounter;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TSegment m_benderSegment;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD m_prevPoint;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double m_rotationVersus;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//!
Toshihiro Shimizu 890ddd
	ArrayOfStroke m_strokesToRotate;
Toshihiro Shimizu 890ddd
	//!
Toshihiro Shimizu 890ddd
	ArrayOfStroke m_strokesToBend;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 3bfa54
	std::vector<int> m_changedStrokes;</int>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool m_enableDragSelection;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void findCurves(TVectorImageP &);
Toshihiro Shimizu 890ddd
	void findVersus(const TPointD &p);
Toshihiro Shimizu 890ddd
	double computeRotationVersus(const TPointD &,
Toshihiro Shimizu 890ddd
								 const TPointD &);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	void initBenderAction(TVectorImageP &, const TPointD &);
Toshihiro Shimizu 890ddd
	// BenderTool(TVectorImageP  vimage, GLTestWidget* ref );
Toshihiro Shimizu 890ddd
	BenderTool();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	virtual ~BenderTool();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ToolType getToolType() const { return TTool::LevelWriteTool; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void draw();
Toshihiro Shimizu 890ddd
	void leftButtonDown(const TPointD &, const TMouseEvent &);
Toshihiro Shimizu 890ddd
	void leftButtonDrag(const TPointD &, const TMouseEvent &);
Toshihiro Shimizu 890ddd
	void leftButtonUp(const TPointD &, const TMouseEvent &);
Toshihiro Shimizu 890ddd
	void onEnter();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void onActivate()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_buttonDownCounter = 1;
Toshihiro Shimizu 890ddd
		m_prevPoint = TConsts::napd;
Toshihiro Shimizu 890ddd
		m_benderSegment.setP0(TConsts::napd);
Toshihiro Shimizu 890ddd
		m_benderSegment.setP1(TConsts::napd);
Toshihiro Shimizu 890ddd
		m_metaStroke.clear();
Toshihiro Shimizu 890ddd
		clearPointerMap(m_hitStrokeCorners);
Toshihiro Shimizu 890ddd
		m_hitStrokeCorners.clear();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int getCursorId() const { return m_cursor; }
Toshihiro Shimizu 890ddd
} BenderTool;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
BenderTool::BenderTool()
Toshihiro Shimizu 890ddd
	: TTool("T_Bender"), m_showTangents(false), m_buttonDownCounter(1), m_rotationVersus(0.0), m_enableDragSelection(false), m_undo(0), m_cursor(ToolCursor::BenderCursor)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	bind(TTool::Vectors);
Toshihiro Shimizu 890ddd
	m_prevPoint = TConsts::napd;
Toshihiro Shimizu 890ddd
	m_benderSegment.setP0(TConsts::napd);
Toshihiro Shimizu 890ddd
	m_benderSegment.setP1(TConsts::napd);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
BenderTool::~BenderTool()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void BenderTool::onEnter()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if ((TVectorImageP)getImage(false))
Toshihiro Shimizu 890ddd
		m_cursor = ToolCursor::BenderCursor;
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		m_cursor = ToolCursor::CURSOR_NO;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void BenderTool::leftButtonUp(const TPointD &pos, const TMouseEvent &)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_active = false;
Toshihiro Shimizu 890ddd
	TVectorImageP vi = TImageP(getImage(true));
Toshihiro Shimizu 890ddd
	if (!vi)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	QMutexLocker lock(vi->getMutex());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_active = true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 3bfa54
	std::vector<tstroke *=""> oldStrokesArray(m_changedStrokes.size());</tstroke>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < (int)m_changedStrokes.size(); i++)
Toshihiro Shimizu 890ddd
		oldStrokesArray[i] = new TStroke(*(vi->getStroke(m_changedStrokes[i])));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (3 == m_buttonDownCounter) {
Toshihiro Shimizu 890ddd
		m_rotationVersus = 0.0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// hide bender tool
Toshihiro Shimizu 890ddd
		m_prevPoint = TConsts::napd;
Toshihiro Shimizu 890ddd
		m_benderSegment.setP0(TConsts::napd);
Toshihiro Shimizu 890ddd
		m_benderSegment.setP1(TConsts::napd);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		typedef std::map<tstroke *,="" arrayofstroke="">::iterator itAATS;</tstroke>
Toshihiro Shimizu 890ddd
		//UINT count=0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (itAATS it1 = m_metaStroke.begin(); it1 != m_metaStroke.end(); ++it1) {
Toshihiro Shimizu 890ddd
			UINT i;
Toshihiro Shimizu 890ddd
			// copy vector and...
Toshihiro Shimizu 890ddd
			ArrayOfStroke &refA = it1->second;
Toshihiro Shimizu 890ddd
			TStroke *s = it1->first;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TStroke *out = merge(refA);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			out->reduceControlPoints(getPixelSize(), *(m_hitStrokeCorners[s]));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (it1->first->isSelfLoop()) {
Toshihiro Shimizu 890ddd
				int cpCount = out->getControlPointCount();
Toshihiro Shimizu 890ddd
				TThickPoint p1 = out->getControlPoint(0);
Toshihiro Shimizu 890ddd
				TThickPoint p2 = out->getControlPoint(cpCount - 1);
Toshihiro Shimizu 890ddd
				TThickPoint midP = (p1 + p2) * 0.5;
Toshihiro Shimizu 890ddd
				out->setControlPoint(0, midP);
Toshihiro Shimizu 890ddd
				out->setControlPoint(cpCount - 1, midP);
Toshihiro Shimizu 890ddd
				out->setSelfLoop(true);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			it1->first->swap(*out);
Toshihiro Shimizu 890ddd
			it1->first->setStyle(out->getStyle());
Toshihiro Shimizu 890ddd
			it1->first->outlineOptions() = out->outlineOptions();
Toshihiro Shimizu 890ddd
			it1->first->invalidate();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			for (i = 0; i < refA.size(); ++i)
Toshihiro Shimizu 890ddd
				delete refA[i];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			delete out;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_metaStroke.clear();
Toshihiro Shimizu 890ddd
		clearPointerMap(m_hitStrokeCorners);
Toshihiro Shimizu 890ddd
		m_hitStrokeCorners.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_buttonDownCounter = 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		UINT lastCpIndex, i, size = m_changedStrokes.size();
Toshihiro Shimizu 890ddd
		TStroke *stroke;
Toshihiro Shimizu 890ddd
		TThickPoint p1, p2, middleP;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double loopError = 0.5 * getPixelSize();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (i = 0; i < size; i++) {
Toshihiro Shimizu 890ddd
			stroke = vi->getStroke(m_changedStrokes[i]);
Toshihiro Shimizu 890ddd
			if (m_directionIsChanged[i])
Toshihiro Shimizu 890ddd
				stroke->changeDirection();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			lastCpIndex = stroke->getControlPointCount() - 1;
Toshihiro Shimizu 890ddd
			p1 = stroke->getControlPoint(0);
Toshihiro Shimizu 890ddd
			p2 = stroke->getControlPoint(lastCpIndex);
Toshihiro Shimizu 890ddd
			if (isAlmostZero(p1.x - p2.x, loopError) && isAlmostZero(p1.y - p2.y, loopError)) {
Toshihiro Shimizu 890ddd
				middleP = (p1 + p2) * 0.5;
Toshihiro Shimizu 890ddd
				stroke->setControlPoint(0, middleP);
Toshihiro Shimizu 890ddd
				stroke->setControlPoint(lastCpIndex, middleP);
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				stroke->setSelfLoop(false);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		vi->notifyChangedStrokes(m_changedStrokes, oldStrokesArray);
Toshihiro Shimizu 890ddd
		notifyImageChanged();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_undo)
Toshihiro Shimizu 890ddd
			TUndoManager::manager()->add(m_undo);
Toshihiro Shimizu 890ddd
		m_undo = 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	clearPointerContainer(oldStrokesArray);
Toshihiro Shimizu 890ddd
	m_active = false;
Toshihiro Shimizu 890ddd
	invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void BenderTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_active)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	TVectorImageP vi = TImageP(getImage(true));
Toshihiro Shimizu 890ddd
	if (!vi)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	QMutexLocker lock(vi->getMutex());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double pixelSize = getPixelSize();
Toshihiro Shimizu 890ddd
	if (tdistance2(pos, m_prevPoint) < 9.0 * pixelSize * pixelSize)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_buttonDownCounter < 3)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	if (m_enableDragSelection) {
Toshihiro Shimizu 890ddd
		m_accumulator.push_back(pos);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_accumulator.size() < 3)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TPointD middlePnt;
Toshihiro Shimizu 890ddd
		accumulate(m_accumulator.begin(), m_accumulator.end(), middlePnt);
Toshihiro Shimizu 890ddd
		static const double inv_of_3 = 1.0 / 2.0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		middlePnt = inv_of_3 * middlePnt;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_accumulator.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		initBenderAction(vi, pos + middlePnt);
Toshihiro Shimizu 890ddd
		m_enableDragSelection = false;
Toshihiro Shimizu 890ddd
		m_buttonDownCounter = 3;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD p = pos;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD
Toshihiro Shimizu 890ddd
		vc(p - m_benderSegment.getP0()),		   // current vector
Toshihiro Shimizu 890ddd
		vp(m_prevPoint - m_benderSegment.getP0()); // previous vector
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD s2v = m_benderSegment.getSpeed();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// some check to jump invalid case
Toshihiro Shimizu 890ddd
	double norm2BenderSeg = norm2(s2v);
Toshihiro Shimizu 890ddd
	double norm2CurrentVect = norm2(vc);
Toshihiro Shimizu 890ddd
	double norm2PreviousVect = norm2(vp);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// invalid segments
Toshihiro Shimizu 890ddd
	if (0.0 == norm2BenderSeg ||
Toshihiro Shimizu 890ddd
		0.0 == norm2PreviousVect ||
Toshihiro Shimizu 890ddd
		0.0 == norm2CurrentVect)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// invalid rotation versus
Toshihiro Shimizu 890ddd
	if (tsign(cross(s2v, vc)) != m_rotationVersus)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// compute delta of rotation angle
Toshihiro Shimizu 890ddd
	double diff = asin(cross(normalize(vp), normalize(vc)));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// make a rototranslation matrix
Toshihiro Shimizu 890ddd
	TRotation rot(m_benderSegment.getP0(), rad2degree(diff));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// rotate references
Toshihiro Shimizu 890ddd
	for (itAS its = m_strokesToRotate.begin(); its != m_strokesToRotate.end(); ++its)
Toshihiro Shimizu 890ddd
		(*its)->transform(rot);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// deform strokes
Toshihiro Shimizu 890ddd
	for (UINT i = 0; i < m_info.size(); ++i) {
Toshihiro Shimizu 890ddd
		TStroke &ref = *m_info[i].m_stroke;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// DoublePair  &extr   = m_info[i].m_extremes;
Toshihiro Shimizu 890ddd
		double strokeLength = ref.getLength();
Toshihiro Shimizu 890ddd
		double initLength = retrieveInitLength(strokeLength, m_info[i].m_isBeginEndOrAll); // ? 0.0 : strokeLength;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (MY_ERROR == initLength)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int innerOrOuter = m_info[i].m_isBeginEndOrAll == IS_ALL ? TStrokeBenderDeformation::OUTER : TStrokeBenderDeformation::INNER;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TStrokeBenderDeformation
Toshihiro Shimizu 890ddd
			def(&ref,
Toshihiro Shimizu 890ddd
				m_benderSegment.getP0(),
Toshihiro Shimizu 890ddd
				diff,
Toshihiro Shimizu 890ddd
				initLength,
Toshihiro Shimizu 890ddd
				innerOrOuter,
Toshihiro Shimizu 890ddd
				strokeLength);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		modifyControlPoints(ref, def);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// fix previous point
Toshihiro Shimizu 890ddd
	m_prevPoint = p;
Toshihiro Shimizu 890ddd
	invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void BenderTool::leftButtonDown(const TPointD &p, const TMouseEvent &)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_active = false;
Toshihiro Shimizu 890ddd
	TVectorImageP vi = TImageP(getImage(true));
Toshihiro Shimizu 890ddd
	if (!vi)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	QMutexLocker lock(vi->getMutex());
Toshihiro Shimizu 890ddd
	m_active = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	switch (m_buttonDownCounter) {
Toshihiro Shimizu 890ddd
	case 1:
Toshihiro Shimizu 890ddd
		findCurves(vi);
Toshihiro Shimizu 890ddd
		m_strokesToRotate.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// le curve puntate sono state eliminate dalla clear precedente
Toshihiro Shimizu 890ddd
		m_info.clear();
Toshihiro Shimizu 890ddd
		m_benderSegment.setP0(p);
Toshihiro Shimizu 890ddd
		m_benderSegment.setP1(p);
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	case 2: // second buttonDown
Toshihiro Shimizu 890ddd
		m_prevPoint = p;
Toshihiro Shimizu 890ddd
		m_benderSegment.setP1(p);
Toshihiro Shimizu 890ddd
		m_enableDragSelection = true;
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
		/*
Toshihiro Shimizu 890ddd
    case 3: // third buttonDown      
Toshihiro Shimizu 890ddd
    // initBenderAction( vi, p );
Toshihiro Shimizu 890ddd
    break;
Toshihiro Shimizu 890ddd
    */
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	++m_buttonDownCounter;
Toshihiro Shimizu 890ddd
	invalidate();
Toshihiro Shimizu 890ddd
	//vi->validateRegionEdges(vi->getStroke( m_strokeIndex ), true);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void BenderTool::findVersus(const TPointD &p)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TPointD
Toshihiro Shimizu 890ddd
		v1 = m_benderSegment.getSpeed(),
Toshihiro Shimizu 890ddd
		v2 = p - m_benderSegment.getP0();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// fix rotation versus
Toshihiro Shimizu 890ddd
	m_rotationVersus = tsign(cross(v1, v2));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (isAlmostZero(m_rotationVersus))
Toshihiro Shimizu 890ddd
		m_rotationVersus = 1.0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline void one_minus_x(double &x)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	x = 1.0 - x;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void BenderTool::findCurves(TVectorImageP &vi)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	ArrayOfStroke strokeToModify;
Toshihiro Shimizu 890ddd
	m_changedStrokes.clear();
Toshihiro Shimizu 890ddd
	m_directionIsChanged.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	UINT j;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (UINT i = 0; i < vi->getStrokeCount(); ++i) // for all stroke in image
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (!vi->inCurrentGroup(i))
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TStroke *s = vi->getStroke(i); // a useful reference
Toshihiro Shimizu 890ddd
Shinya Kitaoka 3bfa54
		std::vector<doublepair> pair_intersection; // informations about extremes</doublepair>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// if there is interesection between stroke and bender tool
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (intersect(*s, m_benderSegment, pair_intersection)) {
Toshihiro Shimizu 890ddd
			if (s->isSelfLoop()) {
Toshihiro Shimizu 890ddd
				//make the semgnet longer
Toshihiro Shimizu 890ddd
				// such as the points are just a littleBit
Toshihiro Shimizu 890ddd
				// outside the stroke bbox
Toshihiro Shimizu 890ddd
				const double littleBit = 0.1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				TRectD bbox = s->getBBox();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				TPointD bboxP0 = bbox.getP00();
Toshihiro Shimizu 890ddd
				TPointD bboxP1 = bbox.getP11();
Toshihiro Shimizu 890ddd
				double bboxX0 = tmin(bboxP0.x, bboxP1.x);
Toshihiro Shimizu 890ddd
				double bboxX1 = tmax(bboxP0.x, bboxP1.x);
Toshihiro Shimizu 890ddd
				double bboxY0 = tmin(bboxP0.y, bboxP1.y);
Toshihiro Shimizu 890ddd
				double bboxY1 = tmax(bboxP0.y, bboxP1.y);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				TSegment segment;
Toshihiro Shimizu 890ddd
				TPointD pp0 = m_benderSegment.getP0();
Toshihiro Shimizu 890ddd
				TPointD pp1 = m_benderSegment.getP1();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				TPointD newP0;
Toshihiro Shimizu 890ddd
				TPointD newP1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (bbox.contains(pp1)) {
Toshihiro Shimizu 890ddd
					double x = (pp0.x < pp1.x) ? bboxX1 : bboxX0;
Toshihiro Shimizu 890ddd
					double y = (pp0.y < pp1.y) ? bboxY1 : bboxY0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					double t;
Toshihiro Shimizu 890ddd
					if (pp1.x == pp0.x && pp1.y == pp0.y) {
Toshihiro Shimizu 890ddd
						assert(!"segmento del bender puntiforme");
Toshihiro Shimizu 890ddd
						return;
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					if (pp1.x == pp0.x)
Toshihiro Shimizu 890ddd
						t = (y - pp0.y) / (pp1.y - pp0.y);
Toshihiro Shimizu 890ddd
					else if (pp1.y == pp0.y)
Toshihiro Shimizu 890ddd
						t = (x - pp0.x) / (pp1.x - pp0.x);
Toshihiro Shimizu 890ddd
					else
Toshihiro Shimizu 890ddd
						t = tmin((x - pp0.x) / (pp1.x - pp0.x), (y - pp0.y) / (pp1.y - pp0.y));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					newP1 = (t > 1) ? m_benderSegment.getPoint(t + littleBit) : pp1;
Toshihiro Shimizu 890ddd
				} else
Toshihiro Shimizu 890ddd
					newP1 = pp1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (bbox.contains(pp0)) {
Toshihiro Shimizu 890ddd
					double x = (pp0.x > pp1.x) ? bboxX1 : bboxX0;
Toshihiro Shimizu 890ddd
					double y = (pp0.y > pp1.y) ? bboxY1 : bboxY0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					double t;
Toshihiro Shimizu 890ddd
					if (pp1.x == pp0.x && pp1.y == pp0.y) {
Toshihiro Shimizu 890ddd
						assert(!"segmento del bender puntiforme");
Toshihiro Shimizu 890ddd
						return;
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					if (pp1.x == pp0.x)
Toshihiro Shimizu 890ddd
						t = (y - pp0.y) / (pp1.y - pp0.y);
Toshihiro Shimizu 890ddd
					else if (pp1.y == pp0.y)
Toshihiro Shimizu 890ddd
						t = (x - pp0.x) / (pp1.x - pp0.x);
Toshihiro Shimizu 890ddd
					else
Toshihiro Shimizu 890ddd
						t = tmax((x - pp0.x) / (pp1.x - pp0.x), (y - pp0.y) / (pp1.y - pp0.y));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					newP0 = (t < 0) ? m_benderSegment.getPoint(t - littleBit) : pp0;
Toshihiro Shimizu 890ddd
				} else
Toshihiro Shimizu 890ddd
					newP0 = pp0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				segment = TSegment(newP0, newP1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				pair_intersection.clear();
Toshihiro Shimizu 890ddd
				intersect(*s, segment, pair_intersection);
Toshihiro Shimizu 890ddd
				assert(isEven(pair_intersection.size()));
Toshihiro Shimizu 890ddd
				assert(!pair_intersection.empty());
Toshihiro Shimizu 890ddd
				if (pair_intersection.empty()) //non dovrebbe accadere
Toshihiro Shimizu 890ddd
					continue;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			strokeToModify.push_back(s);
Toshihiro Shimizu 890ddd
			m_changedStrokes.push_back(i);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_metaStroke[s] = ArrayOfStroke();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			ArrayOfStroke &tempAS = m_metaStroke[s];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// extract information about intersection parameter
Toshihiro Shimizu 890ddd
			ArrayOfDouble intersection;
Toshihiro Shimizu 890ddd
			extract(pair_intersection, intersection);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// now add stroke to rotate in m_info struct
Toshihiro Shimizu 890ddd
			TPointD v = s->getSpeed(intersection[0]);
Toshihiro Shimizu 890ddd
			TPointD normalToBenderSeg;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			normalToBenderSeg = m_rotationVersus * rotate90(m_benderSegment.getSpeed());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_atLeastOneIsChanged = false;
Toshihiro Shimizu 890ddd
			//m_directionIsChanged = false;
Toshihiro Shimizu 890ddd
			if (tsign(v * normalToBenderSeg) < 0) {
Toshihiro Shimizu 890ddd
				m_atLeastOneIsChanged = true;
Toshihiro Shimizu 890ddd
				m_directionIsChanged.push_back(true);
Toshihiro Shimizu 890ddd
				std::for_each(intersection.begin(), intersection.end(), one_minus_x);
Toshihiro Shimizu 890ddd
				std::reverse(intersection.begin(), intersection.end());
Toshihiro Shimizu 890ddd
				s->changeDirection();
Toshihiro Shimizu 890ddd
			} else
Toshihiro Shimizu 890ddd
				m_directionIsChanged.push_back(false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			splitStroke(*s, intersection, tempAS);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// number of curves is number of intersection plus one
Toshihiro Shimizu 890ddd
			UINT numberOfCurves = intersection.size() + 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// and begin increase of control point
Toshihiro Shimizu 890ddd
			if (isEven(intersection.size()) && m_atLeastOneIsChanged) // if solution are even
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				for (j = 0; j < numberOfCurves; ++j) {
Toshihiro Shimizu 890ddd
					if (isOdd(j))
Toshihiro Shimizu 890ddd
						increaseCP(tempAS[j], IS_ALL);
Toshihiro Shimizu 890ddd
					else
Toshihiro Shimizu 890ddd
						m_strokesToRotate.push_back(tempAS[j]);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				increaseCP(tempAS[0], IS_END);
Toshihiro Shimizu 890ddd
				for (j = 1; j < numberOfCurves - 1; ++j) {
Toshihiro Shimizu 890ddd
					if (isEven(j))
Toshihiro Shimizu 890ddd
						increaseCP(tempAS[j], IS_ALL);
Toshihiro Shimizu 890ddd
					else
Toshihiro Shimizu 890ddd
						m_strokesToRotate.push_back(tempAS[j]);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (isOdd(numberOfCurves))
Toshihiro Shimizu 890ddd
					increaseCP(tempAS.back(), IS_BEGIN);
Toshihiro Shimizu 890ddd
				else
Toshihiro Shimizu 890ddd
					m_strokesToRotate.push_back(tempAS.back());
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TStroke *tempForCorners = merge(tempAS);
Shinya Kitaoka 3bfa54
			std::vector<int> *corners = new std::vector<int>;</int></int>
Toshihiro Shimizu 890ddd
			corners->push_back(0);
Toshihiro Shimizu 890ddd
			detectCorners(tempForCorners, 20, *corners);
Toshihiro Shimizu 890ddd
			corners->push_back(tempForCorners->getChunkCount());
Toshihiro Shimizu 890ddd
			m_hitStrokeCorners[s] = corners;
Toshihiro Shimizu 890ddd
			delete tempForCorners;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!strokeToModify.empty()) {
Toshihiro Shimizu 890ddd
		UINT i, size = strokeToModify.size();
Toshihiro Shimizu 890ddd
		for (i = 0; i < size; i++)
Toshihiro Shimizu 890ddd
			if (m_directionIsChanged[i])
Toshihiro Shimizu 890ddd
				strokeToModify[i]->changeDirection();
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 UndoModifyListStroke(sl, id, strokeToModify);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (i = 0; i < size; i++)
Toshihiro Shimizu 890ddd
			if (m_directionIsChanged[i])
Toshihiro Shimizu 890ddd
				strokeToModify[i]->changeDirection();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void BenderTool::increaseCP(TStroke *tmpStroke, int beginEndOrAll)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	DoublePair extremes;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double strokeLength = tmpStroke->getLength();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double initLength = retrieveInitLength(strokeLength, beginEndOrAll);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (MY_ERROR == initLength)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TStrokeBenderDeformation deformer(tmpStroke, initLength, strokeLength * 0.5);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	increaseControlPoints(*tmpStroke, deformer, getPixelSize());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	tmpStroke->disableComputeOfCaches();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_info.push_back(benderStrokeInfo(tmpStroke, extremes, beginEndOrAll));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void BenderTool::draw()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//TAffine viewMatrix = getViewer()->getViewMatrix();
Toshihiro Shimizu 890ddd
	//glPushMatrix();
Toshihiro Shimizu 890ddd
	//tglMultMatrix(viewMatrix);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double pixelSize = getPixelSize();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	typedef std::map<tstroke *,="" arrayofstroke="">::const_iterator mapTACit;</tstroke>
Toshihiro Shimizu 890ddd
	for (mapTACit cit1 = m_metaStroke.begin(); cit1 != m_metaStroke.end(); ++cit1) {
Toshihiro Shimizu 890ddd
		const ArrayOfStroke &tmp = (*cit1).second;
Toshihiro Shimizu 890ddd
		tglColor(TPixel32::Red);
Toshihiro Shimizu 890ddd
		for (citAS cit2 = tmp.begin(); cit2 != tmp.end(); ++cit2)
Toshihiro Shimizu 890ddd
			drawStrokeCenterline(**cit2, pixelSize);
Toshihiro Shimizu 890ddd
		//drawStroke(**cit2, TRect(0,0,1000,1000), TAffine() );
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double length = m_benderSegment.getLength();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// pnt to draw rotation vector
Toshihiro Shimizu 890ddd
	TPointD pnt;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (length != 0.0) {
Toshihiro Shimizu 890ddd
		TPointD v = m_prevPoint - m_benderSegment.getP0();
Toshihiro Shimizu 890ddd
		double tmp = norm2(v);
Toshihiro Shimizu 890ddd
		if (tmp != 0.0) {
Toshihiro Shimizu 890ddd
			pnt = v * (length / sqrt(tmp));
Toshihiro Shimizu 890ddd
			pnt += m_benderSegment.getP0();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else
Toshihiro Shimizu 890ddd
		pnt = m_prevPoint;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// rotation vector
Toshihiro Shimizu 890ddd
	if (m_buttonDownCounter == 3) {
Toshihiro Shimizu 890ddd
		tglColor(TPixel::Black);
Toshihiro Shimizu 890ddd
		tglDrawSegment(m_benderSegment.getP0(), pnt);
Toshihiro Shimizu 890ddd
		drawPoint(pnt, pixelSize);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// bender vector
Toshihiro Shimizu 890ddd
	tglColor(TPixel::Red);
Toshihiro Shimizu 890ddd
	tglDrawSegment(m_benderSegment.getP0(), m_benderSegment.getP1());
Toshihiro Shimizu 890ddd
	drawPoint(m_benderSegment.getP0(), pixelSize);
Toshihiro Shimizu 890ddd
	drawPoint(m_benderSegment.getP1(), pixelSize);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// point where is mouse pointer
Toshihiro Shimizu 890ddd
	drawPoint(m_prevPoint, pixelSize);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// arrow in up direction
Toshihiro Shimizu 890ddd
	TPointD vDir = m_benderSegment.getSpeed();
Toshihiro Shimizu 890ddd
	double length2 = norm2(vDir);
Toshihiro Shimizu 890ddd
	if (length2 == 0.0) {
Toshihiro Shimizu 890ddd
		//glPopMatrix();
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	TPointD vUp = 15.0 * normalize(rotate90(vDir));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	tglColor(TPixel::Magenta);
Toshihiro Shimizu 890ddd
	TPointD middlePnt = 0.5 * (m_benderSegment.getP0() + m_benderSegment.getP1());
Toshihiro Shimizu 890ddd
	drawArrow(TSegment(middlePnt, m_rotationVersus * vUp + middlePnt), pixelSize);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//glPopMatrix();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void BenderTool::initBenderAction(TVectorImageP &vi, const TPointD &p)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// reset counter
Toshihiro Shimizu 890ddd
	// m_buttonDownCounter = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Versus of bender segment depends from
Toshihiro Shimizu 890ddd
	//  point selected to do rotation
Toshihiro Shimizu 890ddd
	// P0 is always center of rotation
Toshihiro Shimizu 890ddd
	if (tdistance2(p, m_benderSegment.getP0()) <
Toshihiro Shimizu 890ddd
		tdistance2(p, m_benderSegment.getP1())) {
Toshihiro Shimizu 890ddd
		TPointD tmpPnt = m_benderSegment.getP1();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_benderSegment.setP1(m_benderSegment.getP0());
Toshihiro Shimizu 890ddd
		m_benderSegment.setP0(tmpPnt);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// fix information about versus
Toshihiro Shimizu 890ddd
	findVersus(p);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// find curves to bender and init data structures
Toshihiro Shimizu 890ddd
	findCurves(vi);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// now it's possible set first position of rotation
Toshihiro Shimizu 890ddd
	// in the same position of extremes
Toshihiro Shimizu 890ddd
	m_benderSegment.setP1(p);
Toshihiro Shimizu 890ddd
	m_prevPoint = p;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
} //namespace
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//TTool *getBenderTool() {return &BenderTool;}