summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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