summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/tools/qline.cpp11
-rw-r--r--src/corelib/tools/qline.h11
-rw-r--r--tests/auto/corelib/tools/qline/tst_qline.cpp14
3 files changed, 18 insertions, 18 deletions
diff --git a/src/corelib/tools/qline.cpp b/src/corelib/tools/qline.cpp
index ebcbba0195..1eb645501c 100644
--- a/src/corelib/tools/qline.cpp
+++ b/src/corelib/tools/qline.cpp
@@ -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()
*/
/*!
diff --git a/src/corelib/tools/qline.h b/src/corelib/tools/qline.h
index 4948559509..9b544f2e7e 100644
--- a/src/corelib/tools/qline.h
+++ b/src/corelib/tools/qline.h
@@ -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
diff --git a/tests/auto/corelib/tools/qline/tst_qline.cpp b/tests/auto/corelib/tools/qline/tst_qline.cpp
index f4ac51fc24..9d5df728a1 100644
--- a/tests/auto/corelib/tools/qline/tst_qline.cpp
+++ b/tests/auto/corelib/tools/qline/tst_qline.cpp
@@ -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));
}