source: trunk/src/gui/painting/qpainterpath.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 97.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qpainterpath.h"
43#include "qpainterpath_p.h"
44
45#include <qbitmap.h>
46#include <qdebug.h>
47#include <qiodevice.h>
48#include <qlist.h>
49#include <qmatrix.h>
50#include <qpen.h>
51#include <qpolygon.h>
52#include <qtextlayout.h>
53#include <qvarlengtharray.h>
54#include <qmath.h>
55
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>
63
64#include <limits.h>
65
66#if 0
67#include <performance.h>
68#else
69#define PM_INIT
70#define PM_MEASURE(x)
71#define PM_DISPLAY
72#endif
73
74QT_BEGIN_NAMESPACE
75
76struct QPainterPathPrivateDeleter
77{
78 static inline void cleanup(QPainterPathPrivate *d)
79 {
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);
84 }
85};
86
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.
90
91// #define QPP_DEBUG
92// #define QPP_STROKE_DEBUG
93//#define QPP_FILLPOLYGONS_DEBUG
94
95QPainterPath qt_stroke_dash(const QPainterPath &path, qreal *dashes, int dashCount);
96
97void qt_find_ellipse_coords(const QRectF &r, qreal angle, qreal length,
98 QPointF* startPoint, QPointF *endPoint)
99{
100 if (r.isNull()) {
101 if (startPoint)
102 *startPoint = QPointF();
103 if (endPoint)
104 *endPoint = QPointF();
105 return;
106 }
107
108 qreal w2 = r.width() / 2;
109 qreal h2 = r.height() / 2;
110
111 qreal angles[2] = { angle, angle + length };
112 QPointF *points[2] = { startPoint, endPoint };
113
114 for (int i = 0; i < 2; ++i) {
115 if (!points[i])
116 continue;
117
118 qreal theta = angles[i] - 360 * qFloor(angles[i] / 360);
119 qreal t = theta / 90;
120 // truncate
121 int quadrant = int(t);
122 t -= quadrant;
123
124 t = qt_t_for_arc_angle(90 * t);
125
126 // swap x and y?
127 if (quadrant & 1)
128 t = 1 - t;
129
130 qreal a, b, c, d;
131 QBezier::coefficients(t, a, b, c, d);
132 QPointF p(a + b + c*QT_PATH_KAPPA, d + c + b*QT_PATH_KAPPA);
133
134 // left quadrants
135 if (quadrant == 1 || quadrant == 2)
136 p.rx() = -p.x();
137
138 // top quadrants
139 if (quadrant == 0 || quadrant == 1)
140 p.ry() = -p.y();
141
142 *points[i] = r.center() + QPointF(w2 * p.x(), h2 * p.y());
143 }
144}
145
146#ifdef QPP_DEBUG
147static void qt_debug_path(const QPainterPath &path)
148{
149 const char *names[] = {
150 "MoveTo ",
151 "LineTo ",
152 "CurveTo ",
153 "CurveToData"
154 };
155
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);
161 }
162}
163#endif
164
165/*!
166 \class QPainterPath
167 \ingroup painting
168 \ingroup shared
169
170 \brief The QPainterPath class provides a container for painting operations,
171 enabling graphical shapes to be constructed and reused.
172
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.
179
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.
186
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.
192
193 \tableofcontents
194
195 \section1 Composing a QPainterPath
196
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
202 as argument.
203
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().
213
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.
219
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.
224
225 Below is a code snippet that shows how a QPainterPath object can
226 be used:
227
228 \table 100%
229 \row
230 \o \inlineimage qpainterpath-construction.png
231 \o
232 \snippet doc/src/snippets/code/src_gui_painting_qpainterpath.cpp 0
233 \endtable
234
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:
241
242 \table
243 \row
244 \o \inlineimage qt-fillrule-oddeven.png
245 \o \inlineimage qt-fillrule-winding.png
246 \header
247 \o Qt::OddEvenFill
248 \o Qt::WindingFill
249 \endtable
250
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()
254 function.
255
256 \section1 QPainterPath Information
257
258 The QPainterPath class provides a collection of functions that
259 returns information about the path and its elements.
260
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.
267
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.
273
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.
278
279 \section1 QPainterPath Conversion
280
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.
287
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.
297
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
303 outline of the path.
304
305 \section1 Examples
306
307 Qt provides the \l {painting/painterpaths}{Painter Paths Example}
308 and the \l {demos/deform}{Vector Deformation Demo} which are
309 located in Qt's example and demo directories respectively.
310
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 {demos/deform}{Vector Deformation Demo} shows how to use
315 QPainterPath to draw text.
316
317 \table
318 \row
319 \o \inlineimage qpainterpath-example.png
320 \o \inlineimage qpainterpath-demo.png
321 \header
322 \o \l {painting/painterpaths}{Painter Paths Example}
323 \o \l {demos/deform}{Vector Deformation Demo}
324 \endtable
325
326 \sa QPainterPathStroker, QPainter, QRegion, {Painter Paths Example}
327*/
328
329/*!
330 \enum QPainterPath::ElementType
331
332 This enum describes the types of elements used to connect vertices
333 in subpaths.
334
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
339 cubicTo() functions.
340
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.
346
347 \sa elementAt(), elementCount()
348*/
349
350/*!
351 \class QPainterPath::Element
352
353 \brief The QPainterPath::Element class specifies the position and
354 type of a subpath.
355
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
359 components).
360
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.
367
368 \sa QPainterPath
369*/
370
371/*!
372 \variable QPainterPath::Element::x
373 \brief the x coordinate of the element's position.
374
375 \sa {operator QPointF()}
376*/
377
378/*!
379 \variable QPainterPath::Element::y
380 \brief the y coordinate of the element's position.
381
382 \sa {operator QPointF()}
383*/
384
385/*!
386 \variable QPainterPath::Element::type
387 \brief the type of element
388
389 \sa isCurveTo(), isLineTo(), isMoveTo()
390*/
391
392/*!
393 \fn bool QPainterPath::Element::operator==(const Element &other) const
394 \since 4.2
395
396 Returns true if this element is equal to \a other;
397 otherwise returns false.
398
399 \sa operator!=()
400*/
401
402/*!
403 \fn bool QPainterPath::Element::operator!=(const Element &other) const
404 \since 4.2
405
406 Returns true if this element is not equal to \a other;
407 otherwise returns false.
408
409 \sa operator==()
410*/
411
412/*!
413 \fn bool QPainterPath::Element::isCurveTo () const
414
415 Returns true if the element is a curve, otherwise returns false.
416
417 \sa type, QPainterPath::CurveToElement
418*/
419
420/*!
421 \fn bool QPainterPath::Element::isLineTo () const
422
423 Returns true if the element is a line, otherwise returns false.
424
425 \sa type, QPainterPath::LineToElement
426*/
427
428/*!
429 \fn bool QPainterPath::Element::isMoveTo () const
430
431 Returns true if the element is moving the current position,
432 otherwise returns false.
433
434 \sa type, QPainterPath::MoveToElement
435*/
436
437/*!
438 \fn QPainterPath::Element::operator QPointF () const
439
440 Returns the element's position.
441
442 \sa x, y
443*/
444
445/*!
446 \fn void QPainterPath::addEllipse(qreal x, qreal y, qreal width, qreal height)
447 \overload
448
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.
452*/
453
454/*!
455 \since 4.4
456
457 \fn void QPainterPath::addEllipse(const QPointF &center, qreal rx, qreal ry)
458 \overload
459
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.
462*/
463
464/*!
465 \fn void QPainterPath::addText(qreal x, qreal y, const QFont &font, const QString &text)
466 \overload
467
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).
471*/
472
473/*!
474 \fn int QPainterPath::elementCount() const
475
476 Returns the number of path elements in the painter path.
477
478 \sa ElementType, elementAt(), isEmpty()
479*/
480
481/*!
482 \fn const QPainterPath::Element &QPainterPath::elementAt(int index) const
483
484 Returns the element at the given \a index in the painter path.
485
486 \sa ElementType, elementCount(), isEmpty()
487*/
488
489/*!
490 \fn void QPainterPath::setElementPositionAt(int index, qreal x, qreal y)
491 \since 4.2
492
493 Sets the x and y coordinate of the element at index \a index to \a
494 x and \a y.
495*/
496
497/*###
498 \fn QPainterPath &QPainterPath::operator +=(const QPainterPath &other)
499
500 Appends the \a other painter path to this painter path and returns a
501 reference to the result.
502*/
503
504/*!
505 Constructs an empty QPainterPath object.
506*/
507QPainterPath::QPainterPath()
508 : d_ptr(0)
509{
510}
511
512/*!
513 \fn QPainterPath::QPainterPath(const QPainterPath &path)
514
515 Creates a QPainterPath object that is a copy of the given \a path.
516
517 \sa operator=()
518*/
519QPainterPath::QPainterPath(const QPainterPath &other)
520 : d_ptr(other.d_ptr.data())
521{
522 if (d_ptr)
523 d_ptr->ref.ref();
524}
525
526/*!
527 Creates a QPainterPath object with the given \a startPoint as its
528 current position.
529*/
530
531QPainterPath::QPainterPath(const QPointF &startPoint)
532 : d_ptr(new QPainterPathData)
533{
534 Element e = { startPoint.x(), startPoint.y(), MoveToElement };
535 d_func()->elements << e;
536}
537
538/*!
539 \internal
540*/
541void QPainterPath::detach_helper()
542{
543 QPainterPathPrivate *data = new QPainterPathData(*d_func());
544 d_ptr.reset(data);
545}
546
547/*!
548 \internal
549*/
550void QPainterPath::ensureData_helper()
551{
552 QPainterPathPrivate *data = new QPainterPathData;
553 data->elements.reserve(16);
554 QPainterPath::Element e = { 0, 0, QPainterPath::MoveToElement };
555 data->elements << e;
556 d_ptr.reset(data);
557 Q_ASSERT(d_ptr != 0);
558}
559
560/*!
561 \fn QPainterPath &QPainterPath::operator=(const QPainterPath &path)
562
563 Assigns the given \a path to this painter path.
564
565 \sa QPainterPath()
566*/
567QPainterPath &QPainterPath::operator=(const QPainterPath &other)
568{
569 if (other.d_func() != d_func()) {
570 QPainterPathPrivate *data = other.d_func();
571 if (data)
572 data->ref.ref();
573 d_ptr.reset(data);
574 }
575 return *this;
576}
577
578/*!
579 Destroys this QPainterPath object.
580*/
581QPainterPath::~QPainterPath()
582{
583}
584
585/*!
586 Closes the current subpath by drawing a line to the beginning of
587 the subpath, automatically starting a new path. The current point
588 of the new path is (0, 0).
589
590 If the subpath does not contain any elements, this function does
591 nothing.
592
593 \sa moveTo(), {QPainterPath#Composing a QPainterPath}{Composing
594 a QPainterPath}
595 */
596void QPainterPath::closeSubpath()
597{
598#ifdef QPP_DEBUG
599 printf("QPainterPath::closeSubpath()\n");
600#endif
601 if (isEmpty())
602 return;
603 detach();
604
605 d_func()->close();
606}
607
608/*!
609 \fn void QPainterPath::moveTo(qreal x, qreal y)
610
611 \overload
612
613 Moves the current position to (\a{x}, \a{y}) and starts a new
614 subpath, implicitly closing the previous path.
615*/
616
617/*!
618 \fn void QPainterPath::moveTo(const QPointF &point)
619
620 Moves the current point to the given \a point, implicitly starting
621 a new subpath and closing the previous one.
622
623 \sa closeSubpath(), {QPainterPath#Composing a
624 QPainterPath}{Composing a QPainterPath}
625*/
626void QPainterPath::moveTo(const QPointF &p)
627{
628#ifdef QPP_DEBUG
629 printf("QPainterPath::moveTo() (%.2f,%.2f)\n", p.x(), p.y());
630#endif
631#ifndef QT_NO_DEBUG
632 if (qt_is_nan(p.x()) || qt_is_nan(p.y()))
633 qWarning("QPainterPath::moveTo: Adding point where x or y is NaN, results are undefined");
634#endif
635 ensureData();
636 detach();
637
638 QPainterPathData *d = d_func();
639 Q_ASSERT(!d->elements.isEmpty());
640
641 d->require_moveTo = false;
642
643 if (d->elements.last().type == MoveToElement) {
644 d->elements.last().x = p.x();
645 d->elements.last().y = p.y();
646 } else {
647 Element elm = { p.x(), p.y(), MoveToElement };
648 d->elements.append(elm);
649 }
650 d->cStart = d->elements.size() - 1;
651}
652
653/*!
654 \fn void QPainterPath::lineTo(qreal x, qreal y)
655
656 \overload
657
658 Draws a line from the current position to the point (\a{x},
659 \a{y}).
660*/
661
662/*!
663 \fn void QPainterPath::lineTo(const QPointF &endPoint)
664
665 Adds a straight line from the current position to the given \a
666 endPoint. After the line is drawn, the current position is updated
667 to be at the end point of the line.
668
669 \sa addPolygon(), addRect(), {QPainterPath#Composing a
670 QPainterPath}{Composing a QPainterPath}
671 */
672void QPainterPath::lineTo(const QPointF &p)
673{
674#ifdef QPP_DEBUG
675 printf("QPainterPath::lineTo() (%.2f,%.2f)\n", p.x(), p.y());
676#endif
677#ifndef QT_NO_DEBUG
678 if (qt_is_nan(p.x()) || qt_is_nan(p.y()))
679 qWarning("QPainterPath::lineTo: Adding point where x or y is NaN, results are undefined");
680#endif
681 ensureData();
682 detach();
683
684 QPainterPathData *d = d_func();
685 Q_ASSERT(!d->elements.isEmpty());
686 d->maybeMoveTo();
687 if (p == QPointF(d->elements.last()))
688 return;
689 Element elm = { p.x(), p.y(), LineToElement };
690 d->elements.append(elm);
691
692 d->convex = d->elements.size() == 3 || (d->elements.size() == 4 && d->isClosed());
693}
694
695/*!
696 \fn void QPainterPath::cubicTo(qreal c1X, qreal c1Y, qreal c2X,
697 qreal c2Y, qreal endPointX, qreal endPointY);
698
699 \overload
700
701 Adds a cubic Bezier curve between the current position and the end
702 point (\a{endPointX}, \a{endPointY}) with control points specified
703 by (\a{c1X}, \a{c1Y}) and (\a{c2X}, \a{c2Y}).
704*/
705
706/*!
707 \fn void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &endPoint)
708
709 Adds a cubic Bezier curve between the current position and the
710 given \a endPoint using the control points specified by \a c1, and
711 \a c2.
712
713 After the curve is added, the current position is updated to be at
714 the end point of the curve.
715
716 \table 100%
717 \row
718 \o \inlineimage qpainterpath-cubicto.png
719 \o
720 \snippet doc/src/snippets/code/src_gui_painting_qpainterpath.cpp 1
721 \endtable
722
723 \sa quadTo(), {QPainterPath#Composing a QPainterPath}{Composing
724 a QPainterPath}
725*/
726void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &e)
727{
728#ifdef QPP_DEBUG
729 printf("QPainterPath::cubicTo() (%.2f,%.2f), (%.2f,%.2f), (%.2f,%.2f)\n",
730 c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
731#endif
732#ifndef QT_NO_DEBUG
733 if (qt_is_nan(c1.x()) || qt_is_nan(c1.y()) || qt_is_nan(c2.x()) || qt_is_nan(c2.y())
734 || qt_is_nan(e.x()) || qt_is_nan(e.y()))
735 qWarning("QPainterPath::cubicTo: Adding point where x or y is NaN, results are undefined");
736#endif
737 ensureData();
738 detach();
739
740 QPainterPathData *d = d_func();
741 Q_ASSERT(!d->elements.isEmpty());
742
743
744 // Abort on empty curve as a stroker cannot handle this and the
745 // curve is irrelevant anyway.
746 if (d->elements.last() == c1 && c1 == c2 && c2 == e)
747 return;
748
749 d->maybeMoveTo();
750
751 Element ce1 = { c1.x(), c1.y(), CurveToElement };
752 Element ce2 = { c2.x(), c2.y(), CurveToDataElement };
753 Element ee = { e.x(), e.y(), CurveToDataElement };
754 d->elements << ce1 << ce2 << ee;
755}
756
757/*!
758 \fn void QPainterPath::quadTo(qreal cx, qreal cy, qreal endPointX, qreal endPointY);
759
760 \overload
761
762 Adds a quadratic Bezier curve between the current point and the endpoint
763 (\a{endPointX}, \a{endPointY}) with the control point specified by
764 (\a{cx}, \a{cy}).
765*/
766
767/*!
768 \fn void QPainterPath::quadTo(const QPointF &c, const QPointF &endPoint)
769
770 Adds a quadratic Bezier curve between the current position and the
771 given \a endPoint with the control point specified by \a c.
772
773 After the curve is added, the current point is updated to be at
774 the end point of the curve.
775
776 \sa cubicTo(), {QPainterPath#Composing a QPainterPath}{Composing a
777 QPainterPath}
778*/
779void QPainterPath::quadTo(const QPointF &c, const QPointF &e)
780{
781#ifdef QPP_DEBUG
782 printf("QPainterPath::quadTo() (%.2f,%.2f), (%.2f,%.2f)\n",
783 c.x(), c.y(), e.x(), e.y());
784#endif
785#ifndef QT_NO_DEBUG
786 if (qt_is_nan(c.x()) || qt_is_nan(c.y()) || qt_is_nan(e.x()) || qt_is_nan(e.y()))
787 qWarning("QPainterPath::quadTo: Adding point where x or y is NaN, results are undefined");
788#endif
789 ensureData();
790 detach();
791
792 Q_D(QPainterPath);
793 Q_ASSERT(!d->elements.isEmpty());
794 const QPainterPath::Element &elm = d->elements.at(elementCount()-1);
795 QPointF prev(elm.x, elm.y);
796
797 // Abort on empty curve as a stroker cannot handle this and the
798 // curve is irrelevant anyway.
799 if (prev == c && c == e)
800 return;
801
802 QPointF c1((prev.x() + 2*c.x()) / 3, (prev.y() + 2*c.y()) / 3);
803 QPointF c2((e.x() + 2*c.x()) / 3, (e.y() + 2*c.y()) / 3);
804 cubicTo(c1, c2, e);
805}
806
807/*!
808 \fn void QPainterPath::arcTo(qreal x, qreal y, qreal width, qreal
809 height, qreal startAngle, qreal sweepLength)
810
811 \overload
812
813 Creates an arc that occupies the rectangle QRectF(\a x, \a y, \a
814 width, \a height), beginning at the specified \a startAngle and
815 extending \a sweepLength degrees counter-clockwise.
816
817*/
818
819/*!
820 \fn void QPainterPath::arcTo(const QRectF &rectangle, qreal startAngle, qreal sweepLength)
821
822 Creates an arc that occupies the given \a rectangle, beginning at
823 the specified \a startAngle and extending \a sweepLength degrees
824 counter-clockwise.
825
826 Angles are specified in degrees. Clockwise arcs can be specified
827 using negative angles.
828
829 Note that this function connects the starting point of the arc to
830 the current position if they are not already connected. After the
831 arc has been added, the current position is the last point in
832 arc. To draw a line back to the first point, use the
833 closeSubpath() function.
834
835 \table 100%
836 \row
837 \o \inlineimage qpainterpath-arcto.png
838 \o
839 \snippet doc/src/snippets/code/src_gui_painting_qpainterpath.cpp 2
840 \endtable
841
842 \sa arcMoveTo(), addEllipse(), QPainter::drawArc(), QPainter::drawPie(),
843 {QPainterPath#Composing a QPainterPath}{Composing a
844 QPainterPath}
845*/
846void QPainterPath::arcTo(const QRectF &rect, qreal startAngle, qreal sweepLength)
847{
848#ifdef QPP_DEBUG
849 printf("QPainterPath::arcTo() (%.2f, %.2f, %.2f, %.2f, angle=%.2f, sweep=%.2f\n",
850 rect.x(), rect.y(), rect.width(), rect.height(), startAngle, sweepLength);
851#endif
852#ifndef QT_NO_DEBUG
853 if (qt_is_nan(rect.x()) || qt_is_nan(rect.y()) || qt_is_nan(rect.width()) || qt_is_nan(rect.height())
854 || qt_is_nan(startAngle) || qt_is_nan(sweepLength))
855 qWarning("QPainterPath::arcTo: Adding arc where a parameter is NaN, results are undefined");
856#endif
857 if (rect.isNull())
858 return;
859
860 ensureData();
861 detach();
862
863 int point_count;
864 QPointF pts[15];
865 QPointF curve_start = qt_curves_for_arc(rect, startAngle, sweepLength, pts, &point_count);
866
867 lineTo(curve_start);
868 for (int i=0; i<point_count; i+=3) {
869 cubicTo(pts[i].x(), pts[i].y(),
870 pts[i+1].x(), pts[i+1].y(),
871 pts[i+2].x(), pts[i+2].y());
872 }
873
874}
875
876
877/*!
878 \fn void QPainterPath::arcMoveTo(qreal x, qreal y, qreal width, qreal height, qreal angle)
879 \overload
880 \since 4.2
881
882 Creates a move to that lies on the arc that occupies the
883 QRectF(\a x, \a y, \a width, \a height) at \a angle.
884*/
885
886
887/*!
888 \fn void QPainterPath::arcMoveTo(const QRectF &rectangle, qreal angle)
889 \since 4.2
890
891 Creates a move to that lies on the arc that occupies the given \a
892 rectangle at \a angle.
893
894 Angles are specified in degrees. Clockwise arcs can be specified
895 using negative angles.
896
897 \sa moveTo(), arcTo()
898*/
899
900void QPainterPath::arcMoveTo(const QRectF &rect, qreal angle)
901{
902 if (rect.isNull())
903 return;
904
905 QPointF pt;
906 qt_find_ellipse_coords(rect, angle, 0, &pt, 0);
907 moveTo(pt);
908}
909
910
911
912/*!
913 \fn QPointF QPainterPath::currentPosition() const
914
915 Returns the current position of the path.
916*/
917QPointF QPainterPath::currentPosition() const
918{
919 return !d_ptr || d_func()->elements.isEmpty()
920 ? QPointF()
921 : QPointF(d_func()->elements.last().x, d_func()->elements.last().y);
922}
923
924
925/*!
926 \fn void QPainterPath::addRect(qreal x, qreal y, qreal width, qreal height)
927
928 \overload
929
930 Adds a rectangle at position (\a{x}, \a{y}), with the given \a
931 width and \a height, as a closed subpath.
932*/
933
934/*!
935 \fn void QPainterPath::addRect(const QRectF &rectangle)
936
937 Adds the given \a rectangle to this path as a closed subpath.
938
939 The \a rectangle is added as a clockwise set of lines. The painter
940 path's current position after the \a rectangle has been added is
941 at the top-left corner of the rectangle.
942
943 \table 100%
944 \row
945 \o \inlineimage qpainterpath-addrectangle.png
946 \o
947 \snippet doc/src/snippets/code/src_gui_painting_qpainterpath.cpp 3
948 \endtable
949
950 \sa addRegion(), lineTo(), {QPainterPath#Composing a
951 QPainterPath}{Composing a QPainterPath}
952*/
953void QPainterPath::addRect(const QRectF &r)
954{
955#ifndef QT_NO_DEBUG
956 if (qt_is_nan(r.x()) || qt_is_nan(r.y()) || qt_is_nan(r.width()) || qt_is_nan(r.height()))
957 qWarning("QPainterPath::addRect: Adding rect where a parameter is NaN, results are undefined");
958#endif
959 if (r.isNull())
960 return;
961
962 ensureData();
963 detach();
964
965 bool first = d_func()->elements.size() < 2;
966
967 d_func()->elements.reserve(d_func()->elements.size() + 5);
968 moveTo(r.x(), r.y());
969
970 Element l1 = { r.x() + r.width(), r.y(), LineToElement };
971 Element l2 = { r.x() + r.width(), r.y() + r.height(), LineToElement };
972 Element l3 = { r.x(), r.y() + r.height(), LineToElement };
973 Element l4 = { r.x(), r.y(), LineToElement };
974
975 d_func()->elements << l1 << l2 << l3 << l4;
976 d_func()->require_moveTo = true;
977 d_func()->convex = first;
978}
979
980/*!
981 Adds the given \a polygon to the path as an (unclosed) subpath.
982
983 Note that the current position after the polygon has been added,
984 is the last point in \a polygon. To draw a line back to the first
985 point, use the closeSubpath() function.
986
987 \table 100%
988 \row
989 \o \inlineimage qpainterpath-addpolygon.png
990 \o
991 \snippet doc/src/snippets/code/src_gui_painting_qpainterpath.cpp 4
992 \endtable
993
994 \sa lineTo(), {QPainterPath#Composing a QPainterPath}{Composing
995 a QPainterPath}
996*/
997void QPainterPath::addPolygon(const QPolygonF &polygon)
998{
999 if (polygon.isEmpty())
1000 return;
1001
1002 ensureData();
1003 detach();
1004
1005 d_func()->elements.reserve(d_func()->elements.size() + polygon.size());
1006
1007 moveTo(polygon.first());
1008 for (int i=1; i<polygon.size(); ++i) {
1009 Element elm = { polygon.at(i).x(), polygon.at(i).y(), LineToElement };
1010 d_func()->elements << elm;
1011 }
1012}
1013
1014/*!
1015 \fn void QPainterPath::addEllipse(const QRectF &boundingRectangle)
1016
1017 Creates an ellipse within the specified \a boundingRectangle
1018 and adds it to the painter path as a closed subpath.
1019
1020 The ellipse is composed of a clockwise curve, starting and
1021 finishing at zero degrees (the 3 o'clock position).
1022
1023 \table 100%
1024 \row
1025 \o \inlineimage qpainterpath-addellipse.png
1026 \o
1027 \snippet doc/src/snippets/code/src_gui_painting_qpainterpath.cpp 5
1028 \endtable
1029
1030 \sa arcTo(), QPainter::drawEllipse(), {QPainterPath#Composing a
1031 QPainterPath}{Composing a QPainterPath}
1032*/
1033void QPainterPath::addEllipse(const QRectF &boundingRect)
1034{
1035#ifndef QT_NO_DEBUG
1036 if (qt_is_nan(boundingRect.x()) || qt_is_nan(boundingRect.y())
1037 || qt_is_nan(boundingRect.width()) || qt_is_nan(boundingRect.height()))
1038 qWarning("QPainterPath::addEllipse: Adding ellipse where a parameter is NaN, results are undefined");
1039#endif
1040 if (boundingRect.isNull())
1041 return;
1042
1043 ensureData();
1044 detach();
1045
1046 Q_D(QPainterPath);
1047 bool first = d_func()->elements.size() < 2;
1048 d->elements.reserve(d->elements.size() + 13);
1049
1050 QPointF pts[12];
1051 int point_count;
1052 QPointF start = qt_curves_for_arc(boundingRect, 0, -360, pts, &point_count);
1053
1054 moveTo(start);
1055 cubicTo(pts[0], pts[1], pts[2]); // 0 -> 270
1056 cubicTo(pts[3], pts[4], pts[5]); // 270 -> 180
1057 cubicTo(pts[6], pts[7], pts[8]); // 180 -> 90
1058 cubicTo(pts[9], pts[10], pts[11]); // 90 - >0
1059 d_func()->require_moveTo = true;
1060
1061 d_func()->convex = first;
1062}
1063
1064/*!
1065 \fn void QPainterPath::addText(const QPointF &point, const QFont &font, const QString &text)
1066
1067 Adds the given \a text to this path as a set of closed subpaths
1068 created from the \a font supplied. The subpaths are positioned so
1069 that the left end of the text's baseline lies at the specified \a
1070 point.
1071
1072 \table 100%
1073 \row
1074 \o \inlineimage qpainterpath-addtext.png
1075 \o
1076 \snippet doc/src/snippets/code/src_gui_painting_qpainterpath.cpp 6
1077 \endtable
1078
1079 \sa QPainter::drawText(), {QPainterPath#Composing a
1080 QPainterPath}{Composing a QPainterPath}
1081*/
1082void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &text)
1083{
1084 if (text.isEmpty())
1085 return;
1086
1087 ensureData();
1088 detach();
1089
1090 QTextLayout layout(text, f);
1091 layout.setCacheEnabled(true);
1092 QTextEngine *eng = layout.engine();
1093 layout.beginLayout();
1094 QTextLine line = layout.createLine();
1095 layout.endLayout();
1096 const QScriptLine &sl = eng->lines[0];
1097 if (!sl.length || !eng->layoutData)
1098 return;
1099
1100 int nItems = eng->layoutData->items.size();
1101
1102 qreal x(point.x());
1103 qreal y(point.y());
1104
1105 QVarLengthArray<int> visualOrder(nItems);
1106 QVarLengthArray<uchar> levels(nItems);
1107 for (int i = 0; i < nItems; ++i)
1108 levels[i] = eng->layoutData->items[i].analysis.bidiLevel;
1109 QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
1110
1111 for (int i = 0; i < nItems; ++i) {
1112 int item = visualOrder[i];
1113 QScriptItem &si = eng->layoutData->items[item];
1114
1115 if (si.analysis.flags < QScriptAnalysis::TabOrObject) {
1116 QGlyphLayout glyphs = eng->shapedGlyphs(&si);
1117 QFontEngine *fe = f.d->engineForScript(si.analysis.script);
1118 Q_ASSERT(fe);
1119 fe->addOutlineToPath(x, y, glyphs, this,
1120 si.analysis.bidiLevel % 2
1121 ? QTextItem::RenderFlags(QTextItem::RightToLeft)
1122 : QTextItem::RenderFlags(0));
1123
1124 const qreal lw = fe->lineThickness().toReal();
1125 if (f.d->underline) {
1126 qreal pos = fe->underlinePosition().toReal();
1127 addRect(x, y + pos, si.width.toReal(), lw);
1128 }
1129 if (f.d->overline) {
1130 qreal pos = fe->ascent().toReal() + 1;
1131 addRect(x, y - pos, si.width.toReal(), lw);
1132 }
1133 if (f.d->strikeOut) {
1134 qreal pos = fe->ascent().toReal() / 3;
1135 addRect(x, y - pos, si.width.toReal(), lw);
1136 }
1137 }
1138 x += si.width.toReal();
1139 }
1140}
1141
1142/*!
1143 \fn void QPainterPath::addPath(const QPainterPath &path)
1144
1145 Adds the given \a path to \e this path as a closed subpath.
1146
1147 \sa connectPath(), {QPainterPath#Composing a
1148 QPainterPath}{Composing a QPainterPath}
1149*/
1150void QPainterPath::addPath(const QPainterPath &other)
1151{
1152 if (other.isEmpty())
1153 return;
1154
1155 ensureData();
1156 detach();
1157
1158 QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
1159 // Remove last moveto so we don't get multiple moveto's
1160 if (d->elements.last().type == MoveToElement)
1161 d->elements.remove(d->elements.size()-1);
1162
1163 // Locate where our own current subpath will start after the other path is added.
1164 int cStart = d->elements.size() + other.d_func()->cStart;
1165 d->elements += other.d_func()->elements;
1166 d->cStart = cStart;
1167
1168 d->require_moveTo = other.d_func()->isClosed();
1169}
1170
1171
1172/*!
1173 \fn void QPainterPath::connectPath(const QPainterPath &path)
1174
1175 Connects the given \a path to \e this path by adding a line from the
1176 last element of this path to the first element of the given path.
1177
1178 \sa addPath(), {QPainterPath#Composing a QPainterPath}{Composing
1179 a QPainterPath}
1180*/
1181void QPainterPath::connectPath(const QPainterPath &other)
1182{
1183 if (other.isEmpty())
1184 return;
1185
1186 ensureData();
1187 detach();
1188
1189 QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
1190 // Remove last moveto so we don't get multiple moveto's
1191 if (d->elements.last().type == MoveToElement)
1192 d->elements.remove(d->elements.size()-1);
1193
1194 // Locate where our own current subpath will start after the other path is added.
1195 int cStart = d->elements.size() + other.d_func()->cStart;
1196 int first = d->elements.size();
1197 d->elements += other.d_func()->elements;
1198
1199 if (first != 0)
1200 d->elements[first].type = LineToElement;
1201
1202 // avoid duplicate points
1203 if (first > 0 && QPointF(d->elements[first]) == QPointF(d->elements[first - 1])) {
1204 d->elements.remove(first--);
1205 --cStart;
1206 }
1207
1208 if (cStart != first)
1209 d->cStart = cStart;
1210}
1211
1212/*!
1213 Adds the given \a region to the path by adding each rectangle in
1214 the region as a separate closed subpath.
1215
1216 \sa addRect(), {QPainterPath#Composing a QPainterPath}{Composing
1217 a QPainterPath}
1218*/
1219void QPainterPath::addRegion(const QRegion &region)
1220{
1221 ensureData();
1222 detach();
1223
1224 QVector<QRect> rects = region.rects();
1225 d_func()->elements.reserve(rects.size() * 5);
1226 for (int i=0; i<rects.size(); ++i)
1227 addRect(rects.at(i));
1228}
1229
1230
1231/*!
1232 Returns the painter path's currently set fill rule.
1233
1234 \sa setFillRule()
1235*/
1236Qt::FillRule QPainterPath::fillRule() const
1237{
1238 return isEmpty() ? Qt::OddEvenFill : d_func()->fillRule;
1239}
1240
1241/*!
1242 \fn void QPainterPath::setFillRule(Qt::FillRule fillRule)
1243
1244 Sets the fill rule of the painter path to the given \a
1245 fillRule. Qt provides two methods for filling paths:
1246
1247 \table
1248 \row
1249 \o \inlineimage qt-fillrule-oddeven.png
1250 \o \inlineimage qt-fillrule-winding.png
1251 \header
1252 \o Qt::OddEvenFill (default)
1253 \o Qt::WindingFill
1254 \endtable
1255
1256 \sa fillRule()
1257*/
1258void QPainterPath::setFillRule(Qt::FillRule fillRule)
1259{
1260 ensureData();
1261 if (d_func()->fillRule == fillRule)
1262 return;
1263 detach();
1264
1265 d_func()->fillRule = fillRule;
1266}
1267
1268#define QT_BEZIER_A(bezier, coord) 3 * (-bezier.coord##1 \
1269 + 3*bezier.coord##2 \
1270 - 3*bezier.coord##3 \
1271 +bezier.coord##4)
1272
1273#define QT_BEZIER_B(bezier, coord) 6 * (bezier.coord##1 \
1274 - 2*bezier.coord##2 \
1275 + bezier.coord##3)
1276
1277#define QT_BEZIER_C(bezier, coord) 3 * (- bezier.coord##1 \
1278 + bezier.coord##2)
1279
1280#define QT_BEZIER_CHECK_T(bezier, t) \
1281 if (t >= 0 && t <= 1) { \
1282 QPointF p(b.pointAt(t)); \
1283 if (p.x() < minx) minx = p.x(); \
1284 else if (p.x() > maxx) maxx = p.x(); \
1285 if (p.y() < miny) miny = p.y(); \
1286 else if (p.y() > maxy) maxy = p.y(); \
1287 }
1288
1289
1290static QRectF qt_painterpath_bezier_extrema(const QBezier &b)
1291{
1292 qreal minx, miny, maxx, maxy;
1293
1294 // initialize with end points
1295 if (b.x1 < b.x4) {
1296 minx = b.x1;
1297 maxx = b.x4;
1298 } else {
1299 minx = b.x4;
1300 maxx = b.x1;
1301 }
1302 if (b.y1 < b.y4) {
1303 miny = b.y1;
1304 maxy = b.y4;
1305 } else {
1306 miny = b.y4;
1307 maxy = b.y1;
1308 }
1309
1310 // Update for the X extrema
1311 {
1312 qreal ax = QT_BEZIER_A(b, x);
1313 qreal bx = QT_BEZIER_B(b, x);
1314 qreal cx = QT_BEZIER_C(b, x);
1315 // specialcase quadratic curves to avoid div by zero
1316 if (qFuzzyIsNull(ax)) {
1317
1318 // linear curves are covered by initialization.
1319 if (!qFuzzyIsNull(bx)) {
1320 qreal t = -cx / bx;
1321 QT_BEZIER_CHECK_T(b, t);
1322 }
1323
1324 } else {
1325 const qreal tx = bx * bx - 4 * ax * cx;
1326
1327 if (tx >= 0) {
1328 qreal temp = qSqrt(tx);
1329 qreal rcp = 1 / (2 * ax);
1330 qreal t1 = (-bx + temp) * rcp;
1331 QT_BEZIER_CHECK_T(b, t1);
1332
1333 qreal t2 = (-bx - temp) * rcp;
1334 QT_BEZIER_CHECK_T(b, t2);
1335 }
1336 }
1337 }
1338
1339 // Update for the Y extrema
1340 {
1341 qreal ay = QT_BEZIER_A(b, y);
1342 qreal by = QT_BEZIER_B(b, y);
1343 qreal cy = QT_BEZIER_C(b, y);
1344
1345 // specialcase quadratic curves to avoid div by zero
1346 if (qFuzzyIsNull(ay)) {
1347
1348 // linear curves are covered by initialization.
1349 if (!qFuzzyIsNull(by)) {
1350 qreal t = -cy / by;
1351 QT_BEZIER_CHECK_T(b, t);
1352 }
1353
1354 } else {
1355 const qreal ty = by * by - 4 * ay * cy;
1356
1357 if (ty > 0) {
1358 qreal temp = qSqrt(ty);
1359 qreal rcp = 1 / (2 * ay);
1360 qreal t1 = (-by + temp) * rcp;
1361 QT_BEZIER_CHECK_T(b, t1);
1362
1363 qreal t2 = (-by - temp) * rcp;
1364 QT_BEZIER_CHECK_T(b, t2);
1365 }
1366 }
1367 }
1368 return QRectF(minx, miny, maxx - minx, maxy - miny);
1369}
1370
1371/*!
1372 Returns the bounding rectangle of this painter path as a rectangle with
1373 floating point precision.
1374
1375 \sa controlPointRect()
1376*/
1377QRectF QPainterPath::boundingRect() const
1378{
1379 if (!d_ptr)
1380 return QRectF();
1381 QPainterPathData *d = d_func();
1382
1383 if (d->dirtyBounds)
1384 computeBoundingRect();
1385 return d->bounds;
1386}
1387
1388/*!
1389 Returns the rectangle containing all the points and control points
1390 in this path.
1391
1392 This function is significantly faster to compute than the exact
1393 boundingRect(), and the returned rectangle is always a superset of
1394 the rectangle returned by boundingRect().
1395
1396 \sa boundingRect()
1397*/
1398QRectF QPainterPath::controlPointRect() const
1399{
1400 if (!d_ptr)
1401 return QRectF();
1402 QPainterPathData *d = d_func();
1403
1404 if (d->dirtyControlBounds)
1405 computeControlPointRect();
1406 return d->controlBounds;
1407}
1408
1409
1410/*!
1411 \fn bool QPainterPath::isEmpty() const
1412
1413 Returns true if either there are no elements in this path, or if the only
1414 element is a MoveToElement; otherwise returns false.
1415
1416 \sa elementCount()
1417*/
1418
1419/*!
1420 Creates and returns a reversed copy of the path.
1421
1422 It is the order of the elements that is reversed: If a
1423 QPainterPath is composed by calling the moveTo(), lineTo() and
1424 cubicTo() functions in the specified order, the reversed copy is
1425 composed by calling cubicTo(), lineTo() and moveTo().
1426*/
1427QPainterPath QPainterPath::toReversed() const
1428{
1429 Q_D(const QPainterPath);
1430 QPainterPath rev;
1431
1432 if (isEmpty()) {
1433 rev = *this;
1434 return rev;
1435 }
1436
1437 rev.moveTo(d->elements.at(d->elements.size()-1).x, d->elements.at(d->elements.size()-1).y);
1438
1439 for (int i=d->elements.size()-1; i>=1; --i) {
1440 const QPainterPath::Element &elm = d->elements.at(i);
1441 const QPainterPath::Element &prev = d->elements.at(i-1);
1442 switch (elm.type) {
1443 case LineToElement:
1444 rev.lineTo(prev.x, prev.y);
1445 break;
1446 case MoveToElement:
1447 rev.moveTo(prev.x, prev.y);
1448 break;
1449 case CurveToDataElement:
1450 {
1451 Q_ASSERT(i>=3);
1452 const QPainterPath::Element &cp1 = d->elements.at(i-2);
1453 const QPainterPath::Element &sp = d->elements.at(i-3);
1454 Q_ASSERT(prev.type == CurveToDataElement);
1455 Q_ASSERT(cp1.type == CurveToElement);
1456 rev.cubicTo(prev.x, prev.y, cp1.x, cp1.y, sp.x, sp.y);
1457 i -= 2;
1458 break;
1459 }
1460 default:
1461 Q_ASSERT(!"qt_reversed_path");
1462 break;
1463 }
1464 }
1465 //qt_debug_path(rev);
1466 return rev;
1467}
1468
1469/*!
1470 Converts the path into a list of polygons using the QTransform
1471 \a matrix, and returns the list.
1472
1473 This function creates one polygon for each subpath regardless of
1474 intersecting subpaths (i.e. overlapping bounding rectangles). To
1475 make sure that such overlapping subpaths are filled correctly, use
1476 the toFillPolygons() function instead.
1477
1478 \sa toFillPolygons(), toFillPolygon(), {QPainterPath#QPainterPath
1479 Conversion}{QPainterPath Conversion}
1480*/
1481QList<QPolygonF> QPainterPath::toSubpathPolygons(const QTransform &matrix) const
1482{
1483
1484 Q_D(const QPainterPath);
1485 QList<QPolygonF> flatCurves;
1486 if (isEmpty())
1487 return flatCurves;
1488
1489 QPolygonF current;
1490 for (int i=0; i<elementCount(); ++i) {
1491 const QPainterPath::Element &e = d->elements.at(i);
1492 switch (e.type) {
1493 case QPainterPath::MoveToElement:
1494 if (current.size() > 1)
1495 flatCurves += current;
1496 current.clear();
1497 current.reserve(16);
1498 current += QPointF(e.x, e.y) * matrix;
1499 break;
1500 case QPainterPath::LineToElement:
1501 current += QPointF(e.x, e.y) * matrix;
1502 break;
1503 case QPainterPath::CurveToElement: {
1504 Q_ASSERT(d->elements.at(i+1).type == QPainterPath::CurveToDataElement);
1505 Q_ASSERT(d->elements.at(i+2).type == QPainterPath::CurveToDataElement);
1506 QBezier bezier = QBezier::fromPoints(QPointF(d->elements.at(i-1).x, d->elements.at(i-1).y) * matrix,
1507 QPointF(e.x, e.y) * matrix,
1508 QPointF(d->elements.at(i+1).x, d->elements.at(i+1).y) * matrix,
1509 QPointF(d->elements.at(i+2).x, d->elements.at(i+2).y) * matrix);
1510 bezier.addToPolygon(&current);
1511 i+=2;
1512 break;
1513 }
1514 case QPainterPath::CurveToDataElement:
1515 Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
1516 break;
1517 }
1518 }
1519
1520 if (current.size()>1)
1521 flatCurves += current;
1522
1523 return flatCurves;
1524}
1525
1526/*!
1527 \overload
1528 */
1529QList<QPolygonF> QPainterPath::toSubpathPolygons(const QMatrix &matrix) const
1530{
1531 return toSubpathPolygons(QTransform(matrix));
1532}
1533
1534/*!
1535 Converts the path into a list of polygons using the
1536 QTransform \a matrix, and returns the list.
1537
1538 The function differs from the toFillPolygon() function in that it
1539 creates several polygons. It is provided because it is usually
1540 faster to draw several small polygons than to draw one large
1541 polygon, even though the total number of points drawn is the same.
1542
1543 The toFillPolygons() function differs from the toSubpathPolygons()
1544 function in that it create only polygon for subpaths that have
1545 overlapping bounding rectangles.
1546
1547 Like the toFillPolygon() function, this function uses a rewinding
1548 technique to make sure that overlapping subpaths can be filled
1549 using the correct fill rule. Note that rewinding inserts addition
1550 lines in the polygons so the outline of the fill polygon does not
1551 match the outline of the path.
1552
1553 \sa toSubpathPolygons(), toFillPolygon(),
1554 {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
1555*/
1556QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
1557{
1558
1559 QList<QPolygonF> polys;
1560
1561 QList<QPolygonF> subpaths = toSubpathPolygons(matrix);
1562 int count = subpaths.size();
1563
1564 if (count == 0)
1565 return polys;
1566
1567 QList<QRectF> bounds;
1568 for (int i=0; i<count; ++i)
1569 bounds += subpaths.at(i).boundingRect();
1570
1571#ifdef QPP_FILLPOLYGONS_DEBUG
1572 printf("QPainterPath::toFillPolygons, subpathCount=%d\n", count);
1573 for (int i=0; i<bounds.size(); ++i)
1574 qDebug() << " bounds" << i << bounds.at(i);
1575#endif
1576
1577 QVector< QList<int> > isects;
1578 isects.resize(count);
1579
1580 // find all intersections
1581 for (int j=0; j<count; ++j) {
1582 if (subpaths.at(j).size() <= 2)
1583 continue;
1584 QRectF cbounds = bounds.at(j);
1585 for (int i=0; i<count; ++i) {
1586 if (cbounds.intersects(bounds.at(i))) {
1587 isects[j] << i;
1588 }
1589 }
1590 }
1591
1592#ifdef QPP_FILLPOLYGONS_DEBUG
1593 printf("Intersections before flattening:\n");
1594 for (int i = 0; i < count; ++i) {
1595 printf("%d: ", i);
1596 for (int j = 0; j < isects[i].size(); ++j) {
1597 printf("%d ", isects[i][j]);
1598 }
1599 printf("\n");
1600 }
1601#endif
1602
1603 // flatten the sets of intersections
1604 for (int i=0; i<count; ++i) {
1605 const QList<int> &current_isects = isects.at(i);
1606 for (int j=0; j<current_isects.size(); ++j) {
1607 int isect_j = current_isects.at(j);
1608 if (isect_j == i)
1609 continue;
1610 for (int k=0; k<isects[isect_j].size(); ++k) {
1611 int isect_k = isects[isect_j][k];
1612 if (isect_k != i && !isects.at(i).contains(isect_k)) {
1613 isects[i] += isect_k;
1614 }
1615 }
1616 isects[isect_j].clear();
1617 }
1618 }
1619
1620#ifdef QPP_FILLPOLYGONS_DEBUG
1621 printf("Intersections after flattening:\n");
1622 for (int i = 0; i < count; ++i) {
1623 printf("%d: ", i);
1624 for (int j = 0; j < isects[i].size(); ++j) {
1625 printf("%d ", isects[i][j]);
1626 }
1627 printf("\n");
1628 }
1629#endif
1630
1631 // Join the intersected subpaths as rewinded polygons
1632 for (int i=0; i<count; ++i) {
1633 const QList<int> &subpath_list = isects[i];
1634 if (!subpath_list.isEmpty()) {
1635 QPolygonF buildUp;
1636 for (int j=0; j<subpath_list.size(); ++j) {
1637 const QPolygonF &subpath = subpaths.at(subpath_list.at(j));
1638 buildUp += subpath;
1639 if (!subpath.isClosed())
1640 buildUp += subpath.first();
1641 if (!buildUp.isClosed())
1642 buildUp += buildUp.first();
1643 }
1644 polys += buildUp;
1645 }
1646 }
1647
1648 return polys;
1649}
1650
1651/*!
1652 \overload
1653 */
1654QList<QPolygonF> QPainterPath::toFillPolygons(const QMatrix &matrix) const
1655{
1656 return toFillPolygons(QTransform(matrix));
1657}
1658
1659//same as qt_polygon_isect_line in qpolygon.cpp
1660static void qt_painterpath_isect_line(const QPointF &p1,
1661 const QPointF &p2,
1662 const QPointF &pos,
1663 int *winding)
1664{
1665 qreal x1 = p1.x();
1666 qreal y1 = p1.y();
1667 qreal x2 = p2.x();
1668 qreal y2 = p2.y();
1669 qreal y = pos.y();
1670
1671 int dir = 1;
1672
1673 if (qFuzzyCompare(y1, y2)) {
1674 // ignore horizontal lines according to scan conversion rule
1675 return;
1676 } else if (y2 < y1) {
1677 qreal x_tmp = x2; x2 = x1; x1 = x_tmp;
1678 qreal y_tmp = y2; y2 = y1; y1 = y_tmp;
1679 dir = -1;
1680 }
1681
1682 if (y >= y1 && y < y2) {
1683 qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1);
1684
1685 // count up the winding number if we're
1686 if (x<=pos.x()) {
1687 (*winding) += dir;
1688 }
1689 }
1690}
1691
1692static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
1693 int *winding)
1694{
1695 qreal y = pt.y();
1696 qreal x = pt.x();
1697 QRectF bounds = bezier.bounds();
1698
1699 // potential intersection, divide and try again...
1700 // Please note that a sideeffect of the bottom exclusion is that
1701 // horizontal lines are dropped, but this is correct according to
1702 // scan conversion rules.
1703 if (y >= bounds.y() && y < bounds.y() + bounds.height()) {
1704
1705 // hit lower limit... This is a rough threshold, but its a
1706 // tradeoff between speed and precision.
1707 const qreal lower_bound = qreal(.001);
1708 if (bounds.width() < lower_bound && bounds.height() < lower_bound) {
1709 // We make the assumption here that the curve starts to
1710 // approximate a line after while (i.e. that it doesn't
1711 // change direction drastically during its slope)
1712 if (bezier.pt1().x() <= x) {
1713 (*winding) += (bezier.pt4().y() > bezier.pt1().y() ? 1 : -1);
1714 }
1715 return;
1716 }
1717
1718 // split curve and try again...
1719 QBezier first_half, second_half;
1720 bezier.split(&first_half, &second_half);
1721 qt_painterpath_isect_curve(first_half, pt, winding);
1722 qt_painterpath_isect_curve(second_half, pt, winding);
1723 }
1724}
1725
1726/*!
1727 \fn bool QPainterPath::contains(const QPointF &point) const
1728
1729 Returns true if the given \a point is inside the path, otherwise
1730 returns false.
1731
1732 \sa intersects()
1733*/
1734bool QPainterPath::contains(const QPointF &pt) const
1735{
1736 if (isEmpty() || !controlPointRect().contains(pt))
1737 return false;
1738
1739 QPainterPathData *d = d_func();
1740
1741 int winding_number = 0;
1742
1743 QPointF last_pt;
1744 QPointF last_start;
1745 for (int i=0; i<d->elements.size(); ++i) {
1746 const Element &e = d->elements.at(i);
1747
1748 switch (e.type) {
1749
1750 case MoveToElement:
1751 if (i > 0) // implicitly close all paths.
1752 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1753 last_start = last_pt = e;
1754 break;
1755
1756 case LineToElement:
1757 qt_painterpath_isect_line(last_pt, e, pt, &winding_number);
1758 last_pt = e;
1759 break;
1760
1761 case CurveToElement:
1762 {
1763 const QPainterPath::Element &cp2 = d->elements.at(++i);
1764 const QPainterPath::Element &ep = d->elements.at(++i);
1765 qt_painterpath_isect_curve(QBezier::fromPoints(last_pt, e, cp2, ep),
1766 pt, &winding_number);
1767 last_pt = ep;
1768
1769 }
1770 break;
1771
1772 default:
1773 break;
1774 }
1775 }
1776
1777 // implicitly close last subpath
1778 if (last_pt != last_start)
1779 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1780
1781 return (d->fillRule == Qt::WindingFill
1782 ? (winding_number != 0)
1783 : ((winding_number % 2) != 0));
1784}
1785
1786static bool qt_painterpath_isect_line_rect(qreal x1, qreal y1, qreal x2, qreal y2,
1787 const QRectF &rect)
1788{
1789 qreal left = rect.left();
1790 qreal right = rect.right();
1791 qreal top = rect.top();
1792 qreal bottom = rect.bottom();
1793
1794 enum { Left, Right, Top, Bottom };
1795 // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html
1796 int p1 = ((x1 < left) << Left)
1797 | ((x1 > right) << Right)
1798 | ((y1 < top) << Top)
1799 | ((y1 > bottom) << Bottom);
1800 int p2 = ((x2 < left) << Left)
1801 | ((x2 > right) << Right)
1802 | ((y2 < top) << Top)
1803 | ((y2 > bottom) << Bottom);
1804
1805 if (p1 & p2)
1806 // completely inside
1807 return false;
1808
1809 if (p1 | p2) {
1810 qreal dx = x2 - x1;
1811 qreal dy = y2 - y1;
1812
1813 // clip x coordinates
1814 if (x1 < left) {
1815 y1 += dy/dx * (left - x1);
1816 x1 = left;
1817 } else if (x1 > right) {
1818 y1 -= dy/dx * (x1 - right);
1819 x1 = right;
1820 }
1821 if (x2 < left) {
1822 y2 += dy/dx * (left - x2);
1823 x2 = left;
1824 } else if (x2 > right) {
1825 y2 -= dy/dx * (x2 - right);
1826 x2 = right;
1827 }
1828
1829 p1 = ((y1 < top) << Top)
1830 | ((y1 > bottom) << Bottom);
1831 p2 = ((y2 < top) << Top)
1832 | ((y2 > bottom) << Bottom);
1833
1834 if (p1 & p2)
1835 return false;
1836
1837 // clip y coordinates
1838 if (y1 < top) {
1839 x1 += dx/dy * (top - y1);
1840 y1 = top;
1841 } else if (y1 > bottom) {
1842 x1 -= dx/dy * (y1 - bottom);
1843 y1 = bottom;
1844 }
1845 if (y2 < top) {
1846 x2 += dx/dy * (top - y2);
1847 y2 = top;
1848 } else if (y2 > bottom) {
1849 x2 -= dx/dy * (y2 - bottom);
1850 y2 = bottom;
1851 }
1852
1853 p1 = ((x1 < left) << Left)
1854 | ((x1 > right) << Right);
1855 p2 = ((x2 < left) << Left)
1856 | ((x2 > right) << Right);
1857
1858 if (p1 & p2)
1859 return false;
1860
1861 return true;
1862 }
1863 return false;
1864}
1865
1866static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2)
1867{
1868 QRectF bounds = bezier.bounds();
1869
1870 if (y >= bounds.top() && y < bounds.bottom()
1871 && bounds.right() >= x1 && bounds.left() < x2) {
1872 const qreal lower_bound = qreal(.01);
1873 if (bounds.width() < lower_bound && bounds.height() < lower_bound)
1874 return true;
1875
1876 QBezier first_half, second_half;
1877 bezier.split(&first_half, &second_half);
1878 if (qt_isect_curve_horizontal(first_half, y, x1, x2)
1879 || qt_isect_curve_horizontal(second_half, y, x1, x2))
1880 return true;
1881 }
1882 return false;
1883}
1884
1885static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2)
1886{
1887 QRectF bounds = bezier.bounds();
1888
1889 if (x >= bounds.left() && x < bounds.right()
1890 && bounds.bottom() >= y1 && bounds.top() < y2) {
1891 const qreal lower_bound = qreal(.01);
1892 if (bounds.width() < lower_bound && bounds.height() < lower_bound)
1893 return true;
1894
1895 QBezier first_half, second_half;
1896 bezier.split(&first_half, &second_half);
1897 if (qt_isect_curve_vertical(first_half, x, y1, y2)
1898 || qt_isect_curve_vertical(second_half, x, y1, y2))
1899 return true;
1900 }
1901 return false;
1902}
1903
1904/*
1905 Returns true if any lines or curves cross the four edges in of rect
1906*/
1907static bool qt_painterpath_check_crossing(const QPainterPath *path, const QRectF &rect)
1908{
1909 QPointF last_pt;
1910 QPointF last_start;
1911 for (int i=0; i<path->elementCount(); ++i) {
1912 const QPainterPath::Element &e = path->elementAt(i);
1913
1914 switch (e.type) {
1915
1916 case QPainterPath::MoveToElement:
1917 if (i > 0
1918 && qFuzzyCompare(last_pt.x(), last_start.x())
1919 && qFuzzyCompare(last_pt.y(), last_start.y())
1920 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
1921 last_start.x(), last_start.y(), rect))
1922 return true;
1923 last_start = last_pt = e;
1924 break;
1925
1926 case QPainterPath::LineToElement:
1927 if (qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), e.x, e.y, rect))
1928 return true;
1929 last_pt = e;
1930 break;
1931
1932 case QPainterPath::CurveToElement:
1933 {
1934 QPointF cp2 = path->elementAt(++i);
1935 QPointF ep = path->elementAt(++i);
1936 QBezier bezier = QBezier::fromPoints(last_pt, e, cp2, ep);
1937 if (qt_isect_curve_horizontal(bezier, rect.top(), rect.left(), rect.right())
1938 || qt_isect_curve_horizontal(bezier, rect.bottom(), rect.left(), rect.right())
1939 || qt_isect_curve_vertical(bezier, rect.left(), rect.top(), rect.bottom())
1940 || qt_isect_curve_vertical(bezier, rect.right(), rect.top(), rect.bottom()))
1941 return true;
1942 last_pt = ep;
1943 }
1944 break;
1945
1946 default:
1947 break;
1948 }
1949 }
1950
1951 // implicitly close last subpath
1952 if (last_pt != last_start
1953 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
1954 last_start.x(), last_start.y(), rect))
1955 return true;
1956
1957 return false;
1958}
1959
1960/*!
1961 \fn bool QPainterPath::intersects(const QRectF &rectangle) const
1962
1963 Returns true if any point in the given \a rectangle intersects the
1964 path; otherwise returns false.
1965
1966 There is an intersection if any of the lines making up the
1967 rectangle crosses a part of the path or if any part of the
1968 rectangle overlaps with any area enclosed by the path. This
1969 function respects the current fillRule to determine what is
1970 considered inside the path.
1971
1972 \sa contains()
1973*/
1974bool QPainterPath::intersects(const QRectF &rect) const
1975{
1976 if (elementCount() == 1 && rect.contains(elementAt(0)))
1977 return true;
1978
1979 if (isEmpty())
1980 return false;
1981
1982 QRectF cp = controlPointRect();
1983 QRectF rn = rect.normalized();
1984
1985 // QRectF::intersects returns false if one of the rects is a null rect
1986 // which would happen for a painter path consisting of a vertical or
1987 // horizontal line
1988 if (qMax(rn.left(), cp.left()) > qMin(rn.right(), cp.right())
1989 || qMax(rn.top(), cp.top()) > qMin(rn.bottom(), cp.bottom()))
1990 return false;
1991
1992 // If any path element cross the rect its bound to be an intersection
1993 if (qt_painterpath_check_crossing(this, rect))
1994 return true;
1995
1996 if (contains(rect.center()))
1997 return true;
1998
1999 Q_D(QPainterPath);
2000
2001 // Check if the rectangle surounds any subpath...
2002 for (int i=0; i<d->elements.size(); ++i) {
2003 const Element &e = d->elements.at(i);
2004 if (e.type == QPainterPath::MoveToElement && rect.contains(e))
2005 return true;
2006 }
2007
2008 return false;
2009}
2010
2011/*!
2012 Translates all elements in the path by (\a{dx}, \a{dy}).
2013
2014 \since 4.6
2015 \sa translated()
2016*/
2017void QPainterPath::translate(qreal dx, qreal dy)
2018{
2019 if (!d_ptr || (dx == 0 && dy == 0))
2020 return;
2021
2022 int elementsLeft = d_ptr->elements.size();
2023 if (elementsLeft <= 0)
2024 return;
2025
2026 detach();
2027 QPainterPath::Element *element = d_func()->elements.data();
2028 Q_ASSERT(element);
2029 while (elementsLeft--) {
2030 element->x += dx;
2031 element->y += dy;
2032 ++element;
2033 }
2034}
2035
2036/*!
2037 \fn void QPainterPath::translate(const QPointF &offset)
2038 \overload
2039 \since 4.6
2040
2041 Translates all elements in the path by the given \a offset.
2042
2043 \sa translated()
2044*/
2045
2046/*!
2047 Returns a copy of the path that is translated by (\a{dx}, \a{dy}).
2048
2049 \since 4.6
2050 \sa translate()
2051*/
2052QPainterPath QPainterPath::translated(qreal dx, qreal dy) const
2053{
2054 QPainterPath copy(*this);
2055 copy.translate(dx, dy);
2056 return copy;
2057}
2058
2059/*!
2060 \fn QPainterPath QPainterPath::translated(const QPointF &offset) const;
2061 \overload
2062 \since 4.6
2063
2064 Returns a copy of the path that is translated by the given \a offset.
2065
2066 \sa translate()
2067*/
2068
2069/*!
2070 \fn bool QPainterPath::contains(const QRectF &rectangle) const
2071
2072 Returns true if the given \a rectangle is inside the path,
2073 otherwise returns false.
2074*/
2075bool QPainterPath::contains(const QRectF &rect) const
2076{
2077 Q_D(QPainterPath);
2078
2079 // the path is empty or the control point rect doesn't completely
2080 // cover the rectangle we abort stratight away.
2081 if (isEmpty() || !controlPointRect().contains(rect))
2082 return false;
2083
2084 // if there are intersections, chances are that the rect is not
2085 // contained, except if we have winding rule, in which case it
2086 // still might.
2087 if (qt_painterpath_check_crossing(this, rect)) {
2088 if (fillRule() == Qt::OddEvenFill) {
2089 return false;
2090 } else {
2091 // Do some wague sampling in the winding case. This is not
2092 // precise but it should mostly be good enough.
2093 if (!contains(rect.topLeft()) ||
2094 !contains(rect.topRight()) ||
2095 !contains(rect.bottomRight()) ||
2096 !contains(rect.bottomLeft()))
2097 return false;
2098 }
2099 }
2100
2101 // If there exists a point inside that is not part of the path its
2102 // because: rectangle lies completely outside path or a subpath
2103 // excludes parts of the rectangle. Both cases mean that the rect
2104 // is not contained
2105 if (!contains(rect.center()))
2106 return false;
2107
2108 // If there are any subpaths inside this rectangle we need to
2109 // check if they are still contained as a result of the fill
2110 // rule. This can only be the case for WindingFill though. For
2111 // OddEvenFill the rect will never be contained if it surrounds a
2112 // subpath. (the case where two subpaths are completely identical
2113 // can be argued but we choose to neglect it).
2114 for (int i=0; i<d->elements.size(); ++i) {
2115 const Element &e = d->elements.at(i);
2116 if (e.type == QPainterPath::MoveToElement && rect.contains(e)) {
2117 if (fillRule() == Qt::OddEvenFill)
2118 return false;
2119
2120 bool stop = false;
2121 for (; !stop && i<d->elements.size(); ++i) {
2122 const Element &el = d->elements.at(i);
2123 switch (el.type) {
2124 case MoveToElement:
2125 stop = true;
2126 break;
2127 case LineToElement:
2128 if (!contains(el))
2129 return false;
2130 break;
2131 case CurveToElement:
2132 if (!contains(d->elements.at(i+2)))
2133 return false;
2134 i += 2;
2135 break;
2136 default:
2137 break;
2138 }
2139 }
2140
2141 // compensate for the last ++i in the inner for
2142 --i;
2143 }
2144 }
2145
2146 return true;
2147}
2148
2149static inline bool epsilonCompare(const QPointF &a, const QPointF &b, const QSizeF &epsilon)
2150{
2151 return qAbs(a.x() - b.x()) <= epsilon.width()
2152 && qAbs(a.y() - b.y()) <= epsilon.height();
2153}
2154
2155/*!
2156 Returns true if this painterpath is equal to the given \a path.
2157
2158 Note that comparing paths may involve a per element comparison
2159 which can be slow for complex paths.
2160
2161 \sa operator!=()
2162*/
2163
2164bool QPainterPath::operator==(const QPainterPath &path) const
2165{
2166 QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
2167 if (path.d_func() == d)
2168 return true;
2169 else if (!d || !path.d_func())
2170 return false;
2171 else if (d->fillRule != path.d_func()->fillRule)
2172 return false;
2173 else if (d->elements.size() != path.d_func()->elements.size())
2174 return false;
2175
2176 const qreal qt_epsilon = sizeof(qreal) == sizeof(double) ? 1e-12 : qreal(1e-5);
2177
2178 QSizeF epsilon = boundingRect().size();
2179 epsilon.rwidth() *= qt_epsilon;
2180 epsilon.rheight() *= qt_epsilon;
2181
2182 for (int i = 0; i < d->elements.size(); ++i)
2183 if (d->elements.at(i).type != path.d_func()->elements.at(i).type
2184 || !epsilonCompare(d->elements.at(i), path.d_func()->elements.at(i), epsilon))
2185 return false;
2186
2187 return true;
2188}
2189
2190/*!
2191 Returns true if this painter path differs from the given \a path.
2192
2193 Note that comparing paths may involve a per element comparison
2194 which can be slow for complex paths.
2195
2196 \sa operator==()
2197*/
2198
2199bool QPainterPath::operator!=(const QPainterPath &path) const
2200{
2201 return !(*this==path);
2202}
2203
2204/*!
2205 \since 4.5
2206
2207 Returns the intersection of this path and the \a other path.
2208
2209 \sa intersected(), operator&=(), united(), operator|()
2210*/
2211QPainterPath QPainterPath::operator&(const QPainterPath &other) const
2212{
2213 return intersected(other);
2214}
2215
2216/*!
2217 \since 4.5
2218
2219 Returns the union of this path and the \a other path.
2220
2221 \sa united(), operator|=(), intersected(), operator&()
2222*/
2223QPainterPath QPainterPath::operator|(const QPainterPath &other) const
2224{
2225 return united(other);
2226}
2227
2228/*!
2229 \since 4.5
2230
2231 Returns the union of this path and the \a other path. This function is equivalent
2232 to operator|().
2233
2234 \sa united(), operator+=(), operator-()
2235*/
2236QPainterPath QPainterPath::operator+(const QPainterPath &other) const
2237{
2238 return united(other);
2239}
2240
2241/*!
2242 \since 4.5
2243
2244 Subtracts the \a other path from a copy of this path, and returns the copy.
2245
2246 \sa subtracted(), operator-=(), operator+()
2247*/
2248QPainterPath QPainterPath::operator-(const QPainterPath &other) const
2249{
2250 return subtracted(other);
2251}
2252
2253/*!
2254 \since 4.5
2255
2256 Intersects this path with \a other and returns a reference to this path.
2257
2258 \sa intersected(), operator&(), operator|=()
2259*/
2260QPainterPath &QPainterPath::operator&=(const QPainterPath &other)
2261{
2262 return *this = (*this & other);
2263}
2264
2265/*!
2266 \since 4.5
2267
2268 Unites this path with \a other and returns a reference to this path.
2269
2270 \sa united(), operator|(), operator&=()
2271*/
2272QPainterPath &QPainterPath::operator|=(const QPainterPath &other)
2273{
2274 return *this = (*this | other);
2275}
2276
2277/*!
2278 \since 4.5
2279
2280 Unites this path with \a other, and returns a reference to this path. This
2281 is equivalent to operator|=().
2282
2283 \sa united(), operator+(), operator-=()
2284*/
2285QPainterPath &QPainterPath::operator+=(const QPainterPath &other)
2286{
2287 return *this = (*this + other);
2288}
2289
2290/*!
2291 \since 4.5
2292
2293 Subtracts \a other from this path, and returns a reference to this
2294 path.
2295
2296 \sa subtracted(), operator-(), operator+=()
2297*/
2298QPainterPath &QPainterPath::operator-=(const QPainterPath &other)
2299{
2300 return *this = (*this - other);
2301}
2302
2303#ifndef QT_NO_DATASTREAM
2304/*!
2305 \fn QDataStream &operator<<(QDataStream &stream, const QPainterPath &path)
2306 \relates QPainterPath
2307
2308 Writes the given painter \a path to the given \a stream, and
2309 returns a reference to the \a stream.
2310
2311 \sa {Serializing Qt Data Types}
2312*/
2313QDataStream &operator<<(QDataStream &s, const QPainterPath &p)
2314{
2315 if (p.isEmpty()) {
2316 s << 0;
2317 return s;
2318 }
2319
2320 s << p.elementCount();
2321 for (int i=0; i < p.d_func()->elements.size(); ++i) {
2322 const QPainterPath::Element &e = p.d_func()->elements.at(i);
2323 s << int(e.type);
2324 s << double(e.x) << double(e.y);
2325 }
2326 s << p.d_func()->cStart;
2327 s << int(p.d_func()->fillRule);
2328 return s;
2329}
2330
2331/*!
2332 \fn QDataStream &operator>>(QDataStream &stream, QPainterPath &path)
2333 \relates QPainterPath
2334
2335 Reads a painter path from the given \a stream into the specified \a path,
2336 and returns a reference to the \a stream.
2337
2338 \sa {Serializing Qt Data Types}
2339*/
2340QDataStream &operator>>(QDataStream &s, QPainterPath &p)
2341{
2342 int size;
2343 s >> size;
2344
2345 if (size == 0)
2346 return s;
2347
2348 p.ensureData(); // in case if p.d_func() == 0
2349 if (p.d_func()->elements.size() == 1) {
2350 Q_ASSERT(p.d_func()->elements.at(0).type == QPainterPath::MoveToElement);
2351 p.d_func()->elements.clear();
2352 }
2353 p.d_func()->elements.reserve(p.d_func()->elements.size() + size);
2354 for (int i=0; i<size; ++i) {
2355 int type;
2356 double x, y;
2357 s >> type;
2358 s >> x;
2359 s >> y;
2360 Q_ASSERT(type >= 0 && type <= 3);
2361#ifndef QT_NO_DEBUG
2362 if (qt_is_nan(x) || qt_is_nan(y))
2363 qWarning("QDataStream::operator>>: Adding a NaN element to path, results are undefined");
2364#endif
2365 QPainterPath::Element elm = { x, y, QPainterPath::ElementType(type) };
2366 p.d_func()->elements.append(elm);
2367 }
2368 s >> p.d_func()->cStart;
2369 int fillRule;
2370 s >> fillRule;
2371 Q_ASSERT(fillRule == Qt::OddEvenFill || Qt::WindingFill);
2372 p.d_func()->fillRule = Qt::FillRule(fillRule);
2373 p.d_func()->dirtyBounds = true;
2374 p.d_func()->dirtyControlBounds = true;
2375 return s;
2376}
2377#endif // QT_NO_DATASTREAM
2378
2379
2380/*******************************************************************************
2381 * class QPainterPathStroker
2382 */
2383
2384void qt_path_stroke_move_to(qfixed x, qfixed y, void *data)
2385{
2386 ((QPainterPath *) data)->moveTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
2387}
2388
2389void qt_path_stroke_line_to(qfixed x, qfixed y, void *data)
2390{
2391 ((QPainterPath *) data)->lineTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
2392}
2393
2394void qt_path_stroke_cubic_to(qfixed c1x, qfixed c1y,
2395 qfixed c2x, qfixed c2y,
2396 qfixed ex, qfixed ey,
2397 void *data)
2398{
2399 ((QPainterPath *) data)->cubicTo(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y),
2400 qt_fixed_to_real(c2x), qt_fixed_to_real(c2y),
2401 qt_fixed_to_real(ex), qt_fixed_to_real(ey));
2402}
2403
2404/*!
2405 \since 4.1
2406 \class QPainterPathStroker
2407 \ingroup painting
2408
2409 \brief The QPainterPathStroker class is used to generate fillable
2410 outlines for a given painter path.
2411
2412 By calling the createStroke() function, passing a given
2413 QPainterPath as argument, a new painter path representing the
2414 outline of the given path is created. The newly created painter
2415 path can then be filled to draw the original painter path's
2416 outline.
2417
2418 You can control the various design aspects (width, cap styles,
2419 join styles and dash pattern) of the outlining using the following
2420 functions:
2421
2422 \list
2423 \o setWidth()
2424 \o setCapStyle()
2425 \o setJoinStyle()
2426 \o setDashPattern()
2427 \endlist
2428
2429 The setDashPattern() function accepts both a Qt::PenStyle object
2430 and a vector representation of the pattern as argument.
2431
2432 In addition you can specify a curve's threshold, controlling the
2433 granularity with which a curve is drawn, using the
2434 setCurveThreshold() function. The default threshold is a well
2435 adjusted value (0.25), and normally you should not need to modify
2436 it. However, you can make the curve's appearance smoother by
2437 decreasing its value.
2438
2439 You can also control the miter limit for the generated outline
2440 using the setMiterLimit() function. The miter limit describes how
2441 far from each join the miter join can extend. The limit is
2442 specified in the units of width so the pixelwise miter limit will
2443 be \c {miterlimit * width}. This value is only used if the join
2444 style is Qt::MiterJoin.
2445
2446 The painter path generated by the createStroke() function should
2447 only be used for outlining the given painter path. Otherwise it
2448 may cause unexpected behavior. Generated outlines also require the
2449 Qt::WindingFill rule which is set by default.
2450
2451 \sa QPen, QBrush
2452*/
2453
2454QPainterPathStrokerPrivate::QPainterPathStrokerPrivate()
2455 : dashOffset(0)
2456{
2457 stroker.setMoveToHook(qt_path_stroke_move_to);
2458 stroker.setLineToHook(qt_path_stroke_line_to);
2459 stroker.setCubicToHook(qt_path_stroke_cubic_to);
2460}
2461
2462/*!
2463 Creates a new stroker.
2464 */
2465QPainterPathStroker::QPainterPathStroker()
2466 : d_ptr(new QPainterPathStrokerPrivate)
2467{
2468}
2469
2470/*!
2471 Destroys the stroker.
2472*/
2473QPainterPathStroker::~QPainterPathStroker()
2474{
2475}
2476
2477
2478/*!
2479 Generates a new path that is a fillable area representing the
2480 outline of the given \a path.
2481
2482 The various design aspects of the outline are based on the
2483 stroker's properties: width(), capStyle(), joinStyle(),
2484 dashPattern(), curveThreshold() and miterLimit().
2485
2486 The generated path should only be used for outlining the given
2487 painter path. Otherwise it may cause unexpected
2488 behavior. Generated outlines also require the Qt::WindingFill rule
2489 which is set by default.
2490*/
2491QPainterPath QPainterPathStroker::createStroke(const QPainterPath &path) const
2492{
2493 QPainterPathStrokerPrivate *d = const_cast<QPainterPathStrokerPrivate *>(d_func());
2494 QPainterPath stroke;
2495 if (path.isEmpty())
2496 return path;
2497 if (d->dashPattern.isEmpty()) {
2498 d->stroker.strokePath(path, &stroke, QTransform());
2499 } else {
2500 QDashStroker dashStroker(&d->stroker);
2501 dashStroker.setDashPattern(d->dashPattern);
2502 dashStroker.setDashOffset(d->dashOffset);
2503 dashStroker.setClipRect(d->stroker.clipRect());
2504 dashStroker.strokePath(path, &stroke, QTransform());
2505 }
2506 stroke.setFillRule(Qt::WindingFill);
2507 return stroke;
2508}
2509
2510/*!
2511 Sets the width of the generated outline painter path to \a width.
2512
2513 The generated outlines will extend approximately 50% of \a width
2514 to each side of the given input path's original outline.
2515*/
2516void QPainterPathStroker::setWidth(qreal width)
2517{
2518 Q_D(QPainterPathStroker);
2519 if (width <= 0)
2520 width = 1;
2521 d->stroker.setStrokeWidth(qt_real_to_fixed(width));
2522}
2523
2524/*!
2525 Returns the width of the generated outlines.
2526*/
2527qreal QPainterPathStroker::width() const
2528{
2529 return qt_fixed_to_real(d_func()->stroker.strokeWidth());
2530}
2531
2532
2533/*!
2534 Sets the cap style of the generated outlines to \a style. If a
2535 dash pattern is set, each segment of the pattern is subject to the
2536 cap \a style.
2537*/
2538void QPainterPathStroker::setCapStyle(Qt::PenCapStyle style)
2539{
2540 d_func()->stroker.setCapStyle(style);
2541}
2542
2543
2544/*!
2545 Returns the cap style of the generated outlines.
2546*/
2547Qt::PenCapStyle QPainterPathStroker::capStyle() const
2548{
2549 return d_func()->stroker.capStyle();
2550}
2551
2552/*!
2553 Sets the join style of the generated outlines to \a style.
2554*/
2555void QPainterPathStroker::setJoinStyle(Qt::PenJoinStyle style)
2556{
2557 d_func()->stroker.setJoinStyle(style);
2558}
2559
2560/*!
2561 Returns the join style of the generated outlines.
2562*/
2563Qt::PenJoinStyle QPainterPathStroker::joinStyle() const
2564{
2565 return d_func()->stroker.joinStyle();
2566}
2567
2568/*!
2569 Sets the miter limit of the generated outlines to \a limit.
2570
2571 The miter limit describes how far from each join the miter join
2572 can extend. The limit is specified in units of the currently set
2573 width. So the pixelwise miter limit will be \c { miterlimit *
2574 width}.
2575
2576 This value is only used if the join style is Qt::MiterJoin.
2577*/
2578void QPainterPathStroker::setMiterLimit(qreal limit)
2579{
2580 d_func()->stroker.setMiterLimit(qt_real_to_fixed(limit));
2581}
2582
2583/*!
2584 Returns the miter limit for the generated outlines.
2585*/
2586qreal QPainterPathStroker::miterLimit() const
2587{
2588 return qt_fixed_to_real(d_func()->stroker.miterLimit());
2589}
2590
2591
2592/*!
2593 Specifies the curve flattening \a threshold, controlling the
2594 granularity with which the generated outlines' curve is drawn.
2595
2596 The default threshold is a well adjusted value (0.25), and
2597 normally you should not need to modify it. However, you can make
2598 the curve's appearance smoother by decreasing its value.
2599*/
2600void QPainterPathStroker::setCurveThreshold(qreal threshold)
2601{
2602 d_func()->stroker.setCurveThreshold(qt_real_to_fixed(threshold));
2603}
2604
2605/*!
2606 Returns the curve flattening threshold for the generated
2607 outlines.
2608*/
2609qreal QPainterPathStroker::curveThreshold() const
2610{
2611 return qt_fixed_to_real(d_func()->stroker.curveThreshold());
2612}
2613
2614/*!
2615 Sets the dash pattern for the generated outlines to \a style.
2616*/
2617void QPainterPathStroker::setDashPattern(Qt::PenStyle style)
2618{
2619 d_func()->dashPattern = QDashStroker::patternForStyle(style);
2620}
2621
2622/*!
2623 \overload
2624
2625 Sets the dash pattern for the generated outlines to \a
2626 dashPattern. This function makes it possible to specify custom
2627 dash patterns.
2628
2629 Each element in the vector contains the lengths of the dashes and spaces
2630 in the stroke, beginning with the first dash in the first element, the
2631 first space in the second element, and alternating between dashes and
2632 spaces for each following pair of elements.
2633
2634 The vector can contain an odd number of elements, in which case the last
2635 element will be extended by the length of the first element when the
2636 pattern repeats.
2637*/
2638void QPainterPathStroker::setDashPattern(const QVector<qreal> &dashPattern)
2639{
2640 d_func()->dashPattern.clear();
2641 for (int i=0; i<dashPattern.size(); ++i)
2642 d_func()->dashPattern << qt_real_to_fixed(dashPattern.at(i));
2643}
2644
2645/*!
2646 Returns the dash pattern for the generated outlines.
2647*/
2648QVector<qreal> QPainterPathStroker::dashPattern() const
2649{
2650 return d_func()->dashPattern;
2651}
2652
2653/*!
2654 Returns the dash offset for the generated outlines.
2655 */
2656qreal QPainterPathStroker::dashOffset() const
2657{
2658 return d_func()->dashOffset;
2659}
2660
2661/*!
2662 Sets the dash offset for the generated outlines to \a offset.
2663
2664 See the documentation for QPen::setDashOffset() for a description of the
2665 dash offset.
2666 */
2667void QPainterPathStroker::setDashOffset(qreal offset)
2668{
2669 d_func()->dashOffset = offset;
2670}
2671
2672/*!
2673 Converts the path into a polygon using the QTransform
2674 \a matrix, and returns the polygon.
2675
2676 The polygon is created by first converting all subpaths to
2677 polygons, then using a rewinding technique to make sure that
2678 overlapping subpaths can be filled using the correct fill rule.
2679
2680 Note that rewinding inserts addition lines in the polygon so
2681 the outline of the fill polygon does not match the outline of
2682 the path.
2683
2684 \sa toSubpathPolygons(), toFillPolygons(),
2685 {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
2686*/
2687QPolygonF QPainterPath::toFillPolygon(const QTransform &matrix) const
2688{
2689
2690 QList<QPolygonF> flats = toSubpathPolygons(matrix);
2691 QPolygonF polygon;
2692 if (flats.isEmpty())
2693 return polygon;
2694 QPointF first = flats.first().first();
2695 for (int i=0; i<flats.size(); ++i) {
2696 polygon += flats.at(i);
2697 if (!flats.at(i).isClosed())
2698 polygon += flats.at(i).first();
2699 if (i > 0)
2700 polygon += first;
2701 }
2702 return polygon;
2703}
2704
2705/*!
2706 \overload
2707*/
2708QPolygonF QPainterPath::toFillPolygon(const QMatrix &matrix) const
2709{
2710 return toFillPolygon(QTransform(matrix));
2711}
2712
2713
2714//derivative of the equation
2715static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
2716{
2717 return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
2718}
2719
2720/*!
2721 Returns the length of the current path.
2722*/
2723qreal QPainterPath::length() const
2724{
2725 Q_D(QPainterPath);
2726 if (isEmpty())
2727 return 0;
2728
2729 qreal len = 0;
2730 for (int i=1; i<d->elements.size(); ++i) {
2731 const Element &e = d->elements.at(i);
2732
2733 switch (e.type) {
2734 case MoveToElement:
2735 break;
2736 case LineToElement:
2737 {
2738 len += QLineF(d->elements.at(i-1), e).length();
2739 break;
2740 }
2741 case CurveToElement:
2742 {
2743 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2744 e,
2745 d->elements.at(i+1),
2746 d->elements.at(i+2));
2747 len += b.length();
2748 i += 2;
2749 break;
2750 }
2751 default:
2752 break;
2753 }
2754 }
2755 return len;
2756}
2757
2758/*!
2759 Returns percentage of the whole path at the specified length \a len.
2760
2761 Note that similarly to other percent methods, the percentage measurement
2762 is not linear with regards to the length, if curves are present
2763 in the path. When curves are present the percentage argument is mapped
2764 to the t parameter of the Bezier equations.
2765*/
2766qreal QPainterPath::percentAtLength(qreal len) const
2767{
2768 Q_D(QPainterPath);
2769 if (isEmpty() || len <= 0)
2770 return 0;
2771
2772 qreal totalLength = length();
2773 if (len > totalLength)
2774 return 1;
2775
2776 qreal curLen = 0;
2777 for (int i=1; i<d->elements.size(); ++i) {
2778 const Element &e = d->elements.at(i);
2779
2780 switch (e.type) {
2781 case MoveToElement:
2782 break;
2783 case LineToElement:
2784 {
2785 QLineF line(d->elements.at(i-1), e);
2786 qreal llen = line.length();
2787 curLen += llen;
2788 if (curLen >= len) {
2789 return len/totalLength ;
2790 }
2791
2792 break;
2793 }
2794 case CurveToElement:
2795 {
2796 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2797 e,
2798 d->elements.at(i+1),
2799 d->elements.at(i+2));
2800 qreal blen = b.length();
2801 qreal prevLen = curLen;
2802 curLen += blen;
2803
2804 if (curLen >= len) {
2805 qreal res = b.tAtLength(len - prevLen);
2806 return (res * blen + prevLen)/totalLength;
2807 }
2808
2809 i += 2;
2810 break;
2811 }
2812 default:
2813 break;
2814 }
2815 }
2816
2817 return 0;
2818}
2819
2820static inline QBezier bezierAtT(const QPainterPath &path, qreal t, qreal *startingLength, qreal *bezierLength)
2821{
2822 *startingLength = 0;
2823 if (t > 1)
2824 return QBezier();
2825
2826 qreal curLen = 0;
2827 qreal totalLength = path.length();
2828
2829 const int lastElement = path.elementCount() - 1;
2830 for (int i=0; i <= lastElement; ++i) {
2831 const QPainterPath::Element &e = path.elementAt(i);
2832
2833 switch (e.type) {
2834 case QPainterPath::MoveToElement:
2835 break;
2836 case QPainterPath::LineToElement:
2837 {
2838 QLineF line(path.elementAt(i-1), e);
2839 qreal llen = line.length();
2840 curLen += llen;
2841 if (i == lastElement || curLen/totalLength >= t) {
2842 *bezierLength = llen;
2843 QPointF a = path.elementAt(i-1);
2844 QPointF delta = e - a;
2845 return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
2846 }
2847 break;
2848 }
2849 case QPainterPath::CurveToElement:
2850 {
2851 QBezier b = QBezier::fromPoints(path.elementAt(i-1),
2852 e,
2853 path.elementAt(i+1),
2854 path.elementAt(i+2));
2855 qreal blen = b.length();
2856 curLen += blen;
2857
2858 if (i + 2 == lastElement || curLen/totalLength >= t) {
2859 *bezierLength = blen;
2860 return b;
2861 }
2862
2863 i += 2;
2864 break;
2865 }
2866 default:
2867 break;
2868 }
2869 *startingLength = curLen;
2870 }
2871 return QBezier();
2872}
2873
2874/*!
2875 Returns the point at at the percentage \a t of the current path.
2876 The argument \a t has to be between 0 and 1.
2877
2878 Note that similarly to other percent methods, the percentage measurement
2879 is not linear with regards to the length, if curves are present
2880 in the path. When curves are present the percentage argument is mapped
2881 to the t parameter of the Bezier equations.
2882*/
2883QPointF QPainterPath::pointAtPercent(qreal t) const
2884{
2885 if (t < 0 || t > 1) {
2886 qWarning("QPainterPath::pointAtPercent accepts only values between 0 and 1");
2887 return QPointF();
2888 }
2889
2890 if (isEmpty())
2891 return QPointF();
2892
2893 qreal totalLength = length();
2894 qreal curLen = 0;
2895 qreal bezierLen = 0;
2896 QBezier b = bezierAtT(*this, t, &curLen, &bezierLen);
2897 qreal realT = (totalLength * t - curLen) / bezierLen;
2898
2899 return b.pointAt(qBound(qreal(0), realT, qreal(1)));
2900}
2901
2902/*!
2903 Returns the angle of the path tangent at the percentage \a t.
2904 The argument \a t has to be between 0 and 1.
2905
2906 Positive values for the angles mean counter-clockwise while negative values
2907 mean the clockwise direction. Zero degrees is at the 3 o'clock position.
2908
2909 Note that similarly to the other percent methods, the percentage measurement
2910 is not linear with regards to the length if curves are present
2911 in the path. When curves are present the percentage argument is mapped
2912 to the t parameter of the Bezier equations.
2913*/
2914qreal QPainterPath::angleAtPercent(qreal t) const
2915{
2916 if (t < 0 || t > 1) {
2917 qWarning("QPainterPath::angleAtPercent accepts only values between 0 and 1");
2918 return 0;
2919 }
2920
2921 qreal totalLength = length();
2922 qreal curLen = 0;
2923 qreal bezierLen = 0;
2924 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
2925 qreal realT = (totalLength * t - curLen) / bezierLen;
2926
2927 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
2928 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
2929
2930 return QLineF(0, 0, m1, m2).angle();
2931}
2932
2933#if defined(Q_WS_WINCE)
2934#pragma warning( disable : 4056 4756 )
2935#endif
2936
2937/*!
2938 Returns the slope of the path at the percentage \a t. The
2939 argument \a t has to be between 0 and 1.
2940
2941 Note that similarly to other percent methods, the percentage measurement
2942 is not linear with regards to the length, if curves are present
2943 in the path. When curves are present the percentage argument is mapped
2944 to the t parameter of the Bezier equations.
2945*/
2946qreal QPainterPath::slopeAtPercent(qreal t) const
2947{
2948 if (t < 0 || t > 1) {
2949 qWarning("QPainterPath::slopeAtPercent accepts only values between 0 and 1");
2950 return 0;
2951 }
2952
2953 qreal totalLength = length();
2954 qreal curLen = 0;
2955 qreal bezierLen = 0;
2956 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
2957 qreal realT = (totalLength * t - curLen) / bezierLen;
2958
2959 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
2960 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
2961 //tangent line
2962 qreal slope = 0;
2963
2964#define SIGN(x) ((x < 0)?-1:1)
2965 if (m1)
2966 slope = m2/m1;
2967 else {
2968 //windows doesn't define INFINITY :(
2969#ifdef INFINITY
2970 slope = INFINITY*SIGN(m2);
2971#else
2972 if (sizeof(qreal) == sizeof(double)) {
2973 return 1.79769313486231570e+308;
2974 } else {
2975 return ((qreal)3.40282346638528860e+38);
2976 }
2977#endif
2978 }
2979
2980 return slope;
2981}
2982
2983/*!
2984 \since 4.4
2985
2986 Adds the given rectangle \a rect with rounded corners to the path.
2987
2988 The \a xRadius and \a yRadius arguments specify the radii of
2989 the ellipses defining the corners of the rounded rectangle.
2990 When \a mode is Qt::RelativeSize, \a xRadius and
2991 \a yRadius are specified in percentage of half the rectangle's
2992 width and height respectively, and should be in the range 0.0 to 100.0.
2993
2994 \sa addRect()
2995*/
2996void QPainterPath::addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius,
2997 Qt::SizeMode mode)
2998{
2999 QRectF r = rect.normalized();
3000
3001 if (r.isNull())
3002 return;
3003
3004 if (mode == Qt::AbsoluteSize) {
3005 qreal w = r.width() / 2;
3006 qreal h = r.height() / 2;
3007
3008 if (w == 0) {
3009 xRadius = 0;
3010 } else {
3011 xRadius = 100 * qMin(xRadius, w) / w;
3012 }
3013 if (h == 0) {
3014 yRadius = 0;
3015 } else {
3016 yRadius = 100 * qMin(yRadius, h) / h;
3017 }
3018 } else {
3019 if (xRadius > 100) // fix ranges
3020 xRadius = 100;
3021
3022 if (yRadius > 100)
3023 yRadius = 100;
3024 }
3025
3026 if (xRadius <= 0 || yRadius <= 0) { // add normal rectangle
3027 addRect(r);
3028 return;
3029 }
3030
3031 qreal x = r.x();
3032 qreal y = r.y();
3033 qreal w = r.width();
3034 qreal h = r.height();
3035 qreal rxx2 = w*xRadius/100;
3036 qreal ryy2 = h*yRadius/100;
3037
3038 ensureData();
3039 detach();
3040
3041 bool first = d_func()->elements.size() < 2;
3042
3043 arcMoveTo(x, y, rxx2, ryy2, 180);
3044 arcTo(x, y, rxx2, ryy2, 180, -90);
3045 arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3046 arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3047 arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3048 closeSubpath();
3049
3050 d_func()->require_moveTo = true;
3051 d_func()->convex = first;
3052}
3053
3054/*!
3055 \fn void QPainterPath::addRoundedRect(qreal x, qreal y, qreal w, qreal h, qreal xRadius, qreal yRadius, Qt::SizeMode mode = Qt::AbsoluteSize);
3056 \since 4.4
3057 \overload
3058
3059 Adds the given rectangle \a x, \a y, \a w, \a h with rounded corners to the path.
3060 */
3061
3062/*!
3063 \obsolete
3064
3065 Adds a rectangle \a r with rounded corners to the path.
3066
3067 The \a xRnd and \a yRnd arguments specify how rounded the corners
3068 should be. 0 is angled corners, 99 is maximum roundedness.
3069
3070 \sa addRoundedRect()
3071*/
3072void QPainterPath::addRoundRect(const QRectF &r, int xRnd, int yRnd)
3073{
3074 if(xRnd >= 100) // fix ranges
3075 xRnd = 99;
3076 if(yRnd >= 100)
3077 yRnd = 99;
3078 if(xRnd <= 0 || yRnd <= 0) { // add normal rectangle
3079 addRect(r);
3080 return;
3081 }
3082
3083 QRectF rect = r.normalized();
3084
3085 if (rect.isNull())
3086 return;
3087
3088 qreal x = rect.x();
3089 qreal y = rect.y();
3090 qreal w = rect.width();
3091 qreal h = rect.height();
3092 qreal rxx2 = w*xRnd/100;
3093 qreal ryy2 = h*yRnd/100;
3094
3095 ensureData();
3096 detach();
3097
3098 bool first = d_func()->elements.size() < 2;
3099
3100 arcMoveTo(x, y, rxx2, ryy2, 180);
3101 arcTo(x, y, rxx2, ryy2, 180, -90);
3102 arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3103 arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3104 arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3105 closeSubpath();
3106
3107 d_func()->require_moveTo = true;
3108 d_func()->convex = first;
3109}
3110
3111/*!
3112 \obsolete
3113
3114 \fn bool QPainterPath::addRoundRect(const QRectF &rect, int roundness);
3115 \since 4.3
3116 \overload
3117
3118 Adds a rounded rectangle, \a rect, to the path.
3119
3120 The \a roundness argument specifies uniform roundness for the
3121 rectangle. Vertical and horizontal roundness factors will be
3122 adjusted accordingly to act uniformly around both axes. Use this
3123 method if you want a rectangle equally rounded across both the X and
3124 Y axis.
3125
3126 \sa addRoundedRect()
3127*/
3128
3129/*!
3130 \obsolete
3131
3132 \fn void QPainterPath::addRoundRect(qreal x, qreal y, qreal w, qreal h, int xRnd, int yRnd);
3133 \overload
3134
3135 Adds a rectangle with rounded corners to the path. The rectangle
3136 is constructed from \a x, \a y, and the width and height \a w
3137 and \a h.
3138
3139 The \a xRnd and \a yRnd arguments specify how rounded the corners
3140 should be. 0 is angled corners, 99 is maximum roundedness.
3141
3142 \sa addRoundedRect()
3143 */
3144
3145/*!
3146 \obsolete
3147
3148 \fn bool QPainterPath::addRoundRect(qreal x, qreal y, qreal width, qreal height, int roundness);
3149 \since 4.3
3150 \overload
3151
3152 Adds a rounded rectangle to the path, defined by the coordinates \a
3153 x and \a y with the specified \a width and \a height.
3154
3155 The \a roundness argument specifies uniform roundness for the
3156 rectangle. Vertical and horizontal roundness factors will be
3157 adjusted accordingly to act uniformly around both axes. Use this
3158 method if you want a rectangle equally rounded across both the X and
3159 Y axis.
3160
3161 \sa addRoundedRect()
3162*/
3163
3164/*!
3165 \since 4.3
3166
3167 Returns a path which is the union of this path's fill area and \a p's fill area.
3168
3169 Set operations on paths will treat the paths as areas. Non-closed
3170 paths will be treated as implicitly closed.
3171 Bezier curves may be flattened to line segments due to numerical instability of
3172 doing bezier curve intersections.
3173
3174 \sa intersected(), subtracted()
3175*/
3176QPainterPath QPainterPath::united(const QPainterPath &p) const
3177{
3178 if (isEmpty() || p.isEmpty())
3179 return isEmpty() ? p : *this;
3180 QPathClipper clipper(*this, p);
3181 return clipper.clip(QPathClipper::BoolOr);
3182}
3183
3184/*!
3185 \since 4.3
3186
3187 Returns a path which is the intersection of this path's fill area and \a p's fill area.
3188 Bezier curves may be flattened to line segments due to numerical instability of
3189 doing bezier curve intersections.
3190*/
3191QPainterPath QPainterPath::intersected(const QPainterPath &p) const
3192{
3193 if (isEmpty() || p.isEmpty())
3194 return QPainterPath();
3195 QPathClipper clipper(*this, p);
3196 return clipper.clip(QPathClipper::BoolAnd);
3197}
3198
3199/*!
3200 \since 4.3
3201
3202 Returns a path which is \a p's fill area subtracted from this path's fill area.
3203
3204 Set operations on paths will treat the paths as areas. Non-closed
3205 paths will be treated as implicitly closed.
3206 Bezier curves may be flattened to line segments due to numerical instability of
3207 doing bezier curve intersections.
3208*/
3209QPainterPath QPainterPath::subtracted(const QPainterPath &p) const
3210{
3211 if (isEmpty() || p.isEmpty())
3212 return *this;
3213 QPathClipper clipper(*this, p);
3214 return clipper.clip(QPathClipper::BoolSub);
3215}
3216
3217/*!
3218 \since 4.3
3219 \obsolete
3220
3221 Use subtracted() instead.
3222
3223 \sa subtracted()
3224*/
3225QPainterPath QPainterPath::subtractedInverted(const QPainterPath &p) const
3226{
3227 return p.subtracted(*this);
3228}
3229
3230/*!
3231 \since 4.4
3232
3233 Returns a simplified version of this path. This implies merging all subpaths that intersect,
3234 and returning a path containing no intersecting edges. Consecutive parallel lines will also
3235 be merged. The simplified path will always use the default fill rule, Qt::OddEvenFill.
3236 Bezier curves may be flattened to line segments due to numerical instability of
3237 doing bezier curve intersections.
3238*/
3239QPainterPath QPainterPath::simplified() const
3240{
3241 if(isEmpty())
3242 return *this;
3243 QPathClipper clipper(*this, QPainterPath());
3244 return clipper.clip(QPathClipper::Simplify);
3245}
3246
3247/*!
3248 \since 4.3
3249
3250 Returns true if the current path intersects at any point the given path \a p.
3251 Also returns true if the current path contains or is contained by any part of \a p.
3252
3253 Set operations on paths will treat the paths as areas. Non-closed
3254 paths will be treated as implicitly closed.
3255
3256 \sa contains()
3257 */
3258bool QPainterPath::intersects(const QPainterPath &p) const
3259{
3260 if (p.elementCount() == 1)
3261 return contains(p.elementAt(0));
3262 if (isEmpty() || p.isEmpty())
3263 return false;
3264 QPathClipper clipper(*this, p);
3265 return clipper.intersect();
3266}
3267
3268/*!
3269 \since 4.3
3270
3271 Returns true if the given path \a p is contained within
3272 the current path. Returns false if any edges of the current path and
3273 \a p intersect.
3274
3275 Set operations on paths will treat the paths as areas. Non-closed
3276 paths will be treated as implicitly closed.
3277
3278 \sa intersects()
3279 */
3280bool QPainterPath::contains(const QPainterPath &p) const
3281{
3282 if (p.elementCount() == 1)
3283 return contains(p.elementAt(0));
3284 if (isEmpty() || p.isEmpty())
3285 return false;
3286 QPathClipper clipper(*this, p);
3287 return clipper.contains();
3288}
3289
3290void QPainterPath::setDirty(bool dirty)
3291{
3292 d_func()->dirtyBounds = dirty;
3293 d_func()->dirtyControlBounds = dirty;
3294 delete d_func()->pathConverter;
3295 d_func()->pathConverter = 0;
3296 d_func()->convex = false;
3297}
3298
3299void QPainterPath::computeBoundingRect() const
3300{
3301 QPainterPathData *d = d_func();
3302 d->dirtyBounds = false;
3303 if (!d_ptr) {
3304 d->bounds = QRect();
3305 return;
3306 }
3307
3308 qreal minx, maxx, miny, maxy;
3309 minx = maxx = d->elements.at(0).x;
3310 miny = maxy = d->elements.at(0).y;
3311 for (int i=1; i<d->elements.size(); ++i) {
3312 const Element &e = d->elements.at(i);
3313
3314 switch (e.type) {
3315 case MoveToElement:
3316 case LineToElement:
3317 if (e.x > maxx) maxx = e.x;
3318 else if (e.x < minx) minx = e.x;
3319 if (e.y > maxy) maxy = e.y;
3320 else if (e.y < miny) miny = e.y;
3321 break;
3322 case CurveToElement:
3323 {
3324 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
3325 e,
3326 d->elements.at(i+1),
3327 d->elements.at(i+2));
3328 QRectF r = qt_painterpath_bezier_extrema(b);
3329 qreal right = r.right();
3330 qreal bottom = r.bottom();
3331 if (r.x() < minx) minx = r.x();
3332 if (right > maxx) maxx = right;
3333 if (r.y() < miny) miny = r.y();
3334 if (bottom > maxy) maxy = bottom;
3335 i += 2;
3336 }
3337 break;
3338 default:
3339 break;
3340 }
3341 }
3342 d->bounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3343}
3344
3345
3346void QPainterPath::computeControlPointRect() const
3347{
3348 QPainterPathData *d = d_func();
3349 d->dirtyControlBounds = false;
3350 if (!d_ptr) {
3351 d->controlBounds = QRect();
3352 return;
3353 }
3354
3355 qreal minx, maxx, miny, maxy;
3356 minx = maxx = d->elements.at(0).x;
3357 miny = maxy = d->elements.at(0).y;
3358 for (int i=1; i<d->elements.size(); ++i) {
3359 const Element &e = d->elements.at(i);
3360 if (e.x > maxx) maxx = e.x;
3361 else if (e.x < minx) minx = e.x;
3362 if (e.y > maxy) maxy = e.y;
3363 else if (e.y < miny) miny = e.y;
3364 }
3365 d->controlBounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3366}
3367
3368#ifndef QT_NO_DEBUG_STREAM
3369QDebug operator<<(QDebug s, const QPainterPath &p)
3370{
3371 s.nospace() << "QPainterPath: Element count=" << p.elementCount() << endl;
3372 const char *types[] = {"MoveTo", "LineTo", "CurveTo", "CurveToData"};
3373 for (int i=0; i<p.elementCount(); ++i) {
3374 s.nospace() << " -> " << types[p.elementAt(i).type] << "(x=" << p.elementAt(i).x << ", y=" << p.elementAt(i).y << ')' << endl;
3375
3376 }
3377 return s;
3378}
3379#endif
3380
3381QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.