Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1dfaa89
Added distance calculation method considering the radius
adityapande-1995 May 27, 2022
2561aa1
Merge branch 'main' into aditya/distance_with_radius
adityapande-1995 May 31, 2022
99f2496
Reverted overloading of Distance function
adityapande-1995 Jun 2, 2022
4d68400
Added MOON and CUSTOM surface types, api to set radius
adityapande-1995 Jun 2, 2022
073d0c2
Merge branch 'main' into aditya/distance_with_radius
adityapande-1995 Jun 2, 2022
ecd86e0
Added new constructor for custom surface, updated tests
adityapande-1995 Jun 4, 2022
d804ebd
Linter erros fixed
adityapande-1995 Jun 4, 2022
d8d5c5c
Merge branch 'main' into aditya/distance_with_radius
adityapande-1995 Jun 10, 2022
b401946
Updated docstrings
adityapande-1995 Jun 10, 2022
03869a9
Filter neg values in sllipse props, overload SetSurface
adityapande-1995 Jun 13, 2022
bc32184
Merge branch 'main' into aditya/distance_with_radius
adityapande-1995 Jun 13, 2022
d34ce64
Added getter methods, tests
adityapande-1995 Jun 13, 2022
a66fd7b
Added tests, pybind update
adityapande-1995 Jun 14, 2022
5f3668c
Add invalid surface tests
adityapande-1995 Jun 14, 2022
0a30e5a
Added test for constructor
adityapande-1995 Jun 14, 2022
723b454
Deprecated and renamed the static Distance() function
adityapande-1995 Jun 15, 2022
243b673
Fixed pybind warnings
adityapande-1995 Jun 15, 2022
8a30e07
Fixed broken pybind test
adityapande-1995 Jun 15, 2022
b1baee5
Updaed Migration.md, renamed methods, updated error msgs
adityapande-1995 Jun 16, 2022
765b8d9
Set radius in SetSurface method
adityapande-1995 Jun 16, 2022
c487de3
[ign -> gz] CMake functions (#441)
chapulina Jun 16, 2022
d4ca4c4
ign -> gz Macro Migration : gz-math (#437)
methylDragon Jun 17, 2022
9e756fe
Suppress warnings (#444)
mjcarroll Jun 21, 2022
2a7c853
Updated comments, added radius check in tests
adityapande-1995 Jun 22, 2022
571735b
Merge branch 'main' into aditya/distance_with_radius
adityapande-1995 Jun 22, 2022
f9a3f07
Merge branch 'main' into aditya/distance_with_radius
adityapande-1995 Jun 28, 2022
dd251a2
Merge branch 'main' into aditya/distance_with_radius
adityapande-1995 Jun 28, 2022
1fa3f5a
Updated python tests
adityapande-1995 Jun 29, 2022
ea26be0
pybind export enums
adityapande-1995 Jun 29, 2022
d3b3a1f
pybind fix
adityapande-1995 Jun 29, 2022
e0525a6
Deduce flattening parameter from equatorial and polar axes
adityapande-1995 Jun 30, 2022
b8c4887
Calculate radius from eq and polar axes
adityapande-1995 Jun 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ release will remove the deprecated code.
+ All mutator functions that lacked a `Set` prefix have been deprecated
and replaced by version with a `Set` prefix.

1. **SphericalCoordinates.hh**
+ ***Deprecation:*** public: static double Distance(const Angle&, const Angle&, const Angle&, const Angle&)
+ ***Replacement:*** public: static double DistanceWGS84(const Angle&, const Angle&, const Angle&, const Angle&)

1. **Matrix3.hh**
+ ***Deprecation:*** public: void Axes(const Vector3<T> &, const Vector3<T> &, const Vector3<T> &)
+ ***Replacement:*** public: void SetAxes(const Vector3<T> &, const Vector3<T> &, const Vector3<T> &)
Expand Down
84 changes: 81 additions & 3 deletions include/gz/math/SphericalCoordinates.hh
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,15 @@ namespace gz
{
/// \brief Model of reference ellipsoid for earth, based on
/// WGS 84 standard. see wikipedia: World_Geodetic_System
EARTH_WGS84 = 1
EARTH_WGS84 = 1,

/// \brief Model of the moon, based on the Selenographic
/// coordinate system, see wikipedia: Selenographic
/// Coordinate System.
MOON_SCS = 2,

/// \brief Custom surface type
CUSTOM_SURFACE = 10
};

/// \enum CoordinateType
Expand Down Expand Up @@ -73,6 +81,16 @@ namespace gz
/// \param[in] _type SurfaceType specification.
public: explicit SphericalCoordinates(const SurfaceType _type);

/// \brief Constructor with surface type input and properties
/// input. To be used for CUSTOM_SURFACE.
/// \param[in] _type SurfaceType specification.
/// \param[in] _axisEquatorial Semi major axis of the surface.
/// \param[in] _axisPolar Semi minor axis of the surface.
public: SphericalCoordinates(
const SurfaceType _type,
const double _axisEquatorial,
const double _axisPolar);

/// \brief Constructor with surface type, angle, and elevation inputs.
/// \param[in] _type SurfaceType specification.
/// \param[in] _latitude Reference latitude.
Expand All @@ -85,7 +103,6 @@ namespace gz
const double _elevation,
const gz::math::Angle &_heading);


/// \brief Convert a Cartesian position vector to geodetic coordinates.
/// This performs a `PositionTransform` from LOCAL to SPHERICAL.
///
Expand Down Expand Up @@ -136,15 +153,66 @@ namespace gz
/// \param[in] _latB Latitude of point B.
/// \param[in] _lonB Longitude of point B.
/// \return Distance in meters.
public: static double Distance(const gz::math::Angle &_latA,
/// \deprecated Use DistanceWGS84 instead.
public: GZ_DEPRECATED(7) static double Distance(
const gz::math::Angle &_latA,
const gz::math::Angle &_lonA,
const gz::math::Angle &_latB,
const gz::math::Angle &_lonB);

/// \brief Get the distance between two points expressed in geographic
/// latitude and longitude. It assumes that both points are at sea level.
/// Example: _latA = 38.0016667 and _lonA = -123.0016667) represents
/// the point with latitude 38d 0'6.00"N and longitude 123d 0'6.00"W.
/// This method assumes that the surface model is EARTH_WGS84.
/// \param[in] _latA Latitude of point A.
/// \param[in] _lonA Longitude of point A.
/// \param[in] _latB Latitude of point B.
/// \param[in] _lonB Longitude of point B.
/// \return Distance in meters.
public: static double DistanceWGS84(
const gz::math::Angle &_latA,
const gz::math::Angle &_lonA,
const gz::math::Angle &_latB,
const gz::math::Angle &_lonB);

/// \brief Get the distance between two points expressed in geographic
/// latitude and longitude. It assumes that both points are at sea level.
/// Example: _latA = 38.0016667 and _lonA = -123.0016667) represents
/// the point with latitude 38d 0'6.00"N and longitude 123d 0'6.00"W.
/// This is different from the deprecated static Distance() method as it
/// takes into account the set surface's radius.
/// \param[in] _latA Latitude of point A.
/// \param[in] _lonA Longitude of point A.
/// \param[in] _latB Latitude of point B.
/// \param[in] _lonB Longitude of point B.
/// \return Distance in meters.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be too nitpicky but if the radius was set in different units then the distance returned would be in those units (eg. radius is in km). Not sure if we should mention this, remove meters in the comment, add in meters to the comments anywhere radius is mentioned, or ignore my nitpicky comment? Any thoughts @scpeters ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we use meters everywhere in our API, so I think we can just leave it at that

public: double DistanceBetweenPoints(
const gz::math::Angle &_latA,
const gz::math::Angle &_lonA,
const gz::math::Angle &_latB,
const gz::math::Angle &_lonB);

/// \brief Get SurfaceType currently in use.
/// \return Current SurfaceType value.
public: SurfaceType Surface() const;

/// \brief Get the radius of the surface.
/// \return radius of the surface in use.
public: double SurfaceRadius();

/// \brief Get the major axis of the surface.
/// \return Equatorial axis of the surface in use.
public: double SurfaceAxisEquatorial();

/// \brief Get the minor axis of the surface.
/// \return Polar axis of the surface in use.
public: double SurfaceAxisPolar();

/// \brief Get the flattening of the surface.
/// \return Flattening parameter of the surface in use.
public: double SurfaceFlattening();

/// \brief Get reference geodetic latitude.
/// \return Reference geodetic latitude.
public: gz::math::Angle LatitudeReference() const;
Expand All @@ -167,6 +235,16 @@ namespace gz
/// \param[in] _type SurfaceType value.
public: void SetSurface(const SurfaceType &_type);

/// \brief Set SurfaceType for planetary surface model with
/// custom ellipsoid properties.
/// \param[in] _type SurfaceType value.
/// \param[in] _axisEquatorial Equatorial axis of the surface.
/// \param[in] _axisPolar Polar axis of the surface.
public: void SetSurface(
const SurfaceType &_type,
const double _axisEquatorial,
const double _axisPolar);

/// \brief Set reference geodetic latitude.
/// \param[in] _angle Reference geodetic latitude.
public: void SetLatitudeReference(const gz::math::Angle &_angle);
Expand Down
182 changes: 181 additions & 1 deletion src/SphericalCoordinates.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,31 @@ const double g_EarthWGS84Flattening = 1.0/298.257223563;
// Radius of the Earth (meters).
const double g_EarthRadius = 6371000.0;

// Radius of the Moon (meters).
// Source: https://lunar.gsfc.nasa.gov/library/451-SCI-000958.pdf
const double g_MoonRadius = 1737400.0;

// a: Equatorial radius of the Moon.
// Source : https://nssdc.gsfc.nasa.gov/planetary/factsheet/moonfact.html
const double g_MoonAxisEquatorial = 1738100.0;

// b: Polar radius of the Moon.
// Source : https://nssdc.gsfc.nasa.gov/planetary/factsheet/moonfact.html
const double g_MoonAxisPolar = 1736000.0;

// if: Unitless flattening parameter for the Moon.
// Source : https://nssdc.gsfc.nasa.gov/planetary/factsheet/moonfact.html
const double g_MoonFlattening = 0.0012;

// Private data for the SphericalCoordinates class.
class gz::math::SphericalCoordinates::Implementation
{
/// \brief Type of surface being used.
public: SphericalCoordinates::SurfaceType surfaceType;

/// \brief Radius of the given SurfaceType.
public: double surfaceRadius = 0;

/// \brief Latitude of reference point.
public: gz::math::Angle latitudeReference;

Expand Down Expand Up @@ -94,6 +113,10 @@ SphericalCoordinates::SurfaceType SphericalCoordinates::Convert(
{
if ("EARTH_WGS84" == _str)
return EARTH_WGS84;
else if ("MOON_SCS" == _str)
return MOON_SCS;
else if ("CUSTOM_SURFACE" == _str)
return CUSTOM_SURFACE;

std::cerr << "SurfaceType string not recognized, "
<< "EARTH_WGS84 returned by default" << std::endl;
Expand All @@ -106,6 +129,10 @@ std::string SphericalCoordinates::Convert(
{
if (_type == EARTH_WGS84)
return "EARTH_WGS84";
else if (_type == MOON_SCS)
return "MOON_SCS";
else if (_type == CUSTOM_SURFACE)
return "CUSTOM_SURFACE";

std::cerr << "SurfaceType not recognized, "
<< "EARTH_WGS84 returned by default" << std::endl;
Expand All @@ -128,6 +155,20 @@ SphericalCoordinates::SphericalCoordinates(const SurfaceType _type)
this->SetElevationReference(0.0);
}

//////////////////////////////////////////////////
SphericalCoordinates::SphericalCoordinates(
const SurfaceType _type,
const double _axisEquatorial,
const double _axisPolar)
: SphericalCoordinates()
{
// Set properties
this->SetSurface(_type, _axisEquatorial,
_axisPolar);

this->SetElevationReference(0.0);
}

//////////////////////////////////////////////////
SphericalCoordinates::SphericalCoordinates(const SurfaceType _type,
const gz::math::Angle &_latitude,
Expand Down Expand Up @@ -208,6 +249,42 @@ void SphericalCoordinates::SetSurface(const SurfaceType &_type)
std::pow(this->dataPtr->ellA, 2) / std::pow(this->dataPtr->ellB, 2) -
1.0);

// Set the radius of the surface.
this->dataPtr->surfaceRadius = g_EarthRadius;

break;
}
case MOON_SCS:
{
// Set the semi-major axis
this->dataPtr->ellA = g_MoonAxisEquatorial;

// Set the semi-minor axis
this->dataPtr->ellB = g_MoonAxisPolar;

// Set the flattening parameter
this->dataPtr->ellF = g_MoonFlattening;

// Set the first eccentricity ellipse parameter
// https://en.wikipedia.org/wiki/Eccentricity_(mathematics)#Ellipses
this->dataPtr->ellE = sqrt(1.0 -
std::pow(this->dataPtr->ellB, 2) / std::pow(this->dataPtr->ellA, 2));

// Set the second eccentricity ellipse parameter
// https://en.wikipedia.org/wiki/Eccentricity_(mathematics)#Ellipses
this->dataPtr->ellP = sqrt(
std::pow(this->dataPtr->ellA, 2) / std::pow(this->dataPtr->ellB, 2) -
1.0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the ellE and ellP computations are repeated between this MOON_SCS case and the prior EARTH_WGS84 case. We could potentially move them outside of this switch block if the CUSTOM_SERVICE and default cases had a return instead of break, but this isn't a big deal, so it's not required


// Set the radius of the surface.
this->dataPtr->surfaceRadius = g_MoonRadius;

break;
}
case CUSTOM_SURFACE:
{
std::cerr << "For custom surfaces, use SetSurface(type, radius,"
"axisEquatorial, axisPolar)" << std::endl;
break;
}
default:
Expand All @@ -219,6 +296,53 @@ void SphericalCoordinates::SetSurface(const SurfaceType &_type)
}
}

//////////////////////////////////////////////////
void SphericalCoordinates::SetSurface(
const SurfaceType &_type,
const double _axisEquatorial,
const double _axisPolar)
{
if ((_type != EARTH_WGS84) &&
(_type != MOON_SCS) &&
(_type != CUSTOM_SURFACE))
{
std::cerr << "Unknown surface type["
<< _type << "]\n";
return;
}

this->dataPtr->surfaceType = _type;

if ((_axisEquatorial > 0)
&& (_axisPolar > 0)
&& (_axisPolar <= _axisEquatorial))
{
this->dataPtr->ellA = _axisEquatorial;
this->dataPtr->ellB = _axisPolar;
this->dataPtr->ellF =
(_axisEquatorial - _axisPolar) / _axisEquatorial;
// Arithmetic mean radius
this->dataPtr->surfaceRadius =
(2 * _axisEquatorial + _axisPolar) / 3.0;
}
else
{
std::cerr << "Invalid parameters found, defaulting to "
"Earth's parameters" << std::endl;

this->dataPtr->ellA = g_EarthWGS84AxisEquatorial;
this->dataPtr->ellB = g_EarthWGS84AxisPolar;
this->dataPtr->ellF = g_EarthWGS84Flattening;
this->dataPtr->surfaceRadius = g_EarthRadius;
}

this->dataPtr->ellE = sqrt(1.0 -
std::pow(this->dataPtr->ellB, 2) / std::pow(this->dataPtr->ellA, 2));
this->dataPtr->ellP = sqrt(
std::pow(this->dataPtr->ellA, 2) / std::pow(this->dataPtr->ellB, 2) -
1.0);
}

//////////////////////////////////////////////////
void SphericalCoordinates::SetLatitudeReference(
const gz::math::Angle &_angle)
Expand Down Expand Up @@ -286,7 +410,7 @@ gz::math::Vector3d SphericalCoordinates::LocalFromGlobalVelocity(

//////////////////////////////////////////////////
/// Based on Haversine formula (http://en.wikipedia.org/wiki/Haversine_formula).
double SphericalCoordinates::Distance(const gz::math::Angle &_latA,
double SphericalCoordinates::DistanceWGS84(const gz::math::Angle &_latA,
const gz::math::Angle &_lonA,
const gz::math::Angle &_latB,
const gz::math::Angle &_lonB)
Expand All @@ -303,6 +427,62 @@ double SphericalCoordinates::Distance(const gz::math::Angle &_latA,
return d;
}

//////////////////////////////////////////////////
/// Based on Haversine formula (http://en.wikipedia.org/wiki/Haversine_formula).
double SphericalCoordinates::Distance(const gz::math::Angle &_latA,
const gz::math::Angle &_lonA,
const gz::math::Angle &_latB,
const gz::math::Angle &_lonB)
{
return gz::math::SphericalCoordinates::DistanceWGS84(
_latA, _lonA, _latB, _lonB);
}

//////////////////////////////////////////////////
/// Based on Haversine formula (http://en.wikipedia.org/wiki/Haversine_formula).
/// This takes into account the surface type.
double SphericalCoordinates::DistanceBetweenPoints(
const gz::math::Angle &_latA,
const gz::math::Angle &_lonA,
const gz::math::Angle &_latB,
const gz::math::Angle &_lonB)
{
gz::math::Angle dLat = _latB - _latA;
gz::math::Angle dLon = _lonB - _lonA;

double a = sin(dLat.Radian() / 2) * sin(dLat.Radian() / 2) +
sin(dLon.Radian() / 2) * sin(dLon.Radian() / 2) *
cos(_latA.Radian()) * cos(_latB.Radian());

double c = 2 * atan2(sqrt(a), sqrt(1 - a));
double d = this->dataPtr->surfaceRadius * c;
return d;
}

//////////////////////////////////////////////////
double SphericalCoordinates::SurfaceRadius()
{
return this->dataPtr->surfaceRadius;
}

//////////////////////////////////////////////////
double SphericalCoordinates::SurfaceAxisEquatorial()
{
return this->dataPtr->ellA;
}

//////////////////////////////////////////////////
double SphericalCoordinates::SurfaceAxisPolar()
{
return this->dataPtr->ellB;
}

//////////////////////////////////////////////////
double SphericalCoordinates::SurfaceFlattening()
{
return this->dataPtr->ellF;
}

//////////////////////////////////////////////////
void SphericalCoordinates::UpdateTransformationMatrix()
{
Expand Down
Loading