summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Angelelli <paolo.angelelli@qt.io>2018-12-07 14:22:08 +0100
committerPaolo Angelelli <paolo.angelelli@qt.io>2018-12-21 21:51:12 +0000
commite7bb8f636086c04acd97e4eb3c42e7c6c05dc8f2 (patch)
treebf629bcd6b906672fcd8e27aada231e66e508f0c
parent1ac9abf01cf60e817a830f877fe91ef3403a7d3f (diff)
QGeoPath/QGeoPolygon: defer bbox computation
This patch introduces 2 versions of QGeoPath/polygon private: a lazy version (default) and an eager version. The reason is that certain classes such as MapItems make heavy use of the bounding box of the geoshapes, as well as the contains method, and in those cases it's beneficial to have it eagerly computed and cached. Other use cases do not see this feature so much in use, and the added costs, both in terms of computation and in terms of memory requirements for cached data can be avoided. As the patch currently stands, using copy constructors for QGeoPath and QGeoPolygon with a QGeoPathEager and a QGeoPolygonEager (and vice-versa) changes the type of d_ptr. This means that doing, for example, QGeoPath(someQGeoPathEager) effectively returns a QGeoPath that behaves like a QGeoPathEager (although not being one). Change-Id: I8cfed1e0a747139d0fb6d5fb5236bf5f5fbf24c1 Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
-rw-r--r--src/location/declarativemaps/qdeclarativepolygonmapitem.cpp4
-rw-r--r--src/location/declarativemaps/qdeclarativepolylinemapitem.cpp16
-rw-r--r--src/positioning/positioning.pro1
-rw-r--r--src/positioning/qgeopath.cpp462
-rw-r--r--src/positioning/qgeopath_p.h248
-rw-r--r--src/positioning/qgeopolygon.cpp259
-rw-r--r--src/positioning/qgeopolygon.h3
-rw-r--r--src/positioning/qgeopolygon_p.h135
8 files changed, 777 insertions, 351 deletions
diff --git a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp
index f4cdc6bf..23ea5666 100644
--- a/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp
+++ b/src/location/declarativemaps/qdeclarativepolygonmapitem.cpp
@@ -50,6 +50,7 @@
#include <QtPositioning/private/qdoublevector2d_p.h>
#include <QtPositioning/private/qclipperutils_p.h>
+#include <QtPositioning/private/qgeopolygon_p.h>
/* poly2tri triangulator includes */
#include <clip2tri.h>
@@ -318,6 +319,7 @@ QDeclarativePolygonMapItem::QDeclarativePolygonMapItem(QQuickItem *parent)
: QDeclarativeGeoMapItemBase(parent), border_(this), color_(Qt::transparent), dirtyMaterial_(true),
updatingGeometry_(false)
{
+ geopath_ = QGeoPolygonEager();
setFlag(ItemHasContents, true);
QObject::connect(&border_, SIGNAL(colorChanged(QColor)),
this, SLOT(markSourceDirtyAndUpdate()));
@@ -611,7 +613,7 @@ void QDeclarativePolygonMapItem::setGeoShape(const QGeoShape &shape)
if (shape == geopath_)
return;
- geopath_ = shape;
+ geopath_ = QGeoPathEager(shape);
regenerateCache();
geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
borderGeometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
diff --git a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp
index 2fb3098d..2bed0896 100644
--- a/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp
+++ b/src/location/declarativemaps/qdeclarativepolylinemapitem.cpp
@@ -54,6 +54,7 @@
#include <QtGui/private/qtriangulator_p.h>
#include <QtPositioning/private/qclipperutils_p.h>
+#include <QtPositioning/private/qgeopath_p.h>
#include <array>
QT_BEGIN_NAMESPACE
@@ -738,6 +739,7 @@ bool QGeoMapPolylineGeometry::contains(const QPointF &point) const
QDeclarativePolylineMapItem::QDeclarativePolylineMapItem(QQuickItem *parent)
: QDeclarativeGeoMapItemBase(parent), line_(this), dirtyMaterial_(true), updatingGeometry_(false)
{
+ geopath_ = QGeoPathEager();
setFlag(ItemHasContents, true);
QObject::connect(&line_, SIGNAL(colorChanged(QColor)),
this, SLOT(updateAfterLinePropertiesChanged()));
@@ -806,7 +808,7 @@ void QDeclarativePolylineMapItem::setPath(const QGeoPath &path)
if (geopath_.path() == path.path())
return;
- geopath_ = path;
+ geopath_ = QGeoPathEager(path);
regenerateCache();
geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
markSourceDirtyAndUpdate();
@@ -1135,18 +1137,8 @@ const QGeoShape &QDeclarativePolylineMapItem::geoShape() const
void QDeclarativePolylineMapItem::setGeoShape(const QGeoShape &shape)
{
- if (shape == geopath_)
- return;
-
const QGeoPath geopath(shape); // if shape isn't a path, path will be created as a default-constructed path
- const bool pathHasChanged = geopath.path() != geopath_.path();
- geopath_ = geopath;
-
- regenerateCache();
- geometry_.setPreserveGeometry(true, geopath_.boundingGeoRectangle().topLeft());
- markSourceDirtyAndUpdate();
- if (pathHasChanged)
- emit pathChanged();
+ setPath(geopath);
}
QGeoMap::ItemType QDeclarativePolylineMapItem::itemType() const
diff --git a/src/positioning/positioning.pro b/src/positioning/positioning.pro
index 9ba1e9c6..35e8e9e1 100644
--- a/src/positioning/positioning.pro
+++ b/src/positioning/positioning.pro
@@ -56,6 +56,7 @@ PRIVATE_HEADERS += \
qlocationdata_simulator_p.h \
qdoublematrix4x4_p.h \
qgeopath_p.h \
+ qgeopolygon_p.h \
qgeocoordinateobject_p.h \
qgeopositioninfo_p.h \
qclipperutils_p.h
diff --git a/src/positioning/qgeopath.cpp b/src/positioning/qgeopath.cpp
index 31bff2f7..843b3f1b 100644
--- a/src/positioning/qgeopath.cpp
+++ b/src/positioning/qgeopath.cpp
@@ -114,7 +114,7 @@ Q_GLOBAL_STATIC(PathVariantConversions, initPathConversions)
Constructs a new, empty geo path.
*/
QGeoPath::QGeoPath()
-: QGeoShape(new QGeoPathPrivate(QGeoShape::PathType))
+: QGeoShape(new QGeoPathPrivate())
{
initPathConversions();
}
@@ -124,7 +124,7 @@ QGeoPath::QGeoPath()
(\a path and \a width).
*/
QGeoPath::QGeoPath(const QList<QGeoCoordinate> &path, const qreal &width)
-: QGeoShape(new QGeoPathPrivate(QGeoShape::PathType, path, width))
+: QGeoShape(new QGeoPathPrivate(path, width))
{
initPathConversions();
}
@@ -146,7 +146,7 @@ QGeoPath::QGeoPath(const QGeoShape &other)
{
initPathConversions();
if (type() != QGeoShape::PathType)
- d_ptr = new QGeoPathPrivate(QGeoShape::PathType);
+ d_ptr = new QGeoPathPrivate();
}
/*!
@@ -391,128 +391,70 @@ QString QGeoPath::toString() const
}
/*******************************************************************************
- * QGeoPathPrivate
+ *
+ * QGeoPathPrivate & friends
+ *
*******************************************************************************/
-QGeoPathPrivate::QGeoPathPrivate(QGeoShape::ShapeType type)
-: QGeoShapePrivate(type), m_width(0), m_clipperDirty(true)
+QGeoPathPrivate::QGeoPathPrivate()
+: QGeoShapePrivate(QGeoShape::PathType)
{
+
}
-QGeoPathPrivate::QGeoPathPrivate(QGeoShape::ShapeType type, const QList<QGeoCoordinate> &path, const qreal width)
-: QGeoShapePrivate(type), m_width(0), m_clipperDirty(true)
+QGeoPathPrivate::QGeoPathPrivate(const QList<QGeoCoordinate> &path, const qreal width)
+: QGeoShapePrivate(QGeoShape::PathType)
{
setPath(path);
setWidth(width);
}
-QGeoPathPrivate::QGeoPathPrivate(const QGeoPathPrivate &other)
-: QGeoShapePrivate(other.type), m_path(other.m_path),
- m_deltaXs(other.m_deltaXs), m_minX(other.m_minX), m_maxX(other.m_maxX), m_minLati(other.m_minLati),
- m_maxLati(other.m_maxLati), m_bbox(other.m_bbox), m_width(other.m_width), m_clipperDirty(true)
+QGeoPathPrivate::~QGeoPathPrivate()
{
-}
-QGeoPathPrivate::~QGeoPathPrivate() {}
+}
QGeoShapePrivate *QGeoPathPrivate::clone() const
{
return new QGeoPathPrivate(*this);
}
-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;
-
- if (type == QGeoShape::PathType)
- return m_width == otherPath.m_width && m_path == otherPath.m_path;
- else
- return m_path == otherPath.m_path && m_holesList == otherPath.m_holesList;
-}
-
bool QGeoPathPrivate::isValid() const
{
- if (type == QGeoShape::PathType)
- return !isEmpty();
- else
- return m_path.size() > 2;
-
+ return !isEmpty();
}
bool QGeoPathPrivate::isEmpty() const
{
- return m_path.isEmpty(); // this should perhaps return geometric emptiness, less than 2 points for line, or empty polygon for polygons
-}
-
-const QList<QGeoCoordinate> &QGeoPathPrivate::path() const
-{
- return m_path;
-}
-
-void QGeoPathPrivate::setPath(const QList<QGeoCoordinate> &path)
-{
- for (const QGeoCoordinate &c: path)
- if (!c.isValid())
- return;
- m_path = path;
- computeBoundingBox();
-}
-
-void QGeoPathPrivate::clearPath()
-{
- m_path.clear();
- computeBoundingBox();
+ return path().isEmpty(); // this should perhaps return geometric emptiness, less than 2 points for line, or empty polygon for polygons
}
-qreal QGeoPathPrivate::width() const
+QGeoCoordinate QGeoPathPrivate::center() const
{
- return m_width;
+ return boundingGeoRectangle().center();
}
-void QGeoPathPrivate::setWidth(const qreal &width)
+void QGeoPathPrivate::extendShape(const QGeoCoordinate &coordinate)
{
- if (qIsNaN(width) || width < 0.0)
+ if (!coordinate.isValid() || contains(coordinate))
return;
- m_width = width;
+ addCoordinate(coordinate);
}
-double QGeoPathPrivate::length(int indexFrom, int indexTo) const
+bool QGeoPathPrivate::operator==(const QGeoShapePrivate &other) 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 (int 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;
-}
+ if (!QGeoShapePrivate::operator==(other))
+ return false;
-int QGeoPathPrivate::size() const
-{
- return m_path.size();
+ 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;
}
-/*!
- Returns true if coordinate is present in m_path.
-*/
-bool QGeoPathPrivate::contains(const QGeoCoordinate &coordinate) const
+const QList<QGeoCoordinate> &QGeoPathPrivate::path() const
{
- if (type == QGeoShape::PathType)
- return lineContains(coordinate);
- else
- return polygonContains(coordinate);
+ return m_path;
}
bool QGeoPathPrivate::lineContains(const QGeoCoordinate &coordinate) const
@@ -584,54 +526,67 @@ bool QGeoPathPrivate::lineContains(const QGeoCoordinate &coordinate) const
return (m_path[0].distanceTo(coordinate) <= lineRadius);
}
-/*!
- modified version of polygonContains with holes support.
-*/
-bool QGeoPathPrivate::polygonContains(const QGeoCoordinate &coordinate) const
+bool QGeoPathPrivate::contains(const QGeoCoordinate &coordinate) const
{
- if (m_clipperDirty)
- const_cast<QGeoPathPrivate *>(this)->updateClipperPath();
-
- // iterates the holes List checking whether the point is contained inside the holes
- for (const QList<QGeoCoordinate> &holePath : qAsConst(m_holesList)) {
+ return lineContains(coordinate);
+}
- QGeoPolygon holePolygon;
- holePolygon.setPath(holePath);
- QGeoPath holeBoundary;
- holeBoundary.setPath(holePath);
+qreal QGeoPathPrivate::width() const
+{
+ return m_width;
+}
- if (holePolygon.contains(coordinate) && !(holeBoundary.contains(coordinate)))
- return false;
- }
+void QGeoPathPrivate::setWidth(const qreal &width)
+{
+ if (qIsNaN(width) || width < 0.0)
+ return;
+ m_width = width;
+}
- QDoubleVector2D coord = QWebMercator::coordToMercator(coordinate);
- double tlx = QWebMercator::coordToMercator(m_bbox.topLeft()).x();
- if (coord.x() < tlx)
- coord.setX(coord.x() + 1.0);
+double QGeoPathPrivate::length(int indexFrom, int indexTo) const
+{
+ if (path().isEmpty())
+ return 0.0;
- IntPoint intCoord = QClipperUtils::toIntPoint(coord);
- return c2t::clip2tri::pointInPolygon(intCoord, m_clipperPath) != 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 (int 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;
}
-QGeoCoordinate QGeoPathPrivate::center() const
+int QGeoPathPrivate::size() const
{
- return boundingGeoRectangle().center();
+ return m_path.size();
}
-QGeoRectangle QGeoPathPrivate::boundingGeoRectangle() const
+QGeoCoordinate QGeoPathPrivate::coordinateAt(int index) const
{
- return m_bbox;
+ if (index < 0 || index >= m_path.size())
+ return QGeoCoordinate();
+
+ return m_path.at(index);
}
-void QGeoPathPrivate::extendShape(const QGeoCoordinate &coordinate)
+bool QGeoPathPrivate::containsCoordinate(const QGeoCoordinate &coordinate) const
{
- if (!coordinate.isValid() || contains(coordinate))
- return;
- addCoordinate(coordinate);
+ return m_path.indexOf(coordinate) > -1;
}
void QGeoPathPrivate::translate(double degreesLatitude, double degreesLongitude)
{
+ // Need min/maxLati, so update bbox
+ QVector<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
@@ -640,17 +595,29 @@ void QGeoPathPrivate::translate(double degreesLatitude, double degreesLongitude)
p.setLatitude(p.latitude() + degreesLatitude);
p.setLongitude(QLocationUtils::wrapLong(p.longitude() + degreesLongitude));
}
- if (!m_holesList.isEmpty()){
- for (QList<QGeoCoordinate> &hole: m_holesList){
- for (QGeoCoordinate &holeVertex: hole){
- holeVertex.setLatitude(holeVertex.latitude() + degreesLatitude);
- holeVertex.setLongitude(QLocationUtils::wrapLong(holeVertex.longitude() + degreesLongitude));
- }
- }
- }
m_bbox.translate(degreesLatitude, degreesLongitude);
- m_minLati += degreesLatitude;
- m_maxLati += degreesLatitude;
+}
+
+QGeoRectangle QGeoPathPrivate::boundingGeoRectangle() const
+{
+ if (m_bboxDirty)
+ const_cast<QGeoPathPrivate &>(*this).computeBoundingBox();
+ return m_bbox;
+}
+
+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)
@@ -658,38 +625,23 @@ void QGeoPathPrivate::addCoordinate(const QGeoCoordinate &coordinate)
if (!coordinate.isValid())
return;
m_path.append(coordinate);
- updateBoundingBox();
+ markDirty();
}
void QGeoPathPrivate::insertCoordinate(int index, const QGeoCoordinate &coordinate)
{
if (index < 0 || index > m_path.size() || !coordinate.isValid())
return;
-
m_path.insert(index, coordinate);
- computeBoundingBox();
+ markDirty();
}
void QGeoPathPrivate::replaceCoordinate(int index, const QGeoCoordinate &coordinate)
{
if (index < 0 || index >= m_path.size() || !coordinate.isValid())
return;
-
m_path[index] = coordinate;
- computeBoundingBox();
-}
-
-QGeoCoordinate QGeoPathPrivate::coordinateAt(int 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;
+ markDirty();
}
void QGeoPathPrivate::removeCoordinate(const QGeoCoordinate &coordinate)
@@ -702,171 +654,121 @@ void QGeoPathPrivate::removeCoordinate(int index)
{
if (index < 0 || index >= m_path.size())
return;
-
m_path.removeAt(index);
- computeBoundingBox();
+ markDirty();
+}
+
+void QGeoPathPrivate::markDirty()
+{
+ m_bboxDirty = true;
}
void QGeoPathPrivate::computeBoundingBox()
{
- m_clipperDirty = true;
- if (m_path.isEmpty()) {
- m_deltaXs.clear();
- m_minX = qInf();
- m_maxX = -qInf();
- m_minLati = qInf();
- m_maxLati = -qInf();
- m_bbox = QGeoRectangle();
- return;
- }
+ QVector<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_minLati = m_maxLati = m_path.at(0).latitude();
- int minId = 0;
- int maxId = 0;
- m_deltaXs.resize(m_path.size());
- m_deltaXs[0] = m_minX = m_maxX = 0.0;
+QGeoPathPrivateEager::QGeoPathPrivateEager()
+: QGeoPathPrivate()
+{
+ m_bboxDirty = false; // never dirty on the eager version
+}
- for (int i = 1; i < m_path.size(); i++) {
- const QGeoCoordinate &geoFrom = m_path.at(i-1);
- const QGeoCoordinate &geoTo = m_path.at(i);
- double longiFrom = geoFrom.longitude();
- double longiTo = geoTo.longitude();
- double deltaLongi = longiTo - longiFrom;
- if (qAbs(deltaLongi) > 180.0) {
- if (longiTo > 0.0)
- longiTo -= 360.0;
- else
- longiTo += 360.0;
- deltaLongi = longiTo - longiFrom;
- }
- m_deltaXs[i] = m_deltaXs[i-1] + deltaLongi;
- if (m_deltaXs[i] < m_minX) {
- m_minX = m_deltaXs[i];
- minId = i;
- }
- if (m_deltaXs[i] > m_maxX) {
- m_maxX = m_deltaXs[i];
- maxId = i;
- }
- if (geoTo.latitude() > m_maxLati)
- m_maxLati = geoTo.latitude();
- if (geoTo.latitude() < m_minLati)
- m_minLati = geoTo.latitude();
- }
+QGeoPathPrivateEager::QGeoPathPrivateEager(const QList<QGeoCoordinate> &path, const qreal width)
+: QGeoPathPrivate(path, width)
+{
+ m_bboxDirty = false; // never dirty on the eager version
+}
+
+QGeoPathPrivateEager::~QGeoPathPrivateEager()
+{
- m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, m_path.at(minId).longitude()),
- QGeoCoordinate(m_minLati, m_path.at(maxId).longitude()));
}
-void QGeoPathPrivate::updateBoundingBox()
+QGeoShapePrivate *QGeoPathPrivateEager::clone() const
{
- m_clipperDirty = true;
- if (m_path.isEmpty()) {
- m_deltaXs.clear();
- m_minX = qInf();
- m_maxX = -qInf();
- m_minLati = qInf();
- m_maxLati = -qInf();
- m_bbox = QGeoRectangle();
- return;
- } else if (m_path.size() == 1) { // was 0 now is 1
- m_deltaXs.resize(1);
- m_deltaXs[0] = m_minX = m_maxX = 0.0;
- m_minLati = m_maxLati = m_path.at(0).latitude();
- m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, m_path.at(0).longitude()),
- QGeoCoordinate(m_minLati, m_path.at(0).longitude()));
- return;
- } else if ( m_path.size() != m_deltaXs.size() + 1 ) { // this case should not happen
- computeBoundingBox(); // something went wrong
- return;
- }
+ return new QGeoPathPrivateEager(*this);
+}
- const QGeoCoordinate &geoFrom = m_path.at(m_path.size()-2);
- const QGeoCoordinate &geoTo = m_path.last();
- double longiFrom = geoFrom.longitude();
- double longiTo = geoTo.longitude();
- double deltaLongi = longiTo - longiFrom;
- if (qAbs(deltaLongi) > 180.0) {
- if (longiTo > 0.0)
- longiTo -= 360.0;
- else
- longiTo += 360.0;
- deltaLongi = longiTo - longiFrom;
- }
+void QGeoPathPrivateEager::markDirty()
+{
+ computeBoundingBox();
+}
- m_deltaXs.push_back(m_deltaXs.last() + deltaLongi);
- double currentMinLongi = m_bbox.topLeft().longitude();
- double currentMaxLongi = m_bbox.bottomRight().longitude();
- if (m_deltaXs.last() < m_minX) {
- m_minX = m_deltaXs.last();
- currentMinLongi = geoTo.longitude();
- }
- if (m_deltaXs.last() > m_maxX) {
- m_maxX = m_deltaXs.last();
- currentMaxLongi = geoTo.longitude();
- }
- if (geoTo.latitude() > m_maxLati)
- m_maxLati = geoTo.latitude();
- if (geoTo.latitude() < m_minLati)
- m_minLati = geoTo.latitude();
- m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, currentMinLongi),
- QGeoCoordinate(m_minLati, currentMaxLongi));
-}
-
-void QGeoPathPrivate::updateClipperPath()
-{
- 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)
- crd.setX(crd.x() + 1.0);
- preservedPath << crd;
+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_clipperPath = QClipperUtils::qListToPath(preservedPath);
+ m_bbox.translate(degreesLatitude, degreesLongitude);
+ m_minLati += degreesLatitude;
+ m_maxLati += degreesLatitude;
}
-
-/*!
- Sets the \a path for an Hole inside the polygon.The hole has QList<QGeoCoordinate> type
-*/
-void QGeoPathPrivate::addHole(const QList<QGeoCoordinate> &holePath)
+void QGeoPathPrivateEager::addCoordinate(const QGeoCoordinate &coordinate)
{
- for (const QGeoCoordinate &holeVertex: holePath)
- if (!holeVertex.isValid())
- return;
+ if (!coordinate.isValid())
+ return;
+ m_path.append(coordinate);
+ //m_clipperDirty = true; // clipper not used in polylines
+ updateBoundingBox();
+}
- m_holesList << holePath;
+void QGeoPathPrivateEager::QGeoPathPrivateEager::computeBoundingBox()
+{
+ computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
}
-/*!
- Returns a QVariant containing a QList<QGeoCoordinate> representing the hole at index
-*/
-const QList<QGeoCoordinate> QGeoPathPrivate::holePath(int index) const
+void QGeoPathPrivateEager::QGeoPathPrivateEager::updateBoundingBox()
{
- return m_holesList.at(index);
+ updateBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
}
+QGeoPathEager::QGeoPathEager() : QGeoPath()
+{
+ initPathConversions();
+ d_ptr = new QGeoPathPrivateEager;
+}
-/*!
- Removes element at position \a index from the holes QList.
-*/
-void QGeoPathPrivate::removeHole(int index)
+QGeoPathEager::QGeoPathEager(const QList<QGeoCoordinate> &path, const qreal &width) : QGeoPath()
{
- if (index < 0 || index >= m_holesList.size())
- return;
+ initPathConversions();
+ d_ptr = new QGeoPathPrivateEager(path, width);
+}
- m_holesList.removeAt(index);
+QGeoPathEager::QGeoPathEager(const QGeoPath &other) : QGeoPath()
+{
+ initPathConversions();
+ d_ptr = new QGeoPathPrivateEager;
+ setPath(other.path());
+ setWidth(other.width());
}
-/*!
- Returns the number of holes.
-*/
-int QGeoPathPrivate::holesCount() const
+QGeoPathEager::QGeoPathEager(const QGeoShape &other) : QGeoPath()
{
- return m_holesList.size();
+ initPathConversions();
+ if (other.type() == QGeoShape::PathType)
+ *this = QGeoPathEager(QGeoPath(other));
+ else
+ d_ptr = new QGeoPathPrivateEager;
}
+QGeoPathEager::~QGeoPathEager() {}
+
QT_END_NAMESPACE
+
+
+
+
+
+
+
diff --git a/src/positioning/qgeopath_p.h b/src/positioning/qgeopath_p.h
index d39f0ab2..4fffe61d 100644
--- a/src/positioning/qgeopath_p.h
+++ b/src/positioning/qgeopath_p.h
@@ -51,73 +51,217 @@
// We mean it.
//
+#include <QtPositioning/private/qpositioningglobal_p.h>
#include "qgeoshape_p.h"
#include "qgeocoordinate.h"
#include "qlocationutils_p.h"
#include <QtPositioning/private/qclipperutils_p.h>
-
+#include <QtPositioning/qgeopath.h>
#include <QtCore/QVector>
QT_BEGIN_NAMESPACE
-class QGeoPathPrivate : public QGeoShapePrivate
+inline static void computeBBox( const QList<QGeoCoordinate> &m_path,
+ QVector<double> &m_deltaXs,
+ double &m_minX,
+ double &m_maxX,
+ double &m_minLati,
+ double &m_maxLati,
+ QGeoRectangle &m_bbox)
+{
+ if (m_path.isEmpty()) {
+ m_deltaXs.clear();
+ m_minX = qInf();
+ m_maxX = -qInf();
+ m_minLati = qInf();
+ m_maxLati = -qInf();
+ m_bbox = QGeoRectangle();
+ return;
+ }
+
+ m_minLati = m_maxLati = m_path.at(0).latitude();
+ int minId = 0;
+ int maxId = 0;
+ m_deltaXs.resize(m_path.size());
+ m_deltaXs[0] = m_minX = m_maxX = 0.0;
+
+ for (int i = 1; i < m_path.size(); i++) {
+ const QGeoCoordinate &geoFrom = m_path.at(i-1);
+ const QGeoCoordinate &geoTo = m_path.at(i);
+ double longiFrom = geoFrom.longitude();
+ double longiTo = geoTo.longitude();
+ double deltaLongi = longiTo - longiFrom;
+ if (qAbs(deltaLongi) > 180.0) {
+ if (longiTo > 0.0)
+ longiTo -= 360.0;
+ else
+ longiTo += 360.0;
+ deltaLongi = longiTo - longiFrom;
+ }
+ m_deltaXs[i] = m_deltaXs[i-1] + deltaLongi;
+ if (m_deltaXs[i] < m_minX) {
+ m_minX = m_deltaXs[i];
+ minId = i;
+ }
+ if (m_deltaXs[i] > m_maxX) {
+ m_maxX = m_deltaXs[i];
+ maxId = i;
+ }
+ if (geoTo.latitude() > m_maxLati)
+ m_maxLati = geoTo.latitude();
+ if (geoTo.latitude() < m_minLati)
+ m_minLati = geoTo.latitude();
+ }
+
+ m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, m_path.at(minId).longitude()),
+ QGeoCoordinate(m_minLati, m_path.at(maxId).longitude()));
+}
+
+inline static void updateBBox( const QList<QGeoCoordinate> &m_path,
+ QVector<double> &m_deltaXs,
+ double &m_minX,
+ double &m_maxX,
+ double &m_minLati,
+ double &m_maxLati,
+ QGeoRectangle &m_bbox)
+{
+ if (m_path.isEmpty()) {
+ m_deltaXs.clear();
+ m_minX = qInf();
+ m_maxX = -qInf();
+ m_minLati = qInf();
+ m_maxLati = -qInf();
+ m_bbox = QGeoRectangle();
+ return;
+ } else if (m_path.size() == 1) { // was 0 now is 1
+ m_deltaXs.resize(1);
+ m_deltaXs[0] = m_minX = m_maxX = 0.0;
+ m_minLati = m_maxLati = m_path.at(0).latitude();
+ m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, m_path.at(0).longitude()),
+ QGeoCoordinate(m_minLati, m_path.at(0).longitude()));
+ return;
+ } else if ( m_path.size() != m_deltaXs.size() + 1 ) { // this case should not happen
+ computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox); // something went wrong
+ return;
+ }
+
+ const QGeoCoordinate &geoFrom = m_path.at(m_path.size()-2);
+ const QGeoCoordinate &geoTo = m_path.last();
+ double longiFrom = geoFrom.longitude();
+ double longiTo = geoTo.longitude();
+ double deltaLongi = longiTo - longiFrom;
+ if (qAbs(deltaLongi) > 180.0) {
+ if (longiTo > 0.0)
+ longiTo -= 360.0;
+ else
+ longiTo += 360.0;
+ deltaLongi = longiTo - longiFrom;
+ }
+
+ m_deltaXs.push_back(m_deltaXs.last() + deltaLongi);
+ double currentMinLongi = m_bbox.topLeft().longitude();
+ double currentMaxLongi = m_bbox.bottomRight().longitude();
+ if (m_deltaXs.last() < m_minX) {
+ m_minX = m_deltaXs.last();
+ currentMinLongi = geoTo.longitude();
+ }
+ if (m_deltaXs.last() > m_maxX) {
+ m_maxX = m_deltaXs.last();
+ currentMaxLongi = geoTo.longitude();
+ }
+ if (geoTo.latitude() > m_maxLati)
+ m_maxLati = geoTo.latitude();
+ if (geoTo.latitude() < m_minLati)
+ m_minLati = geoTo.latitude();
+ m_bbox = QGeoRectangle(QGeoCoordinate(m_maxLati, currentMinLongi),
+ QGeoCoordinate(m_minLati, currentMaxLongi));
+}
+
+// Lazy by default. Eager, within the module, used only in MapItems/MapObjectsQSG
+class Q_POSITIONING_PRIVATE_EXPORT QGeoPathPrivate : public QGeoShapePrivate
{
public:
- QGeoPathPrivate(QGeoShape::ShapeType type);
- QGeoPathPrivate(QGeoShape::ShapeType type, const QList<QGeoCoordinate> &path, const qreal width = 0.0);
- QGeoPathPrivate(const QGeoPathPrivate &other);
+ QGeoPathPrivate();
+ QGeoPathPrivate(const QList<QGeoCoordinate> &path, const qreal width = 0.0);
~QGeoPathPrivate();
- bool isValid() const override;
- bool isEmpty() const override;
- bool contains(const QGeoCoordinate &coordinate) const override;
- bool lineContains(const QGeoCoordinate &coordinate) const;
- bool polygonContains(const QGeoCoordinate &coordinate) const;
-
- QGeoCoordinate center() const override;
- QGeoRectangle boundingGeoRectangle() const override;
- void extendShape(const QGeoCoordinate &coordinate) override;
- void translate(double degreesLatitude, double degreesLongitude);
-
- QGeoShapePrivate *clone() const override;
-
- bool operator==(const QGeoShapePrivate &other) const override;
-
- const QList<QGeoCoordinate> &path() const;
- void setPath(const QList<QGeoCoordinate> &path);
- void clearPath();
-
- qreal width() const;
- void setWidth(const qreal &width);
- double length(int indexFrom, int indexTo) const;
- int size() const;
- void addCoordinate(const QGeoCoordinate &coordinate);
- void insertCoordinate(int index, const QGeoCoordinate &coordinate);
- void replaceCoordinate(int index, const QGeoCoordinate &coordinate);
- QGeoCoordinate coordinateAt(int index) const;
- bool containsCoordinate(const QGeoCoordinate &coordinate) const;
- void removeCoordinate(const QGeoCoordinate &coordinate);
- void removeCoordinate(int index);
- void computeBoundingBox();
- void updateBoundingBox();
- void updateClipperPath();
- void addHole(const QList<QGeoCoordinate> &holePath);
- const QList<QGeoCoordinate> holePath(int index) const;
- void removeHole(int index);
- int holesCount() const;
+// QGeoShape API
+ virtual QGeoShapePrivate *clone() const override;
+ virtual bool isValid() const override;
+ virtual bool isEmpty() const override;
+ virtual QGeoCoordinate center() const override;
+ virtual bool operator==(const QGeoShapePrivate &other) const override;
+ virtual bool contains(const QGeoCoordinate &coordinate) const override;
+ virtual QGeoRectangle boundingGeoRectangle() const override;
+ virtual void extendShape(const QGeoCoordinate &coordinate) override;
+// QGeoPathPrivate API
+ virtual const QList<QGeoCoordinate> &path() const;
+ virtual bool lineContains(const QGeoCoordinate &coordinate) const;
+ virtual qreal width() const;
+ virtual double length(int indexFrom, int indexTo) const;
+ virtual int size() const;
+ virtual QGeoCoordinate coordinateAt(int index) const;
+ virtual bool containsCoordinate(const QGeoCoordinate &coordinate) const;
+
+ virtual void setWidth(const qreal &width);
+ virtual void translate(double degreesLatitude, double degreesLongitude);
+ virtual void setPath(const QList<QGeoCoordinate> &path);
+ virtual void clearPath();
+ virtual void addCoordinate(const QGeoCoordinate &coordinate);
+ virtual void insertCoordinate(int index, const QGeoCoordinate &coordinate);
+ virtual void replaceCoordinate(int index, const QGeoCoordinate &coordinate);
+ virtual void removeCoordinate(const QGeoCoordinate &coordinate);
+ virtual void removeCoordinate(int index);
+ virtual void computeBoundingBox();
+ virtual void markDirty();
+
+// data members
QList<QGeoCoordinate> m_path;
- QList<QList<QGeoCoordinate>> m_holesList;
- QVector<double> m_deltaXs; // longitude deltas from m_path[0]
- double m_minX; // minimum value inside deltaXs
- double m_maxX; // maximum value inside deltaXs
- double m_minLati; // minimum latitude. paths do not wrap around through the poles
- double m_maxLati; // minimum latitude. paths do not wrap around through the poles
- QGeoRectangle m_bbox;
- qreal m_width;
- bool m_clipperDirty;
- QtClipperLib::Path m_clipperPath;
+ qreal m_width = 0;
+ QGeoRectangle m_bbox; // cached
+ bool m_bboxDirty = false;
+};
+
+class Q_POSITIONING_PRIVATE_EXPORT QGeoPathPrivateEager : public QGeoPathPrivate
+{
+public:
+ QGeoPathPrivateEager();
+ QGeoPathPrivateEager(const QList<QGeoCoordinate> &path, const qreal width = 0.0);
+ ~QGeoPathPrivateEager();
+
+// QGeoShapePrivate API
+ virtual QGeoShapePrivate *clone() const override;
+ virtual void translate(double degreesLatitude, double degreesLongitude) override;
+
+// QGeoShapePrivate API
+ virtual void markDirty() override;
+ virtual void addCoordinate(const QGeoCoordinate &coordinate) override;
+ virtual void computeBoundingBox() override;
+
+// *Eager API
+ void updateBoundingBox();
+
+// data members
+ QVector<double> m_deltaXs; // longitude deltas from m_path[0]
+ double m_minX = 0; // minimum value inside deltaXs
+ double m_maxX = 0; // maximum value inside deltaXs
+ double m_minLati = 0; // minimum latitude. paths do not wrap around through the poles
+ double m_maxLati = 0; // minimum latitude. paths do not wrap around through the poles
+};
+
+// This is a mean of creating a QGeoPathPrivateEager and injecting it into QGeoPaths via operator=
+class Q_POSITIONING_PRIVATE_EXPORT QGeoPathEager : public QGeoPath
+{
+ Q_GADGET
+public:
+
+ QGeoPathEager();
+ QGeoPathEager(const QList<QGeoCoordinate> &path, const qreal &width = 0.0);
+ QGeoPathEager(const QGeoPath &other);
+ QGeoPathEager(const QGeoShape &other);
+ ~QGeoPathEager();
};
QT_END_NAMESPACE
diff --git a/src/positioning/qgeopolygon.cpp b/src/positioning/qgeopolygon.cpp
index 66659d4b..4e902be5 100644
--- a/src/positioning/qgeopolygon.cpp
+++ b/src/positioning/qgeopolygon.cpp
@@ -38,7 +38,7 @@
****************************************************************************/
#include "qgeopolygon.h"
-#include "qgeopath_p.h"
+#include "qgeopolygon_p.h"
#include "qgeocoordinate.h"
#include "qnumeric.h"
@@ -111,7 +111,7 @@ Q_GLOBAL_STATIC(PolygonVariantConversions, initPolygonConversions)
Constructs a new, empty geo polygon.
*/
QGeoPolygon::QGeoPolygon()
-: QGeoShape(new QGeoPolygonPrivate(QGeoShape::PolygonType))
+: QGeoShape(new QGeoPolygonPrivate())
{
initPolygonConversions();
}
@@ -120,7 +120,7 @@ QGeoPolygon::QGeoPolygon()
Constructs a new geo \a polygon from a list of coordinates.
*/
QGeoPolygon::QGeoPolygon(const QList<QGeoCoordinate> &path)
-: QGeoShape(new QGeoPolygonPrivate(QGeoShape::PolygonType, path))
+: QGeoShape(new QGeoPolygonPrivate(path))
{
initPolygonConversions();
}
@@ -142,7 +142,7 @@ QGeoPolygon::QGeoPolygon(const QGeoShape &other)
{
initPolygonConversions();
if (type() != QGeoShape::PolygonType)
- d_ptr = new QGeoPolygonPrivate(QGeoShape::PolygonType);
+ d_ptr = new QGeoPolygonPrivate();
}
/*!
@@ -432,4 +432,255 @@ int QGeoPolygon::holesCount() const
return d->holesCount();
}
+/*******************************************************************************
+ *
+ * QGeoPathPrivate & friends
+ *
+*******************************************************************************/
+
+QGeoPolygonPrivate::QGeoPolygonPrivate()
+: QGeoPathPrivate()
+{
+ type = QGeoShape::PolygonType;
+}
+
+QGeoPolygonPrivate::QGeoPolygonPrivate(const QList<QGeoCoordinate> &path)
+: QGeoPathPrivate(path)
+{
+ type = QGeoShape::PolygonType;
+}
+
+QGeoPolygonPrivate::~QGeoPolygonPrivate() {}
+
+QGeoShapePrivate *QGeoPolygonPrivate::clone() const
+{
+ return new QGeoPolygonPrivate(*this);
+}
+
+bool QGeoPolygonPrivate::isValid() const
+{
+ return path().size() > 2;
+}
+
+bool QGeoPolygonPrivate::contains(const QGeoCoordinate &coordinate) const
+{
+ return polygonContains(coordinate);
+}
+
+inline static void translatePoly( QList<QGeoCoordinate> &m_path,
+ QList<QList<QGeoCoordinate>> &m_holesList,
+ QGeoRectangle &m_bbox,
+ double degreesLatitude,
+ double degreesLongitude,
+ double m_maxLati,
+ double m_minLati)
+{
+ 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));
+ }
+ if (!m_holesList.isEmpty()){
+ for (QList<QGeoCoordinate> &hole: m_holesList){
+ for (QGeoCoordinate &holeVertex: hole){
+ holeVertex.setLatitude(holeVertex.latitude() + degreesLatitude);
+ holeVertex.setLongitude(QLocationUtils::wrapLong(holeVertex.longitude() + degreesLongitude));
+ }
+ }
+ }
+ m_bbox.translate(degreesLatitude, degreesLongitude);
+}
+
+void QGeoPolygonPrivate::translate(double degreesLatitude, double degreesLongitude)
+{
+ // Need min/maxLati, so update bbox
+ QVector<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);
+
+ translatePoly(m_path, m_holesList, m_bbox, degreesLatitude, degreesLongitude, m_maxLati, m_minLati);
+}
+
+bool QGeoPolygonPrivate::operator==(const QGeoShapePrivate &other) const
+{
+ if (!QGeoShapePrivate::operator==(other)) // checks type
+ return false;
+
+ const QGeoPolygonPrivate &otherPath = static_cast<const QGeoPolygonPrivate &>(other);
+ if (m_path.size() != otherPath.m_path.size()
+ || m_holesList.size() != otherPath.m_holesList.size())
+ return false;
+ return m_path == otherPath.m_path && m_holesList == otherPath.m_holesList;
+}
+
+void QGeoPolygonPrivate::addHole(const QList<QGeoCoordinate> &holePath)
+{
+ for (const QGeoCoordinate &holeVertex: holePath)
+ if (!holeVertex.isValid())
+ return;
+
+ m_holesList << holePath;
+ // ToDo: mark clipper dirty when hole caching gets added
+}
+
+const QList<QGeoCoordinate> QGeoPolygonPrivate::holePath(int index) const
+{
+ return m_holesList.at(index);
+}
+
+void QGeoPolygonPrivate::removeHole(int index)
+{
+ if (index < 0 || index >= m_holesList.size())
+ return;
+
+ m_holesList.removeAt(index);
+ // ToDo: mark clipper dirty when hole caching gets added
+}
+
+int QGeoPolygonPrivate::holesCount() const
+{
+ return m_holesList.size();
+}
+
+bool QGeoPolygonPrivate::polygonContains(const QGeoCoordinate &coordinate) const
+{
+ if (m_clipperDirty)
+ 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)
+ coord.setX(coord.x() + 1.0);
+
+ IntPoint intCoord = QClipperUtils::toIntPoint(coord);
+ if (!c2t::clip2tri::pointInPolygon(intCoord, m_clipperPath))
+ return false;
+
+ // else iterates the holes List checking whether the point is contained inside the holes
+ for (const QList<QGeoCoordinate> &holePath : qAsConst(m_holesList)) {
+ // ToDo: cache these
+ QGeoPolygon holePolygon;
+ holePolygon.setPath(holePath);
+ // QGeoPath holeBoundary;
+ // holeBoundary.setPath(holePath);
+
+ if (holePolygon.contains(coordinate)
+ // && !(holeBoundary.contains(coordinate))
+ )
+ return false;
+ }
+ return true;
+}
+
+void QGeoPolygonPrivate::markDirty()
+{
+ m_bboxDirty = m_clipperDirty = true;
+}
+
+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)
+ crd.setX(crd.x() + 1.0);
+ preservedPath << crd;
+ }
+ m_clipperPath = QClipperUtils::qListToPath(preservedPath);
+}
+
+QGeoPolygonPrivateEager::QGeoPolygonPrivateEager() : QGeoPolygonPrivate()
+{
+ m_bboxDirty = false; // never dirty on the eager version
+}
+
+QGeoPolygonPrivateEager::QGeoPolygonPrivateEager(const QList<QGeoCoordinate> &path) : QGeoPolygonPrivate(path)
+{
+ m_bboxDirty = false; // never dirty on the eager version
+}
+
+QGeoPolygonPrivateEager::~QGeoPolygonPrivateEager()
+{
+
+}
+
+QGeoShapePrivate *QGeoPolygonPrivateEager::clone() const
+{
+ return new QGeoPolygonPrivate(*this);
+}
+
+void QGeoPolygonPrivateEager::translate(double degreesLatitude, double degreesLongitude)
+{
+ translatePoly(m_path, m_holesList, m_bbox, degreesLatitude, degreesLongitude, m_maxLati, m_minLati);
+}
+
+void QGeoPolygonPrivateEager::markDirty()
+{
+ m_clipperDirty = true;
+ computeBoundingBox();
+}
+
+void QGeoPolygonPrivateEager::addCoordinate(const QGeoCoordinate &coordinate)
+{
+ if (!coordinate.isValid())
+ return;
+ m_path.append(coordinate);
+ m_clipperDirty = true;
+ updateBoundingBox(); // do not markDirty as it uses computeBoundingBox instead
+}
+
+void QGeoPolygonPrivateEager::computeBoundingBox()
+{
+ computeBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
+}
+
+void QGeoPolygonPrivateEager::updateBoundingBox()
+{
+ updateBBox(m_path, m_deltaXs, m_minX, m_maxX, m_minLati, m_maxLati, m_bbox);
+}
+
+QGeoPolygonEager::QGeoPolygonEager() : QGeoPolygon()
+{
+ initPolygonConversions();
+ d_ptr = new QGeoPolygonPrivateEager;
+}
+
+QGeoPolygonEager::QGeoPolygonEager(const QList<QGeoCoordinate> &path) : QGeoPolygon()
+{
+ initPolygonConversions();
+ d_ptr = new QGeoPolygonPrivateEager(path);
+}
+
+QGeoPolygonEager::QGeoPolygonEager(const QGeoPolygon &other) : QGeoPolygon()
+{
+ initPolygonConversions();
+ // without being able to dynamic_cast the d_ptr, only way to be sure is to reconstruct a new QGeoPolygonPrivateEager
+ d_ptr = new QGeoPolygonPrivateEager;
+ setPath(other.path());
+ for (int i = 0; i < other.holesCount(); i++)
+ addHole(other.holePath(i));
+}
+
+QGeoPolygonEager::QGeoPolygonEager(const QGeoShape &other) : QGeoPolygon()
+{
+ initPolygonConversions();
+ if (other.type() == QGeoShape::PolygonType)
+ *this = QGeoPolygonEager(QGeoPolygon(other));
+ else
+ d_ptr = new QGeoPolygonPrivateEager;
+}
+
+QGeoPolygonEager::~QGeoPolygonEager()
+{
+
+}
+
QT_END_NAMESPACE
diff --git a/src/positioning/qgeopolygon.h b/src/positioning/qgeopolygon.h
index ccc4b98b..8becda8f 100644
--- a/src/positioning/qgeopolygon.h
+++ b/src/positioning/qgeopolygon.h
@@ -46,8 +46,7 @@
QT_BEGIN_NAMESPACE
class QGeoCoordinate;
-class QGeoPathPrivate;
-typedef QGeoPathPrivate QGeoPolygonPrivate;
+class QGeoPolygonPrivate;
class Q_POSITIONING_EXPORT QGeoPolygon : public QGeoShape
{
diff --git a/src/positioning/qgeopolygon_p.h b/src/positioning/qgeopolygon_p.h
new file mode 100644
index 00000000..d28fcc6e
--- /dev/null
+++ b/src/positioning/qgeopolygon_p.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 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$
+**
+****************************************************************************/
+
+#ifndef QGEOPOLYGON_P_H
+#define QGEOPOLYGON_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtPositioning/private/qgeopath_p.h>
+#include <QtPositioning/qgeopolygon.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_POSITIONING_PRIVATE_EXPORT QGeoPolygonPrivate : public QGeoPathPrivate
+{
+public:
+ QGeoPolygonPrivate();
+ QGeoPolygonPrivate(const QList<QGeoCoordinate> &path);
+ ~QGeoPolygonPrivate();
+
+// QGeoShape API
+ virtual QGeoShapePrivate *clone() const override;
+ virtual bool isValid() const override;
+ virtual bool contains(const QGeoCoordinate &coordinate) const override;
+ virtual void translate(double degreesLatitude, double degreesLongitude) override;
+ virtual bool operator==(const QGeoShapePrivate &other) const override;
+
+// QGeoPath API
+ virtual void markDirty() override;
+
+// QGeoPolygonPrivate API
+ int holesCount() const;
+ bool polygonContains(const QGeoCoordinate &coordinate) const;
+ const QList<QGeoCoordinate> holePath(int index) const;
+
+ virtual void addHole(const QList<QGeoCoordinate> &holePath);
+ virtual void removeHole(int index);
+ virtual void updateClipperPath();
+
+// data members
+ bool m_clipperDirty = true;
+ QList<QList<QGeoCoordinate>> m_holesList;
+ QtClipperLib::Path m_clipperPath;
+};
+
+class Q_POSITIONING_PRIVATE_EXPORT QGeoPolygonPrivateEager : public QGeoPolygonPrivate
+{
+public:
+ QGeoPolygonPrivateEager();
+ QGeoPolygonPrivateEager(const QList<QGeoCoordinate> &path);
+ ~QGeoPolygonPrivateEager();
+
+// QGeoShape API
+ virtual QGeoShapePrivate *clone() const override;
+ virtual void translate(double degreesLatitude, double degreesLongitude) override;
+
+// QGeoPath API
+ virtual void markDirty() override;
+ virtual void addCoordinate(const QGeoCoordinate &coordinate) override;
+ virtual void computeBoundingBox() override;
+
+// QGeoPolygonPrivate API
+
+// *Eager API
+ void updateBoundingBox();
+
+// data members
+ QVector<double> m_deltaXs; // longitude deltas from m_path[0]
+ double m_minX = 0; // minimum value inside deltaXs
+ double m_maxX = 0; // maximum value inside deltaXs
+ double m_minLati = 0; // minimum latitude. paths do not wrap around through the poles
+ double m_maxLati = 0; // minimum latitude. paths do not wrap around through the poles
+};
+
+// This is a mean of creating a QGeoPolygonPrivateEager and injecting it into QGeoPolygons via operator=
+class Q_POSITIONING_PRIVATE_EXPORT QGeoPolygonEager : public QGeoPolygon
+{
+ Q_GADGET
+public:
+
+ QGeoPolygonEager();
+ QGeoPolygonEager(const QList<QGeoCoordinate> &path);
+ QGeoPolygonEager(const QGeoPolygon &other);
+ QGeoPolygonEager(const QGeoShape &other);
+ ~QGeoPolygonEager();
+};
+
+QT_END_NAMESPACE
+
+#endif // QGEOPOLYGON_P_H