diff options
-rw-r--r-- | src/corelib/tools/qline.cpp | 11 | ||||
-rw-r--r-- | src/corelib/tools/qline.h | 11 | ||||
-rw-r--r-- | tests/auto/corelib/tools/qline/tst_qline.cpp | 14 |
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)); } |