123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include "GNSSFormatConversions.h"
- constexpr double earthSemimajorAxis = 6378137.0;
- constexpr double reciprocalFlattening = 1.0 / 298.257223563;
- constexpr double earthSemiminorAxis = earthSemimajorAxis * (1.0 - reciprocalFlattening);
- constexpr double firstEccentricitySquared = 2.0 * reciprocalFlattening - reciprocalFlattening * reciprocalFlattening;
- constexpr double secondEccentrictySquared =
- reciprocalFlattening * (2.0 - reciprocalFlattening) / ((1.0 - reciprocalFlattening) * (1.0 - reciprocalFlattening));
- // Based on http://wiki.gis.com/wiki/index.php/Geodetic_system
- namespace Georeferencing::Utils::GeodeticConversions
- {
- inline double DegToRad(double degrees)
- {
- return degrees * M_PI / 180.0;
- }
- inline double RadToDeg(double radians)
- {
- return radians * 180.0 / M_PI;
- }
- WGS::Vector3d WGS84ToECEF(const WGS::WGS84Coordinate& latitudeLongitudeAltitude)
- {
- const double latitudeRad = DegToRad(latitudeLongitudeAltitude.m_latitude);
- const double longitudeRad = DegToRad(latitudeLongitudeAltitude.m_longitude);
- const double altitude = latitudeLongitudeAltitude.m_altitude;
- const double helper = std::sqrt(1.0f - firstEccentricitySquared * std::sin(latitudeRad) * std::sin(latitudeRad));
- const double X = (earthSemimajorAxis / helper + altitude) * std::cos(latitudeRad) * std::cos(longitudeRad);
- const double Y = (earthSemimajorAxis / helper + altitude) * std::cos(latitudeRad) * std::sin(longitudeRad);
- const double Z = (earthSemimajorAxis * (1.0 - firstEccentricitySquared) / helper + altitude) * std::sin(latitudeRad);
- return { X, Y, Z };
- }
- WGS::Vector3d ECEFToENU(const WGS::WGS84Coordinate& referenceLatitudeLongitudeAltitude, const WGS::Vector3d& ECEFPoint)
- {
- const WGS::Vector3d referencePointInECEF = WGS84ToECEF(referenceLatitudeLongitudeAltitude);
- const WGS::Vector3d pointToReferencePointECEF = ECEFPoint - referencePointInECEF;
- const double referenceLatitudeRad = DegToRad(referenceLatitudeLongitudeAltitude.m_latitude);
- const double referenceLongitudeRad = DegToRad(referenceLatitudeLongitudeAltitude.m_longitude);
- return { -sin(referenceLongitudeRad) * pointToReferencePointECEF.m_x + cos(referenceLongitudeRad) * pointToReferencePointECEF.m_y,
- -sin(referenceLatitudeRad) * cos(referenceLongitudeRad) * pointToReferencePointECEF.m_x -
- sin(referenceLatitudeRad) * sin(referenceLongitudeRad) * pointToReferencePointECEF.m_y +
- cos(referenceLatitudeRad) * pointToReferencePointECEF.m_z,
- cos(referenceLatitudeRad) * cos(referenceLongitudeRad) * pointToReferencePointECEF.m_x +
- cos(referenceLatitudeRad) * sin(referenceLongitudeRad) * pointToReferencePointECEF.m_y +
- sin(referenceLatitudeRad) * pointToReferencePointECEF.m_z };
- }
- WGS::Vector3d ENUToECEF(const WGS::WGS84Coordinate& referenceLatitudeLongitudeAltitude, const WGS::Vector3d& ENUPoint)
- {
- const auto referenceECEF = WGS84ToECEF(referenceLatitudeLongitudeAltitude);
- const double referenceLatitudeRad = DegToRad(referenceLatitudeLongitudeAltitude.m_latitude);
- const double referenceLongitudeRad = DegToRad(referenceLatitudeLongitudeAltitude.m_longitude);
- const double& e = ENUPoint.m_x;
- const double& n = ENUPoint.m_y;
- const double& u = ENUPoint.m_z;
- return { -std::sin(referenceLongitudeRad) * e - std::cos(referenceLongitudeRad) * std::sin(referenceLatitudeRad) * n +
- std::cos(referenceLongitudeRad) * std::cos(referenceLatitudeRad) * u + referenceECEF.m_x,
- std::cos(referenceLongitudeRad) * e - std::sin(referenceLongitudeRad) * std::sin(referenceLatitudeRad) * n +
- std::cos(referenceLatitudeRad) * std::sin(referenceLongitudeRad) * u + referenceECEF.m_y,
- std::cos(referenceLatitudeRad) * n + std::sin(referenceLatitudeRad) * u + referenceECEF.m_z };
- }
- WGS::WGS84Coordinate ECEFToWGS84(const WGS::Vector3d& ECFEPoint)
- {
- const double& x = ECFEPoint.m_x;
- const double& y = ECFEPoint.m_y;
- const double& z = ECFEPoint.m_z;
- const double radiusSquared = x * x + y * y;
- const double radius = std::sqrt(radiusSquared);
- const double E2 = earthSemimajorAxis * earthSemimajorAxis - earthSemiminorAxis * earthSemiminorAxis;
- const double F = 54.0 * earthSemiminorAxis * earthSemiminorAxis * z * z;
- const double G = radiusSquared + (1.0 - firstEccentricitySquared) * z * z - firstEccentricitySquared * E2;
- const double c = (firstEccentricitySquared * firstEccentricitySquared * F * radiusSquared) / (G * G * G);
- const double s = std::pow(1. + c + std::sqrt(c * c + 2. * c), 1. / 3);
- const double P = F / (3.0 * (s + 1.0 / s + 1.0) * (s + 1.0 / s + 1.0) * G * G);
- const double Q = std::sqrt(1.0 + 2.0 * firstEccentricitySquared * firstEccentricitySquared * P);
- const double ro = -(firstEccentricitySquared * P * radius) / (1.0 + Q) +
- std::sqrt(
- (earthSemimajorAxis * earthSemimajorAxis / 2.0) * (1.0 + 1.0 / Q) -
- ((1.0 - firstEccentricitySquared) * P * z * z) / (Q * (1.0 + Q)) - P * radiusSquared / 2.0);
- const double tmp = (radius - firstEccentricitySquared * ro) * (radius - firstEccentricitySquared * ro);
- const double U = std::sqrt(tmp + z * z);
- const double V = std::sqrt(tmp + (1.0 - firstEccentricitySquared) * z * z);
- const double zo = (earthSemiminorAxis * earthSemiminorAxis * z) / (earthSemimajorAxis * V);
- const double latitude = std::atan((z + secondEccentrictySquared * zo) / radius);
- const double longitude = std::atan2(y, x);
- const double altitude = U * (1.0 - earthSemiminorAxis * earthSemiminorAxis / (earthSemimajorAxis * V));
- return { RadToDeg(latitude), RadToDeg(longitude), altitude };
- }
- } // namespace Georeferencing::Utils::GeodeticConversions
|