source: trunk/src/gui/painting/qpolygon.cpp@ 719

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

trunk: Merged in qt 4.6.2 sources.

File size: 23.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qpolygon.h"
43#include "qrect.h"
44#include "qdatastream.h"
45#include "qmatrix.h"
46#include "qdebug.h"
47#include "qpainterpath.h"
48#include "qvariant.h"
49#include "qpainterpath_p.h"
50#include "qbezier_p.h"
51
52#include <stdarg.h>
53
54QT_BEGIN_NAMESPACE
55
56//same as qt_painterpath_isect_line in qpainterpath.cpp
57static void qt_polygon_isect_line(const QPointF &p1, const QPointF &p2, const QPointF &pos,
58 int *winding)
59{
60 qreal x1 = p1.x();
61 qreal y1 = p1.y();
62 qreal x2 = p2.x();
63 qreal y2 = p2.y();
64 qreal y = pos.y();
65
66 int dir = 1;
67
68 if (qFuzzyCompare(y1, y2)) {
69 // ignore horizontal lines according to scan conversion rule
70 return;
71 } else if (y2 < y1) {
72 qreal x_tmp = x2; x2 = x1; x1 = x_tmp;
73 qreal y_tmp = y2; y2 = y1; y1 = y_tmp;
74 dir = -1;
75 }
76
77 if (y >= y1 && y < y2) {
78 qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1);
79
80 // count up the winding number if we're
81 if (x<=pos.x()) {
82 (*winding) += dir;
83 }
84 }
85}
86
87/*!
88 \class QPolygon
89 \brief The QPolygon class provides a vector of points using
90 integer precision.
91
92 \reentrant
93
94 \ingroup painting
95 \ingroup shared
96
97 A QPolygon object is a QVector<QPoint>. The easiest way to add
98 points to a QPolygon is to use QVector's streaming operator, as
99 illustrated below:
100
101 \snippet doc/src/snippets/polygon/polygon.cpp 0
102
103 In addition to the functions provided by QVector, QPolygon
104 provides some point-specific functions.
105
106 Each point in a polygon can be retrieved by passing its index to
107 the point() function. To populate the polygon, QPolygon provides
108 the setPoint() function to set the point at a given index, the
109 setPoints() function to set all the points in the polygon
110 (resizing it to the given number of points), and the putPoints()
111 function which copies a number of given points into the polygon
112 from a specified index (resizing the polygon if necessary).
113
114 QPolygon provides the boundingRect() and translate() functions for
115 geometry functions. Use the QMatrix::map() function for more
116 general transformations of QPolygons.
117
118 The QPolygon class is \l {Implicit Data Sharing}{implicitly
119 shared}.
120
121 \sa QVector, QPolygonF, QLine
122*/
123
124
125/*****************************************************************************
126 QPolygon member functions
127 *****************************************************************************/
128
129/*!
130 \fn QPolygon::QPolygon()
131
132 Constructs a polygon with no points.
133
134 \sa QVector::isEmpty()
135*/
136
137/*!
138 \fn QPolygon::QPolygon(int size)
139
140 Constructs a polygon of the given \a size. Creates an empty
141 polygon if \a size == 0.
142
143 \sa QVector::isEmpty()
144*/
145
146/*!
147 \fn QPolygon::QPolygon(const QPolygon &polygon)
148
149 Constructs a copy of the given \a polygon.
150
151 \sa setPoints()
152*/
153
154/*!
155 \fn QPolygon::QPolygon(const QVector<QPoint> &points)
156
157 Constructs a polygon containing the specified \a points.
158
159 \sa setPoints()
160*/
161
162/*!
163 \fn QPolygon::QPolygon(const QRect &rectangle, bool closed)
164
165 Constructs a polygon from the given \a rectangle. If \a closed is
166 false, the polygon just contains the four points of the rectangle
167 ordered clockwise, otherwise the polygon's fifth point is set to
168 \a {rectangle}.topLeft().
169
170 Note that the bottom-right corner of the rectangle is located at
171 (rectangle.x() + rectangle.width(), rectangle.y() +
172 rectangle.height()).
173
174 \sa setPoints()
175*/
176
177QPolygon::QPolygon(const QRect &r, bool closed)
178{
179 reserve(closed ? 5 : 4);
180 *this << QPoint(r.x(), r.y())
181 << QPoint(r.x() + r.width(), r.y())
182 << QPoint(r.x() + r.width(), r.y() + r.height())
183 << QPoint(r.x(), r.y() + r.height());
184 if (closed)
185 *this << QPoint(r.left(), r.top());
186}
187
188/*!
189 \internal
190 Constructs a point array with \a nPoints points, taken from the
191 \a points array.
192
193 Equivalent to setPoints(nPoints, points).
194*/
195
196QPolygon::QPolygon(int nPoints, const int *points)
197{
198 setPoints(nPoints, points);
199}
200
201
202/*!
203 \fn QPolygon::~QPolygon()
204
205 Destroys the polygon.
206*/
207
208
209/*!
210 Translates all points in the polygon by (\a{dx}, \a{dy}).
211
212 \sa translated()
213*/
214
215void QPolygon::translate(int dx, int dy)
216{
217 if (dx == 0 && dy == 0)
218 return;
219
220 register QPoint *p = data();
221 register int i = size();
222 QPoint pt(dx, dy);
223 while (i--) {
224 *p += pt;
225 ++p;
226 }
227}
228
229/*!
230 \fn void QPolygon::translate(const QPoint &offset)
231 \overload
232
233 Translates all points in the polygon by the given \a offset.
234
235 \sa translated()
236*/
237
238/*!
239 Returns a copy of the polygon that is translated by (\a{dx}, \a{dy}).
240
241 \since 4.6
242 \sa translate()
243*/
244QPolygon QPolygon::translated(int dx, int dy) const
245{
246 QPolygon copy(*this);
247 copy.translate(dx, dy);
248 return copy;
249}
250
251/*!
252 \fn void QPolygon::translated(const QPoint &offset) const
253 \overload
254 \since 4.6
255
256 Returns a copy of the polygon that is translated by the given \a offset.
257
258 \sa translate()
259*/
260
261/*!
262 Extracts the coordinates of the point at the given \a index to
263 *\a{x} and *\a{y} (if they are valid pointers).
264
265 \sa setPoint()
266*/
267
268void QPolygon::point(int index, int *x, int *y) const
269{
270 QPoint p = at(index);
271 if (x)
272 *x = (int)p.x();
273 if (y)
274 *y = (int)p.y();
275}
276
277/*!
278 \fn QPoint QPolygon::point(int index) const
279 \overload
280
281 Returns the point at the given \a index.
282*/
283
284/*!
285 \fn void QPolygon::setPoint(int index, const QPoint &point)
286 \overload
287
288 Sets the point at the given \a index to the given \a point.
289*/
290
291/*!
292 \fn void QPolygon::setPoint(int index, int x, int y)
293
294 Sets the point at the given \a index to the point specified by
295 (\a{x}, \a{y}).
296
297 \sa point(), putPoints(), setPoints(),
298*/
299
300/*!
301 Resizes the polygon to \a nPoints and populates it with the given
302 \a points.
303
304 The example code creates a polygon with two points (10, 20) and
305 (30, 40):
306
307 \snippet doc/src/snippets/polygon/polygon.cpp 2
308
309 \sa setPoint() putPoints()
310*/
311
312void QPolygon::setPoints(int nPoints, const int *points)
313{
314 resize(nPoints);
315 int i = 0;
316 while (nPoints--) {
317 setPoint(i++, *points, *(points+1));
318 points += 2;
319 }
320}
321
322/*!
323 \overload
324
325 Resizes the polygon to \a nPoints and populates it with the points
326 specified by the variable argument list. The points are given as a
327 sequence of integers, starting with \a firstx then \a firsty, and
328 so on.
329
330 The example code creates a polygon with two points (10, 20) and
331 (30, 40):
332
333 \snippet doc/src/snippets/polygon/polygon.cpp 3
334*/
335
336void QPolygon::setPoints(int nPoints, int firstx, int firsty, ...)
337{
338 va_list ap;
339 resize(nPoints);
340 setPoint(0, firstx, firsty);
341 int i = 0, x, y;
342 va_start(ap, firsty);
343 while (--nPoints) {
344 x = va_arg(ap, int);
345 y = va_arg(ap, int);
346 setPoint(++i, x, y);
347 }
348 va_end(ap);
349}
350
351/*!
352 \overload
353 \internal
354
355 Copies \a nPoints points from the \a points coord array into this
356 point array, and resizes the point array if \c{index+nPoints}
357 exceeds the size of the array.
358
359 \sa setPoint()
360*/
361
362void QPolygon::putPoints(int index, int nPoints, const int *points)
363{
364 if (index + nPoints > size())
365 resize(index + nPoints);
366 int i = index;
367 while (nPoints--) {
368 setPoint(i++, *points, *(points+1));
369 points += 2;
370 }
371}
372
373/*!
374 Copies \a nPoints points from the variable argument list into this
375 polygon from the given \a index.
376
377 The points are given as a sequence of integers, starting with \a
378 firstx then \a firsty, and so on. The polygon is resized if
379 \c{index+nPoints} exceeds its current size.
380
381 The example code creates a polygon with three points (4,5), (6,7)
382 and (8,9), by expanding the polygon from 1 to 3 points:
383
384 \snippet doc/src/snippets/polygon/polygon.cpp 4
385
386 The following code has the same result, but here the putPoints()
387 function overwrites rather than extends:
388
389 \snippet doc/src/snippets/polygon/polygon.cpp 5
390
391 \sa setPoints()
392*/
393
394void QPolygon::putPoints(int index, int nPoints, int firstx, int firsty, ...)
395{
396 va_list ap;
397 if (index + nPoints > size())
398 resize(index + nPoints);
399 if (nPoints <= 0)
400 return;
401 setPoint(index, firstx, firsty);
402 int i = index, x, y;
403 va_start(ap, firsty);
404 while (--nPoints) {
405 x = va_arg(ap, int);
406 y = va_arg(ap, int);
407 setPoint(++i, x, y);
408 }
409 va_end(ap);
410}
411
412
413/*!
414 \fn void QPolygon::putPoints(int index, int nPoints, const QPolygon &fromPolygon, int fromIndex)
415 \overload
416
417 Copies \a nPoints points from the given \a fromIndex ( 0 by
418 default) in \a fromPolygon into this polygon, starting at the
419 specified \a index. For example:
420
421 \snippet doc/src/snippets/polygon/polygon.cpp 6
422*/
423
424void QPolygon::putPoints(int index, int nPoints, const QPolygon & from, int fromIndex)
425{
426 if (index + nPoints > size())
427 resize(index + nPoints);
428 if (nPoints <= 0)
429 return;
430 int n = 0;
431 while(n < nPoints) {
432 setPoint(index + n, from[fromIndex+n]);
433 ++n;
434 }
435}
436
437
438/*!
439 Returns the bounding rectangle of the polygon, or QRect(0, 0, 0,
440 0) if the polygon is empty.
441
442 \sa QVector::isEmpty()
443*/
444
445QRect QPolygon::boundingRect() const
446{
447 if (isEmpty())
448 return QRect(0, 0, 0, 0);
449 register const QPoint *pd = constData();
450 int minx, maxx, miny, maxy;
451 minx = maxx = pd->x();
452 miny = maxy = pd->y();
453 ++pd;
454 for (int i = 1; i < size(); ++i) {
455 if (pd->x() < minx)
456 minx = pd->x();
457 else if (pd->x() > maxx)
458 maxx = pd->x();
459 if (pd->y() < miny)
460 miny = pd->y();
461 else if (pd->y() > maxy)
462 maxy = pd->y();
463 ++pd;
464 }
465 return QRect(QPoint(minx,miny), QPoint(maxx,maxy));
466}
467
468#ifndef QT_NO_DEBUG_STREAM
469QDebug operator<<(QDebug dbg, const QPolygon &a)
470{
471#ifndef Q_BROKEN_DEBUG_STREAM
472 dbg.nospace() << "QPolygon(";
473 for (int i = 0; i < a.count(); ++i)
474 dbg.nospace() << a.at(i);
475 dbg.nospace() << ')';
476 return dbg.space();
477#else
478 qWarning("This compiler doesn't support streaming QPolygon to QDebug");
479 return dbg;
480 Q_UNUSED(a);
481#endif
482}
483#endif
484
485
486/*!
487 \class QPolygonF
488 \brief The QPolygonF class provides a vector of points using
489 floating point precision.
490
491 \reentrant
492 \ingroup painting
493 \ingroup shared
494
495 A QPolygonF is a QVector<QPointF>. The easiest way to add points
496 to a QPolygonF is to use its streaming operator, as illustrated
497 below:
498
499 \snippet doc/src/snippets/polygon/polygon.cpp 1
500
501 In addition to the functions provided by QVector, QPolygonF
502 provides the boundingRect() and translate() functions for geometry
503 operations. Use the QMatrix::map() function for more general
504 transformations of QPolygonFs.
505
506 QPolygonF also provides the isClosed() function to determine
507 whether a polygon's start and end points are the same, and the
508 toPolygon() function returning an integer precision copy of this
509 polygon.
510
511 The QPolygonF class is \l {Implicit Data Sharing}{implicitly
512 shared}.
513
514 \sa QVector, QPolygon, QLineF
515*/
516
517
518/*****************************************************************************
519 QPolygonF member functions
520 *****************************************************************************/
521
522/*!
523 \fn QPolygonF::QPolygonF()
524
525 Constructs a polygon with no points.
526
527 \sa QVector::isEmpty()
528*/
529
530/*!
531 \fn QPolygonF::QPolygonF(int size)
532
533 Constructs a polygon of the given \a size. Creates an empty
534 polygon if \a size == 0.