Change QLineF::setLength() to work whenever length() is non-zero

Previously it only worked when isNull() was false, which is true for
very short lines, even though length() may be non-zero.

[ChangeLog][QtCore][QLineF] QLineF::setLength() will now set the
length if the line's length() is non-zero. Previously, it was
documented to only set the length if isNull() was false; this is a
fuzzy check, so isNull() could be true for a line with non-zero
length().

Fixes: QTBUG-89569
Change-Id: I803e622ad09c85815dde25df8dd3ba6dfcba0714
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
(cherry picked from commit 6974737695eae5a41bc8a3f344a4f1f199006f21)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Edward Welbourne 2020-09-08 16:50:13 +02:00 committed by Qt Cherry-pick Bot
parent 636fcc4bb2
commit 28ba7ac178
3 changed files with 18 additions and 18 deletions

View File

@ -517,12 +517,13 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
\fn void QLineF::setLength(qreal length)
Sets the length of the line to the given \a length. QLineF will
move the end point - p2() - of the line to give the line its new length.
move the end point - p2() - of the line to give the line its new
length, unless length() was previously zero, in which case no
scaling is attempted. For lines with very short lengths
(represented by denormal floating-point values), results may be
imprecise.
A null line will not be rescaled. For non-null lines with very short lengths
(represented by denormal floating-point values), results may be imprecise.
\sa length(), isNull(), unitVector()
\sa length(), unitVector()
*/
/*!

View File

@ -372,12 +372,11 @@ constexpr inline QPointF QLineF::center() const
inline void QLineF::setLength(qreal len)
{
if (isNull())
return;
Q_ASSERT(length() > 0);
const QLineF v = unitVector();
len /= v.length(); // In case it's not quite exactly 1.
pt2 = QPointF(pt1.x() + len * v.dx(), pt1.y() + len * v.dy());
const qreal oldLength = length();
// Scale len by dx() / length() and dy() / length(), two O(1) quantities,
// rather than scaling dx() and dy() by len / length(), which might overflow.
if (oldLength > 0)
pt2 = QPointF(pt1.x() + len * (dx() / oldLength), pt1.y() + len * (dy() / oldLength));
}
constexpr inline QPointF QLineF::pointAt(qreal t) const

View File

@ -247,8 +247,8 @@ void tst_QLine::testLength_data()
<< -(tiny * .5) << -(tiny * .5) << (tiny * .5) << (tiny * .5)
<< (tiny * M_SQRT2) << (2 * M_SQRT2) << 2.0 << 2.0;
QTest::newRow("[1+3e-13,1+4e-13]|1895| (1, 1)")
<< 1.0 << 1.0 << (1 + 3e-13) << (1 + 4e-13) // isNull(), so ignores setLength()
<< 5e-13 << 1895.0 << 3e-13 << 4e-13;
<< 1.0 << 1.0 << (1 + 3e-13) << (1 + 4e-13)
<< 5e-13 << 1895.0 << 1137.0 << 1516.0;
QTest::newRow("[4e-323,5e-324]|1892|") // Unavoidable underflow: denormals
<< 0.0 << 0.0 << 4e-323 << 5e-324
<< 4e-323 << 1892.0 << 4e-323 << 5e-324; // vx, vy values ignored
@ -266,14 +266,14 @@ void tst_QLine::testLength()
QFETCH(double, vy);
QLineF l(x1, y1, x2, y2);
const bool wasNull = l.isNull();
if (!wasNull)
QCOMPARE(l.length(), qreal(length));
QCOMPARE(l.length(), qreal(length));
l.setLength(lengthToSet);
QCOMPARE(l.length(), wasNull ? qreal(length) : qreal(lengthToSet));
// Scaling tiny values up to big can be imprecise: don't try to test vx, vy
if (wasNull || !qFuzzyIsNull(length)) {
if (length > 0 && qFuzzyIsNull(length)) {
QVERIFY(l.length() > lengthToSet / 2 && l.length() < lengthToSet * 2);
} else {
QCOMPARE(l.length(), length > 0 ? qreal(lengthToSet) : qreal(length));
QCOMPARE(l.dx(), qreal(vx));
QCOMPARE(l.dy(), qreal(vy));
}