diff options
author | Samuel Rødal <sroedal@trolltech.com> | 2009-06-17 13:46:19 (GMT) |
---|---|---|
committer | Samuel Rødal <sroedal@trolltech.com> | 2009-06-17 14:29:42 (GMT) |
commit | c65262cf3e3cd9c72184582306e550f686b2f27e (patch) | |
tree | 7e5857a1abf3b3378416810f90c94fc9509b8af8 | |
parent | e3736c5031b941a665952a9696d989d79b25f32f (diff) | |
download | Qt-c65262cf3e3cd9c72184582306e550f686b2f27e.zip Qt-c65262cf3e3cd9c72184582306e550f686b2f27e.tar.gz Qt-c65262cf3e3cd9c72184582306e550f686b2f27e.tar.bz2 |
Fixed bugs in QPainterPath::united().
Change from a relative to an absolute fuzzy compare as was the case
pre-4.4. With a relative fuzzy compare points that have an x or y
coordinate of 0 will never be merged with points that are very close to
0, for example (1e-15, 0).
Task-number: 251909
Reviewed-by: Trond
-rw-r--r-- | src/gui/painting/qpathclipper.cpp | 69 | ||||
-rw-r--r-- | tests/auto/qpathclipper/tst_qpathclipper.cpp | 20 |
2 files changed, 62 insertions, 27 deletions
diff --git a/src/gui/painting/qpathclipper.cpp b/src/gui/painting/qpathclipper.cpp index 544b838..d4c92cc 100644 --- a/src/gui/painting/qpathclipper.cpp +++ b/src/gui/painting/qpathclipper.cpp @@ -45,9 +45,6 @@ #include <private/qdatabuffer_p.h> #include <qmath.h> -#include <QImage> -#include <QPainter> - /** The algorithm is as follows: @@ -68,6 +65,20 @@ QT_BEGIN_NAMESPACE +static inline bool fuzzyIsNull(qreal d) +{ + if (sizeof(qreal) == sizeof(double)) + return qAbs(d) <= 1e-12; + else + return qAbs(d) <= 1e-5f; +} + +static inline bool comparePoints(const QPointF &a, const QPointF &b) +{ + return fuzzyIsNull(a.x() - b.x()) + && fuzzyIsNull(a.y() - b.y()); +} + //#define QDEBUG_CLIPPER static qreal dot(const QPointF &a, const QPointF &b) { @@ -105,8 +116,10 @@ private: bool QIntersectionFinder::beziersIntersect(const QBezier &one, const QBezier &two) const { - return (one.pt1() == two.pt1() && one.pt2() == two.pt2() && one.pt3() == two.pt3() && one.pt4() == two.pt4()) - || (one.pt1() == two.pt4() && one.pt2() == two.pt3() && one.pt3() == two.pt2() && one.pt4() == two.pt1()) + return (comparePoints(one.pt1(), two.pt1()) && comparePoints(one.pt2(), two.pt2()) + && comparePoints(one.pt3(), two.pt3()) && comparePoints(one.pt4(), two.pt4())) + || (comparePoints(one.pt1(), two.pt4()) && comparePoints(one.pt2(), two.pt3()) + && comparePoints(one.pt3(), two.pt2()) && comparePoints(one.pt4(), two.pt1())) || QBezier::findIntersections(one, two, 0); } @@ -118,17 +131,17 @@ bool QIntersectionFinder::linesIntersect(const QLineF &a, const QLineF &b) const const QPointF q1 = b.p1(); const QPointF q2 = b.p2(); - if (p1 == p2 || q1 == q2) + if (comparePoints(p1, p2) || comparePoints(q1, q2)) return false; - const bool p1_equals_q1 = (p1 == q1); - const bool p2_equals_q2 = (p2 == q2); + const bool p1_equals_q1 = comparePoints(p1, q1); + const bool p2_equals_q2 = comparePoints(p2, q2); if (p1_equals_q1 && p2_equals_q2) return true; - const bool p1_equals_q2 = (p1 == q2); - const bool p2_equals_q1 = (p2 == q1); + const bool p1_equals_q2 = comparePoints(p1, q2); + const bool p2_equals_q1 = comparePoints(p2, q1); if (p1_equals_q2 && p2_equals_q1) return true; @@ -184,8 +197,10 @@ bool QIntersectionFinder::linesIntersect(const QLineF &a, const QLineF &b) const void QIntersectionFinder::intersectBeziers(const QBezier &one, const QBezier &two, QVector<QPair<qreal, qreal> > &t, QDataBuffer<QIntersection> &intersections) { - if ((one.pt1() == two.pt1() && one.pt2() == two.pt2() && one.pt3() == two.pt3() && one.pt4() == two.pt4()) - || (one.pt1() == two.pt4() && one.pt2() == two.pt3() && one.pt3() == two.pt2() && one.pt4() == two.pt1())) { + if ((comparePoints(one.pt1(), two.pt1()) && comparePoints(one.pt2(), two.pt2()) + && comparePoints(one.pt3(), two.pt3()) && comparePoints(one.pt4(), two.pt4())) + || (comparePoints(one.pt1(), two.pt4()) && comparePoints(one.pt2(), two.pt3()) + && comparePoints(one.pt3(), two.pt2()) && comparePoints(one.pt4(), two.pt1()))) { return; } @@ -230,17 +245,17 @@ void QIntersectionFinder::intersectLines(const QLineF &a, const QLineF &b, QData const QPointF q1 = b.p1(); const QPointF q2 = b.p2(); - if (p1 == p2 || q1 == q2) + if (comparePoints(p1, p2) || comparePoints(q1, q2)) return; - const bool p1_equals_q1 = (p1 == q1); - const bool p2_equals_q2 = (p2 == q2); + const bool p1_equals_q1 = comparePoints(p1, q1); + const bool p2_equals_q2 = comparePoints(p2, q2); if (p1_equals_q1 && p2_equals_q2) return; - const bool p1_equals_q2 = (p1 == q2); - const bool p2_equals_q1 = (p2 == q1); + const bool p1_equals_q2 = comparePoints(p1, q2); + const bool p2_equals_q1 = comparePoints(p2, q1); if (p1_equals_q2 && p2_equals_q1) return; @@ -624,11 +639,11 @@ public: const qreal pivot = pivotComponents[depth & 1]; const qreal value = pointComponents[depth & 1]; - if (qFuzzyCompare(pivot, value)) { + if (fuzzyIsNull(pivot - value)) { const qreal pivot2 = pivotComponents[(depth + 1) & 1]; const qreal value2 = pointComponents[(depth + 1) & 1]; - if (qFuzzyCompare(pivot2, value2)) { + if (fuzzyIsNull(pivot2 - value2)) { if (node.id < 0) node.id = m_tree->nextId(); @@ -802,15 +817,15 @@ QWingedEdge::TraversalStatus QWingedEdge::next(const QWingedEdge::TraversalStatu static bool isLine(const QBezier &bezier) { - const bool equal_1_2 = bezier.pt1() == bezier.pt2(); - const bool equal_2_3 = bezier.pt2() == bezier.pt3(); - const bool equal_3_4 = bezier.pt3() == bezier.pt4(); + const bool equal_1_2 = comparePoints(bezier.pt1(), bezier.pt2()); + const bool equal_2_3 = comparePoints(bezier.pt2(), bezier.pt3()); + const bool equal_3_4 = comparePoints(bezier.pt3(), bezier.pt4()); // point? if (equal_1_2 && equal_2_3 && equal_3_4) return true; - if (bezier.pt1() == bezier.pt4()) + if (comparePoints(bezier.pt1(), bezier.pt4())) return equal_1_2 || equal_3_4; return (equal_1_2 && equal_3_4) || (equal_1_2 && equal_2_3) || (equal_2_3 && equal_3_4); @@ -844,14 +859,14 @@ void QPathSegments::addPath(const QPainterPath &path) else currentPoint = path.elementAt(i); - if (i > 0 && m_points.at(lastMoveTo) == currentPoint) + if (i > 0 && comparePoints(m_points.at(lastMoveTo), currentPoint)) current = lastMoveTo; else m_points << currentPoint; switch (path.elementAt(i).type) { case QPainterPath::MoveToElement: - if (hasMoveTo && last != lastMoveTo && m_points.at(last) != m_points.at(lastMoveTo)) + if (hasMoveTo && last != lastMoveTo && !comparePoints(m_points.at(last), m_points.at(lastMoveTo))) m_segments << Segment(m_pathId, last, lastMoveTo); hasMoveTo = true; last = lastMoveTo = current; @@ -879,7 +894,7 @@ void QPathSegments::addPath(const QPainterPath &path) } } - if (hasMoveTo && last != lastMoveTo && m_points.at(last) != m_points.at(lastMoveTo)) + if (hasMoveTo && last != lastMoveTo && !comparePoints(m_points.at(last), m_points.at(lastMoveTo))) m_segments << Segment(m_pathId, last, lastMoveTo); for (int i = firstSegment; i < m_segments.size(); ++i) { @@ -1357,7 +1372,7 @@ void QWingedEdge::addBezierEdge(const QBezier *bezier, const QPointF &a, const Q if (qFuzzyCompare(alphaA, alphaB)) return; - if (a == b) { + if (comparePoints(a, b)) { int v = insert(a); addBezierEdge(bezier, v, v, alphaA, alphaB, path); diff --git a/tests/auto/qpathclipper/tst_qpathclipper.cpp b/tests/auto/qpathclipper/tst_qpathclipper.cpp index f3077ee..6e6b632 100644 --- a/tests/auto/qpathclipper/tst_qpathclipper.cpp +++ b/tests/auto/qpathclipper/tst_qpathclipper.cpp @@ -93,6 +93,7 @@ private slots: void task204301(); void task209056(); + void task251909(); }; Q_DECLARE_METATYPE(QPainterPath) @@ -1397,6 +1398,25 @@ void tst_QPathClipper::task209056() QVERIFY(p3 != QPainterPath()); } +void tst_QPathClipper::task251909() +{ + QPainterPath p1; + p1.moveTo(0, -10); + p1.lineTo(10, -10); + p1.lineTo(10, 0); + p1.lineTo(0, 0); + + QPainterPath p2; + p2.moveTo(0, 8e-14); + p2.lineTo(10, -8e-14); + p2.lineTo(10, 10); + p2.lineTo(0, 10); + + QPainterPath result = p1.united(p2); + + QVERIFY(result.elementCount() <= 5); +} + QTEST_APPLESS_MAIN(tst_QPathClipper) |