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 "qgeopath.h"
41 #include "qgeopolygon.h"
42 #include "qgeopath_p.h"
43 
44 #include "qgeocoordinate.h"
45 #include "qnumeric.h"
46 #include "qlocationutils_p.h"
47 #include "qwebmercator_p.h"
48 
49 #include "qdoublevector2d_p.h"
50 #include "qdoublevector3d_p.h"
51 QT_BEGIN_NAMESPACE
52 
53 /*!
54     \class QGeoPath
55     \inmodule QtPositioning
56     \ingroup QtPositioning-positioning
57     \since 5.9
58 
59     \brief The QGeoPath class defines a geographic path.
60 
61     The path is defined by an ordered list of QGeoCoordinates.
62 
63     Each two adjacent elements in the path are intended to be connected
64     together by the shortest line segment of constant bearing passing
65     through both elements.
66     This type of connection can cross the dateline in the longitudinal direction,
67     but never crosses the poles.
68 
69     This is relevant for the calculation of the bounding box returned by
70     \l QGeoShape::boundingGeoRectangle() for this shape, which will have the latitude of
71     the top left corner set to the maximum latitude in the path point set.
72     Similarly, the latitude of the bottom right corner will be the minimum latitude
73     in the path point set.
74 
75     This class is a \l Q_GADGET.
76     It can be \l{Cpp_value_integration_positioning}{directly used from C++ and QML}.
77 
78     A QGeoPath is both invalid and empty if it contains no coordinate.
79 
80     \note A default constructed QGeoPath is both invalid and empty as it does not contain any coordinates.
81 */
82 
83 /*!
84     \property QGeoPath::path
85     \brief This property holds the list of coordinates for the geo path.
86 
87     \note The coordinates cannot be processed in place. To change the value
88     of this property, retrieve the complete list of coordinates, process them,
89     and assign the new value to the property.
90 */
91 
d_func()92 inline QGeoPathPrivate *QGeoPath::d_func()
93 {
94     return static_cast<QGeoPathPrivate *>(d_ptr.data());
95 }
96 
d_func() const97 inline const QGeoPathPrivate *QGeoPath::d_func() const
98 {
99     return static_cast<const QGeoPathPrivate *>(d_ptr.constData());
100 }
101 
102 struct PathVariantConversions
103 {
PathVariantConversionsPathVariantConversions104     PathVariantConversions()
105     {
106         QMetaType::registerConverter<QGeoShape, QGeoPath>();
107         QMetaType::registerConverter<QGeoPath, QGeoShape>();
108     }
109 };
110 
Q_GLOBAL_STATIC(PathVariantConversions,initPathConversions)111 Q_GLOBAL_STATIC(PathVariantConversions, initPathConversions)
112 
113 /*!
114     Constructs a new, empty geo path.
115 */
116 QGeoPath::QGeoPath()
117 :   QGeoShape(new QGeoPathPrivate())
118 {
119     initPathConversions();
120 }
121 
122 /*!
123     Constructs a new geo path from a list of coordinates
124     (\a path and \a width).
125 */
QGeoPath(const QList<QGeoCoordinate> & path,const qreal & width)126 QGeoPath::QGeoPath(const QList<QGeoCoordinate> &path, const qreal &width)
127 :   QGeoShape(new QGeoPathPrivate(path, width))
128 {
129     initPathConversions();
130 }
131 
132 /*!
133     Constructs a new geo path from the contents of \a other.
134 */
QGeoPath(const QGeoPath & other)135 QGeoPath::QGeoPath(const QGeoPath &other)
136 :   QGeoShape(other)
137 {
138     initPathConversions();
139 }
140 
141 /*!
142     Constructs a new geo path from the contents of \a other.
143 */
QGeoPath(const QGeoShape & other)144 QGeoPath::QGeoPath(const QGeoShape &other)
145 :   QGeoShape(other)
146 {
147     initPathConversions();
148     if (type() != QGeoShape::PathType)
149         d_ptr = new QGeoPathPrivate();
150 }
151 
152 /*!
153     Destroys this path.
154 */
~QGeoPath()155 QGeoPath::~QGeoPath() {}
156 
157 /*!
158     Assigns \a other to this geo path and returns a reference to this geo path.
159 */
operator =(const QGeoPath & other)160 QGeoPath &QGeoPath::operator=(const QGeoPath &other)
161 {
162     QGeoShape::operator=(other);
163     return *this;
164 }
165 
166 /*!
167     Returns whether this geo path is equal to \a other.
168 */
operator ==(const QGeoPath & other) const169 bool QGeoPath::operator==(const QGeoPath &other) const
170 {
171     Q_D(const QGeoPath);
172     return *d == *other.d_func();
173 }
174 
175 /*!
176     Returns whether this geo path is not equal to \a other.
177 */
operator !=(const QGeoPath & other) const178 bool QGeoPath::operator!=(const QGeoPath &other) const
179 {
180     Q_D(const QGeoPath);
181     return !(*d == *other.d_func());
182 }
183 
184 /*!
185     Sets all the elements of the \a path.
186 */
setPath(const QList<QGeoCoordinate> & path)187 void QGeoPath::setPath(const QList<QGeoCoordinate> &path)
188 {
189     Q_D(QGeoPath);
190     return d->setPath(path);
191 }
192 
193 /*!
194     Returns all the elements of the path.
195 */
path() const196 const QList<QGeoCoordinate> &QGeoPath::path() const
197 {
198     Q_D(const QGeoPath);
199     return d->path();
200 }
201 
202 /*!
203     Clears the path.
204 
205     \since 5.12
206 */
clearPath()207 void QGeoPath::clearPath()
208 {
209     Q_D(QGeoPath);
210     d->clearPath();
211 }
212 
213 /*!
214     Sets all the elements of the path.
215 
216     \internal
217 */
setVariantPath(const QVariantList & path)218 void QGeoPath::setVariantPath(const QVariantList &path)
219 {
220     Q_D(QGeoPath);
221     QList<QGeoCoordinate> p;
222     for (const auto &c: path) {
223         if (c.canConvert<QGeoCoordinate>())
224             p << c.value<QGeoCoordinate>();
225     }
226     d->setPath(p);
227 }
228 /*!
229     Returns all the elements of the path.
230 
231     \internal
232 */
variantPath() const233 QVariantList QGeoPath::variantPath() const
234 {
235     Q_D(const QGeoPath);
236     QVariantList p;
237     for (const auto &c: d->path())
238         p << QVariant::fromValue(c);
239     return p;
240 }
241 
242 
243 /*!
244     \property QGeoPath::width
245 
246     \brief the width of the path in meters.
247 */
setWidth(const qreal & width)248 void QGeoPath::setWidth(const qreal &width)
249 {
250     Q_D(QGeoPath);
251     d->setWidth(width);
252 }
253 
254 /*!
255     Returns the width of the path, in meters. This information is used in the \l contains method.
256     The default value is 0.
257 */
width() const258 qreal QGeoPath::width() const
259 {
260     Q_D(const QGeoPath);
261     return d->width();
262 }
263 
264 /*!
265     Translates this geo path by \a degreesLatitude northwards and \a degreesLongitude eastwards.
266 
267     Negative values of \a degreesLatitude and \a degreesLongitude correspond to
268     southward and westward translation respectively.
269 */
translate(double degreesLatitude,double degreesLongitude)270 void QGeoPath::translate(double degreesLatitude, double degreesLongitude)
271 {
272     Q_D(QGeoPath);
273     d->translate(degreesLatitude, degreesLongitude);
274 }
275 
276 /*!
277     Returns a copy of this geo path translated by \a degreesLatitude northwards and
278     \a degreesLongitude eastwards.
279 
280     Negative values of \a degreesLatitude and \a degreesLongitude correspond to
281     southward and westward translation respectively.
282 
283     \sa translate()
284 */
translated(double degreesLatitude,double degreesLongitude) const285 QGeoPath QGeoPath::translated(double degreesLatitude, double degreesLongitude) const
286 {
287     QGeoPath result(*this);
288     result.translate(degreesLatitude, degreesLongitude);
289     return result;
290 }
291 
292 /*!
293     Returns the length of the path, in meters, from the element \a indexFrom to the element \a indexTo.
294     The length is intended to be the sum of the shortest distances for each pair of adjacent points.
295 
296     If \a indexTo is -1 (the default value), the length will be including the distance between last coordinate
297     and the first (closed loop).
298     To retrieve the length for the path, use 0 for \a indexFrom and \l QGeoPath::size() - 1 for \a indexTo.
299 */
length(int indexFrom,int indexTo) const300 double QGeoPath::length(int indexFrom, int indexTo) const
301 {
302     Q_D(const QGeoPath);
303     return d->length(indexFrom, indexTo);
304 }
305 
306 /*!
307     Returns the number of elements in the path.
308 
309     \since 5.10
310 */
size() const311 int QGeoPath::size() const
312 {
313     Q_D(const QGeoPath);
314     return d->size();
315 }
316 
317 /*!
318     Appends \a coordinate to the path.
319 */
addCoordinate(const QGeoCoordinate & coordinate)320 void QGeoPath::addCoordinate(const QGeoCoordinate &coordinate)
321 {
322     Q_D(QGeoPath);
323     d->addCoordinate(coordinate);
324 }
325 
326 /*!
327     Inserts \a coordinate at the specified \a index.
328 */
insertCoordinate(int index,const QGeoCoordinate & coordinate)329 void QGeoPath::insertCoordinate(int index, const QGeoCoordinate &coordinate)
330 {
331     Q_D(QGeoPath);
332     d->insertCoordinate(index, coordinate);
333 }
334 
335 /*!
336     Replaces the path element at the specified \a index with \a coordinate.
337 */
replaceCoordinate(int index,const QGeoCoordinate & coordinate)338 void QGeoPath::replaceCoordinate(int index, const QGeoCoordinate &coordinate)
339 {
340     Q_D(QGeoPath);
341     d->replaceCoordinate(index, coordinate);
342 }
343 
344 /*!
345     Returns the coordinate at \a index .
346 */
coordinateAt(int index) const347 QGeoCoordinate QGeoPath::coordinateAt(int index) const
348 {
349     Q_D(const QGeoPath);
350     return d->coordinateAt(index);
351 }
352 
353 /*!
354     Returns true if the path contains \a coordinate as one of the elements.
355 */
containsCoordinate(const QGeoCoordinate & coordinate) const356 bool QGeoPath::containsCoordinate(const QGeoCoordinate &coordinate) const
357 {
358     Q_D(const QGeoPath);
359     return d->containsCoordinate(coordinate);
360 }
361 
362 /*!
363     Removes the last occurrence of \a coordinate from the path.
364 */
removeCoordinate(const QGeoCoordinate & coordinate)365 void QGeoPath::removeCoordinate(const QGeoCoordinate &coordinate)
366 {
367     Q_D(QGeoPath);
368     d->removeCoordinate(coordinate);
369 }
370 
371 /*!
372     Removes element at position \a index from the path.
373 */
removeCoordinate(int index)374 void QGeoPath::removeCoordinate(int index)
375 {
376     Q_D(QGeoPath);
377     d->removeCoordinate(index);
378 }
379 
380 /*!
381     Returns the geo path properties as a string.
382 */
toString() const383 QString QGeoPath::toString() const
384 {
385     if (type() != QGeoShape::PathType) {
386         qWarning("Not a path");
387         return QStringLiteral("QGeoPath(not a path)");
388     }
389 
390     QString pathString;
391     for (const auto &p : path())
392         pathString += p.toString() + QLatin1Char(',');
393 
394     return QStringLiteral("QGeoPath([ %1 ])").arg(pathString);
395 }
396 
397 /*******************************************************************************
398  *
399  * QGeoPathPrivate & friends
400  *
401 *******************************************************************************/
402 
QGeoPathPrivate()403 QGeoPathPrivate::QGeoPathPrivate()
404 :   QGeoShapePrivate(QGeoShape::PathType)
405 {
406 
407 }
408 
QGeoPathPrivate(const QList<QGeoCoordinate> & path,const qreal width)409 QGeoPathPrivate::QGeoPathPrivate(const QList<QGeoCoordinate> &path, const qreal width)
410 :   QGeoShapePrivate(QGeoShape::PathType)
411 {
412     setPath(path);
413     setWidth(width);
414 }
415 
~QGeoPathPrivate()416 QGeoPathPrivate::~QGeoPathPrivate()
417 {
418 
419 }
420 
clone() const421 QGeoShapePrivate *QGeoPathPrivate::clone() const
422 {
423     return new QGeoPathPrivate(*this);
424 }
425 
isValid() const426 bool QGeoPathPrivate::isValid() const
427 {
428     return !isEmpty();
429 }
430 
isEmpty() const431 bool QGeoPathPrivate::isEmpty() const
432 {
433     return path().isEmpty(); // this should perhaps return geometric emptiness, less than 2 points for line, or empty polygon for polygons
434 }
435 
center() const436 QGeoCoordinate QGeoPathPrivate::center() const
437 {
438     return boundingGeoRectangle().center();
439 }
440 
extendShape(const QGeoCoordinate & coordinate)441 void QGeoPathPrivate::extendShape(const QGeoCoordinate &coordinate)
442 {
443     if (!coordinate.isValid() || contains(coordinate))
444         return;
445     addCoordinate(coordinate);
446 }
447 
operator ==(const QGeoShapePrivate & other) const448 bool QGeoPathPrivate::operator==(const QGeoShapePrivate &other) const
449 {
450     if (!QGeoShapePrivate::operator==(other))
451         return false;
452 
453     const QGeoPathPrivate &otherPath = static_cast<const QGeoPathPrivate &>(other);
454     if (m_path.size() != otherPath.m_path.size())
455         return false;
456     return m_width == otherPath.m_width && m_path == otherPath.m_path;
457 }
458 
path() const459 const QList<QGeoCoordinate> &QGeoPathPrivate::path() const
460 {
461     return m_path;
462 }
463 
lineContains(const QGeoCoordinate & coordinate) const464 bool QGeoPathPrivate::lineContains(const QGeoCoordinate &coordinate) const
465 {
466     // Unoptimized approach:
467     // - consider each segment of the path
468     // - project it into mercator space (rhumb lines are straight in mercator space)
469     // - find closest point to coordinate
470     // - unproject the closest point
471     // - calculate coordinate to closest point distance with distanceTo()
472     // - if not within lineRadius, advance
473     //
474     // To keep wrapping into the equation:
475     //   If the mercator x value of a coordinate of the line, or the coordinate parameter, is less
476     // than mercator(m_bbox).x, add that to the conversion.
477 
478     if (m_bboxDirty)
479         const_cast<QGeoPathPrivate &>(*this).computeBoundingBox();
480 
481     double lineRadius = qMax(width() * 0.5, 0.2); // minimum radius: 20cm
482 
483     if (!m_path.size())
484         return false;
485     else if (m_path.size() == 1)
486         return (m_path[0].distanceTo(coordinate) <= lineRadius);
487 
488     QDoubleVector2D p = QWebMercator::coordToMercator(coordinate);
489     if (p.x() < m_leftBoundWrapped)
490         p.setX(p.x() + m_leftBoundWrapped);  // unwrap X
491 
492     QDoubleVector2D a;
493     QDoubleVector2D b;
494     if (m_path.size()) {
495         a = QWebMercator::coordToMercator(m_path[0]);
496         if (a.x() < m_leftBoundWrapped)
497             a.setX(a.x() + m_leftBoundWrapped);  // unwrap X
498     }
499     for (int i = 1; i < m_path.size(); i++) {
500         b = QWebMercator::coordToMercator(m_path[i]);
501         if (b.x() < m_leftBoundWrapped)
502             b.setX(b.x() + m_leftBoundWrapped);  // unwrap X
503         if (b == a)
504             continue;
505 
506         double u = ((p.x() - a.x()) * (b.x() - a.x()) + (p.y() - a.y()) * (b.y() - a.y()) ) / (b - a).lengthSquared();
507         QDoubleVector2D intersection(a.x() + u * (b.x() - a.x()) , a.y() + u * (b.y() - a.y()) );
508 
509         QDoubleVector2D candidate = ( (p-a).length() < (p-b).length() ) ? a : b;
510 
511         if (u > 0 && u < 1
512             && (p-intersection).length() < (p-candidate).length()  ) // And it falls in the segment
513                 candidate = intersection;
514 
515 
516         if (candidate.x() > 1.0)
517             candidate.setX(candidate.x() - m_leftBoundWrapped); // wrap X
518 
519         QGeoCoordinate closest = QWebMercator::mercatorToCoord(candidate);
520 
521         double distanceMeters = coordinate.distanceTo(closest);
522         if (distanceMeters <= lineRadius)
523             return true;
524 
525         // swap
526         a = b;
527     }
528 
529     // Last check if the coordinate is on the left of leftBoundMercator, but close enough to
530     // m_path[0]
531     return (m_path[0].distanceTo(coordinate) <= lineRadius);
532 }
533 
contains(const QGeoCoordinate & coordinate) const534 bool QGeoPathPrivate::contains(const QGeoCoordinate &coordinate) const
535 {
536     return lineContains(coordinate);
537 }
538 
width() const539 qreal QGeoPathPrivate::width() const
540 {
541     return m_width;
542 }
543 
setWidth(const qreal & width)544 void QGeoPathPrivate::setWidth(const qreal &width)
545 {
546     if (qIsNaN(width) || width < 0.0)
547         return;
548     m_width = width;
549 }
550 
length(int indexFrom,int indexTo) const551 double QGeoPathPrivate::length(int indexFrom, int indexTo) const
552 {
553     if (path().isEmpty())
554         return 0.0;
555 
556     bool wrap = indexTo == -1;
557     if (indexTo < 0 || indexTo >= path().size())
558         indexTo = path().size() - 1;
559     double len = 0.0;
560     // TODO: consider calculating the length of the actual rhumb line segments
561     // instead of the shortest path from A to B.
562     for (int i = indexFrom; i < indexTo; i++)
563         len += m_path[i].distanceTo(m_path[i+1]);
564     if (wrap)
565         len += m_path.last().distanceTo(m_path.first());
566     return len;
567 }
568 
size() const569 int QGeoPathPrivate::size() const
570 {
571     return m_path.size();
572 }
573 
coordinateAt(int index) const574 QGeoCoordinate QGeoPathPrivate::coordinateAt(int index) const
575 {
576     if (index < 0 || index >= m_path.size())
577         return QGeoCoordinate();
578 
579     return m_path.at(index);
580 }
581 
containsCoordinate(const QGeoCoordinate & coordinate) const582 bool QGeoPathPrivate::containsCoordinate(const QGeoCoordinate &coordinate) const
583 {
584     return m_path.indexOf(coordinate) > -1;
585 }
586 
translate(double degreesLatitude,double degreesLongitude)587 void QGeoPathPrivate::translate(double degreesLatitude, double degreesLongitude)
588 {
589     // Need min/maxLati, so update bbox
590     QVector<double> m_deltaXs;
591     double m_minX, m_maxX, m_minLati, m_maxLati;
592     m_bboxDirty = false;
593     computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
594 
595     if (degreesLatitude > 0.0)
596         degreesLatitude = qMin(degreesLatitude, 90.0 - m_maxLati);
597     else
598         degreesLatitude = qMax(degreesLatitude, -90.0 - m_minLati);
599     for (QGeoCoordinate &p: m_path) {
600         p.setLatitude(p.latitude() + degreesLatitude);
601         p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude));
602     }
603     m_bbox.translate(degreesLatitude, degreesLongitude);
604     m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
605 }
606 
boundingGeoRectangle() const607 QGeoRectangle QGeoPathPrivate::boundingGeoRectangle() const
608 {
609     if (m_bboxDirty)
610         const_cast<QGeoPathPrivate &>(*this).computeBoundingBox();
611     return m_bbox;
612 }
613 
setPath(const QList<QGeoCoordinate> & path)614 void QGeoPathPrivate::setPath(const QList<QGeoCoordinate> &path)
615 {
616     for (const QGeoCoordinate &c: path)
617         if (!c.isValid())
618             return;
619     m_path = path;
620     markDirty();
621 }
622 
clearPath()623 void QGeoPathPrivate::clearPath()
624 {
625     m_path.clear();
626     markDirty();
627 }
628 
addCoordinate(const QGeoCoordinate & coordinate)629 void QGeoPathPrivate::addCoordinate(const QGeoCoordinate &coordinate)
630 {
631     if (!coordinate.isValid())
632         return;
633     m_path.append(coordinate);
634     markDirty();
635 }
636 
insertCoordinate(int index,const QGeoCoordinate & coordinate)637 void QGeoPathPrivate::insertCoordinate(int index, const QGeoCoordinate &coordinate)
638 {
639     if (index < 0 || index > m_path.size() || !coordinate.isValid())
640         return;
641     m_path.insert(index, coordinate);
642     markDirty();
643 }
644 
replaceCoordinate(int index,const QGeoCoordinate & coordinate)645 void QGeoPathPrivate::replaceCoordinate(int index, const QGeoCoordinate &coordinate)
646 {
647     if (index < 0 || index >= m_path.size() || !coordinate.isValid())
648         return;
649     m_path[index] = coordinate;
650     markDirty();
651 }
652 
removeCoordinate(const QGeoCoordinate & coordinate)653 void QGeoPathPrivate::removeCoordinate(const QGeoCoordinate &coordinate)
654 {
655     int index = m_path.lastIndexOf(coordinate);
656     removeCoordinate(index);
657 }
658 
removeCoordinate(int index)659 void QGeoPathPrivate::removeCoordinate(int index)
660 {
661     if (index < 0 || index >= m_path.size())
662         return;
663     m_path.removeAt(index);
664     markDirty();
665 }
666 
markDirty()667 void QGeoPathPrivate::markDirty()
668 {
669     m_bboxDirty = true;
670 }
671 
computeBoundingBox()672 void QGeoPathPrivate::computeBoundingBox()
673 {
674     QVector<double> m_deltaXs;
675     double m_minX, m_maxX, m_minLati, m_maxLati;
676     m_bboxDirty = false;
677     computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
678     m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
679 }
680 
QGeoPathPrivateEager()681 QGeoPathPrivateEager::QGeoPathPrivateEager()
682 :   QGeoPathPrivate()
683 {
684     m_bboxDirty = false; // never dirty on the eager version
685 }
686 
QGeoPathPrivateEager(const QList<QGeoCoordinate> & path,const qreal width)687 QGeoPathPrivateEager::QGeoPathPrivateEager(const QList<QGeoCoordinate> &path, const qreal width)
688 :   QGeoPathPrivate(path, width)
689 {
690     m_bboxDirty = false; // never dirty on the eager version
691 }
692 
~QGeoPathPrivateEager()693 QGeoPathPrivateEager::~QGeoPathPrivateEager()
694 {
695 
696 }
697 
clone() const698 QGeoShapePrivate *QGeoPathPrivateEager::clone() const
699 {
700     return new QGeoPathPrivateEager(*this);
701 }
702 
markDirty()703 void QGeoPathPrivateEager::markDirty()
704 {
705     computeBoundingBox();
706 }
707 
translate(double degreesLatitude,double degreesLongitude)708 void QGeoPathPrivateEager::translate(double degreesLatitude, double degreesLongitude)
709 {
710     if (degreesLatitude > 0.0)
711         degreesLatitude = qMin(degreesLatitude, 90.0 - m_maxLati);
712     else
713         degreesLatitude = qMax(degreesLatitude, -90.0 - m_minLati);
714     for (QGeoCoordinate &p: m_path) {
715         p.setLatitude(p.latitude() + degreesLatitude);
716         p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude));
717     }
718     m_bbox.translate(degreesLatitude, degreesLongitude);
719     m_minLati += degreesLatitude;
720     m_maxLati += degreesLatitude;
721     m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
722 }
723 
addCoordinate(const QGeoCoordinate & coordinate)724 void QGeoPathPrivateEager::addCoordinate(const QGeoCoordinate &coordinate)
725 {
726     if (!coordinate.isValid())
727         return;
728     m_path.append(coordinate);
729     //m_clipperDirty = true; // clipper not used in polylines
730     updateBoundingBox();
731 }
732 
computeBoundingBox()733 void QGeoPathPrivateEager::QGeoPathPrivateEager::computeBoundingBox()
734 {
735     computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
736     m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
737 }
738 
updateBoundingBox()739 void QGeoPathPrivateEager::QGeoPathPrivateEager::updateBoundingBox()
740 {
741     updateBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
742     m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
743 }
744 
QGeoPathEager()745 QGeoPathEager::QGeoPathEager() : QGeoPath()
746 {
747     initPathConversions();
748     d_ptr = new QGeoPathPrivateEager;
749 }
750 
QGeoPathEager(const QList<QGeoCoordinate> & path,const qreal & width)751 QGeoPathEager::QGeoPathEager(const QList<QGeoCoordinate> &path, const qreal &width) : QGeoPath()
752 {
753     initPathConversions();
754     d_ptr = new QGeoPathPrivateEager(path, width);
755 }
756 
QGeoPathEager(const QGeoPath & other)757 QGeoPathEager::QGeoPathEager(const QGeoPath &other) : QGeoPath()
758 {
759     initPathConversions();
760     d_ptr = new QGeoPathPrivateEager;
761     setPath(other.path());
762     setWidth(other.width());
763 }
764 
QGeoPathEager(const QGeoShape & other)765 QGeoPathEager::QGeoPathEager(const QGeoShape &other) : QGeoPath()
766 {
767     initPathConversions();
768     if (other.type() == QGeoShape::PathType)
769         *this = QGeoPathEager(QGeoPath(other));
770     else
771         d_ptr = new QGeoPathPrivateEager;
772 }
773 
~QGeoPathEager()774 QGeoPathEager::~QGeoPathEager() {}
775 
776 QT_END_NAMESPACE
777 
778 
779 
780 
781 
782 
783 
784 
785