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 | |
29 | #include <QtTest/QtTest> |
30 | #include <QtQml/qqmlengine.h> |
31 | #include <QtQml/qqmlcomponent.h> |
32 | #include <QtQuick/private/qquickpath_p.h> |
33 | |
34 | #include "../../shared/util.h" |
35 | |
36 | class tst_QuickPath : public QQmlDataTest |
37 | { |
38 | Q_OBJECT |
39 | public: |
40 | tst_QuickPath() {} |
41 | |
42 | private slots: |
43 | void arc(); |
44 | void angleArc(); |
45 | void catmullRomCurve(); |
46 | void closedCatmullRomCurve(); |
47 | void svg(); |
48 | void line(); |
49 | |
50 | private: |
51 | void arc(QSizeF scale); |
52 | void angleArc(QSizeF scale); |
53 | void catmullRomCurve(QSizeF scale, const QVector<QPointF> &points); |
54 | void closedCatmullRomCurve(QSizeF scale, const QVector<QPointF> &points); |
55 | void svg(QSizeF scale); |
56 | void line(QSizeF scale); |
57 | }; |
58 | |
59 | static void compare(const QPointF &point, const QSizeF &scale, int line, double x, double y) |
60 | { |
61 | QVERIFY2(qFuzzyCompare(float(point.x()), float(x * scale.width())), |
62 | (QStringLiteral("Actual: " ) + QString::number(point.x(),'g',14) |
63 | + QStringLiteral(" Expected: " ) + QString::number(x * scale.width(),'g',14) |
64 | + QStringLiteral(" At: " ) + QString::number(line)).toLatin1().data()); |
65 | QVERIFY2(qFuzzyCompare(float(point.y()), float(y * scale.height())), |
66 | (QStringLiteral("Actual: " ) + QString::number(point.y(),'g',14) |
67 | + QStringLiteral(" Expected: " ) + QString::number(y * scale.height(),'g',14) |
68 | + QStringLiteral(" At: " ) + QString::number(line)).toLatin1().data()); |
69 | } |
70 | static void compare(const QPointF &point, int line, const QPointF &pt) |
71 | { |
72 | return compare(point, scale: QSizeF(1,1), line, x: pt.x(), y: pt.y()); |
73 | } |
74 | |
75 | void tst_QuickPath::arc(QSizeF scale) |
76 | { |
77 | QQmlEngine engine; |
78 | QQmlComponent c(&engine, testFileUrl(fileName: "arc.qml" )); |
79 | QQuickPath *obj = qobject_cast<QQuickPath*>(object: c.create()); |
80 | QVERIFY(obj != nullptr); |
81 | if (scale != QSizeF(1,1)) |
82 | obj->setProperty(name: "scale" , value: scale); |
83 | |
84 | QCOMPARE(obj->startX(), 0.); |
85 | QCOMPARE(obj->startY(), 0.); |
86 | |
87 | QQmlListReference list(obj, "pathElements" ); |
88 | QCOMPARE(list.count(), 1); |
89 | |
90 | QQuickPathArc* arc = qobject_cast<QQuickPathArc*>(object: list.at(0)); |
91 | QVERIFY(arc != nullptr); |
92 | QCOMPARE(arc->x(), 100.); |
93 | QCOMPARE(arc->y(), 100.); |
94 | QCOMPARE(arc->radiusX(), 100.); |
95 | QCOMPARE(arc->radiusY(), 100.); |
96 | QCOMPARE(arc->useLargeArc(), false); |
97 | QCOMPARE(arc->direction(), QQuickPathArc::Clockwise); |
98 | |
99 | QPainterPath path = obj->path(); |
100 | QVERIFY(path != QPainterPath()); |
101 | |
102 | QPointF pos = obj->pointAtPercent(t: 0); |
103 | QCOMPARE(pos, QPointF(0,0)); |
104 | pos = obj->pointAtPercent(t: .25); |
105 | compare(point: pos, scale, __LINE__, x: 38.9244897744, y: 7.85853964341); |
106 | pos = obj->pointAtPercent(t: .75); |
107 | compare(point: pos, scale, __LINE__, x: 92.141460356592, y: 61.07551022559); |
108 | pos = obj->pointAtPercent(t: 1); |
109 | QCOMPARE(pos, QPointF(100 * scale.width(), 100 * scale.height())); |
110 | } |
111 | |
112 | void tst_QuickPath::arc() |
113 | { |
114 | arc(scale: QSizeF(1,1)); |
115 | arc(scale: QSizeF(2.2,3.4)); |
116 | } |
117 | |
118 | void tst_QuickPath::angleArc(QSizeF scale) |
119 | { |
120 | QQmlEngine engine; |
121 | QQmlComponent c(&engine, testFileUrl(fileName: "anglearc.qml" )); |
122 | QQuickPath *obj = qobject_cast<QQuickPath*>(object: c.create()); |
123 | QVERIFY(obj != nullptr); |
124 | if (scale != QSizeF(1,1)) |
125 | obj->setProperty(name: "scale" , value: scale); |
126 | |
127 | QQmlListReference list(obj, "pathElements" ); |
128 | QCOMPARE(list.count(), 1); |
129 | |
130 | QQuickPathAngleArc* arc = qobject_cast<QQuickPathAngleArc*>(object: list.at(0)); |
131 | QVERIFY(arc != nullptr); |
132 | QCOMPARE(arc->centerX(), 100.); |
133 | QCOMPARE(arc->centerY(), 100.); |
134 | QCOMPARE(arc->radiusX(), 50.); |
135 | QCOMPARE(arc->radiusY(), 50.); |
136 | QCOMPARE(arc->startAngle(), 45.); |
137 | QCOMPARE(arc->sweepAngle(), 90.); |
138 | QCOMPARE(arc->moveToStart(), true); |
139 | |
140 | QPainterPath path = obj->path(); |
141 | QVERIFY(path != QPainterPath()); |
142 | |
143 | QPointF pos = obj->pointAtPercent(t: 0); |
144 | compare(point: pos, scale, __LINE__, x: 135.35533905867, y: 135.35533905867); |
145 | pos = obj->pointAtPercent(t: .25); |
146 | compare(point: pos, scale, __LINE__, x: 119.46222180396, y: 146.07068621369); |
147 | pos = obj->pointAtPercent(t: .75); |
148 | compare(point: pos, scale, __LINE__, x: 80.537778196007, y: 146.07068621366); |
149 | pos = obj->pointAtPercent(t: 1); |
150 | compare(point: pos, scale, __LINE__, x: 64.644660941173, y: 135.35533905867); |
151 | |
152 | // if moveToStart is false, we should have a line starting from startX/Y |
153 | arc->setMoveToStart(false); |
154 | pos = obj->pointAtPercent(t: 0); |
155 | QCOMPARE(pos, QPointF(0,0)); |
156 | } |
157 | |
158 | void tst_QuickPath::angleArc() |
159 | { |
160 | angleArc(scale: QSizeF(1,1)); |
161 | angleArc(scale: QSizeF(2.7,0.92)); |
162 | } |
163 | |
164 | void tst_QuickPath::catmullRomCurve(QSizeF scale, const QVector<QPointF> &points) |
165 | { |
166 | QQmlEngine engine; |
167 | QQmlComponent c(&engine, testFileUrl(fileName: "curve.qml" )); |
168 | QQuickPath *obj = qobject_cast<QQuickPath*>(object: c.create()); |
169 | QVERIFY(obj != nullptr); |
170 | if (scale != QSizeF(1,1)) |
171 | obj->setProperty(name: "scale" , value: scale); |
172 | |
173 | QCOMPARE(obj->startX(), 0.); |
174 | QCOMPARE(obj->startY(), 0.); |
175 | |
176 | QQmlListReference list(obj, "pathElements" ); |
177 | QCOMPARE(list.count(), 3); |
178 | |
179 | QQuickPathCatmullRomCurve* curve = qobject_cast<QQuickPathCatmullRomCurve*>(object: list.at(0)); |
180 | QVERIFY(curve != nullptr); |
181 | QCOMPARE(curve->x(), 100.); |
182 | QCOMPARE(curve->y(), 50.); |
183 | |
184 | curve = qobject_cast<QQuickPathCatmullRomCurve*>(object: list.at(2)); |
185 | QVERIFY(curve != nullptr); |
186 | QCOMPARE(curve->x(), 100.); |
187 | QCOMPARE(curve->y(), 150.); |
188 | |
189 | QPainterPath path = obj->path(); |
190 | QVERIFY(path != QPainterPath()); |
191 | |
192 | QPointF pos = path.pointAtPercent(t: 0); |
193 | QCOMPARE(pos, points.at(0)); |
194 | pos = path.pointAtPercent(t: .25); |
195 | compare(point: pos, __LINE__, pt: points.at(i: 1)); |
196 | pos = path.pointAtPercent(t: .75); |
197 | compare(point: pos, __LINE__, pt: points.at(i: 2)); |
198 | pos = path.pointAtPercent(t: 1); |
199 | compare(point: pos, __LINE__, pt: points.at(i: 3)); |
200 | } |
201 | |
202 | void tst_QuickPath::catmullRomCurve() |
203 | { |
204 | catmullRomCurve(scale: QSizeF(1,1), points: { QPointF(0,0), |
205 | QPointF(62.917022919131, 26.175485291549), |
206 | QPointF(51.194527196674 , 105.27985623074), |
207 | QPointF(100, 150) }); |
208 | catmullRomCurve(scale: QSizeF(2,5.3), points: { QPointF(0,0), |
209 | QPointF(150.80562419914, 170.34065984615), |
210 | QPointF(109.08400252853 , 588.35165918579), |
211 | QPointF(200, 795) }); |
212 | } |
213 | |
214 | void tst_QuickPath::closedCatmullRomCurve(QSizeF scale, const QVector<QPointF> &points) |
215 | { |
216 | QQmlEngine engine; |
217 | QQmlComponent c(&engine, testFileUrl(fileName: "closedcurve.qml" )); |
218 | QQuickPath *obj = qobject_cast<QQuickPath*>(object: c.create()); |
219 | QVERIFY(obj != nullptr); |
220 | if (scale != QSizeF(1,1)) |
221 | obj->setProperty(name: "scale" , value: scale); |
222 | |
223 | QCOMPARE(obj->startX(), 50.); |
224 | QCOMPARE(obj->startY(), 50.); |
225 | |
226 | QQmlListReference list(obj, "pathElements" ); |
227 | QCOMPARE(list.count(), 3); |
228 | |
229 | QQuickPathCatmullRomCurve* curve = qobject_cast<QQuickPathCatmullRomCurve*>(object: list.at(2)); |
230 | QVERIFY(curve != nullptr); |
231 | QCOMPARE(curve->x(), 50.); |
232 | QCOMPARE(curve->y(), 50.); |
233 | |
234 | QVERIFY(obj->isClosed()); |
235 | |
236 | QPainterPath path = obj->path(); |
237 | QVERIFY(path != QPainterPath()); |
238 | |
239 | QPointF pos = path.pointAtPercent(t: 0); |
240 | QCOMPARE(pos, points.at(0)); |
241 | pos = path.pointAtPercent(t: .1); |
242 | compare(point: pos, __LINE__, pt: points.at(i: 1)); |
243 | pos = path.pointAtPercent(t: .75); |
244 | compare(point: pos, __LINE__, pt: points.at(i: 2)); |
245 | pos = path.pointAtPercent(t: 1); |
246 | compare(point: pos, __LINE__, pt: points.at(i: 3)); |
247 | } |
248 | |
249 | void tst_QuickPath::closedCatmullRomCurve() |
250 | { |
251 | closedCatmullRomCurve(scale: QSizeF(1,1), points: { QPointF(50,50), |
252 | QPointF(66.776225481812, 55.617435304145), |
253 | QPointF(44.10269379731 , 116.33512508175), |
254 | QPointF(50, 50) }); |
255 | closedCatmullRomCurve(scale: QSizeF(2,3), points: { QPointF(100,150), |
256 | QPointF(136.49725836178, 170.25466686363), |
257 | QPointF(87.713232151943 , 328.29232737977), |
258 | QPointF(100, 150) }); |
259 | } |
260 | |
261 | void tst_QuickPath::svg(QSizeF scale) |
262 | { |
263 | QQmlEngine engine; |
264 | QQmlComponent c(&engine, testFileUrl(fileName: "svg.qml" )); |
265 | QQuickPath *obj = qobject_cast<QQuickPath*>(object: c.create()); |
266 | QVERIFY(obj != nullptr); |
267 | if (scale != QSizeF(1,1)) |
268 | obj->setProperty(name: "scale" , value: scale); |
269 | |
270 | QCOMPARE(obj->startX(), 0.); |
271 | QCOMPARE(obj->startY(), 0.); |
272 | |
273 | QQmlListReference list(obj, "pathElements" ); |
274 | QCOMPARE(list.count(), 1); |
275 | |
276 | QQuickPathSvg* svg = qobject_cast<QQuickPathSvg*>(object: list.at(0)); |
277 | QVERIFY(svg != nullptr); |
278 | QCOMPARE(svg->path(), QLatin1String("M200,300 Q400,50 600,300 T1000,300" )); |
279 | |
280 | QPainterPath path = obj->path(); |
281 | QVERIFY(path != QPainterPath()); |
282 | |
283 | QPointF pos = obj->pointAtPercent(t: 0); |
284 | QCOMPARE(pos, QPointF(200 * scale.width(),300 * scale.height())); |
285 | pos = obj->pointAtPercent(t: .25); |
286 | QCOMPARE(pos.toPoint(), QPoint(400 * scale.width(),175 * scale.height())); //fuzzy compare |
287 | pos = obj->pointAtPercent(t: .75); |
288 | QCOMPARE(pos.toPoint(), QPoint(800 * scale.width(),425 * scale.height())); //fuzzy compare |
289 | pos = obj->pointAtPercent(t: 1); |
290 | QCOMPARE(pos, QPointF(1000 * scale.width(),300 * scale.height())); |
291 | } |
292 | |
293 | void tst_QuickPath::svg() |
294 | { |
295 | svg(scale: QSizeF(1,1)); |
296 | svg(scale: QSizeF(5,3)); |
297 | } |
298 | |
299 | void tst_QuickPath::line(QSizeF scale) |
300 | { |
301 | QQmlEngine engine; |
302 | QQmlComponent c1(&engine); |
303 | c1.setData( |
304 | "import QtQuick 2.0\n" |
305 | "Path {\n" |
306 | "startX: 0; startY: 0\n" |
307 | "PathLine { x: 100; y: 100 }\n" |
308 | "}" , baseUrl: QUrl()); |
309 | QScopedPointer<QObject> o1(c1.create()); |
310 | QQuickPath *path1 = qobject_cast<QQuickPath *>(object: o1.data()); |
311 | QVERIFY(path1); |
312 | if (scale != QSizeF(1,1)) |
313 | path1->setProperty(name: "scale" , value: scale); |
314 | |
315 | QQmlComponent c2(&engine); |
316 | c2.setData( |
317 | "import QtQuick 2.0\n" |
318 | "Path {\n" |
319 | "startX: 0; startY: 0\n" |
320 | "PathLine { x: 50; y: 50 }\n" |
321 | "PathLine { x: 100; y: 100 }\n" |
322 | "}" , baseUrl: QUrl()); |
323 | QScopedPointer<QObject> o2(c2.create()); |
324 | QQuickPath *path2 = qobject_cast<QQuickPath *>(object: o2.data()); |
325 | QVERIFY(path2); |
326 | if (scale != QSizeF(1,1)) |
327 | path2->setProperty(name: "scale" , value: scale); |
328 | |
329 | for (int i = 0; i < 167; ++i) { |
330 | qreal t = i / 167.0; |
331 | |
332 | QPointF p1 = path1->pointAtPercent(t); |
333 | QCOMPARE(p1.x(), p1.y()); |
334 | |
335 | QPointF p2 = path2->pointAtPercent(t); |
336 | QCOMPARE(p1.toPoint(), p2.toPoint()); |
337 | } |
338 | } |
339 | |
340 | void tst_QuickPath::line() |
341 | { |
342 | line(scale: QSizeF(1,1)); |
343 | line(scale: QSizeF(7.23,7.23)); |
344 | } |
345 | |
346 | QTEST_MAIN(tst_QuickPath) |
347 | |
348 | #include "tst_qquickpath.moc" |
349 | |