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
25QT_BEGIN_NAMESPACE
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(p: 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 friend Q_QUICK_EXPORT QDebug operator<<(QDebug, const QQuadPath::Element &);
186 };
187
188 void moveTo(const QVector2D &to)
189 {
190 m_subPathToStart = true;
191 m_currentPoint = to;
192 }
193
194 void lineTo(const QVector2D &to)
195 {
196 addElement(control: {}, to, isLine: true);
197 }
198
199 void quadTo(const QVector2D &control, const QVector2D &to)
200 {
201 addElement(control, to);
202 }
203
204 Element &elementAt(int i)
205 {
206 return i < 0 ? m_childElements[-(i + 1)] : m_elements[i];
207 }
208
209 const Element &elementAt(int i) const
210 {
211 return i < 0 ? m_childElements[-(i + 1)] : m_elements[i];
212 }
213
214 int indexOfChildAt(int i, int childNumber) const
215 {
216 return elementAt(i).indexOfChild(childNumber);
217 }
218
219 QRectF controlPointRect() const;
220
221 Qt::FillRule fillRule() const { return m_windingFill ? Qt::WindingFill : Qt::OddEvenFill; }
222 void setFillRule(Qt::FillRule rule) { m_windingFill = (rule == Qt::WindingFill); }
223
224 void reserve(int size) { m_elements.reserve(asize: size); }
225 int elementCount() const { return m_elements.size(); }
226 bool isEmpty() const { return m_elements.size() == 0; }
227 int elementCountRecursive() const;
228
229 static QQuadPath fromPainterPath(const QPainterPath &path, PathHints hints = {});
230 QPainterPath toPainterPath() const;
231 QString asSvgString() const;
232
233 QQuadPath subPathsClosed(bool *didClose = nullptr) const;
234 void addCurvatureData();
235 QQuadPath flattened() const;
236 QQuadPath dashed(qreal lineWidth, const QList<qreal> &dashPattern, qreal dashOffset = 0) const;
237 void splitElementAt(int index);
238 bool contains(const QVector2D &point) const;
239 bool contains(const QVector2D &point, int fromIndex, int toIndex) const;
240 Element::FillSide fillSideOf(int elementIdx, float elementT) const;
241
242 template<typename Func>
243 void iterateChildrenOf(Element &e, Func &&lambda)
244 {
245 const int lastChildIndex = e.m_firstChildIndex + e.childCount() - 1;
246 for (int i = e.m_firstChildIndex; i <= lastChildIndex; i++) {
247 Element &c = m_childElements[i];
248 if (c.childCount() > 0)
249 iterateChildrenOf(c, lambda);
250 else
251 lambda(c, -(i + 1));
252 }
253 }
254
255 template<typename Func>
256 void iterateChildrenOf(const Element &e, Func &&lambda) const
257 {
258 const int lastChildIndex = e.m_firstChildIndex + e.childCount() - 1;
259 for (int i = e.m_firstChildIndex; i <= lastChildIndex; i++) {
260 const Element &c = m_childElements[i];
261 if (c.childCount() > 0)
262 iterateChildrenOf(c, lambda);
263 else
264 lambda(c, -(i + 1));
265 }
266 }
267
268 template<typename Func>
269 void iterateElements(Func &&lambda)
270 {
271 for (int i = 0; i < m_elements.size(); i++) {
272 Element &e = m_elements[i];
273 if (e.childCount() > 0)
274 iterateChildrenOf(e, lambda);
275 else
276 lambda(e, i);
277 }
278 }
279
280 template<typename Func>
281 void iterateElements(Func &&lambda) const
282 {
283 for (int i = 0; i < m_elements.size(); i++) {
284 const Element &e = m_elements[i];
285 if (e.childCount() > 0)
286 iterateChildrenOf(e, lambda);
287 else
288 lambda(e, i);
289 }
290 }
291
292 static QVector2D closestPointOnLine(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
293 static bool isPointOnLeft(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
294 static bool isPointOnLine(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
295 static bool isPointNearLine(const QVector2D &p, const QVector2D &sp, const QVector2D &ep);
296
297 bool testHint(PathHint hint) const
298 {
299 return m_hints.testFlag(flag: hint);
300 }
301
302 void setHint(PathHint hint, bool on = true)
303 {
304 m_hints.setFlag(flag: hint, on);
305 }
306
307 PathHints pathHints() const
308 {
309 return m_hints;
310 }
311
312 void setPathHints(PathHints newHints)
313 {
314 m_hints = newHints;
315 }
316
317private:
318 void addElement(const QVector2D &control, const QVector2D &to, bool isLine = false);
319 void addElement(const Element &e);
320 Element::CurvatureFlags coordinateOrderOfElement(const Element &element) const;
321
322 friend Q_QUICK_EXPORT QDebug operator<<(QDebug, const QQuadPath &);
323
324 QList<Element> m_elements;
325 QList<Element> m_childElements;
326 QVector2D m_currentPoint;
327 bool m_subPathToStart = true;
328 bool m_windingFill = false;
329 PathHints m_hints;
330
331 friend class QSGCurveProcessor;
332};
333
334Q_DECLARE_OPERATORS_FOR_FLAGS(QQuadPath::PathHints);
335
336Q_QUICK_EXPORT QDebug operator<<(QDebug, const QQuadPath::Element &);
337Q_QUICK_EXPORT QDebug operator<<(QDebug, const QQuadPath &);
338
339QT_END_NAMESPACE
340
341#endif
342

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtdeclarative/src/quick/scenegraph/util/qquadpath_p.h