summaryrefslogtreecommitdiff
path: root/src/location/quickmapitems/qdeclarativegeomapitemutils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/location/quickmapitems/qdeclarativegeomapitemutils.cpp')
-rw-r--r--src/location/quickmapitems/qdeclarativegeomapitemutils.cpp66
1 files changed, 66 insertions, 0 deletions
diff --git a/src/location/quickmapitems/qdeclarativegeomapitemutils.cpp b/src/location/quickmapitems/qdeclarativegeomapitemutils.cpp
index a1501dd6..6c45e164 100644
--- a/src/location/quickmapitems/qdeclarativegeomapitemutils.cpp
+++ b/src/location/quickmapitems/qdeclarativegeomapitemutils.cpp
@@ -191,6 +191,72 @@ QRectF boundingRectangleFromList(const QList<QDoubleVector2D> &list)
return QRectF(xMin, yMin, xMax - xMin, yMax - yMin);
}
+QList<QGeoCoordinate> greaterCirclePath(const QList<QGeoCoordinate> &cornerPoints,
+ greaterCirclePathForm form, int N)
+{
+ QList<QGeoCoordinate> path;
+ path.reserve(N);
+ //If the path has to be closed we include the first coordinate again at the end of the procedure
+ qsizetype lineCount = cornerPoints.size() - ((form == OpenPath) ? 1 : 0);
+ for (qsizetype i = 0; i < lineCount; i++) {
+ path.append(cornerPoints.at(i));
+ const double p_lat = cornerPoints.at(i).latitude() / 180.0 * M_PI; //latitude point p in rad
+ const double p_lon = cornerPoints.at(i).longitude() / 180.0 * M_PI; //longitude point p in rad
+ const double q_lat = cornerPoints.at((i + 1) % cornerPoints.size()).latitude() / 180.0 * M_PI; //latitude point q in rad
+ const double q_lon = cornerPoints.at((i + 1) % cornerPoints.size()).longitude() / 180.0 * M_PI;//longitude point q in rad
+
+ const double c_p_lat = cos(p_lat);
+ const double c_p_lon = cos(p_lon);
+ const double s_p_lat = sin(p_lat);
+ const double s_p_lon = sin(p_lon);
+ const double c_q_lat = cos(q_lat);
+ const double c_q_lon = cos(q_lon);
+ const double s_q_lat = sin(q_lat);
+ const double s_q_lon = sin(q_lon);
+
+ const QDoubleVector3D p(c_p_lat * c_p_lon,
+ c_p_lat * s_p_lon,
+ s_p_lat);
+ const QDoubleVector3D q(c_q_lat * c_q_lon,
+ c_q_lat * s_q_lon,
+ s_q_lat);
+ const double qp = QDoubleVector3D::dotProduct(q, p); //scalar product of q p
+
+ if (qp <= -1.0 || qp >= 1.0)
+ continue;
+
+ // the path from q to p will be parametrized as a combination of points p and q:
+ // x = s*p + t*q.
+ // We will then directly calculate the latitude and longitude of the interpolated point x
+ // from the latitude and longitude of cornerpoints q and p.
+ // The parameters s and t depend on each other to ensure that x is located on the
+ // surface of the earth: s*s + 2*s*t*qp + t*t = 1
+ // Their minimum value is 0, as negative values indicate a path that goes around earth
+ // long way. Their maximum value follows as
+ const double paramMax = sqrt(1 / (1 - qp * qp));
+
+ double t = 0.0;
+ for (int sign = 1; sign > -2.0; sign -= 2.0) {
+ for (; t <= paramMax && t >= 0.0; t += sign * paramMax / N / 2) {
+ // dependence between s and t requires a plus/minus
+ // therefore we solve this equation two times with sign = -1/+1
+ const double s = - t * qp + sign * sqrt(t * t * (qp * qp - 1.0) + 1.0);
+ if (s < 0.0) //s > paramMax will never happen. If s < 0 we are done.
+ break;
+ const double lat = asin(s * s_p_lat + t * s_q_lat);
+ const double lon = atan2(s * c_p_lat * s_p_lon + t * c_q_lat * s_q_lon,
+ s * c_p_lat * c_p_lon + t * c_q_lat * c_q_lon);
+ path.append(QGeoCoordinate(lat * 180.0 / M_PI, lon * 180.0 / M_PI));
+ }
+ t -= paramMax / N / 2;
+ }
+ }
+ if (form == OpenPath)
+ path.append(cornerPoints.last());
+ path.squeeze();
+ return path;
+}
+
} // namespace QDeclarativeGeoMapItemUtils
QT_END_NAMESPACE