1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | #ifndef PATHCOMPARE_H |
29 | #define PATHCOMPARE_H |
30 | |
31 | #include <qmath.h> |
32 | |
33 | namespace QPathCompare { |
34 | |
35 | static const int precision = 8; |
36 | static const qreal epsilon = qPow(x: 0.1, y: precision); |
37 | |
38 | static inline bool fuzzyIsZero(qreal x, qreal relative) |
39 | { |
40 | if (qAbs(t: relative) < epsilon) |
41 | return qAbs(t: x) < epsilon; |
42 | else |
43 | return qAbs(t: x / relative) < epsilon; |
44 | } |
45 | |
46 | static bool fuzzyCompare(const QPointF &a, const QPointF &b) |
47 | { |
48 | const QPointF delta = a - b; |
49 | |
50 | const qreal x = qMax(a: qAbs(t: a.x()), b: qAbs(t: b.x())); |
51 | const qreal y = qMax(a: qAbs(t: a.y()), b: qAbs(t: b.y())); |
52 | |
53 | return fuzzyIsZero(x: delta.x(), relative: x) && fuzzyIsZero(x: delta.y(), relative: y); |
54 | } |
55 | |
56 | static bool isClosed(const QPainterPath &path) |
57 | { |
58 | if (path.elementCount() == 0) |
59 | return false; |
60 | |
61 | QPointF first = path.elementAt(i: 0); |
62 | QPointF last = path.elementAt(i: path.elementCount() - 1); |
63 | |
64 | return fuzzyCompare(a: first, b: last); |
65 | } |
66 | |
67 | // rotation and direction independent path comparison |
68 | // allows paths to be shifted or reversed relative to each other |
69 | static bool comparePaths(const QPainterPath &actual, const QPainterPath &expected) |
70 | { |
71 | const int endActual = isClosed(path: actual) ? actual.elementCount() - 1 : actual.elementCount(); |
72 | const int endExpected = isClosed(path: expected) ? expected.elementCount() - 1 : expected.elementCount(); |
73 | |
74 | if (endActual != endExpected) |
75 | return false; |
76 | |
77 | for (int i = 0; i < endActual; ++i) { |
78 | int k = 0; |
79 | for (k = 0; k < endActual; ++k) { |
80 | int i1 = k; |
81 | int i2 = (i + k) % endActual; |
82 | |
83 | QPointF a = actual.elementAt(i: i1); |
84 | QPointF b = expected.elementAt(i: i2); |
85 | |
86 | if (!fuzzyCompare(a, b)) |
87 | break; |
88 | } |
89 | |
90 | if (k == endActual) |
91 | return true; |
92 | |
93 | for (k = 0; k < endActual; ++k) { |
94 | int i1 = k; |
95 | int i2 = (i + endActual - k) % endActual; |
96 | |
97 | QPointF a = actual.elementAt(i: i1); |
98 | QPointF b = expected.elementAt(i: i2); |
99 | |
100 | if (!fuzzyCompare(a, b)) |
101 | break; |
102 | } |
103 | |
104 | if (k == endActual) |
105 | return true; |
106 | } |
107 | |
108 | return false; |
109 | } |
110 | |
111 | } |
112 | |
113 | #endif |
114 | |