ralpha-assets/Plugins/CesiumForUnreal/Source/ThirdParty/include/CesiumGeospatial/WebMercatorProjection.h

177 lines
6.0 KiB
C++

#pragma once
#include <CesiumGeospatial/Ellipsoid.h>
#include <CesiumGeospatial/GlobeRectangle.h>
#include <CesiumGeospatial/Library.h>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
namespace CesiumGeospatial {
class Cartographic;
/**
* @brief The map projection used by Google Maps, Bing Maps, and most of ArcGIS
* Online, EPSG:3857.
*
* This projection uses geodetic longitude and latitude expressed with WGS84 and
* transforms them to Mercator using the spherical (rather than ellipsoidal)
* equations.
*
* @see GeographicProjection
*/
class CESIUMGEOSPATIAL_API WebMercatorProjection final {
public:
/**
* @brief The maximum latitude (both North and South) supported by a Web
* Mercator (EPSG:3857) projection.
*
* Technically, the Mercator projection is defined for any latitude
* up to (but not including) 90 degrees, but it makes sense
* to cut it off sooner because it grows exponentially with increasing
* latitude. The logic behind this particular cutoff value, which is the one
* used by Google Maps, Bing Maps, and Esri, is that it makes the projection
* square. That is, the rectangle is equal in the X and Y directions.
*
* The constant value is computed by calling:
* `CesiumGeospatial::WebMercatorProjection::mercatorAngleToGeodeticLatitude(CesiumUtility::Math::OnePi)`
*/
static const double MAXIMUM_LATITUDE;
/**
* @brief The maximum bounding rectangle of the Web Mercator projection,
* ranging from -PI to PI radians longitude and
* from -MAXIMUM_LATITUDE to +MAXIMUM_LATITUDE.
*/
static const GlobeRectangle MAXIMUM_GLOBE_RECTANGLE;
/**
* @brief Computes the maximum rectangle that can be covered with this
* projection
*
* @param ellipsoid The {@link Ellipsoid}. Default value:
* {@link Ellipsoid::WGS84}.
* @return The rectangle
*/
static constexpr CesiumGeometry::Rectangle computeMaximumProjectedRectangle(
const Ellipsoid& ellipsoid CESIUM_DEFAULT_ELLIPSOID) noexcept {
const double value =
ellipsoid.getMaximumRadius() * CesiumUtility::Math::OnePi;
return CesiumGeometry::Rectangle(-value, -value, value, value);
}
/**
* @brief Constructs a new instance.
*
* @param ellipsoid The {@link Ellipsoid}.
*/
WebMercatorProjection(
const Ellipsoid& ellipsoid CESIUM_DEFAULT_ELLIPSOID) noexcept;
/**
* @brief Gets the {@link Ellipsoid}.
*/
const Ellipsoid& getEllipsoid() const noexcept { return this->_ellipsoid; }
/**
* @brief Converts geodedic ellipsoid coordinates to Web Mercator coordinates.
*
* Converts geodetic ellipsoid coordinates, in radians, to the equivalent Web
* Mercator X, Y, Z coordinates expressed in meters. The height is copied
* unmodified to the `z` coordinate.
*
* @param cartographic The geodetic coordinates in radians.
* @returns The equivalent web mercator X, Y, Z coordinates, in meters.
*/
glm::dvec3 project(const Cartographic& cartographic) const noexcept;
/**
* @brief Projects a globe rectangle to Web Mercator coordinates.
*
* This is done by projecting the southwest and northeast corners.
*
* @param rectangle The globe rectangle to project.
* @return The projected rectangle.
*/
CesiumGeometry::Rectangle
project(const CesiumGeospatial::GlobeRectangle& rectangle) const noexcept;
/**
* @brief Converts Web Mercator coordinates to geodetic ellipsoid coordinates.
*
* Converts Web Mercator X and Y coordinates, expressed in meters, to a
* {@link Cartographic} containing geodetic ellipsoid coordinates.
* The height is set to 0.0.
*
* @param projectedCoordinates The web mercator projected coordinates to
* unproject.
* @returns The equivalent cartographic coordinates.
*/
Cartographic unproject(const glm::dvec2& projectedCoordinates) const noexcept;
/**
* @brief Converts Web Mercator coordinates to geodetic ellipsoid coordinates.
*
* Converts Web Mercator X, Y coordinates, expressed in meters, to a
* {@link Cartographic} containing geodetic ellipsoid coordinates.
* The Z coordinate is copied unmodified to the height.
*
* @param projectedCoordinates The web mercator projected coordinates to
* unproject, with height (z) in meters.
* @returns The equivalent cartographic coordinates.
*/
Cartographic unproject(const glm::dvec3& projectedCoordinates) const noexcept;
/**
* @brief Unprojects a Web Mercator rectangle to the globe.
*
* This is done by unprojecting the southwest and northeast corners.
*
* @param rectangle The rectangle to unproject.
* @returns The unprojected rectangle.
*/
CesiumGeospatial::GlobeRectangle
unproject(const CesiumGeometry::Rectangle& rectangle) const noexcept;
/**
* @brief Converts a Mercator angle, in the range -PI to PI, to a geodetic
* latitude in the range -PI/2 to PI/2.
*
* @param mercatorAngle The angle to convert.
* @returns The geodetic latitude in radians.
*/
static double mercatorAngleToGeodeticLatitude(double mercatorAngle) noexcept;
/**
* @brief Converts a geodetic latitude in radians, in the range -PI/2 to PI/2,
* to a Mercator angle in the range -PI to PI.
*
* @param latitude The geodetic latitude in radians.
* @returns The Mercator angle.
*/
static double geodeticLatitudeToMercatorAngle(double latitude) noexcept;
/**
* @brief Returns `true` if two projections (i.e. their ellipsoids) are equal.
*/
bool operator==(const WebMercatorProjection& rhs) const noexcept {
return this->_ellipsoid == rhs._ellipsoid;
};
/**
* @brief Returns `true` if two projections (i.e. their ellipsoids) are *not*
* equal.
*/
bool operator!=(const WebMercatorProjection& rhs) const noexcept {
return !(*this == rhs);
};
private:
Ellipsoid _ellipsoid;
double _semimajorAxis;
double _oneOverSemimajorAxis;
};
} // namespace CesiumGeospatial