|
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 |
}
|
|
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 |
}
|