13#include <QtCore/QString>
17#include <GeographicLib/Geocentric.hpp>
18#include <GeographicLib/Geodesic.hpp>
19#include <GeographicLib/GeodesicLine.hpp>
20#include <GeographicLib/LocalCartesian.hpp>
21#include <GeographicLib/MGRS.hpp>
22#include <GeographicLib/PolygonArea.hpp>
23#include <GeographicLib/UTMUPS.hpp>
34void convertGeoToNed(
const QGeoCoordinate &coord,
const QGeoCoordinate &origin,
double &x,
double &y,
double &z)
36 if (coord == origin) {
42 const double originAlt = std::isnan(origin.altitude()) ? 0.0 : origin.altitude();
43 const double coordAlt = std::isnan(coord.altitude()) ? 0.0 : coord.altitude();
45 double east, north, up;
46 GeographicLib::LocalCartesian ltp(origin.latitude(), origin.longitude(), originAlt,
47 GeographicLib::Geocentric::WGS84());
48 ltp.Forward(coord.latitude(), coord.longitude(), coordAlt, east, north, up);
56void convertNedToGeo(
double x,
double y,
double z,
const QGeoCoordinate &origin, QGeoCoordinate &coord)
59 const double east = y;
60 const double north = x;
64 const double originAlt = std::isnan(origin.altitude()) ? 0.0 : origin.altitude();
67 GeographicLib::LocalCartesian ltp(origin.latitude(), origin.longitude(), originAlt,
68 GeographicLib::Geocentric::WGS84());
69 ltp.Reverse(east, north, up, lat, lon, alt);
71 coord.setLatitude(lat);
72 coord.setLongitude(lon);
73 coord.setAltitude(alt);
83 GeographicLib::LocalCartesian ltp(ref.latitude(), ref.longitude(), ref.altitude(),
84 GeographicLib::Geocentric::WGS84());
85 ltp.Forward(coord.latitude(), coord.longitude(), coord.altitude(), x, y, z);
86 return QVector3D(x, y, z);
92 GeographicLib::LocalCartesian ltp(ref.latitude(), ref.longitude(), ref.altitude(),
93 GeographicLib::Geocentric::WGS84());
94 ltp.Reverse(enu.x(), enu.y(), enu.z(), lat, lon, alt);
95 return QGeoCoordinate(lat, lon, alt);
105 GeographicLib::Geocentric::WGS84().Forward(coord.latitude(), coord.longitude(), coord.altitude(), x, y, z);
106 return QVector3D(x, y, z);
111 double lat, lon, alt;
112 GeographicLib::Geocentric::WGS84().Reverse(ecef.x(), ecef.y(), ecef.z(), lat, lon, alt);
113 return QGeoCoordinate(lat, lon, alt);
120 GeographicLib::Geocentric::WGS84().Reverse(ecef.x(), ecef.y(), ecef.z(), lat, lon, h);
124 GeographicLib::LocalCartesian ltp(ref.latitude(), ref.longitude(), ref.altitude(),
125 GeographicLib::Geocentric::WGS84());
126 ltp.Forward(lat, lon, h, x, y, z);
127 return QVector3D(x, y, z);
134 GeographicLib::LocalCartesian ltp(ref.latitude(), ref.longitude(), ref.altitude(),
135 GeographicLib::Geocentric::WGS84());
136 ltp.Reverse(enu.x(), enu.y(), enu.z(), lat, lon, h);
140 GeographicLib::Geocentric::WGS84().Forward(lat, lon, h, x, y, z);
141 return QVector3D(x, y, z);
153 GeographicLib::UTMUPS::Forward(coord.latitude(), coord.longitude(), zone, northp, easting, northing);
155 }
catch (
const GeographicLib::GeographicErr &e) {
156 qCDebug(QGCGeoLog) << e.what();
161bool convertUTMToGeo(
double easting,
double northing,
int zone,
bool southhemi, QGeoCoordinate &coord)
165 GeographicLib::UTMUPS::Reverse(zone, !southhemi, easting, northing, lat, lon);
166 coord.setLatitude(lat);
167 coord.setLongitude(lon);
169 }
catch (
const GeographicLib::GeographicErr &e) {
170 qCDebug(QGCGeoLog) << e.what();
185 GeographicLib::UTMUPS::Forward(coord.latitude(), coord.longitude(), zone, northp, x, y);
188 GeographicLib::MGRS::Forward(zone, northp, x, y, coord.latitude(), 5, mgrs);
191 const QString qstr = QString::fromStdString(mgrs);
192 for (
int i = qstr.length() - 1; i >= 0; i--) {
193 if (!qstr.at(i).isDigit()) {
194 const int numLen = (qstr.length() - i - 1) / 2;
195 return qstr.left(i + 1) +
" " + qstr.mid(i + 1, numLen) +
" " + qstr.mid(i + 1 + numLen);
199 }
catch (
const GeographicLib::GeographicErr &e) {
200 qCDebug(QGCGeoLog) << e.what();
211 GeographicLib::MGRS::Reverse(mgrs.simplified().replace(
" ",
"").toStdString(), zone, northp, x, y, prec);
214 GeographicLib::UTMUPS::Reverse(zone, northp, x, y, lat, lon);
216 coord.setLatitude(lat);
217 coord.setLongitude(lon);
219 }
catch (
const GeographicLib::GeographicErr &e) {
220 qCDebug(QGCGeoLog) << e.what();
232 GeographicLib::Geodesic::WGS84().Inverse(from.latitude(), from.longitude(),
233 to.latitude(), to.longitude(), distance);
239 double distance, azimuth1, azimuth2;
240 GeographicLib::Geodesic::WGS84().Inverse(from.latitude(), from.longitude(),
241 to.latitude(), to.longitude(), distance, azimuth1, azimuth2);
244 if (azimuth1 < 0.0) {
253 GeographicLib::Geodesic::WGS84().Direct(from.latitude(), from.longitude(), azimuth, distance, lat, lon);
254 return QGeoCoordinate(lat, lon, from.altitude());
263 if (path.size() < 2) {
267 double totalLength = 0.0;
268 for (
int i = 1; i < path.size(); ++i) {
276 if (polygon.size() < 3) {
280 GeographicLib::PolygonArea poly(GeographicLib::Geodesic::WGS84());
281 for (
const QGeoCoordinate &coord : polygon) {
282 poly.AddPoint(coord.latitude(), coord.longitude());
285 double perimeter, area;
286 poly.Compute(
false,
true, perimeter, area);
294 if (polygon.size() < 2) {
298 GeographicLib::PolygonArea poly(GeographicLib::Geodesic::WGS84());
299 for (
const QGeoCoordinate &coord : polygon) {
300 poly.AddPoint(coord.latitude(), coord.longitude());
303 double perimeter, area;
304 poly.Compute(
false,
true, perimeter, area);
308QList<QGeoCoordinate>
interpolatePath(
const QGeoCoordinate &from,
const QGeoCoordinate &to,
int numPoints)
310 QList<QGeoCoordinate> result;
313 constexpr int kMaxPoints = 10000;
316 }
else if (numPoints > kMaxPoints) {
317 qCWarning(QGCGeoLog) <<
"interpolatePath: numPoints" << numPoints <<
"exceeds maximum, clamping to" << kMaxPoints;
318 numPoints = kMaxPoints;
322 for (
int i = 0; i < numPoints; ++i) {
329 const GeographicLib::GeodesicLine line = GeographicLib::Geodesic::WGS84().InverseLine(
330 from.latitude(), from.longitude(), to.latitude(), to.longitude());
332 const double totalDistance = line.Distance();
333 const double altDiff = to.altitude() - from.altitude();
335 for (
int i = 0; i < numPoints; ++i) {
336 const double fraction =
static_cast<double>(i) / (numPoints - 1);
337 const double distance = totalDistance * fraction;
340 line.Position(distance, lat, lon);
342 const double alt = from.altitude() + altDiff * fraction;
343 result.append(QGeoCoordinate(lat, lon, alt));
351 if (from == to || distance <= 0.0) {
355 const GeographicLib::GeodesicLine line = GeographicLib::Geodesic::WGS84().InverseLine(
356 from.latitude(), from.longitude(), to.latitude(), to.longitude());
358 const double totalDistance = line.Distance();
360 if (distance >= totalDistance) {
365 line.Position(distance, lat, lon);
368 const double fraction = distance / totalDistance;
369 const double alt = from.altitude() + (to.altitude() - from.altitude()) * fraction;
371 return QGeoCoordinate(lat, lon, alt);
Geographic coordinate conversion utilities using GeographicLib.
#define QGC_LOGGING_CATEGORY(name, categoryStr)
QList< QGeoCoordinate > interpolatePath(const QGeoCoordinate &from, const QGeoCoordinate &to, int numPoints)
QVector3D convertEcefToEnu(const QVector3D &ecef, const QGeoCoordinate &ref)
void convertGeoToNed(const QGeoCoordinate &coord, const QGeoCoordinate &origin, double &x, double &y, double &z)
double polygonPerimeter(const QList< QGeoCoordinate > &polygon)
double geodesicAzimuth(const QGeoCoordinate &from, const QGeoCoordinate &to)
QVector3D convertGeodeticToEcef(const QGeoCoordinate &coord)
QGeoCoordinate geodesicDestination(const QGeoCoordinate &from, double azimuth, double distance)
QGeoCoordinate convertEcefToGeodetic(const QVector3D &ecef)
QString convertGeoToMGRS(const QGeoCoordinate &coord)
double pathLength(const QList< QGeoCoordinate > &path)
double polygonArea(const QList< QGeoCoordinate > &polygon)
double geodesicDistance(const QGeoCoordinate &from, const QGeoCoordinate &to)
QVector3D convertEnuToEcef(const QVector3D &enu, const QGeoCoordinate &ref)
int convertGeoToUTM(const QGeoCoordinate &coord, double &easting, double &northing)
void convertNedToGeo(double x, double y, double z, const QGeoCoordinate &origin, QGeoCoordinate &coord)
QGeoCoordinate convertEnuToGps(const QVector3D &enu, const QGeoCoordinate &ref)
QVector3D convertGpsToEnu(const QGeoCoordinate &coord, const QGeoCoordinate &ref)
bool convertUTMToGeo(double easting, double northing, int zone, bool southhemi, QGeoCoordinate &coord)
QGeoCoordinate interpolateAtDistance(const QGeoCoordinate &from, const QGeoCoordinate &to, double distance)
bool convertMGRSToGeo(const QString &mgrs, QGeoCoordinate &coord)