| |
| |
|
|
| |
| |
| |
| |
| |
| |
| #include "tstrokedeformations.h" |
| #include "tcurveutil.h" |
| #include "tmathutil.h" |
| #include "tstroke.h" |
| |
| using namespace std; |
| |
| |
| |
| namespace { |
| const double nine_inv = 1.0 / 9.0; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| struct bowlPotential { |
| double m_radiusInner; |
| double m_radiusOuter; |
| |
| bowlPotential(double radiusInner, double radiusOuter) |
| : m_radiusInner(radiusInner), m_radiusOuter(radiusOuter) { |
| assert(m_radiusInner > 0); |
| assert(m_radiusOuter >= m_radiusInner); |
| } |
| |
| virtual double value(double radiusToTest) { |
| assert(radiusToTest >= 0); |
| if (radiusToTest <= m_radiusInner) return 1.0; |
| if (radiusToTest > m_radiusOuter) return 0.0; |
| |
| return 0.5 * (1.0 + cos((radiusToTest - m_radiusInner) / |
| (m_radiusOuter - m_radiusInner) * M_PI)); |
| } |
| |
| virtual double gradient(double radiusToTest) { |
| assert(radiusToTest >= 0); |
| if (radiusToTest <= m_radiusInner || radiusToTest > m_radiusOuter) |
| return 0.0; |
| |
| double den = M_PI / (m_radiusOuter - m_radiusInner); |
| |
| return -0.5 * den * sin(den * (radiusToTest - m_radiusInner)); |
| } |
| |
| virtual ~bowlPotential() {} |
| }; |
| |
| double wyvillPotential(double r, double R) { |
| if (0.0 == R) return 0.0; |
| |
| if (0 > r || r >= R) return 0.0; |
| |
| double ratio2 = sq(r / R); |
| double ratio4 = sq(ratio2); |
| double ratio6 = ratio2 * ratio4; |
| |
| return 1.0 + (17.0 * ratio4 - (4.0 * ratio6 + 22.0 * ratio2)) * nine_inv; |
| } |
| |
| |
| |
| double derivateOfWyvillPotential(double r, double R) { |
| if (0.0 == R) return 0.0; |
| if (0 > r || r > R) return 0.0; |
| |
| double inv_of_R = 1.0 / R; |
| double ratio = r / R; |
| double ratio2 = sq(ratio); |
| double ratio3 = ratio * ratio2; |
| double ratio5 = ratio3 * ratio2; |
| |
| return inv_of_R * nine_inv * (68.0 * ratio3 - (24.0 * ratio5 + 66.0 * ratio)); |
| } |
| |
| const double c_maxLengthOfGaussian = 3.0; |
| |
| |
| |
| double gaussianPotential(double x) { return exp(-sq(x)); } |
| |
| |
| |
| double derivateOfGaussianPotential(double x) { return -2 * x * exp(-sq(x)); } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| double normOfGradientOfWyvillPotential(double r, double R) { |
| TPointD grad; |
| |
| grad.x = 1.0; |
| grad.y = derivateOfWyvillPotential(r, R); |
| |
| return norm(grad); |
| } |
| |
| } |
| |
| |
| |
| struct TStrokePointDeformation::Imp { |
| TPointD m_circleCenter; |
| double m_circleRadius; |
| TPointD *m_vect; |
| |
| bowlPotential *m_potential; |
| |
| Imp(const TPointD ¢er, double radius) |
| : m_circleCenter(center), m_circleRadius(radius), m_vect(0) { |
| m_potential = new bowlPotential(0.3 * m_circleRadius, m_circleRadius); |
| } |
| |
| Imp(const TPointD &vect, const TPointD ¢er, double radius) |
| : m_circleCenter(center) |
| , m_circleRadius(radius) |
| , m_vect(new TPointD(vect)) { |
| m_potential = new bowlPotential(0.3 * m_circleRadius, m_circleRadius); |
| } |
| |
| ~Imp() { |
| delete m_vect; |
| delete m_potential; |
| } |
| }; |
| |
| TStrokePointDeformation::TStrokePointDeformation(const TPointD ¢er, |
| double radius) |
| : m_imp(new Imp(center, radius)) {} |
| |
| |
| |
| TStrokePointDeformation::TStrokePointDeformation(const TPointD &vect, |
| const TPointD ¢er, |
| double radius) |
| : m_imp(new Imp(vect, center, radius)) {} |
| |
| |
| |
| TStrokePointDeformation::~TStrokePointDeformation() {} |
| |
| |
| |
| TThickPoint TStrokePointDeformation::getDisplacementForControlPoint( |
| const TStroke &stroke, UINT n) const { |
| |
| TPointD pntOfStroke(convert(stroke.getControlPoint(n))); |
| |
| double d = tdistance(pntOfStroke, m_imp->m_circleCenter); |
| |
| if (m_imp->m_vect) |
| return m_imp->m_potential->value(d) * TThickPoint(*m_imp->m_vect, 0); |
| else { |
| double outVal = m_imp->m_potential->value(d); |
| |
| return TThickPoint(outVal, outVal, 0); |
| } |
| } |
| |
| TThickPoint TStrokePointDeformation::getDisplacementForControlPointLen( |
| const TStroke &stroke, double cpLen) const { |
| assert(0); |
| return TThickPoint(); |
| } |
| |
| |
| |
| TThickPoint TStrokePointDeformation::getDisplacement(const TStroke &stroke, |
| double w) const { |
| |
| TThickPoint thickPnt = m_imp->m_vect ? stroke.getControlPointAtParameter(w) |
| : stroke.getThickPoint(w); |
| |
| assert(thickPnt != TConsts::natp); |
| |
| TPointD pntOfStroke(convert(thickPnt)); |
| |
| double d = tdistance(pntOfStroke, m_imp->m_circleCenter); |
| |
| if (m_imp->m_vect) |
| return m_imp->m_potential->value(d) * TThickPoint(*m_imp->m_vect, 0); |
| else { |
| double outVal = m_imp->m_potential->value(d); |
| |
| return TThickPoint(outVal, outVal, 0); |
| } |
| } |
| |
| |
| |
| double TStrokePointDeformation::getDelta(const TStroke &stroke, |
| double w) const { |
| |
| TThickPoint thickPnt = m_imp->m_vect ? stroke.getControlPointAtParameter(w) |
| : stroke.getThickPoint(w); |
| |
| assert(thickPnt != TConsts::natp); |
| |
| TPointD pntOfStroke = convert(thickPnt); |
| |
| double d = tdistance(pntOfStroke, m_imp->m_circleCenter); |
| |
| return m_imp->m_potential->gradient(d); |
| } |
| |
| |
| |
| double TStrokePointDeformation::getMaxDiff() const { return 0.005; } |
| |
| |
| |
| TStrokeParamDeformation::TStrokeParamDeformation(const TStroke *ref, |
| const TPointD &vect, double s, |
| double l) |
| : m_pRef(ref) |
| , m_startParameter(s) |
| , m_lengthOfDeformation(l) |
| , m_vect(new TPointD(vect)) { |
| assert(m_lengthOfDeformation >= 0); |
| if (isAlmostZero(m_lengthOfDeformation)) |
| m_lengthOfDeformation = TConsts::epsilon; |
| } |
| |
| |
| |
| TStrokeParamDeformation::TStrokeParamDeformation(const TStroke *ref, double s, |
| double l) |
| : m_pRef(ref), m_startParameter(s), m_lengthOfDeformation(l), m_vect(0) { |
| assert(m_lengthOfDeformation >= 0); |
| if (isAlmostZero(m_lengthOfDeformation)) |
| m_lengthOfDeformation = TConsts::epsilon; |
| } |
| |
| |
| TThickPoint TStrokeParamDeformation::getDisplacementForControlPoint( |
| const TStroke &stroke, UINT n) const { |
| |
| |
| double diff = stroke.getLengthAtControlPoint(n); |
| |
| diff = diff - m_startParameter; |
| if (fabs(diff) <= m_lengthOfDeformation) { |
| |
| |
| |
| |
| diff *= (1.0 / m_lengthOfDeformation) * c_maxLengthOfGaussian; |
| |
| if (m_vect) |
| return gaussianPotential(diff) * TThickPoint(*m_vect, 0); |
| else { |
| double outVal = gaussianPotential(diff); |
| return TThickPoint(outVal, outVal, 0); |
| } |
| } |
| |
| return TThickPoint(); |
| } |
| |
| TThickPoint TStrokeParamDeformation::getDisplacementForControlPointLen( |
| const TStroke &stroke, double cpLenDiff) const { |
| |
| |
| |
| |
| |
| double diff = cpLenDiff; |
| if (fabs(diff) <= m_lengthOfDeformation) { |
| |
| |
| |
| |
| diff *= (1.0 / m_lengthOfDeformation) * c_maxLengthOfGaussian; |
| |
| if (m_vect) |
| return gaussianPotential(diff) * TThickPoint(*m_vect, 0); |
| else { |
| double outVal = gaussianPotential(diff); |
| return TThickPoint(outVal, outVal, 0); |
| } |
| } |
| |
| return TThickPoint(); |
| } |
| |
| |
| |
| TThickPoint TStrokeParamDeformation::getDisplacement(const TStroke &stroke, |
| double w) const { |
| |
| |
| double diff = stroke.getLength(w); |
| |
| diff = diff - m_startParameter; |
| if (fabs(diff) <= m_lengthOfDeformation) { |
| |
| |
| |
| |
| diff *= (1.0 / m_lengthOfDeformation) * c_maxLengthOfGaussian; |
| |
| if (m_vect) |
| return gaussianPotential(diff) * TThickPoint(*m_vect, 0); |
| else { |
| double outVal = gaussianPotential(diff); |
| return TThickPoint(outVal, outVal, 0); |
| } |
| } |
| |
| return TThickPoint(); |
| } |
| |
| |
| |
| double TStrokeParamDeformation::getDelta(const TStroke &stroke, |
| double w) const { |
| |
| |
| double diff = stroke.getLength(w); |
| |
| diff = diff - m_startParameter; |
| if (fabs(diff) <= m_lengthOfDeformation) { |
| |
| |
| |
| |
| diff *= (1.0 / m_lengthOfDeformation) * c_maxLengthOfGaussian; |
| |
| return derivateOfGaussianPotential(diff); |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| double TStrokeParamDeformation::getMaxDiff() const { return 0.09; } |
| |
| |
| |
| TStrokeParamDeformation::~TStrokeParamDeformation() { delete m_vect; } |
| |
| |
| |
| |
| |
| |
| TStrokeBenderDeformation::TStrokeBenderDeformation(const TStroke *ref, double s, |
| double l) |
| : m_pRef(ref) |
| , m_startLength(s) |
| , m_lengthOfDeformation(l) |
| , m_vect(0) |
| , m_versus(INNER) { |
| assert(m_lengthOfDeformation >= 0); |
| |
| if (isAlmostZero(m_lengthOfDeformation)) |
| m_lengthOfDeformation = TConsts::epsilon; |
| } |
| |
| |
| |
| TStrokeBenderDeformation::TStrokeBenderDeformation(const TStroke *ref, |
| const TPointD &vect, |
| double angle, double s, |
| int innerOrOuter, double l) |
| : m_pRef(ref) |
| , m_startLength(s) |
| , m_lengthOfDeformation(l) |
| , m_vect(new TPointD(vect)) |
| , m_versus(innerOrOuter) |
| , m_angle(angle) { |
| assert(m_lengthOfDeformation >= 0); |
| if (isAlmostZero(m_lengthOfDeformation)) |
| m_lengthOfDeformation = TConsts::epsilon; |
| } |
| |
| |
| |
| TStrokeBenderDeformation::~TStrokeBenderDeformation() { delete m_vect; } |
| |
| |
| |
| double TStrokeBenderDeformation::getMaxDiff() const { |
| |
| return 0.4; |
| } |
| |
| |
| |
| TThickPoint TStrokeBenderDeformation::getDisplacementForControlPoint( |
| const TStroke &s, UINT n) const { |
| |
| |
| double strokeLengthAtParameter = s.getLengthAtControlPoint(n); |
| double diff = strokeLengthAtParameter - m_startLength; |
| |
| if (m_vect) { |
| double outVal = 0; |
| |
| if (fabs(diff) <= m_lengthOfDeformation && m_versus == INNER) { |
| diff *= (1.0 / m_lengthOfDeformation) * c_maxLengthOfGaussian; |
| outVal = gaussianPotential(diff); |
| } else if (m_versus == OUTER) { |
| double valForGaussian = -c_maxLengthOfGaussian + |
| 2 * c_maxLengthOfGaussian / |
| m_lengthOfDeformation * |
| strokeLengthAtParameter; |
| outVal = 1.0 - gaussianPotential(valForGaussian); |
| } |
| |
| TPointD cp = convert(s.getControlPoint(n)); |
| TPointD p = cp; |
| |
| TRotation rot(*m_vect, outVal * rad2degree(m_angle)); |
| |
| p = rot * p; |
| |
| return TThickPoint(p - cp, 0.0); |
| } |
| |
| return TThickPoint(); |
| } |
| |
| TThickPoint TStrokeBenderDeformation::getDisplacementForControlPointLen( |
| const TStroke &stroke, double cpLen) const { |
| assert(0); |
| return TThickPoint(); |
| } |
| |
| |
| |
| TThickPoint TStrokeBenderDeformation::getDisplacement(const TStroke &s, |
| double w) const { |
| |
| |
| double strokeLengthAtParameter = s.getLength(w); |
| double diff = strokeLengthAtParameter - m_startLength; |
| |
| if (m_vect) { |
| double outVal = 0.0; |
| |
| if (fabs(diff) <= m_lengthOfDeformation) |
| if (m_versus == INNER) { |
| diff *= (1.0 / m_lengthOfDeformation) * c_maxLengthOfGaussian; |
| outVal = gaussianPotential(diff); |
| } else if (m_versus == OUTER) { |
| double valForGaussian = -c_maxLengthOfGaussian + |
| 2 * c_maxLengthOfGaussian / |
| m_lengthOfDeformation * |
| strokeLengthAtParameter; |
| outVal = 1.0 - gaussianPotential(valForGaussian); |
| } |
| |
| TPointD cp = convert(s.getControlPointAtParameter(w)); |
| TPointD p = cp; |
| |
| TRotation rot(*m_vect, outVal * rad2degree(m_angle)); |
| |
| p = rot * p; |
| |
| return TThickPoint(p - cp, 0.0); |
| } |
| |
| return TThickPoint(); |
| } |
| |
| |
| |
| double TStrokeBenderDeformation::getDelta(const TStroke &s, double w) const { |
| double totalLength = s.getLength(); |
| |
| if (totalLength != 0) { |
| double val = s.getLength(w) / totalLength * (M_PI * 10.0); |
| |
| return sin(val); |
| } |
| return 0; |
| } |
| |
| |
| |
| TStrokeTwirlDeformation::TStrokeTwirlDeformation(const TPointD ¢er, |
| double radius) |
| : m_center(center) |
| , m_innerRadius2(sq(radius)) |
| , m_vectorOfMovement(TPointD()) { |
| m_outerRadius = 1.25 * radius; |
| } |
| |
| |
| |
| TStrokeTwirlDeformation::TStrokeTwirlDeformation(const TPointD ¢er, |
| double radius, |
| const TPointD &v) |
| : m_center(center), m_innerRadius2(sq(radius)), m_vectorOfMovement(v) { |
| m_outerRadius = 1.25 * radius; |
| } |
| |
| |
| |
| TStrokeTwirlDeformation::~TStrokeTwirlDeformation() {} |
| |
| |
| |
| TThickPoint TStrokeTwirlDeformation::getDisplacement(const TStroke &stroke, |
| double s) const { |
| double outVal = 0; |
| |
| double distance2 = |
| tdistance2(convert(stroke.getControlPointAtParameter(s)), m_center); |
| |
| if (distance2 <= m_innerRadius2) |
| outVal = wyvillPotential(distance2, m_innerRadius2); |
| |
| return TThickPoint(m_vectorOfMovement * outVal, 0); |
| } |
| |
| |
| |
| double TStrokeTwirlDeformation::getDelta(const TStroke &stroke, |
| double s) const { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| return 0; |
| } |
| |
| |
| |
| double TStrokeTwirlDeformation::getMaxDiff() const { return 0.4; } |
| |
| |
| |
| |
| |
| |
| |
| TStrokeThicknessDeformation::TStrokeThicknessDeformation(const TStroke *ref, |
| const TPointD &vect, |
| double s, double l, |
| double versus) |
| : m_lengthOfDeformation(l) |
| , m_startParameter(s) |
| , m_versus(versus) |
| , m_vect(new TPointD(vect)) |
| , m_pRef(ref) { |
| assert(m_lengthOfDeformation >= 0); |
| if (isAlmostZero(m_lengthOfDeformation)) |
| m_lengthOfDeformation = TConsts::epsilon; |
| } |
| |
| |
| |
| TStrokeThicknessDeformation::TStrokeThicknessDeformation(const TStroke *ref, |
| double s, double l) |
| : m_lengthOfDeformation(l), m_startParameter(s), m_vect(0), m_pRef(ref) { |
| assert(m_lengthOfDeformation >= 0); |
| if (isAlmostZero(m_lengthOfDeformation)) |
| m_lengthOfDeformation = TConsts::epsilon; |
| } |
| |
| |
| TThickPoint TStrokeThicknessDeformation::getDisplacementForControlPoint( |
| const TStroke &stroke, UINT n) const { |
| |
| |
| double diff = stroke.getLengthAtControlPoint(n); |
| |
| diff = diff - m_startParameter; |
| |
| if (fabs(diff) <= m_lengthOfDeformation) { |
| |
| |
| |
| |
| diff *= (1.0 / m_lengthOfDeformation) * c_maxLengthOfGaussian; |
| |
| TThickPoint delta; |
| |
| if (m_vect) { |
| |
| delta = |
| TThickPoint(0, 0, m_versus * norm(*m_vect) * gaussianPotential(diff)); |
| } else { |
| double outVal = gaussianPotential(diff); |
| delta = TThickPoint(0, 0, outVal); |
| } |
| |
| |
| return delta; |
| } |
| return TThickPoint(); |
| } |
| |
| TThickPoint TStrokeThicknessDeformation::getDisplacementForControlPointLen( |
| const TStroke &stroke, double diff) const { |
| if (fabs(diff) <= m_lengthOfDeformation) { |
| |
| |
| |
| |
| diff *= (1.0 / m_lengthOfDeformation) * c_maxLengthOfGaussian; |
| |
| TThickPoint delta; |
| |
| if (m_vect) { |
| |
| delta = |
| TThickPoint(0, 0, m_versus * norm(*m_vect) * gaussianPotential(diff)); |
| } else { |
| double outVal = gaussianPotential(diff); |
| delta = TThickPoint(0, 0, outVal); |
| } |
| |
| |
| return delta; |
| } |
| return TThickPoint(); |
| } |
| |
| TThickPoint TStrokeThicknessDeformation::getDisplacement(const TStroke &stroke, |
| double w) const { |
| |
| |
| double diff = stroke.getLength(w); |
| |
| diff = diff - m_startParameter; |
| |
| if (fabs(diff) <= m_lengthOfDeformation) { |
| |
| |
| |
| |
| diff *= (1.0 / m_lengthOfDeformation) * c_maxLengthOfGaussian; |
| |
| if (m_vect) |
| return gaussianPotential(diff) * TThickPoint(*m_vect, 0); |
| else { |
| double outVal = gaussianPotential(diff); |
| return TThickPoint(0, 0, outVal); |
| } |
| } |
| |
| return TThickPoint(); |
| } |
| |
| |
| |
| double TStrokeThicknessDeformation::getDelta(const TStroke &stroke, |
| double w) const { |
| |
| |
| double diff = stroke.getLength(w); |
| |
| diff = diff - m_startParameter; |
| |
| if (fabs(diff) <= m_lengthOfDeformation) { |
| |
| |
| |
| |
| diff *= (1.0 / m_lengthOfDeformation) * c_maxLengthOfGaussian; |
| |
| return derivateOfGaussianPotential(diff); |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| double TStrokeThicknessDeformation::getMaxDiff() const { return 0.09; } |
| |
| |
| |
| TStrokeThicknessDeformation::~TStrokeThicknessDeformation() { delete m_vect; } |
| |
| |
| |
| TPointDeformation::TPointDeformation(const TStroke *stroke, |
| const TPointD ¢er, double radius) |
| : m_strokeRef(stroke), m_center(center), m_radius(radius) { |
| assert(m_strokeRef); |
| } |
| |
| |
| |
| TPointDeformation::TPointDeformation() {} |
| |
| |
| |
| TPointDeformation::~TPointDeformation() {} |
| |
| |
| |
| TThickPoint TPointDeformation::getDisplacement(double s) const { |
| |
| TThickPoint thickPnt = m_strokeRef->getPointAtLength(s); |
| |
| assert(thickPnt != TConsts::natp); |
| |
| TPointD pntOfStroke(convert(thickPnt)); |
| |
| double d = tdistance(pntOfStroke, m_center); |
| |
| double outVal = wyvillPotential(d, m_radius); |
| |
| return TThickPoint(outVal, outVal, 0); |
| } |
| |
| |
| |
| |
| double TPointDeformation::getCPDensity(double s) const { |
| |
| TThickPoint thickPnt = m_strokeRef->getThickPointAtLength(s); |
| |
| assert(thickPnt != TConsts::natp); |
| |
| TPointD pntOfStroke = convert(thickPnt); |
| |
| double d = tdistance(pntOfStroke, m_center); |
| |
| return normOfGradientOfWyvillPotential(d, m_radius); |
| } |
| |
| |
| |
| double TPointDeformation::getCPCountInRange(double s0, double s1) const { |
| if (s1 < s0) swap(s1, s0); |
| |
| double step = (s1 - s0) * 0.1; |
| |
| double cpCount = 0.0; |
| |
| for (double s = s0; s < s1; s += step) cpCount += getCPDensity(s); |
| |
| cpCount += getCPDensity(s1); |
| |
| return cpCount; |
| } |
| |
| |
| |
| double TPointDeformation::getMinCPDensity() const { return 0.3; } |
| |
| |
| |
| |
| |