// Copyright 2020-2024 CesiumGS, Inc. and Contributors #pragma once #include "CesiumGeospatial/Ellipsoid.h" #include "CesiumGeospatial/LocalHorizontalCoordinateSystem.h" #include "HAL/Platform.h" #include "Math/Matrix.h" #include #include /** * @brief A lightweight structure to encapsulate coordinate transforms. * * It encapsulates the conversions between... * - Earth-Centered, Earth-Fixed (ECEF) coordinates * - Georeferenced coordinates (Latitude/Longitude/Height) * - Unreal coordinates (relative to the unreal world origin) * */ class CESIUMRUNTIME_API GeoTransforms { public: /** * @brief Creates a new instance. */ GeoTransforms(); /** * @brief Creates a new instance. * * The center position is the position of the origin of the * local coordinate system that is established by this instance. * * @param ellipsoid The ellipsoid to use for the georeferenced coordinates * @param center The center position. * @param scale The scale factor of the globe in the Unreal world. */ GeoTransforms( const CesiumGeospatial::Ellipsoid& ellipsoid, const glm::dvec3& center, double scale); /** * @brief Set the center position of this instance * * The center position is the position of the origin of the * local coordinate system that is established by this instance. * * @param center The center position. */ void setCenter(const glm::dvec3& center) noexcept; /** * @brief Set the ellipsoid of this instance * * @param ellipsoid The ellipsoid */ void setEllipsoid(const CesiumGeospatial::Ellipsoid& ellipsoid) noexcept; /** * Transforms the given longitude in degrees (x), latitude in * degrees (y), and height in meters (z) into Earth-Centered, Earth-Fixed * (ECEF) coordinates. */ glm::dvec3 TransformLongitudeLatitudeHeightToEcef( const glm::dvec3& LongitudeLatitudeHeight) const noexcept; /** * Transforms the given Earth-Centered, Earth-Fixed (ECEF) coordinates into * longitude in degrees (x), latitude in degrees (y), and height in * meters (z). */ glm::dvec3 TransformEcefToLongitudeLatitudeHeight(const glm::dvec3& Ecef) const noexcept; /** * Transforms the given longitude in degrees (x), latitude in * degrees (y), and height in meters (z) into Unreal world coordinates * (relative to the floating origin). */ glm::dvec3 TransformLongitudeLatitudeHeightToUnreal( const glm::dvec3& origin, const glm::dvec3& LongitudeLatitudeHeight) const noexcept; /** * Transforms Unreal world coordinates (relative to the floating origin) into * longitude in degrees (x), latitude in degrees (y), and height in * meters (z). */ glm::dvec3 TransformUnrealToLongitudeLatitudeHeight( const glm::dvec3& origin, const glm::dvec3& Ue) const noexcept; /** * Transforms the given point from Earth-Centered, Earth-Fixed (ECEF) into * Unreal world coordinates (relative to the floating origin). */ glm::dvec3 TransformEcefToUnreal( const glm::dvec3& origin, const glm::dvec3& Ecef) const noexcept; /** * Transforms the given point from Unreal world coordinates (relative to the * floating origin) to Earth-Centered, Earth-Fixed (ECEF). */ glm::dvec3 TransformUnrealToEcef( const glm::dvec3& origin, const glm::dvec3& Ue) const noexcept; /** * Transforms a rotator from Unreal world to East-South-Up at the given * Unreal relative world location (relative to the floating origin). */ glm::dquat TransformRotatorUnrealToEastSouthUp( const glm::dvec3& origin, const glm::dquat& UeRotator, const glm::dvec3& UeLocation) const noexcept; /** * Transforms a rotator from East-South-Up to Unreal world at the given * Unreal world location (relative to the floating origin). */ glm::dquat TransformRotatorEastSouthUpToUnreal( const glm::dvec3& origin, const glm::dquat& EnuRotator, const glm::dvec3& UeLocation) const noexcept; /** * Computes the rotation matrix from the local East-South-Up to Unreal at the * specified Unreal world location (relative to the floating * origin). The returned transformation works in Unreal's left-handed * coordinate system. */ glm::dmat4 ComputeEastSouthUpToUnreal( const glm::dvec3& origin, const glm::dvec3& Ue) const noexcept; /** * Computes the rotation matrix from the local East-North-Up to * Earth-Centered, Earth-Fixed (ECEF) at the specified ECEF location. */ glm::dmat3 ComputeEastNorthUpToEcef(const glm::dvec3& Ecef) const noexcept; /* * GEOREFERENCE TRANSFORMS */ /** * @brief Gets the transformation from the _absolute_ "Unreal World" reference * frame to the "Ellipsoid-centered" reference frame (i.e. ECEF). * * Gets a matrix that transforms coordinates from the absolute "Unreal World" * reference frame (with respect to the absolute world origin, not the * floating origin) to the "Ellipsoid-centered" reference frame (which is * usually Earth-centered, Earth-fixed). See {@link reference-frames.md}. */ const glm::dmat4& GetAbsoluteUnrealWorldToEllipsoidCenteredTransform() const noexcept { return this->_coordinateSystem.getLocalToEcefTransformation(); } /** * @brief Gets the transformation from the "Ellipsoid-centered" reference * frame (i.e. ECEF) to the absolute "Unreal World" reference frame. * * Gets a matrix that transforms coordinates from the "Ellipsoid-centered" * reference frame (which is usually Earth-centered, Earth-fixed) to the * absolute "Unreal world" reference frame (with respect to the absolute world * origin, not the floating origin). See {@link reference-frames.md}. */ const glm::dmat4& GetEllipsoidCenteredToAbsoluteUnrealWorldTransform() const noexcept { return this->_coordinateSystem.getEcefToLocalTransformation(); } /** * @brief Computes the normal of the plane tangent to the surface of the * ellipsoid that is used by this instance, at the provided position. * * @param position The cartesian position for which to to determine the * surface normal. * @return The normal. */ glm::dvec3 ComputeGeodeticSurfaceNormal(const glm::dvec3& position) const { return _ellipsoid.geodeticSurfaceNormal(position); } /** * Computes the rotation in ellipsoid surface normal between an old position * and a new position. This rotation is expressed in terms of Unreal world * coordinates, and can be used to maintain an object's orientation relative * to the local horizontal as it moves over the globe. * * @param oldPosition The old ECEF position that the object moved from. * @param newPosition The new ECEF position that the object moved to. * @return The rotation from the ellipsoid surface normal at the old position * to the ellipsoid surface normal at the new position. */ glm::dquat ComputeSurfaceNormalRotation( const glm::dvec3& oldPosition, const glm::dvec3& newPosition) const; /** * Computes the rotation in ellipsoid surface normal between an old position * and a new position. This rotation is expressed in terms of Unreal world * coordinates, and can be used to maintain an object's orientation relative * to the local horizontal as it moves over the globe. * * @param oldPosition The old ECEF position that the object moved from. * @param newPosition The new ECEF position that the object moved to. * @return The rotation from the ellipsoid surface normal at the old position * to the ellipsoid surface normal at the new position. */ glm::dquat ComputeSurfaceNormalRotationUnreal( const glm::dvec3& oldPosition, const glm::dvec3& newPosition) const; const FMatrix& GetEllipsoidCenteredToAbsoluteUnrealWorldMatrix() const { return this->_ecefToUnreal; } const FMatrix& GetAbsoluteUnrealWorldToEllipsoidCenteredMatrix() const { return this->_unrealToEcef; } private: /** * Update the derived state (i.e. the local horizontal coordinate system) when * either the center or the ellipsoid has changed. */ void updateTransforms() noexcept; CesiumGeospatial::LocalHorizontalCoordinateSystem _coordinateSystem; // Modifiable state CesiumGeospatial::Ellipsoid _ellipsoid; glm::dvec3 _center; double _scale; FMatrix _ecefToUnreal; FMatrix _unrealToEcef; };