Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tmachine.h"
Toshihiro Shimizu 890ddd
#include "tmathutil.h"
Toshihiro Shimizu 890ddd
#include "tstrokeutil.h"
Toshihiro Shimizu 890ddd
#include "tstrokeoutline.h"
Toshihiro Shimizu 890ddd
#include "tcurves.h"
Toshihiro Shimizu 890ddd
#include "tbezier.h"
Toshihiro Shimizu 890ddd
#include "tzerofinder.h"
Toshihiro Shimizu 890ddd
#include "tcurveutil.h"
Campbell Barton 8c6c57
#include "cornerdetector.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <limits>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define USE_NEW_3D_ERROR_COMPUTE 1
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Some using declaration
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace TConsts;
Toshihiro Shimizu 890ddd
using namespace std;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Some useful typedefs
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef std::vector<double> DoubleArray;
Toshihiro Shimizu 890ddd
typedef DoubleArray::iterator DoubleIt;
Toshihiro Shimizu 890ddd
typedef std::vector<TThickQuadratic *> QuadStrokeChunkArray;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
static int numSaved = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void extractStrokeControlPoints(const QuadStrokeChunkArray &curves,
Shinya Kitaoka 120a6e
                                vector<TThickPoint> &ctrlPnts) {
Shinya Kitaoka 120a6e
  const TThickQuadratic *prev = curves[0];
Shinya Kitaoka 120a6e
  assert(prev);
Shinya Kitaoka 120a6e
  const TThickQuadratic *curr;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ctrlPnts.push_back(prev->getThickP0());
Shinya Kitaoka 120a6e
  ctrlPnts.push_back(prev->getThickP1());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (UINT i = 1; i < curves.size(); ++i) {
Shinya Kitaoka 120a6e
    curr = curves[i];
Shinya Kitaoka 120a6e
    assert(curr);
Shinya Kitaoka 120a6e
    TThickPoint middlePnt = (prev->getThickP2() + curr->getThickP0()) * 0.5;
Shinya Kitaoka 120a6e
    ctrlPnts.push_back(middlePnt);
Shinya Kitaoka 120a6e
    ctrlPnts.push_back(curr->getThickP1());
Shinya Kitaoka 120a6e
    prev = curr;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ctrlPnts.push_back(prev->getThickP2());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline TThickPoint adapter(const TThickPoint &tp) { return tp; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline TThickPoint adapter(const TPointD &p) { return TThickPoint(p); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename T>
Toshihiro Shimizu 890ddd
void buildChunksFromControlPoints(QuadStrokeChunkArray &tq,
Shinya Kitaoka 120a6e
                                  const vector<T> &v) {
Shinya Kitaoka 120a6e
  TThickQuadratic *chunk;
Shinya Kitaoka 120a6e
  T temp;
Shinya Kitaoka 120a6e
  switch (v.size()) {
Shinya Kitaoka 120a6e
  case 0:
Shinya Kitaoka 120a6e
    tq.push_back(new TThickQuadratic);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case 1:
Shinya Kitaoka 120a6e
    temp  = adapter(v.front());
Shinya Kitaoka 120a6e
    chunk = new TThickQuadratic(temp, temp, temp);
Shinya Kitaoka 120a6e
    tq.push_back(chunk);
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case 2: {
Shinya Kitaoka 120a6e
    TThickSegment s(adapter(v.front()), adapter(v.back()));
Shinya Kitaoka 120a6e
    chunk = new TThickQuadratic(s.getThickP0(), s.getThickPoint(0.5),
Shinya Kitaoka 120a6e
                                s.getThickP1());
Shinya Kitaoka 120a6e
    tq.push_back(chunk);
Shinya Kitaoka 120a6e
  } break;
Shinya Kitaoka 120a6e
  default:
Shinya Kitaoka 120a6e
    assert(v.size() & 1);  //  v.size() == 2 * chunk + 1
Shinya Kitaoka 120a6e
    for (UINT i = 0; i < v.size() - 1; i += 2) {
Shinya Kitaoka 120a6e
      chunk = new TThickQuadratic(adapter(v[i]), adapter(v[i + 1]),
Shinya Kitaoka 120a6e
                                  adapter(v[i + 2]));
Shinya Kitaoka 120a6e
      tq.push_back(chunk);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// WARNING  duplicata in tellipticbrush
Toshihiro Shimizu 890ddd
//  dovrebbe essere eliminata da tellipticbrush perche' qui
Toshihiro Shimizu 890ddd
//  viene usata per  eliminare le strokes a thickness negativa
Toshihiro Shimizu 890ddd
//  evitandone la gestione in tellip...
Shinya Kitaoka 120a6e
inline bool pairValuesAreEqual(const DoublePair &p) {
Shinya Kitaoka 120a6e
  return p.first == p.second;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// WARNING  duplicata in tellipticbrush
Toshihiro Shimizu 890ddd
//  dovrebbe essere eliminata da tellipticbrush perche' qui
Toshihiro Shimizu 890ddd
//  viene usata per  eliminare le strokes a thickness negativa
Toshihiro Shimizu 890ddd
//  evitandone la gestione in tellip...
Shinya Kitaoka 120a6e
void analyzeSolution(const vector<double> &coeff,
Shinya Kitaoka 120a6e
                     vector<DoublePair> &interval) {
Shinya Kitaoka 120a6e
  //  risolve la disequazione  coeff[2]*t^2 + coeff[1]*t + coeff[0] >= 0  in [0,
Shinya Kitaoka 120a6e
  //  1] ritornando le soluzioni
Shinya Kitaoka 120a6e
  //  come sotto-intervalli chiusi di [0, 1] (gli intervalli degeneri [s, s]
Shinya Kitaoka 120a6e
  //  isolati vengono eliminati)
Shinya Kitaoka 120a6e
  vector<double> sol;
Shinya Kitaoka 120a6e
  // int numberOfIntervalSolution = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  rootFinding(coeff, sol);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (isAlmostZero(coeff[2])) {
Shinya Kitaoka 120a6e
    //  disequazione di 1^ grado
Shinya Kitaoka 120a6e
    if (isAlmostZero(coeff[1])) {
Shinya Kitaoka 120a6e
      if (coeff[0] >= 0) interval.push_back(DoublePair(0.0, 1.0));
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double singleSol = -coeff[0] / coeff[1];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (coeff[1] > 0) {
Shinya Kitaoka 120a6e
      if (singleSol < 1)
Shinya Kitaoka 120a6e
        interval.push_back(DoublePair(std::max(0.0, singleSol), 1.0));
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      if (singleSol > 0)
Shinya Kitaoka 120a6e
        interval.push_back(DoublePair(0.0, std::min(1.0, singleSol)));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //  disequazione di 2^ grado effettivo
Shinya Kitaoka 120a6e
  // double delta = sq(coeff[1]) - 4*coeff[2]*coeff[0];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  sort(sol.begin(), sol.end());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (coeff[2] > 0) {
Shinya Kitaoka 120a6e
    switch (sol.size()) {
Shinya Kitaoka 120a6e
    case 0:
Shinya Kitaoka 120a6e
      interval.push_back(DoublePair(0.0, 1.0));
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    case 1:
Shinya Kitaoka 120a6e
      interval.push_back(DoublePair(0.0, 1.0));
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    case 2:
Shinya Kitaoka 120a6e
      interval.push_back(DoublePair(0.0, std::min(std::max(sol[0], 0.0), 1.0)));
Shinya Kitaoka 120a6e
      interval.push_back(DoublePair(std::max(std::min(sol[1], 1.0), 0.0), 1.0));
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (coeff[2] < 0 && sol.size() == 2)
Shinya Kitaoka 120a6e
    interval.push_back(DoublePair(std::min(std::max(sol[0], 0.0), 1.0),
Shinya Kitaoka 120a6e
                                  std::max(std::min(sol[1], 1.0), 0.0)));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // eat not valid interval
Shinya Kitaoka 120a6e
  std::vector<DoublePair>::iterator it =
Shinya Kitaoka 120a6e
      std::remove_if(interval.begin(), interval.end(), pairValuesAreEqual);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  interval.erase(it, interval.end());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void floorNegativeThickness(TThickQuadratic *quad) {
Shinya Kitaoka 120a6e
  assert(quad);
Shinya Kitaoka 120a6e
  double val = quad->getThickP0().thick;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (val < 0 && isAlmostZero(val))
Shinya Kitaoka 120a6e
    quad->setThickP0(TThickPoint(quad->getP0(), 0.0));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  val = quad->getThickP1().thick;
Shinya Kitaoka 120a6e
  if (val < 0 && isAlmostZero(val))
Shinya Kitaoka 120a6e
    quad->setThickP1(TThickPoint(quad->getP1(), 0.0));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  val = quad->getThickP2().thick;
Shinya Kitaoka 120a6e
  if (val < 0 && isAlmostZero(val))
Shinya Kitaoka 120a6e
    quad->setThickP2(TThickPoint(quad->getP2(), 0.0));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// potrebbe essere realizzata come unary function da usare in una transform
Shinya Kitaoka 120a6e
void roundNegativeThickess(QuadStrokeChunkArray &v) {
Shinya Kitaoka 120a6e
  QuadStrokeChunkArray protoStroke, tempVectTQ;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThickQuadratic *tempTQ = 0, *tempTQ_1 = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int chunkCount = v.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  vector<double> coeff;
Shinya Kitaoka 120a6e
  double alpha, beta, gamma;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  vector<DoublePair> positiveIntervals;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < chunkCount; ++i) {
Shinya Kitaoka 120a6e
    const TThickQuadratic &ttq = *v[i];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    alpha = ttq.getThickP0().thick - 2 * ttq.getThickP1().thick +
Shinya Kitaoka 120a6e
            ttq.getThickP2().thick;
Shinya Kitaoka 120a6e
    beta  = 2.0 * (ttq.getThickP1().thick - ttq.getThickP0().thick);
Shinya Kitaoka 120a6e
    gamma = ttq.getThickP0().thick;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    coeff.push_back(gamma);
Shinya Kitaoka 120a6e
    coeff.push_back(beta);
Shinya Kitaoka 120a6e
    coeff.push_back(alpha);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    //  return sotto-intervalli non degeneri di [0, 1] in cui coeff[2]*t^2 +
Shinya Kitaoka 120a6e
    //  coeff[1]*t + coeff[0] >= 0
Shinya Kitaoka 120a6e
    analyzeSolution(coeff, positiveIntervals);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    //  il caso isAlmostZero(r(t)) per t in [0, 1] e' gestito direttamente da
Shinya Kitaoka 120a6e
    //  computeOutline
Shinya Kitaoka 120a6e
    switch (positiveIntervals.size()) {
Shinya Kitaoka 120a6e
    case 0:  //  r(t) <= 0 per t in [0, 1]
Shinya Kitaoka 120a6e
      tempTQ = new TThickQuadratic(ttq);
Shinya Kitaoka 120a6e
      tempTQ->setThickP0(TThickPoint(tempTQ->getP0(), 0.0));
Shinya Kitaoka 120a6e
      tempTQ->setThickP1(TThickPoint(tempTQ->getP1(), 0.0));
Shinya Kitaoka 120a6e
      tempTQ->setThickP2(TThickPoint(tempTQ->getP2(), 0.0));
Shinya Kitaoka 120a6e
      protoStroke.push_back(tempTQ);
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case 1:
Shinya Kitaoka 120a6e
      if (positiveIntervals[0].first == 0.0 &&
Shinya Kitaoka 120a6e
          positiveIntervals[0].second == 1.0)
Shinya Kitaoka 120a6e
        protoStroke.push_back(new TThickQuadratic(ttq));
Shinya Kitaoka 120a6e
      else if (positiveIntervals[0].first == 0.0) {
Shinya Kitaoka 120a6e
        tempTQ   = new TThickQuadratic;
Shinya Kitaoka 120a6e
        tempTQ_1 = new TThickQuadratic;
Shinya Kitaoka 120a6e
        ttq.split(positiveIntervals[0].first, *tempTQ, *tempTQ_1);
Shinya Kitaoka 120a6e
        tempTQ_1->setThickP0(TThickPoint(tempTQ_1->getP0(), 0.0));
Shinya Kitaoka 120a6e
        tempTQ_1->setThickP1(TThickPoint(tempTQ_1->getP1(), 0.0));
Shinya Kitaoka 120a6e
        tempTQ_1->setThickP2(TThickPoint(tempTQ_1->getP2(), 0.0));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        floorNegativeThickness(tempTQ);
Shinya Kitaoka 120a6e
        protoStroke.push_back(tempTQ);
Shinya Kitaoka 120a6e
        protoStroke.push_back(tempTQ_1);
Shinya Kitaoka 120a6e
      } else if (positiveIntervals[0].second == 1.0) {
Shinya Kitaoka 120a6e
        tempTQ   = new TThickQuadratic;
Shinya Kitaoka 120a6e
        tempTQ_1 = new TThickQuadratic;
Shinya Kitaoka 120a6e
        ttq.split(positiveIntervals[0].first, *tempTQ, *tempTQ_1);
Shinya Kitaoka 120a6e
        tempTQ->setThickP0(TThickPoint(tempTQ->getP0(), 0.0));
Shinya Kitaoka 120a6e
        tempTQ->setThickP1(TThickPoint(tempTQ->getP1(), 0.0));
Shinya Kitaoka 120a6e
        tempTQ->setThickP2(TThickPoint(tempTQ->getP2(), 0.0));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        protoStroke.push_back(tempTQ);
Shinya Kitaoka 120a6e
        floorNegativeThickness(tempTQ_1);
Shinya Kitaoka 120a6e
        protoStroke.push_back(tempTQ_1);
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        coeff.clear();
Shinya Kitaoka 120a6e
        coeff.push_back(positiveIntervals[0].first);
Shinya Kitaoka 120a6e
        coeff.push_back(positiveIntervals[0].second);
Shinya Kitaoka 120a6e
        split<TThickQuadratic>(ttq, coeff, tempVectTQ);
Shinya Kitaoka 120a6e
        assert(tempVectTQ.size() == 3);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        tempVectTQ[0]->setThickP0(TThickPoint(tempVectTQ[0]->getP0(), 0.0));
Shinya Kitaoka 120a6e
        tempVectTQ[0]->setThickP1(TThickPoint(tempVectTQ[0]->getP1(), 0.0));
Shinya Kitaoka 120a6e
        tempVectTQ[0]->setThickP2(TThickPoint(tempVectTQ[0]->getP2(), 0.0));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // controllo che i valori prossimi a zero siano in ogni caso positivi
Shinya Kitaoka 120a6e
        floorNegativeThickness(tempVectTQ[1]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        tempVectTQ[2]->setThickP0(TThickPoint(tempVectTQ[2]->getP0(), 0.0));
Shinya Kitaoka 120a6e
        tempVectTQ[2]->setThickP1(TThickPoint(tempVectTQ[2]->getP1(), 0.0));
Shinya Kitaoka 120a6e
        tempVectTQ[2]->setThickP2(TThickPoint(tempVectTQ[2]->getP2(), 0.0));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        copy(tempVectTQ.begin(), tempVectTQ.end(), back_inserter(protoStroke));
Shinya Kitaoka 120a6e
        tempVectTQ
Shinya Kitaoka 120a6e
            .clear();  // non serve una clearPointerArray perchè il possesso
Shinya Kitaoka 120a6e
                       // va alla protoStroke
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    case 2:
Shinya Kitaoka 120a6e
      assert(positiveIntervals[0].first == 0.0);
Shinya Kitaoka 120a6e
      assert(positiveIntervals[1].second == 1.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      coeff.clear();
Shinya Kitaoka 120a6e
      coeff.push_back(positiveIntervals[0].second);
Shinya Kitaoka 120a6e
      coeff.push_back(positiveIntervals[1].first);
Shinya Kitaoka 120a6e
      split<TThickQuadratic>(ttq, coeff, tempVectTQ);
Shinya Kitaoka 120a6e
      assert(tempVectTQ.size() == 3);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      floorNegativeThickness(tempVectTQ[0]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      tempVectTQ[1]->setThickP0(TThickPoint(tempVectTQ[1]->getP0(), 0.0));
Shinya Kitaoka 120a6e
      tempVectTQ[1]->setThickP1(TThickPoint(tempVectTQ[1]->getP1(), 0.0));
Shinya Kitaoka 120a6e
      tempVectTQ[1]->setThickP2(TThickPoint(tempVectTQ[1]->getP2(), 0.0));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      floorNegativeThickness(tempVectTQ[2]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      copy(tempVectTQ.begin(), tempVectTQ.end(), back_inserter(protoStroke));
Shinya Kitaoka 120a6e
      tempVectTQ.clear();  // non serve una clearPointerArray perchè il possesso
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    positiveIntervals.clear();
Shinya Kitaoka 120a6e
    coeff.clear();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  swap(protoStroke, v);
Shinya Kitaoka 120a6e
  clearPointerContainer(protoStroke);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Some usefuf constant
Toshihiro Shimizu 890ddd
// used in printContainer to set number of row to print
Toshihiro Shimizu 890ddd
const int MAX_ROW = 10;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline void changeTQDirection(TThickQuadratic *tq) {
Shinya Kitaoka 120a6e
  TThickPoint p = tq->getThickP2();
Shinya Kitaoka 120a6e
  tq->setThickP2(tq->getThickP0());
Shinya Kitaoka 120a6e
  tq->setThickP0(p);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
  //---------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double getTQDistance2(const TThickQuadratic& tq,
Shinya Kitaoka 120a6e
    const TPointD& p,
Shinya Kitaoka 120a6e
    double maxDistance2,
Toshihiro Shimizu 890ddd
    double& currT)
Toshihiro Shimizu 890ddd
  {
Toshihiro Shimizu 890ddd
    TRectD rect = tq.getBBox();
Toshihiro Shimizu 890ddd
    if (!rect.contains(p))
Toshihiro Shimizu 890ddd
    {
Toshihiro Shimizu 890ddd
      double dist21 = tdistance2(p, rect.getP00());
Toshihiro Shimizu 890ddd
      double dist22 = tdistance2(p, rect.getP01());
Toshihiro Shimizu 890ddd
      double dist23 = tdistance2(p, rect.getP10());
Toshihiro Shimizu 890ddd
      double dist24 = tdistance2(p, rect.getP11());
Shinya Kitaoka 120a6e
Shinya Kitaoka 12c444
      if (std::min(dist21, dist22, dist23, dist24)>=maxDistance2)
Toshihiro Shimizu 890ddd
        return maxDistance2;
Toshihiro Shimizu 890ddd
    }
Toshihiro Shimizu 890ddd
    currT = tq.getT(p);
Shinya Kitaoka 120a6e
    double dist2 = tdistance2(tq.getPoint(currT), p);
Toshihiro Shimizu 890ddd
    return (dist2<maxDistance2)?dist2:maxDistance2;
Toshihiro Shimizu 890ddd
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  //---------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  template <class K, class T>
Toshihiro Shimizu 890ddd
    void clearMap(std::map<K,T>& v)
Toshihiro Shimizu 890ddd
  {
Toshihiro Shimizu 890ddd
    typedef std::map<K,T>::iterator TypeIt;
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
    TypeIt it = v.begin();
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
    for( ;it!=v.end(); ++it)
Toshihiro Shimizu 890ddd
      delete it->second;
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
    v.clear();
Toshihiro Shimizu 890ddd
  }
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
  Local binary function to find approx values in a vector.
Toshihiro Shimizu 890ddd
  */
Shinya Kitaoka 120a6e
bool bfAreAlmostEqual(double x, double y) {
Shinya Kitaoka 120a6e
  double x_y = (x > y) ? x - y : y - x;
Shinya Kitaoka 120a6e
  return x_y < TConsts::epsilon;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
  Sends values of a container in standard input.
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
template <class T>
Shinya Kitaoka 120a6e
void printContainer(const T &c, int maxRow = MAX_ROW) {
Shinya Kitaoka 120a6e
  /*  DA DECOMMENTARE SE NECESSARIO!!!!!
Shinya Kitaoka 120a6e
      //(commentato per non avere dipendenze da tsystem.lib 7/1/2004)
Shinya Kitaoka 120a6e
if (maxRow <=0 ) maxRow = MAX_ROW;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
typename T::const_iterator cit;
Shinya Kitaoka 120a6e
cit = c.begin();
Shinya Kitaoka 120a6e
ostrstream  oss1;
Shinya Kitaoka 120a6e
oss1<<'['<<c.size()<<']'<<"=\n";
Shinya Kitaoka 120a6e
TSystem::outputDebug( oss1.str() );
Shinya Kitaoka 120a6e
oss1.freeze(false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int counter = 0;
Shinya Kitaoka 120a6e
for( ; cit != c.end(); ++cit)
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
ostrstream  oss;
Shinya Kitaoka 120a6e
if( ++counter == maxRow-1)
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
  oss<<'\n';
Shinya Kitaoka 120a6e
  counter = 0;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
oss<<(*cit)<<'\n'<<'\0';
Shinya Kitaoka 120a6e
TSystem::outputDebug( oss.str() );
Shinya Kitaoka 120a6e
oss.freeze(false);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
          */
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <class T>
Shinya Kitaoka 120a6e
void printContainer(ostream &os, const T &c, int maxRow = MAX_ROW) {
Shinya Kitaoka 120a6e
  if (maxRow <= 0) maxRow = MAX_ROW;
Shinya Kitaoka 120a6e
  typename T::const_iterator cit;
Shinya Kitaoka 120a6e
  cit = c.begin();
Shinya Kitaoka 120a6e
  os << '[' << c.size() << ']' << "=\n";
Shinya Kitaoka 120a6e
  int counter = 0;
Shinya Kitaoka 120a6e
  for (; cit != c.end(); ++cit) {
Shinya Kitaoka 120a6e
    if (++counter == maxRow - 1) {
Shinya Kitaoka 120a6e
      os << '\n';
Shinya Kitaoka 120a6e
      counter = 0;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    os << (*cit) << ' ';
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <class T>
Shinya Kitaoka 120a6e
void printContainerOfPointer(ostream &os, const T &c, int maxRow = MAX_ROW) {
Shinya Kitaoka 120a6e
  if (maxRow <= 0) maxRow = MAX_ROW;
Shinya Kitaoka 120a6e
  typename T::const_iterator cit;
Shinya Kitaoka 120a6e
  cit = c.begin();
Shinya Kitaoka 120a6e
  os << '[' << c.size() << ']' << " - ";
Shinya Kitaoka 120a6e
  int counter = 0;
Shinya Kitaoka 120a6e
  for (; cit != c.end(); ++cit) {
Shinya Kitaoka 120a6e
    if (++counter == maxRow - 1) {
Shinya Kitaoka 120a6e
      os << '\n';
Shinya Kitaoka 120a6e
      counter = 0;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    os << **cit << ' ';
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
  Compute a proportion of type x:a=b:c
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
template <class T>
Shinya Kitaoka 120a6e
T proportion(T a, T b, T c) {
Shinya Kitaoka 120a6e
  assert(c != T(0));
Shinya Kitaoka 120a6e
  return a * b / c;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
  Compute a proportion of type x-off:a-off=b:c
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
template <class T>
Shinya Kitaoka 120a6e
T proportion(T a, T b, T c, T offset) {
Shinya Kitaoka 120a6e
  assert(c != T(0));
Shinya Kitaoka 120a6e
  return (a - offset) * b / c + offset;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Toshihiro Shimizu 890ddd
    backinserter
Toshihiro Shimizu 890ddd
   */
Shinya Kitaoka 120a6e
template <typename type_, typename container_>
Shinya Kitaoka 120a6e
class TBackInserterPointer {
Shinya Kitaoka 120a6e
  container_ &m_c;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  explicit TBackInserterPointer(container_ &c) : m_c(c){};
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TBackInserterPointer &operator=(const type_ *value) {
Shinya Kitaoka 120a6e
    m_c.push_back(new type_(*value));
Shinya Kitaoka 120a6e
    return *this;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TBackInserterPointer &operator=(const type_ &value) {
Shinya Kitaoka 120a6e
    m_c.push_back(new type_(value));
Shinya Kitaoka 120a6e
    return *this;
Shinya Kitaoka 120a6e
  };
Toshihiro Shimizu 890ddd
#ifdef MACOSX
Shinya Kitaoka 120a6e
  typedef type_ value_type;
Shinya Kitaoka 120a6e
  typedef type_ &reference;
Shinya Kitaoka 120a6e
  typedef type_ *pointer;
Shinya Kitaoka 120a6e
  typedef output_iterator_tag iterator_category;
Shinya Kitaoka 120a6e
  typedef ptrdiff_t difference_type;
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  /* SIC */
Shinya Kitaoka 120a6e
  TBackInserterPointer &operator*() { return *this; }
Shinya Kitaoka 120a6e
  TBackInserterPointer &operator++() { return *this; }
Shinya Kitaoka 120a6e
  TBackInserterPointer operator++(int val) { return *this; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
typedef TBackInserterPointer<TThickQuadratic, QuadStrokeChunkArray>
Shinya Kitaoka 120a6e
    TThickQuadraticArrayInsertIterator;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Toshihiro Shimizu 890ddd
  simple adapter for find zero algorithm
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
struct computeOffset_ {
Shinya Kitaoka 120a6e
  TQuadraticLengthEvaluator m_lengthEval;
Shinya Kitaoka 120a6e
  double m_offset;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  computeOffset_(const TThickQuadratic *ttq, double offset)
Shinya Kitaoka 120a6e
      : m_lengthEval(*ttq), m_offset(offset) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double operator()(double par) {
Shinya Kitaoka 120a6e
    return m_lengthEval.getLengthAt(par) - m_offset;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Toshihiro Shimizu 890ddd
  simple adapter for find zero algorithm
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
struct computeSpeed_ {
Shinya Kitaoka 120a6e
  const TThickQuadratic *ref_;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  computeSpeed_(const TThickQuadratic *ref) : ref_(ref) {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double operator()(double par) { return norm(ref_->getSpeed(par)); }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Shinya Kitaoka 120a6e
}  // end of unnamed namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
const BYTE TStroke::c_selected_flag       = 0x1;
Toshihiro Shimizu 890ddd
const BYTE TStroke::c_changed_region_flag = 0x2;
Shinya Kitaoka 120a6e
const BYTE TStroke::c_dirty_flag          = 0x4;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// TStroke::Imp
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct TStroke::Imp {
Shinya Kitaoka 120a6e
  // Geometry-related infos
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  BYTE m_flag;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //! This flag checks if changes occurs and if it is neccessary to update
Shinya Kitaoka 120a6e
  //! lenght.
Shinya Kitaoka 120a6e
  bool m_isValidLength;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //! This flag checks if changes occurs and if it is neccessary to update
Shinya Kitaoka 120a6e
  //! outline.
Shinya Kitaoka 120a6e
  bool m_isOutlineValid;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //! Control calculus of cache vector.
Shinya Kitaoka 120a6e
  bool m_areDisabledComputeOfCaches;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //! Bounding Box of a stroke
Shinya Kitaoka 120a6e
  TRectD m_bBox;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //! This vector contains length computed for  each control point of stroke.
Shinya Kitaoka 120a6e
  DoubleArray m_partialLenghtArray;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //! This vector contains parameter computed for each control point of stroke.
Shinya Kitaoka 120a6e
  DoubleArray m_parameterValueAtControlPoint;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //! This vector contains outline of stroke.
Shinya Kitaoka 120a6e
  QuadStrokeChunkArray m_centerLineArray;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool m_selfLoop;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int m_negativeThicknessPoints;
Shinya Kitaoka 120a6e
  double m_averageThickness;
Shinya Kitaoka 120a6e
  double m_maxThickness;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //-------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Not-geometrical vars (style infos)
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int m_id;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int m_styleId;
Shinya Kitaoka 120a6e
  TStrokeProp *m_prop;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TStroke::OutlineOptions m_outlineOptions;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //-------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  Imp();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  Imp(const vector<TPointD> &v);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  Imp(const vector<TThickPoint> &v);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  ~Imp() {
Shinya Kitaoka 120a6e
    delete m_prop;
Shinya Kitaoka 120a6e
    clearPointerContainer(m_centerLineArray);
Shinya Kitaoka 120a6e
    // delete m_style;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void init();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // void  computeOutlines( double pixelSize );
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  inline double getW(int index) {
Shinya Kitaoka 120a6e
    return ((int)m_parameterValueAtControlPoint.size() > index)
Shinya Kitaoka 120a6e
               ? m_parameterValueAtControlPoint[index]
Shinya Kitaoka 120a6e
               : m_parameterValueAtControlPoint.back();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRectD computeCenterlineBBox();
Shinya Kitaoka 120a6e
  /*!
Shinya Kitaoka 120a6e
It computes the bounding box of the subStroke in the parameter range w0-w1.
Shinya Kitaoka 120a6e
*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void computeMaxThickness();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRectD computeSubBBox(double w0, double w1) const;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  inline QuadStrokeChunkArray &getTQArray() { return m_centerLineArray; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /*!
Shinya Kitaoka 120a6e
Swaps the geometrical infos only
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  void swapGeometry(TStroke::Imp &other) throw();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //! compute cache vector
Shinya Kitaoka 120a6e
  void computeCacheVector();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /*!
Shinya Kitaoka 120a6e
Set value in m_parameterValueAtControlPoint
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  void computeParameterInControlPoint();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /*!
Shinya Kitaoka 120a6e
Update parameter in m_parameterValueAtControlPoint
Shinya Kitaoka 120a6e
after insert of control point in stroke.
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  void updateParameterValue(double w, UINT chunk, TThickQuadratic *tq1,
Shinya Kitaoka 120a6e
                            TThickQuadratic *tq2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*!
Shinya Kitaoka 120a6e
From parameter w retrieves chunk and its parameter ( t in [0,1] ).
Shinya Kitaoka 120a6e
Return
Shinya Kitaoka 120a6e
true  ->  error (parameter w out of range, etc)
Shinya Kitaoka 120a6e
false ->  ok
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  bool retrieveChunkAndItsParamameter(double w, int &chunk, double &t);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /*!
Shinya Kitaoka 120a6e
From lenght s retrieves chunk and its parameter ( t in [0,1] ).
Shinya Kitaoka 120a6e
Return
Shinya Kitaoka 120a6e
true  ->  error (parameter w out of range, etc)
Shinya Kitaoka 120a6e
false ->  ok
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  bool retrieveChunkAndItsParamameterAtLength(double s, int &chunk, double &t);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /*!
Shinya Kitaoka 120a6e
Retrieve chunk which contains the n-th control point of stroke.
Shinya Kitaoka 120a6e
If control point is between two chunks return the left point.
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  int retrieveChunkFromControlPointIndex(int n) {
Shinya Kitaoka 120a6e
    assert(0 <= n && n < getControlPointCount());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (n & 1) ++n;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    n >>= 1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    return n ? n - 1 : n;
Shinya Kitaoka 120a6e
  };
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /*!
Shinya Kitaoka 120a6e
Retrieve range for a chunk.
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  DoublePair retrieveParametersFromChunk(UINT chunk) {
Shinya Kitaoka 120a6e
    DoublePair outPar;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int nFirst, nSecond;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    nFirst  = chunk * 2;
Shinya Kitaoka 120a6e
    nSecond = (chunk + 1) * 2;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    outPar.first  = getW(nFirst);
Shinya Kitaoka 120a6e
    outPar.second = getW(nSecond);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    return outPar;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void print(ostream &os);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  inline int getChunkCount() const { return m_centerLineArray.size(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  inline int getControlPointCount() const {
Shinya Kitaoka 120a6e
    UINT out = 2 * getChunkCount() + 1;
Shinya Kitaoka 120a6e
    return out;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TThickQuadratic *getChunk(int index) {
Shinya Kitaoka 120a6e
    if (0 <= index && index < getChunkCount()) return m_centerLineArray[index];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  // Declared but not defined.
Shinya Kitaoka 120a6e
  Imp(const Imp &other);
Shinya Kitaoka 120a6e
  Imp &operator=(const Imp &other);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
int maxStrokeId = 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
/*! init() is required to initialize all variable
Toshihiro Shimizu 890ddd
Call init after centerline initialization, because
Toshihiro Shimizu 890ddd
it's necessary to compute BBox
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void TStroke::Imp::init() {
Shinya Kitaoka 120a6e
  m_flag = c_dirty_flag;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_styleId = 1;  // DefaultStrokeStyle;
Shinya Kitaoka 120a6e
  m_prop    = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_id                         = ++maxStrokeId;
Shinya Kitaoka 120a6e
  m_isValidLength              = false;
Shinya Kitaoka 120a6e
  m_isOutlineValid             = false;
Shinya Kitaoka 120a6e
  m_areDisabledComputeOfCaches = false;
Shinya Kitaoka 120a6e
  m_selfLoop                   = false;
Shinya Kitaoka 120a6e
  m_averageThickness           = 0;
Shinya Kitaoka 120a6e
  m_maxThickness               = -1;
Shinya Kitaoka 120a6e
  m_negativeThicknessPoints    = 0;
Shinya Kitaoka 120a6e
  for (UINT j = 0; j < m_centerLineArray.size(); j++) {
Shinya Kitaoka 120a6e
    if (m_centerLineArray[j]->getThickP0().thick <= 0)
Shinya Kitaoka 120a6e
      m_negativeThicknessPoints++;
Shinya Kitaoka 120a6e
    if (m_centerLineArray[j]->getThickP1().thick <= 0)
Shinya Kitaoka 120a6e
      m_negativeThicknessPoints++;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (!m_centerLineArray.empty() &&
Shinya Kitaoka 120a6e
      m_centerLineArray.back()->getThickP2().thick <= 0)
Shinya Kitaoka 120a6e
    m_negativeThicknessPoints++;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  computeParameterInControlPoint();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke::Imp::Imp() { init(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke::Imp::Imp(const std::vector<TThickPoint> &v) {
Shinya Kitaoka 120a6e
  buildChunksFromControlPoints(m_centerLineArray, v);
Shinya Kitaoka 120a6e
  roundNegativeThickess(m_centerLineArray);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  init();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke::Imp::Imp(const std::vector<TPointD> &v) {
Shinya Kitaoka 120a6e
  buildChunksFromControlPoints(m_centerLineArray, v);
Shinya Kitaoka 120a6e
  roundNegativeThickess(m_centerLineArray);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  init();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::Imp::swapGeometry(Imp &other) throw() {
Shinya Kitaoka 120a6e
  std::swap(m_flag, other.m_flag);
Shinya Kitaoka 120a6e
  std::swap(m_isValidLength, other.m_isValidLength);
Shinya Kitaoka 120a6e
  std::swap(m_isOutlineValid, other.m_isOutlineValid);
Shinya Kitaoka 120a6e
  std::swap(m_areDisabledComputeOfCaches, other.m_areDisabledComputeOfCaches);
Shinya Kitaoka 120a6e
  std::swap(m_bBox, other.m_bBox);
Shinya Kitaoka 120a6e
  std::swap(m_partialLenghtArray, other.m_partialLenghtArray);
Shinya Kitaoka 120a6e
  std::swap(m_parameterValueAtControlPoint,
Shinya Kitaoka 120a6e
            other.m_parameterValueAtControlPoint);
Shinya Kitaoka 120a6e
  std::swap(m_centerLineArray, other.m_centerLineArray);
Shinya Kitaoka 120a6e
  std::swap(m_selfLoop, other.m_selfLoop);
Shinya Kitaoka 120a6e
  std::swap(m_negativeThicknessPoints, other.m_negativeThicknessPoints);
Shinya Kitaoka 120a6e
  std::swap(m_averageThickness, other.m_averageThickness);
Shinya Kitaoka 120a6e
  std::swap(m_maxThickness, other.m_maxThickness);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::Imp::computeMaxThickness() {
Shinya Kitaoka 120a6e
  m_maxThickness = m_centerLineArray[0]->getThickP0().thick;
Shinya Kitaoka 120a6e
  for (UINT i = 0; i < m_centerLineArray.size(); i++)
Shinya Kitaoka 120a6e
    m_maxThickness =
Shinya Kitaoka 120a6e
        std::max({m_maxThickness, m_centerLineArray[i]->getThickP1().thick,
Shinya Kitaoka 120a6e
                  m_centerLineArray[i]->getThickP2().thick});
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::Imp::computeCacheVector() {
Shinya Kitaoka 120a6e
  // se la stroke e' stata invalidata a causa dell'inserimento di punti
Shinya Kitaoka 120a6e
  //  di controllo o dal ricampionamento
Shinya Kitaoka 120a6e
  if (!m_areDisabledComputeOfCaches && !m_isValidLength) {
Shinya Kitaoka 120a6e
    if (getChunkCount() > 0)  // se ci sono cionchi
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      // (re)inizializzo un vettore
Shinya Kitaoka 120a6e
      m_partialLenghtArray.resize(getControlPointCount(),
Shinya Kitaoka 120a6e
                                  (std::numeric_limits<double>::max)());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      m_partialLenghtArray[0] = 0.0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      double length = 0.0;
Shinya Kitaoka 120a6e
      int j         = 0;
Shinya Kitaoka 120a6e
      const TThickQuadratic *tq;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      TQuadraticLengthEvaluator lengthEvaluator;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      for (int i = 0; i < getChunkCount(); ++i) {
Shinya Kitaoka 120a6e
        assert(j <= getControlPointCount());
Shinya Kitaoka 120a6e
        tq = getChunk(i);
Shinya Kitaoka 120a6e
        lengthEvaluator.setQuad(*tq);
Shinya Kitaoka 120a6e
        m_partialLenghtArray[j++] = length;
Shinya Kitaoka 120a6e
        m_partialLenghtArray[j++] = length + lengthEvaluator.getLengthAt(0.5);
Shinya Kitaoka 120a6e
        length += lengthEvaluator.getLengthAt(1.0);
Shinya Kitaoka 120a6e
      }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      m_partialLenghtArray[j++] = length;
Shinya Kitaoka 120a6e
      assert(j == getControlPointCount());
Shinya Kitaoka 120a6e
      // assert( m_parameterValueAtControlPoint.size() ==
Shinya Kitaoka 120a6e
      // m_partialLenghtArray.size() );
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_isValidLength = true;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::Imp::computeParameterInControlPoint() {
Shinya Kitaoka 120a6e
  if (!m_areDisabledComputeOfCaches) {
Shinya Kitaoka 120a6e
    // questa funzione ricalcola i valori dei parametri nei cionchi
Shinya Kitaoka 120a6e
    //  N.B. deve essere richiamata quando si effettuano inserimenti
Shinya Kitaoka 120a6e
    //    di punti di controllo che cambiano la lunghezza della curva
Shinya Kitaoka 120a6e
    //  insert, push e costruttore
Shinya Kitaoka 120a6e
    if (!getChunkCount()) {
Shinya Kitaoka 120a6e
      m_parameterValueAtControlPoint.clear();
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    int controlPointCount = getControlPointCount();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_parameterValueAtControlPoint.resize(controlPointCount, 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // N.B. number of control point is reduced of 1
Shinya Kitaoka 120a6e
    --controlPointCount;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    double val = 0.0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    assert(controlPointCount >= 0.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    for (int i = 0; i <= controlPointCount; ++i) {
Shinya Kitaoka 120a6e
      val                               = i / (double)controlPointCount;
Shinya Kitaoka 120a6e
      m_parameterValueAtControlPoint[i] = val;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::Imp::updateParameterValue(double w, UINT chunk,
Shinya Kitaoka 120a6e
                                        TThickQuadratic *tq1,
Shinya Kitaoka 120a6e
                                        TThickQuadratic *tq2) {
Shinya Kitaoka 120a6e
  DoublePair p = retrieveParametersFromChunk(chunk);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  UINT controlPointToErase = 2 * chunk + 1;
Shinya Kitaoka 120a6e
  DoubleIt it              = m_parameterValueAtControlPoint.begin();
Shinya Kitaoka 120a6e
  std::advance(it, controlPointToErase);
Shinya Kitaoka 120a6e
  m_parameterValueAtControlPoint.erase(it);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double normalizedParam = tq2->getT(tq2->getP1());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<double>::iterator first;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  normalizedParam = proportion(p.second, normalizedParam, 1.0, w);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  first =
Shinya Kitaoka 120a6e
      std::upper_bound(m_parameterValueAtControlPoint.begin(),
Shinya Kitaoka 120a6e
                       m_parameterValueAtControlPoint.end(), normalizedParam);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (first != m_parameterValueAtControlPoint.end()) {
Shinya Kitaoka 120a6e
    first = m_parameterValueAtControlPoint.insert(first, normalizedParam);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    first = m_parameterValueAtControlPoint.insert(first, w);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    normalizedParam = tq1->getT(tq1->getP1());
Shinya Kitaoka 120a6e
    normalizedParam = proportion(w, normalizedParam, 1.0, p.first);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_parameterValueAtControlPoint.insert(first, normalizedParam);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /* FAB
Shinya Kitaoka 120a6e
assert( getControlPointCount() <=
Shinya Kitaoka 120a6e
    (int)m_parameterValueAtControlPoint.size() );
Shinya Kitaoka 120a6e
//*/
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TStroke::getChunkAndTAtLength(double s, int &chunk, double &t) const {
Shinya Kitaoka 120a6e
  return m_imp->retrieveChunkAndItsParamameterAtLength(s, chunk, t);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TStroke::Imp::retrieveChunkAndItsParamameterAtLength(double s, int &chunk,
Shinya Kitaoka 120a6e
                                                          double &t) {
Shinya Kitaoka 120a6e
  vector<double>::iterator first;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // cerco nella cache la posizione che compete alla lunghezza s
Shinya Kitaoka 120a6e
  first = std::upper_bound(m_partialLenghtArray.begin(),
Shinya Kitaoka 120a6e
                           m_partialLenghtArray.end(), s);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // se s e' interna al vettore di cache
Shinya Kitaoka 120a6e
  if (first != m_partialLenghtArray.end()) {
Shinya Kitaoka 120a6e
    // individuo il punto di controllo della stroke...
Shinya Kitaoka 120a6e
    int controlPointOffset = distance(m_partialLenghtArray.begin(), first);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // ...e da questo il cionco relativo.
Shinya Kitaoka 120a6e
    chunk = retrieveChunkFromControlPointIndex(controlPointOffset);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (first != m_partialLenghtArray.begin() && s == *(first - 1)) {
Shinya Kitaoka 120a6e
      controlPointOffset--;
Shinya Kitaoka 120a6e
      if (controlPointOffset & 1) {
Shinya Kitaoka 120a6e
        const DoublePair &p = retrieveParametersFromChunk(chunk);
Shinya Kitaoka 120a6e
        t = proportion(1.0, getW(controlPointOffset) - p.first,
Shinya Kitaoka 120a6e
                       p.second - p.first);
Shinya Kitaoka 120a6e
      } else
Shinya Kitaoka 120a6e
        t = 0.0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // fisso un offset per l'algoritmo di bisezione
Shinya Kitaoka 120a6e
    double offset = (first == m_partialLenghtArray.begin())
Shinya Kitaoka 120a6e
                        ? s
Shinya Kitaoka 120a6e
                        : s - m_partialLenghtArray[chunk * 2];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // cerco il parametro minimo a meno di una tolleranza epsilon
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    const double tol = TConsts::epsilon * 0.1;
Shinya Kitaoka 120a6e
    int err;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    computeOffset_ op(getChunk(chunk), offset);
Shinya Kitaoka 120a6e
    computeSpeed_ op2(getChunk(chunk));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (!findZero_Newton(0.0, 1.0, op, op2, tol, tol, 100, t, err))
Shinya Kitaoka 120a6e
      t = -1;  // if can not find a good value set parameter to error value
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // se l'algoritmo di ricerca ha fallito fissa il valore ad uno dei due
Shinya Kitaoka 120a6e
    // estremi
Shinya Kitaoka 120a6e
    if (t == -1) {
Shinya Kitaoka 120a6e
      if (s <= m_partialLenghtArray[controlPointOffset]) t = 0.0;
Shinya Kitaoka 120a6e
      t                                                    = 1.0;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (s <= 0.0) {
Shinya Kitaoka 120a6e
    chunk = 0;
Shinya Kitaoka 120a6e
    t     = 0.0;
Shinya Kitaoka 120a6e
  } else if (s >= m_partialLenghtArray.back()) {
Shinya Kitaoka 120a6e
    chunk = getChunkCount() - 1;
Shinya Kitaoka 120a6e
    t     = 1.0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TStroke::getChunkAndT(double w, int &chunk, double &t) const {
Shinya Kitaoka 120a6e
  return m_imp->retrieveChunkAndItsParamameter(w, chunk, t);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TStroke::Imp::retrieveChunkAndItsParamameter(double w, int &chunk,
Shinya Kitaoka 120a6e
                                                  double &t) {
Shinya Kitaoka 120a6e
  vector<double>::iterator first;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // trova l'iteratore alla prima posizione che risulta maggiore o uguale a w
Shinya Kitaoka 120a6e
  first = std::lower_bound(m_parameterValueAtControlPoint.begin(),
Shinya Kitaoka 120a6e
                           m_parameterValueAtControlPoint.end(), w);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // se non e' stato possibile trovare w nel vettore ritorna errore
Shinya Kitaoka 120a6e
  if (first == m_parameterValueAtControlPoint.end()) return true;
Shinya Kitaoka 120a6e
  /* FAB
Shinya Kitaoka 120a6e
double
Shinya Kitaoka 120a6e
found = *first;
Shinya Kitaoka 120a6e
assert(found  <=  *first);
Shinya Kitaoka 120a6e
//*/
Shinya Kitaoka 120a6e
  // individuo il punto di controllo che compete alla posizione nel vettore
Shinya Kitaoka 120a6e
  int controlPointOffset =
Shinya Kitaoka 120a6e
      distance(m_parameterValueAtControlPoint.begin(), first);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // individuo il cionco relativo al punto di controllo
Shinya Kitaoka 120a6e
  chunk = retrieveChunkFromControlPointIndex(controlPointOffset);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // calcolo il parametro relativo al cionco
Shinya Kitaoka 120a6e
  DoublePair p = retrieveParametersFromChunk(chunk);
Shinya Kitaoka 120a6e
  /* FAB
Shinya Kitaoka 120a6e
assert( p.first <= w &&
Shinya Kitaoka 120a6e
    w <= p.second );
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef  _DEBUG
Shinya Kitaoka 120a6e
chunk = retrieveChunkFromControlPointIndex( controlPointOffset );
Shinya Kitaoka 120a6e
p = retrieveParametersFromChunk( chunk );
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
//*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (w < p.first || w > p.second) {
Shinya Kitaoka 120a6e
    t = (p.first + p.second) * 0.5;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    t = proportion(1.0, w - p.first, p.second - p.first);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /* FAB
Shinya Kitaoka 120a6e
assert( 0.0 <= t && t <= 1.0 );
Shinya Kitaoka 120a6e
//*/
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRectD TStroke::Imp::computeCenterlineBBox() {
Shinya Kitaoka 120a6e
  UINT n = m_centerLineArray.size();
Shinya Kitaoka 120a6e
  if (m_centerLineArray.empty()) return TRectD();
Shinya Kitaoka 120a6e
  TQuadratic q(m_centerLineArray[0]->getP0(), m_centerLineArray[0]->getP1(),
Shinya Kitaoka 120a6e
               m_centerLineArray[0]->getP2());
Shinya Kitaoka 120a6e
  TRectD bbox = q.getBBox();
Shinya Kitaoka 120a6e
  for (UINT i = 1; i < n; i++) {
Shinya Kitaoka 120a6e
    q = TQuadratic(m_centerLineArray[i]->getP0(), m_centerLineArray[i]->getP1(),
Shinya Kitaoka 120a6e
                   m_centerLineArray[i]->getP2());
Shinya Kitaoka 120a6e
    bbox += q.getBBox();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return bbox;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRectD TStroke::Imp::computeSubBBox(double w0, double w1) const {
Shinya Kitaoka 120a6e
  if (m_centerLineArray.empty()) return TRectD();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int n = m_centerLineArray.size();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRectD bBox;
Shinya Kitaoka 120a6e
  const double eps = 0.000000001;
Shinya Kitaoka 120a6e
  int i;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (w0 > w1) tswap(w0, w1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double nw0 = w0 * n;
Shinya Kitaoka 120a6e
  double nw1 = w1 * n;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int i0 = (int)nw0;  // indice della quadrica che contiene w0
Shinya Kitaoka 120a6e
  int i1 = (int)nw1;  // idem per w1
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double t0 =
Shinya Kitaoka 120a6e
      nw0 -
Shinya Kitaoka 120a6e
      (double)i0;  // parametro di w0 rispetto alla quadrica che lo contiene
Shinya Kitaoka 120a6e
  double t1 = nw1 - (double)i1;  // idem per w1
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (t0 < eps)  // se t0 e' quasi uguale a zero, evito di fare lo split e
Shinya Kitaoka 120a6e
                 // considero tutta la quadrica i0
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    i0--;
Shinya Kitaoka 120a6e
    t0 = 1.0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (t1 > (1 - eps))  // se t1 e' quasi uguale a uno, evito di fare lo split e
Shinya Kitaoka 120a6e
                       // considero tutta la quadrica i1
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    i1++;
Shinya Kitaoka 120a6e
    t1 = 0.0;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TThickQuadratic quadratic1, quadratic2, quadratic3;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (i0 == i1)  // i due punti di taglio capitano nella stessa quadratica
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    if (t0 < eps && t1 > (1 - eps)) return m_centerLineArray[i0]->getBBox();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (t0 < eps) {
Shinya Kitaoka 120a6e
      m_centerLineArray[i0]->split(t1, quadratic1, quadratic2);
Shinya Kitaoka 120a6e
      return quadratic1.getBBox();
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (t1 > (1 - eps)) {
Shinya Kitaoka 120a6e
      m_centerLineArray[i0]->split(t0, quadratic1, quadratic2);
Shinya Kitaoka 120a6e
      return quadratic2.getBBox();
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // quadratic1 e' la quadratica risultante dallo split tra t0 e t1 di
Shinya Kitaoka 120a6e
    // m_centerLineArray[i0]
Shinya Kitaoka 120a6e
    m_centerLineArray[i0]->split(t0, quadratic1, quadratic2);
Shinya Kitaoka 120a6e
    quadratic2.split((t1 - t0) / (1 - t0), quadratic1, quadratic3);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    return quadratic1.getBBox();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // se i due punti di taglio capitano in quadratiche diverse
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // sommo le bbox di quelle interne
Shinya Kitaoka 120a6e
  for (i = i0 + 1; i < i1; i++) bBox += m_centerLineArray[i]->getBBox();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // e sommo le bbox delle quadratiche splittate agli estremi se non sono
Shinya Kitaoka 120a6e
  // irrilevanti
Shinya Kitaoka 120a6e
  if (i0 >= 0 && t0 < (1 - eps)) {
Shinya Kitaoka 120a6e
    m_centerLineArray[i0]->split(t0, quadratic1, quadratic2);
Shinya Kitaoka 120a6e
    bBox += quadratic2.getBBox();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (i1 < n && t1 > eps) {
Shinya Kitaoka 120a6e
    m_centerLineArray[i1]->split(t1, quadratic1, quadratic2);
Shinya Kitaoka 120a6e
    bBox += quadratic1.getBBox();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return bBox;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::Imp::print(ostream &os) {
Toshihiro Shimizu 890ddd
#if defined(_DEBUG) || defined(DEBUG)
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  os << "m_isValidLength:" << m_isValidLength << endl;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  os << "m_isOutlineValid:" << m_isOutlineValid << endl;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  os << "m_areDisabledComputeOfCaches:" << m_areDisabledComputeOfCaches << endl;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  os << "m_bBox:" << m_bBox << endl;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  os << "m_partialLenghtArray";
Shinya Kitaoka 120a6e
  printContainer(os, m_partialLenghtArray);
Shinya Kitaoka 120a6e
  os << endl;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  os << "m_parameterValueAtControlPoint";
Shinya Kitaoka 120a6e
  printContainer(os, m_parameterValueAtControlPoint);
Shinya Kitaoka 120a6e
  os << endl;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  os << "m_centerLineArray";
Shinya Kitaoka 120a6e
  // os.setf(myIOFlags::scientific);
Shinya Kitaoka 120a6e
  printContainerOfPointer(os, m_centerLineArray);
Shinya Kitaoka 120a6e
  os << endl;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
  vector<TPixel> m_outlineColorArray;
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
    vector<TPointD> m_texArray;
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
      TFilePath m_filePath;
Toshihiro Shimizu 890ddd
      TRasterP  m_texture;
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
// TSystem::outputDebug( os.str());
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  Needed to DEBUG
Toshihiro Shimizu 890ddd
DEFINE_CLASS_CODE(TStroke, 15)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Costructor
Shinya Kitaoka 120a6e
TStroke::TStroke() : TSmartObject(m_classCode) {
Shinya Kitaoka 120a6e
  vector<TThickPoint> p(3);
Shinya Kitaoka 120a6e
  p[0] = TThickPoint(0, 0, 0);
Shinya Kitaoka 120a6e
  p[1] = p[0];
Shinya Kitaoka 120a6e
  p[2] = p[1];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_imp.reset(new TStroke::Imp(p));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
// da fissare deve trovarsi prima della init
Shinya Kitaoka 120a6e
m_imp->m_centerLineArray.push_back ( new TThickQuadratic );
Shinya Kitaoka 120a6e
*/
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Build a stroke from a set of ThickPoint
Toshihiro Shimizu 890ddd
TStroke::TStroke(const vector<TThickPoint> &v)
Shinya Kitaoka 120a6e
    : TSmartObject(m_classCode), m_imp(new TStroke::Imp(v)) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TStroke::TStroke(const vector<TPointD> &v)
Shinya Kitaoka 120a6e
    : TSmartObject(m_classCode), m_imp(new TStroke::Imp(v)) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke::~TStroke() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TStroke::TStroke(const TStroke &other)
Shinya Kitaoka 120a6e
    : TSmartObject(m_classCode), m_imp(new TStroke::Imp()) {
Shinya Kitaoka 120a6e
  m_imp->m_bBox           = other.getBBox();
Shinya Kitaoka 120a6e
  m_imp->m_isValidLength  = other.m_imp->m_isValidLength;
Shinya Kitaoka 120a6e
  m_imp->m_isOutlineValid = other.m_imp->m_isOutlineValid;
Shinya Kitaoka 120a6e
  m_imp->m_areDisabledComputeOfCaches =
Shinya Kitaoka 120a6e
      other.m_imp->m_areDisabledComputeOfCaches;
Shinya Kitaoka 120a6e
  m_imp->m_flag           = other.m_imp->m_flag;
Shinya Kitaoka 120a6e
  m_imp->m_outlineOptions = other.m_imp->m_outlineOptions;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Are they sure as regards exceptions ?
Shinya Kitaoka 120a6e
  m_imp->m_centerLineArray.resize(other.m_imp->m_centerLineArray.size());
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < (int)other.m_imp->m_centerLineArray.size(); i++)
Shinya Kitaoka 120a6e
    m_imp->m_centerLineArray[i] =
Shinya Kitaoka 120a6e
        new TThickQuadratic(*other.m_imp->m_centerLineArray[i]);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // copy(  other.m_imp->m_centerLineArray.begin(),
Shinya Kitaoka 120a6e
  //   other.m_imp->m_centerLineArray.end(),
Shinya Kitaoka 120a6e
  //   TThickQuadraticArrayInsertIterator(m_imp->m_centerLineArray));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  copy(other.m_imp->m_partialLenghtArray.begin(),
Shinya Kitaoka 120a6e
       other.m_imp->m_partialLenghtArray.end(),
Shinya Kitaoka 120a6e
       back_inserter<DoubleArray>(m_imp->m_partialLenghtArray));
Shinya Kitaoka 120a6e
  copy(other.m_imp->m_parameterValueAtControlPoint.begin(),
Shinya Kitaoka 120a6e
       other.m_imp->m_parameterValueAtControlPoint.end(),
Shinya Kitaoka 120a6e
       back_inserter<DoubleArray>(m_imp->m_parameterValueAtControlPoint));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_imp->m_styleId = other.m_imp->m_styleId;
Shinya Kitaoka 120a6e
  m_imp->m_prop =
Shinya Kitaoka 120a6e
      0;  // other.m_imp->m_prop ? other.m_imp->m_prop->clone(this) : 0;
Shinya Kitaoka 120a6e
  m_imp->m_selfLoop                = other.m_imp->m_selfLoop;
Shinya Kitaoka 120a6e
  m_imp->m_negativeThicknessPoints = other.m_imp->m_negativeThicknessPoints;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke &TStroke::operator=(const TStroke &other) {
Shinya Kitaoka 120a6e
  TStroke temp(other);
Shinya Kitaoka 120a6e
  swap(temp);
Shinya Kitaoka 120a6e
  return *this;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TStroke::getNearestW(const TPointD &p, double &outW, double &dist2,
Shinya Kitaoka 120a6e
                          bool checkBBox) const {
Shinya Kitaoka 120a6e
  double outT;
Shinya Kitaoka 120a6e
  int chunkIndex;
Shinya Kitaoka 120a6e
  bool ret      = getNearestChunk(p, outT, chunkIndex, dist2, checkBBox);
Shinya Kitaoka 120a6e
  if (ret) outW = getW(chunkIndex, outT);
Shinya Kitaoka 120a6e
  return ret;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
bool TStroke::getNearestChunk(const TPointD &p, double &outT, int &chunkIndex,
Shinya Kitaoka 120a6e
                              double &dist2, bool checkBBox) const {
Shinya Kitaoka 120a6e
  dist2 = (numeric_limits<double>::max)();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (UINT i = 0; i < m_imp->m_centerLineArray.size(); i++) {
Shinya Kitaoka 120a6e
    if (checkBBox &&
Shinya Kitaoka 120a6e
        !m_imp->m_centerLineArray[i]->getBBox().enlarge(30).contains(p))
Shinya Kitaoka 120a6e
      continue;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    double t    = (m_imp->m_centerLineArray)[i]->getT(p);
Shinya Kitaoka 120a6e
    double dist = tdistance2((m_imp->m_centerLineArray)[i]->getPoint(t), p);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (dist < dist2) {
Shinya Kitaoka 120a6e
      dist2      = dist;
Shinya Kitaoka 120a6e
      chunkIndex = i;
Shinya Kitaoka 120a6e
      outT       = t;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return dist2 < (numeric_limits<double>::max)();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
// finds all points on stroke which are "enough" close to point p. return the
Shinya Kitaoka 120a6e
// number of such points.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int TStroke::getNearChunks(const TThickPoint &p,
Shinya Kitaoka 120a6e
                           vector<TThickPoint> &pointsOnStroke,
Shinya Kitaoka 120a6e
                           bool checkBBox) const {
Shinya Kitaoka 120a6e
  int currIndex    = -100;
Shinya Kitaoka 120a6e
  double currDist2 = 100000;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (UINT i = 0; i < m_imp->m_centerLineArray.size(); i++) {
Shinya Kitaoka 120a6e
    TThickQuadratic *q = m_imp->m_centerLineArray[i];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (checkBBox && !q->getBBox().enlarge(30).contains(p)) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double t       = q->getT(p);
Shinya Kitaoka 120a6e
    TThickPoint p1 = q->getThickPoint(t);
Shinya Kitaoka 120a6e
    double dist2   = tdistance2(p1, p);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (dist2 < (p1.thick + p.thick + 5) * (p1.thick + p.thick + 5)) {
Shinya Kitaoka 120a6e
      if (!pointsOnStroke.empty() &&
Shinya Kitaoka 120a6e
          areAlmostEqual(p1, pointsOnStroke.back(), 1e-3))
Shinya Kitaoka 120a6e
        continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (currIndex == i - 1) {
Shinya Kitaoka 120a6e
        if (dist2 < currDist2)
Shinya Kitaoka 120a6e
          pointsOnStroke.pop_back();
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          continue;
Shinya Kitaoka 120a6e
      }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      currIndex = i;
Shinya Kitaoka 120a6e
      currDist2 = dist2;
Shinya Kitaoka 120a6e
      pointsOnStroke.push_back(p1);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return pointsOnStroke.size();  // dist2 < (numeric_limits<double>::max)();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::getControlPoints(vector<TThickPoint> &v) const {
Shinya Kitaoka 120a6e
  assert(v.empty());
Shinya Kitaoka 120a6e
  v.resize(m_imp->m_centerLineArray.size() * 2 + 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  v[0] = m_imp->m_centerLineArray[0]->getThickP0();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (UINT i = 0; i < m_imp->m_centerLineArray.size(); i++) {
Shinya Kitaoka 120a6e
    TThickQuadratic *q = m_imp->m_centerLineArray[i];
Shinya Kitaoka 120a6e
    v[2 * i + 1]       = q->getThickP1();
Shinya Kitaoka 120a6e
    v[2 * i + 2]       = q->getThickP2();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TThickPoint TStroke::getControlPoint(int n) const {
Shinya Kitaoka 120a6e
  if (n <= 0) return m_imp->m_centerLineArray.front()->getThickP0();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (n >= getControlPointCount())
Shinya Kitaoka 120a6e
    return m_imp->m_centerLineArray.back()->getThickP2();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // calcolo l'offset del chunk risolvendo l'equazione
Shinya Kitaoka 120a6e
  //  2 * chunkNumber + 1 = n
Shinya Kitaoka 120a6e
  //  chunkNumber = tceil((n - 1) / 2)
Shinya Kitaoka 120a6e
  int chunkNumber = tceil((n - 1) * 0.5);
Shinya Kitaoka 120a6e
  assert(chunkNumber <= getChunkCount());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int pointOffset = n - chunkNumber * 2;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (chunkNumber == getChunkCount())  // e' l'ultimo punto della stroke
Shinya Kitaoka 120a6e
    return getChunk(chunkNumber - 1)->getThickP2();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  switch (pointOffset) {
Shinya Kitaoka 120a6e
  case 0:
Shinya Kitaoka 120a6e
    return getChunk(chunkNumber)->getThickP0();
Shinya Kitaoka 120a6e
  case 1:
Shinya Kitaoka 120a6e
    return getChunk(chunkNumber)->getThickP1();
Shinya Kitaoka 120a6e
  case 2:
Shinya Kitaoka 120a6e
    return getChunk(chunkNumber)->getThickP2();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert("Not yet finished" && false);
Shinya Kitaoka 120a6e
  return getControlPoint(0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TThickPoint TStroke::getControlPointAtParameter(double w) const {
Shinya Kitaoka 120a6e
  if (w <= 0) return m_imp->m_centerLineArray.front()->getThickP0();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (w >= 1.0) return m_imp->m_centerLineArray.back()->getThickP2();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  vector<double>::iterator it_begin =
Shinya Kitaoka 120a6e
                               m_imp->m_parameterValueAtControlPoint.begin(),
Shinya Kitaoka 120a6e
                           first,
Shinya Kitaoka 120a6e
                           it_end = m_imp->m_parameterValueAtControlPoint.end();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // find iterator at position greater or equal to w
Shinya Kitaoka 120a6e
  first = std::lower_bound(it_begin, it_end, w);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(first != it_end);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // now is possible to get control point
Shinya Kitaoka 120a6e
  // if( areAlmostEqual(*first, w, 0.1) )
Shinya Kitaoka 120a6e
  //  return  getControlPoint( distance(it_begin, first) );
Shinya Kitaoka 120a6e
  if (first == it_begin)
Shinya Kitaoka 120a6e
    return getControlPoint(0);
Shinya Kitaoka 120a6e
  else if ((*first - w) <= w - *(first - 1))
Shinya Kitaoka 120a6e
    return getControlPoint(distance(it_begin, first));
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return getControlPoint(distance(it_begin, first - 1));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TStroke::getControlPointIndexAfterParameter(double w) const {
Shinya Kitaoka 120a6e
  const vector<double>::const_iterator
Shinya Kitaoka 120a6e
      begin = m_imp->m_parameterValueAtControlPoint.begin(),
Shinya Kitaoka 120a6e
      end   = m_imp->m_parameterValueAtControlPoint.end();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  vector<double>::const_iterator it = std::upper_bound(begin, end, w);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (it == end)
Shinya Kitaoka 120a6e
    return getControlPointCount();
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return std::distance(begin, it);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::setControlPoint(int n, const TThickPoint &pos) {
Shinya Kitaoka 120a6e
  assert(n >= 0);
Shinya Kitaoka 120a6e
  assert(n < getControlPointCount());
Shinya Kitaoka 120a6e
  if (n < 0 || n >= getControlPointCount()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QuadStrokeChunkArray &chunkArray = m_imp->m_centerLineArray;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (getControlPoint(n).thick <= 0 && pos.thick > 0)
Shinya Kitaoka 120a6e
    m_imp->m_negativeThicknessPoints--;
Shinya Kitaoka 120a6e
  else if (getControlPoint(n).thick > 0 && pos.thick <= 0)
Shinya Kitaoka 120a6e
    m_imp->m_negativeThicknessPoints++;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (n == 0) {
Shinya Kitaoka 120a6e
    chunkArray[0]->setThickP0(pos);
Shinya Kitaoka 120a6e
    // m_imp->computeBBox();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int chunkNumber = tceil((n - 1) * 0.5);
Shinya Kitaoka 120a6e
  assert(chunkNumber <= getChunkCount());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int pointOffset = n - chunkNumber * 2;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (chunkNumber == getChunkCount())  // e' l'ultimo punto della stroke
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    chunkArray[chunkNumber - 1]->setThickP2(pos);
Shinya Kitaoka 120a6e
    // m_imp->computeBBox();
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (0 == pointOffset) {
Shinya Kitaoka 120a6e
    chunkArray[chunkNumber]->setThickP0(pos);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (chunkNumber >= 1) {
Shinya Kitaoka 120a6e
      chunkNumber--;
Shinya Kitaoka 120a6e
      chunkArray[chunkNumber]->setThickP2(pos);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (1 == pointOffset)
Shinya Kitaoka 120a6e
    chunkArray[chunkNumber]->setThickP1(pos);
Shinya Kitaoka 120a6e
  else if (2 == pointOffset) {
Shinya Kitaoka 120a6e
    chunkArray[chunkNumber]->setThickP2(pos);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (chunkNumber < getChunkCount() - 1) {
Shinya Kitaoka 120a6e
      chunkNumber++;
Shinya Kitaoka 120a6e
      chunkArray[chunkNumber]->setThickP0(pos);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // m_imp->computeBBox();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Ridisegna lo stroke
Shinya Kitaoka 120a6e
void TStroke::reshape(const TThickPoint pos[], int count) {
Shinya Kitaoka 120a6e
  // count deve essere dispari e maggiore o uguale a tre
Shinya Kitaoka 120a6e
  assert(count >= 3);
Shinya Kitaoka 120a6e
  assert(count & 1);
Shinya Kitaoka 120a6e
  QuadStrokeChunkArray &chunkArray = m_imp->m_centerLineArray;
Shinya Kitaoka 120a6e
  clearPointerContainer(chunkArray);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_imp->m_negativeThicknessPoints = 0;
Shinya Kitaoka 120a6e
  for (int i = 0; i < count - 1; i += 2) {
Shinya Kitaoka 120a6e
    chunkArray.push_back(new TThickQuadratic(pos[i], pos[i + 1], pos[i + 2]));
Shinya Kitaoka 120a6e
    if (pos[i].thick <= 0) m_imp->m_negativeThicknessPoints++;
Shinya Kitaoka 120a6e
    if (pos[i + 1].thick <= 0) m_imp->m_negativeThicknessPoints++;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (pos[count - 1].thick <= 0) m_imp->m_negativeThicknessPoints++;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  invalidate();
Shinya Kitaoka 120a6e
  // m_imp->computeBBox();
Shinya Kitaoka 120a6e
  m_imp->computeParameterInControlPoint();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TStroke::getApproximateLength(double w0, double w1, double error) const {
Shinya Kitaoka 120a6e
  m_imp->computeCacheVector();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert((int)m_imp->m_partialLenghtArray.size() == getControlPointCount());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (w0 == w1) return 0.0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  w0 = min(max(0.0, w0), 1.0);
Shinya Kitaoka 120a6e
  w1 = min(max(0.0, w1), 1.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (w0 > w1) std::swap(w0, w1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // vede se la lunghezza e' individuabile nella cache
Shinya Kitaoka 120a6e
  if (0.0 == w0) {
Shinya Kitaoka 120a6e
    vector<double>::iterator first;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // trova l'iteratore alla prima posizione che risulta maggiore di w
Shinya Kitaoka 120a6e
    first = std::upper_bound(m_imp->m_parameterValueAtControlPoint.begin(),
Shinya Kitaoka 120a6e
                             m_imp->m_parameterValueAtControlPoint.end(),
Shinya Kitaoka 120a6e
                             w1 - TConsts::epsilon);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (first != m_imp->m_parameterValueAtControlPoint.end() &&
Shinya Kitaoka 120a6e
        *first < w1 + TConsts::epsilon) {
Shinya Kitaoka 120a6e
      int offset =
Shinya Kitaoka 120a6e
          distance(m_imp->m_parameterValueAtControlPoint.begin(), first);
Shinya Kitaoka 120a6e
      return m_imp->m_partialLenghtArray[offset];
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int firstChunk, secondChunk;
Shinya Kitaoka 120a6e
  double firstT, secondT;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // calcolo i chunk interessati ed i valori del parametro t
Shinya Kitaoka 120a6e
  bool val1 = m_imp->retrieveChunkAndItsParamameter(w0, firstChunk, firstT);
Shinya Kitaoka 120a6e
  assert(val1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool val2 = m_imp->retrieveChunkAndItsParamameter(w1, secondChunk, secondT);
Shinya Kitaoka 120a6e
  assert(val2);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (firstChunk == secondChunk)
Shinya Kitaoka 120a6e
    return getChunk(firstChunk)->getApproximateLength(firstT, secondT, error);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double totalLength = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  totalLength += getChunk(firstChunk)->getApproximateLength(firstT, 1, error);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // lunghezza dei pezzi intermedi
Shinya Kitaoka 120a6e
  for (int i = firstChunk + 1; i != secondChunk; i++)
Shinya Kitaoka 120a6e
    totalLength += getChunk(i)->getApproximateLength(0.0, 1.0, error);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  totalLength +=
Shinya Kitaoka 120a6e
      getChunk(secondChunk)->getApproximateLength(0.0, secondT, error);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return totalLength;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TStroke::getLength(double w0, double w1) const {
Shinya Kitaoka 120a6e
  if (w0 == w1) return 0.0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // If necessary, swap values
Shinya Kitaoka 120a6e
  w0 = min(max(0.0, w0), 1.0);
Shinya Kitaoka 120a6e
  w1 = min(max(0.0, w1), 1.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (w0 > w1) std::swap(w0, w1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Retrieve s1
Shinya Kitaoka 120a6e
  int chunk;
Shinya Kitaoka 120a6e
  double t;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool ok = !m_imp->retrieveChunkAndItsParamameter(w1, chunk, t);
Shinya Kitaoka 120a6e
  assert(ok);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double s1 = getLength(chunk, t);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (w0 == 0.0) return s1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Retrieve s0
Shinya Kitaoka 120a6e
  ok = !m_imp->retrieveChunkAndItsParamameter(w0, chunk, t);
Shinya Kitaoka 120a6e
  assert(ok);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return s1 - getLength(chunk, t);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TStroke::getLength(int chunk, double t) const {
Shinya Kitaoka 120a6e
  // Compute length caches
Shinya Kitaoka 120a6e
  m_imp->computeCacheVector();
Shinya Kitaoka 120a6e
  assert((int)m_imp->m_partialLenghtArray.size() == getControlPointCount());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (t == 1.0) ++chunk, t = 0.0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double s = m_imp->m_partialLenghtArray[chunk << 1];
Shinya Kitaoka 120a6e
  if (t > 0.0) s += getChunk(chunk)->getLength(t);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return s;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::invalidate() {
Shinya Kitaoka 120a6e
  m_imp->m_maxThickness   = -1;
Shinya Kitaoka 120a6e
  m_imp->m_isOutlineValid = false;
Shinya Kitaoka 120a6e
  m_imp->m_isValidLength  = false;
Shinya Kitaoka 120a6e
  m_imp->m_flag           = m_imp->m_flag | c_dirty_flag;
Shinya Kitaoka 120a6e
  if (m_imp->m_prop) m_imp->m_prop->notifyStrokeChange();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
/*!
Toshihiro Shimizu 890ddd
N.B. Questa funzione e' piu' lenta rispetto alla insertCP
Toshihiro Shimizu 890ddd
perche' ricerca la posizione di s con un algoritmo di bisezione.
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
void TStroke::insertControlPointsAtLength(double s) {
Shinya Kitaoka 120a6e
  if (0 > s || s > getLength()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int chunk;
Shinya Kitaoka 120a6e
  double t;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // cerca il cionco ed il parametro alla lunghezza s
Shinya Kitaoka 120a6e
  if (!m_imp->retrieveChunkAndItsParamameterAtLength(s, chunk, t)) {
Shinya Kitaoka 120a6e
    if (isAlmostZero(t) || areAlmostEqual(t, 1)) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // calcolo i due "cionchi"
Shinya Kitaoka 120a6e
    TThickQuadratic *tqfirst  = new TThickQuadratic,
Shinya Kitaoka 120a6e
                    *tqsecond = new TThickQuadratic;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    getChunk(chunk)->split(t, *tqfirst, *tqsecond);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    double parameterInStroke;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (0 == chunk)
Shinya Kitaoka 120a6e
      parameterInStroke = m_imp->getW(2) * t;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      parameterInStroke =
Shinya Kitaoka 120a6e
          t * m_imp->getW((chunk + 1) * 2) + (1 - t) * m_imp->getW(chunk * 2);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    m_imp->updateParameterValue(parameterInStroke, chunk, tqfirst, tqsecond);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // recupero la posizione nella lista delle curve
Shinya Kitaoka 120a6e
    QuadStrokeChunkArray::iterator it = m_imp->m_centerLineArray.begin();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // elimino la curva vecchia
Shinya Kitaoka 120a6e
    advance(it, chunk);
Shinya Kitaoka 120a6e
    delete *it;
Shinya Kitaoka 120a6e
    it = m_imp->m_centerLineArray.erase(it);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // ed aggiungo le nuove
Shinya Kitaoka 120a6e
    it = m_imp->m_centerLineArray.insert(it, tqsecond);
Shinya Kitaoka 120a6e
    it = m_imp->m_centerLineArray.insert(it, tqfirst);
Toshihiro Shimizu 890ddd
  }
Shinya Kitaoka 120a6e
  /* FAB
Shinya Kitaoka 120a6e
#ifdef  _DEBUG
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
const int
Shinya Kitaoka 120a6e
size = m_imp->m_parameterValueAtControlPoint.size();
Shinya Kitaoka 120a6e
double
Shinya Kitaoka 120a6e
prev = m_imp->m_parameterValueAtControlPoint[0];
Shinya Kitaoka 120a6e
for( int i = 1;
Shinya Kitaoka 120a6e
   i < size;
Shinya Kitaoka 120a6e
   ++i )
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
assert( prev <= m_imp->m_parameterValueAtControlPoint[i] );
Shinya Kitaoka 120a6e
prev = m_imp->m_parameterValueAtControlPoint[i];
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
}
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
//*/
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::insertControlPoints(double w) {
Shinya Kitaoka 120a6e
  if (0.0 > w || w > 1.0) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int chunk;
Shinya Kitaoka 120a6e
  double tOfDivision = -1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_imp->retrieveChunkAndItsParamameter(w, chunk, tOfDivision)) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (isAlmostZero(tOfDivision) || areAlmostEqual(tOfDivision, 1)) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(0 <= chunk && chunk < getChunkCount());
Shinya Kitaoka 120a6e
  assert(0 <= tOfDivision && tOfDivision <= 1.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // calcolo i due "cionchi"
Shinya Kitaoka 120a6e
  TThickQuadratic *tqfirst  = new TThickQuadratic,
Shinya Kitaoka 120a6e
                  *tqsecond = new TThickQuadratic;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  getChunk(chunk)->split(tOfDivision, *tqfirst, *tqsecond);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_imp->updateParameterValue(w, chunk, tqfirst, tqsecond);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // recupero la posizione nella lista delle curve
Shinya Kitaoka 120a6e
  QuadStrokeChunkArray::iterator it = m_imp->m_centerLineArray.begin();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // elimino la curva vecchia
Shinya Kitaoka 120a6e
  advance(it, chunk);
Shinya Kitaoka 120a6e
  delete *it;
Shinya Kitaoka 120a6e
  it = m_imp->m_centerLineArray.erase(it);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // ed aggiungo le nuove
Shinya Kitaoka 120a6e
  it = m_imp->m_centerLineArray.insert(it, tqsecond);
Shinya Kitaoka 120a6e
  m_imp->m_centerLineArray.insert(it, tqfirst);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  invalidate();
Shinya Kitaoka 120a6e
  m_imp->computeCacheVector();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_imp->m_negativeThicknessPoints = 0;
Shinya Kitaoka 120a6e
  for (UINT j = 0; j < m_imp->m_centerLineArray.size(); j++) {
Shinya Kitaoka 120a6e
    if (m_imp->m_centerLineArray[j]->getThickP0().thick <= 0)
Shinya Kitaoka 120a6e
      m_imp->m_negativeThicknessPoints++;
Shinya Kitaoka 120a6e
    if (m_imp->m_centerLineArray[j]->getThickP1().thick <= 0)
Shinya Kitaoka 120a6e
      m_imp->m_negativeThicknessPoints++;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (!m_imp->m_centerLineArray.empty() &&
Shinya Kitaoka 120a6e
      m_imp->m_centerLineArray.back()->getThickP2().thick <= 0)
Shinya Kitaoka 120a6e
    m_imp->m_negativeThicknessPoints++;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::reduceControlPoints(double error, vector<int> corners) {
Shinya Kitaoka 120a6e
  double step, quadLen;
Shinya Kitaoka 120a6e
  vector<TThickPoint> tempVect, controlPoints;
Shinya Kitaoka 120a6e
  TStroke *tempStroke = 0;
Shinya Kitaoka 120a6e
  double missedLen    = 0;
Shinya Kitaoka 120a6e
  UINT cp, nextQuad, quadI, cornI, cpSize, size;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const TThickQuadratic *quad = m_imp->m_centerLineArray.front();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  size = corners.size();
Shinya Kitaoka 120a6e
  assert(size > 1);
Shinya Kitaoka 120a6e
  if (size < 2) {
Shinya Kitaoka 120a6e
    // Have at least the first and last stroke points as corners
Shinya Kitaoka 120a6e
    corners.resize(2);
Shinya Kitaoka 120a6e
    corners[0] = 0;
Shinya Kitaoka 120a6e
    corners[1] = m_imp->m_centerLineArray.size();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // For every corners interval
Shinya Kitaoka 120a6e
  for (cornI = 0; cornI < size - 1; ++cornI) {
Shinya Kitaoka 120a6e
    tempVect.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    nextQuad = corners[cornI + 1];
Shinya Kitaoka 120a6e
    if (nextQuad > m_imp->m_centerLineArray.size()) {
Shinya Kitaoka 120a6e
      assert(!"bad quadric index");
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (corners[cornI] >= (int)m_imp->m_centerLineArray.size()) {
Shinya Kitaoka 120a6e
      assert(!"bad quadric index");
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (quadI = corners[cornI]; quadI < nextQuad; quadI++) {
Shinya Kitaoka 120a6e
      quad    = getChunk(quadI);
Shinya Kitaoka 120a6e
      quadLen = quad->getLength();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      missedLen += quadLen;
Shinya Kitaoka 120a6e
      if (quadLen && (missedLen > 1 || quadI == 0 ||
Shinya Kitaoka 120a6e
                      quadI == nextQuad - 1))  // err instead of 1?
Shinya Kitaoka 120a6e
      {
Shinya Kitaoka 120a6e
        missedLen = 0;
Shinya Kitaoka 120a6e
        step      = 1.0 / quadLen;  // err instead of 1.0?
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // si, lo so che t non e' lineare sulla lunghezza, ma secondo me
Shinya Kitaoka 120a6e
        // funziona benissimo
Shinya Kitaoka 120a6e
        // cosi'. tanto devo interpolare dei punto e non e' richiesto che siano
Shinya Kitaoka 120a6e
        // a distanze
Shinya Kitaoka 120a6e
        // simili. e poi difficilmete il punto p1 di una quadratica e' cosi'
Shinya Kitaoka 120a6e
        // asimmetrico
Shinya Kitaoka 120a6e
        for (double t = 0; t < 1.0; t += step)
Shinya Kitaoka 120a6e
          tempVect.push_back(quad->getThickPoint(t));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    tempVect.push_back(quad->getThickP2());
Shinya Kitaoka 120a6e
    tempStroke = TStroke::interpolate(tempVect, error, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    cpSize = tempStroke->getControlPointCount();
Shinya Kitaoka 120a6e
    for (cp = 0; cp < cpSize - 1; cp++) {
Shinya Kitaoka 120a6e
      controlPoints.push_back(tempStroke->getControlPoint(cp));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    delete tempStroke;
Shinya Kitaoka 120a6e
    tempStroke = 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  controlPoints.push_back(m_imp->m_centerLineArray.back()->getThickP2());
Toshihiro Shimizu 890ddd
Campbell Barton d869b5
#ifdef _DEBUG
Shinya Kitaoka 120a6e
  cpSize = controlPoints.size();
Shinya Kitaoka 120a6e
  for (cp = 1; cp < cpSize; cp++)
Shinya Kitaoka 120a6e
    assert(!(controlPoints[cp - 1] == controlPoints[cp]));
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  reshape(&(controlPoints[0]), controlPoints.size());
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::reduceControlPoints(double error) {
Shinya Kitaoka 120a6e
  vector<int> corners;
Shinya Kitaoka 120a6e
  corners.push_back(0);
Shinya Kitaoka 120a6e
  detectCorners(this, 10, corners);
Shinya Kitaoka 120a6e
  corners.push_back(getChunkCount());
Shinya Kitaoka 120a6e
  reduceControlPoints(error, corners);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TStroke::getAverageThickness() const {
Shinya Kitaoka 120a6e
  return m_imp->m_averageThickness;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TStroke::getMaxThickness() {
Shinya Kitaoka 120a6e
  if (m_imp->m_maxThickness == -1) m_imp->computeMaxThickness();
Shinya Kitaoka 120a6e
  return m_imp->m_maxThickness;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::setAverageThickness(double thickness) {
Shinya Kitaoka 120a6e
  m_imp->m_averageThickness = thickness;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TStroke::operator==(const TStroke &s) const {
Shinya Kitaoka 120a6e
  if (getChunkCount() != s.getChunkCount()) return false;
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < getChunkCount(); i++) {
Shinya Kitaoka 120a6e
    const TThickQuadratic *chanck  = getChunk(i);
Shinya Kitaoka 120a6e
    const TThickQuadratic *sChanck = s.getChunk(i);
Shinya Kitaoka 120a6e
    if (chanck->getThickP0() != sChanck->getThickP0() ||
Shinya Kitaoka 120a6e
        chanck->getThickP1() != sChanck->getThickP1() ||
Shinya Kitaoka 120a6e
        chanck->getThickP2() != sChanck->getThickP2())
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TStroke::getChunkCount() const { return m_imp->getChunkCount(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TStroke::getControlPointCount() const {
Shinya Kitaoka 120a6e
  return m_imp->getControlPointCount();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
const TThickQuadratic *TStroke::getChunk(int index) const {
Shinya Kitaoka 120a6e
  return m_imp->getChunk(index);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRectD TStroke::getBBox(double w0, double w1) const {
Shinya Kitaoka 120a6e
  if (w0 > w1) tswap(w0, w1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (w0 != 0.0 || w1 != 1.0) return m_imp->computeSubBBox(w0, w1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_imp->m_flag & c_dirty_flag) ((TStroke *)this)->computeBBox();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return m_imp->m_bBox;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::computeBBox() {
Shinya Kitaoka 120a6e
  m_imp->m_bBox = TOutlineUtil::computeBBox(*this);
Shinya Kitaoka 120a6e
  m_imp->m_flag &= ~c_dirty_flag;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TRectD TStroke::getCenterlineBBox() const {
Shinya Kitaoka 120a6e
  return m_imp->computeCenterlineBBox();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::disableComputeOfCaches() {
Shinya Kitaoka 120a6e
  m_imp->m_areDisabledComputeOfCaches = true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::enableComputeOfCaches() {
Shinya Kitaoka 120a6e
  m_imp->m_areDisabledComputeOfCaches = false;
Shinya Kitaoka 120a6e
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// DEL double TStroke::getDistance2(const   TPointD &p,
Shinya Kitaoka 120a6e
// DEL                              double  maxDistance2,
Shinya Kitaoka 120a6e
// DEL                              UINT    &chunkIndex,
Shinya Kitaoka 120a6e
// DEL                              double  &currT)
Shinya Kitaoka 120a6e
// DEL {
Shinya Kitaoka 120a6e
// DEL   TRectD rect = getBBox();
Shinya Kitaoka 120a6e
// DEL
Shinya Kitaoka 120a6e
// DEL   if (!rect.contains(p))
Shinya Kitaoka 120a6e
// DEL   {
Shinya Kitaoka 120a6e
// DEL     double dist21 = tdistance2(p, rect.getP00());
Shinya Kitaoka 120a6e
// DEL     double dist22 = tdistance2(p, rect.getP01());
Shinya Kitaoka 120a6e
// DEL     double dist23 = tdistance2(p, rect.getP10());
Shinya Kitaoka 120a6e
// DEL     double dist24 = tdistance2(p, rect.getP11());
Shinya Kitaoka 120a6e
// DEL
Shinya Kitaoka 120a6e
// DEL     if (std::min(dist21, dist22, dist23, dist24)>=maxDistance2)
Shinya Kitaoka 120a6e
// DEL       return maxDistance2;
Shinya Kitaoka 120a6e
// DEL   }
Shinya Kitaoka 120a6e
// DEL
Shinya Kitaoka 120a6e
// DEL   double distance2, curMaxDistance2=maxDistance2;
Shinya Kitaoka 120a6e
// DEL
Shinya Kitaoka 120a6e
// DEL   for (UINT i=0; i < m_imp->m_centerLineArray.size(); i++)
Shinya Kitaoka 120a6e
// DEL   {
Shinya Kitaoka 120a6e
// DEL     distance2 = getTQDistance2(*(m_imp->m_centerLineArray)[i], p,
Shinya Kitaoka 120a6e
// maxDistance2, currT);
Shinya Kitaoka 120a6e
// DEL     if (distance2 < curMaxDistance2)
Shinya Kitaoka 120a6e
// DEL     {
Shinya Kitaoka 120a6e
// DEL       curMaxDistance2 = distance2;
Shinya Kitaoka 120a6e
// DEL       chunkIndex = i;
Shinya Kitaoka 120a6e
// DEL     }
Shinya Kitaoka 120a6e
// DEL   }
Shinya Kitaoka 120a6e
// DEL
Shinya Kitaoka 120a6e
// DEL   return curMaxDistance2;
Shinya Kitaoka 120a6e
// DEL }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TThickPoint TStroke::getThickPointAtLength(double s) const {
Shinya Kitaoka 120a6e
  assert(!m_imp->m_centerLineArray.empty());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (s <= 0) return getControlPoint(0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (s >= getLength()) return getControlPoint(getControlPointCount() - 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int chunk;
Shinya Kitaoka 120a6e
  double tOfDivision;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool error =
Shinya Kitaoka 120a6e
      m_imp->retrieveChunkAndItsParamameterAtLength(s, chunk, tOfDivision);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (error)
Shinya Kitaoka 120a6e
    error =
Shinya Kitaoka 120a6e
        m_imp->retrieveChunkAndItsParamameterAtLength(s, chunk, tOfDivision);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(!error);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (error) return getControlPoint(0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return getChunk(chunk)->getThickPoint(tOfDivision);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
TThickPoint TStroke::getThickPoint(double w) const {
Shinya Kitaoka 120a6e
  assert(!m_imp->m_centerLineArray.empty());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (w < 0) return getControlPoint(0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (w > 1.0) return getControlPoint(getControlPointCount() - 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int chunk = 0;
Shinya Kitaoka 120a6e
  double t  = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool error = m_imp->retrieveChunkAndItsParamameter(w, chunk, t);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(!error);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (error) return getControlPoint(0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return getChunk(chunk)->getThickPoint(t);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TStroke::getParameterAtLength(double s) const {
Shinya Kitaoka 120a6e
  if (s <= 0)
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
  else if (s >= getLength())
Shinya Kitaoka 120a6e
    return 1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int chunk;
Shinya Kitaoka 120a6e
  double t;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!m_imp->retrieveChunkAndItsParamameterAtLength(s, chunk, t)) {
Shinya Kitaoka 120a6e
    DoublePair p = m_imp->retrieveParametersFromChunk(chunk);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    return proportion(p.second, t, 1.0, p.first);
Shinya Kitaoka 120a6e
  } else if (chunk < (int)getChunkCount() && t == -1)
Shinya Kitaoka 120a6e
    return getParameterAtControlPoint(2 * chunk);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return 1.0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TStroke::getParameterAtControlPoint(int n) const {
Shinya Kitaoka 120a6e
  double out = -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (0 <= n && n < getControlPointCount()) out = m_imp->getW(n);
Shinya Kitaoka 120a6e
  /* FAB
Shinya Kitaoka 120a6e
assert( 0.0 <= out &&
Shinya Kitaoka 120a6e
    out <= 1.0 );
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  if (0.0 > out) return 0.0;
Shinya Kitaoka 120a6e
  if (out > 1.0) return 1.0;
Shinya Kitaoka 120a6e
  return out;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TStroke::getW(int chunkIndex, double t) const {
Shinya Kitaoka 120a6e
  DoublePair parRange = m_imp->retrieveParametersFromChunk(chunkIndex);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double w = proportion(parRange.second, t, 1.0, parRange.first);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(0 <= w && w <= 1.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return w;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TStroke::getW(const TPointD &p) const {
Shinya Kitaoka 120a6e
  int chunkIndex;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double tOfchunk, distance2 = (numeric_limits<double>::max)();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // cerca il chunk piu' vicino senza testare la BBox
Shinya Kitaoka 120a6e
  getNearestChunk(p, tOfchunk, chunkIndex, distance2, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(0 <= chunkIndex && chunkIndex <= getChunkCount());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  DoublePair parRange = m_imp->retrieveParametersFromChunk(chunkIndex);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double t = proportion(parRange.second, tOfchunk, 1.0, parRange.first);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(0 <= t && t <= 1.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return t;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TStroke::getSpeedTwoValues(double w, TPointD &speed0,
Shinya Kitaoka 120a6e
                                TPointD &speed1) const {
Shinya Kitaoka 120a6e
  bool ret = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(!m_imp->m_centerLineArray.empty());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (w < 0) {
Shinya Kitaoka 120a6e
    speed0 = m_imp->m_centerLineArray.front()->getSpeed(0.0);
Shinya Kitaoka 120a6e
    return ret;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (w > 1.0) {
Shinya Kitaoka 120a6e
    speed0 = m_imp->m_centerLineArray.back()->getSpeed(1.0);
Shinya Kitaoka 120a6e
    return ret;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int chunk;
Shinya Kitaoka 120a6e
  double t;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool error = m_imp->retrieveChunkAndItsParamameter(w, chunk, t);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(!error);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (error) {
Shinya Kitaoka 120a6e
    speed0 = m_imp->m_centerLineArray.front()->getSpeed(0.0);
Shinya Kitaoka 120a6e
    speed1 = -speed0;
Shinya Kitaoka 120a6e
    return ret;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  speed0 = getChunk(chunk)->getSpeed(t);
Shinya Kitaoka 120a6e
  speed1 = -speed0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (areAlmostEqual(t, 0.0, 1e-9) && chunk > 0 &&
Shinya Kitaoka 120a6e
      (speed1 = -getChunk(chunk - 1)->getSpeed(1.0)) != -speed0)
Shinya Kitaoka 120a6e
    ret = true;
Shinya Kitaoka 120a6e
  else if (areAlmostEqual(t, 1.0, 1e-9) && chunk < getChunkCount() - 1 &&
Shinya Kitaoka 120a6e
           (speed1 = -getChunk(chunk + 1)->getSpeed(0.0)) != -speed0) {
Shinya Kitaoka 120a6e
    TPointD aux = -speed0;
Shinya Kitaoka 120a6e
    speed0      = -speed1;
Shinya Kitaoka 120a6e
    speed1      = aux;
Shinya Kitaoka 120a6e
    ret         = true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (speed0 == TPointD())  // la quadratica e' degenere!!!
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    while (speed0 == TPointD()) {
Shinya Kitaoka 120a6e
      speed0 = getChunk(chunk--)->getSpeed(1.0);
Shinya Kitaoka 120a6e
      if (chunk <= 0) break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    chunk = 0;
Shinya Kitaoka 120a6e
    while (speed0 == TPointD()) {
Shinya Kitaoka 120a6e
      speed0 = getChunk(chunk++)->getSpeed(0.0);
Shinya Kitaoka 120a6e
      if (chunk >= getChunkCount() - 1) break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (speed0 == TPointD()) {
Shinya Kitaoka 120a6e
      if (getChunkCount() == 1) {
Shinya Kitaoka 120a6e
        const TThickQuadratic *q = getChunk(0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (q->getP0() == q->getP1() && q->getP1() != q->getP2())
Shinya Kitaoka 120a6e
          speed0 = TSegment(q->getP1(), q->getP2()).getSpeed(t);
Shinya Kitaoka 120a6e
        else if (q->getP1() == q->getP2() && q->getP0() != q->getP1())
Shinya Kitaoka 120a6e
          speed0 = TSegment(q->getP0(), q->getP1()).getSpeed(t);
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          assert(speed0 != TPointD());
Shinya Kitaoka 120a6e
      } else
Shinya Kitaoka 120a6e
        assert(speed0 != TPointD());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return ret;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
TPointD TStroke::getSpeed(double w, bool outSpeed) const {
Shinya Kitaoka 120a6e
  assert(!m_imp->m_centerLineArray.empty());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (w < 0) return m_imp->m_centerLineArray.front()->getSpeed(0.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (w > 1.0) return m_imp->m_centerLineArray.back()->getSpeed(1.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int chunk;
Shinya Kitaoka 120a6e
  double t;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool error = m_imp->retrieveChunkAndItsParamameter(w, chunk, t);
Shinya Kitaoka 120a6e
  if (t == 1 && outSpeed && chunk < getChunkCount() - 1) {
Shinya Kitaoka 120a6e
    chunk++;
Shinya Kitaoka 120a6e
    t = 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  assert(!error);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (error) return m_imp->m_centerLineArray.front()->getSpeed(0.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPointD speed = getChunk(chunk)->getSpeed(t);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (speed == TPointD())  // la quadratica e' degenere!!!
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    while (speed == TPointD()) {
Shinya Kitaoka 120a6e
      speed = getChunk(chunk--)->getSpeed(1.0);
Shinya Kitaoka 120a6e
      if (chunk <= 0) break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    chunk = 0;
Shinya Kitaoka 120a6e
    while (speed == TPointD()) {
Shinya Kitaoka 120a6e
      speed = getChunk(chunk++)->getSpeed(0.0);
Shinya Kitaoka 120a6e
      if (chunk >= getChunkCount() - 1) break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (speed == TPointD()) {
Shinya Kitaoka 120a6e
      if (getChunkCount() == 1) {
Shinya Kitaoka 120a6e
        const TThickQuadratic *q = getChunk(0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (q->getP0() == q->getP1() && q->getP1() != q->getP2())
Shinya Kitaoka 120a6e
          return TSegment(q->getP1(), q->getP2()).getSpeed(t);
Shinya Kitaoka 120a6e
        else if (q->getP1() == q->getP2() && q->getP0() != q->getP1())
Shinya Kitaoka 120a6e
          return TSegment(q->getP0(), q->getP1()).getSpeed(t);
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          assert(speed != TPointD());
Shinya Kitaoka 120a6e
      } else
Shinya Kitaoka 120a6e
        assert(speed != TPointD());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return speed;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TPointD TStroke::getSpeedAtLength(double s) const {
Shinya Kitaoka 120a6e
  double t = getParameterAtLength(s);
Shinya Kitaoka 120a6e
  return getSpeed(t);
Shinya Kitaoka 120a6e
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double TStroke::getLengthAtControlPoint(int n) const {
Shinya Kitaoka 120a6e
  m_imp->computeCacheVector();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (n >= getControlPointCount()) return m_imp->m_partialLenghtArray.back();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (n <= 0) return m_imp->m_partialLenghtArray.front();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return m_imp->m_partialLenghtArray[n];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::split(double w, TStroke &f, TStroke &s) const {
Shinya Kitaoka 120a6e
  int chunk;
Shinya Kitaoka 120a6e
  double t;
Shinya Kitaoka 120a6e
  f.m_imp->m_maxThickness = -1;
Shinya Kitaoka 120a6e
  s.m_imp->m_maxThickness = -1;
Shinya Kitaoka 120a6e
  if (!m_imp->retrieveChunkAndItsParamameter(w, chunk, t)) {
Shinya Kitaoka 120a6e
    assert(0 <= chunk && chunk < getChunkCount());
Shinya Kitaoka 120a6e
    assert(0 <= w && w <= 1.0);
Shinya Kitaoka 120a6e
    assert(0 <= t && t <= 1.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    QuadStrokeChunkArray &chunkArray = m_imp->m_centerLineArray;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // build two temporary quadratic
Shinya Kitaoka 120a6e
    TThickQuadratic *tq1 = new TThickQuadratic, *tq2 = new TThickQuadratic;
Shinya Kitaoka 120a6e
    // make split
Shinya Kitaoka 120a6e
    chunkArray[chunk]->split(t, *tq1, *tq2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // a temporary vector of ThickQuadratic
Shinya Kitaoka 120a6e
    QuadStrokeChunkArray vTQ;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // copy all chunk of stroke in a vTQ
Shinya Kitaoka 120a6e
    int i;
Shinya Kitaoka 120a6e
    for (i = 0; i < chunk; ++i) vTQ.push_back(chunkArray[i]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // not insert null length chunk (unless vTQ is empty....)
Shinya Kitaoka 120a6e
    if (tq1->getLength() != 0.0 || w == 0.0 || vTQ.empty()) vTQ.push_back(tq1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // build a temp and swap
Shinya Kitaoka 120a6e
    TStroke *ts1  = TStroke::create(vTQ);
Shinya Kitaoka 120a6e
    if (!ts1) ts1 = new TStroke;
Shinya Kitaoka 120a6e
    ts1->swapGeometry(f);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // clear vector (chunks are now under TStroke control)
Shinya Kitaoka 120a6e
    vTQ.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // idem...
Shinya Kitaoka 120a6e
    if (tq2->getLength() != 0.0 || w == 1.0 || getChunkCount() == 0)
Shinya Kitaoka 120a6e
      vTQ.push_back(tq2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = chunk + 1; i < getChunkCount(); ++i) vTQ.push_back(chunkArray[i]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TStroke *ts2  = TStroke::create(vTQ);
Shinya Kitaoka 120a6e
    if (!ts2) ts2 = new TStroke;
Shinya Kitaoka 120a6e
    ts2->swapGeometry(s);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Copy style infos
Shinya Kitaoka 120a6e
    f.setStyle(getStyle());
Shinya Kitaoka 120a6e
    s.setStyle(getStyle());
Shinya Kitaoka 120a6e
    f.outlineOptions() = s.outlineOptions() = outlineOptions();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    delete ts2;
Shinya Kitaoka 120a6e
    delete ts1;
Shinya Kitaoka 120a6e
    // delete temporary quadratic
Shinya Kitaoka 120a6e
    delete tq1;
Shinya Kitaoka 120a6e
    delete tq2;
Shinya Kitaoka 120a6e
    if (f.getControlPointCount() == 3 &&
Shinya Kitaoka 120a6e
        f.getControlPoint(0) !=
Shinya Kitaoka 120a6e
            f.getControlPoint(2))  // gli stroke con solo 1 chunk vengono fatti
Shinya Kitaoka 120a6e
                                   // dal tape tool...e devono venir
Shinya Kitaoka 120a6e
                                   // riconosciuti come speciali di autoclose
Shinya Kitaoka 120a6e
                                   // proprio dal fatto che hanno 1 solo chunk.
Shinya Kitaoka 120a6e
      f.insertControlPoints(0.5);
Shinya Kitaoka 120a6e
    if (s.getControlPointCount() == 3 &&
Shinya Kitaoka 120a6e
        s.getControlPoint(0) !=
Shinya Kitaoka 120a6e
            s.getControlPoint(2))  // gli stroke con solo 1 chunk vengono fatti
Shinya Kitaoka 120a6e
                                   // dal tape tool...e devono venir
Shinya Kitaoka 120a6e
                                   // riconosciuti come speciali di autoclose
Shinya Kitaoka 120a6e
                                   // proprio dal fatto che hanno 1 solo chunk.
Shinya Kitaoka 120a6e
      s.insertControlPoints(0.5);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void TStroke::print(ostream &os) const {
Shinya Kitaoka 120a6e
  // m_imp->print(os);
Shinya Kitaoka 120a6e
  const TThickQuadratic *q;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  os << "Punti di controllo\n";
Shinya Kitaoka 120a6e
  for (int i = 0; i < getChunkCount(); ++i) {
Shinya Kitaoka 120a6e
    os << "quad #" << i << ":" << endl;
Shinya Kitaoka 120a6e
    q = getChunk(i);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    os << "    P0:" << q->getThickP0().x << ", " << q->getThickP0().y << ", "
Shinya Kitaoka 120a6e
       << q->getThickP0().thick << endl;
Shinya Kitaoka 120a6e
    os << "    P1:" << q->getThickP1().x << ", " << q->getThickP1().y << ", "
Shinya Kitaoka 120a6e
       << q->getThickP1().thick << endl;
Shinya Kitaoka 120a6e
    assert(i == getChunkCount() - 1 ||
Shinya Kitaoka 120a6e
           (getChunk(i)->getThickP2() == getChunk(i + 1)->getThickP0()));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  q = getChunk(getChunkCount() - 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  os << "    P2:" << q->getThickP2().x << ", " << q->getThickP2().y << ", "
Shinya Kitaoka 120a6e
     << q->getThickP2().thick << endl;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::transform(const TAffine &aff, bool doChangeThickness) {
Shinya Kitaoka 120a6e
  for (UINT i = 0; i < m_imp->m_centerLineArray.size(); ++i) {
Shinya Kitaoka 120a6e
    TThickQuadratic &ref = *m_imp->m_centerLineArray[i];
Shinya Kitaoka 120a6e
    ref                  = transformQuad(aff, ref, doChangeThickness);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (doChangeThickness) {
Shinya Kitaoka 120a6e
      double det                                     = aff.det();
Shinya Kitaoka 120a6e
      if (det == 0) m_imp->m_negativeThicknessPoints = getControlPointCount();
Shinya Kitaoka 120a6e
      if (m_imp->m_maxThickness != -1) m_imp->m_maxThickness *= sqrt(fabs(det));
Shinya Kitaoka 120a6e
      // else if(det<0)
Shinya Kitaoka 120a6e
      //  m_imp->m_negativeThicknessPoints=getControlPointCount()-m_imp->m_negativeThicknessPoints;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
void TStroke::draw(const TVectorRenderData &rd) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
  if(! m_imp->m_styleId)
Toshihiro Shimizu 890ddd
    return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  TColorStyle * style = rd.m_palette->getStyle(m_imp->m_styleId);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  if( !style->isStrokeStyle() || style->isEnabled() == false )
Toshihiro Shimizu 890ddd
    return;
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  if( !m_imp->m_prop || style != m_imp->m_prop->getColorStyle() )
Toshihiro Shimizu 890ddd
  {
Toshihiro Shimizu 890ddd
    delete m_imp->m_prop;
Shinya Kitaoka 120a6e
    m_imp->m_prop = style->makeStrokeProp(this);
Toshihiro Shimizu 890ddd
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  m_imp->m_prop->draw(rd);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStrokeProp *TStroke::getProp() const {
Campbell Barton d869b5
#if !defined(DISEGNO_OUTLINE)
Shinya Kitaoka 120a6e
  if (!m_imp->m_styleId) return 0;
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
TColorStyle * style = palette->getStyle(m_imp->m_styleId);
Shinya Kitaoka 120a6e
if( !style->isStrokeStyle() || style->isEnabled() == false )
Shinya Kitaoka 120a6e
return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
if( !m_imp->m_prop || style != m_imp->m_prop->getColorStyle() )
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
delete m_imp->m_prop;
Shinya Kitaoka 120a6e
m_imp->m_prop = style->makeStrokeProp(this);
Shinya Kitaoka 120a6e
}
Toshihiro Shimizu 890ddd
*/
Shinya Kitaoka 120a6e
  return m_imp->m_prop;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::setProp(TStrokeProp *prop) {
Shinya Kitaoka 120a6e
  assert(prop);
Shinya Kitaoka 120a6e
  delete m_imp->m_prop;
Shinya Kitaoka 120a6e
  m_imp->m_prop = prop;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TStroke::getStyle() const { return m_imp->m_styleId; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::setStyle(int styleId) {
Shinya Kitaoka 120a6e
  m_imp->m_styleId = styleId;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
if (!colorStyle || (colorStyle && colorStyle->isStrokeStyle())  )
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
m_imp->m_colorStyle = colorStyle;
Shinya Kitaoka 120a6e
delete m_imp->m_prop;
Shinya Kitaoka 120a6e
m_imp->m_prop = 0;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
*/
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke &TStroke::changeDirection() {
Shinya Kitaoka 120a6e
  UINT chunkCount = getChunkCount();
Shinya Kitaoka 120a6e
  UINT to         = tfloor(chunkCount * 0.5);
Shinya Kitaoka 120a6e
  UINT i;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (chunkCount & 1) changeTQDirection(m_imp->m_centerLineArray[to]);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  --chunkCount;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (i = 0; i < to; ++i) {
Shinya Kitaoka 120a6e
    changeTQDirection(m_imp->m_centerLineArray[i]);
Shinya Kitaoka 120a6e
    changeTQDirection(m_imp->m_centerLineArray[chunkCount - i]);
Shinya Kitaoka 120a6e
    TThickQuadratic *q1         = m_imp->m_centerLineArray[i];
Shinya Kitaoka 120a6e
    m_imp->m_centerLineArray[i] = m_imp->m_centerLineArray[chunkCount - i];
Shinya Kitaoka 120a6e
    m_imp->m_centerLineArray[chunkCount - i] = q1;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return *this;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::setFlag(TStrokeFlag flag, bool status) {
Shinya Kitaoka 120a6e
  if (status)
Shinya Kitaoka 120a6e
    m_imp->m_flag |= flag;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    m_imp->m_flag &= ~flag;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TStroke::getFlag(TStrokeFlag flag) const {
Shinya Kitaoka 120a6e
  return (m_imp->m_flag & flag) != 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::swap(TStroke &ref) {
Shinya Kitaoka 120a6e
  std::swap(m_imp, ref.m_imp);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Stroke props need to update their stroke owners
Shinya Kitaoka 120a6e
  if (m_imp->m_prop) m_imp->m_prop->setStroke(this);
Shinya Kitaoka 120a6e
  if (ref.m_imp->m_prop) ref.m_imp->m_prop->setStroke(&ref);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // The id is retained. This is coherent as the stroke id is supposedly
Shinya Kitaoka 120a6e
  // not an exchangeable info.
Shinya Kitaoka 120a6e
  std::swap(m_imp->m_id, ref.m_imp->m_id);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::swapGeometry(TStroke &ref) { m_imp->swapGeometry(*ref.m_imp); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int TStroke::getId() const { return m_imp->m_id; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::setId(int id) { m_imp->m_id = id; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// magari poi la sposto in un altro file
Shinya Kitaoka 120a6e
TThickPoint TStroke::getCentroid() const {
Shinya Kitaoka 120a6e
  double totalLen = getLength();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (totalLen == 0) return getControlPoint(0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double step           = totalLen * 0.1;
Shinya Kitaoka 120a6e
  double len            = 0;
Shinya Kitaoka 120a6e
  if (step > 10.0) step = 10.0;
Shinya Kitaoka 120a6e
  int count             = 0;
Shinya Kitaoka 120a6e
  TThickPoint point;
Shinya Kitaoka 120a6e
  for (; len <= totalLen; len += step) {
Shinya Kitaoka 120a6e
    count++;
Shinya Kitaoka 120a6e
    point += getThickPointAtLength(len);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return point * (1.0 / (double)count);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TStroke::setSelfLoop(bool loop) {
Shinya Kitaoka 120a6e
  if (loop) {
Shinya Kitaoka 120a6e
    // assert that a self loop is a stroke where first and last control points
Shinya Kitaoka 120a6e
    // are the same
Shinya Kitaoka 120a6e
    const int cpCount = this->getControlPointCount();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TThickPoint p, p0 = this->getControlPoint(0),
Shinya Kitaoka 120a6e
                   pn = this->getControlPoint(cpCount - 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    assert(areAlmostEqual(p0, pn, 2));
Shinya Kitaoka 120a6e
    p = (p0 + pn) * 0.5;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    this->setControlPoint(0, p);
Shinya Kitaoka 120a6e
    this->setControlPoint(cpCount - 1, p);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_imp->m_selfLoop = loop;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TStroke::isSelfLoop() const { return m_imp->m_selfLoop; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool TStroke::isCenterLine() const {
Shinya Kitaoka 120a6e
  assert(m_imp->m_negativeThicknessPoints <= getControlPointCount());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return m_imp->m_negativeThicknessPoints == getControlPointCount();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke::OutlineOptions &TStroke::outlineOptions() {
Shinya Kitaoka 120a6e
  return m_imp->m_outlineOptions;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
const TStroke::OutlineOptions &TStroke::outlineOptions() const {
Shinya Kitaoka 120a6e
  return m_imp->m_outlineOptions;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//  End Of File
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke *joinStrokes(const TStroke *s0, const TStroke *s1) {
Shinya Kitaoka 120a6e
  TStroke *newStroke;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (s0 == s1) {
Shinya Kitaoka 120a6e
    newStroke = new TStroke(*s0);
Shinya Kitaoka 120a6e
    newStroke->setSelfLoop();
Shinya Kitaoka 120a6e
    return newStroke;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  vector<TThickPoint> v;
Shinya Kitaoka 120a6e
  for (i = 0; i < s0->getControlPointCount(); i++)
Shinya Kitaoka 120a6e
    v.push_back(s0->getControlPoint(i));
Shinya Kitaoka 120a6e
  if (areAlmostEqual(v.back(), s1->getControlPoint(0), 1e-3))
Shinya Kitaoka 120a6e
    for (i = 1; i < s1->getControlPointCount(); i++)
Shinya Kitaoka 120a6e
      v.push_back(s1->getControlPoint(i));
Shinya Kitaoka 120a6e
  else if (areAlmostEqual(v.back(),
Shinya Kitaoka 120a6e
                          s1->getControlPoint(s1->getControlPointCount() - 1),
Shinya Kitaoka 120a6e
                          1e-3))
Shinya Kitaoka 120a6e
    for (i = s1->getControlPointCount() - 2; i >= 0; i--)
Shinya Kitaoka 120a6e
      v.push_back(s1->getControlPoint(i));
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    assert(false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  newStroke = new TStroke(v);
Shinya Kitaoka 120a6e
  newStroke->setStyle(s0->getStyle());
Shinya Kitaoka 120a6e
  newStroke->outlineOptions() = s0->outlineOptions();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return newStroke;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
int cpCount1 = stroke1->getControlPointCount();
Shinya Kitaoka 120a6e
int cpCount2 = stroke2->getControlPointCount();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int qCount1 = stroke1->getChunkCount();
Shinya Kitaoka 120a6e
const TThickQuadratic* q1=stroke1->getChunk(qCount1-1 );
Shinya Kitaoka 120a6e
const TThickQuadratic* q2=stroke2->getChunk(0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TThickPoint extreme1 = q1->getThickP2() ;
Shinya Kitaoka 120a6e
TThickPoint extreme2 = q2->getThickP0();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
vector<TThickPoint> points;
Shinya Kitaoka 120a6e
points.reserve(cpCount1+cpCount2-1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int i =  0;
Shinya Kitaoka 120a6e
for(; i!=cpCount1-1; i++)
Shinya Kitaoka 120a6e
points.push_back( stroke1->getControlPoint(i));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
if(extreme1==extreme2)
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
points.push_back(extreme1);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
else
Shinya Kitaoka 120a6e
{
Shinya Kitaoka 120a6e
double len1=q1->getLength();
Shinya Kitaoka 120a6e
assert(len1>=0);
Shinya Kitaoka 120a6e
if(len1<=0)
Shinya Kitaoka 120a6e
len1=0;
Shinya Kitaoka 120a6e
double w1= exp(-len1*0.01);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double len2=q2->getLength();
Shinya Kitaoka 120a6e
assert(len2>=0);
Shinya Kitaoka 120a6e
if(len2<=0)
Shinya Kitaoka 120a6e
len2=0;
Shinya Kitaoka 120a6e
double w2= exp(-len2*0.01);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
TThickPoint m1=q1->getThickP1();
Shinya Kitaoka 120a6e
TThickPoint m2=q2->getThickP1();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
TThickPoint p1= extreme1*(1-w1)+m1*w1;
Shinya Kitaoka 120a6e
TThickPoint p2= extreme2*(1-w2)+m2*w2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
TThickPoint middleP= (p1 + p2)*0.5;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
double angle=fabs(cross(normalize(m1-middleP),normalize(m2-middleP)));
Shinya Kitaoka 120a6e
if(  angle< 0.05)
Shinya Kitaoka 120a6e
middleP=(m1+m2)*0.5;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
points.push_back(middleP);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
for(i = 1; i!=cpCount2; i++)
Shinya Kitaoka 120a6e
points.push_back( stroke2->getControlPoint(i));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
newStroke = new TStroke(points);
Shinya Kitaoka 120a6e
newStroke->setStyle(stroke1->getStyle());
Shinya Kitaoka 120a6e
return newStroke;
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int local_intersect(const TStroke &stroke, const TSegment &segment,
Shinya Kitaoka 120a6e
                    std::vector<DoublePair> &intersections,
Shinya Kitaoka 120a6e
                    bool strokeIsFirst) {
Shinya Kitaoka 120a6e
  const TThickQuadratic *chunk;
Shinya Kitaoka 120a6e
  for (int i = 0; i < stroke.getChunkCount(); i++) {
Shinya Kitaoka 120a6e
    std::vector<DoublePair> localIntersections;
Shinya Kitaoka 120a6e
    chunk = stroke.getChunk(i);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (intersect(*chunk, segment, localIntersections)) {
Shinya Kitaoka 120a6e
      for (UINT j = 0; j < localIntersections.size(); j++) {
Shinya Kitaoka 120a6e
        double strokePar = localIntersections[j].first;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        strokePar = stroke.getW(chunk->getPoint(strokePar));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        // check for multiple solution
Shinya Kitaoka 120a6e
        DoublePair sol(
Shinya Kitaoka 120a6e
            strokeIsFirst ? strokePar : localIntersections[j].second,
Shinya Kitaoka 120a6e
            strokeIsFirst ? localIntersections[j].second : strokePar);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        std::vector<DoublePair>::iterator it_end = intersections.end();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        if (it_end == std::find(intersections.begin(), it_end, sol))
Shinya Kitaoka 120a6e
          intersections.push_back(sol);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return intersections.size();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool almostOverlaps(const TRectD &r0, const TRectD &r1) {
Shinya Kitaoka 120a6e
  if (r0.overlaps(r1)) return true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if ((r0.x1 < r1.x0) && (areAlmostEqual(r0.x1, r1.x0, 1e-5)))
Shinya Kitaoka 120a6e
    return true;
Shinya Kitaoka 120a6e
  else if ((r1.x1 < r0.x0) && (areAlmostEqual(r1.x1, r0.x0, 1e-5)))
Shinya Kitaoka 120a6e
    return true;
Shinya Kitaoka 120a6e
  if ((r0.y1 < r1.y0) && (areAlmostEqual(r0.y1, r1.y0, 1e-5)))
Shinya Kitaoka 120a6e
    return true;
Shinya Kitaoka 120a6e
  else if ((r1.y1 < r0.y0) && (areAlmostEqual(r1.y1, r0.y0, 1e-5)))
Shinya Kitaoka 120a6e
    return true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool greaterThanOneAndLesserThanZero(double val) {
Shinya Kitaoka 120a6e
  if (val > 1.0 || val < 0.0) return true;
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int intersect(const TStroke *s1, const TStroke *s2,
Shinya Kitaoka 120a6e
              std::vector<DoublePair> &intersections, bool checkBBox) {
Shinya Kitaoka 120a6e
  UINT k = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  intersections.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (checkBBox && !s1->getBBox().overlaps(s2->getBBox())) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < s1->getChunkCount(); i++) {
Shinya Kitaoka 120a6e
    const TQuadratic *q1 = s1->getChunk(i);
Shinya Kitaoka 120a6e
    if (q1->getP0() == q1->getP2() && q1->getP1() == q1->getP2()) continue;
Shinya Kitaoka 120a6e
    int j = 0;
Shinya Kitaoka 120a6e
    if (s1 ==
Shinya Kitaoka 120a6e
        s2)  // this 'if': if after i-th stroke there are degenere strokes,
Shinya Kitaoka 120a6e
    // I do not consider them; so, instead of starting from j = i+2
Shinya Kitaoka 120a6e
    // I start from j = i+2+numDegeneres
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      j = i + 2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      while (j <= s2->getChunkCount()) {
Shinya Kitaoka 120a6e
        const TQuadratic *qAux = s2->getChunk(j - 1);
Shinya Kitaoka 120a6e
        if (qAux->getP0() != qAux->getP2() || qAux->getP1() != qAux->getP2())
Shinya Kitaoka 120a6e
          break;
Shinya Kitaoka 120a6e
        j++;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (; j < s2->getChunkCount(); j++) {
Shinya Kitaoka 120a6e
      const TQuadratic *q2 = s2->getChunk(j);
Shinya Kitaoka 120a6e
      if (q2->getP0() == q2->getP2() && q2->getP1() == q2->getP2()) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (!almostOverlaps(q1->getBBox(), q2->getBBox())) continue;
Toshihiro Shimizu 890ddd
#ifdef CHECK_DEGLI_ESTREMI
Shinya Kitaoka 120a6e
      vector<DoublePair> quadIntersections1;
Shinya Kitaoka 120a6e
      if (i == 0 || i == s1->getChunkCount() - 1) && (j==0 || j==s2->getChunkCount()-1))
Toshihiro Shimizu 890ddd
				{
Shinya Kitaoka 120a6e
          TPointD pp1 = (i == 0 ? q1->getP0() : q1->getP2());
Shinya Kitaoka 120a6e
          TPointD pp2 = (j == 0 ? q2->getP0() : q2->getP2());
Shinya Kitaoka 120a6e
          if (areAlmostEqual(pp1, pp2)) {
Shinya Kitaoka 120a6e
            intersections.push_back(
Shinya Kitaoka 120a6e
                DoublePair(i == 0 ? 0.0 : 1.0, j == 0 ? 0.0 : 1.0));
Shinya Kitaoka 120a6e
            k++;
Shinya Kitaoka 120a6e
            continue;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
          if (s1->getChunkCount() == 1 && s2->getChunkCount() == 1) {
Shinya Kitaoka 120a6e
            TPointD pp1 = q1->getP2();
Shinya Kitaoka 120a6e
            TPointD pp2 = q2->getP2();
Shinya Kitaoka 120a6e
            if (areAlmostEqual(pp1, pp2)) {
Shinya Kitaoka 120a6e
              intersections.push_back(DoublePair(1.0, 1.0));
Shinya Kitaoka 120a6e
              k++;
Shinya Kitaoka 120a6e
              continue;
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
          if (s1->getChunkCount() == 1) {
Shinya Kitaoka 120a6e
            TPointD pp1 = q1->getP2();
Shinya Kitaoka 120a6e
            TPointD pp2 = (j == 0 ? q2->getP0() : q2->getP2());
Shinya Kitaoka 120a6e
            if (areAlmostEqual(pp1, pp2)) {
Shinya Kitaoka 120a6e
              intersections.push_back(DoublePair(1.0, j == 0 ? 0.0 : 1.0));
Shinya Kitaoka 120a6e
              k++;
Shinya Kitaoka 120a6e
              continue;
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
          if (s2->getChunkCount() == 1) {
Shinya Kitaoka 120a6e
            TPointD pp1 = (i == 0 ? q1->getP0() : q1->getP2());
Shinya Kitaoka 120a6e
            TPointD pp2 = q2->getP2();
Shinya Kitaoka 120a6e
            if (areAlmostEqual(pp1, pp2)) {
Shinya Kitaoka 120a6e
              intersections.push_back(DoublePair(i == 0 ? 0.0 : 1.0, 1.0));
Shinya Kitaoka 120a6e
              k++;
Shinya Kitaoka 120a6e
              continue;
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      // if (j<s2->getChunkCount()-1)
Shinya Kitaoka 120a6e
      //  {
Shinya Kitaoka 120a6e
      // const TQuadratic *q3= s2->getChunk(j==0?0:j+1);
Shinya Kitaoka 120a6e
      // evito di intersecare se le quadratiche sono uguali
Shinya Kitaoka 120a6e
      if (*q1 == *q2 ||
Shinya Kitaoka 120a6e
          (q1->getP0() == q2->getP2() && q1->getP1() == q2->getP1() &&
Shinya Kitaoka 120a6e
           q1->getP2() == q2->getP0())) {
Shinya Kitaoka 120a6e
        // j+=((j==0)?1:2);
Shinya Kitaoka 120a6e
        continue;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      //  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      vector<DoublePair> quadIntersections;
Shinya Kitaoka 120a6e
      if (intersect(*q1, *q2, quadIntersections))
Shinya Kitaoka 120a6e
        for (int h = 0; h < (int)quadIntersections.size(); h++) {
Shinya Kitaoka 120a6e
          DoublePair res(getWfromChunkAndT(s1, i, quadIntersections[h].first),
Shinya Kitaoka 120a6e
                         getWfromChunkAndT(s2, j, quadIntersections[h].second));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (areAlmostEqual(quadIntersections[h].first, 0) ||
Shinya Kitaoka 120a6e
              areAlmostEqual(quadIntersections[h].first, 1) ||
Shinya Kitaoka 120a6e
              areAlmostEqual(quadIntersections[h].second, 0) ||
Shinya Kitaoka 120a6e
              areAlmostEqual(quadIntersections[h].second, 1)) {
Shinya Kitaoka 120a6e
            int q = 0;
Shinya Kitaoka 120a6e
            for (q = 0; q < (int)intersections.size(); q++)
Shinya Kitaoka 120a6e
              if (areAlmostEqual(intersections[q].first, res.first, 1e-8) &&
Shinya Kitaoka 120a6e
                  areAlmostEqual(intersections[q].second, res.second, 1e-8))
Shinya Kitaoka 120a6e
                break;
Shinya Kitaoka 120a6e
            if (q < (int)intersections.size()) continue;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
          intersections.push_back(res);
Shinya Kitaoka 120a6e
          // if (k==0 || intersections[k].first!=intersections[k-1].first ||
Shinya Kitaoka 120a6e
          // intersections[k].second!=intersections[k-1].second)
Shinya Kitaoka 120a6e
          k++;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (s1 == s2 &&
Shinya Kitaoka 120a6e
      (s1->isSelfLoop() || s1->getPoint(0.0) == s1->getPoint(1.0))) {
Shinya Kitaoka 120a6e
    int i;
Shinya Kitaoka 120a6e
    for (i = 0; i < (int)intersections.size(); i++) {
Shinya Kitaoka 120a6e
      assert(!(areAlmostEqual(intersections[i].first, 1.0, 1e-1) &&
Shinya Kitaoka 120a6e
               areAlmostEqual(intersections[i].second, 0.0, 1e-1)));
Shinya Kitaoka 120a6e
      if (areAlmostEqual(intersections[i].first, 0.0, 1e-1) &&
Shinya Kitaoka 120a6e
          areAlmostEqual(intersections[i].second, 1.0, 1e-1))
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (i == (int)intersections.size()) {
Shinya Kitaoka 120a6e
      intersections.push_back(DoublePair(0.0, 1.0));
Shinya Kitaoka 120a6e
      k++;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return k;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int intersect(const TSegment &segment, const TStroke &stroke,
Shinya Kitaoka 120a6e
              std::vector<DoublePair> &intersections) {
Shinya Kitaoka 120a6e
  return local_intersect(stroke, segment, intersections, false);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int intersect(const TStroke &stroke, const TSegment &segment,
Shinya Kitaoka 120a6e
              std::vector<DoublePair> &intersections) {
Shinya Kitaoka 120a6e
  return local_intersect(stroke, segment, intersections, true);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int intersect(const TStroke &stroke, const TPointD &center, double radius,
Shinya Kitaoka 120a6e
              vector<double> &intersections) {
Shinya Kitaoka 120a6e
  //            2    2    2
Shinya Kitaoka 120a6e
  // riconduco x  + y  = r  con x(t) y(t) alla forma
Shinya Kitaoka 120a6e
  //        2                2           2              2    2
Shinya Kitaoka 120a6e
  // ( a_x t + b_x t + c_x  ) + ( a_y t + b_y t + c_y  )  = r
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //     2
Shinya Kitaoka 120a6e
  //  a x  + b x + c
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const int a = 2;
Shinya Kitaoka 120a6e
  const int b = 1;
Shinya Kitaoka 120a6e
  const int c = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  vector<TPointD> bez(3);
Shinya Kitaoka 120a6e
  vector<TPointD> pol(3);
Shinya Kitaoka 120a6e
  vector<double> coeff(5);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int chunk = 0; chunk < stroke.getChunkCount(); ++chunk) {
Shinya Kitaoka 120a6e
    const TThickQuadratic *tq = stroke.getChunk(chunk);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    bez[0] = tq->getP0();
Shinya Kitaoka 120a6e
    bez[1] = tq->getP1();
Shinya Kitaoka 120a6e
    bez[2] = tq->getP2();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    bezier2poly(bez, pol);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    pol[c] -= center;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    coeff[4] = sq(pol[a].x) + sq(pol[a].y);
Shinya Kitaoka 120a6e
    coeff[3] = 2.0 * (pol[a].x * pol[b].x + pol[a].y * pol[b].y);
Shinya Kitaoka 120a6e
    coeff[2] = 2.0 * (pol[a].x * pol[c].x + pol[a].y * pol[c].y) +
Shinya Kitaoka 120a6e
               sq(pol[b].x) + sq(pol[b].y);
Shinya Kitaoka 120a6e
    coeff[1] = 2.0 * (pol[b].x * pol[c].x + pol[b].y * pol[c].y);
Shinya Kitaoka 120a6e
    coeff[0] = sq(pol[c].x) + sq(pol[c].y) - sq(radius);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    vector<double> sol;
Shinya Kitaoka 120a6e
    rootFinding(coeff, sol);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    sol.erase(
Shinya Kitaoka 120a6e
        remove_if(sol.begin(), sol.end(), greaterThanOneAndLesserThanZero),
Shinya Kitaoka 120a6e
        sol.end());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (UINT j = 0; j < sol.size(); ++j)
Shinya Kitaoka 120a6e
      intersections.push_back(getWfromChunkAndT(&stroke, chunk, sol[j]));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#if defined(DEBUG) || defined(_DEBUG)
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
cout<<"interesections:";
Shinya Kitaoka 120a6e
copy( intersections.begin(), intersections.end(), ostream_iterator<double>(
Shinya Kitaoka 120a6e
cout, " " ) );
Shinya Kitaoka 120a6e
cout<<endl;
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  // assert to test intersections are not decrescent
Shinya Kitaoka 120a6e
  vector<double> test;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  adjacent_difference(intersections.begin(), intersections.end(),
Shinya Kitaoka 120a6e
                      back_inserter(test));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  while (!test.empty()) {
Shinya Kitaoka 120a6e
    assert(test.back() >= 0);
Shinya Kitaoka 120a6e
    test.pop_back();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return intersections.size();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void splitStroke(const TStroke &tq, const vector<double> &pars,
Shinya Kitaoka 120a6e
                 std::vector<TStroke *> &v) {
Shinya Kitaoka 120a6e
  if (pars.empty()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  UINT i, vSize = pars.size();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  vector<double> length(vSize);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // primo passo estraggo i parametri di lunghezza
Shinya Kitaoka 120a6e
  for (i = 0; i < vSize; ++i) length[i] = tq.getLength(pars[i]);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::adjacent_difference(length.begin(), length.end(), length.begin());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TStroke *q1, q2, q3;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  q1 = new TStroke();
Shinya Kitaoka 120a6e
  tq.split(pars[0], *q1, q2);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(areAlmostEqual(q1->getLength(), length[0], 1e-4));
Shinya Kitaoka 120a6e
  v.push_back(q1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (i = 1; i < vSize; ++i) {
Shinya Kitaoka 120a6e
    q1         = new TStroke();
Shinya Kitaoka 120a6e
    double par = q2.getParameterAtLength(length[i]);
Shinya Kitaoka 120a6e
    assert(0 <= par && par <= 1.0);
Shinya Kitaoka 120a6e
    q2.split(par, *q1, q3);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    assert(areAlmostEqual(q1->getLength(), length[i], 1e-4));
Shinya Kitaoka 120a6e
    v.push_back(q1);
Shinya Kitaoka 120a6e
    q2 = q3;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  v.push_back(new TStroke(q2));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void detectCorners(const TStroke *stroke, double minDegree,
Shinya Kitaoka 120a6e
                   std::vector<int> &corners) {
Shinya Kitaoka 120a6e
  const double minSin = fabs(sin(minDegree * M_PI_180));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const TThickQuadratic *quad1 = 0;
Shinya Kitaoka 120a6e
  const TThickQuadratic *quad2 = 0;
Shinya Kitaoka 120a6e
  UINT quadCount1              = stroke->getChunkCount();
Shinya Kitaoka 120a6e
  TPointD speed1, speed2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPointD tan1, tan2;
Shinya Kitaoka 120a6e
  quad1 = stroke->getChunk(0);
Shinya Kitaoka 120a6e
  for (UINT j = 1; j < quadCount1; j++) {
Shinya Kitaoka 120a6e
    quad2 = stroke->getChunk(j);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    speed1 = quad1->getSpeed(1);
Shinya Kitaoka 120a6e
    speed2 = quad2->getSpeed(0);
Shinya Kitaoka 120a6e
    if (!(speed1 == TPointD() || speed2 == TPointD())) {
Shinya Kitaoka 120a6e
      tan1 = normalize(speed1);
Shinya Kitaoka 120a6e
      tan2 = normalize(speed2);
Shinya Kitaoka 120a6e
      if (tan1 * tan2 < 0 || fabs(cross(tan1, tan2)) >= minSin)
Shinya Kitaoka 120a6e
        corners.push_back(j);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    quad1 = quad2;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Rimuove le quadratiche nulle, cioe' i chunk in cui i TThickPoint sono quasi
Shinya Kitaoka 120a6e
//! uguali
Shinya Kitaoka 120a6e
bool removeNullQuadratic(TStroke *stroke, bool checkThickness = true) {
Shinya Kitaoka 120a6e
  vector<TThickPoint> points;
Shinya Kitaoka 120a6e
  UINT i, qCount = stroke->getChunkCount();
Shinya Kitaoka 120a6e
  const TThickQuadratic *q;
Shinya Kitaoka 120a6e
  TThickPoint p1, p2, p3;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // se i punti coincidono e' una stroke puntiforme ed e' ammessa
Shinya Kitaoka 120a6e
  if (qCount == 1) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool check = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i != qCount; i++) {
Shinya Kitaoka 120a6e
    q  = stroke->getChunk(i);
Shinya Kitaoka 120a6e
    p1 = q->getThickP0();
Shinya Kitaoka 120a6e
    p2 = q->getThickP1();
Shinya Kitaoka 120a6e
    p3 = q->getThickP2();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (areAlmostEqual(p1.x, p2.x) && areAlmostEqual(p2.x, p3.x) &&
Shinya Kitaoka 120a6e
        areAlmostEqual(p1.y, p2.y) && areAlmostEqual(p2.y, p3.y) &&
Shinya Kitaoka 120a6e
        (!checkThickness || (areAlmostEqual(p1.thick, p2.thick) &&
Shinya Kitaoka 120a6e
                             areAlmostEqual(p2.thick, p3.thick)))) {
Shinya Kitaoka 120a6e
      // assert(!"null quadratic");
Shinya Kitaoka 120a6e
      check = true;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      points.push_back(p1);
Shinya Kitaoka 120a6e
      points.push_back(p2);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (check) {
Shinya Kitaoka 120a6e
    points.push_back(p3);
Shinya Kitaoka 120a6e
    stroke->reshape(&(points[0]), points.size());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return check;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Converte un TThickPoint p0 in un T3DPoint
Shinya Kitaoka 120a6e
inline T3DPointD thickPntTo3DPnt(const TThickPoint &p0) {
Shinya Kitaoka 120a6e
  return T3DPointD(p0.x, p0.y, p0.thick);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Converte un vettore di TThickPoint from in un vettore di T3DPointD to
Shinya Kitaoka 120a6e
void convert(const vector<TThickPoint> &from, vector<T3DPointD> &to) {
Shinya Kitaoka 120a6e
  to.resize(from.size());
Shinya Kitaoka 120a6e
  transform(from.begin(), from.end(), to.begin(), thickPntTo3DPnt);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef vector<TThickCubic *> TThickCubicArray;
Toshihiro Shimizu 890ddd
typedef vector<TThickQuadratic *> QuadStrokeChunkArray;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
/*!
Shinya Kitaoka 120a6e
          Restituisce un puntatore ad un array di double che contiene la
Shinya Kitaoka 120a6e
   distanza tra
Shinya Kitaoka 120a6e
                il primo punto e i successivi diviso la distanza tra il primo
Shinya Kitaoka 120a6e
   punto e l'ultimo
Shinya Kitaoka 120a6e
                */
Shinya Kitaoka 120a6e
double *chordLengthParameterize3D(const T3DPointD *pointsArrayBegin, int size) {
Shinya Kitaoka 120a6e
  double *u = new double[size];
Shinya Kitaoka 120a6e
  u[0]      = 0.0;
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 1; i < size; i++)
Shinya Kitaoka 120a6e
    u[i] = u[i - 1] +
Shinya Kitaoka 120a6e
           tdistance(*(pointsArrayBegin + i), *(pointsArrayBegin + i - 1));
Shinya Kitaoka 120a6e
  for (i = 1; i < size; i++) {
Shinya Kitaoka 120a6e
    assert(!isAlmostZero(u[size - 1]));
Shinya Kitaoka 120a6e
    u[i] = u[i] / u[size - 1];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return u;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Toshihiro Shimizu 890ddd
    Returns a \a measure of the maximal discrepancy of the points specified
Toshihiro Shimizu 890ddd
    by pointsArray from the corresponding cubic(u[]) points.
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
double computeMaxError3D(const TThickCubic &cubic,
Shinya Kitaoka 120a6e
                         const T3DPointD *pointsArrayBegin, int size, double *u,
Shinya Kitaoka 120a6e
                         int &splitPoint) {
Shinya Kitaoka 120a6e
  double err, maxErr = 0;
Shinya Kitaoka 120a6e
  splitPoint = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int i = 1; i < size - 1; i++) {
Toshihiro Shimizu 890ddd
#ifdef USE_NEW_3D_ERROR_COMPUTE
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Being cubic a THICK cubic, we assume that the supplied points' z
Shinya Kitaoka 120a6e
    // refers to thicknesses as well.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // So, given 2 thick points in the plane, we use the maximal distance
Shinya Kitaoka 120a6e
    // of 'corresponding' outline points. Correspondence refers to the
Shinya Kitaoka 120a6e
    // same relative position from centers. It's easily verifiable that
Shinya Kitaoka 120a6e
    // such maximal distance is found when the relative positions both lie
Shinya Kitaoka 120a6e
    // along the line connecting the two centers.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    const TThickPoint &A(cubic.getThickPoint(u[i]));
Shinya Kitaoka 120a6e
    const T3DPointD &B(pointsArrayBegin[i]);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    err = sqrt(sq(B.x - A.x) + sq(B.y - A.y)) + fabs(B.z - A.thick);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Old version, less intuitive. Similar to the above, except that the
Shinya Kitaoka 120a6e
    // 2d-norm is
Shinya Kitaoka 120a6e
    // roughly multiplied by  norm((TPointD) B-A) / A.thick      ... I wonder
Shinya Kitaoka 120a6e
    // why ....
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    T3DPointD delta =
Shinya Kitaoka 120a6e
        thickPntTo3DPnt(cubic.getThickPoint(u[i])) - *(pointsArrayBegin + i);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    double thick            = cubic.getThickPoint(u[i]).thick;
Shinya Kitaoka 120a6e
    if (thick <= 2.0) thick = 2.0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    err = norm2(TPointD(delta.x, delta.y)) / thick;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (fabs(delta.z) > 2.0) err = err + fabs(delta.z);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (err >= maxErr) {
Shinya Kitaoka 120a6e
      maxErr     = err;
Shinya Kitaoka 120a6e
      splitPoint = i;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return maxErr;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
double NewtonRaphsonRootFind3D(const TThickCubic &cubic, const T3DPointD &p3D,
Shinya Kitaoka 120a6e
                               double u) {
Shinya Kitaoka 120a6e
  TPointD qU  = cubic.getPoint(u);
Shinya Kitaoka 120a6e
  TPointD q1U = cubic.getSpeed(u);
Shinya Kitaoka 120a6e
  TPointD q2U = cubic.getAcceleration(u);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPointD p(p3D.x, p3D.y);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return u - ((qU - p) * q1U) / (norm2(q1U) + (qU - p) * q2U);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Shinya Kitaoka 120a6e
int compareDouble(const void *e1, const void *e2) {
Shinya Kitaoka 120a6e
  return (*(double *)e1 < *(double *)e2)
Shinya Kitaoka 120a6e
             ? -1
Shinya Kitaoka 120a6e
             : (*(double *)e1 == *(double *)e2) ? 0 : 1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//! Ricalcola i valori di u[] sulla base del metodo di Newton Raphson
Toshihiro Shimizu 890ddd
double *reparameterize3D(const TThickCubic &cubic,
Shinya Kitaoka 120a6e
                         const T3DPointD *pointsArrayBegin, int size,
Shinya Kitaoka 120a6e
                         double *u) {
Shinya Kitaoka 120a6e
  double *uPrime = new double[size];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < size; i++) {
Shinya Kitaoka 120a6e
    uPrime[i] = NewtonRaphsonRootFind3D(cubic, *(pointsArrayBegin + i), u[i]);
Shinya Kitaoka 120a6e
    if (!_finite(uPrime[i])) {
Campbell Barton 620578
      delete[] uPrime;
Campbell Barton 620578
      return NULL;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  qsort(uPrime, size, sizeof(double), compareDouble);
Shinya Kitaoka 120a6e
  // std::sort( uPrime, uPrime+size );
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (uPrime[0] < 0.0 || uPrime[size - 1] > 1.0) {
Campbell Barton 620578
    delete[] uPrime;
Campbell Barton 620578
    return NULL;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(uPrime[0] >= 0.0);
Shinya Kitaoka 120a6e
  assert(uPrime[size - 1] <= 1.0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return uPrime;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline double B1(double u) {
Shinya Kitaoka 120a6e
  double tmp = 1.0 - u;
Shinya Kitaoka 120a6e
  return 3 * u * tmp * tmp;
Toshihiro Shimizu 890ddd
}
Shinya Kitaoka 120a6e
inline double B2(double u) { return 3 * u * u * (1 - u); }
Shinya Kitaoka 120a6e
inline double B0plusB1(double u) {
Shinya Kitaoka 120a6e
  double tmp = 1.0 - u;
Shinya Kitaoka 120a6e
  return tmp * tmp * (1.0 + 2.0 * u);
Toshihiro Shimizu 890ddd
}
Shinya Kitaoka 120a6e
inline double B2plusB3(double u) { return u * u * (3.0 - 2.0 * u); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // end of unnamed namespace
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Classe che definisce uno stroke cubico
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
class TCubicStroke {
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  //! Genera un TThickCubic
Shinya Kitaoka 120a6e
  TThickCubic *generateCubic3D(const T3DPointD pointsArrayBegin[],
Shinya Kitaoka 120a6e
                               const double uPrime[], int size,
Shinya Kitaoka 120a6e
                               const T3DPointD &tangentLeft,
Shinya Kitaoka 120a6e
                               const T3DPointD &tangentRight);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //! Genera una cubica in modo ricorsivo
Shinya Kitaoka 120a6e
  void fitCubic3D(const T3DPointD pointsArrayBegin[], int size,
Shinya Kitaoka 120a6e
                  const T3DPointD &tangentLeft, const T3DPointD &tangentRight,
Shinya Kitaoka 120a6e
                  double error);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //! Rettangolo che contiene il TCubicStroke
Shinya Kitaoka 120a6e
  TRectD m_bBox;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  //! Puntatore a vettore di puntatori a TThickCubic
Shinya Kitaoka 120a6e
  vector<TThickCubic *> *m_cubicChunkArray;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //! Costruttore
Shinya Kitaoka 120a6e
  TCubicStroke();
Shinya Kitaoka 120a6e
  //! Costruttore
Shinya Kitaoka 120a6e
  /*!
Shinya Kitaoka 120a6e
            Costruisce un TCubicStroke uguale al TCubicStroke datogli
Shinya Kitaoka 120a6e
            */
Shinya Kitaoka 120a6e
  TCubicStroke(const TCubicStroke &stroke);
Shinya Kitaoka 120a6e
  //! Costruttore
Shinya Kitaoka 120a6e
  /*!
Shinya Kitaoka 120a6e
            Costruisce un TCubicStroke da un array di T3DPointD,
Shinya Kitaoka 120a6e
            in funzione dei due parametri error e doDetectCorners
Shinya Kitaoka 120a6e
            */
Shinya Kitaoka 120a6e
  TCubicStroke(const vector<T3DPointD> &pointsArray3D, double error,
Shinya Kitaoka 120a6e
               bool doDetectCorners = true);
Shinya Kitaoka 120a6e
  /*
Shinya Kitaoka 120a6e
TCubicStroke(       vector<TPointD> &pointsArray,
Shinya Kitaoka 120a6e
double          error,
Shinya Kitaoka 120a6e
const TPointD         &tangentLeft,
Shinya Kitaoka 120a6e
const TPointD         &tangentRight);
Shinya Kitaoka 120a6e
*/
Shinya Kitaoka 120a6e
  //! Distruttore
Shinya Kitaoka 120a6e
  ~TCubicStroke();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// It implements the degree reduction algorithm, returning the times
Toshihiro Shimizu 890ddd
// that the cubic must be splitted (in the half), in order to approximate
Toshihiro Shimizu 890ddd
// it with a sequence of quadratic bezier curves.
Toshihiro Shimizu 890ddd
// This method doesn't take into count the thickness of the control points,
Toshihiro Shimizu 890ddd
// so it just operates on the center line of the fat cubic curve
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*! It splits a cubic bezier curve 'splits' times in the half. Then each
Toshihiro Shimizu 890ddd
      subcurve is converted into quadratic curve, computing the middle control
Toshihiro Shimizu 890ddd
      circle as the weighted averege of the four control circles of the
Toshihiro Shimizu 890ddd
      original cubic subcurve.
Toshihiro Shimizu 890ddd
  */
Shinya Kitaoka 120a6e
void doComputeQuadraticsFromCubic(const TThickCubic &cubic, int splits,
Shinya Kitaoka 120a6e
                                  vector<TThickQuadratic *> &chunkArray) {
Shinya Kitaoka 120a6e
  TThickPoint p0r, p1r, p2r, p3r, p0l, p1l, p2l, p3l;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  p0l = cubic.getThickP0();
Shinya Kitaoka 120a6e
  p1l = cubic.getThickP1();
Shinya Kitaoka 120a6e
  p2l = cubic.getThickP2();
Shinya Kitaoka 120a6e
  p3l = cubic.getThickP3();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  p3l = 0.5 * (p3l + p2l);
Shinya Kitaoka 120a6e
  p2l = 0.5 * (p2l + p1l);
Shinya Kitaoka 120a6e
  p1l = 0.5 * (p1l + p0l);
Shinya Kitaoka 120a6e
  p3l = 0.5 * (p3l + p2l);
Shinya Kitaoka 120a6e
  p2l = 0.5 * (p2l + p1l);
Shinya Kitaoka 120a6e
  p3l = 0.5 * (p3l + p2l);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //  cubic.getControlPoints(p0r, p1r, p2r, p3r);
Shinya Kitaoka 120a6e
  p0r = cubic.getThickP0();
Shinya Kitaoka 120a6e
  p1r = cubic.getThickP1();
Shinya Kitaoka 120a6e
  p2r = cubic.getThickP2();
Shinya Kitaoka 120a6e
  p3r = cubic.getThickP3();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  p0r = 0.5 * (p0r + p1r);
Shinya Kitaoka 120a6e
  p1r = 0.5 * (p1r + p2r);
Shinya Kitaoka 120a6e
  p2r = 0.5 * (p2r + p3r);
Shinya Kitaoka 120a6e
  p0r = 0.5 * (p0r + p1r);
Shinya Kitaoka 120a6e
  p1r = 0.5 * (p1r + p2r);
Shinya Kitaoka 120a6e
  p0r = 0.5 * (p0r + p1r);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (splits > 0) {
Shinya Kitaoka 120a6e
    TThickCubic cubic1(cubic);
Shinya Kitaoka 120a6e
    TThickCubic tmp_1(p0l, p1l, p2l, p3l);
Shinya Kitaoka 120a6e
    std::swap(cubic1, tmp_1);
Shinya Kitaoka 120a6e
    doComputeQuadraticsFromCubic(cubic1, splits - 1, chunkArray);
Shinya Kitaoka 120a6e
    TThickCubic tmp_2(p0r, p1r, p2r, p3r);
Shinya Kitaoka 120a6e
    std::swap(cubic1, tmp_2);
Shinya Kitaoka 120a6e
    doComputeQuadraticsFromCubic(cubic1, splits - 1, chunkArray);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    TThickQuadratic *chunkL =
Shinya Kitaoka 120a6e
        new TThickQuadratic(p0l, 0.25 * (3 * (p1l + p2l) - (p0l + p3l)), p3l);
Shinya Kitaoka 120a6e
    TThickQuadratic *chunkR =
Shinya Kitaoka 120a6e
        new TThickQuadratic(p0r, 0.25 * (3 * (p1r + p2r) - (p0r + p3r)), p3r);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // int size = chunkArray.size();
Shinya Kitaoka 120a6e
    chunkArray.push_back(chunkL);
Shinya Kitaoka 120a6e
    chunkArray.push_back(chunkR);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Shinya Kitaoka 120a6e
          Genera una o piu' quadratiche da una cubica.
Toshihiro Shimizu 890ddd
    Pone una serie di condizioni , se sono verificate crea una unica quadratica,
Shinya Kitaoka 120a6e
                altrimenti richiama doComputeQuadraticsFromCubic
Shinya Kitaoka 120a6e
          */
Shinya Kitaoka 120a6e
void computeQuadraticsFromCubic(const TThickCubic &cubic, double error,
Shinya Kitaoka 120a6e
                                vector<TThickQuadratic *> &chunkArray) {
Shinya Kitaoka 120a6e
  const double T = 0.21132486540518711775; /* 1/2 - sqrt(3)/6 */
Shinya Kitaoka 120a6e
  const double S = (1 - T);
Shinya Kitaoka 120a6e
  int splits;
Shinya Kitaoka 120a6e
  double dist2 = tdistance2(cubic.getP1(), cubic.getP2());
Shinya Kitaoka 120a6e
  if (dist2 < 2) {
Shinya Kitaoka 120a6e
    chunkArray.push_back(new TThickQuadratic(
Shinya Kitaoka 120a6e
        cubic.getThickP0(), 0.5 * (cubic.getThickP1() + cubic.getThickP2()),
Shinya Kitaoka 120a6e
        cubic.getThickP3()));
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPointD dp = ((S * S * S) - (S * S - S * T / 2)) * cubic.getP0() +
Shinya Kitaoka 120a6e
               ((3 * S * S * T) - (S * T * 3 / 2)) * cubic.getP1() +
Shinya Kitaoka 120a6e
               ((3 * S * T * T) - (S * T * 3 / 2)) * cubic.getP2() +
Shinya Kitaoka 120a6e
               ((T * T * T) - (T * T - S * T / 2)) * cubic.getP3();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double dist_sq = norm2(dp);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (splits = 0; dist_sq > error; splits++) dist_sq *= 0.125 * 0.125;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (splits == 0) {
Shinya Kitaoka 120a6e
    TPointD p0 = cubic.getP0();
Shinya Kitaoka 120a6e
    TPointD p1 = cubic.getP1();
Shinya Kitaoka 120a6e
    TPointD p2 = cubic.getP2();
Shinya Kitaoka 120a6e
    TPointD p3 = cubic.getP3();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPointD side01 = p1 - p0;
Shinya Kitaoka 120a6e
    TPointD side32 = p2 - p3;
Shinya Kitaoka 120a6e
    //  se sono verificate TUTTE le condizioni dei seguenti if nidificati,
Shinya Kitaoka 120a6e
    //  allora viene
Shinya Kitaoka 120a6e
    //  generata un'unica quadratica per approssimare cubic. Altrimenti,
Shinya Kitaoka 120a6e
    //  se NON viene verificata ALMENO una delle condizioni dei seguenti if
Shinya Kitaoka 120a6e
    //  nidificati, allora
Shinya Kitaoka 120a6e
    //  cubic viene splittata ulteriormente e trattata da
Shinya Kitaoka 120a6e
    //  doComputeQuadraticsFromCubic
Shinya Kitaoka 120a6e
    double det =
Shinya Kitaoka 120a6e
        -side01.x * side32.y + side01.y * side32.x;  //  -cross(side01, side32)
Shinya Kitaoka 120a6e
    if (!isAlmostZero(det))  // side01 incidente side32 (verra' calcolata
Shinya Kitaoka 120a6e
                             // l'intersezione...)
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      TPointD side03 = p3 - p0;
Shinya Kitaoka 120a6e
      double det01   = -side03.x * side32.y + side03.y * side32.x;
Shinya Kitaoka 120a6e
      double det32   = side01.x * side03.y - side01.y * side03.x;
Shinya Kitaoka 120a6e
      double t01     = det01 / det;
Shinya Kitaoka 120a6e
      double t32     = det32 / det;
Toshihiro Shimizu 890ddd
// unused variable
Toshihiro Shimizu 890ddd
#if 0 
Toshihiro Shimizu 890ddd
        TPointD p01 = p0 + t01*(p1 - p0); // debug
Toshihiro Shimizu 890ddd
        TPointD p32 = p3 + t32*(p2 - p3); // debug
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
      // TPointD intersection = p0 + t01*(p1 - p0) = p3 + t32*(p2 - p3)
Shinya Kitaoka 120a6e
      // assert (areAlmostEqual(p0 + t01*(p1 - p0), p3 + t32*(p2 - p3)));
Shinya Kitaoka 120a6e
      if (t01 >= 1 && t32 >= 1) {  //  poligonale p0_p1_p2_p3 NON e' a "zig-zag"
Shinya Kitaoka 120a6e
        double norm2_side0p = norm2(t01 * side01);
Shinya Kitaoka 120a6e
        double norm2_side3p = norm2(t32 * side32);
Shinya Kitaoka 120a6e
        if (!isAlmostZero(norm2_side0p, 1e-20) &&
Shinya Kitaoka 120a6e
            !isAlmostZero(norm2_side3p,
Shinya Kitaoka 120a6e
                          1e-20)) {  //  la condizione puo' essere violata anche
Shinya Kitaoka 120a6e
                                     //  nel caso !isAlmostZero(det) == true
Shinya Kitaoka 120a6e
          double norm2_side03 = norm2(side03);
Shinya Kitaoka 120a6e
          double tmp          = norm2_side0p + norm2_side3p - norm2_side03;
Shinya Kitaoka 120a6e
          // double cs = tmp/(2*sqrt(norm2_side0p)*sqrt(norm2_side3p));  //
Shinya Kitaoka 120a6e
          // debug
Shinya Kitaoka 120a6e
          double cs_sign =
Shinya Kitaoka 120a6e
              tmp >= 0 ? 1 : -1;  //  cs2 "perde" il segno (cs2 = cs*cs)
Shinya Kitaoka 120a6e
          //  th coseno: gli assert del tipo acos(sqrt(cs2)) sono commentati
Shinya Kitaoka 120a6e
          //  perche' puo' essere cs2 > 1 per errori
Shinya Kitaoka 120a6e
          //  di approssimazione: tuttavia la cosa non costituisce problema
Shinya Kitaoka 120a6e
          //  (acos non viene mai eseguta...)
Shinya Kitaoka 120a6e
          double cs2 = sq(tmp) / (4 * norm2_side0p * norm2_side3p);
Shinya Kitaoka 120a6e
          // assert (0 <= cs2 && cs2 <= 1 + TConsts::epsilon);
Shinya Kitaoka 120a6e
          assert(areAlmostEqual(
Shinya Kitaoka 120a6e
              tsign(cs_sign) * sqrt(cs2),
Shinya Kitaoka 120a6e
              tmp / (2 * sqrt(norm2_side0p) * sqrt(norm2_side3p))));
Shinya Kitaoka 120a6e
          if (cs_sign < 0 || cs2 < 0.969846)  //  cos(10°)^2 = 0.969846
Shinya Kitaoka 120a6e
          {  //  limita distanza di intersection: elimina quadratiche "cappio"
Shinya Kitaoka 120a6e
             //  (con p1 "lontano")
Shinya Kitaoka 120a6e
            // assert (acos(tsign(cs_sign)*sqrt(cs2)) > 10*M_PI_180);
Shinya Kitaoka 120a6e
            assert(tsign(cs_sign) * sqrt(cs2) < cos(10 * M_PI_180));
Shinya Kitaoka 120a6e
            TPointD intersection =
Shinya Kitaoka 120a6e
                p0 + t01 * (p1 - p0);  //  = p2 + t32*(p2 - p3)
Shinya Kitaoka 120a6e
            TThickPoint p(
Shinya Kitaoka 120a6e
                intersection.x, intersection.y,
Shinya Kitaoka 120a6e
                0.5 * (cubic.getThickP1().thick +
Shinya Kitaoka 120a6e
                       cubic.getThickP2()
Shinya Kitaoka 120a6e
                           .thick));  //  compatibilita' precedente funzione
Shinya Kitaoka 120a6e
            chunkArray.push_back(
Shinya Kitaoka 120a6e
                new TThickQuadratic(cubic.getThickP0(), p, cubic.getThickP3()));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Shinya Kitaoka 120a6e
            TThickQuadratic *lastTq = chunkArray.back();
Shinya Kitaoka 120a6e
            TThickPoint pDeb        = lastTq->getThickP0();
Shinya Kitaoka 120a6e
            assert(_finite(pDeb.x));
Shinya Kitaoka 120a6e
            assert(_finite(pDeb.y));
Shinya Kitaoka 120a6e
            assert(_finite(pDeb.thick));
Shinya Kitaoka 120a6e
            pDeb = lastTq->getThickP1();
Shinya Kitaoka 120a6e
            assert(_finite(pDeb.x));
Shinya Kitaoka 120a6e
            assert(_finite(pDeb.y));
Shinya Kitaoka 120a6e
            assert(_finite(pDeb.thick));
Shinya Kitaoka 120a6e
            pDeb = lastTq->getThickP2();
Shinya Kitaoka 120a6e
            assert(_finite(pDeb.x));
Shinya Kitaoka 120a6e
            assert(_finite(pDeb.y));
Shinya Kitaoka 120a6e
            assert(_finite(pDeb.thick));
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
            numSaved++;  //  variabile debug: compatibilita' precedente funzione
Shinya Kitaoka 120a6e
            return;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      TPointD side03 = p3 - p0;
Shinya Kitaoka 120a6e
      double det01   = -side03.x * side32.y + side03.y * side32.x;
Shinya Kitaoka 120a6e
      if (isAlmostZero(det01)) {
Shinya Kitaoka 120a6e
        // e' una retta!, crea unica quadratica con p in mezzo a p1 e p2
Shinya Kitaoka 120a6e
        chunkArray.push_back(new TThickQuadratic(
Shinya Kitaoka 120a6e
            cubic.getThickP0(), (cubic.getThickP1() + cubic.getThickP2()) * 0.5,
Shinya Kitaoka 120a6e
            cubic.getThickP3()));
Shinya Kitaoka 120a6e
        numSaved++;  //  variabile debug: compatibilita' precedente funzione
Shinya Kitaoka 120a6e
        return;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    // else: se arriva qui, almeno una delle condizioni negli if nidificati
Shinya Kitaoka 120a6e
    // precedenti e' falsa
Shinya Kitaoka 120a6e
    splits++;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  doComputeQuadraticsFromCubic(cubic, splits - 1, chunkArray);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//  TStroke *computeQuadStroke(const TCubicStroke& cubic, double error)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//! Ricava uno stroke quadratico da uno stroke cubico
Shinya Kitaoka 120a6e
TStroke *computeQuadStroke(const TCubicStroke &cubic) {
Shinya Kitaoka 120a6e
  vector<TThickQuadratic *> chunkArray;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (UINT i = 0; i < cubic.m_cubicChunkArray->size(); i++) {
Shinya Kitaoka 120a6e
    TThickCubic tmp(*(*cubic.m_cubicChunkArray)[i]);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      TThickPoint p = tmp.getThickP0();
Shinya Kitaoka 120a6e
      assert(_finite(p.x));
Shinya Kitaoka 120a6e
      assert(_finite(p.y));
Shinya Kitaoka 120a6e
      assert(_finite(p.thick));
Shinya Kitaoka 120a6e
      p = tmp.getThickP1();
Shinya Kitaoka 120a6e
      assert(_finite(p.x));
Shinya Kitaoka 120a6e
      assert(_finite(p.y));
Shinya Kitaoka 120a6e
      assert(_finite(p.thick));
Shinya Kitaoka 120a6e
      p = tmp.getThickP2();
Shinya Kitaoka 120a6e
      assert(_finite(p.x));
Shinya Kitaoka 120a6e
      assert(_finite(p.y));
Shinya Kitaoka 120a6e
      assert(_finite(p.thick));
Shinya Kitaoka 120a6e
      p = tmp.getThickP3();
Shinya Kitaoka 120a6e
      assert(_finite(p.x));
Shinya Kitaoka 120a6e
      assert(_finite(p.y));
Shinya Kitaoka 120a6e
      assert(_finite(p.thick));
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // this code use a Chebychev version of degree reduction
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // This code is for old algorithm only:
Shinya Kitaoka 120a6e
    computeQuadraticsFromCubic(tmp, 2.0 /*0.5*/, chunkArray);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TStroke *outStroke = TStroke::create(chunkArray);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  clearPointerContainer(chunkArray);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return outStroke;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// helper function (defined in tstroke.h)
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void computeQuadraticsFromCubic(const TThickPoint &p0, const TThickPoint &p1,
Shinya Kitaoka 120a6e
                                const TThickPoint &p2, const TThickPoint &p3,
Shinya Kitaoka 120a6e
                                double error,
Shinya Kitaoka 120a6e
                                vector<TThickQuadratic *> &chunkArray) {
Shinya Kitaoka 120a6e
  computeQuadraticsFromCubic(TThickCubic(p0, p1, p2, p3), error, chunkArray);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TCubicStroke::TCubicStroke() : m_bBox() {
Shinya Kitaoka 120a6e
  m_cubicChunkArray = new TThickCubicArray();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TCubicStroke::TCubicStroke(const TCubicStroke &stroke)
Shinya Kitaoka 120a6e
    : m_bBox(stroke.m_bBox), m_cubicChunkArray(stroke.m_cubicChunkArray) {
Shinya Kitaoka 120a6e
  m_cubicChunkArray = new TThickCubicArray(*stroke.m_cubicChunkArray);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TCubicStroke::~TCubicStroke() {
Shinya Kitaoka 120a6e
  if (m_cubicChunkArray) {
Shinya Kitaoka 120a6e
    while (!m_cubicChunkArray->empty()) {
Shinya Kitaoka 120a6e
      delete m_cubicChunkArray->back();
Shinya Kitaoka 120a6e
      m_cubicChunkArray->pop_back();
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    delete m_cubicChunkArray;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TCubicStroke::TCubicStroke(const vector<T3DPointD> &pointsArray3D, double error,
Shinya Kitaoka 120a6e
                           bool doDetectCorners) {
Shinya Kitaoka 120a6e
  vector<int> corners;
Shinya Kitaoka 120a6e
  corners.push_back(0);
Shinya Kitaoka 120a6e
  if (doDetectCorners) detectCorners(pointsArray3D, 3, 3, 15, 100, corners);
Shinya Kitaoka 120a6e
  corners.push_back(pointsArray3D.size() - 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef USE_NEW_3D_ERROR_COMPUTE
Shinya Kitaoka 120a6e
  error *= error;
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_cubicChunkArray = new vector<TThickCubic *>();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 1; i < (int)corners.size(); i++) {
Shinya Kitaoka 120a6e
    int size       = corners[i] - corners[i - 1] + 1;
Shinya Kitaoka 120a6e
    int firstPoint = corners[i - 1];
Shinya Kitaoka 120a6e
    T3DPointD tanLeft, tanRigth;
Shinya Kitaoka 120a6e
    assert(size > 0);
Shinya Kitaoka 120a6e
    if (size > 1)  //  capita che corners[i] = corners[i - 1] ("clic" senza drag
Shinya Kitaoka 120a6e
                   //  oppure bug (noto!!!) del cornerDetector)
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      tanLeft  = -pointsArray3D[firstPoint + 1] + pointsArray3D[firstPoint];
Shinya Kitaoka 120a6e
      tanRigth = pointsArray3D[firstPoint + size - 2] -
Shinya Kitaoka 120a6e
                 pointsArray3D[firstPoint + size - 1];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (norm2(tanLeft) > 0) tanLeft = normalize(tanLeft);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (norm2(tanRigth) > 0) tanRigth = normalize(tanRigth);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      fitCubic3D(&pointsArray3D[firstPoint], size, tanLeft, tanRigth, error);
Shinya Kitaoka 120a6e
    } else if (pointsArray3D.size() == 1) {
Shinya Kitaoka 120a6e
      //  caso in cui i non calcola nessun corner a meno di quello iniziale
Shinya Kitaoka 120a6e
      //  e finale coincidenti: 1 solo punto campionato ("clic" senza drag)
Shinya Kitaoka 120a6e
      assert(size == 1);
Shinya Kitaoka 120a6e
      assert(corners.size() == 2);
Shinya Kitaoka 120a6e
      assert(corners[0] == 0);
Shinya Kitaoka 120a6e
      assert(corners[1] == 0);
Shinya Kitaoka 120a6e
      m_cubicChunkArray->push_back(
Shinya Kitaoka 120a6e
          new TThickCubic(pointsArray3D[0], pointsArray3D[0], pointsArray3D[0],
Shinya Kitaoka 120a6e
                          pointsArray3D[0]));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//-----------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void TCubicStroke::fitCubic3D(const T3DPointD pointsArrayBegin[], int size,
Shinya Kitaoka 120a6e
                              const T3DPointD &tangentLeft,
Shinya Kitaoka 120a6e
                              const T3DPointD &tangentRight, double error) {
Shinya Kitaoka 120a6e
  int maxIterations = 4;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (size == 2) {
Shinya Kitaoka 120a6e
    double dist = tdistance(*pointsArrayBegin, *(pointsArrayBegin + 1)) / 3.0;
Shinya Kitaoka 120a6e
    TThickCubic *strokeCubicChunk = new TThickCubic(
Shinya Kitaoka 120a6e
        *pointsArrayBegin, *pointsArrayBegin - dist * tangentLeft,
Shinya Kitaoka 120a6e
        *(pointsArrayBegin + 1) + dist * tangentRight, *(pointsArrayBegin + 1));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_cubicChunkArray->push_back(strokeCubicChunk);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double *u = chordLengthParameterize3D(pointsArrayBegin, size);
Shinya Kitaoka 120a6e
  TThickCubic *cubic =
Shinya Kitaoka 120a6e
      generateCubic3D(pointsArrayBegin, u, size, tangentLeft, tangentRight);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int splitPoint;
Shinya Kitaoka 120a6e
  double maxError =
Shinya Kitaoka 120a6e
      computeMaxError3D(*cubic, pointsArrayBegin, size, u, splitPoint);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (maxError < error) {
Shinya Kitaoka 120a6e
    delete[] u;
Shinya Kitaoka 120a6e
    m_cubicChunkArray->push_back(cubic);
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // if (maxError<error)
Shinya Kitaoka 120a6e
  {
Campbell Barton c39a8a
    double *uPrime = NULL;
Shinya Kitaoka 120a6e
    for (int i = 0; i < maxIterations; i++) {
Shinya Kitaoka 120a6e
      // delete uPrime;
Shinya Kitaoka 120a6e
      uPrime = reparameterize3D(*cubic, pointsArrayBegin, size, u);
Shinya Kitaoka 120a6e
      if (!uPrime) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      delete cubic;
Shinya Kitaoka 120a6e
      cubic = generateCubic3D(pointsArrayBegin, uPrime, size, tangentLeft,
Shinya Kitaoka 120a6e
                              tangentRight);
Shinya Kitaoka 120a6e
      maxError =
Shinya Kitaoka 120a6e
          computeMaxError3D(*cubic, pointsArrayBegin, size, uPrime, splitPoint);
Shinya Kitaoka 120a6e
      if (maxError < error) {
Campbell Barton c39a8a
        delete[] uPrime;
Shinya Kitaoka 120a6e
        delete[] u;
Shinya Kitaoka 120a6e
        m_cubicChunkArray->push_back(cubic);
Shinya Kitaoka 120a6e
        return;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      delete[] u;
Shinya Kitaoka 120a6e
      u = uPrime;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  delete[] u;
Shinya Kitaoka 120a6e
  delete cubic;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  T3DPointD centralTangent;
Shinya Kitaoka 120a6e
  if (*(pointsArrayBegin + splitPoint - 1) ==
Shinya Kitaoka 120a6e
      *(pointsArrayBegin + splitPoint + 1))
Shinya Kitaoka 120a6e
    centralTangent = normalize(*(pointsArrayBegin + splitPoint) -
Shinya Kitaoka 120a6e
                               *(pointsArrayBegin + splitPoint + 1));
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    centralTangent = normalize(*(pointsArrayBegin + splitPoint - 1) -
Shinya Kitaoka 120a6e
                               *(pointsArrayBegin + splitPoint + 1));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  fitCubic3D(pointsArrayBegin, splitPoint + 1, tangentLeft, centralTangent,
Shinya Kitaoka 120a6e
             error);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  fitCubic3D(pointsArrayBegin + splitPoint, size - splitPoint, centralTangent,
Shinya Kitaoka 120a6e
             tangentRight, error);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TThickCubic *TCubicStroke::generateCubic3D(const T3DPointD pointsArrayBegin[],
Shinya Kitaoka 120a6e
                                           const double uPrime[], int size,
Shinya Kitaoka 120a6e
                                           const T3DPointD &tangentLeft,
Shinya Kitaoka 120a6e
                                           const T3DPointD &tangentRight) {
Shinya Kitaoka 120a6e
  double X[2], C[2][2];
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  T3DPointD p0 = *pointsArrayBegin;
Shinya Kitaoka 120a6e
  T3DPointD p3 = *(pointsArrayBegin + size - 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  C[0][0] = C[0][1] = X[0] = 0;
Shinya Kitaoka 120a6e
  C[1][0] = C[1][1] = X[1] = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < size; i++) {
Shinya Kitaoka 120a6e
    const T3DPointD A[2] = {
Shinya Kitaoka 120a6e
        tangentLeft * B1(uPrime[i]), tangentRight * B2(uPrime[i]),
Shinya Kitaoka 120a6e
    };
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    C[0][0] += A[0] * A[0];
Shinya Kitaoka 120a6e
    C[0][1] += A[0] * A[1];
Shinya Kitaoka 120a6e
    C[1][1] += A[1] * A[1];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    C[1][0] = C[0][1];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    T3DPointD tmp = *(pointsArrayBegin + i) - (B0plusB1(uPrime[i]) * p0) +
Shinya Kitaoka 120a6e
                    B2plusB3(uPrime[i]) * p3;
Shinya Kitaoka 120a6e
    X[0] += A[0] * tmp;
Shinya Kitaoka 120a6e
    X[1] += A[1] * tmp;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double detC0C1 = C[0][0] * C[1][1] - C[0][1] * C[1][0];
Shinya Kitaoka 120a6e
  double detC0X  = X[1] * C[0][0] - X[0] * C[0][1];
Shinya Kitaoka 120a6e
  double detXC1  = X[0] * C[1][1] - X[1] * C[0][1];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (isAlmostZero(detC0C1)) detC0C1 = C[0][0] * C[1][1] * 10e-12;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double alphaL = detXC1 / detC0C1;
Shinya Kitaoka 120a6e
  double alphaR = detC0X / detC0C1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /////////////////////////////////////////////////////////////////////////////////////////////////
Shinya Kitaoka 120a6e
  //
Shinya Kitaoka 120a6e
  //  il problema e' che i valori stupidi per alpha non adrebbere messi solo
Shinya Kitaoka 120a6e
  //  quando ci si accorge
Shinya Kitaoka 120a6e
  //  che il segno e' sbagliato, ma anche se i valori sono troppo alti. Ma come
Shinya Kitaoka 120a6e
  //  fare a valutarlo?
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //  Intanto bisognerebbe accertarsi che 'sti valori alcune volte sono cosi'
Shinya Kitaoka 120a6e
  //  assurdi solo per problemi
Shinya Kitaoka 120a6e
  //  di approssimazione e non per bachi nel codice
Shinya Kitaoka 120a6e
  //
Shinya Kitaoka 120a6e
  /////////////////////////////////////////////////////////////////////////////////////////////////
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double xmin     = (numeric_limits<double>::max)();
Shinya Kitaoka 120a6e
  double ymin     = (numeric_limits<double>::max)();
Shinya Kitaoka 120a6e
  double xmax     = -(numeric_limits<double>::max)();
Shinya Kitaoka 120a6e
  double ymax     = -(numeric_limits<double>::max)();
Shinya Kitaoka 120a6e
  double thickmin = (numeric_limits<double>::max)();
Shinya Kitaoka 120a6e
  double thickmax = -(numeric_limits<double>::max)();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < size; i++) {
Shinya Kitaoka 120a6e
    if (pointsArrayBegin[i].x < xmin) xmin         = pointsArrayBegin[i].x;
Shinya Kitaoka 120a6e
    if (pointsArrayBegin[i].x > xmax) xmax         = pointsArrayBegin[i].x;
Shinya Kitaoka 120a6e
    if (pointsArrayBegin[i].y < ymin) ymin         = pointsArrayBegin[i].y;
Shinya Kitaoka 120a6e
    if (pointsArrayBegin[i].y > ymax) ymax         = pointsArrayBegin[i].y;
Shinya Kitaoka 120a6e
    if (pointsArrayBegin[i].z < thickmin) thickmin = pointsArrayBegin[i].z;
Shinya Kitaoka 120a6e
    if (pointsArrayBegin[i].z > thickmax) thickmax = pointsArrayBegin[i].z;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double lx = xmax - xmin;
Shinya Kitaoka 120a6e
  assert(lx >= 0);
Shinya Kitaoka 120a6e
  double ly = ymax - ymin;
Shinya Kitaoka 120a6e
  assert(ly >= 0);
Shinya Kitaoka 120a6e
  double lt = thickmax - thickmin;
Shinya Kitaoka 120a6e
  assert(lt >= 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  xmin -= lx;
Shinya Kitaoka 120a6e
  xmax += lx;
Shinya Kitaoka 120a6e
  ymin -= ly;
Shinya Kitaoka 120a6e
  ymax += ly;
Shinya Kitaoka 120a6e
  thickmin -= lt;
Shinya Kitaoka 120a6e
  thickmax += lt;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TRectD bbox(xmin, ymin, xmax, ymax);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (alphaL < 0.0 || alphaR < 0.0)
Shinya Kitaoka 120a6e
    alphaL = alphaR = sqrt(tdistance2(p0, p3)) / 3.0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  T3DPointD p1 = p0 - tangentLeft * alphaL;
Shinya Kitaoka 120a6e
  T3DPointD p2 = p3 + tangentRight * alphaR;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!bbox.contains(TPointD(p1.x, p1.y)) ||
Shinya Kitaoka 120a6e
      !bbox.contains(TPointD(p2.x, p2.y))) {
Shinya Kitaoka 120a6e
    alphaL = alphaR = sqrt(tdistance2(p0, p3)) / 3.0;
Shinya Kitaoka 120a6e
    p1              = p0 - tangentLeft * alphaL;
Shinya Kitaoka 120a6e
    p2              = p3 + tangentRight * alphaR;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (p1.z < thickmin)
Shinya Kitaoka 120a6e
    p1.z = thickmin;
Shinya Kitaoka 120a6e
  else if (p1.z > thickmax)
Shinya Kitaoka 120a6e
    p1.z = thickmax;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (p2.z < thickmin)
Shinya Kitaoka 120a6e
    p2.z = thickmin;
Shinya Kitaoka 120a6e
  else if (p2.z > thickmax)
Shinya Kitaoka 120a6e
    p2.z = thickmax;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThickCubic *thickCubic = new TThickCubic(
Shinya Kitaoka 120a6e
      TThickPoint(p0.x, p0.y, p0.z), TThickPoint(p1.x, p1.y, p1.z),
Shinya Kitaoka 120a6e
      TThickPoint(p2.x, p2.y, p2.z), TThickPoint(p3.x, p3.y, p3.z));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return thickCubic;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//! Restituisce uno stroke da un vettore di TThickPoint
Toshihiro Shimizu 890ddd
/*!
Shinya Kitaoka 120a6e
  Trasforma un vettore di TThickPoint in un vettore di T3DPointD che usa per
Shinya Kitaoka 120a6e
  trovare un
Shinya Kitaoka 120a6e
        TCubicStroke, cioe' uno stroke cubico. Da questo trova lo stroke
Shinya Kitaoka 120a6e
  quadratico.
Toshihiro Shimizu 890ddd
  */
Shinya Kitaoka 120a6e
TStroke *TStroke::interpolate(const vector<TThickPoint> &points, double error,
Shinya Kitaoka 120a6e
                              bool findCorners) {
Shinya Kitaoka 120a6e
  vector<T3DPointD> pointsArray3D;
Shinya Kitaoka 120a6e
  convert(points, pointsArray3D);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TCubicStroke cubicStroke(pointsArray3D, error, findCorners);
Shinya Kitaoka 120a6e
  numSaved = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //  TStroke *stroke = computeQuadStroke(cubicStroke,error);
Shinya Kitaoka 120a6e
  TStroke *stroke = computeQuadStroke(cubicStroke);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  UINT cpIndex = 0;
Shinya Kitaoka 120a6e
  TThickPoint p;
Shinya Kitaoka 120a6e
  for (; cpIndex != (UINT)stroke->getControlPointCount(); cpIndex++) {
Shinya Kitaoka 120a6e
    p = stroke->getControlPoint(cpIndex);
Shinya Kitaoka 120a6e
    assert(_finite(p.x));
Shinya Kitaoka 120a6e
    assert(_finite(p.y));
Shinya Kitaoka 120a6e
    assert(_finite(p.thick));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  removeNullQuadratic(stroke);
Shinya Kitaoka 120a6e
  stroke->invalidate();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return stroke;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//! Restituisce uno stroke da un vettore di TThickQuadratic
Toshihiro Shimizu 890ddd
/*!
Toshihiro Shimizu 890ddd
  Estrae dalle curve i punti di controllo e crea con questi un nuovo stroke
Toshihiro Shimizu 890ddd
  */
Shinya Kitaoka 120a6e
TStroke *TStroke::create(const vector<TThickQuadratic *> &curves) {
Shinya Kitaoka 120a6e
  if (curves.empty()) return 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // make a vector of control points
Shinya Kitaoka 120a6e
  vector<TThickPoint> ctrlPnts;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  extractStrokeControlPoints(curves, ctrlPnts);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TStroke *stroke = new TStroke(ctrlPnts);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  stroke->invalidate();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return stroke;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TStrokeProp::TStrokeProp(const TStroke *stroke)
Shinya Kitaoka 120a6e
    : m_stroke(stroke), m_strokeChanged(true), m_mutex() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TStroke::OutlineOptions::OutlineOptions()
Shinya Kitaoka 120a6e
    : m_capStyle(ROUND_CAP)
Shinya Kitaoka 120a6e
    , m_joinStyle(ROUND_JOIN)
Shinya Kitaoka 120a6e
    , m_miterLower(0.0)
Shinya Kitaoka 120a6e
    , m_miterUpper(4.0) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke::OutlineOptions::OutlineOptions(UCHAR capStyle, UCHAR joinStyle,
Shinya Kitaoka 120a6e
                                        double lower, double upper)
Shinya Kitaoka 120a6e
    : m_capStyle(capStyle)
Shinya Kitaoka 120a6e
    , m_joinStyle(joinStyle)
Shinya Kitaoka 120a6e
    , m_miterLower(lower)
Shinya Kitaoka 120a6e
    , m_miterUpper(upper) {}