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

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 96.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
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 qt-info@nokia.com.
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 d->elements[first].type = LineToElement;
1200
1201 // avoid duplicate points
1202 if (first > 0 && QPointF(d->elements[first]) == QPointF(d->elements[first - 1])) {
1203 d->elements.remove(first--);
1204 --cStart;
1205 }
1206
1207 if (cStart != first)
1208 d->cStart = cStart;
1209}
1210
1211/*!
1212 Adds the given \a region to the path by adding each rectangle in
1213 the region as a separate closed subpath.
1214
1215 \sa addRect(), {QPainterPath#Composing a QPainterPath}{Composing
1216 a QPainterPath}
1217*/
1218void QPainterPath::addRegion(const QRegion &region)
1219{
1220 ensureData();
1221 detach();
1222
1223 QVector<QRect> rects = region.rects();
1224 d_func()->elements.reserve(rects.size() * 5);
1225 for (int i=0; i<rects.size(); ++i)
1226 addRect(rects.at(i));
1227}
1228
1229
1230/*!
1231 Returns the painter path's currently set fill rule.
1232
1233 \sa setFillRule()
1234*/
1235Qt::FillRule QPainterPath::fillRule() const
1236{
1237 return isEmpty() ? Qt::OddEvenFill : d_func()->fillRule;
1238}
1239
1240/*!
1241 \fn void QPainterPath::setFillRule(Qt::FillRule fillRule)
1242
1243 Sets the fill rule of the painter path to the given \a
1244 fillRule. Qt provides two methods for filling paths:
1245
1246 \table
1247 \row
1248 \o \inlineimage qt-fillrule-oddeven.png
1249 \o \inlineimage qt-fillrule-winding.png
1250 \header
1251 \o Qt::OddEvenFill (default)
1252 \o Qt::WindingFill
1253 \endtable
1254
1255 \sa fillRule()
1256*/
1257void QPainterPath::setFillRule(Qt::FillRule fillRule)
1258{
1259 ensureData();
1260 detach();
1261
1262 d_func()->fillRule = fillRule;
1263}
1264
1265#define QT_BEZIER_A(bezier, coord) 3 * (-bezier.coord##1 \
1266 + 3*bezier.coord##2 \
1267 - 3*bezier.coord##3 \
1268 +bezier.coord##4)
1269
1270#define QT_BEZIER_B(bezier, coord) 6 * (bezier.coord##1 \
1271 - 2*bezier.coord##2 \
1272 + bezier.coord##3)
1273
1274#define QT_BEZIER_C(bezier, coord) 3 * (- bezier.coord##1 \
1275 + bezier.coord##2)
1276
1277#define QT_BEZIER_CHECK_T(bezier, t) \
1278 if (t >= 0 && t <= 1) { \
1279 QPointF p(b.pointAt(t)); \
1280 if (p.x() < minx) minx = p.x(); \
1281 else if (p.x() > maxx) maxx = p.x(); \
1282 if (p.y() < miny) miny = p.y(); \
1283 else if (p.y() > maxy) maxy = p.y(); \
1284 }
1285
1286
1287static QRectF qt_painterpath_bezier_extrema(const QBezier &b)
1288{
1289 qreal minx, miny, maxx, maxy;
1290
1291 // initialize with end points
1292 if (b.x1 < b.x4) {
1293 minx = b.x1;
1294 maxx = b.x4;
1295 } else {
1296 minx = b.x4;
1297 maxx = b.x1;
1298 }
1299 if (b.y1 < b.y4) {
1300 miny = b.y1;
1301 maxy = b.y4;
1302 } else {
1303 miny = b.y4;
1304 maxy = b.y1;
1305 }
1306
1307 // Update for the X extrema
1308 {
1309 qreal ax = QT_BEZIER_A(b, x);
1310 qreal bx = QT_BEZIER_B(b, x);
1311 qreal cx = QT_BEZIER_C(b, x);
1312 // specialcase quadratic curves to avoid div by zero
1313 if (qFuzzyIsNull(ax)) {
1314
1315 // linear curves are covered by initialization.
1316 if (!qFuzzyIsNull(bx)) {
1317 qreal t = -cx / bx;
1318 QT_BEZIER_CHECK_T(b, t);
1319 }
1320
1321 } else {
1322 const qreal tx = bx * bx - 4 * ax * cx;
1323
1324 if (tx >= 0) {
1325 qreal temp = qSqrt(tx);
1326 qreal rcp = 1 / (2 * ax);
1327 qreal t1 = (-bx + temp) * rcp;
1328 QT_BEZIER_CHECK_T(b, t1);
1329
1330 qreal t2 = (-bx - temp) * rcp;
1331 QT_BEZIER_CHECK_T(b, t2);
1332 }
1333 }
1334 }
1335
1336 // Update for the Y extrema
1337 {
1338 qreal ay = QT_BEZIER_A(b, y);
1339 qreal by = QT_BEZIER_B(b, y);
1340 qreal cy = QT_BEZIER_C(b, y);
1341
1342 // specialcase quadratic curves to avoid div by zero
1343 if (qFuzzyIsNull(ay)) {
1344
1345 // linear curves are covered by initialization.
1346 if (!qFuzzyIsNull(by)) {
1347 qreal t = -cy / by;
1348 QT_BEZIER_CHECK_T(b, t);
1349 }
1350
1351 } else {
1352 const qreal ty = by * by - 4 * ay * cy;
1353
1354 if (ty > 0) {
1355 qreal temp = qSqrt(ty);
1356 qreal rcp = 1 / (2 * ay);
1357 qreal t1 = (-by + temp) * rcp;
1358 QT_BEZIER_CHECK_T(b, t1);
1359
1360 qreal t2 = (-by - temp) * rcp;
1361 QT_BEZIER_CHECK_T(b, t2);
1362 }
1363 }
1364 }
1365 return QRectF(minx, miny, maxx - minx, maxy - miny);
1366}
1367
1368/*!
1369 Returns the bounding rectangle of this painter path as a rectangle with
1370 floating point precision.
1371
1372 \sa controlPointRect()
1373*/
1374QRectF QPainterPath::boundingRect() const
1375{
1376 if (!d_ptr)
1377 return QRectF();
1378 QPainterPathData *d = d_func();
1379
1380 if (d->dirtyBounds)
1381 computeBoundingRect();
1382 return d->bounds;
1383}
1384
1385/*!
1386 Returns the rectangle containing all the points and control points
1387 in this path.
1388
1389 This function is significantly faster to compute than the exact
1390 boundingRect(), and the returned rectangle is always a superset of
1391 the rectangle returned by boundingRect().
1392
1393 \sa boundingRect()
1394*/
1395QRectF QPainterPath::controlPointRect() const
1396{
1397 if (!d_ptr)
1398 return QRectF();
1399 QPainterPathData *d = d_func();
1400
1401 if (d->dirtyControlBounds)
1402 computeControlPointRect();
1403 return d->controlBounds;
1404}
1405
1406
1407/*!
1408 \fn bool QPainterPath::isEmpty() const
1409
1410 Returns true if either there are no elements in this path, or if the only
1411 element is a MoveToElement; otherwise returns false.
1412
1413 \sa elementCount()
1414*/
1415
1416/*!
1417 Creates and returns a reversed copy of the path.
1418
1419 It is the order of the elements that is reversed: If a
1420 QPainterPath is composed by calling the moveTo(), lineTo() and
1421 cubicTo() functions in the specified order, the reversed copy is
1422 composed by calling cubicTo(), lineTo() and moveTo().
1423*/
1424QPainterPath QPainterPath::toReversed() const
1425{
1426 Q_D(const QPainterPath);
1427 QPainterPath rev;
1428
1429 if (isEmpty()) {
1430 rev = *this;
1431 return rev;
1432 }
1433
1434 rev.moveTo(d->elements.at(d->elements.size()-1).x, d->elements.at(d->elements.size()-1).y);
1435
1436 for (int i=d->elements.size()-1; i>=1; --i) {
1437 const QPainterPath::Element &elm = d->elements.at(i);
1438 const QPainterPath::Element &prev = d->elements.at(i-1);
1439 switch (elm.type) {
1440 case LineToElement:
1441 rev.lineTo(prev.x, prev.y);
1442 break;
1443 case MoveToElement:
1444 rev.moveTo(prev.x, prev.y);
1445 break;
1446 case CurveToDataElement:
1447 {
1448 Q_ASSERT(i>=3);
1449 const QPainterPath::Element &cp1 = d->elements.at(i-2);
1450 const QPainterPath::Element &sp = d->elements.at(i-3);
1451 Q_ASSERT(prev.type == CurveToDataElement);
1452 Q_ASSERT(cp1.type == CurveToElement);
1453 rev.cubicTo(prev.x, prev.y, cp1.x, cp1.y, sp.x, sp.y);
1454 i -= 2;
1455 break;
1456 }
1457 default:
1458 Q_ASSERT(!"qt_reversed_path");
1459 break;
1460 }
1461 }
1462 //qt_debug_path(rev);
1463 return rev;
1464}
1465
1466/*!
1467 Converts the path into a list of polygons using the QTransform
1468 \a matrix, and returns the list.
1469
1470 This function creates one polygon for each subpath regardless of
1471 intersecting subpaths (i.e. overlapping bounding rectangles). To
1472 make sure that such overlapping subpaths are filled correctly, use
1473 the toFillPolygons() function instead.
1474
1475 \sa toFillPolygons(), toFillPolygon(), {QPainterPath#QPainterPath
1476 Conversion}{QPainterPath Conversion}
1477*/
1478QList<QPolygonF> QPainterPath::toSubpathPolygons(const QTransform &matrix) const
1479{
1480
1481 Q_D(const QPainterPath);
1482 QList<QPolygonF> flatCurves;
1483 if (isEmpty())
1484 return flatCurves;
1485
1486 QPolygonF current;
1487 for (int i=0; i<elementCount(); ++i) {
1488 const QPainterPath::Element &e = d->elements.at(i);
1489 switch (e.type) {
1490 case QPainterPath::MoveToElement:
1491 if (current.size() > 1)
1492 flatCurves += current;
1493 current.clear();
1494 current.reserve(16);
1495 current += QPointF(e.x, e.y) * matrix;
1496 break;
1497 case QPainterPath::LineToElement:
1498 current += QPointF(e.x, e.y) * matrix;
1499 break;
1500 case QPainterPath::CurveToElement: {
1501 Q_ASSERT(d->elements.at(i+1).type == QPainterPath::CurveToDataElement);
1502 Q_ASSERT(d->elements.at(i+2).type == QPainterPath::CurveToDataElement);
1503 QBezier bezier = QBezier::fromPoints(QPointF(d->elements.at(i-1).x, d->elements.at(i-1).y) * matrix,
1504 QPointF(e.x, e.y) * matrix,
1505 QPointF(d->elements.at(i+1).x, d->elements.at(i+1).y) * matrix,
1506 QPointF(d->elements.at(i+2).x, d->elements.at(i+2).y) * matrix);
1507 bezier.addToPolygon(&current);
1508 i+=2;
1509 break;
1510 }
1511 case QPainterPath::CurveToDataElement:
1512 Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
1513 break;
1514 }
1515 }
1516
1517 if (current.size()>1)
1518 flatCurves += current;
1519
1520 return flatCurves;
1521}
1522
1523/*!
1524 \overload
1525 */
1526QList<QPolygonF> QPainterPath::toSubpathPolygons(const QMatrix &matrix) const
1527{
1528 return toSubpathPolygons(QTransform(matrix));
1529}
1530
1531/*!
1532 Converts the path into a list of polygons using the
1533 QTransform \a matrix, and returns the list.
1534
1535 The function differs from the toFillPolygon() function in that it
1536 creates several polygons. It is provided because it is usually
1537 faster to draw several small polygons than to draw one large
1538 polygon, even though the total number of points drawn is the same.
1539
1540 The toFillPolygons() function differs from the toSubpathPolygons()
1541 function in that it create only polygon for subpaths that have
1542 overlapping bounding rectangles.
1543
1544 Like the toFillPolygon() function, this function uses a rewinding
1545 technique to make sure that overlapping subpaths can be filled
1546 using the correct fill rule. Note that rewinding inserts addition
1547 lines in the polygons so the outline of the fill polygon does not
1548 match the outline of the path.
1549
1550 \sa toSubpathPolygons(), toFillPolygon(),
1551 {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
1552*/
1553QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
1554{
1555
1556 QList<QPolygonF> polys;
1557
1558 QList<QPolygonF> subpaths = toSubpathPolygons(matrix);
1559 int count = subpaths.size();
1560
1561 if (count == 0)
1562 return polys;
1563
1564 QList<QRectF> bounds;
1565 for (int i=0; i<count; ++i)
1566 bounds += subpaths.at(i).boundingRect();
1567
1568#ifdef QPP_FILLPOLYGONS_DEBUG
1569 printf("QPainterPath::toFillPolygons, subpathCount=%d\n", count);
1570 for (int i=0; i<bounds.size(); ++i)
1571 qDebug() << " bounds" << i << bounds.at(i);
1572#endif
1573
1574 QVector< QList<int> > isects;
1575 isects.resize(count);
1576
1577 // find all intersections
1578 for (int j=0; j<count; ++j) {
1579 if (subpaths.at(j).size() <= 2)
1580 continue;
1581 QRectF cbounds = bounds.at(j);
1582 for (int i=0; i<count; ++i) {
1583 if (cbounds.intersects(bounds.at(i))) {
1584 isects[j] << i;
1585 }
1586 }
1587 }
1588
1589#ifdef QPP_FILLPOLYGONS_DEBUG
1590 printf("Intersections before flattening:\n");
1591 for (int i = 0; i < count; ++i) {
1592 printf("%d: ", i);
1593 for (int j = 0; j < isects[i].size(); ++j) {
1594 printf("%d ", isects[i][j]);
1595 }
1596 printf("\n");
1597 }
1598#endif
1599
1600 // flatten the sets of intersections
1601 for (int i=0; i<count; ++i) {
1602 const QList<int> &current_isects = isects.at(i);
1603 for (int j=0; j<current_isects.size(); ++j) {
1604 int isect_j = current_isects.at(j);
1605 if (isect_j == i)
1606 continue;
1607 for (int k=0; k<isects[isect_j].size(); ++k) {
1608 int isect_k = isects[isect_j][k];
1609 if (isect_k != i && !isects.at(i).contains(isect_k)) {
1610 isects[i] += isect_k;
1611 }
1612 }
1613 isects[isect_j].clear();
1614 }
1615 }
1616
1617#ifdef QPP_FILLPOLYGONS_DEBUG
1618 printf("Intersections after flattening:\n");
1619 for (int i = 0; i < count; ++i) {
1620 printf("%d: ", i);
1621 for (int j = 0; j < isects[i].size(); ++j) {
1622 printf("%d ", isects[i][j]);
1623 }
1624 printf("\n");
1625 }
1626#endif
1627
1628 // Join the intersected subpaths as rewinded polygons
1629 for (int i=0; i<count; ++i) {
1630 const QList<int> &subpath_list = isects[i];
1631 if (!subpath_list.isEmpty()) {
1632 QPolygonF buildUp;
1633 for (int j=0; j<subpath_list.size(); ++j) {
1634 const QPolygonF &subpath = subpaths.at(subpath_list.at(j));
1635 buildUp += subpath;
1636 if (!subpath.isClosed())
1637 buildUp += subpath.first();
1638 if (!buildUp.isClosed())
1639 buildUp += buildUp.first();
1640 }
1641 polys += buildUp;
1642 }
1643 }
1644
1645 return polys;
1646}
1647
1648/*!
1649 \overload
1650 */
1651QList<QPolygonF> QPainterPath::toFillPolygons(const QMatrix &matrix) const
1652{
1653 return toFillPolygons(QTransform(matrix));
1654}
1655
1656//same as qt_polygon_isect_line in qpolygon.cpp
1657static void qt_painterpath_isect_line(const QPointF &p1,
1658 const QPointF &p2,
1659 const QPointF &pos,
1660 int *winding)
1661{
1662 qreal x1 = p1.x();
1663 qreal y1 = p1.y();
1664 qreal x2 = p2.x();
1665 qreal y2 = p2.y();
1666 qreal y = pos.y();
1667
1668 int dir = 1;
1669
1670 if (qFuzzyCompare(y1, y2)) {
1671 // ignore horizontal lines according to scan conversion rule
1672 return;
1673 } else if (y2 < y1) {
1674 qreal x_tmp = x2; x2 = x1; x1 = x_tmp;
1675 qreal y_tmp = y2; y2 = y1; y1 = y_tmp;
1676 dir = -1;
1677 }
1678
1679 if (y >= y1 && y < y2) {
1680 qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1);
1681
1682 // count up the winding number if we're
1683 if (x<=pos.x()) {
1684 (*winding) += dir;
1685 }
1686 }
1687}
1688
1689static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
1690 int *winding)
1691{
1692 qreal y = pt.y();
1693 qreal x = pt.x();
1694 QRectF bounds = bezier.bounds();
1695
1696 // potential intersection, divide and try again...
1697 // Please note that a sideeffect of the bottom exclusion is that
1698 // horizontal lines are dropped, but this is correct according to
1699 // scan conversion rules.
1700 if (y >= bounds.y() && y < bounds.y() + bounds.height()) {
1701
1702 // hit lower limit... This is a rough threshold, but its a
1703 // tradeoff between speed and precision.
1704 const qreal lower_bound = qreal(.001);
1705 if (bounds.width() < lower_bound && bounds.height() < lower_bound) {
1706 // We make the assumption here that the curve starts to
1707 // approximate a line after while (i.e. that it doesn't
1708 // change direction drastically during its slope)
1709 if (bezier.pt1().x() <= x) {
1710 (*winding) += (bezier.pt4().y() > bezier.pt1().y() ? 1 : -1);
1711 }
1712 return;
1713 }
1714
1715 // split curve and try again...
1716 QBezier first_half, second_half;
1717 bezier.split(&first_half, &second_half);
1718 qt_painterpath_isect_curve(first_half, pt, winding);
1719 qt_painterpath_isect_curve(second_half, pt, winding);
1720 }
1721}
1722
1723/*!
1724 \fn bool QPainterPath::contains(const QPointF &point) const
1725
1726 Returns true if the given \a point is inside the path, otherwise
1727 returns false.
1728
1729 \sa intersects()
1730*/
1731bool QPainterPath::contains(const QPointF &pt) const
1732{
1733 if (isEmpty() || !controlPointRect().contains(pt))
1734 return false;
1735
1736 QPainterPathData *d = d_func();
1737
1738 int winding_number = 0;
1739
1740 QPointF last_pt;
1741 QPointF last_start;
1742 for (int i=0; i<d->elements.size(); ++i) {
1743 const Element &e = d->elements.at(i);
1744
1745 switch (e.type) {
1746
1747 case MoveToElement:
1748 if (i > 0) // implicitly close all paths.
1749 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1750 last_start = last_pt = e;
1751 break;
1752
1753 case LineToElement:
1754 qt_painterpath_isect_line(last_pt, e, pt, &winding_number);
1755 last_pt = e;
1756 break;
1757
1758 case CurveToElement:
1759 {
1760 const QPainterPath::Element &cp2 = d->elements.at(++i);
1761 const QPainterPath::Element &ep = d->elements.at(++i);
1762 qt_painterpath_isect_curve(QBezier::fromPoints(last_pt, e, cp2, ep),
1763 pt, &winding_number);
1764 last_pt = ep;
1765
1766 }
1767 break;
1768
1769 default:
1770 break;
1771 }
1772 }
1773
1774 // implicitly close last subpath
1775 if (last_pt != last_start)
1776 qt_painterpath_isect_line(last_pt, last_start, pt, &winding_number);
1777
1778 return (d->fillRule == Qt::WindingFill
1779 ? (winding_number != 0)
1780 : ((winding_number % 2) != 0));
1781}
1782
1783static bool qt_painterpath_isect_line_rect(qreal x1, qreal y1, qreal x2, qreal y2,
1784 const QRectF &rect)
1785{
1786 qreal left = rect.left();
1787 qreal right = rect.right();
1788 qreal top = rect.top();
1789 qreal bottom = rect.bottom();
1790
1791 enum { Left, Right, Top, Bottom };
1792 // clip the lines, after cohen-sutherland, see e.g. http://www.nondot.org/~sabre/graphpro/line6.html
1793 int p1 = ((x1 < left) << Left)
1794 | ((x1 > right) << Right)
1795 | ((y1 < top) << Top)
1796 | ((y1 > bottom) << Bottom);
1797 int p2 = ((x2 < left) << Left)
1798 | ((x2 > right) << Right)
1799 | ((y2 < top) << Top)
1800 | ((y2 > bottom) << Bottom);
1801
1802 if (p1 & p2)
1803 // completely inside
1804 return false;
1805
1806 if (p1 | p2) {
1807 qreal dx = x2 - x1;
1808 qreal dy = y2 - y1;
1809
1810 // clip x coordinates
1811 if (x1 < left) {
1812 y1 += dy/dx * (left - x1);
1813 x1 = left;
1814 } else if (x1 > right) {
1815 y1 -= dy/dx * (x1 - right);
1816 x1 = right;
1817 }
1818 if (x2 < left) {
1819 y2 += dy/dx * (left - x2);
1820 x2 = left;
1821 } else if (x2 > right) {
1822 y2 -= dy/dx * (x2 - right);
1823 x2 = right;
1824 }
1825
1826 p1 = ((y1 < top) << Top)
1827 | ((y1 > bottom) << Bottom);
1828 p2 = ((y2 < top) << Top)
1829 | ((y2 > bottom) << Bottom);
1830
1831 if (p1 & p2)
1832 return false;
1833
1834 // clip y coordinates
1835 if (y1 < top) {
1836 x1 += dx/dy * (top - y1);
1837 y1 = top;
1838 } else if (y1 > bottom) {
1839 x1 -= dx/dy * (y1 - bottom);
1840 y1 = bottom;
1841 }
1842 if (y2 < top) {
1843 x2 += dx/dy * (top - y2);
1844 y2 = top;
1845 } else if (y2 > bottom) {
1846 x2 -= dx/dy * (y2 - bottom);
1847 y2 = bottom;
1848 }
1849
1850 p1 = ((x1 < left) << Left)
1851 | ((x1 > right) << Right);
1852 p2 = ((x2 < left) << Left)
1853 | ((x2 > right) << Right);
1854
1855 if (p1 & p2)
1856 return false;
1857
1858 return true;
1859 }
1860 return false;
1861}
1862
1863static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2)
1864{
1865 QRectF bounds = bezier.bounds();
1866
1867 if (y >= bounds.top() && y < bounds.bottom()
1868 && bounds.right() >= x1 && bounds.left() < x2) {
1869 const qreal lower_bound = qreal(.01);
1870 if (bounds.width() < lower_bound && bounds.height() < lower_bound)
1871 return true;
1872
1873 QBezier first_half, second_half;
1874 bezier.split(&first_half, &second_half);
1875 if (qt_isect_curve_horizontal(first_half, y, x1, x2)
1876 || qt_isect_curve_horizontal(second_half, y, x1, x2))
1877 return true;
1878 }
1879 return false;
1880}
1881
1882static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2)
1883{
1884 QRectF bounds = bezier.bounds();
1885
1886 if (x >= bounds.left() && x < bounds.right()
1887 && bounds.bottom() >= y1 && bounds.top() < y2) {
1888 const qreal lower_bound = qreal(.01);
1889 if (bounds.width() < lower_bound && bounds.height() < lower_bound)
1890 return true;
1891
1892 QBezier first_half, second_half;
1893 bezier.split(&first_half, &second_half);
1894 if (qt_isect_curve_vertical(first_half, x, y1, y2)
1895 || qt_isect_curve_vertical(second_half, x, y1, y2))
1896 return true;
1897 }
1898 return false;
1899}
1900
1901/*
1902 Returns true if any lines or curves cross the four edges in of rect
1903*/
1904static bool qt_painterpath_check_crossing(const QPainterPath *path, const QRectF &rect)
1905{
1906 QPointF last_pt;
1907 QPointF last_start;
1908 for (int i=0; i<path->elementCount(); ++i) {
1909 const QPainterPath::Element &e = path->elementAt(i);
1910
1911 switch (e.type) {
1912
1913 case QPainterPath::MoveToElement:
1914 if (i > 0
1915 && qFuzzyCompare(last_pt.x(), last_start.y())
1916 && qFuzzyCompare(last_pt.y(), last_start.y())
1917 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
1918 last_start.x(), last_start.y(), rect))
1919 return true;
1920 last_start = last_pt = e;
1921 break;
1922
1923 case QPainterPath::LineToElement:
1924 if (qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(), e.x, e.y, rect))
1925 return true;
1926 last_pt = e;
1927 break;
1928
1929 case QPainterPath::CurveToElement:
1930 {
1931 QPointF cp2 = path->elementAt(++i);
1932 QPointF ep = path->elementAt(++i);
1933 QBezier bezier = QBezier::fromPoints(last_pt, e, cp2, ep);
1934 if (qt_isect_curve_horizontal(bezier, rect.top(), rect.left(), rect.right())
1935 || qt_isect_curve_horizontal(bezier, rect.bottom(), rect.left(), rect.right())
1936 || qt_isect_curve_vertical(bezier, rect.left(), rect.top(), rect.bottom())
1937 || qt_isect_curve_vertical(bezier, rect.right(), rect.top(), rect.bottom()))
1938 return true;
1939 last_pt = ep;
1940 }
1941 break;
1942
1943 default:
1944 break;
1945 }
1946 }
1947
1948 // implicitly close last subpath
1949 if (last_pt != last_start
1950 && qt_painterpath_isect_line_rect(last_pt.x(), last_pt.y(),
1951 last_start.x(), last_start.y(), rect))
1952 return true;
1953
1954 return false;
1955}
1956
1957/*!
1958 \fn bool QPainterPath::intersects(const QRectF &rectangle) const
1959
1960 Returns true if any point in the given \a rectangle intersects the
1961 path; otherwise returns false.
1962
1963 There is an intersection if any of the lines making up the
1964 rectangle crosses a part of the path or if any part of the
1965 rectangle overlaps with any area enclosed by the path. This
1966 function respects the current fillRule to determine what is
1967 considered inside the path.
1968
1969 \sa contains()
1970*/
1971bool QPainterPath::intersects(const QRectF &rect) const
1972{
1973 if (elementCount() == 1 && rect.contains(elementAt(0)))
1974 return true;
1975
1976 if (isEmpty())
1977 return false;
1978
1979 QRectF cp = controlPointRect();
1980 QRectF rn = rect.normalized();
1981
1982 // QRectF::intersects returns false if one of the rects is a null rect
1983 // which would happen for a painter path consisting of a vertical or
1984 // horizontal line
1985 if (qMax(rn.left(), cp.left()) > qMin(rn.right(), cp.right())
1986 || qMax(rn.top(), cp.top()) > qMin(rn.bottom(), cp.bottom()))
1987 return false;
1988
1989 // If any path element cross the rect its bound to be an intersection
1990 if (qt_painterpath_check_crossing(this, rect))
1991 return true;
1992
1993 if (contains(rect.center()))
1994 return true;
1995
1996 Q_D(QPainterPath);
1997
1998 // Check if the rectangle surounds any subpath...
1999 for (int i=0; i<d->elements.size(); ++i) {
2000 const Element &e = d->elements.at(i);
2001 if (e.type == QPainterPath::MoveToElement && rect.contains(e))
2002 return true;
2003 }
2004
2005 return false;
2006}
2007
2008/*!
2009 Translates all elements in the path by (\a{dx}, \a{dy}).
2010
2011 \since 4.6
2012 \sa translated()
2013*/
2014void QPainterPath::translate(qreal dx, qreal dy)
2015{
2016 if (!d_ptr || (dx == 0 && dy == 0))
2017 return;
2018
2019 int elementsLeft = d_ptr->elements.size();
2020 if (elementsLeft <= 0)
2021 return;
2022
2023 detach();
2024 QPainterPath::Element *element = d_func()->elements.data();
2025 Q_ASSERT(element);
2026 while (elementsLeft--) {
2027 element->x += dx;
2028 element->y += dy;
2029 ++element;
2030 }
2031}
2032
2033/*!
2034 \fn void QPainterPath::translate(const QPointF &offset)
2035 \overload
2036 \since 4.6
2037
2038 Translates all elements in the path by the given \a offset.
2039
2040 \sa translated()
2041*/
2042
2043/*!
2044 Returns a copy of the path that is translated by (\a{dx}, \a{dy}).
2045
2046 \since 4.6
2047 \sa translate()
2048*/
2049QPainterPath QPainterPath::translated(qreal dx, qreal dy) const
2050{
2051 QPainterPath copy(*this);
2052 copy.translate(dx, dy);
2053 return copy;
2054}
2055
2056/*!
2057 \fn QPainterPath QPainterPath::translated(const QPointF &offset) const;
2058 \overload
2059 \since 4.6
2060
2061 Returns a copy of the path that is translated by the given \a offset.
2062
2063 \sa translate()
2064*/
2065
2066/*!
2067 \fn bool QPainterPath::contains(const QRectF &rectangle) const
2068
2069 Returns true if the given \a rectangle is inside the path,
2070 otherwise returns false.
2071*/
2072bool QPainterPath::contains(const QRectF &rect) const
2073{
2074 Q_D(QPainterPath);
2075
2076 // the path is empty or the control point rect doesn't completely
2077 // cover the rectangle we abort stratight away.
2078 if (isEmpty() || !controlPointRect().contains(rect))
2079 return false;
2080
2081 // if there are intersections, chances are that the rect is not
2082 // contained, except if we have winding rule, in which case it
2083 // still might.
2084 if (qt_painterpath_check_crossing(this, rect)) {
2085 if (fillRule() == Qt::OddEvenFill) {
2086 return false;
2087 } else {
2088 // Do some wague sampling in the winding case. This is not
2089 // precise but it should mostly be good enough.
2090 if (!contains(rect.topLeft()) ||
2091 !contains(rect.topRight()) ||
2092 !contains(rect.bottomRight()) ||
2093 !contains(rect.bottomLeft()))
2094 return false;
2095 }
2096 }
2097
2098 // If there exists a point inside that is not part of the path its
2099 // because: rectangle lies completely outside path or a subpath
2100 // excludes parts of the rectangle. Both cases mean that the rect
2101 // is not contained
2102 if (!contains(rect.center()))
2103 return false;
2104
2105 // If there are any subpaths inside this rectangle we need to
2106 // check if they are still contained as a result of the fill
2107 // rule. This can only be the case for WindingFill though. For
2108 // OddEvenFill the rect will never be contained if it surrounds a
2109 // subpath. (the case where two subpaths are completely identical
2110 // can be argued but we choose to neglect it).
2111 for (int i=0; i<d->elements.size(); ++i) {
2112 const Element &e = d->elements.at(i);
2113 if (e.type == QPainterPath::MoveToElement && rect.contains(e)) {
2114 if (fillRule() == Qt::OddEvenFill)
2115 return false;
2116
2117 bool stop = false;
2118 for (; !stop && i<d->elements.size(); ++i) {
2119 const Element &el = d->elements.at(i);
2120 switch (el.type) {
2121 case MoveToElement:
2122 stop = true;
2123 break;
2124 case LineToElement:
2125 if (!contains(el))
2126 return false;
2127 break;
2128 case CurveToElement:
2129 if (!contains(d->elements.at(i+2)))
2130 return false;
2131 i += 2;
2132 break;
2133 default:
2134 break;
2135 }
2136 }
2137
2138 // compensate for the last ++i in the inner for
2139 --i;
2140 }
2141 }
2142
2143 return true;
2144}
2145
2146static inline bool epsilonCompare(const QPointF &a, const QPointF &b, const QSizeF &epsilon)
2147{
2148 return qAbs(a.x() - b.x()) <= epsilon.width()
2149 && qAbs(a.y() - b.y()) <= epsilon.height();
2150}
2151
2152/*!
2153 Returns true if this painterpath is equal to the given \a path.
2154
2155 Note that comparing paths may involve a per element comparison
2156 which can be slow for complex paths.
2157
2158 \sa operator!=()
2159*/
2160
2161bool QPainterPath::operator==(const QPainterPath &path) const
2162{
2163 QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
2164 if (path.d_func() == d)
2165 return true;
2166 else if (!d || !path.d_func())
2167 return false;
2168 else if (d->fillRule != path.d_func()->fillRule)
2169 return false;
2170 else if (d->elements.size() != path.d_func()->elements.size())
2171 return false;
2172
2173 const qreal qt_epsilon = sizeof(qreal) == sizeof(double) ? 1e-12 : qreal(1e-5);
2174
2175 QSizeF epsilon = boundingRect().size();
2176 epsilon.rwidth() *= qt_epsilon;
2177 epsilon.rheight() *= qt_epsilon;
2178
2179 for (int i = 0; i < d->elements.size(); ++i)
2180 if (d->elements.at(i).type != path.d_func()->elements.at(i).type
2181 || !epsilonCompare(d->elements.at(i), path.d_func()->elements.at(i), epsilon))
2182 return false;
2183
2184 return true;
2185}
2186
2187/*!
2188 Returns true if this painter path differs from the given \a path.
2189
2190 Note that comparing paths may involve a per element comparison
2191 which can be slow for complex paths.
2192
2193 \sa operator==()
2194*/
2195
2196bool QPainterPath::operator!=(const QPainterPath &path) const
2197{
2198 return !(*this==path);
2199}
2200
2201/*!
2202 \since 4.5
2203
2204 Returns the intersection of this path and the \a other path.
2205
2206 \sa intersected(), operator&=(), united(), operator|()
2207*/
2208QPainterPath QPainterPath::operator&(const QPainterPath &other) const
2209{
2210 return intersected(other);
2211}
2212
2213/*!
2214 \since 4.5
2215
2216 Returns the union of this path and the \a other path.
2217
2218 \sa united(), operator|=(), intersected(), operator&()
2219*/
2220QPainterPath QPainterPath::operator|(const QPainterPath &other) const
2221{
2222 return united(other);
2223}
2224
2225/*!
2226 \since 4.5
2227
2228 Returns the union of this path and the \a other path. This function is equivalent
2229 to operator|().
2230
2231 \sa united(), operator+=(), operator-()
2232*/
2233QPainterPath QPainterPath::operator+(const QPainterPath &other) const
2234{
2235 return united(other);
2236}
2237
2238/*!
2239 \since 4.5
2240
2241 Subtracts the \a other path from a copy of this path, and returns the copy.
2242
2243 \sa subtracted(), operator-=(), operator+()
2244*/
2245QPainterPath QPainterPath::operator-(const QPainterPath &other) const
2246{
2247 return subtracted(other);
2248}
2249
2250/*!
2251 \since 4.5
2252
2253 Intersects this path with \a other and returns a reference to this path.
2254
2255 \sa intersected(), operator&(), operator|=()
2256*/
2257QPainterPath &QPainterPath::operator&=(const QPainterPath &other)
2258{
2259 return *this = (*this & other);
2260}
2261
2262/*!
2263 \since 4.5
2264
2265 Unites this path with \a other and returns a reference to this path.
2266
2267 \sa united(), operator|(), operator&=()
2268*/
2269QPainterPath &QPainterPath::operator|=(const QPainterPath &other)
2270{
2271 return *this = (*this | other);
2272}
2273
2274/*!
2275 \since 4.5
2276
2277 Unites this path with \a other, and returns a reference to this path. This
2278 is equivalent to operator|=().
2279
2280 \sa united(), operator+(), operator-=()
2281*/
2282QPainterPath &QPainterPath::operator+=(const QPainterPath &other)
2283{
2284 return *this = (*this + other);
2285}
2286
2287/*!
2288 \since 4.5
2289
2290 Subtracts \a other from this path, and returns a reference to this
2291 path.
2292
2293 \sa subtracted(), operator-(), operator+=()
2294*/
2295QPainterPath &QPainterPath::operator-=(const QPainterPath &other)
2296{
2297 return *this = (*this - other);
2298}
2299
2300#ifndef QT_NO_DATASTREAM
2301/*!
2302 \fn QDataStream &operator<<(QDataStream &stream, const QPainterPath &path)
2303 \relates QPainterPath
2304
2305 Writes the given painter \a path to the given \a stream, and
2306 returns a reference to the \a stream.
2307
2308 \sa {Format of the QDataStream Operators}
2309*/
2310QDataStream &operator<<(QDataStream &s, const QPainterPath &p)
2311{
2312 if (p.isEmpty()) {
2313 s << 0;
2314 return s;
2315 }
2316
2317 s << p.elementCount();
2318 for (int i=0; i < p.d_func()->elements.size(); ++i) {
2319 const QPainterPath::Element &e = p.d_func()->elements.at(i);
2320 s << int(e.type);
2321 s << double(e.x) << double(e.y);
2322 }
2323 s << p.d_func()->cStart;
2324 s << int(p.d_func()->fillRule);
2325 return s;
2326}
2327
2328/*!
2329 \fn QDataStream &operator>>(QDataStream &stream, QPainterPath &path)
2330 \relates QPainterPath
2331
2332 Reads a painter path from the given \a stream into the specified \a path,
2333 and returns a reference to the \a stream.
2334
2335 \sa {Format of the QDataStream Operators}
2336*/
2337QDataStream &operator>>(QDataStream &s, QPainterPath &p)
2338{
2339 int size;
2340 s >> size;
2341
2342 if (size == 0)
2343 return s;
2344
2345 p.ensureData(); // in case if p.d_func() == 0
2346 if (p.d_func()->elements.size() == 1) {
2347 Q_ASSERT(p.d_func()->elements.at(0).type == QPainterPath::MoveToElement);
2348 p.d_func()->elements.clear();
2349 }
2350 p.d_func()->elements.reserve(p.d_func()->elements.size() + size);
2351 for (int i=0; i<size; ++i) {
2352 int type;
2353 double x, y;
2354 s >> type;
2355 s >> x;
2356 s >> y;
2357 Q_ASSERT(type >= 0 && type <= 3);
2358#ifndef QT_NO_DEBUG
2359 if (qt_is_nan(x) || qt_is_nan(y))
2360 qWarning("QDataStream::operator>>: Adding a NaN element to path, results are undefined");
2361#endif
2362 QPainterPath::Element elm = { x, y, QPainterPath::ElementType(type) };
2363 p.d_func()->elements.append(elm);
2364 }
2365 s >> p.d_func()->cStart;
2366 int fillRule;
2367 s >> fillRule;
2368 Q_ASSERT(fillRule == Qt::OddEvenFill || Qt::WindingFill);
2369 p.d_func()->fillRule = Qt::FillRule(fillRule);
2370 p.d_func()->dirtyBounds = true;
2371 p.d_func()->dirtyControlBounds = true;
2372 return s;
2373}
2374#endif // QT_NO_DATASTREAM
2375
2376
2377/*******************************************************************************
2378 * class QPainterPathStroker
2379 */
2380
2381void qt_path_stroke_move_to(qfixed x, qfixed y, void *data)
2382{
2383 ((QPainterPath *) data)->moveTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
2384}
2385
2386void qt_path_stroke_line_to(qfixed x, qfixed y, void *data)
2387{
2388 ((QPainterPath *) data)->lineTo(qt_fixed_to_real(x), qt_fixed_to_real(y));
2389}
2390
2391void qt_path_stroke_cubic_to(qfixed c1x, qfixed c1y,
2392 qfixed c2x, qfixed c2y,
2393 qfixed ex, qfixed ey,
2394 void *data)
2395{
2396 ((QPainterPath *) data)->cubicTo(qt_fixed_to_real(c1x), qt_fixed_to_real(c1y),
2397 qt_fixed_to_real(c2x), qt_fixed_to_real(c2y),
2398 qt_fixed_to_real(ex), qt_fixed_to_real(ey));
2399}
2400
2401/*!
2402 \since 4.1
2403 \class QPainterPathStroker
2404 \ingroup painting
2405
2406 \brief The QPainterPathStroker class is used to generate fillable
2407 outlines for a given painter path.
2408
2409 By calling the createStroke() function, passing a given
2410 QPainterPath as argument, a new painter path representing the
2411 outline of the given path is created. The newly created painter
2412 path can then be filled to draw the original painter path's
2413 outline.
2414
2415 You can control the various design aspects (width, cap styles,
2416 join styles and dash pattern) of the outlining using the following
2417 functions:
2418
2419 \list
2420 \o setWidth()
2421 \o setCapStyle()
2422 \o setJoinStyle()
2423 \o setDashPattern()
2424 \endlist
2425
2426 The setDashPattern() function accepts both a Qt::PenStyle object
2427 and a vector representation of the pattern as argument.
2428
2429 In addition you can specify a curve's threshold, controlling the
2430 granularity with which a curve is drawn, using the
2431 setCurveThreshold() function. The default threshold is a well
2432 adjusted value (0.25), and normally you should not need to modify
2433 it. However, you can make the curve's appearance smoother by
2434 decreasing its value.
2435
2436 You can also control the miter limit for the generated outline
2437 using the setMiterLimit() function. The miter limit describes how
2438 far from each join the miter join can extend. The limit is
2439 specified in the units of width so the pixelwise miter limit will
2440 be \c {miterlimit * width}. This value is only used if the join
2441 style is Qt::MiterJoin.
2442
2443 The painter path generated by the createStroke() function should
2444 only be used for outlining the given painter path. Otherwise it
2445 may cause unexpected behavior. Generated outlines also require the
2446 Qt::WindingFill rule which is set by default.
2447
2448 \sa QPen, QBrush
2449*/
2450
2451QPainterPathStrokerPrivate::QPainterPathStrokerPrivate()
2452 : dashOffset(0)
2453{
2454 stroker.setMoveToHook(qt_path_stroke_move_to);
2455 stroker.setLineToHook(qt_path_stroke_line_to);
2456 stroker.setCubicToHook(qt_path_stroke_cubic_to);
2457}
2458
2459/*!
2460 Creates a new stroker.
2461 */
2462QPainterPathStroker::QPainterPathStroker()
2463 : d_ptr(new QPainterPathStrokerPrivate)
2464{
2465}
2466
2467/*!
2468 Destroys the stroker.
2469*/
2470QPainterPathStroker::~QPainterPathStroker()
2471{
2472}
2473
2474
2475/*!
2476 Generates a new path that is a fillable area representing the
2477 outline of the given \a path.
2478
2479 The various design aspects of the outline are based on the
2480 stroker's properties: width(), capStyle(), joinStyle(),
2481 dashPattern(), curveThreshold() and miterLimit().
2482
2483 The generated path should only be used for outlining the given
2484 painter path. Otherwise it may cause unexpected
2485 behavior. Generated outlines also require the Qt::WindingFill rule
2486 which is set by default.
2487*/
2488QPainterPath QPainterPathStroker::createStroke(const QPainterPath &path) const
2489{
2490 QPainterPathStrokerPrivate *d = const_cast<QPainterPathStrokerPrivate *>(d_func());
2491 QPainterPath stroke;
2492 if (path.isEmpty())
2493 return path;
2494 if (d->dashPattern.isEmpty()) {
2495 d->stroker.strokePath(path, &stroke, QTransform());
2496 } else {
2497 QDashStroker dashStroker(&d->stroker);
2498 dashStroker.setDashPattern(d->dashPattern);
2499 dashStroker.setDashOffset(d->dashOffset);
2500 dashStroker.setClipRect(d->stroker.clipRect());
2501 dashStroker.strokePath(path, &stroke, QTransform());
2502 }
2503 stroke.setFillRule(Qt::WindingFill);
2504 return stroke;
2505}
2506
2507/*!
2508 Sets the width of the generated outline painter path to \a width.
2509
2510 The generated outlines will extend approximately 50% of \a width
2511 to each side of the given input path's original outline.
2512*/
2513void QPainterPathStroker::setWidth(qreal width)
2514{
2515 Q_D(QPainterPathStroker);
2516 if (width <= 0)
2517 width = 1;
2518 d->stroker.setStrokeWidth(qt_real_to_fixed(width));
2519}
2520
2521/*!
2522 Returns the width of the generated outlines.
2523*/
2524qreal QPainterPathStroker::width() const
2525{
2526 return qt_fixed_to_real(d_func()->stroker.strokeWidth());
2527}
2528
2529
2530/*!
2531 Sets the cap style of the generated outlines to \a style. If a
2532 dash pattern is set, each segment of the pattern is subject to the
2533 cap \a style.
2534*/
2535void QPainterPathStroker::setCapStyle(Qt::PenCapStyle style)
2536{
2537 d_func()->stroker.setCapStyle(style);
2538}
2539
2540
2541/*!
2542 Returns the cap style of the generated outlines.
2543*/
2544Qt::PenCapStyle QPainterPathStroker::capStyle() const
2545{
2546 return d_func()->stroker.capStyle();
2547}
2548
2549/*!
2550 Sets the join style of the generated outlines to \a style.
2551*/
2552void QPainterPathStroker::setJoinStyle(Qt::PenJoinStyle style)
2553{
2554 d_func()->stroker.setJoinStyle(style);
2555}
2556
2557/*!
2558 Returns the join style of the generated outlines.
2559*/
2560Qt::PenJoinStyle QPainterPathStroker::joinStyle() const
2561{
2562 return d_func()->stroker.joinStyle();
2563}
2564
2565/*!
2566 Sets the miter limit of the generated outlines to \a limit.
2567
2568 The miter limit describes how far from each join the miter join
2569 can extend. The limit is specified in units of the currently set
2570 width. So the pixelwise miter limit will be \c { miterlimit *
2571 width}.
2572
2573 This value is only used if the join style is Qt::MiterJoin.
2574*/
2575void QPainterPathStroker::setMiterLimit(qreal limit)
2576{
2577 d_func()->stroker.setMiterLimit(qt_real_to_fixed(limit));
2578}
2579
2580/*!
2581 Returns the miter limit for the generated outlines.
2582*/
2583qreal QPainterPathStroker::miterLimit() const
2584{
2585 return qt_fixed_to_real(d_func()->stroker.miterLimit());
2586}
2587
2588
2589/*!
2590 Specifies the curve flattening \a threshold, controlling the
2591 granularity with which the generated outlines' curve is drawn.
2592
2593 The default threshold is a well adjusted value (0.25), and
2594 normally you should not need to modify it. However, you can make
2595 the curve's appearance smoother by decreasing its value.
2596*/
2597void QPainterPathStroker::setCurveThreshold(qreal threshold)
2598{
2599 d_func()->stroker.setCurveThreshold(qt_real_to_fixed(threshold));
2600}
2601
2602/*!
2603 Returns the curve flattening threshold for the generated
2604 outlines.
2605*/
2606qreal QPainterPathStroker::curveThreshold() const
2607{
2608 return qt_fixed_to_real(d_func()->stroker.curveThreshold());
2609}
2610
2611/*!
2612 Sets the dash pattern for the generated outlines to \a style.
2613*/
2614void QPainterPathStroker::setDashPattern(Qt::PenStyle style)
2615{
2616 d_func()->dashPattern = QDashStroker::patternForStyle(style);
2617}
2618
2619/*!
2620 \overload
2621
2622 Sets the dash pattern for the generated outlines to \a
2623 dashPattern. This function makes it possible to specify custom
2624 dash patterns.
2625
2626 Each element in the vector contains the lengths of the dashes and spaces
2627 in the stroke, beginning with the first dash in the first element, the
2628 first space in the second element, and alternating between dashes and
2629 spaces for each following pair of elements.
2630
2631 The vector can contain an odd number of elements, in which case the last
2632 element will be extended by the length of the first element when the
2633 pattern repeats.
2634*/
2635void QPainterPathStroker::setDashPattern(const QVector<qreal> &dashPattern)
2636{
2637 d_func()->dashPattern.clear();
2638 for (int i=0; i<dashPattern.size(); ++i)
2639 d_func()->dashPattern << qt_real_to_fixed(dashPattern.at(i));
2640}
2641
2642/*!
2643 Returns the dash pattern for the generated outlines.
2644*/
2645QVector<qreal> QPainterPathStroker::dashPattern() const
2646{
2647 return d_func()->dashPattern;
2648}
2649
2650/*!
2651 Returns the dash offset for the generated outlines.
2652 */
2653qreal QPainterPathStroker::dashOffset() const
2654{
2655 return d_func()->dashOffset;
2656}
2657
2658/*!
2659 Sets the dash offset for the generated outlines to \a offset.
2660
2661 See the documentation for QPen::setDashOffset() for a description of the
2662 dash offset.
2663 */
2664void QPainterPathStroker::setDashOffset(qreal offset)
2665{
2666 d_func()->dashOffset = offset;
2667}
2668
2669/*!
2670 Converts the path into a polygon using the QTransform
2671 \a matrix, and returns the polygon.
2672
2673 The polygon is created by first converting all subpaths to
2674 polygons, then using a rewinding technique to make sure that
2675 overlapping subpaths can be filled using the correct fill rule.
2676
2677 Note that rewinding inserts addition lines in the polygon so
2678 the outline of the fill polygon does not match the outline of
2679 the path.
2680
2681 \sa toSubpathPolygons(), toFillPolygons(),
2682 {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
2683*/
2684QPolygonF QPainterPath::toFillPolygon(const QTransform &matrix) const
2685{
2686
2687 QList<QPolygonF> flats = toSubpathPolygons(matrix);
2688 QPolygonF polygon;
2689 if (flats.isEmpty())
2690 return polygon;
2691 QPointF first = flats.first().first();
2692 for (int i=0; i<flats.size(); ++i) {
2693 polygon += flats.at(i);
2694 if (!flats.at(i).isClosed())
2695 polygon += flats.at(i).first();
2696 if (i > 0)
2697 polygon += first;
2698 }
2699 return polygon;
2700}
2701
2702/*!
2703 \overload
2704*/
2705QPolygonF QPainterPath::toFillPolygon(const QMatrix &matrix) const
2706{
2707 return toFillPolygon(QTransform(matrix));
2708}
2709
2710
2711//derivative of the equation
2712static inline qreal slopeAt(qreal t, qreal a, qreal b, qreal c, qreal d)
2713{
2714 return 3*t*t*(d - 3*c + 3*b - a) + 6*t*(c - 2*b + a) + 3*(b - a);
2715}
2716
2717/*!
2718 Returns the length of the current path.
2719*/
2720qreal QPainterPath::length() const
2721{
2722 Q_D(QPainterPath);
2723 if (isEmpty())
2724 return 0;
2725
2726 qreal len = 0;
2727 for (int i=1; i<d->elements.size(); ++i) {
2728 const Element &e = d->elements.at(i);
2729
2730 switch (e.type) {
2731 case MoveToElement:
2732 break;
2733 case LineToElement:
2734 {
2735 len += QLineF(d->elements.at(i-1), e).length();
2736 break;
2737 }
2738 case CurveToElement:
2739 {
2740 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2741 e,
2742 d->elements.at(i+1),
2743 d->elements.at(i+2));
2744 len += b.length();
2745 i += 2;
2746 break;
2747 }
2748 default:
2749 break;
2750 }
2751 }
2752 return len;
2753}
2754
2755/*!
2756 Returns percentage of the whole path at the specified length \a len.
2757
2758 Note that similarly to other percent methods, the percentage measurement
2759 is not linear with regards to the length, if curves are present
2760 in the path. When curves are present the percentage argument is mapped
2761 to the t parameter of the Bezier equations.
2762*/
2763qreal QPainterPath::percentAtLength(qreal len) const
2764{
2765 Q_D(QPainterPath);
2766 if (isEmpty() || len <= 0)
2767 return 0;
2768
2769 qreal totalLength = length();
2770 if (len > totalLength)
2771 return 1;
2772
2773 qreal curLen = 0;
2774 for (int i=1; i<d->elements.size(); ++i) {
2775 const Element &e = d->elements.at(i);
2776
2777 switch (e.type) {
2778 case MoveToElement:
2779 break;
2780 case LineToElement:
2781 {
2782 QLineF line(d->elements.at(i-1), e);
2783 qreal llen = line.length();
2784 curLen += llen;
2785 if (curLen >= len) {
2786 return len/totalLength ;
2787 }
2788
2789 break;
2790 }
2791 case CurveToElement:
2792 {
2793 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
2794 e,
2795 d->elements.at(i+1),
2796 d->elements.at(i+2));
2797 qreal blen = b.length();
2798 qreal prevLen = curLen;
2799 curLen += blen;
2800
2801 if (curLen >= len) {
2802 qreal res = b.tAtLength(len - prevLen);
2803 return (res * blen + prevLen)/totalLength;
2804 }
2805
2806 i += 2;
2807 break;
2808 }
2809 default:
2810 break;
2811 }
2812 }
2813
2814 return 0;
2815}
2816
2817static inline QBezier bezierAtT(const QPainterPath &path, qreal t, qreal *startingLength, qreal *bezierLength)
2818{
2819 *startingLength = 0;
2820 if (t > 1)
2821 return QBezier();
2822
2823 qreal curLen = 0;
2824 qreal totalLength = path.length();
2825
2826 const int lastElement = path.elementCount() - 1;
2827 for (int i=0; i <= lastElement; ++i) {
2828 const QPainterPath::Element &e = path.elementAt(i);
2829
2830 switch (e.type) {
2831 case QPainterPath::MoveToElement:
2832 break;
2833 case QPainterPath::LineToElement:
2834 {
2835 QLineF line(path.elementAt(i-1), e);
2836 qreal llen = line.length();
2837 curLen += llen;
2838 if (i == lastElement || curLen/totalLength >= t) {
2839 *bezierLength = llen;
2840 QPointF a = path.elementAt(i-1);
2841 QPointF delta = e - a;
2842 return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
2843 }
2844 break;
2845 }
2846 case QPainterPath::CurveToElement:
2847 {
2848 QBezier b = QBezier::fromPoints(path.elementAt(i-1),
2849 e,
2850 path.elementAt(i+1),
2851 path.elementAt(i+2));
2852 qreal blen = b.length();
2853 curLen += blen;
2854
2855 if (i + 2 == lastElement || curLen/totalLength >= t) {
2856 *bezierLength = blen;
2857 return b;
2858 }
2859
2860 i += 2;
2861 break;
2862 }
2863 default:
2864 break;
2865 }
2866 *startingLength = curLen;
2867 }
2868 return QBezier();
2869}
2870
2871/*!
2872 Returns the point at at the percentage \a t of the current path.
2873 The argument \a t has to be between 0 and 1.
2874
2875 Note that similarly to other percent methods, the percentage measurement
2876 is not linear with regards to the length, if curves are present
2877 in the path. When curves are present the percentage argument is mapped
2878 to the t parameter of the Bezier equations.
2879*/
2880QPointF QPainterPath::pointAtPercent(qreal t) const
2881{
2882 if (t < 0 || t > 1) {
2883 qWarning("QPainterPath::pointAtPercent accepts only values between 0 and 1");
2884 return QPointF();
2885 }
2886
2887 if (isEmpty())
2888 return QPointF();
2889
2890 qreal totalLength = length();
2891 qreal curLen = 0;
2892 qreal bezierLen = 0;
2893 QBezier b = bezierAtT(*this, t, &curLen, &bezierLen);
2894 qreal realT = (totalLength * t - curLen) / bezierLen;
2895
2896 return b.pointAt(qBound(qreal(0), realT, qreal(1)));
2897}
2898
2899/*!
2900 Returns the angle of the path tangent at the percentage \a t.
2901 The argument \a t has to be between 0 and 1.
2902
2903 Positive values for the angles mean counter-clockwise while negative values
2904 mean the clockwise direction. Zero degrees is at the 3 o'clock position.
2905
2906 Note that similarly to the other percent methods, the percentage measurement
2907 is not linear with regards to the length if curves are present
2908 in the path. When curves are present the percentage argument is mapped
2909 to the t parameter of the Bezier equations.
2910*/
2911qreal QPainterPath::angleAtPercent(qreal t) const
2912{
2913 if (t < 0 || t > 1) {
2914 qWarning("QPainterPath::angleAtPercent accepts only values between 0 and 1");
2915 return 0;
2916 }
2917
2918 qreal totalLength = length();
2919 qreal curLen = 0;
2920 qreal bezierLen = 0;
2921 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
2922 qreal realT = (totalLength * t - curLen) / bezierLen;
2923
2924 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
2925 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
2926
2927 return QLineF(0, 0, m1, m2).angle();
2928}
2929
2930#if defined(Q_WS_WINCE)
2931#pragma warning( disable : 4056 4756 )
2932#endif
2933
2934/*!
2935 Returns the slope of the path at the percentage \a t. The
2936 argument \a t has to be between 0 and 1.
2937
2938 Note that similarly to other percent methods, the percentage measurement
2939 is not linear with regards to the length, if curves are present
2940 in the path. When curves are present the percentage argument is mapped
2941 to the t parameter of the Bezier equations.
2942*/
2943qreal QPainterPath::slopeAtPercent(qreal t) const
2944{
2945 if (t < 0 || t > 1) {
2946 qWarning("QPainterPath::slopeAtPercent accepts only values between 0 and 1");
2947 return 0;
2948 }
2949
2950 qreal totalLength = length();
2951 qreal curLen = 0;
2952 qreal bezierLen = 0;
2953 QBezier bez = bezierAtT(*this, t, &curLen, &bezierLen);
2954 qreal realT = (totalLength * t - curLen) / bezierLen;
2955
2956 qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
2957 qreal m2 = slopeAt(realT, bez.y1, bez.y2, bez.y3, bez.y4);
2958 //tangent line
2959 qreal slope = 0;
2960
2961#define SIGN(x) ((x < 0)?-1:1)
2962 if (m1)
2963 slope = m2/m1;
2964 else {
2965 //windows doesn't define INFINITY :(
2966#ifdef INFINITY
2967 slope = INFINITY*SIGN(m2);
2968#else
2969 if (sizeof(qreal) == sizeof(double)) {
2970 return 1.79769313486231570e+308;
2971 } else {
2972 return ((qreal)3.40282346638528860e+38);
2973 }
2974#endif
2975 }
2976
2977 return slope;
2978}
2979
2980/*!
2981 \since 4.4
2982
2983 Adds the given rectangle \a rect with rounded corners to the path.
2984
2985 The \a xRadius and \a yRadius arguments specify the radii of
2986 the ellipses defining the corners of the rounded rectangle.
2987 When \a mode is Qt::RelativeSize, \a xRadius and
2988 \a yRadius are specified in percentage of half the rectangle's
2989 width and height respectively, and should be in the range 0.0 to 100.0.
2990
2991 \sa addRect()
2992*/
2993void QPainterPath::addRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius,
2994 Qt::SizeMode mode)
2995{
2996 QRectF r = rect.normalized();
2997
2998 if (r.isNull())
2999 return;
3000
3001 if (mode == Qt::AbsoluteSize) {
3002 qreal w = r.width() / 2;
3003 qreal h = r.height() / 2;
3004
3005 if (w == 0) {
3006 xRadius = 0;
3007 } else {
3008 xRadius = 100 * qMin(xRadius, w) / w;
3009 }
3010 if (h == 0) {
3011 yRadius = 0;
3012 } else {
3013 yRadius = 100 * qMin(yRadius, h) / h;
3014 }
3015 } else {
3016 if (xRadius > 100) // fix ranges
3017 xRadius = 100;
3018
3019 if (yRadius > 100)
3020 yRadius = 100;
3021 }
3022
3023 if (xRadius <= 0 || yRadius <= 0) { // add normal rectangle
3024 addRect(r);
3025 return;
3026 }
3027
3028 qreal x = r.x();
3029 qreal y = r.y();
3030 qreal w = r.width();
3031 qreal h = r.height();
3032 qreal rxx2 = w*xRadius/100;
3033 qreal ryy2 = h*yRadius/100;
3034
3035 ensureData();
3036 detach();
3037
3038 bool first = d_func()->elements.size() < 2;
3039
3040 arcMoveTo(x, y, rxx2, ryy2, 180);
3041 arcTo(x, y, rxx2, ryy2, 180, -90);
3042 arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3043 arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3044 arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3045 closeSubpath();
3046
3047 d_func()->require_moveTo = true;
3048 d_func()->convex = first;
3049}
3050
3051/*!
3052 \fn void QPainterPath::addRoundedRect(qreal x, qreal y, qreal w, qreal h, qreal xRadius, qreal yRadius, Qt::SizeMode mode = Qt::AbsoluteSize);
3053 \since 4.4
3054 \overload
3055
3056 Adds the given rectangle \a x, \a y, \a w, \a h with rounded corners to the path.
3057 */
3058
3059/*!
3060 \obsolete
3061
3062 Adds a rectangle \a r with rounded corners to the path.
3063
3064 The \a xRnd and \a yRnd arguments specify how rounded the corners
3065 should be. 0 is angled corners, 99 is maximum roundedness.
3066
3067 \sa addRoundedRect()
3068*/
3069void QPainterPath::addRoundRect(const QRectF &r, int xRnd, int yRnd)
3070{
3071 if(xRnd >= 100) // fix ranges
3072 xRnd = 99;
3073 if(yRnd >= 100)
3074 yRnd = 99;
3075 if(xRnd <= 0 || yRnd <= 0) { // add normal rectangle
3076 addRect(r);
3077 return;
3078 }
3079
3080 QRectF rect = r.normalized();
3081
3082 if (rect.isNull())
3083 return;
3084
3085 qreal x = rect.x();
3086 qreal y = rect.y();
3087 qreal w = rect.width();
3088 qreal h = rect.height();
3089 qreal rxx2 = w*xRnd/100;
3090 qreal ryy2 = h*yRnd/100;
3091
3092 ensureData();
3093 detach();
3094
3095 bool first = d_func()->elements.size() < 2;
3096
3097 arcMoveTo(x, y, rxx2, ryy2, 180);
3098 arcTo(x, y, rxx2, ryy2, 180, -90);
3099 arcTo(x+w-rxx2, y, rxx2, ryy2, 90, -90);
3100 arcTo(x+w-rxx2, y+h-ryy2, rxx2, ryy2, 0, -90);
3101 arcTo(x, y+h-ryy2, rxx2, ryy2, 270, -90);
3102 closeSubpath();
3103
3104 d_func()->require_moveTo = true;
3105 d_func()->convex = first;
3106}
3107
3108/*!
3109 \obsolete
3110
3111 \fn bool QPainterPath::addRoundRect(const QRectF &rect, int roundness);
3112 \since 4.3
3113 \overload
3114
3115 Adds a rounded rectangle, \a rect, to the path.
3116
3117 The \a roundness argument specifies uniform roundness for the
3118 rectangle. Vertical and horizontal roundness factors will be
3119 adjusted accordingly to act uniformly around both axes. Use this
3120 method if you want a rectangle equally rounded across both the X and
3121 Y axis.
3122
3123 \sa addRoundedRect()
3124*/
3125
3126/*!
3127 \obsolete
3128
3129 \fn void QPainterPath::addRoundRect(qreal x, qreal y, qreal w, qreal h, int xRnd, int yRnd);
3130 \overload
3131
3132 Adds a rectangle with rounded corners to the path. The rectangle
3133 is constructed from \a x, \a y, and the width and height \a w
3134 and \a h.
3135
3136 The \a xRnd and \a yRnd arguments specify how rounded the corners
3137 should be. 0 is angled corners, 99 is maximum roundedness.
3138
3139 \sa addRoundedRect()
3140 */
3141
3142/*!
3143 \obsolete
3144
3145 \fn bool QPainterPath::addRoundRect(qreal x, qreal y, qreal width, qreal height, int roundness);
3146 \since 4.3
3147 \overload
3148
3149 Adds a rounded rectangle to the path, defined by the coordinates \a
3150 x and \a y with the specified \a width and \a height.
3151
3152 The \a roundness argument specifies uniform roundness for the
3153 rectangle. Vertical and horizontal roundness factors will be
3154 adjusted accordingly to act uniformly around both axes. Use this
3155 method if you want a rectangle equally rounded across both the X and
3156 Y axis.
3157
3158 \sa addRoundedRect()
3159*/
3160
3161/*!
3162 \since 4.3
3163
3164 Returns a path which is the union of this path's fill area and \a p's fill area.
3165
3166 Set operations on paths will treat the paths as areas. Non-closed
3167 paths will be treated as implicitly closed.
3168
3169 \sa intersected(), subtracted()
3170*/
3171QPainterPath QPainterPath::united(const QPainterPath &p) const
3172{
3173 if (isEmpty() || p.isEmpty())
3174 return isEmpty() ? p : *this;
3175 QPathClipper clipper(*this, p);
3176 return clipper.clip(QPathClipper::BoolOr);
3177}
3178
3179/*!
3180 \since 4.3
3181
3182 Returns a path which is the intersection of this path's fill area and \a p's fill area.
3183*/
3184QPainterPath QPainterPath::intersected(const QPainterPath &p) const
3185{
3186 if (isEmpty() || p.isEmpty())
3187 return QPainterPath();
3188 QPathClipper clipper(*this, p);
3189 return clipper.clip(QPathClipper::BoolAnd);
3190}
3191
3192/*!
3193 \since 4.3
3194
3195 Returns a path which is \a p's fill area subtracted from this path's fill area.
3196
3197 Set operations on paths will treat the paths as areas. Non-closed
3198 paths will be treated as implicitly closed.
3199
3200*/
3201QPainterPath QPainterPath::subtracted(const QPainterPath &p) const
3202{
3203 if (isEmpty() || p.isEmpty())
3204 return *this;
3205 QPathClipper clipper(*this, p);
3206 return clipper.clip(QPathClipper::BoolSub);
3207}
3208
3209/*!
3210 \since 4.3
3211 \obsolete
3212
3213 Use subtracted() instead.
3214
3215 \sa subtracted()
3216*/
3217QPainterPath QPainterPath::subtractedInverted(const QPainterPath &p) const
3218{
3219 return p.subtracted(*this);
3220}
3221
3222/*!
3223 \since 4.4
3224
3225 Returns a simplified version of this path. This implies merging all subpaths that intersect,
3226 and returning a path containing no intersecting edges. Consecutive parallel lines will also
3227 be merged. The simplified path will always use the default fill rule, Qt::OddEvenFill.
3228*/
3229QPainterPath QPainterPath::simplified() const
3230{
3231 if(isEmpty())
3232 return *this;
3233 QPathClipper clipper(*this, QPainterPath());
3234 return clipper.clip(QPathClipper::Simplify);
3235}
3236
3237/*!
3238 \since 4.3
3239
3240 Returns true if the current path intersects at any point the given path \a p.
3241 Also returns true if the current path contains or is contained by any part of \a p.
3242
3243 Set operations on paths will treat the paths as areas. Non-closed
3244 paths will be treated as implicitly closed.
3245
3246 \sa contains()
3247 */
3248bool QPainterPath::intersects(const QPainterPath &p) const
3249{
3250 if (p.elementCount() == 1)
3251 return contains(p.elementAt(0));
3252 if (isEmpty() || p.isEmpty())
3253 return false;
3254 QPathClipper clipper(*this, p);
3255 return clipper.intersect();
3256}
3257
3258/*!
3259 \since 4.3
3260
3261 Returns true if the given path \a p is contained within
3262 the current path. Returns false if any edges of the current path and
3263 \a p intersect.
3264
3265 Set operations on paths will treat the paths as areas. Non-closed
3266 paths will be treated as implicitly closed.
3267
3268 \sa intersects()
3269 */
3270bool QPainterPath::contains(const QPainterPath &p) const
3271{
3272 if (p.elementCount() == 1)
3273 return contains(p.elementAt(0));
3274 if (isEmpty() || p.isEmpty())
3275 return false;
3276 QPathClipper clipper(*this, p);
3277 return clipper.contains();
3278}
3279
3280void QPainterPath::setDirty(bool dirty)
3281{
3282 d_func()->dirtyBounds = dirty;
3283 d_func()->dirtyControlBounds = dirty;
3284 delete d_func()->pathConverter;
3285 d_func()->pathConverter = 0;
3286 d_func()->convex = false;
3287}
3288
3289void QPainterPath::computeBoundingRect() const
3290{
3291 QPainterPathData *d = d_func();
3292 d->dirtyBounds = false;
3293 if (!d_ptr) {
3294 d->bounds = QRect();
3295 return;
3296 }
3297
3298 qreal minx, maxx, miny, maxy;
3299 minx = maxx = d->elements.at(0).x;
3300 miny = maxy = d->elements.at(0).y;
3301 for (int i=1; i<d->elements.size(); ++i) {
3302 const Element &e = d->elements.at(i);
3303
3304 switch (e.type) {
3305 case MoveToElement:
3306 case LineToElement:
3307 if (e.x > maxx) maxx = e.x;
3308 else if (e.x < minx) minx = e.x;
3309 if (e.y > maxy) maxy = e.y;
3310 else if (e.y < miny) miny = e.y;
3311 break;
3312 case CurveToElement:
3313 {
3314 QBezier b = QBezier::fromPoints(d->elements.at(i-1),
3315 e,
3316 d->elements.at(i+1),
3317 d->elements.at(i+2));
3318 QRectF r = qt_painterpath_bezier_extrema(b);
3319 qreal right = r.right();
3320 qreal bottom = r.bottom();
3321 if (r.x() < minx) minx = r.x();
3322 if (right > maxx) maxx = right;
3323 if (r.y() < miny) miny = r.y();
3324 if (bottom > maxy) maxy = bottom;
3325 i += 2;
3326 }
3327 break;
3328 default:
3329 break;
3330 }
3331 }
3332 d->bounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3333}
3334
3335
3336void QPainterPath::computeControlPointRect() const
3337{
3338 QPainterPathData *d = d_func();
3339 d->dirtyControlBounds = false;
3340 if (!d_ptr) {
3341 d->controlBounds = QRect();
3342 return;
3343 }
3344
3345 qreal minx, maxx, miny, maxy;
3346 minx = maxx = d->elements.at(0).x;
3347 miny = maxy = d->elements.at(0).y;
3348 for (int i=1; i<d->elements.size(); ++i) {
3349 const Element &e = d->elements.at(i);
3350 if (e.x > maxx) maxx = e.x;
3351 else if (e.x < minx) minx = e.x;
3352 if (e.y > maxy) maxy = e.y;
3353 else if (e.y < miny) miny = e.y;
3354 }
3355 d->controlBounds = QRectF(minx, miny, maxx - minx, maxy - miny);
3356}
3357
3358#ifndef QT_NO_DEBUG_STREAM
3359QDebug operator<<(QDebug s, const QPainterPath &p)
3360{
3361 s.nospace() << "QPainterPath: Element count=" << p.elementCount() << endl;
3362 const char *types[] = {"MoveTo", "LineTo", "CurveTo", "CurveToData"};
3363 for (int i=0; i<p.elementCount(); ++i) {
3364 s.nospace() << " -> " << types[p.elementAt(i).type] << "(x=" << p.elementAt(i).x << ", y=" << p.elementAt(i).y << ')' << endl;
3365
3366 }
3367 return s;
3368}
3369#endif
3370
3371QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.