summaryrefslogtreecommitdiffstats
path: root/src/positioning/qgeopath.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/positioning/qgeopath.cpp')
-rw-r--r--src/positioning/qgeopath.cpp774
1 files changed, 0 insertions, 774 deletions
diff --git a/src/positioning/qgeopath.cpp b/src/positioning/qgeopath.cpp
deleted file mode 100644
index 4d6b1af2..00000000
--- a/src/positioning/qgeopath.cpp
+++ /dev/null
@@ -1,774 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtPositioning module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qgeopath.h"
-#include "qgeopolygon.h"
-#include "qgeopath_p.h"
-
-#include "qgeocoordinate.h"
-#include "qnumeric.h"
-#include "qlocationutils_p.h"
-#include "qwebmercator_p.h"
-
-#include "qdoublevector2d_p.h"
-#include "qdoublevector3d_p.h"
-QT_BEGIN_NAMESPACE
-
-constexpr int kMaxInt = std::numeric_limits<int>::max();
-constexpr auto kWarningString = u"The path has more elements than fit into an int. "
- "This can cause errors while querying elements from QML";
-
-/*!
- \class QGeoPath
- \inmodule QtPositioning
- \ingroup QtPositioning-positioning
- \since 5.9
-
- \brief The QGeoPath class defines a geographic path.
-
- The path is defined by an ordered list of \l QGeoCoordinate objects.
-
- Each two adjacent elements in the path are intended to be connected
- together by the shortest line segment of constant bearing passing
- through both elements.
- This type of connection can cross the dateline in the longitudinal direction,
- but never crosses the poles.
-
- This is relevant for the calculation of the bounding box returned by
- \l QGeoShape::boundingGeoRectangle() for this shape, which will have the latitude of
- the top left corner set to the maximum latitude in the path point set.
- Similarly, the latitude of the bottom right corner will be the minimum latitude
- in the path point set.
-
- This class is a \l Q_GADGET.
- It can be \l{Cpp_value_integration_positioning}{directly used from C++ and QML}.
-
- A QGeoPath is both invalid and empty if it contains no coordinate.
-
- \note A default constructed QGeoPath is both invalid and empty as it does not contain any coordinates.
-*/
-
-/*!
- \property QGeoPath::path
- \brief This property holds the list of coordinates for the geo path.
-
- \note The coordinates cannot be processed in place. To change the value
- of this property, retrieve the complete list of coordinates, process them,
- and assign the new value to the property.
-*/
-
-inline QGeoPathPrivate *QGeoPath::d_func()
-{
- return static_cast<QGeoPathPrivate *>(d_ptr.data());
-}
-
-inline const QGeoPathPrivate *QGeoPath::d_func() const
-{
- return static_cast<const QGeoPathPrivate *>(d_ptr.constData());
-}
-
-struct PathVariantConversions
-{
- PathVariantConversions()
- {
- QMetaType::registerConverter<QGeoShape, QGeoPath>();
- QMetaType::registerConverter<QGeoPath, QGeoShape>();
- }
-};
-
-Q_GLOBAL_STATIC(PathVariantConversions, initPathConversions)
-
-/*!
- Constructs a new, empty geo path.
-*/
-QGeoPath::QGeoPath()
-: QGeoShape(new QGeoPathPrivate())
-{
- initPathConversions();
-}
-
-/*!
- Constructs a new geo path from a list of coordinates
- (\a path and \a width).
-*/
-QGeoPath::QGeoPath(const QList<QGeoCoordinate> &path, const qreal &width)
-: QGeoShape(new QGeoPathPrivate(path, width))
-{
- initPathConversions();
-}
-
-/*!
- Constructs a new geo path from the contents of \a other.
-*/
-QGeoPath::QGeoPath(const QGeoPath &other)
-: QGeoShape(other)
-{
- initPathConversions();
-}
-
-/*!
- Constructs a new geo path from the contents of \a other.
-*/
-QGeoPath::QGeoPath(const QGeoShape &other)
-: QGeoShape(other)
-{
- initPathConversions();
- if (type() != QGeoShape::PathType)
- d_ptr = new QGeoPathPrivate();
-}
-
-/*!
- Destroys this path.
-*/
-QGeoPath::~QGeoPath() {}
-
-/*!
- Assigns \a other to this geo path and returns a reference to this geo path.
-*/
-QGeoPath &QGeoPath::operator=(const QGeoPath &other)
-{
- QGeoShape::operator=(other);
- return *this;
-}
-
-/*!
- Sets all the elements of the \a path.
-*/
-void QGeoPath::setPath(const QList<QGeoCoordinate> &path)
-{
- Q_D(QGeoPath);
- return d->setPath(path);
-}
-
-/*!
- Returns all the elements of the path.
-*/
-const QList<QGeoCoordinate> &QGeoPath::path() const
-{
- Q_D(const QGeoPath);
- return d->path();
-}
-
-/*!
- Clears the path.
-
- \since 5.12
-*/
-void QGeoPath::clearPath()
-{
- Q_D(QGeoPath);
- d->clearPath();
-}
-
-/*!
- Sets all the elements of the path.
-
- \internal
-*/
-void QGeoPath::setVariantPath(const QVariantList &path)
-{
- Q_D(QGeoPath);
- QList<QGeoCoordinate> p;
- for (const auto &c: path) {
- if (c.canConvert<QGeoCoordinate>())
- p << c.value<QGeoCoordinate>();
- }
- d->setPath(p);
-}
-/*!
- Returns all the elements of the path.
-
- \internal
-*/
-QVariantList QGeoPath::variantPath() const
-{
- Q_D(const QGeoPath);
- QVariantList p;
- for (const auto &c: d->path())
- p << QVariant::fromValue(c);
- return p;
-}
-
-
-/*!
- \property QGeoPath::width
-
- \brief the width of the path in meters.
-*/
-void QGeoPath::setWidth(const qreal &width)
-{
- Q_D(QGeoPath);
- d->setWidth(width);
-}
-
-/*!
- Returns the width of the path, in meters. This information is used in the \l contains method.
- The default value is 0.
-*/
-qreal QGeoPath::width() const
-{
- Q_D(const QGeoPath);
- return d->width();
-}
-
-/*!
- Translates this geo path by \a degreesLatitude northwards and \a degreesLongitude eastwards.
-
- Negative values of \a degreesLatitude and \a degreesLongitude correspond to
- southward and westward translation respectively.
-*/
-void QGeoPath::translate(double degreesLatitude, double degreesLongitude)
-{
- Q_D(QGeoPath);
- d->translate(degreesLatitude, degreesLongitude);
-}
-
-/*!
- Returns a copy of this geo path translated by \a degreesLatitude northwards and
- \a degreesLongitude eastwards.
-
- Negative values of \a degreesLatitude and \a degreesLongitude correspond to
- southward and westward translation respectively.
-
- \sa translate()
-*/
-QGeoPath QGeoPath::translated(double degreesLatitude, double degreesLongitude) const
-{
- QGeoPath result(*this);
- result.translate(degreesLatitude, degreesLongitude);
- return result;
-}
-
-/*!
- Returns the length of the path, in meters, from the element \a indexFrom to the element \a indexTo.
- The length is intended to be the sum of the shortest distances for each pair of adjacent points.
-
- If \a indexTo is -1 (the default value), the length will be including the distance between last coordinate
- and the first (closed loop).
- To retrieve the length for the path, use 0 for \a indexFrom and \l QGeoPath::size() - 1 for \a indexTo.
-*/
-double QGeoPath::length(qsizetype indexFrom, qsizetype indexTo) const
-{
- Q_D(const QGeoPath);
- return d->length(indexFrom, indexTo);
-}
-
-/*!
- Returns the number of elements in the path.
-
- \since 5.10
-*/
-qsizetype QGeoPath::size() const
-{
- Q_D(const QGeoPath);
- const qsizetype result = d->size();
- if (result > kMaxInt)
- qWarning() << kWarningString;
- return result;
-}
-
-/*!
- Appends \a coordinate to the path.
-*/
-void QGeoPath::addCoordinate(const QGeoCoordinate &coordinate)
-{
- Q_D(QGeoPath);
- d->addCoordinate(coordinate);
- if (d->size() > kMaxInt)
- qWarning() << kWarningString;
-}
-
-/*!
- Inserts \a coordinate at the specified \a index.
-*/
-void QGeoPath::insertCoordinate(qsizetype index, const QGeoCoordinate &coordinate)
-{
- Q_D(QGeoPath);
- d->insertCoordinate(index, coordinate);
-}
-
-/*!
- Replaces the path element at the specified \a index with \a coordinate.
-*/
-void QGeoPath::replaceCoordinate(qsizetype index, const QGeoCoordinate &coordinate)
-{
- Q_D(QGeoPath);
- d->replaceCoordinate(index, coordinate);
-}
-
-/*!
- Returns the coordinate at \a index .
-*/
-QGeoCoordinate QGeoPath::coordinateAt(qsizetype index) const
-{
- Q_D(const QGeoPath);
- return d->coordinateAt(index);
-}
-
-/*!
- Returns true if the path contains \a coordinate as one of the elements.
-*/
-bool QGeoPath::containsCoordinate(const QGeoCoordinate &coordinate) const
-{
- Q_D(const QGeoPath);
- return d->containsCoordinate(coordinate);
-}
-
-/*!
- Removes the last occurrence of \a coordinate from the path.
-*/
-void QGeoPath::removeCoordinate(const QGeoCoordinate &coordinate)
-{
- Q_D(QGeoPath);
- d->removeCoordinate(coordinate);
-}
-
-/*!
- Removes element at position \a index from the path.
-*/
-void QGeoPath::removeCoordinate(qsizetype index)
-{
- Q_D(QGeoPath);
- d->removeCoordinate(index);
-}
-
-/*!
- Returns the geo path properties as a string.
-*/
-QString QGeoPath::toString() const
-{
- if (type() != QGeoShape::PathType) {
- qWarning("Not a path");
- return QStringLiteral("QGeoPath(not a path)");
- }
-
- QString pathString;
- for (const auto &p : path())
- pathString += p.toString() + QLatin1Char(',');
-
- return QStringLiteral("QGeoPath([ %1 ])").arg(pathString);
-}
-
-/*******************************************************************************
- *
- * QGeoPathPrivate & friends
- *
-*******************************************************************************/
-
-QGeoPathPrivate::QGeoPathPrivate()
-: QGeoShapePrivate(QGeoShape::PathType)
-{
-
-}
-
-QGeoPathPrivate::QGeoPathPrivate(const QList<QGeoCoordinate> &path, const qreal width)
-: QGeoShapePrivate(QGeoShape::PathType)
-{
- setPath(path);
- setWidth(width);
-}
-
-QGeoPathPrivate::~QGeoPathPrivate()
-{
-
-}
-
-QGeoShapePrivate *QGeoPathPrivate::clone() const
-{
- return new QGeoPathPrivate(*this);
-}
-
-bool QGeoPathPrivate::isValid() const
-{
- return !isEmpty();
-}
-
-bool QGeoPathPrivate::isEmpty() const
-{
- return path().isEmpty(); // this should perhaps return geometric emptiness, less than 2 points for line, or empty polygon for polygons
-}
-
-QGeoCoordinate QGeoPathPrivate::center() const
-{
- return boundingGeoRectangle().center();
-}
-
-bool QGeoPathPrivate::operator==(const QGeoShapePrivate &other) const
-{
- if (!QGeoShapePrivate::operator==(other))
- return false;
-
- const QGeoPathPrivate &otherPath = static_cast<const QGeoPathPrivate &>(other);
- if (m_path.size() != otherPath.m_path.size())
- return false;
- return m_width == otherPath.m_width && m_path == otherPath.m_path;
-}
-
-const QList<QGeoCoordinate> &QGeoPathPrivate::path() const
-{
- return m_path;
-}
-
-bool QGeoPathPrivate::lineContains(const QGeoCoordinate &coordinate) const
-{
- // Unoptimized approach:
- // - consider each segment of the path
- // - project it into mercator space (rhumb lines are straight in mercator space)
- // - find closest point to coordinate
- // - unproject the closest point
- // - calculate coordinate to closest point distance with distanceTo()
- // - if not within lineRadius, advance
- //
- // To keep wrapping into the equation:
- // If the mercator x value of a coordinate of the line, or the coordinate parameter, is less
- // than mercator(m_bbox).x, add that to the conversion.
-
- if (m_bboxDirty)
- const_cast<QGeoPathPrivate &>(*this).computeBoundingBox();
-
- double lineRadius = qMax(width() * 0.5, 0.2); // minimum radius: 20cm
-
- if (!m_path.size())
- return false;
- else if (m_path.size() == 1)
- return (m_path[0].distanceTo(coordinate) <= lineRadius);
-
- QDoubleVector2D p = QWebMercator::coordToMercator(coordinate);
- if (p.x() < m_leftBoundWrapped)
- p.setX(p.x() + m_leftBoundWrapped); // unwrap X
-
- QDoubleVector2D a;
- QDoubleVector2D b;
- if (m_path.size()) {
- a = QWebMercator::coordToMercator(m_path[0]);
- if (a.x() < m_leftBoundWrapped)
- a.setX(a.x() + m_leftBoundWrapped); // unwrap X
- }
- for (qsizetype i = 1; i < m_path.size(); i++) {
- b = QWebMercator::coordToMercator(m_path[i]);
- if (b.x() < m_leftBoundWrapped)
- b.setX(b.x() + m_leftBoundWrapped); // unwrap X
- if (b == a)
- continue;
-
- double u = ((p.x() - a.x()) * (b.x() - a.x()) + (p.y() - a.y()) * (b.y() - a.y()) ) / (b - a).lengthSquared();
- QDoubleVector2D intersection(a.x() + u * (b.x() - a.x()) , a.y() + u * (b.y() - a.y()) );
-
- QDoubleVector2D candidate = ( (p-a).length() < (p-b).length() ) ? a : b;
-
- if (u > 0 && u < 1
- && (p-intersection).length() < (p-candidate).length() ) // And it falls in the segment
- candidate = intersection;
-
-
- if (candidate.x() > 1.0)
- candidate.setX(candidate.x() - m_leftBoundWrapped); // wrap X
-
- QGeoCoordinate closest = QWebMercator::mercatorToCoord(candidate);
-
- double distanceMeters = coordinate.distanceTo(closest);
- if (distanceMeters <= lineRadius)
- return true;
-
- // swap
- a = b;
- }
-
- // Last check if the coordinate is on the left of leftBoundMercator, but close enough to
- // m_path[0]
- return (m_path[0].distanceTo(coordinate) <= lineRadius);
-}
-
-bool QGeoPathPrivate::contains(const QGeoCoordinate &coordinate) const
-{
- return lineContains(coordinate);
-}
-
-qreal QGeoPathPrivate::width() const
-{
- return m_width;
-}
-
-void QGeoPathPrivate::setWidth(const qreal &width)
-{
- if (qIsNaN(width) || width < 0.0)
- return;
- m_width = width;
-}
-
-double QGeoPathPrivate::length(qsizetype indexFrom, qsizetype indexTo) const
-{
- if (path().isEmpty())
- return 0.0;
-
- bool wrap = indexTo == -1;
- if (indexTo < 0 || indexTo >= path().size())
- indexTo = path().size() - 1;
- double len = 0.0;
- // TODO: consider calculating the length of the actual rhumb line segments
- // instead of the shortest path from A to B.
- for (qsizetype i = indexFrom; i < indexTo; i++)
- len += m_path[i].distanceTo(m_path[i+1]);
- if (wrap)
- len += m_path.last().distanceTo(m_path.first());
- return len;
-}
-
-qsizetype QGeoPathPrivate::size() const
-{
- return m_path.size();
-}
-
-QGeoCoordinate QGeoPathPrivate::coordinateAt(qsizetype index) const
-{
- if (index < 0 || index >= m_path.size())
- return QGeoCoordinate();
-
- return m_path.at(index);
-}
-
-bool QGeoPathPrivate::containsCoordinate(const QGeoCoordinate &coordinate) const
-{
- return m_path.indexOf(coordinate) > -1;
-}
-
-void QGeoPathPrivate::translate(double degreesLatitude, double degreesLongitude)
-{
- // Need min/maxLati, so update bbox
- QList<double> m_deltaXs;
- double m_minX, m_maxX, m_minLati, m_maxLati;
- m_bboxDirty = false;
- computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
-
- if (degreesLatitude > 0.0)
- degreesLatitude = qMin(degreesLatitude, 90.0 - m_maxLati);
- else
- degreesLatitude = qMax(degreesLatitude, -90.0 - m_minLati);
- for (QGeoCoordinate &p: m_path) {
- p.setLatitude(p.latitude() + degreesLatitude);
- p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude));
- }
- m_bbox.translate(degreesLatitude, degreesLongitude);
- m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
-}
-
-QGeoRectangle QGeoPathPrivate::boundingGeoRectangle() const
-{
- if (m_bboxDirty)
- const_cast<QGeoPathPrivate &>(*this).computeBoundingBox();
- return m_bbox;
-}
-
-size_t QGeoPathPrivate::hash(size_t seed) const
-{
- const size_t res = qHashRange(m_path.cbegin(), m_path.cend(), seed);
- return qHashMulti(seed, res, m_width);
-}
-
-void QGeoPathPrivate::setPath(const QList<QGeoCoordinate> &path)
-{
- for (const QGeoCoordinate &c: path)
- if (!c.isValid())
- return;
- m_path = path;
- markDirty();
-}
-
-void QGeoPathPrivate::clearPath()
-{
- m_path.clear();
- markDirty();
-}
-
-void QGeoPathPrivate::addCoordinate(const QGeoCoordinate &coordinate)
-{
- if (!coordinate.isValid())
- return;
- m_path.append(coordinate);
- markDirty();
-}
-
-void QGeoPathPrivate::insertCoordinate(qsizetype index, const QGeoCoordinate &coordinate)
-{
- if (index < 0 || index > m_path.size() || !coordinate.isValid())
- return;
- m_path.insert(index, coordinate);
- markDirty();
-}
-
-void QGeoPathPrivate::replaceCoordinate(qsizetype index, const QGeoCoordinate &coordinate)
-{
- if (index < 0 || index >= m_path.size() || !coordinate.isValid())
- return;
- m_path[index] = coordinate;
- markDirty();
-}
-
-void QGeoPathPrivate::removeCoordinate(const QGeoCoordinate &coordinate)
-{
- qsizetype index = m_path.lastIndexOf(coordinate);
- removeCoordinate(index);
-}
-
-void QGeoPathPrivate::removeCoordinate(qsizetype index)
-{
- if (index < 0 || index >= m_path.size())
- return;
- m_path.removeAt(index);
- markDirty();
-}
-
-void QGeoPathPrivate::markDirty()
-{
- m_bboxDirty = true;
-}
-
-void QGeoPathPrivate::computeBoundingBox()
-{
- QList<double> m_deltaXs;
- double m_minX, m_maxX, m_minLati, m_maxLati;
- m_bboxDirty = false;
- computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
- m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
-}
-
-QGeoPathPrivateEager::QGeoPathPrivateEager()
-: QGeoPathPrivate()
-{
- m_bboxDirty = false; // never dirty on the eager version
-}
-
-QGeoPathPrivateEager::QGeoPathPrivateEager(const QList<QGeoCoordinate> &path, const qreal width)
-: QGeoPathPrivate(path, width)
-{
- m_bboxDirty = false; // never dirty on the eager version
-}
-
-QGeoPathPrivateEager::~QGeoPathPrivateEager()
-{
-
-}
-
-QGeoShapePrivate *QGeoPathPrivateEager::clone() const
-{
- return new QGeoPathPrivateEager(*this);
-}
-
-void QGeoPathPrivateEager::markDirty()
-{
- computeBoundingBox();
-}
-
-void QGeoPathPrivateEager::translate(double degreesLatitude, double degreesLongitude)
-{
- if (degreesLatitude > 0.0)
- degreesLatitude = qMin(degreesLatitude, 90.0 - m_maxLati);
- else
- degreesLatitude = qMax(degreesLatitude, -90.0 - m_minLati);
- for (QGeoCoordinate &p: m_path) {
- p.setLatitude(p.latitude() + degreesLatitude);
- p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude));
- }
- m_bbox.translate(degreesLatitude, degreesLongitude);
- m_minLati += degreesLatitude;
- m_maxLati += degreesLatitude;
- m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
-}
-
-void QGeoPathPrivateEager::addCoordinate(const QGeoCoordinate &coordinate)
-{
- if (!coordinate.isValid())
- return;
- m_path.append(coordinate);
- //m_clipperDirty = true; // clipper not used in polylines
- updateBoundingBox();
-}
-
-void QGeoPathPrivateEager::QGeoPathPrivateEager::computeBoundingBox()
-{
- computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
- m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
-}
-
-void QGeoPathPrivateEager::QGeoPathPrivateEager::updateBoundingBox()
-{
- updateBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
- m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
-}
-
-QGeoPathEager::QGeoPathEager() : QGeoPath()
-{
- initPathConversions();
- d_ptr = new QGeoPathPrivateEager;
-}
-
-QGeoPathEager::QGeoPathEager(const QList<QGeoCoordinate> &path, const qreal &width) : QGeoPath()
-{
- initPathConversions();
- d_ptr = new QGeoPathPrivateEager(path, width);
-}
-
-QGeoPathEager::QGeoPathEager(const QGeoPath &other) : QGeoPath()
-{
- initPathConversions();
- d_ptr = new QGeoPathPrivateEager;
- setPath(other.path());
- setWidth(other.width());
-}
-
-QGeoPathEager::QGeoPathEager(const QGeoShape &other) : QGeoPath()
-{
- initPathConversions();
- if (other.type() == QGeoShape::PathType)
- *this = QGeoPathEager(QGeoPath(other));
- else
- d_ptr = new QGeoPathPrivateEager;
-}
-
-QGeoPathEager::~QGeoPathEager() {}
-
-QT_END_NAMESPACE
-
-
-
-
-
-
-
-