Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquadpath_p.h
Go to the documentation of this file.
1// Copyright (C) 2022 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#ifndef QQUADPATH_P_H
5#define QQUADPATH_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists for the convenience
12// of a number of Qt sources files. This header file may change from
13// version to version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/qrect.h>
19#include <QtCore/qlist.h>
20#include <QtCore/qdebug.h>
21#include <QtGui/qvector2d.h>
22#include <QtGui/qpainterpath.h>
23#include <QtQuick/qtquickexports.h>
24
26
27class Q_QUICK_EXPORT QQuadPath
28{
29public:
30 // This is a copy of the flags in QQuickShapePath ### TODO: use a common definition
31 enum PathHint : quint8 {
32 PathLinear = 0x1,
33 PathQuadratic = 0x2,
34 PathConvex = 0x4,
35 PathFillOnRight = 0x8,
36 PathSolid = 0x10,
37 PathNonIntersecting = 0x20,
38 PathNonOverlappingControlPointTriangles = 0x40
39 };
40 Q_DECLARE_FLAGS(PathHints, PathHint)
41
42 class Q_QUICK_EXPORT Element
43 {
44 public:
45 Element ()
46 : m_isSubpathStart(false), m_isSubpathEnd(false), m_isLine(false)
47 {
48 }
49
50 Element (QVector2D s, QVector2D c, QVector2D e)
51 : sp(s), cp(c), ep(e), m_isSubpathStart(false), m_isSubpathEnd(false), m_isLine(false)
52 {
53 }
54
55 bool isSubpathStart() const
56 {
57 return m_isSubpathStart;
58 }
59
60 bool isSubpathEnd() const
61 {
62 return m_isSubpathEnd;
63 }
64
65 bool isLine() const
66 {
67 return m_isLine;
68 }
69
70 bool isConvex() const
71 {
72 return m_curvatureFlags & Convex;
73 }
74
75 QVector2D startPoint() const
76 {
77 return sp;
78 }
79
80 QVector2D controlPoint() const
81 {
82 return cp;
83 }
84
85 QVector2D endPoint() const
86 {
87 return ep;
88 }
89
90 QVector2D midPoint() const
91 {
92 return isLine() ? 0.5f * (sp + ep) : (0.25f * sp) + (0.5f * cp) + (0.25 * ep);
93 }
94
95 /* For a curve, returns the control point. For a line, returns an arbitrary point on the
96 * inside side of the line (assuming the curvature has been set for the path). The point
97 * doesn't need to actually be inside the shape: it just makes for easier calculations
98 * later when it is at the same side as the fill. */
99 QVector2D referencePoint() const
100 {
101 if (isLine()) {
102 QVector2D normal(sp.y() - ep.y(), ep.x() - sp.x());
103 return m_curvatureFlags & Element::FillOnRight ? sp + normal : sp - normal;
104 } else {
105 return cp;
106 }
107 }
108
109 Element segmentFromTo(float t0, float t1) const;
110
111 Element reversed() const;
112
113 int childCount() const { return m_numChildren; }
114
115 int indexOfChild(int childNumber) const
116 {
117 Q_ASSERT(childNumber >= 0 && childNumber < childCount());
118 return -(m_firstChildIndex + 1 + childNumber);
119 }
120
121 QVector2D pointAtFraction(float t) const;
122
123 QVector2D tangentAtFraction(float t) const
124 {
125 return isLine() ? (ep - sp) : ((1 - t) * 2 * (cp - sp)) + (t * 2 * (ep - cp));
126 }
127
128 QVector2D normalAtFraction(float t) const
129 {
130 const QVector2D tan = tangentAtFraction(t);
131 return QVector2D(-tan.y(), tan.x());
132 }
133
134 float extent() const;
135
136 void setAsConvex(bool isConvex)
137 {
138 if (isConvex)
139 m_curvatureFlags = Element::CurvatureFlags(m_curvatureFlags | Element::Convex);
140 else
141 m_curvatureFlags = Element::CurvatureFlags(m_curvatureFlags & ~Element::Convex);
142 }
143
144 void setFillOnRight(bool isFillOnRight)
145 {
146 if (isFillOnRight)
147 m_curvatureFlags = Element::CurvatureFlags(m_curvatureFlags | Element::FillOnRight);
148 else
149 m_curvatureFlags = Element::CurvatureFlags(m_curvatureFlags & ~Element::FillOnRight);
150 }
151
152 bool isFillOnRight() const { return m_curvatureFlags & FillOnRight; }
153
154 bool isControlPointOnLeft() const
155 {
156 return isPointOnLeft(cp, sp, ep);
157 }
158
159 enum CurvatureFlags : quint8 {
160 CurvatureUndetermined = 0,
161 FillOnRight = 1,
162 Convex = 2
163 };
164
165 enum FillSide : quint8 {
166 FillSideUndetermined = 0,
167 FillSideRight = 1,
168 FillSideLeft = 2,
169 FillSideBoth = 3
170 };
171
172 private:
173 int intersectionsAtY(float y, float *fractions, bool swapXY = false) const;
174
175 QVector2D sp;
176 QVector2D cp;
177 QVector2D ep;
178 int m_firstChildIndex = 0;
179 quint8 m_numChildren = 0;
180 CurvatureFlags m_curvatureFlags = CurvatureUndetermined;
181 quint8 m_isSubpathStart : 1;
182 quint8 m_isSubpathEnd : 1;
183 quint8 m_isLine : 1;
184 friend class QQuadPath;
185#ifndef QT_NO_DEBUG_STREAM
186 friend Q_QUICK_EXPORT QDebug operator<<(QDebug, const QQuadPath::Element &);
187#endif
188 };
189
190 void moveTo(const QVector2D &to)
191 {
192 m_subPathToStart = true;
193 m_currentPoint = to;
194 }
195
196 void lineTo(const QVector2D &to)
197 {
198 addElement({}, to, true);
199 }
200
201 void quadTo(const QVector2D &control, const QVector2D &to)
202 {
203 addElement(control, to);
204 }
205
206 Element &elementAt(int i)
207 {
208 return i < 0 ? m_childElements[-(i + 1)] : m_elements[i];
209 }
210
211 const Element &elementAt(int i) const
212 {
213 return i < 0 ? m_childElements[-(i + 1)] : m_elements[i];
214 }
215
216 int indexOfChildAt(int i, int childNumber) const
217 {
218 return elementAt(i).indexOfChild(childNumber);
219 }
220
221 QRectF controlPointRect() const;
222
223 Qt::FillRule fillRule() const { return m_windingFill ? Qt::WindingFill : Qt::OddEvenFill; }
224 void setFillRule(Qt::FillRule rule) { m_windingFill = (rule == Qt::WindingFill); }
225
226 void reserve(int size) { m_elements.reserve(size); }
227 int elementCount() const { return m_elements.size(); }
228 bool isEmpty() const { return m_elements.size() == 0; }
229 int elementCountRecursive() const;
230
231 static QQuadPath fromPainterPath(const QPainterPath &path, PathHints hints = {});
232 QPainterPath toPainterPath() const;
233 QString asSvgString() const;
234
235 QQuadPath subPathsClosed(bool *didClose = nullptr) const;
236 void addCurvatureData();
237 QQuadPath flattened() const;
238 QQuadPath dashed(qreal lineWidth, const QList<qreal> &dashPattern, qreal dashOffset = 0) const;
239 void splitElementAt(int index);
240 bool contains(const QVector2D &point) const;
241 bool contains(const QVector2D &point, int fromIndex, int toIndex) const;
242 Element::FillSide fillSideOf(int elementIdx, float elementT) const;
243
244 template<typename Func>
245 void iterateChildrenOf(Element &e, Func &&lambda)
246 {
247 const int lastChildIndex = e.m_firstChildIndex + e.childCount() - 1;
248 for (int i = e.m_firstChildIndex; i <= lastChildIndex; i++) {
249 Element &c = m_childElements[i];
250 if (c.childCount() > 0)
251 iterateChildrenOf(c, lambda);
252 else
253 lambda(c, -(i + 1));
254 }
255 }
256
257 template<typename Func>
258 void iterateChildrenOf(const Element &e, Func &&lambda) const
259 {
260 const int lastChildIndex = e.m_firstChildIndex + e.childCount() - 1;
261 for (int i = e.m_firstChildIndex; i <= lastChildIndex; i++) {
262 const Element &c = m_childElements[i];
263 if (c.childCount() > 0)
264 iterateChildrenOf(c, lambda);
265 else
266 lambda(c, -(i + 1));
267 }
268 }
269
270 template<typename Func>
271 void iterateElements(Func &&lambda)
272 {
273 for (int i = 0; i < m_elements.size(); i++) {
274 Element &e = m_elements[i];
275 if (e.childCount() > 0)
276 iterateChildrenOf(e, lambda);
277 else
278 lambda(e, i);
279 }
280 }
281
282 template<typename Func>
283 void iterateElements(Func &&lambda) const
284 {
285 for (int i = 0; i < m_elements.size(); i++) {
286 const Element &e = m_elements[i];
287 if (e.childCount() > 0)
288 iterateChildrenOf(e, lambda);
289 else
290 lambda(e, i);
291 }
292 }
293
294 static QVector2D closestPointOnLine(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
295 static bool isPointOnLeft(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
296 static bool isPointOnLine(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
297 static bool isPointNearLine(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
298
299 bool testHint(PathHint hint) const
300 {
301 return m_hints.testFlag(hint);
302 }
303
304 void setHint(PathHint hint, bool on = true)
305 {
306 m_hints.setFlag(hint, on);
307 }
308
309 PathHints pathHints() const
310 {
311 return m_hints;
312 }
313
314 void setPathHints(PathHints newHints)
315 {
316 m_hints = newHints;
317 }
318
319private:
320 void addElement(const QVector2D &control, const QVector2D &to, bool isLine = false);
321 void addElement(const Element &e);
322 Element::FillSide coordinateOrderOfElement(const Element &element) const;
323
324#ifndef QT_NO_DEBUG_STREAM
325 friend Q_QUICK_EXPORT QDebug operator<<(QDebug, const QQuadPath &);
326#endif
327
328 QList<Element> m_elements;
329 QList<Element> m_childElements;
330 QVector2D m_currentPoint;
331 bool m_subPathToStart = true;
332 bool m_windingFill = false;
333 PathHints m_hints;
334
335 friend class QSGCurveProcessor;
336};
337
338Q_DECLARE_OPERATORS_FOR_FLAGS(QQuadPath::PathHints);
339
340#ifndef QT_NO_DEBUG_STREAM
341Q_QUICK_EXPORT QDebug operator<<(QDebug, const QQuadPath::Element &);
342Q_QUICK_EXPORT QDebug operator<<(QDebug, const QQuadPath &);
343#endif
344
345QT_END_NAMESPACE
346
347#endif
Q_CORE_EXPORT QDebug operator<<(QDebug debug, QDir::Filters filters)
Definition qdir.cpp:2568