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 ¢er = 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