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