Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qpainterpath.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qpainterpath.h"
5#include "qpainterpath_p.h"
6
7#include <qbitmap.h>
8#include <qdebug.h>
9#include <qiodevice.h>
10#include <qlist.h>
11#include <qpen.h>
12#include <qpolygon.h>
13#include <qtextlayout.h>
14#include <qvarlengtharray.h>
15#include <qmath.h>
16
17#include <private/qbezier_p.h>
18#include <private/qfontengine_p.h>
19#include <private/qnumeric_p.h>
20#include <private/qobject_p.h>
21#include <private/qpathclipper_p.h>
22#include <private/qstroker_p.h>
23#include <private/qtextengine_p.h>
24
25#include <limits.h>
26
27#if 0
28#include <performance.h>
29#else
30#define PM_INIT
31#define PM_MEASURE(x)
32#define PM_DISPLAY
33#endif
34
36
37static inline bool isValidCoord(qreal c)
38{
39 if (sizeof(qreal) >= sizeof(double))
40 return qIsFinite(c) && fabs(c) < 1e128;
41 else
42 return qIsFinite(c) && fabsf(float(c)) < 1e16f;
43}
44
46{
47 return isValidCoord(p.x()) && isValidCoord(p.y());
48}
49
51{
52 return isValidCoord(r.x()) && isValidCoord(r.y()) && isValidCoord(r.width()) && isValidCoord(r.height());
53}
54
55// This value is used to determine the length of control point vectors
56// when approximating arc segments as curves. The factor is multiplied
57// with the radius of the circle.
58
59// #define QPP_DEBUG
60// #define QPP_STROKE_DEBUG
61//#define QPP_FILLPOLYGONS_DEBUG
62
64
66 QPointF* startPoint, QPointF *endPoint)
67{
68 if (r.isNull()) {
69 if (startPoint)
70 *startPoint = QPointF();
71 if (endPoint)
72 *endPoint = QPointF();
73 return;
74 }
75
76 qreal w2 = r.width() / 2;
77 qreal h2 = r.height() / 2;
78
79 qreal angles[2] = { angle, angle + length };
80 QPointF *points[2] = { startPoint, endPoint };
81
82 for (int i = 0; i < 2; ++i) {
83 if (!points[i])
84 continue;
85
86 qreal theta = angles[i] - 360 * qFloor(angles[i] / 360);
87 qreal t = theta / 90;
88 // truncate
89 int quadrant = int(t);
90 t -= quadrant;
91
92 t = qt_t_for_arc_angle(90 * t);
93
94 // swap x and y?
95 if (quadrant & 1)
96 t = 1 - t;
97
98 qreal a, b, c, d;
101
102 // left quadrants
103 if (quadrant == 1 || quadrant == 2)
104 p.rx() = -p.x();
105
106 // top quadrants
107 if (quadrant == 0 || quadrant == 1)
108 p.ry() = -p.y();
109
110 *points[i] = r.center() + QPointF(w2 * p.x(), h2 * p.y());
111 }
112}
113
114#ifdef QPP_DEBUG
115static void qt_debug_path(const QPainterPath &path)
116{
117 const char *names[] = {
118 "MoveTo ",
119 "LineTo ",
120 "CurveTo ",
121 "CurveToData"
122 };
123
124 printf("\nQPainterPath: elementCount=%d\n", path.elementCount());
125 for (int i=0; i<path.elementCount(); ++i) {
126 const QPainterPath::Element &e = path.elementAt(i);
127 Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
128 printf(" - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
129 }
130}
131#endif
132
452{
453 return d_ptr ? d_ptr->elements.size() : 0;
454}
455
465{
466 Q_ASSERT(d_ptr);
467 Q_ASSERT(i >= 0 && i < elementCount());
468 return d_ptr->elements.at(i);
469}
470
480{
481 Q_ASSERT(d_ptr);
482 Q_ASSERT(i >= 0 && i < elementCount());
483 detach();
484 QPainterPath::Element &e = d_ptr->elements[i];
485 e.x = x;
486 e.y = y;
487}
488
489
490/*###
491 \fn QPainterPath &QPainterPath::operator +=(const QPainterPath &other)
492
493 Appends the \a other painter path to this painter path and returns a
494 reference to the result.
495*/
496
501 : d_ptr(nullptr)
502{
503}
504
513
520 : d_ptr(new QPainterPathPrivate)
521{
522 Element e = { startPoint.x(), startPoint.y(), MoveToElement };
523 d_func()->elements << e;
524}
525
526void QPainterPath::detach()
527{
528 d_ptr.detach();
529 setDirty(true);
530}
531
535void QPainterPath::ensureData_helper()
536{
538 data->elements.reserve(16);
540 data->elements << e;
541 d_ptr.reset(data);
542 Q_ASSERT(d_ptr != nullptr);
543}
544
553{
555 swap(copy);
556 return *this;
557}
558
579{
580}
581
591{
592 if (!d_ptr)
593 return;
594
595 detach();
596 d_func()->clear();
597 d_func()->elements.append( {0, 0, MoveToElement} );
598}
599
609{
610 Q_D(QPainterPath);
611 if ((!d && size > 0) || (d && d->elements.capacity() < size)) {
612 ensureData();
613 detach();
614 d_func()->elements.reserve(size);
615 }
616}
617
625{
626 Q_D(QPainterPath);
627 if (d)
628 return d->elements.capacity();
629
630 return 0;
631}
632
645{
646#ifdef QPP_DEBUG
647 printf("QPainterPath::closeSubpath()\n");
648#endif
649 if (isEmpty())
650 return;
651 detach();
652
653 d_func()->close();
654}
655
675{
676#ifdef QPP_DEBUG
677 printf("QPainterPath::moveTo() (%.2f,%.2f)\n", p.x(), p.y());
678#endif
679
680 if (!hasValidCoords(p)) {
681#ifndef QT_NO_DEBUG
682 qWarning("QPainterPath::moveTo: Adding point with invalid coordinates, ignoring call");
683#endif
684 return;
685 }
686
687 ensureData();
688 detach();
689
690 QPainterPathPrivate *d = d_func();
691 Q_ASSERT(!d->elements.isEmpty());
692
693 d->require_moveTo = false;
694
695 if (d->elements.constLast().type == MoveToElement) {
696 d->elements.last().x = p.x();
697 d->elements.last().y = p.y();
698 } else {
699 Element elm = { p.x(), p.y(), MoveToElement };
700 d->elements.append(elm);
701 }
702 d->cStart = d->elements.size() - 1;
703}
704
725{
726#ifdef QPP_DEBUG
727 printf("QPainterPath::lineTo() (%.2f,%.2f)\n", p.x(), p.y());
728#endif
729
730 if (!hasValidCoords(p)) {
731#ifndef QT_NO_DEBUG
732 qWarning("QPainterPath::lineTo: Adding point with invalid coordinates, ignoring call");
733#endif
734 return;
735 }
736
737 ensureData();
738 detach();
739
740 QPainterPathPrivate *d = d_func();
741 Q_ASSERT(!d->elements.isEmpty());
742 d->maybeMoveTo();
743 if (p == QPointF(d->elements.constLast()))
744 return;
745 Element elm = { p.x(), p.y(), LineToElement };
746 d->elements.append(elm);
747
748 d->convex = d->elements.size() == 3 || (d->elements.size() == 4 && d->isClosed());
749}
750
782void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &e)
783{
784#ifdef QPP_DEBUG
785 printf("QPainterPath::cubicTo() (%.2f,%.2f), (%.2f,%.2f), (%.2f,%.2f)\n",
786 c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
787#endif
788
789 if (!hasValidCoords(c1) || !hasValidCoords(c2) || !hasValidCoords(e)) {
790#ifndef QT_NO_DEBUG
791 qWarning("QPainterPath::cubicTo: Adding point with invalid coordinates, ignoring call");
792#endif
793 return;
794 }
795
796 ensureData();
797 detach();
798
799 QPainterPathPrivate *d = d_func();
800 Q_ASSERT(!d->elements.isEmpty());
801
802
803 // Abort on empty curve as a stroker cannot handle this and the
804 // curve is irrelevant anyway.
805 if (d->elements.constLast() == c1 && c1 == c2 && c2 == e)
806 return;
807
808 d->maybeMoveTo();
809
810 Element ce1 = { c1.x(), c1.y(), CurveToElement };
811 Element ce2 = { c2.x(), c2.y(), CurveToDataElement };
812 Element ee = { e.x(), e.y(), CurveToDataElement };
813 d->elements << ce1 << ce2 << ee;
814}
815
839{
840#ifdef QPP_DEBUG
841 printf("QPainterPath::quadTo() (%.2f,%.2f), (%.2f,%.2f)\n",
842 c.x(), c.y(), e.x(), e.y());
843#endif
844
845 if (!hasValidCoords(c) || !hasValidCoords(e)) {
846#ifndef QT_NO_DEBUG
847 qWarning("QPainterPath::quadTo: Adding point with invalid coordinates, ignoring call");
848#endif
849 return;
850 }
851
852 ensureData();
853 detach();
854
855 Q_D(QPainterPath);
856 Q_ASSERT(!d->elements.isEmpty());
857 const QPainterPath::Element &elm = d->elements.at(elementCount()-1);
858 QPointF prev(elm.x, elm.y);
859
860 // Abort on empty curve as a stroker cannot handle this and the
861 // curve is irrelevant anyway.
862 if (prev == c && c == e)
863 return;
864
865 QPointF c1((prev.x() + 2*c.x()) / 3, (prev.y() + 2*c.y()) / 3);
866 QPointF c2((e.x() + 2*c.x()) / 3, (e.y() + 2*c.y()) / 3);
867 cubicTo(c1, c2, e);
868}
869
909void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength)
910{
911#ifdef QPP_DEBUG
912 printf("QPainterPath::arcTo() (%.2f, %.2f, %.2f, %.2f, angle=%.2f, sweep=%.2f\n",
913 rect.x(), rect.y(), rect.width(), rect.height(), startAngle, sweepLength);
914#endif
915
916 if (!hasValidCoords(rect) || !isValidCoord(startAngle) || !isValidCoord(sweepLength)) {
917#ifndef QT_NO_DEBUG
918 qWarning("QPainterPath::arcTo: Adding point with invalid coordinates, ignoring call");
919#endif
920 return;
921 }
922
923 if (rect.isNull())
924 return;
925
926 ensureData();
927 detach();
928
929 int point_count;
930 QPointF pts[15];
931 QPointF curve_start = qt_curves_for_arc(rect, startAngle, sweepLength, pts, &point_count);
932
933 lineTo(curve_start);
934 for (int i=0; i<point_count; i+=3) {
935 cubicTo(pts[i].x(), pts[i].y(),
936 pts[i+1].x(), pts[i+1].y(),
937 pts[i+2].x(), pts[i+2].y());
938 }
939
940}
941
942
967{
968 if (rect.isNull())
969 return;
970
971 QPointF pt;
972 qt_find_ellipse_coords(rect, angle, 0, &pt, nullptr);
973 moveTo(pt);
974}
975
976
977
984{
985 return !d_ptr || d_func()->elements.isEmpty()
986 ? QPointF()
987 : QPointF(d_func()->elements.constLast().x, d_func()->elements.constLast().y);
988}
989
990
1020{
1021 if (!hasValidCoords(r)) {
1022#ifndef QT_NO_DEBUG
1023 qWarning("QPainterPath::addRect: Adding point with invalid coordinates, ignoring call");
1024#endif
1025 return;
1026 }
1027
1028 if (r.isNull())
1029 return;
1030
1031 ensureData();
1032 detach();
1033
1034 bool first = d_func()->elements.size() < 2;
1035
1036 moveTo(r.x(), r.y());
1037
1038 Element l1 = { r.x() + r.width(), r.y(), LineToElement };
1039 Element l2 = { r.x() + r.width(), r.y() + r.height(), LineToElement };
1040 Element l3 = { r.x(), r.y() + r.height(), LineToElement };
1041 Element l4 = { r.x(), r.y(), LineToElement };
1042
1043 d_func()->elements << l1 << l2 << l3 << l4;
1044 d_func()->require_moveTo = true;
1045 d_func()->convex = first;
1046}
1047
1066{
1067 if (polygon.isEmpty())
1068 return;
1069
1070 ensureData();
1071 detach();
1072
1073 moveTo(polygon.constFirst());
1074 for (int i=1; i<polygon.size(); ++i) {
1075 Element elm = { polygon.at(i).x(), polygon.at(i).y(), LineToElement };
1076 d_func()->elements << elm;
1077 }
1078}
1079
1100{
1102#ifndef QT_NO_DEBUG
1103 qWarning("QPainterPath::addEllipse: Adding point with invalid coordinates, ignoring call");
1104#endif
1105 return;
1106 }
1107
1108 if (boundingRect.isNull())
1109 return;
1110
1111 ensureData();
1112 detach();
1113
1114 bool first = d_func()->elements.size() < 2;
1115
1116 QPointF pts[12];
1117 int point_count;
1118 QPointF start = qt_curves_for_arc(boundingRect, 0, -360, pts, &point_count);
1119
1120 moveTo(start);
1121 cubicTo(pts[0], pts[1], pts[2]); // 0 -> 270
1122 cubicTo(pts[3], pts[4], pts[5]); // 270 -> 180
1123 cubicTo(pts[6], pts[7], pts[8]); // 180 -> 90
1124 cubicTo(pts[9], pts[10], pts[11]); // 90 - >0
1125 d_func()->require_moveTo = true;
1126
1127 d_func()->convex = first;
1128}
1129
1151void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &text)
1152{
1153 if (text.isEmpty())
1154 return;
1155
1156 ensureData();
1157 detach();
1158
1160 layout.setCacheEnabled(true);
1161
1162 QTextOption opt = layout.textOption();
1163 opt.setUseDesignMetrics(true);
1164 layout.setTextOption(opt);
1165
1166 QTextEngine *eng = layout.engine();
1167 layout.beginLayout();
1168 QTextLine line = layout.createLine();
1169 Q_UNUSED(line);
1170 layout.endLayout();
1171 const QScriptLine &sl = eng->lines[0];
1172 if (!sl.length || !eng->layoutData)
1173 return;
1174
1175 int nItems = eng->layoutData->items.size();
1176
1177 qreal x(point.x());
1178 qreal y(point.y());
1179
1180 QVarLengthArray<int> visualOrder(nItems);
1182 for (int i = 0; i < nItems; ++i)
1184 QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
1185
1186 for (int i = 0; i < nItems; ++i) {
1187 int item = visualOrder[i];
1188 const QScriptItem &si = eng->layoutData->items.at(item);
1189
1191 QGlyphLayout glyphs = eng->shapedGlyphs(&si);
1192 QFontEngine *fe = eng->fontEngine(si);
1193 Q_ASSERT(fe);
1194 fe->addOutlineToPath(x, y, glyphs, this,
1195 si.analysis.bidiLevel % 2
1196 ? QTextItem::RenderFlags(QTextItem::RightToLeft)
1197 : QTextItem::RenderFlags{});
1198
1199 const qreal lw = fe->lineThickness().toReal();
1200 if (f.d->underline) {
1202 addRect(x, y + pos, si.width.toReal(), lw);
1203 }
1204 if (f.d->overline) {
1205 qreal pos = fe->ascent().toReal() + 1;
1206 addRect(x, y - pos, si.width.toReal(), lw);
1207 }
1208 if (f.d->strikeOut) {
1209 qreal pos = fe->ascent().toReal() / 3;
1210 addRect(x, y - pos, si.width.toReal(), lw);
1211 }
1212 }
1213 x += si.width.toReal();
1214 }
1215}
1216
1226{
1227 if (other.isEmpty())
1228 return;
1229
1230 ensureData();
1231 detach();
1232
1233 QPainterPathPrivate *d = d_func();
1234 // Remove last moveto so we don't get multiple moveto's
1235 if (d->elements.constLast().type == MoveToElement)
1236 d->elements.remove(d->elements.size()-1);
1237
1238 // Locate where our own current subpath will start after the other path is added.
1239 int cStart = d->elements.size() + other.d_func()->cStart;
1240 d->elements += other.d_func()->elements;
1241 d->cStart = cStart;
1242
1243 d->require_moveTo = other.d_func()->isClosed();
1244}
1245
1246
1257{
1258 if (other.isEmpty())
1259 return;
1260
1261 ensureData();
1262 detach();
1263
1264 QPainterPathPrivate *d = d_func();
1265 // Remove last moveto so we don't get multiple moveto's
1266 if (d->elements.constLast().type == MoveToElement)
1267 d->elements.remove(d->elements.size()-1);
1268
1269 // Locate where our own current subpath will start after the other path is added.
1270 int cStart = d->elements.size() + other.d_func()->cStart;
1271 int first = d->elements.size();
1272 d->elements += other.d_func()->elements;
1273
1274 if (first != 0)
1275 d->elements[first].type = LineToElement;
1276
1277 // avoid duplicate points
1278 if (first > 0 && QPointF(d->elements.at(first)) == QPointF(d->elements.at(first - 1))) {
1279 d->elements.remove(first--);
1280 --cStart;
1281 }
1282
1283 if (cStart != first)
1284 d->cStart = cStart;
1285}
1286
1295{
1296 ensureData();
1297 detach();
1298
1299 for (const QRect &rect : region)
1300 addRect(rect);
1301}
1302
1303
1310{
1311 return !d_func() ? Qt::OddEvenFill : d_func()->fillRule;
1312}
1313
1332{
1333 ensureData();
1334 if (d_func()->fillRule == fillRule)
1335 return;
1336 detach();
1337
1338 d_func()->fillRule = fillRule;
1339}
1340
1341#define QT_BEZIER_A(bezier, coord) 3 * (-bezier.coord##1 \
1342 + 3*bezier.coord##2 \
1343 - 3*bezier.coord##3 \
1344 +bezier.coord##4)
1345
1346#define QT_BEZIER_B(bezier, coord) 6 * (bezier.coord##1 \
1347 - 2*bezier.coord##2 \
1348 + bezier.coord##3)
1349
1350#define QT_BEZIER_C(bezier, coord) 3 * (- bezier.coord##1 \
1351 + bezier.coord##2)
1352
1353#define QT_BEZIER_CHECK_T(bezier, t) \
1354 if (t >= 0 && t <= 1) { \
1355 QPointF p(b.pointAt(t)); \
1356 if (p.x() < minx) minx = p.x(); \
1357 else if (p.x() > maxx) maxx = p.x(); \
1358 if (p.y() < miny) miny = p.y(); \
1359 else if (p.y() > maxy) maxy = p.y(); \
1360 }
1361
1362
1364{
1365 qreal minx, miny, maxx, maxy;
1366
1367 // initialize with end points
1368 if (b.x1 < b.x4) {
1369 minx = b.x1;
1370 maxx = b.x4;
1371 } else {
1372 minx = b.x4;
1373 maxx = b.x1;
1374 }
1375 if (b.y1 < b.y4) {
1376 miny = b.y1;
1377 maxy = b.y4;
1378 } else {
1379 miny = b.y4;
1380 maxy = b.y1;
1381 }
1382
1383 // Update for the X extrema
1384 {
1385 qreal ax = QT_BEZIER_A(b, x);
1386 qreal bx = QT_BEZIER_B(b, x);
1387 qreal cx = QT_BEZIER_C(b, x);
1388 // specialcase quadratic curves to avoid div by zero
1389 if (qFuzzyIsNull(ax)) {
1390
1391 // linear curves are covered by initialization.
1392 if (!qFuzzyIsNull(bx)) {
1393 qreal t = -cx / bx;
1395 }
1396
1397 } else {
1398 const qreal tx = bx * bx - 4 * ax * cx;
1399
1400 if (tx >= 0) {
1401 qreal temp = qSqrt(tx);
1402 qreal rcp = 1 / (2 * ax);
1403 qreal t1 = (-bx + temp) * rcp;
1405
1406 qreal t2 = (-bx - temp) * rcp;
1408 }
1409 }
1410 }
1411
1412 // Update for the Y extrema
1413 {
1414 qreal ay = QT_BEZIER_A(b, y);
1415 qreal by = QT_BEZIER_B(b, y);
1416 qreal cy = QT_BEZIER_C(b, y);
1417
1418 // specialcase quadratic curves to avoid div by zero
1419 if (qFuzzyIsNull(ay)) {
1420
1421 // linear curves are covered by initialization.
1422 if (!qFuzzyIsNull(by)) {
1423 qreal t = -cy / by;
1425 }
1426
1427 } else {
1428 const qreal ty = by * by - 4 * ay * cy;
1429
1430 if (ty > 0) {
1431 qreal temp = qSqrt(ty);
1432 qreal rcp = 1 / (2 * ay);
1433 qreal t1 = (-by + temp) * rcp;
1435
1436 qreal t2 = (-by - temp) * rcp;
1438 }
1439 }
1440 }
1441 return QRectF(minx, miny, maxx - minx, maxy - miny);
1442}
1443
1451{
1452 if (!d_ptr)
1453 return QRectF();
1454 QPainterPathPrivate *d = d_func();
1455
1456 if (d->dirtyBounds)
1457 computeBoundingRect();
1458 return d->bounds;
1459}
1460
1472{
1473 if (!d_ptr)
1474 return QRectF();
1475 QPainterPathPrivate *d = d_func();
1476
1477 if (d->dirtyControlBounds)
1478 computeControlPointRect();
1479 return d->controlBounds;
1480}
1481
1482
1493{
1494 return !d_ptr || (d_ptr->elements.size() == 1 && d_ptr->elements.first().type == MoveToElement);
1495}
1496
1506{
1507 Q_D(const QPainterPath);
1508 QPainterPath rev;
1509
1510 if (isEmpty()) {
1511 rev = *this;
1512 return rev;
1513 }
1514
1515 rev.moveTo(d->elements.at(d->elements.size()-1).x, d->elements.at(d->elements.size()-1).y);
1516
1517 for (int i=d->elements.size()-1; i>=1; --i) {
1518 const QPainterPath::Element &elm = d->elements.at(i);
1519 const QPainterPath::Element &prev = d->elements.at(i-1);
1520 switch (elm.type) {
1521 case LineToElement:
1522 rev.lineTo(prev.x, prev.y);
1523 break;
1524 case MoveToElement:
1525 rev.moveTo(prev.x, prev.y);
1526 break;
1527 case CurveToDataElement:
1528 {
1529 Q_ASSERT(i>=3);
1530 const QPainterPath::Element &cp1 = d->elements.at(i-2);
1531 const QPainterPath::Element &sp = d->elements.at(i-3);
1534 rev.cubicTo(prev.x, prev.y, cp1.x, cp1.y, sp.x, sp.y);
1535 i -= 2;
1536 break;
1537 }
1538 default:
1539 Q_ASSERT(!"qt_reversed_path");
1540 break;
1541 }
1542 }
1543 //qt_debug_path(rev);
1544 return rev;
1545}
1546
1560{
1561
1562 Q_D(const QPainterPath);
1563 QList<QPolygonF> flatCurves;
1564 if (isEmpty())
1565 return flatCurves;
1566
1567 QPolygonF current;
1568 for (int i=0; i<elementCount(); ++i) {
1569 const QPainterPath::Element &e = d->elements.at(i);
1570 switch (e.type) {
1572 if (current.size() > 1)
1573 flatCurves += current;
1574 current.clear();
1575 current.reserve(16);
1576 current += QPointF(e.x, e.y) * matrix;
1577 break;
1579 current += QPointF(e.x, e.y) * matrix;
1580 break;
1582 Q_ASSERT(d->elements.at(i+1).type == QPainterPath::CurveToDataElement);
1583 Q_ASSERT(d->elements.at(i+2).type == QPainterPath::CurveToDataElement);
1584 QBezier bezier = QBezier::fromPoints(QPointF(d->elements.at(i-1).x, d->elements.at(i-1).y) * matrix,
1585 QPointF(e.x, e.y) * matrix,
1586 QPointF(d->elements.at(i+1).x, d->elements.at(i+1).y) * matrix,
1587 QPointF(d->elements.at(i+2).x, d->elements.at(i+2).y) * matrix);
1588 bezier.addToPolygon(&current);
1589 i+=2;
1590 break;
1591 }
1593 Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
1594 break;
1595 }
1596 }
1597
1598 if (current.size()>1)
1599 flatCurves += current;
1600
1601 return flatCurves;
1602}
1603
1627{
1628
1629 QList<QPolygonF> polys;
1630
1632 int count = subpaths.size();
1633
1634 if (count == 0)
1635 return polys;
1636
1637 QList<QRectF> bounds;
1638 bounds.reserve(count);
1639 for (int i=0; i<count; ++i)
1640 bounds += subpaths.at(i).boundingRect();
1641
1642#ifdef QPP_FILLPOLYGONS_DEBUG
1643 printf("QPainterPath::toFillPolygons, subpathCount=%d\n", count);
1644 for (int i=0; i<bounds.size(); ++i)
1645 qDebug() << " bounds" << i << bounds.at(i);
1646#endif
1647
1648 QList< QList<int> > isects;
1649 isects.resize(count);
1650
1651 // find all intersections
1652 for (int j=0; j<count; ++j) {
1653 if (subpaths.at(j).size() <= 2)
1654 continue;
1655 QRectF cbounds = bounds.at(j);
1656 for (int i=0; i<count; ++i) {
1657 if (cbounds.intersects(bounds.at(i))) {
1658 isects[j] << i;
1659 }
1660 }
1661 }
1662
1663#ifdef QPP_FILLPOLYGONS_DEBUG
1664 printf("Intersections before flattening:\n");
1665 for (int i = 0; i < count; ++i) {
1666 printf("%d: ", i);
1667 for (int j = 0; j < isects[i].size(); ++j) {
1668 printf("%d ", isects[i][j]);
1669 }
1670 printf("\n");
1671 }
1672#endif
1673
1674 // flatten the sets of intersections
1675 for (int i=0; i<count; ++i) {
1676 const QList<int> &current_isects = isects.at(i);
1677 for (int j=0; j<current_isects.size(); ++j) {
1678 int isect_j = current_isects.at(j);
1679 if (isect_j == i)
1680 continue;
1681 const QList<int> &isects_j = isects.at(isect_j);
1682 for (int k = 0, size = isects_j.size(); k < size; ++k) {
1683 int isect_k = isects_j.at(k);
1684 if (isect_k != i && !isects.at(i).contains(isect_k)) {
1685 isects[i] += isect_k;
1686 }
1687 }
1688 isects[isect_j].clear();
1689 }
1690 }
1691
1692#ifdef QPP_FILLPOLYGONS_DEBUG
1693 printf("Intersections after flattening:\n");
1694 for (int i = 0; i < count; ++i) {
1695 printf("%d: ", i);
1696 for (int j = 0; j < isects[i].size(); ++j) {
1697 printf("%d ", isects[i][j]);
1698 }
1699 printf("\n");
1700 }
1701#endif
1702
1703 // Join the intersected subpaths as rewinded polygons
1704 for (int i=0; i<count; ++i) {
1705 const QList<int> &subpath_list = isects.at(i);
1706 if (!subpath_list.isEmpty()) {
1707 QPolygonF buildUp;
1708 for (int j=0; j<subpath_list.size(); ++j) {
1709 const QPolygonF &subpath = subpaths.at(subpath_list.at(j));
1710 buildUp += subpath;
1711 if (!subpath.isClosed())
1712 buildUp += subpath.first();
1713 if (!buildUp.isClosed())
1714 buildUp += buildUp.constFirst();
1715 }
1716 polys += buildUp;
1717 }
1718 }
1719
1720 return polys;
1721}
1722
1723//same as qt_polygon_isect_line in qpolygon.cpp
1725 const QPointF &p2,
1726 const QPointF &pos,
1727 int *winding)
1728{
1729 qreal x1 = p1.x();
1730 qreal y1 = p1.y();
1731 qreal x2 = p2.x();
1732 qreal y2 = p2.y();
1733 qreal y = pos.y();
1734
1735 int dir = 1;
1736
1737 if (qFuzzyCompare(y1, y2)) {
1738 // ignore horizontal lines according to scan conversion rule
1739 return;
1740 } else if (y2 < y1) {
1741 qreal x_tmp = x2; x2 = x1; x1 = x_tmp;
1742 qreal y_tmp = y2; y2 = y1; y1 = y_tmp;
1743 dir = -1;
1744 }
1745
1746 if (y >= y1 && y < y2) {
1747 qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1);
1748
1749 // count up the winding number if we're
1750 if (x<=pos.x()) {
1751 (*winding) += dir;
1752 }
1753 }
1754}
1755
1756static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
1757 int *winding, int depth = 0)
1758{
1759 qreal y = pt.y();
1760 qreal x = pt.x();
1761 QRectF bounds = bezier.bounds();
1762
1763 // potential intersection, divide and try again...
1764 // Please note that a sideeffect of the bottom exclusion is that
1765 // horizontal lines are dropped, but this is correct according to
1766 // scan conversion rules.
1767 if (y >= bounds.y() && y < bounds.y() + bounds.height()) {
1768
1769 // hit lower limit... This is a rough threshold, but its a
1770 // tradeoff between speed and precision.
1771 const qreal lower_bound = qreal(.001);
1772 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) {
1773 // We make the assumption here that the curve starts to
1774 // approximate a line after while (i.e. that it doesn't
1775 // change direction drastically during its slope)
1776 if (bezier.pt1().x() <= x) {
1777 (*winding) += (bezier.pt4().y() > bezier.pt1().y() ? 1 : -1);
1778 }
1779 return;
1780 }
1781
1782 // split curve and try again...
1783 const auto halves = bezier.split();
1784 qt_painterpath_isect_curve(halves.first, pt, winding, depth + 1);
1785 qt_painterpath_isect_curve(halves.second, pt, winding, depth + 1);
1786 }
1787}
1788
1797bool QPainterPath::contains(const QPointF &pt) const
1798{
1799 if (isEmpty() || !controlPointRect().contains(pt))
1800 return false;
1801
1802 QPainterPathPrivate *d = d_func();
1803
1804 int winding_number = 0;
1805
1806 QPointF last_pt;
1807 QPointF last_start;
1808 for (int i=0; i<d->elements.size(); ++i) {
1809 const Element &e = d->elements.at(i);
1810
1811 switch (e.type) {
1812
1813 case MoveToElement:
1814 if (i > 0) // implicitly close all paths.
1815 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1816 last_start = last_pt = e;
1817 break;
1818
1819 case LineToElement:
1820 qt_painterpath_isect_line(last_pt, e, pt, &winding_number);
1821 last_pt = e;
1822 break;
1823
1824 case CurveToElement:
1825 {
1826 const QPainterPath::Element &cp2 = d->elements.at(++i);
1827 const QPainterPath::Element &ep = d->elements.at(++i);
1829 pt, &winding_number);
1830 last_pt = ep;
1831
1832 }
1833 break;
1834
1835 default:
1836 break;
1837 }
1838 }
1839
1840 // implicitly close last subpath
1841 if (last_pt != last_start)
1842 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1843
1844 return (d->fillRule == Qt::WindingFill
1845 ? (winding_number != 0)
1846 : ((winding_number % 2) != 0));
1847}
1848
1850
1852 const QRectF &rect)
1853{
1854 qreal left = rect.left();
1855 qreal right = rect.right();
1856 qreal top = rect.top();
1857 qreal bottom = rect.bottom();
1858
1859 // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html
1860 int p1 = ((x1 < left) << Left)
1861 | ((x1 > right) << Right)
1862 | ((y1 < top) << Top)
1863 | ((y1 > bottom) << Bottom);
1864 int p2 = ((x2 < left) << Left)
1865 | ((x2 > right) << Right)
1866 | ((y2 < top) << Top)
1867 | ((y2 > bottom) << Bottom);
1868
1869 if (p1 & p2)
1870 // completely inside
1871 return false;
1872
1873 if (p1 | p2) {
1874 qreal dx = x2 - x1;
1875 qreal dy = y2 - y1;
1876
1877 // clip x coordinates
1878 if (x1 < left) {
1879 y1 += dy/dx * (left - x1);
1880 x1 = left;
1881 } else if (x1 > right) {
1882 y1 -= dy/dx * (x1 - right);
1883 x1 = right;
1884 }
1885 if (x2 < left) {
1886 y2 += dy/dx * (left - x2);
1887 x2 = left;
1888 } else if (x2 > right) {
1889 y2 -= dy/dx * (x2 - right);
1890 x2 = right;
1891 }
1892
1893 p1 = ((y1 < top) << Top)
1894 | ((y1 > bottom) << Bottom);
1895 p2 = ((y2 < top) << Top)
1896 | ((y2 > bottom) << Bottom);
1897
1898 if (p1 & p2)
1899 return false;
1900
1901 // clip y coordinates
1902 if (y1 < top) {
1903 x1 += dx/dy * (top - y1);
1904 y1 = top;
1905 } else if (y1 > bottom) {
1906 x1 -= dx/dy * (y1 - bottom);
1907 y1 = bottom;
1908 }
1909 if (y2 < top) {
1910 x2 += dx/dy * (top - y2);
1911 y2 = top;
1912 } else if (y2 > bottom) {
1913 x2 -= dx/dy * (y2 - bottom);
1914 y2 = bottom;
1915 }
1916
1917 p1 = ((x1 < left) << Left)
1918 | ((x1 > right) << Right);
1919 p2 = ((x2 < left) << Left)
1920 | ((x2 > right) << Right);
1921
1922 if (p1 & p2)
1923 return false;
1924
1925 return true;
1926 }
1927 return false;
1928}
1929
1930static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2, int depth = 0)
1931{
1932 QRectF bounds = bezier.bounds();
1933
1934 if (y >= bounds.top() && y < bounds.bottom()
1935 && bounds.right() >= x1 && bounds.left() < x2) {
1936 const qreal lower_bound = qreal(.01);
1937 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
1938 return true;
1939
1940 const auto halves = bezier.split();
1941 if (qt_isect_curve_horizontal(halves.first, y, x1, x2, depth + 1)
1942 || qt_isect_curve_horizontal(halves.second, y, x1, x2, depth + 1))
1943 return true;
1944 }
1945 return false;
1946}
1947
1948static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2, int depth = 0)
1949{
1950 QRectF bounds = bezier.bounds();
1951
1952 if (x >= bounds.left() && x < bounds.right()
1953 && bounds.bottom() >= y1 && bounds.top() < y2) {
1954 const qreal lower_bound = qreal(.01);
1955 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
1956 return true;
1957
1958 const auto halves = bezier.split();
1959 if (qt_isect_curve_vertical(halves.first, x, y1, y2, depth + 1)
1960 || qt_isect_curve_vertical(halves.second, x, y1, y2, depth + 1))
1961 return true;
1962 }
1963 return false;
1964}
1965
1966static bool pointOnEdge(const QRectF &rect, const QPointF &point)
1967{
1968 if ((point.x() == rect.left() || point.x() == rect.right()) &&
1969 (point.y() >= rect.top() && point.y() <= rect.bottom()))
1970 return true;
1971 if ((point.y() == rect.top() || point.y() == rect.bottom()) &&
1972 (point.x() >= rect.left() && point.x() <= rect.right()))
1973 return true;
1974 return false;
1975}
1976
1977/*
1978 Returns \c true if any lines or curves cross the four edges in of rect
1979*/
1981{
1982 QPointF last_pt;
1983 QPointF last_start;
1984 enum { OnRect, InsideRect, OutsideRect} edgeStatus = OnRect;
1985 for (int i=0; i<path->elementCount(); ++i) {
1986 const QPainterPath::Element &e = path->elementAt(i);
1987
1988 switch (e.type) {
1989
1991 if (i > 0
1992 && qFuzzyCompare(last_pt.x(), last_start.x())
1993 && qFuzzyCompare(last_pt.y(), last_start.y())
1994 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
1995 last_start.x(), last_start.y(), rect))
1996 return true;
1997 last_start = last_pt = e;
1998 break;
1999
2001 if (qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), e.x, e.y, rect))
2002 return true;
2003 last_pt = e;
2004 break;
2005
2007 {
2008 QPointF cp2 = path->elementAt(++i);
2009 QPointF ep = path->elementAt(++i);
2010 QBezier bezier = QBezier::fromPoints(last_pt, e, cp2, ep);
2011 if (qt_isect_curve_horizontal(bezier, rect.top(), rect.left(), rect.right())
2012 || qt_isect_curve_horizontal(bezier, rect.bottom(), rect.left(), rect.right())
2013 || qt_isect_curve_vertical(bezier, rect.left(), rect.top(), rect.bottom())
2014 || qt_isect_curve_vertical(bezier, rect.right(), rect.top(), rect.bottom()))
2015 return true;
2016 last_pt = ep;
2017 }
2018 break;
2019
2020 default:
2021 break;
2022 }
2023 // Handle crossing the edges of the rect at the end-points of individual sub-paths.
2024 // A point on on the edge itself is considered neither inside nor outside for this purpose.
2025 if (!pointOnEdge(rect, last_pt)) {
2026 bool contained = rect.contains(last_pt);
2027 switch (edgeStatus) {
2028 case OutsideRect:
2029 if (contained)
2030 return true;
2031 break;
2032 case InsideRect:
2033 if (!contained)
2034 return true;
2035 break;
2036 case OnRect:
2037 edgeStatus = contained ? InsideRect : OutsideRect;
2038 break;
2039 }
2040 } else {
2041 if (last_pt == last_start)
2042 edgeStatus = OnRect;
2043 }
2044 }
2045
2046 // implicitly close last subpath
2047 if (last_pt != last_start
2048 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
2049 last_start.x(), last_start.y(), rect))
2050 return true;
2051
2052 return false;
2053}
2054
2070{
2071 if (elementCount() == 1 && rect.contains(elementAt(0)))
2072 return true;
2073
2074 if (isEmpty())
2075 return false;
2076
2077 QRectF cp = controlPointRect();
2078 QRectF rn = rect.normalized();
2079
2080 // QRectF::intersects returns false if one of the rects is a null rect
2081 // which would happen for a painter path consisting of a vertical or
2082 // horizontal line
2083 if (qMax(rn.left(), cp.left()) > qMin(rn.right(), cp.right())
2084 || qMax(rn.top(), cp.top()) > qMin(rn.bottom(), cp.bottom()))
2085 return false;
2086
2087 // If any path element cross the rect its bound to be an intersection
2089 return true;
2090
2091 if (contains(rect.center()))
2092 return true;
2093
2094 Q_D(QPainterPath);
2095
2096 // Check if the rectangle surrounds any subpath...
2097 for (int i=0; i<d->elements.size(); ++i) {
2098 const Element &e = d->elements.at(i);
2099 if (e.type == QPainterPath::MoveToElement && rect.contains(e))
2100 return true;
2101 }
2102
2103 return false;
2104}
2105
2113{
2114 if (!d_ptr || (dx == 0 && dy == 0))
2115 return;
2116
2117 int elementsLeft = d_ptr->elements.size();
2118 if (elementsLeft <= 0)
2119 return;
2120
2121 detach();
2122 QPainterPath::Element *element = d_func()->elements.data();
2123 Q_ASSERT(element);
2124 while (elementsLeft--) {
2125 element->x += dx;
2126 element->y += dy;
2127 ++element;
2128 }
2129}
2130
2148{
2149 QPainterPath copy(*this);
2150 copy.translate(dx, dy);
2151 return copy;
2152}
2153
2171{
2172 Q_D(QPainterPath);
2173
2174 // the path is empty or the control point rect doesn't completely
2175 // cover the rectangle we abort stratight away.
2177 return false;
2178
2179 // if there are intersections, chances are that the rect is not
2180 // contained, except if we have winding rule, in which case it
2181 // still might.
2183 if (fillRule() == Qt::OddEvenFill) {
2184 return false;
2185 } else {
2186 // Do some wague sampling in the winding case. This is not
2187 // precise but it should mostly be good enough.
2188 if (!contains(rect.topLeft()) ||
2189 !contains(rect.topRight()) ||
2190 !contains(rect.bottomRight()) ||
2191 !contains(rect.bottomLeft()))
2192 return false;
2193 }
2194 }
2195
2196 // If there exists a point inside that is not part of the path its
2197 // because: rectangle lies completely outside path or a subpath
2198 // excludes parts of the rectangle. Both cases mean that the rect
2199 // is not contained
2200 if (!contains(rect.center()))
2201 return false;
2202
2203 // If there are any subpaths inside this rectangle we need to
2204 // check if they are still contained as a result of the fill
2205 // rule. This can only be the case for WindingFill though. For
2206 // OddEvenFill the rect will never be contained if it surrounds a
2207 // subpath. (the case where two subpaths are completely identical
2208 // can be argued but we choose to neglect it).
2209 for (int i=0; i<d->elements.size(); ++i) {
2210 const Element &e = d->elements.at(i);
2211 if (e.type == QPainterPath::MoveToElement && rect.contains(e)) {
2212 if (fillRule() == Qt::OddEvenFill)
2213 return false;
2214
2215 bool stop = false;
2216 for (; !stop && i<d->elements.size(); ++i) {
2217 const Element &el = d->elements.at(i);
2218 switch (el.type) {
2219 case MoveToElement:
2220 stop = true;
2221 break;
2222 case LineToElement:
2223 if (!contains(el))
2224 return false;
2225 break;
2226 case CurveToElement:
2227 if (!contains(d->elements.at(i+2)))
2228 return false;
2229 i += 2;
2230 break;
2231 default:
2232 break;
2233 }
2234 }
2235
2236 // compensate for the last ++i in the inner for
2237 --i;
2238 }
2239 }
2240
2241 return true;
2242}
2243
2244static inline bool epsilonCompare(const QPointF &a, const QPointF &b, const QSizeF &epsilon)
2245{
2246 return qAbs(a.x() - b.x()) <= epsilon.width()
2247 && qAbs(a.y() - b.y()) <= epsilon.height();
2248}
2249
2260{
2261 QPainterPathPrivate *d = d_func();
2262 QPainterPathPrivate *other_d = path.d_func();
2263 if (other_d == d) {
2264 return true;
2265 } else if (!d || !other_d) {
2266 if (!other_d && isEmpty() && elementAt(0) == QPointF() && d->fillRule == Qt::OddEvenFill)
2267 return true;
2268 if (!d && path.isEmpty() && path.elementAt(0) == QPointF() && other_d->fillRule == Qt::OddEvenFill)
2269 return true;
2270 return false;
2271 }
2272 else if (d->fillRule != other_d->fillRule)
2273 return false;
2274 else if (d->elements.size() != other_d->elements.size())
2275 return false;
2276
2277 const qreal qt_epsilon = sizeof(qreal) == sizeof(double) ? 1e-12 : qreal(1e-5);
2278
2280 epsilon.rwidth() *= qt_epsilon;
2281 epsilon.rheight() *= qt_epsilon;
2282
2283 for (int i = 0; i < d->elements.size(); ++i)
2284 if (d->elements.at(i).type != other_d->elements.at(i).type
2285 || !epsilonCompare(d->elements.at(i), other_d->elements.at(i), epsilon))
2286 return false;
2287
2288 return true;
2289}
2290
2301{
2302 return !(*this==path);
2303}
2304
2313{
2314 return intersected(other);
2315}
2316
2325{
2326 return united(other);
2327}
2328
2338{
2339 return united(other);
2340}
2341
2350{
2351 return subtracted(other);
2352}
2353
2362{
2363 return *this = (*this & other);
2364}
2365
2374{
2375 return *this = (*this | other);
2376}
2377
2387{
2388 return *this = (*this + other);
2389}
2390
2400{
2401 return *this = (*this - other);
2402}
2403
2404#ifndef QT_NO_DATASTREAM
2415{
2416 if (p.isEmpty()) {
2417 s << 0;
2418 return s;
2419 }
2420
2421 s << p.elementCount();
2422 for (int i=0; i < p.d_func()->elements.size(); ++i) {
2423 const QPainterPath::Element &e = p.d_func()->elements.at(i);
2424 s << int(e.type);
2425 s << double(e.x) << double(e.y);
2426 }
2427 s << p.d_func()->cStart;
2428 s << int(p.d_func()->fillRule);
2429 return s;
2430}
2431
2442{
2443 bool errorDetected = false;
2444 int size;
2445 s >> size;
2446
2447 if (size == 0)
2448 return s;
2449
2450 p.ensureData(); // in case if p.d_func() == 0
2451 if (p.d_func()->elements.size() == 1) {
2452 Q_ASSERT(p.d_func()->elements.at(0).type == QPainterPath::MoveToElement);
2453 p.d_func()->elements.clear();
2454 }
2455 for (int i=0; i<size; ++i) {
2456 int type;
2457 double x, y;
2458 s >> type;
2459 s >> x;
2460 s >> y;
2461 Q_ASSERT(type >= 0 && type <= 3);
2462 if (!isValidCoord(qreal(x)) || !isValidCoord(qreal(y))) {
2463#ifndef QT_NO_DEBUG
2464 qWarning("QDataStream::operator>>: Invalid QPainterPath coordinates read, skipping it");
2465#endif
2466 errorDetected = true;
2467 continue;
2468 }
2470 p.d_func()->elements.append(elm);
2471 }
2472 s >> p.d_func()->cStart;
2473 int fillRule;
2474 s >> fillRule;
2475 Q_ASSERT(fillRule == Qt::OddEvenFill || fillRule == Qt::WindingFill);
2476 p.d_func()->fillRule = Qt::FillRule(fillRule);
2477 p.d_func()->dirtyBounds = true;
2478 p.d_func()->dirtyControlBounds = true;
2479 if (errorDetected)
2480 p = QPainterPath(); // Better than to return path with possibly corrupt datastructure, which would likely cause crash
2481 return s;
2482}
2483#endif // QT_NO_DATASTREAM
2484
2485
2486/*******************************************************************************
2487 * class QPainterPathStroker
2488 */
2489
2491{
2493}
2494
2496{
2498}
2499
2501 qfixed c2x, qfixed c2y,
2502 qfixed ex, qfixed ey,
2503 void *data)
2504{
2505 ((QPainterPath *) data)->cubicTo(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y),
2508}
2509
2562 : dashOffset(0)
2563{
2567}
2568
2573 : d_ptr(new QPainterPathStrokerPrivate)
2574{
2575}
2576
2583 : d_ptr(new QPainterPathStrokerPrivate)
2584{
2585 setWidth(pen.widthF());
2586 setCapStyle(pen.capStyle());
2587 setJoinStyle(pen.joinStyle());
2590
2591 if (pen.style() == Qt::CustomDashLine)
2593 else
2594 setDashPattern(pen.style());
2595}
2596
2601{
2602}
2603
2604
2619{
2620 QPainterPathStrokerPrivate *d = const_cast<QPainterPathStrokerPrivate *>(d_func());
2621 QPainterPath stroke;
2622 if (path.isEmpty())
2623 return path;
2624 if (d->dashPattern.isEmpty()) {
2625 d->stroker.strokePath(path, &stroke, QTransform());
2626 } else {
2627 QDashStroker dashStroker(&d->stroker);
2628 dashStroker.setDashPattern(d->dashPattern);
2629 dashStroker.setDashOffset(d->dashOffset);
2630 dashStroker.setClipRect(d->stroker.clipRect());
2631 dashStroker.strokePath(path, &stroke, QTransform());
2632 }
2634 return stroke;
2635}
2636
2644{
2646 if (width <= 0)
2647 width = 1;
2648 d->stroker.setStrokeWidth(qt_real_to_fixed(width));
2649}
2650
2655{
2656 return qt_fixed_to_real(d_func()->stroker.strokeWidth());
2657}
2658
2659
2666{
2667 d_func()->stroker.setCapStyle(style);
2668}
2669
2670
2675{
2676 return d_func()->stroker.capStyle();
2677}
2678
2683{
2684 d_func()->stroker.setJoinStyle(style);
2685}
2686
2691{
2692 return d_func()->stroker.joinStyle();
2693}
2694
2706{
2707 d_func()->stroker.setMiterLimit(qt_real_to_fixed(limit));
2708}
2709
2714{
2715 return qt_fixed_to_real(d_func()->stroker.miterLimit());
2716}
2717
2718
2728{
2729 d_func()->stroker.setCurveThreshold(qt_real_to_fixed(threshold));
2730}
2731
2737{
2738 return qt_fixed_to_real(d_func()->stroker.curveThreshold());
2739}
2740
2745{
2746 d_func()->dashPattern = QDashStroker::patternForStyle(style);
2747}
2748
2766{
2767 d_func()->dashPattern.clear();
2768 for (int i=0; i<dashPattern.size(); ++i)
2769 d_func()->dashPattern << qt_real_to_fixed(dashPattern.at(i));
2770}
2771
2776{
2777 return d_func()->dashPattern;
2778}
2779
2784{
2785 return d_func()->dashOffset;
2786}
2787
2795{
2796 d_func()->dashOffset = offset;
2797}
2798
2815{
2818 if (flats.isEmpty())
2819 return polygon;
2820 QPointF first = flats.first().first();
2821 for (int i=0; i<flats.size(); ++i) {
2822 polygon += flats.at(i);
2823 if (!flats.at(i).isClosed())
2824 polygon += flats.at(i).first();
2825 if (i > 0)
2826 polygon += first;
2827 }
2828 return polygon;
2829}
2830
2831//derivative of the equation
2833{
2834 return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
2835}
2836
2841{
2842 Q_D(QPainterPath);
2843 if (isEmpty())
2844 return 0;
2845
2846 qreal len = 0;
2847 for (int i=1; i<d->elements.size(); ++i) {
2848 const Element &e = d->elements.at(i);
2849
2850 switch (e.type) {
2851 case MoveToElement:
2852 break;
2853 case LineToElement:
2854 {
2855 len += QLineF(d->elements.at(i-1), e).length();
2856 break;
2857 }
2858 case CurveToElement:
2859 {
2860 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2861 e,
2862 d->elements.at(i+1),
2863 d->elements.at(i+2));
2864 len += b.length();
2865 i += 2;
2866 break;
2867 }
2868 default:
2869 break;
2870 }
2871 }
2872 return len;
2873}
2874
2884{
2885 Q_D(QPainterPath);
2886 if (isEmpty() || len <= 0)
2887 return 0;
2888
2889 qreal totalLength = length();
2890 if (len > totalLength)
2891 return 1;
2892
2893 qreal curLen = 0;
2894 for (int i=1; i<d->elements.size(); ++i) {
2895 const Element &e = d->elements.at(i);
2896
2897 switch (e.type) {
2898 case MoveToElement:
2899 break;
2900 case LineToElement:
2901 {
2902 QLineF line(d->elements.at(i-1), e);
2903 qreal llen = line.length();
2904 curLen += llen;
2905 if (curLen >= len) {
2906 return len/totalLength ;
2907 }
2908
2909 break;
2910 }
2911 case CurveToElement:
2912 {
2913 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2914 e,
2915 d->elements.at(i+1),
2916 d->elements.at(i+2));
2917 qreal blen = b.length();
2918 qreal prevLen = curLen;
2919 curLen += blen;
2920
2921 if (curLen >= len) {
2922 qreal res = b.tAtLength(len - prevLen);
2923 return (res * blen + prevLen)/totalLength;
2924 }
2925
2926 i += 2;
2927 break;
2928 }
2929 default:
2930 break;
2931 }
2932 }
2933
2934 return 0;
2935}
2936
2937static inline QBezier bezierAtT(const QPainterPath &path, qreal t, qreal *startingLength, qreal *bezierLength)
2938{
2939 *startingLength = 0;
2940 if (t > 1)
2941 return QBezier();
2942
2943 qreal curLen = 0;
2944 qreal totalLength = path.length();
2945
2946 const int lastElement = path.elementCount() - 1;
2947 for (int i=0; i <= lastElement; ++i) {
2948 const QPainterPath::Element &e = path.elementAt(i);
2949
2950 switch (e.type) {
2952 break;
2954 {
2955 QLineF line(path.elementAt(i-1), e);
2956 qreal llen = line.length();
2957 curLen += llen;
2958 if (i == lastElement || curLen/totalLength >= t) {
2959 *bezierLength = llen;
2960 QPointF a = path.elementAt(i-1);
2961 QPointF delta = e - a;
2962 return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
2963 }
2964 break;
2965 }
2967 {
2968 QBezier b = QBezier::fromPoints(path.elementAt(i-1),
2969 e,
2970 path.elementAt(i+1),
2971 path.elementAt(i+2));
2972 qreal blen = b.length();
2973 curLen += blen;
2974
2975 if (i + 2 == lastElement || curLen/totalLength >= t) {
2976 *bezierLength = blen;
2977 return b;
2978 }
2979
2980 i += 2;
2981 break;
2982 }
2983 default:
2984 break;
2985 }
2986 *startingLength = curLen;
2987 }
2988 return QBezier();
2989}
2990
3001{
3002 if (t < 0 || t > 1) {
3003 qWarning("QPainterPath::pointAtPercent accepts only values between 0 and 1");
3004 return QPointF();
3005 }
3006
3007 if (!d_ptr || d_ptr->elements.size() == 0)
3008 return QPointF();
3009
3010 if (d_ptr->elements.size() == 1)
3011 return d_ptr->elements.at(0);
3012
3013 qreal totalLength = length();
3014 qreal curLen = 0;
3015 qreal bezierLen = 0;
3016 QBezier b = bezierAtT(*this, t, &curLen, &bezierLen);
3017 qreal realT = (totalLength * t - curLen) / bezierLen;
3018
3019 return b.pointAt(qBound(qreal(0), realT, qreal(1)));
3020}
3021
3035{
3036 if (t < 0 || t > 1) {
3037 qWarning("QPainterPath::angleAtPercent accepts only values between 0 and 1");
3038 return 0;
3039 }
3040
3041 qreal totalLength = length();
3042 qreal curLen = 0;
3043 qreal bezierLen = 0;
3044 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
3045 qreal realT = (totalLength * t - curLen) / bezierLen;
3046
3047 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
3048 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
3049
3050 return QLineF(0, 0, m1, m2).angle();
3051}
3052
3053
3064{
3065 if (t < 0 || t > 1) {
3066 qWarning("QPainterPath::slopeAtPercent accepts only values between 0 and 1");
3067 return 0;
3068 }
3069
3070 qreal totalLength = length();
3071 qreal curLen = 0;
3072 qreal bezierLen = 0;
3073 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
3074 qreal realT = (totalLength * t - curLen) / bezierLen;
3075
3076 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
3077 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
3078 //tangent line
3079 qreal slope = 0;
3080
3081 if (m1)
3082 slope = m2/m1;
3083 else {
3084 if (std::numeric_limits<qreal>::has_infinity) {
3085 slope = (m2 < 0) ? -std::numeric_limits<qreal>::infinity()
3086 : std::numeric_limits<qreal>::infinity();
3087 } else {
3088 if (sizeof(qreal) == sizeof(double)) {
3089 return 1.79769313486231570e+308;
3090 } else {
3091 return ((qreal)3.40282346638528860e+38);
3092 }
3093 }
3094 }
3095
3096 return slope;
3097}
3098
3114{
3115 QRectF r = rect.normalized();
3116
3117 if (r.isNull())
3118 return;
3119
3120 if (mode == Qt::AbsoluteSize) {
3121 qreal w = r.width() / 2;
3122 qreal h = r.height() / 2;
3123
3124 if (w == 0) {
3125 xRadius = 0;
3126 } else {
3127 xRadius = 100 * qMin(xRadius, w) / w;
3128 }
3129 if (h == 0) {
3130 yRadius = 0;
3131 } else {
3132 yRadius = 100 * qMin(yRadius, h) / h;
3133 }
3134 } else {
3135 if (xRadius > 100) // fix ranges
3136 xRadius = 100;
3137
3138 if (yRadius > 100)
3139 yRadius = 100;
3140 }
3141
3142 if (xRadius <= 0 || yRadius <= 0) { // add normal rectangle
3143 addRect(r);
3144 return;
3145 }
3146
3147 qreal x = r.x();
3148 qreal y = r.y();
3149 qreal w = r.width();
3150 qreal h = r.height();
3151 qreal rxx2 = w*xRadius/100;
3152 qreal ryy2 = h*yRadius/100;
3153
3154 ensureData();
3155 detach();
3156
3157 bool first = d_func()->elements.size() < 2;
3158
3159 arcMoveTo(x, y, rxx2, ryy2, 180);
3160 arcTo(x, y, rxx2, ryy2, 180, -90);
3161 arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3162 arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3163 arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3164 closeSubpath();
3165
3166 d_func()->require_moveTo = true;
3167 d_func()->convex = first;
3168}
3169
3191{
3192 if (isEmpty() || p.isEmpty())
3193 return isEmpty() ? p : *this;
3194 QPathClipper clipper(*this, p);
3195 return clipper.clip(QPathClipper::BoolOr);
3196}
3197
3206{
3207 if (isEmpty() || p.isEmpty())
3208 return QPainterPath();
3209 QPathClipper clipper(*this, p);
3210 return clipper.clip(QPathClipper::BoolAnd);
3211}
3212
3224{
3225 if (isEmpty() || p.isEmpty())
3226 return *this;
3227 QPathClipper clipper(*this, p);
3228 return clipper.clip(QPathClipper::BoolSub);
3229}
3230
3241{
3242 if (isEmpty())
3243 return *this;
3244 QPathClipper clipper(*this, QPainterPath());
3245 return clipper.clip(QPathClipper::Simplify);
3246}
3247
3260{
3261 if (p.elementCount() == 1)
3262 return contains(p.elementAt(0));
3263 if (isEmpty() || p.isEmpty())
3264 return false;
3265 QPathClipper clipper(*this, p);
3266 return clipper.intersect();
3267}
3268
3282{
3283 if (p.elementCount() == 1)
3284 return contains(p.elementAt(0));
3285 if (isEmpty() || p.isEmpty())
3286 return false;
3287 QPathClipper clipper(*this, p);
3288 return clipper.contains();
3289}
3290
3291void QPainterPath::setDirty(bool dirty)
3292{
3293 d_func()->dirtyBounds = dirty;
3294 d_func()->dirtyControlBounds = dirty;
3295 d_func()->pathConverter.reset();
3296 d_func()->convex = false;
3297}
3298
3299void QPainterPath::computeBoundingRect() const
3300{
3301 QPainterPathPrivate *d = d_func();
3302 d->dirtyBounds = false;
3303 if (!d_ptr) {
3304 d->bounds = QRect();
3305 return;
3306 }
3307
3308 qreal minx, maxx, miny, maxy;
3309 minx = maxx = d->elements.at(0).x;
3310 miny = maxy = d->elements.at(0).y;
3311 for (int i=1; i<d->elements.size(); ++i) {
3312 const Element &e = d->elements.at(i);
3313
3314 switch (e.type) {
3315 case MoveToElement:
3316 case LineToElement:
3317 if (e.x > maxx) maxx = e.x;
3318 else if (e.x < minx) minx = e.x;
3319 if (e.y > maxy) maxy = e.y;
3320 else if (e.y < miny) miny = e.y;
3321 break;
3322 case CurveToElement:
3323 {
3324 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
3325 e,
3326 d->elements.at(i+1),
3327 d->elements.at(i+2));
3329 qreal right = r.right();
3330 qreal bottom = r.bottom();
3331 if (r.x() < minx) minx = r.x();
3332 if (right > maxx) maxx = right;
3333 if (r.y() < miny) miny = r.y();
3334 if (bottom > maxy) maxy = bottom;
3335 i += 2;
3336 }
3337 break;
3338 default:
3339 break;
3340 }
3341 }
3342 d->bounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3343}
3344
3345
3346void QPainterPath::computeControlPointRect() const
3347{
3348 QPainterPathPrivate *d = d_func();
3349 d->dirtyControlBounds = false;
3350 if (!d_ptr) {
3351 d->controlBounds = QRect();
3352 return;
3353 }
3354
3355 qreal minx, maxx, miny, maxy;
3356 minx = maxx = d->elements.at(0).x;
3357 miny = maxy = d->elements.at(0).y;
3358 for (int i=1; i<d->elements.size(); ++i) {
3359 const Element &e = d->elements.at(i);
3360 if (e.x > maxx) maxx = e.x;
3361 else if (e.x < minx) minx = e.x;
3362 if (e.y > maxy) maxy = e.y;
3363 else if (e.y < miny) miny = e.y;
3364 }
3365 d->controlBounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3366}
3367
3368#ifndef QT_NO_DEBUG_STREAM
3370{
3371 s.nospace() << "QPainterPath: Element count=" << p.elementCount() << Qt::endl;
3372 const char *types[] = {"MoveTo", "LineTo", "CurveTo", "CurveToData"};
3373 for (int i=0; i<p.elementCount(); ++i) {
3374 s.nospace() << " -> " << types[p.elementAt(i).type] << "(x=" << p.elementAt(i).x << ", y=" << p.elementAt(i).y << ')' << Qt::endl;
3375
3376 }
3377 return s;
3378}
3379#endif
3380
QPointF pt1() const
Definition qbezier_p.h:63
qreal x4
Definition qbezier_p.h:85
QRectF bounds() const
Definition qbezier.cpp:239
static QBezier fromPoints(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4)
Definition qbezier_p.h:34
std::pair< QBezier, QBezier > split() const
Definition qbezier_p.h:193
qreal y1
Definition qbezier_p.h:85
qreal y4
Definition qbezier_p.h:85
static void coefficients(qreal t, qreal &a, qreal &b, qreal &c, qreal &d)
Definition qbezier_p.h:121
qreal x1
Definition qbezier_p.h:85
QPointF pt4() const
Definition qbezier_p.h:66
qreal x3
Definition qbezier_p.h:85
qreal y3
Definition qbezier_p.h:85
qreal x2
Definition qbezier_p.h:85
void addToPolygon(QPolygonF *p, qreal bezier_flattening_threshold=0.5) const
Definition qbezier.cpp:65
qreal y2
Definition qbezier_p.h:85
void setDashPattern(const QList< qfixed > &dashPattern)
Definition qstroker_p.h:237
void setDashOffset(qreal offset)
Definition qstroker_p.h:240
static QList< qfixed > patternForStyle(Qt::PenStyle style)
Definition qstroker.cpp:995
\inmodule QtCore\reentrant
Definition qdatastream.h:30
\inmodule QtCore
void reset(T *ptr=nullptr) noexcept
void detach()
If the shared data object's reference count is greater than 1, this function creates a deep copy of t...
virtual QFixed ascent() const
virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags)
virtual QFixed lineThickness() const
virtual QFixed underlinePosition() const
\reentrant
Definition qfont.h:20
\inmodule QtCore
Definition qline.h:182
qreal angle() const
Definition qline.cpp:558
qreal length() const
Returns the length of the line.
Definition qline.cpp:542
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
T & first()
Definition qlist.h:628
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
const T & constFirst() const noexcept
Definition qlist.h:630
void reserve(qsizetype size)
Definition qlist.h:746
pointer data()
Definition qlist.h:414
void resize(qsizetype size)
Definition qlist.h:392
void append(parameter_type t)
Definition qlist.h:441
void clear()
Definition qlist.h:417
The QPainterPathStroker class is used to generate fillable outlines for a given painter path.
void setCurveThreshold(qreal threshold)
Specifies the curve flattening threshold, controlling the granularity with which the generated outlin...
Qt::PenJoinStyle joinStyle() const
Returns the join style of the generated outlines.
QList< qreal > dashPattern() const
Returns the dash pattern for the generated outlines.
void setDashPattern(Qt::PenStyle)
Sets the dash pattern for the generated outlines to style.
qreal miterLimit() const
Returns the miter limit for the generated outlines.
qreal curveThreshold() const
Returns the curve flattening threshold for the generated outlines.
Qt::PenCapStyle capStyle() const
Returns the cap style of the generated outlines.
~QPainterPathStroker()
Destroys the stroker.
qreal width() const
Returns the width of the generated outlines.
void setDashOffset(qreal offset)
Sets the dash offset for the generated outlines to offset.
void setCapStyle(Qt::PenCapStyle style)
Sets the cap style of the generated outlines to style.
void setWidth(qreal width)
Sets the width of the generated outline painter path to width.
QPainterPath createStroke(const QPainterPath &path) const
Generates a new path that is a fillable area representing the outline of the given path.
QPainterPathStroker()
Creates a new stroker.
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style of the generated outlines to style.
qreal dashOffset() const
Returns the dash offset for the generated outlines.
void setMiterLimit(qreal length)
Sets the miter limit of the generated outlines to limit.
\inmodule QtGui
\inmodule QtGui
void quadTo(const QPointF &ctrlPt, const QPointF &endPt)
Adds a quadratic Bezier curve between the current position and the given endPoint with the control po...
int capacity() const
Returns the number of elements allocated by the QPainterPath.
QPainterPath operator-(const QPainterPath &other) const
QPainterPath translated(qreal dx, qreal dy) const
Returns a copy of the path that is translated by ({dx}, {dy}).
void translate(qreal dx, qreal dy)
Translates all elements in the path by ({dx}, {dy}).
void addRect(const QRectF &rect)
Adds the given rectangle to this path as a closed subpath.
QList< QPolygonF > toSubpathPolygons(const QTransform &matrix=QTransform()) const
Converts the path into a list of polygons using the QTransform matrix, and returns the list.
void moveTo(const QPointF &p)
Moves the current point to the given point, implicitly starting a new subpath and closing the previou...
~QPainterPath()
Destroys this QPainterPath object.
void addEllipse(const QRectF &rect)
Creates an ellipse within the specified boundingRectangle and adds it to the painter path as a closed...
qreal angleAtPercent(qreal t) const
Returns the angle of the path tangent at the percentage t.
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule of the painter path to the given fillRule.
void setElementPositionAt(int i, qreal x, qreal y)
QPainterPath subtracted(const QPainterPath &r) const
QPainterPath & operator=(const QPainterPath &other)
Assigns the given path to this painter path.
QPainterPath operator+(const QPainterPath &other) const
QPainterPath::Element elementAt(int i) const
Returns the element at the given index in the painter path.
QPainterPath() noexcept
Constructs an empty QPainterPath object.
void connectPath(const QPainterPath &path)
Connects the given path to this path by adding a line from the last element of this path to the first...
int elementCount() const
Returns the number of path elements in the painter path.
void addPolygon(const QPolygonF &polygon)
Adds the given polygon to the path as an (unclosed) subpath.
QPainterPath & operator&=(const QPainterPath &other)
QPainterPath simplified() const
void addPath(const QPainterPath &path)
Adds the given path to this path as a closed subpath.
QPolygonF toFillPolygon(const QTransform &matrix=QTransform()) const
Converts the path into a polygon using the QTransform matrix, and returns the polygon.
QRectF controlPointRect() const
Returns the rectangle containing all the points and control points in this path.
QPainterPath & operator|=(const QPainterPath &other)
bool intersects(const QRectF &rect) const
Returns true if any point in the given rectangle intersects the path; otherwise returns false.
QList< QPolygonF > toFillPolygons(const QTransform &matrix=QTransform()) const
Converts the path into a list of polygons using the QTransform matrix, and returns the list.
void clear()
Clears the path elements stored.
QRectF boundingRect() const
Returns the bounding rectangle of this painter path as a rectangle with floating point precision.
bool contains(const QPointF &pt) const
Returns true if the given point is inside the path, otherwise returns false.
bool operator!=(const QPainterPath &other) const
Returns true if this painter path differs from the given path.
Qt::FillRule fillRule() const
Returns the painter path's currently set fill rule.
bool isEmpty() const
Returns true if either there are no elements in this path, or if the only element is a MoveToElement;...
QPointF pointAtPercent(qreal t) const
Returns the point at at the percentage t of the current path.
QPainterPath united(const QPainterPath &r) const
void addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode=Qt::AbsoluteSize)
void reserve(int size)
Reserves a given amount of elements in QPainterPath's internal memory.
QPainterPath & operator-=(const QPainterPath &other)
void arcTo(const QRectF &rect, qreal startAngle, qreal arcLength)
Creates an arc that occupies the given rectangle, beginning at the specified startAngle and extending...
QPainterPath operator|(const QPainterPath &other) const
bool operator==(const QPainterPath &other) const
Returns true if this painterpath is equal to the given path.
QPainterPath intersected(const QPainterPath &r) const
qreal percentAtLength(qreal t) const
Returns percentage of the whole path at the specified length len.
QPainterPath toReversed() const
Creates and returns a reversed copy of the path.
ElementType
This enum describes the types of elements used to connect vertices in subpaths.
QPainterPath & operator+=(const QPainterPath &other)
qreal slopeAtPercent(qreal t) const
Returns the slope of the path at the percentage t.
void closeSubpath()
Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting ...
void addText(const QPointF &point, const QFont &f, const QString &text)
Adds the given text to this path as a set of closed subpaths created from the font supplied.
void lineTo(const QPointF &p)
Adds a straight line from the current position to the given endPoint.
QPointF currentPosition() const
Returns the current position of the path.
qreal length() const
Returns the length of the current path.
void swap(QPainterPath &other) noexcept
void cubicTo(const QPointF &ctrlPt1, const QPointF &ctrlPt2, const QPointF &endPt)
Adds a cubic Bezier curve between the current position and the given endPoint using the control point...
void addRegion(const QRegion &region)
Adds the given region to the path by adding each rectangle in the region as a separate closed subpath...
QPainterPath operator&(const QPainterPath &other) const
void arcMoveTo(const QRectF &rect, qreal angle)
QPainterPath clip(Operation op=BoolAnd)
\inmodule QtGui
Definition qpen.h:25
qreal widthF() const
Returns the pen width with floating point precision.
Definition qpen.cpp:598
QList< qreal > dashPattern() const
Returns the dash pattern of this pen.
Definition qpen.cpp:420
Qt::PenCapStyle capStyle() const
Returns the pen's cap style.
Definition qpen.cpp:662
Qt::PenJoinStyle joinStyle() const
Returns the pen's join style.
Definition qpen.cpp:689
qreal miterLimit() const
Returns the miter limit of the pen.
Definition qpen.cpp:548
qreal dashOffset() const
Returns the dash offset for the pen.
Definition qpen.cpp:506
Qt::PenStyle style() const
Returns the pen style.
Definition qpen.cpp:385
\inmodule QtCore\reentrant
Definition qpoint.h:214
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:333
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:338
The QPolygonF class provides a list of points using floating point precision.
Definition qpolygon.h:96
bool isClosed() const
Returns true if the polygon is closed; otherwise returns false.
Definition qpolygon.h:116
\inmodule QtCore\reentrant
Definition qrect.h:483
constexpr qreal bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:499
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:658
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:718
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:715
constexpr qreal left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:496
bool intersects(const QRectF &r) const noexcept
Returns true if this rectangle intersects with the given rectangle (i.e.
Definition qrect.cpp:2263
constexpr bool isNull() const noexcept
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition qrect.h:644
constexpr QSizeF size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:721
constexpr qreal top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:497
constexpr qreal right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:498
\inmodule QtCore\reentrant
Definition qrect.h:30
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
\inmodule QtCore
Definition qsize.h:207
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
qsizetype length() const
Returns the number of characters in this string.
Definition qstring.h:187
void setCubicToHook(qStrokerCubicToHook cubicToHook)
Definition qstroker_p.h:114
void setMoveToHook(qStrokerMoveToHook moveToHook)
Definition qstroker_p.h:112
void strokePath(const QPainterPath &path, void *data, const QTransform &matrix)
Convenience function that decomposes path into begin(), moveTo(), lineTo(), curevTo() and end() calls...
Definition qstroker.cpp:200
void setLineToHook(qStrokerLineToHook lineToHook)
Definition qstroker_p.h:113
void setClipRect(const QRectF &clip)
Definition qstroker_p.h:129
QScriptLineArray lines
LayoutData * layoutData
QGlyphLayout shapedGlyphs(const QScriptItem *si) const
QFontEngine * fontEngine(const QScriptItem &si, QFixed *ascent=nullptr, QFixed *descent=nullptr, QFixed *leading=nullptr) const
static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder)
\reentrant
Definition qtextlayout.h:70
\reentrant
\reentrant
Definition qtextoption.h:18
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
T * data() noexcept
QPixmap p2
QPixmap p1
[0]
QString text
double e
rect
[4]
QStyleOptionButton opt
Combined button and popup list for selecting options.
@ AbsoluteSize
@ CustomDashLine
PenJoinStyle
@ WindingFill
@ OddEvenFill
QTextStream & endl(QTextStream &stream)
Writes '\n' to the stream and flushes the stream.
PenCapStyle
static jboolean copy(JNIEnv *, jobject)
bool qIsFinite(qfloat16 f) noexcept
Definition qfloat16.h:239
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:287
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:303
qfloat16 qSqrt(qfloat16 f)
Definition qfloat16.h:243
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
int qFloor(T v)
Definition qmath.h:42
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum mode
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint GLfloat GLfloat GLfloat x1
GLsizei GLenum GLenum * types
GLenum GLuint GLenum GLsizei length
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLdouble GLdouble right
GLfloat GLfloat f
GLsizei levels
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
[4]
GLint GLsizei width
GLint left
GLenum type
GLint GLint bottom
GLfloat angle
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint start
GLenum GLuint GLintptr offset
GLint first
GLsizei dashCount
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLfixed GLfixed GLint GLint GLfixed points
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble GLdouble w2
GLuint res
const GLubyte * c
GLfixed GLfixed GLfixed y2
GLuint GLuint * names
GLenum GLsizei len
GLint limit
GLuint GLenum matrix
GLfixed GLfixed x2
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLbyte ty
GLbyte by
static const QRectF boundingRect(const QPointF *points, int pointCount)
static QBezier bezierAtT(const QPainterPath &path, qreal t, qreal *startingLength, qreal *bezierLength)
static qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
void qt_path_stroke_move_to(qfixed x, qfixed y, void *data)
static bool qt_painterpath_check_crossing(const QPainterPath *path, const QRectF &rect)
QDataStream & operator<<(QDataStream &s, const QPainterPath &p)
static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2, int depth=0)
static void qt_painterpath_isect_line(const QPointF &p1, const QPointF &p2, const QPointF &pos, int *winding)
static QRectF qt_painterpath_bezier_extrema(const QBezier &b)
#define QT_BEZIER_CHECK_T(bezier, t)
PainterDirections
@ Bottom
@ Top
@ Left
@ Right
static bool qt_painterpath_isect_line_rect(qreal x1, qreal y1, qreal x2, qreal y2, const QRectF &rect)
#define QT_BEZIER_C(bezier, coord)
void qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length, QPointF *startPoint, QPointF *endPoint)
QDataStream & operator>>(QDataStream &s, QPainterPath &p)
void qt_path_stroke_cubic_to(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey, void *data)
#define QT_BEZIER_A(bezier, coord)
static bool epsilonCompare(const QPointF &a, const QPointF &b, const QSizeF &epsilon)
#define QT_BEZIER_B(bezier, coord)
static QT_BEGIN_NAMESPACE bool isValidCoord(qreal c)
static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt, int *winding, int depth=0)
static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2, int depth=0)
static bool pointOnEdge(const QRectF &rect, const QPointF &point)
QPainterPath qt_stroke_dash(const QPainterPath &path, qreal *dashes, int dashCount)
static bool hasValidCoords(QPointF p)
void qt_path_stroke_line_to(qfixed x, qfixed y, void *data)
static const qreal epsilon
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
qreal qt_t_for_arc_angle(qreal angle)
Definition qstroker.cpp:756
QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength, QPointF *curves, int *point_count)
Definition qstroker.cpp:816
#define QT_PATH_KAPPA
Definition qstroker_p.h:77
#define qt_fixed_to_real(fixed)
Definition qstroker_p.h:65
#define qt_real_to_fixed(real)
Definition qstroker_p.h:64
QT_BEGIN_NAMESPACE typedef qreal qfixed
Definition qstroker_p.h:63
#define sp
#define t2
static const QTextHtmlElement elements[Html_NumElements]
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:92
QVBoxLayout * layout
MyCustomStruct c2
QSharedPointer< T > other(t)
[5]
QString dir
[11]
QGraphicsItem * item
QStringView el
constexpr qreal toReal() const
Definition qfixed_p.h:42
unsigned short flags
unsigned short bidiLevel
QScriptAnalysis analysis
signed int length
QScriptItemArray items