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 
54 QT_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 
d_func()91 inline QGeoPolygonPrivate *QGeoPolygon::d_func()
92 {
93     return static_cast<QGeoPolygonPrivate *>(d_ptr.data());
94 }
95 
d_func() const96 inline const QGeoPolygonPrivate *QGeoPolygon::d_func() const
97 {
98     return static_cast<const QGeoPolygonPrivate *>(d_ptr.constData());
99 }
100 
101 struct PolygonVariantConversions
102 {
PolygonVariantConversionsPolygonVariantConversions103     PolygonVariantConversions()
104     {
105         QMetaType::registerConverter<QGeoShape, QGeoPolygon>();
106         QMetaType::registerConverter<QGeoPolygon, QGeoShape>();
107     }
108 };
109 
Q_GLOBAL_STATIC(PolygonVariantConversions,initPolygonConversions)110 Q_GLOBAL_STATIC(PolygonVariantConversions, initPolygonConversions)
111 
112 /*!
113     Constructs a new, empty geo polygon.
114 */
115 QGeoPolygon::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 */
QGeoPolygon(const QList<QGeoCoordinate> & path)125 QGeoPolygon::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 */
QGeoPolygon(const QGeoPolygon & other)134 QGeoPolygon::QGeoPolygon(const QGeoPolygon &other)
135 :   QGeoShape(other)
136 {
137     initPolygonConversions();
138 }
139 
calculatePeripheralPoints(QList<QGeoCoordinate> & path,const QGeoCircle & circle,int steps)140 static 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(steps, 3);
152     qreal centerLon = center.longitude();
153     qreal latRad = QLocationUtils::radians(center.latitude());
154     qreal lonRad = QLocationUtils::radians(centerLon);
155     qreal cosLatRad = std::cos(latRad);
156     qreal sinLatRad = std::sin(latRad);
157     qreal ratio = (distance / QLocationUtils::earthMeanRadius());
158     qreal cosRatio = std::cos(ratio);
159     qreal sinRatio = std::sin(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(sinLatRad_x_cosRatio
165                                    + cosLatRad_x_sinRatio * std::cos(azimuthRad));
166         qreal resultLonRad = lonRad + std::atan2(std::sin(azimuthRad) * cosLatRad_x_sinRatio,
167                                        cosRatio - sinLatRad * std::sin(resultLatRad));
168         qreal lat2 = QLocationUtils::degrees(resultLatRad);
169         qreal lon2 = QLocationUtils::wrapLong(QLocationUtils::degrees(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 */
QGeoPolygon(const QGeoShape & other)178 QGeoPolygon::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(perimeter, circle, 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 */
~QGeoPolygon()203 QGeoPolygon::~QGeoPolygon() {}
204 
205 /*!
206     Assigns \a other to this geo polygon and returns a reference to this geo polygon.
207 */
operator =(const QGeoPolygon & other)208 QGeoPolygon &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 */
operator ==(const QGeoPolygon & other) const217 bool 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 */
operator !=(const QGeoPolygon & other) const226 bool 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 */
setPath(const QList<QGeoCoordinate> & path)235 void 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 */
path() const244 const 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 */
setPerimeter(const QVariantList & path)257 void 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 */
perimeter() const273 QVariantList QGeoPolygon::perimeter() const
274 {
275     Q_D(const QGeoPolygon);
276     QVariantList p;
277     for (const auto &c: d->path())
278         p << QVariant::fromValue(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 */
translate(double degreesLatitude,double degreesLongitude)288 void 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 */
translated(double degreesLatitude,double degreesLongitude) const303 QGeoPolygon 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 */
length(int indexFrom,int indexTo) const314 double 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 */
size() const325 int QGeoPolygon::size() const
326 {
327     Q_D(const QGeoPolygon);
328     return d->size();
329 }
330 
331 /*!
332     Appends \a coordinate to the polygon.
333 */
addCoordinate(const QGeoCoordinate & coordinate)334 void 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 */
insertCoordinate(int index,const QGeoCoordinate & coordinate)343 void 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 */
replaceCoordinate(int index,const QGeoCoordinate & coordinate)352 void 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 */
coordinateAt(int index) const361 QGeoCoordinate 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 */
containsCoordinate(const QGeoCoordinate & coordinate) const370 bool 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 */
removeCoordinate(const QGeoCoordinate & coordinate)379 void 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 */
removeCoordinate(int index)388 void 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 */
toString() const397 QString QGeoPolygon::toString() const
398 {
399     if (type() != QGeoShape::PolygonType) {
400         qWarning("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(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 */
addHole(const QVariant & holePath)417 void 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(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 */
addHole(const QList<QGeoCoordinate> & holePath)437 void 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 */
hole(int index) const449 const 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(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 */
holePath(int index) const463 const 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 */
removeHole(int index)474 void 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 */
holesCount() const485 int QGeoPolygon::holesCount() const
486 {
487     Q_D(const QGeoPolygon);
488     return d->holesCount();
489 }
490 
491 /*******************************************************************************
492  *
493  * QGeoPathPrivate & friends
494  *
495 *******************************************************************************/
496 
QGeoPolygonPrivate()497 QGeoPolygonPrivate::QGeoPolygonPrivate()
498 :   QGeoPathPrivate()
499 {
500     type = QGeoShape::PolygonType;
501 }
502 
QGeoPolygonPrivate(const QList<QGeoCoordinate> & path)503 QGeoPolygonPrivate::QGeoPolygonPrivate(const QList<QGeoCoordinate> &path)
504 :   QGeoPathPrivate(path)
505 {
506     type = QGeoShape::PolygonType;
507 }
508 
~QGeoPolygonPrivate()509 QGeoPolygonPrivate::~QGeoPolygonPrivate() {}
510 
clone() const511 QGeoShapePrivate *QGeoPolygonPrivate::clone() const
512 {
513     return new QGeoPolygonPrivate(*this);
514 }
515 
isValid() const516 bool QGeoPolygonPrivate::isValid() const
517 {
518     return path().size() > 2;
519 }
520 
contains(const QGeoCoordinate & coordinate) const521 bool QGeoPolygonPrivate::contains(const QGeoCoordinate &coordinate) const
522 {
523     return polygonContains(coordinate);
524 }
525 
translatePoly(QList<QGeoCoordinate> & m_path,QList<QList<QGeoCoordinate>> & m_holesList,QGeoRectangle & m_bbox,double degreesLatitude,double degreesLongitude,double m_maxLati,double m_minLati)526 inline 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(degreesLatitude, 90.0 - m_maxLati);
536     else
537         degreesLatitude = qMax(degreesLatitude, -90.0 - m_minLati);
538     for (QGeoCoordinate &p: m_path) {
539         p.setLatitude(p.latitude() + degreesLatitude);
540         p.setLongitude(QLocationUtils::wrapLong(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(holeVertex.longitude() + degreesLongitude));
547             }
548         }
549     }
550     m_bbox.translate(degreesLatitude, degreesLongitude);
551 }
552 
translate(double degreesLatitude,double degreesLongitude)553 void 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(m_bbox.topLeft()).x();
562     m_clipperDirty = true;
563 }
564 
operator ==(const QGeoShapePrivate & other) const565 bool 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 
addHole(const QList<QGeoCoordinate> & holePath)577 void 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 
holePath(int index) const587 const QList<QGeoCoordinate> QGeoPolygonPrivate::holePath(int index) const
588 {
589     return m_holesList.at(index);
590 }
591 
removeHole(int index)592 void QGeoPolygonPrivate::removeHole(int index)
593 {
594     if (index < 0 || index >= m_holesList.size())
595         return;
596 
597     m_holesList.removeAt(index);
598     // ToDo: mark clipper dirty when hole caching gets added
599 }
600 
holesCount() const601 int QGeoPolygonPrivate::holesCount() const
602 {
603     return m_holesList.size();
604 }
605 
polygonContains(const QGeoCoordinate & coordinate) const606 bool 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(coordinate);
612 
613     if (coord.x() < m_leftBoundWrapped)
614         coord.setX(coord.x() + 1.0);
615 
616 
617     IntPoint intCoord = QClipperUtils::toIntPoint(coord);
618     if (!c2t::clip2tri::pointInPolygon(intCoord, 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(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 
markDirty()632 void QGeoPolygonPrivate::markDirty()
633 {
634     m_bboxDirty = m_clipperDirty = true;
635 }
636 
updateClipperPath()637 void 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(c);
646         if (crd.x() < m_leftBoundWrapped)
647             crd.setX(crd.x() + 1.0);
648         preservedPath << crd;
649     }
650     m_clipperPath = QClipperUtils::qListToPath(preservedPath);
651 }
652 
QGeoPolygonPrivateEager()653 QGeoPolygonPrivateEager::QGeoPolygonPrivateEager() : QGeoPolygonPrivate()
654 {
655     m_bboxDirty = false; // never dirty on the eager version
656 }
657 
QGeoPolygonPrivateEager(const QList<QGeoCoordinate> & path)658 QGeoPolygonPrivateEager::QGeoPolygonPrivateEager(const QList<QGeoCoordinate> &path) : QGeoPolygonPrivate(path)
659 {
660     m_bboxDirty = false; // never dirty on the eager version
661 }
662 
~QGeoPolygonPrivateEager()663 QGeoPolygonPrivateEager::~QGeoPolygonPrivateEager()
664 {
665 
666 }
667 
clone() const668 QGeoShapePrivate *QGeoPolygonPrivateEager::clone() const
669 {
670     return new QGeoPolygonPrivate(*this);
671 }
672 
translate(double degreesLatitude,double degreesLongitude)673 void 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(m_bbox.topLeft()).x();
677     m_clipperDirty = true;
678 }
679 
markDirty()680 void QGeoPolygonPrivateEager::markDirty()
681 {
682     m_clipperDirty = true;
683     computeBoundingBox();
684 }
685 
addCoordinate(const QGeoCoordinate & coordinate)686 void QGeoPolygonPrivateEager::addCoordinate(const QGeoCoordinate &coordinate)
687 {
688     if (!coordinate.isValid())
689         return;
690     m_path.append(coordinate);
691     m_clipperDirty = true;
692     updateBoundingBox(); // do not markDirty as it uses computeBoundingBox instead
693 }
694 
computeBoundingBox()695 void QGeoPolygonPrivateEager::computeBoundingBox()
696 {
697     computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
698     m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
699 }
700 
updateBoundingBox()701 void QGeoPolygonPrivateEager::updateBoundingBox()
702 {
703     updateBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
704 }
705 
QGeoPolygonEager()706 QGeoPolygonEager::QGeoPolygonEager() : QGeoPolygon()
707 {
708     initPolygonConversions();
709     d_ptr = new QGeoPolygonPrivateEager;
710 }
711 
QGeoPolygonEager(const QList<QGeoCoordinate> & path)712 QGeoPolygonEager::QGeoPolygonEager(const QList<QGeoCoordinate> &path) : QGeoPolygon()
713 {
714     initPolygonConversions();
715     d_ptr = new QGeoPolygonPrivateEager(path);
716 }
717 
QGeoPolygonEager(const QGeoPolygon & other)718 QGeoPolygonEager::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(other.holePath(i));
726 }
727 
QGeoPolygonEager(const QGeoShape & other)728 QGeoPolygonEager::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 
~QGeoPolygonEager()737 QGeoPolygonEager::~QGeoPolygonEager()
738 {
739 
740 }
741 
742 QT_END_NAMESPACE
743