Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
#define _STLP_DEBUG 1
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
#include <tcurves.h></tcurves.h>
Toshihiro Shimizu 890ddd
#include <tstroke.h></tstroke.h>
Toshihiro Shimizu 890ddd
#include <tmathutil.h></tmathutil.h>
Toshihiro Shimizu 890ddd
#include <tcurveutil.h></tcurveutil.h>
Toshihiro Shimizu 890ddd
#include <tgl.h></tgl.h>
Toshihiro Shimizu 890ddd
#include <set></set>
Toshihiro Shimizu 890ddd
#include <iterator></iterator>
Toshihiro Shimizu 890ddd
// please do not move, it is necessary to be the last
Toshihiro Shimizu 890ddd
// to work properely with DVAPI macro
Toshihiro Shimizu 890ddd
#include "ext/ExtUtil.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// just to override assert
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Toshihiro Shimizu 890ddd
#define EXT_NORMALIZE(a) norm2(a) != 0.0 ? normalize(a) : a
Toshihiro Shimizu 890ddd
#define DEBUG_EXPORT DVAPI
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
#define EXT_NORMALIZE(a) normalize(a)
Toshihiro Shimizu 890ddd
#define DEBUG_EXPORT static
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline bool isWGood(double first, double w, double second, const TStroke *s) {
Shinya Kitaoka 120a6e
  if (!ToonzExt::isValid(first) || !ToonzExt::isValid(second) ||
Shinya Kitaoka 120a6e
      !ToonzExt::isValid(w))
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (s) {
Rozhuk Ivan 823a31
    if (s->isSelfLoop()) {
Shinya Kitaoka 120a6e
      if (first > second) {
Shinya Kitaoka 120a6e
        if ((first < w && w <= 1.0) || (0.0 <= w && w < second)) return true;
Shinya Kitaoka 120a6e
      } else if (first == second) {
Shinya Kitaoka 120a6e
        if (areAlmostEqual(w, first)) return true;
Shinya Kitaoka 120a6e
      }
Rozhuk Ivan 823a31
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (first < w && w < second) return true;
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline int normalizeAngle(int angle) {
Shinya Kitaoka 120a6e
  if (angle < 0) angle = -angle;
Shinya Kitaoka 120a6e
  return angle %= 181;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int getStrokeId(const TStroke *s, const TVectorImageP &vi) {
Shinya Kitaoka 120a6e
  if (!ToonzExt::isValid(s) || !vi) return -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int count = vi->getStrokeCount();
Shinya Kitaoka 120a6e
  if (!count) return -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (count--) {
Shinya Kitaoka 120a6e
    if (s == vi->getStroke(count)) return count;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return -1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/**
Toshihiro Shimizu 890ddd
   * Verify if a curve is a "almost" point.
Toshihiro Shimizu 890ddd
   */
Toshihiro Shimizu 890ddd
template <class t=""></class>
Shinya Kitaoka 120a6e
bool isImproper(const T *tq) {
Shinya Kitaoka 120a6e
  TPointD v1 = tq->getP0() - tq->getP1(), v2 = tq->getP2() - tq->getP1();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (isAlmostZero(norm2(v1)) && isAlmostZero(norm2(v2))) 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 areParallel(const TPointD &v1, const TPointD &v2) {
Shinya Kitaoka 120a6e
  double res = cross(EXT_NORMALIZE(v1), EXT_NORMALIZE(v2));
Shinya Kitaoka 120a6e
  if (isAlmostZero(res)) return true;
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool areInSameDirection(const TPointD &v1, const TPointD &v2) {
Shinya Kitaoka 120a6e
  if (v1 * v2 >= 0) return true;
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/**
Toshihiro Shimizu 890ddd
   * Verify if a curve is a straight line.
Toshihiro Shimizu 890ddd
   */
Toshihiro Shimizu 890ddd
template <class t=""></class>
Shinya Kitaoka 120a6e
bool curveIsStraight(const T *tq, double &t) {
Shinya Kitaoka 120a6e
  t = -1;
Shinya Kitaoka 120a6e
  assert(tq);
Shinya Kitaoka 120a6e
  if (!tq) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPointD v1 = tq->getP1() - tq->getP0();
Shinya Kitaoka 120a6e
  TPointD v2 = tq->getP2() - tq->getP1();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double res = cross(v1, v2);
Shinya Kitaoka 120a6e
  if (isAlmostZero(res)) {
Shinya Kitaoka 120a6e
    if (v1 * v2 < 0) {
Shinya Kitaoka 120a6e
      t = tq->getT(tq->getP1());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/**
Toshihiro Shimizu 890ddd
   * Verify if junction between two curves, is smooth.
Toshihiro Shimizu 890ddd
   */
Toshihiro Shimizu 890ddd
template <class t=""></class>
Shinya Kitaoka 120a6e
bool corner(const T *q1, const T *q2, double tolerance) {
Shinya Kitaoka 120a6e
  if (!q1 || !q2 || !areAlmostEqual(q1->getP2(), q2->getP0())) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // really near to the extremes
Shinya Kitaoka 120a6e
  TPointD
Shinya Kitaoka 120a6e
      // pnt = q1->getP2(),
Shinya Kitaoka 120a6e
      v1 = q1->getSpeed(1.0),  // q1->getPoint(1.0-TConsts::epsilon) - pnt,
Shinya Kitaoka 120a6e
      v2 = q2->getSpeed(0.0);  // q2->getPoint(TConsts::epsilon) - pnt;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  v1 = EXT_NORMALIZE(v1);
Shinya Kitaoka 120a6e
  v2 = EXT_NORMALIZE(v2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double res = cross(v1, v2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!isAlmostZero(res, tolerance)) return true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int detectStraightIntervals_(const TThickQuadratic *ttq,
Shinya Kitaoka 120a6e
                             ToonzExt::Intervals &intervals, double tolerance) {
Shinya Kitaoka 120a6e
  if (!ttq) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPointD v0 = ttq->getP1() - ttq->getP0(), v1 = ttq->getP2() - ttq->getP1();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double v0_norm2 = norm(v0), v1_norm2 = norm(v1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (v0_norm2 != 0.0) v0 = v0 * (1.0 / v0_norm2);
Shinya Kitaoka 120a6e
  if (v1_norm2 != 0.0) v1 = v1 * (1.0 / v1_norm2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double v0xv1 = v0 * v1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (v0xv1 == 0.0 && v0_norm2 == 0.0 &&
Shinya Kitaoka 120a6e
      v1_norm2 == 0.0)  // null value with all zero
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (isAlmostZero(cross(v0, v1) /*,tolerance*/)) {
Shinya Kitaoka 120a6e
    if (v0xv1 >= 0) {
Shinya Kitaoka 120a6e
      intervals.push_back(ToonzExt::Interval(0.0, 1.0));
Shinya Kitaoka 120a6e
      return 1;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      double t = ttq->getT(ttq->getP1());
Shinya Kitaoka 120a6e
      intervals.push_back(ToonzExt::Interval(0.0, t));
Shinya Kitaoka 120a6e
      intervals.push_back(ToonzExt::Interval(t, 1.0));
Shinya Kitaoka 120a6e
      return 2;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
#if 0
Toshihiro Shimizu 890ddd
    // need to be analysed
Toshihiro Shimizu 890ddd
    else
Toshihiro Shimizu 890ddd
    {
Toshihiro Shimizu 890ddd
      double
Toshihiro Shimizu 890ddd
        pixelSize = 1.0;
Toshihiro Shimizu 890ddd
#ifndef _DEBUG
Toshihiro Shimizu 890ddd
      pixelSize = sqrt(tglGetPixelSize2());
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
      double
Toshihiro Shimizu 890ddd
        step = computeStep(*ttq,
Toshihiro Shimizu 890ddd
        pixelSize);
Toshihiro Shimizu 890ddd
      
Toshihiro Shimizu 890ddd
      //assert( step < 1.0 );
Toshihiro Shimizu 890ddd
      if( step > 1.0 )
Toshihiro Shimizu 890ddd
        return 0;
Toshihiro Shimizu 890ddd
      
Toshihiro Shimizu 890ddd
      double 
Toshihiro Shimizu 890ddd
        t = 0.0;
Toshihiro Shimizu 890ddd
      
Toshihiro Shimizu 890ddd
      TPointD
Toshihiro Shimizu 890ddd
        pnt ,
Toshihiro Shimizu 890ddd
        p0 = ttq->getP0(),
Toshihiro Shimizu 890ddd
        pn;
Toshihiro Shimizu 890ddd
      
Toshihiro Shimizu 890ddd
      ToonzExt::Interval
Toshihiro Shimizu 890ddd
        last_interval(-1,-1),
Toshihiro Shimizu 890ddd
        curr_interval;
Toshihiro Shimizu 890ddd
      
Toshihiro Shimizu 890ddd
      pnt = ttq->getPoint(step);
Toshihiro Shimizu 890ddd
      v0 = pnt - p0;
Toshihiro Shimizu 890ddd
      if( t+step < 1.0)
Toshihiro Shimizu 890ddd
        pn = ttq->getPoint( step+step );
Toshihiro Shimizu 890ddd
      else
Toshihiro Shimizu 890ddd
        pn = ttq->getP2();
Toshihiro Shimizu 890ddd
      v1 = pn - pnt;
Toshihiro Shimizu 890ddd
      
Toshihiro Shimizu 890ddd
      v0 = EXT_NORMALIZE(v0);
Toshihiro Shimizu 890ddd
      v1 = EXT_NORMALIZE(v1);
Toshihiro Shimizu 890ddd
      if( isAlmostZero( cross(v0,v1), tolerance ) )
Toshihiro Shimizu 890ddd
      {
Toshihiro Shimizu 890ddd
        assert( v0*v1 >0);
Toshihiro Shimizu 890ddd
        last_interval.first = ttq->getT(p0);
Toshihiro Shimizu 890ddd
        last_interval.second= ttq->getT(pn);
Toshihiro Shimizu 890ddd
      }
Toshihiro Shimizu 890ddd
      p0 = pn;
Toshihiro Shimizu 890ddd
      
Toshihiro Shimizu 890ddd
      for(t=2.0*step;
Toshihiro Shimizu 890ddd
      t<1.0;
Toshihiro Shimizu 890ddd
      t+=2.0*step)
Toshihiro Shimizu 890ddd
      {
Toshihiro Shimizu 890ddd
        pnt = ttq->getPoint(t);
Toshihiro Shimizu 890ddd
        v0 = pnt - p0;
Toshihiro Shimizu 890ddd
        if( t+step < 1.0)
Toshihiro Shimizu 890ddd
          pn = ttq->getPoint( t+step );
Toshihiro Shimizu 890ddd
        else
Toshihiro Shimizu 890ddd
          pn = ttq->getP2();
Toshihiro Shimizu 890ddd
        v1 = pn - pnt;
Toshihiro Shimizu 890ddd
        
Toshihiro Shimizu 890ddd
        v0 = EXT_NORMALIZE(v0);
Toshihiro Shimizu 890ddd
        v1 = EXT_NORMALIZE(v1);
Toshihiro Shimizu 890ddd
        if( isAlmostZero( cross(v0,v1), tolerance ) )
Toshihiro Shimizu 890ddd
        {
Toshihiro Shimizu 890ddd
          //assert( v0 * v1 > 0 );
Toshihiro Shimizu 890ddd
          curr_interval.first  = ttq->getT(p0);
Toshihiro Shimizu 890ddd
          curr_interval.second = ttq->getT(pn);
Toshihiro Shimizu 890ddd
          
Toshihiro Shimizu 890ddd
          if( curr_interval.first != last_interval.second ||
Toshihiro Shimizu 890ddd
            v0 * v1 < 0)
Toshihiro Shimizu 890ddd
          {
Toshihiro Shimizu 890ddd
            intervals.push_back(last_interval);
Toshihiro Shimizu 890ddd
            last_interval.first =
Toshihiro Shimizu 890ddd
              last_interval.second = curr_interval.second;
Toshihiro Shimizu 890ddd
          }
Toshihiro Shimizu 890ddd
          else
Toshihiro Shimizu 890ddd
          {
Toshihiro Shimizu 890ddd
            last_interval.second = curr_interval.second;
Toshihiro Shimizu 890ddd
          }
Toshihiro Shimizu 890ddd
        }
Toshihiro Shimizu 890ddd
        // for quadratic is not possible
Toshihiro Shimizu 890ddd
        std::swap(p0,pn);
Toshihiro Shimizu 890ddd
      }
Toshihiro Shimizu 890ddd
      
Toshihiro Shimizu 890ddd
      pn=ttq->getP2();
Toshihiro Shimizu 890ddd
      v1 = pn - pnt;
Toshihiro Shimizu 890ddd
      if( isAlmostZero( cross(v0,v1), tolerance ) )
Toshihiro Shimizu 890ddd
      {
Toshihiro Shimizu 890ddd
        if( v0 * v1 > 0 )
Toshihiro Shimizu 890ddd
        {
Toshihiro Shimizu 890ddd
          curr_interval.first  = ttq->getT(p0);
Toshihiro Shimizu 890ddd
          curr_interval.second = ttq->getT(pn);
Toshihiro Shimizu 890ddd
          
Toshihiro Shimizu 890ddd
          if( curr_interval.first == last_interval.second )
Toshihiro Shimizu 890ddd
            last_interval.second = curr_interval.second;
Toshihiro Shimizu 890ddd
          
Toshihiro Shimizu 890ddd
          intervals.push_back(last_interval);
Toshihiro Shimizu 890ddd
        }
Toshihiro Shimizu 890ddd
      }
Toshihiro Shimizu 890ddd
      return intervals.size();
Toshihiro Shimizu 890ddd
    }
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
  int
Toshihiro Shimizu 890ddd
  detectStraightIntervals_(const TThickQuadratic* ttq,
Toshihiro Shimizu 890ddd
                           std::set<double>& values)</double>
Toshihiro Shimizu 890ddd
  {
Toshihiro Shimizu 890ddd
    if(!ttq ||
Toshihiro Shimizu 890ddd
       isImproper( ttq ))
Toshihiro Shimizu 890ddd
      return 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    TPointD
Toshihiro Shimizu 890ddd
      v0 = ttq->getP1() - ttq->getP0(),
Toshihiro Shimizu 890ddd
      v1 = ttq->getP2() - ttq->getP1();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    if( isAlmostZero( cross(v0,v1) ) )
Toshihiro Shimizu 890ddd
    {
Toshihiro Shimizu 890ddd
      values.insert(0.0);
Toshihiro Shimizu 890ddd
      values.insert(1.0);
Toshihiro Shimizu 890ddd
      if(v0 * v1 > 0 )
Toshihiro Shimizu 890ddd
      {
Toshihiro Shimizu 890ddd
        return values.size()-1;
Toshihiro Shimizu 890ddd
      }
Toshihiro Shimizu 890ddd
      else
Toshihiro Shimizu 890ddd
      {
Toshihiro Shimizu 890ddd
        double
Toshihiro Shimizu 890ddd
          t = ttq->getT(ttq->getP1());
Toshihiro Shimizu 890ddd
        values.insert( t );
Toshihiro Shimizu 890ddd
        return values.size()-1;
Toshihiro Shimizu 890ddd
      }
Toshihiro Shimizu 890ddd
    }
Toshihiro Shimizu 890ddd
    else
Toshihiro Shimizu 890ddd
    {
Toshihiro Shimizu 890ddd
      double
Toshihiro Shimizu 890ddd
        pixelSize = 1.0;
Toshihiro Shimizu 890ddd
#ifndef  _DEBUG
Toshihiro Shimizu 890ddd
      pixelSize = sqrt(tglGetPixelSize2());
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
      double
Toshihiro Shimizu 890ddd
        step = computeStep(*ttq,
Toshihiro Shimizu 890ddd
                           pixelSize);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      double
Toshihiro Shimizu 890ddd
        t = 0.0;
Shinya Kitaoka 120a6e
Toshihiro Shimizu 890ddd
      TPointD
Toshihiro Shimizu 890ddd
        pnt ,
Toshihiro Shimizu 890ddd
        p0 = ttq->getP0(),
Toshihiro Shimizu 890ddd
        pn;
Toshihiro Shimizu 890ddd
      for(t=step;
Toshihiro Shimizu 890ddd
          t<1.0;
Toshihiro Shimizu 890ddd
          t+=2.0*step)
Toshihiro Shimizu 890ddd
      {
Toshihiro Shimizu 890ddd
        pnt = ttq->getPoint(t);
Toshihiro Shimizu 890ddd
        v0 = pnt - p0;
Toshihiro Shimizu 890ddd
        if( t+step < 1.0)
Toshihiro Shimizu 890ddd
          pn = ttq->getPoint( t+step );
Toshihiro Shimizu 890ddd
        else
Toshihiro Shimizu 890ddd
          pn = ttq->getP2();
Toshihiro Shimizu 890ddd
        v1 = pn - pnt;
Toshihiro Shimizu 890ddd
        if( isAlmostZero( cross(v0,v1) ) )
Toshihiro Shimizu 890ddd
        {
Toshihiro Shimizu 890ddd
          assert( v0 * v1 > 0 );
Toshihiro Shimizu 890ddd
          values.insert(ttq->getT(p0));
Toshihiro Shimizu 890ddd
          values.insert(ttq->getT(pn));
Toshihiro Shimizu 890ddd
        }
Toshihiro Shimizu 890ddd
        // for quadratic is not possible
Toshihiro Shimizu 890ddd
        std::swap(p0,pn);
Toshihiro Shimizu 890ddd
      }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
      pn=ttq->getP2();
Toshihiro Shimizu 890ddd
      v1 = pn - pnt;
Toshihiro Shimizu 890ddd
      if( isAlmostZero( cross(v0,v1) ) )
Toshihiro Shimizu 890ddd
      {
Toshihiro Shimizu 890ddd
        assert( v0 * v1 > 0 );
Toshihiro Shimizu 890ddd
        values.insert(ttq->getT(p0));
Toshihiro Shimizu 890ddd
        values.insert(ttq->getT(pn));
Toshihiro Shimizu 890ddd
      }
Toshihiro Shimizu 890ddd
    }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
    return values.size()-1;
Toshihiro Shimizu 890ddd
  }
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool mapValueInStroke(const TStroke *stroke, const TThickQuadratic *ttq,
Shinya Kitaoka 120a6e
                      double value, double &out) {
Shinya Kitaoka 120a6e
  assert(ttq);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!ttq || !ToonzExt::isValid(stroke) || !ToonzExt::isValid(value))
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (value == 1.0) {
Shinya Kitaoka 120a6e
    if (ttq->getPoint(1.0) == stroke->getPoint(1.0)) {
Shinya Kitaoka 120a6e
      if (!stroke->isSelfLoop())
Shinya Kitaoka 120a6e
        out = 1.0;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        out = 0.0;
Shinya Kitaoka 120a6e
      return true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  out = stroke->getW(ttq->getPoint(value));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool mapIntervalInStroke(const TStroke *stroke, const TThickQuadratic *ttq,
Shinya Kitaoka 120a6e
                         const ToonzExt::Interval &ttq_interval,
Shinya Kitaoka 120a6e
                         ToonzExt::Interval &stroke_interval) {
Shinya Kitaoka 120a6e
  if (!ttq || !ToonzExt::isValid(stroke)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (ttq_interval.first > ttq_interval.second || 0.0 > ttq_interval.first ||
Shinya Kitaoka 120a6e
      ttq_interval.second > 1.0)
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool check =
Shinya Kitaoka 120a6e
      mapValueInStroke(stroke, ttq, ttq_interval.first, stroke_interval.first);
Shinya Kitaoka 120a6e
  assert(check);
Shinya Kitaoka 120a6e
  if (!check) return false;
Shinya Kitaoka 120a6e
  check = mapValueInStroke(stroke, ttq, ttq_interval.second,
Shinya Kitaoka 120a6e
                           stroke_interval.second);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(check);
Shinya Kitaoka 120a6e
  if (!check) return false;
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool addQuadraticIntervalInStroke(const TStroke *stroke,
Shinya Kitaoka 120a6e
                                  ToonzExt::Intervals &stroke_intervals,
Shinya Kitaoka 120a6e
                                  const TThickQuadratic *ttq,
Shinya Kitaoka 120a6e
                                  ToonzExt::Intervals &ttq_intervals) {
Shinya Kitaoka 120a6e
  if (!ttq || !ToonzExt::isValid(stroke)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const int size = ttq_intervals.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (size == 0) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int i = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < size; ++i) {
Shinya Kitaoka 120a6e
    const ToonzExt::Interval &tmp = ttq_intervals[i];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (tmp.first > tmp.second || 0.0 > tmp.first || tmp.second > 1.0)
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < size; ++i) {
Shinya Kitaoka 120a6e
    const ToonzExt::Interval &ttq_interval = ttq_intervals[i];
Shinya Kitaoka 120a6e
    ToonzExt::Interval stroke_interval;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // start to add interval in stroke
Shinya Kitaoka 120a6e
    if (mapIntervalInStroke(stroke, ttq, ttq_interval, stroke_interval)) {
Shinya Kitaoka 120a6e
      stroke_intervals.push_back(stroke_interval);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool addQuadraticSetInStroke(const TStroke *stroke,
Shinya Kitaoka 120a6e
                             ToonzExt::Intervals &stroke_intervals,
Shinya Kitaoka 120a6e
                             const TThickQuadratic *ttq,
Shinya Kitaoka 120a6e
                             const std::set<double> &ttq_set) {</double>
Shinya Kitaoka 120a6e
  if (!ttq || !ToonzExt::isValid(stroke)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const int size = ttq_set.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (size < 1) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::set<double>::const_iterator cit, cit_end = ttq_set.end();</double>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (cit = ttq_set.begin(); cit != cit_end; ++cit) {
Shinya Kitaoka 120a6e
    if (0.0 > *cit || *cit > 1.0) return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  cit                                       = ttq_set.begin();
Shinya Kitaoka 120a6e
  std::set<double>::const_iterator next_cit = cit;</double>
Shinya Kitaoka 120a6e
  std::advance(next_cit, 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (; next_cit != cit_end; ++next_cit) {
Shinya Kitaoka 120a6e
    ToonzExt::Interval stroke_interval;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    bool check = mapValueInStroke(stroke, ttq, *cit, stroke_interval.first);
Shinya Kitaoka 120a6e
    assert(check);
Shinya Kitaoka 120a6e
    if (!check) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    check = mapValueInStroke(stroke, ttq, *next_cit, stroke_interval.second);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert(check);
Shinya Kitaoka 120a6e
    if (!check) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert(stroke_interval.first <= stroke_interval.second);
Shinya Kitaoka 120a6e
    if (stroke_interval.first > stroke_interval.second) return false;
Shinya Kitaoka 120a6e
    stroke_intervals.push_back(stroke_interval);
Shinya Kitaoka 120a6e
    cit = next_cit;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isThere(double value, const ToonzExt::Intervals &intervals) {
Shinya Kitaoka 120a6e
  ToonzExt::Intervals::const_iterator cit     = intervals.begin(),
Shinya Kitaoka 120a6e
                                      cit_end = intervals.end();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (cit != cit_end) {
Shinya Kitaoka 120a6e
    if (cit->first == value || cit->second == value) return true;
Shinya Kitaoka 120a6e
    ++cit;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isThere(double value, const std::set<double> &mySet) {</double>
Shinya Kitaoka 120a6e
  std::set<double>::const_iterator cit_end = mySet.end();</double>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (cit_end == mySet.find(value)) return false;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool isCorner(const ToonzExt::Intervals &values, double w, double tolerance) {
Shinya Kitaoka 120a6e
  ToonzExt::Interval prev = values[0], curr = prev;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // first point
Shinya Kitaoka 120a6e
  if (areAlmostEqual(prev.first, w, tolerance)) return true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const int size = values.size();
Shinya Kitaoka 120a6e
  for (int i = 1; i < size; ++i) {
Shinya Kitaoka 120a6e
    curr = values[i];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (areAlmostEqual(prev.second, curr.first) &&
Shinya Kitaoka 120a6e
        areAlmostEqual(w, curr.first, tolerance))
Shinya Kitaoka 120a6e
      return true;
Shinya Kitaoka 120a6e
    prev = curr;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // last point
Shinya Kitaoka 120a6e
  if (areAlmostEqual(curr.second, w, tolerance)) return true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
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
DEBUG_EXPORT bool isThereACornerMinusThan(double minCos, double minSin,
Shinya Kitaoka 120a6e
                                          const TThickQuadratic *quad1,
Shinya Kitaoka 120a6e
                                          const TThickQuadratic *quad2) {
Shinya Kitaoka 120a6e
  if (!quad1 || !quad2 || !ToonzExt::isValid(fabs(minCos)) ||
Shinya Kitaoka 120a6e
      !ToonzExt::isValid(fabs(minSin)))
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPointD
Shinya Kitaoka 120a6e
      // speed1,
Shinya Kitaoka 120a6e
      // speed2,
Shinya Kitaoka 120a6e
      tan1,
Shinya Kitaoka 120a6e
      tan2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // speed1 = quad1->getSpeed(1);
Shinya Kitaoka 120a6e
  // speed2 = -quad2->getSpeed(0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  tan1 = quad1->getSpeed(1);
Shinya Kitaoka 120a6e
  tan2 = -quad2->getSpeed(0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (norm2(tan1) == 0.0 || norm2(tan2) == 0.0) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  tan1 = normalize(tan1);
Shinya Kitaoka 120a6e
  tan2 = normalize(tan2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // move cos value to compare just positive values
Shinya Kitaoka 120a6e
  minCos += 1.0;
Shinya Kitaoka 120a6e
  double cosVal = 1.0 + (tan1 * tan2);  //, sinVal = fabs(cross(tan1,tan2));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(minCos >= 0.0);
Shinya Kitaoka 120a6e
  if (cosVal >= minCos) return true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DEBUG_EXPORT double degree2cos(int degree) {
Shinya Kitaoka 120a6e
  int tmp = degree < 0 ? -degree : degree;
Shinya Kitaoka 120a6e
  tmp %= 360;
Shinya Kitaoka 120a6e
  degree = degree < 0 ? 360 - tmp : degree;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (degree == 0) return 1.0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (degree == 180) return -1.0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (degree == 90 || degree == 270) return 0.0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return cos(degree * M_PI_180);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DEBUG_EXPORT double degree2sin(int degree) { return degree2cos(degree - 90); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DVAPI bool ToonzExt::findNearestSpireCorners(
Shinya Kitaoka 120a6e
    const TStroke *stroke, double w, ToonzExt::Interval &out, int cornerSize,
Shinya Kitaoka 120a6e
    const ToonzExt::Intervals *const cl, double tolerance) {
Shinya Kitaoka 120a6e
  if (!ToonzExt::isValid(stroke) || !ToonzExt::isValid(w)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const ToonzExt::Intervals *values = cl;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ToonzExt::Intervals tmpValues;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!cl) {
Shinya Kitaoka 120a6e
    cornerSize = normalizeAngle(cornerSize);
Shinya Kitaoka 120a6e
    if (!ToonzExt::detectSpireIntervals(stroke, tmpValues, cornerSize))
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
    values = &tmpValues;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!values || values->empty()) {
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return findNearestCorners(stroke, w, out, *values, tolerance);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DVAPI bool ToonzExt::isASpireCorner(const TStroke *s, double w, int cornerSize,
Shinya Kitaoka 120a6e
                                    const ToonzExt::Intervals *const cl,
Shinya Kitaoka 120a6e
                                    double tolerance) {
Shinya Kitaoka 120a6e
  if (!ToonzExt::isValid(s) || !ToonzExt::isValid(w)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ToonzExt::Intervals tmpValues;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const ToonzExt::Intervals *values = cl;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!cl) {
Shinya Kitaoka 120a6e
    if (!ToonzExt::detectSpireIntervals(s, tmpValues, cornerSize)) return false;
Shinya Kitaoka 120a6e
    values = &tmpValues;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!values || values->empty()) {
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return isCorner(*values, w, tolerance);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DVAPI bool ToonzExt::detectStraightIntervals(const TStroke *stroke,
Shinya Kitaoka 120a6e
                                             ToonzExt::Intervals &intervals,
Shinya Kitaoka 120a6e
                                             double tolerance) {
Shinya Kitaoka 120a6e
  if (!ToonzExt::isValid(stroke)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(tolerance > 0.0 && tolerance < 1.0 &&
Shinya Kitaoka 120a6e
         "Strange tolerance are you sure???");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  intervals.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // first step:
Shinya Kitaoka 120a6e
  //  store information about chunk and straight interval
Shinya Kitaoka 120a6e
  typedef std::pair<const *,="" toonzext::intervals="" tthickquadratic=""></const>
Shinya Kitaoka 120a6e
      ChunkStraights;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::map<int, chunkstraights=""> arrayOfChunkIntervals;</int,>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int chunkCount = stroke->getChunkCount();
Shinya Kitaoka 120a6e
  int counter    = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < chunkCount; ++i) {
Shinya Kitaoka 120a6e
    ToonzExt::Intervals values;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    const TThickQuadratic *chunk = stroke->getChunk(i);
Shinya Kitaoka 120a6e
    if (chunk->getLength() == 0.0) continue;
Shinya Kitaoka 120a6e
    int howMany = detectStraightIntervals_(chunk, values, tolerance);
Shinya Kitaoka 120a6e
    if (howMany > 0) {
Shinya Kitaoka 120a6e
      arrayOfChunkIntervals[counter] = ChunkStraights(chunk, values);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    ++counter;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // second step:
Shinya Kitaoka 120a6e
  //  add intervals vs stroke
Shinya Kitaoka 120a6e
  std::map<int, chunkstraights="">::iterator it = arrayOfChunkIntervals.begin(),</int,>
Shinya Kitaoka 120a6e
                                          end = arrayOfChunkIntervals.end(),
Shinya Kitaoka 120a6e
                                          aux;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ToonzExt::Interval myRange = ToonzExt::Interval(-1, -1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (; it != end; ++it) {
Shinya Kitaoka 120a6e
    aux = it;
Shinya Kitaoka 120a6e
    std::advance(aux, 1);
Shinya Kitaoka 120a6e
    ChunkStraights &cs1 = it->second;
Shinya Kitaoka 120a6e
    if (aux != end) {
Shinya Kitaoka 120a6e
      ChunkStraights &cs2 = aux->second;
Shinya Kitaoka 120a6e
      const int i1 = it->first, i2 = aux->first;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // if chunk are a sequence
Shinya Kitaoka 120a6e
      if ((i1 + 1 == i2) && !corner(cs1.first, cs2.first, tolerance)) {
Shinya Kitaoka 120a6e
        const ToonzExt::Intervals &cs1Intervals = cs1.second;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        const int size = cs1Intervals.size();
Shinya Kitaoka 120a6e
        int i;
Shinya Kitaoka 120a6e
        ToonzExt::Interval tmp;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        for (i = 0; i < size; ++i) {
Shinya Kitaoka 120a6e
          tmp = cs1Intervals[i];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          if (tmp.second == 1.0) break;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
          ToonzExt::Interval stroke_interval;
Shinya Kitaoka 120a6e
          if (mapIntervalInStroke(stroke, cs1.first, tmp, stroke_interval))
Shinya Kitaoka 120a6e
            intervals.push_back(stroke_interval);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
        // assert( i == size-1 );
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (myRange.first == -1) {
Shinya Kitaoka 120a6e
          if (!mapValueInStroke(stroke, cs1.first, tmp.first, myRange.first))
Shinya Kitaoka 120a6e
            assert(!"Ops problemone!!!");
Shinya Kitaoka 120a6e
          // remove value added to merge
Shinya Kitaoka 120a6e
          //  adjacent straight interval
Shinya Kitaoka 120a6e
          cs1.second.pop_back();
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        tmp = cs2.second.front();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (!mapValueInStroke(stroke, cs2.first, tmp.second, myRange.second))
Shinya Kitaoka 120a6e
          assert(!"Ops problemone!!!");
Shinya Kitaoka 120a6e
        cs2.second.erase(cs2.second.begin());
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        if (myRange.first != -1 && myRange.second != -1) {
Shinya Kitaoka 120a6e
          intervals.push_back(myRange);
Shinya Kitaoka 120a6e
          myRange = ToonzExt::Interval(-1, -1);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // add remaining interval of current stroke
Shinya Kitaoka 120a6e
        addQuadraticIntervalInStroke(stroke, intervals, cs1.first, cs1.second);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      if (myRange.first != -1 && myRange.second != -1) {
Shinya Kitaoka 120a6e
        intervals.push_back(myRange);
Shinya Kitaoka 120a6e
        myRange = ToonzExt::Interval(-1, -1);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // add remaining interval of current stroke
Shinya Kitaoka 120a6e
      addQuadraticIntervalInStroke(stroke, intervals, cs1.first, cs1.second);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (stroke->isSelfLoop()) {
Shinya Kitaoka 120a6e
    TPointD v0 = stroke->getSpeed(0.0), vn = stroke->getSpeed(1.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (areParallel(v0, vn) && areInSameDirection(v0, vn) &&
Shinya Kitaoka 120a6e
        intervals.size() > 1) {
Shinya Kitaoka 120a6e
      // then first interval probably can be merged
Shinya Kitaoka 120a6e
      ToonzExt::Interval first = intervals.front(), last = intervals.back();
Shinya Kitaoka 120a6e
      if (first.first == 0.0 && last.second == 0.0) {
Shinya Kitaoka 120a6e
        intervals.pop_back();
Shinya Kitaoka 120a6e
        first.first  = last.first;
Shinya Kitaoka 120a6e
        intervals[0] = first;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return !intervals.empty();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DVAPI bool ToonzExt::detectSpireIntervals(const TStroke *stroke,
Shinya Kitaoka 120a6e
                                          ToonzExt::Intervals &intervals,
Shinya Kitaoka 120a6e
                                          int minDegree) {
Shinya Kitaoka 120a6e
  if (!ToonzExt::isValid(stroke)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  minDegree = normalizeAngle(minDegree);
Shinya Kitaoka 120a6e
  std::vector<double> corners;</double>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool found = ToonzExt::cornersDetector(stroke, minDegree, corners);
Shinya Kitaoka 120a6e
  if (!found) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(!corners.empty());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  intervals.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double first = corners[0], last = first;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int size = corners.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 1; i < size; ++i) {
Shinya Kitaoka 120a6e
    last = corners[i];
Shinya Kitaoka 120a6e
    intervals.push_back(ToonzExt::Interval(first, last));
Shinya Kitaoka 120a6e
    first = last;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // intervals.push_back( ToonzExt::Interval(last,1.0));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (stroke->isSelfLoop()) {
Shinya Kitaoka 120a6e
    if (corners.size() == 1) {
Shinya Kitaoka 120a6e
      double val = corners[0];
Shinya Kitaoka 120a6e
      intervals.push_back(ToonzExt::Interval(val, val));
Shinya Kitaoka 120a6e
    } else if (!intervals.empty()) {
Shinya Kitaoka 120a6e
      ToonzExt::Interval first = intervals.front(), last = intervals.back();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      intervals.insert(intervals.begin(),
Shinya Kitaoka 120a6e
                       ToonzExt::Interval(last.second, first.first));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return !intervals.empty();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DVAPI bool ToonzExt::isAStraightCorner(const TStroke *stroke, double w,
Shinya Kitaoka 120a6e
                                       const ToonzExt::Intervals *const cl,
Shinya Kitaoka 120a6e
                                       double tolerance) {
Shinya Kitaoka 120a6e
  if (!ToonzExt::isValid(stroke) || !ToonzExt::isValid(w)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ToonzExt::Intervals tmpValues;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const ToonzExt::Intervals *values = cl;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!cl) {
Shinya Kitaoka 120a6e
    if (!ToonzExt::detectStraightIntervals(stroke, tmpValues, tolerance))
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
    values = &tmpValues;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!values || values->empty()) {
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return isCorner(*values, w, tolerance);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DVAPI bool ToonzExt::findNearestStraightCorners(
Shinya Kitaoka 120a6e
    const TStroke *stroke, double w, ToonzExt::Interval &out,
Shinya Kitaoka 120a6e
    const ToonzExt::Intervals *const cl, double tolerance) {
Shinya Kitaoka 120a6e
  if (!stroke || w < 0.0 || w > 1.0) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const ToonzExt::Intervals *values = cl;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ToonzExt::Intervals tmpValues;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!cl) {
Shinya Kitaoka 120a6e
    if (!ToonzExt::detectStraightIntervals(stroke, tmpValues, tolerance))
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
    values = &tmpValues;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!values || values->empty()) {
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return findNearestCorners(stroke, w, out, *values, tolerance);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke *ToonzExt::rotateControlPoint(const TStroke *stroke,
Shinya Kitaoka 120a6e
                                      const ToonzExt::EvenInt &evenControlPoint,
Shinya Kitaoka 120a6e
                                      double atLength) {
Shinya Kitaoka 120a6e
  if (!stroke || !stroke->isSelfLoop() || !evenControlPoint.isEven()) return 0;
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Shinya Kitaoka 120a6e
  TThickPoint tp1 = stroke->getControlPoint(0);
Shinya Kitaoka 120a6e
  TThickPoint tp2 = stroke->getControlPoint(stroke->getControlPointCount() - 1);
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  int controlPoint = (int)evenControlPoint;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const double length = stroke->getLength();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // invalid length
Shinya Kitaoka 120a6e
  if (0.0 > atLength || atLength > length) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const int cpCountAtBegin = stroke->getControlPointCount();
Shinya Kitaoka 120a6e
  // invalid control point
Shinya Kitaoka 120a6e
  if (0 > controlPoint || controlPoint > cpCountAtBegin) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // identity
Shinya Kitaoka 120a6e
  if ((controlPoint == 0 || controlPoint == (cpCountAtBegin - 1)) &&
Shinya Kitaoka 120a6e
      (areAlmostEqual(atLength, length) || isAlmostZero(atLength)))
Shinya Kitaoka 120a6e
    return new TStroke(*stroke);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStroke tmpStroke(*stroke);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> cp;</tthickpoint>
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    int count = stroke->getControlPointCount();
Shinya Kitaoka 120a6e
    for (int i = 0; i < count; ++i) {
Shinya Kitaoka 120a6e
      cp.push_back(stroke->getControlPoint(i));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // add a control point where is necessary to have rotation (head_queue cp)
Shinya Kitaoka 120a6e
  tmpStroke.insertControlPointsAtLength(atLength);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    int count  = stroke->getControlPointCount(),
Shinya Kitaoka 120a6e
        count2 = tmpStroke.getControlPointCount();
Shinya Kitaoka 120a6e
    int i, firstDifference = -1;
Shinya Kitaoka 120a6e
    for (i = 0; i < count; ++i) {
Shinya Kitaoka 120a6e
      if ((tp1 = stroke->getControlPoint(i)) !=
Shinya Kitaoka 120a6e
          (tp2 = tmpStroke.getControlPoint(i))) {
Shinya Kitaoka 120a6e
        firstDifference = i;
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = 0; i < count; ++i) {
Shinya Kitaoka 120a6e
      if (i < firstDifference)
Shinya Kitaoka 120a6e
        assert((tp1 = stroke->getControlPoint(i)) ==
Shinya Kitaoka 120a6e
               (tp2 = tmpStroke.getControlPoint(i)));
Shinya Kitaoka 120a6e
      else {
Shinya Kitaoka 120a6e
        //        assert( (tp1=stroke->getControlPoint(i)) ==
Shinya Kitaoka 120a6e
        //                (tp2=tmpStroke.getControlPoint(i+2)));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      tp1 = stroke->getControlPoint(i);
Shinya Kitaoka 120a6e
      tp2 = tmpStroke.getControlPoint(i);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
  const int cpCount = tmpStroke.getControlPointCount();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double w = tmpStroke.getParameterAtLength(atLength);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double butta = tmpStroke.getLength(w);
Shinya Kitaoka 120a6e
  assert(areAlmostEqual(butta, atLength));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // retrieve head_queue control point
Shinya Kitaoka 120a6e
  TThickPoint head_queue = tmpStroke.getControlPointAtParameter(w);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // recover index
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < cpCount; ++i) {
Shinya Kitaoka 120a6e
    if (head_queue == tmpStroke.getControlPoint(i)) break;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const int head_index = i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // uhmmm really strange
Shinya Kitaoka 120a6e
  if (head_index == cpCount) {
Shinya Kitaoka 120a6e
    assert(!"Error on procedure!!! Not control point found!!!"
Toshihiro Shimizu 890ddd
				" Wrong insert control point!!!");
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // head_index is the new head of stroke
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> new_stroke_cp;</tthickpoint>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = head_index; i < cpCount; ++i) {
Shinya Kitaoka 120a6e
    TThickPoint to_add = tmpStroke.getControlPoint(i);
Shinya Kitaoka 120a6e
    new_stroke_cp.push_back(to_add);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TThickPoint tmpCP = tmpStroke.getControlPoint(0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool check = areAlmostEqual(new_stroke_cp.back(), tmpCP, 0.01);
Shinya Kitaoka 120a6e
  // relaxed check
Shinya Kitaoka 120a6e
  assert(check);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!check) {
Shinya Kitaoka 120a6e
    assert(!"Error on procedure!!! Please verify algorithm!!!");
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // 0 position is already inserted
Shinya Kitaoka 120a6e
  for (i = 1; i < head_index; ++i) {
Shinya Kitaoka 120a6e
    TThickPoint to_add = tmpStroke.getControlPoint(i);
Shinya Kitaoka 120a6e
    new_stroke_cp.push_back(to_add);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // now add queue == head cp
Shinya Kitaoka 120a6e
  new_stroke_cp.push_back(new_stroke_cp[0]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert((int)new_stroke_cp.size() == cpCount);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (new_stroke_cp.back() != tmpStroke.getControlPoint(head_index)) {
Shinya Kitaoka 120a6e
    assert(!"Error on procedure!!! Please verify algorithm!!!");
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TStroke *out = new TStroke(new_stroke_cp);
Shinya Kitaoka 120a6e
  out->setSelfLoop();
Shinya Kitaoka 120a6e
  return out;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*
Toshihiro Shimizu 890ddd
 * A corner is straight, only if is contained two times
Toshihiro Shimizu 890ddd
 * in the list of intervals.
Toshihiro Shimizu 890ddd
 */
Shinya Kitaoka 120a6e
DVAPI bool ToonzExt::straightCornersDetector(const TStroke *stroke,
Shinya Kitaoka 120a6e
                                             std::vector<double> &corners) {</double>
Shinya Kitaoka 120a6e
  ToonzExt::Intervals intervals;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(corners.empty());
Shinya Kitaoka 120a6e
  if (!corners.empty()) corners.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!ToonzExt::detectStraightIntervals(stroke, intervals)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(!intervals.empty() && "Intervals are empty!!!");
Shinya Kitaoka 120a6e
  if (intervals.empty()) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double first;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ToonzExt::Interval prev = intervals[0], curr;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (stroke->isSelfLoop()) first = prev.first;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int size = intervals.size();
Shinya Kitaoka 120a6e
  for (int i = 1; i < size; ++i) {
Shinya Kitaoka 120a6e
    curr = intervals[i];
Shinya Kitaoka 120a6e
    if (prev.second == curr.first) corners.push_back(curr.first);
Shinya Kitaoka 120a6e
    prev = curr;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (stroke->isSelfLoop() && curr.second == first) corners.push_back(first);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return !corners.empty();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DVAPI bool ToonzExt::cornersDetector(const TStroke *stroke, int minDegree,
Shinya Kitaoka 120a6e
                                     std::vector<double> &corners) {</double>
Shinya Kitaoka 120a6e
  assert(stroke);
Shinya Kitaoka 120a6e
  if (!stroke) return false;
Shinya Kitaoka 120a6e
  assert(corners.empty());
Shinya Kitaoka 120a6e
  if (!corners.empty()) corners.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(0 <= minDegree && minDegree <= 180);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  minDegree = normalizeAngle(minDegree);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const double minSin = degree2sin(minDegree), minCos = degree2cos(minDegree);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(0.0 <= minSin && minSin <= 1.0);
Shinya Kitaoka 120a6e
MCCCS a0ce32
  // first step remove chunks with null length
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const TThickQuadratic *quad1 = 0, *quad2 = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  UINT chunkCount = stroke->getChunkCount();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  quad1 = stroke->getChunk(0);
Shinya Kitaoka 120a6e
  assert(quad1);
Shinya Kitaoka 120a6e
  if (!quad1) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool error = false, check = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::set<double> internal_corners;</double>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double t;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (curveIsStraight(quad1, t)) {
Shinya Kitaoka 120a6e
    if (t != -1) {
Shinya Kitaoka 120a6e
      check = mapValueInStroke(stroke, quad1, t, t);
Shinya Kitaoka 120a6e
      assert(check);
Shinya Kitaoka 120a6e
      if (check) internal_corners.insert(t);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (UINT j = 1; j < chunkCount; j++) {
Shinya Kitaoka 120a6e
    quad2 = stroke->getChunk(j);
Shinya Kitaoka 120a6e
    if (curveIsStraight(quad2, t)) {
Shinya Kitaoka 120a6e
      if (t != -1) {
Shinya Kitaoka 120a6e
        check = mapValueInStroke(stroke, quad2, t, t);
Shinya Kitaoka 120a6e
        assert(check);
Shinya Kitaoka 120a6e
        if (check) internal_corners.insert(t);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    assert(quad2);
Shinya Kitaoka 120a6e
    if (!quad2) error = true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double tmp = stroke->getW(quad2->getP0());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // jump zero length curves
Shinya Kitaoka 120a6e
    if (!isAlmostZero(quad1->getLength()) &&
Shinya Kitaoka 120a6e
        !isAlmostZero(quad2->getLength()) &&
Shinya Kitaoka 120a6e
        isThereACornerMinusThan(minCos, minSin, quad1, quad2))
Shinya Kitaoka 120a6e
      internal_corners.insert(tmp);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (!isAlmostZero(quad2->getLength())) quad1 = quad2;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (stroke->isSelfLoop() && chunkCount > 0) {
Shinya Kitaoka 120a6e
    quad2 = stroke->getChunk(0);
Shinya Kitaoka 120a6e
    quad1 = stroke->getChunk(chunkCount - 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (isThereACornerMinusThan(minCos, minSin, quad1, quad2))
Shinya Kitaoka 120a6e
      internal_corners.insert(0.0);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    internal_corners.insert(0.0);
Shinya Kitaoka 120a6e
    internal_corners.insert(1.0);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (error) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::copy(internal_corners.begin(), internal_corners.end(),
Shinya Kitaoka 120a6e
            std::back_inserter(corners));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _DEBUG
Shinya Kitaoka 120a6e
  double temp = 0;
Shinya Kitaoka 120a6e
  for (unsigned int k = 0; k < corners.size(); ++k) {
Shinya Kitaoka 120a6e
    assert(corners[k] >= temp);
Shinya Kitaoka 120a6e
    temp = corners[k];
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return !corners.empty();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ToonzExt::cloneStrokeStatus(const TStroke *from, TStroke *to) {
Shinya Kitaoka 120a6e
  if (!ToonzExt::isValid(from) || !ToonzExt::isValid(to)) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  to->setId(from->getId());
Shinya Kitaoka 120a6e
  to->setSelfLoop(from->isSelfLoop());
Shinya Kitaoka 120a6e
  to->setStyle(from->getStyle());
Shinya Kitaoka 120a6e
  to->setAverageThickness(from->getAverageThickness());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  to->invalidate();
Shinya Kitaoka 120a6e
  to->enableComputeOfCaches();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DVAPI bool ToonzExt::replaceStroke(TStroke *old_stroke, TStroke *new_stroke,
Shinya Kitaoka 120a6e
                                   unsigned int n_, TVectorImageP &vi) {
Shinya Kitaoka 120a6e
  if (!ToonzExt::isValid(old_stroke) || !ToonzExt::isValid(new_stroke) || !vi)
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const unsigned int strokesCount = vi->getStrokeCount();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(n_ <= strokesCount);
Shinya Kitaoka 120a6e
  if (n_ > strokesCount) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(vi->getStroke(n_) == old_stroke);
Shinya Kitaoka 120a6e
  if (vi->getStroke(n_) != old_stroke) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // stroke is replaced (old stroke is deleted)
Shinya Kitaoka 120a6e
  // in vector image
Shinya Kitaoka 120a6e
  vi->replaceStroke(n_, new_stroke);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int new_id = getStrokeId(new_stroke, vi);
Shinya Kitaoka 120a6e
  if (new_id == -1) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  n_ = new_id;
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DVAPI bool ToonzExt::getAllW(const TStroke *stroke, const TPointD &pnt,
Shinya Kitaoka 120a6e
                             double &dist2, std::vector<double> ¶meters) {</double>
Shinya Kitaoka 120a6e
  assert(!"To be finished!!!");
Shinya Kitaoka 120a6e
  std::set<double> tmp;</double>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(stroke);
Shinya Kitaoka 120a6e
  if (ToonzExt::isValid(stroke)) return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double outT, w;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const TThickQuadratic *tq = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int chunkFound = -1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double distance2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (stroke->getNearestChunk(pnt, outT, chunkFound, distance2, false)) {
Shinya Kitaoka 120a6e
    dist2 = distance2;
Shinya Kitaoka 120a6e
    tq    = stroke->getChunk(chunkFound);
Shinya Kitaoka 120a6e
    if (tq) {
Shinya Kitaoka 120a6e
      w = stroke->getW(tq->getPoint(outT));
Shinya Kitaoka 120a6e
      if (ToonzExt::isValid(w)) tmp.insert(w);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int i, chunkCount = stroke->getChunkCount();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < chunkCount; i++) {
Shinya Kitaoka 120a6e
    if (i != chunkFound) {
Shinya Kitaoka 120a6e
      tq              = stroke->getChunk(i);
Shinya Kitaoka 120a6e
      TPointD tmp_pnt = tq->getPoint(tq->getT(pnt));
Shinya Kitaoka 120a6e
      if (areAlmostEqual(tdistance2(tmp_pnt, pnt), dist2)) {
Shinya Kitaoka 120a6e
        w = stroke->getW(tmp_pnt);
Shinya Kitaoka 120a6e
        if (ToonzExt::isValid(w)) tmp.insert(w);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::copy(tmp.begin(), tmp.end(), std::back_inserter(parameters));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return !tmp.empty();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DVAPI bool ToonzExt::findNearestCorners(const TStroke *stroke, double w,
Shinya Kitaoka 120a6e
                                        ToonzExt::Interval &out,
Shinya Kitaoka 120a6e
                                        const ToonzExt::Intervals &values,
Shinya Kitaoka 120a6e
                                        double tolerance) {
Shinya Kitaoka 120a6e
  out = ToonzExt::Interval(-1.0, -1.0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!ToonzExt::isValid(stroke) || !ToonzExt::isValid(w) || values.empty())
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ToonzExt::Interval prev = values[0], curr = prev;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!stroke->isSelfLoop() && areAlmostEqual(w, prev.first, tolerance)) {
Shinya Kitaoka 120a6e
    out = prev;
Shinya Kitaoka 120a6e
    return true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const int size = values.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 1; i <= size; ++i) {
Shinya Kitaoka 120a6e
    if (i < size)
Shinya Kitaoka 120a6e
      curr = values[i];
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      curr = values[0];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // this case, w is an extreme and needs to be considered
Shinya Kitaoka 120a6e
    //  the nearest external interval
Shinya Kitaoka 120a6e
    if (areAlmostEqual(w, curr.first, tolerance) &&
Shinya Kitaoka 120a6e
        (prev.second == curr.first)) {
Shinya Kitaoka 120a6e
      if (isWGood(prev.first, w, curr.second, stroke) ||
Shinya Kitaoka 120a6e
          (prev.first == curr.second)) {
Shinya Kitaoka 120a6e
        out.first  = prev.first;
Shinya Kitaoka 120a6e
        out.second = curr.second;
Shinya Kitaoka 120a6e
        return true;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // normal case
Shinya Kitaoka 120a6e
    if (isWGood(curr.first, w, curr.second, stroke)) {
Shinya Kitaoka 120a6e
      out = curr;
Shinya Kitaoka 120a6e
      return true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    prev = curr;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  curr = values.back();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // last point
Shinya Kitaoka 120a6e
  if (!stroke->isSelfLoop() && areAlmostEqual(curr.second, w, tolerance)) {
Shinya Kitaoka 120a6e
    out = curr;
Shinya Kitaoka 120a6e
    return true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DVAPI void ToonzExt::findCorners(const TStroke *stroke,
Shinya Kitaoka 120a6e
                                 ToonzExt::Intervals &corners,
Shinya Kitaoka 120a6e
                                 ToonzExt::Intervals &intervals, int angle,
Shinya Kitaoka 120a6e
                                 double tolerance) {
Shinya Kitaoka 120a6e
  assert(stroke && "Stroke is null!!!");
Shinya Kitaoka 120a6e
  if (!ToonzExt::isValid(stroke)) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  angle = normalizeAngle(angle);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ToonzExt::detectSpireIntervals(stroke, corners, angle);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // a corner SPIRE is also a STRAIGHT
Shinya Kitaoka 120a6e
  ToonzExt::detectStraightIntervals(stroke, intervals, tolerance);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//  End Of File
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------