Qt 4.8
qstroker.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "private/qstroker_p.h"
43 #include "private/qbezier_p.h"
44 #include "private/qmath_p.h"
45 #include "qline.h"
46 #include "qtransform.h"
47 #include <qmath.h>
48 
50 
51 // #define QPP_STROKE_DEBUG
52 
54 {
55 public:
57  : m_path(path), m_pos(0) { }
58  inline int position() const { return m_pos; }
59  inline bool hasNext() const { return m_pos < m_path->size(); }
60  inline QStrokerOps::Element next() { Q_ASSERT(hasNext()); return m_path->at(m_pos++); }
61 
62 private:
64  int m_pos;
65 };
66 
68 {
69 public:
71  : m_path(path), m_pos(path->size() - 1) { }
72 
73  inline int position() const { return m_pos; }
74 
75  inline bool hasNext() const { return m_pos >= 0; }
76 
78  {
79  Q_ASSERT(hasNext());
80 
81  QStrokerOps::Element ce = m_path->at(m_pos); // current element
82 
83  if (m_pos == m_path->size() - 1) {
84  --m_pos;
86  return ce;
87  }
88 
89  const QStrokerOps::Element &pe = m_path->at(m_pos + 1); // previous element
90 
91  switch (pe.type) {
94  break;
96  // First control point?
99  } else { // Second control point then
101  }
102  break;
105  break;
106  default:
107  qWarning("QSubpathReverseIterator::next: Case %d unhandled", ce.type);
108  break;
109  }
110  --m_pos;
111 
112  return ce;
113  }
114 
115 private:
117  int m_pos;
118 };
119 
121 {
122 public:
124  : m_path(path), m_pos(0), m_curve_index(-1), m_curve_threshold(threshold) { }
125 
126  inline bool hasNext() const { return m_curve_index >= 0 || m_pos < m_path->size(); }
127 
129  {
130  Q_ASSERT(hasNext());
131 
132  if (m_curve_index >= 0) {
134  qt_real_to_fixed(m_curve.at(m_curve_index).x()),
135  qt_real_to_fixed(m_curve.at(m_curve_index).y())
136  };
137  ++m_curve_index;
138  if (m_curve_index >= m_curve.size())
139  m_curve_index = -1;
140  return e;
141  }
142 
144  if (e.isCurveTo()) {
145  Q_ASSERT(m_pos > 0);
146  Q_ASSERT(m_pos < m_path->size());
147 
151  qt_fixed_to_real(e.y)),
155  qt_fixed_to_real(m_path->at(m_pos+2).y))).toPolygon(m_curve_threshold);
156  m_curve_index = 1;
158  e.x = m_curve.at(0).x();
159  e.y = m_curve.at(0).y();
160  m_pos += 2;
161  }
162  Q_ASSERT(e.isLineTo() || e.isMoveTo());
163  ++m_pos;
164  return e;
165  }
166 
167 private:
169  int m_pos;
173 };
174 
175 template <class Iterator> bool qt_stroke_side(Iterator *it, QStroker *stroker,
176  bool capFirst, QLineF *startTangent);
177 
178 /*******************************************************************************
179  * QLineF::angle gives us the smalles angle between two lines. Here we
180  * want to identify the line's angle direction on the unit circle.
181  */
182 static inline qreal adapted_angle_on_x(const QLineF &line)
183 {
184  qreal angle = line.angle(QLineF(0, 0, 1, 0));
185  if (line.dy() > 0)
186  angle = 360 - angle;
187  return angle;
188 }
189 
191  : m_elements(0)
192  , m_curveThreshold(qt_real_to_fixed(0.25))
193  , m_dashThreshold(qt_real_to_fixed(0.25))
194  , m_customData(0)
195  , m_moveTo(0)
196  , m_lineTo(0)
197  , m_cubicTo(0)
198 {
199 }
200 
202 {
203 }
204 
213 void QStrokerOps::begin(void *customData)
214 {
215  m_customData = customData;
216  m_elements.reset();
217 }
218 
219 
225 {
226  if (m_elements.size() > 1)
228  m_customData = 0;
229 }
230 
242 void QStrokerOps::strokePath(const QPainterPath &path, void *customData, const QTransform &matrix)
243 {
244  if (path.isEmpty())
245  return;
246 
248  begin(customData);
249  int count = path.elementCount();
250  if (matrix.isIdentity()) {
251  for (int i=0; i<count; ++i) {
252  const QPainterPath::Element &e = path.elementAt(i);
253  switch (e.type) {
256  break;
259  break;
261  {
262  const QPainterPath::Element &cp2 = path.elementAt(++i);
263  const QPainterPath::Element &ep = path.elementAt(++i);
267  }
268  break;
269  default:
270  break;
271  }
272  }
273  } else {
274  for (int i=0; i<count; ++i) {
275  const QPainterPath::Element &e = path.elementAt(i);
276  QPointF pt = QPointF(e.x, e.y) * matrix;
277  switch (e.type) {
280  break;
283  break;
285  {
286  QPointF cp2 = ((QPointF) path.elementAt(++i)) * matrix;
287  QPointF ep = ((QPointF) path.elementAt(++i)) * matrix;
289  qt_real_to_fixed(cp2.x()), qt_real_to_fixed(cp2.y()),
290  qt_real_to_fixed(ep.x()), qt_real_to_fixed(ep.y()));
291  }
292  break;
293  default:
294  break;
295  }
296  }
297  }
298  end();
299 }
300 
313 void QStrokerOps::strokePolygon(const QPointF *points, int pointCount, bool implicit_close,
314  void *data, const QTransform &matrix)
315 {
316  if (!pointCount)
317  return;
318 
320  begin(data);
321  if (matrix.isIdentity()) {
322  moveTo(qt_real_to_fixed(points[0].x()), qt_real_to_fixed(points[0].y()));
323  for (int i=1; i<pointCount; ++i)
324  lineTo(qt_real_to_fixed(points[i].x()),
325  qt_real_to_fixed(points[i].y()));
326  if (implicit_close)
327  lineTo(qt_real_to_fixed(points[0].x()), qt_real_to_fixed(points[0].y()));
328  } else {
329  QPointF start = points[0] * matrix;
330  moveTo(qt_real_to_fixed(start.x()), qt_real_to_fixed(start.y()));
331  for (int i=1; i<pointCount; ++i) {
332  QPointF pt = points[i] * matrix;
334  }
335  if (implicit_close)
336  lineTo(qt_real_to_fixed(start.x()), qt_real_to_fixed(start.y()));
337  }
338  end();
339 }
340 
346 void QStrokerOps::strokeEllipse(const QRectF &rect, void *data, const QTransform &matrix)
347 {
348  int count = 0;
349  QPointF pts[12];
350  QPointF start = qt_curves_for_arc(rect, 0, -360, pts, &count);
351  Q_ASSERT(count == 12); // a perfect circle..
352 
353  if (!matrix.isIdentity()) {
354  start = start * matrix;
355  for (int i=0; i<12; ++i) {
356  pts[i] = pts[i] * matrix;
357  }
358  }
359 
361  begin(data);
362  moveTo(qt_real_to_fixed(start.x()), qt_real_to_fixed(start.y()));
363  for (int i=0; i<12; i+=3) {
364  cubicTo(qt_real_to_fixed(pts[i].x()), qt_real_to_fixed(pts[i].y()),
365  qt_real_to_fixed(pts[i+1].x()), qt_real_to_fixed(pts[i+1].y()),
366  qt_real_to_fixed(pts[i+2].x()), qt_real_to_fixed(pts[i+2].y()));
367  }
368  end();
369 }
370 
371 
373  : m_capStyle(SquareJoin), m_joinStyle(FlatJoin),
374  m_back1X(0), m_back1Y(0),
375  m_back2X(0), m_back2Y(0)
376 {
379 }
380 
382 {
383 }
384 
386 {
387  if (mode == FlatJoin) return Qt::FlatCap;
388  else if (mode == SquareJoin) return Qt::SquareCap;
389  else return Qt::RoundCap;
390 }
391 
393 {
394  if (style == Qt::FlatCap) return FlatJoin;
395  else if (style == Qt::SquareCap) return SquareJoin;
396  else return RoundCap;
397 }
398 
400 {
401  if (mode == FlatJoin) return Qt::BevelJoin;
402  else if (mode == MiterJoin) return Qt::MiterJoin;
403  else if (mode == SvgMiterJoin) return Qt::SvgMiterJoin;
404  else return Qt::RoundJoin;
405 }
406 
408 {
409  if (joinStyle == Qt::BevelJoin) return FlatJoin;
410  else if (joinStyle == Qt::MiterJoin) return MiterJoin;
411  else if (joinStyle == Qt::SvgMiterJoin) return SvgMiterJoin;
412  else return RoundJoin;
413 }
414 
415 
421 {
422  Q_ASSERT(!m_elements.isEmpty());
424  Q_ASSERT(m_elements.size() > 1);
425 
428 
429  QLineF fwStartTangent, bwStartTangent;
430 
431  bool fwclosed = qt_stroke_side(&fwit, this, false, &fwStartTangent);
432  bool bwclosed = qt_stroke_side(&bwit, this, !fwclosed, &bwStartTangent);
433 
434  if (!bwclosed)
435  joinPoints(m_elements.at(0).x, m_elements.at(0).y, fwStartTangent, m_capStyle);
436 }
437 
438 
442 void QStroker::joinPoints(qfixed focal_x, qfixed focal_y, const QLineF &nextLine, LineJoinMode join)
443 {
444 #ifdef QPP_STROKE_DEBUG
445  printf(" -----> joinPoints: around=(%.0f, %.0f), next_p1=(%.0f, %.f) next_p2=(%.0f, %.f)\n",
446  qt_fixed_to_real(focal_x),
447  qt_fixed_to_real(focal_y),
448  nextLine.x1(), nextLine.y1(), nextLine.x2(), nextLine.y2());
449 #endif
450  // points connected already, don't join
451 
452 #if !defined (QFIXED_26_6) && !defined (Q_FIXED_32_32)
453  if (qFuzzyCompare(m_back1X, nextLine.x1()) && qFuzzyCompare(m_back1Y, nextLine.y1()))
454  return;
455 #else
456  if (m_back1X == qt_real_to_fixed(nextLine.x1())
457  && m_back1Y == qt_real_to_fixed(nextLine.y1())) {
458  return;
459  }
460 #endif
461 
462  if (join == FlatJoin) {
465  QPointF isect;
466  QLineF::IntersectType type = prevLine.intersect(nextLine, &isect);
467  QLineF shortCut(prevLine.p2(), nextLine.p1());
468  qreal angle = shortCut.angleTo(prevLine);
469  if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) {
470  emitLineTo(focal_x, focal_y);
471  emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
472  return;
473  }
474  emitLineTo(qt_real_to_fixed(nextLine.x1()),
475  qt_real_to_fixed(nextLine.y1()));
476 
477  } else {
480 
481  QPointF isect;
482  QLineF::IntersectType type = prevLine.intersect(nextLine, &isect);
483 
484  if (join == MiterJoin) {
485  qreal appliedMiterLimit = qt_fixed_to_real(m_strokeWidth * m_miterLimit);
486 
487  // If we are on the inside, do the short cut...
488  QLineF shortCut(prevLine.p2(), nextLine.p1());
489  qreal angle = shortCut.angleTo(prevLine);
490  if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) {
491  emitLineTo(focal_x, focal_y);
492  emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
493  return;
494  }
496  qt_fixed_to_real(m_back1Y)), isect);
497  if (type == QLineF::NoIntersection || miterLine.length() > appliedMiterLimit) {
498  QLineF l1(prevLine);
499  l1.setLength(appliedMiterLimit);
500  l1.translate(prevLine.dx(), prevLine.dy());
501 
502  QLineF l2(nextLine);
503  l2.setLength(appliedMiterLimit);
504  l2.translate(-l2.dx(), -l2.dy());
505 
508  emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
509  } else {
510  emitLineTo(qt_real_to_fixed(isect.x()), qt_real_to_fixed(isect.y()));
511  emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
512  }
513 
514  } else if (join == SquareJoin) {
515  qfixed offset = m_strokeWidth / 2;
516 
517  QLineF l1(prevLine);
518  l1.translate(l1.dx(), l1.dy());
519  l1.setLength(qt_fixed_to_real(offset));
520  QLineF l2(nextLine.p2(), nextLine.p1());
521  l2.translate(l2.dx(), l2.dy());
522  l2.setLength(qt_fixed_to_real(offset));
524  emitLineTo(qt_real_to_fixed(l2.x2()), qt_real_to_fixed(l2.y2()));
525  emitLineTo(qt_real_to_fixed(l2.x1()), qt_real_to_fixed(l2.y1()));
526 
527  } else if (join == RoundJoin) {
528  qfixed offset = m_strokeWidth / 2;
529 
530  QLineF shortCut(prevLine.p2(), nextLine.p1());
531  qreal angle = shortCut.angleTo(prevLine);
532  if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) {
533  emitLineTo(focal_x, focal_y);
534  emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
535  return;
536  }
537  qreal l1_on_x = adapted_angle_on_x(prevLine);
538  qreal l2_on_x = adapted_angle_on_x(nextLine);
539 
540  qreal sweepLength = qAbs(l2_on_x - l1_on_x);
541 
542  int point_count;
543  QPointF curves[15];
544 
545  QPointF curve_start =
546  qt_curves_for_arc(QRectF(qt_fixed_to_real(focal_x - offset),
547  qt_fixed_to_real(focal_y - offset),
548  qt_fixed_to_real(offset * 2),
549  qt_fixed_to_real(offset * 2)),
550  l1_on_x + 90, -sweepLength,
551  curves, &point_count);
552 
553 // // line to the beginning of the arc segment, (should not be needed).
554 // emitLineTo(qt_real_to_fixed(curve_start.x()), qt_real_to_fixed(curve_start.y()));
555  Q_UNUSED(curve_start);
556 
557  for (int i=0; i<point_count; i+=3) {
558  emitCubicTo(qt_real_to_fixed(curves[i].x()),
559  qt_real_to_fixed(curves[i].y()),
560  qt_real_to_fixed(curves[i+1].x()),
561  qt_real_to_fixed(curves[i+1].y()),
562  qt_real_to_fixed(curves[i+2].x()),
563  qt_real_to_fixed(curves[i+2].y()));
564  }
565 
566  // line to the end of the arc segment, (should also not be needed).
567  emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
568 
569  // Same as round join except we know its 180 degrees. Can also optimize this
570  // later based on the addEllipse logic
571  } else if (join == RoundCap) {
572  qfixed offset = m_strokeWidth / 2;
573 
574  // first control line
575  QLineF l1 = prevLine;
576  l1.translate(l1.dx(), l1.dy());
577  l1.setLength(QT_PATH_KAPPA * offset);
578 
579  // second control line, find through normal between prevLine and focal.
580  QLineF l2(qt_fixed_to_real(focal_x), qt_fixed_to_real(focal_y),
581  prevLine.x2(), prevLine.y2());
582  l2.translate(-l2.dy(), l2.dx());
583  l2.setLength(QT_PATH_KAPPA * offset);
584 
586  qt_real_to_fixed(l1.y2()),
587  qt_real_to_fixed(l2.x2()),
588  qt_real_to_fixed(l2.y2()),
589  qt_real_to_fixed(l2.x1()),
590  qt_real_to_fixed(l2.y1()));
591 
592  // move so that it matches
593  l2 = QLineF(l2.x1(), l2.y1(), l2.x1()-l2.dx(), l2.y1()-l2.dy());
594 
595  // last line is parallel to l1 so just shift it down.
596  l1.translate(nextLine.x1() - l1.x1(), nextLine.y1() - l1.y1());
597 
598  emitCubicTo(qt_real_to_fixed(l2.x2()),
599  qt_real_to_fixed(l2.y2()),
600  qt_real_to_fixed(l1.x2()),
601  qt_real_to_fixed(l1.y2()),
602  qt_real_to_fixed(l1.x1()),
603  qt_real_to_fixed(l1.y1()));
604  } else if (join == SvgMiterJoin) {
605  QLineF shortCut(prevLine.p2(), nextLine.p1());
606  qreal angle = shortCut.angleTo(prevLine);
607  if (type == QLineF::BoundedIntersection || (angle > 90 && !qFuzzyCompare(angle, (qreal)90))) {
608  emitLineTo(focal_x, focal_y);
609  emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
610  return;
611  }
612  QLineF miterLine(QPointF(qt_fixed_to_real(focal_x),
613  qt_fixed_to_real(focal_y)), isect);
614  if (type == QLineF::NoIntersection || miterLine.length() > qt_fixed_to_real(m_strokeWidth * m_miterLimit) / 2) {
615  emitLineTo(qt_real_to_fixed(nextLine.x1()),
616  qt_real_to_fixed(nextLine.y1()));
617  } else {
618  emitLineTo(qt_real_to_fixed(isect.x()), qt_real_to_fixed(isect.y()));
619  emitLineTo(qt_real_to_fixed(nextLine.x1()), qt_real_to_fixed(nextLine.y1()));
620  }
621  } else {
622  Q_ASSERT(!"QStroker::joinPoints(), bad join style...");
623  }
624  }
625 }
626 
627 
628 /*
629  Strokes a subpath side using the \a it as source. Results are put into
630  \a stroke. The function returns true if the subpath side was closed.
631  If \a capFirst is true, we will use capPoints instead of joinPoints to
632  connect the first segment, other segments will be joined using joinPoints.
633  This is to put capping in order...
634 */
635 template <class Iterator> bool qt_stroke_side(Iterator *it,
636  QStroker *stroker,
637  bool capFirst,
638  QLineF *startTangent)
639 {
640  // Used in CurveToElement section below.
641  const int MAX_OFFSET = 16;
642  QBezier offsetCurves[MAX_OFFSET];
643 
644  Q_ASSERT(it->hasNext()); // The initaial move to
645  QStrokerOps::Element first_element = it->next();
646  Q_ASSERT(first_element.isMoveTo());
647 
648  qfixed2d start = first_element;
649 
650 #ifdef QPP_STROKE_DEBUG
651  qDebug(" -> (side) [%.2f, %.2f], startPos=%d",
652  qt_fixed_to_real(start.x),
653  qt_fixed_to_real(start.y));
654 #endif
655 
656  qfixed2d prev = start;
657 
658  bool first = true;
659 
660  qfixed offset = stroker->strokeWidth() / 2;
661 
662  while (it->hasNext()) {
663  QStrokerOps::Element e = it->next();
664 
665  // LineToElement
666  if (e.isLineTo()) {
667 #ifdef QPP_STROKE_DEBUG
668  qDebug("\n ---> (side) lineto [%.2f, %.2f]", e.x, e.y);
669 #endif
670  QLineF line(qt_fixed_to_real(prev.x), qt_fixed_to_real(prev.y),
672  if (line.p1() != line.p2()) {
673  QLineF normal = line.normalVector();
674  normal.setLength(offset);
675  line.translate(normal.dx(), normal.dy());
676 
677  // If we are starting a new subpath, move to correct starting point.
678  if (first) {
679  if (capFirst)
680  stroker->joinPoints(prev.x, prev.y, line, stroker->capStyleMode());
681  else
682  stroker->emitMoveTo(qt_real_to_fixed(line.x1()), qt_real_to_fixed(line.y1()));
683  *startTangent = line;
684  first = false;
685  } else {
686  stroker->joinPoints(prev.x, prev.y, line, stroker->joinStyleMode());
687  }
688 
689  // Add the stroke for this line.
690  stroker->emitLineTo(qt_real_to_fixed(line.x2()),
691  qt_real_to_fixed(line.y2()));
692  prev = e;
693  }
694 
695  // CurveToElement
696  } else if (e.isCurveTo()) {
697  QStrokerOps::Element cp2 = it->next(); // control point 2
698  QStrokerOps::Element ep = it->next(); // end point
699 
700 #ifdef QPP_STROKE_DEBUG
701  qDebug("\n ---> (side) cubicTo [%.2f, %.2f]",
702  qt_fixed_to_real(ep.x),
703  qt_fixed_to_real(ep.y));
704 #endif
705 
706  QBezier bezier =
711 
712  int count = bezier.shifted(offsetCurves,
713  MAX_OFFSET,
714  offset,
715  stroker->curveThreshold());
716 
717  if (count) {
718  // If we are starting a new subpath, move to correct starting point
719  QLineF tangent = bezier.startTangent();
720  tangent.translate(offsetCurves[0].pt1() - bezier.pt1());
721  if (first) {
722  QPointF pt = offsetCurves[0].pt1();
723  if (capFirst) {
724  stroker->joinPoints(prev.x, prev.y,
725  tangent,
726  stroker->capStyleMode());
727  } else {
728  stroker->emitMoveTo(qt_real_to_fixed(pt.x()),
729  qt_real_to_fixed(pt.y()));
730  }
731  *startTangent = tangent;
732  first = false;
733  } else {
734  stroker->joinPoints(prev.x, prev.y,
735  tangent,
736  stroker->joinStyleMode());
737  }
738 
739  // Add these beziers
740  for (int i=0; i<count; ++i) {
741  QPointF cp1 = offsetCurves[i].pt2();
742  QPointF cp2 = offsetCurves[i].pt3();
743  QPointF ep = offsetCurves[i].pt4();
744  stroker->emitCubicTo(qt_real_to_fixed(cp1.x()), qt_real_to_fixed(cp1.y()),
745  qt_real_to_fixed(cp2.x()), qt_real_to_fixed(cp2.y()),
746  qt_real_to_fixed(ep.x()), qt_real_to_fixed(ep.y()));
747  }
748  }
749 
750  prev = ep;
751  }
752  }
753 
754  if (start == prev) {
755  // closed subpath, join first and last point
756 #ifdef QPP_STROKE_DEBUG
757  qDebug("\n ---> (side) closed subpath");
758 #endif
759  // don't join empty subpaths
760  if (!first)
761  stroker->joinPoints(prev.x, prev.y, *startTangent, stroker->joinStyleMode());
762  return true;
763  } else {
764 #ifdef QPP_STROKE_DEBUG
765  qDebug("\n ---> (side) open subpath");
766 #endif
767  return false;
768  }
769 }
770 
797 {
798  if (qFuzzyIsNull(angle))
799  return 0;
800 
801  if (qFuzzyCompare(angle, qreal(90)))
802  return 1;
803 
804  qreal radians = Q_PI * angle / 180;
805  qreal cosAngle = qCos(radians);
806  qreal sinAngle = qSin(radians);
807 
808  // initial guess
809  qreal tc = angle / 90;
810  // do some iterations of newton's method to approximate cosAngle
811  // finds the zero of the function b.pointAt(tc).x() - cosAngle
812  tc -= ((((2-3*QT_PATH_KAPPA) * tc + 3*(QT_PATH_KAPPA-1)) * tc) * tc + 1 - cosAngle) // value
813  / (((6-9*QT_PATH_KAPPA) * tc + 6*(QT_PATH_KAPPA-1)) * tc); // derivative
814  tc -= ((((2-3*QT_PATH_KAPPA) * tc + 3*(QT_PATH_KAPPA-1)) * tc) * tc + 1 - cosAngle) // value
815  / (((6-9*QT_PATH_KAPPA) * tc + 6*(QT_PATH_KAPPA-1)) * tc); // derivative
816 
817  // initial guess
818  qreal ts = tc;
819  // do some iterations of newton's method to approximate sinAngle
820  // finds the zero of the function b.pointAt(tc).y() - sinAngle
821  ts -= ((((3*QT_PATH_KAPPA-2) * ts - 6*QT_PATH_KAPPA + 3) * ts + 3*QT_PATH_KAPPA) * ts - sinAngle)
822  / (((9*QT_PATH_KAPPA-6) * ts + 12*QT_PATH_KAPPA - 6) * ts + 3*QT_PATH_KAPPA);
823  ts -= ((((3*QT_PATH_KAPPA-2) * ts - 6*QT_PATH_KAPPA + 3) * ts + 3*QT_PATH_KAPPA) * ts - sinAngle)
824  / (((9*QT_PATH_KAPPA-6) * ts + 12*QT_PATH_KAPPA - 6) * ts + 3*QT_PATH_KAPPA);
825 
826  // use the average of the t that best approximates cosAngle
827  // and the t that best approximates sinAngle
828  qreal t = 0.5 * (tc + ts);
829 
830 #if 0
831  printf("angle: %f, t: %f\n", angle, t);
832  qreal a, b, c, d;
833  bezierCoefficients(t, a, b, c, d);
834  printf("cosAngle: %.10f, value: %.10f\n", cosAngle, a + b + c * QT_PATH_KAPPA);
835  printf("sinAngle: %.10f, value: %.10f\n", sinAngle, b * QT_PATH_KAPPA + c + d);
836 #endif
837 
838  return t;
839 }
840 
842  QPointF* startPoint, QPointF *endPoint);
843 
859 QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength,
860  QPointF *curves, int *point_count)
861 {
862  Q_ASSERT(point_count);
863  Q_ASSERT(curves);
864 
865  *point_count = 0;
866  if (qt_is_nan(rect.x()) || qt_is_nan(rect.y()) || qt_is_nan(rect.width()) || qt_is_nan(rect.height())
867  || qt_is_nan(startAngle) || qt_is_nan(sweepLength)) {
868  qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN, results are undefined");
869  return QPointF();
870  }
871 
872  if (rect.isNull()) {
873  return QPointF();
874  }
875 
876  qreal x = rect.x();
877  qreal y = rect.y();
878 
879  qreal w = rect.width();
880  qreal w2 = rect.width() / 2;
881  qreal w2k = w2 * QT_PATH_KAPPA;
882 
883  qreal h = rect.height();
884  qreal h2 = rect.height() / 2;
885  qreal h2k = h2 * QT_PATH_KAPPA;
886 
887  QPointF points[16] =
888  {
889  // start point
890  QPointF(x + w, y + h2),
891 
892  // 0 -> 270 degrees
893  QPointF(x + w, y + h2 + h2k),
894  QPointF(x + w2 + w2k, y + h),
895  QPointF(x + w2, y + h),
896 
897  // 270 -> 180 degrees
898  QPointF(x + w2 - w2k, y + h),
899  QPointF(x, y + h2 + h2k),
900  QPointF(x, y + h2),
901 
902  // 180 -> 90 degrees
903  QPointF(x, y + h2 - h2k),
904  QPointF(x + w2 - w2k, y),
905  QPointF(x + w2, y),
906 
907  // 90 -> 0 degrees
908  QPointF(x + w2 + w2k, y),
909  QPointF(x + w, y + h2 - h2k),
910  QPointF(x + w, y + h2)
911  };
912 
913  if (sweepLength > 360) sweepLength = 360;
914  else if (sweepLength < -360) sweepLength = -360;
915 
916  // Special case fast paths
917  if (startAngle == 0.0) {
918  if (sweepLength == 360.0) {
919  for (int i = 11; i >= 0; --i)
920  curves[(*point_count)++] = points[i];
921  return points[12];
922  } else if (sweepLength == -360.0) {
923  for (int i = 1; i <= 12; ++i)
924  curves[(*point_count)++] = points[i];
925  return points[0];
926  }
927  }
928 
929  int startSegment = int(qFloor(startAngle / 90));
930  int endSegment = int(qFloor((startAngle + sweepLength) / 90));
931 
932  qreal startT = (startAngle - startSegment * 90) / 90;
933  qreal endT = (startAngle + sweepLength - endSegment * 90) / 90;
934 
935  int delta = sweepLength > 0 ? 1 : -1;
936  if (delta < 0) {
937  startT = 1 - startT;
938  endT = 1 - endT;
939  }
940 
941  // avoid empty start segment
942  if (qFuzzyIsNull(startT - qreal(1))) {
943  startT = 0;
944  startSegment += delta;
945  }
946 
947  // avoid empty end segment
948  if (qFuzzyIsNull(endT)) {
949  endT = 1;
950  endSegment -= delta;
951  }
952 
953  startT = qt_t_for_arc_angle(startT * 90);
954  endT = qt_t_for_arc_angle(endT * 90);
955 
956  const bool splitAtStart = !qFuzzyIsNull(startT);
957  const bool splitAtEnd = !qFuzzyIsNull(endT - qreal(1));
958 
959  const int end = endSegment + delta;
960 
961  // empty arc?
962  if (startSegment == end) {
963  const int quadrant = 3 - ((startSegment % 4) + 4) % 4;
964  const int j = 3 * quadrant;
965  return delta > 0 ? points[j + 3] : points[j];
966  }
967 
968  QPointF startPoint, endPoint;
969  qt_find_ellipse_coords(rect, startAngle, sweepLength, &startPoint, &endPoint);
970 
971  for (int i = startSegment; i != end; i += delta) {
972  const int quadrant = 3 - ((i % 4) + 4) % 4;
973  const int j = 3 * quadrant;
974 
975  QBezier b;
976  if (delta > 0)
977  b = QBezier::fromPoints(points[j + 3], points[j + 2], points[j + 1], points[j]);
978  else
979  b = QBezier::fromPoints(points[j], points[j + 1], points[j + 2], points[j + 3]);
980 
981  // empty arc?
982  if (startSegment == endSegment && qFuzzyCompare(startT, endT))
983  return startPoint;
984 
985  if (i == startSegment) {
986  if (i == endSegment && splitAtEnd)
987  b = b.bezierOnInterval(startT, endT);
988  else if (splitAtStart)
989  b = b.bezierOnInterval(startT, 1);
990  } else if (i == endSegment && splitAtEnd) {
991  b = b.bezierOnInterval(0, endT);
992  }
993 
994  // push control points
995  curves[(*point_count)++] = b.pt2();
996  curves[(*point_count)++] = b.pt3();
997  curves[(*point_count)++] = b.pt4();
998  }
999 
1000  Q_ASSERT(*point_count > 0);
1001  curves[*(point_count)-1] = endPoint;
1002 
1003  return startPoint;
1004 }
1005 
1006 
1007 static inline void qdashstroker_moveTo(qfixed x, qfixed y, void *data) {
1008  ((QStroker *) data)->moveTo(x, y);
1009 }
1010 
1011 static inline void qdashstroker_lineTo(qfixed x, qfixed y, void *data) {
1012  ((QStroker *) data)->lineTo(x, y);
1013 }
1014 
1015 static inline void qdashstroker_cubicTo(qfixed, qfixed, qfixed, qfixed, qfixed, qfixed, void *) {
1016  Q_ASSERT(0);
1017 // ((QStroker *) data)->cubicTo(c1x, c1y, c2x, c2y, ex, ey);
1018 }
1019 
1020 
1021 /*******************************************************************************
1022  * QDashStroker members
1023  */
1025  : m_stroker(stroker), m_dashOffset(0), m_stroke_width(1), m_miter_limit(1)
1026 {
1027  if (m_stroker) {
1031  }
1032 }
1033 
1035 {
1036  const qfixed space = 2;
1037  const qfixed dot = 1;
1038  const qfixed dash = 4;
1039 
1040  QVector<qfixed> pattern;
1041 
1042  switch (style) {
1043  case Qt::DashLine:
1044  pattern << dash << space;
1045  break;
1046  case Qt::DotLine:
1047  pattern << dot << space;
1048  break;
1049  case Qt::DashDotLine:
1050  pattern << dash << space << dot << space;
1051  break;
1052  case Qt::DashDotDotLine:
1053  pattern << dash << space << dot << space << dot << space;
1054  break;
1055  default:
1056  break;
1057  }
1058 
1059  return pattern;
1060 }
1061 
1062 static inline bool lineRectIntersectsRect(qfixed2d p1, qfixed2d p2, const qfixed2d &tl, const qfixed2d &br)
1063 {
1064  return ((p1.x > tl.x || p2.x > tl.x) && (p1.x < br.x || p2.x < br.x)
1065  && (p1.y > tl.y || p2.y > tl.y) && (p1.y < br.y || p2.y < br.y));
1066 }
1067 
1068 // If the line intersects the rectangle, this function will return true.
1069 static bool lineIntersectsRect(qfixed2d p1, qfixed2d p2, const qfixed2d &tl, const qfixed2d &br)
1070 {
1071  if (!lineRectIntersectsRect(p1, p2, tl, br))
1072  return false;
1073  if (p1.x == p2.x || p1.y == p2.y)
1074  return true;
1075 
1076  if (p1.y > p2.y)
1077  qSwap(p1, p2); // make p1 above p2
1078  qfixed2d u;
1079  qfixed2d v;
1080  qfixed2d w = {p2.x - p1.x, p2.y - p1.y};
1081  if (p1.x < p2.x) {
1082  // backslash
1083  u.x = tl.x - p1.x; u.y = br.y - p1.y;
1084  v.x = br.x - p1.x; v.y = tl.y - p1.y;
1085  } else {
1086  // slash
1087  u.x = tl.x - p1.x; u.y = tl.y - p1.y;
1088  v.x = br.x - p1.x; v.y = br.y - p1.y;
1089  }
1090 #if defined(QFIXED_IS_26_6) || defined(QFIXED_IS_16_16)
1091  qint64 val1 = qint64(u.x) * qint64(w.y) - qint64(u.y) * qint64(w.x);
1092  qint64 val2 = qint64(v.x) * qint64(w.y) - qint64(v.y) * qint64(w.x);
1093  return (val1 < 0 && val2 > 0) || (val1 > 0 && val2 < 0);
1094 #elif defined(QFIXED_IS_32_32)
1095  // Cannot do proper test because it may overflow.
1096  return true;
1097 #else
1098  qreal val1 = u.x * w.y - u.y * w.x;
1099  qreal val2 = v.x * w.y - v.y * w.x;
1100  return (val1 < 0 && val2 > 0) || (val1 > 0 && val2 < 0);
1101 #endif
1102 }
1103 
1105 {
1106  int dashCount = qMin(m_dashPattern.size(), 32);
1107  qfixed dashes[32];
1108 
1109  if (m_stroker) {
1113  }
1114 
1115  qreal longestLength = 0;
1116  qreal sumLength = 0;
1117  for (int i=0; i<dashCount; ++i) {
1118  dashes[i] = qMax(m_dashPattern.at(i), qreal(0)) * m_stroke_width;
1119  sumLength += dashes[i];
1120  if (dashes[i] > longestLength)
1121  longestLength = dashes[i];
1122  }
1123 
1124  if (qFuzzyIsNull(sumLength))
1125  return;
1126 
1127  qreal invSumLength = qreal(1) / sumLength;
1128 
1129  Q_ASSERT(dashCount > 0);
1130 
1131  dashCount = dashCount & -2; // Round down to even number
1132 
1133  int idash = 0; // Index to current dash
1134  qreal pos = 0; // The position on the curve, 0 <= pos <= path.length
1135  qreal elen = 0; // element length
1136  qreal doffset = m_dashOffset * m_stroke_width;
1137 
1138  // make sure doffset is in range [0..sumLength)
1139  doffset -= qFloor(doffset * invSumLength) * sumLength;
1140 
1141  while (doffset >= dashes[idash]) {
1142  doffset -= dashes[idash];
1143  if (++idash >= dashCount)
1144  idash = 0;
1145  }
1146 
1147  qreal estart = 0; // The elements starting position
1148  qreal estop = 0; // The element stop position
1149 
1150  QLineF cline;
1151 
1152  QPainterPath dashPath;
1153 
1155  qfixed2d prev = it.next();
1156 
1157  bool clipping = !m_clip_rect.isEmpty();
1158  qfixed2d move_to_pos = prev;
1159  qfixed2d line_to_pos;
1160 
1161  // Pad to avoid clipping the borders of thick pens.
1162  qfixed padding = qt_real_to_fixed(qMax(m_stroke_width, m_miter_limit) * longestLength);
1163  qfixed2d clip_tl = { qt_real_to_fixed(m_clip_rect.left()) - padding,
1164  qt_real_to_fixed(m_clip_rect.top()) - padding };
1165  qfixed2d clip_br = { qt_real_to_fixed(m_clip_rect.right()) + padding ,
1166  qt_real_to_fixed(m_clip_rect.bottom()) + padding };
1167 
1168  bool hasMoveTo = false;
1169  while (it.hasNext()) {
1170  QStrokerOps::Element e = it.next();
1171 
1172  Q_ASSERT(e.isLineTo());
1173  cline = QLineF(qt_fixed_to_real(prev.x),
1174  qt_fixed_to_real(prev.y),
1175  qt_fixed_to_real(e.x),
1176  qt_fixed_to_real(e.y));
1177  elen = cline.length();
1178 
1179  estop = estart + elen;
1180 
1181  bool done = pos >= estop;
1182 
1183  if (clipping) {
1184  // Check if the entire line can be clipped away.
1185  if (!lineIntersectsRect(prev, e, clip_tl, clip_br)) {
1186  // Cut away full dash sequences.
1187  elen -= qFloor(elen * invSumLength) * sumLength;
1188  // Update dash offset.
1189  while (!done) {
1190  qreal dpos = pos + dashes[idash] - doffset - estart;
1191 
1192  Q_ASSERT(dpos >= 0);
1193 
1194  if (dpos > elen) { // dash extends this line
1195  doffset = dashes[idash] - (dpos - elen); // subtract the part already used
1196  pos = estop; // move pos to next path element
1197  done = true;
1198  } else { // Dash is on this line
1199  pos = dpos + estart;
1200  done = pos >= estop;
1201  if (++idash >= dashCount)
1202  idash = 0;
1203  doffset = 0; // full segment so no offset on next.
1204  }
1205  }
1206  hasMoveTo = false;
1207  move_to_pos = e;
1208  }
1209  }
1210 
1211  // Dash away...
1212  while (!done) {
1213  QPointF p2;
1214 
1215  bool has_offset = doffset > 0;
1216  bool evenDash = (idash & 1) == 0;
1217  qreal dpos = pos + dashes[idash] - doffset - estart;
1218 
1219  Q_ASSERT(dpos >= 0);
1220 
1221  if (dpos > elen) { // dash extends this line
1222  doffset = dashes[idash] - (dpos - elen); // subtract the part already used
1223  pos = estop; // move pos to next path element
1224  done = true;
1225  p2 = cline.p2();
1226  } else { // Dash is on this line
1227  p2 = cline.pointAt(dpos/elen);
1228  pos = dpos + estart;
1229  done = pos >= estop;
1230  if (++idash >= dashCount)
1231  idash = 0;
1232  doffset = 0; // full segment so no offset on next.
1233  }
1234 
1235  if (evenDash) {
1236  line_to_pos.x = qt_real_to_fixed(p2.x());
1237  line_to_pos.y = qt_real_to_fixed(p2.y());
1238 
1239  if (!clipping
1240  || lineRectIntersectsRect(move_to_pos, line_to_pos, clip_tl, clip_br))
1241  {
1242  // If we have an offset, we're continuing a dash
1243  // from a previous element and should only
1244  // continue the current dash, without starting a
1245  // new subpath.
1246  if (!has_offset || !hasMoveTo) {
1247  emitMoveTo(move_to_pos.x, move_to_pos.y);
1248  hasMoveTo = true;
1249  }
1250 
1251  emitLineTo(line_to_pos.x, line_to_pos.y);
1252  } else {
1253  hasMoveTo = false;
1254  }
1255  move_to_pos = line_to_pos;
1256  } else {
1257  move_to_pos.x = qt_real_to_fixed(p2.x());
1258  move_to_pos.y = qt_real_to_fixed(p2.y());
1259  }
1260  }
1261 
1262  // Shuffle to the next cycle...
1263  estart = estop;
1264  prev = e;
1265  }
1266 
1267 }
1268 
ElementType type
the type of element
Definition: qpainterpath.h:81
qfixed m_back1Y
Definition: qstroker_p.h:247
double d
Definition: qnumeric_p.h:62
The QPainterPath::Element class specifies the position and type of a subpath.
Definition: qpainterpath.h:77
QPointF pt4() const
Definition: qbezier_p.h:97
qfixed strokeWidth() const
Definition: qstroker_p.h:213
bool isEmpty() const
Returns true if either there are no elements in this path, or if the only element is a MoveToElement;...
Definition: qpainterpath.h:392
QDataBuffer< Element > m_elements
Definition: qstroker_p.h:183
qreal y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:667
qreal right() const
Returns the x-coordinate of the rectangle&#39;s right edge.
Definition: qrect.h:527
#define qt_real_to_fixed(real)
Definition: qstroker_p.h:101
int type
Definition: qmetatype.cpp:239
QLineF startTangent() const
Definition: qbezier_p.h:132
bool isMoveTo() const
Definition: qstroker_p.h:138
double qreal
Definition: qglobal.h:1193
QDashStroker(QStroker *stroker)
Definition: qstroker.cpp:1024
unsigned char c[8]
Definition: qnumeric_p.h:62
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QPainterPath::ElementType type
Definition: qstroker_p.h:134
const QDataBuffer< QStrokerOps::Element > * m_path
Definition: qstroker.cpp:63
qreal length() const
Returns the length of the line.
Definition: qline.cpp:698
void lineTo(qfixed x, qfixed y)
Definition: qstroker_p.h:317
#define it(className, varName)
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:67
static LineJoinMode joinModeForJoin(Qt::PenJoinStyle joinStyle)
Definition: qstroker.cpp:407
bool hasNext() const
Definition: qstroker.cpp:75
void emitCubicTo(qfixed c1x, qfixed c1y, qfixed c2x, qfixed c2y, qfixed ex, qfixed ey)
Definition: qstroker_p.h:354
qreal x2() const
Returns the x-coordinate of the line&#39;s end point.
Definition: qline.h:304
void emitLineTo(qfixed x, qfixed y)
Definition: qstroker_p.h:296
int qFloor(qreal v)
Definition: qmath.h:73
static LineJoinMode joinModeForCap(Qt::PenCapStyle)
Definition: qstroker.cpp:392
#define Q_GUI_EXPORT
Definition: qglobal.h:1450
QPointF p1() const
Returns the line&#39;s start point.
Definition: qline.h:314
virtual ~QStrokerOps()
Definition: qstroker.cpp:201
qreal y2() const
Returns the y-coordinate of the line&#39;s end point.
Definition: qline.h:309
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
LineJoinMode capStyleMode() const
Definition: qstroker_p.h:217
qreal left() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:525
QStrokerOps::Element next()
Definition: qstroker.cpp:77
QRectF m_clip_rect
Definition: qstroker_p.h:185
static bool lineIntersectsRect(qfixed2d p1, qfixed2d p2, const qfixed2d &tl, const qfixed2d &br)
Definition: qstroker.cpp:1069
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:313
static bool qt_is_nan(double d)
Definition: qnumeric_p.h:183
static Qt::PenJoinStyle joinForJoinMode(LineJoinMode mode)
Definition: qstroker.cpp:399
static Q_DECL_CONSTEXPR bool qFuzzyCompare(double p1, double p2)
Definition: qglobal.h:2030
IntersectType intersect(const QLineF &l, QPointF *intersectionPoint) const
Returns a value indicating whether or not this line intersects with the given line.
Definition: qline.cpp:813
quint16 u
#define QT_PATH_KAPPA
Definition: qstroker_p.h:113
static Qt::PenCapStyle capForJoinMode(LineJoinMode mode)
Definition: qstroker.cpp:385
long ASN1_INTEGER_get ASN1_INTEGER * a
qreal dy() const
Returns the vertical component of the line&#39;s vector.
Definition: qline.h:329
virtual void processCurrentSubpath()
Definition: qstroker.cpp:1104
qreal y
the y coordinate of the element&#39;s position.
Definition: qpainterpath.h:80
QPointF pt1() const
Definition: qbezier_p.h:94
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
void setCurveThresholdFromTransform(const QTransform &transform)
Definition: qstroker_p.h:167
const QPainterPath::Element & elementAt(int i) const
Returns the element at the given index in the painter path.
Definition: qpainterpath.h:402
PenStyle
Definition: qnamespace.h:1134
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
void setCubicToHook(qStrokerCubicToHook cubicToHook)
Definition: qstroker_p.h:150
void cubicTo(qfixed x1, qfixed y1, qfixed x2, qfixed y2, qfixed ex, qfixed ey)
Definition: qstroker_p.h:323
virtual void processCurrentSubpath()=0
qreal x() const
Returns the x-coordinate of this point.
Definition: qpoint.h:282
PenCapStyle
Definition: qnamespace.h:1147
void emitMoveTo(qfixed x, qfixed y)
Definition: qstroker_p.h:336
int shifted(QBezier *curveSegments, int maxSegmets, qreal offset, float threshold) const
Definition: qbezier.cpp:433
The QLineF class provides a two-dimensional vector using floating point precision.
Definition: qline.h:212
bool isIdentity() const
Returns true if the matrix is the identity matrix, otherwise returns false.
Definition: qtransform.h:204
bool isLineTo() const
Definition: qstroker_p.h:139
QSubpathFlatIterator(const QDataBuffer< QStrokerOps::Element > *path, qreal threshold)
Definition: qstroker.cpp:123
Q_CORE_EXPORT void qDebug(const char *,...)
virtual void processCurrentSubpath()
This function is called to stroke the currently built up subpath.
Definition: qstroker.cpp:420
static void qdashstroker_moveTo(qfixed x, qfixed y, void *data)
Definition: qstroker.cpp:1007
qfixed m_back2Y
Definition: qstroker_p.h:250
static QBezier fromPoints(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4)
Definition: qbezier.cpp:71
QSubpathBackwardIterator(const QDataBuffer< QStrokerOps::Element > *path)
Definition: qstroker.cpp:70
int position() const
Definition: qstroker.cpp:58
qreal qt_t_for_arc_angle(qreal angle)
Definition: qstroker.cpp:796
void emitMoveTo(qfixed x, qfixed y)
Definition: qstroker_p.h:290
void translate(const QPointF &p)
Translates this line by the given offset.
Definition: qline.h:339
qreal m_dashOffset
Definition: qstroker_p.h:279
QBezier bezierOnInterval(qreal t0, qreal t1) const
Definition: qbezier.cpp:687
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
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:242
qfixed x
Definition: qstroker_p.h:105
static void qdashstroker_lineTo(qfixed x, qfixed y, void *data)
Definition: qstroker.cpp:1011
void * m_customData
Definition: qstroker_p.h:189
qreal qSin(qreal v)
Definition: qmath.h:93
bool qt_stroke_side(Iterator *it, QStroker *stroker, bool capFirst, QLineF *startTangent)
Definition: qstroker.cpp:635
bool hasNext() const
Definition: qstroker.cpp:59
qreal height() const
Returns the height of the rectangle.
Definition: qrect.h:710
static qreal adapted_angle_on_x(const QLineF &line)
Definition: qstroker.cpp:182
IntersectType
Describes the intersection between two lines.
Definition: qline.h:215
void strokeEllipse(const QRectF &ellipse, void *data, const QTransform &matrix)
Convenience function for stroking an ellipse with bounding rect rect.
Definition: qstroker.cpp:346
qreal y1() const
Returns the y-coordinate of the line&#39;s start point.
Definition: qline.h:299
QVector< qfixed > m_dashPattern
Definition: qstroker_p.h:278
The QPolygonF class provides a vector of points using floating point precision.
Definition: qpolygon.h:134
Q_CORE_EXPORT void qWarning(const char *,...)
qreal angle() const
Returns the angle of the line in degrees.
Definition: qline.cpp:719
Type & at(int i)
Definition: qdatabuffer_p.h:86
static const char * data(const QByteArray &arr)
const QDataBuffer< QStrokerOps::Element > * m_path
Definition: qstroker.cpp:116
LineJoinMode joinStyleMode() const
Definition: qstroker_p.h:221
void setLength(qreal len)
Sets the length of the line to the given length.
Definition: qline.h:360
qreal width() const
Returns the width of the rectangle.
Definition: qrect.h:707
qfixed y
Definition: qstroker_p.h:106
PenJoinStyle
Definition: qnamespace.h:1154
__int64 qint64
Definition: qglobal.h:942
qfixed m_strokeWidth
Definition: qstroker_p.h:240
virtual void end()
Finishes the stroke.
Definition: qstroker.cpp:224
qfixed m_miterLimit
Definition: qstroker_p.h:241
qreal dx() const
Returns the horizontal component of the line&#39;s vector.
Definition: qline.h:324
qfixed miterLimit() const
Definition: qstroker_p.h:224
qfixed curveThreshold() const
Definition: qstroker_p.h:175
virtual void begin(void *customData)
Prepares the stroker.
Definition: qstroker.cpp:213
void qSwap(T &value1, T &value2)
Definition: qglobal.h:2181
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
static bool lineRectIntersectsRect(qfixed2d p1, qfixed2d p2, const qfixed2d &tl, const qfixed2d &br)
Definition: qstroker.cpp:1062
void joinPoints(qfixed x, qfixed y, const QLineF &nextLine, LineJoinMode join)
Definition: qstroker.cpp:442
#define qt_fixed_to_real(fixed)
Definition: qstroker_p.h:102
Q_GUI_EXPORT void qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length, QPointF *startPoint, QPointF *endPoint)
qreal angle(const QPointF &p1, const QPointF &p2)
static void qdashstroker_cubicTo(qfixed, qfixed, qfixed, qfixed, qfixed, qfixed, void *)
Definition: qstroker.cpp:1015
qreal x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:664
QPointF pt2() const
Definition: qbezier_p.h:95
QStroker * m_stroker
Definition: qstroker_p.h:277
bool hasNext() const
Definition: qstroker.cpp:126
QPointF p2() const
Returns the line&#39;s end point.
Definition: qline.h:319
qfixed m_back1X
Definition: qstroker_p.h:246
qfixed m_back2X
Definition: qstroker_p.h:249
QPointF pt3() const
Definition: qbezier_p.h:96
qreal x
the x coordinate of the element&#39;s position.
Definition: qpainterpath.h:79
qreal y() const
Returns the y-coordinate of this point.
Definition: qpoint.h:287
const QDataBuffer< QStrokerOps::Element > * m_path
Definition: qstroker.cpp:168
qreal m_stroke_width
Definition: qstroker_p.h:281
bool isCurveTo() const
Definition: qstroker_p.h:140
qreal top() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:526
QLineF normalVector() const
Returns a line that is perpendicular to this line with the same starting point and length...
Definition: qline.h:334
static Q_DECL_CONSTEXPR bool qFuzzyIsNull(double d)
Definition: qglobal.h:2043
void setLineToHook(qStrokerLineToHook lineToHook)
Definition: qstroker_p.h:149
QSubpathForwardIterator(const QDataBuffer< QStrokerOps::Element > *path)
Definition: qstroker.cpp:56
qfixed m_dashThreshold
Definition: qstroker_p.h:187
qreal m_miter_limit
Definition: qstroker_p.h:282
void moveTo(qfixed x, qfixed y)
Definition: qstroker_p.h:308
int elementCount() const
Returns the number of path elements in the painter path.
Definition: qpainterpath.h:397
qreal bottom() const
Returns the y-coordinate of the rectangle&#39;s bottom edge.
Definition: qrect.h:528
QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLength, QPointF *curves, int *point_count)
Creates a number of curves for a given arc definition.
Definition: qstroker.cpp:859
void setMoveToHook(qStrokerMoveToHook moveToHook)
Definition: qstroker_p.h:148
Qt::PenJoinStyle joinStyle() const
Definition: qstroker_p.h:220
bool isEmpty() const
Returns true if the rectangle is empty, otherwise returns false.
Definition: qrect.h:658
qreal x1() const
Returns the x-coordinate of the line&#39;s start point.
Definition: qline.h:294
QStrokerOps::Element next()
Definition: qstroker.cpp:60
static qreal dot(const QPointF &a, const QPointF &b)
qreal qCos(qreal v)
Definition: qmath.h:109
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
void emitLineTo(qfixed x, qfixed y)
Definition: qstroker_p.h:345
bool isNull() const
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition: qrect.h:655
qreal qfixed
Definition: qstroker_p.h:100
LineJoinMode m_capStyle
Definition: qstroker_p.h:243
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:65
static QVector< qfixed > patternForStyle(Qt::PenStyle style)
Definition: qstroker.cpp:1034
int size() const
Definition: qdatabuffer_p.h:83
QStrokerOps::Element next()
Definition: qstroker.cpp:128
static const qreal Q_PI
Definition: qmath_p.h:61