Reduce memory usage of QQuickPath for simple paths.
For a single segment line path we can get correct results by interpolating across just two points, so there no need to allocate the comparatively large point cache required for more complex paths. This also correct a normally small interpolation error caused by including the terminal point in the number of intervals. Change-Id: I564c3c012b6822831251276951603fca8544a356 Reviewed-by: Michael Brasser <michael.brasser@nokia.com>
This commit is contained in:
parent
a0adcc6480
commit
b50aa539e8
|
@ -455,6 +455,20 @@ static inline QBezier nextBezier(const QPainterPath &path, int *current, qreal *
|
|||
return QBezier();
|
||||
}
|
||||
|
||||
static inline int segmentCount(const QPainterPath &path, qreal pathLength)
|
||||
{
|
||||
// In the really simple case of a single straight line we can interpolate without jitter
|
||||
// between just two points.
|
||||
if (path.elementCount() == 2
|
||||
&& path.elementAt(0).type == QPainterPath::MoveToElement
|
||||
&& path.elementAt(1).type == QPainterPath::LineToElement) {
|
||||
return 1;
|
||||
}
|
||||
// more points means less jitter between items as they move along the
|
||||
// path, but takes longer to generate
|
||||
return qCeil(pathLength*5);
|
||||
}
|
||||
|
||||
//derivative of the equation
|
||||
static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
|
||||
{
|
||||
|
@ -467,11 +481,10 @@ void QQuickPath::createPointCache() const
|
|||
qreal pathLength = d->pathLength;
|
||||
if (pathLength <= 0 || qIsNaN(pathLength))
|
||||
return;
|
||||
// more points means less jitter between items as they move along the
|
||||
// path, but takes longer to generate
|
||||
const int points = qCeil(pathLength*5);
|
||||
|
||||
const int segments = segmentCount(d->_path, pathLength);
|
||||
const int lastElement = d->_path.elementCount() - 1;
|
||||
d->_pointCache.resize(points+1);
|
||||
d->_pointCache.resize(segments+1);
|
||||
|
||||
int currElement = -1;
|
||||
qreal bezLength = 0;
|
||||
|
@ -484,7 +497,7 @@ void QQuickPath::createPointCache() const
|
|||
qreal prevPercent = 0;
|
||||
qreal prevOrigPercent = 0;
|
||||
for (int ii = 0; ii < d->_attributePoints.count(); ++ii) {
|
||||
qreal percent = qreal(i)/points;
|
||||
qreal percent = qreal(i)/segments;
|
||||
const AttributePoint &point = d->_attributePoints.at(ii);
|
||||
if (percent < point.percent || ii == d->_attributePoints.count() - 1) { //### || is special case for very last item
|
||||
qreal elementPercent = (percent - prevPercent);
|
||||
|
@ -657,12 +670,12 @@ QPointF QQuickPath::pointAt(qreal p) const
|
|||
return QPointF();
|
||||
}
|
||||
|
||||
const int pointCacheSize = d->_pointCache.size();
|
||||
qreal idxf = p*pointCacheSize;
|
||||
const int segmentCount = d->_pointCache.size() - 1;
|
||||
qreal idxf = p*segmentCount;
|
||||
int idx1 = qFloor(idxf);
|
||||
qreal delta = idxf - idx1;
|
||||
if (idx1 >= pointCacheSize)
|
||||
idx1 = pointCacheSize - 1;
|
||||
if (idx1 > segmentCount)
|
||||
idx1 = segmentCount;
|
||||
else if (idx1 < 0)
|
||||
idx1 = 0;
|
||||
|
||||
|
@ -671,8 +684,8 @@ QPointF QQuickPath::pointAt(qreal p) const
|
|||
|
||||
// interpolate between the two points.
|
||||
int idx2 = qCeil(idxf);
|
||||
if (idx2 >= pointCacheSize)
|
||||
idx2 = pointCacheSize - 1;
|
||||
if (idx2 > segmentCount)
|
||||
idx2 = segmentCount;
|
||||
else if (idx2 < 0)
|
||||
idx2 = 0;
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ private slots:
|
|||
void catmullromCurve();
|
||||
void closedCatmullromCurve();
|
||||
void svg();
|
||||
void line();
|
||||
};
|
||||
|
||||
void tst_QuickPath::arc()
|
||||
|
@ -193,6 +194,43 @@ void tst_QuickPath::svg()
|
|||
QCOMPARE(pos, QPointF(1000,300));
|
||||
}
|
||||
|
||||
void tst_QuickPath::line()
|
||||
{
|
||||
QQmlEngine engine;
|
||||
QQmlComponent c1(&engine);
|
||||
c1.setData(
|
||||
"import QtQuick 2.0\n"
|
||||
"Path {\n"
|
||||
"startX: 0; startY: 0\n"
|
||||
"PathLine { x: 100; y: 100 }\n"
|
||||
"}", QUrl());
|
||||
QScopedPointer<QObject> o1(c1.create());
|
||||
QQuickPath *path1 = qobject_cast<QQuickPath *>(o1.data());
|
||||
QVERIFY(path1);
|
||||
|
||||
QQmlComponent c2(&engine);
|
||||
c2.setData(
|
||||
"import QtQuick 2.0\n"
|
||||
"Path {\n"
|
||||
"startX: 0; startY: 0\n"
|
||||
"PathLine { x: 50; y: 50 }\n"
|
||||
"PathLine { x: 100; y: 100 }\n"
|
||||
"}", QUrl());
|
||||
QScopedPointer<QObject> o2(c2.create());
|
||||
QQuickPath *path2 = qobject_cast<QQuickPath *>(o2.data());
|
||||
QVERIFY(path2);
|
||||
|
||||
for (int i = 0; i < 167; ++i) {
|
||||
qreal t = i / 167.0;
|
||||
|
||||
QPointF p1 = path1->pointAt(t);
|
||||
QCOMPARE(p1.x(), p1.y());
|
||||
|
||||
QPointF p2 = path2->pointAt(t);
|
||||
QCOMPARE(p1, p2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QTEST_MAIN(tst_QuickPath)
|
||||
|
||||
|
|
Loading…
Reference in New Issue