summaryrefslogtreecommitdiff
path: root/src/location
diff options
context:
space:
mode:
Diffstat (limited to 'src/location')
-rw-r--r--src/location/qlocation.cpp13
-rw-r--r--src/location/qlocationglobal_p.h20
-rw-r--r--src/location/quickmapitems/qdeclarativecirclemapitem.cpp38
-rw-r--r--src/location/quickmapitems/qdeclarativecirclemapitem_p_p.h10
-rw-r--r--src/location/quickmapitems/qdeclarativegeomapitembase.cpp14
-rw-r--r--src/location/quickmapitems/qdeclarativegeomapitembase_p.h9
-rw-r--r--src/location/quickmapitems/qdeclarativegeomapitemutils.cpp66
-rw-r--r--src/location/quickmapitems/qdeclarativegeomapitemutils_p.h8
-rw-r--r--src/location/quickmapitems/qdeclarativepolygonmapitem.cpp95
-rw-r--r--src/location/quickmapitems/qdeclarativepolygonmapitem_p_p.h39
-rw-r--r--src/location/quickmapitems/qdeclarativepolylinemapitem.cpp29
-rw-r--r--src/location/quickmapitems/qdeclarativerectanglemapitem.cpp28
12 files changed, 341 insertions, 28 deletions
diff --git a/src/location/qlocation.cpp b/src/location/qlocation.cpp
index 5a32cce8..6733bd4a 100644
--- a/src/location/qlocation.cpp
+++ b/src/location/qlocation.cpp
@@ -40,6 +40,19 @@ namespace QLocation {
When \e searching for places, unspecified means that places of any scope is returned.
*/
+
+/*!
+ \enum QLocation::ReferenceSurface
+
+ Defines the reference surface on which various map items (e.g. polygons, polylines) are defined.
+
+ \value Map Items are defined on a map. This means, e.g. for a polyline that
+ nodes are connected with straight lines on the map.
+ \value Globe Items are defined on the globe. This means, e.g. for a polyine
+ that nodes are connected with circle sections that represent the
+ shortest connection between points on a sphere. This connection is
+ also known as great circle path.
+*/
}
QT_END_NAMESPACE
diff --git a/src/location/qlocationglobal_p.h b/src/location/qlocationglobal_p.h
index 7d1befea..33ed3d07 100644
--- a/src/location/qlocationglobal_p.h
+++ b/src/location/qlocationglobal_p.h
@@ -16,7 +16,27 @@
//
#include "qlocationglobal.h"
+#include <qqml.h>
#include "private/qglobal_p.h"
#include <QtLocation/private/qtlocationexports_p.h>
+QT_BEGIN_NAMESPACE
+
+namespace QLocation
+{
+Q_NAMESPACE_EXPORT(Q_LOCATION_PRIVATE_EXPORT)
+QML_NAMED_ELEMENT(QtLocation)
+QML_ADDED_IN_VERSION(6, 6)
+Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
+
+enum class ReferenceSurface : uint8_t {
+ Map,
+ Globe
+};
+Q_ENUM_NS(ReferenceSurface)
+
+}
+
+QT_END_NAMESPACE
+
#endif // QLOCATIONGLOBAL_P_H
diff --git a/src/location/quickmapitems/qdeclarativecirclemapitem.cpp b/src/location/quickmapitems/qdeclarativecirclemapitem.cpp
index 7cf69e59..8d1de1c9 100644
--- a/src/location/quickmapitems/qdeclarativecirclemapitem.cpp
+++ b/src/location/quickmapitems/qdeclarativecirclemapitem.cpp
@@ -87,6 +87,19 @@ QT_BEGIN_NAMESPACE
\since 5.14
*/
+/*!
+ \qmlproperty enum QtLocation::MapCircle::referenceSurface
+
+ This property determines the reference surface of the circle. If it is set to
+ \l QLocation::ReferenceSurface::Map the circle is drawn as a circe on the map with
+ \l radius approximated to match the map scale at the center of the circle.
+ If it is set to \l QLocation::ReferenceSurface::Globe the circle is mapped onto
+ a sphere and the great circle path is used to determine the coverage of the circle.
+ Default value is \l QLocation::ReferenceSurface::Map.
+
+ \since 6.5
+*/
+
struct Vertex
{
QVector2D position;
@@ -108,6 +121,8 @@ QDeclarativeCircleMapItem::QDeclarativeCircleMapItem(QQuickItem *parent)
this, &QDeclarativeCircleMapItem::onLinePropertiesChanged);
QObject::connect(&m_border, &QDeclarativeMapLineProperties::widthChanged,
this, &QDeclarativeCircleMapItem::onLinePropertiesChanged);
+ QObject::connect(this, &QDeclarativeCircleMapItem::referenceSurfaceChanged,
+ [=]() {m_d->onGeoGeometryChanged();});
}
QDeclarativeCircleMapItem::~QDeclarativeCircleMapItem()
@@ -392,7 +407,24 @@ int QDeclarativeCircleMapItemPrivate::crossEarthPole(const QGeoCoordinate &cente
(distanceToSouthPole < distance? 1 : 0);
}
-void QDeclarativeCircleMapItemPrivate::calculatePeripheralPoints(QList<QDoubleVector2D> &path,
+void QDeclarativeCircleMapItemPrivate::calculatePeripheralPointsSimple(QList<QDoubleVector2D> &path,
+ const QGeoCoordinate &center,
+ qreal distance,
+ const QGeoProjectionWebMercator &p,
+ int steps)
+{
+ const double lambda = 0.0001;
+ const QDoubleVector2D c = p.geoToMapProjection(center);
+ const double lambda_geo = center.distanceTo(p.mapProjectionToGeo(c + QDoubleVector2D(lambda, 0)));
+ const qreal mapDistance = distance * lambda / lambda_geo;
+
+ for (int i = 0; i < steps; ++i) {
+ const qreal rad = 2 * M_PI * i / steps;
+ path << c + QDoubleVector2D(cos(rad), sin(rad)) * mapDistance;
+ }
+}
+
+void QDeclarativeCircleMapItemPrivate::calculatePeripheralPointsGreatCircle(QList<QDoubleVector2D> &path,
const QGeoCoordinate &center,
qreal distance,
const QGeoProjectionWebMercator &p,
@@ -459,7 +491,7 @@ void QDeclarativeCircleMapItemPrivateCPU::updatePolish()
const qreal &radius = m_circle.m_circle.radius();
// if circle crosses north/south pole, then don't preserve circular shape,
- int crossingPoles = crossEarthPole(center, radius);
+ int crossingPoles = m_circle.referenceSurface() == QLocation::ReferenceSurface::Globe ? crossEarthPole(center, radius) : 0;
if (crossingPoles == 1) { // If the circle crosses both poles, we will remove it from a rectangle
includeOnePoleInPath(circlePath, center, radius, p);
m_geometry.updateSourcePoints(*m_circle.map(), QList<QList<QDoubleVector2D>>{circlePath}, QGeoMapPolygonGeometry::DrawOnce);
@@ -486,7 +518,7 @@ void QDeclarativeCircleMapItemPrivateCPU::updatePolish()
surroundingRect = {{anchorRect, -0.1}, {anchorRect + 1.0, -0.1},
{anchorRect + 1.0, 1.1}, {anchorRect, 1.1}};
- wrappingMode = QGeoMapPolygonGeometry::WrapAround;
+ wrappingMode = QGeoMapPolygonGeometry::Duplicate;
}
m_geometry.updateSourcePoints(*m_circle.map(), {surroundingRect, circlePath}, wrappingMode);
} else {
diff --git a/src/location/quickmapitems/qdeclarativecirclemapitem_p_p.h b/src/location/quickmapitems/qdeclarativecirclemapitem_p_p.h
index 117dcb63..ee6e8d57 100644
--- a/src/location/quickmapitems/qdeclarativecirclemapitem_p_p.h
+++ b/src/location/quickmapitems/qdeclarativecirclemapitem_p_p.h
@@ -62,7 +62,10 @@ public:
m_circlePath.clear();
const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_circle.map()->geoProjection());
- calculatePeripheralPoints(m_circlePath, m_circle.center(), m_circle.radius(), p, CircleSamples);
+ if (m_circle.referenceSurface() == QLocation::ReferenceSurface::Map)
+ calculatePeripheralPointsSimple(m_circlePath, m_circle.center(), m_circle.radius(), p, CircleSamples);
+ else
+ calculatePeripheralPointsGreatCircle(m_circlePath, m_circle.center(), m_circle.radius(), p, CircleSamples);
}
static int crossEarthPole(const QGeoCoordinate &center, qreal distance);
@@ -70,7 +73,10 @@ public:
static void includeOnePoleInPath(QList<QDoubleVector2D> &path, const QGeoCoordinate &center,
qreal distance, const QGeoProjectionWebMercator &p);
- static void calculatePeripheralPoints(QList<QDoubleVector2D> &path, const QGeoCoordinate &center,
+ static void calculatePeripheralPointsSimple(QList<QDoubleVector2D> &path, const QGeoCoordinate &center,
+ qreal distance, const QGeoProjectionWebMercator &p, int steps);
+
+ static void calculatePeripheralPointsGreatCircle(QList<QDoubleVector2D> &path, const QGeoCoordinate &center,
qreal distance, const QGeoProjectionWebMercator &p, int steps);
QDeclarativeCircleMapItem &m_circle;
diff --git a/src/location/quickmapitems/qdeclarativegeomapitembase.cpp b/src/location/quickmapitems/qdeclarativegeomapitembase.cpp
index 233ea82d..1e455816 100644
--- a/src/location/quickmapitems/qdeclarativegeomapitembase.cpp
+++ b/src/location/quickmapitems/qdeclarativegeomapitembase.cpp
@@ -161,6 +161,20 @@ void QDeclarativeGeoMapItemBase::setAutoFadeIn(bool fadeIn)
polishAndUpdate();
}
+QLocation::ReferenceSurface QDeclarativeGeoMapItemBase::referenceSurface() const
+{
+ return m_referenceSurface;
+}
+
+void QDeclarativeGeoMapItemBase::setReferenceSurface(QLocation::ReferenceSurface referenceSurface)
+{
+ if (referenceSurface == m_referenceSurface)
+ return;
+ m_referenceSurface = referenceSurface;
+ emit referenceSurfaceChanged();
+ updatePolish();
+}
+
int QDeclarativeGeoMapItemBase::lodThreshold() const
{
return m_lodThreshold;
diff --git a/src/location/quickmapitems/qdeclarativegeomapitembase_p.h b/src/location/quickmapitems/qdeclarativegeomapitembase_p.h
index 38eef2db..9f2de62b 100644
--- a/src/location/quickmapitems/qdeclarativegeomapitembase_p.h
+++ b/src/location/quickmapitems/qdeclarativegeomapitembase_p.h
@@ -20,6 +20,7 @@
#include <QtQuick/QQuickItem>
#include <QtPositioning/QGeoShape>
+#include <QtLocation/qlocation.h>
#include <QtLocation/private/qdeclarativegeomap_p.h>
#include <QtLocation/private/qlocationglobal_p.h>
#include <QtLocation/private/qgeomap_p.h>
@@ -48,15 +49,18 @@ class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemBase : public QQuickItem
QML_NAMED_ELEMENT(GeoMapItemBase)
QML_ADDED_IN_VERSION(5, 0)
QML_UNCREATABLE("GeoMapItemBase is not intended instantiable by developer.")
+ Q_ENUMS(ReferenceSurface)
Q_PROPERTY(QGeoShape geoShape READ geoShape WRITE setGeoShape STORED false )
Q_PROPERTY(bool autoFadeIn READ autoFadeIn WRITE setAutoFadeIn REVISION(5, 14))
+ Q_PROPERTY(QLocation::ReferenceSurface referenceSurface READ referenceSurface WRITE setReferenceSurface NOTIFY referenceSurfaceChanged REVISION(6, 6))
Q_PROPERTY(int lodThreshold READ lodThreshold WRITE setLodThreshold NOTIFY lodThresholdChanged REVISION(5, 15))
public:
explicit QDeclarativeGeoMapItemBase(QQuickItem *parent = nullptr);
virtual ~QDeclarativeGeoMapItemBase();
+
virtual void setMap(QDeclarativeGeoMap *quickMap, QGeoMap *map);
virtual void setPositionOnMap(const QGeoCoordinate &coordinate, const QPointF &offset);
@@ -68,6 +72,9 @@ public:
bool autoFadeIn() const;
void setAutoFadeIn(bool fadeIn);
+ QLocation::ReferenceSurface referenceSurface() const;
+ void setReferenceSurface(QLocation::ReferenceSurface referenceSurface);
+
int lodThreshold() const;
void setLodThreshold(int lt);
unsigned int zoomForLOD(int zoom) const;
@@ -101,6 +108,7 @@ Q_SIGNALS:
void mapItemOpacityChanged();
Q_REVISION(12) void addTransitionFinished();
Q_REVISION(12) void removeTransitionFinished();
+ void referenceSurfaceChanged();
void lodThresholdChanged();
protected Q_SLOTS:
@@ -129,6 +137,7 @@ private:
std::unique_ptr<QDeclarativeGeoMapItemTransitionManager> m_transitionManager;
bool m_autoFadeIn = true;
+ QLocation::ReferenceSurface m_referenceSurface = QLocation::ReferenceSurface::Map;
int m_lodThreshold = 0;
friend class QDeclarativeGeoMap;
diff --git a/src/location/quickmapitems/qdeclarativegeomapitemutils.cpp b/src/location/quickmapitems/qdeclarativegeomapitemutils.cpp
index a1501dd6..6c45e164 100644
--- a/src/location/quickmapitems/qdeclarativegeomapitemutils.cpp
+++ b/src/location/quickmapitems/qdeclarativegeomapitemutils.cpp
@@ -191,6 +191,72 @@ QRectF boundingRectangleFromList(const QList<QDoubleVector2D> &list)
return QRectF(xMin, yMin, xMax - xMin, yMax - yMin);
}
+QList<QGeoCoordinate> greaterCirclePath(const QList<QGeoCoordinate> &cornerPoints,
+ greaterCirclePathForm form, int N)
+{
+ QList<QGeoCoordinate> path;
+ path.reserve(N);
+ //If the path has to be closed we include the first coordinate again at the end of the procedure
+ qsizetype lineCount = cornerPoints.size() - ((form == OpenPath) ? 1 : 0);
+ for (qsizetype i = 0; i < lineCount; i++) {
+ path.append(cornerPoints.at(i));
+ const double p_lat = cornerPoints.at(i).latitude() / 180.0 * M_PI; //latitude point p in rad
+ const double p_lon = cornerPoints.at(i).longitude() / 180.0 * M_PI; //longitude point p in rad
+ const double q_lat = cornerPoints.at((i + 1) % cornerPoints.size()).latitude() / 180.0 * M_PI; //latitude point q in rad
+ const double q_lon = cornerPoints.at((i + 1) % cornerPoints.size()).longitude() / 180.0 * M_PI;//longitude point q in rad
+
+ const double c_p_lat = cos(p_lat);
+ const double c_p_lon = cos(p_lon);
+ const double s_p_lat = sin(p_lat);
+ const double s_p_lon = sin(p_lon);
+ const double c_q_lat = cos(q_lat);
+ const double c_q_lon = cos(q_lon);
+ const double s_q_lat = sin(q_lat);
+ const double s_q_lon = sin(q_lon);
+
+ const QDoubleVector3D p(c_p_lat * c_p_lon,
+ c_p_lat * s_p_lon,
+ s_p_lat);
+ const QDoubleVector3D q(c_q_lat * c_q_lon,
+ c_q_lat * s_q_lon,
+ s_q_lat);
+ const double qp = QDoubleVector3D::dotProduct(q, p); //scalar product of q p
+
+ if (qp <= -1.0 || qp >= 1.0)
+ continue;
+
+ // the path from q to p will be parametrized as a combination of points p and q:
+ // x = s*p + t*q.
+ // We will then directly calculate the latitude and longitude of the interpolated point x
+ // from the latitude and longitude of cornerpoints q and p.
+ // The parameters s and t depend on each other to ensure that x is located on the
+ // surface of the earth: s*s + 2*s*t*qp + t*t = 1
+ // Their minimum value is 0, as negative values indicate a path that goes around earth
+ // long way. Their maximum value follows as
+ const double paramMax = sqrt(1 / (1 - qp * qp));
+
+ double t = 0.0;
+ for (int sign = 1; sign > -2.0; sign -= 2.0) {
+ for (; t <= paramMax && t >= 0.0; t += sign * paramMax / N / 2) {
+ // dependence between s and t requires a plus/minus
+ // therefore we solve this equation two times with sign = -1/+1
+ const double s = - t * qp + sign * sqrt(t * t * (qp * qp - 1.0) + 1.0);
+ if (s < 0.0) //s > paramMax will never happen. If s < 0 we are done.
+ break;
+ const double lat = asin(s * s_p_lat + t * s_q_lat);
+ const double lon = atan2(s * c_p_lat * s_p_lon + t * c_q_lat * s_q_lon,
+ s * c_p_lat * c_p_lon + t * c_q_lat * c_q_lon);
+ path.append(QGeoCoordinate(lat * 180.0 / M_PI, lon * 180.0 / M_PI));
+ }
+ t -= paramMax / N / 2;
+ }
+ }
+ if (form == OpenPath)
+ path.append(cornerPoints.last());
+ path.squeeze();
+ return path;
+}
+
} // namespace QDeclarativeGeoMapItemUtils
QT_END_NAMESPACE
diff --git a/src/location/quickmapitems/qdeclarativegeomapitemutils_p.h b/src/location/quickmapitems/qdeclarativegeomapitemutils_p.h
index 50ece528..3637d1e4 100644
--- a/src/location/quickmapitems/qdeclarativegeomapitemutils_p.h
+++ b/src/location/quickmapitems/qdeclarativegeomapitemutils_p.h
@@ -25,6 +25,11 @@ QT_BEGIN_NAMESPACE
namespace QDeclarativeGeoMapItemUtils
{
+ enum greaterCirclePathForm {
+ OpenPath,
+ ClosedPath
+ };
+
struct vec2 {
float x;
float y;
@@ -90,6 +95,9 @@ namespace QDeclarativeGeoMapItemUtils
QRectF boundingRectangleFromList(const QList<QDoubleVector2D> &list);
+ QList<QGeoCoordinate> greaterCirclePath(const QList<QGeoCoordinate> &cornerPoints,
+ greaterCirclePathForm form = QDeclarativeGeoMapItemUtils::OpenPath,
+ int N=360);
};
QT_END_NAMESPACE
diff --git a/src/location/quickmapitems/qdeclarativepolygonmapitem.cpp b/src/location/quickmapitems/qdeclarativepolygonmapitem.cpp
index 0ace1629..40cab843 100644
--- a/src/location/quickmapitems/qdeclarativepolygonmapitem.cpp
+++ b/src/location/quickmapitems/qdeclarativepolygonmapitem.cpp
@@ -96,13 +96,26 @@ QT_BEGIN_NAMESPACE
\since 5.14
*/
+/*!
+ \qmlproperty enum QtLocation::MapPolygon::referenceSurface
+
+ This property determines the reference surface of the polygon. If it is set to
+ \l QLocation::ReferenceSurface::Map the polygons vertices are connected with straight
+ lines on the map. If it is set to \l QLocation::ReferenceSurface::Globe, the vertices
+ are connected following the great circle path, describing the shortest connection of
+ two points on a sphere.
+ Default value is \l QLocation::ReferenceSurface::Map.
+
+ \since 6.5
+*/
+
QGeoMapPolygonGeometry::QGeoMapPolygonGeometry() = default;
/*!
\internal
*/
void QGeoMapPolygonGeometry::updateSourcePoints(const QGeoMap &map,
- const QList<QList <QDoubleVector2D>> &paths,
+ const QList<QList <QDoubleVector2D>> &basePaths,
MapBorderBehaviour wrapping)
{
// A polygon consists of mutliple paths. This is usually a perimeter and multiple holes
@@ -112,17 +125,77 @@ void QGeoMapPolygonGeometry::updateSourcePoints(const QGeoMap &map,
const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(map.geoProjection());
srcPath_ = QPainterPath();
srcOrigin_ = p.mapProjectionToGeo(QDoubleVector2D(0.0, 0.0)); //avoid warning of NaN values if function is returned early
+ const QRectF cameraRect = QDeclarativeGeoMapItemUtils::boundingRectangleFromList(p.visibleGeometry());
+
+ QList<QList<QDoubleVector2D>> paths;
+
+ if (wrapping == WrapAround) {
+ // 0.1 Wrap the points around the globe if the path makes more sense that way.
+ // Ultimately, this is done if it is closer to walk around the day-border than the other direction
+ paths.reserve(basePaths.size());
+ for (qsizetype j = 0; j< basePaths.size(); j++) {
+ const QList<QDoubleVector2D> &bp = basePaths[j];
+ if (bp.isEmpty())
+ continue;
+ paths << QList<QDoubleVector2D>({bp[0]});
+ QList<QDoubleVector2D> &pp = paths[j];
+ pp.reserve(bp.size());
+ for (qsizetype i = 1; i < bp.size(); i++) {
+ if (bp[i].x() > pp.last().x() + 0.5)
+ pp << bp[i] - QDoubleVector2D(1.0, 0.0);
+ else if (bp[i].x() < pp.last().x() - 0.5)
+ pp << bp[i] + QDoubleVector2D(1.0, 0.0);
+ else
+ pp << bp[i];
+ }
+ }
+
+ // 0.2 Check and include one of the poles if necessary to make sense out of the polygon
+ for (qsizetype j = 0; j < paths.size(); j++) {
+ QList<QDoubleVector2D> &pp = paths[j];
+
+ if (pp.last().x() - pp.first().x() < -0.5) {
+ for (qsizetype i = 0; i < floor(pp.length()/2.); i++)
+ pp.swapItemsAt(i, pp.length() - i - 1);
+ }
+ if (pp.last().x() - pp.first().x() > 0.5) {
+
+ const double leftBorder = cameraRect.left();
+ const double rightBorder = cameraRect.right();
+
+ qsizetype originalPathLength = pp.length();
+
+ if (pp.last().x() < rightBorder) {
+ for (qsizetype i = 0; i < originalPathLength; i++)
+ pp.append(pp[i] + QDoubleVector2D(1.0, 0.0));
+ }
+ if (pp.first().x() > leftBorder) {
+ for (qsizetype i = 0; i < originalPathLength; i++)
+ pp.insert(i, pp[2*i] - QDoubleVector2D(1.0, 0.0));
+ }
+ const double newPoleLat = (pp.first().y() + pp.last().y() < 1.0) ? 0.0 : 1.0; //mean of y < 0.5?
+ const QDoubleVector2D P1 = pp.first();
+ const QDoubleVector2D P2 = pp.last();
+ pp.push_front(QDoubleVector2D(P1.x(), newPoleLat));
+ pp.append(QDoubleVector2D(P2.x(), newPoleLat));
+
+ wrapping = DrawOnce;
+ }
+ }
+ } else {
+ paths = basePaths;
+ }
//1 The bounding rectangle of the polygon and camera view are compared to determine if the polygon is visible
// The viewport is periodic in x-direction in the interval [-1; 1].
// The polygon (maybe) has to be ploted periodically too by shifting it by -1 or +1;
- const QRectF cameraRect = QDeclarativeGeoMapItemUtils::boundingRectangleFromList(p.visibleGeometry());
- QRectF itemRect;
- for (const auto &path : paths)
- itemRect |= QDeclarativeGeoMapItemUtils::boundingRectangleFromList(path);
QList<QList<QDoubleVector2D>> wrappedPaths;
- if (wrapping == WrapAround) {
+ if (wrapping == Duplicate || wrapping == WrapAround) {
+ QRectF itemRect;
+ for (const auto &path : paths)
+ itemRect |= QDeclarativeGeoMapItemUtils::boundingRectangleFromList(path);
+
for (double xoffset : {-1.0, 0.0, 1.0}) {
if (!cameraRect.intersects(itemRect.translated(QPointF(xoffset, 0.0))))
continue;
@@ -134,8 +207,9 @@ void QGeoMapPolygonGeometry::updateSourcePoints(const QGeoMap &map,
wP.append(coord+QDoubleVector2D(xoffset, 0.0));
}
}
- } else
+ } else {
wrappedPaths = paths;
+ }
if (wrappedPaths.isEmpty()) // the polygon boundary rectangle does not overlap with the viewport rectangle
return;
@@ -257,7 +331,10 @@ void QDeclarativePolygonMapItemPrivateCPU::updatePolish()
QScopedValueRollback<bool> rollback(m_poly.m_updatingGeometry);
m_poly.m_updatingGeometry = true;
- m_geometry.updateSourcePoints(*map, m_geopathProjected);
+ m_geometry.updateSourcePoints(*map, m_geopathProjected,
+ m_poly.referenceSurface() == QLocation::ReferenceSurface::Globe ?
+ QGeoMapPolygonGeometry::WrapAround :
+ QGeoMapPolygonGeometry::Duplicate);
const QRectF bb = m_geometry.sourceBoundingBox();
@@ -316,6 +393,8 @@ QDeclarativePolygonMapItem::QDeclarativePolygonMapItem(QQuickItem *parent)
this, &QDeclarativePolygonMapItem::onLinePropertiesChanged);
QObject::connect(&m_border, &QDeclarativeMapLineProperties::widthChanged,
this, &QDeclarativePolygonMapItem::onLinePropertiesChanged);
+ QObject::connect(this, &QDeclarativePolygonMapItem::referenceSurfaceChanged,
+ [=]() {m_d->onGeoGeometryChanged();});
}
QDeclarativePolygonMapItem::~QDeclarativePolygonMapItem()
diff --git a/src/location/quickmapitems/qdeclarativepolygonmapitem_p_p.h b/src/location/quickmapitems/qdeclarativepolygonmapitem_p_p.h
index ce0ed18e..acaa92a4 100644
--- a/src/location/quickmapitems/qdeclarativepolygonmapitem_p_p.h
+++ b/src/location/quickmapitems/qdeclarativepolygonmapitem_p_p.h
@@ -40,6 +40,7 @@ class Q_LOCATION_PRIVATE_EXPORT QGeoMapPolygonGeometry : public QGeoMapItemGeome
public:
enum MapBorderBehaviour {
DrawOnce,
+ Duplicate,
WrapAround
};
@@ -49,7 +50,7 @@ public:
void updateSourcePoints(const QGeoMap &map,
const QList<QList<QDoubleVector2D>> &path,
- MapBorderBehaviour wrapping = WrapAround);
+ MapBorderBehaviour wrapping = Duplicate);
QPainterPath srcPath() const { return srcPath_; }
qreal maxCoord() const { return maxCoord_; }
@@ -108,15 +109,33 @@ public:
m_geopathProjected.clear();
m_geopathProjected << QList<QDoubleVector2D>();
QList<QDoubleVector2D> &pP = m_geopathProjected.last();
- pP.reserve(m_poly.m_geopoly.perimeter().size());
- for (const QGeoCoordinate &c : m_poly.m_geopoly.perimeter())
- pP << p.geoToMapProjection(c);
+ if (m_poly.referenceSurface() == QLocation::ReferenceSurface::Globe) {
+ const QList<QGeoCoordinate> realPath = QDeclarativeGeoMapItemUtils::greaterCirclePath(m_poly.m_geopoly.perimeter(),
+ QDeclarativeGeoMapItemUtils::ClosedPath);
+ pP.reserve(realPath.size());
+ for (const QGeoCoordinate &c : realPath)
+ pP << p.geoToMapProjection(c);
+ } else {
+ pP.reserve(m_poly.m_geopoly.perimeter().size());
+ const QList<QGeoCoordinate> perimeter = m_poly.m_geopoly.perimeter();
+ for (const QGeoCoordinate &c : perimeter)
+ pP << p.geoToMapProjection(c);
+ }
for (int i = 0; i < m_poly.m_geopoly.holesCount(); i++) {
m_geopathProjected << QList<QDoubleVector2D>();
QList<QDoubleVector2D> &pH = m_geopathProjected.last();
- pH.reserve(m_poly.m_geopoly.holePath(i).size());
- for (const QGeoCoordinate &c : m_poly.m_geopoly.holePath(i))
- pH << p.geoToMapProjection(c);
+ if (m_poly.referenceSurface() == QLocation::ReferenceSurface::Globe) {
+ const QList<QGeoCoordinate> realPath = QDeclarativeGeoMapItemUtils::greaterCirclePath(m_poly.m_geopoly.holePath(i),
+ QDeclarativeGeoMapItemUtils::ClosedPath);
+ pH.reserve(realPath.size());
+ for (const QGeoCoordinate &c : realPath)
+ pH << p.geoToMapProjection(c);
+ } else {
+ pH.reserve(m_poly.m_geopoly.holePath(i).size());
+ const QList<QGeoCoordinate> holePath = m_poly.m_geopoly.holePath(i);
+ for (const QGeoCoordinate &c : holePath)
+ pH << p.geoToMapProjection(c);
+ }
}
}
void updateCache()
@@ -125,7 +144,11 @@ public:
return;
const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection());
QList<QDoubleVector2D> &pP = m_geopathProjected.first();
- pP << p.geoToMapProjection(m_poly.m_geopoly.perimeter().last());
+ if (m_poly.referenceSurface() == QLocation::ReferenceSurface::Globe && m_poly.m_geopoly.perimeter().size() > 1) {
+ regenerateCache(); //giving up here. Too difficult to take back all the interpolated points
+ } else {
+ pP << p.geoToMapProjection(m_poly.m_geopoly.perimeter().last());
+ }
}
void afterViewportChanged() override
{
diff --git a/src/location/quickmapitems/qdeclarativepolylinemapitem.cpp b/src/location/quickmapitems/qdeclarativepolylinemapitem.cpp
index 81c135a5..b0e88a8b 100644
--- a/src/location/quickmapitems/qdeclarativepolylinemapitem.cpp
+++ b/src/location/quickmapitems/qdeclarativepolylinemapitem.cpp
@@ -240,6 +240,19 @@ static QList<QList<QDoubleVector2D> > clipLine(
\since 5.14
*/
+/*!
+ \qmlproperty enum QtLocation::MapPolyline::referenceSurface
+
+ This property determines the reference surface of the polyline. If it is set to
+ \l QLocation::ReferenceSurface::Map the polylines vertices are connected with straight
+ lines on the map. If it is set to \l QLocation::ReferenceSurface::Globe, the vertices
+ are connected following the great circle path, describing the shortest connection of
+ two points on a sphere.
+ Default value is \l QLocation::ReferenceSurface::Map.
+
+ \since 6.5
+*/
+
QDeclarativeMapLineProperties::QDeclarativeMapLineProperties(QObject *parent)
: QObject(parent)
{
@@ -415,9 +428,17 @@ void QDeclarativePolylineMapItemPrivateCPU::regenerateCache()
return;
const QGeoProjectionWebMercator &p = static_cast<const QGeoProjectionWebMercator&>(m_poly.map()->geoProjection());
m_geopathProjected.clear();
- m_geopathProjected.reserve(m_poly.m_geopath.path().size());
- for (const QGeoCoordinate &c : m_poly.m_geopath.path())
- m_geopathProjected << p.geoToMapProjection(c);
+ if (m_poly.referenceSurface() == QLocation::ReferenceSurface::Globe) {
+ const QList<QGeoCoordinate> realPath = QDeclarativeGeoMapItemUtils::greaterCirclePath(m_poly.m_geopath.path());
+ m_geopathProjected.reserve(realPath.size());
+ for (const QGeoCoordinate &c : realPath)
+ m_geopathProjected << p.geoToMapProjection(c);
+ } else {
+ m_geopathProjected.reserve(m_poly.m_geopath.path().size());
+ const QList<QGeoCoordinate> path = m_poly.m_geopath.path();
+ for (const QGeoCoordinate &c : path)
+ m_geopathProjected << p.geoToMapProjection(c);
+ }
}
void QDeclarativePolylineMapItemPrivateCPU::updateCache()
@@ -514,6 +535,8 @@ QDeclarativePolylineMapItem::QDeclarativePolylineMapItem(QQuickItem *parent)
this, &QDeclarativePolylineMapItem::updateAfterLinePropertiesChanged);
QObject::connect(&m_line, &QDeclarativeMapLineProperties::widthChanged,
this, &QDeclarativePolylineMapItem::updateAfterLinePropertiesChanged);
+ QObject::connect(this, &QDeclarativePolylineMapItem::referenceSurfaceChanged,
+ [=]() {m_d->onGeoGeometryChanged();});
}
QDeclarativePolylineMapItem::~QDeclarativePolylineMapItem()
diff --git a/src/location/quickmapitems/qdeclarativerectanglemapitem.cpp b/src/location/quickmapitems/qdeclarativerectanglemapitem.cpp
index b1c03fd6..c3c1ea23 100644
--- a/src/location/quickmapitems/qdeclarativerectanglemapitem.cpp
+++ b/src/location/quickmapitems/qdeclarativerectanglemapitem.cpp
@@ -3,7 +3,6 @@
#include "qdeclarativerectanglemapitem_p.h"
#include "qdeclarativerectanglemapitem_p_p.h"
-#include "qdeclarativepolygonmapitem_p.h"
#include <QtCore/QScopedValueRollback>
#include <QPainterPath>
@@ -85,6 +84,19 @@ QT_BEGIN_NAMESPACE
\since 5.14
*/
+/*!
+ \qmlproperty enum QtLocation::MapRectangle::referenceSurface
+
+ This property determines the reference surface of the rectangle. If it is set to
+ \l QLocation::ReferenceSurface::Map the edge points are connected with straight lines
+ on the map. If it is set to \l QLocation::ReferenceSurface::Globe, the edge points
+ are connected following the great circle path, describing the shortest connection of
+ two points on a sphere.
+ Default value is \l QLocation::ReferenceSurface::Map.
+
+ \since 6.5
+*/
+
QDeclarativeRectangleMapItem::QDeclarativeRectangleMapItem(QQuickItem *parent)
: QDeclarativeGeoMapItemBase(parent), m_border(this),
m_d(new QDeclarativeRectangleMapItemPrivateCPU(*this))
@@ -346,10 +358,18 @@ void QDeclarativeRectangleMapItemPrivateCPU::updatePolish()
QScopedValueRollback<bool> rollback(m_rect.m_updatingGeometry);
m_rect.m_updatingGeometry = true;
- const QList<QGeoCoordinate> perimeter = QGeoMapItemGeometry::path(m_rect.m_rectangle);
- const QList<QDoubleVector2D> pathMercator_ = QGeoMapItemGeometry::pathMercator(perimeter);
- m_geometry.updateSourcePoints(*m_rect.map(), QList<QList<QDoubleVector2D>>{pathMercator_});
+ QList<QGeoCoordinate> perimeter = QGeoMapItemGeometry::path(m_rect.m_rectangle);
+
+ if (m_rect.referenceSurface() == QLocation::ReferenceSurface::Globe) {
+ perimeter = QDeclarativeGeoMapItemUtils::greaterCirclePath(perimeter,
+ QDeclarativeGeoMapItemUtils::ClosedPath);
+ }
+
+ const QList<QDoubleVector2D> pathMercator = QGeoMapItemGeometry::pathMercator(perimeter);
+ m_geometry.updateSourcePoints(*m_rect.map(), QList<QList<QDoubleVector2D>>{pathMercator},
+ m_rect.referenceSurface() == QLocation::ReferenceSurface::Globe ? QGeoMapPolygonGeometry::WrapAround :
+ QGeoMapPolygonGeometry::Duplicate);
m_rect.setShapeTriangulationScale(m_shape, m_geometry.maxCoord());
const bool hasBorder = m_rect.m_border.color().alpha() != 0 && m_rect.m_border.width() > 0;