summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/tools/qline.cpp39
-rw-r--r--src/corelib/tools/qline.h13
-rw-r--r--tests/auto/corelib/tools/qline/tst_qline.cpp58
3 files changed, 63 insertions, 47 deletions
diff --git a/src/corelib/tools/qline.cpp b/src/corelib/tools/qline.cpp
index d284883dcc..ebcbba0195 100644
--- a/src/corelib/tools/qline.cpp
+++ b/src/corelib/tools/qline.cpp
@@ -38,8 +38,10 @@
****************************************************************************/
#include "qline.h"
+
#include "qdebug.h"
#include "qdatastream.h"
+#include "qmath.h"
#include <private/qnumeric_p.h>
QT_BEGIN_NAMESPACE
@@ -98,7 +100,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn bool QLine::isNull() const
- Returns \c true if the line is not set up with valid start and end point;
+ Returns \c true if the line does not have distinct start and end points;
otherwise returns \c false.
*/
@@ -427,8 +429,14 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
/*!
\fn bool QLineF::isNull() const
- Returns \c true if the line is not set up with valid start and end point;
- otherwise returns \c false.
+ Returns \c true if the line does not have distinct start and end points;
+ otherwise returns \c false. The start and end points are considered distinct
+ if qFuzzyCompare() can distinguish them in at least one coordinate.
+
+ \note Due to the use of fuzzy comparison, isNull() may return \c true for
+ lines whose length() is not zero.
+
+ \sa qFuzzyCompare(), length()
*/
/*!
@@ -511,10 +519,10 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
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.
- If the line is a null line, the length will remain zero regardless
- of the length specified.
+ 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()
+ \sa length(), isNull(), unitVector()
*/
/*!
@@ -559,13 +567,12 @@ QDataStream &operator>>(QDataStream &stream, QLine &line)
/*!
Returns the length of the line.
- \sa setLength()
+ \sa setLength(), isNull()
*/
qreal QLineF::length() const
{
- qreal x = pt2.x() - pt1.x();
- qreal y = pt2.y() - pt1.y();
- return qSqrt(x*x + y*y);
+ using std::hypot;
+ return hypot(dx(), dy());
}
/*!
@@ -636,16 +643,18 @@ QLineF QLineF::fromPolar(qreal length, qreal angle)
/*!
Returns the unit vector for this line, i.e a line starting at the
- same point as \e this line with a length of 1.0.
+ same point as \e this line with a length of 1.0, provided the line
+ is non-null.
- \sa normalVector()
+ \sa normalVector(), setLength()
*/
QLineF QLineF::unitVector() const
{
- qreal x = pt2.x() - pt1.x();
- qreal y = pt2.y() - pt1.y();
+ qreal x = dx();
+ qreal y = dy();
+ using std::hypot;
+ qreal len = hypot(x, y);
- qreal len = qSqrt(x*x + y*y);
QLineF f(p1(), QPointF(pt1.x() + x/len, pt1.y() + y/len));
#ifndef QT_NO_DEBUG
diff --git a/src/corelib/tools/qline.h b/src/corelib/tools/qline.h
index adef545d86..8d57e09c4a 100644
--- a/src/corelib/tools/qline.h
+++ b/src/corelib/tools/qline.h
@@ -40,8 +40,6 @@
#ifndef QLINE_H
#define QLINE_H
-#include <QtCore/qmath.h>
-
#include <QtCore/qpoint.h>
QT_BEGIN_NAMESPACE
@@ -372,15 +370,14 @@ constexpr inline QPointF QLineF::center() const
return QPointF(0.5 * pt1.x() + 0.5 * pt2.x(), 0.5 * pt1.y() + 0.5 * pt2.y());
}
-QT_WARNING_DISABLE_FLOAT_COMPARE
-
inline void QLineF::setLength(qreal len)
{
- const qreal oldlength = qSqrt(dx() * dx() + dy() * dy());
- if (!oldlength)
+ if (isNull())
return;
- const qreal factor = len / oldlength;
- pt2 = QPointF(pt1.x() + dx() * factor, pt1.y() + dy() * factor);
+ 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());
}
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 7e07e9d1e2..f4ac51fc24 100644
--- a/tests/auto/corelib/tools/qline/tst_qline.cpp
+++ b/tests/auto/corelib/tools/qline/tst_qline.cpp
@@ -40,8 +40,6 @@ private slots:
void testLength();
void testLength_data();
- void testSetLength();
-
void testCenter();
void testCenter_data();
@@ -214,11 +212,13 @@ void tst_QLine::testLength_data()
QTest::addColumn<double>("vx");
QTest::addColumn<double>("vy");
- QTest::newRow("[1,0]*2") << 0.0 << 0.0 << 1.0 << 0.0 << 1.0 << 2.0 << 2.0 << 0.0;
- QTest::newRow("[0,1]*2") << 0.0 << 0.0 << 0.0 << 1.0 << 1.0 << 2.0 << 0.0 << 2.0;
- QTest::newRow("[-1,0]*2") << 0.0 << 0.0 << -1.0 << 0.0 << 1.0 << 2.0 << -2.0 << 0.0;
- QTest::newRow("[0,-1]*2") << 0.0 << 0.0 << 0.0 << -1.0 << 1.0 << 2.0 << 0.0 << -2.0;
- QTest::newRow("[1,1]->|1|") << 0.0 << 0.0 << 1.0 << 1.0
+ // Test name: [dx,dy]->|lenToSet| (x1,x2)
+ // with the last part omitted if (0,0)
+ QTest::newRow("[1,0]->|2|") << 0.0 << 0.0 << 1.0 << 0.0 << 1.0 << 2.0 << 2.0 << 0.0;
+ QTest::newRow("[0,1]->|2|") << 0.0 << 0.0 << 0.0 << 1.0 << 1.0 << 2.0 << 0.0 << 2.0;
+ QTest::newRow("[-1,0]->|2|") << 0.0 << 0.0 << -1.0 << 0.0 << 1.0 << 2.0 << -2.0 << 0.0;
+ QTest::newRow("[0,-1]->|2|") << 0.0 << 0.0 << 0.0 << -1.0 << 1.0 << 2.0 << 0.0 << -2.0;
+ QTest::newRow("[1,1]->->|1|") << 0.0 << 0.0 << 1.0 << 1.0
<< M_SQRT2 << 1.0 << M_SQRT1_2 << M_SQRT1_2;
QTest::newRow("[-1,1]->|1|") << 0.0 << 0.0 << -1.0 << 1.0
<< M_SQRT2 << 1.0 << -M_SQRT1_2 << M_SQRT1_2;
@@ -226,10 +226,10 @@ void tst_QLine::testLength_data()
<< M_SQRT2 << 1.0 << M_SQRT1_2 << -M_SQRT1_2;
QTest::newRow("[-1,-1]->|1|") << 0.0 << 0.0 << -1.0 << -1.0
<< M_SQRT2 << 1.0 << -M_SQRT1_2 << -M_SQRT1_2;
- QTest::newRow("[1,0]*2 (2,2)") << 2.0 << 2.0 << 3.0 << 2.0 << 1.0 << 2.0 << 2.0 << 0.0;
- QTest::newRow("[0,1]*2 (2,2)") << 2.0 << 2.0 << 2.0 << 3.0 << 1.0 << 2.0 << 0.0 << 2.0;
- QTest::newRow("[-1,0]*2 (2,2)") << 2.0 << 2.0 << 1.0 << 2.0 << 1.0 << 2.0 << -2.0 << 0.0;
- QTest::newRow("[0,-1]*2 (2,2)") << 2.0 << 2.0 << 2.0 << 1.0 << 1.0 << 2.0 << 0.0 << -2.0;
+ QTest::newRow("[1,0]->|2| (2,2)") << 2.0 << 2.0 << 3.0 << 2.0 << 1.0 << 2.0 << 2.0 << 0.0;
+ QTest::newRow("[0,1]->|2| (2,2)") << 2.0 << 2.0 << 2.0 << 3.0 << 1.0 << 2.0 << 0.0 << 2.0;
+ QTest::newRow("[-1,0]->|2| (2,2)") << 2.0 << 2.0 << 1.0 << 2.0 << 1.0 << 2.0 << -2.0 << 0.0;
+ QTest::newRow("[0,-1]->|2| (2,2)") << 2.0 << 2.0 << 2.0 << 1.0 << 1.0 << 2.0 << 0.0 << -2.0;
QTest::newRow("[1,1]->|1| (2,2)") << 2.0 << 2.0 << 3.0 << 3.0
<< M_SQRT2 << 1.0 << M_SQRT1_2 << M_SQRT1_2;
QTest::newRow("[-1,1]->|1| (2,2)") << 2.0 << 2.0 << 1.0 << 3.0
@@ -238,6 +238,20 @@ void tst_QLine::testLength_data()
<< M_SQRT2 << 1.0 << M_SQRT1_2 << -M_SQRT1_2;
QTest::newRow("[-1,-1]->|1| (2,2)") << 2.0 << 2.0 << 1.0 << 1.0
<< M_SQRT2 << 1.0 << -M_SQRT1_2 << -M_SQRT1_2;
+ const double small = qSqrt(std::numeric_limits<qreal>::denorm_min()) / 8;
+ QTest::newRow("[small,small]->|2| (-small/2,-small/2)")
+ << -(small * .5) << -(small * .5) << (small * .5) << (small * .5)
+ << (small * M_SQRT2) << (2 * M_SQRT2) << 2.0 << 2.0;
+ const double tiny = std::numeric_limits<qreal>::min() / 2;
+ QTest::newRow("[tiny,tiny]->|2| (-tiny/2,-tiny/2)")
+ << -(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;
+ 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
}
void tst_QLine::testLength()
@@ -252,21 +266,17 @@ void tst_QLine::testLength()
QFETCH(double, vy);
QLineF l(x1, y1, x2, y2);
- QCOMPARE(l.length(), qreal(length));
+ const bool wasNull = l.isNull();
+ if (!wasNull)
+ QCOMPARE(l.length(), qreal(length));
l.setLength(lengthToSet);
- QCOMPARE(l.length(), qreal(lengthToSet));
- QCOMPARE(l.dx(), qreal(vx));
- QCOMPARE(l.dy(), qreal(vy));
-}
-
-void tst_QLine::testSetLength()
-{
- QLineF l(0, 0, 4e-323, 5e-324);
- const qreal newLength = 1892;
- const qreal oldLength = l.length();
- l.setLength(newLength);
- QCOMPARE(l.length(), oldLength ? newLength : 0);
+ 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)) {
+ QCOMPARE(l.dx(), qreal(vx));
+ QCOMPARE(l.dy(), qreal(vy));
+ }
}
void tst_QLine::testCenter()