1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtPositioning module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qgeopolygon.h"
41#include "qgeopolygon_p.h"
42#include "qgeopath_p.h"
43#include "qgeocircle.h"
44
45#include "qgeocoordinate.h"
46#include "qnumeric.h"
47#include "qlocationutils_p.h"
48#include "qwebmercator_p.h"
49
50#include "qdoublevector2d_p.h"
51#include "qdoublevector3d_p.h"
52#include "qwebmercator_p.h"
53
54QT_BEGIN_NAMESPACE
55
56/*!
57 \class QGeoPolygon
58 \inmodule QtPositioning
59 \ingroup QtPositioning-positioning
60 \since 5.10
61
62 \brief The QGeoPolygon class defines a geographic polygon.
63
64 The polygon is defined by an ordered list of QGeoCoordinates representing its perimeter.
65
66 Each two adjacent elements in this list are intended to be connected
67 together by the shortest line segment of constant bearing passing
68 through both elements.
69 This type of connection can cross the date line in the longitudinal direction,
70 but never crosses the poles.
71
72 This is relevant for the calculation of the bounding box returned by
73 \l QGeoShape::boundingGeoRectangle() for this shape, which will have the latitude of
74 the top left corner set to the maximum latitude in the path point set.
75 Similarly, the latitude of the bottom right corner will be the minimum latitude
76 in the path point set.
77
78 This class is a \l Q_GADGET.
79 It can be \l{Cpp_value_integration_positioning}{directly used from C++ and QML}.
80*/
81
82/*
83 \property QGeoPolygon::path
84 \brief This property holds the list of coordinates for the geo polygon.
85
86 The polygon is both invalid and empty if it contains no coordinate.
87
88 A default constructed QGeoPolygon is therefore invalid.
89*/
90
91inline QGeoPolygonPrivate *QGeoPolygon::d_func()
92{
93 return static_cast<QGeoPolygonPrivate *>(d_ptr.data());
94}
95
96inline const QGeoPolygonPrivate *QGeoPolygon::d_func() const
97{
98 return static_cast<const QGeoPolygonPrivate *>(d_ptr.constData());
99}
100
101struct PolygonVariantConversions
102{
103 PolygonVariantConversions()
104 {
105 QMetaType::registerConverter<QGeoShape, QGeoPolygon>();
106 QMetaType::registerConverter<QGeoPolygon, QGeoShape>();
107 }
108};
109
110Q_GLOBAL_STATIC(PolygonVariantConversions, initPolygonConversions)
111
112/*!
113 Constructs a new, empty geo polygon.
114*/
115QGeoPolygon::QGeoPolygon()
116: QGeoShape(new QGeoPolygonPrivate())
117{
118 initPolygonConversions();
119}
120
121/*!
122 Constructs a new geo polygon from the coordinates specified
123 in \a path.
124*/
125QGeoPolygon::QGeoPolygon(const QList<QGeoCoordinate> &path)
126: QGeoShape(new QGeoPolygonPrivate(path))
127{
128 initPolygonConversions();
129}
130
131/*!
132 Constructs a new geo polygon from the contents of \a other.
133*/
134QGeoPolygon::QGeoPolygon(const QGeoPolygon &other)
135: QGeoShape(other)
136{
137 initPolygonConversions();
138}
139
140static void calculatePeripheralPoints(QList<QGeoCoordinate> &path,
141 const QGeoCircle &circle,
142 int steps)
143{
144 const QGeoCoordinate &center = circle.center();
145 const qreal distance = circle.radius();
146 // Calculate points based on great-circle distance
147 // Calculation is the same as GeoCoordinate's atDistanceAndAzimuth function
148 // but tweaked here for computing multiple points
149
150 // pre-calculations
151 steps = qMax(a: steps, b: 3);
152 qreal centerLon = center.longitude();
153 qreal latRad = QLocationUtils::radians(degrees: center.latitude());
154 qreal lonRad = QLocationUtils::radians(degrees: centerLon);
155 qreal cosLatRad = std::cos(x: latRad);
156 qreal sinLatRad = std::sin(x: latRad);
157 qreal ratio = (distance / QLocationUtils::earthMeanRadius());
158 qreal cosRatio = std::cos(x: ratio);
159 qreal sinRatio = std::sin(x: ratio);
160 qreal sinLatRad_x_cosRatio = sinLatRad * cosRatio;
161 qreal cosLatRad_x_sinRatio = cosLatRad * sinRatio;
162 for (int i = 0; i < steps; ++i) {
163 qreal azimuthRad = 2 * M_PI * i / steps;
164 qreal resultLatRad = std::asin(x: sinLatRad_x_cosRatio
165 + cosLatRad_x_sinRatio * std::cos(x: azimuthRad));
166 qreal resultLonRad = lonRad + std::atan2(y: std::sin(x: azimuthRad) * cosLatRad_x_sinRatio,
167 x: cosRatio - sinLatRad * std::sin(x: resultLatRad));
168 qreal lat2 = QLocationUtils::degrees(radians: resultLatRad);
169 qreal lon2 = QLocationUtils::wrapLong(lng: QLocationUtils::degrees(radians: resultLonRad));
170
171 path << QGeoCoordinate(lat2, lon2, center.altitude());
172 }
173}
174
175/*!
176 Constructs a new geo polygon from the contents of \a other.
177*/
178QGeoPolygon::QGeoPolygon(const QGeoShape &other)
179: QGeoShape(other)
180{
181 initPolygonConversions();
182 if (type() != QGeoShape::PolygonType) {
183 QGeoPolygonPrivate *poly = new QGeoPolygonPrivate();
184 if (type() == QGeoShape::CircleType) {
185 const QGeoCircle &circle = static_cast<const QGeoCircle &>(other);
186 QList<QGeoCoordinate> perimeter;
187 calculatePeripheralPoints(path&: perimeter, circle, steps: 128);
188 poly->setPath(perimeter);
189 } else if (type() == QGeoShape::RectangleType) {
190 const QGeoRectangle &rect = static_cast<const QGeoRectangle &>(other);
191 QList<QGeoCoordinate> perimeter;
192 perimeter << rect.topLeft() << rect.topRight()
193 << rect.bottomRight() << rect.bottomLeft();
194 poly->setPath(perimeter);
195 }
196 d_ptr = poly;
197 }
198}
199
200/*!
201 Destroys this polygon.
202*/
203QGeoPolygon::~QGeoPolygon() {}
204
205/*!
206 Assigns \a other to this geo polygon and returns a reference to this geo polygon.
207*/
208QGeoPolygon &QGeoPolygon::operator=(const QGeoPolygon &other)
209{
210 QGeoShape::operator=(other);
211 return *this;
212}
213
214/*!
215 Returns whether this geo polygon is equal to \a other.
216*/
217bool QGeoPolygon::operator==(const QGeoPolygon &other) const
218{
219 Q_D(const QGeoPolygon);
220 return *d == *other.d_func();
221}
222
223/*!
224 Returns whether this geo polygon is not equal to \a other.
225*/
226bool QGeoPolygon::operator!=(const QGeoPolygon &other) const
227{
228 Q_D(const QGeoPolygon);
229 return !(*d == *other.d_func());
230}
231
232/*!
233 Sets the \a path for the polygon.
234*/
235void QGeoPolygon::setPath(const QList<QGeoCoordinate> &path)
236{
237 Q_D(QGeoPolygon);
238 return d->setPath(path);
239}
240
241/*!
242 Returns all the elements of the polygon's boundary.
243*/
244const QList<QGeoCoordinate> &QGeoPolygon::path() const
245{
246 Q_D(const QGeoPolygon);
247 return d->path();
248}
249
250/*!
251 Sets all the elements of the polygon's perimeter
252 based on a list of coordinates (\a path).
253.
254
255 \since QtPositioning 5.12
256*/
257void QGeoPolygon::setPerimeter(const QVariantList &path)
258{
259 Q_D(QGeoPolygon);
260 QList<QGeoCoordinate> p;
261 for (const auto &c: path) {
262 if (c.canConvert<QGeoCoordinate>())
263 p << c.value<QGeoCoordinate>();
264 }
265 d->setPath(p);
266}
267
268/*!
269 Returns all the elements of the polygon's perimeter.
270
271 \since QtPositioning 5.12
272*/
273QVariantList QGeoPolygon::perimeter() const
274{
275 Q_D(const QGeoPolygon);
276 QVariantList p;
277 for (const auto &c: d->path())
278 p << QVariant::fromValue(value: c);
279 return p;
280}
281
282/*!
283 Translates this geo polygon by \a degreesLatitude northwards and \a degreesLongitude eastwards.
284
285 Negative values of \a degreesLatitude and \a degreesLongitude correspond to
286 southward and westward translation respectively.
287*/
288void QGeoPolygon::translate(double degreesLatitude, double degreesLongitude)
289{
290 Q_D(QGeoPolygon);
291 d->translate(degreesLatitude, degreesLongitude);
292}
293
294/*!
295 Returns a copy of this geo polygon translated by \a degreesLatitude northwards and
296 \a degreesLongitude eastwards.
297
298 Negative values of \a degreesLatitude and \a degreesLongitude correspond to
299 southward and westward translation respectively.
300
301 \sa translate()
302*/
303QGeoPolygon QGeoPolygon::translated(double degreesLatitude, double degreesLongitude) const
304{
305 QGeoPolygon result(*this);
306 result.translate(degreesLatitude, degreesLongitude);
307 return result;
308}
309
310/*!
311 Returns the length of the polygon's perimeter, in meters, from the element \a indexFrom to the element \a indexTo.
312 The length is intended to be the sum of the shortest distances for each pair of adjacent points.
313*/
314double QGeoPolygon::length(int indexFrom, int indexTo) const
315{
316 Q_D(const QGeoPolygon);
317 return d->length(indexFrom, indexTo);
318}
319
320/*!
321 Returns the number of elements in the polygon.
322
323 \since 5.10
324*/
325int QGeoPolygon::size() const
326{
327 Q_D(const QGeoPolygon);
328 return d->size();
329}
330
331/*!
332 Appends \a coordinate to the polygon.
333*/
334void QGeoPolygon::addCoordinate(const QGeoCoordinate &coordinate)
335{
336 Q_D(QGeoPolygon);
337 d->addCoordinate(coordinate);
338}
339
340/*!
341 Inserts \a coordinate at the specified \a index.
342*/
343void QGeoPolygon::insertCoordinate(int index, const QGeoCoordinate &coordinate)
344{
345 Q_D(QGeoPolygon);
346 d->insertCoordinate(index, coordinate);
347}
348
349/*!
350 Replaces the path element at the specified \a index with \a coordinate.
351*/
352void QGeoPolygon::replaceCoordinate(int index, const QGeoCoordinate &coordinate)
353{
354 Q_D(QGeoPolygon);
355 d->replaceCoordinate(index, coordinate);
356}
357
358/*!
359 Returns the coordinate at \a index .
360*/
361QGeoCoordinate QGeoPolygon::coordinateAt(int index) const
362{
363 Q_D(const QGeoPolygon);
364 return d->coordinateAt(index);
365}
366
367/*!
368 Returns true if the polygon's perimeter contains \a coordinate as one of the elements.
369*/
370bool QGeoPolygon::containsCoordinate(const QGeoCoordinate &coordinate) const
371{
372 Q_D(const QGeoPolygon);
373 return d->containsCoordinate(coordinate);
374}
375
376/*!
377 Removes the last occurrence of \a coordinate from the polygon.
378*/
379void QGeoPolygon::removeCoordinate(const QGeoCoordinate &coordinate)
380{
381 Q_D(QGeoPolygon);
382 d->removeCoordinate(coordinate);
383}
384
385/*!
386 Removes element at position \a index from the polygon.
387*/
388void QGeoPolygon::removeCoordinate(int index)
389{
390 Q_D(QGeoPolygon);
391 d->removeCoordinate(index);
392}
393
394/*!
395 Returns the geo polygon properties as a string.
396*/
397QString QGeoPolygon::toString() const
398{
399 if (type() != QGeoShape::PolygonType) {
400 qWarning(msg: "Not a polygon");
401 return QStringLiteral("QGeoPolygon(not a polygon)");
402 }
403
404 QString pathString;
405 for (const auto &p : path())
406 pathString += p.toString() + QLatin1Char(',');
407
408 return QStringLiteral("QGeoPolygon([ %1 ])").arg(a: pathString);
409}
410
411/*!
412 Sets the \a holePath for a hole inside the polygon. The hole is a
413 QVariant containing a QList<QGeoCoordinate>.
414
415 \since 5.12
416*/
417void QGeoPolygon::addHole(const QVariant &holePath)
418{
419 Q_D(QGeoPolygon);
420 QList<QGeoCoordinate> qgcHolePath;
421 if (holePath.canConvert<QVariantList>()) {
422 const QVariantList qvlHolePath = holePath.toList();
423 for (const QVariant &vertex : qvlHolePath) {
424 if (vertex.canConvert<QGeoCoordinate>())
425 qgcHolePath << vertex.value<QGeoCoordinate>();
426 }
427 }
428 //ToDo: add QGeoShape support
429 return d->addHole(holePath: qgcHolePath);
430}
431
432/*!
433 Overloaded method. Sets the \a holePath for a hole inside the polygon. The hole is a QList<QGeoCoordinate>.
434
435 \since 5.12
436*/
437void QGeoPolygon::addHole(const QList<QGeoCoordinate> &holePath)
438{
439 Q_D(QGeoPolygon);
440 return d->addHole(holePath);
441}
442
443/*!
444 Returns a QVariant containing a QVariant containing a QList<QGeoCoordinate>
445 which represents the hole at \a index.
446
447 \since 5.12
448*/
449const QVariantList QGeoPolygon::hole(int index) const
450{
451 Q_D(const QGeoPolygon);
452 QVariantList holeCoordinates;
453 for (const QGeoCoordinate &coords: d->holePath(index))
454 holeCoordinates << QVariant::fromValue(value: coords);
455 return holeCoordinates;
456}
457
458/*!
459 Returns a QList<QGeoCoordinate> which represents the hole at \a index.
460
461 \since 5.12
462*/
463const QList<QGeoCoordinate> QGeoPolygon::holePath(int index) const
464{
465 Q_D(const QGeoPolygon);
466 return d->holePath(index);
467}
468
469/*!
470 Removes element at position \a index from the holes QList.
471
472 \since 5.12
473*/
474void QGeoPolygon::removeHole(int index)
475{
476 Q_D(QGeoPolygon);
477 return d->removeHole(index);
478}
479
480/*!
481 Returns the number of holes.
482
483 \since 5.12
484*/
485int QGeoPolygon::holesCount() const
486{
487 Q_D(const QGeoPolygon);
488 return d->holesCount();
489}
490
491/*******************************************************************************
492 *
493 * QGeoPathPrivate & friends
494 *
495*******************************************************************************/
496
497QGeoPolygonPrivate::QGeoPolygonPrivate()
498: QGeoPathPrivate()
499{
500 type = QGeoShape::PolygonType;
501}
502
503QGeoPolygonPrivate::QGeoPolygonPrivate(const QList<QGeoCoordinate> &path)
504: QGeoPathPrivate(path)
505{
506 type = QGeoShape::PolygonType;
507}
508
509QGeoPolygonPrivate::~QGeoPolygonPrivate() {}
510
511QGeoShapePrivate *QGeoPolygonPrivate::clone() const
512{
513 return new QGeoPolygonPrivate(*this);
514}
515
516bool QGeoPolygonPrivate::isValid() const
517{
518 return path().size() > 2;
519}
520
521bool QGeoPolygonPrivate::contains(const QGeoCoordinate &coordinate) const
522{
523 return polygonContains(coordinate);
524}
525
526inline static void translatePoly( QList<QGeoCoordinate> &m_path,
527 QList<QList<QGeoCoordinate>> &m_holesList,
528 QGeoRectangle &m_bbox,
529 double degreesLatitude,
530 double degreesLongitude,
531 double m_maxLati,
532 double m_minLati)
533{
534 if (degreesLatitude > 0.0)
535 degreesLatitude = qMin(a: degreesLatitude, b: 90.0 - m_maxLati);
536 else
537 degreesLatitude = qMax(a: degreesLatitude, b: -90.0 - m_minLati);
538 for (QGeoCoordinate &p: m_path) {
539 p.setLatitude(p.latitude() + degreesLatitude);
540 p.setLongitude(QLocationUtils::wrapLong(lng: p.longitude() + degreesLongitude));
541 }
542 if (!m_holesList.isEmpty()){
543 for (QList<QGeoCoordinate> &hole: m_holesList){
544 for (QGeoCoordinate &holeVertex: hole){
545 holeVertex.setLatitude(holeVertex.latitude() + degreesLatitude);
546 holeVertex.setLongitude(QLocationUtils::wrapLong(lng: holeVertex.longitude() + degreesLongitude));
547 }
548 }
549 }
550 m_bbox.translate(degreesLatitude, degreesLongitude);
551}
552
553void QGeoPolygonPrivate::translate(double degreesLatitude, double degreesLongitude)
554{
555 // Need min/maxLati, so update bbox
556 QVector<double> m_deltaXs;
557 double m_minX, m_maxX, m_minLati, m_maxLati;
558 m_bboxDirty = false; // Updated in translatePoly
559 computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
560 translatePoly(m_path, m_holesList, m_bbox, degreesLatitude, degreesLongitude, m_maxLati, m_minLati);
561 m_leftBoundWrapped = QWebMercator::coordToMercator(coord: m_bbox.topLeft()).x();
562 m_clipperDirty = true;
563}
564
565bool QGeoPolygonPrivate::operator==(const QGeoShapePrivate &other) const
566{
567 if (!QGeoShapePrivate::operator==(other)) // checks type
568 return false;
569
570 const QGeoPolygonPrivate &otherPath = static_cast<const QGeoPolygonPrivate &>(other);
571 if (m_path.size() != otherPath.m_path.size()
572 || m_holesList.size() != otherPath.m_holesList.size())
573 return false;
574 return m_path == otherPath.m_path && m_holesList == otherPath.m_holesList;
575}
576
577void QGeoPolygonPrivate::addHole(const QList<QGeoCoordinate> &holePath)
578{
579 for (const QGeoCoordinate &holeVertex: holePath)
580 if (!holeVertex.isValid())
581 return;
582
583 m_holesList << holePath;
584 // ToDo: mark clipper dirty when hole caching gets added
585}
586
587const QList<QGeoCoordinate> QGeoPolygonPrivate::holePath(int index) const
588{
589 return m_holesList.at(i: index);
590}
591
592void QGeoPolygonPrivate::removeHole(int index)
593{
594 if (index < 0 || index >= m_holesList.size())
595 return;
596
597 m_holesList.removeAt(i: index);
598 // ToDo: mark clipper dirty when hole caching gets added
599}
600
601int QGeoPolygonPrivate::holesCount() const
602{
603 return m_holesList.size();
604}
605
606bool QGeoPolygonPrivate::polygonContains(const QGeoCoordinate &coordinate) const
607{
608 if (m_clipperDirty)
609 const_cast<QGeoPolygonPrivate *>(this)->updateClipperPath(); // this one updates bbox too if needed
610
611 QDoubleVector2D coord = QWebMercator::coordToMercator(coord: coordinate);
612
613 if (coord.x() < m_leftBoundWrapped)
614 coord.setX(coord.x() + 1.0);
615
616
617 IntPoint intCoord = QClipperUtils::toIntPoint(p: coord);
618 if (!c2t::clip2tri::pointInPolygon(pt: intCoord, path: m_clipperPath))
619 return false;
620
621 // else iterates the holes List checking whether the point is contained inside the holes
622 for (const QList<QGeoCoordinate> &holePath : qAsConst(t: m_holesList)) {
623 // ToDo: cache these
624 QGeoPolygon holePolygon;
625 holePolygon.setPath(holePath);
626 if (holePolygon.contains(coordinate))
627 return false;
628 }
629 return true;
630}
631
632void QGeoPolygonPrivate::markDirty()
633{
634 m_bboxDirty = m_clipperDirty = true;
635}
636
637void QGeoPolygonPrivate::updateClipperPath()
638{
639 if (m_bboxDirty)
640 computeBoundingBox();
641 m_clipperDirty = false;
642
643 QList<QDoubleVector2D> preservedPath;
644 for (const QGeoCoordinate &c : m_path) {
645 QDoubleVector2D crd = QWebMercator::coordToMercator(coord: c);
646 if (crd.x() < m_leftBoundWrapped)
647 crd.setX(crd.x() + 1.0);
648 preservedPath << crd;
649 }
650 m_clipperPath = QClipperUtils::qListToPath(list: preservedPath);
651}
652
653QGeoPolygonPrivateEager::QGeoPolygonPrivateEager() : QGeoPolygonPrivate()
654{
655 m_bboxDirty = false; // never dirty on the eager version
656}
657
658QGeoPolygonPrivateEager::QGeoPolygonPrivateEager(const QList<QGeoCoordinate> &path) : QGeoPolygonPrivate(path)
659{
660 m_bboxDirty = false; // never dirty on the eager version
661}
662
663QGeoPolygonPrivateEager::~QGeoPolygonPrivateEager()
664{
665
666}
667
668QGeoShapePrivate *QGeoPolygonPrivateEager::clone() const
669{
670 return new QGeoPolygonPrivate(*this);
671}
672
673void QGeoPolygonPrivateEager::translate(double degreesLatitude, double degreesLongitude)
674{
675 translatePoly(m_path, m_holesList, m_bbox, degreesLatitude, degreesLongitude, m_maxLati, m_minLati);
676 m_leftBoundWrapped = QWebMercator::coordToMercator(coord: m_bbox.topLeft()).x();
677 m_clipperDirty = true;
678}
679
680void QGeoPolygonPrivateEager::markDirty()
681{
682 m_clipperDirty = true;
683 computeBoundingBox();
684}
685
686void QGeoPolygonPrivateEager::addCoordinate(const QGeoCoordinate &coordinate)
687{
688 if (!coordinate.isValid())
689 return;
690 m_path.append(t: coordinate);
691 m_clipperDirty = true;
692 updateBoundingBox(); // do not markDirty as it uses computeBoundingBox instead
693}
694
695void QGeoPolygonPrivateEager::computeBoundingBox()
696{
697 computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
698 m_leftBoundWrapped = QWebMercator::coordToMercator(coord: m_bbox.topLeft()).x();
699}
700
701void QGeoPolygonPrivateEager::updateBoundingBox()
702{
703 updateBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
704}
705
706QGeoPolygonEager::QGeoPolygonEager() : QGeoPolygon()
707{
708 initPolygonConversions();
709 d_ptr = new QGeoPolygonPrivateEager;
710}
711
712QGeoPolygonEager::QGeoPolygonEager(const QList<QGeoCoordinate> &path) : QGeoPolygon()
713{
714 initPolygonConversions();
715 d_ptr = new QGeoPolygonPrivateEager(path);
716}
717
718QGeoPolygonEager::QGeoPolygonEager(const QGeoPolygon &other) : QGeoPolygon()
719{
720 initPolygonConversions();
721 // without being able to dynamic_cast the d_ptr, only way to be sure is to reconstruct a new QGeoPolygonPrivateEager
722 d_ptr = new QGeoPolygonPrivateEager;
723 setPath(other.path());
724 for (int i = 0; i < other.holesCount(); i++)
725 addHole(holePath: other.holePath(index: i));
726}
727
728QGeoPolygonEager::QGeoPolygonEager(const QGeoShape &other) : QGeoPolygon()
729{
730 initPolygonConversions();
731 if (other.type() == QGeoShape::PolygonType)
732 *this = QGeoPolygonEager(QGeoPolygon(other));
733 else
734 d_ptr = new QGeoPolygonPrivateEager;
735}
736
737QGeoPolygonEager::~QGeoPolygonEager()
738{
739
740}
741
742QT_END_NAMESPACE
743

source code of qtlocation/src/positioning/qgeopolygon.cpp