Skip to content

Commit

Permalink
Huge performance boost with custom Bezier interpolation
Browse files Browse the repository at this point in the history
  • Loading branch information
hrobeers committed May 4, 2013
1 parent 291e758 commit 449713c
Show file tree
Hide file tree
Showing 14 changed files with 127 additions and 41 deletions.
29 changes: 16 additions & 13 deletions src/fineditors/outlineeditor/contourcalculator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,28 +35,29 @@

using namespace fineditors;

ContourCalculator::ContourCalculator(qreal percContourHeight, QPainterPath *outline, QPainterPath *profile,
QPainterPath *thickness, QPainterPath *result, bool fast)
ContourCalculator::ContourCalculator(qreal percContourHeight, EditablePath *outline, EditablePath *profile, EditablePath *thickness, QPainterPath *result, bool fast)
{
_percContourHeight = percContourHeight;
_outline = outline;
_profile = profile;
_thickness = thickness;


_percContourHeight = percContourHeight;
_result = result;

if (fast)
{
_sectionCount = 20;
_resolution = 200;
_tTol = 0.002;
_fTol = 0.01;
_sectionCount = 200;
_resolution = 500;
_tTol = 0.0001;
_fTol = 0.001;
}
else
{
_sectionCount = 150;
_resolution = 400;
_tTol = 0.0001;
_fTol = 0.001;
_sectionCount = 1000;
_resolution = 2000;
_tTol = 0.00001;
_fTol = 0.0001;
}
}

Expand All @@ -67,13 +68,15 @@ void ContourCalculator::run()
qreal thicknessArray[_sectionCount];
sampleThickess(sectionHeightArray, thicknessArray);

// create the pathfunctors
f_yValueAtPercentEPath yOutline(_outline);
f_yValueAtPercentEPath yProfile(_profile);

// find the top of the outline
f_yValueAtPercent yOutline(_outline);
qreal t_top = 0.5; // start value
qreal y_top = hrlib::Brent::local_min(0, 1, _tTol, yOutline, t_top); // glomin isn't finding a correct top

// find dimensions of the profile
f_yValueAtPercent yProfile(_profile);
qreal t_profileTop = 0.3; // start value
qreal y_profileTop = hrlib::Brent::local_min(0, 1, _tTol, yProfile, t_profileTop);
qreal profileLength = _profile->pointAtPercent(1).x();
Expand Down
15 changes: 9 additions & 6 deletions src/fineditors/outlineeditor/contourcalculator.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,31 @@
#define CONTOURCALCULATOR_H

#include "hrlibfwd/qtfwd.h"
#include "patheditorfwd/patheditorfwd.h"

#include <QRunnable>

using namespace patheditor;

