diff options
-rw-r--r-- | src/location/declarativemaps/qdeclarativepolygonmapitem.cpp | 4 | ||||
-rw-r--r-- | src/location/declarativemaps/qdeclarativepolylinemapitem.cpp | 16 | ||||
-rw-r--r-- | src/positioning/positioning.pro | 1 | ||||
-rw-r--r-- | src/positioning/qgeopath.cpp | 462 | ||||
-rw-r--r-- | src/positioning/qgeopath_p.h | 248 | ||||
-rw-r--r-- | src/positioning/qgeopolygon.cpp | 259 | ||||
-rw-r--r-- | src/positioning/qgeopolygon.h | 3 | ||||
-rw-r--r-- | src/positioning/qgeopolygon_p.h | 135 |
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 |