#ifdef WIN32
#define NOMINMAX
#endif
#include "ext/NotSimmetricBezierPotential.h"
#include "tstroke.h"
#include <tmathutil.h>
#include <tcurves.h>
#include <algorithm>
using namespace std;
using namespace std;
using namespace ToonzExt;
//-----------------------------------------------------------------------------
namespace
{
typedef unary_function<double, double> unary_functionDD;
//---------------------------------------------------------------------------
class myBlendFunc : unary_functionDD
{
//TCubic c;
TQuadratic curve;
public:
myBlendFunc(double t = 0.0)
{
curve.setP0(TPointD(0.0, 1.0));
curve.setP1(TPointD(0.5 * (1.0 - t), 1.0));
curve.setP2(TPointD(1.0, 0.0));
}
result_type operator()(argument_type x)
{
result_type out = 0.0;
x = fabs(x);
if (x >= 1.0)
return 0.0;
out = curve.getPoint(x).y;
return out;
}
};
}
//-----------------------------------------------------------------------------
ToonzExt::NotSimmetricBezierPotential::~NotSimmetricBezierPotential()
{
}
//-----------------------------------------------------------------------------
void ToonzExt::NotSimmetricBezierPotential::setParameters_(const TStroke *ref,
double w,
double al)
{
assert(ref);
ref_ = ref;
par_ = w;
actionLength_ = al;
strokeLength_ = ref->getLength();
lenghtAtParam_ = ref->getLength(par_);
// lunghezza dal pto di click all'inizio della curva
leftFactor_ = min(lenghtAtParam_,
actionLength_ * 0.5); //lenghtAtParam_ / strokeLength_;
// lunghezza dal pto di click alla fine
rightFactor_ = min(strokeLength_ - lenghtAtParam_,
actionLength_ * 0.5);
}
//-----------------------------------------------------------------------------
double
ToonzExt::NotSimmetricBezierPotential::value_(double value2test) const
{
assert(0.0 <= value2test &&
value2test <= 1.0);
return this->compute_value(value2test);
}
//-----------------------------------------------------------------------------
// normalization of parameter in range interval
double ToonzExt::NotSimmetricBezierPotential::compute_shape(double value2test) const
{
double x = ref_->getLength(value2test);
double shape = this->actionLength_ * 0.5;
if (isAlmostZero(shape))
shape = 1.0;
x = (x - lenghtAtParam_) / shape;
return x;
}
//-----------------------------------------------------------------------------
double
ToonzExt::NotSimmetricBezierPotential::compute_value(double value2test) const
{
myBlendFunc me;
// on extremes use
// 2
// 1-x
//
// when is near to extreme uses a mix notation
double x = 0.0;
double res = 0.0;
// lenght at parameter
x = ref_->getLength(value2test);
const double tolerance = 0.0; // need to be pixel based
// if is an extreme
if (max(lenghtAtParam_, 0.0) < tolerance ||
max(strokeLength_ - lenghtAtParam_, 0.0) < tolerance) {
double tmp_al = actionLength_ * 0.5;
// compute correct parameter considering offset
// try to have a square curve like shape
//
// 2
// m = x
//
if (leftFactor_ <= tolerance)
x = 1.0 - x / tmp_al;
else
x = (x - (strokeLength_ - tmp_al)) / tmp_al;
if (x < 0.0)
return 0.0;
assert(0.0 <= x &&
x <= 1.0 + TConsts::epsilon);
x = std::min(x, 1.0); // just to avoid problem in production code
res = sq(x);
} else // when is not an extreme
{
double lenght_at_value2test = ref_->getLength(value2test);
const double min_level = 0.01;
// if check a parameter over click point
if (lenght_at_value2test >= lenghtAtParam_) {
// check if extreme can be moved from this parameter configuration
double tmp_x = this->compute_shape(1.0);
double tmp_res = me(tmp_x);
if (tmp_res > min_level) {
// please note that in this case
// lenghtAtParam_ + rightFactor_ == strokeLength_
// (by ctor).
if (rightFactor_ != 0.0)
x = (lenght_at_value2test - lenghtAtParam_) / rightFactor_;
else
x = 0.0;
assert(0.0 - TConsts::epsilon <= x &&
x <= 1.0 + TConsts::epsilon);
if (isAlmostZero(x))
x = 0.0;
if (areAlmostEqual(x, 1.0))
x = 1.0;
double how_many_of_shape = (strokeLength_ - lenghtAtParam_) / (actionLength_ * 0.5);
assert(0.0 <= how_many_of_shape &&
how_many_of_shape <= 1.0);
myBlendFunc bf(how_many_of_shape);
return bf(x);
}
} else {
// leftFactor_
double tmp_x = this->compute_shape(0.0);
double tmp_res = me(tmp_x);
if (tmp_res > min_level) {
double x = lenght_at_value2test / leftFactor_;
assert(0.0 <= x &&
x <= 1.0);
// then movement use another shape
double diff = x - 1.0;
double how_many_of_shape = lenghtAtParam_ / (actionLength_ * 0.5);
assert(0.0 <= how_many_of_shape &&
how_many_of_shape <= 1.0);
myBlendFunc bf(how_many_of_shape);
return bf(diff);
}
}
// default behaviour is an exp
x = this->compute_shape(value2test);
res = me(x);
}
return res;
}
//-----------------------------------------------------------------------------
ToonzExt::Potential *
ToonzExt::NotSimmetricBezierPotential::clone()
{
return new NotSimmetricBezierPotential;
}
//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------