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
//
Toshihiro Shimizu 890ddd
// A point along a stroke: ths 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
Toshihiro Shimizu 890ddd
// the first intersection is mirroed 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
}