Skip to content

Commit 33a4827

Browse files
adityapande-1995chapulinamethylDragonMichael Carroll
authored
Compute distance between points on a general celestial body (#434)
* Added distance calculation method considering the radius, deprecated old distance method, updated python bindings Signed-off-by: Aditya <aditya050995@gmail.com> Co-authored-by: Louise Poubel <louise@openrobotics.org> Co-authored-by: methylDragon <methylDragon@gmail.com> Co-authored-by: Michael Carroll <michael@openrobotics.org>
1 parent d15c9b2 commit 33a4827

File tree

6 files changed

+532
-17
lines changed

6 files changed

+532
-17
lines changed

Migration.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ release will remove the deprecated code.
2424
+ All mutator functions that lacked a `Set` prefix have been deprecated
2525
and replaced by version with a `Set` prefix.
2626

27+
1. **SphericalCoordinates.hh**
28+
+ ***Deprecation:*** public: static double Distance(const Angle&, const Angle&, const Angle&, const Angle&)
29+
+ ***Replacement:*** public: static double DistanceWGS84(const Angle&, const Angle&, const Angle&, const Angle&)
30+
2731
1. **Matrix3.hh**
2832
+ ***Deprecation:*** public: void Axes(const Vector3<T> &, const Vector3<T> &, const Vector3<T> &)
2933
+ ***Replacement:*** public: void SetAxes(const Vector3<T> &, const Vector3<T> &, const Vector3<T> &)

include/gz/math/SphericalCoordinates.hh

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,15 @@ namespace gz
4141
{
4242
/// \brief Model of reference ellipsoid for earth, based on
4343
/// WGS 84 standard. see wikipedia: World_Geodetic_System
44-
EARTH_WGS84 = 1
44+
EARTH_WGS84 = 1,
45+
46+
/// \brief Model of the moon, based on the Selenographic
47+
/// coordinate system, see wikipedia: Selenographic
48+
/// Coordinate System.
49+
MOON_SCS = 2,
50+
51+
/// \brief Custom surface type
52+
CUSTOM_SURFACE = 10
4553
};
4654

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

84+
/// \brief Constructor with surface type input and properties
85+
/// input. To be used for CUSTOM_SURFACE.
86+
/// \param[in] _type SurfaceType specification.
87+
/// \param[in] _axisEquatorial Semi major axis of the surface.
88+
/// \param[in] _axisPolar Semi minor axis of the surface.
89+
public: SphericalCoordinates(
90+
const SurfaceType _type,
91+
const double _axisEquatorial,
92+
const double _axisPolar);
93+
7694
/// \brief Constructor with surface type, angle, and elevation inputs.
7795
/// \param[in] _type SurfaceType specification.
7896
/// \param[in] _latitude Reference latitude.
@@ -85,7 +103,6 @@ namespace gz
85103
const double _elevation,
86104
const gz::math::Angle &_heading);
87105

