31 enum PathHint : quint8 {
35 PathFillOnRight = 0x8,
37 PathNonIntersecting = 0x20,
38 PathNonOverlappingControlPointTriangles = 0x40
40 Q_DECLARE_FLAGS(PathHints, PathHint)
42 class Q_QUICK_EXPORT Element
46 : m_isSubpathStart(
false), m_isSubpathEnd(
false), m_isLine(
false)
50 Element (QVector2D s, QVector2D c, QVector2D e)
51 : sp(s), cp(c), ep(e), m_isSubpathStart(
false), m_isSubpathEnd(
false), m_isLine(
false)
55 Element (QVector2D s, QVector2D e)
56 : sp(s), cp(s), ep(e), m_isSubpathStart(
false), m_isSubpathEnd(
false), m_isLine(
true)
60 bool isSubpathStart()
const
62 return m_isSubpathStart;
65 bool isSubpathEnd()
const
67 return m_isSubpathEnd;
77 return m_curvatureFlags & Convex;
80 QVector2D startPoint()
const
85 QVector2D controlPoint()
const
90 QVector2D endPoint()
const
95 QVector2D midPoint()
const
97 return isLine() ? 0.5f * (sp + ep) : (0.25f * sp) + (0.5f * cp) + (0.25 * ep);
101
102
103
104 QVector2D referencePoint()
const
107 QVector2D normal(sp.y() - ep.y(), ep.x() - sp.x());
108 return m_curvatureFlags & Element::FillOnRight ? sp + normal : sp - normal;
114 Element segmentFromTo(
float t0,
float t1)
const;
116 Element reversed()
const;
118 int childCount()
const {
return m_numChildren; }
120 int indexOfChild(
int childNumber)
const
122 Q_ASSERT(childNumber >= 0 && childNumber < childCount());
123 return -(m_firstChildIndex + 1 + childNumber);
126 QVector2D pointAtFraction(
float t)
const;
128 QVector2D tangentAtFraction(
float t)
const
130 return isLine() ? (ep - sp) : ((1 - t) * 2 * (cp - sp)) + (t * 2 * (ep - cp));
133 QVector2D normalAtFraction(
float t)
const
135 const QVector2D tan = tangentAtFraction(t);
136 return QVector2D(-tan.y(), tan.x());
139 float extent()
const;
141 void setAsConvex(
bool isConvex)
144 m_curvatureFlags = Element::CurvatureFlags(m_curvatureFlags | Element::Convex);
146 m_curvatureFlags = Element::CurvatureFlags(m_curvatureFlags & ~Element::Convex);
149 void setFillOnRight(
bool isFillOnRight)
152 m_curvatureFlags = Element::CurvatureFlags(m_curvatureFlags | Element::FillOnRight);
154 m_curvatureFlags = Element::CurvatureFlags(m_curvatureFlags & ~Element::FillOnRight);
157 bool isFillOnRight()
const {
return m_curvatureFlags & FillOnRight; }
159 bool isControlPointOnLeft()
const
161 return isPointOnLeft(cp, sp, ep);
164 enum CurvatureFlags : quint8 {
165 CurvatureUndetermined = 0,
170 enum FillSide : quint8 {
171 FillSideUndetermined = 0,
178 int intersectionsAtY(
float y,
float *fractions,
bool swapXY =
false)
const;
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;
189 friend class QQuadPath;
190#ifndef QT_NO_DEBUG_STREAM
191 friend Q_QUICK_EXPORT QDebug operator<<(QDebug,
const QQuadPath::Element &);
195 void moveTo(
const QVector2D &to)
197 m_subPathToStart =
true;
201 void lineTo(
const QVector2D &to)
203 addElement({}, to,
true);
206 void quadTo(
const QVector2D &control,
const QVector2D &to)
208 addElement(control, to);
211 Element &elementAt(
int i)
213 return i < 0 ? m_childElements[-(i + 1)] : m_elements[i];
216 const Element &elementAt(
int i)
const
218 return i < 0 ? m_childElements[-(i + 1)] : m_elements[i];
221 int indexOfChildAt(
int i,
int childNumber)
const
223 return elementAt(i).indexOfChild(childNumber);
226 QRectF controlPointRect()
const;
228 Qt::FillRule fillRule()
const {
return m_windingFill ? Qt::WindingFill : Qt::OddEvenFill; }
229 void setFillRule(Qt::FillRule rule) { m_windingFill = (rule == Qt::WindingFill); }
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
237 return std::count_if(m_elements.cbegin(), m_elements.cend(),
238 [](
const Element &e) {
return e.isLine(); });
241 static QQuadPath fromPainterPath(
const QPainterPath &path, PathHints hints = {});
242 QPainterPath toPainterPath()
const;
243 QString asSvgString()
const;
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;
254 template<
typename Func>
255 void iterateChildrenOf(Element &e, Func &&lambda)
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);
267 template<
typename Func>
268 void iterateChildrenOf(
const Element &e, Func &&lambda)
const
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);
280 template<
typename Func>
281 void iterateElements(Func &&lambda)
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);
292 template<
typename Func>
293 void iterateElements(Func &&lambda)
const
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);
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);
309 bool testHint(PathHint hint)
const
311 return m_hints.testFlag(hint);
314 void setHint(PathHint hint,
bool on =
true)
316 m_hints.setFlag(hint, on);
319 PathHints pathHints()
const
324 void setPathHints(PathHints newHints)
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;
334#ifndef QT_NO_DEBUG_STREAM
335 friend Q_QUICK_EXPORT QDebug operator<<(QDebug,
const QQuadPath &);
338 QList<Element> m_elements;
339 QList<Element> m_childElements;
340 QVector2D m_currentPoint;
341 bool m_subPathToStart =
true;
342 bool m_windingFill =
false;
345 friend class QSGCurveProcessor;