Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tl2lautocloser.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <qdebug></qdebug>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
#ifdef WIN32
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class MyTimer
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	bool m_enabled;
Toshihiro Shimizu 890ddd
	LARGE_INTEGER m_freq;
Toshihiro Shimizu 890ddd
	LARGE_INTEGER m_startTime, m_overhead;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	MyTimer() : m_enabled(false)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (QueryPerformanceFrequency(&m_freq)) {
Toshihiro Shimizu 890ddd
			m_enabled = true;
Toshihiro Shimizu 890ddd
			LARGE_INTEGER curTime;
Toshihiro Shimizu 890ddd
			QueryPerformanceCounter(&m_startTime);
Toshihiro Shimizu 890ddd
			QueryPerformanceCounter(&curTime);
Toshihiro Shimizu 890ddd
			m_overhead.QuadPart = curTime.QuadPart - m_startTime.QuadPart;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void start()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (!m_enabled)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		QueryPerformanceCounter(&m_startTime);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double elapsedSeconds()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		LARGE_INTEGER curTime;
Toshihiro Shimizu 890ddd
		QueryPerformanceCounter(&curTime);
Toshihiro Shimizu 890ddd
		LONGLONG microseconds = 1000000 *
Toshihiro Shimizu 890ddd
								(curTime.QuadPart - m_startTime.QuadPart - m_overhead.QuadPart) / m_freq.QuadPart;
Toshihiro Shimizu 890ddd
		return 0.000001 * (double)microseconds;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// find the stroke curvature at w
Toshihiro Shimizu 890ddd
// cfr. http://en.wikipedia.org/wiki/Curvature
Toshihiro Shimizu 890ddd
TPointD getCurvature(TStroke *stroke, double w)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const double h = 0.0001;
Toshihiro Shimizu 890ddd
	double w0 = tmax(0.0, w - h);
Toshihiro Shimizu 890ddd
	double w1 = tmin(1.0, w + h);
Toshihiro Shimizu 890ddd
	TPointD p0 = stroke->getPoint(w0);
Toshihiro Shimizu 890ddd
	TPointD p1 = stroke->getPoint(w1);
Toshihiro Shimizu 890ddd
	double ds = norm(p0 - p1);
Toshihiro Shimizu 890ddd
	double f = (w1 - w0) / ds;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD d = stroke->getSpeed(w) * f;
Toshihiro Shimizu 890ddd
	TPointD d0 = stroke->getSpeed(w0) * f;
Toshihiro Shimizu 890ddd
	TPointD d1 = stroke->getSpeed(w1) * f;
Toshihiro Shimizu 890ddd
	TPointD dd = (d1 - d0) * (1.0 / ds);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double c = (d.x * dd.y - d.y * dd.x) / pow(d.x * d.x + d.y * d.y, 1.5);
Toshihiro Shimizu 890ddd
	TPointD crv = normalize(rotate90(d)) * c;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return crv;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// A point along a stroke: ths stroke itself, pos, w,s, crv
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
struct StrokePoint {
Toshihiro Shimizu 890ddd
	double w, s;
Toshihiro Shimizu 890ddd
	TPointD pos, crv, crvdir; // crvdir is crv normalized (or 0)
Toshihiro Shimizu 890ddd
	TPointD tgdir;			  // tgdir is the normalized tangent
Toshihiro Shimizu 890ddd
	TStroke *stroke;
Toshihiro Shimizu 890ddd
	StrokePoint(TStroke *stroke_, double s_)
Toshihiro Shimizu 890ddd
		: stroke(stroke_), w(stroke_->getParameterAtLength(s_)), s(s_)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		pos = stroke->getPoint(w);
Toshihiro Shimizu 890ddd
		crv = getCurvature(stroke, w);
Toshihiro Shimizu 890ddd
		double c = norm(crv);
Toshihiro Shimizu 890ddd
		if (c > 0)
Toshihiro Shimizu 890ddd
			crvdir = crv * (1.0 / c);
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			crvdir = TPointD();
Toshihiro Shimizu 890ddd
		tgdir = stroke->getSpeed(w);
Toshihiro Shimizu 890ddd
		double tgdirNorm = norm(tgdir);
Toshihiro Shimizu 890ddd
		if (tgdirNorm > 0.000001)
Toshihiro Shimizu 890ddd
			tgdir = tgdir * (1.0 / tgdirNorm);
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			tgdir = TPointD(0, 0);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	StrokePoint()
Toshihiro Shimizu 890ddd
		: w(0), s(0), pos(), crv(), crvdir(), stroke(0)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// a set of StrokePoint evenly spaced along the whole stroke
Toshihiro Shimizu 890ddd
// (curvilinear distance between two adjacent point is "inc")
Toshihiro Shimizu 890ddd
struct StrokePointSet {
Toshihiro Shimizu 890ddd
	TStroke *stroke;
Toshihiro Shimizu 890ddd
	std::vector<strokepoint> points;</strokepoint>
Toshihiro Shimizu 890ddd
	StrokePointSet(TStroke *stroke_ = 0)
Toshihiro Shimizu 890ddd
		: stroke(stroke_)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const double inc = 5;
Toshihiro Shimizu 890ddd
		if (stroke_) {
Toshihiro Shimizu 890ddd
			double length = stroke->getLength();
Toshihiro Shimizu 890ddd
			double s = 0;
Toshihiro Shimizu 890ddd
			if (stroke->isSelfLoop())
Toshihiro Shimizu 890ddd
				length -= inc;
Toshihiro Shimizu 890ddd
			while (s < length) {
Toshihiro Shimizu 890ddd
				points.push_back(StrokePoint(stroke, s));
Toshihiro Shimizu 890ddd
				s += inc;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class StrokesIntersection
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	std::vector<double> m_ida, m_idb; // distances to the closest intersection</double>
Toshihiro Shimizu 890ddd
									  // (referred to StrokePointSet)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	StrokesIntersection() {}
Toshihiro Shimizu 890ddd
	StrokesIntersection(
Toshihiro Shimizu 890ddd
		const StrokePointSet &psa,
Toshihiro Shimizu 890ddd
		const StrokePointSet &psb,
Toshihiro Shimizu 890ddd
		const std::vector<doublepair> *intersection);</doublepair>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	~StrokesIntersection()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void update(
Toshihiro Shimizu 890ddd
		const StrokePointSet &psa,
Toshihiro Shimizu 890ddd
		const StrokePointSet &psb,
Toshihiro Shimizu 890ddd
		const std::vector<doublepair> &intersections);</doublepair>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static void wrap(std::vector<double> &is, TStroke *stroke);</double>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static void computeIntersectionDistances(
Toshihiro Shimizu 890ddd
		std::vector<double> &id,</double>
Toshihiro Shimizu 890ddd
		const StrokePointSet &ps,
Toshihiro Shimizu 890ddd
		const std::vector<double> &is);</double>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	StrokesIntersection *swapped() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		StrokesIntersection *s = new StrokesIntersection();
Toshihiro Shimizu 890ddd
		s->m_ida = m_idb;
Toshihiro Shimizu 890ddd
		s->m_idb = m_ida;
Toshihiro Shimizu 890ddd
		return s;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
StrokesIntersection::StrokesIntersection(const StrokePointSet &psa, const StrokePointSet &psb,
Toshihiro Shimizu 890ddd
										 const std::vector<doublepair> *intersections)</doublepair>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!psa.stroke || !psb.stroke)
Toshihiro Shimizu 890ddd
		return; // it should never happen
Toshihiro Shimizu 890ddd
	std::vector<doublepair> myIntersections;</doublepair>
Toshihiro Shimizu 890ddd
	if (!intersections) {
Toshihiro Shimizu 890ddd
		intersections = &myIntersections;
Toshihiro Shimizu 890ddd
		intersect(psa.stroke, psb.stroke, myIntersections);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	update(psa, psb, *intersections);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void StrokesIntersection::update(
Toshihiro Shimizu 890ddd
	const StrokePointSet &psa,
Toshihiro Shimizu 890ddd
	const StrokePointSet &psb,
Toshihiro Shimizu 890ddd
	const std::vector<doublepair> &intersections)</doublepair>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStroke *strokea = psa.stroke;
Toshihiro Shimizu 890ddd
	TStroke *strokeb = psb.stroke;
Toshihiro Shimizu 890ddd
	m_ida.clear();
Toshihiro Shimizu 890ddd
	m_idb.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!strokea || !strokeb)
Toshihiro Shimizu 890ddd
		return; // it should never happen
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_ida.resize(psa.points.size(), -1);
Toshihiro Shimizu 890ddd
	m_idb.resize(psb.points.size(), -1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int n = (int)intersections.size();
Toshihiro Shimizu 890ddd
	if (n <= 0)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// compute intersection arclengths
Toshihiro Shimizu 890ddd
	std::vector<double> isa(n), isb(n);</double>
Toshihiro Shimizu 890ddd
	for (int i = 0; i < n; i++) {
Toshihiro Shimizu 890ddd
		isa[i] = strokea->getLength(intersections[i].first);
Toshihiro Shimizu 890ddd
		isb[i] = strokeb->getLength(intersections[i].second);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (strokea == strokeb) {
Toshihiro Shimizu 890ddd
		// una sola stroke. ogni intersezione deve valere per due
Toshihiro Shimizu 890ddd
		isa.insert(isa.end(), isb.begin(), isb.end());
Toshihiro Shimizu 890ddd
		std::sort(isa.begin(), isa.end());
Toshihiro Shimizu 890ddd
		isb = isa;
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		// due stroke. ordino
Toshihiro Shimizu 890ddd
		std::sort(isa.begin(), isa.end());
Toshihiro Shimizu 890ddd
		std::sort(isb.begin(), isb.end());
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (strokea->isSelfLoop() && !isa.empty())
Toshihiro Shimizu 890ddd
		wrap(isa, strokea);
Toshihiro Shimizu 890ddd
	if (strokeb->isSelfLoop() && !isb.empty())
Toshihiro Shimizu 890ddd
		wrap(isb, strokeb);
Toshihiro Shimizu 890ddd
	computeIntersectionDistances(m_ida, psa, isa);
Toshihiro Shimizu 890ddd
	computeIntersectionDistances(m_idb, psb, isb);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// the stroke is a self loop. the last intersection is mirrored before s=0
Toshihiro Shimizu 890ddd
// the first intersection is mirroed after s=length
Toshihiro Shimizu 890ddd
void StrokesIntersection::wrap(std::vector<double> &is, TStroke *stroke)</double>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(stroke->isSelfLoop());
Toshihiro Shimizu 890ddd
	if (!is.empty()) {
Toshihiro Shimizu 890ddd
		double length = stroke->getLength();
Toshihiro Shimizu 890ddd
		is.insert(is.begin(), is.back() - length);
Toshihiro Shimizu 890ddd
		is.push_back(is[1] + length);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// for each StrokePoint computes the related intersection distance (i.e. the distance to
Toshihiro Shimizu 890ddd
// the closest intersection)
Toshihiro Shimizu 890ddd
void StrokesIntersection::computeIntersectionDistances(
Toshihiro Shimizu 890ddd
	std::vector<double> &id,</double>
Toshihiro Shimizu 890ddd
	const StrokePointSet &ps,
Toshihiro Shimizu 890ddd
	const std::vector<double> &is)</double>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	id.clear();
Toshihiro Shimizu 890ddd
	id.resize(ps.points.size(), -1);
Toshihiro Shimizu 890ddd
	int isn = (int)is.size();
Toshihiro Shimizu 890ddd
	int k = 0;
Toshihiro Shimizu 890ddd
	for (int i = 0; i < (int)ps.points.size(); i++) {
Toshihiro Shimizu 890ddd
		double d = -1;
Toshihiro Shimizu 890ddd
		if (k < isn) {
Toshihiro Shimizu 890ddd
			double s = ps.points[i].s;
Toshihiro Shimizu 890ddd
			while (k + 1 < isn && is[k + 1] < s)
Toshihiro Shimizu 890ddd
				k++;
Toshihiro Shimizu 890ddd
			if (is[k] > s)
Toshihiro Shimizu 890ddd
				d = is[k] - s;
Toshihiro Shimizu 890ddd
			else if (k + 1 < isn)
Toshihiro Shimizu 890ddd
				d = tmin(is[k + 1] - s, s - is[k]);
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				d = s - is[k];
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		id[i] = d;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class TL2LAutocloser::Imp
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	double m_maxDist2;
Toshihiro Shimizu 890ddd
	std::map<tstroke *="" *,="" strokepointset=""> m_strokes;</tstroke>
Toshihiro Shimizu 890ddd
	std::map<std::pair<tstroke *="" *,="" tstroke="">, StrokesIntersection *> m_intersections;</std::pair<tstroke>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// debug
Toshihiro Shimizu 890ddd
	std::pair<strokepointset *="" *,="" strokepointset=""> m_lastStrokePair;</strokepointset>
Toshihiro Shimizu 890ddd
	std::vector<tl2lautocloser::segment> m_segments;</tl2lautocloser::segment>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Imp() : m_maxDist2(50 * 50), m_lastStrokePair((StrokePointSet *)0, (StrokePointSet *)0) {}
Toshihiro Shimizu 890ddd
	~Imp();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	StrokePointSet *getPointSet(TStroke *stroke)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		std::map<tstroke *="" *,="" strokepointset="">::iterator it = m_strokes.find(stroke);</tstroke>
Toshihiro Shimizu 890ddd
		if (it != m_strokes.end())
Toshihiro Shimizu 890ddd
			return it->second;
Toshihiro Shimizu 890ddd
		StrokePointSet *ps = new StrokePointSet(stroke);
Toshihiro Shimizu 890ddd
		m_strokes[stroke] = ps;
Toshihiro Shimizu 890ddd
		return ps;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	StrokesIntersection *getIntersection(TStroke *strokea, TStroke *strokeb,
Toshihiro Shimizu 890ddd
										 const std::vector<doublepair> *intersection)</doublepair>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		std::map<std::pair<tstroke *="" *,="" tstroke="">, StrokesIntersection *>::iterator</std::pair<tstroke>
Toshihiro Shimizu 890ddd
			it = m_intersections.find(std::make_pair(strokea, strokeb));
Toshihiro Shimizu 890ddd
		if (it != m_intersections.end())
Toshihiro Shimizu 890ddd
			return it->second;
Toshihiro Shimizu 890ddd
		StrokesIntersection *si = new StrokesIntersection(strokea, strokeb, intersection);
Toshihiro Shimizu 890ddd
		m_intersections[std::make_pair(strokea, strokeb)] = si;
Toshihiro Shimizu 890ddd
		m_intersections[std::make_pair(strokeb, strokea)] = si->swapped();
Toshihiro Shimizu 890ddd
		return si;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void search(std::vector<tl2lautocloser::segment> &segments,</tl2lautocloser::segment>
Toshihiro Shimizu 890ddd
				TStroke *strokea, TStroke *strokeb,
Toshihiro Shimizu 890ddd
				const std::vector<doublepair> *intersection);</doublepair>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void drawLinks();
Toshihiro Shimizu 890ddd
	void drawStroke(StrokePointSet *);
Toshihiro Shimizu 890ddd
	void drawStrokes();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TL2LAutocloser::Imp::~Imp()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::map<tstroke *="" *,="" strokepointset="">::iterator i;</tstroke>
Toshihiro Shimizu 890ddd
	for (i = m_strokes.begin(); i != m_strokes.end(); ++i)
Toshihiro Shimizu 890ddd
		delete i->second;
Toshihiro Shimizu 890ddd
	std::map<std::pair<tstroke *="" *,="" tstroke="">, StrokesIntersection *>::iterator j;</std::pair<tstroke>
Toshihiro Shimizu 890ddd
	for (j = m_intersections.begin(); j != m_intersections.end(); ++j)
Toshihiro Shimizu 890ddd
		delete j->second;
Toshihiro Shimizu 890ddd
	m_strokes.clear();
Toshihiro Shimizu 890ddd
	m_intersections.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TL2LAutocloser::Imp::drawLinks()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	glColor3d(0, 0, 1);
Toshihiro Shimizu 890ddd
	glBegin(GL_LINES);
Toshihiro Shimizu 890ddd
	for (int i = 0; i < (int)m_segments.size(); i++) {
Toshihiro Shimizu 890ddd
		tglVertex(m_segments[i].p0);
Toshihiro Shimizu 890ddd
		tglVertex(m_segments[i].p1);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	glEnd();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TL2LAutocloser::Imp::drawStroke(StrokePointSet *ps)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (ps && ps->points.size() >= 2) {
Toshihiro Shimizu 890ddd
		glBegin(GL_LINES);
Toshihiro Shimizu 890ddd
		for (int i = 0; i < (int)ps->points.size(); i++)
Toshihiro Shimizu 890ddd
			tglVertex(ps->points[i].pos);
Toshihiro Shimizu 890ddd
		glEnd();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TL2LAutocloser::Imp::drawStrokes()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_lastStrokePair.first) {
Toshihiro Shimizu 890ddd
		if (m_lastStrokePair.first == m_lastStrokePair.second) {
Toshihiro Shimizu 890ddd
			glColor3d(1, 0, 1);
Toshihiro Shimizu 890ddd
			drawStroke(m_lastStrokePair.first);
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			glColor3d(1, 0, 0);
Toshihiro Shimizu 890ddd
			drawStroke(m_lastStrokePair.first);
Toshihiro Shimizu 890ddd
			glColor3d(0, 1, 0);
Toshihiro Shimizu 890ddd
			drawStroke(m_lastStrokePair.second);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// search autoclose segments
Toshihiro Shimizu 890ddd
void TL2LAutocloser::Imp::search(
Toshihiro Shimizu 890ddd
	std::vector<tl2lautocloser::segment> &segments,</tl2lautocloser::segment>
Toshihiro Shimizu 890ddd
	TStroke *strokea, TStroke *strokeb,
Toshihiro Shimizu 890ddd
	const std::vector<doublepair> *intersections)</doublepair>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_lastStrokePair.first = m_lastStrokePair.second = 0;
Toshihiro Shimizu 890ddd
	if (strokea == 0 || strokeb == 0)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	/*
Toshihiro Shimizu 890ddd
#ifdef WIN32
Toshihiro Shimizu 890ddd
  MyTimer timer;
Toshihiro Shimizu 890ddd
  qDebug() << "search started";
Toshihiro Shimizu 890ddd
  timer.start();
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
	bool sameStroke = strokea == strokeb;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	StrokePointSet *psa = getPointSet(strokea);
Toshihiro Shimizu 890ddd
	StrokePointSet *psb = sameStroke ? psa : getPointSet(strokeb);
Toshihiro Shimizu 890ddd
	m_lastStrokePair.first = psa;
Toshihiro Shimizu 890ddd
	m_lastStrokePair.second = psb;
Toshihiro Shimizu 890ddd
	StrokesIntersection *si = getIntersection(strokea, strokeb, intersections);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// find links (i.e. best matching point in psb for each point in psa)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<std::pair<int, int="">> links;</std::pair<int,>
Toshihiro Shimizu 890ddd
	int na = (int)psa->points.size();
Toshihiro Shimizu 890ddd
	int nb = (int)psb->points.size();
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < na; i++) {
Toshihiro Shimizu 890ddd
		double minDist2 = 0;
Toshihiro Shimizu 890ddd
		int k = -1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int j0 = 0;
Toshihiro Shimizu 890ddd
		if (sameStroke)
Toshihiro Shimizu 890ddd
			j0 = i + 1;
Toshihiro Shimizu 890ddd
		for (int j = 0; j < nb; j++) {
Toshihiro Shimizu 890ddd
			TPointD delta = psb->points[j].pos - psa->points[i].pos;
Toshihiro Shimizu 890ddd
			double dist2 = norm2(delta);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (dist2 > m_maxDist2)
Toshihiro Shimizu 890ddd
				continue;
Toshihiro Shimizu 890ddd
			if (dist2 < 0.000001)
Toshihiro Shimizu 890ddd
				continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double dist = sqrt(dist2);
Toshihiro Shimizu 890ddd
			delta = delta * (1.0 / dist);
Toshihiro Shimizu 890ddd
			double cs = 0.005;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if ((psa->points[i].crvdir * delta) > -cs)
Toshihiro Shimizu 890ddd
				continue;
Toshihiro Shimizu 890ddd
			if ((psb->points[j].crvdir * delta) < cs)
Toshihiro Shimizu 890ddd
				continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (sameStroke) {
Toshihiro Shimizu 890ddd
				double ds = fabs(psa->points[i].s - psb->points[j].s);
Toshihiro Shimizu 890ddd
				if (ds < dist * 1.5)
Toshihiro Shimizu 890ddd
					continue;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			if ((si->m_ida[i] > 0 && si->m_ida[i] < dist) || (si->m_idb[j] > 0 && si->m_idb[j] < dist))
Toshihiro Shimizu 890ddd
				continue;
Toshihiro Shimizu 890ddd
			if (k < 0 || dist2 < minDist2) {
Toshihiro Shimizu 890ddd
				k = j;
Toshihiro Shimizu 890ddd
				minDist2 = dist2;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		if (k >= 0 && (!sameStroke || k > i) && (0 < i && i < na - 1) && (0 < k && k < nb - 1)) {
Toshihiro Shimizu 890ddd
			links.push_back(std::make_pair(i, k));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	/*
Toshihiro Shimizu 890ddd
  for(i=0;i<(int)links.size();i++)
Toshihiro Shimizu 890ddd
  {
Toshihiro Shimizu 890ddd
    int ia = links[i].first;
Toshihiro Shimizu 890ddd
    int ib = links[i].second;
Toshihiro Shimizu 890ddd
    double mind2 = norm2(psa->points[ia].pos - psb->points[ib].pos);
Toshihiro Shimizu 890ddd
    TL2LAutocloser::Segment segment;
Toshihiro Shimizu 890ddd
    segment.stroke0 = strokea;
Toshihiro Shimizu 890ddd
    segment.stroke1 = strokeb;
Toshihiro Shimizu 890ddd
    segment.w0 = psa->points[ia].w;
Toshihiro Shimizu 890ddd
    segment.w1 = psb->points[ib].w;
Toshihiro Shimizu 890ddd
    segment.p0 = strokea->getThickPoint(segment.w0);
Toshihiro Shimizu 890ddd
    segment.p1 = strokeb->getThickPoint(segment.w1);
Toshihiro Shimizu 890ddd
    segment.dist2 = mind2;
Toshihiro Shimizu 890ddd
    segments.push_back(segment);
Toshihiro Shimizu 890ddd
  }
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// select best links
Toshihiro Shimizu 890ddd
	for (i = 0; i < (int)links.size(); i++) {
Toshihiro Shimizu 890ddd
		int ia = links[i].first;
Toshihiro Shimizu 890ddd
		int ib = links[i].second;
Toshihiro Shimizu 890ddd
		double d2 = norm2(psa->points[ia].pos - psb->points[ib].pos);
Toshihiro Shimizu 890ddd
		double mind2 = d2;
Toshihiro Shimizu 890ddd
		int k = i;
Toshihiro Shimizu 890ddd
		while (i + 1 < (int)links.size()) {
Toshihiro Shimizu 890ddd
			int ia2 = links[i + 1].first;
Toshihiro Shimizu 890ddd
			int ib2 = links[i + 1].second;
Toshihiro Shimizu 890ddd
			double d22 = norm2(psa->points[ia2].pos - psb->points[ib2].pos);
Toshihiro Shimizu 890ddd
			double d2m = (d2 + d22) * 0.5;
Toshihiro Shimizu 890ddd
			double dsa = psa->points[ia2].s - psa->points[ia].s;
Toshihiro Shimizu 890ddd
			double dsb = psb->points[ib2].s - psb->points[ib].s;
Toshihiro Shimizu 890ddd
			if (dsa * dsa > d2m || dsb * dsb > d2m)
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			if (d22 < mind2) {
Toshihiro Shimizu 890ddd
				mind2 = d22;
Toshihiro Shimizu 890ddd
				k = i + 1;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			ia = ia2;
Toshihiro Shimizu 890ddd
			ib = ib2;
Toshihiro Shimizu 890ddd
			d2 = d22;
Toshihiro Shimizu 890ddd
			i++;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		ia = links[k].first;
Toshihiro Shimizu 890ddd
		ib = links[k].second;
Toshihiro Shimizu 890ddd
		TL2LAutocloser::Segment segment;
Toshihiro Shimizu 890ddd
		segment.stroke0 = strokea;
Toshihiro Shimizu 890ddd
		segment.stroke1 = strokeb;
Toshihiro Shimizu 890ddd
		segment.w0 = psa->points[ia].w;
Toshihiro Shimizu 890ddd
		segment.w1 = psb->points[ib].w;
Toshihiro Shimizu 890ddd
		segment.p0 = strokea->getThickPoint(segment.w0);
Toshihiro Shimizu 890ddd
		segment.p1 = strokeb->getThickPoint(segment.w1);
Toshihiro Shimizu 890ddd
		segment.dist2 = mind2;
Toshihiro Shimizu 890ddd
		segments.push_back(segment);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	/*
Toshihiro Shimizu 890ddd
#ifdef WIN32
Toshihiro Shimizu 890ddd
  double elapsed = timer.elapsedSeconds();
Toshihiro Shimizu 890ddd
  qDebug() << "search completed. time=" << elapsed << "s";
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
 */
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TL2LAutocloser::TL2LAutocloser()
Toshihiro Shimizu 890ddd
	: m_imp(new Imp())
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TL2LAutocloser::~TL2LAutocloser()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	delete m_imp;
Toshihiro Shimizu 890ddd
	m_imp = 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TL2LAutocloser::setMaxDistance2(double dist2)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_imp->m_maxDist2 = dist2;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
double TL2LAutocloser::getMaxDistance2() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_imp->m_maxDist2;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TL2LAutocloser::search(std::vector<segment> &segments, TStroke *stroke0, TStroke *stroke1)</segment>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (stroke0 && stroke1)
Toshihiro Shimizu 890ddd
		m_imp->search(segments, stroke0, stroke1, 0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TL2LAutocloser::search(
Toshihiro Shimizu 890ddd
	std::vector<segment> &segments,</segment>
Toshihiro Shimizu 890ddd
	TStroke *stroke0, TStroke *stroke1,
Toshihiro Shimizu 890ddd
	const std::vector<doublepair> &intersection)</doublepair>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (stroke0 && stroke1)
Toshihiro Shimizu 890ddd
		m_imp->search(segments, stroke0, stroke1, &intersection);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void TL2LAutocloser::draw()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_imp->drawStrokes();
Toshihiro Shimizu 890ddd
	m_imp->drawLinks();
Toshihiro Shimizu 890ddd
}