- UBGraphicsScene calls UBGraphicsStroke::addPoint, which returns a list of points that can be drawn. It may be none (e.g we discard very small segments), one (if we do no interpolation) or several. - Added a UBInterpolator base, abstract class. Various interpolation methods can be added easily. - Current methods: Basic spline (custom), Catmull-Rom spline (based on alglib), and Bézier - Added a setting to toggle interpolation. Added this to the UI as wellpreferencesAboutTextFull
parent
fb6bc855e9
commit
4491341a4d
@ -0,0 +1,139 @@ |
|||||||
|
#include "UBInterpolator.h" |
||||||
|
|
||||||
|
UBInterpolator::UBInterpolator() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
UBInterpolator::~UBInterpolator() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
UBSimpleSpline::UBSimpleSpline() |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void UBSimpleSpline::setPoints(QList<QPointF> points) |
||||||
|
{ |
||||||
|
setPoints(points[0], points[1], points[2]); |
||||||
|
} |
||||||
|
|
||||||
|
void UBSimpleSpline::setPoints(QPointF p0, QPointF p1, QPointF p2) |
||||||
|
{ |
||||||
|
/*
|
||||||
|
p0 -= p0; |
||||||
|
p1 -= p0; |
||||||
|
p2 -= p0; |
||||||
|
*/ |
||||||
|
long double x0, x1, x2, y0, y1, y2; |
||||||
|
x0 = p0.x(); |
||||||
|
x1 = p1.x(); |
||||||
|
x2 = p2.x(); |
||||||
|
y0 = p0.y(); |
||||||
|
y1 = p1.y(); |
||||||
|
y2 = p2.y(); |
||||||
|
|
||||||
|
long double k1 = (y2-y0)/(x2-x0); |
||||||
|
|
||||||
|
m_a = (y1-y2-k1*(x1-x2))/(pow(x1,3) - pow(x2,3) - 3*x2*(pow(x1,2)-pow(x2,2)) - |
||||||
|
3*(pow(x1,2) - 2*x1*x2)*(x1-x2)); |
||||||
|
|
||||||
|
m_b = -3*m_a*x2; |
||||||
|
m_c = k1 - 3*m_a*pow(x1,2) - 2*m_b*x1; |
||||||
|
m_d = y1 - m_a*pow(x1,3) - m_b*pow(x1,2) - m_c*x1; |
||||||
|
} |
||||||
|
|
||||||
|
double UBSimpleSpline::y(double x) |
||||||
|
{ |
||||||
|
return m_a*pow(x, 3) + m_b*pow(x, 2) + m_c*x + m_d; |
||||||
|
} |
||||||
|
|
||||||
|
UBCatmullRomSpline::UBCatmullRomSpline() |
||||||
|
{ |
||||||
|
mInterpolant = 0; |
||||||
|
} |
||||||
|
|
||||||
|
UBCatmullRomSpline::~UBCatmullRomSpline() |
||||||
|
{ |
||||||
|
if (mInterpolant) |
||||||
|
delete mInterpolant; |
||||||
|
} |
||||||
|
|
||||||
|
void UBCatmullRomSpline::setPoints(QList<QPointF> points) |
||||||
|
{ |
||||||
|
// todo : basis change to avoid crashing when several X's are equal
|
||||||
|
mInterpolant = new alglib::spline1dinterpolant(); |
||||||
|
|
||||||
|
// alglib arrays are defined as strings
|
||||||
|
QString x = "["; |
||||||
|
QString y = "["; |
||||||
|
|
||||||
|
foreach(QPointF point, points) { |
||||||
|
x += (QString::number(point.x()) + QString(",")); |
||||||
|
y += (QString::number(point.y()) + QString(",")); |
||||||
|
} |
||||||
|
|
||||||
|
x.chop(1); |
||||||
|
y.chop(1); |
||||||
|
|
||||||
|
x+="]"; |
||||||
|
y+="]"; |
||||||
|
|
||||||
|
alglib::real_1d_array xArray = x.toLatin1().data(); |
||||||
|
alglib::real_1d_array yArray = y.toLatin1().data(); |
||||||
|
|
||||||
|
alglib::spline1dbuildcatmullrom(xArray, yArray, *mInterpolant); |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
double UBCatmullRomSpline::y(double x) |
||||||
|
{ |
||||||
|
return alglib::spline1dcalc(*mInterpolant, x); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
UBQuadraticBezier::UBQuadraticBezier() |
||||||
|
{ |
||||||
|
mPath = 0; |
||||||
|
} |
||||||
|
|
||||||
|
UBQuadraticBezier::~UBQuadraticBezier() |
||||||
|
{ |
||||||
|
if (mPath) |
||||||
|
delete mPath; |
||||||
|
} |
||||||
|
|
||||||
|
void UBQuadraticBezier::setPoints(QList<QPointF> points) |
||||||
|
{ |
||||||
|
setPoints(points[0], points[1], points[2]); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void UBQuadraticBezier::setPoints(QPointF start, QPointF control, QPointF end) |
||||||
|
{ |
||||||
|
mPath = new QPainterPath(start); |
||||||
|
mPath->quadTo(control, end); |
||||||
|
} |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return n points along the curve, including start and end points (thus n should be larger than or equal to 2). |
||||||
|
* |
||||||
|
* The higher n, the more accurate the result |
||||||
|
*/ |
||||||
|
QList<QPointF> UBQuadraticBezier::getPoints(int n) |
||||||
|
{ |
||||||
|
QList<QPointF> points; |
||||||
|
|
||||||
|
if (n <= 1) |
||||||
|
return points; |
||||||
|
|
||||||
|
for (int i(0); i <= n; ++i) { |
||||||
|
qreal percent = qreal(i)/qreal(n); |
||||||
|
|
||||||
|
points << mPath->pointAtPercent(percent); |
||||||
|
} |
||||||
|
|
||||||
|
return points; |
||||||
|
} |
@ -0,0 +1,96 @@ |
|||||||
|
#ifndef UBINTERPOLATOR_H |
||||||
|
#define UBINTERPOLATOR_H |
||||||
|
|
||||||
|
#include <QtGui> |
||||||
|
|
||||||
|
#include "spline.h" |
||||||
|
#include "interpolation.h" |
||||||
|
|
||||||
|
class UBInterpolator |
||||||
|
{ |
||||||
|
/* Abstract class representing an interpolator */ |
||||||
|
|
||||||
|
public: |
||||||
|
enum InterpolationMethod { |
||||||
|
NoInterpolation, |
||||||
|
SimpleSpline, |
||||||
|
CatmullRom, |
||||||
|
Bezier |
||||||
|
}; |
||||||
|
|
||||||
|
UBInterpolator(); |
||||||
|
virtual ~UBInterpolator(); |
||||||
|
|
||||||
|
virtual void setPoints(QList<QPointF> points) = 0; |
||||||
|
virtual double y(double x) {} |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
class UBSimpleSpline : public UBInterpolator |
||||||
|
{ |
||||||
|
/* A basic cubic spline interpolator, that requires only three
|
||||||
|
* points to interpolate between the second and third one. |
||||||
|
* To do so, the curvature at p2 is set to 0, so the resulting |
||||||
|
* curve is not very smooth. |
||||||
|
* However, it is better than linear interpolation and requires no |
||||||
|
* "future" points, so it can be used seamlessly during drawing. |
||||||
|
*/ |
||||||
|
|
||||||
|
public: |
||||||
|
UBSimpleSpline(); |
||||||
|
virtual ~UBSimpleSpline() {} |
||||||
|
|
||||||
|
virtual void setPoints(QList<QPointF> points); |
||||||
|
void setPoints(QPointF p0, QPointF p1, QPointF p2); |
||||||
|
|
||||||
|
virtual double y(double x); |
||||||
|
|
||||||
|
private: |
||||||
|
long double m_a, |
||||||
|
m_b, |
||||||
|
m_c, |
||||||
|
m_d; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
class UBCatmullRomSpline : public UBInterpolator |
||||||
|
{ |
||||||
|
/* Catmull-Rom spline, using AlgLib as backend
|
||||||
|
* |
||||||
|
* This requires four points to interpolate between the middle two. |
||||||
|
*/ |
||||||
|
|
||||||
|
public: |
||||||
|
UBCatmullRomSpline(); |
||||||
|
virtual ~UBCatmullRomSpline(); |
||||||
|
|
||||||
|
virtual void setPoints(QList<QPointF> points); |
||||||
|
virtual double y(double x); |
||||||
|
|
||||||
|
private: |
||||||
|
alglib::spline1dinterpolant * mInterpolant; |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
class UBQuadraticBezier : public UBInterpolator |
||||||
|
{ |
||||||
|
|
||||||
|
public: |
||||||
|
UBQuadraticBezier(); |
||||||
|
virtual ~UBQuadraticBezier(); |
||||||
|
|
||||||
|
virtual void setPoints(QList<QPointF> points); |
||||||
|
void setPoints(QPointF start, QPointF control, QPointF end); |
||||||
|
|
||||||
|
//virtual double y(double x);
|
||||||
|
|
||||||
|
QList<QPointF> getPoints(int n); |
||||||
|
|
||||||
|
private: |
||||||
|
|
||||||
|
QPainterPath* mPath; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // UBINTERPOLATOR_H
|
Loading…
Reference in new issue