Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qgeopath.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qgeopath.h"
6#include "qgeopolygon.h"
7#include "qgeopath_p.h"
8
10#include "qnumeric.h"
12#include "qwebmercator_p.h"
13
15
16#include <QtCore/qmutex.h>
17
18#include <mutex>
19
20QT_BEGIN_NAMESPACE
21
22QT_IMPL_METATYPE_EXTERN(QGeoPath)
23
24constexpr auto kWarningString = u"The path has more elements than fit into an int. "
25 "This can cause errors while querying elements from QML";
26
27/*!
28 \class QGeoPath
29 \inmodule QtPositioning
30 \ingroup QtPositioning-positioning
31 \since 5.9
32
33 \brief The QGeoPath class defines a geographic path.
34
35 The path is defined by an ordered list of \l QGeoCoordinate objects.
36
37 Each two adjacent elements in the path are intended to be connected
38 together by the shortest line segment of constant bearing passing
39 through both elements.
40 This type of connection can cross the dateline in the longitudinal direction,
41 but never crosses the poles.
42
43 This is relevant for the calculation of the bounding box returned by
44 \l QGeoShape::boundingGeoRectangle() for this shape, which will have the latitude of
45 the top left corner set to the maximum latitude in the path point set.
46 Similarly, the latitude of the bottom right corner will be the minimum latitude
47 in the path point set.
48
49 This class is also accessible in QML as \l[QML]{geoPath}.
50
51 A QGeoPath is both invalid and empty if it contains no coordinate.
52
53 \note A default constructed QGeoPath is both invalid and empty as it does not contain any coordinates.
54*/
55
56/*!
57 \property QGeoPath::path
58 \brief This property holds the list of coordinates for the geo path.
59
60 \note The coordinates cannot be processed in place. To change the value
61 of this property, retrieve the complete list of coordinates, process them,
62 and assign the new value to the property.
63*/
64
65inline QGeoPathPrivate *QGeoPath::d_func()
66{
67 return static_cast<QGeoPathPrivate *>(d_ptr.data());
68}
69
70inline const QGeoPathPrivate *QGeoPath::d_func() const
71{
72 return static_cast<const QGeoPathPrivate *>(d_ptr.constData());
73}
74
75/*!
76 Constructs a new, empty geo path.
77*/
78QGeoPath::QGeoPath()
79: QGeoShape(new QGeoPathPrivate())
80{
81}
82
83/*!
84 Constructs a new geo path from a list of coordinates
85 (\a path and \a width).
86*/
87QGeoPath::QGeoPath(const QList<QGeoCoordinate> &path, const qreal &width)
88: QGeoShape(new QGeoPathPrivate(path, width))
89{
90}
91
92/*!
93 Constructs a new geo path from the contents of \a other.
94*/
95QGeoPath::QGeoPath(const QGeoPath &other)
96: QGeoShape(other)
97{
98}
99
100/*!
101 Constructs a new geo path from the contents of \a other.
102*/
103QGeoPath::QGeoPath(const QGeoShape &other)
104: QGeoShape(other)
105{
106 if (type() != QGeoShape::PathType)
107 d_ptr = new QGeoPathPrivate();
108}
109
110/*!
111 Destroys this path.
112*/
113QGeoPath::~QGeoPath() {}
114
115/*!
116 Assigns \a other to this geo path and returns a reference to this geo path.
117*/
118QGeoPath &QGeoPath::operator=(const QGeoPath &other)
119{
120 QGeoShape::operator=(other);
121 return *this;
122}
123
124/*!
125 Sets all the elements of the \a path.
126*/
127void QGeoPath::setPath(const QList<QGeoCoordinate> &path)
128{
129 Q_D(QGeoPath);
130 return d->setPath(path);
131}
132
133/*!
134 Returns all the elements of the path.
135*/
136const QList<QGeoCoordinate> &QGeoPath::path() const
137{
138 Q_D(const QGeoPath);
139 return d->path();
140}
141
142/*!
143 Clears the path.
144
145 \since 5.12
146*/
147void QGeoPath::clearPath()
148{
149 Q_D(QGeoPath);
150 d->clearPath();
151}
152
153/*!
154 Sets all the elements of the path.
155
156 \internal
157*/
158void QGeoPath::setVariantPath(const QVariantList &path)
159{
160 Q_D(QGeoPath);
161 QList<QGeoCoordinate> p;
162 for (const auto &c: path) {
163 if (c.canConvert<QGeoCoordinate>())
164 p << c.value<QGeoCoordinate>();
165 }
166 d->setPath(p);
167}
168/*!
169 Returns all the elements of the path.
170
171 \internal
172*/
173QVariantList QGeoPath::variantPath() const
174{
175 Q_D(const QGeoPath);
176 QVariantList p;
177 for (const auto &c: d->path())
178 p << QVariant::fromValue(c);
179 return p;
180}
181
182
183/*!
184 \property QGeoPath::width
185
186 \brief the width of the path in meters.
187*/
188void QGeoPath::setWidth(const qreal &width)
189{
190 Q_D(QGeoPath);
191 d->setWidth(width);
192}
193
194/*!
195 Returns the width of the path, in meters. This information is used in the \l contains method.
196 The default value is 0.
197*/
198qreal QGeoPath::width() const
199{
200 Q_D(const QGeoPath);
201 return d->width();
202}
203
204/*!
205 Translates this geo path by \a degreesLatitude northwards and \a degreesLongitude eastwards.
206
207 Negative values of \a degreesLatitude and \a degreesLongitude correspond to
208 southward and westward translation respectively.
209*/
210void QGeoPath::translate(double degreesLatitude, double degreesLongitude)
211{
212 Q_D(QGeoPath);
213 d->translate(degreesLatitude, degreesLongitude);
214}
215
216/*!
217 Returns a copy of this geo path translated by \a degreesLatitude northwards and
218 \a degreesLongitude eastwards.
219
220 Negative values of \a degreesLatitude and \a degreesLongitude correspond to
221 southward and westward translation respectively.
222
223 \sa translate()
224*/
225QGeoPath QGeoPath::translated(double degreesLatitude, double degreesLongitude) const
226{
227 QGeoPath result(*this);
228 result.translate(degreesLatitude, degreesLongitude);
229 return result;
230}
231
232/*!
233 Returns the length of the path, in meters, from the element \a indexFrom to the element \a indexTo.
234 The length is intended to be the sum of the shortest distances for each pair of adjacent points.
235
236 If \a indexTo is -1 (the default value), the length will be including the distance between last coordinate
237 and the first (closed loop).
238 To retrieve the length for the path, use 0 for \a indexFrom and \l QGeoPath::size() - 1 for \a indexTo.
239*/
240double QGeoPath::length(qsizetype indexFrom, qsizetype indexTo) const
241{
242 Q_D(const QGeoPath);
243 return d->length(indexFrom, indexTo);
244}
245
246/*!
247 Returns the number of elements in the path.
248
249 \since 5.10
250*/
251qsizetype QGeoPath::size() const
252{
253 Q_D(const QGeoPath);
254 const qsizetype result = d->size();
255 if (result > std::numeric_limits<int>::max())
256 qWarning() << kWarningString;
257 return result;
258}
259
260/*!
261 Appends \a coordinate to the path.
262*/
263void QGeoPath::addCoordinate(const QGeoCoordinate &coordinate)
264{
265 Q_D(QGeoPath);
266 d->addCoordinate(coordinate);
267 if (d->size() > std::numeric_limits<int>::max())
268 qWarning() << kWarningString;
269}
270
271/*!
272 Inserts \a coordinate at the specified \a index.
273*/
274void QGeoPath::insertCoordinate(qsizetype index, const QGeoCoordinate &coordinate)
275{
276 Q_D(QGeoPath);
277 d->insertCoordinate(index, coordinate);
278}
279
280/*!
281 Replaces the path element at the specified \a index with \a coordinate.
282*/
283void QGeoPath::replaceCoordinate(qsizetype index, const QGeoCoordinate &coordinate)
284{
285 Q_D(QGeoPath);
286 d->replaceCoordinate(index, coordinate);
287}
288
289/*!
290 Returns the coordinate at \a index .
291*/
292QGeoCoordinate QGeoPath::coordinateAt(qsizetype index) const
293{
294 Q_D(const QGeoPath);
295 return d->coordinateAt(index);
296}
297
298/*!
299 Returns true if the path contains \a coordinate as one of the elements.
300*/
301bool QGeoPath::containsCoordinate(const QGeoCoordinate &coordinate) const
302{
303 Q_D(const QGeoPath);
304 return d->containsCoordinate(coordinate);
305}
306
307/*!
308 Removes the last occurrence of \a coordinate from the path.
309*/
310void QGeoPath::removeCoordinate(const QGeoCoordinate &coordinate)
311{
312 Q_D(QGeoPath);
313 d->removeCoordinate(coordinate);
314}
315
316/*!
317 Removes element at position \a index from the path.
318*/
319void QGeoPath::removeCoordinate(qsizetype index)
320{
321 Q_D(QGeoPath);
322 d->removeCoordinate(index);
323}
324
325/*!
326 Returns the geo path properties as a string.
327*/
328QString QGeoPath::toString() const
329{
330 if (type() != QGeoShape::PathType) {
331 qWarning("Not a path");
332 return QStringLiteral("QGeoPath(not a path)");
333 }
334
335 QString pathString;
336 for (const auto &p : path())
337 pathString += p.toString() + QLatin1Char(',');
338
339 return QStringLiteral("QGeoPath([ %1 ])").arg(pathString);
340}
341
342/*******************************************************************************
343 *
344 * QGeoPathPrivateBase & friends
345 *
346*******************************************************************************/
347
348Q_CONSTINIT static QBasicMutex globalPathMutex;
349
350QGeoPathPrivateBase::QGeoPathPrivateBase()
351 : QGeoShapePrivate(QGeoShape::PathType)
352{
353}
354
355QGeoPathPrivateBase::QGeoPathPrivateBase(const QList<QGeoCoordinate> &path)
356 : QGeoPathPrivateBase()
357{
358 setPath(path);
359}
360
361QGeoPathPrivateBase::QGeoPathPrivateBase(const QGeoPathPrivateBase &other)
362 : QGeoShapePrivate(other),
363 m_path(other.m_path)
364{
365 // Do not copy cached members: they would need mutex locked!
366 // m_dirty is set to true by default, so that it'll properly trigger
367 // re-evaluation when needed.
368}
369
370QGeoPathPrivateBase::~QGeoPathPrivateBase()
371{
372}
373
374bool QGeoPathPrivateBase::isValid() const
375{
376 return !isEmpty();
377}
378
379bool QGeoPathPrivateBase::isEmpty() const
380{
381 return path().isEmpty(); // this should perhaps return geometric emptiness, less than 2 points for line, or empty polygon for polygons
382}
383
384QGeoCoordinate QGeoPathPrivateBase::center() const
385{
386 return boundingGeoRectangle().center();
387}
388
389bool QGeoPathPrivateBase::operator==(const QGeoShapePrivate &other) const
390{
391 if (!QGeoShapePrivate::operator==(other)) // checks type
392 return false;
393
394 const QGeoPathPrivateBase &otherBase = static_cast<const QGeoPathPrivateBase &>(other);
395 return m_path == otherBase.m_path;
396}
397
398QGeoRectangle QGeoPathPrivateBase::boundingGeoRectangle() const
399{
400 ensureBoundingBoxUpdated();
401 return m_bbox;
402}
403
404size_t QGeoPathPrivateBase::hash(size_t seed) const
405{
406 return qHashRange(m_path.cbegin(), m_path.cend(), seed);
407}
408
409const QList<QGeoCoordinate> &QGeoPathPrivateBase::path() const
410{
411 return m_path;
412}
413
414double QGeoPathPrivateBase::length(qsizetype indexFrom, qsizetype indexTo) const
415{
416 if (path().isEmpty())
417 return 0.0;
418
419 bool wrap = indexTo == -1;
420 if (indexTo < 0 || indexTo >= path().size())
421 indexTo = path().size() - 1;
422 double len = 0.0;
423 // TODO: consider calculating the length of the actual rhumb line segments
424 // instead of the shortest path from A to B.
425 for (qsizetype i = indexFrom; i < indexTo; i++)
426 len += m_path[i].distanceTo(m_path[i + 1]);
427 if (wrap)
428 len += m_path.last().distanceTo(m_path.first());
429 return len;
430}
431
432qsizetype QGeoPathPrivateBase::size() const
433{
434 return m_path.size();
435}
436
437QGeoCoordinate QGeoPathPrivateBase::coordinateAt(qsizetype index) const
438{
439 if (index < 0 || index >= m_path.size())
440 return QGeoCoordinate();
441
442 return m_path.at(index);
443}
444
445bool QGeoPathPrivateBase::containsCoordinate(const QGeoCoordinate &coordinate) const
446{
447 return m_path.indexOf(coordinate) > -1;
448}
449
450void QGeoPathPrivateBase::translate(double degreesLatitude, double degreesLongitude)
451{
452 // Need min/maxLati, so update bbox
453 QList<double> deltaXs;
454 double minX, maxX, minLati, maxLati;
455 computeBBox(m_path, deltaXs, minX, maxX, minLati, maxLati, m_bbox);
456
457 if (degreesLatitude > 0.0)
458 degreesLatitude = qMin(degreesLatitude, 90.0 - maxLati);
459 else
460 degreesLatitude = qMax(degreesLatitude, -90.0 - minLati);
461 for (QGeoCoordinate &p: m_path) {
462 p.setLatitude(p.latitude() + degreesLatitude);
463 p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude));
464 }
465 m_bbox.translate(degreesLatitude, degreesLongitude);
466
467 m_bboxDirty.store(false, std::memory_order_release);
468}
469
470void QGeoPathPrivateBase::setPath(const QList<QGeoCoordinate> &path)
471{
472 for (const QGeoCoordinate &c: path) {
473 if (!c.isValid())
474 return;
475 }
476 m_path = path;
477 markDirty();
478}
479
480void QGeoPathPrivateBase::clearPath()
481{
482 m_path.clear();
483 markDirty();
484}
485
486void QGeoPathPrivateBase::addCoordinate(const QGeoCoordinate &coordinate)
487{
488 if (!coordinate.isValid())
489 return;
490 m_path.append(coordinate);
491 markDirty();
492}
493
494void QGeoPathPrivateBase::insertCoordinate(qsizetype index, const QGeoCoordinate &coordinate)
495{
496 if (index < 0 || index > m_path.size() || !coordinate.isValid())
497 return;
498 m_path.insert(index, coordinate);
499 markDirty();
500}
501
502void QGeoPathPrivateBase::replaceCoordinate(qsizetype index, const QGeoCoordinate &coordinate)
503{
504 if (index < 0 || index >= m_path.size() || !coordinate.isValid())
505 return;
506 m_path[index] = coordinate;
507 markDirty();
508}
509
510void QGeoPathPrivateBase::removeCoordinate(const QGeoCoordinate &coordinate)
511{
512 qsizetype index = m_path.lastIndexOf(coordinate);
513 removeCoordinate(index);
514}
515
516void QGeoPathPrivateBase::removeCoordinate(qsizetype index)
517{
518 if (index < 0 || index >= m_path.size())
519 return;
520 m_path.removeAt(index);
521 markDirty();
522}
523
524void QGeoPathPrivateBase::markDirty()
525{
526 m_bboxDirty.store(true, std::memory_order_release);
527}
528
529void QGeoPathPrivateBase::ensureBoundingBoxUpdated() const
530{
531 if (m_bboxDirty.load(std::memory_order_acquire)) {
532 const std::scoped_lock lock(globalPathMutex);
533 if (m_bboxDirty.load(std::memory_order_acquire)) {
534 QList<double> deltaXs;
535 double minX, maxX, minLati, maxLati;
536 computeBBox(m_path, deltaXs, minX, maxX, minLati, maxLati, m_bbox);
537 m_bboxDirty.store(false, std::memory_order_release);
538 }
539 }
540}
541
542
543QGeoPathPrivate::QGeoPathPrivate()
544 : QGeoPathPrivateBase()
545{
546}
547
548QGeoPathPrivate::QGeoPathPrivate(const QList<QGeoCoordinate> &path, const qreal width)
549 : QGeoPathPrivateBase(path)
550{
551 setWidth(width);
552}
553
554QGeoPathPrivate::~QGeoPathPrivate()
555{
556}
557
558QGeoShapePrivate *QGeoPathPrivate::clone() const
559{
560 return new QGeoPathPrivate(*this);
561}
562
563bool QGeoPathPrivate::operator==(const QGeoShapePrivate &other) const
564{
565 if (!QGeoPathPrivateBase::operator==(other)) // checks type
566 return false;
567
568 const QGeoPathPrivate &otherPath = static_cast<const QGeoPathPrivate &>(other);
569 return m_width == otherPath.m_width;
570}
571
572bool QGeoPathPrivate::lineContains(const QGeoCoordinate &coordinate) const
573{
574 // Unoptimized approach:
575 // - consider each segment of the path (a rhumb line)
576 // - project it into Mercator space (in which it is straight)
577 // - find Mercator-closest point to coordinate
578 // - unproject the closest point
579 // - calculate coordinate to closest point distance with distanceTo()
580 // - if not within lineRadius, advance to next segment.
581 //
582 // When considering each segment, wrap its start-point to x-within 0.5 of
583 // its end-point and (initially) the target point to x-within the mid-point
584 // of the thus-narrowed segment. That position will usually find the actual
585 // Mercator-closest point and makes it easy to test for the obscure case
586 // where a different wrap-position for it might work better; when that is
587 // possible, try that other wrap-position for it in a second pass.
588
589 double lineRadius = qMax(width() * 0.5, 0.2); // minimum radius: 20cm
590
591 if (m_path.isEmpty())
592 return false;
593 else if (m_path.size() == 1)
594 return (m_path[0].distanceTo(coordinate) <= lineRadius);
595
596 Q_ASSERT(m_path.size() > 1);
597 const QDoubleVector2D pt = QWebMercator::coordToMercator(coordinate);
598 QDoubleVector2D last = QWebMercator::coordToMercator(m_path[0]);
599 for (qsizetype i = 1; i < m_path.size(); i++) {
600 const QDoubleVector2D here = QWebMercator::coordToMercator(m_path[i]);
601 // Wrap last to gets its x() within ±0.5 of that of here:
602 if (here.x() > last.x() + 0.5)
603 last.setX(last.x() + 1.0);
604 else if (here.x() < last.x() - 0.5)
605 last.setX(last.x() - 1.0);
606
607 if (here == last) {
608 // The whole line segment is one point, so easy to test.
609 if (m_path[i].distanceTo(coordinate) <= lineRadius)
610 return true;
611 continue;
612 }
613
614 QDoubleVector2D p = pt;
615 {
616 QDoubleVector2D mid = (last + here) / 2.0;
617 // Wrap p to gets its x() within ±0.5 of that of mid:
618 if (p.x() > mid.x() + 0.5)
619 p.setX(p.x() - 1.0);
620 else if (p.x() < mid.x() - 0.5)
621 p.setX(p.x() + 1.0);
622 }
623 // See comment on updating p after j == 0; loop to catch the corner case.
624 for (int j = 0; j < 2; ++j) {
625 const QDoubleVector2D pml = p - last, hml = here - last;
626 const double u = (pml.x() * hml.x() + pml.y() * hml.y()) / hml.lengthSquared();
627 // Interpolate between 0 < u < 1, use nearer end otherwise:
628 const QDoubleVector2D candidate = u > 0 ? u < 1 ? last + u * hml : here : last;
629 const double distance = coordinate.distanceTo(QWebMercator::mercatorToCoord(candidate));
630 if (distance <= lineRadius)
631 return true;
632
633 if (j == 0) {
634 /* Our initial p's .x() is within 0.5 of mid.x(), hence of at
635 least one of last.x() and here.x(). If it's within 0.5 of
636 both of these, the candidate we just tried is definitely our
637 best bet. Otherwise - though it's very obscure and can't
638 matter unless lineRadius is comparable with the rhumb line's
639 distance from the planet's spin axis - there are technically
640 two parabolic segments p could be in (y-closer to one end but
641 x-closer to the other), that would put p further from
642 last:here than from its more x()-distant end's wrapped
643 version the other side of p. So wrap p to its version that
644 would be closer to that distant end, were this to arise.
645 */
646 if (p.x() > qMin(last.x(), here.x()) + 0.5)
647 p.setX(p.x() - 1.0);
648 else if (p.x() < qMax(last.x(), here.x()) - 0.5)
649 p.setX(p.x() + 1.0);
650 else
651 break;
652 }
653 }
654 // swap
655 last = here;
656 }
657
658 return false;
659}
660
661bool QGeoPathPrivate::contains(const QGeoCoordinate &coordinate) const
662{
663 return lineContains(coordinate);
664}
665
666qreal QGeoPathPrivate::width() const
667{
668 return m_width;
669}
670
671void QGeoPathPrivate::setWidth(const qreal &width)
672{
673 if (qIsNaN(width) || width < 0.0)
674 return;
675 m_width = width;
676}
677
678size_t QGeoPathPrivate::hash(size_t seed) const
679{
680 const size_t res = QGeoPathPrivateBase::hash(seed);
681 return qHashMulti(seed, res, m_width);
682}
683
684QGeoPathPrivateEager::QGeoPathPrivateEager()
685: QGeoPathPrivate()
686{
687 m_bboxDirty.store(false, std::memory_order_relaxed); // never dirty on the eager version
688}
689
690QGeoPathPrivateEager::QGeoPathPrivateEager(const QList<QGeoCoordinate> &path, const qreal width)
691: QGeoPathPrivate(path, width)
692{
693 m_bboxDirty.store(false, std::memory_order_relaxed); // never dirty on the eager version
694 markDirty(); // calculate the cached values
695}
696
697QGeoPathPrivateEager::QGeoPathPrivateEager(const QGeoPathPrivateEager &other)
698 : QGeoPathPrivate(other)
699{
700 m_bboxDirty.store(false, std::memory_order_relaxed); // never dirty on the eager version
701 markDirty(); // calculate the cached values
702}
703
704QGeoPathPrivateEager::~QGeoPathPrivateEager()
705{
706
707}
708
709QGeoShapePrivate *QGeoPathPrivateEager::clone() const
710{
711 return new QGeoPathPrivateEager(*this);
712}
713
714void QGeoPathPrivateEager::markDirty()
715{
716 // do the calculations directly
717 computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
718}
719
720void QGeoPathPrivateEager::translate(double degreesLatitude, double degreesLongitude)
721{
722 if (degreesLatitude > 0.0)
723 degreesLatitude = qMin(degreesLatitude, 90.0 - m_maxLati);
724 else
725 degreesLatitude = qMax(degreesLatitude, -90.0 - m_minLati);
726 for (QGeoCoordinate &p: m_path) {
727 p.setLatitude(p.latitude() + degreesLatitude);
728 p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude));
729 }
730 m_bbox.translate(degreesLatitude, degreesLongitude);
731 m_minLati += degreesLatitude;
732 m_maxLati += degreesLatitude;
733}
734
735void QGeoPathPrivateEager::addCoordinate(const QGeoCoordinate &coordinate)
736{
737 if (!coordinate.isValid())
738 return;
739 m_path.append(coordinate);
740 //m_clipperDirty = true; // clipper not used in polylines
741 updateBoundingBox();
742}
743
744void QGeoPathPrivateEager::QGeoPathPrivateEager::updateBoundingBox()
745{
746 updateBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
747}
748
749QGeoPathEager::QGeoPathEager() : QGeoPath()
750{
751 d_ptr = new QGeoPathPrivateEager;
752}
753
754QGeoPathEager::QGeoPathEager(const QList<QGeoCoordinate> &path, const qreal &width) : QGeoPath()
755{
756 d_ptr = new QGeoPathPrivateEager(path, width);
757}
758
759QGeoPathEager::QGeoPathEager(const QGeoPath &other) : QGeoPath()
760{
761 d_ptr = new QGeoPathPrivateEager;
762 setPath(other.path());
763 setWidth(other.width());
764}
765
766QGeoPathEager::QGeoPathEager(const QGeoShape &other) : QGeoPath()
767{
768 if (other.type() == QGeoShape::PathType)
769 *this = QGeoPathEager(QGeoPath(other));
770 else
771 d_ptr = new QGeoPathPrivateEager;
772}
773
774QGeoPathEager::~QGeoPathEager() {}
775
776QT_END_NAMESPACE
777
778#include "moc_qgeopath_p.cpp"
779#include "moc_qgeopath.cpp"
\inmodule QtPositioning
Definition qgeopath.h:17
QT_BEGIN_NAMESPACE constexpr auto kWarningString
Definition qgeopath.cpp:24