1 /* This file is part of the KDE project
2 * Copyright (C) 2008-2009 Jan Hambrecht <jaham@gmx.net>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "TestPathSegment.h"
21 #include <KoPathSegment.h>
22 #include <KoPathPoint.h>
23 #include <QPainterPath>
24 #include <QTest>
25
segmentAssign()26 void TestPathSegment::segmentAssign()
27 {
28 KoPathSegment s1(QPointF(0, 0), QPointF(100, 100));
29 KoPathSegment s1Copy = s1;
30 QVERIFY(s1 == s1Copy);
31
32 KoPathSegment s2(QPointF(0, 0), QPointF(100, 100), QPointF(200, 0));
33 KoPathSegment s2Copy = s2;
34 QVERIFY(s2 == s2Copy);
35
36 KoPathSegment s3(QPointF(0, 0), QPointF(100, 100), QPointF(200, 100), QPointF(300, 0));
37 KoPathSegment s3Copy = s3;
38 QVERIFY(s3 == s3Copy);
39 }
40
segmentCopy()41 void TestPathSegment::segmentCopy()
42 {
43 KoPathSegment s1(QPointF(0, 0), QPointF(100, 100));
44 KoPathSegment s1Copy(s1);
45 QVERIFY(s1 == s1Copy);
46
47 KoPathSegment s2(QPointF(0, 0), QPointF(100, 100), QPointF(200, 0));
48 KoPathSegment s2Copy(s2);
49 QVERIFY(s2 == s2Copy);
50
51 KoPathSegment s3(QPointF(0, 0), QPointF(100, 100), QPointF(200, 100), QPointF(300, 0));
52 KoPathSegment s3Copy(s3);
53 QVERIFY(s3 == s3Copy);
54 }
55
segmentDegree()56 void TestPathSegment::segmentDegree()
57 {
58 KoPathSegment s0(0, 0);
59 QCOMPARE(s0.degree(), -1);
60
61 KoPathSegment s1(QPointF(0, 0), QPointF(100, 100));
62 QCOMPARE(s1.degree(), 1);
63
64 KoPathSegment s2(QPointF(0, 0), QPointF(100, 100), QPointF(200, 0));
65 QCOMPARE(s2.degree(), 2);
66
67 KoPathSegment s3(QPointF(0, 0), QPointF(100, 100), QPointF(200, 100), QPointF(300, 0));
68 QCOMPARE(s3.degree(), 3);
69 }
70
segmentConvexHull()71 void TestPathSegment::segmentConvexHull()
72 {
73 KoPathSegment s1(QPointF(0, 0), QPointF(100, 100));
74 QList<QPointF> hull1 = s1.convexHull();
75 QCOMPARE(hull1.count(), 2);
76 QCOMPARE(hull1[0], QPointF(0, 0));
77 QCOMPARE(hull1[1], QPointF(100, 100));
78
79 KoPathSegment s2(QPointF(0, 0), QPointF(100, 100), QPointF(200, 0));
80 QList<QPointF> hull2 = s2.convexHull();
81 QCOMPARE(hull2.count(), 3);
82 QCOMPARE(hull2[0], QPointF(0, 0));
83 QCOMPARE(hull2[1], QPointF(100, 100));
84 QCOMPARE(hull2[2], QPointF(200, 0));
85
86 KoPathSegment s3(QPointF(0, 0), QPointF(100, 100), QPointF(200, 100), QPointF(300, 0));
87 QList<QPointF> hull3 = s3.convexHull();
88 QCOMPARE(hull3.count(), 4);
89 QCOMPARE(hull3[0], QPointF(0, 0));
90 QCOMPARE(hull3[1], QPointF(100, 100));
91 QCOMPARE(hull3[2], QPointF(200, 100));
92 QCOMPARE(hull3[3], QPointF(300, 0));
93
94 KoPathSegment s4(QPointF(0, 0), QPointF(150, 100), QPointF(150, 50), QPointF(300, 0));
95 QList<QPointF> hull4 = s4.convexHull();
96 QCOMPARE(hull4.count(), 3);
97 QCOMPARE(hull4[0], QPointF(0, 0));
98 QCOMPARE(hull4[1], QPointF(150, 100));
99 QCOMPARE(hull4[2], QPointF(300, 0));
100 }
101
segmentPointAt()102 void TestPathSegment::segmentPointAt()
103 {
104 KoPathSegment s1(QPointF(0, 0), QPointF(100, 0));
105 QCOMPARE(s1.pointAt(0.0), QPointF(0, 0));
106 QCOMPARE(s1.pointAt(0.5), QPointF(50, 0));
107 QCOMPARE(s1.pointAt(1.0), QPointF(100, 0));
108
109 KoPathSegment s2(QPointF(0, 0), QPointF(100, 100), QPointF(200, 0));
110 QCOMPARE(s2.pointAt(0.0), QPointF(0, 0));
111 QCOMPARE(s2.pointAt(0.5), QPointF(100, 50));
112 QCOMPARE(s2.pointAt(1.0), QPointF(200, 0));
113
114 KoPathSegment s3(QPointF(0, 0), QPointF(100, 100), QPointF(200, 100), QPointF(300, 0));
115 QCOMPARE(s3.pointAt(0.0), QPointF(0, 0));
116 QCOMPARE(s3.pointAt(1.0 / 3.0), QPointF(100, 100*2.0 / 3.0));
117 QCOMPARE(s3.pointAt(2.0 / 3.0), QPointF(200, 100*2.0 / 3.0));
118 QCOMPARE(s3.pointAt(1.0), QPointF(300, 0));
119 }
120
segmentSplitAt()121 void TestPathSegment::segmentSplitAt()
122 {
123 KoPathSegment s1(QPointF(0, 0), QPointF(100, 0));
124 QPair<KoPathSegment, KoPathSegment> parts1 = s1.splitAt( 0.5 );
125 QCOMPARE(parts1.first.first()->point(), QPointF(0, 0));
126 QCOMPARE(parts1.first.second()->point(), QPointF(50, 0));
127 QCOMPARE(parts1.first.degree(), 1);
128 QCOMPARE(parts1.second.first()->point(), QPointF(50, 0));
129 QCOMPARE(parts1.second.second()->point(), QPointF(100, 0));
130 QCOMPARE(parts1.second.degree(), 1);
131
132 QPainterPath p1;
133 p1.moveTo( QPoint(0, 0) );
134 p1.lineTo( QPointF(100, 0) );
135 QCOMPARE( parts1.first.second()->point(), p1.pointAtPercent( 0.5 ) );
136
137 KoPathSegment s2(QPointF(0, 0), QPointF(100, 100), QPointF(200, 0));
138 QPair<KoPathSegment, KoPathSegment> parts2 = s2.splitAt( 0.5 );
139 QCOMPARE(parts2.first.first()->point(), QPointF(0, 0));
140 QCOMPARE(parts2.first.second()->point(), QPointF(100, 50));
141 QCOMPARE(parts2.first.degree(), 2);
142 QCOMPARE(parts2.second.first()->point(), QPointF(100, 50));
143 QCOMPARE(parts2.second.second()->point(), QPointF(200, 0));
144 QCOMPARE(parts2.second.degree(), 2);
145
146 QPainterPath p2;
147 p2.moveTo( QPoint(0, 0) );
148 p2.quadTo( QPointF(100, 100), QPointF(200, 0) );
149 QCOMPARE( parts2.first.second()->point(), p2.pointAtPercent( 0.5 ) );
150
151 KoPathSegment s3(QPointF(0, 0), QPointF(100, 100), QPointF(200, 100), QPointF(300, 0));
152 QPair<KoPathSegment, KoPathSegment> parts3 = s3.splitAt( 0.5 );
153 QCOMPARE(parts3.first.first()->point(), QPointF(0, 0));
154 QCOMPARE(parts3.first.second()->point(), QPointF(150, 75));
155 QCOMPARE(parts3.first.degree(), 3);
156 QCOMPARE(parts3.second.first()->point(), QPointF(150, 75));
157 QCOMPARE(parts3.second.second()->point(), QPointF(300, 0));
158 QCOMPARE(parts3.second.degree(), 3);
159
160 QPainterPath p3;
161 p3.moveTo( QPoint(0, 0) );
162 p3.cubicTo( QPointF(100, 100), QPointF(200, 100), QPointF(300, 0) );
163 QCOMPARE( parts3.first.second()->point(), p3.pointAtPercent( 0.5 ) );
164 }
165
segmentIntersections()166 void TestPathSegment::segmentIntersections()
167 {
168 // simple line intersections
169 {
170 KoPathSegment s1(QPointF(0, 0), QPointF(100, 0));
171 KoPathSegment s2(QPointF(50, -50), QPointF(50, 50));
172 QList<QPointF> isects = s1.intersections(s2);
173 QCOMPARE(isects.count(), 1);
174 }
175 {
176 KoPathSegment s1(QPointF(0, 0), QPointF(100, 100));
177 KoPathSegment s2(QPointF(25, 100), QPointF(75, 50));
178 QList<QPointF> isects = s1.intersections(s2);
179 QCOMPARE(isects.count(), 1);
180 }
181 // curve intersections
182 {
183 KoPathSegment s1(QPointF(0, 0), QPointF(50, 50), QPointF(100, -50), QPointF(150, 0));
184 KoPathSegment s2(QPointF(75, 75), QPointF(125, 25), QPointF(25, -25), QPointF(75, -75));
185 QList<QPointF> isects = s1.intersections(s2);
186 QCOMPARE(isects.count(), 1);
187 }
188 {
189 KoPathSegment s1(QPointF(0, 0), QPointF(50, 50), QPointF(100, -50), QPointF(150, 0));
190 KoPathSegment s2(QPointF(100, 75), QPointF(150, 25), QPointF(50, -25), QPointF(100, -75));
191 QList<QPointF> isects = s1.intersections(s2);
192 QCOMPARE(isects.count(), 1);
193 }
194 {
195 KoPathSegment s1(QPointF(0, 0), QPointF(25, 50), QPointF(75, 50), QPointF(100, 0));
196 KoPathSegment s2(QPointF(0, 30), QPointF(25, -20), QPointF(75, -20), QPointF(100, 30));
197 QList<QPointF> isects = s1.intersections(s2);
198 QCOMPARE(isects.count(), 2);
199 }
200 }
201
segmentLength()202 void TestPathSegment::segmentLength()
203 {
204 {
205 // line segment
206 KoPathSegment s(QPointF(0, 0), QPointF(100, 0));
207 QCOMPARE(s.length(), 100.0);
208 }
209 {
210 // quadric curve segment
211 KoPathSegment s1(QPointF(0, 0), QPointF(50, 0), QPointF(100, 0));
212 QCOMPARE(s1.length(), 100.0);
213 KoPathSegment s2(QPointF(0, 0), QPointF(50, 50), QPointF(100, 0));
214 QPainterPath p2;
215 p2.moveTo(QPointF(0, 0));
216 p2.quadTo(QPointF(50, 50), QPointF(100, 0));
217 // verify that difference is less than 0.5 percent of the length
218 QVERIFY(s2.length() - p2.length() < 0.005 * s2.length(0.01));
219 }
220 {
221 // cubic curve segment
222 KoPathSegment s1(QPointF(0, 0), QPointF(25, 0), QPointF(75, 0), QPointF(100, 0));
223 QCOMPARE(s1.length(), 100.0);
224 KoPathSegment s2(QPointF(0, 0), QPointF(25, 50), QPointF(75, 50), QPointF(100, 0));
225 QPainterPath p2;
226 p2.moveTo(QPointF(0, 0));
227 p2.cubicTo(QPointF(25, 50), QPointF(75, 50), QPointF(100, 0));
228 // verify that difference is less than 0.5 percent of the length
229 QVERIFY(s2.length() - p2.length() < 0.005 * s2.length(0.01));
230 }
231 }
232
segmentFlatness()233 void TestPathSegment::segmentFlatness()
234 {
235 // line segments
236 {
237 KoPathSegment s1(QPointF(0, 0), QPointF(100, 0));
238 QVERIFY(s1.isFlat());
239 KoPathSegment s2(QPointF(0, 0), QPointF(0, 100));
240 QVERIFY(s2.isFlat());
241 KoPathSegment s3(QPointF(0, 0), QPointF(100, 100));
242 QVERIFY(s3.isFlat());
243 }
244 // quadratic segments
245 {
246 KoPathSegment s1(QPointF(0, 0), QPointF(50, 0), QPointF(100, 0));
247 QVERIFY(s1.isFlat());
248 KoPathSegment s2(QPointF(0, 0), QPointF(0, 50), QPointF(0, 100));
249 QVERIFY(s2.isFlat());
250 KoPathSegment s3(QPointF(0, 0), QPointF(50, 50), QPointF(100, 100));
251 QVERIFY(s3.isFlat());
252 KoPathSegment s4(QPointF(0, 0), QPointF(50, 50), QPointF(100, 0));
253 QVERIFY(! s4.isFlat());
254 KoPathSegment s5(QPointF(0, 0), QPointF(50, -50), QPointF(100, 0));
255 QVERIFY(! s5.isFlat());
256 KoPathSegment s6(QPointF(0, 0), QPointF(0, 100), QPointF(100, 100));
257 QVERIFY(! s6.isFlat());
258 }
259 // cubic segments
260 {
261 KoPathSegment s1(QPointF(0, 0), QPointF(25, 0), QPointF(75, 0), QPointF(100, 0));
262 QVERIFY(s1.isFlat());
263 KoPathSegment s2(QPointF(0, 0), QPointF(0, 25), QPointF(0, 75), QPointF(0, 100));
264 QVERIFY(s2.isFlat());
265 KoPathSegment s3(QPointF(0, 0), QPointF(25, 25), QPointF(75, 75), QPointF(100, 100));
266 QVERIFY(s3.isFlat());
267 KoPathSegment s4(QPointF(0, 0), QPointF(25, 50), QPointF(75, 50), QPointF(100, 0));
268 QVERIFY(! s4.isFlat());
269 KoPathSegment s5(QPointF(0, 0), QPointF(25, -50), QPointF(75, -50), QPointF(100, 0));
270 QVERIFY(! s5.isFlat());
271 KoPathSegment s6(QPointF(0, 0), QPointF(-25, 75), QPointF(25, 125), QPointF(100, 100));
272 QVERIFY(! s6.isFlat());
273 }
274 }
275
nearestPoint()276 void TestPathSegment::nearestPoint()
277 {
278 // line segments
279 {
280 KoPathSegment s1(QPointF(0, 0), QPointF(100, 0));
281 QCOMPARE( s1.nearestPoint( QPointF(0,0) ), 0.0 );
282 QCOMPARE( s1.nearestPoint( QPointF(-20,0) ), 0.0 );
283 QCOMPARE( s1.nearestPoint( QPointF(100,0) ), 1.0 );
284 QCOMPARE( s1.nearestPoint( QPointF(120,0) ), 1.0 );
285 QCOMPARE( s1.nearestPoint( QPointF(50,0) ), 0.5 );
286 QCOMPARE( s1.nearestPoint( QPointF(50,-10) ), 0.5 );
287 QCOMPARE( s1.nearestPoint( QPointF(50,10) ), 0.5 );
288 QCOMPARE( s1.nearestPoint( QPointF(63,50) ), 0.63 );
289 QCOMPARE( s1.nearestPoint( QPointF(63,50) ), 0.63 );
290 QCOMPARE( s1.nearestPoint( QPointF(63,50) ), 0.63 );
291 QCOMPARE( s1.nearestPoint( s1.pointAt( 0.25 ) ), 0.25 );
292 QCOMPARE( s1.nearestPoint( s1.pointAt( 0.75 ) ), 0.75 );
293 }
294 // quadratic segments
295 {
296 KoPathSegment s1(QPointF(0, 0), QPointF(50, 0), QPointF(100, 0));
297 QCOMPARE( s1.nearestPoint( QPointF(0,0) ), 0.0 );
298 QCOMPARE( s1.nearestPoint( QPointF(-20,0) ), 0.0 );
299 QCOMPARE( s1.nearestPoint( QPointF(100,0) ), 1.0 );
300 QCOMPARE( s1.nearestPoint( QPointF(120,0) ), 1.0 );
301 QCOMPARE( s1.nearestPoint( QPointF(50,0) ), 0.5 );
302 QCOMPARE( s1.nearestPoint( QPointF(50,-10) ), 0.5 );
303 QCOMPARE( s1.nearestPoint( QPointF(50,10) ), 0.5 );
304 KoPathSegment s2(QPointF(0, 0), QPointF(50, 50), QPointF(100, 0));
305 QCOMPARE( s2.nearestPoint( QPointF(0,0) ), 0.0 );
306 QCOMPARE( s2.nearestPoint( QPointF(-20,0) ), 0.0 );
307 QCOMPARE( s2.nearestPoint( QPointF(100,0) ), 1.0 );
308 QCOMPARE( s2.nearestPoint( QPointF(120,0) ), 1.0 );
309 QCOMPARE( s2.nearestPoint( QPointF(50,50) ), 0.5 );
310
311 QCOMPARE( s2.nearestPoint( s2.pointAt( 0.0 ) ), 0.0 );
312 QCOMPARE( s2.nearestPoint( s2.pointAt( 0.25 ) ), 0.25 );
313 QCOMPARE( s2.nearestPoint( s2.pointAt( 0.5 ) ), 0.5 );
314 QCOMPARE( s2.nearestPoint( s2.pointAt( 0.75 ) ), 0.75 );
315 QCOMPARE( s2.nearestPoint( s2.pointAt( 1.0 ) ), 1.0 );
316 }
317 // cubic segments
318 {
319 // a flat cubic bezier
320 KoPathSegment s1(QPointF(0, 0), QPointF(25, 0), QPointF(75, 0), QPointF(100, 0));
321 QCOMPARE( s1.nearestPoint( QPointF(0,0) ), 0.0 );
322 QCOMPARE( s1.nearestPoint( QPointF(-20,0) ), 0.0 );
323 QCOMPARE( s1.nearestPoint( QPointF(100,0) ), 1.0 );
324 QCOMPARE( s1.nearestPoint( QPointF(120,0) ), 1.0 );
325 QCOMPARE( s1.nearestPoint( QPointF(50,0) ), 0.5 );
326 QCOMPARE( s1.nearestPoint( QPointF(50,-10) ), 0.5 );
327 QCOMPARE( s1.nearestPoint( QPointF(50,10) ), 0.5 );
328 KoPathSegment s2(QPointF(0, 0), QPointF(25, 50), QPointF(75, 50), QPointF(100, 0));
329 QCOMPARE( s2.nearestPoint( QPointF(0,0) ), 0.0 );
330 QCOMPARE( s2.nearestPoint( QPointF(-20,0) ), 0.0 );
331 QCOMPARE( s2.nearestPoint( QPointF(100,0) ), 1.0 );
332 QCOMPARE( s2.nearestPoint( QPointF(120,0) ), 1.0 );
333 QCOMPARE( s2.nearestPoint( QPointF(50,50) ), 0.5 );
334
335 QCOMPARE( s2.nearestPoint( s2.pointAt( 0.0 ) ), 0.0 );
336 QCOMPARE( s2.nearestPoint( s2.pointAt( 0.25 ) ), 0.25 );
337 QCOMPARE( s2.nearestPoint( s2.pointAt( 0.5 ) ), 0.5 );
338 QCOMPARE( s2.nearestPoint( s2.pointAt( 0.75 ) ), 0.75 );
339 QCOMPARE( s2.nearestPoint( s2.pointAt( 1.0 ) ), 1.0 );
340 }
341 }
342
paramAtLength()343 void TestPathSegment::paramAtLength()
344 {
345 // line segment
346 {
347 KoPathSegment s1(QPointF(0,0), QPointF(100,0));
348 QCOMPARE(s1.paramAtLength(0), 0.0);
349 QCOMPARE(s1.paramAtLength(100.0), 1.0);
350 QCOMPARE(s1.paramAtLength(50.0), 0.5);
351 QCOMPARE(s1.paramAtLength(120.0), 1.0);
352 }
353 // quadratic segments
354 {
355 // a flat quadratic bezier
356 KoPathSegment s1(QPointF(0, 0), QPointF(50, 0), QPointF(100, 0));
357 QCOMPARE(s1.paramAtLength(0), 0.0);
358 QCOMPARE(s1.paramAtLength(100.0), 1.0);
359 QCOMPARE(s1.paramAtLength(120.0), 1.0);
360 }
361 // cubic segments
362 {
363 // a flat cubic bezier
364 KoPathSegment s1(QPointF(0, 0), QPointF(25, 0), QPointF(75, 0), QPointF(100, 0));
365 QCOMPARE(s1.paramAtLength(0), 0.0);
366 QCOMPARE(s1.paramAtLength(100.0), 1.0);
367 QCOMPARE(s1.paramAtLength(120.0), 1.0);
368 }
369 }
370
371 QTEST_MAIN(TestPathSegment)
372