1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qpainterpath.h"
43 #include "qpainterpath_p.h"
47 #include <qiodevice.h>
52 #include <qtextlayout.h>
53 #include <qvarlengtharray.h>
56 #include <private/qbezier_p.h>
57 #include <private/qfontengine_p.h>
58 #include <private/qnumeric_p.h>
59 #include <private/qobject_p.h>
60 #include <private/qpathclipper_p.h>
61 #include <private/qstroker_p.h>
62 #include <private/qtextengine_p.h>
67 #include <performance.h>
76 struct QPainterPathPrivateDeleter
78 static inline void cleanup(QPainterPathPrivate *d)
80 // note - we must up-cast to QPainterPathData since QPainterPathPrivate
81 // has a non-virtual destructor!
82 if (d && !d->ref.deref())
83 delete static_cast<QPainterPathData *>(d);
87 // This value is used to determine the length of control point vectors
88 // when approximating arc segments as curves. The factor is multiplied
89 // with the radius of the circle.
92 // #define QPP_STROKE_DEBUG
93 //#define QPP_FILLPOLYGONS_DEBUG
95 QPainterPath qt_stroke_dash(const QPainterPath &path, qreal *dashes, int dashCount);
97 void qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length,
98 QPointF* startPoint, QPointF *endPoint)
102 *startPoint = QPointF();
104 *endPoint = QPointF();
108 qreal w2 = r.width() / 2;
109 qreal h2 = r.height() / 2;
111 qreal angles[2] = { angle, angle + length };
112 QPointF *points[2] = { startPoint, endPoint };
114 for (int i = 0; i < 2; ++i) {
118 qreal theta = angles[i] - 360 * qFloor(angles[i] / 360);
119 qreal t = theta / 90;
121 int quadrant = int(t);
124 t = qt_t_for_arc_angle(90 * t);
131 QBezier::coefficients(t, a, b, c, d);
132 QPointF p(a + b + c*QT_PATH_KAPPA, d + c + b*QT_PATH_KAPPA);
135 if (quadrant == 1 || quadrant == 2)
139 if (quadrant == 0 || quadrant == 1)
142 *points[i] = r.center() + QPointF(w2 * p.x(), h2 * p.y());
147 static void qt_debug_path(const QPainterPath &path)
149 const char *names[] = {
156 printf("\nQPainterPath: elementCount=%d\n", path.elementCount());
157 for (int i=0; i<path.elementCount(); ++i) {
158 const QPainterPath::Element &e = path.elementAt(i);
159 Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
160 printf(" - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
170 \brief The QPainterPath class provides a container for painting operations,
171 enabling graphical shapes to be constructed and reused.
173 A painter path is an object composed of a number of graphical
174 building blocks, such as rectangles, ellipses, lines, and curves.
175 Building blocks can be joined in closed subpaths, for example as a
176 rectangle or an ellipse. A closed path has coinciding start and
177 end points. Or they can exist independently as unclosed subpaths,
178 such as lines and curves.
180 A QPainterPath object can be used for filling, outlining, and
181 clipping. To generate fillable outlines for a given painter path,
182 use the QPainterPathStroker class. The main advantage of painter
183 paths over normal drawing operations is that complex shapes only
184 need to be created once; then they can be drawn many times using
185 only calls to the QPainter::drawPath() function.
187 QPainterPath provides a collection of functions that can be used
188 to obtain information about the path and its elements. In addition
189 it is possible to reverse the order of the elements using the
190 toReversed() function. There are also several functions to convert
191 this painter path object into a polygon representation.
195 \section1 Composing a QPainterPath
197 A QPainterPath object can be constructed as an empty path, with a
198 given start point, or as a copy of another QPainterPath object.
199 Once created, lines and curves can be added to the path using the
200 lineTo(), arcTo(), cubicTo() and quadTo() functions. The lines and
201 curves stretch from the currentPosition() to the position passed
204 The currentPosition() of the QPainterPath object is always the end
205 position of the last subpath that was added (or the initial start
206 point). Use the moveTo() function to move the currentPosition()
207 without adding a component. The moveTo() function implicitly
208 starts a new subpath, and closes the previous one. Another way of
209 starting a new subpath is to call the closeSubpath() function
210 which closes the current path by adding a line from the
211 currentPosition() back to the path's start position. Note that the
212 new path will have (0, 0) as its initial currentPosition().
214 QPainterPath class also provides several convenience functions to
215 add closed subpaths to a painter path: addEllipse(), addPath(),
216 addRect(), addRegion() and addText(). The addPolygon() function
217 adds an \e unclosed subpath. In fact, these functions are all
218 collections of moveTo(), lineTo() and cubicTo() operations.
220 In addition, a path can be added to the current path using the
221 connectPath() function. But note that this function will connect
222 the last element of the current path to the first element of given
223 one by adding a line.
225 Below is a code snippet that shows how a QPainterPath object can
230 \li \inlineimage qpainterpath-construction.png
232 \snippet code/src_gui_painting_qpainterpath.cpp 0
235 The painter path is initially empty when constructed. We first add
236 a rectangle, which is a closed subpath. Then we add two bezier
237 curves which together form a closed subpath even though they are
238 not closed individually. Finally we draw the entire path. The path
239 is filled using the default fill rule, Qt::OddEvenFill. Qt
240 provides two methods for filling paths:
247 \li \inlineimage qt-fillrule-oddeven.png
248 \li \inlineimage qt-fillrule-winding.png
251 See the Qt::FillRule documentation for the definition of the
252 rules. A painter path's currently set fill rule can be retrieved
253 using the fillRule() function, and altered using the setFillRule()
256 \section1 QPainterPath Information
258 The QPainterPath class provides a collection of functions that
259 returns information about the path and its elements.
261 The currentPosition() function returns the end point of the last
262 subpath that was added (or the initial start point). The
263 elementAt() function can be used to retrieve the various subpath
264 elements, the \e number of elements can be retrieved using the
265 elementCount() function, and the isEmpty() function tells whether
266 this QPainterPath object contains any elements at all.
268 The controlPointRect() function returns the rectangle containing
269 all the points and control points in this path. This function is
270 significantly faster to compute than the exact boundingRect()
271 which returns the bounding rectangle of this painter path with
272 floating point precision.
274 Finally, QPainterPath provides the contains() function which can
275 be used to determine whether a given point or rectangle is inside
276 the path, and the intersects() function which determines if any of
277 the points inside a given rectangle also are inside this path.
279 \section1 QPainterPath Conversion
281 For compatibility reasons, it might be required to simplify the
282 representation of a painter path: QPainterPath provides the
283 toFillPolygon(), toFillPolygons() and toSubpathPolygons()
284 functions which convert the painter path into a polygon. The
285 toFillPolygon() returns the painter path as one single polygon,
286 while the two latter functions return a list of polygons.
288 The toFillPolygons() and toSubpathPolygons() functions are
289 provided because it is usually faster to draw several small
290 polygons than to draw one large polygon, even though the total
291 number of points drawn is the same. The difference between the two
292 is the \e number of polygons they return: The toSubpathPolygons()
293 creates one polygon for each subpath regardless of intersecting
294 subpaths (i.e. overlapping bounding rectangles), while the
295 toFillPolygons() functions creates only one polygon for
296 overlapping subpaths.
298 The toFillPolygon() and toFillPolygons() functions first convert
299 all the subpaths to polygons, then uses a rewinding technique to
300 make sure that overlapping subpaths can be filled using the
301 correct fill rule. Note that rewinding inserts additional lines in
302 the polygon so the outline of the fill polygon does not match the
307 Qt provides the \l {painting/painterpaths}{Painter Paths Example}
308 and the \l {painting/deform}{Vector Deformation example} which are
309 located in Qt's example directory.
311 The \l {painting/painterpaths}{Painter Paths Example} shows how
312 painter paths can be used to build complex shapes for rendering
313 and lets the user experiment with the filling and stroking. The
314 \l {painting/deform}{Vector Deformation Example} shows how to use
315 QPainterPath to draw text.
319 \li \l {painting/painterpaths}{Painter Paths Example}
320 \li \l {painting/deform}{Vector Deformation Example}
322 \li \inlineimage qpainterpath-example.png
323 \li \inlineimage qpainterpath-demo.png
326 \sa QPainterPathStroker, QPainter, QRegion, {Painter Paths Example}
330 \enum QPainterPath::ElementType
332 This enum describes the types of elements used to connect vertices
335 Note that elements added as closed subpaths using the
336 addEllipse(), addPath(), addPolygon(), addRect(), addRegion() and
337 addText() convenience functions, is actually added to the path as
338 a collection of separate elements using the moveTo(), lineTo() and
341 \value MoveToElement A new subpath. See also moveTo().
342 \value LineToElement A line. See also lineTo().
343 \value CurveToElement A curve. See also cubicTo() and quadTo().
344 \value CurveToDataElement The extra data required to describe a curve in
345 a CurveToElement element.
347 \sa elementAt(), elementCount()
351 \class QPainterPath::Element
353 \brief The QPainterPath::Element class specifies the position and
356 Once a QPainterPath object is constructed, subpaths like lines and
357 curves can be added to the path (creating
358 QPainterPath::LineToElement and QPainterPath::CurveToElement
361 The lines and curves stretch from the currentPosition() to the
362 position passed as argument. The currentPosition() of the
363 QPainterPath object is always the end position of the last subpath
364 that was added (or the initial start point). The moveTo() function
365 can be used to move the currentPosition() without adding a line or
366 curve, creating a QPainterPath::MoveToElement component.
372 \variable QPainterPath::Element::x
373 \brief the x coordinate of the element's position.
375 \sa {operator QPointF()}
379 \variable QPainterPath::Element::y
380 \brief the y coordinate of the element's position.
382 \sa {operator QPointF()}
386 \variable QPainterPath::Element::type
387 \brief the type of element
389 \sa isCurveTo(), isLineTo(), isMoveTo()
393 \fn bool QPainterPath::Element::operator==(const Element &other) const
396 Returns true if this element is equal to \a other;
397 otherwise returns false.
403 \fn bool QPainterPath::Element::operator!=(const Element &other) const
406 Returns true if this element is not equal to \a other;
407 otherwise returns false.
413 \fn bool QPainterPath::Element::isCurveTo () const
415 Returns true if the element is a curve, otherwise returns false.
417 \sa type, QPainterPath::CurveToElement
421 \fn bool QPainterPath::Element::isLineTo () const
423 Returns true if the element is a line, otherwise returns false.
425 \sa type, QPainterPath::LineToElement
429 \fn bool QPainterPath::Element::isMoveTo () const
431 Returns true if the element is moving the current position,
432 otherwise returns false.
434 \sa type, QPainterPath::MoveToElement
438 \fn QPainterPath::Element::operator QPointF () const
440 Returns the element's position.
446 \fn void QPainterPath::addEllipse(qreal x, qreal y, qreal width, qreal height)
449 Creates an ellipse within the bounding rectangle defined by its top-left
450 corner at (\a x, \a y), \a width and \a height, and adds it to the
451 painter path as a closed subpath.
457 \fn void QPainterPath::addEllipse(const QPointF ¢er, qreal rx, qreal ry)
460 Creates an ellipse positioned at \a{center} with radii \a{rx} and \a{ry},
461 and adds it to the painter path as a closed subpath.
465 \fn void QPainterPath::addText(qreal x, qreal y, const QFont &font, const QString &text)
468 Adds the given \a text to this path as a set of closed subpaths created
469 from the \a font supplied. The subpaths are positioned so that the left
470 end of the text's baseline lies at the point specified by (\a x, \a y).
474 \fn int QPainterPath::elementCount() const
476 Returns the number of path elements in the painter path.
478 \sa ElementType, elementAt(), isEmpty()
481 int QPainterPath::elementCount() const
483 return d_ptr ? d_ptr->elements.size() : 0;
487 \fn QPainterPath::Element QPainterPath::elementAt(int index) const
489 Returns the element at the given \a index in the painter path.
491 \sa ElementType, elementCount(), isEmpty()
494 QPainterPath::Element QPainterPath::elementAt(int i) const
497 Q_ASSERT(i >= 0 && i < elementCount());
498 return d_ptr->elements.at(i);
502 \fn void QPainterPath::setElementPositionAt(int index, qreal x, qreal y)
505 Sets the x and y coordinate of the element at index \a index to \a
509 void QPainterPath::setElementPositionAt(int i, qreal x, qreal y)
512 Q_ASSERT(i >= 0 && i < elementCount());
514 QPainterPath::Element &e = d_ptr->elements[i];
521 \fn QPainterPath &QPainterPath::operator +=(const QPainterPath &other)
523 Appends the \a other painter path to this painter path and returns a
524 reference to the result.
528 Constructs an empty QPainterPath object.
530 QPainterPath::QPainterPath()
536 \fn QPainterPath::QPainterPath(const QPainterPath &path)
538 Creates a QPainterPath object that is a copy of the given \a path.
542 QPainterPath::QPainterPath(const QPainterPath &other)
543 : d_ptr(other.d_ptr.data())
550 Creates a QPainterPath object with the given \a startPoint as its
554 QPainterPath::QPainterPath(const QPointF &startPoint)
555 : d_ptr(new QPainterPathData)
557 Element e = { startPoint.x(), startPoint.y(), MoveToElement };
558 d_func()->elements << e;
561 void QPainterPath::detach()
563 if (d_ptr->ref.load() != 1)
571 void QPainterPath::detach_helper()
573 QPainterPathPrivate *data = new QPainterPathData(*d_func());
580 void QPainterPath::ensureData_helper()
582 QPainterPathPrivate *data = new QPainterPathData;
583 data->elements.reserve(16);
584 QPainterPath::Element e = { 0, 0, QPainterPath::MoveToElement };
587 Q_ASSERT(d_ptr != 0);
591 \fn QPainterPath &QPainterPath::operator=(const QPainterPath &path)
593 Assigns the given \a path to this painter path.
597 QPainterPath &QPainterPath::operator=(const QPainterPath &other)
599 if (other.d_func() != d_func()) {
600 QPainterPathPrivate *data = other.d_func();
609 \fn void QPainterPath::swap(QPainterPath &other)
612 Swaps painter path \a other with this painter path. This operation is very
613 fast and never fails.
617 Destroys this QPainterPath object.
619 QPainterPath::~QPainterPath()
624 Closes the current subpath by drawing a line to the beginning of
625 the subpath, automatically starting a new path. The current point
626 of the new path is (0, 0).
628 If the subpath does not contain any elements, this function does
631 \sa moveTo(), {QPainterPath#Composing a QPainterPath}{Composing
634 void QPainterPath::closeSubpath()
637 printf("QPainterPath::closeSubpath()\n");
647 \fn void QPainterPath::moveTo(qreal x, qreal y)
651 Moves the current position to (\a{x}, \a{y}) and starts a new
652 subpath, implicitly closing the previous path.
656 \fn void QPainterPath::moveTo(const QPointF &point)
658 Moves the current point to the given \a point, implicitly starting
659 a new subpath and closing the previous one.
661 \sa closeSubpath(), {QPainterPath#Composing a
662 QPainterPath}{Composing a QPainterPath}
664 void QPainterPath::moveTo(const QPointF &p)
667 printf("QPainterPath::moveTo() (%.2f,%.2f)\n", p.x(), p.y());
670 if (!qt_is_finite(p.x()) || !qt_is_finite(p.y())) {
672 qWarning("QPainterPath::moveTo: Adding point where x or y is NaN or Inf, ignoring call");
680 QPainterPathData *d = d_func();
681 Q_ASSERT(!d->elements.isEmpty());
683 d->require_moveTo = false;
685 if (d->elements.last().type == MoveToElement) {
686 d->elements.last().x = p.x();
687 d->elements.last().y = p.y();
689 Element elm = { p.x(), p.y(), MoveToElement };
690 d->elements.append(elm);
692 d->cStart = d->elements.size() - 1;
696 \fn void QPainterPath::lineTo(qreal x, qreal y)
700 Draws a line from the current position to the point (\a{x},
705 \fn void QPainterPath::lineTo(const QPointF &endPoint)
707 Adds a straight line from the current position to the given \a
708 endPoint. After the line is drawn, the current position is updated
709 to be at the end point of the line.
711 \sa addPolygon(), addRect(), {QPainterPath#Composing a
712 QPainterPath}{Composing a QPainterPath}
714 void QPainterPath::lineTo(const QPointF &p)
717 printf("QPainterPath::lineTo() (%.2f,%.2f)\n", p.x(), p.y());
720 if (!qt_is_finite(p.x()) || !qt_is_finite(p.y())) {
722 qWarning("QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call");
730 QPainterPathData *d = d_func();
731 Q_ASSERT(!d->elements.isEmpty());
733 if (p == QPointF(d->elements.last()))
735 Element elm = { p.x(), p.y(), LineToElement };
736 d->elements.append(elm);
738 d->convex = d->elements.size() == 3 || (d->elements.size() == 4 && d->isClosed());
742 \fn void QPainterPath::cubicTo(qreal c1X, qreal c1Y, qreal c2X,
743 qreal c2Y, qreal endPointX, qreal endPointY);
747 Adds a cubic Bezier curve between the current position and the end
748 point (\a{endPointX}, \a{endPointY}) with control points specified
749 by (\a{c1X}, \a{c1Y}) and (\a{c2X}, \a{c2Y}).
753 \fn void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &endPoint)
755 Adds a cubic Bezier curve between the current position and the
756 given \a endPoint using the control points specified by \a c1, and
759 After the curve is added, the current position is updated to be at
760 the end point of the curve.
764 \li \inlineimage qpainterpath-cubicto.png
766 \snippet code/src_gui_painting_qpainterpath.cpp 1
769 \sa quadTo(), {QPainterPath#Composing a QPainterPath}{Composing
772 void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &e)
775 printf("QPainterPath::cubicTo() (%.2f,%.2f), (%.2f,%.2f), (%.2f,%.2f)\n",
776 c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
779 if (!qt_is_finite(c1.x()) || !qt_is_finite(c1.y()) || !qt_is_finite(c2.x()) || !qt_is_finite(c2.y())
780 || !qt_is_finite(e.x()) || !qt_is_finite(e.y())) {
782 qWarning("QPainterPath::cubicTo: Adding point where x or y is NaN or Inf, ignoring call");
790 QPainterPathData *d = d_func();
791 Q_ASSERT(!d->elements.isEmpty());
794 // Abort on empty curve as a stroker cannot handle this and the
795 // curve is irrelevant anyway.
796 if (d->elements.last() == c1 && c1 == c2 && c2 == e)
801 Element ce1 = { c1.x(), c1.y(), CurveToElement };
802 Element ce2 = { c2.x(), c2.y(), CurveToDataElement };
803 Element ee = { e.x(), e.y(), CurveToDataElement };
804 d->elements << ce1 << ce2 << ee;
808 \fn void QPainterPath::quadTo(qreal cx, qreal cy, qreal endPointX, qreal endPointY);
812 Adds a quadratic Bezier curve between the current point and the endpoint
813 (\a{endPointX}, \a{endPointY}) with the control point specified by
818 \fn void QPainterPath::quadTo(const QPointF &c, const QPointF &endPoint)
820 Adds a quadratic Bezier curve between the current position and the
821 given \a endPoint with the control point specified by \a c.
823 After the curve is added, the current point is updated to be at
824 the end point of the curve.
826 \sa cubicTo(), {QPainterPath#Composing a QPainterPath}{Composing a
829 void QPainterPath::quadTo(const QPointF &c, const QPointF &e)
832 printf("QPainterPath::quadTo() (%.2f,%.2f), (%.2f,%.2f)\n",
833 c.x(), c.y(), e.x(), e.y());
836 if (!qt_is_finite(c.x()) || !qt_is_finite(c.y()) || !qt_is_finite(e.x()) || !qt_is_finite(e.y())) {
838 qWarning("QPainterPath::quadTo: Adding point where x or y is NaN or Inf, ignoring call");
847 Q_ASSERT(!d->elements.isEmpty());
848 const QPainterPath::Element &elm = d->elements.at(elementCount()-1);
849 QPointF prev(elm.x, elm.y);
851 // Abort on empty curve as a stroker cannot handle this and the
852 // curve is irrelevant anyway.
853 if (prev == c && c == e)
856 QPointF c1((prev.x() + 2*c.x()) / 3, (prev.y() + 2*c.y()) / 3);
857 QPointF c2((e.x() + 2*c.x()) / 3, (e.y() + 2*c.y()) / 3);
862 \fn void QPainterPath::arcTo(qreal x, qreal y, qreal width, qreal
863 height, qreal startAngle, qreal sweepLength)
867 Creates an arc that occupies the rectangle QRectF(\a x, \a y, \a
868 width, \a height), beginning at the specified \a startAngle and
869 extending \a sweepLength degrees counter-clockwise.
874 \fn void QPainterPath::arcTo(const QRectF &rectangle, qreal startAngle, qreal sweepLength)
876 Creates an arc that occupies the given \a rectangle, beginning at
877 the specified \a startAngle and extending \a sweepLength degrees
880 Angles are specified in degrees. Clockwise arcs can be specified
881 using negative angles.
883 Note that this function connects the starting point of the arc to
884 the current position if they are not already connected. After the
885 arc has been added, the current position is the last point in
886 arc. To draw a line back to the first point, use the
887 closeSubpath() function.
891 \li \inlineimage qpainterpath-arcto.png
893 \snippet code/src_gui_painting_qpainterpath.cpp 2
896 \sa arcMoveTo(), addEllipse(), QPainter::drawArc(), QPainter::drawPie(),
897 {QPainterPath#Composing a QPainterPath}{Composing a
900 void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength)
903 printf("QPainterPath::arcTo() (%.2f, %.2f, %.2f, %.2f, angle=%.2f, sweep=%.2f\n",
904 rect.x(), rect.y(), rect.width(), rect.height(), startAngle, sweepLength);
907 if ((!qt_is_finite(rect.x()) && !qt_is_finite(rect.y())) || !qt_is_finite(rect.width()) || !qt_is_finite(rect.height())
908 || !qt_is_finite(startAngle) || !qt_is_finite(sweepLength)) {
910 qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN or Inf, ignoring call");
923 QPointF curve_start = qt_curves_for_arc(rect, startAngle, sweepLength, pts, &point_count);
926 for (int i=0; i<point_count; i+=3) {
927 cubicTo(pts[i].x(), pts[i].y(),
928 pts[i+1].x(), pts[i+1].y(),
929 pts[i+2].x(), pts[i+2].y());
936 \fn void QPainterPath::arcMoveTo(qreal x, qreal y, qreal width, qreal height, qreal angle)
940 Creates a move to that lies on the arc that occupies the
941 QRectF(\a x, \a y, \a width, \a height) at \a angle.
946 \fn void QPainterPath::arcMoveTo(const QRectF &rectangle, qreal angle)
949 Creates a move to that lies on the arc that occupies the given \a
950 rectangle at \a angle.
952 Angles are specified in degrees. Clockwise arcs can be specified
953 using negative angles.
955 \sa moveTo(), arcTo()
958 void QPainterPath::arcMoveTo(const QRectF &rect, qreal angle)
964 qt_find_ellipse_coords(rect, angle, 0, &pt, 0);
971 \fn QPointF QPainterPath::currentPosition() const
973 Returns the current position of the path.
975 QPointF QPainterPath::currentPosition() const
977 return !d_ptr || d_func()->elements.isEmpty()
979 : QPointF(d_func()->elements.last().x, d_func()->elements.last().y);
984 \fn void QPainterPath::addRect(qreal x, qreal y, qreal width, qreal height)
988 Adds a rectangle at position (\a{x}, \a{y}), with the given \a
989 width and \a height, as a closed subpath.
993 \fn void QPainterPath::addRect(const QRectF &rectangle)
995 Adds the given \a rectangle to this path as a closed subpath.
997 The \a rectangle is added as a clockwise set of lines. The painter
998 path's current position after the \a rectangle has been added is
999 at the top-left corner of the rectangle.
1003 \li \inlineimage qpainterpath-addrectangle.png
1005 \snippet code/src_gui_painting_qpainterpath.cpp 3
1008 \sa addRegion(), lineTo(), {QPainterPath#Composing a
1009 QPainterPath}{Composing a QPainterPath}
1011 void QPainterPath::addRect(const QRectF &r)
1013 if (!qt_is_finite(r.x()) || !qt_is_finite(r.y()) || !qt_is_finite(r.width()) || !qt_is_finite(r.height())) {
1015 qWarning("QPainterPath::addRect: Adding rect where a parameter is NaN or Inf, ignoring call");
1026 bool first = d_func()->elements.size() < 2;
1028 d_func()->elements.reserve(d_func()->elements.size() + 5);
1029 moveTo(r.x(), r.y());
1031 Element l1 = { r.x() + r.width(), r.y(), LineToElement };
1032 Element l2 = { r.x() + r.width(), r.y() + r.height(), LineToElement };
1033 Element l3 = { r.x(), r.y() + r.height(), LineToElement };
1034 Element l4 = { r.x(), r.y(), LineToElement };
1036 d_func()->elements << l1 << l2 << l3 << l4;
1037 d_func()->require_moveTo = true;
1038 d_func()->convex = first;
1042 Adds the given \a polygon to the path as an (unclosed) subpath.
1044 Note that the current position after the polygon has been added,
1045 is the last point in \a polygon. To draw a line back to the first
1046 point, use the closeSubpath() function.
1050 \li \inlineimage qpainterpath-addpolygon.png
1052 \snippet code/src_gui_painting_qpainterpath.cpp 4
1055 \sa lineTo(), {QPainterPath#Composing a QPainterPath}{Composing
1058 void QPainterPath::addPolygon(const QPolygonF &polygon)
1060 if (polygon.isEmpty())
1066 d_func()->elements.reserve(d_func()->elements.size() + polygon.size());
1068 moveTo(polygon.first());
1069 for (int i=1; i<polygon.size(); ++i) {
1070 Element elm = { polygon.at(i).x(), polygon.at(i).y(), LineToElement };
1071 d_func()->elements << elm;
1076 \fn void QPainterPath::addEllipse(const QRectF &boundingRectangle)
1078 Creates an ellipse within the specified \a boundingRectangle
1079 and adds it to the painter path as a closed subpath.
1081 The ellipse is composed of a clockwise curve, starting and
1082 finishing at zero degrees (the 3 o'clock position).
1086 \li \inlineimage qpainterpath-addellipse.png
1088 \snippet code/src_gui_painting_qpainterpath.cpp 5
1091 \sa arcTo(), QPainter::drawEllipse(), {QPainterPath#Composing a
1092 QPainterPath}{Composing a QPainterPath}
1094 void QPainterPath::addEllipse(const QRectF &boundingRect)
1096 if (!qt_is_finite(boundingRect.x()) || !qt_is_finite(boundingRect.y())
1097 || !qt_is_finite(boundingRect.width()) || !qt_is_finite(boundingRect.height())) {
1099 qWarning("QPainterPath::addEllipse: Adding ellipse where a parameter is NaN or Inf, ignoring call");
1104 if (boundingRect.isNull())
1111 bool first = d_func()->elements.size() < 2;
1112 d->elements.reserve(d->elements.size() + 13);
1116 QPointF start = qt_curves_for_arc(boundingRect, 0, -360, pts, &point_count);
1119 cubicTo(pts[0], pts[1], pts[2]); // 0 -> 270
1120 cubicTo(pts[3], pts[4], pts[5]); // 270 -> 180
1121 cubicTo(pts[6], pts[7], pts[8]); // 180 -> 90
1122 cubicTo(pts[9], pts[10], pts[11]); // 90 - >0
1123 d_func()->require_moveTo = true;
1125 d_func()->convex = first;
1129 \fn void QPainterPath::addText(const QPointF &point, const QFont &font, const QString &text)
1131 Adds the given \a text to this path as a set of closed subpaths
1132 created from the \a font supplied. The subpaths are positioned so
1133 that the left end of the text's baseline lies at the specified \a
1138 \li \inlineimage qpainterpath-addtext.png
1140 \snippet code/src_gui_painting_qpainterpath.cpp 6
1143 \sa QPainter::drawText(), {QPainterPath#Composing a
1144 QPainterPath}{Composing a QPainterPath}
1146 void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &text)
1154 QTextLayout layout(text, f);
1155 layout.setCacheEnabled(true);
1156 QTextEngine *eng = layout.engine();
1157 layout.beginLayout();
1158 QTextLine line = layout.createLine();
1161 const QScriptLine &sl = eng->lines[0];
1162 if (!sl.length || !eng->layoutData)
1165 int nItems = eng->layoutData->items.size();
1170 QVarLengthArray<int> visualOrder(nItems);
1171 QVarLengthArray<uchar> levels(nItems);
1172 for (int i = 0; i < nItems; ++i)
1173 levels[i] = eng->layoutData->items[i].analysis.bidiLevel;
1174 QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
1176 for (int i = 0; i < nItems; ++i) {
1177 int item = visualOrder[i];
1178 QScriptItem &si = eng->layoutData->items[item];
1180 if (si.analysis.flags < QScriptAnalysis::TabOrObject) {
1181 QGlyphLayout glyphs = eng->shapedGlyphs(&si);
1182 QFontEngine *fe = f.d->engineForScript(si.analysis.script);
1184 fe->addOutlineToPath(x, y, glyphs, this,
1185 si.analysis.bidiLevel % 2
1186 ? QTextItem::RenderFlags(QTextItem::RightToLeft)
1187 : QTextItem::RenderFlags(0));
1189 const qreal lw = fe->lineThickness().toReal();
1190 if (f.d->underline) {
1191 qreal pos = fe->underlinePosition().toReal();
1192 addRect(x, y + pos, si.width.toReal(), lw);
1194 if (f.d->overline) {
1195 qreal pos = fe->ascent().toReal() + 1;
1196 addRect(x, y - pos, si.width.toReal(), lw);
1198 if (f.d->strikeOut) {
1199 qreal pos = fe->ascent().toReal() / 3;
1200 addRect(x, y - pos, si.width.toReal(), lw);
1203 x += si.width.toReal();
1208 \fn void QPainterPath::addPath(const QPainterPath &path)
1210 Adds the given \a path to \e this path as a closed subpath.
1212 \sa connectPath(), {QPainterPath#Composing a
1213 QPainterPath}{Composing a QPainterPath}
1215 void QPainterPath::addPath(const QPainterPath &other)
1217 if (other.isEmpty())
1223 QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
1224 // Remove last moveto so we don't get multiple moveto's
1225 if (d->elements.last().type == MoveToElement)
1226 d->elements.remove(d->elements.size()-1);
1228 // Locate where our own current subpath will start after the other path is added.
1229 int cStart = d->elements.size() + other.d_func()->cStart;
1230 d->elements += other.d_func()->elements;
1233 d->require_moveTo = other.d_func()->isClosed();
1238 \fn void QPainterPath::connectPath(const QPainterPath &path)
1240 Connects the given \a path to \e this path by adding a line from the
1241 last element of this path to the first element of the given path.
1243 \sa addPath(), {QPainterPath#Composing a QPainterPath}{Composing
1246 void QPainterPath::connectPath(const QPainterPath &other)
1248 if (other.isEmpty())
1254 QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
1255 // Remove last moveto so we don't get multiple moveto's
1256 if (d->elements.last().type == MoveToElement)
1257 d->elements.remove(d->elements.size()-1);
1259 // Locate where our own current subpath will start after the other path is added.
1260 int cStart = d->elements.size() + other.d_func()->cStart;
1261 int first = d->elements.size();
1262 d->elements += other.d_func()->elements;
1265 d->elements[first].type = LineToElement;
1267 // avoid duplicate points
1268 if (first > 0 && QPointF(d->elements[first]) == QPointF(d->elements[first - 1])) {
1269 d->elements.remove(first--);
1273 if (cStart != first)
1278 Adds the given \a region to the path by adding each rectangle in
1279 the region as a separate closed subpath.
1281 \sa addRect(), {QPainterPath#Composing a QPainterPath}{Composing
1284 void QPainterPath::addRegion(const QRegion ®ion)
1289 QVector<QRect> rects = region.rects();
1290 d_func()->elements.reserve(rects.size() * 5);
1291 for (int i=0; i<rects.size(); ++i)
1292 addRect(rects.at(i));
1297 Returns the painter path's currently set fill rule.
1301 Qt::FillRule QPainterPath::fillRule() const
1303 return isEmpty() ? Qt::OddEvenFill : d_func()->fillRule;
1307 \fn void QPainterPath::setFillRule(Qt::FillRule fillRule)
1309 Sets the fill rule of the painter path to the given \a
1310 fillRule. Qt provides two methods for filling paths:
1314 \li Qt::OddEvenFill (default)
1317 \li \inlineimage qt-fillrule-oddeven.png
1318 \li \inlineimage qt-fillrule-winding.png
1323 void QPainterPath::setFillRule(Qt::FillRule fillRule)
1326 if (d_func()->fillRule == fillRule)
1330 d_func()->fillRule = fillRule;
1333 #define QT_BEZIER_A(bezier, coord) 3 * (-bezier.coord##1 \
1334 + 3*bezier.coord##2 \
1335 - 3*bezier.coord##3 \
1338 #define QT_BEZIER_B(bezier, coord) 6 * (bezier.coord##1 \
1339 - 2*bezier.coord##2 \
1342 #define QT_BEZIER_C(bezier, coord) 3 * (- bezier.coord##1 \
1345 #define QT_BEZIER_CHECK_T(bezier, t) \
1346 if (t >= 0 && t <= 1) { \
1347 QPointF p(b.pointAt(t)); \
1348 if (p.x() < minx) minx = p.x(); \
1349 else if (p.x() > maxx) maxx = p.x(); \
1350 if (p.y() < miny) miny = p.y(); \
1351 else if (p.y() > maxy) maxy = p.y(); \
1355 static QRectF qt_painterpath_bezier_extrema(const QBezier &b)
1357 qreal minx, miny, maxx, maxy;
1359 // initialize with end points
1375 // Update for the X extrema
1377 qreal ax = QT_BEZIER_A(b, x);
1378 qreal bx = QT_BEZIER_B(b, x);
1379 qreal cx = QT_BEZIER_C(b, x);
1380 // specialcase quadratic curves to avoid div by zero
1381 if (qFuzzyIsNull(ax)) {
1383 // linear curves are covered by initialization.
1384 if (!qFuzzyIsNull(bx)) {
1386 QT_BEZIER_CHECK_T(b, t);
1390 const qreal tx = bx * bx - 4 * ax * cx;
1393 qreal temp = qSqrt(tx);
1394 qreal rcp = 1 / (2 * ax);
1395 qreal t1 = (-bx + temp) * rcp;
1396 QT_BEZIER_CHECK_T(b, t1);
1398 qreal t2 = (-bx - temp) * rcp;
1399 QT_BEZIER_CHECK_T(b, t2);
1404 // Update for the Y extrema
1406 qreal ay = QT_BEZIER_A(b, y);
1407 qreal by = QT_BEZIER_B(b, y);
1408 qreal cy = QT_BEZIER_C(b, y);
1410 // specialcase quadratic curves to avoid div by zero
1411 if (qFuzzyIsNull(ay)) {
1413 // linear curves are covered by initialization.
1414 if (!qFuzzyIsNull(by)) {
1416 QT_BEZIER_CHECK_T(b, t);
1420 const qreal ty = by * by - 4 * ay * cy;
1423 qreal temp = qSqrt(ty);
1424 qreal rcp = 1 / (2 * ay);
1425 qreal t1 = (-by + temp) * rcp;
1426 QT_BEZIER_CHECK_T(b, t1);
1428 qreal t2 = (-by - temp) * rcp;
1429 QT_BEZIER_CHECK_T(b, t2);
1433 return QRectF(minx, miny, maxx - minx, maxy - miny);
1437 Returns the bounding rectangle of this painter path as a rectangle with
1438 floating point precision.
1440 \sa controlPointRect()
1442 QRectF QPainterPath::boundingRect() const
1446 QPainterPathData *d = d_func();
1449 computeBoundingRect();
1454 Returns the rectangle containing all the points and control points
1457 This function is significantly faster to compute than the exact
1458 boundingRect(), and the returned rectangle is always a superset of
1459 the rectangle returned by boundingRect().
1463 QRectF QPainterPath::controlPointRect() const
1467 QPainterPathData *d = d_func();
1469 if (d->dirtyControlBounds)
1470 computeControlPointRect();
1471 return d->controlBounds;
1476 \fn bool QPainterPath::isEmpty() const
1478 Returns true if either there are no elements in this path, or if the only
1479 element is a MoveToElement; otherwise returns false.
1484 bool QPainterPath::isEmpty() const
1486 return !d_ptr || (d_ptr->elements.size() == 1 && d_ptr->elements.first().type == MoveToElement);
1490 Creates and returns a reversed copy of the path.
1492 It is the order of the elements that is reversed: If a
1493 QPainterPath is composed by calling the moveTo(), lineTo() and
1494 cubicTo() functions in the specified order, the reversed copy is
1495 composed by calling cubicTo(), lineTo() and moveTo().
1497 QPainterPath QPainterPath::toReversed() const
1499 Q_D(const QPainterPath);
1507 rev.moveTo(d->elements.at(d->elements.size()-1).x, d->elements.at(d->elements.size()-1).y);
1509 for (int i=d->elements.size()-1; i>=1; --i) {
1510 const QPainterPath::Element &elm = d->elements.at(i);
1511 const QPainterPath::Element &prev = d->elements.at(i-1);
1514 rev.lineTo(prev.x, prev.y);
1517 rev.moveTo(prev.x, prev.y);
1519 case CurveToDataElement:
1522 const QPainterPath::Element &cp1 = d->elements.at(i-2);
1523 const QPainterPath::Element &sp = d->elements.at(i-3);
1524 Q_ASSERT(prev.type == CurveToDataElement);
1525 Q_ASSERT(cp1.type == CurveToElement);
1526 rev.cubicTo(prev.x, prev.y, cp1.x, cp1.y, sp.x, sp.y);
1531 Q_ASSERT(!"qt_reversed_path");
1535 //qt_debug_path(rev);
1540 Converts the path into a list of polygons using the QTransform
1541 \a matrix, and returns the list.
1543 This function creates one polygon for each subpath regardless of
1544 intersecting subpaths (i.e. overlapping bounding rectangles). To
1545 make sure that such overlapping subpaths are filled correctly, use
1546 the toFillPolygons() function instead.
1548 \sa toFillPolygons(), toFillPolygon(), {QPainterPath#QPainterPath
1549 Conversion}{QPainterPath Conversion}
1551 QList<QPolygonF> QPainterPath::toSubpathPolygons(const QTransform &matrix) const
1554 Q_D(const QPainterPath);
1555 QList<QPolygonF> flatCurves;
1560 for (int i=0; i<elementCount(); ++i) {
1561 const QPainterPath::Element &e = d->elements.at(i);
1563 case QPainterPath::MoveToElement:
1564 if (current.size() > 1)
1565 flatCurves += current;
1567 current.reserve(16);
1568 current += QPointF(e.x, e.y) * matrix;
1570 case QPainterPath::LineToElement:
1571 current += QPointF(e.x, e.y) * matrix;
1573 case QPainterPath::CurveToElement: {
1574 Q_ASSERT(d->elements.at(i+1).type == QPainterPath::CurveToDataElement);
1575 Q_ASSERT(d->elements.at(i+2).type == QPainterPath::CurveToDataElement);
1576 QBezier bezier = QBezier::fromPoints(QPointF(d->elements.at(i-1).x, d->elements.at(i-1).y) * matrix,
1577 QPointF(e.x, e.y) * matrix,
1578 QPointF(d->elements.at(i+1).x, d->elements.at(i+1).y) * matrix,
1579 QPointF(d->elements.at(i+2).x, d->elements.at(i+2).y) * matrix);
1580 bezier.addToPolygon(¤t);
1584 case QPainterPath::CurveToDataElement:
1585 Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
1590 if (current.size()>1)
1591 flatCurves += current;
1599 QList<QPolygonF> QPainterPath::toSubpathPolygons(const QMatrix &matrix) const
1601 return toSubpathPolygons(QTransform(matrix));
1605 Converts the path into a list of polygons using the
1606 QTransform \a matrix, and returns the list.
1608 The function differs from the toFillPolygon() function in that it
1609 creates several polygons. It is provided because it is usually
1610 faster to draw several small polygons than to draw one large
1611 polygon, even though the total number of points drawn is the same.
1613 The toFillPolygons() function differs from the toSubpathPolygons()
1614 function in that it create only polygon for subpaths that have
1615 overlapping bounding rectangles.
1617 Like the toFillPolygon() function, this function uses a rewinding
1618 technique to make sure that overlapping subpaths can be filled
1619 using the correct fill rule. Note that rewinding inserts addition
1620 lines in the polygons so the outline of the fill polygon does not
1621 match the outline of the path.
1623 \sa toSubpathPolygons(), toFillPolygon(),
1624 {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
1626 QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
1629 QList<QPolygonF> polys;
1631 QList<QPolygonF> subpaths = toSubpathPolygons(matrix);
1632 int count = subpaths.size();
1637 QList<QRectF> bounds;
1638 for (int i=0; i<count; ++i)
1639 bounds += subpaths.at(i).boundingRect();
1641 #ifdef QPP_FILLPOLYGONS_DEBUG
1642 printf("QPainterPath::toFillPolygons, subpathCount=%d\n", count);
1643 for (int i=0; i<bounds.size(); ++i)
1644 qDebug() << " bounds" << i << bounds.at(i);
1647 QVector< QList<int> > isects;
1648 isects.resize(count);
1650 // find all intersections
1651 for (int j=0; j<count; ++j) {
1652 if (subpaths.at(j).size() <= 2)
1654 QRectF cbounds = bounds.at(j);
1655 for (int i=0; i<count; ++i) {
1656 if (cbounds.intersects(bounds.at(i))) {
1662 #ifdef QPP_FILLPOLYGONS_DEBUG
1663 printf("Intersections before flattening:\n");
1664 for (int i = 0; i < count; ++i) {
1666 for (int j = 0; j < isects[i].size(); ++j) {
1667 printf("%d ", isects[i][j]);
1673 // flatten the sets of intersections
1674 for (int i=0; i<count; ++i) {
1675 const QList<int> ¤t_isects = isects.at(i);
1676 for (int j=0; j<current_isects.size(); ++j) {
1677 int isect_j = current_isects.at(j);
1680 for (int k=0; k<isects[isect_j].size(); ++k) {
1681 int isect_k = isects[isect_j][k];
1682 if (isect_k != i && !isects.at(i).contains(isect_k)) {
1683 isects[i] += isect_k;
1686 isects[isect_j].clear();
1690 #ifdef QPP_FILLPOLYGONS_DEBUG
1691 printf("Intersections after flattening:\n");
1692 for (int i = 0; i < count; ++i) {
1694 for (int j = 0; j < isects[i].size(); ++j) {
1695 printf("%d ", isects[i][j]);
1701 // Join the intersected subpaths as rewinded polygons
1702 for (int i=0; i<count; ++i) {
1703 const QList<int> &subpath_list = isects[i];
1704 if (!subpath_list.isEmpty()) {
1706 for (int j=0; j<subpath_list.size(); ++j) {
1707 const QPolygonF &subpath = subpaths.at(subpath_list.at(j));
1709 if (!subpath.isClosed())
1710 buildUp += subpath.first();
1711 if (!buildUp.isClosed())
1712 buildUp += buildUp.first();
1724 QList<QPolygonF> QPainterPath::toFillPolygons(const QMatrix &matrix) const
1726 return toFillPolygons(QTransform(matrix));
1729 //same as qt_polygon_isect_line in qpolygon.cpp
1730 static void qt_painterpath_isect_line(const QPointF &p1,
1743 if (qFuzzyCompare(y1, y2)) {
1744 // ignore horizontal lines according to scan conversion rule
1746 } else if (y2 < y1) {
1747 qreal x_tmp = x2; x2 = x1; x1 = x_tmp;
1748 qreal y_tmp = y2; y2 = y1; y1 = y_tmp;
1752 if (y >= y1 && y < y2) {
1753 qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1);
1755 // count up the winding number if we're
1762 static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
1763 int *winding, int depth = 0)
1767 QRectF bounds = bezier.bounds();
1769 // potential intersection, divide and try again...
1770 // Please note that a sideeffect of the bottom exclusion is that
1771 // horizontal lines are dropped, but this is correct according to
1772 // scan conversion rules.
1773 if (y >= bounds.y() && y < bounds.y() + bounds.height()) {
1775 // hit lower limit... This is a rough threshold, but its a
1776 // tradeoff between speed and precision.
1777 const qreal lower_bound = qreal(.001);
1778 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) {
1779 // We make the assumption here that the curve starts to
1780 // approximate a line after while (i.e. that it doesn't
1781 // change direction drastically during its slope)
1782 if (bezier.pt1().x() <= x) {
1783 (*winding) += (bezier.pt4().y() > bezier.pt1().y() ? 1 : -1);
1788 // split curve and try again...
1789 QBezier first_half, second_half;
1790 bezier.split(&first_half, &second_half);
1791 qt_painterpath_isect_curve(first_half, pt, winding, depth + 1);
1792 qt_painterpath_isect_curve(second_half, pt, winding, depth + 1);
1797 \fn bool QPainterPath::contains(const QPointF &point) const
1799 Returns true if the given \a point is inside the path, otherwise
1804 bool QPainterPath::contains(const QPointF &pt) const
1806 if (isEmpty() || !controlPointRect().contains(pt))
1809 QPainterPathData *d = d_func();
1811 int winding_number = 0;
1815 for (int i=0; i<d->elements.size(); ++i) {
1816 const Element &e = d->elements.at(i);
1821 if (i > 0) // implicitly close all paths.
1822 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1823 last_start = last_pt = e;
1827 qt_painterpath_isect_line(last_pt, e, pt, &winding_number);
1831 case CurveToElement:
1833 const QPainterPath::Element &cp2 = d->elements.at(++i);
1834 const QPainterPath::Element &ep = d->elements.at(++i);
1835 qt_painterpath_isect_curve(QBezier::fromPoints(last_pt, e, cp2, ep),
1836 pt, &winding_number);
1847 // implicitly close last subpath
1848 if (last_pt != last_start)
1849 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1851 return (d->fillRule == Qt::WindingFill
1852 ? (winding_number != 0)
1853 : ((winding_number % 2) != 0));
1856 static bool qt_painterpath_isect_line_rect(qreal x1, qreal y1, qreal x2, qreal y2,
1859 qreal left = rect.left();
1860 qreal right = rect.right();
1861 qreal top = rect.top();
1862 qreal bottom = rect.bottom();
1864 enum { Left, Right, Top, Bottom };
1865 // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html
1866 int p1 = ((x1 < left) << Left)
1867 | ((x1 > right) << Right)
1868 | ((y1 < top) << Top)
1869 | ((y1 > bottom) << Bottom);
1870 int p2 = ((x2 < left) << Left)
1871 | ((x2 > right) << Right)
1872 | ((y2 < top) << Top)
1873 | ((y2 > bottom) << Bottom);
1876 // completely inside
1883 // clip x coordinates
1885 y1 += dy/dx * (left - x1);
1887 } else if (x1 > right) {
1888 y1 -= dy/dx * (x1 - right);
1892 y2 += dy/dx * (left - x2);
1894 } else if (x2 > right) {
1895 y2 -= dy/dx * (x2 - right);
1899 p1 = ((y1 < top) << Top)
1900 | ((y1 > bottom) << Bottom);
1901 p2 = ((y2 < top) << Top)
1902 | ((y2 > bottom) << Bottom);
1907 // clip y coordinates
1909 x1 += dx/dy * (top - y1);
1911 } else if (y1 > bottom) {
1912 x1 -= dx/dy * (y1 - bottom);
1916 x2 += dx/dy * (top - y2);
1918 } else if (y2 > bottom) {
1919 x2 -= dx/dy * (y2 - bottom);
1923 p1 = ((x1 < left) << Left)
1924 | ((x1 > right) << Right);
1925 p2 = ((x2 < left) << Left)
1926 | ((x2 > right) << Right);
1936 static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2, int depth = 0)
1938 QRectF bounds = bezier.bounds();
1940 if (y >= bounds.top() && y < bounds.bottom()
1941 && bounds.right() >= x1 && bounds.left() < x2) {
1942 const qreal lower_bound = qreal(.01);
1943 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
1946 QBezier first_half, second_half;
1947 bezier.split(&first_half, &second_half);
1948 if (qt_isect_curve_horizontal(first_half, y, x1, x2, depth + 1)
1949 || qt_isect_curve_horizontal(second_half, y, x1, x2, depth + 1))
1955 static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2, int depth = 0)
1957 QRectF bounds = bezier.bounds();
1959 if (x >= bounds.left() && x < bounds.right()
1960 && bounds.bottom() >= y1 && bounds.top() < y2) {
1961 const qreal lower_bound = qreal(.01);
1962 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
1965 QBezier first_half, second_half;
1966 bezier.split(&first_half, &second_half);
1967 if (qt_isect_curve_vertical(first_half, x, y1, y2, depth + 1)
1968 || qt_isect_curve_vertical(second_half, x, y1, y2, depth + 1))
1975 Returns true if any lines or curves cross the four edges in of rect
1977 static bool qt_painterpath_check_crossing(const QPainterPath *path, const QRectF &rect)
1981 for (int i=0; i<path->elementCount(); ++i) {
1982 const QPainterPath::Element &e = path->elementAt(i);
1986 case QPainterPath::MoveToElement:
1988 && qFuzzyCompare(last_pt.x(), last_start.x())
1989 && qFuzzyCompare(last_pt.y(), last_start.y())
1990 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
1991 last_start.x(), last_start.y(), rect))
1993 last_start = last_pt = e;
1996 case QPainterPath::LineToElement:
1997 if (qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), e.x, e.y, rect))
2002 case QPainterPath::CurveToElement:
2004 QPointF cp2 = path->elementAt(++i);
2005 QPointF ep = path->elementAt(++i);
2006 QBezier bezier = QBezier::fromPoints(last_pt, e, cp2, ep);
2007 if (qt_isect_curve_horizontal(bezier, rect.top(), rect.left(), rect.right())
2008 || qt_isect_curve_horizontal(bezier, rect.bottom(), rect.left(), rect.right())
2009 || qt_isect_curve_vertical(bezier, rect.left(), rect.top(), rect.bottom())
2010 || qt_isect_curve_vertical(bezier, rect.right(), rect.top(), rect.bottom()))
2021 // implicitly close last subpath
2022 if (last_pt != last_start
2023 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
2024 last_start.x(), last_start.y(), rect))
2031 \fn bool QPainterPath::intersects(const QRectF &rectangle) const
2033 Returns true if any point in the given \a rectangle intersects the
2034 path; otherwise returns false.
2036 There is an intersection if any of the lines making up the
2037 rectangle crosses a part of the path or if any part of the
2038 rectangle overlaps with any area enclosed by the path. This
2039 function respects the current fillRule to determine what is
2040 considered inside the path.
2044 bool QPainterPath::intersects(const QRectF &rect) const
2046 if (elementCount() == 1 && rect.contains(elementAt(0)))
2052 QRectF cp = controlPointRect();
2053 QRectF rn = rect.normalized();
2055 // QRectF::intersects returns false if one of the rects is a null rect
2056 // which would happen for a painter path consisting of a vertical or
2058 if (qMax(rn.left(), cp.left()) > qMin(rn.right(), cp.right())
2059 || qMax(rn.top(), cp.top()) > qMin(rn.bottom(), cp.bottom()))
2062 // If any path element cross the rect its bound to be an intersection
2063 if (qt_painterpath_check_crossing(this, rect))
2066 if (contains(rect.center()))
2071 // Check if the rectangle surounds any subpath...
2072 for (int i=0; i<d->elements.size(); ++i) {
2073 const Element &e = d->elements.at(i);
2074 if (e.type == QPainterPath::MoveToElement && rect.contains(e))
2082 Translates all elements in the path by (\a{dx}, \a{dy}).
2087 void QPainterPath::translate(qreal dx, qreal dy)
2089 if (!d_ptr || (dx == 0 && dy == 0))
2092 int elementsLeft = d_ptr->elements.size();
2093 if (elementsLeft <= 0)
2097 QPainterPath::Element *element = d_func()->elements.data();
2099 while (elementsLeft--) {
2107 \fn void QPainterPath::translate(const QPointF &offset)
2111 Translates all elements in the path by the given \a offset.
2117 Returns a copy of the path that is translated by (\a{dx}, \a{dy}).
2122 QPainterPath QPainterPath::translated(qreal dx, qreal dy) const
2124 QPainterPath copy(*this);
2125 copy.translate(dx, dy);
2130 \fn QPainterPath QPainterPath::translated(const QPointF &offset) const;
2134 Returns a copy of the path that is translated by the given \a offset.
2140 \fn bool QPainterPath::contains(const QRectF &rectangle) const
2142 Returns true if the given \a rectangle is inside the path,
2143 otherwise returns false.
2145 bool QPainterPath::contains(const QRectF &rect) const
2149 // the path is empty or the control point rect doesn't completely
2150 // cover the rectangle we abort stratight away.
2151 if (isEmpty() || !controlPointRect().contains(rect))
2154 // if there are intersections, chances are that the rect is not
2155 // contained, except if we have winding rule, in which case it
2157 if (qt_painterpath_check_crossing(this, rect)) {
2158 if (fillRule() == Qt::OddEvenFill) {
2161 // Do some wague sampling in the winding case. This is not
2162 // precise but it should mostly be good enough.
2163 if (!contains(rect.topLeft()) ||
2164 !contains(rect.topRight()) ||
2165 !contains(rect.bottomRight()) ||
2166 !contains(rect.bottomLeft()))
2171 // If there exists a point inside that is not part of the path its
2172 // because: rectangle lies completely outside path or a subpath
2173 // excludes parts of the rectangle. Both cases mean that the rect
2175 if (!contains(rect.center()))
2178 // If there are any subpaths inside this rectangle we need to
2179 // check if they are still contained as a result of the fill
2180 // rule. This can only be the case for WindingFill though. For
2181 // OddEvenFill the rect will never be contained if it surrounds a
2182 // subpath. (the case where two subpaths are completely identical
2183 // can be argued but we choose to neglect it).
2184 for (int i=0; i<d->elements.size(); ++i) {
2185 const Element &e = d->elements.at(i);
2186 if (e.type == QPainterPath::MoveToElement && rect.contains(e)) {
2187 if (fillRule() == Qt::OddEvenFill)
2191 for (; !stop && i<d->elements.size(); ++i) {
2192 const Element &el = d->elements.at(i);
2201 case CurveToElement:
2202 if (!contains(d->elements.at(i+2)))
2211 // compensate for the last ++i in the inner for
2219 static inline bool epsilonCompare(const QPointF &a, const QPointF &b, const QSizeF &epsilon)
2221 return qAbs(a.x() - b.x()) <= epsilon.width()
2222 && qAbs(a.y() - b.y()) <= epsilon.height();
2226 Returns true if this painterpath is equal to the given \a path.
2228 Note that comparing paths may involve a per element comparison
2229 which can be slow for complex paths.
2234 bool QPainterPath::operator==(const QPainterPath &path) const
2236 QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
2237 if (path.d_func() == d)
2239 else if (!d || !path.d_func())
2241 else if (d->fillRule != path.d_func()->fillRule)
2243 else if (d->elements.size() != path.d_func()->elements.size())
2246 const qreal qt_epsilon = sizeof(qreal) == sizeof(double) ? 1e-12 : qreal(1e-5);
2248 QSizeF epsilon = boundingRect().size();
2249 epsilon.rwidth() *= qt_epsilon;
2250 epsilon.rheight() *= qt_epsilon;
2252 for (int i = 0; i < d->elements.size(); ++i)
2253 if (d->elements.at(i).type != path.d_func()->elements.at(i).type
2254 || !epsilonCompare(d->elements.at(i), path.d_func()->elements.at(i), epsilon))
2261 Returns true if this painter path differs from the given \a path.
2263 Note that comparing paths may involve a per element comparison
2264 which can be slow for complex paths.
2269 bool QPainterPath::operator!=(const QPainterPath &path) const
2271 return !(*this==path);
2277 Returns the intersection of this path and the \a other path.
2279 \sa intersected(), operator&=(), united(), operator|()
2281 QPainterPath QPainterPath::operator&(const QPainterPath &other) const
2283 return intersected(other);
2289 Returns the union of this path and the \a other path.
2291 \sa united(), operator|=(), intersected(), operator&()
2293 QPainterPath QPainterPath::operator|(const QPainterPath &other) const
2295 return united(other);
2301 Returns the union of this path and the \a other path. This function is equivalent
2304 \sa united(), operator+=(), operator-()
2306 QPainterPath QPainterPath::operator+(const QPainterPath &other) const
2308 return united(other);
2314 Subtracts the \a other path from a copy of this path, and returns the copy.
2316 \sa subtracted(), operator-=(), operator+()
2318 QPainterPath QPainterPath::operator-(const QPainterPath &other) const
2320 return subtracted(other);
2326 Intersects this path with \a other and returns a reference to this path.
2328 \sa intersected(), operator&(), operator|=()
2330 QPainterPath &QPainterPath::operator&=(const QPainterPath &other)
2332 return *this = (*this & other);
2338 Unites this path with \a other and returns a reference to this path.
2340 \sa united(), operator|(), operator&=()
2342 QPainterPath &QPainterPath::operator|=(const QPainterPath &other)
2344 return *this = (*this | other);
2350 Unites this path with \a other, and returns a reference to this path. This
2351 is equivalent to operator|=().
2353 \sa united(), operator+(), operator-=()
2355 QPainterPath &QPainterPath::operator+=(const QPainterPath &other)
2357 return *this = (*this + other);
2363 Subtracts \a other from this path, and returns a reference to this
2366 \sa subtracted(), operator-(), operator+=()
2368 QPainterPath &QPainterPath::operator-=(const QPainterPath &other)
2370 return *this = (*this - other);
2373 #ifndef QT_NO_DATASTREAM
2375 \fn QDataStream &operator<<(QDataStream &stream, const QPainterPath &path)
2376 \relates QPainterPath
2378 Writes the given painter \a path to the given \a stream, and
2379 returns a reference to the \a stream.
2381 \sa {Serializing Qt Data Types}
2383 QDataStream &operator<<(QDataStream &s, const QPainterPath &p)
2390 s << p.elementCount();
2391 for (int i=0; i < p.d_func()->elements.size(); ++i) {
2392 const QPainterPath::Element &e = p.d_func()->elements.at(i);
2394 s << double(e.x) << double(e.y);
2396 s << p.d_func()->cStart;
2397 s << int(p.d_func()->fillRule);
2402 \fn QDataStream &operator>>(QDataStream &stream, QPainterPath &path)
2403 \relates QPainterPath
2405 Reads a painter path from the given \a stream into the specified \a path,
2406 and returns a reference to the \a stream.
2408 \sa {Serializing Qt Data Types}
2410 QDataStream &operator>>(QDataStream &s, QPainterPath &p)
2418 p.ensureData(); // in case if p.d_func() == 0
2419 if (p.d_func()->elements.size() == 1) {
2420 Q_ASSERT(p.d_func()->elements.at(0).type == QPainterPath::MoveToElement);
2421 p.d_func()->elements.clear();
2423 p.d_func()->elements.reserve(p.d_func()->elements.size() + size);
2424 for (int i=0; i<size; ++i) {
2430 Q_ASSERT(type >= 0 && type <= 3);
2431 if (!qt_is_finite(x) || !qt_is_finite(y)) {
2433 qWarning("QDataStream::operator>>: NaN or Inf element found in path, skipping it");
2437 QPainterPath::Element elm = { qreal(x), qreal(y), QPainterPath::ElementType(type) };
2438 p.d_func()->elements.append(elm);
2440 s >> p.d_func()->cStart;
2443 Q_ASSERT(fillRule == Qt::OddEvenFill || Qt::WindingFill);
2444 p.d_func()->fillRule = Qt::FillRule(fillRule);
2445 p.d_func()->dirtyBounds = true;
2446 p.d_func()->dirtyControlBounds = true;
2449 #endif // QT_NO_DATASTREAM
2452 /*******************************************************************************
2453 * class QPainterPathStroker
2456 void qt_path_stroke_move_to(qfixed x, qfixed y, void *data)
2458 ((QPainterPath *) data)->moveTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
2461 void qt_path_stroke_line_to(qfixed x, qfixed y, void *data)
2463 ((QPainterPath *) data)->lineTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
2466 void qt_path_stroke_cubic_to(qfixed c1x, qfixed c1y,
2467 qfixed c2x, qfixed c2y,
2468 qfixed ex, qfixed ey,
2471 ((QPainterPath *) data)->cubicTo(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y),
2472 qt_fixed_to_real(c2x), qt_fixed_to_real(c2y),
2473 qt_fixed_to_real(ex), qt_fixed_to_real(ey));
2478 \class QPainterPathStroker
2481 \brief The QPainterPathStroker class is used to generate fillable
2482 outlines for a given painter path.
2484 By calling the createStroke() function, passing a given
2485 QPainterPath as argument, a new painter path representing the
2486 outline of the given path is created. The newly created painter
2487 path can then be filled to draw the original painter path's
2490 You can control the various design aspects (width, cap styles,
2491 join styles and dash pattern) of the outlining using the following
2498 \li setDashPattern()
2501 The setDashPattern() function accepts both a Qt::PenStyle object
2502 and a vector representation of the pattern as argument.
2504 In addition you can specify a curve's threshold, controlling the
2505 granularity with which a curve is drawn, using the
2506 setCurveThreshold() function. The default threshold is a well
2507 adjusted value (0.25), and normally you should not need to modify
2508 it. However, you can make the curve's appearance smoother by
2509 decreasing its value.
2511 You can also control the miter limit for the generated outline
2512 using the setMiterLimit() function. The miter limit describes how
2513 far from each join the miter join can extend. The limit is
2514 specified in the units of width so the pixelwise miter limit will
2515 be \c {miterlimit * width}. This value is only used if the join
2516 style is Qt::MiterJoin.
2518 The painter path generated by the createStroke() function should
2519 only be used for outlining the given painter path. Otherwise it
2520 may cause unexpected behavior. Generated outlines also require the
2521 Qt::WindingFill rule which is set by default.
2526 QPainterPathStrokerPrivate::QPainterPathStrokerPrivate()
2529 stroker.setMoveToHook(qt_path_stroke_move_to);
2530 stroker.setLineToHook(qt_path_stroke_line_to);
2531 stroker.setCubicToHook(qt_path_stroke_cubic_to);
2535 Creates a new stroker.
2537 QPainterPathStroker::QPainterPathStroker()
2538 : d_ptr(new QPainterPathStrokerPrivate)
2543 Destroys the stroker.
2545 QPainterPathStroker::~QPainterPathStroker()
2551 Generates a new path that is a fillable area representing the
2552 outline of the given \a path.
2554 The various design aspects of the outline are based on the
2555 stroker's properties: width(), capStyle(), joinStyle(),
2556 dashPattern(), curveThreshold() and miterLimit().
2558 The generated path should only be used for outlining the given
2559 painter path. Otherwise it may cause unexpected
2560 behavior. Generated outlines also require the Qt::WindingFill rule
2561 which is set by default.
2563 QPainterPath QPainterPathStroker::createStroke(const QPainterPath &path) const
2565 QPainterPathStrokerPrivate *d = const_cast<QPainterPathStrokerPrivate *>(d_func());
2566 QPainterPath stroke;
2569 if (d->dashPattern.isEmpty()) {
2570 d->stroker.strokePath(path, &stroke, QTransform());
2572 QDashStroker dashStroker(&d->stroker);
2573 dashStroker.setDashPattern(d->dashPattern);
2574 dashStroker.setDashOffset(d->dashOffset);
2575 dashStroker.setClipRect(d->stroker.clipRect());
2576 dashStroker.strokePath(path, &stroke, QTransform());
2578 stroke.setFillRule(Qt::WindingFill);
2583 Sets the width of the generated outline painter path to \a width.
2585 The generated outlines will extend approximately 50% of \a width
2586 to each side of the given input path's original outline.
2588 void QPainterPathStroker::setWidth(qreal width)
2590 Q_D(QPainterPathStroker);
2593 d->stroker.setStrokeWidth(qt_real_to_fixed(width));
2597 Returns the width of the generated outlines.
2599 qreal QPainterPathStroker::width() const
2601 return qt_fixed_to_real(d_func()->stroker.strokeWidth());
2606 Sets the cap style of the generated outlines to \a style. If a
2607 dash pattern is set, each segment of the pattern is subject to the
2610 void QPainterPathStroker::setCapStyle(Qt::PenCapStyle style)
2612 d_func()->stroker.setCapStyle(style);
2617 Returns the cap style of the generated outlines.
2619 Qt::PenCapStyle QPainterPathStroker::capStyle() const
2621 return d_func()->stroker.capStyle();
2625 Sets the join style of the generated outlines to \a style.
2627 void QPainterPathStroker::setJoinStyle(Qt::PenJoinStyle style)
2629 d_func()->stroker.setJoinStyle(style);
2633 Returns the join style of the generated outlines.
2635 Qt::PenJoinStyle QPainterPathStroker::joinStyle() const
2637 return d_func()->stroker.joinStyle();
2641 Sets the miter limit of the generated outlines to \a limit.
2643 The miter limit describes how far from each join the miter join
2644 can extend. The limit is specified in units of the currently set
2645 width. So the pixelwise miter limit will be \c { miterlimit *
2648 This value is only used if the join style is Qt::MiterJoin.
2650 void QPainterPathStroker::setMiterLimit(qreal limit)
2652 d_func()->stroker.setMiterLimit(qt_real_to_fixed(limit));
2656 Returns the miter limit for the generated outlines.
2658 qreal QPainterPathStroker::miterLimit() const
2660 return qt_fixed_to_real(d_func()->stroker.miterLimit());
2665 Specifies the curve flattening \a threshold, controlling the
2666 granularity with which the generated outlines' curve is drawn.
2668 The default threshold is a well adjusted value (0.25), and
2669 normally you should not need to modify it. However, you can make
2670 the curve's appearance smoother by decreasing its value.
2672 void QPainterPathStroker::setCurveThreshold(qreal threshold)
2674 d_func()->stroker.setCurveThreshold(qt_real_to_fixed(threshold));
2678 Returns the curve flattening threshold for the generated
2681 qreal QPainterPathStroker::curveThreshold() const
2683 return qt_fixed_to_real(d_func()->stroker.curveThreshold());
2687 Sets the dash pattern for the generated outlines to \a style.
2689 void QPainterPathStroker::setDashPattern(Qt::PenStyle style)
2691 d_func()->dashPattern = QDashStroker::patternForStyle(style);
2697 Sets the dash pattern for the generated outlines to \a
2698 dashPattern. This function makes it possible to specify custom
2701 Each element in the vector contains the lengths of the dashes and spaces
2702 in the stroke, beginning with the first dash in the first element, the
2703 first space in the second element, and alternating between dashes and
2704 spaces for each following pair of elements.
2706 The vector can contain an odd number of elements, in which case the last
2707 element will be extended by the length of the first element when the
2710 void QPainterPathStroker::setDashPattern(const QVector<qreal> &dashPattern)
2712 d_func()->dashPattern.clear();
2713 for (int i=0; i<dashPattern.size(); ++i)
2714 d_func()->dashPattern << qt_real_to_fixed(dashPattern.at(i));
2718 Returns the dash pattern for the generated outlines.
2720 QVector<qreal> QPainterPathStroker::dashPattern() const
2722 return d_func()->dashPattern;
2726 Returns the dash offset for the generated outlines.
2728 qreal QPainterPathStroker::dashOffset() const
2730 return d_func()->dashOffset;
2734 Sets the dash offset for the generated outlines to \a offset.
2736 See the documentation for QPen::setDashOffset() for a description of the
2739 void QPainterPathStroker::setDashOffset(qreal offset)
2741 d_func()->dashOffset = offset;
2745 Converts the path into a polygon using the QTransform
2746 \a matrix, and returns the polygon.
2748 The polygon is created by first converting all subpaths to
2749 polygons, then using a rewinding technique to make sure that
2750 overlapping subpaths can be filled using the correct fill rule.
2752 Note that rewinding inserts addition lines in the polygon so
2753 the outline of the fill polygon does not match the outline of
2756 \sa toSubpathPolygons(), toFillPolygons(),
2757 {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
2759 QPolygonF QPainterPath::toFillPolygon(const QTransform &matrix) const
2762 QList<QPolygonF> flats = toSubpathPolygons(matrix);
2764 if (flats.isEmpty())
2766 QPointF first = flats.first().first();
2767 for (int i=0; i<flats.size(); ++i) {
2768 polygon += flats.at(i);
2769 if (!flats.at(i).isClosed())
2770 polygon += flats.at(i).first();
2780 QPolygonF QPainterPath::toFillPolygon(const QMatrix &matrix) const
2782 return toFillPolygon(QTransform(matrix));
2786 //derivative of the equation
2787 static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
2789 return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
2793 Returns the length of the current path.
2795 qreal QPainterPath::length() const
2802 for (int i=1; i<d->elements.size(); ++i) {
2803 const Element &e = d->elements.at(i);
2810 len += QLineF(d->elements.at(i-1), e).length();
2813 case CurveToElement:
2815 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2817 d->elements.at(i+1),
2818 d->elements.at(i+2));
2831 Returns percentage of the whole path at the specified length \a len.
2833 Note that similarly to other percent methods, the percentage measurement
2834 is not linear with regards to the length, if curves are present
2835 in the path. When curves are present the percentage argument is mapped
2836 to the t parameter of the Bezier equations.
2838 qreal QPainterPath::percentAtLength(qreal len) const
2841 if (isEmpty() || len <= 0)
2844 qreal totalLength = length();
2845 if (len > totalLength)
2849 for (int i=1; i<d->elements.size(); ++i) {
2850 const Element &e = d->elements.at(i);
2857 QLineF line(d->elements.at(i-1), e);
2858 qreal llen = line.length();
2860 if (curLen >= len) {
2861 return len/totalLength ;
2866 case CurveToElement:
2868 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2870 d->elements.at(i+1),
2871 d->elements.at(i+2));
2872 qreal blen = b.length();
2873 qreal prevLen = curLen;
2876 if (curLen >= len) {
2877 qreal res = b.tAtLength(len - prevLen);
2878 return (res * blen + prevLen)/totalLength;
2892 static inline QBezier bezierAtT(const QPainterPath &path, qreal t, qreal *startingLength, qreal *bezierLength)
2894 *startingLength = 0;
2899 qreal totalLength = path.length();
2901 const int lastElement = path.elementCount() - 1;
2902 for (int i=0; i <= lastElement; ++i) {
2903 const QPainterPath::Element &e = path.elementAt(i);
2906 case QPainterPath::MoveToElement:
2908 case QPainterPath::LineToElement:
2910 QLineF line(path.elementAt(i-1), e);
2911 qreal llen = line.length();
2913 if (i == lastElement || curLen/totalLength >= t) {
2914 *bezierLength = llen;
2915 QPointF a = path.elementAt(i-1);
2916 QPointF delta = e - a;
2917 return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
2921 case QPainterPath::CurveToElement:
2923 QBezier b = QBezier::fromPoints(path.elementAt(i-1),
2925 path.elementAt(i+1),
2926 path.elementAt(i+2));
2927 qreal blen = b.length();
2930 if (i + 2 == lastElement || curLen/totalLength >= t) {
2931 *bezierLength = blen;
2941 *startingLength = curLen;
2947 Returns the point at at the percentage \a t of the current path.
2948 The argument \a t has to be between 0 and 1.
2950 Note that similarly to other percent methods, the percentage measurement
2951 is not linear with regards to the length, if curves are present
2952 in the path. When curves are present the percentage argument is mapped
2953 to the t parameter of the Bezier equations.
2955 QPointF QPainterPath::pointAtPercent(qreal t) const
2957 if (t < 0 || t > 1) {
2958 qWarning("QPainterPath::pointAtPercent accepts only values between 0 and 1");
2962 if (!d_ptr || d_ptr->elements.size() == 0)
2965 if (d_ptr->elements.size() == 1)
2966 return d_ptr->elements.at(0);
2968 qreal totalLength = length();
2970 qreal bezierLen = 0;
2971 QBezier b = bezierAtT(*this, t, &curLen, &bezierLen);
2972 qreal realT = (totalLength * t - curLen) / bezierLen;
2974 return b.pointAt(qBound(qreal(0), realT, qreal(1)));
2978 Returns the angle of the path tangent at the percentage \a t.
2979 The argument \a t has to be between 0 and 1.
2981 Positive values for the angles mean counter-clockwise while negative values
2982 mean the clockwise direction. Zero degrees is at the 3 o'clock position.
2984 Note that similarly to the other percent methods, the percentage measurement
2985 is not linear with regards to the length if curves are present
2986 in the path. When curves are present the percentage argument is mapped
2987 to the t parameter of the Bezier equations.
2989 qreal QPainterPath::angleAtPercent(qreal t) const
2991 if (t < 0 || t > 1) {
2992 qWarning("QPainterPath::angleAtPercent accepts only values between 0 and 1");
2996 qreal totalLength = length();
2998 qreal bezierLen = 0;
2999 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
3000 qreal realT = (totalLength * t - curLen) / bezierLen;
3002 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
3003 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
3005 return QLineF(0, 0, m1, m2).angle();
3010 Returns the slope of the path at the percentage \a t. The
3011 argument \a t has to be between 0 and 1.
3013 Note that similarly to other percent methods, the percentage measurement
3014 is not linear with regards to the length, if curves are present
3015 in the path. When curves are present the percentage argument is mapped
3016 to the t parameter of the Bezier equations.
3018 qreal QPainterPath::slopeAtPercent(qreal t) const
3020 if (t < 0 || t > 1) {
3021 qWarning("QPainterPath::slopeAtPercent accepts only values between 0 and 1");
3025 qreal totalLength = length();
3027 qreal bezierLen = 0;
3028 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
3029 qreal realT = (totalLength * t - curLen) / bezierLen;
3031 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
3032 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
3036 #define SIGN(x) ((x < 0)?-1:1)
3040 //windows doesn't define INFINITY :(
3042 slope = INFINITY*SIGN(m2);
3044 if (sizeof(qreal) == sizeof(double)) {
3045 return 1.79769313486231570e+308;
3047 return ((qreal)3.40282346638528860e+38);
3058 Adds the given rectangle \a rect with rounded corners to the path.
3060 The \a xRadius and \a yRadius arguments specify the radii of
3061 the ellipses defining the corners of the rounded rectangle.
3062 When \a mode is Qt::RelativeSize, \a xRadius and
3063 \a yRadius are specified in percentage of half the rectangle's
3064 width and height respectively, and should be in the range 0.0 to 100.0.
3068 void QPainterPath::addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius,
3071 QRectF r = rect.normalized();
3076 if (mode == Qt::AbsoluteSize) {
3077 qreal w = r.width() / 2;
3078 qreal h = r.height() / 2;
3083 xRadius = 100 * qMin(xRadius, w) / w;
3088 yRadius = 100 * qMin(yRadius, h) / h;
3091 if (xRadius > 100) // fix ranges
3098 if (xRadius <= 0 || yRadius <= 0) { // add normal rectangle
3105 qreal w = r.width();
3106 qreal h = r.height();
3107 qreal rxx2 = w*xRadius/100;
3108 qreal ryy2 = h*yRadius/100;
3113 bool first = d_func()->elements.size() < 2;
3115 arcMoveTo(x, y, rxx2, ryy2, 180);
3116 arcTo(x, y, rxx2, ryy2, 180, -90);
3117 arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3118 arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3119 arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3122 d_func()->require_moveTo = true;
3123 d_func()->convex = first;
3127 \fn void QPainterPath::addRoundedRect(qreal x, qreal y, qreal w, qreal h, qreal xRadius, qreal yRadius, Qt::SizeMode mode = Qt::AbsoluteSize);
3131 Adds the given rectangle \a x, \a y, \a w, \a h with rounded corners to the path.
3137 Adds a rectangle \a r with rounded corners to the path.
3139 The \a xRnd and \a yRnd arguments specify how rounded the corners
3140 should be. 0 is angled corners, 99 is maximum roundedness.
3142 \sa addRoundedRect()
3144 void QPainterPath::addRoundRect(const QRectF &r, int xRnd, int yRnd)
3146 if(xRnd >= 100) // fix ranges
3150 if(xRnd <= 0 || yRnd <= 0) { // add normal rectangle
3155 QRectF rect = r.normalized();
3162 qreal w = rect.width();
3163 qreal h = rect.height();
3164 qreal rxx2 = w*xRnd/100;
3165 qreal ryy2 = h*yRnd/100;
3170 bool first = d_func()->elements.size() < 2;
3172 arcMoveTo(x, y, rxx2, ryy2, 180);
3173 arcTo(x, y, rxx2, ryy2, 180, -90);
3174 arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3175 arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3176 arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3179 d_func()->require_moveTo = true;
3180 d_func()->convex = first;
3186 \fn bool QPainterPath::addRoundRect(const QRectF &rect, int roundness);
3190 Adds a rounded rectangle, \a rect, to the path.
3192 The \a roundness argument specifies uniform roundness for the
3193 rectangle. Vertical and horizontal roundness factors will be
3194 adjusted accordingly to act uniformly around both axes. Use this
3195 method if you want a rectangle equally rounded across both the X and
3198 \sa addRoundedRect()
3204 \fn void QPainterPath::addRoundRect(qreal x, qreal y, qreal w, qreal h, int xRnd, int yRnd);
3207 Adds a rectangle with rounded corners to the path. The rectangle
3208 is constructed from \a x, \a y, and the width and height \a w
3211 The \a xRnd and \a yRnd arguments specify how rounded the corners
3212 should be. 0 is angled corners, 99 is maximum roundedness.
3214 \sa addRoundedRect()
3220 \fn bool QPainterPath::addRoundRect(qreal x, qreal y, qreal width, qreal height, int roundness);
3224 Adds a rounded rectangle to the path, defined by the coordinates \a
3225 x and \a y with the specified \a width and \a height.
3227 The \a roundness argument specifies uniform roundness for the
3228 rectangle. Vertical and horizontal roundness factors will be
3229 adjusted accordingly to act uniformly around both axes. Use this
3230 method if you want a rectangle equally rounded across both the X and
3233 \sa addRoundedRect()
3239 Returns a path which is the union of this path's fill area and \a p's fill area.
3241 Set operations on paths will treat the paths as areas. Non-closed
3242 paths will be treated as implicitly closed.
3243 Bezier curves may be flattened to line segments due to numerical instability of
3244 doing bezier curve intersections.
3246 \sa intersected(), subtracted()
3248 QPainterPath QPainterPath::united(const QPainterPath &p) const
3250 if (isEmpty() || p.isEmpty())
3251 return isEmpty() ? p : *this;
3252 QPathClipper clipper(*this, p);
3253 return clipper.clip(QPathClipper::BoolOr);
3259 Returns a path which is the intersection of this path's fill area and \a p's fill area.
3260 Bezier curves may be flattened to line segments due to numerical instability of
3261 doing bezier curve intersections.
3263 QPainterPath QPainterPath::intersected(const QPainterPath &p) const
3265 if (isEmpty() || p.isEmpty())
3266 return QPainterPath();
3267 QPathClipper clipper(*this, p);
3268 return clipper.clip(QPathClipper::BoolAnd);
3274 Returns a path which is \a p's fill area subtracted from this path's fill area.
3276 Set operations on paths will treat the paths as areas. Non-closed
3277 paths will be treated as implicitly closed.
3278 Bezier curves may be flattened to line segments due to numerical instability of
3279 doing bezier curve intersections.
3281 QPainterPath QPainterPath::subtracted(const QPainterPath &p) const
3283 if (isEmpty() || p.isEmpty())
3285 QPathClipper clipper(*this, p);
3286 return clipper.clip(QPathClipper::BoolSub);
3293 Use subtracted() instead.
3297 QPainterPath QPainterPath::subtractedInverted(const QPainterPath &p) const
3299 return p.subtracted(*this);
3305 Returns a simplified version of this path. This implies merging all subpaths that intersect,
3306 and returning a path containing no intersecting edges. Consecutive parallel lines will also
3307 be merged. The simplified path will always use the default fill rule, Qt::OddEvenFill.
3308 Bezier curves may be flattened to line segments due to numerical instability of
3309 doing bezier curve intersections.
3311 QPainterPath QPainterPath::simplified() const
3315 QPathClipper clipper(*this, QPainterPath());
3316 return clipper.clip(QPathClipper::Simplify);
3322 Returns true if the current path intersects at any point the given path \a p.
3323 Also returns true if the current path contains or is contained by any part of \a p.
3325 Set operations on paths will treat the paths as areas. Non-closed
3326 paths will be treated as implicitly closed.
3330 bool QPainterPath::intersects(const QPainterPath &p) const
3332 if (p.elementCount() == 1)
3333 return contains(p.elementAt(0));
3334 if (isEmpty() || p.isEmpty())
3336 QPathClipper clipper(*this, p);
3337 return clipper.intersect();
3343 Returns true if the given path \a p is contained within
3344 the current path. Returns false if any edges of the current path and
3347 Set operations on paths will treat the paths as areas. Non-closed
3348 paths will be treated as implicitly closed.
3352 bool QPainterPath::contains(const QPainterPath &p) const
3354 if (p.elementCount() == 1)
3355 return contains(p.elementAt(0));
3356 if (isEmpty() || p.isEmpty())
3358 QPathClipper clipper(*this, p);
3359 return clipper.contains();
3362 void QPainterPath::setDirty(bool dirty)
3364 d_func()->dirtyBounds = dirty;
3365 d_func()->dirtyControlBounds = dirty;
3366 delete d_func()->pathConverter;
3367 d_func()->pathConverter = 0;
3368 d_func()->convex = false;
3371 void QPainterPath::computeBoundingRect() const
3373 QPainterPathData *d = d_func();
3374 d->dirtyBounds = false;
3376 d->bounds = QRect();
3380 qreal minx, maxx, miny, maxy;
3381 minx = maxx = d->elements.at(0).x;
3382 miny = maxy = d->elements.at(0).y;
3383 for (int i=1; i<d->elements.size(); ++i) {
3384 const Element &e = d->elements.at(i);
3389 if (e.x > maxx) maxx = e.x;
3390 else if (e.x < minx) minx = e.x;
3391 if (e.y > maxy) maxy = e.y;
3392 else if (e.y < miny) miny = e.y;
3394 case CurveToElement:
3396 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
3398 d->elements.at(i+1),
3399 d->elements.at(i+2));
3400 QRectF r = qt_painterpath_bezier_extrema(b);
3401 qreal right = r.right();
3402 qreal bottom = r.bottom();
3403 if (r.x() < minx) minx = r.x();
3404 if (right > maxx) maxx = right;
3405 if (r.y() < miny) miny = r.y();
3406 if (bottom > maxy) maxy = bottom;
3414 d->bounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3418 void QPainterPath::computeControlPointRect() const
3420 QPainterPathData *d = d_func();
3421 d->dirtyControlBounds = false;
3423 d->controlBounds = QRect();
3427 qreal minx, maxx, miny, maxy;
3428 minx = maxx = d->elements.at(0).x;
3429 miny = maxy = d->elements.at(0).y;
3430 for (int i=1; i<d->elements.size(); ++i) {
3431 const Element &e = d->elements.at(i);
3432 if (e.x > maxx) maxx = e.x;
3433 else if (e.x < minx) minx = e.x;
3434 if (e.y > maxy) maxy = e.y;
3435 else if (e.y < miny) miny = e.y;
3437 d->controlBounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3440 #ifndef QT_NO_DEBUG_STREAM
3441 QDebug operator<<(QDebug s, const QPainterPath &p)
3443 s.nospace() << "QPainterPath: Element count=" << p.elementCount() << endl;
3444 const char *types[] = {"MoveTo", "LineTo", "CurveTo", "CurveToData"};
3445 for (int i=0; i<p.elementCount(); ++i) {
3446 s.nospace() << " -> " << types[p.elementAt(i).type] << "(x=" << p.elementAt(i).x << ", y=" << p.elementAt(i).y << ')' << endl;