Optimize Bezier curve shape approximation

Using CubicBezier::pointAtPercent instead of
QPainterPath::pointAtPercent makes layout about 25% faster in some
cases.
This commit is contained in:
Dmitri Ovodok 2019-02-12 12:20:19 +03:00
parent f78dbf0876
commit c9c1f03a2f
3 changed files with 31 additions and 10 deletions

View file

@ -311,17 +311,13 @@ void SlurSegment::computeBezier(QPointF p6o)
ups(Grip::DRAG).p = t.map(p5);
ups(Grip::SHOULDER).p = t.map(p6);
QPainterPath p;
p.moveTo(QPointF());
p.cubicTo(p3 + p3o, p4 + p4o, p2);
p = t.map(p);
_shape.clear();
QPointF start = pp1;
int nbShapes = 32; // (pp2.x() - pp1.x()) / _spatium;
qreal minH = qAbs(3 * w);
const CubicBezier b(pp1, ups(Grip::BEZIER1).pos(), ups(Grip::BEZIER2).pos(), ups(Grip::END).pos());
for (int i = 1; i <= nbShapes; i++) {
QPointF point = p.pointAtPercent(i/float(nbShapes));
const QPointF point = b.pointAtPercent(i/float(nbShapes));
QRectF re = QRectF(start, point).normalized();
if (re.height() < minH) {
qreal d1 = (minH - re.height()) * .5;

View file

@ -41,9 +41,36 @@ struct UP {
QPointF p; // layout position relative to pos()
QPointF off; // user offset in point units
QPointF pos() const { return p + off; }
bool operator!=(const UP& up) const { return p != up.p || off != up.off; }
};
//---------------------------------------------------------
// CubicBezier
// Helper class to optimize cubic Bezier curve points
// calculation.
//---------------------------------------------------------
class CubicBezier {
QPointF p1;
QPointF p2;
QPointF p3;
QPointF p4;
public:
CubicBezier(QPointF _p1, QPointF _p2, QPointF _p3, QPointF _p4)
: p1(_p1), p2(_p2), p3(_p3), p4(_p4) {}
QPointF pointAtPercent(qreal t) const
{
Q_ASSERT(t >= 0.0 && t <= 1.0);
const qreal r = 1.0 - t;
const QPointF B123 = r * (r*p1 + t*p2) + t * (r*p2 + t*p3);
const QPointF B234 = r * (r*p2 + t*p3) + t * (r*p3 + t*p4);
return r*B123 + t*B234;
}
};
class SlurTie;
//---------------------------------------------------------

View file

@ -305,17 +305,15 @@ void TieSegment::computeBezier(QPointF p6o)
// path.translate(staffOffset);
// shapePath.translate(staffOffset);
QPainterPath p;
p.moveTo(QPointF());
p.cubicTo(p3 + p3o, p4 + p4o, p2);
_shape.clear();
QPointF start;
start = t.map(start);
qreal minH = qAbs(3.0 * w);
int nbShapes = 15;
const CubicBezier b(pp1, ups(Grip::BEZIER1).pos(), ups(Grip::BEZIER2).pos(), ups(Grip::END).pos());
for (int i = 1; i <= nbShapes; i++) {
QPointF point = t.map(p.pointAtPercent(i/float(nbShapes)));
const QPointF point = b.pointAtPercent(i/float(nbShapes));
QRectF re = QRectF(start, point).normalized();
if (re.height() < minH) {
d = (minH - re.height()) * .5;