summaryrefslogtreecommitdiff
path: root/src/positioning/qgeopath.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/positioning/qgeopath.cpp')
-rw-r--r--src/positioning/qgeopath.cpp462
1 files changed, 182 insertions, 280 deletions
diff --git a/src/positioning/qgeopath.cpp b/src/positioning/qgeopath.cpp
index c4b13d01..1225d7c8 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();
}
/*!
@@ -395,128 +395,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;
-}
-
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
@@ -588,54 +530,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
@@ -644,17 +599,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)
@@ -662,38 +629,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)
@@ -706,171 +658,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
+
+
+
+
+
+
+