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