1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qpolygon.h" |
5 | #include "qrect.h" |
6 | #include "qdatastream.h" |
7 | #include "qdebug.h" |
8 | #include "qpainterpath.h" |
9 | #include "qtransform.h" |
10 | #include "qvariant.h" |
11 | #include "qpainterpath_p.h" |
12 | #include "qbezier_p.h" |
13 | |
14 | #include <stdarg.h> |
15 | |
16 | QT_BEGIN_NAMESPACE |
17 | |
18 | //same as qt_painterpath_isect_line in qpainterpath.cpp |
19 | static void qt_polygon_isect_line(const QPointF &p1, const QPointF &p2, const QPointF &pos, |
20 | int *winding) |
21 | { |
22 | qreal x1 = p1.x(); |
23 | qreal y1 = p1.y(); |
24 | qreal x2 = p2.x(); |
25 | qreal y2 = p2.y(); |
26 | qreal y = pos.y(); |
27 | |
28 | int dir = 1; |
29 | |
30 | if (qFuzzyCompare(p1: y1, p2: y2)) { |
31 | // ignore horizontal lines according to scan conversion rule |
32 | return; |
33 | } else if (y2 < y1) { |
34 | qreal x_tmp = x2; x2 = x1; x1 = x_tmp; |
35 | qreal y_tmp = y2; y2 = y1; y1 = y_tmp; |
36 | dir = -1; |
37 | } |
38 | |
39 | if (y >= y1 && y < y2) { |
40 | qreal x = x1 + ((x2 - x1) / (y2 - y1)) * (y - y1); |
41 | |
42 | // count up the winding number if we're |
43 | if (x<=pos.x()) { |
44 | (*winding) += dir; |
45 | } |
46 | } |
47 | } |
48 | |
49 | /*! |
50 | \class QPolygon |
51 | \brief The QPolygon class provides a list of points using |
52 | integer precision. |
53 | \inmodule QtGui |
54 | |
55 | \reentrant |
56 | |
57 | \ingroup painting |
58 | \ingroup shared |
59 | |
60 | A QPolygon object is a QList<QPoint>. The easiest way to add |
61 | points to a QPolygon is to use QList's streaming operator, as |
62 | illustrated below: |
63 | |
64 | \snippet polygon/polygon.cpp 0 |
65 | |
66 | In addition to the functions provided by QList, QPolygon |
67 | provides some point-specific functions. |
68 | |
69 | Each point in a polygon can be retrieved by passing its index to |
70 | the point() function. To populate the polygon, QPolygon provides |
71 | the setPoint() function to set the point at a given index, the |
72 | setPoints() function to set all the points in the polygon |
73 | (resizing it to the given number of points), and the putPoints() |
74 | function which copies a number of given points into the polygon |
75 | from a specified index (resizing the polygon if necessary). |
76 | |
77 | QPolygon provides the boundingRect() and translate() functions for |
78 | geometry functions. Use the QTransform::map() function for more |
79 | general transformations of QPolygons. |
80 | |
81 | The QPolygon class is \l {Implicit Data Sharing}{implicitly |
82 | shared}. |
83 | |
84 | \sa QList, QPolygonF, QLine |
85 | */ |
86 | |
87 | |
88 | /***************************************************************************** |
89 | QPolygon member functions |
90 | *****************************************************************************/ |
91 | |
92 | /*! |
93 | \fn QPolygon::QPolygon() |
94 | |
95 | Constructs a polygon with no points. |
96 | |
97 | \sa QList::isEmpty() |
98 | */ |
99 | |
100 | /*! |
101 | \fn QPolygon::QPolygon(const QList<QPoint> &points) |
102 | |
103 | Constructs a polygon containing the specified \a points. |
104 | |
105 | \sa setPoints() |
106 | */ |
107 | |
108 | /*! |
109 | \fn QPolygon::QPolygon(const QRect &rectangle, bool closed) |
110 | |
111 | Constructs a polygon from the given \a rectangle. If \a closed is |
112 | false, the polygon just contains the four points of the rectangle |
113 | ordered clockwise, otherwise the polygon's fifth point is set to |
114 | \a {rectangle}.topLeft(). |
115 | |
116 | Note that the bottom-right corner of the rectangle is located at |
117 | (rectangle.x() + rectangle.width(), rectangle.y() + |
118 | rectangle.height()). |
119 | |
120 | \sa setPoints() |
121 | */ |
122 | |
123 | QPolygon::QPolygon(const QRect &r, bool closed) |
124 | { |
125 | reserve(asize: closed ? 5 : 4); |
126 | *this << QPoint(r.x(), r.y()) |
127 | << QPoint(r.x() + r.width(), r.y()) |
128 | << QPoint(r.x() + r.width(), r.y() + r.height()) |
129 | << QPoint(r.x(), r.y() + r.height()); |
130 | if (closed) |
131 | *this << QPoint(r.left(), r.top()); |
132 | } |
133 | |
134 | /*! |
135 | \internal |
136 | Constructs a point array with \a nPoints points, taken from the |
137 | \a points array. |
138 | |
139 | Equivalent to setPoints(nPoints, points). |
140 | */ |
141 | |
142 | QPolygon::QPolygon(int nPoints, const int *points) |
143 | { |
144 | setPoints(nPoints, points); |
145 | } |
146 | |
147 | /*! |
148 | Translates all points in the polygon by (\a{dx}, \a{dy}). |
149 | |
150 | \sa translated() |
151 | */ |
152 | |
153 | void QPolygon::translate(int dx, int dy) |
154 | { |
155 | if (dx == 0 && dy == 0) |
156 | return; |
157 | |
158 | QPoint *p = data(); |
159 | int i = size(); |
160 | QPoint pt(dx, dy); |
161 | while (i--) { |
162 | *p += pt; |
163 | ++p; |
164 | } |
165 | } |
166 | |
167 | /*! |
168 | \fn void QPolygon::translate(const QPoint &offset) |
169 | \overload |
170 | |
171 | Translates all points in the polygon by the given \a offset. |
172 | |
173 | \sa translated() |
174 | */ |
175 | |
176 | /*! |
177 | Returns a copy of the polygon that is translated by (\a{dx}, \a{dy}). |
178 | |
179 | \since 4.6 |
180 | \sa translate() |
181 | */ |
182 | QPolygon QPolygon::translated(int dx, int dy) const |
183 | { |
184 | QPolygon copy(*this); |
185 | copy.translate(dx, dy); |
186 | return copy; |
187 | } |
188 | |
189 | /*! |
190 | \fn void QPolygon::translated(const QPoint &offset) const |
191 | \overload |
192 | \since 4.6 |
193 | |
194 | Returns a copy of the polygon that is translated by the given \a offset. |
195 | |
196 | \sa translate() |
197 | */ |
198 | |
199 | /*! |
200 | Extracts the coordinates of the point at the given \a index to |
201 | *\a{x} and *\a{y} (if they are valid pointers). |
202 | |
203 | \sa setPoint() |
204 | */ |
205 | |
206 | void QPolygon::point(int index, int *x, int *y) const |
207 | { |
208 | QPoint p = at(i: index); |
209 | if (x) |
210 | *x = (int)p.x(); |
211 | if (y) |
212 | *y = (int)p.y(); |
213 | } |
214 | |
215 | /*! |
216 | \fn QPoint QPolygon::point(int index) const |
217 | \overload |
218 | |
219 | Returns the point at the given \a index. |
220 | */ |
221 | |
222 | /*! |
223 | \fn void QPolygon::setPoint(int index, const QPoint &point) |
224 | \overload |
225 | |
226 | Sets the point at the given \a index to the given \a point. |
227 | */ |
228 | |
229 | /*! |
230 | Sets the point at the given \a index to the point specified by |
231 | (\a{x}, \a{y}). |
232 | |
233 | \sa point(), putPoints(), setPoints(), |
234 | */ |
235 | void QPolygon::setPoint(int index, int x, int y) |
236 | { |
237 | (*this)[index] = QPoint(x, y); |
238 | } |
239 | |
240 | |
241 | /*! |
242 | Resizes the polygon to \a nPoints and populates it with the given |
243 | \a points. |
244 | |
245 | The example code creates a polygon with two points (10, 20) and |
246 | (30, 40): |
247 | |
248 | \snippet polygon/polygon.cpp 2 |
249 | |
250 | \sa setPoint(), putPoints() |
251 | */ |
252 | |
253 | void QPolygon::setPoints(int nPoints, const int *points) |
254 | { |
255 | resize(size: nPoints); |
256 | int i = 0; |
257 | while (nPoints--) { |
258 | setPoint(index: i++, x: *points, y: *(points+1)); |
259 | points += 2; |
260 | } |
261 | } |
262 | |
263 | /*! |
264 | \overload |
265 | |
266 | Resizes the polygon to \a nPoints and populates it with the points |
267 | specified by the variable argument list. The points are given as a |
268 | sequence of integers, starting with \a firstx then \a firsty, and |
269 | so on. |
270 | |
271 | The example code creates a polygon with two points (10, 20) and |
272 | (30, 40): |
273 | |
274 | \snippet polygon/polygon.cpp 3 |
275 | */ |
276 | |
277 | void QPolygon::setPoints(int nPoints, int firstx, int firsty, ...) |
278 | { |
279 | va_list ap; |
280 | resize(size: nPoints); |
281 | setPoint(index: 0, x: firstx, y: firsty); |
282 | int i = 0, x, y; |
283 | va_start(ap, firsty); |
284 | while (--nPoints) { |
285 | x = va_arg(ap, int); |
286 | y = va_arg(ap, int); |
287 | setPoint(index: ++i, x, y); |
288 | } |
289 | va_end(ap); |
290 | } |
291 | |
292 | /*! |
293 | \overload |
294 | \internal |
295 | |
296 | Copies \a nPoints points from the \a points coord array into this |
297 | point array, and resizes the point array if \c{index+nPoints} |
298 | exceeds the size of the array. |
299 | |
300 | \sa setPoint() |
301 | */ |
302 | |
303 | void QPolygon::putPoints(int index, int nPoints, const int *points) |
304 | { |
305 | if (index + nPoints > size()) |
306 | resize(size: index + nPoints); |
307 | int i = index; |
308 | while (nPoints--) { |
309 | setPoint(index: i++, x: *points, y: *(points+1)); |
310 | points += 2; |
311 | } |
312 | } |
313 | |
314 | /*! |
315 | Copies \a nPoints points from the variable argument list into this |
316 | polygon from the given \a index. |
317 | |
318 | The points are given as a sequence of integers, starting with \a |
319 | firstx then \a firsty, and so on. The polygon is resized if |
320 | \c{index+nPoints} exceeds its current size. |
321 | |
322 | The example code creates a polygon with three points (4,5), (6,7) |
323 | and (8,9), by expanding the polygon from 1 to 3 points: |
324 | |
325 | \snippet polygon/polygon.cpp 4 |
326 | |
327 | The following code has the same result, but here the putPoints() |
328 | function overwrites rather than extends: |
329 | |
330 | \snippet polygon/polygon.cpp 5 |
331 | |
332 | \sa setPoints() |
333 | */ |
334 | |
335 | void QPolygon::putPoints(int index, int nPoints, int firstx, int firsty, ...) |
336 | { |
337 | va_list ap; |
338 | if (index + nPoints > size()) |
339 | resize(size: index + nPoints); |
340 | if (nPoints <= 0) |
341 | return; |
342 | setPoint(index, x: firstx, y: firsty); |
343 | int i = index, x, y; |
344 | va_start(ap, firsty); |
345 | while (--nPoints) { |
346 | x = va_arg(ap, int); |
347 | y = va_arg(ap, int); |
348 | setPoint(index: ++i, x, y); |
349 | } |
350 | va_end(ap); |
351 | } |
352 | |
353 | |
354 | /*! |
355 | \fn void QPolygon::putPoints(int index, int nPoints, const QPolygon &fromPolygon, int fromIndex) |
356 | \overload |
357 | |
358 | Copies \a nPoints points from the given \a fromIndex ( 0 by |
359 | default) in \a fromPolygon into this polygon, starting at the |
360 | specified \a index. For example: |
361 | |
362 | \snippet polygon/polygon.cpp 6 |
363 | */ |
364 | |
365 | void QPolygon::putPoints(int index, int nPoints, const QPolygon & from, int fromIndex) |
366 | { |
367 | if (index + nPoints > size()) |
368 | resize(size: index + nPoints); |
369 | if (nPoints <= 0) |
370 | return; |
371 | int n = 0; |
372 | while(n < nPoints) { |
373 | setPoint(index: index + n, pt: from[fromIndex+n]); |
374 | ++n; |
375 | } |
376 | } |
377 | |
378 | |
379 | /*! |
380 | Returns the bounding rectangle of the polygon, or QRect(0, 0, 0, |
381 | 0) if the polygon is empty. |
382 | |
383 | \sa QList::isEmpty() |
384 | */ |
385 | |
386 | QRect QPolygon::boundingRect() const |
387 | { |
388 | const QPoint *pd = constData(); |
389 | const QPoint *pe = pd + size(); |
390 | if (pd == pe) |
391 | return QRect(0, 0, 0, 0); |
392 | int minx, maxx, miny, maxy; |
393 | minx = maxx = pd->x(); |
394 | miny = maxy = pd->y(); |
395 | ++pd; |
396 | for (; pd != pe; ++pd) { |
397 | if (pd->x() < minx) |
398 | minx = pd->x(); |
399 | else if (pd->x() > maxx) |
400 | maxx = pd->x(); |
401 | if (pd->y() < miny) |
402 | miny = pd->y(); |
403 | else if (pd->y() > maxy) |
404 | maxy = pd->y(); |
405 | } |
406 | return QRect(QPoint(minx,miny), QPoint(maxx,maxy)); |
407 | } |
408 | |
409 | /*! |
410 | \fn QPolygon::toPolygonF() const |
411 | \since 6.4 |
412 | |
413 | Returns this polygon as a polygon with floating point accuracy. |
414 | |
415 | \sa QPolygonF::toPolygon() |
416 | */ |
417 | |
418 | |
419 | #ifndef QT_NO_DEBUG_STREAM |
420 | QDebug operator<<(QDebug dbg, const QPolygon &a) |
421 | { |
422 | return QtPrivate::printSequentialContainer(debug: dbg, which: "QPolygon" , c: a); |
423 | } |
424 | #endif |
425 | |
426 | |
427 | /*! |
428 | \class QPolygonF |
429 | \brief The QPolygonF class provides a list of points using |
430 | floating point precision. |
431 | \inmodule QtGui |
432 | |
433 | \reentrant |
434 | \ingroup painting |
435 | \ingroup shared |
436 | |
437 | A QPolygonF is a QList<QPointF>. The easiest way to add points |
438 | to a QPolygonF is to use its streaming operator, as illustrated |
439 | below: |
440 | |
441 | \snippet polygon/polygon.cpp 1 |
442 | |
443 | In addition to the functions provided by QList, QPolygonF |
444 | provides the boundingRect() and translate() functions for geometry |
445 | operations. Use the QTransform::map() function for more general |
446 | transformations of QPolygonFs. |
447 | |
448 | QPolygonF also provides the isClosed() function to determine |
449 | whether a polygon's start and end points are the same, and the |
450 | toPolygon() function returning an integer precision copy of this |
451 | polygon. |
452 | |
453 | The QPolygonF class is \l {Implicit Data Sharing}{implicitly |
454 | shared}. |
455 | |
456 | \sa QList, QPolygon, QLineF |
457 | */ |
458 | |
459 | |
460 | /***************************************************************************** |
461 | QPolygonF member functions |
462 | *****************************************************************************/ |
463 | |
464 | /*! |
465 | \fn QPolygonF::QPolygonF() |
466 | |
467 | Constructs a polygon with no points. |
468 | |
469 | \sa QList::isEmpty() |
470 | */ |
471 | |
472 | /*! |
473 | \fn QPolygonF::QPolygonF(const QList<QPointF> &points) |
474 | |
475 | Constructs a polygon containing the specified \a points. |
476 | */ |
477 | |
478 | /*! |
479 | \fn QPolygonF::QPolygonF(const QRectF &rectangle) |
480 | |
481 | Constructs a closed polygon from the specified \a rectangle. |
482 | |
483 | The polygon contains the four vertices of the rectangle in |
484 | clockwise order starting and ending with the top-left vertex. |
485 | |
486 | \sa isClosed() |
487 | */ |
488 | |
489 | QPolygonF::QPolygonF(const QRectF &r) |
490 | { |
491 | reserve(asize: 5); |
492 | append(t: QPointF(r.x(), r.y())); |
493 | append(t: QPointF(r.x() + r.width(), r.y())); |
494 | append(t: QPointF(r.x() + r.width(), r.y() + r.height())); |
495 | append(t: QPointF(r.x(), r.y() + r.height())); |
496 | append(t: QPointF(r.x(), r.y())); |
497 | } |
498 | |
499 | /*! |
500 | \fn QPolygonF::QPolygonF(const QPolygon &polygon) |
501 | |
502 | Constructs a float based polygon from the specified integer based |
503 | \a polygon. |
504 | |
505 | \sa toPolygon() |
506 | */ |
507 | |
508 | QPolygonF::QPolygonF(const QPolygon &a) |
509 | { |
510 | reserve(asize: a.size()); |
511 | for (int i=0; i<a.size(); ++i) |
512 | append(t: a.at(i)); |
513 | } |
514 | |
515 | /*! |
516 | Translate all points in the polygon by the given \a offset. |
517 | |
518 | \sa translated() |
519 | */ |
520 | |
521 | void QPolygonF::translate(const QPointF &offset) |
522 | { |
523 | if (offset.isNull()) |
524 | return; |
525 | |
526 | QPointF *p = data(); |
527 | int i = size(); |
528 | while (i--) { |
529 | *p += offset; |
530 | ++p; |
531 | } |
532 | } |
533 | |
534 | /*! |
535 | \fn void QPolygonF::translate(qreal dx, qreal dy) |
536 | \overload |
537 | |
538 | Translates all points in the polygon by (\a{dx}, \a{dy}). |
539 | |
540 | \sa translated() |
541 | */ |
542 | |
543 | /*! |
544 | Returns a copy of the polygon that is translated by the given \a offset. |
545 | |
546 | \since 4.6 |
547 | \sa translate() |
548 | */ |
549 | QPolygonF QPolygonF::translated(const QPointF &offset) const |
550 | { |
551 | QPolygonF copy(*this); |
552 | copy.translate(offset); |
553 | return copy; |
554 | } |
555 | |
556 | /*! |
557 | \fn void QPolygonF::translated(qreal dx, qreal dy) const |
558 | \overload |
559 | \since 4.6 |
560 | |
561 | Returns a copy of the polygon that is translated by (\a{dx}, \a{dy}). |
562 | |
563 | \sa translate() |
564 | */ |
565 | |
566 | /*! |
567 | \fn bool QPolygonF::isClosed() const |
568 | |
569 | Returns \c true if the polygon is closed; otherwise returns \c false. |
570 | |
571 | A polygon is said to be closed if its start point and end point are equal. |
572 | |
573 | \sa QList::first(), QList::last() |
574 | */ |
575 | |
576 | /*! |
577 | Returns the bounding rectangle of the polygon, or QRectF(0,0,0,0) |
578 | if the polygon is empty. |
579 | |
580 | \sa QList::isEmpty() |
581 | */ |
582 | |
583 | QRectF QPolygonF::boundingRect() const |
584 | { |
585 | const QPointF *pd = constData(); |
586 | const QPointF *pe = pd + size(); |
587 | if (pd == pe) |
588 | return QRectF(0, 0, 0, 0); |
589 | qreal minx, maxx, miny, maxy; |
590 | minx = maxx = pd->x(); |
591 | miny = maxy = pd->y(); |
592 | ++pd; |
593 | while (pd != pe) { |
594 | if (pd->x() < minx) |
595 | minx = pd->x(); |
596 | else if (pd->x() > maxx) |
597 | maxx = pd->x(); |
598 | if (pd->y() < miny) |
599 | miny = pd->y(); |
600 | else if (pd->y() > maxy) |
601 | maxy = pd->y(); |
602 | ++pd; |
603 | } |
604 | return QRectF(minx,miny, maxx - minx, maxy - miny); |
605 | } |
606 | |
607 | /*! |
608 | Creates and returns a QPolygon by converting each QPointF to a |
609 | QPoint. |
610 | |
611 | \sa QPointF::toPoint() |
612 | */ |
613 | |
614 | QPolygon QPolygonF::toPolygon() const |
615 | { |
616 | QPolygon a; |
617 | a.reserve(asize: size()); |
618 | for (int i=0; i<size(); ++i) |
619 | a.append(t: at(i).toPoint()); |
620 | return a; |
621 | } |
622 | |
623 | /*! |
624 | \fn void QPolygon::swap(QPolygon &other) |
625 | \since 4.8 |
626 | |
627 | Swaps polygon \a other with this polygon. This operation is very |
628 | fast and never fails. |
629 | */ |
630 | |
631 | /*! |
632 | \fn void QPolygonF::swap(QPolygonF &other) |
633 | \since 4.8 |
634 | |
635 | Swaps polygon \a other with this polygon. This operation is very |
636 | fast and never fails. |
637 | */ |
638 | |
639 | /*! |
640 | Returns the polygon as a QVariant |
641 | */ |
642 | QPolygon::operator QVariant() const |
643 | { |
644 | return QVariant::fromValue(value: *this); |
645 | } |
646 | |
647 | /***************************************************************************** |
648 | QPolygon stream functions |
649 | *****************************************************************************/ |
650 | #ifndef QT_NO_DATASTREAM |
651 | /*! |
652 | \fn QDataStream &operator<<(QDataStream &stream, const QPolygon &polygon) |
653 | \since 4.4 |
654 | \relates QPolygon |
655 | |
656 | Writes the given \a polygon to the given \a stream, and returns a |
657 | reference to the stream. |
658 | |
659 | \sa {Serializing Qt Data Types} |
660 | */ |
661 | QDataStream &operator<<(QDataStream &s, const QPolygon &a) |
662 | { |
663 | const QList<QPoint> &v = a; |
664 | return s << v; |
665 | } |
666 | |
667 | /*! |
668 | \fn QDataStream &operator>>(QDataStream &stream, QPolygon &polygon) |
669 | \since 4.4 |
670 | \relates QPolygon |
671 | |
672 | Reads a polygon from the given \a stream into the given \a |
673 | polygon, and returns a reference to the stream. |
674 | |
675 | \sa {Serializing Qt Data Types} |
676 | */ |
677 | QDataStream &operator>>(QDataStream &s, QPolygon &a) |
678 | { |
679 | QList<QPoint> &v = a; |
680 | return s >> v; |
681 | } |
682 | #endif // QT_NO_DATASTREAM |
683 | |
684 | /***************************************************************************** |
685 | QPolygonF stream functions |
686 | *****************************************************************************/ |
687 | #ifndef QT_NO_DATASTREAM |
688 | /*! |
689 | \fn QDataStream &operator<<(QDataStream &stream, const QPolygonF &polygon) |
690 | \relates QPolygonF |
691 | |
692 | Writes the given \a polygon to the given \a stream, and returns a |
693 | reference to the stream. |
694 | |
695 | \sa {Serializing Qt Data Types} |
696 | */ |
697 | |
698 | QDataStream &operator<<(QDataStream &s, const QPolygonF &a) |
699 | { |
700 | return s << static_cast<const QList<QPointF> &>(a); |
701 | } |
702 | |
703 | /*! |
704 | \fn QDataStream &operator>>(QDataStream &stream, QPolygonF &polygon) |
705 | \relates QPolygonF |
706 | |
707 | Reads a polygon from the given \a stream into the given \a |
708 | polygon, and returns a reference to the stream. |
709 | |
710 | \sa {Serializing Qt Data Types} |
711 | */ |
712 | |
713 | QDataStream &operator>>(QDataStream &s, QPolygonF &a) |
714 | { |
715 | return s >> static_cast<QList<QPointF> &>(a); |
716 | } |
717 | #endif //QT_NO_DATASTREAM |
718 | |
719 | #ifndef QT_NO_DEBUG_STREAM |
720 | QDebug operator<<(QDebug dbg, const QPolygonF &a) |
721 | { |
722 | return QtPrivate::printSequentialContainer(debug: dbg, which: "QPolygonF" , c: a); |
723 | } |
724 | #endif |
725 | |
726 | |
727 | /*! |
728 | \since 4.3 |
729 | |
730 | \fn bool QPolygonF::containsPoint(const QPointF &point, Qt::FillRule fillRule) const |
731 | |
732 | Returns \c true if the given \a point is inside the polygon according to |
733 | the specified \a fillRule; otherwise returns \c false. |
734 | */ |
735 | bool QPolygonF::containsPoint(const QPointF &pt, Qt::FillRule fillRule) const |
736 | { |
737 | if (isEmpty()) |
738 | return false; |
739 | |
740 | int winding_number = 0; |
741 | |
742 | QPointF last_pt = at(i: 0); |
743 | QPointF last_start = at(i: 0); |
744 | for (int i = 1; i < size(); ++i) { |
745 | const QPointF &e = at(i); |
746 | qt_polygon_isect_line(p1: last_pt, p2: e, pos: pt, winding: &winding_number); |
747 | last_pt = e; |
748 | } |
749 | |
750 | // implicitly close last subpath |
751 | if (last_pt != last_start) |
752 | qt_polygon_isect_line(p1: last_pt, p2: last_start, pos: pt, winding: &winding_number); |
753 | |
754 | return (fillRule == Qt::WindingFill |
755 | ? (winding_number != 0) |
756 | : ((winding_number % 2) != 0)); |
757 | } |
758 | |
759 | /*! |
760 | \since 4.3 |
761 | |
762 | \fn bool QPolygon::containsPoint(const QPoint &point, Qt::FillRule fillRule) const |
763 | Returns \c true if the given \a point is inside the polygon according to |
764 | the specified \a fillRule; otherwise returns \c false. |
765 | */ |
766 | bool QPolygon::containsPoint(const QPoint &pt, Qt::FillRule fillRule) const |
767 | { |
768 | if (isEmpty()) |
769 | return false; |
770 | |
771 | int winding_number = 0; |
772 | |
773 | QPoint last_pt = at(i: 0); |
774 | QPoint last_start = at(i: 0); |
775 | for (int i = 1; i < size(); ++i) { |
776 | const QPoint &e = at(i); |
777 | qt_polygon_isect_line(p1: last_pt, p2: e, pos: pt, winding: &winding_number); |
778 | last_pt = e; |
779 | } |
780 | |
781 | // implicitly close last subpath |
782 | if (last_pt != last_start) |
783 | qt_polygon_isect_line(p1: last_pt, p2: last_start, pos: pt, winding: &winding_number); |
784 | |
785 | return (fillRule == Qt::WindingFill |
786 | ? (winding_number != 0) |
787 | : ((winding_number % 2) != 0)); |
788 | } |
789 | |
790 | /*! |
791 | \since 4.3 |
792 | |
793 | Returns a polygon which is the union of this polygon and \a r. |
794 | |
795 | Set operations on polygons, will treat the polygons as areas, and |
796 | implicitly close the polygon. |
797 | |
798 | \sa intersected(), subtracted() |
799 | */ |
800 | |
801 | QPolygon QPolygon::united(const QPolygon &r) const |
802 | { |
803 | QPainterPath subject; subject.addPolygon(polygon: *this); |
804 | QPainterPath clip; clip.addPolygon(polygon: r); |
805 | |
806 | return subject.united(r: clip).toFillPolygon().toPolygon(); |
807 | } |
808 | |
809 | /*! |
810 | \since 4.3 |
811 | |
812 | Returns a polygon which is the intersection of this polygon and \a r. |
813 | |
814 | Set operations on polygons will treat the polygons as |
815 | areas. Non-closed polygons will be treated as implicitly closed. |
816 | |
817 | \sa intersects() |
818 | */ |
819 | |
820 | QPolygon QPolygon::intersected(const QPolygon &r) const |
821 | { |
822 | QPainterPath subject; subject.addPolygon(polygon: *this); |
823 | QPainterPath clip; clip.addPolygon(polygon: r); |
824 | |
825 | return subject.intersected(r: clip).toFillPolygon().toPolygon(); |
826 | } |
827 | |
828 | /*! |
829 | \since 4.3 |
830 | |
831 | Returns a polygon which is \a r subtracted from this polygon. |
832 | |
833 | Set operations on polygons will treat the polygons as |
834 | areas. Non-closed polygons will be treated as implicitly closed. |
835 | |
836 | */ |
837 | |
838 | QPolygon QPolygon::subtracted(const QPolygon &r) const |
839 | { |
840 | QPainterPath subject; subject.addPolygon(polygon: *this); |
841 | QPainterPath clip; clip.addPolygon(polygon: r); |
842 | |
843 | return subject.subtracted(r: clip).toFillPolygon().toPolygon(); |
844 | } |
845 | |
846 | /*! |
847 | \since 5.10 |
848 | |
849 | Returns \c true if the current polygon intersects at any point the given polygon \a p. |
850 | Also returns \c true if the current polygon contains or is contained by any part of \a p. |
851 | |
852 | Set operations on polygons will treat the polygons as |
853 | areas. Non-closed polygons will be treated as implicitly closed. |
854 | |
855 | \sa intersected() |
856 | */ |
857 | |
858 | bool QPolygon::intersects(const QPolygon &p) const |
859 | { |
860 | QPainterPath subject; subject.addPolygon(polygon: *this); |
861 | QPainterPath clip; clip.addPolygon(polygon: p); |
862 | |
863 | return subject.intersects(p: clip); |
864 | } |
865 | |
866 | /*! |
867 | \since 4.3 |
868 | |
869 | Returns a polygon which is the union of this polygon and \a r. |
870 | |
871 | Set operations on polygons will treat the polygons as |
872 | areas. Non-closed polygons will be treated as implicitly closed. |
873 | |
874 | \sa intersected(), subtracted() |
875 | */ |
876 | |
877 | QPolygonF QPolygonF::united(const QPolygonF &r) const |
878 | { |
879 | QPainterPath subject; subject.addPolygon(polygon: *this); |
880 | QPainterPath clip; clip.addPolygon(polygon: r); |
881 | |
882 | return subject.united(r: clip).toFillPolygon(); |
883 | } |
884 | |
885 | /*! |
886 | \since 4.3 |
887 | |
888 | Returns a polygon which is the intersection of this polygon and \a r. |
889 | |
890 | Set operations on polygons will treat the polygons as |
891 | areas. Non-closed polygons will be treated as implicitly closed. |
892 | |
893 | \sa intersects() |
894 | */ |
895 | |
896 | QPolygonF QPolygonF::intersected(const QPolygonF &r) const |
897 | { |
898 | QPainterPath subject; subject.addPolygon(polygon: *this); |
899 | QPainterPath clip; clip.addPolygon(polygon: r); |
900 | |
901 | return subject.intersected(r: clip).toFillPolygon(); |
902 | } |
903 | |
904 | /*! |
905 | \since 4.3 |
906 | |
907 | Returns a polygon which is \a r subtracted from this polygon. |
908 | |
909 | Set operations on polygons will treat the polygons as |
910 | areas. Non-closed polygons will be treated as implicitly closed. |
911 | |
912 | */ |
913 | |
914 | QPolygonF QPolygonF::subtracted(const QPolygonF &r) const |
915 | { |
916 | QPainterPath subject; subject.addPolygon(polygon: *this); |
917 | QPainterPath clip; clip.addPolygon(polygon: r); |
918 | return subject.subtracted(r: clip).toFillPolygon(); |
919 | } |
920 | |
921 | /*! |
922 | \since 5.10 |
923 | |
924 | Returns \c true if the current polygon intersects at any point the given polygon \a p. |
925 | Also returns \c true if the current polygon contains or is contained by any part of \a p. |
926 | |
927 | Set operations on polygons will treat the polygons as |
928 | areas. Non-closed polygons will be treated as implicitly closed. |
929 | |
930 | \sa intersected() |
931 | */ |
932 | |
933 | bool QPolygonF::intersects(const QPolygonF &p) const |
934 | { |
935 | QPainterPath subject; subject.addPolygon(polygon: *this); |
936 | QPainterPath clip; clip.addPolygon(polygon: p); |
937 | |
938 | return subject.intersects(p: clip); |
939 | } |
940 | |
941 | /*! |
942 | Returns the polygon as a QVariant. |
943 | */ |
944 | |
945 | QPolygonF::operator QVariant() const |
946 | { |
947 | return QVariant::fromValue(value: *this); |
948 | } |
949 | |
950 | QT_END_NAMESPACE |
951 | |