diff --git a/OpenBoard.pro b/OpenBoard.pro index 4558b666..13b005e6 100644 --- a/OpenBoard.pro +++ b/OpenBoard.pro @@ -66,6 +66,9 @@ INCLUDEPATH += src/pdf-merger include(src/pdf-merger/pdfMerger.pri) #ThirdParty +INCLUDEPATH += $$THIRD_PARTY_PATH/spline/ +INCLUDEPATH += $$THIRD_PARTY_PATH/alglib/ +include($$THIRD_PARTY_PATH/alglib/alglib.pri) DEPENDPATH += $$THIRD_PARTY_PATH/quazip/ INCLUDEPATH += $$THIRD_PARTY_PATH/quazip/ include($$THIRD_PARTY_PATH/quazip/quazip.pri) diff --git a/resources/forms/brushProperties.ui b/resources/forms/brushProperties.ui index 19883e90..eea50fba 100644 --- a/resources/forms/brushProperties.ui +++ b/resources/forms/brushProperties.ui @@ -1,7 +1,8 @@ - + + brushProperties - - + + 0 0 @@ -9,25 +10,25 @@ 808 - + - + QFrame::NoFrame - + QFrame::Plain - - - - + + + + Qt::Vertical - + QSizePolicy::Fixed - + 20 40 @@ -35,53 +36,40 @@ - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - - + + + QFrame::NoFrame - + QFrame::Raised - - + + 0 - - + + QFrame::NoFrame - + QFrame::Raised - + - - + + On Light Background - - + + Qt::Horizontal - + 40 20 @@ -90,17 +78,17 @@ - - + + 32 32 - + QFrame::StyledPanel - + QFrame::Raised @@ -109,27 +97,27 @@ - - + + QFrame::NoFrame - + QFrame::Raised - + - - + + On Dark Background - - + + Qt::Horizontal - + 40 20 @@ -138,17 +126,17 @@ - - + + 32 32 - + QFrame::StyledPanel - + QFrame::Raised @@ -159,34 +147,21 @@ - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - - + + + QFrame::NoFrame - + QFrame::Raised - + - - + + Qt::Horizontal - + 154 20 @@ -195,40 +170,40 @@ - - + + Opacity - - + + 20 - + 100 - + 50 - + Qt::Horizontal - + QSlider::TicksAbove - + 20 - - + + Qt::Horizontal - + 156 20 @@ -239,40 +214,27 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - + + + + 0 0 - + Line Width - - - - + + + + Qt::Horizontal - + QSizePolicy::Fixed - + 40 20 @@ -280,15 +242,15 @@ - - - + + + Qt::Horizontal - + QSizePolicy::Fixed - + 40 20 @@ -296,149 +258,149 @@ - - - + + + 5 - + 500 - + 5 - + Qt::Horizontal - + QSlider::TicksAbove - + 100 - - - + + + Medium - - - + + + 5 - + 500 - + Qt::Horizontal - + QSlider::TicksAbove - + 100 - - - + + + Strong - - - + + + 5 - + 500 - + Qt::Horizontal - + QSlider::TicksAbove - + 100 - - - - + + + + 60 60 - + 60 60 - + QFrame::StyledPanel - + QFrame::Raised - - - - + + + + 60 60 - + 60 60 - + QFrame::StyledPanel - + QFrame::Raised - - - - + + + + 60 60 - + 60 60 - + QFrame::StyledPanel - + QFrame::Raised - - - + + + Fine @@ -446,50 +408,85 @@ - - - + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + QFrame::NoFrame - + QFrame::Raised - - + + + 0 + + + 0 + + + 0 + + 0 - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - + + + 0 0 - + Pen is Pressure Sensitive - - + + Qt::Horizontal - + 198 20 @@ -500,6 +497,30 @@ + + + + + + Smooth strokes (experimental) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/src/core/UBPreferencesController.cpp b/src/core/UBPreferencesController.cpp index e2ec529e..56baf2b4 100644 --- a/src/core/UBPreferencesController.cpp +++ b/src/core/UBPreferencesController.cpp @@ -163,6 +163,7 @@ void UBPreferencesController::wire() connect(mPenProperties->mediumSlider, SIGNAL(valueChanged(int)), this, SLOT(widthSliderChanged(int))); connect(mPenProperties->strongSlider, SIGNAL(valueChanged(int)), this, SLOT(widthSliderChanged(int))); connect(mPenProperties->pressureSensitiveCheckBox, SIGNAL(clicked(bool)), settings, SLOT(setPenPressureSensitive(bool))); + connect(mPenProperties->interpolateStrokesCheckBox, SIGNAL(clicked(bool)), settings->boardInterpolatePenStrokes, SLOT(setBool(bool))); // marker QList markerLightBackgroundColors = settings->boardMarkerLightBackgroundColors->colors(); @@ -229,6 +230,7 @@ void UBPreferencesController::init() mPenProperties->mediumSlider->setValue(settings->boardPenMediumWidth->get().toDouble() * sSliderRatio); mPenProperties->strongSlider->setValue(settings->boardPenStrongWidth->get().toDouble() * sSliderRatio); mPenProperties->pressureSensitiveCheckBox->setChecked(settings->boardPenPressureSensitive->get().toBool()); + mPenProperties->interpolateStrokesCheckBox->setChecked(settings->boardInterpolatePenStrokes->get().toBool()); // marker tab mMarkerProperties->fineSlider->setValue(settings->boardMarkerFineWidth->get().toDouble() * sSliderRatio); diff --git a/src/core/UBSettings.cpp b/src/core/UBSettings.cpp index d0dfc237..9a32b48e 100644 --- a/src/core/UBSettings.cpp +++ b/src/core/UBSettings.cpp @@ -267,6 +267,8 @@ void UBSettings::init() boardUseHighResTabletEvent = new UBSetting(this, "Board", "UseHighResTabletEvent", true); + boardInterpolatePenStrokes = new UBSetting(this, "Board", "InterpolatePenStrokes", true); + boardKeyboardPaletteKeyBtnSize = new UBSetting(this, "Board", "KeyboardPaletteKeyBtnSize", "16x16"); ValidateKeyboardPaletteKeyBtnSize(); diff --git a/src/core/UBSettings.h b/src/core/UBSettings.h index b7e0bc08..f4210f19 100644 --- a/src/core/UBSettings.h +++ b/src/core/UBSettings.h @@ -269,6 +269,8 @@ class UBSettings : public QObject UBSetting* boardUseHighResTabletEvent; + UBSetting* boardInterpolatePenStrokes; + UBSetting* boardKeyboardPaletteKeyBtnSize; UBSetting* appStartMode; diff --git a/src/domain/UBGraphicsScene.cpp b/src/domain/UBGraphicsScene.cpp index f4091c21..72eae6a9 100644 --- a/src/domain/UBGraphicsScene.cpp +++ b/src/domain/UBGraphicsScene.cpp @@ -23,6 +23,7 @@ */ +#include #include "UBGraphicsScene.h" @@ -35,6 +36,7 @@ #include "frameworks/UBGeometryUtils.h" #include "frameworks/UBPlatformUtils.h" +#include "frameworks/UBInterpolator.h" #include "core/UBApplication.h" #include "core/UBSettings.h" @@ -430,6 +432,8 @@ bool UBGraphicsScene::inputDevicePress(const QPointF& scenePos, const qreal& pre else { moveTo(scenePos); drawLineTo(scenePos, width, UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Line); + + mCurrentStroke->addPoint(scenePos); } accepted = true; } @@ -537,7 +541,48 @@ bool UBGraphicsScene::inputDeviceMove(const QPointF& scenePos, const qreal& pres dc->mActiveRuler->DrawLine(position, width); } else{ - drawLineTo(position, width, UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Line); + bool showDots = false; + + if (showDots) { + UBGraphicsPolygonItem * p = lineToPolygonItem(QLineF(scenePos, scenePos), width, width); + p->setColor(Qt::red); + this->addItem(p); + } + + UBInterpolator::InterpolationMethod interpolator = UBInterpolator::NoInterpolation; + + if (currentTool == UBStylusTool::Marker) { + // The marker is already super slow due to the transparency, we can't also do interpolation + interpolator = UBInterpolator::NoInterpolation; + } + + else if (UBSettings::settings()->boardInterpolatePenStrokes->get().toBool()) { + interpolator = UBInterpolator::Bezier; + } + + QList newPoints = mCurrentStroke->addPoint(scenePos, interpolator); + int n = newPoints.length(); + int i = 1; + qreal startWidth = mPreviousWidth; + foreach(QPointF point, newPoints) { + + if (showDots) { + if (point != scenePos) { + UBGraphicsPolygonItem * p = lineToPolygonItem(QLineF(point, point), width, width); + p->setColor(Qt::yellow); + this->addItem(p); + } + } + + + // linear interpolation of the end width + qreal endWidth = mPreviousWidth + qreal(i)*(width - mPreviousWidth)/qreal(n); + i++; + + drawLineTo(point, startWidth, endWidth, UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Line); + startWidth = endWidth; + } + //drawLineTo(scenePos, width, UBDrawingController::drawingController()->stylusTool() == UBStylusTool::Line); } } else if (currentTool == UBStylusTool::Eraser) @@ -606,6 +651,30 @@ bool UBGraphicsScene::inputDeviceRelease() mDrawWithCompass = false; } else if (mCurrentStroke){ + /* + // ------------------------------------------------------------------------- + // Replace the stroke by a smoother one + // ------------------------------------------------------------------------- + UBGraphicsStroke* smoothStroke = mCurrentStroke->smoothe(); + + foreach(UBGraphicsPolygonItem* poly, mCurrentStroke->polygons()){ + mPreviousPolygonItems.removeAll(poly); + removeItem(poly); + } + delete mCurrentStroke; + mCurrentStroke = smoothStroke; + + moveTo(smoothStroke->points()[0]); + for (int i(1); i < smoothStroke->points().size(); ++i) { + QPointF currentPoint = smoothStroke->points()[i]; + + drawLineTo(currentPoint, dc->currentToolWidth(), dc->currentToolWidth(), false); + moveTo(currentPoint); + } + + // ------------------------------------------------------------------------- + */ + UBGraphicsStrokesGroup* pStrokes = new UBGraphicsStrokesGroup(); // Remove the strokes that were just drawn here and replace them by a stroke item @@ -771,15 +840,24 @@ void UBGraphicsScene::moveTo(const QPointF &pPoint) mArcPolygonItem = 0; mDrawWithCompass = false; } - void UBGraphicsScene::drawLineTo(const QPointF &pEndPoint, const qreal &pWidth, bool bLineStyle) +{ + drawLineTo(pEndPoint, pWidth, pWidth, bLineStyle); + +} + +void UBGraphicsScene::drawLineTo(const QPointF &pEndPoint, const qreal &startWidth, const qreal &endWidth, bool bLineStyle) { if (mPreviousWidth == -1.0) - mPreviousWidth = pWidth; + mPreviousWidth = startWidth; + + qreal initialWidth = startWidth; + if (initialWidth == endWidth) + initialWidth = mPreviousWidth; // UBGraphicsPolygonItem *polygonItem = lineToPolygonItem(QLineF(mPreviousPoint, pEndPoint), pWidth); - UBGraphicsPolygonItem *polygonItem = lineToPolygonItem(QLineF(mPreviousPoint, pEndPoint), mPreviousWidth,pWidth); + UBGraphicsPolygonItem *polygonItem = lineToPolygonItem(QLineF(mPreviousPoint, pEndPoint), initialWidth, endWidth); if (!polygonItem->brush().isOpaque()) { @@ -822,7 +900,7 @@ void UBGraphicsScene::drawLineTo(const QPointF &pEndPoint, const qreal &pWidth, if (!bLineStyle) { mPreviousPoint = pEndPoint; - mPreviousWidth = pWidth; + mPreviousWidth = endWidth; } } diff --git a/src/domain/UBGraphicsScene.h b/src/domain/UBGraphicsScene.h index b040cf2e..19571d62 100644 --- a/src/domain/UBGraphicsScene.h +++ b/src/domain/UBGraphicsScene.h @@ -191,6 +191,7 @@ class UBGraphicsScene: public UBCoreGraphicsScene, public UBItem void moveTo(const QPointF& pPoint); void drawLineTo(const QPointF& pEndPoint, const qreal& pWidth, bool bLineStyle); + void drawLineTo(const QPointF& pEndPoint, const qreal& pStartWidth, const qreal& endWidth, bool bLineStyle); void eraseLineTo(const QPointF& pEndPoint, const qreal& pWidth); void drawArcTo(const QPointF& pCenterPoint, qreal pSpanAngle); diff --git a/src/domain/UBGraphicsStroke.cpp b/src/domain/UBGraphicsStroke.cpp index f6954b47..9208315c 100644 --- a/src/domain/UBGraphicsStroke.cpp +++ b/src/domain/UBGraphicsStroke.cpp @@ -31,6 +31,7 @@ #include "core/memcheck.h" + UBGraphicsStroke::UBGraphicsStroke() { // NOOP @@ -61,6 +62,129 @@ QList UBGraphicsStroke::polygons() const return mPolygons; } +/** + * @brief Add a point to the curve, interpolating extra points if required + * @return The points (or point, if none were interpolated) that were added + */ +QList UBGraphicsStroke::addPoint(const QPointF& point, UBInterpolator::InterpolationMethod interpolationMethod) +{ + int n = mDrawnPoints.size(); + + /* + if (n > 0) { + qreal MIN_DISTANCE = 3; + QPointF lastPoint = mDrawnPoints.last(); + qreal distance = QLineF(lastPoint, point).length(); + + //qDebug() << "distance: " << distance; + + if (distance < MIN_DISTANCE) + return QList(); + } + */ + + if (interpolationMethod == UBInterpolator::NoInterpolation || n == 0) { + mDrawnPoints << point; + mAllPoints << point; + return QList() << point; + } + + else if (interpolationMethod == UBInterpolator::Bezier) { + // This is a bit special, as the curve we are interpolating is not between two drawn points; + // it is between the midway points of the second-to-last and last point, and last and current point. + qreal MIN_DISTANCE = 3; + QPointF lastPoint = mDrawnPoints.last(); + qreal distance = QLineF(lastPoint, point).length(); + + //qDebug() << "distance: " << distance; + + if (distance < MIN_DISTANCE) + return QList(); + if (n == 1) { + // We start with a straight line to the first midway point + QPointF lastPoint = mDrawnPoints[0]; + mDrawnPoints << point; + + return QList() << ((lastPoint + point)/2.0); + } + + QPointF p0 = mDrawnPoints[mDrawnPoints.size() - 2]; + QPointF p1 = mDrawnPoints[mDrawnPoints.size() - 1]; + QPointF p2 = point; + + UBQuadraticBezier bz; + + QPointF startPoint = (p1+p0)/2.0; + QPointF endPoint = (p2+p1)/2.0; + + bz.setPoints(startPoint, p1, endPoint); + + QList newPoints = bz.getPoints(7); + + foreach(QPointF p, newPoints) { + mAllPoints << p; + } + + mDrawnPoints << point; + return newPoints; + + + } + + else { + + qreal MIN_INTERPOLATION_DISTANCE = 0; + + QPointF lastPoint; + if (!mDrawnPoints.isEmpty()) + lastPoint = mDrawnPoints.last(); + + QList newPoints; + + // Interpolation + if (n > 3 && QLineF(lastPoint, point).length() > MIN_INTERPOLATION_DISTANCE) { + + /* + UBSimpleSpline sp; + sp.setPoints(mDrawnPoints[n-2], mDrawnPoints[n-1], point); + */ + + // todo: better way of avoiding problems with constant x's. in the meantime this'll do. + qreal x0 = mDrawnPoints[n-3].x(); + qreal x1 = mDrawnPoints[n-2].x(); + qreal x2 = mDrawnPoints[n-1].x(); + qreal x3 = point.x(); + if (!(x0 == x1 || x0 == x2 || x0 == x3 || x1 == x2 || x1 == x3 || x2 == x3)) { + + UBCatmullRomSpline sp; + sp.setPoints(QList() << mDrawnPoints[n-3] << mDrawnPoints[n-2] << mDrawnPoints[n-1] << point); + + // get an extra 3 values in between the current point and last one + int n_points = 3; // number of points to interpolate + double interval = (point.x() - lastPoint.x())/double(n_points+1); + + qDebug() << "Interpolating between: " << lastPoint << " and " << point; + + for (int i(1); i <= n_points; ++i) { + double x = lastPoint.x() + i*interval; + QPointF newPoint(x, sp.y(x)); + qDebug() << newPoint; + + newPoints << newPoint; + mAllPoints << newPoint; + //qDebug() << "Got new point: " << newPoint; + } + } + + } + + newPoints << point; + mAllPoints << point; + mDrawnPoints << point; + + return newPoints; + } +} bool UBGraphicsStroke::hasPressure() { @@ -105,3 +229,50 @@ void UBGraphicsStroke::clear() } } + +/** + * @brief Smoothe the curve, by interpolating extra points where needed. + * + * @return A new stroke based on the current one. + */ +UBGraphicsStroke* UBGraphicsStroke::smoothe() +{ + // Catmull-Rom spline interpolation + UBCatmullRomSpline sp; + + UBGraphicsStroke * smoothStroke = new UBGraphicsStroke(); + + smoothStroke->mAllPoints << mAllPoints[0]; + + for (int i(0); i < mAllPoints.size() - 3; ++i) { + QPointF p1, p2; + + p1 = mAllPoints[i+1]; + p2 = mAllPoints[i+2]; + + qreal x0 = mAllPoints[i].x(); + qreal x1 = p1.x(); + qreal x2 = p2.x(); + qreal x3 = mAllPoints[i+3].x(); + + if (!(x0 == x1 || x0 == x2 || x0 == x3 || x1 == x2 || x1 == x3 || x2 == x3)) { + sp.setPoints(QList() << mAllPoints[i] << mAllPoints[i+1] << mAllPoints[i+2] << mAllPoints[i+3]); + + smoothStroke->mAllPoints << mAllPoints[i+1]; + int n_points = 3; // number of points to interpolate + double interval = (p2.x() - p1.x())/double(n_points+1); + + for (int i(1); i <= n_points; ++i) { + double x = p1.x() + i*interval; + QPointF newPoint(x, sp.y(x)); + + smoothStroke->mAllPoints << newPoint; + } + } + + } + smoothStroke->mAllPoints << mAllPoints[mAllPoints.size() - 2] << mAllPoints[mAllPoints.size() - 1]; + + + return smoothStroke; +} diff --git a/src/domain/UBGraphicsStroke.h b/src/domain/UBGraphicsStroke.h index d7f8852d..2f9b2759 100644 --- a/src/domain/UBGraphicsStroke.h +++ b/src/domain/UBGraphicsStroke.h @@ -31,6 +31,8 @@ #include #include "core/UB.h" +#include "frameworks/UBInterpolator.h" + class UBGraphicsPolygonItem; @@ -55,6 +57,12 @@ class UBGraphicsStroke void clear(); + QList addPoint(const QPointF& point, UBInterpolator::InterpolationMethod interpolationMethod = UBInterpolator::NoInterpolation); + + UBGraphicsStroke* smoothe(); + + const QList& points() { return mAllPoints; } + protected: void addPolygon(UBGraphicsPolygonItem* pol); @@ -62,6 +70,9 @@ class UBGraphicsStroke QList mPolygons; + QList mDrawnPoints; + QList mAllPoints; + }; #endif /* UBGRAPHICSSTROKE_H_ */ diff --git a/src/frameworks/UBInterpolator.cpp b/src/frameworks/UBInterpolator.cpp new file mode 100644 index 00000000..bd40b038 --- /dev/null +++ b/src/frameworks/UBInterpolator.cpp @@ -0,0 +1,139 @@ +#include "UBInterpolator.h" + +UBInterpolator::UBInterpolator() +{ +} + +UBInterpolator::~UBInterpolator() +{ +} + + +UBSimpleSpline::UBSimpleSpline() +{ + +} + +void UBSimpleSpline::setPoints(QList 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 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 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 UBQuadraticBezier::getPoints(int n) +{ + QList 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; +} diff --git a/src/frameworks/UBInterpolator.h b/src/frameworks/UBInterpolator.h new file mode 100644 index 00000000..1a028523 --- /dev/null +++ b/src/frameworks/UBInterpolator.h @@ -0,0 +1,96 @@ +#ifndef UBINTERPOLATOR_H +#define UBINTERPOLATOR_H + +#include + +#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 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 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 points); + virtual double y(double x); + +private: + alglib::spline1dinterpolant * mInterpolant; + +}; + + +class UBQuadraticBezier : public UBInterpolator +{ + +public: + UBQuadraticBezier(); + virtual ~UBQuadraticBezier(); + + virtual void setPoints(QList points); + void setPoints(QPointF start, QPointF control, QPointF end); + + //virtual double y(double x); + + QList getPoints(int n); + +private: + + QPainterPath* mPath; +}; + +#endif // UBINTERPOLATOR_H diff --git a/src/frameworks/frameworks.pri b/src/frameworks/frameworks.pri index 74d6edbb..8d6d435d 100644 --- a/src/frameworks/frameworks.pri +++ b/src/frameworks/frameworks.pri @@ -6,7 +6,8 @@ HEADERS += src/frameworks/UBGeometryUtils.h \ src/frameworks/UBVersion.h \ src/frameworks/UBCoreGraphicsScene.h \ src/frameworks/UBCryptoUtils.h \ - src/frameworks/UBBase32.h + src/frameworks/UBBase32.h \ + $$PWD/UBInterpolator.h SOURCES += src/frameworks/UBGeometryUtils.cpp \ src/frameworks/UBPlatformUtils.cpp \ @@ -15,7 +16,8 @@ SOURCES += src/frameworks/UBGeometryUtils.cpp \ src/frameworks/UBVersion.cpp \ src/frameworks/UBCoreGraphicsScene.cpp \ src/frameworks/UBCryptoUtils.cpp \ - src/frameworks/UBBase32.cpp + src/frameworks/UBBase32.cpp \ + $$PWD/UBInterpolator.cpp win32 {