1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** 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 \o \inlineimage qpainterpath-construction.png
232 \snippet doc/src/snippets/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 \o \inlineimage qt-fillrule-oddeven.png
248 \o \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 \o \l {painting/painterpaths}{Painter Paths Example}
320 \o \l {painting/deform}{Vector Deformation Example}
322 \o \inlineimage qpainterpath-example.png
323 \o \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()
482 \fn const QPainterPath::Element &QPainterPath::elementAt(int index) const
484 Returns the element at the given \a index in the painter path.
486 \sa ElementType, elementCount(), isEmpty()
490 \fn void QPainterPath::setElementPositionAt(int index, qreal x, qreal y)
493 Sets the x and y coordinate of the element at index \a index to \a
498 \fn QPainterPath &QPainterPath::operator +=(const QPainterPath &other)
500 Appends the \a other painter path to this painter path and returns a
501 reference to the result.
505 Constructs an empty QPainterPath object.
507 QPainterPath::QPainterPath()
513 \fn QPainterPath::QPainterPath(const QPainterPath &path)
515 Creates a QPainterPath object that is a copy of the given \a path.
519 QPainterPath::QPainterPath(const QPainterPath &other)
520 : d_ptr(other.d_ptr.data())
527 Creates a QPainterPath object with the given \a startPoint as its
531 QPainterPath::QPainterPath(const QPointF &startPoint)
532 : d_ptr(new QPainterPathData)
534 Element e = { startPoint.x(), startPoint.y(), MoveToElement };
535 d_func()->elements << e;
541 void QPainterPath::detach_helper()
543 QPainterPathPrivate *data = new QPainterPathData(*d_func());
550 void QPainterPath::ensureData_helper()
552 QPainterPathPrivate *data = new QPainterPathData;
553 data->elements.reserve(16);
554 QPainterPath::Element e = { 0, 0, QPainterPath::MoveToElement };
557 Q_ASSERT(d_ptr != 0);
561 \fn QPainterPath &QPainterPath::operator=(const QPainterPath &path)
563 Assigns the given \a path to this painter path.
567 QPainterPath &QPainterPath::operator=(const QPainterPath &other)
569 if (other.d_func() != d_func()) {
570 QPainterPathPrivate *data = other.d_func();
579 \fn void QPainterPath::swap(QPainterPath &other)
582 Swaps painter path \a other with this painter path. This operation is very
583 fast and never fails.
587 Destroys this QPainterPath object.
589 QPainterPath::~QPainterPath()
594 Closes the current subpath by drawing a line to the beginning of
595 the subpath, automatically starting a new path. The current point
596 of the new path is (0, 0).
598 If the subpath does not contain any elements, this function does
601 \sa moveTo(), {QPainterPath#Composing a QPainterPath}{Composing
604 void QPainterPath::closeSubpath()
607 printf("QPainterPath::closeSubpath()\n");
617 \fn void QPainterPath::moveTo(qreal x, qreal y)
621 Moves the current position to (\a{x}, \a{y}) and starts a new
622 subpath, implicitly closing the previous path.
626 \fn void QPainterPath::moveTo(const QPointF &point)
628 Moves the current point to the given \a point, implicitly starting
629 a new subpath and closing the previous one.
631 \sa closeSubpath(), {QPainterPath#Composing a
632 QPainterPath}{Composing a QPainterPath}
634 void QPainterPath::moveTo(const QPointF &p)
637 printf("QPainterPath::moveTo() (%.2f,%.2f)\n", p.x(), p.y());
640 if (!qt_is_finite(p.x()) || !qt_is_finite(p.y())) {
642 qWarning("QPainterPath::moveTo: Adding point where x or y is NaN or Inf, ignoring call");
650 QPainterPathData *d = d_func();
651 Q_ASSERT(!d->elements.isEmpty());
653 d->require_moveTo = false;
655 if (d->elements.last().type == MoveToElement) {
656 d->elements.last().x = p.x();
657 d->elements.last().y = p.y();
659 Element elm = { p.x(), p.y(), MoveToElement };
660 d->elements.append(elm);
662 d->cStart = d->elements.size() - 1;
666 \fn void QPainterPath::lineTo(qreal x, qreal y)
670 Draws a line from the current position to the point (\a{x},
675 \fn void QPainterPath::lineTo(const QPointF &endPoint)
677 Adds a straight line from the current position to the given \a
678 endPoint. After the line is drawn, the current position is updated
679 to be at the end point of the line.
681 \sa addPolygon(), addRect(), {QPainterPath#Composing a
682 QPainterPath}{Composing a QPainterPath}
684 void QPainterPath::lineTo(const QPointF &p)
687 printf("QPainterPath::lineTo() (%.2f,%.2f)\n", p.x(), p.y());
690 if (!qt_is_finite(p.x()) || !qt_is_finite(p.y())) {
692 qWarning("QPainterPath::lineTo: Adding point where x or y is NaN or Inf, ignoring call");
700 QPainterPathData *d = d_func();
701 Q_ASSERT(!d->elements.isEmpty());
703 if (p == QPointF(d->elements.last()))
705 Element elm = { p.x(), p.y(), LineToElement };
706 d->elements.append(elm);
708 d->convex = d->elements.size() == 3 || (d->elements.size() == 4 && d->isClosed());
712 \fn void QPainterPath::cubicTo(qreal c1X, qreal c1Y, qreal c2X,
713 qreal c2Y, qreal endPointX, qreal endPointY);
717 Adds a cubic Bezier curve between the current position and the end
718 point (\a{endPointX}, \a{endPointY}) with control points specified
719 by (\a{c1X}, \a{c1Y}) and (\a{c2X}, \a{c2Y}).
723 \fn void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &endPoint)
725 Adds a cubic Bezier curve between the current position and the
726 given \a endPoint using the control points specified by \a c1, and
729 After the curve is added, the current position is updated to be at
730 the end point of the curve.
734 \o \inlineimage qpainterpath-cubicto.png
736 \snippet doc/src/snippets/code/src_gui_painting_qpainterpath.cpp 1
739 \sa quadTo(), {QPainterPath#Composing a QPainterPath}{Composing
742 void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &e)
745 printf("QPainterPath::cubicTo() (%.2f,%.2f), (%.2f,%.2f), (%.2f,%.2f)\n",
746 c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
749 if (!qt_is_finite(c1.x()) || !qt_is_finite(c1.y()) || !qt_is_finite(c2.x()) || !qt_is_finite(c2.y())
750 || !qt_is_finite(e.x()) || !qt_is_finite(e.y())) {
752 qWarning("QPainterPath::cubicTo: Adding point where x or y is NaN or Inf, ignoring call");
760 QPainterPathData *d = d_func();
761 Q_ASSERT(!d->elements.isEmpty());
764 // Abort on empty curve as a stroker cannot handle this and the
765 // curve is irrelevant anyway.
766 if (d->elements.last() == c1 && c1 == c2 && c2 == e)
771 Element ce1 = { c1.x(), c1.y(), CurveToElement };
772 Element ce2 = { c2.x(), c2.y(), CurveToDataElement };
773 Element ee = { e.x(), e.y(), CurveToDataElement };
774 d->elements << ce1 << ce2 << ee;
778 \fn void QPainterPath::quadTo(qreal cx, qreal cy, qreal endPointX, qreal endPointY);
782 Adds a quadratic Bezier curve between the current point and the endpoint
783 (\a{endPointX}, \a{endPointY}) with the control point specified by
788 \fn void QPainterPath::quadTo(const QPointF &c, const QPointF &endPoint)
790 Adds a quadratic Bezier curve between the current position and the
791 given \a endPoint with the control point specified by \a c.
793 After the curve is added, the current point is updated to be at
794 the end point of the curve.
796 \sa cubicTo(), {QPainterPath#Composing a QPainterPath}{Composing a
799 void QPainterPath::quadTo(const QPointF &c, const QPointF &e)
802 printf("QPainterPath::quadTo() (%.2f,%.2f), (%.2f,%.2f)\n",
803 c.x(), c.y(), e.x(), e.y());
806 if (!qt_is_finite(c.x()) || !qt_is_finite(c.y()) || !qt_is_finite(e.x()) || !qt_is_finite(e.y())) {
808 qWarning("QPainterPath::quadTo: Adding point where x or y is NaN or Inf, ignoring call");
817 Q_ASSERT(!d->elements.isEmpty());
818 const QPainterPath::Element &elm = d->elements.at(elementCount()-1);
819 QPointF prev(elm.x, elm.y);
821 // Abort on empty curve as a stroker cannot handle this and the
822 // curve is irrelevant anyway.
823 if (prev == c && c == e)
826 QPointF c1((prev.x() + 2*c.x()) / 3, (prev.y() + 2*c.y()) / 3);
827 QPointF c2((e.x() + 2*c.x()) / 3, (e.y() + 2*c.y()) / 3);
832 \fn void QPainterPath::arcTo(qreal x, qreal y, qreal width, qreal
833 height, qreal startAngle, qreal sweepLength)
837 Creates an arc that occupies the rectangle QRectF(\a x, \a y, \a
838 width, \a height), beginning at the specified \a startAngle and
839 extending \a sweepLength degrees counter-clockwise.
844 \fn void QPainterPath::arcTo(const QRectF &rectangle, qreal startAngle, qreal sweepLength)
846 Creates an arc that occupies the given \a rectangle, beginning at
847 the specified \a startAngle and extending \a sweepLength degrees
850 Angles are specified in degrees. Clockwise arcs can be specified
851 using negative angles.
853 Note that this function connects the starting point of the arc to
854 the current position if they are not already connected. After the
855 arc has been added, the current position is the last point in
856 arc. To draw a line back to the first point, use the
857 closeSubpath() function.
861 \o \inlineimage qpainterpath-arcto.png
863 \snippet doc/src/snippets/code/src_gui_painting_qpainterpath.cpp 2
866 \sa arcMoveTo(), addEllipse(), QPainter::drawArc(), QPainter::drawPie(),
867 {QPainterPath#Composing a QPainterPath}{Composing a
870 void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength)
873 printf("QPainterPath::arcTo() (%.2f, %.2f, %.2f, %.2f, angle=%.2f, sweep=%.2f\n",
874 rect.x(), rect.y(), rect.width(), rect.height(), startAngle, sweepLength);
877 if ((!qt_is_finite(rect.x()) && !qt_is_finite(rect.y())) || !qt_is_finite(rect.width()) || !qt_is_finite(rect.height())
878 || !qt_is_finite(startAngle) || !qt_is_finite(sweepLength)) {
880 qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN or Inf, ignoring call");
893 QPointF curve_start = qt_curves_for_arc(rect, startAngle, sweepLength, pts, &point_count);
896 for (int i=0; i<point_count; i+=3) {
897 cubicTo(pts[i].x(), pts[i].y(),
898 pts[i+1].x(), pts[i+1].y(),
899 pts[i+2].x(), pts[i+2].y());
906 \fn void QPainterPath::arcMoveTo(qreal x, qreal y, qreal width, qreal height, qreal angle)
910 Creates a move to that lies on the arc that occupies the
911 QRectF(\a x, \a y, \a width, \a height) at \a angle.
916 \fn void QPainterPath::arcMoveTo(const QRectF &rectangle, qreal angle)
919 Creates a move to that lies on the arc that occupies the given \a
920 rectangle at \a angle.
922 Angles are specified in degrees. Clockwise arcs can be specified
923 using negative angles.
925 \sa moveTo(), arcTo()
928 void QPainterPath::arcMoveTo(const QRectF &rect, qreal angle)
934 qt_find_ellipse_coords(rect, angle, 0, &pt, 0);
941 \fn QPointF QPainterPath::currentPosition() const
943 Returns the current position of the path.
945 QPointF QPainterPath::currentPosition() const
947 return !d_ptr || d_func()->elements.isEmpty()
949 : QPointF(d_func()->elements.last().x, d_func()->elements.last().y);
954 \fn void QPainterPath::addRect(qreal x, qreal y, qreal width, qreal height)
958 Adds a rectangle at position (\a{x}, \a{y}), with the given \a
959 width and \a height, as a closed subpath.
963 \fn void QPainterPath::addRect(const QRectF &rectangle)
965 Adds the given \a rectangle to this path as a closed subpath.
967 The \a rectangle is added as a clockwise set of lines. The painter
968 path's current position after the \a rectangle has been added is
969 at the top-left corner of the rectangle.
973 \o \inlineimage qpainterpath-addrectangle.png
975 \snippet doc/src/snippets/code/src_gui_painting_qpainterpath.cpp 3
978 \sa addRegion(), lineTo(), {QPainterPath#Composing a
979 QPainterPath}{Composing a QPainterPath}
981 void QPainterPath::addRect(const QRectF &r)
983 if (!qt_is_finite(r.x()) || !qt_is_finite(r.y()) || !qt_is_finite(r.width()) || !qt_is_finite(r.height())) {
985 qWarning("QPainterPath::addRect: Adding rect where a parameter is NaN or Inf, ignoring call");
996 bool first = d_func()->elements.size() < 2;
998 d_func()->elements.reserve(d_func()->elements.size() + 5);
999 moveTo(r.x(), r.y());
1001 Element l1 = { r.x() + r.width(), r.y(), LineToElement };
1002 Element l2 = { r.x() + r.width(), r.y() + r.height(), LineToElement };
1003 Element l3 = { r.x(), r.y() + r.height(), LineToElement };
1004 Element l4 = { r.x(), r.y(), LineToElement };
1006 d_func()->elements << l1 << l2 << l3 << l4;
1007 d_func()->require_moveTo = true;
1008 d_func()->convex = first;
1012 Adds the given \a polygon to the path as an (unclosed) subpath.
1014 Note that the current position after the polygon has been added,
1015 is the last point in \a polygon. To draw a line back to the first
1016 point, use the closeSubpath() function.
1020 \o \inlineimage qpainterpath-addpolygon.png
1022 \snippet doc/src/snippets/code/src_gui_painting_qpainterpath.cpp 4
1025 \sa lineTo(), {QPainterPath#Composing a QPainterPath}{Composing
1028 void QPainterPath::addPolygon(const QPolygonF &polygon)
1030 if (polygon.isEmpty())
1036 d_func()->elements.reserve(d_func()->elements.size() + polygon.size());
1038 moveTo(polygon.first());
1039 for (int i=1; i<polygon.size(); ++i) {
1040 Element elm = { polygon.at(i).x(), polygon.at(i).y(), LineToElement };
1041 d_func()->elements << elm;
1046 \fn void QPainterPath::addEllipse(const QRectF &boundingRectangle)
1048 Creates an ellipse within the specified \a boundingRectangle
1049 and adds it to the painter path as a closed subpath.
1051 The ellipse is composed of a clockwise curve, starting and
1052 finishing at zero degrees (the 3 o'clock position).
1056 \o \inlineimage qpainterpath-addellipse.png
1058 \snippet doc/src/snippets/code/src_gui_painting_qpainterpath.cpp 5
1061 \sa arcTo(), QPainter::drawEllipse(), {QPainterPath#Composing a
1062 QPainterPath}{Composing a QPainterPath}
1064 void QPainterPath::addEllipse(const QRectF &boundingRect)
1066 if (!qt_is_finite(boundingRect.x()) || !qt_is_finite(boundingRect.y())
1067 || !qt_is_finite(boundingRect.width()) || !qt_is_finite(boundingRect.height())) {
1069 qWarning("QPainterPath::addEllipse: Adding ellipse where a parameter is NaN or Inf, ignoring call");
1074 if (boundingRect.isNull())
1081 bool first = d_func()->elements.size() < 2;
1082 d->elements.reserve(d->elements.size() + 13);
1086 QPointF start = qt_curves_for_arc(boundingRect, 0, -360, pts, &point_count);
1089 cubicTo(pts[0], pts[1], pts[2]); // 0 -> 270
1090 cubicTo(pts[3], pts[4], pts[5]); // 270 -> 180
1091 cubicTo(pts[6], pts[7], pts[8]); // 180 -> 90
1092 cubicTo(pts[9], pts[10], pts[11]); // 90 - >0
1093 d_func()->require_moveTo = true;
1095 d_func()->convex = first;
1099 \fn void QPainterPath::addText(const QPointF &point, const QFont &font, const QString &text)
1101 Adds the given \a text to this path as a set of closed subpaths
1102 created from the \a font supplied. The subpaths are positioned so
1103 that the left end of the text's baseline lies at the specified \a
1108 \o \inlineimage qpainterpath-addtext.png
1110 \snippet doc/src/snippets/code/src_gui_painting_qpainterpath.cpp 6
1113 \sa QPainter::drawText(), {QPainterPath#Composing a
1114 QPainterPath}{Composing a QPainterPath}
1116 void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &text)
1124 QTextLayout layout(text, f);
1125 layout.setCacheEnabled(true);
1126 QTextEngine *eng = layout.engine();
1127 layout.beginLayout();
1128 QTextLine line = layout.createLine();
1131 const QScriptLine &sl = eng->lines[0];
1132 if (!sl.length || !eng->layoutData)
1135 int nItems = eng->layoutData->items.size();
1140 QVarLengthArray<int> visualOrder(nItems);
1141 QVarLengthArray<uchar> levels(nItems);
1142 for (int i = 0; i < nItems; ++i)
1143 levels[i] = eng->layoutData->items[i].analysis.bidiLevel;
1144 QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
1146 for (int i = 0; i < nItems; ++i) {
1147 int item = visualOrder[i];
1148 QScriptItem &si = eng->layoutData->items[item];
1150 if (si.analysis.flags < QScriptAnalysis::TabOrObject) {
1151 QGlyphLayout glyphs = eng->shapedGlyphs(&si);
1152 QFontEngine *fe = f.d->engineForScript(si.analysis.script);
1154 fe->addOutlineToPath(x, y, glyphs, this,
1155 si.analysis.bidiLevel % 2
1156 ? QTextItem::RenderFlags(QTextItem::RightToLeft)
1157 : QTextItem::RenderFlags(0));
1159 const qreal lw = fe->lineThickness().toReal();
1160 if (f.d->underline) {
1161 qreal pos = fe->underlinePosition().toReal();
1162 addRect(x, y + pos, si.width.toReal(), lw);
1164 if (f.d->overline) {
1165 qreal pos = fe->ascent().toReal() + 1;
1166 addRect(x, y - pos, si.width.toReal(), lw);
1168 if (f.d->strikeOut) {
1169 qreal pos = fe->ascent().toReal() / 3;
1170 addRect(x, y - pos, si.width.toReal(), lw);
1173 x += si.width.toReal();
1178 \fn void QPainterPath::addPath(const QPainterPath &path)
1180 Adds the given \a path to \e this path as a closed subpath.
1182 \sa connectPath(), {QPainterPath#Composing a
1183 QPainterPath}{Composing a QPainterPath}
1185 void QPainterPath::addPath(const QPainterPath &other)
1187 if (other.isEmpty())
1193 QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
1194 // Remove last moveto so we don't get multiple moveto's
1195 if (d->elements.last().type == MoveToElement)
1196 d->elements.remove(d->elements.size()-1);
1198 // Locate where our own current subpath will start after the other path is added.
1199 int cStart = d->elements.size() + other.d_func()->cStart;
1200 d->elements += other.d_func()->elements;
1203 d->require_moveTo = other.d_func()->isClosed();
1208 \fn void QPainterPath::connectPath(const QPainterPath &path)
1210 Connects the given \a path to \e this path by adding a line from the
1211 last element of this path to the first element of the given path.
1213 \sa addPath(), {QPainterPath#Composing a QPainterPath}{Composing
1216 void QPainterPath::connectPath(const QPainterPath &other)
1218 if (other.isEmpty())
1224 QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
1225 // Remove last moveto so we don't get multiple moveto's
1226 if (d->elements.last().type == MoveToElement)
1227 d->elements.remove(d->elements.size()-1);
1229 // Locate where our own current subpath will start after the other path is added.
1230 int cStart = d->elements.size() + other.d_func()->cStart;
1231 int first = d->elements.size();
1232 d->elements += other.d_func()->elements;
1235 d->elements[first].type = LineToElement;
1237 // avoid duplicate points
1238 if (first > 0 && QPointF(d->elements[first]) == QPointF(d->elements[first - 1])) {
1239 d->elements.remove(first--);
1243 if (cStart != first)
1248 Adds the given \a region to the path by adding each rectangle in
1249 the region as a separate closed subpath.
1251 \sa addRect(), {QPainterPath#Composing a QPainterPath}{Composing
1254 void QPainterPath::addRegion(const QRegion ®ion)
1259 QVector<QRect> rects = region.rects();
1260 d_func()->elements.reserve(rects.size() * 5);
1261 for (int i=0; i<rects.size(); ++i)
1262 addRect(rects.at(i));
1267 Returns the painter path's currently set fill rule.
1271 Qt::FillRule QPainterPath::fillRule() const
1273 return isEmpty() ? Qt::OddEvenFill : d_func()->fillRule;
1277 \fn void QPainterPath::setFillRule(Qt::FillRule fillRule)
1279 Sets the fill rule of the painter path to the given \a
1280 fillRule. Qt provides two methods for filling paths:
1284 \o Qt::OddEvenFill (default)
1287 \o \inlineimage qt-fillrule-oddeven.png
1288 \o \inlineimage qt-fillrule-winding.png
1293 void QPainterPath::setFillRule(Qt::FillRule fillRule)
1296 if (d_func()->fillRule == fillRule)
1300 d_func()->fillRule = fillRule;
1303 #define QT_BEZIER_A(bezier, coord) 3 * (-bezier.coord##1 \
1304 + 3*bezier.coord##2 \
1305 - 3*bezier.coord##3 \
1308 #define QT_BEZIER_B(bezier, coord) 6 * (bezier.coord##1 \
1309 - 2*bezier.coord##2 \
1312 #define QT_BEZIER_C(bezier, coord) 3 * (- bezier.coord##1 \
1315 #define QT_BEZIER_CHECK_T(bezier, t) \
1316 if (t >= 0 && t <= 1) { \
1317 QPointF p(b.pointAt(t)); \
1318 if (p.x() < minx) minx = p.x(); \
1319 else if (p.x() > maxx) maxx = p.x(); \
1320 if (p.y() < miny) miny = p.y(); \
1321 else if (p.y() > maxy) maxy = p.y(); \
1325 static QRectF qt_painterpath_bezier_extrema(const QBezier &b)
1327 qreal minx, miny, maxx, maxy;
1329 // initialize with end points
1345 // Update for the X extrema
1347 qreal ax = QT_BEZIER_A(b, x);
1348 qreal bx = QT_BEZIER_B(b, x);
1349 qreal cx = QT_BEZIER_C(b, x);
1350 // specialcase quadratic curves to avoid div by zero
1351 if (qFuzzyIsNull(ax)) {
1353 // linear curves are covered by initialization.
1354 if (!qFuzzyIsNull(bx)) {
1356 QT_BEZIER_CHECK_T(b, t);
1360 const qreal tx = bx * bx - 4 * ax * cx;
1363 qreal temp = qSqrt(tx);
1364 qreal rcp = 1 / (2 * ax);
1365 qreal t1 = (-bx + temp) * rcp;
1366 QT_BEZIER_CHECK_T(b, t1);
1368 qreal t2 = (-bx - temp) * rcp;
1369 QT_BEZIER_CHECK_T(b, t2);
1374 // Update for the Y extrema
1376 qreal ay = QT_BEZIER_A(b, y);
1377 qreal by = QT_BEZIER_B(b, y);
1378 qreal cy = QT_BEZIER_C(b, y);
1380 // specialcase quadratic curves to avoid div by zero
1381 if (qFuzzyIsNull(ay)) {
1383 // linear curves are covered by initialization.
1384 if (!qFuzzyIsNull(by)) {
1386 QT_BEZIER_CHECK_T(b, t);
1390 const qreal ty = by * by - 4 * ay * cy;
1393 qreal temp = qSqrt(ty);
1394 qreal rcp = 1 / (2 * ay);
1395 qreal t1 = (-by + temp) * rcp;
1396 QT_BEZIER_CHECK_T(b, t1);
1398 qreal t2 = (-by - temp) * rcp;
1399 QT_BEZIER_CHECK_T(b, t2);
1403 return QRectF(minx, miny, maxx - minx, maxy - miny);
1407 Returns the bounding rectangle of this painter path as a rectangle with
1408 floating point precision.
1410 \sa controlPointRect()
1412 QRectF QPainterPath::boundingRect() const
1416 QPainterPathData *d = d_func();
1419 computeBoundingRect();
1424 Returns the rectangle containing all the points and control points
1427 This function is significantly faster to compute than the exact
1428 boundingRect(), and the returned rectangle is always a superset of
1429 the rectangle returned by boundingRect().
1433 QRectF QPainterPath::controlPointRect() const
1437 QPainterPathData *d = d_func();
1439 if (d->dirtyControlBounds)
1440 computeControlPointRect();
1441 return d->controlBounds;
1446 \fn bool QPainterPath::isEmpty() const
1448 Returns true if either there are no elements in this path, or if the only
1449 element is a MoveToElement; otherwise returns false.
1455 Creates and returns a reversed copy of the path.
1457 It is the order of the elements that is reversed: If a
1458 QPainterPath is composed by calling the moveTo(), lineTo() and
1459 cubicTo() functions in the specified order, the reversed copy is
1460 composed by calling cubicTo(), lineTo() and moveTo().
1462 QPainterPath QPainterPath::toReversed() const
1464 Q_D(const QPainterPath);
1472 rev.moveTo(d->elements.at(d->elements.size()-1).x, d->elements.at(d->elements.size()-1).y);
1474 for (int i=d->elements.size()-1; i>=1; --i) {
1475 const QPainterPath::Element &elm = d->elements.at(i);
1476 const QPainterPath::Element &prev = d->elements.at(i-1);
1479 rev.lineTo(prev.x, prev.y);
1482 rev.moveTo(prev.x, prev.y);
1484 case CurveToDataElement:
1487 const QPainterPath::Element &cp1 = d->elements.at(i-2);
1488 const QPainterPath::Element &sp = d->elements.at(i-3);
1489 Q_ASSERT(prev.type == CurveToDataElement);
1490 Q_ASSERT(cp1.type == CurveToElement);
1491 rev.cubicTo(prev.x, prev.y, cp1.x, cp1.y, sp.x, sp.y);
1496 Q_ASSERT(!"qt_reversed_path");
1500 //qt_debug_path(rev);
1505 Converts the path into a list of polygons using the QTransform
1506 \a matrix, and returns the list.
1508 This function creates one polygon for each subpath regardless of
1509 intersecting subpaths (i.e. overlapping bounding rectangles). To
1510 make sure that such overlapping subpaths are filled correctly, use
1511 the toFillPolygons() function instead.
1513 \sa toFillPolygons(), toFillPolygon(), {QPainterPath#QPainterPath
1514 Conversion}{QPainterPath Conversion}
1516 QList<QPolygonF> QPainterPath::toSubpathPolygons(const QTransform &matrix) const
1519 Q_D(const QPainterPath);
1520 QList<QPolygonF> flatCurves;
1525 for (int i=0; i<elementCount(); ++i) {
1526 const QPainterPath::Element &e = d->elements.at(i);
1528 case QPainterPath::MoveToElement:
1529 if (current.size() > 1)
1530 flatCurves += current;
1532 current.reserve(16);
1533 current += QPointF(e.x, e.y) * matrix;
1535 case QPainterPath::LineToElement:
1536 current += QPointF(e.x, e.y) * matrix;
1538 case QPainterPath::CurveToElement: {
1539 Q_ASSERT(d->elements.at(i+1).type == QPainterPath::CurveToDataElement);
1540 Q_ASSERT(d->elements.at(i+2).type == QPainterPath::CurveToDataElement);
1541 QBezier bezier = QBezier::fromPoints(QPointF(d->elements.at(i-1).x, d->elements.at(i-1).y) * matrix,
1542 QPointF(e.x, e.y) * matrix,
1543 QPointF(d->elements.at(i+1).x, d->elements.at(i+1).y) * matrix,
1544 QPointF(d->elements.at(i+2).x, d->elements.at(i+2).y) * matrix);
1545 bezier.addToPolygon(¤t);
1549 case QPainterPath::CurveToDataElement:
1550 Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
1555 if (current.size()>1)
1556 flatCurves += current;
1564 QList<QPolygonF> QPainterPath::toSubpathPolygons(const QMatrix &matrix) const
1566 return toSubpathPolygons(QTransform(matrix));
1570 Converts the path into a list of polygons using the
1571 QTransform \a matrix, and returns the list.
1573 The function differs from the toFillPolygon() function in that it
1574 creates several polygons. It is provided because it is usually
1575 faster to draw several small polygons than to draw one large
1576 polygon, even though the total number of points drawn is the same.
1578 The toFillPolygons() function differs from the toSubpathPolygons()
1579 function in that it create only polygon for subpaths that have
1580 overlapping bounding rectangles.
1582 Like the toFillPolygon() function, this function uses a rewinding
1583 technique to make sure that overlapping subpaths can be filled
1584 using the correct fill rule. Note that rewinding inserts addition
1585 lines in the polygons so the outline of the fill polygon does not
1586 match the outline of the path.
1588 \sa toSubpathPolygons(), toFillPolygon(),
1589 {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
1591 QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
1594 QList<QPolygonF> polys;
1596 QList<QPolygonF> subpaths = toSubpathPolygons(matrix);
1597 int count = subpaths.size();
1602 QList<QRectF> bounds;
1603 for (int i=0; i<count; ++i)
1604 bounds += subpaths.at(i).boundingRect();
1606 #ifdef QPP_FILLPOLYGONS_DEBUG
1607 printf("QPainterPath::toFillPolygons, subpathCount=%d\n", count);
1608 for (int i=0; i<bounds.size(); ++i)
1609 qDebug() << " bounds" << i << bounds.at(i);
1612 QVector< QList<int> > isects;
1613 isects.resize(count);
1615 // find all intersections
1616 for (int j=0; j<count; ++j) {
1617 if (subpaths.at(j).size() <= 2)
1619 QRectF cbounds = bounds.at(j);
1620 for (int i=0; i<count; ++i) {
1621 if (cbounds.intersects(bounds.at(i))) {
1627 #ifdef QPP_FILLPOLYGONS_DEBUG
1628 printf("Intersections before flattening:\n");
1629 for (int i = 0; i < count; ++i) {
1631 for (int j = 0; j < isects[i].size(); ++j) {
1632 printf("%d ", isects[i][j]);
1638 // flatten the sets of intersections
1639 for (int i=0; i<count; ++i) {
1640 const QList<int> ¤t_isects = isects.at(i);
1641 for (int j=0; j<current_isects.size(); ++j) {
1642 int isect_j = current_isects.at(j);
1645 for (int k=0; k<isects[isect_j].size(); ++k) {
1646 int isect_k = isects[isect_j][k];
1647 if (isect_k != i && !isects.at(i).contains(isect_k)) {
1648 isects[i] += isect_k;
1651 isects[isect_j].clear();
1655 #ifdef QPP_FILLPOLYGONS_DEBUG
1656 printf("Intersections after flattening:\n");
1657 for (int i = 0; i < count; ++i) {
1659 for (int j = 0; j < isects[i].size(); ++j) {
1660 printf("%d ", isects[i][j]);
1666 // Join the intersected subpaths as rewinded polygons
1667 for (int i=0; i<count; ++i) {
1668 const QList<int> &subpath_list = isects[i];
1669 if (!subpath_list.isEmpty()) {
1671 for (int j=0; j<subpath_list.size(); ++j) {
1672 const QPolygonF &subpath = subpaths.at(subpath_list.at(j));
1674 if (!subpath.isClosed())
1675 buildUp += subpath.first();
1676 if (!buildUp.isClosed())
1677 buildUp += buildUp.first();
1689 QList<QPolygonF> QPainterPath::toFillPolygons(const QMatrix &matrix) const
1691 return toFillPolygons(QTransform(matrix));
1694 //same as qt_polygon_isect_line in qpolygon.cpp
1695 static void qt_painterpath_isect_line(const QPointF &p1,
1708 if (qFuzzyCompare(y1, y2)) {
1709 // ignore horizontal lines according to scan conversion rule
1711 } else if (y2 < y1) {
1712 qreal x_tmp = x2; x2 = x1; x1 = x_tmp;
1713 qreal y_tmp = y2; y2 = y1; y1 = y_tmp;
1717 if (y >= y1 && y < y2) {
1718 qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1);
1720 // count up the winding number if we're
1727 static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
1728 int *winding, int depth = 0)
1732 QRectF bounds = bezier.bounds();
1734 // potential intersection, divide and try again...
1735 // Please note that a sideeffect of the bottom exclusion is that
1736 // horizontal lines are dropped, but this is correct according to
1737 // scan conversion rules.
1738 if (y >= bounds.y() && y < bounds.y() + bounds.height()) {
1740 // hit lower limit... This is a rough threshold, but its a
1741 // tradeoff between speed and precision.
1742 const qreal lower_bound = qreal(.001);
1743 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) {
1744 // We make the assumption here that the curve starts to
1745 // approximate a line after while (i.e. that it doesn't
1746 // change direction drastically during its slope)
1747 if (bezier.pt1().x() <= x) {
1748 (*winding) += (bezier.pt4().y() > bezier.pt1().y() ? 1 : -1);
1753 // split curve and try again...
1754 QBezier first_half, second_half;
1755 bezier.split(&first_half, &second_half);
1756 qt_painterpath_isect_curve(first_half, pt, winding, depth + 1);
1757 qt_painterpath_isect_curve(second_half, pt, winding, depth + 1);
1762 \fn bool QPainterPath::contains(const QPointF &point) const
1764 Returns true if the given \a point is inside the path, otherwise
1769 bool QPainterPath::contains(const QPointF &pt) const
1771 if (isEmpty() || !controlPointRect().contains(pt))
1774 QPainterPathData *d = d_func();
1776 int winding_number = 0;
1780 for (int i=0; i<d->elements.size(); ++i) {
1781 const Element &e = d->elements.at(i);
1786 if (i > 0) // implicitly close all paths.
1787 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1788 last_start = last_pt = e;
1792 qt_painterpath_isect_line(last_pt, e, pt, &winding_number);
1796 case CurveToElement:
1798 const QPainterPath::Element &cp2 = d->elements.at(++i);
1799 const QPainterPath::Element &ep = d->elements.at(++i);
1800 qt_painterpath_isect_curve(QBezier::fromPoints(last_pt, e, cp2, ep),
1801 pt, &winding_number);
1812 // implicitly close last subpath
1813 if (last_pt != last_start)
1814 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1816 return (d->fillRule == Qt::WindingFill
1817 ? (winding_number != 0)
1818 : ((winding_number % 2) != 0));
1821 static bool qt_painterpath_isect_line_rect(qreal x1, qreal y1, qreal x2, qreal y2,
1824 qreal left = rect.left();
1825 qreal right = rect.right();
1826 qreal top = rect.top();
1827 qreal bottom = rect.bottom();
1829 enum { Left, Right, Top, Bottom };
1830 // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html
1831 int p1 = ((x1 < left) << Left)
1832 | ((x1 > right) << Right)
1833 | ((y1 < top) << Top)
1834 | ((y1 > bottom) << Bottom);
1835 int p2 = ((x2 < left) << Left)
1836 | ((x2 > right) << Right)
1837 | ((y2 < top) << Top)
1838 | ((y2 > bottom) << Bottom);
1841 // completely inside
1848 // clip x coordinates
1850 y1 += dy/dx * (left - x1);
1852 } else if (x1 > right) {
1853 y1 -= dy/dx * (x1 - right);
1857 y2 += dy/dx * (left - x2);
1859 } else if (x2 > right) {
1860 y2 -= dy/dx * (x2 - right);
1864 p1 = ((y1 < top) << Top)
1865 | ((y1 > bottom) << Bottom);
1866 p2 = ((y2 < top) << Top)
1867 | ((y2 > bottom) << Bottom);
1872 // clip y coordinates
1874 x1 += dx/dy * (top - y1);
1876 } else if (y1 > bottom) {
1877 x1 -= dx/dy * (y1 - bottom);
1881 x2 += dx/dy * (top - y2);
1883 } else if (y2 > bottom) {
1884 x2 -= dx/dy * (y2 - bottom);
1888 p1 = ((x1 < left) << Left)
1889 | ((x1 > right) << Right);
1890 p2 = ((x2 < left) << Left)
1891 | ((x2 > right) << Right);
1901 static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2, int depth = 0)
1903 QRectF bounds = bezier.bounds();
1905 if (y >= bounds.top() && y < bounds.bottom()
1906 && bounds.right() >= x1 && bounds.left() < x2) {
1907 const qreal lower_bound = qreal(.01);
1908 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
1911 QBezier first_half, second_half;
1912 bezier.split(&first_half, &second_half);
1913 if (qt_isect_curve_horizontal(first_half, y, x1, x2, depth + 1)
1914 || qt_isect_curve_horizontal(second_half, y, x1, x2, depth + 1))
1920 static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2, int depth = 0)
1922 QRectF bounds = bezier.bounds();
1924 if (x >= bounds.left() && x < bounds.right()
1925 && bounds.bottom() >= y1 && bounds.top() < y2) {
1926 const qreal lower_bound = qreal(.01);
1927 if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
1930 QBezier first_half, second_half;
1931 bezier.split(&first_half, &second_half);
1932 if (qt_isect_curve_vertical(first_half, x, y1, y2, depth + 1)
1933 || qt_isect_curve_vertical(second_half, x, y1, y2, depth + 1))
1940 Returns true if any lines or curves cross the four edges in of rect
1942 static bool qt_painterpath_check_crossing(const QPainterPath *path, const QRectF &rect)
1946 for (int i=0; i<path->elementCount(); ++i) {
1947 const QPainterPath::Element &e = path->elementAt(i);
1951 case QPainterPath::MoveToElement:
1953 && qFuzzyCompare(last_pt.x(), last_start.x())
1954 && qFuzzyCompare(last_pt.y(), last_start.y())
1955 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
1956 last_start.x(), last_start.y(), rect))
1958 last_start = last_pt = e;
1961 case QPainterPath::LineToElement:
1962 if (qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), e.x, e.y, rect))
1967 case QPainterPath::CurveToElement:
1969 QPointF cp2 = path->elementAt(++i);
1970 QPointF ep = path->elementAt(++i);
1971 QBezier bezier = QBezier::fromPoints(last_pt, e, cp2, ep);
1972 if (qt_isect_curve_horizontal(bezier, rect.top(), rect.left(), rect.right())
1973 || qt_isect_curve_horizontal(bezier, rect.bottom(), rect.left(), rect.right())
1974 || qt_isect_curve_vertical(bezier, rect.left(), rect.top(), rect.bottom())
1975 || qt_isect_curve_vertical(bezier, rect.right(), rect.top(), rect.bottom()))
1986 // implicitly close last subpath
1987 if (last_pt != last_start
1988 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
1989 last_start.x(), last_start.y(), rect))
1996 \fn bool QPainterPath::intersects(const QRectF &rectangle) const
1998 Returns true if any point in the given \a rectangle intersects the
1999 path; otherwise returns false.
2001 There is an intersection if any of the lines making up the
2002 rectangle crosses a part of the path or if any part of the
2003 rectangle overlaps with any area enclosed by the path. This
2004 function respects the current fillRule to determine what is
2005 considered inside the path.
2009 bool QPainterPath::intersects(const QRectF &rect) const
2011 if (elementCount() == 1 && rect.contains(elementAt(0)))
2017 QRectF cp = controlPointRect();
2018 QRectF rn = rect.normalized();
2020 // QRectF::intersects returns false if one of the rects is a null rect
2021 // which would happen for a painter path consisting of a vertical or
2023 if (qMax(rn.left(), cp.left()) > qMin(rn.right(), cp.right())
2024 || qMax(rn.top(), cp.top()) > qMin(rn.bottom(), cp.bottom()))
2027 // If any path element cross the rect its bound to be an intersection
2028 if (qt_painterpath_check_crossing(this, rect))
2031 if (contains(rect.center()))
2036 // Check if the rectangle surounds any subpath...
2037 for (int i=0; i<d->elements.size(); ++i) {
2038 const Element &e = d->elements.at(i);
2039 if (e.type == QPainterPath::MoveToElement && rect.contains(e))
2047 Translates all elements in the path by (\a{dx}, \a{dy}).
2052 void QPainterPath::translate(qreal dx, qreal dy)
2054 if (!d_ptr || (dx == 0 && dy == 0))
2057 int elementsLeft = d_ptr->elements.size();
2058 if (elementsLeft <= 0)
2062 QPainterPath::Element *element = d_func()->elements.data();
2064 while (elementsLeft--) {
2072 \fn void QPainterPath::translate(const QPointF &offset)
2076 Translates all elements in the path by the given \a offset.
2082 Returns a copy of the path that is translated by (\a{dx}, \a{dy}).
2087 QPainterPath QPainterPath::translated(qreal dx, qreal dy) const
2089 QPainterPath copy(*this);
2090 copy.translate(dx, dy);
2095 \fn QPainterPath QPainterPath::translated(const QPointF &offset) const;
2099 Returns a copy of the path that is translated by the given \a offset.
2105 \fn bool QPainterPath::contains(const QRectF &rectangle) const
2107 Returns true if the given \a rectangle is inside the path,
2108 otherwise returns false.
2110 bool QPainterPath::contains(const QRectF &rect) const
2114 // the path is empty or the control point rect doesn't completely
2115 // cover the rectangle we abort stratight away.
2116 if (isEmpty() || !controlPointRect().contains(rect))
2119 // if there are intersections, chances are that the rect is not
2120 // contained, except if we have winding rule, in which case it
2122 if (qt_painterpath_check_crossing(this, rect)) {
2123 if (fillRule() == Qt::OddEvenFill) {
2126 // Do some wague sampling in the winding case. This is not
2127 // precise but it should mostly be good enough.
2128 if (!contains(rect.topLeft()) ||
2129 !contains(rect.topRight()) ||
2130 !contains(rect.bottomRight()) ||
2131 !contains(rect.bottomLeft()))
2136 // If there exists a point inside that is not part of the path its
2137 // because: rectangle lies completely outside path or a subpath
2138 // excludes parts of the rectangle. Both cases mean that the rect
2140 if (!contains(rect.center()))
2143 // If there are any subpaths inside this rectangle we need to
2144 // check if they are still contained as a result of the fill
2145 // rule. This can only be the case for WindingFill though. For
2146 // OddEvenFill the rect will never be contained if it surrounds a
2147 // subpath. (the case where two subpaths are completely identical
2148 // can be argued but we choose to neglect it).
2149 for (int i=0; i<d->elements.size(); ++i) {
2150 const Element &e = d->elements.at(i);
2151 if (e.type == QPainterPath::MoveToElement && rect.contains(e)) {
2152 if (fillRule() == Qt::OddEvenFill)
2156 for (; !stop && i<d->elements.size(); ++i) {
2157 const Element &el = d->elements.at(i);
2166 case CurveToElement:
2167 if (!contains(d->elements.at(i+2)))
2176 // compensate for the last ++i in the inner for
2184 static inline bool epsilonCompare(const QPointF &a, const QPointF &b, const QSizeF &epsilon)
2186 return qAbs(a.x() - b.x()) <= epsilon.width()
2187 && qAbs(a.y() - b.y()) <= epsilon.height();
2191 Returns true if this painterpath is equal to the given \a path.
2193 Note that comparing paths may involve a per element comparison
2194 which can be slow for complex paths.
2199 bool QPainterPath::operator==(const QPainterPath &path) const
2201 QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
2202 if (path.d_func() == d)
2204 else if (!d || !path.d_func())
2206 else if (d->fillRule != path.d_func()->fillRule)
2208 else if (d->elements.size() != path.d_func()->elements.size())
2211 const qreal qt_epsilon = sizeof(qreal) == sizeof(double) ? 1e-12 : qreal(1e-5);
2213 QSizeF epsilon = boundingRect().size();
2214 epsilon.rwidth() *= qt_epsilon;
2215 epsilon.rheight() *= qt_epsilon;
2217 for (int i = 0; i < d->elements.size(); ++i)
2218 if (d->elements.at(i).type != path.d_func()->elements.at(i).type
2219 || !epsilonCompare(d->elements.at(i), path.d_func()->elements.at(i), epsilon))
2226 Returns true if this painter path differs from 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 return !(*this==path);
2242 Returns the intersection of this path and the \a other path.
2244 \sa intersected(), operator&=(), united(), operator|()
2246 QPainterPath QPainterPath::operator&(const QPainterPath &other) const
2248 return intersected(other);
2254 Returns the union of this path and the \a other path.
2256 \sa united(), operator|=(), intersected(), operator&()
2258 QPainterPath QPainterPath::operator|(const QPainterPath &other) const
2260 return united(other);
2266 Returns the union of this path and the \a other path. This function is equivalent
2269 \sa united(), operator+=(), operator-()
2271 QPainterPath QPainterPath::operator+(const QPainterPath &other) const
2273 return united(other);
2279 Subtracts the \a other path from a copy of this path, and returns the copy.
2281 \sa subtracted(), operator-=(), operator+()
2283 QPainterPath QPainterPath::operator-(const QPainterPath &other) const
2285 return subtracted(other);
2291 Intersects this path with \a other and returns a reference to this path.
2293 \sa intersected(), operator&(), operator|=()
2295 QPainterPath &QPainterPath::operator&=(const QPainterPath &other)
2297 return *this = (*this & other);
2303 Unites this path with \a other and returns a reference to this path.
2305 \sa united(), operator|(), operator&=()
2307 QPainterPath &QPainterPath::operator|=(const QPainterPath &other)
2309 return *this = (*this | other);
2315 Unites this path with \a other, and returns a reference to this path. This
2316 is equivalent to operator|=().
2318 \sa united(), operator+(), operator-=()
2320 QPainterPath &QPainterPath::operator+=(const QPainterPath &other)
2322 return *this = (*this + other);
2328 Subtracts \a other from this path, and returns a reference to this
2331 \sa subtracted(), operator-(), operator+=()
2333 QPainterPath &QPainterPath::operator-=(const QPainterPath &other)
2335 return *this = (*this - other);
2338 #ifndef QT_NO_DATASTREAM
2340 \fn QDataStream &operator<<(QDataStream &stream, const QPainterPath &path)
2341 \relates QPainterPath
2343 Writes the given painter \a path to the given \a stream, and
2344 returns a reference to the \a stream.
2346 \sa {Serializing Qt Data Types}
2348 QDataStream &operator<<(QDataStream &s, const QPainterPath &p)
2355 s << p.elementCount();
2356 for (int i=0; i < p.d_func()->elements.size(); ++i) {
2357 const QPainterPath::Element &e = p.d_func()->elements.at(i);
2359 s << double(e.x) << double(e.y);
2361 s << p.d_func()->cStart;
2362 s << int(p.d_func()->fillRule);
2367 \fn QDataStream &operator>>(QDataStream &stream, QPainterPath &path)
2368 \relates QPainterPath
2370 Reads a painter path from the given \a stream into the specified \a path,
2371 and returns a reference to the \a stream.
2373 \sa {Serializing Qt Data Types}
2375 QDataStream &operator>>(QDataStream &s, QPainterPath &p)
2383 p.ensureData(); // in case if p.d_func() == 0
2384 if (p.d_func()->elements.size() == 1) {
2385 Q_ASSERT(p.d_func()->elements.at(0).type == QPainterPath::MoveToElement);
2386 p.d_func()->elements.clear();
2388 p.d_func()->elements.reserve(p.d_func()->elements.size() + size);
2389 for (int i=0; i<size; ++i) {
2395 Q_ASSERT(type >= 0 && type <= 3);
2396 if (!qt_is_finite(x) || !qt_is_finite(y)) {
2398 qWarning("QDataStream::operator>>: NaN or Inf element found in path, skipping it");
2402 QPainterPath::Element elm = { x, y, QPainterPath::ElementType(type) };
2403 p.d_func()->elements.append(elm);
2405 s >> p.d_func()->cStart;
2408 Q_ASSERT(fillRule == Qt::OddEvenFill || Qt::WindingFill);
2409 p.d_func()->fillRule = Qt::FillRule(fillRule);
2410 p.d_func()->dirtyBounds = true;
2411 p.d_func()->dirtyControlBounds = true;
2414 #endif // QT_NO_DATASTREAM
2417 /*******************************************************************************
2418 * class QPainterPathStroker
2421 void qt_path_stroke_move_to(qfixed x, qfixed y, void *data)
2423 ((QPainterPath *) data)->moveTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
2426 void qt_path_stroke_line_to(qfixed x, qfixed y, void *data)
2428 ((QPainterPath *) data)->lineTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
2431 void qt_path_stroke_cubic_to(qfixed c1x, qfixed c1y,
2432 qfixed c2x, qfixed c2y,
2433 qfixed ex, qfixed ey,
2436 ((QPainterPath *) data)->cubicTo(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y),
2437 qt_fixed_to_real(c2x), qt_fixed_to_real(c2y),
2438 qt_fixed_to_real(ex), qt_fixed_to_real(ey));
2443 \class QPainterPathStroker
2446 \brief The QPainterPathStroker class is used to generate fillable
2447 outlines for a given painter path.
2449 By calling the createStroke() function, passing a given
2450 QPainterPath as argument, a new painter path representing the
2451 outline of the given path is created. The newly created painter
2452 path can then be filled to draw the original painter path's
2455 You can control the various design aspects (width, cap styles,
2456 join styles and dash pattern) of the outlining using the following
2466 The setDashPattern() function accepts both a Qt::PenStyle object
2467 and a vector representation of the pattern as argument.
2469 In addition you can specify a curve's threshold, controlling the
2470 granularity with which a curve is drawn, using the
2471 setCurveThreshold() function. The default threshold is a well
2472 adjusted value (0.25), and normally you should not need to modify
2473 it. However, you can make the curve's appearance smoother by
2474 decreasing its value.
2476 You can also control the miter limit for the generated outline
2477 using the setMiterLimit() function. The miter limit describes how
2478 far from each join the miter join can extend. The limit is
2479 specified in the units of width so the pixelwise miter limit will
2480 be \c {miterlimit * width}. This value is only used if the join
2481 style is Qt::MiterJoin.
2483 The painter path generated by the createStroke() function should
2484 only be used for outlining the given painter path. Otherwise it
2485 may cause unexpected behavior. Generated outlines also require the
2486 Qt::WindingFill rule which is set by default.
2491 QPainterPathStrokerPrivate::QPainterPathStrokerPrivate()
2494 stroker.setMoveToHook(qt_path_stroke_move_to);
2495 stroker.setLineToHook(qt_path_stroke_line_to);
2496 stroker.setCubicToHook(qt_path_stroke_cubic_to);
2500 Creates a new stroker.
2502 QPainterPathStroker::QPainterPathStroker()
2503 : d_ptr(new QPainterPathStrokerPrivate)
2508 Destroys the stroker.
2510 QPainterPathStroker::~QPainterPathStroker()
2516 Generates a new path that is a fillable area representing the
2517 outline of the given \a path.
2519 The various design aspects of the outline are based on the
2520 stroker's properties: width(), capStyle(), joinStyle(),
2521 dashPattern(), curveThreshold() and miterLimit().
2523 The generated path should only be used for outlining the given
2524 painter path. Otherwise it may cause unexpected
2525 behavior. Generated outlines also require the Qt::WindingFill rule
2526 which is set by default.
2528 QPainterPath QPainterPathStroker::createStroke(const QPainterPath &path) const
2530 QPainterPathStrokerPrivate *d = const_cast<QPainterPathStrokerPrivate *>(d_func());
2531 QPainterPath stroke;
2534 if (d->dashPattern.isEmpty()) {
2535 d->stroker.strokePath(path, &stroke, QTransform());
2537 QDashStroker dashStroker(&d->stroker);
2538 dashStroker.setDashPattern(d->dashPattern);
2539 dashStroker.setDashOffset(d->dashOffset);
2540 dashStroker.setClipRect(d->stroker.clipRect());
2541 dashStroker.strokePath(path, &stroke, QTransform());
2543 stroke.setFillRule(Qt::WindingFill);
2548 Sets the width of the generated outline painter path to \a width.
2550 The generated outlines will extend approximately 50% of \a width
2551 to each side of the given input path's original outline.
2553 void QPainterPathStroker::setWidth(qreal width)
2555 Q_D(QPainterPathStroker);
2558 d->stroker.setStrokeWidth(qt_real_to_fixed(width));
2562 Returns the width of the generated outlines.
2564 qreal QPainterPathStroker::width() const
2566 return qt_fixed_to_real(d_func()->stroker.strokeWidth());
2571 Sets the cap style of the generated outlines to \a style. If a
2572 dash pattern is set, each segment of the pattern is subject to the
2575 void QPainterPathStroker::setCapStyle(Qt::PenCapStyle style)
2577 d_func()->stroker.setCapStyle(style);
2582 Returns the cap style of the generated outlines.
2584 Qt::PenCapStyle QPainterPathStroker::capStyle() const
2586 return d_func()->stroker.capStyle();
2590 Sets the join style of the generated outlines to \a style.
2592 void QPainterPathStroker::setJoinStyle(Qt::PenJoinStyle style)
2594 d_func()->stroker.setJoinStyle(style);
2598 Returns the join style of the generated outlines.
2600 Qt::PenJoinStyle QPainterPathStroker::joinStyle() const
2602 return d_func()->stroker.joinStyle();
2606 Sets the miter limit of the generated outlines to \a limit.
2608 The miter limit describes how far from each join the miter join
2609 can extend. The limit is specified in units of the currently set
2610 width. So the pixelwise miter limit will be \c { miterlimit *
2613 This value is only used if the join style is Qt::MiterJoin.
2615 void QPainterPathStroker::setMiterLimit(qreal limit)
2617 d_func()->stroker.setMiterLimit(qt_real_to_fixed(limit));
2621 Returns the miter limit for the generated outlines.
2623 qreal QPainterPathStroker::miterLimit() const
2625 return qt_fixed_to_real(d_func()->stroker.miterLimit());
2630 Specifies the curve flattening \a threshold, controlling the
2631 granularity with which the generated outlines' curve is drawn.
2633 The default threshold is a well adjusted value (0.25), and
2634 normally you should not need to modify it. However, you can make
2635 the curve's appearance smoother by decreasing its value.
2637 void QPainterPathStroker::setCurveThreshold(qreal threshold)
2639 d_func()->stroker.setCurveThreshold(qt_real_to_fixed(threshold));
2643 Returns the curve flattening threshold for the generated
2646 qreal QPainterPathStroker::curveThreshold() const
2648 return qt_fixed_to_real(d_func()->stroker.curveThreshold());
2652 Sets the dash pattern for the generated outlines to \a style.
2654 void QPainterPathStroker::setDashPattern(Qt::PenStyle style)
2656 d_func()->dashPattern = QDashStroker::patternForStyle(style);
2662 Sets the dash pattern for the generated outlines to \a
2663 dashPattern. This function makes it possible to specify custom
2666 Each element in the vector contains the lengths of the dashes and spaces
2667 in the stroke, beginning with the first dash in the first element, the
2668 first space in the second element, and alternating between dashes and
2669 spaces for each following pair of elements.
2671 The vector can contain an odd number of elements, in which case the last
2672 element will be extended by the length of the first element when the
2675 void QPainterPathStroker::setDashPattern(const QVector<qreal> &dashPattern)
2677 d_func()->dashPattern.clear();
2678 for (int i=0; i<dashPattern.size(); ++i)
2679 d_func()->dashPattern << qt_real_to_fixed(dashPattern.at(i));
2683 Returns the dash pattern for the generated outlines.
2685 QVector<qreal> QPainterPathStroker::dashPattern() const
2687 return d_func()->dashPattern;
2691 Returns the dash offset for the generated outlines.
2693 qreal QPainterPathStroker::dashOffset() const
2695 return d_func()->dashOffset;
2699 Sets the dash offset for the generated outlines to \a offset.
2701 See the documentation for QPen::setDashOffset() for a description of the
2704 void QPainterPathStroker::setDashOffset(qreal offset)
2706 d_func()->dashOffset = offset;
2710 Converts the path into a polygon using the QTransform
2711 \a matrix, and returns the polygon.
2713 The polygon is created by first converting all subpaths to
2714 polygons, then using a rewinding technique to make sure that
2715 overlapping subpaths can be filled using the correct fill rule.
2717 Note that rewinding inserts addition lines in the polygon so
2718 the outline of the fill polygon does not match the outline of
2721 \sa toSubpathPolygons(), toFillPolygons(),
2722 {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
2724 QPolygonF QPainterPath::toFillPolygon(const QTransform &matrix) const
2727 QList<QPolygonF> flats = toSubpathPolygons(matrix);
2729 if (flats.isEmpty())
2731 QPointF first = flats.first().first();
2732 for (int i=0; i<flats.size(); ++i) {
2733 polygon += flats.at(i);
2734 if (!flats.at(i).isClosed())
2735 polygon += flats.at(i).first();
2745 QPolygonF QPainterPath::toFillPolygon(const QMatrix &matrix) const
2747 return toFillPolygon(QTransform(matrix));
2751 //derivative of the equation
2752 static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
2754 return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
2758 Returns the length of the current path.
2760 qreal QPainterPath::length() const
2767 for (int i=1; i<d->elements.size(); ++i) {
2768 const Element &e = d->elements.at(i);
2775 len += QLineF(d->elements.at(i-1), e).length();
2778 case CurveToElement:
2780 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2782 d->elements.at(i+1),
2783 d->elements.at(i+2));
2796 Returns percentage of the whole path at the specified length \a len.
2798 Note that similarly to other percent methods, the percentage measurement
2799 is not linear with regards to the length, if curves are present
2800 in the path. When curves are present the percentage argument is mapped
2801 to the t parameter of the Bezier equations.
2803 qreal QPainterPath::percentAtLength(qreal len) const
2806 if (isEmpty() || len <= 0)
2809 qreal totalLength = length();
2810 if (len > totalLength)
2814 for (int i=1; i<d->elements.size(); ++i) {
2815 const Element &e = d->elements.at(i);
2822 QLineF line(d->elements.at(i-1), e);
2823 qreal llen = line.length();
2825 if (curLen >= len) {
2826 return len/totalLength ;
2831 case CurveToElement:
2833 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2835 d->elements.at(i+1),
2836 d->elements.at(i+2));
2837 qreal blen = b.length();
2838 qreal prevLen = curLen;
2841 if (curLen >= len) {
2842 qreal res = b.tAtLength(len - prevLen);
2843 return (res * blen + prevLen)/totalLength;
2857 static inline QBezier bezierAtT(const QPainterPath &path, qreal t, qreal *startingLength, qreal *bezierLength)
2859 *startingLength = 0;
2864 qreal totalLength = path.length();
2866 const int lastElement = path.elementCount() - 1;
2867 for (int i=0; i <= lastElement; ++i) {
2868 const QPainterPath::Element &e = path.elementAt(i);
2871 case QPainterPath::MoveToElement:
2873 case QPainterPath::LineToElement:
2875 QLineF line(path.elementAt(i-1), e);
2876 qreal llen = line.length();
2878 if (i == lastElement || curLen/totalLength >= t) {
2879 *bezierLength = llen;
2880 QPointF a = path.elementAt(i-1);
2881 QPointF delta = e - a;
2882 return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
2886 case QPainterPath::CurveToElement:
2888 QBezier b = QBezier::fromPoints(path.elementAt(i-1),
2890 path.elementAt(i+1),
2891 path.elementAt(i+2));
2892 qreal blen = b.length();
2895 if (i + 2 == lastElement || curLen/totalLength >= t) {
2896 *bezierLength = blen;
2906 *startingLength = curLen;
2912 Returns the point at at the percentage \a t of the current path.
2913 The argument \a t has to be between 0 and 1.
2915 Note that similarly to other percent methods, the percentage measurement
2916 is not linear with regards to the length, if curves are present
2917 in the path. When curves are present the percentage argument is mapped
2918 to the t parameter of the Bezier equations.
2920 QPointF QPainterPath::pointAtPercent(qreal t) const
2922 if (t < 0 || t > 1) {
2923 qWarning("QPainterPath::pointAtPercent accepts only values between 0 and 1");
2927 if (!d_ptr || d_ptr->elements.size() == 0)
2930 if (d_ptr->elements.size() == 1)
2931 return d_ptr->elements.at(0);
2933 qreal totalLength = length();
2935 qreal bezierLen = 0;
2936 QBezier b = bezierAtT(*this, t, &curLen, &bezierLen);
2937 qreal realT = (totalLength * t - curLen) / bezierLen;
2939 return b.pointAt(qBound(qreal(0), realT, qreal(1)));
2943 Returns the angle of the path tangent at the percentage \a t.
2944 The argument \a t has to be between 0 and 1.
2946 Positive values for the angles mean counter-clockwise while negative values
2947 mean the clockwise direction. Zero degrees is at the 3 o'clock position.
2949 Note that similarly to the other percent methods, the percentage measurement
2950 is not linear with regards to the length if curves are present
2951 in the path. When curves are present the percentage argument is mapped
2952 to the t parameter of the Bezier equations.
2954 qreal QPainterPath::angleAtPercent(qreal t) const
2956 if (t < 0 || t > 1) {
2957 qWarning("QPainterPath::angleAtPercent accepts only values between 0 and 1");
2961 qreal totalLength = length();
2963 qreal bezierLen = 0;
2964 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
2965 qreal realT = (totalLength * t - curLen) / bezierLen;
2967 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
2968 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
2970 return QLineF(0, 0, m1, m2).angle();
2973 #if defined(Q_WS_WINCE)
2974 #pragma warning( disable : 4056 4756 )
2978 Returns the slope of the path at the percentage \a t. The
2979 argument \a t has to be between 0 and 1.
2981 Note that similarly to other percent methods, the percentage measurement
2982 is not linear with regards to the length, if curves are present
2983 in the path. When curves are present the percentage argument is mapped
2984 to the t parameter of the Bezier equations.
2986 qreal QPainterPath::slopeAtPercent(qreal t) const
2988 if (t < 0 || t > 1) {
2989 qWarning("QPainterPath::slopeAtPercent accepts only values between 0 and 1");
2993 qreal totalLength = length();
2995 qreal bezierLen = 0;
2996 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
2997 qreal realT = (totalLength * t - curLen) / bezierLen;
2999 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
3000 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
3004 #define SIGN(x) ((x < 0)?-1:1)
3008 //windows doesn't define INFINITY :(
3010 slope = INFINITY*SIGN(m2);
3012 if (sizeof(qreal) == sizeof(double)) {
3013 return 1.79769313486231570e+308;
3015 return ((qreal)3.40282346638528860e+38);
3026 Adds the given rectangle \a rect with rounded corners to the path.
3028 The \a xRadius and \a yRadius arguments specify the radii of
3029 the ellipses defining the corners of the rounded rectangle.
3030 When \a mode is Qt::RelativeSize, \a xRadius and
3031 \a yRadius are specified in percentage of half the rectangle's
3032 width and height respectively, and should be in the range 0.0 to 100.0.
3036 void QPainterPath::addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius,
3039 QRectF r = rect.normalized();
3044 if (mode == Qt::AbsoluteSize) {
3045 qreal w = r.width() / 2;
3046 qreal h = r.height() / 2;
3051 xRadius = 100 * qMin(xRadius, w) / w;
3056 yRadius = 100 * qMin(yRadius, h) / h;
3059 if (xRadius > 100) // fix ranges
3066 if (xRadius <= 0 || yRadius <= 0) { // add normal rectangle
3073 qreal w = r.width();
3074 qreal h = r.height();
3075 qreal rxx2 = w*xRadius/100;
3076 qreal ryy2 = h*yRadius/100;
3081 bool first = d_func()->elements.size() < 2;
3083 arcMoveTo(x, y, rxx2, ryy2, 180);
3084 arcTo(x, y, rxx2, ryy2, 180, -90);
3085 arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3086 arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3087 arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3090 d_func()->require_moveTo = true;
3091 d_func()->convex = first;
3095 \fn void QPainterPath::addRoundedRect(qreal x, qreal y, qreal w, qreal h, qreal xRadius, qreal yRadius, Qt::SizeMode mode = Qt::AbsoluteSize);
3099 Adds the given rectangle \a x, \a y, \a w, \a h with rounded corners to the path.
3105 Adds a rectangle \a r with rounded corners to the path.
3107 The \a xRnd and \a yRnd arguments specify how rounded the corners
3108 should be. 0 is angled corners, 99 is maximum roundedness.
3110 \sa addRoundedRect()
3112 void QPainterPath::addRoundRect(const QRectF &r, int xRnd, int yRnd)
3114 if(xRnd >= 100) // fix ranges
3118 if(xRnd <= 0 || yRnd <= 0) { // add normal rectangle
3123 QRectF rect = r.normalized();
3130 qreal w = rect.width();
3131 qreal h = rect.height();
3132 qreal rxx2 = w*xRnd/100;
3133 qreal ryy2 = h*yRnd/100;
3138 bool first = d_func()->elements.size() < 2;
3140 arcMoveTo(x, y, rxx2, ryy2, 180);
3141 arcTo(x, y, rxx2, ryy2, 180, -90);
3142 arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3143 arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3144 arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3147 d_func()->require_moveTo = true;
3148 d_func()->convex = first;
3154 \fn bool QPainterPath::addRoundRect(const QRectF &rect, int roundness);
3158 Adds a rounded rectangle, \a rect, to the path.
3160 The \a roundness argument specifies uniform roundness for the
3161 rectangle. Vertical and horizontal roundness factors will be
3162 adjusted accordingly to act uniformly around both axes. Use this
3163 method if you want a rectangle equally rounded across both the X and
3166 \sa addRoundedRect()
3172 \fn void QPainterPath::addRoundRect(qreal x, qreal y, qreal w, qreal h, int xRnd, int yRnd);
3175 Adds a rectangle with rounded corners to the path. The rectangle
3176 is constructed from \a x, \a y, and the width and height \a w
3179 The \a xRnd and \a yRnd arguments specify how rounded the corners
3180 should be. 0 is angled corners, 99 is maximum roundedness.
3182 \sa addRoundedRect()
3188 \fn bool QPainterPath::addRoundRect(qreal x, qreal y, qreal width, qreal height, int roundness);
3192 Adds a rounded rectangle to the path, defined by the coordinates \a
3193 x and \a y with the specified \a width and \a height.
3195 The \a roundness argument specifies uniform roundness for the
3196 rectangle. Vertical and horizontal roundness factors will be
3197 adjusted accordingly to act uniformly around both axes. Use this
3198 method if you want a rectangle equally rounded across both the X and
3201 \sa addRoundedRect()
3207 Returns a path which is the union of this path's fill area and \a p's fill area.
3209 Set operations on paths will treat the paths as areas. Non-closed
3210 paths will be treated as implicitly closed.
3211 Bezier curves may be flattened to line segments due to numerical instability of
3212 doing bezier curve intersections.
3214 \sa intersected(), subtracted()
3216 QPainterPath QPainterPath::united(const QPainterPath &p) const
3218 if (isEmpty() || p.isEmpty())
3219 return isEmpty() ? p : *this;
3220 QPathClipper clipper(*this, p);
3221 return clipper.clip(QPathClipper::BoolOr);
3227 Returns a path which is the intersection of this path's fill area and \a p's fill area.
3228 Bezier curves may be flattened to line segments due to numerical instability of
3229 doing bezier curve intersections.
3231 QPainterPath QPainterPath::intersected(const QPainterPath &p) const
3233 if (isEmpty() || p.isEmpty())
3234 return QPainterPath();
3235 QPathClipper clipper(*this, p);
3236 return clipper.clip(QPathClipper::BoolAnd);
3242 Returns a path which is \a p's fill area subtracted from this path's fill area.
3244 Set operations on paths will treat the paths as areas. Non-closed
3245 paths will be treated as implicitly closed.
3246 Bezier curves may be flattened to line segments due to numerical instability of
3247 doing bezier curve intersections.
3249 QPainterPath QPainterPath::subtracted(const QPainterPath &p) const
3251 if (isEmpty() || p.isEmpty())
3253 QPathClipper clipper(*this, p);
3254 return clipper.clip(QPathClipper::BoolSub);
3261 Use subtracted() instead.
3265 QPainterPath QPainterPath::subtractedInverted(const QPainterPath &p) const
3267 return p.subtracted(*this);
3273 Returns a simplified version of this path. This implies merging all subpaths that intersect,
3274 and returning a path containing no intersecting edges. Consecutive parallel lines will also
3275 be merged. The simplified path will always use the default fill rule, Qt::OddEvenFill.
3276 Bezier curves may be flattened to line segments due to numerical instability of
3277 doing bezier curve intersections.
3279 QPainterPath QPainterPath::simplified() const
3283 QPathClipper clipper(*this, QPainterPath());
3284 return clipper.clip(QPathClipper::Simplify);
3290 Returns true if the current path intersects at any point the given path \a p.
3291 Also returns true if the current path contains or is contained by any part of \a p.
3293 Set operations on paths will treat the paths as areas. Non-closed
3294 paths will be treated as implicitly closed.
3298 bool QPainterPath::intersects(const QPainterPath &p) const
3300 if (p.elementCount() == 1)
3301 return contains(p.elementAt(0));
3302 if (isEmpty() || p.isEmpty())
3304 QPathClipper clipper(*this, p);
3305 return clipper.intersect();
3311 Returns true if the given path \a p is contained within
3312 the current path. Returns false if any edges of the current path and
3315 Set operations on paths will treat the paths as areas. Non-closed
3316 paths will be treated as implicitly closed.
3320 bool QPainterPath::contains(const QPainterPath &p) const
3322 if (p.elementCount() == 1)
3323 return contains(p.elementAt(0));
3324 if (isEmpty() || p.isEmpty())
3326 QPathClipper clipper(*this, p);
3327 return clipper.contains();
3330 void QPainterPath::setDirty(bool dirty)
3332 d_func()->dirtyBounds = dirty;
3333 d_func()->dirtyControlBounds = dirty;
3334 delete d_func()->pathConverter;
3335 d_func()->pathConverter = 0;
3336 d_func()->convex = false;
3339 void QPainterPath::computeBoundingRect() const
3341 QPainterPathData *d = d_func();
3342 d->dirtyBounds = false;
3344 d->bounds = QRect();
3348 qreal minx, maxx, miny, maxy;
3349 minx = maxx = d->elements.at(0).x;
3350 miny = maxy = d->elements.at(0).y;
3351 for (int i=1; i<d->elements.size(); ++i) {
3352 const Element &e = d->elements.at(i);
3357 if (e.x > maxx) maxx = e.x;
3358 else if (e.x < minx) minx = e.x;
3359 if (e.y > maxy) maxy = e.y;
3360 else if (e.y < miny) miny = e.y;
3362 case CurveToElement:
3364 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
3366 d->elements.at(i+1),
3367 d->elements.at(i+2));
3368 QRectF r = qt_painterpath_bezier_extrema(b);
3369 qreal right = r.right();
3370 qreal bottom = r.bottom();
3371 if (r.x() < minx) minx = r.x();
3372 if (right > maxx) maxx = right;
3373 if (r.y() < miny) miny = r.y();
3374 if (bottom > maxy) maxy = bottom;
3382 d->bounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3386 void QPainterPath::computeControlPointRect() const
3388 QPainterPathData *d = d_func();
3389 d->dirtyControlBounds = false;
3391 d->controlBounds = QRect();
3395 qreal minx, maxx, miny, maxy;
3396 minx = maxx = d->elements.at(0).x;
3397 miny = maxy = d->elements.at(0).y;
3398 for (int i=1; i<d->elements.size(); ++i) {
3399 const Element &e = d->elements.at(i);
3400 if (e.x > maxx) maxx = e.x;
3401 else if (e.x < minx) minx = e.x;
3402 if (e.y > maxy) maxy = e.y;
3403 else if (e.y < miny) miny = e.y;
3405 d->controlBounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3408 #ifndef QT_NO_DEBUG_STREAM
3409 QDebug operator<<(QDebug s, const QPainterPath &p)
3411 s.nospace() << "QPainterPath: Element count=" << p.elementCount() << endl;
3412 const char *types[] = {"MoveTo", "LineTo", "CurveTo", "CurveToData"};
3413 for (int i=0; i<p.elementCount(); ++i) {
3414 s.nospace() << " -> " << types[p.elementAt(i).type] << "(x=" << p.elementAt(i).x << ", y=" << p.elementAt(i).y << ')' << endl;