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
36class tst_QuickPath : public QQmlDataTest
37{
38 Q_OBJECT
39public:
40 tst_QuickPath() {}
41
42private slots:
43 void arc();
44 void angleArc();
45 void catmullRomCurve();
46 void closedCatmullRomCurve();
47 void svg();
48 void line();
49
50private:
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
59static 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}
70static 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
75void 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
112void tst_QuickPath::arc()
113{
114 arc(scale: QSizeF(1,1));
115 arc(scale: QSizeF(2.2,3.4));
116}
117
118void 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
158void tst_QuickPath::angleArc()
159{
160 angleArc(scale: QSizeF(1,1));
161 angleArc(scale: QSizeF(2.7,0.92));
162}
163
164void 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
202void 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
214void 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
249void 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
261void 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
293void tst_QuickPath::svg()
294{
295 svg(scale: QSizeF(1,1));
296 svg(scale: QSizeF(5,3));
297}
298
299void 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
340void tst_QuickPath::line()
341{
342 line(scale: QSizeF(1,1));
343 line(scale: QSizeF(7.23,7.23));
344}
345
346QTEST_MAIN(tst_QuickPath)
347
348#include "tst_qquickpath.moc"
349

source code of qtdeclarative/tests/auto/quick/qquickpath/tst_qquickpath.cpp