Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
4#include "qgeopath.h"
5#include "qgeopolygon.h"
6#include "qgeopath_p.h"
7
8#include "qgeocoordinate.h"
9#include "qnumeric.h"
10#include "qlocationutils_p.h"
11#include "qwebmercator_p.h"
12
13#include "qdoublevector2d_p.h"
14#include "qdoublevector3d_p.h"
16
18
19constexpr auto kWarningString = u"The path has more elements than fit into an int. "
20 "This can cause errors while querying elements from QML";
21
61inline QGeoPathPrivate *QGeoPath::d_func()
62{
63 return static_cast<QGeoPathPrivate *>(d_ptr.data());
64}
65
66inline const QGeoPathPrivate *QGeoPath::d_func() const
67{
68 return static_cast<const QGeoPathPrivate *>(d_ptr.constData());
69}
70
78
83QGeoPath::QGeoPath(const QList<QGeoCoordinate> &path, const qreal &width)
85{
86}
87
95
105
110
115{
117 return *this;
118}
119
123void QGeoPath::setPath(const QList<QGeoCoordinate> &path)
124{
125 Q_D(QGeoPath);
126 return d->setPath(path);
127}
128
132const QList<QGeoCoordinate> &QGeoPath::path() const
133{
134 Q_D(const QGeoPath);
135 return d->path();
136}
137
144{
145 Q_D(QGeoPath);
146 d->clearPath();
147}
148
155{
156 Q_D(QGeoPath);
157 QList<QGeoCoordinate> p;
158 for (const auto &c: path) {
159 if (c.canConvert<QGeoCoordinate>())
160 p << c.value<QGeoCoordinate>();
161 }
162 d->setPath(p);
163}
170{
171 Q_D(const QGeoPath);
173 for (const auto &c: d->path())
175 return p;
176}
177
178
185{
186 Q_D(QGeoPath);
187 d->setWidth(width);
188}
189
195{
196 Q_D(const QGeoPath);
197 return d->width();
198}
199
206void QGeoPath::translate(double degreesLatitude, double degreesLongitude)
207{
208 Q_D(QGeoPath);
209 d->translate(degreesLatitude, degreesLongitude);
210}
211
221QGeoPath QGeoPath::translated(double degreesLatitude, double degreesLongitude) const
222{
223 QGeoPath result(*this);
224 result.translate(degreesLatitude, degreesLongitude);
225 return result;
226}
227
236double QGeoPath::length(qsizetype indexFrom, qsizetype indexTo) const
237{
238 Q_D(const QGeoPath);
239 return d->length(indexFrom, indexTo);
240}
241
248{
249 Q_D(const QGeoPath);
250 const qsizetype result = d->size();
251 if (result > std::numeric_limits<int>::max())
253 return result;
254}
255
260{
261 Q_D(QGeoPath);
262 d->addCoordinate(coordinate);
263 if (d->size() > std::numeric_limits<int>::max())
265}
266
271{
272 Q_D(QGeoPath);
273 d->insertCoordinate(index, coordinate);
274}
275
280{
281 Q_D(QGeoPath);
282 d->replaceCoordinate(index, coordinate);
283}
284
289{
290 Q_D(const QGeoPath);
291 return d->coordinateAt(index);
292}
293
297bool QGeoPath::containsCoordinate(const QGeoCoordinate &coordinate) const
298{
299 Q_D(const QGeoPath);
300 return d->containsCoordinate(coordinate);
301}
302
307{
308 Q_D(QGeoPath);
309 d->removeCoordinate(coordinate);
310}
311
316{
317 Q_D(QGeoPath);
318 d->removeCoordinate(index);
319}
320
325{
326 if (type() != QGeoShape::PathType) {
327 qWarning("Not a path");
328 return QStringLiteral("QGeoPath(not a path)");
329 }
330
332 for (const auto &p : path())
333 pathString += p.toString() + QLatin1Char(',');
334
335 return QStringLiteral("QGeoPath([ %1 ])").arg(pathString);
336}
337
338/*******************************************************************************
339 *
340 * QGeoPathPrivate & friends
341 *
342*******************************************************************************/
343
349
350QGeoPathPrivate::QGeoPathPrivate(const QList<QGeoCoordinate> &path, const qreal width)
351: QGeoShapePrivate(QGeoShape::PathType)
352{
353 setPath(path);
355}
356
361
363{
364 return new QGeoPathPrivate(*this);
365}
366
368{
369 return !isEmpty();
370}
371
373{
374 return path().isEmpty(); // this should perhaps return geometric emptiness, less than 2 points for line, or empty polygon for polygons
375}
376
378{
379 return boundingGeoRectangle().center();
380}
381
383{
384 if (!QGeoShapePrivate::operator==(other))
385 return false;
386
387 const QGeoPathPrivate &otherPath = static_cast<const QGeoPathPrivate &>(other);
388 if (m_path.size() != otherPath.m_path.size())
389 return false;
390 return m_width == otherPath.m_width && m_path == otherPath.m_path;
391}
392
393const QList<QGeoCoordinate> &QGeoPathPrivate::path() const
394{
395 return m_path;
396}
397
399{
400 // Unoptimized approach:
401 // - consider each segment of the path
402 // - project it into mercator space (rhumb lines are straight in mercator space)
403 // - find closest point to coordinate
404 // - unproject the closest point
405 // - calculate coordinate to closest point distance with distanceTo()
406 // - if not within lineRadius, advance
407 //
408 // To keep wrapping into the equation:
409 // If the mercator x value of a coordinate of the line, or the coordinate parameter, is less
410 // than mercator(m_bbox).x, add that to the conversion.
411
412 if (m_bboxDirty)
413 const_cast<QGeoPathPrivate &>(*this).computeBoundingBox();
414
415 double lineRadius = qMax(width() * 0.5, 0.2); // minimum radius: 20cm
416
417 if (m_path.isEmpty())
418 return false;
419 else if (m_path.size() == 1)
420 return (m_path[0].distanceTo(coordinate) <= lineRadius);
421
423 if (p.x() < m_leftBoundWrapped)
424 p.setX(p.x() + m_leftBoundWrapped); // unwrap X
425
428 if (!m_path.isEmpty()) {
430 if (a.x() < m_leftBoundWrapped)
431 a.setX(a.x() + m_leftBoundWrapped); // unwrap X
432 }
433 for (qsizetype i = 1; i < m_path.size(); i++) {
435 if (b.x() < m_leftBoundWrapped)
436 b.setX(b.x() + m_leftBoundWrapped); // unwrap X
437 if (b == a)
438 continue;
439
440 double u = ((p.x() - a.x()) * (b.x() - a.x()) + (p.y() - a.y()) * (b.y() - a.y()) ) / (b - a).lengthSquared();
441 QDoubleVector2D intersection(a.x() + u * (b.x() - a.x()) , a.y() + u * (b.y() - a.y()) );
442
443 QDoubleVector2D candidate = ( (p-a).length() < (p-b).length() ) ? a : b;
444
445 if (u > 0 && u < 1
446 && (p-intersection).length() < (p-candidate).length() ) // And it falls in the segment
447 candidate = intersection;
448
449
450 if (candidate.x() > 1.0)
451 candidate.setX(candidate.x() - m_leftBoundWrapped); // wrap X
452
454
455 double distanceMeters = coordinate.distanceTo(closest);
456 if (distanceMeters <= lineRadius)
457 return true;
458
459 // swap
460 a = b;
461 }
462
463 // Last check if the coordinate is on the left of leftBoundMercator, but close enough to
464 // m_path[0]
465 return (m_path[0].distanceTo(coordinate) <= lineRadius);
466}
467
468bool QGeoPathPrivate::contains(const QGeoCoordinate &coordinate) const
469{
470 return lineContains(coordinate);
471}
472
474{
475 return m_width;
476}
477
479{
480 if (qIsNaN(width) || width < 0.0)
481 return;
482 m_width = width;
483}
484
485double QGeoPathPrivate::length(qsizetype indexFrom, qsizetype indexTo) const
486{
487 if (path().isEmpty())
488 return 0.0;
489
490 bool wrap = indexTo == -1;
491 if (indexTo < 0 || indexTo >= path().size())
492 indexTo = path().size() - 1;
493 double len = 0.0;
494 // TODO: consider calculating the length of the actual rhumb line segments
495 // instead of the shortest path from A to B.
496 for (qsizetype i = indexFrom; i < indexTo; i++)
497 len += m_path[i].distanceTo(m_path[i+1]);
498 if (wrap)
500 return len;
501}
502
504{
505 return m_path.size();
506}
507
509{
510 if (index < 0 || index >= m_path.size())
511 return QGeoCoordinate();
512
513 return m_path.at(index);
514}
515
517{
518 return m_path.indexOf(coordinate) > -1;
519}
520
521void QGeoPathPrivate::translate(double degreesLatitude, double degreesLongitude)
522{
523 // Need min/maxLati, so update bbox
524 QList<double> m_deltaXs;
525 double m_minX, m_maxX, m_minLati, m_maxLati;
526 m_bboxDirty = false;
527 computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
528
529 if (degreesLatitude > 0.0)
530 degreesLatitude = qMin(degreesLatitude, 90.0 - m_maxLati);
531 else
532 degreesLatitude = qMax(degreesLatitude, -90.0 - m_minLati);
533 for (QGeoCoordinate &p: m_path) {
534 p.setLatitude(p.latitude() + degreesLatitude);
535 p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude));
536 }
537 m_bbox.translate(degreesLatitude, degreesLongitude);
539}
540
542{
543 if (m_bboxDirty)
544 const_cast<QGeoPathPrivate &>(*this).computeBoundingBox();
545 return m_bbox;
546}
547
548size_t QGeoPathPrivate::hash(size_t seed) const
549{
550 const size_t res = qHashRange(m_path.cbegin(), m_path.cend(), seed);
551 return qHashMulti(seed, res, m_width);
552}
553
554void QGeoPathPrivate::setPath(const QList<QGeoCoordinate> &path)
555{
556 for (const QGeoCoordinate &c: path)
557 if (!c.isValid())
558 return;
559 m_path = path;
560 markDirty();
561}
562
564{
565 m_path.clear();
566 markDirty();
567}
568
570{
571 if (!coordinate.isValid())
572 return;
573 m_path.append(coordinate);
574 markDirty();
575}
576
578{
579 if (index < 0 || index > m_path.size() || !coordinate.isValid())
580 return;
581 m_path.insert(index, coordinate);
582 markDirty();
583}
584
586{
587 if (index < 0 || index >= m_path.size() || !coordinate.isValid())
588 return;
589 m_path[index] = coordinate;
590 markDirty();
591}
592
598
600{
601 if (index < 0 || index >= m_path.size())
602 return;
604 markDirty();
605}
606
608{
609 m_bboxDirty = true;
610}
611
613{
614 QList<double> m_deltaXs;
615 double m_minX, m_maxX, m_minLati, m_maxLati;
616 m_bboxDirty = false;
617 computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
619}
620
623{
624 m_bboxDirty = false; // never dirty on the eager version
625}
626
627QGeoPathPrivateEager::QGeoPathPrivateEager(const QList<QGeoCoordinate> &path, const qreal width)
629{
630 m_bboxDirty = false; // never dirty on the eager version
631}
632
637
639{
640 return new QGeoPathPrivateEager(*this);
641}
642
647
648void QGeoPathPrivateEager::translate(double degreesLatitude, double degreesLongitude)
649{
650 if (degreesLatitude > 0.0)
651 degreesLatitude = qMin(degreesLatitude, 90.0 - m_maxLati);
652 else
653 degreesLatitude = qMax(degreesLatitude, -90.0 - m_minLati);
654 for (QGeoCoordinate &p: m_path) {
655 p.setLatitude(p.latitude() + degreesLatitude);
656 p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude));
657 }
658 m_bbox.translate(degreesLatitude, degreesLongitude);
659 m_minLati += degreesLatitude;
660 m_maxLati += degreesLatitude;
662}
663
665{
666 if (!coordinate.isValid())
667 return;
668 m_path.append(coordinate);
669 //m_clipperDirty = true; // clipper not used in polylines
671}
672
673void QGeoPathPrivateEager::QGeoPathPrivateEager::computeBoundingBox()
674{
675 computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
676 m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
677}
678
679void QGeoPathPrivateEager::QGeoPathPrivateEager::updateBoundingBox()
680{
681 updateBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
682 m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
683}
684
689
690QGeoPathEager::QGeoPathEager(const QList<QGeoCoordinate> &path, const qreal &width) : QGeoPath()
691{
693}
694
696{
698 setPath(other.path());
699 setWidth(other.width());
700}
701
703{
704 if (other.type() == QGeoShape::PathType)
705 *this = QGeoPathEager(QGeoPath(other));
706 else
708}
709
711
713
714#include "moc_qgeopath_p.cpp"
715#include "moc_qgeopath.cpp"
716
717
718
719
720
721
722
void setX(double x)
Q_DECL_CONSTEXPR double x() const
\inmodule QtPositioning
Q_INVOKABLE qreal distanceTo(const QGeoCoordinate &other) const
Returns the distance (in meters) from this coordinate to the coordinate specified by other.
bool isValid
This property holds the validity of this geo coordinate.
virtual void computeBoundingBox() override
virtual void translate(double degreesLatitude, double degreesLongitude) override
Definition qgeopath.cpp:648
virtual QGeoShapePrivate * clone() const override
Definition qgeopath.cpp:638
virtual void markDirty() override
Definition qgeopath.cpp:643
virtual void addCoordinate(const QGeoCoordinate &coordinate) override
Definition qgeopath.cpp:664
virtual qreal width() const
Definition qgeopath.cpp:473
virtual qsizetype size() const
Definition qgeopath.cpp:503
virtual QGeoCoordinate coordinateAt(qsizetype index) const
Definition qgeopath.cpp:508
virtual bool containsCoordinate(const QGeoCoordinate &coordinate) const
Definition qgeopath.cpp:516
virtual void insertCoordinate(qsizetype index, const QGeoCoordinate &coordinate)
Definition qgeopath.cpp:577
virtual bool contains(const QGeoCoordinate &coordinate) const override
Definition qgeopath.cpp:468
virtual void clearPath()
Definition qgeopath.cpp:563
QList< QGeoCoordinate > m_path
Definition qgeopath_p.h:175
virtual void translate(double degreesLatitude, double degreesLongitude)
Definition qgeopath.cpp:521
QGeoRectangle m_bbox
Definition qgeopath_p.h:177
virtual void replaceCoordinate(qsizetype index, const QGeoCoordinate &coordinate)
Definition qgeopath.cpp:585
virtual void addCoordinate(const QGeoCoordinate &coordinate)
Definition qgeopath.cpp:569
virtual QGeoCoordinate center() const override
Definition qgeopath.cpp:377
virtual double length(qsizetype indexFrom, qsizetype indexTo) const
Definition qgeopath.cpp:485
virtual void markDirty()
Definition qgeopath.cpp:607
virtual QGeoShapePrivate * clone() const override
Definition qgeopath.cpp:362
virtual void setPath(const QList< QGeoCoordinate > &path)
Definition qgeopath.cpp:554
virtual void setWidth(const qreal &width)
Definition qgeopath.cpp:478
virtual void removeCoordinate(const QGeoCoordinate &coordinate)
Definition qgeopath.cpp:593
size_t hash(size_t seed) const override
Definition qgeopath.cpp:548
virtual bool isValid() const override
Definition qgeopath.cpp:367
virtual void computeBoundingBox()
Definition qgeopath.cpp:612
virtual const QList< QGeoCoordinate > & path() const
Definition qgeopath.cpp:393
virtual bool lineContains(const QGeoCoordinate &coordinate) const
Definition qgeopath.cpp:398
virtual bool operator==(const QGeoShapePrivate &other) const override
Definition qgeopath.cpp:382
double m_leftBoundWrapped
Definition qgeopath_p.h:178
virtual QGeoRectangle boundingGeoRectangle() const override
Definition qgeopath.cpp:541
virtual bool isEmpty() const override
Definition qgeopath.cpp:372
\inmodule QtPositioning
Definition qgeopath.h:16
Q_INVOKABLE QGeoCoordinate coordinateAt(qsizetype index) const
Returns the coordinate at index .
Definition qgeopath.cpp:288
Q_INVOKABLE void insertCoordinate(qsizetype index, const QGeoCoordinate &coordinate)
Inserts coordinate at the specified index.
Definition qgeopath.cpp:270
Q_INVOKABLE qsizetype size() const
Returns the number of elements in the path.
Definition qgeopath.cpp:247
void setPath(const QList< QGeoCoordinate > &path)
Sets all the elements of the path.
Definition qgeopath.cpp:123
Q_INVOKABLE void translate(double degreesLatitude, double degreesLongitude)
Translates this geo path by degreesLatitude northwards and degreesLongitude eastwards.
Definition qgeopath.cpp:206
Q_INVOKABLE double length(qsizetype indexFrom=0, qsizetype indexTo=-1) const
Returns the length of the path, in meters, from the element indexFrom to the element indexTo.
Definition qgeopath.cpp:236
QVariantList variantPath() const
Returns all the elements of the path.
Definition qgeopath.cpp:169
void setVariantPath(const QVariantList &path)
Sets all the elements of the path.
Definition qgeopath.cpp:154
Q_INVOKABLE void removeCoordinate(const QGeoCoordinate &coordinate)
Removes the last occurrence of coordinate from the path.
Definition qgeopath.cpp:306
QGeoPath()
Constructs a new, empty geo path.
Definition qgeopath.cpp:74
qreal width
the width of the path in meters.
Definition qgeopath.h:19
QGeoPath & operator=(const QGeoPath &other)
Assigns other to this geo path and returns a reference to this geo path.
Definition qgeopath.cpp:114
Q_INVOKABLE bool containsCoordinate(const QGeoCoordinate &coordinate) const
Returns true if the path contains coordinate as one of the elements.
Definition qgeopath.cpp:297
Q_INVOKABLE void addCoordinate(const QGeoCoordinate &coordinate)
Appends coordinate to the path.
Definition qgeopath.cpp:259
void clearPath()
Clears the path.
Definition qgeopath.cpp:143
QVariantList path
This property holds the list of coordinates for the geo path.
Definition qgeopath.h:18
Q_INVOKABLE void replaceCoordinate(qsizetype index, const QGeoCoordinate &coordinate)
Replaces the path element at the specified index with coordinate.
Definition qgeopath.cpp:279
~QGeoPath()
Destroys this path.
Definition qgeopath.cpp:109
void setWidth(const qreal &width)
Definition qgeopath.cpp:184
Q_INVOKABLE QGeoPath translated(double degreesLatitude, double degreesLongitude) const
Returns a copy of this geo path translated by degreesLatitude northwards and degreesLongitude eastwar...
Definition qgeopath.cpp:221
Q_INVOKABLE QString toString() const
Returns the geo path properties as a string.
Definition qgeopath.cpp:324
\inmodule QtPositioning
QGeoCoordinate topLeft
This property holds the top left coordinate of this geo rectangle.
Q_INVOKABLE void translate(double degreesLatitude, double degreesLongitude)
Translates this geo rectangle by degreesLatitude northwards and degreesLongitude eastwards.
\inmodule QtPositioning
Definition qgeoshape.h:17
QGeoShape & operator=(const QGeoShape &other)
Assigns other to this geo shape and returns a reference to this geo shape.
QSharedDataPointer< QGeoShapePrivate > d_ptr
Definition qgeoshape.h:61
ShapeType type
This property holds the type of this geo shape.
Definition qgeoshape.h:19
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
T & first()
Definition qlist.h:645
T & last()
Definition qlist.h:648
void removeAt(qsizetype i)
Definition qlist.h:590
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:488
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
const_iterator cend() const noexcept
Definition qlist.h:631
void append(parameter_type t)
Definition qlist.h:458
const_iterator cbegin() const noexcept
Definition qlist.h:630
void clear()
Definition qlist.h:434
static double wrapLong(double lng)
const T * constData() const noexcept
Returns a const pointer to the shared data object.
Definition qshareddata.h:51
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
static QDoubleVector2D coordToMercator(const QGeoCoordinate &coord)
static QGeoCoordinate mercatorToCoord(const QDoubleVector2D &mercator)
while(i.hasNext()) QString s
Combined button and popup list for selecting options.
bool qIsNaN(qfloat16 f) noexcept
Definition qfloat16.h:284
QT_BEGIN_NAMESPACE constexpr auto kWarningString
Definition qgeopath.cpp:19
static void updateBBox(const QList< QGeoCoordinate > &m_path, QList< double > &m_deltaXs, double &m_minX, double &m_maxX, double &m_minLati, double &m_maxLati, QGeoRectangle &m_bbox)
Definition qgeopath_p.h:79
static QT_BEGIN_NAMESPACE void computeBBox(const QList< QGeoCoordinate > &m_path, QList< double > &m_deltaXs, double &m_minX, double &m_maxX, double &m_minLati, double &m_maxLati, QGeoRectangle &m_bbox)
Definition qgeopath_p.h:27
size_t qHashRange(InputIterator first, InputIterator last, size_t seed=0) noexcept(noexcept(qHash(*first)))
constexpr QtPrivate::QHashMultiReturnType< T... > qHashMulti(size_t seed, const T &... args) noexcept(std::conjunction_v< QtPrivate::QNothrowHashable< T >... >)
#define qWarning
Definition qlogging.h:166
#define QT_IMPL_METATYPE_EXTERN(TYPE)
Definition qmetatype.h:1390
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLenum GLuint GLenum GLsizei length
GLenum GLsizei const void * pathString
GLint GLsizei width
GLuint res
const GLubyte * c
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLenum GLsizei len
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
static QT_BEGIN_NAMESPACE QAsn1Element wrap(quint8 type, const QAsn1Element &child)
#define QStringLiteral(str)
static const QTextHtmlElement elements[Html_NumElements]
ptrdiff_t qsizetype
Definition qtypes.h:165
double qreal
Definition qtypes.h:187
QSharedPointer< T > other(t)
[5]
\inmodule QtCore \reentrant
Definition qchar.h:18
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition qlist.h:962
qsizetype lastIndexOf(const AT &t, qsizetype from=-1) const noexcept
Definition qlist.h:969