namespace fineditors
{
class ContourCalculator : public QRunnable
{
public:
explicit ContourCalculator(qreal percContourHeight, QPainterPath *outline, QPainterPath *profile,
QPainterPath *thickness, QPainterPath *result, bool fast = false);
explicit ContourCalculator(qreal percContourHeight, EditablePath *outline, EditablePath *profile,
EditablePath *thickness, QPainterPath *result, bool fast = false);

virtual void run();

virtual ~ContourCalculator();

private:
private:
enum SplineFunction { bSpline, overhauser };

qreal _percContourHeight;
QPainterPath *_outline;
QPainterPath *_profile;
QPainterPath *_thickness;
EditablePath *_outline;
EditablePath *_profile;
EditablePath *_thickness;
QPainterPath *_result;

int _sectionCount;
Expand Down
31 changes: 27 additions & 4 deletions src/fineditors/outlineeditor/pathfunctors.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,42 @@
#ifndef PATHFUNCTORS_H
#define PATHFUNCTORS_H

#include "hrlib/math/brent.hpp"
#include "hrlibfwd/qtfwd.h"

#include "hrlib/math/brent.hpp"
#include "editablepath.h"

namespace fineditors
{
class f_yValueAtPercent : public hrlib::func_base
class f_yValueAtPercentPPath : public hrlib::func_offset_base
{
private:
QPainterPath *_path;
qreal _offset;

public:
explicit f_yValueAtPercent(QPainterPath *path, qreal offset = 0){
explicit f_yValueAtPercentPPath(QPainterPath *path, qreal offset = 0){
_path = path;
_offset = offset;
}

virtual qreal operator ()(qreal t){
return _path->pointAtPercent(t).y() - _offset;
}

virtual void setOffset(qreal offset){
_offset = offset;
}
};

class f_yValueAtPercentEPath : public hrlib::func_offset_base
{
private:
patheditor::EditablePath *_path;
qreal _offset;

public:
explicit f_yValueAtPercentEPath(patheditor::EditablePath *path, qreal offset = 0){
_path = path;
_offset = offset;
}
Expand All @@ -44,7 +67,7 @@ namespace fineditors
return _path->pointAtPercent(t).y() - _offset;
}

void setOffset(qreal offset){
virtual void setOffset(qreal offset){
_offset = offset;
}
};
Expand Down
26 changes: 15 additions & 11 deletions src/fineditors/outlineeditor/thicknesscontours.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ ThicknessContours::ThicknessContours(QGraphicsItem *parent) :
{
_nextDetailed = false;

_outline = 0;
_profile = 0;
_thickness = 0;

int numOfContours = std::max(_tPool.maxThreadCount(), 3);
qreal increment = qreal(1) / qreal(numOfContours+1);
qreal thickness = 0;
Expand All @@ -49,15 +53,15 @@ ThicknessContours::ThicknessContours(QGraphicsItem *parent) :

void ThicknessContours::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*unused*/, QWidget * /*unused*/)
{
if (!_outline.isNull())
if (_outline != 0)
{
int min = 0;
int max = 255;
int a = 100;
int increment = 0;

painter->setBrush(QColor(min, 0, max, a));
painter->drawPath(*_outline);
painter->drawPath(*(_outline->painterPath()));

calcContours();

Expand All @@ -79,7 +83,7 @@ void ThicknessContours::paint(QPainter *painter, const QStyleOptionGraphicsItem

QRectF ThicknessContours::boundingRect() const
{
if (_outline.isNull())
if (_outline == 0)
{
QRectF retVal;
return retVal;
Expand All @@ -91,20 +95,20 @@ QRectF ThicknessContours::boundingRect() const
void ThicknessContours::onOutlineChange(EditablePath *sender)
{
_fastCalc = !(sender->released());
_outline = sender->painterPath();
_outline = sender;
}

void ThicknessContours::onProfileChange(EditablePath *sender)
{
_fastCalc = !(sender->released());
_profile = sender->painterPath();
_profile = sender;
this->scene()->update(boundingRect());
}

void ThicknessContours::onThicknessChange(EditablePath *sender)
{
_fastCalc = !(sender->released());
_thickness = sender->painterPath();
_thickness = sender;
this->scene()->update(boundingRect());
}

Expand All @@ -119,7 +123,7 @@ void ThicknessContours::calcContours()
QSharedPointer<QPainterPath> path(new QPainterPath());
_contours.append(path);

ContourCalculator calc(thickness, _outline.data(), _profile.data(), _thickness.data(), path.data(), _fastCalc);
ContourCalculator calc(thickness, _outline, _profile, _thickness, path.data(), _fastCalc);
calc.run();
}
#endif
Expand All @@ -129,7 +133,7 @@ void ThicknessContours::calcContours()
QSharedPointer<QPainterPath> path(new QPainterPath());
_contours.append(path);

_tPool.start(new ContourCalculator(thickness, _outline.data(), _profile.data(), _thickness.data(), path.data(), _fastCalc));
_tPool.start(new ContourCalculator(thickness, _outline, _profile, _thickness, path.data(), _fastCalc));
}
_tPool.waitForDone();
#endif
Expand All @@ -138,13 +142,13 @@ void ThicknessContours::calcContours()

bool ThicknessContours::profilesSet()
{
if (_outline.isNull())
if (_outline == 0)
return false;

if (_profile.isNull())
if (_profile == 0)
return false;

if (_thickness.isNull())
if (_thickness == 0)
return false;

return true;
Expand Down
6 changes: 3 additions & 3 deletions src/fineditors/outlineeditor/thicknesscontours.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ namespace fineditors
bool _fastCalc;
QThreadPool _tPool;

QSharedPointer<QPainterPath> _outline;
QSharedPointer<QPainterPath> _profile;
QSharedPointer<QPainterPath> _thickness;
EditablePath* _outline;
EditablePath* _profile;
EditablePath* _thickness;

QList<qreal> _contourThicknesses;
QList<QSharedPointer<QPainterPath> > _contours;
Expand Down
6 changes: 6 additions & 0 deletions src/hrlib/math/brent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ class func_base{
virtual qreal operator() (qreal) = 0;
};

class func_offset_base : public func_base{
public:
virtual qreal operator() (qreal) = 0;
virtual void setOffset(qreal offset) = 0;
};

class monicPoly : public func_base {
public:
std::vector<qreal> coeff;
Expand Down
16 changes: 16 additions & 0 deletions src/patheditor/cubicbezier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,22 @@ QList<QSharedPointer<ControlPoint> > CubicBezier::controlPoints()
return _controlPoints;
}

QPointF CubicBezier::pointAtPercent(qreal t)
{
// X(t) = (1-t)^3 * X0 + 3*(1-t)^2 * t * X1 + 3*(1-t) * t^2 * X2 + t^3 * X3

qreal oneMt = 1-t;
qreal tSq = t*t;
qreal tCu = tSq * t;

qreal xAtPercent = (oneMt*oneMt*oneMt) * startPoint()->x() + 3 * (oneMt*oneMt) * t * _cPoint1->x() +
3 * oneMt * tSq * _cPoint2->x() + tCu * endPoint()->x();
qreal yAtPercent = (oneMt*oneMt*oneMt) * startPoint()->y() + 3 * (oneMt*oneMt) * t * _cPoint1->y() +
3 * oneMt * tSq * _cPoint2->y() + tCu * endPoint()->y();

return QPointF(xAtPercent, yAtPercent);
}

QRectF CubicBezier::boundingRect() const
{
return _boundingRect;
Expand Down
1 change: 1 addition & 0 deletions src/patheditor/cubicbezier.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ namespace patheditor

// implementing PathItem
QList<QSharedPointer<ControlPoint> > controlPoints();
virtual QPointF pointAtPercent(qreal t);

// Implementing QGraphicsItem
QRectF boundingRect() const;
Expand Down
17 changes: 17 additions & 0 deletions src/patheditor/editablepath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,23 @@ QSharedPointer<QPainterPath> EditablePath::painterPath()
return _painterPath;
}

QPointF EditablePath::pointAtPercent(qreal t)
{
int pathItemCount = _pathItemList.count();
qreal itemRange = 1/qreal(pathItemCount);

int item = 0;
while (t > itemRange)
{
t -= itemRange;
item++;
}

t = t/itemRange;

return _pathItemList[item]->pointAtPercent(t);
}

bool EditablePath::released()
{
return _released;
Expand Down
6 changes: 4 additions & 2 deletions src/patheditor/editablepath.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

#include "patheditorfwd/patheditorfwd.h"

#include <QLinkedList>
#include <QList>
#include "pathitem.h"
#include "pathsettings.h"

Expand Down Expand Up @@ -58,6 +58,8 @@ namespace patheditor
*/
QSharedPointer<QPainterPath> painterPath();

QPointF pointAtPercent(qreal t);

bool released();

virtual ~EditablePath() {}
Expand All @@ -77,7 +79,7 @@ namespace patheditor

QSharedPointer<QPainterPath> _painterPath;

QLinkedList<QSharedPointer<PathItem> > _pathItemList;
QList<QSharedPointer<PathItem> > _pathItemList;

void connectPoints(PathItem *pathItem);
};
Expand Down
5 changes: 5 additions & 0 deletions src/patheditor/line.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ QList<QSharedPointer<ControlPoint> > Line::controlPoints()
return _controlPoints;
}

QPointF Line::pointAtPercent(qreal t)
{
return (*endPoint() - *startPoint()) * t + *startPoint();
}

QRectF Line::boundingRect() const
{
return _boundingRect;
Expand Down
1 change: 1 addition & 0 deletions src/patheditor/line.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace patheditor

// implementing PathItem
QList<QSharedPointer<ControlPoint> > controlPoints();
virtual QPointF pointAtPercent(qreal t);

// Implementing QGraphicsItem
QRectF boundingRect() const;
Expand Down
5 changes: 5 additions & 0 deletions src/patheditor/pathitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ namespace patheditor
virtual void paintPathItem(PathSettings *settings, QPainterPath *totalPainterPath, QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget) = 0;

//
// Custom path calculation (preferably faster than using QPainterPath)
//
virtual QPointF pointAtPercent(qreal t) = 0;

virtual ~PathItem() {}

private:
Expand Down
4 changes: 2 additions & 2 deletions src/version_autogen.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#ifndef VERSION_AUTOGEN_H
#define VERSION_AUTOGEN_H

#define BUILD_NUMBER 127
#define COMMIT_HASH "a95010d24e94c042a23e6a2f7710803e46e0ed9e"
#define BUILD_NUMBER 128
#define COMMIT_HASH "291e758411fa0f67fa164f35af0e0a027dc32338"

#endif // VERSION_AUTOGEN_H

0 comments on commit 449713c

Please sign in to comment.