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 Element (QVector2D s, QVector2D e)
56 : sp(s), cp(s), ep(e), m_isSubpathStart(false), m_isSubpathEnd(false), m_isLine(true)
57 {
58 }
59
60 bool isSubpathStart() const
61 {
62 return m_isSubpathStart;
63 }
64
65 bool isSubpathEnd() const
66 {
67 return m_isSubpathEnd;
68 }
69
70 bool isLine() const
71 {
72 return m_isLine;
73 }
74
75 bool isConvex() const
76 {
77 return m_curvatureFlags & Convex;
78 }
79
80 QVector2D startPoint() const
81 {
82 return sp;
83 }
84
85 QVector2D controlPoint() const
86 {
87 return cp;
88 }
89
90 QVector2D endPoint() const
91 {
92 return ep;
93 }
94
95 QVector2D midPoint() const
96 {
97 return isLine() ? 0.5f * (sp + ep) : (0.25f * sp) + (0.5f * cp) + (0.25 * ep);
98 }
99
100 /* For a curve, returns the control point. For a line, returns an arbitrary point on the
101 * inside side of the line (assuming the curvature has been set for the path). The point
102 * doesn't need to actually be inside the shape: it just makes for easier calculations
103 * later when it is at the same side as the fill. */
104 QVector2D referencePoint() const
105 {
106 if (isLine()) {
107 QVector2D normal(sp.y() - ep.y(), ep.x() - sp.x());
108 return m_curvatureFlags & Element::FillOnRight ? sp + normal : sp - normal;
109 } else {
110 return cp;
111 }
112 }
113
114 Element segmentFromTo(float t0, float t1) const;
115
116 Element reversed() const;
117
118 int childCount() const { return m_numChildren; }
119
120 int indexOfChild(int childNumber) const
121 {
122 Q_ASSERT(childNumber >= 0 && childNumber < childCount());
123 return -(m_firstChildIndex + 1 + childNumber);
124 }
125
126 QVector2D pointAtFraction(float t) const;
127
128 QVector2D tangentAtFraction(float t) const
129 {
130 return isLine() ? (ep - sp) : ((1 - t) * 2 * (cp - sp)) + (t * 2 * (ep - cp));
131 }
132
133 QVector2D normalAtFraction(float t) const
134 {
135 const QVector2D tan = tangentAtFraction(t);
136 return QVector2D(-tan.y(), tan.x());
137 }
138
139 float extent() const;
140
141 void setAsConvex(bool isConvex)
142 {
143 if (isConvex)
144 m_curvatureFlags = Element::CurvatureFlags(m_curvatureFlags | Element::Convex);
145 else
146 m_curvatureFlags = Element::CurvatureFlags(m_curvatureFlags & ~Element::Convex);
147 }
148
149 void setFillOnRight(bool isFillOnRight)
150 {
151 if (isFillOnRight)
152 m_curvatureFlags = Element::CurvatureFlags(m_curvatureFlags | Element::FillOnRight);
153 else
154 m_curvatureFlags = Element::CurvatureFlags(m_curvatureFlags & ~Element::FillOnRight);
155 }
156
157 bool isFillOnRight() const { return m_curvatureFlags & FillOnRight; }
158
159 bool isControlPointOnLeft() const
160 {
161 return isPointOnLeft(cp, sp, ep);
162 }
163
164 enum CurvatureFlags : quint8 {
165 CurvatureUndetermined = 0,
166 FillOnRight = 1,
167 Convex = 2
168 };
169
170 enum FillSide : quint8 {
171 FillSideUndetermined = 0,
172 FillSideRight = 1,
173 FillSideLeft = 2,
174 FillSideBoth = 3
175 };
176
177 private:
178 int intersectionsAtY(float y, float *fractions, bool swapXY = false) const;
179
180 QVector2D sp;
181 QVector2D cp;
182 QVector2D ep;
183 int m_firstChildIndex = 0;
184 quint8 m_numChildren = 0;
185 CurvatureFlags m_curvatureFlags = CurvatureUndetermined;
186 quint8 m_isSubpathStart : 1;
187 quint8 m_isSubpathEnd : 1;
188 quint8 m_isLine : 1;
189 friend class QQuadPath;
190#ifndef QT_NO_DEBUG_STREAM
191 friend Q_QUICK_EXPORT QDebug operator<<(QDebug, const QQuadPath::Element &);
192#endif
193 };
194
195 void moveTo(const QVector2D &to)
196 {
197 m_subPathToStart = true;
198 m_currentPoint = to;
199 }
200
201 void lineTo(const QVector2D &to)
202 {
203 addElement({}, to, true);
204 }
205
206 void quadTo(const QVector2D &control, const QVector2D &to)
207 {
208 addElement(control, to);
209 }
210
211 Element &elementAt(int i)
212 {
213 return i < 0 ? m_childElements[-(i + 1)] : m_elements[i];
214 }
215
216 const Element &elementAt(int i) const
217 {
218 return i < 0 ? m_childElements[-(i + 1)] : m_elements[i];
219 }
220
221 int indexOfChildAt(int i, int childNumber) const
222 {
223 return elementAt(i).indexOfChild(childNumber);
224 }
225
226 QRectF controlPointRect() const;
227
228 Qt::FillRule fillRule() const { return m_windingFill ? Qt::WindingFill : Qt::OddEvenFill; }
229 void setFillRule(Qt::FillRule rule) { m_windingFill = (rule == Qt::WindingFill); }
230
231 void reserve(int size) { m_elements.reserve(size); }
232 int elementCount() const { return m_elements.size(); }
233 bool isEmpty() const { return m_elements.size() == 0; }
234 int elementCountRecursive() const;
235 int lineCount() const
236 {
237 return std::count_if(m_elements.cbegin(), m_elements.cend(),
238 [](const Element &e) { return e.isLine(); });
239 }
240
241 static QQuadPath fromPainterPath(const QPainterPath &path, PathHints hints = {});
242 QPainterPath toPainterPath() const;
243 QString asSvgString() const;
244
245 QQuadPath subPathsClosed(bool *didClose = nullptr) const;
246 void addCurvatureData();
247 QQuadPath flattened() const;
248 QQuadPath dashed(qreal lineWidth, const QList<qreal> &dashPattern, qreal dashOffset = 0) const;
249 void splitElementAt(int index);
250 bool contains(const QVector2D &point) const;
251 bool contains(const QVector2D &point, int fromIndex, int toIndex) const;
252 Element::FillSide fillSideOf(int elementIdx, float elementT) const;
253
254 template<typename Func>
255 void iterateChildrenOf(Element &e, Func &&lambda)
256 {
257 const int lastChildIndex = e.m_firstChildIndex + e.childCount() - 1;
258 for (int i = e.m_firstChildIndex; i <= lastChildIndex; i++) {
259 Element &c = m_childElements[i];
260 if (c.childCount() > 0)
261 iterateChildrenOf(c, lambda);
262 else
263 lambda(c, -(i + 1));
264 }
265 }
266
267 template<typename Func>
268 void iterateChildrenOf(const Element &e, Func &&lambda) const
269 {
270 const int lastChildIndex = e.m_firstChildIndex + e.childCount() - 1;
271 for (int i = e.m_firstChildIndex; i <= lastChildIndex; i++) {
272 const Element &c = m_childElements[i];
273 if (c.childCount() > 0)
274 iterateChildrenOf(c, lambda);
275 else
276 lambda(c, -(i + 1));
277 }
278 }
279
280 template<typename Func>
281 void iterateElements(Func &&lambda)
282 {
283 for (int i = 0; i < m_elements.size(); i++) {
284 Element &e = m_elements[i];
285 if (e.childCount() > 0)
286 iterateChildrenOf(e, lambda);
287 else
288 lambda(e, i);
289 }
290 }
291
292 template<typename Func>
293 void iterateElements(Func &&lambda) const
294 {
295 for (int i = 0; i < m_elements.size(); i++) {
296 const Element &e = m_elements[i];
297 if (e.childCount() > 0)
298 iterateChildrenOf(e, lambda);
299 else
300 lambda(e, i);
301 }
302 }
303
304 static QVector2D closestPointOnLine(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
305 static bool isPointOnLeft(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
306 static bool isPointOnLine(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
307 static bool isPointNearLine(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
308
309 bool testHint(PathHint hint) const
310 {
311 return m_hints.testFlag(hint);
312 }
313
314 void setHint(PathHint hint, bool on = true)
315 {
316 m_hints.setFlag(hint, on);
317 }
318
319 PathHints pathHints() const
320 {
321 return m_hints;
322 }
323
324 void setPathHints(PathHints newHints)
325 {
326 m_hints = newHints;
327 }
328
329private:
330 void addElement(const QVector2D &control, const QVector2D &to, bool isLine = false);
331 void addElement(const Element &e);
332 Element::FillSide coordinateOrderOfElement(const Element &element) const;
333
334#ifndef QT_NO_DEBUG_STREAM
335 friend Q_QUICK_EXPORT QDebug operator<<(QDebug, const QQuadPath &);
336#endif
337
338 QList<Element> m_elements;
339 QList<Element> m_childElements;
340 QVector2D m_currentPoint;
341 bool m_subPathToStart = true;
342 bool m_windingFill = false;
343 PathHints m_hints;
344
345 friend class QSGCurveProcessor;
346};
347
348Q_DECLARE_OPERATORS_FOR_FLAGS(QQuadPath::PathHints);
349
350#ifndef QT_NO_DEBUG_STREAM
351Q_QUICK_EXPORT QDebug operator<<(QDebug, const QQuadPath::Element &);
352Q_QUICK_EXPORT QDebug operator<<(QDebug, const QQuadPath &);
353#endif
354
355QT_END_NAMESPACE
356
357#endif
Combined button and popup list for selecting options.
Q_CORE_EXPORT QDebug operator<<(QDebug debug, QDir::Filters filters)
Definition qdir.cpp:2582