diff options
Diffstat (limited to 'src/positioning/qgeopolygon.cpp')
-rw-r--r-- | src/positioning/qgeopolygon.cpp | 259 |
1 files changed, 255 insertions, 4 deletions
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 |