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#include "private/qpathclipper_p.h"
29#include "paths.h"
30#include "pathcompare.h"
31
32#include <QtTest/QtTest>
33
34#include <qpainterpath.h>
35#include <qpolygon.h>
36#include <qdebug.h>
37#include <qpainter.h>
38#include <qrandom.h>
39
40#include <math.h>
41
42class tst_QPathClipper : public QObject
43{
44 Q_OBJECT
45
46public:
47 tst_QPathClipper();
48 virtual ~tst_QPathClipper();
49
50private:
51 void clipTest(int subjectIndex, int clipIndex, QPathClipper::Operation op);
52
53 QList<QPainterPath> paths;
54
55public slots:
56 void initTestCase();
57
58private slots:
59 void testWingedEdge();
60
61 void testComparePaths();
62
63 void clip_data();
64 void clip();
65
66 void clip2();
67 void clip3();
68
69 void testIntersections();
70 void testIntersections2();
71 void testIntersections3();
72 void testIntersections4();
73 void testIntersections5();
74 void testIntersections6();
75 void testIntersections7();
76 void testIntersections8();
77 void testIntersections9();
78
79 void zeroDerivativeCurves();
80
81 void task204301_data();
82 void task204301();
83
84 void task209056();
85 void task251909();
86
87 void qtbug3778();
88 void qtbug60024();
89};
90
91Q_DECLARE_METATYPE(QPainterPath)
92Q_DECLARE_METATYPE(QPathClipper::Operation)
93
94tst_QPathClipper::tst_QPathClipper()
95{
96}
97
98tst_QPathClipper::~tst_QPathClipper()
99{
100}
101
102void tst_QPathClipper::initTestCase()
103{
104 paths << Paths::rect();
105 paths << Paths::heart();
106 paths << Paths::body();
107 paths << Paths::mailbox();
108 paths << Paths::deer();
109 paths << Paths::fire();
110
111 paths << Paths::random1();
112 paths << Paths::random2();
113
114 paths << Paths::heart2();
115 paths << Paths::rect2();
116 paths << Paths::rect3();
117 paths << Paths::rect4();
118 paths << Paths::rect5();
119 paths << Paths::rect6();
120
121 paths << Paths::frame1();
122 paths << Paths::frame2();
123 paths << Paths::frame3();
124 paths << Paths::frame4();
125
126 paths << Paths::triangle1();
127 paths << Paths::triangle2();
128
129 paths << Paths::node();
130 paths << Paths::interRect();
131
132 paths << Paths::simpleCurve();
133 paths << Paths::simpleCurve2();
134 paths << Paths::simpleCurve3();
135
136 paths << Paths::bezier1();
137 paths << Paths::bezier2();
138 paths << Paths::bezier3();
139 paths << Paths::bezier4();
140
141 paths << Paths::bezierFlower();
142 paths << Paths::lips();
143 paths << Paths::clover();
144 paths << Paths::ellipses();
145 paths << Paths::windingFill();
146 paths << Paths::oddEvenFill();
147 paths << Paths::squareWithHole();
148 paths << Paths::circleWithHole();
149 paths << Paths::bezierQuadrant();
150
151 // make sure all the bounding rects are centered at the origin
152 for (int i = 0; i < paths.size(); ++i) {
153 QRectF bounds = paths[i].boundingRect();
154
155 QTransform m(1, 0,
156 0, 1,
157 -bounds.center().x(), -bounds.center().y());
158
159 paths[i] = m.map(p: paths[i]);
160 }
161}
162
163static QPainterPath samplePath1()
164{
165 QPainterPath path;
166 path.moveTo(p: QPointF(200, 246.64789));
167 path.lineTo(p: QPointF(200, 206.64789));
168 path.lineTo(p: QPointF(231.42858, 206.64789));
169 path.lineTo(p: QPointF(231.42858, 246.64789));
170 path.lineTo(p: QPointF(200, 246.64789));
171 return path;
172}
173
174static QPainterPath samplePath2()
175{
176 QPainterPath path;
177 path.moveTo(p: QPointF(200, 146.64789));
178 path.lineTo(p: QPointF(200, 106.64789));
179 path.lineTo(p: QPointF(231.42858, 106.64789));
180 path.lineTo(p: QPointF(231.42858, 146.64789));
181 path.lineTo(p: QPointF(200, 146.64789));
182 return path;
183}
184
185static QPainterPath samplePath3()
186{
187 QPainterPath path;
188 path.moveTo(p: QPointF(231.42858, 80.933609));
189 path.lineTo(p: QPointF(200, 80.933609));
190 path.lineTo(p: QPointF(200, 96.64788999999999));
191 path.lineTo(p: QPointF(231.42858, 96.64788999999999));
192 path.lineTo(p: QPointF(231.42858, 80.933609));
193 return path;
194}
195
196static QPainterPath samplePath4()
197{
198 QPainterPath path;
199 path.moveTo(p: QPointF(288.571434, 80.933609));
200 path.lineTo(p: QPointF(431.42858, 80.933609));
201 path.lineTo(p: QPointF(431.42858, 96.64788999999999));
202 path.lineTo(p: QPointF(288.571434, 96.64788999999999));
203 path.lineTo(p: QPointF(288.571434, 80.933609));
204 return path;
205}
206
207static QPainterPath samplePath5()
208{
209 QPainterPath path;
210 path.moveTo(p: QPointF(588.571434, 80.933609));
211 path.lineTo(p: QPointF(682.85715, 80.933609));
212 path.lineTo(p: QPointF(682.85715, 96.64788999999999));
213 path.lineTo(p: QPointF(588.571434, 96.64788999999999));
214 path.lineTo(p: QPointF(588.571434, 80.933609));
215 return path;
216}
217
218static QPainterPath samplePath6()
219{
220 QPainterPath path;
221 path.moveTo(p: QPointF(588.571434, 80.933609));
222 path.lineTo(p: QPointF(200, 80.933609));
223 path.lineTo(p: QPointF(200, 446.6479));
224 path.lineTo(p: QPointF(682.85715, 446.6479));
225 path.lineTo(p: QPointF(682.85715, 96.64788999999999));
226 path.lineTo(p: QPointF(731.42858, 96.64788999999999));
227 path.lineTo(p: QPointF(731.42858, 56.64788999999999));
228 path.lineTo(p: QPointF(588.571434, 56.64788999999999));
229 path.lineTo(p: QPointF(588.571434, 80.933609));
230 return path;
231}
232
233static QPainterPath samplePath7()
234{
235 QPainterPath path;
236 path.moveTo(p: QPointF(682.85715, 206.64789));
237 path.lineTo(p: QPointF(682.85715, 246.64789));
238 path.lineTo(p: QPointF(588.571434, 246.64789));
239 path.lineTo(p: QPointF(588.571434, 206.64789));
240 path.lineTo(p: QPointF(682.85715, 206.64789));
241 return path;
242}
243
244static QPainterPath samplePath8()
245{
246 QPainterPath path;
247 path.moveTo(p: QPointF(682.85715, 406.64789));
248 path.lineTo(p: QPointF(682.85715, 446.64789));
249 path.lineTo(p: QPointF(588.571434, 446.64789));
250 path.lineTo(p: QPointF(588.571434, 406.64789));
251 path.lineTo(p: QPointF(682.85715, 406.64789));
252 return path;
253}
254
255static QPainterPath samplePath9()
256{
257 QPainterPath path;
258 path.moveTo(p: QPointF(682.85715, 426.64789));
259 path.lineTo(p: QPointF(682.85715, 446.6479));
260 path.lineTo(p: QPointF(568.571434, 446.6479));
261 path.lineTo(p: QPointF(568.571434, 426.64789));
262 path.lineTo(p: QPointF(682.85715, 426.64789));
263 return path;
264}
265
266static QPainterPath samplePath10()
267{
268 QPainterPath path;
269 path.moveTo(p: QPointF(511.42858, 446.6479));
270 path.lineTo(p: QPointF(368.571434, 446.6479));
271 path.lineTo(p: QPointF(368.571434, 426.64789));
272 path.lineTo(p: QPointF(511.42858, 426.64789));
273 path.lineTo(p: QPointF(511.42858, 446.6479));
274 return path;
275}
276
277static QPainterPath samplePath13()
278{
279 QPainterPath path;
280 path.moveTo(p: QPointF(160, 200));
281 path.lineTo(p: QPointF(100, 200));
282 path.lineTo(p: QPointF(100, 130));
283 path.lineTo(p: QPointF(160, 130));
284 path.lineTo(p: QPointF(160, 200));
285 return path;
286}
287
288static QPainterPath samplePath14()
289{
290 QPainterPath path;
291
292 path.moveTo(x: 160, y: 80);
293 path.lineTo(x: 160, y: 180);
294 path.lineTo(x: 100, y: 180);
295 path.lineTo(x: 100, y: 80);
296 path.lineTo(x: 160, y: 80);
297 path.moveTo(x: 160, y: 80);
298 path.lineTo(x: 160, y: 100);
299 path.lineTo(x: 120, y: 100);
300 path.lineTo(x: 120, y: 80);
301
302 return path;
303}
304
305void tst_QPathClipper::clip_data()
306{
307 //create the testtable instance and define the elements
308 QTest::addColumn<QPainterPath>(name: "subject");
309 QTest::addColumn<QPainterPath>(name: "clip");
310 QTest::addColumn<QPathClipper::Operation>(name: "op");
311 QTest::addColumn<QPainterPath>(name: "result");
312
313 //next we fill it with data
314 QTest::newRow( dataTag: "simple1" ) << Paths::frame3()
315 << Paths::frame4()
316 << QPathClipper::BoolAnd
317 << samplePath1();
318
319 QTest::newRow( dataTag: "simple2" ) << Paths::frame3()
320 << Paths::frame4() * QTransform().translate(dx: 0, dy: -100)
321 << QPathClipper::BoolAnd
322 << samplePath2();
323
324 QTest::newRow( dataTag: "simple3" ) << Paths::frame3()
325 << Paths::frame4() * QTransform().translate(dx: 0, dy: -150)
326 << QPathClipper::BoolAnd
327 << samplePath3();
328
329 QTest::newRow( dataTag: "simple4" ) << Paths::frame3()
330 << Paths::frame4() * QTransform().translate(dx: 200, dy: -150)
331 << QPathClipper::BoolAnd
332 << samplePath4();
333
334 QTest::newRow( dataTag: "simple5" ) << Paths::frame3()
335 << Paths::frame4() * QTransform().translate(dx: 500, dy: -150)
336 << QPathClipper::BoolAnd
337 << samplePath5();
338
339 QTest::newRow( dataTag: "simple6" ) << Paths::frame3()
340 << Paths::frame4() * QTransform().translate(dx: 500, dy: -150)
341 << QPathClipper::BoolOr
342 << samplePath6();
343
344 QTest::newRow( dataTag: "simple7" ) << Paths::frame3()
345 << Paths::frame4() * QTransform().translate(dx: 500, dy: 0)
346 << QPathClipper::BoolAnd
347 << samplePath7();
348
349 QTest::newRow( dataTag: "simple8" ) << Paths::frame3()
350 << Paths::frame4() * QTransform().translate(dx: 500, dy: 200)
351 << QPathClipper::BoolAnd
352 << samplePath8();
353
354 QTest::newRow( dataTag: "simple9" ) << Paths::frame3()
355 << Paths::frame4() * QTransform().translate(dx: 480, dy: 220)
356 << QPathClipper::BoolAnd
357 << samplePath9();
358
359 QTest::newRow( dataTag: "simple10" ) << Paths::frame3()
360 << Paths::frame4() * QTransform().translate(dx: 280, dy: 220)
361 << QPathClipper::BoolAnd
362 << samplePath10();
363
364 QTest::newRow( dataTag: "simple_move_to1" ) << Paths::rect4()
365 << Paths::rect2() * QTransform().translate(dx: -20, dy: 50)
366 << QPathClipper::BoolAnd
367 << samplePath13();
368
369 QTest::newRow( dataTag: "simple_move_to2" ) << Paths::rect4()
370 << Paths::rect2() * QTransform().translate(dx: -20, dy: 0)
371 << QPathClipper::BoolAnd
372 << samplePath14();
373}
374
375// sanity check to make sure comparePaths declared above works
376void tst_QPathClipper::testComparePaths()
377{
378 QPainterPath a;
379 QPainterPath b;
380
381 a.addRect(x: 0, y: 0, w: 10, h: 10);
382 b.addRect(x: 0, y: 0, w: 10.00001, h: 10.00001);
383
384 QVERIFY(!QPathCompare::comparePaths(a, b));
385
386 b = QPainterPath();
387 b.addRect(x: 0, y: 0, w: 10.00000000001, h: 10.00000000001);
388
389 QVERIFY(QPathCompare::comparePaths(a, b));
390
391 b = QPainterPath();
392 b.moveTo(x: 10, y: 0);
393 b.lineTo(x: 0, y: 0);
394 b.lineTo(x: 0, y: 10);
395 b.lineTo(x: 10, y: 10);
396
397 QVERIFY(QPathCompare::comparePaths(a, b));
398 b.lineTo(x: 10, y: 0);
399 QVERIFY(QPathCompare::comparePaths(a, b));
400
401 b = QPainterPath();
402 b.moveTo(x: 10, y: 0);
403 b.lineTo(x: 0, y: 10);
404 b.lineTo(x: 0, y: 0);
405 b.lineTo(x: 10, y: 10);
406
407 QVERIFY(!QPathCompare::comparePaths(a, b));
408}
409
410void tst_QPathClipper::clip()
411{
412 if (sizeof(double) != sizeof(qreal)) {
413 QSKIP("This test only works for qreal=double, otherwise ends in rounding errors");
414 }
415 QFETCH( QPainterPath, subject );
416 QFETCH( QPainterPath, clip );
417 QFETCH( QPathClipper::Operation, op );
418 QFETCH( QPainterPath, result);
419 QPathClipper clipper(subject, clip);
420 QPainterPath x = clipper.clip(op);
421
422 QVERIFY(QPathCompare::comparePaths(x, result));
423}
424
425static inline QPointF randomPointInRect(const QRectF &rect)
426{
427 qreal rx = QRandomGenerator::global()->bounded(highest: 1.0);
428 qreal ry = QRandomGenerator::global()->bounded(highest: 1.0);
429
430 return QPointF(rect.left() + rx * rect.width(),
431 rect.top() + ry * rect.height());
432}
433
434void tst_QPathClipper::clipTest(int subjectIndex, int clipIndex, QPathClipper::Operation op)
435{
436 const QPainterPath &subject = paths[subjectIndex];
437 const QPainterPath &clip = paths[clipIndex];
438 const int count = 40;
439
440 QRectF bounds = subject.boundingRect().united(r: clip.boundingRect());
441
442 const qreal adjustX = bounds.width() * 0.01;
443 const qreal adjustY = bounds.height() * 0.01;
444
445 // make sure we test some points that are outside both paths as well
446 bounds = bounds.adjusted(xp1: -adjustX, yp1: -adjustY, xp2: adjustX, yp2: adjustY);
447
448 const int dim = 256;
449 const qreal scale = qMin(a: dim / bounds.width(), b: dim / bounds.height());
450
451 QPathClipper clipper(subject, clip);
452 QPainterPath result = clipper.clip(op);
453
454 // using the image here is a bit of a hacky way to make sure we don't test points that
455 // are too close to the path edges to avoid test fails that are due to numerical errors
456 QImage img(dim, dim, QImage::Format_ARGB32_Premultiplied);
457 img.fill(pixel: 0x0);
458 QPainter p(&img);
459 p.setRenderHint(hint: QPainter::Antialiasing);
460 p.scale(sx: scale, sy: scale);
461 p.translate(offset: -bounds.topLeft());
462 p.setPen(QPen(Qt::black, 0));
463 p.drawPath(path: subject);
464 p.setPen(QPen(Qt::red, 0));
465 p.drawPath(path: clip);
466 p.end();
467
468 for (int i = 0; i < count; ++i) {
469 QPointF point;
470 QRgb pixel;
471 do {
472 point = randomPointInRect(rect: bounds);
473 const QPointF imagePoint = (point - bounds.topLeft()) * scale;
474
475 pixel = img.pixel(x: int(imagePoint.x()), y: int(imagePoint.y()));
476 } while (qAlpha(rgb: pixel) > 0);
477
478 const bool inSubject = subject.contains(pt: point);
479 const bool inClip = clip.contains(pt: point);
480
481 const bool inResult = result.contains(pt: point);
482
483 bool expected = false;
484 switch (op) {
485 case QPathClipper::BoolAnd:
486 expected = inSubject && inClip;
487 break;
488 case QPathClipper::BoolOr:
489 expected = inSubject || inClip;
490 break;
491 case QPathClipper::BoolSub:
492 expected = inSubject && !inClip;
493 break;
494 default:
495 break;
496 }
497
498 if (expected != inResult) {
499 char str[256];
500 const char *opStr =
501 op == QPathClipper::BoolAnd ? "and" :
502 op == QPathClipper::BoolOr ? "or" : "sub";
503 sprintf(s: str, format: "Expected: %d, actual: %d, subject: %d, clip: %d, op: %s\n",
504 int(expected), int(inResult), subjectIndex, clipIndex, opStr);
505 QFAIL(str);
506 }
507 }
508}
509
510void tst_QPathClipper::clip2()
511{
512 if (sizeof(double) != sizeof(qreal))
513 QSKIP("This test only works for qreal=double, otherwise ends in rounding errors");
514
515 int operation = 0;
516
517 for (int i = 0; i < paths.size(); ++i) {
518 for (int j = 0; j <= i; ++j) {
519 QPathClipper::Operation op = QPathClipper::Operation((operation++) % 3);
520 clipTest(subjectIndex: i, clipIndex: j, op);
521 }
522 }
523}
524
525void tst_QPathClipper::clip3()
526{
527 int operation = 0;
528
529 // this subset should work correctly for qreal = float
530 for (int i = 0; i < 20; ++i) {
531 for (int j = 0; j <= i; ++j) {
532 QPathClipper::Operation op = QPathClipper::Operation((operation++) % 3);
533 clipTest(subjectIndex: i, clipIndex: j, op);
534 }
535 }
536}
537
538void tst_QPathClipper::testIntersections()
539{
540 QPainterPath path1;
541 QPainterPath path2;
542
543 path1.addRect(x: 0, y: 0, w: 100, h: 100);
544 path2.addRect(x: 20, y: 20, w: 20, h: 20);
545 QVERIFY(path1.intersects(path2));
546 QVERIFY(path2.intersects(path1));
547 QVERIFY(path1.contains(path2));
548 QVERIFY(!path2.contains(path1));
549
550 path1 = QPainterPath();
551 path2 = QPainterPath();
552 path1.addEllipse(x: 0, y: 0, w: 100, h: 100);
553 path2.addEllipse(x: 200, y: 200, w: 100, h: 100);
554 QVERIFY(!path1.intersects(path2));
555 QVERIFY(!path2.intersects(path1));
556 QVERIFY(!path1.contains(path2));
557 QVERIFY(!path2.contains(path1));
558
559 path1 = QPainterPath();
560 path2 = QPainterPath();
561 path1.addEllipse(x: 0, y: 0, w: 100, h: 100);
562 path2.addEllipse(x: 50, y: 50, w: 100, h: 100);
563 QVERIFY(path1.intersects(path2));
564 QVERIFY(path2.intersects(path1));
565 QVERIFY(!path1.contains(path2));
566 QVERIFY(!path2.contains(path1));
567
568 path1 = QPainterPath();
569 path2 = QPainterPath();
570 path1.addRect(x: 100, y: 100, w: 100, h: 100);
571 path2.addRect(x: 50, y: 100, w: 100, h: 20);
572 QVERIFY(path1.intersects(path2));
573 QVERIFY(path2.intersects(path1));
574 QVERIFY(!path1.contains(path2));
575 QVERIFY(!path2.contains(path1));
576
577 path1 = QPainterPath();
578 path2 = QPainterPath();
579 path1.addRect(x: 100, y: 100, w: 100, h: 100);
580 path2.addRect(x: 110, y: 201, w: 100, h: 20);
581 QVERIFY(!path1.intersects(path2));
582 QVERIFY(!path2.intersects(path1));
583 QVERIFY(!path1.contains(path2));
584 QVERIFY(!path2.contains(path1));
585
586 path1 = QPainterPath();
587 path2 = QPainterPath();
588 path1.addRect(x: 0, y: 0, w: 100, h: 100);
589 path2.addRect(x: 20, y: 20, w: 20, h: 20);
590 path2.addRect(x: 25, y: 25, w: 5, h: 5);
591 QVERIFY(path1.intersects(path2));
592 QVERIFY(path2.intersects(path1));
593 QVERIFY(path1.contains(path2));
594 QVERIFY(!path2.contains(path1));
595}
596
597void tst_QPathClipper::testIntersections2()
598{
599 QPainterPath path1;
600 QPainterPath path2;
601
602 path1 = QPainterPath();
603 path2 = QPainterPath();
604
605 path1.moveTo(x: -8,y: -8);
606 path1.lineTo(x: 107,y: -8);
607 path1.lineTo(x: 107,y: 107);
608 path1.lineTo(x: -8,y: 107);
609
610 path2.moveTo(x: 0,y: 0);
611 path2.lineTo(x: 100,y: 0);
612 path2.lineTo(x: 100,y: 100);
613 path2.lineTo(x: 0,y: 100);
614 path2.lineTo(x: 0,y: 0);
615
616 QVERIFY(path1.intersects(path2));
617 QVERIFY(path2.intersects(path1));
618 QVERIFY(path1.contains(path2));
619 QVERIFY(!path2.contains(path1));
620
621 path1.closeSubpath();
622
623 QVERIFY(path1.intersects(path2));
624 QVERIFY(path2.intersects(path1));
625 QVERIFY(path1.contains(path2));
626 QVERIFY(!path2.contains(path1));
627}
628
629void tst_QPathClipper::testIntersections3()
630{
631 QPainterPath path1 = Paths::node();
632 QPainterPath path2 = Paths::interRect();
633
634 QVERIFY(path1.intersects(path2));
635 QVERIFY(path2.intersects(path1));
636}
637
638void tst_QPathClipper::testIntersections4()
639{
640 QPainterPath path1;
641 QPainterPath path2;
642
643 path1.moveTo(x: -5, y: 0);
644 path1.lineTo(x: 5, y: 0);
645
646 path2.moveTo(x: 0, y: -5);
647 path2.lineTo(x: 0, y: 5);
648
649 QVERIFY(path1.intersects(path2));
650 QVERIFY(path2.intersects(path1));
651}
652
653void tst_QPathClipper::testIntersections5()
654{
655 QPainterPath path1;
656 QPainterPath path2;
657
658 path1.addRect(x: 0, y: 0, w: 4, h: 4);
659 path1.addRect(x: 2, y: 1, w: 1, h: 1);
660 path2.addRect(x: 0.5, y: 2, w: 1, h: 1);
661
662 QVERIFY(path1.intersects(path2));
663 QVERIFY(path2.intersects(path1));
664}
665
666void tst_QPathClipper::testIntersections6()
667{
668 QPainterPath path1;
669 QPainterPath path2;
670
671 path1.moveTo(p: QPointF(-115.567, -98.3254));
672 path1.lineTo(p: QPointF(-45.9007, -98.3254));
673 path1.lineTo(p: QPointF(-45.9007, -28.6588));
674 path1.lineTo(p: QPointF(-115.567, -28.6588));
675
676 path2.moveTo(p: QPointF(-110, -110));
677 path2.lineTo(p: QPointF(110, -110));
678 path2.lineTo(p: QPointF(110, 110));
679 path2.lineTo(p: QPointF(-110, 110));
680 path2.lineTo(p: QPointF(-110, -110));
681
682 QVERIFY(path1.intersects(path2));
683 QVERIFY(path2.intersects(path1));
684}
685
686
687void tst_QPathClipper::testIntersections7()
688{
689 QPainterPath path1;
690 QPainterPath path2;
691
692 path1.addRect(x: 0, y: 0, w: 10, h: 10);
693 path2.addRect(x: 5, y: 0, w: 10, h: 10);
694
695 QVERIFY(path1.intersects(path2));
696 QVERIFY(path2.intersects(path1));
697
698 path1 = QPainterPath();
699 path2 = QPainterPath();
700 path1.addRect(x: 0, y: 0, w: 10, h: 10);
701 path2.addRect(x: 0, y: 5, w: 10, h: 10);
702
703 QVERIFY(path1.intersects(path2));
704 QVERIFY(path2.intersects(path1));
705
706 path1 = QPainterPath();
707 path2 = QPainterPath();
708 path1.addRect(x: 0, y: 0, w: 10, h: 10);
709 path2.addRect(x: 0, y: 0, w: 10, h: 10);
710
711 QVERIFY(path1.intersects(path2));
712 QVERIFY(path2.intersects(path1));
713
714 ///
715 path1 = QPainterPath();
716 path2 = QPainterPath();
717 path1.addRect(x: 1, y: 1, w: 10, h: 10);
718 path2.addRect(x: 5, y: 1, w: 10, h: 10);
719
720 QVERIFY(path1.intersects(path2));
721 QVERIFY(path2.intersects(path1));
722
723 path1 = QPainterPath();
724 path2 = QPainterPath();
725 path1.addRect(x: 1, y: 1, w: 10, h: 10);
726 path2.addRect(x: 1, y: 5, w: 10, h: 10);
727
728 QVERIFY(path1.intersects(path2));
729 QVERIFY(path2.intersects(path1));
730
731 path1 = QPainterPath();
732 path2 = QPainterPath();
733 path1.addRect(x: 1, y: 1, w: 10, h: 10);
734 path2.addRect(x: 1, y: 1, w: 10, h: 10);
735
736 QVERIFY(path1.intersects(path2));
737 QVERIFY(path2.intersects(path1));
738
739 path1 = QPainterPath();
740 path2 = QPainterPath();
741 path1.addRect(x: 1, y: 1, w: 10, h: 10);
742 path2.addRect(x: 5, y: 5, w: 10, h: 10);
743
744 QVERIFY(path1.intersects(path2));
745 QVERIFY(path2.intersects(path1));
746
747 path1 = QPainterPath();
748 path2 = QPainterPath();
749 path1.addRect(x: 1, y: 1, w: 10, h: 10);
750 path2.addRect(x: 9, y: 9, w: 10, h: 10);
751
752 QVERIFY(path1.intersects(path2));
753 QVERIFY(path2.intersects(path1));
754
755 path1 = QPainterPath();
756 path2 = QPainterPath();
757 path1.addRect(x: 1, y: 1, w: 10, h: 10);
758 path2.addRect(x: 10, y: 10, w: 10, h: 10);
759
760 QVERIFY(path1.intersects(path2));
761 QVERIFY(path2.intersects(path1));
762
763 path1 = QPainterPath();
764 path2 = QPainterPath();
765 path1.addRect(x: 1, y: 1, w: 9, h: 9);
766 path2.addRect(x: 11, y: 11, w: 10, h: 10);
767
768 QVERIFY(!path1.intersects(path2));
769 QVERIFY(!path2.intersects(path1));
770
771 path1 = QPainterPath();
772 path2 = QPainterPath();
773 path1.addRect(x: 1, y: 1, w: 10, h: 10);
774 path2.addRect(x: 12, y: 12, w: 10, h: 10);
775
776 QVERIFY(!path1.intersects(path2));
777 QVERIFY(!path2.intersects(path1));
778
779 path1 = QPainterPath();
780 path2 = QPainterPath();
781 path1.addRect(x: 11, y: 11, w: 10, h: 10);
782 path2.addRect(x: 12, y: 12, w: 10, h: 10);
783
784 QVERIFY(path1.intersects(path2));
785 QVERIFY(path2.intersects(path1));
786
787 path1 = QPainterPath();
788 path2 = QPainterPath();
789 path1.addRect(x: 11, y: 11, w: 10, h: 10);
790 path2.addRect(x: 10, y: 10, w: 10, h: 10);
791
792 QVERIFY(path1.intersects(path2));
793 QVERIFY(path2.intersects(path1));
794}
795
796
797void tst_QPathClipper::testIntersections8()
798{
799 QPainterPath path1 = Paths::node() * QTransform().translate(dx: 100, dy: 50);
800 QPainterPath path2 = Paths::node() * QTransform().translate(dx: 150, dy: 50);;
801
802 QVERIFY(path1.intersects(path2));
803 QVERIFY(path2.intersects(path1));
804
805 path1 = Paths::node();
806 path2 = Paths::node();
807
808 QVERIFY(path1.intersects(path2));
809 QVERIFY(path2.intersects(path1));
810
811 path1 = Paths::node();
812 path2 = Paths::node() * QTransform().translate(dx: 0, dy: 30);
813
814 QVERIFY(path1.intersects(path2));
815 QVERIFY(path2.intersects(path1));
816
817 path1 = Paths::node();
818 path2 = Paths::node() * QTransform().translate(dx: 30, dy: 0);
819
820 QVERIFY(path1.intersects(path2));
821 QVERIFY(path2.intersects(path1));
822
823 path1 = Paths::node();
824 path2 = Paths::node() * QTransform().translate(dx: 30, dy: 30);
825
826 QVERIFY(path1.intersects(path2));
827 QVERIFY(path2.intersects(path1));
828
829 path1 = Paths::node();
830 path2 = Paths::node() * QTransform().translate(dx: 1, dy: 1);
831
832 QVERIFY(path1.intersects(path2));
833 QVERIFY(path2.intersects(path1));
834}
835
836
837void tst_QPathClipper::testIntersections9()
838{
839 QPainterPath path1;
840 QPainterPath path2;
841
842 path1.addRect(rect: QRectF(-1,143, 146, 106));
843 path2.addRect(rect: QRectF(-9,145, 150, 100));
844
845 QVERIFY(path1.intersects(path2));
846 QVERIFY(path2.intersects(path1));
847
848 path1 = QPainterPath();;
849 path2 = QPainterPath();
850
851 path1.addRect(rect: QRectF(-1,191, 136, 106));
852 path2.addRect(rect: QRectF(-19,194, 150, 100));
853 QVERIFY(path1.intersects(path2));
854 QVERIFY(path2.intersects(path1));
855
856 path1 = QPainterPath();;
857 path2 = QPainterPath();
858
859 path1.moveTo(x: -1 , y: 143);
860 path1.lineTo(x: 148 , y: 143);
861 path1.lineTo(x: 148 , y: 250);
862 path1.lineTo(x: -1 , y: 250);
863
864 path2.moveTo(x: -5 , y: 146);
865 path2.lineTo(x: 145 , y: 146);
866 path2.lineTo(x: 145 , y: 246);
867 path2.lineTo(x: -5 , y: 246);
868 path2.lineTo(x: -5 , y: 146);
869
870 QVERIFY(path1.intersects(path2));
871 QVERIFY(path2.intersects(path1));
872}
873
874QPainterPath pathFromRect(qreal x, qreal y, qreal w, qreal h)
875{
876 QPainterPath path;
877 path.addRect(rect: QRectF(x, y, w, h));
878 return path;
879}
880
881QPainterPath pathFromLine(qreal x1, qreal y1, qreal x2, qreal y2)
882{
883 QPainterPath path;
884 path.moveTo(x: x1, y: y1);
885 path.lineTo(x: x2, y: y2);
886 return path;
887}
888
889static int loopLength(const QWingedEdge &list, QWingedEdge::TraversalStatus status)
890{
891 int start = status.edge;
892
893 int length = 0;
894 do {
895 ++length;
896 status = list.next(status);
897 } while (status.edge != start);
898
899 return length;
900}
901
902void tst_QPathClipper::testWingedEdge()
903{
904 {
905 QWingedEdge list;
906 int e1 = list.addEdge(a: QPointF(0, 0), b: QPointF(10, 0));
907 int e2 = list.addEdge(a: QPointF(0, 0), b: QPointF(0, 10));
908 int e3 = list.addEdge(a: QPointF(0, 0), b: QPointF(-10, 0));
909 int e4 = list.addEdge(a: QPointF(0, 0), b: QPointF(0, -10));
910
911 QCOMPARE(list.edgeCount(), 4);
912 QCOMPARE(list.vertexCount(), 5);
913
914 QWingedEdge::TraversalStatus status = { .edge: e1, .traversal: QPathEdge::RightTraversal, .direction: QPathEdge::Forward };
915
916 status = list.next(status);
917 QCOMPARE(status.direction, QPathEdge::Backward);
918 QCOMPARE(status.traversal, QPathEdge::LeftTraversal);
919 QCOMPARE(status.edge, e1);
920
921 status = list.next(status);
922 QCOMPARE(status.direction, QPathEdge::Forward);
923 QCOMPARE(status.traversal, QPathEdge::RightTraversal);
924 QCOMPARE(status.edge, e4);
925
926 status = list.next(status);
927 QCOMPARE(status.direction, QPathEdge::Backward);
928 QCOMPARE(status.traversal, QPathEdge::LeftTraversal);
929 QCOMPARE(status.edge, e4);
930
931 status = list.next(status);
932 QCOMPARE(status.direction, QPathEdge::Forward);
933 QCOMPARE(status.traversal, QPathEdge::RightTraversal);
934 QCOMPARE(status.edge, e3);
935
936 status = list.next(status);
937 QCOMPARE(status.direction, QPathEdge::Backward);
938 QCOMPARE(status.traversal, QPathEdge::LeftTraversal);
939 QCOMPARE(status.edge, e3);
940
941 status = list.next(status);
942 QCOMPARE(status.direction, QPathEdge::Forward);
943 QCOMPARE(status.traversal, QPathEdge::RightTraversal);
944 QCOMPARE(status.edge, e2);
945
946 status = list.next(status);
947 QCOMPARE(status.direction, QPathEdge::Backward);
948 QCOMPARE(status.traversal, QPathEdge::LeftTraversal);
949 QCOMPARE(status.edge, e2);
950
951 status = list.next(status);
952 QCOMPARE(status.direction, QPathEdge::Forward);
953 QCOMPARE(status.traversal, QPathEdge::RightTraversal);
954 QCOMPARE(status.edge, e1);
955 }
956 {
957 QWingedEdge list;
958 int e1 = list.addEdge(a: QPointF(5, 0), b: QPointF(5, 10));
959 int e2 = list.addEdge(a: QPointF(5, 0), b: QPointF(10, 5));
960 int e3 = list.addEdge(a: QPointF(10, 5), b: QPointF(5, 10));
961 int e4 = list.addEdge(a: QPointF(5, 0), b: QPointF(0, 5));
962 int e5 = list.addEdge(a: QPointF(0, 5), b: QPointF(5, 10));
963
964 QCOMPARE(list.edgeCount(), 5);
965 QCOMPARE(list.vertexCount(), 4);
966
967 QWingedEdge::TraversalStatus status = { .edge: e1, .traversal: QPathEdge::RightTraversal, .direction: QPathEdge::Forward };
968
969 status = list.next(status);
970 QCOMPARE(status.direction, QPathEdge::Backward);
971 QCOMPARE(status.traversal, QPathEdge::LeftTraversal);
972 QCOMPARE(status.edge, e5);
973
974 status = list.next(status);
975 QCOMPARE(status.direction, QPathEdge::Backward);
976 QCOMPARE(status.traversal, QPathEdge::LeftTraversal);
977 QCOMPARE(status.edge, e4);
978
979 status = list.next(status);
980 QCOMPARE(status.direction, QPathEdge::Forward);
981 QCOMPARE(status.traversal, QPathEdge::RightTraversal);
982 QCOMPARE(status.edge, e1);
983
984 QCOMPARE(loopLength(list, status), 3);
985
986 status.flip();
987 QCOMPARE(status.direction, QPathEdge::Backward);
988 QCOMPARE(status.traversal, QPathEdge::LeftTraversal);
989 QCOMPARE(loopLength(list, status), 3);
990
991 status = list.next(status);
992 QCOMPARE(status.direction, QPathEdge::Forward);
993 QCOMPARE(status.traversal, QPathEdge::RightTraversal);
994 QCOMPARE(status.edge, e2);
995
996 status = list.next(status);
997 QCOMPARE(status.direction, QPathEdge::Forward);
998 QCOMPARE(status.traversal, QPathEdge::RightTraversal);
999 QCOMPARE(status.edge, e3);
1000
1001 status = list.next(status);
1002 QCOMPARE(status.direction, QPathEdge::Backward);
1003 QCOMPARE(status.traversal, QPathEdge::LeftTraversal);
1004 QCOMPARE(status.edge, e1);
1005
1006 status = list.next(status);
1007 status.flip();
1008 QCOMPARE(status.direction, QPathEdge::Backward);
1009 QCOMPARE(status.traversal, QPathEdge::LeftTraversal);
1010 QCOMPARE(status.edge, e2);
1011 QCOMPARE(loopLength(list, status), 4);
1012
1013 status = list.next(status);
1014 QCOMPARE(status.direction, QPathEdge::Forward);
1015 QCOMPARE(status.traversal, QPathEdge::RightTraversal);
1016 QCOMPARE(status.edge, e4);
1017
1018 status = list.next(status);
1019 QCOMPARE(status.direction, QPathEdge::Forward);
1020 QCOMPARE(status.traversal, QPathEdge::RightTraversal);
1021 QCOMPARE(status.edge, e5);
1022
1023 status = list.next(status);
1024 QCOMPARE(status.direction, QPathEdge::Backward);
1025 QCOMPARE(status.traversal, QPathEdge::LeftTraversal);
1026 QCOMPARE(status.edge, e3);
1027
1028 status = list.next(status);
1029 QCOMPARE(status.direction, QPathEdge::Backward);
1030 QCOMPARE(status.traversal, QPathEdge::LeftTraversal);
1031 QCOMPARE(status.edge, e2);
1032 }
1033 {
1034 QPainterPath path = pathFromRect(x: 0, y: 0, w: 20, h: 20);
1035 QWingedEdge list(path, QPainterPath());
1036
1037 QCOMPARE(list.edgeCount(), 4);
1038 QCOMPARE(list.vertexCount(), 4);
1039
1040 QWingedEdge::TraversalStatus status = { .edge: 0, .traversal: QPathEdge::RightTraversal, .direction: QPathEdge::Forward };
1041
1042 QPathEdge *edge = list.edge(edge: status.edge);
1043 QCOMPARE(QPointF(*list.vertex(edge->first)), QPointF(0, 0));
1044 QCOMPARE(QPointF(*list.vertex(edge->second)), QPointF(20, 0));
1045
1046 status = list.next(status);
1047 QCOMPARE(status.edge, 1);
1048
1049 status = list.next(status);
1050 QCOMPARE(status.edge, 2);
1051
1052 status = list.next(status);
1053 QCOMPARE(status.edge, 3);
1054
1055 status = list.next(status);
1056 QCOMPARE(status.edge, 0);
1057
1058 status.flipDirection();
1059 status = list.next(status);
1060 QCOMPARE(status.edge, 3);
1061
1062 status = list.next(status);
1063 QCOMPARE(status.edge, 2);
1064
1065 status = list.next(status);
1066 QCOMPARE(status.edge, 1);
1067
1068 status = list.next(status);
1069 QCOMPARE(status.edge, 0);
1070
1071 QWingedEdge list2(path, pathFromRect(x: 10, y: 5, w: 20, h: 10));
1072
1073 QCOMPARE(list2.edgeCount(), 12);
1074 QCOMPARE(list2.vertexCount(), 10);
1075
1076 status.flipDirection();
1077 QCOMPARE(loopLength(list2, status), 8);
1078
1079 status = list2.next(status);
1080 edge = list2.edge(edge: status.edge);
1081 QCOMPARE(QPointF(*list2.vertex(edge->first)), QPointF(20, 0));
1082 QCOMPARE(QPointF(*list2.vertex(edge->second)), QPointF(20, 5));
1083
1084 status = list2.next(status);
1085 status.flipTraversal();
1086
1087 edge = list2.edge(edge: status.edge);
1088 QCOMPARE(QPointF(*list2.vertex(edge->first)), QPointF(10, 5));
1089 QCOMPARE(QPointF(*list2.vertex(edge->second)), QPointF(20, 5));
1090
1091 QCOMPARE(loopLength(list2, status), 4);
1092
1093 status.flipDirection();
1094 status = list2.next(status);
1095 status.flipTraversal();
1096
1097 edge = list2.edge(edge: status.edge);
1098 QCOMPARE(QPointF(*list2.vertex(edge->first)), QPointF(20, 5));
1099 QCOMPARE(QPointF(*list2.vertex(edge->second)), QPointF(20, 15));
1100
1101 QCOMPARE(loopLength(list2, status), 4);
1102 status = list2.next(status);
1103 status = list2.next(status);
1104
1105 edge = list2.edge(edge: status.edge);
1106 QCOMPARE(QPointF(*list2.vertex(edge->first)), QPointF(30, 5));
1107 QCOMPARE(QPointF(*list2.vertex(edge->second)), QPointF(30, 15));
1108 }
1109}
1110
1111void tst_QPathClipper::zeroDerivativeCurves()
1112{
1113 // zero derivative at end
1114 {
1115 QPainterPath a;
1116 a.cubicTo(ctrlPt1x: 100, ctrlPt1y: 0, ctrlPt2x: 100, ctrlPt2y: 100, endPtx: 100, endPty: 100);
1117 a.lineTo(x: 100, y: 200);
1118 a.lineTo(x: 0, y: 200);
1119
1120 QPainterPath b;
1121 b.moveTo(x: 50, y: 100);
1122 b.lineTo(x: 150, y: 100);
1123 b.lineTo(x: 150, y: 150);
1124 b.lineTo(x: 50, y: 150);
1125
1126 QPainterPath c = a.united(r: b);
1127 QVERIFY(c.contains(QPointF(25, 125)));
1128 QVERIFY(c.contains(QPointF(75, 125)));
1129 QVERIFY(c.contains(QPointF(125, 125)));
1130 }
1131
1132 // zero derivative at start
1133 {
1134 QPainterPath a;
1135 a.cubicTo(ctrlPt1x: 100, ctrlPt1y: 0, ctrlPt2x: 100, ctrlPt2y: 100, endPtx: 100, endPty: 100);
1136 a.lineTo(x: 100, y: 200);
1137 a.lineTo(x: 0, y: 200);
1138
1139 QPainterPath b;
1140 b.moveTo(x: 50, y: 100);
1141 b.lineTo(x: 150, y: 100);
1142 b.lineTo(x: 150, y: 150);
1143 b.lineTo(x: 50, y: 150);
1144
1145 QPainterPath c = a.united(r: b);
1146 QVERIFY(c.contains(QPointF(25, 125)));
1147 QVERIFY(c.contains(QPointF(75, 125)));
1148 QVERIFY(c.contains(QPointF(125, 125)));
1149 }
1150}
1151
1152static bool strictContains(const QPainterPath &a, const QPainterPath &b)
1153{
1154 return b.subtracted(r: a) == QPainterPath();
1155}
1156
1157
1158void tst_QPathClipper::task204301_data()
1159{
1160 QTest::addColumn<QPolygonF>(name: "points");
1161
1162 {
1163 QPointF a(51.09013255685567855835, 31.30814891308546066284);
1164 QPointF b(98.39898971840739250183, 11.02079074829816818237);
1165 QPointF c(91.23911846894770860672, 45.86981737054884433746);
1166 QPointF d(66.58616356085985898972, 63.10526528395712375641);
1167 QPointF e(82.08219456479714892794, 94.90238165489137145414);
1168 QPointF f(16.09013040543221251255, 105.66263409332729850121);
1169 QPointF g(10.62811442650854587555, 65.09154842235147953033);
1170 QPointF h(5.16609844751656055450, 24.52046275138854980469);
1171 QPolygonF v;
1172 v << a << b << c << d << e << f << g << h;
1173 QTest::newRow(dataTag: "failed_on_linux") << v;
1174 }
1175
1176 {
1177 QPointF a(50.014648437500000, 24.392089843750000);
1178 QPointF b(92.836303710937500, 5.548706054687500);
1179 QPointF c(92.145690917968750, 54.390258789062500);
1180 QPointF d(65.402221679687500, 74.345092773437500);
1181 QPointF e(80.789794921787347, 124.298095703129690);
1182 QPointF f(34.961242675812954, 87.621459960852135);
1183 QPointF g(18.305969238281250, 57.426757812500000);
1184 QPointF h(1.650695800781250, 27.232055664062500);
1185 QPolygonF v;
1186 v << a << b << c << d << e << f << g << h;
1187 QTest::newRow(dataTag: "failed_on_windows") << v;
1188 }
1189}
1190
1191void tst_QPathClipper::task204301()
1192{
1193 QFETCH(QPolygonF, points);
1194
1195 QPointF a = points[0];
1196 QPointF b = points[1];
1197 QPointF c = points[2];
1198 QPointF d = points[3];
1199 QPointF e = points[4];
1200 QPointF f = points[5];
1201 QPointF g = points[6];
1202 QPointF h = points[7];
1203
1204 QPainterPath subA;
1205 subA.addPolygon(polygon: QPolygonF() << a << b << c << d);
1206 subA.closeSubpath();
1207
1208 QPainterPath subB;
1209 subB.addPolygon(polygon: QPolygonF() << f << e << d << g);
1210 subB.closeSubpath();
1211
1212 QPainterPath subC;
1213 subC.addPolygon(polygon: QPolygonF() << h << a << d << g);
1214 subC.closeSubpath();
1215
1216 QPainterPath path;
1217 path.addPath(path: subA);
1218 path.addPath(path: subB);
1219 path.addPath(path: subC);
1220
1221 QPainterPath simplified = path.simplified();
1222
1223 QVERIFY(strictContains(simplified, subA));
1224 QVERIFY(strictContains(simplified, subB));
1225 QVERIFY(strictContains(simplified, subC));
1226}
1227
1228void tst_QPathClipper::task209056()
1229{
1230 QPainterPath p1;
1231 p1.moveTo( p: QPointF(188.506, 287.793) );
1232 p1.lineTo( p: QPointF(288.506, 287.793) );
1233 p1.lineTo( p: QPointF(288.506, 387.793) );
1234 p1.lineTo( p: QPointF(188.506, 387.793) );
1235 p1.lineTo( p: QPointF(188.506, 287.793) );
1236
1237 QPainterPath p2;
1238 p2.moveTo( p: QPointF(419.447, 164.383) );
1239 p2.cubicTo( ctrlPt1: QPointF(419.447, 69.5486), ctrlPt2: QPointF(419.447, 259.218),endPt: QPointF(419.447, 164.383) );
1240
1241 p2.cubicTo( ctrlPt1: QPointF(48.9378, 259.218), ctrlPt2: QPointF(131.879, 336.097),endPt: QPointF(234.192, 336.097) );
1242 p2.cubicTo( ctrlPt1: QPointF(336.506, 336.097), ctrlPt2: QPointF(419.447, 259.218),endPt: QPointF(419.447, 164.383) );
1243
1244 QPainterPath p3 = p1.intersected(r: p2);
1245
1246 QVERIFY(p3 != QPainterPath());
1247}
1248
1249void tst_QPathClipper::task251909()
1250{
1251 QPainterPath p1;
1252 p1.moveTo(x: 0, y: -10);
1253 p1.lineTo(x: 10, y: -10);
1254 p1.lineTo(x: 10, y: 0);
1255 p1.lineTo(x: 0, y: 0);
1256
1257 QPainterPath p2;
1258 p2.moveTo(x: 0, y: 8e-14);
1259 p2.lineTo(x: 10, y: -8e-14);
1260 p2.lineTo(x: 10, y: 10);
1261 p2.lineTo(x: 0, y: 10);
1262
1263 QPainterPath result = p1.united(r: p2);
1264
1265 QVERIFY(result.elementCount() <= 5);
1266}
1267
1268void tst_QPathClipper::qtbug3778()
1269{
1270 if (sizeof(double) != sizeof(qreal)) {
1271 QSKIP("This test only works for qreal=double, otherwise ends in rounding errors");
1272 }
1273 QPainterPath path1;
1274 path1.moveTo(x: 200, y: 3.22409e-5);
1275 // e-5 and higher leads to a bug
1276 // Using 3.22409e-4 starts to work correctly
1277 path1.lineTo(x: 0, y: 0);
1278 path1.lineTo(x: 1.07025e-13, y: 1450);
1279 path1.lineTo(x: 750, y: 950);
1280 path1.lineTo(x: 950, y: 750);
1281 path1.lineTo(x: 200, y: 3.22409e-13);
1282
1283 QPainterPath path2;
1284 path2.moveTo(x: 0, y: 0);
1285 path2.lineTo(x: 200, y: 800);
1286 path2.lineTo(x: 600, y: 1500);
1287 path2.lineTo(x: 1500, y: 1400);
1288 path2.lineTo(x: 1900, y: 1200);
1289 path2.lineTo(x: 2000, y: 1000);
1290 path2.lineTo(x: 1400, y: 0);
1291 path2.lineTo(x: 0, y: 0);
1292
1293 QPainterPath p12 = path1.intersected(r: path2);
1294
1295 QVERIFY(p12.contains(QPointF(100, 100)));
1296}
1297
1298void tst_QPathClipper::qtbug60024()
1299{
1300 QPolygonF poly1, poly2;
1301 poly1 << QPointF(508.331,1010.23) ;
1302 poly1 << QPointF(492.798,1023.11) ;
1303 poly1 << QPointF(491.431,1024.23) ;
1304 poly1 << QPointF(491.928,1022.94) ;
1305 poly1 << QPointF(492.054,1022.15) ;
1306 poly1 << QPointF(492.136,1020.91) ;
1307 poly1 << QPointF(491.638,1019.2) ;
1308 poly1 << QPointF(490.436,1017.12) ;
1309 poly1 << QPointF(489.856,1016.46) ;
1310 poly1 << QPointF(489.276,1016.08) ;
1311 poly1 << QPointF(488.16,1015.54) ;
1312 poly1 << QPointF(487.33,1014.91) ;
1313 poly1 << QPointF(486.914,1014.16) ;
1314 poly1 << QPointF(486.875,1013.54) ;
1315 poly1 << QPointF(487.204,1012.38) ;
1316 poly1 << QPointF(487.412,1011.34) ;
1317 poly1 << QPointF(487.373,1009.92) ;
1318 poly1 << QPointF(487.702,1007.34) ;
1319 poly1 << QPointF(487.909,1006.3) ;
1320 poly1 << QPointF(488.242,1005.55) ;
1321 poly1 << QPointF(488.74,1004.14) ;
1322 poly1 << QPointF(489.445,1003.14) ;
1323 poly1 << QPointF(490.107,1001.56) ;
1324 poly1 << QPointF(490.064,1000.98) ;
1325 poly1 << QPointF(489.566,999.936) ;
1326 poly1 << QPointF(488.489,998.194) ;
1327 poly1 << QPointF(488.117,997.274) ;
1328 poly1 << QPointF(487.909,995.946) ;
1329 poly1 << QPointF(487.909,995.027) ;
1330 poly1 << QPointF(488.117,993.16) ;
1331 poly1 << QPointF(488.658,989.749) ;
1332 poly1 << QPointF(488.861,987.002) ;
1333 poly1 << QPointF(489.359,976.434) ;
1334 poly1 << QPointF(489.484,974.476) ;
1335 poly1 << QPointF(489.484,972.859) ;
1336 poly1 << QPointF(489.359,971.775) ;
1337 poly1 << QPointF(489.151,970.986) ;
1338 poly1 << QPointF(488.948,969.323) ;
1339 poly1 << QPointF(488.74,966.036) ;
1340 poly1 << QPointF(488.74,964.118) ;
1341 poly1 << QPointF(489.03,961.292) ;
1342 poly1 << QPointF(489.237,960.667) ;
1343 poly1 << QPointF(489.648,960.043) ;
1344 poly1 << QPointF(490.452,959.229) ;
1345 poly1 << QPointF(491.528,958.225) ;
1346 poly1 << QPointF(491.731,957.515) ;
1347 poly1 << QPointF(491.32,956.812) ;
1348 poly1 << QPointF(490.45,955.852) ;
1349 poly1 << QPointF(489.412,954.354) ;
1350 poly1 << QPointF(488.68,952.934) ;
1351 poly1 << QPointF(488.625,951.201) ;
1352 poly1 << QPointF(488.954,950.072) ;
1353 poly1 << QPointF(489.237,949.225) ;
1354 poly1 << QPointF(489.256,948.668) ;
1355 poly1 << QPointF(489.402,948.186) ;
1356 poly1 << QPointF(489.566,947.437) ;
1357 poly1 << QPointF(490.025,945.899) ;
1358 poly1 << QPointF(490.687,944.026) ;
1359 poly1 << QPointF(491.059,942.073) ;
1360 poly1 << QPointF(491.31,941.159) ;
1361 poly1 << QPointF(491.846,937.248) ;
1362 poly1 << QPointF(492.054,936.374) ;
1363 poly1 << QPointF(492.594,935.29) ;
1364 poly1 << QPointF(492.594,935.086) ;
1365 poly1 << QPointF(492.261,934.416) ;
1366 poly1 << QPointF(492.054,933.377) ;
1367 poly1 << QPointF(492.054,932.628) ;
1368 poly1 << QPointF(492.798,929.217) ;
1369 poly1 << QPointF(493.174,928.217) ;
1370 poly1 << QPointF(493.005,927.514) ;
1371 poly1 << QPointF(492.923,926.719) ;
1372 poly1 << QPointF(493.295,921.44) ;
1373 poly1 << QPointF(493.421,919.771) ;
1374 poly1 << QPointF(493.628,914.492) ;
1375 poly1 << QPointF(493.71,913.158) ;
1376 poly1 << QPointF(493.961,910.831) ;
1377 poly1 << QPointF(494.623,909.247) ;
1378 poly1 << QPointF(495.41,906.085) ;
1379 poly1 << QPointF(495.203,905.421) ;
1380 poly1 << QPointF(494.788,904.632) ;
1381 poly1 << QPointF(494.705,904.297) ;
1382 poly1 << QPointF(494.788,903.797) ;
1383 poly1 << QPointF(495.121,902.844) ;
1384 poly1 << QPointF(495.493,902.055) ;
1385 poly1 << QPointF(496.033,900.556) ;
1386 poly1 << QPointF(496.28,900.096) ;
1387 poly1 << QPointF(496.488,899.222) ;
1388 poly1 << QPointF(496.28,898.723) ;
1389 poly1 << QPointF(495.41,898.098) ;
1390 poly1 << QPointF(494.326,898.084) ;
1391 poly1 << QPointF(493.993,897.42) ;
1392 poly1 << QPointF(493.829,896.67) ;
1393 poly1 << QPointF(493.621,894.962) ;
1394 poly1 << QPointF(493.565,893.93) ;
1395 poly1 << QPointF(494.416,893.358) ;
1396 poly1 << QPointF(501.666,887.435) ;
1397 poly1 << QPointF(513.305,877.908) ;
1398 poly1 << QPointF(523.795,869.356) ;
1399 poly1 << QPointF(603.378,804.221) ;
1400 poly1 << QPointF(618.764,791.762) ;
1401 poly1 << QPointF(618.981,791.584) ;
1402 poly1 << QPointF(634.696,778.743) ;
1403 poly1 << QPointF(673.531,747.007) ;
1404 poly1 << QPointF(726.115,704.031) ;
1405 poly1 << QPointF(759.04,677.12) ;
1406 poly1 << QPointF(759.672,676.62) ;
1407 poly1 << QPointF(778.846,660.773) ;
1408 poly1 << QPointF(789.919,651.709) ;
1409 poly1 << QPointF(810.528,634.696) ;
1410 poly1 << QPointF(810.804,634.468) ;
1411 poly1 << QPointF(818.197,628.365) ;
1412 poly1 << QPointF(826.44,621.505) ;
1413 poly1 << QPointF(832.634,616.351) ;
1414 poly1 << QPointF(835.337,614.05) ;
1415 poly1 << QPointF(835.492,613.931) ;
1416 poly1 << QPointF(852.079,600.176) ;
1417 poly1 << QPointF(860.469,593.219) ;
1418 poly1 << QPointF(869.883,585.411) ;
1419 poly1 << QPointF(896.749,563.131) ;
1420 poly1 << QPointF(922.094,542.111) ;
1421 poly1 << QPointF(936.469,530.189) ;
1422 poly1 << QPointF(990.034,485.759) ;
1423 poly1 << QPointF(1001.65,476.123) ;
1424 poly1 << QPointF(1010.87,468.472) ;
1425 poly1 << QPointF(1028.6,453.769) ;
1426 poly1 << QPointF(1095.89,397.341) ;
1427 poly1 << QPointF(1130.52,368.297) ;
1428 poly1 << QPointF(1135.05,364.497) ;
1429 poly1 << QPointF(1123.55,337.582) ;
1430 poly1 << QPointF(1103.42,290.476) ;
1431 poly1 << QPointF(1095.21,271.259) ;
1432 poly1 << QPointF(1068.04,207.66) ;
1433 poly1 << QPointF(1051.62,169.118) ;
1434 poly1 << QPointF(1038.65,138.708) ;
1435 poly1 << QPointF(1027.81,113.269) ;
1436 poly1 << QPointF(1020.97,97.2145) ;
1437 poly1 << QPointF(1010.84,73.4644) ;
1438 poly1 << QPointF(988.424,20.9198) ;
1439 poly1 << QPointF(968.442,-25.9307) ;
1440 poly1 << QPointF(964.63,-34.8693) ;
1441 poly1 << QPointF(961.883,-41.3111) ;
1442 poly1 << QPointF(953.157,-61.929) ;
1443 poly1 << QPointF(949.712,-70.0717) ;
1444 poly1 << QPointF(946.048,-78.7331) ;
1445 poly1 << QPointF(945.789,-79.3443) ;
1446 poly1 << QPointF(945.548,-79.9146) ;
1447 poly1 << QPointF(941.671,-89.0782) ;
1448 poly1 << QPointF(940.408,-92.0616) ;
1449 poly1 << QPointF(940.095,-92.8021) ;
1450 poly1 << QPointF(938.65,-97.1094) ;
1451 poly1 << QPointF(934.565,-106.581) ;
1452 poly1 << QPointF(928.429,-121.542) ;
1453 poly1 << QPointF(928.24,-122.003) ;
1454 poly1 << QPointF(920.902,-139.241) ;
1455 poly1 << QPointF(910.85,-162.115) ;
1456 poly1 << QPointF(910.744,-162.357) ;
1457 poly1 << QPointF(900.875,-186.271) ;
1458 poly1 << QPointF(889.416,-213.089) ;
1459 poly1 << QPointF(883.705,-226.225) ;
1460 poly1 << QPointF(882.788,-228.422) ;
1461 poly1 << QPointF(881.399,-231.753) ;
1462 poly1 << QPointF(880.373,-234.213) ;
1463 poly1 << QPointF(875.788,-245.204) ;
1464 poly1 << QPointF(872.772,-252.085) ;
1465 poly1 << QPointF(869.686,-259.126) ;
1466 poly1 << QPointF(865.607,-268.43) ;
1467 poly1 << QPointF(868.74,-269.605) ;
1468 poly1 << QPointF(869.315,-269.834) ;
1469 poly1 << QPointF(879.443,-273.853) ;
1470 poly1 << QPointF(880.259,-274.217) ;
1471 poly1 << QPointF(888.958,-278.09) ;
1472 poly1 << QPointF(894.204,-280.426) ;
1473 poly1 << QPointF(902.866,-284.423) ;
1474 poly1 << QPointF(913.804,-289.072) ;
1475 poly1 << QPointF(917.975,-290.846) ;
1476 poly1 << QPointF(921.854,-292.375) ;
1477 poly1 << QPointF(930.52,-295.793) ;
1478 poly1 << QPointF(939.972,-299.79) ;
1479 poly1 << QPointF(940.899,-300.183) ;
1480 poly1 << QPointF(943.262,-294.709) ;
1481 poly1 << QPointF(946.922,-286.233) ;
1482 poly1 << QPointF(952.358,-273.643) ;
1483 poly1 << QPointF(959.976,-256) ;
1484 poly1 << QPointF(975.219,-220.296) ;
1485 poly1 << QPointF(988.991,-188.494) ;
1486 poly1 << QPointF(990.089,-185.959) ;
1487 poly1 << QPointF(1001.86,-158.88) ;
1488 poly1 << QPointF(1003.8,-154.245) ;
1489 poly1 << QPointF(1011.55,-135.749) ;
1490 poly1 << QPointF(1012.2,-134.199) ;
1491 poly1 << QPointF(1012.77,-132.837) ;
1492 poly1 << QPointF(1015.9,-125.529) ;
1493 poly1 << QPointF(1015.99,-125.305) ;
1494 poly1 << QPointF(1016.42,-124.299) ;
1495 poly1 << QPointF(1018.02,-120.569) ;
1496 poly1 << QPointF(1018.47,-119.395) ;
1497 poly1 << QPointF(1028.09,-97.0593) ;
1498 poly1 << QPointF(1028.89,-95.1902) ;
1499 poly1 << QPointF(1032.85,-85.957) ;
1500 poly1 << QPointF(1044.48,-58.8103) ;
1501 poly1 << QPointF(1047.23,-52.3933) ;
1502 poly1 << QPointF(1076.35,15.5527) ;
1503 poly1 << QPointF(1089.43,46.0648) ;
1504 poly1 << QPointF(1105.35,83.1913) ;
1505 poly1 << QPointF(1120.01,117.391) ;
1506 poly1 << QPointF(1131.66,144.66) ;
1507 poly1 << QPointF(1142.1,169.072) ;
1508 poly1 << QPointF(1183.42,265.698) ;
1509 poly1 << QPointF(1200.9,306.583) ;
1510 poly1 << QPointF(1208.48,324.306) ;
1511 poly1 << QPointF(1231.19,377.389) ;
1512 poly1 << QPointF(1241.55,400.064) ;
1513 poly1 << QPointF(1139.56,485.759) ;
1514 poly1 << QPointF(1104.96,514.822) ;
1515 poly1 << QPointF(1044.32,565.761) ;
1516 poly1 << QPointF(1020.92,585.411) ;
1517 poly1 << QPointF(1013.72,591.462) ;
1518 poly1 << QPointF(1012.73,592.285) ;
1519 poly1 << QPointF(926.449,663.776) ;
1520 poly1 << QPointF(843.981,732.099) ;
1521 poly1 << QPointF(826.923,746.23) ;
1522 poly1 << QPointF(810.856,759.539) ;
1523 poly1 << QPointF(736.788,820.887) ;
1524 poly1 << QPointF(709.695,843.348) ;
1525 poly1 << QPointF(693.265,856.967) ;
1526 poly1 << QPointF(690.228,859.484) ;
1527 poly1 << QPointF(673.813,873.091) ;
1528 poly1 << QPointF(672.34,874.317) ;
1529 poly1 << QPointF(618.453,919.164) ;
1530 poly1 << QPointF(607.821,928.011) ;
1531 poly1 << QPointF(596.057,937.538) ;
1532 poly1 << QPointF(580.774,950.204) ;
1533 poly1 << QPointF(573.229,956.457) ;
1534 poly1 << QPointF(533.091,989.719) ;
1535 poly1 << QPointF(513.657,1005.86) ;
1536 poly1 << QPointF(508.331,1010.23) ;
1537
1538 poly2 << QPointF(941.306,435.236) ;
1539 poly2 << QPointF(983.306,435.236) ;
1540 poly2 << QPointF(983.306,473.236) ;
1541 poly2 << QPointF(941.306,473.236) ;
1542 poly2 << QPointF(941.306,435.236) ;
1543
1544 QPainterPath path1, path2;
1545 path1.addPolygon(polygon: poly1);
1546 path2.addPolygon(polygon: poly2);
1547
1548 QVERIFY(!path1.intersects(path2));
1549 QVERIFY(path1.intersected(path2).isEmpty());
1550}
1551
1552QTEST_MAIN(tst_QPathClipper)
1553
1554
1555#include "tst_qpathclipper.moc"
1556

source code of qtbase/tests/auto/gui/painting/qpathclipper/tst_qpathclipper.cpp