88-
89106
/// \brief Convert a Cartesian position vector to geodetic coordinates.
90107
/// This performs a `PositionTransform` from LOCAL to SPHERICAL.
91108
///
@@ -136,15 +153,66 @@ namespace gz
136153
/// \param[in] _latB Latitude of point B.
137154
/// \param[in] _lonB Longitude of point B.
138155
/// \return Distance in meters.
139-
public: static double Distance(const gz::math::Angle &_latA,
156+
/// \deprecated Use DistanceWGS84 instead.
157+
public: GZ_DEPRECATED(7) static double Distance(
158+
const gz::math::Angle &_latA,
159+
const gz::math::Angle &_lonA,
160+
const gz::math::Angle &_latB,
161+
const gz::math::Angle &_lonB);
162+
163+
/// \brief Get the distance between two points expressed in geographic
164+
/// latitude and longitude. It assumes that both points are at sea level.
165+
/// Example: _latA = 38.0016667 and _lonA = -123.0016667) represents
166+
/// the point with latitude 38d 0'6.00"N and longitude 123d 0'6.00"W.
167+
/// This method assumes that the surface model is EARTH_WGS84.
168+
/// \param[in] _latA Latitude of point A.
169+
/// \param[in] _lonA Longitude of point A.
170+
/// \param[in] _latB Latitude of point B.
171+
/// \param[in] _lonB Longitude of point B.
172+
/// \return Distance in meters.
173+
public: static double DistanceWGS84(
174+
const gz::math::Angle &_latA,
140175
const gz::math::Angle &_lonA,
141176
const gz::math::Angle &_latB,
142177
const gz::math::Angle &_lonB);
143178

179+
/// \brief Get the distance between two points expressed in geographic
180+
/// latitude and longitude. It assumes that both points are at sea level.
181+
/// Example: _latA = 38.0016667 and _lonA = -123.0016667) represents
182+
/// the point with latitude 38d 0'6.00"N and longitude 123d 0'6.00"W.
183+
/// This is different from the deprecated static Distance() method as it
184+
/// takes into account the set surface's radius.
185+
/// \param[in] _latA Latitude of point A.
186+
/// \param[in] _lonA Longitude of point A.
187+
/// \param[in] _latB Latitude of point B.
188+
/// \param[in] _lonB Longitude of point B.
189+
/// \return Distance in meters.
190+
public: double DistanceBetweenPoints(
191+
const gz::math::Angle &_latA,
192+
const gz::math::Angle &_lonA,
193+
const gz::math::Angle &_latB,
194+
const gz::math::Angle &_lonB);
195+
144196
/// \brief Get SurfaceType currently in use.
145197
/// \return Current SurfaceType value.
146198
public: SurfaceType Surface() const;
147199

200+
/// \brief Get the radius of the surface.
201+
/// \return radius of the surface in use.
202+
public: double SurfaceRadius();
203+
204+
/// \brief Get the major axis of the surface.
205+
/// \return Equatorial axis of the surface in use.
206+
public: double SurfaceAxisEquatorial();
207+
208+
/// \brief Get the minor axis of the surface.
209+
/// \return Polar axis of the surface in use.
210+
public: double SurfaceAxisPolar();
211+
212+
/// \brief Get the flattening of the surface.
213+
/// \return Flattening parameter of the surface in use.
214+
public: double SurfaceFlattening();
215+
148216
/// \brief Get reference geodetic latitude.
149217
/// \return Reference geodetic latitude.
150218
public: gz::math::Angle LatitudeReference() const;
@@ -167,6 +235,16 @@ namespace gz
167235
/// \param[in] _type SurfaceType value.
168236
public: void SetSurface(const SurfaceType &_type);
169237

238+
/// \brief Set SurfaceType for planetary surface model with
239+
/// custom ellipsoid properties.
240+
/// \param[in] _type SurfaceType value.
241+
/// \param[in] _axisEquatorial Equatorial axis of the surface.
242+
/// \param[in] _axisPolar Polar axis of the surface.
243+
public: void SetSurface(
244+
const SurfaceType &_type,
245+
const double _axisEquatorial,
246+
const double _axisPolar);
247+
170248
/// \brief Set reference geodetic latitude.
171249
/// \param[in] _angle Reference geodetic latitude.
172250
public: void SetLatitudeReference(const gz::math::Angle &_angle);

src/SphericalCoordinates.cc

Lines changed: 181 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,31 @@ const double g_EarthWGS84Flattening = 1.0/298.257223563;
3838
// Radius of the Earth (meters).
3939
const double g_EarthRadius = 6371000.0;
4040

41+
// Radius of the Moon (meters).
42+
// Source: https://lunar.gsfc.nasa.gov/library/451-SCI-000958.pdf
43+
const double g_MoonRadius = 1737400.0;
44+
45+
// a: Equatorial radius of the Moon.
46+
// Source : https://nssdc.gsfc.nasa.gov/planetary/factsheet/moonfact.html
47+
const double g_MoonAxisEquatorial = 1738100.0;
48+
49+
// b: Polar radius of the Moon.
50+
// Source : https://nssdc.gsfc.nasa.gov/planetary/factsheet/moonfact.html
51+
const double g_MoonAxisPolar = 1736000.0;
52+
53+
// if: Unitless flattening parameter for the Moon.
54+
// Source : https://nssdc.gsfc.nasa.gov/planetary/factsheet/moonfact.html
55+
const double g_MoonFlattening = 0.0012;
56+
4157
// Private data for the SphericalCoordinates class.
4258
class gz::math::SphericalCoordinates::Implementation
4359
{
4460
/// \brief Type of surface being used.
4561
public: SphericalCoordinates::SurfaceType surfaceType;
4662

63+
/// \brief Radius of the given SurfaceType.
64+
public: double surfaceRadius = 0;
65+
4766
/// \brief Latitude of reference point.
4867
public: gz::math::Angle latitudeReference;
4968

@@ -94,6 +113,10 @@ SphericalCoordinates::SurfaceType SphericalCoordinates::Convert(
94113
{
95114
if ("EARTH_WGS84" == _str)
96115
return EARTH_WGS84;
116+
else if ("MOON_SCS" == _str)
117+
return MOON_SCS;
118+
else if ("CUSTOM_SURFACE" == _str)
119+
return CUSTOM_SURFACE;
97120

98121
std::cerr << "SurfaceType string not recognized, "
99122
<< "EARTH_WGS84 returned by default" << std::endl;
@@ -106,6 +129,10 @@ std::string SphericalCoordinates::Convert(
106129
{
107130
if (_type == EARTH_WGS84)
108131
return "EARTH_WGS84";
132+
else if (_type == MOON_SCS)
133+
return "MOON_SCS";
134+
else if (_type == CUSTOM_SURFACE)
135+
return "CUSTOM_SURFACE";
109136

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

158+
//////////////////////////////////////////////////
159+
SphericalCoordinates::SphericalCoordinates(
160+
const SurfaceType _type,
161+
const double _axisEquatorial,
162+
const double _axisPolar)
163+
: SphericalCoordinates()
164+
{
165+
// Set properties
166+
this->SetSurface(_type, _axisEquatorial,
167+
_axisPolar);
168+
169+
this->SetElevationReference(0.0);
170+
}
171+
131172
//////////////////////////////////////////////////
132173
SphericalCoordinates::SphericalCoordinates(const SurfaceType _type,
133174
const gz::math::Angle &_latitude,
@@ -208,6 +249,42 @@ void SphericalCoordinates::SetSurface(const SurfaceType &_type)
208249
std::pow(this->dataPtr->ellA, 2) / std::pow(this->dataPtr->ellB, 2) -
209250
1.0);
210251

252+
// Set the radius of the surface.
253+
this->dataPtr->surfaceRadius = g_EarthRadius;
254+
255+
break;
256+
}
257+
case MOON_SCS:
258+
{
259+
// Set the semi-major axis
260+
this->dataPtr->ellA = g_MoonAxisEquatorial;
261+
262+
// Set the semi-minor axis
263+
this->dataPtr->ellB = g_MoonAxisPolar;
264+
265+
// Set the flattening parameter
266+
this->dataPtr->ellF = g_MoonFlattening;
267+
268+
// Set the first eccentricity ellipse parameter
269+
// https://en.wikipedia.org/wiki/Eccentricity_(mathematics)#Ellipses
270+
this->dataPtr->ellE = sqrt(1.0 -
271+
std::pow(this->dataPtr->ellB, 2) / std::pow(this->dataPtr->ellA, 2));
272+
273+
// Set the second eccentricity ellipse parameter
274+
// https://en.wikipedia.org/wiki/Eccentricity_(mathematics)#Ellipses
275+
this->dataPtr->ellP = sqrt(
276+
std::pow(this->dataPtr->ellA, 2) / std::pow(this->dataPtr->ellB, 2) -
277+
1.0);
278+
279+
// Set the radius of the surface.
280+
this->dataPtr->surfaceRadius = g_MoonRadius;
281+
282+
break;
283+
}
284+
case CUSTOM_SURFACE:
285+
{
286+
std::cerr << "For custom surfaces, use SetSurface(type, radius,"
287+
"axisEquatorial, axisPolar)" << std::endl;
211288
break;
212289
}
213290
default:
@@ -219,6 +296,53 @@ void SphericalCoordinates::SetSurface(const SurfaceType &_type)
219296
}
220297
}
221298

299+
//////////////////////////////////////////////////
300+
void SphericalCoordinates::SetSurface(
301+
const SurfaceType &_type,
302+
const double _axisEquatorial,
303+
const double _axisPolar)
304+
{
305+
if ((_type != EARTH_WGS84) &&
306+
(_type != MOON_SCS) &&
307+
(_type != CUSTOM_SURFACE))
308+
{
309+
std::cerr << "Unknown surface type["
310+
<< _type << "]\n";
311+
return;
312+
}
313+
314+
this->dataPtr->surfaceType = _type;
315+
316+
if ((_axisEquatorial > 0)
317+
&& (_axisPolar > 0)
318+
&& (_axisPolar <= _axisEquatorial))
319+
{
320+
this->dataPtr->ellA = _axisEquatorial;
321+
this->dataPtr->ellB = _axisPolar;
322+
this->dataPtr->ellF =
323+
(_axisEquatorial - _axisPolar) / _axisEquatorial;
324+
// Arithmetic mean radius
325+
this->dataPtr->surfaceRadius =
326+
(2 * _axisEquatorial + _axisPolar) / 3.0;
327+
}
328+
else
329+
{
330+
std::cerr << "Invalid parameters found, defaulting to "
331+
"Earth's parameters" << std::endl;
332+
333+
this->dataPtr->ellA = g_EarthWGS84AxisEquatorial;
334+
this->dataPtr->ellB = g_EarthWGS84AxisPolar;
335+
this->dataPtr->ellF = g_EarthWGS84Flattening;
336+
this->dataPtr->surfaceRadius = g_EarthRadius;
337+
}
338+
339+
this->dataPtr->ellE = sqrt(1.0 -
340+
std::pow(this->dataPtr->ellB, 2) / std::pow(this->dataPtr->ellA, 2));
341+
this->dataPtr->ellP = sqrt(
342+
std::pow(this->dataPtr->ellA, 2) / std::pow(this->dataPtr->ellB, 2) -
343+
1.0);
344+
}
345+
222346
//////////////////////////////////////////////////
223347
void SphericalCoordinates::SetLatitudeReference(
224348
const gz::math::Angle &_angle)
@@ -286,7 +410,7 @@ gz::math::Vector3d SphericalCoordinates::LocalFromGlobalVelocity(
286410

287411
//////////////////////////////////////////////////
288412
/// Based on Haversine formula (http://en.wikipedia.org/wiki/Haversine_formula).
289-
double SphericalCoordinates::Distance(const gz::math::Angle &_latA,
413+
double SphericalCoordinates::DistanceWGS84(const gz::math::Angle &_latA,
290414
const gz::math::Angle &_lonA,
291415
const gz::math::Angle &_latB,
292416
const gz::math::Angle &_lonB)
@@ -303,6 +427,62 @@ double SphericalCoordinates::Distance(const gz::math::Angle &_latA,
303427
return d;
304428
}
305429

430+
//////////////////////////////////////////////////
431+
/// Based on Haversine formula (http://en.wikipedia.org/wiki/Haversine_formula).
432+
double SphericalCoordinates::Distance(const gz::math::Angle &_latA,
433+
const gz::math::Angle &_lonA,
434+
const gz::math::Angle &_latB,
435+
const gz::math::Angle &_lonB)
436+
{
437+
return gz::math::SphericalCoordinates::DistanceWGS84(
438+
_latA, _lonA, _latB, _lonB);
439+
}
440+
441+
//////////////////////////////////////////////////
442+
/// Based on Haversine formula (http://en.wikipedia.org/wiki/Haversine_formula).
443+
/// This takes into account the surface type.
444+
double SphericalCoordinates::DistanceBetweenPoints(
445+
const gz::math::Angle &_latA,
446+
const gz::math::Angle &_lonA,
447+
const gz::math::Angle &_latB,
448+
const gz::math::Angle &_lonB)
449+
{
450+
gz::math::Angle dLat = _latB - _latA;
451+
gz::math::Angle dLon = _lonB - _lonA;
452+
453+
double a = sin(dLat.Radian() / 2) * sin(dLat.Radian() / 2) +
454+
sin(dLon.Radian() / 2) * sin(dLon.Radian() / 2) *
455+
cos(_latA.Radian()) * cos(_latB.Radian());
456+
457+
double c = 2 * atan2(sqrt(a), sqrt(1 - a));
458+
double d = this->dataPtr->surfaceRadius * c;
459+
return d;
460+
}
461+
462+
//////////////////////////////////////////////////
463+
double SphericalCoordinates::SurfaceRadius()
464+
{
465+
return this->dataPtr->surfaceRadius;
466+
}
467+
468+
//////////////////////////////////////////////////
469+
double SphericalCoordinates::SurfaceAxisEquatorial()
470+
{
471+
return this->dataPtr->ellA;
472+
}
473+
474+
//////////////////////////////////////////////////
475+
double SphericalCoordinates::SurfaceAxisPolar()
476+
{
477+
return this->dataPtr->ellB;
478+
}
479+
480+
//////////////////////////////////////////////////
481+
double SphericalCoordinates::SurfaceFlattening()
482+
{
483+
return this->dataPtr->ellF;
484+
}
485+
306486
//////////////////////////////////////////////////
307487
void SphericalCoordinates::UpdateTransformationMatrix()
308488
{

0 commit comments

Comments
 (0)