diff options
Diffstat (limited to 'src/positioning')
-rw-r--r-- | src/positioning/qgeocoordinate.h | 1 | ||||
-rw-r--r-- | src/positioning/qgeopath.cpp | 24 | ||||
-rw-r--r-- | src/positioning/qgeopath_p.h | 1 | ||||
-rw-r--r-- | src/positioning/qgeopolygon.cpp | 79 | ||||
-rw-r--r-- | src/positioning/qgeopositioninfosource.cpp | 10 | ||||
-rw-r--r-- | src/positioning/qgeopositioninfosource_p.h | 6 | ||||
-rw-r--r-- | src/positioning/qlocationutils_p.h | 7 |
7 files changed, 97 insertions, 31 deletions
diff --git a/src/positioning/qgeocoordinate.h b/src/positioning/qgeocoordinate.h index ddb6274e..007f7e06 100644 --- a/src/positioning/qgeocoordinate.h +++ b/src/positioning/qgeocoordinate.h @@ -54,6 +54,7 @@ class QGeoCoordinatePrivate; class Q_POSITIONING_EXPORT QGeoCoordinate { Q_GADGET + Q_ENUMS(CoordinateFormat) Q_PROPERTY(double latitude READ latitude WRITE setLatitude) Q_PROPERTY(double longitude READ longitude WRITE setLongitude) diff --git a/src/positioning/qgeopath.cpp b/src/positioning/qgeopath.cpp index 1225d7c8..b6513bc7 100644 --- a/src/positioning/qgeopath.cpp +++ b/src/positioning/qgeopath.cpp @@ -475,6 +475,9 @@ bool QGeoPathPrivate::lineContains(const QGeoCoordinate &coordinate) const // 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()) @@ -482,23 +485,21 @@ bool QGeoPathPrivate::lineContains(const QGeoCoordinate &coordinate) const else if (m_path.size() == 1) return (m_path[0].distanceTo(coordinate) <= lineRadius); - double leftBoundMercator = QWebMercator::coordToMercator(m_bbox.topLeft()).x(); - QDoubleVector2D p = QWebMercator::coordToMercator(coordinate); - if (p.x() < leftBoundMercator) - p.setX(p.x() + leftBoundMercator); // unwrap X + 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() < leftBoundMercator) - a.setX(a.x() + leftBoundMercator); // unwrap X + if (a.x() < m_leftBoundWrapped) + a.setX(a.x() + m_leftBoundWrapped); // unwrap X } for (int i = 1; i < m_path.size(); i++) { b = QWebMercator::coordToMercator(m_path[i]); - if (b.x() < leftBoundMercator) - b.setX(b.x() + leftBoundMercator); // unwrap X + if (b.x() < m_leftBoundWrapped) + b.setX(b.x() + m_leftBoundWrapped); // unwrap X if (b == a) continue; @@ -513,7 +514,7 @@ bool QGeoPathPrivate::lineContains(const QGeoCoordinate &coordinate) const if (candidate.x() > 1.0) - candidate.setX(candidate.x() - leftBoundMercator); // wrap X + candidate.setX(candidate.x() - m_leftBoundWrapped); // wrap X QGeoCoordinate closest = QWebMercator::mercatorToCoord(candidate); @@ -600,6 +601,7 @@ void QGeoPathPrivate::translate(double degreesLatitude, double degreesLongitude) p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude)); } m_bbox.translate(degreesLatitude, degreesLongitude); + m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x(); } QGeoRectangle QGeoPathPrivate::boundingGeoRectangle() const @@ -673,6 +675,7 @@ void QGeoPathPrivate::computeBoundingBox() 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() @@ -715,6 +718,7 @@ void QGeoPathPrivateEager::translate(double degreesLatitude, double degreesLongi 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) @@ -729,11 +733,13 @@ void QGeoPathPrivateEager::addCoordinate(const QGeoCoordinate &coordinate) 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() diff --git a/src/positioning/qgeopath_p.h b/src/positioning/qgeopath_p.h index be73994f..6dd17b09 100644 --- a/src/positioning/qgeopath_p.h +++ b/src/positioning/qgeopath_p.h @@ -220,6 +220,7 @@ public: QList<QGeoCoordinate> m_path; qreal m_width = 0; QGeoRectangle m_bbox; // cached + double m_leftBoundWrapped; // cached bool m_bboxDirty = false; }; diff --git a/src/positioning/qgeopolygon.cpp b/src/positioning/qgeopolygon.cpp index e8fdda76..7d8a0ce0 100644 --- a/src/positioning/qgeopolygon.cpp +++ b/src/positioning/qgeopolygon.cpp @@ -39,6 +39,8 @@ #include "qgeopolygon.h" #include "qgeopolygon_p.h" +#include "qgeopath_p.h" +#include "qgeocircle.h" #include "qgeocoordinate.h" #include "qnumeric.h" @@ -135,6 +137,41 @@ QGeoPolygon::QGeoPolygon(const QGeoPolygon &other) initPolygonConversions(); } +static void calculatePeripheralPoints(QList<QGeoCoordinate> &path, + const QGeoCircle &circle, + int steps) +{ + const QGeoCoordinate ¢er = circle.center(); + const qreal distance = circle.radius(); + // Calculate points based on great-circle distance + // Calculation is the same as GeoCoordinate's atDistanceAndAzimuth function + // but tweaked here for computing multiple points + + // pre-calculations + steps = qMax(steps, 3); + qreal centerLon = center.longitude(); + qreal latRad = QLocationUtils::radians(center.latitude()); + qreal lonRad = QLocationUtils::radians(centerLon); + qreal cosLatRad = std::cos(latRad); + qreal sinLatRad = std::sin(latRad); + qreal ratio = (distance / QLocationUtils::earthMeanRadius()); + qreal cosRatio = std::cos(ratio); + qreal sinRatio = std::sin(ratio); + qreal sinLatRad_x_cosRatio = sinLatRad * cosRatio; + qreal cosLatRad_x_sinRatio = cosLatRad * sinRatio; + for (int i = 0; i < steps; ++i) { + qreal azimuthRad = 2 * M_PI * i / steps; + qreal resultLatRad = std::asin(sinLatRad_x_cosRatio + + cosLatRad_x_sinRatio * std::cos(azimuthRad)); + qreal resultLonRad = lonRad + std::atan2(std::sin(azimuthRad) * cosLatRad_x_sinRatio, + cosRatio - sinLatRad * std::sin(resultLatRad)); + qreal lat2 = QLocationUtils::degrees(resultLatRad); + qreal lon2 = QLocationUtils::wrapLong(QLocationUtils::degrees(resultLonRad)); + + path << QGeoCoordinate(lat2, lon2, center.altitude()); + } +} + /*! Constructs a new geo polygon from the contents of \a other. */ @@ -142,8 +179,22 @@ QGeoPolygon::QGeoPolygon(const QGeoShape &other) : QGeoShape(other) { initPolygonConversions(); - if (type() != QGeoShape::PolygonType) - d_ptr = new QGeoPolygonPrivate(); + if (type() != QGeoShape::PolygonType) { + QGeoPolygonPrivate *poly = new QGeoPolygonPrivate(); + if (type() == QGeoShape::CircleType) { + const QGeoCircle &circle = static_cast<const QGeoCircle &>(other); + QList<QGeoCoordinate> perimeter; + calculatePeripheralPoints(perimeter, circle, 128); + poly->setPath(perimeter); + } else if (type() == QGeoShape::RectangleType) { + const QGeoRectangle &rect = static_cast<const QGeoRectangle &>(other); + QList<QGeoCoordinate> perimeter; + perimeter << rect.topLeft() << rect.topRight() + << rect.bottomRight() << rect.bottomLeft(); + poly->setPath(perimeter); + } + d_ptr = poly; + } } /*! @@ -504,10 +555,11 @@ void QGeoPolygonPrivate::translate(double degreesLatitude, double degreesLongitu // Need min/maxLati, so update bbox QVector<double> m_deltaXs; double m_minX, m_maxX, m_minLati, m_maxLati; - m_bboxDirty = false; + m_bboxDirty = false; // Updated in translatePoly computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox); - translatePoly(m_path, m_holesList, m_bbox, degreesLatitude, degreesLongitude, m_maxLati, m_minLati); + m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x(); + m_clipperDirty = true; } bool QGeoPolygonPrivate::operator==(const QGeoShapePrivate &other) const @@ -557,10 +609,11 @@ bool QGeoPolygonPrivate::polygonContains(const QGeoCoordinate &coordinate) const const_cast<QGeoPolygonPrivate *>(this)->updateClipperPath(); // this one updates bbox too if needed QDoubleVector2D coord = QWebMercator::coordToMercator(coordinate); - double tlx = QWebMercator::coordToMercator(m_bbox.topLeft()).x(); - if (coord.x() < tlx) + + if (coord.x() < m_leftBoundWrapped) coord.setX(coord.x() + 1.0); + IntPoint intCoord = QClipperUtils::toIntPoint(coord); if (!c2t::clip2tri::pointInPolygon(intCoord, m_clipperPath)) return false; @@ -570,12 +623,7 @@ bool QGeoPolygonPrivate::polygonContains(const QGeoCoordinate &coordinate) const // ToDo: cache these QGeoPolygon holePolygon; holePolygon.setPath(holePath); - // QGeoPath holeBoundary; - // holeBoundary.setPath(holePath); - - if (holePolygon.contains(coordinate) - // && !(holeBoundary.contains(coordinate)) - ) + if (holePolygon.contains(coordinate)) return false; } return true; @@ -591,11 +639,11 @@ void QGeoPolygonPrivate::updateClipperPath() if (m_bboxDirty) computeBoundingBox(); m_clipperDirty = false; - double tlx = QWebMercator::coordToMercator(m_bbox.topLeft()).x(); + QList<QDoubleVector2D> preservedPath; for (const QGeoCoordinate &c : m_path) { QDoubleVector2D crd = QWebMercator::coordToMercator(c); - if (crd.x() < tlx) + if (crd.x() < m_leftBoundWrapped) crd.setX(crd.x() + 1.0); preservedPath << crd; } @@ -625,6 +673,8 @@ QGeoShapePrivate *QGeoPolygonPrivateEager::clone() const void QGeoPolygonPrivateEager::translate(double degreesLatitude, double degreesLongitude) { translatePoly(m_path, m_holesList, m_bbox, degreesLatitude, degreesLongitude, m_maxLati, m_minLati); + m_leftBoundWrapped = QWebMercator::coordToMercator(m_bbox.topLeft()).x(); + m_clipperDirty = true; } void QGeoPolygonPrivateEager::markDirty() @@ -645,6 +695,7 @@ void QGeoPolygonPrivateEager::addCoordinate(const QGeoCoordinate &coordinate) void QGeoPolygonPrivateEager::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 QGeoPolygonPrivateEager::updateBoundingBox() diff --git a/src/positioning/qgeopositioninfosource.cpp b/src/positioning/qgeopositioninfosource.cpp index 0610bd79..56ee66d7 100644 --- a/src/positioning/qgeopositioninfosource.cpp +++ b/src/positioning/qgeopositioninfosource.cpp @@ -143,9 +143,9 @@ QVariant QGeoPositionInfoSourcePrivate::backendProperty(const QString &/*name*/) return QVariant(); } -QHash<QString, QJsonObject> QGeoPositionInfoSourcePrivate::plugins(bool reload) +QMultiHash<QString, QJsonObject> QGeoPositionInfoSourcePrivate::plugins(bool reload) { - static QHash<QString, QJsonObject> plugins; + static QMultiHash<QString, QJsonObject> plugins; static bool alreadyDiscovered = false; if (reload == true) @@ -179,7 +179,7 @@ QList<QJsonObject> QGeoPositionInfoSourcePrivate::pluginsSorted() return list; } -void QGeoPositionInfoSourcePrivate::loadPluginMetadata(QHash<QString, QJsonObject> &plugins) +void QGeoPositionInfoSourcePrivate::loadPluginMetadata(QMultiHash<QString, QJsonObject> &plugins) { QFactoryLoader *l = loader(); QList<QJsonObject> meta = l->metaData(); @@ -192,7 +192,7 @@ void QGeoPositionInfoSourcePrivate::loadPluginMetadata(QHash<QString, QJsonObjec continue; } obj.insert(QStringLiteral("index"), i); - plugins.insertMulti(obj.value(QStringLiteral("Provider")).toString(), obj); + plugins.insert(obj.value(QStringLiteral("Provider")).toString(), obj); } } @@ -206,7 +206,7 @@ QGeoPositionInfoSource::QGeoPositionInfoSource(QObject *parent) { qRegisterMetaType<QGeoPositionInfo>(); d->interval = 0; - d->methods = 0; + d->methods = {}; } /*! diff --git a/src/positioning/qgeopositioninfosource_p.h b/src/positioning/qgeopositioninfosource_p.h index 2ae93055..e12ede4c 100644 --- a/src/positioning/qgeopositioninfosource_p.h +++ b/src/positioning/qgeopositioninfosource_p.h @@ -56,7 +56,7 @@ #include "qgeopositioninfosourcefactory.h" #include <QJsonObject> #include <QString> -#include <QHash> +#include <QMultiHash> #include <QList> QT_BEGIN_NAMESPACE @@ -79,8 +79,8 @@ public: virtual bool setBackendProperty(const QString &name, const QVariant &value); virtual QVariant backendProperty(const QString &name) const; - static QHash<QString, QJsonObject> plugins(bool reload = false); - static void loadPluginMetadata(QHash<QString, QJsonObject> &list); + static QMultiHash<QString, QJsonObject> plugins(bool reload = false); + static void loadPluginMetadata(QMultiHash<QString, QJsonObject> &list); static QList<QJsonObject> pluginsSorted(); }; diff --git a/src/positioning/qlocationutils_p.h b/src/positioning/qlocationutils_p.h index e2d739e7..563db200 100644 --- a/src/positioning/qlocationutils_p.h +++ b/src/positioning/qlocationutils_p.h @@ -258,6 +258,13 @@ public: return wrapLong(centerLongitude - leftOffset); } + inline static void split_double(double input, float *hipart, float *lopart) + { + *hipart = (float) input; + double delta = input - ((double) *hipart); + *lopart = (float) delta; + } + static qreal metersPerPixel(qreal zoomLevel, const QGeoCoordinate &coordinate) { const qreal metersPerTile = earthMeanCircumference() * std::cos(radians(coordinate.latitude())) / std::pow(2, zoomLevel); |