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