Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qstroker.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 "private/qstroker_p.h"
5#include "private/qbezier_p.h"
6#include "qline.h"
7#include "qtransform.h"
8#include <qmath.h>
9
11
12// #define QPP_STROKE_DEBUG
13
15{
16public:
17 QSubpathForwardIterator(const QDataBuffer<QStrokerOps::Element> *path)
18 : m_path(path), m_pos(0) { }
19 inline int position() const { return m_pos; }
20 inline bool hasNext() const { return m_pos < m_path->size(); }
21 inline QStrokerOps::Element next() { Q_ASSERT(hasNext()); return m_path->at(m_pos++); }
22
23private:
24 const QDataBuffer<QStrokerOps::Element> *m_path;
25 int m_pos;
26};
27
29{
30public:
31 QSubpathBackwardIterator(const QDataBuffer<QStrokerOps::Element> *path)
32 : m_path(path), m_pos(path->size() - 1) { }
33
34 inline int position() const { return m_pos; }
35
36 inline bool hasNext() const { return m_pos >= 0; }
37
39 {
41
42 QStrokerOps::Element ce = m_path->at(m_pos); // current element
43
44 if (m_pos == m_path->size() - 1) {
45 --m_pos;
47 return ce;
48 }
49
50 const QStrokerOps::Element &pe = m_path->at(m_pos + 1); // previous element
51
52 switch (pe.type) {
55 break;
57 // First control point?
58 if (ce.type == QPainterPath::CurveToElement) {
60 } else { // Second control point then
62 }
63 break;
66 break;
67 default:
68 qWarning("QSubpathReverseIterator::next: Case %d unhandled", ce.type);
69 break;
70 }
71 --m_pos;
72
73 return ce;
74 }
75
76private:
77 const QDataBuffer<QStrokerOps::Element> *m_path;
78 int m_pos;
79};
80
82{
83public:
84 QSubpathFlatIterator(const QDataBuffer<QStrokerOps::Element> *path, qreal threshold)
85 : m_path(path), m_pos(0), m_curve_index(-1), m_curve_threshold(threshold) { }
86
87 inline bool hasNext() const { return m_curve_index >= 0 || m_pos < m_path->size(); }
88
90 {
92
93 if (m_curve_index >= 0) {
95 qt_real_to_fixed(m_curve.at(m_curve_index).x()),
96 qt_real_to_fixed(m_curve.at(m_curve_index).y())
97 };
98 ++m_curve_index;
99 if (m_curve_index >= m_curve.size())
100 m_curve_index = -1;
101 return e;
102 }
103
104 QStrokerOps::Element e = m_path->at(m_pos);
105 if (e.isCurveTo()) {
106 Q_ASSERT(m_pos > 0);
107 Q_ASSERT(m_pos < m_path->size());
108
109 m_curve = QBezier::fromPoints(QPointF(qt_fixed_to_real(m_path->at(m_pos-1).x),
110 qt_fixed_to_real(m_path->at(m_pos-1).y)),
113 QPointF(qt_fixed_to_real(m_path->at(m_pos+1).x),
114 qt_fixed_to_real(m_path->at(m_pos+1).y)),
115 QPointF(qt_fixed_to_real(m_path->at(m_pos+2).x),
116 qt_fixed_to_real(m_path->at(m_pos+2).y))).toPolygon(m_curve_threshold);
117 m_curve_index = 1;
119 e.x = m_curve.at(0).x();
120 e.y = m_curve.at(0).y();
121 m_pos += 2;
122 }
123 Q_ASSERT(e.isLineTo() || e.isMoveTo());
124 ++m_pos;
125 return e;
126 }
127
128private:
129 const QDataBuffer<QStrokerOps::Element> *m_path;
130 int m_pos;
131 QPolygonF m_curve;
132 int m_curve_index;
133 qreal m_curve_threshold;
134};
135
136template <class Iterator> bool qt_stroke_side(Iterator *it, QStroker *stroker,
137 bool capFirst, QLineF *startTangent);
138
139/*******************************************************************************
140 * QLineF::angleTo gives us the angle between two lines with respecting the direction.
141 * Here we want to identify the line's angle direction on the unit circle.
142 */
143static inline qreal adapted_angle_on_x(const QLineF &line)
144{
145 return QLineF(0, 0, 1, 0).angleTo(line);
146}
147
149 : m_elements(0)
150 , m_curveThreshold(qt_real_to_fixed(0.25))
151 , m_dashThreshold(qt_real_to_fixed(0.25))
152 , m_customData(nullptr)
153 , m_moveTo(nullptr)
154 , m_lineTo(nullptr)
155 , m_cubicTo(nullptr)
156{
157}
158
162
171void QStrokerOps::begin(void *customData)
172{
173 m_customData = customData;
174 m_elements.reset();
175}
176
177
183{
184 if (m_elements.size() > 1)
186 m_customData = nullptr;
187}
188
200void QStrokerOps::strokePath(const QPainterPath &path, void *customData, const QTransform &matrix)
201{
202 if (path.isEmpty())
203 return;
204
206 begin(customData);
207 int count = path.elementCount();
208 if (matrix.isIdentity()) {
209 for (int i=0; i<count; ++i) {
210 const QPainterPath::Element &e = path.elementAt(i);
211 switch (e.type) {
214 break;
217 break;
219 {
220 const QPainterPath::Element &cp2 = path.elementAt(++i);
221 const QPainterPath::Element &ep = path.elementAt(++i);
223 qt_real_to_fixed(cp2.x), qt_real_to_fixed(cp2.y),
225 }
226 break;
227 default:
228 break;
229 }
230 }
231 } else {
232 for (int i=0; i<count; ++i) {
233 const QPainterPath::Element &e = path.elementAt(i);
234 QPointF pt = QPointF(e.x, e.y) * matrix;
235 switch (e.type) {
238 break;
241 break;
243 {
244 QPointF cp2 = ((QPointF) path.elementAt(++i)) * matrix;
245 QPointF ep = ((QPointF) path.elementAt(++i)) * matrix;
247 qt_real_to_fixed(cp2.x()), qt_real_to_fixed(cp2.y()),
248 qt_real_to_fixed(ep.x()), qt_real_to_fixed(ep.y()));
249 }
250 break;
251 default:
252 break;
253 }
254 }
255 }
256 end();
257}
258
271void QStrokerOps::strokePolygon(const QPointF *points, int pointCount, bool implicit_close,
272 void *data, const QTransform &matrix)
273{
274 if (!pointCount)
275 return;
276
278 begin(data);
279 if (matrix.isIdentity()) {
281 for (int i=1; i<pointCount; ++i)
284 if (implicit_close)
286 } else {
287 QPointF start = points[0] * matrix;
289 for (int i=1; i<pointCount; ++i) {
290 QPointF pt = points[i] * matrix;
292 }
293 if (implicit_close)
295 }
296 end();
297}
298
305{
306 int count = 0;
307 QPointF pts[12];
308 QPointF start = qt_curves_for_arc(rect, 0, -360, pts, &count);
309 Q_ASSERT(count == 12); // a perfect circle..
310
311 if (!matrix.isIdentity()) {
312 start = start * matrix;
313 for (int i=0; i<12; ++i) {
314 pts[i] = pts[i] * matrix;
315 }
316 }
317
319 begin(data);
321 for (int i=0; i<12; i+=3) {
322 cubicTo(qt_real_to_fixed(pts[i].x()), qt_real_to_fixed(pts[i].y()),
323 qt_real_to_fixed(pts[i+1].x()), qt_real_to_fixed(pts[i+1].y()),
324 qt_real_to_fixed(pts[i+2].x()), qt_real_to_fixed(pts[i+2].y()));
325 }
326 end();
327}
328
329
331 : m_capStyle(SquareJoin), m_joinStyle(FlatJoin),
332 m_back1X(0), m_back1Y(0),
333 m_back2X(0), m_back2Y(0),
334 m_forceOpen(false)
335{
338}
339
343
345{
346 if (mode == FlatJoin) return Qt::FlatCap;
347 else if (mode == SquareJoin) return Qt::SquareCap;
348 else return Qt::RoundCap;
349}
350
352{
353 if (style == Qt::FlatCap) return FlatJoin;
354 else if (style == Qt::SquareCap) return SquareJoin;
355 else return RoundCap;
356}
357
359{
360 if (mode == FlatJoin) return Qt::BevelJoin;
361 else if (mode == MiterJoin) return Qt::MiterJoin;
362 else if (mode == SvgMiterJoin) return Qt::SvgMiterJoin;
363 else return Qt::RoundJoin;
364}
365
367{
368 if (joinStyle == Qt::BevelJoin) return FlatJoin;
369 else if (joinStyle == Qt::MiterJoin) return MiterJoin;
370 else if (joinStyle == Qt::SvgMiterJoin) return SvgMiterJoin;
371 else return RoundJoin;
372}
373
374
380{
381 Q_ASSERT(!m_elements.isEmpty());
383 Q_ASSERT(m_elements.size() > 1);
384
387
388 QLineF fwStartTangent, bwStartTangent;
389
390 bool fwclosed = qt_stroke_side(&fwit, this, false, &fwStartTangent);
391 bool bwclosed = qt_stroke_side(&bwit, this, !fwclosed, &bwStartTangent);
392
393 if (!bwclosed && !fwStartTangent.isNull())
394 joinPoints(m_elements.at(0).x, m_elements.at(0).y, fwStartTangent, m_capStyle);
395}
396
397
401void QStroker::joinPoints(qfixed focal_x, qfixed focal_y, const QLineF &nextLine, LineJoinMode join)
402{
403#ifdef QPP_STROKE_DEBUG
404 printf(" -----> joinPoints: around=(%.0f, %.0f), next_p1=(%.0f, %.f) next_p2=(%.0f, %.f)\n",
405 qt_fixed_to_real(focal_x),
406 qt_fixed_to_real(focal_y),
407 nextLine.x1(), nextLine.y1(), nextLine.x2(), nextLine.y2());
408#endif
409 // points connected already, don't join
410
411#if !defined (QFIXED_26_6) && !defined (Q_FIXED_32_32)
412 if (qFuzzyCompare(m_back1X, nextLine.x1()) && qFuzzyCompare(m_back1Y, nextLine.y1()))
413 return;
414#else
415 if (m_back1X == qt_real_to_fixed(nextLine.x1())
416 && m_back1Y == qt_real_to_fixed(nextLine.y1())) {
417 return;
418 }
419#endif
422 QPointF isect;
423 QLineF::IntersectionType type = prevLine.intersects(nextLine, &isect);
424
425 if (join == FlatJoin) {
426 QLineF shortCut(prevLine.p2(), nextLine.p1());
427 qreal angle = shortCut.angleTo(prevLine);
428 if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) {
429 emitLineTo(focal_x, focal_y);
430 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
431 return;
432 }
433 emitLineTo(qt_real_to_fixed(nextLine.x1()),
434 qt_real_to_fixed(nextLine.y1()));
435
436 } else {
437 if (join == MiterJoin) {
438 qreal appliedMiterLimit = qt_fixed_to_real(m_strokeWidth * m_miterLimit);
439
440 // If we are on the inside, do the short cut...
441 QLineF shortCut(prevLine.p2(), nextLine.p1());
442 qreal angle = shortCut.angleTo(prevLine);
443 if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) {
444 emitLineTo(focal_x, focal_y);
445 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
446 return;
447 }
449 qt_fixed_to_real(m_back1Y)), isect);
450 if (type == QLineF::NoIntersection || miterLine.length() > appliedMiterLimit) {
451 QLineF l1(prevLine);
452 l1.setLength(appliedMiterLimit);
453 l1.translate(prevLine.dx(), prevLine.dy());
454
455 QLineF l2(nextLine);
456 l2.setLength(appliedMiterLimit);
457 l2.translate(-l2.dx(), -l2.dy());
458
459 emitLineTo(qt_real_to_fixed(l1.x2()), qt_real_to_fixed(l1.y2()));
460 emitLineTo(qt_real_to_fixed(l2.x1()), qt_real_to_fixed(l2.y1()));
461 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
462 } else {
463 emitLineTo(qt_real_to_fixed(isect.x()), qt_real_to_fixed(isect.y()));
464 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
465 }
466
467 } else if (join == SquareJoin) {
469
470 QLineF l1(prevLine);
471 qreal dp = QPointF::dotProduct(QPointF(prevLine.dx(), prevLine.dy()), QPointF(nextLine.dx(), nextLine.dy()));
472 if (dp > 0) // same direction, means that prevLine is from a bezier that has been "reversed" by shifting
473 l1 = QLineF(prevLine.p2(), prevLine.p1());
474 else
475 l1.translate(l1.dx(), l1.dy());
476 l1.setLength(qt_fixed_to_real(offset));
477 QLineF l2(nextLine.p2(), nextLine.p1());
478 l2.translate(l2.dx(), l2.dy());
479 l2.setLength(qt_fixed_to_real(offset));
480 emitLineTo(qt_real_to_fixed(l1.x2()), qt_real_to_fixed(l1.y2()));
481 emitLineTo(qt_real_to_fixed(l2.x2()), qt_real_to_fixed(l2.y2()));
482 emitLineTo(qt_real_to_fixed(l2.x1()), qt_real_to_fixed(l2.y1()));
483
484 } else if (join == RoundJoin) {
486
487 QLineF shortCut(prevLine.p2(), nextLine.p1());
488 qreal angle = shortCut.angleTo(prevLine);
489 if ((type == QLineF::BoundedIntersection || (angle > qreal(90.01))) && nextLine.length() > offset) {
490 emitLineTo(focal_x, focal_y);
491 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
492 return;
493 }
494 qreal l1_on_x = adapted_angle_on_x(prevLine);
495 qreal l2_on_x = adapted_angle_on_x(nextLine);
496
497 qreal sweepLength = qAbs(l2_on_x - l1_on_x);
498
499 int point_count;
500 QPointF curves[15];
501
502 QPointF curve_start =
504 qt_fixed_to_real(focal_y - offset),
507 l1_on_x + 90, -sweepLength,
508 curves, &point_count);
509
510// // line to the beginning of the arc segment, (should not be needed).
511// emitLineTo(qt_real_to_fixed(curve_start.x()), qt_real_to_fixed(curve_start.y()));
512 Q_UNUSED(curve_start);
513
514 for (int i=0; i<point_count; i+=3) {
515 emitCubicTo(qt_real_to_fixed(curves[i].x()),
516 qt_real_to_fixed(curves[i].y()),
517 qt_real_to_fixed(curves[i+1].x()),
518 qt_real_to_fixed(curves[i+1].y()),
519 qt_real_to_fixed(curves[i+2].x()),
520 qt_real_to_fixed(curves[i+2].y()));
521 }
522
523 // line to the end of the arc segment, (should also not be needed).
524 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
525
526 // Same as round join except we know its 180 degrees. Can also optimize this
527 // later based on the addEllipse logic
528 } else if (join == RoundCap) {
530
531 // first control line
532 QLineF l1 = prevLine;
533 qreal dp = QPointF::dotProduct(QPointF(prevLine.dx(), prevLine.dy()), QPointF(nextLine.dx(), nextLine.dy()));
534 if (dp > 0) // same direction, means that prevLine is from a bezier that has been "reversed" by shifting
535 l1 = QLineF(prevLine.p2(), prevLine.p1());
536 else
537 l1.translate(l1.dx(), l1.dy());
538 l1.setLength(QT_PATH_KAPPA * offset);
539
540 // second control line, find through normal between prevLine and focal.
541 QLineF l2(qt_fixed_to_real(focal_x), qt_fixed_to_real(focal_y),
542 prevLine.x2(), prevLine.y2());
543 l2.translate(-l2.dy(), l2.dx());
544 l2.setLength(QT_PATH_KAPPA * offset);
545
547 qt_real_to_fixed(l1.y2()),
548 qt_real_to_fixed(l2.x2()),
549 qt_real_to_fixed(l2.y2()),
550 qt_real_to_fixed(l2.x1()),
551 qt_real_to_fixed(l2.y1()));
552
553 // move so that it matches
554 l2 = QLineF(l2.x1(), l2.y1(), l2.x1()-l2.dx(), l2.y1()-l2.dy());
555
556 // last line is parallel to l1 so just shift it down.
557 l1.translate(nextLine.x1() - l1.x1(), nextLine.y1() - l1.y1());
558
560 qt_real_to_fixed(l2.y2()),
561 qt_real_to_fixed(l1.x2()),
562 qt_real_to_fixed(l1.y2()),
563 qt_real_to_fixed(l1.x1()),
564 qt_real_to_fixed(l1.y1()));
565 } else if (join == SvgMiterJoin) {
566 QLineF shortCut(prevLine.p2(), nextLine.p1());
567 qreal angle = shortCut.angleTo(prevLine);
568 if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) {
569 emitLineTo(focal_x, focal_y);
570 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
571 return;
572 }
573 QLineF miterLine(QPointF(qt_fixed_to_real(focal_x),
574 qt_fixed_to_real(focal_y)), isect);
575 if (type == QLineF::NoIntersection || miterLine.length() > qt_fixed_to_real(m_strokeWidth * m_miterLimit) / 2) {
576 emitLineTo(qt_real_to_fixed(nextLine.x1()),
577 qt_real_to_fixed(nextLine.y1()));
578 } else {
579 emitLineTo(qt_real_to_fixed(isect.x()), qt_real_to_fixed(isect.y()));
580 emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
581 }
582 } else {
583 Q_ASSERT(!"QStroker::joinPoints(), bad join style...");
584 }
585 }
586}
587
588
589/*
590 Strokes a subpath side using the \a it as source. Results are put into
591 \a stroke. The function returns \c true if the subpath side was closed.
592 If \a capFirst is true, we will use capPoints instead of joinPoints to
593 connect the first segment, other segments will be joined using joinPoints.
594 This is to put capping in order...
595*/
596template <class Iterator> bool qt_stroke_side(Iterator *it,
597 QStroker *stroker,
598 bool capFirst,
599 QLineF *startTangent)
600{
601 // Used in CurveToElement section below.
602 const int MAX_OFFSET = 16;
603 QBezier offsetCurves[MAX_OFFSET];
604
605 Q_ASSERT(it->hasNext()); // The initaial move to
606 QStrokerOps::Element first_element = it->next();
607 Q_ASSERT(first_element.isMoveTo());
608
609 qfixed2d start = first_element;
610
611#ifdef QPP_STROKE_DEBUG
612 qDebug(" -> (side) [%.2f, %.2f], startPos=%d",
615#endif
616
617 qfixed2d prev = start;
618
619 bool first = true;
620
621 qfixed offset = stroker->strokeWidth() / 2;
622
623 while (it->hasNext()) {
624 QStrokerOps::Element e = it->next();
625
626 // LineToElement
627 if (e.isLineTo()) {
628#ifdef QPP_STROKE_DEBUG
629 qDebug("\n ---> (side) lineto [%.2f, %.2f]", e.x, e.y);
630#endif
633 if (line.p1() != line.p2()) {
634 QLineF normal = line.normalVector();
635 normal.setLength(offset);
636 line.translate(normal.dx(), normal.dy());
637
638 // If we are starting a new subpath, move to correct starting point.
639 if (first) {
640 if (capFirst)
641 stroker->joinPoints(prev.x, prev.y, line, stroker->capStyleMode());
642 else
644 *startTangent = line;
645 first = false;
646 } else {
647 stroker->joinPoints(prev.x, prev.y, line, stroker->joinStyleMode());
648 }
649
650 // Add the stroke for this line.
651 stroker->emitLineTo(qt_real_to_fixed(line.x2()),
652 qt_real_to_fixed(line.y2()));
653 prev = e;
654 }
655
656 // CurveToElement
657 } else if (e.isCurveTo()) {
658 QStrokerOps::Element cp2 = it->next(); // control point 2
659 QStrokerOps::Element ep = it->next(); // end point
660
661#ifdef QPP_STROKE_DEBUG
662 qDebug("\n ---> (side) cubicTo [%.2f, %.2f]",
664 qt_fixed_to_real(ep.y));
665#endif
666
667 QBezier bezier =
672 int count = bezier.shifted(offsetCurves,
673 MAX_OFFSET,
674 offset,
675 stroker->curveThreshold());
676
677 if (count) {
678 // If we are starting a new subpath, move to correct starting point
679 QLineF tangent = bezier.startTangent();
680 tangent.translate(offsetCurves[0].pt1() - bezier.pt1());
681 if (first) {
682 QPointF pt = offsetCurves[0].pt1();
683 if (capFirst) {
684 stroker->joinPoints(prev.x, prev.y,
685 tangent,
686 stroker->capStyleMode());
687 } else {
688 stroker->emitMoveTo(qt_real_to_fixed(pt.x()),
689 qt_real_to_fixed(pt.y()));
690 }
691 *startTangent = tangent;
692 first = false;
693 } else {
694 stroker->joinPoints(prev.x, prev.y,
695 tangent,
696 stroker->joinStyleMode());
697 }
698
699 // Add these beziers
700 for (int i=0; i<count; ++i) {
701 QPointF cp1 = offsetCurves[i].pt2();
702 QPointF cp2 = offsetCurves[i].pt3();
703 QPointF ep = offsetCurves[i].pt4();
704 stroker->emitCubicTo(qt_real_to_fixed(cp1.x()), qt_real_to_fixed(cp1.y()),
705 qt_real_to_fixed(cp2.x()), qt_real_to_fixed(cp2.y()),
706 qt_real_to_fixed(ep.x()), qt_real_to_fixed(ep.y()));
707 }
708 }
709
710 prev = ep;
711 }
712 }
713
714 if (start == prev && !stroker->forceOpen()) {
715 // closed subpath, join first and last point
716#ifdef QPP_STROKE_DEBUG
717 qDebug("\n ---> (side) closed subpath");
718#endif
719 // don't join empty subpaths
720 if (!first)
721 stroker->joinPoints(prev.x, prev.y, *startTangent, stroker->joinStyleMode());
722 return true;
723 } else {
724#ifdef QPP_STROKE_DEBUG
725 qDebug("\n ---> (side) open subpath");
726#endif
727 return false;
728 }
729}
730
757{
758 if (qFuzzyIsNull(angle))
759 return 0;
760
761 if (qFuzzyCompare(angle, qreal(90)))
762 return 1;
763
764 qreal radians = qDegreesToRadians(angle);
765 qreal cosAngle = qCos(radians);
766 qreal sinAngle = qSin(radians);
767
768 // initial guess
769 qreal tc = angle / 90;
770 // do some iterations of newton's method to approximate cosAngle
771 // finds the zero of the function b.pointAt(tc).x() - cosAngle
772 tc -= ((((2-3*QT_PATH_KAPPA) * tc + 3*(QT_PATH_KAPPA-1)) * tc) * tc + 1 - cosAngle) // value
773 / (((6-9*QT_PATH_KAPPA) * tc + 6*(QT_PATH_KAPPA-1)) * tc); // derivative
774 tc -= ((((2-3*QT_PATH_KAPPA) * tc + 3*(QT_PATH_KAPPA-1)) * tc) * tc + 1 - cosAngle) // value
775 / (((6-9*QT_PATH_KAPPA) * tc + 6*(QT_PATH_KAPPA-1)) * tc); // derivative
776
777 // initial guess
778 qreal ts = tc;
779 // do some iterations of newton's method to approximate sinAngle
780 // finds the zero of the function b.pointAt(tc).y() - sinAngle
781 ts -= ((((3*QT_PATH_KAPPA-2) * ts - 6*QT_PATH_KAPPA + 3) * ts + 3*QT_PATH_KAPPA) * ts - sinAngle)
782 / (((9*QT_PATH_KAPPA-6) * ts + 12*QT_PATH_KAPPA - 6) * ts + 3*QT_PATH_KAPPA);
783 ts -= ((((3*QT_PATH_KAPPA-2) * ts - 6*QT_PATH_KAPPA + 3) * ts + 3*QT_PATH_KAPPA) * ts - sinAngle)
784 / (((9*QT_PATH_KAPPA-6) * ts + 12*QT_PATH_KAPPA - 6) * ts + 3*QT_PATH_KAPPA);
785
786 // use the average of the t that best approximates cosAngle
787 // and the t that best approximates sinAngle
788 qreal t = 0.5 * (tc + ts);
789
790#if 0
791 printf("angle: %f, t: %f\n", angle, t);
792 qreal a, b, c, d;
793 bezierCoefficients(t, a, b, c, d);
794 printf("cosAngle: %.10f, value: %.10f\n", cosAngle, a + b + c * QT_PATH_KAPPA);
795 printf("sinAngle: %.10f, value: %.10f\n", sinAngle, b * QT_PATH_KAPPA + c + d);
796#endif
797
798 return t;
799}
800
801Q_GUI_EXPORT void qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length,
802 QPointF* startPoint, QPointF *endPoint);
803
816QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength,
817 QPointF *curves, int *point_count)
818{
819 Q_ASSERT(point_count);
820 Q_ASSERT(curves);
821
822 *point_count = 0;
823 if (qt_is_nan(rect.x()) || qt_is_nan(rect.y()) || qt_is_nan(rect.width()) || qt_is_nan(rect.height())
824 || qt_is_nan(startAngle) || qt_is_nan(sweepLength)) {
825 qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN, results are undefined");
826 return QPointF();
827 }
828
829 if (rect.isNull()) {
830 return QPointF();
831 }
832
833 qreal x = rect.x();
834 qreal y = rect.y();
835
836 qreal w = rect.width();
837 qreal w2 = rect.width() / 2;
838 qreal w2k = w2 * QT_PATH_KAPPA;
839
840 qreal h = rect.height();
841 qreal h2 = rect.height() / 2;
842 qreal h2k = h2 * QT_PATH_KAPPA;
843
844 QPointF points[16] =
845 {
846 // start point
847 QPointF(x + w, y + h2),
848
849 // 0 -> 270 degrees
850 QPointF(x + w, y + h2 + h2k),
851 QPointF(x + w2 + w2k, y + h),
852 QPointF(x + w2, y + h),
853
854 // 270 -> 180 degrees
855 QPointF(x + w2 - w2k, y + h),
856 QPointF(x, y + h2 + h2k),
857 QPointF(x, y + h2),
858
859 // 180 -> 90 degrees
860 QPointF(x, y + h2 - h2k),
861 QPointF(x + w2 - w2k, y),
862 QPointF(x + w2, y),
863
864 // 90 -> 0 degrees
865 QPointF(x + w2 + w2k, y),
866 QPointF(x + w, y + h2 - h2k),
867 QPointF(x + w, y + h2)
868 };
869
870 if (sweepLength > 360) sweepLength = 360;
871 else if (sweepLength < -360) sweepLength = -360;
872
873 // Special case fast paths
874 if (startAngle == 0.0) {
875 if (sweepLength == 360.0) {
876 for (int i = 11; i >= 0; --i)
877 curves[(*point_count)++] = points[i];
878 return points[12];
879 } else if (sweepLength == -360.0) {
880 for (int i = 1; i <= 12; ++i)
881 curves[(*point_count)++] = points[i];
882 return points[0];
883 }
884 }
885
886 int startSegment = int(qFloor(startAngle / 90));
887 int endSegment = int(qFloor((startAngle + sweepLength) / 90));
888
889 qreal startT = (startAngle - startSegment * 90) / 90;
890 qreal endT = (startAngle + sweepLength - endSegment * 90) / 90;
891
892 int delta = sweepLength > 0 ? 1 : -1;
893 if (delta < 0) {
894 startT = 1 - startT;
895 endT = 1 - endT;
896 }
897
898 // avoid empty start segment
899 if (qFuzzyIsNull(startT - qreal(1))) {
900 startT = 0;
901 startSegment += delta;
902 }
903
904 // avoid empty end segment
905 if (qFuzzyIsNull(endT)) {
906 endT = 1;
907 endSegment -= delta;
908 }
909
910 startT = qt_t_for_arc_angle(startT * 90);
911 endT = qt_t_for_arc_angle(endT * 90);
912
913 const bool splitAtStart = !qFuzzyIsNull(startT);
914 const bool splitAtEnd = !qFuzzyIsNull(endT - qreal(1));
915
916 const int end = endSegment + delta;
917
918 // empty arc?
919 if (startSegment == end) {
920 const int quadrant = 3 - ((startSegment % 4) + 4) % 4;
921 const int j = 3 * quadrant;
922 return delta > 0 ? points[j + 3] : points[j];
923 }
924
925 QPointF startPoint, endPoint;
926 qt_find_ellipse_coords(rect, startAngle, sweepLength, &startPoint, &endPoint);
927
928 for (int i = startSegment; i != end; i += delta) {
929 const int quadrant = 3 - ((i % 4) + 4) % 4;
930 const int j = 3 * quadrant;
931
932 QBezier b;
933 if (delta > 0)
934 b = QBezier::fromPoints(points[j + 3], points[j + 2], points[j + 1], points[j]);
935 else
936 b = QBezier::fromPoints(points[j], points[j + 1], points[j + 2], points[j + 3]);
937
938 // empty arc?
939 if (startSegment == endSegment && qFuzzyCompare(startT, endT))
940 return startPoint;
941
942 if (i == startSegment) {
943 if (i == endSegment && splitAtEnd)
944 b = b.bezierOnInterval(startT, endT);
945 else if (splitAtStart)
946 b = b.bezierOnInterval(startT, 1);
947 } else if (i == endSegment && splitAtEnd) {
948 b = b.bezierOnInterval(0, endT);
949 }
950
951 // push control points
952 curves[(*point_count)++] = b.pt2();
953 curves[(*point_count)++] = b.pt3();
954 curves[(*point_count)++] = b.pt4();
955 }
956
957 Q_ASSERT(*point_count > 0);
958 curves[*(point_count)-1] = endPoint;
959
960 return startPoint;
961}
962
963
964static inline void qdashstroker_moveTo(qfixed x, qfixed y, void *data) {
965 ((QStroker *) data)->moveTo(x, y);
966}
967
968static inline void qdashstroker_lineTo(qfixed x, qfixed y, void *data) {
969 ((QStroker *) data)->lineTo(x, y);
970}
971
972static inline void qdashstroker_cubicTo(qfixed, qfixed, qfixed, qfixed, qfixed, qfixed, void *) {
973 Q_ASSERT(0);
974// ((QStroker *) data)->cubicTo(c1x, c1y, c2x, c2y, ex, ey);
975}
976
977
978/*******************************************************************************
979 * QDashStroker members
980 */
982 : m_stroker(stroker), m_dashOffset(0), m_stroke_width(1), m_miter_limit(1)
983{
984 if (m_stroker) {
988 }
989}
990
994
996{
997 const qfixed space = 2;
998 const qfixed dot = 1;
999 const qfixed dash = 4;
1000
1001 QList<qfixed> pattern;
1002
1003 switch (style) {
1004 case Qt::DashLine:
1005 pattern << dash << space;
1006 break;
1007 case Qt::DotLine:
1008 pattern << dot << space;
1009 break;
1010 case Qt::DashDotLine:
1011 pattern << dash << space << dot << space;
1012 break;
1013 case Qt::DashDotDotLine:
1014 pattern << dash << space << dot << space << dot << space;
1015 break;
1016 default:
1017 break;
1018 }
1019
1020 return pattern;
1021}
1022
1023static inline bool lineRectIntersectsRect(qfixed2d p1, qfixed2d p2, const qfixed2d &tl, const qfixed2d &br)
1024{
1025 return ((p1.x > tl.x || p2.x > tl.x) && (p1.x < br.x || p2.x < br.x)
1026 && (p1.y > tl.y || p2.y > tl.y) && (p1.y < br.y || p2.y < br.y));
1027}
1028
1029// If the line intersects the rectangle, this function will return true.
1030static bool lineIntersectsRect(qfixed2d p1, qfixed2d p2, const qfixed2d &tl, const qfixed2d &br)
1031{
1032 if (!lineRectIntersectsRect(p1, p2, tl, br))
1033 return false;
1034 if (p1.x == p2.x || p1.y == p2.y)
1035 return true;
1036
1037 if (p1.y > p2.y)
1038 qSwap(p1, p2); // make p1 above p2
1039 qfixed2d u;
1040 qfixed2d v;
1041 qfixed2d w = {p2.x - p1.x, p2.y - p1.y};
1042 if (p1.x < p2.x) {
1043 // backslash
1044 u.x = tl.x - p1.x; u.y = br.y - p1.y;
1045 v.x = br.x - p1.x; v.y = tl.y - p1.y;
1046 } else {
1047 // slash
1048 u.x = tl.x - p1.x; u.y = tl.y - p1.y;
1049 v.x = br.x - p1.x; v.y = br.y - p1.y;
1050 }
1051#if defined(QFIXED_IS_26_6) || defined(QFIXED_IS_16_16)
1052 qint64 val1 = qint64(u.x) * qint64(w.y) - qint64(u.y) * qint64(w.x);
1053 qint64 val2 = qint64(v.x) * qint64(w.y) - qint64(v.y) * qint64(w.x);
1054 return (val1 < 0 && val2 > 0) || (val1 > 0 && val2 < 0);
1055#elif defined(QFIXED_IS_32_32)
1056 // Cannot do proper test because it may overflow.
1057 return true;
1058#else
1059 qreal val1 = u.x * w.y - u.y * w.x;
1060 qreal val2 = v.x * w.y - v.y * w.x;
1061 return (val1 < 0 && val2 > 0) || (val1 > 0 && val2 < 0);
1062#endif
1063}
1064
1066{
1067 int dashCount = qMin(m_dashPattern.size(), 32);
1068 qfixed dashes[32];
1069
1070 if (m_stroker) {
1074 }
1075
1076 qreal longestLength = 0;
1077 qreal sumLength = 0;
1078 for (int i=0; i<dashCount; ++i) {
1079 dashes[i] = qMax(m_dashPattern.at(i), qreal(0)) * m_stroke_width;
1080 sumLength += dashes[i];
1081 if (dashes[i] > longestLength)
1082 longestLength = dashes[i];
1083 }
1084
1085 if (qFuzzyIsNull(sumLength))
1086 return;
1087
1088 qreal invSumLength = qreal(1) / sumLength;
1089
1090 Q_ASSERT(dashCount > 0);
1091
1092 dashCount = dashCount & -2; // Round down to even number
1093
1094 int idash = 0; // Index to current dash
1095 qreal pos = 0; // The position on the curve, 0 <= pos <= path.length
1096 qreal elen = 0; // element length
1097 qreal doffset = m_dashOffset * m_stroke_width;
1098
1099 // make sure doffset is in range [0..sumLength)
1100 doffset = std::fmod(doffset, sumLength);
1101 if (doffset < 0)
1102 doffset += sumLength;
1103
1104 while (doffset >= dashes[idash]) {
1105 doffset -= dashes[idash];
1106 if (++idash >= dashCount)
1107 idash = 0;
1108 }
1109
1110 qreal estart = 0; // The elements starting position
1111 qreal estop = 0; // The element stop position
1112
1113 QLineF cline;
1114
1116 qfixed2d prev = it.next();
1117 if (!prev.isFinite())
1118 return;
1119
1120 bool clipping = !m_clip_rect.isEmpty();
1121 qfixed2d move_to_pos = prev;
1122 qfixed2d line_to_pos;
1123
1124 // Pad to avoid clipping the borders of thick pens.
1125 qfixed padding = qt_real_to_fixed(qMax(m_stroke_width, m_miter_limit) * longestLength);
1126 qfixed2d clip_tl = { qt_real_to_fixed(m_clip_rect.left()) - padding,
1127 qt_real_to_fixed(m_clip_rect.top()) - padding };
1128 qfixed2d clip_br = { qt_real_to_fixed(m_clip_rect.right()) + padding ,
1129 qt_real_to_fixed(m_clip_rect.bottom()) + padding };
1130
1131 bool hasMoveTo = false;
1132 while (it.hasNext()) {
1133 QStrokerOps::Element e = it.next();
1134 if (!qfixed2d(e).isFinite())
1135 continue;
1136
1137 Q_ASSERT(e.isLineTo());
1138 cline = QLineF(qt_fixed_to_real(prev.x),
1139 qt_fixed_to_real(prev.y),
1141 qt_fixed_to_real(e.y));
1142 elen = cline.length();
1143
1144 estop = estart + elen;
1145
1146 bool done = pos >= estop;
1147
1148 // Check if the entire line should be clipped away or simplified
1149 bool clipIt = clipping && !lineIntersectsRect(prev, e, clip_tl, clip_br);
1150 bool skipDashing = elen * invSumLength > repetitionLimit();
1151 int maxDashes = dashCount;
1152 if (skipDashing || clipIt) {
1153 // Cut away full dash sequences.
1154 elen -= std::floor(elen * invSumLength) * sumLength;
1155 // Update dash offset.
1156 while (!done) {
1157 qreal dpos = pos + dashes[idash] - doffset - estart;
1158
1159 Q_ASSERT(dpos >= 0);
1160
1161 if (dpos > elen) { // dash extends this line
1162 doffset = dashes[idash] - (dpos - elen); // subtract the part already used
1163 pos = estop; // move pos to next path element
1164 done = true;
1165 } else { // Dash is on this line
1166 pos = --maxDashes > 0 ? dpos + estart : estop;
1167 done = pos >= estop;
1168 if (++idash >= dashCount)
1169 idash = 0;
1170 doffset = 0; // full segment so no offset on next.
1171 }
1172 }
1173 if (clipIt) {
1174 hasMoveTo = false;
1175 } else {
1176 // skip costly dashing, just draw solid line
1177 if (!hasMoveTo) {
1178 emitMoveTo(move_to_pos.x, move_to_pos.y);
1179 hasMoveTo = true;
1180 }
1181 emitLineTo(e.x, e.y);
1182 }
1183 move_to_pos = e;
1184 }
1185
1186 // Dash away...
1187 while (!done) {
1188 QPointF p2;
1189
1190 bool has_offset = doffset > 0;
1191 bool evenDash = (idash & 1) == 0;
1192 qreal dpos = pos + dashes[idash] - doffset - estart;
1193
1194 Q_ASSERT(dpos >= 0);
1195
1196 if (dpos > elen) { // dash extends this line
1197 doffset = dashes[idash] - (dpos - elen); // subtract the part already used
1198 pos = estop; // move pos to next path element
1199 done = true;
1200 p2 = cline.p2();
1201 } else { // Dash is on this line
1202 p2 = cline.pointAt(dpos/elen);
1203 pos = dpos + estart;
1204 done = pos >= estop;
1205 if (++idash >= dashCount)
1206 idash = 0;
1207 doffset = 0; // full segment so no offset on next.
1208 }
1209
1210 if (evenDash) {
1211 line_to_pos.x = qt_real_to_fixed(p2.x());
1212 line_to_pos.y = qt_real_to_fixed(p2.y());
1213
1214 if (!clipping
1215 || lineRectIntersectsRect(move_to_pos, line_to_pos, clip_tl, clip_br))
1216 {
1217 // If we have an offset, we're continuing a dash
1218 // from a previous element and should only
1219 // continue the current dash, without starting a
1220 // new subpath.
1221 if (!has_offset || !hasMoveTo) {
1222 emitMoveTo(move_to_pos.x, move_to_pos.y);
1223 hasMoveTo = true;
1224 }
1225
1226 emitLineTo(line_to_pos.x, line_to_pos.y);
1227 } else {
1228 hasMoveTo = false;
1229 }
1230 move_to_pos = line_to_pos;
1231 } else {
1232 move_to_pos.x = qt_real_to_fixed(p2.x());
1233 move_to_pos.y = qt_real_to_fixed(p2.y());
1234 }
1235 }
1236
1237 // Shuffle to the next cycle...
1238 estart = estop;
1239 prev = e;
1240 }
1241
1242}
1243
QPointF pt1() const
Definition qbezier_p.h:58
static QBezier fromPoints(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4)
Definition qbezier_p.h:33
QLineF startTangent() const
Definition qbezier_p.h:96
int shifted(QBezier *curveSegments, int maxSegmets, qreal offset, float threshold) const
Definition qbezier.cpp:355
qreal m_miter_limit
Definition qstroker_p.h:257
void processCurrentSubpath() override
QStroker * m_stroker
Definition qstroker_p.h:252
QDashStroker(QStroker *stroker)
Definition qstroker.cpp:981
QList< qfixed > m_dashPattern
Definition qstroker_p.h:253
static int repetitionLimit()
Definition qstroker_p.h:235
static QList< qfixed > patternForStyle(Qt::PenStyle style)
Definition qstroker.cpp:995
qreal m_dashOffset
Definition qstroker_p.h:254
qreal m_stroke_width
Definition qstroker_p.h:256
Type & at(qsizetype i)
qsizetype size() const
\inmodule QtCore\compares equality \compareswith equality QLine \endcompareswith
Definition qline.h:192
void translate(const QPointF &p)
Translates this line by the given offset.
Definition qline.h:342
constexpr qreal dx() const
Returns the horizontal component of the line's vector.
Definition qline.h:327
constexpr qreal dy() const
Returns the vertical component of the line's vector.
Definition qline.h:332
qreal angleTo(const QLineF &l) const
Definition qline.cpp:773
IntersectionType
\typealias QLineF::IntersectType
Definition qline.h:195
@ NoIntersection
Definition qline.h:195
@ BoundedIntersection
Definition qline.h:195
void setLength(qreal len)
Sets the length of the line to the given finite length.
Definition qline.h:368
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
\inmodule QtGui
\inmodule QtGui
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
static constexpr qreal dotProduct(const QPointF &p1, const QPointF &p2)
Definition qpoint.h:242
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
The QPolygonF class provides a list of points using floating point precision.
Definition qpolygon.h:96
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
Definition qrect.h:661
constexpr qreal bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
Definition qrect.h:500
constexpr qreal left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:497
constexpr qreal top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:498
constexpr qreal right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
Definition qrect.h:499
virtual void begin(void *customData)
Prepares the stroker.
Definition qstroker.cpp:171
void setCubicToHook(qStrokerCubicToHook cubicToHook)
Definition qstroker_p.h:114
void moveTo(qfixed x, qfixed y)
Definition qstroker_p.h:283
void setMoveToHook(qStrokerMoveToHook moveToHook)
Definition qstroker_p.h:112
void setCurveThresholdFromTransform(const QTransform &transform)
Definition qstroker_p.h:131
void strokeEllipse(const QRectF &ellipse, void *data, const QTransform &matrix)
Convenience function for stroking an ellipse with bounding rect rect.
Definition qstroker.cpp:304
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
QDataBuffer< Element > m_elements
Definition qstroker_p.h:147
void cubicTo(qfixed x1, qfixed y1, qfixed x2, qfixed y2, qfixed ex, qfixed ey)
Definition qstroker_p.h:298
void strokePolygon(const QPointF *points, int pointCount, bool implicit_close, void *data, const QTransform &matrix)
Convenience function for stroking a polygon of the pointCount first points in points.
Definition qstroker.cpp:271
void emitLineTo(qfixed x, qfixed y)
Definition qstroker_p.h:271
virtual void end()
Finishes the stroke.
Definition qstroker.cpp:182
virtual ~QStrokerOps()
Definition qstroker.cpp:159
qfixed m_dashThreshold
Definition qstroker_p.h:151
void * m_customData
Definition qstroker_p.h:153
void emitMoveTo(qfixed x, qfixed y)
Definition qstroker_p.h:265
qfixed curveThreshold() const
Definition qstroker_p.h:139
void lineTo(qfixed x, qfixed y)
Definition qstroker_p.h:292
QRectF m_clip_rect
Definition qstroker_p.h:149
virtual void processCurrentSubpath()=0
qfixed m_back1Y
Definition qstroker_p.h:218
qfixed strokeWidth() const
Definition qstroker_p.h:181
void emitLineTo(qfixed x, qfixed y)
Definition qstroker_p.h:320
static Qt::PenJoinStyle joinForJoinMode(LineJoinMode mode)
Definition qstroker.cpp:358
qfixed m_back2Y
Definition qstroker_p.h:221
void processCurrentSubpath() override
This function is called to stroke the currently built up subpath.
Definition qstroker.cpp:379
static LineJoinMode joinModeForJoin(Qt::PenJoinStyle joinStyle)
Definition qstroker.cpp:366
LineJoinMode capStyleMode() const
Definition qstroker_p.h:185
qfixed miterLimit() const
Definition qstroker_p.h:192
LineJoinMode m_capStyle
Definition qstroker_p.h:214
void joinPoints(qfixed x, qfixed y, const QLineF &nextLine, LineJoinMode join)
Definition qstroker.cpp:401
Qt::PenJoinStyle joinStyle() const
Definition qstroker_p.h:188
void emitMoveTo(qfixed x, qfixed y)
Definition qstroker_p.h:311
qfixed m_back1X
Definition qstroker_p.h:217
qfixed m_strokeWidth
Definition qstroker_p.h:211
qfixed m_miterLimit
Definition qstroker_p.h:212
LineJoinMode joinStyleMode() const
Definition qstroker_p.h:189
static LineJoinMode joinModeForCap(Qt::PenCapStyle)
Definition qstroker.cpp:351
bool forceOpen() const
Definition qstroker_p.h:195
qfixed m_back2X
Definition qstroker_p.h:220
static Qt::PenCapStyle capForJoinMode(LineJoinMode mode)
Definition qstroker.cpp:344
void emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey)
Definition qstroker_p.h:329
QStrokerOps::Element next()
Definition qstroker.cpp:38
QSubpathBackwardIterator(const QDataBuffer< QStrokerOps::Element > *path)
Definition qstroker.cpp:31
QSubpathFlatIterator(const QDataBuffer< QStrokerOps::Element > *path, qreal threshold)
Definition qstroker.cpp:84
QStrokerOps::Element next()
Definition qstroker.cpp:89
bool hasNext() const
Definition qstroker.cpp:87
QStrokerOps::Element next()
Definition qstroker.cpp:21
QSubpathForwardIterator(const QDataBuffer< QStrokerOps::Element > *path)
Definition qstroker.cpp:17
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
QPixmap p2
QPixmap p1
[0]
QSet< QString >::iterator it
rect
[4]
Combined button and popup list for selecting options.
@ DashDotDotLine
@ DotLine
@ DashDotLine
@ DashLine
PenJoinStyle
@ SvgMiterJoin
@ BevelJoin
@ MiterJoin
@ RoundJoin
PenCapStyle
@ SquareCap
@ RoundCap
@ FlatCap
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
int qFloor(T v)
Definition qmath.h:42
auto qCos(T v)
Definition qmath.h:60
auto qSin(T v)
Definition qmath.h:54
constexpr float qDegreesToRadians(float degrees)
Definition qmath.h:260
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
static Q_DECL_CONST_FUNCTION bool qt_is_nan(double d)
Definition qnumeric_p.h:112
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLenum mode
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLfloat angle
GLuint start
GLenum GLuint GLintptr offset
GLint first
GLsizei dashCount
GLint y
GLsizei startSegment
GLfloat GLfloat GLfloat GLfloat h
GLfixed GLfixed GLint GLint GLfixed points
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble GLdouble w2
const GLubyte * c
const GLfloat * tc
GLuint GLenum matrix
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLubyte * pattern
static qreal dot(const QPointF &a, const QPointF &b)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static void qdashstroker_moveTo(qfixed x, qfixed y, void *data)
Definition qstroker.cpp:964
Q_GUI_EXPORT void qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length, QPointF *startPoint, QPointF *endPoint)
qreal qt_t_for_arc_angle(qreal angle)
Definition qstroker.cpp:756
static void qdashstroker_cubicTo(qfixed, qfixed, qfixed, qfixed, qfixed, qfixed, void *)
Definition qstroker.cpp:972
static bool lineIntersectsRect(qfixed2d p1, qfixed2d p2, const qfixed2d &tl, const qfixed2d &br)
static qreal adapted_angle_on_x(const QLineF &line)
Definition qstroker.cpp:143
bool qt_stroke_side(Iterator *it, QStroker *stroker, bool capFirst, QLineF *startTangent)
Definition qstroker.cpp:596
QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength, QPointF *curves, int *point_count)
Definition qstroker.cpp:816
static void qdashstroker_lineTo(qfixed x, qfixed y, void *data)
Definition qstroker.cpp:968
static bool lineRectIntersectsRect(qfixed2d p1, qfixed2d p2, const qfixed2d &tl, const qfixed2d &br)
QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength, QPointF *controlPoints, 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
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
Definition qswap.h:20
#define Q_UNUSED(x)
long long qint64
Definition qtypes.h:60
double qreal
Definition qtypes.h:187
QObject::connect nullptr
bool isMoveTo() const
Definition qstroker_p.h:102
bool isLineTo() const
Definition qstroker_p.h:103
QPainterPath::ElementType type
Definition qstroker_p.h:98
bool isCurveTo() const
Definition qstroker_p.h:104
qfixed x
Definition qstroker_p.h:68
bool isFinite()
Definition qstroker_p.h:71
qfixed y
Definition qstroker_p.h:69