add GeographicLib
This commit is contained in:
198
external/include/GeographicLib/Accumulator.hpp
vendored
Normal file
198
external/include/GeographicLib/Accumulator.hpp
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* \file Accumulator.hpp
|
||||
* \brief Header for GeographicLib::Accumulator class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2010-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_ACCUMULATOR_HPP)
|
||||
#define GEOGRAPHICLIB_ACCUMULATOR_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief An accumulator for sums
|
||||
*
|
||||
* This allows many numbers of floating point type \e T to be added together
|
||||
* with twice the normal precision. Thus if \e T is double, the effective
|
||||
* precision of the sum is 106 bits or about 32 decimal places.
|
||||
*
|
||||
* The implementation follows J. R. Shewchuk,
|
||||
* <a href="https://doi.org/10.1007/PL00009321"> Adaptive Precision
|
||||
* Floating-Point Arithmetic and Fast Robust Geometric Predicates</a>,
|
||||
* Discrete & Computational Geometry 18(3) 305--363 (1997).
|
||||
*
|
||||
* Approximate timings (summing a vector<double>)
|
||||
* - double: 2ns
|
||||
* - Accumulator<double>: 23ns
|
||||
*
|
||||
* In the documentation of the member functions, \e sum stands for the value
|
||||
* currently held in the accumulator.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-Accumulator.cpp
|
||||
**********************************************************************/
|
||||
template<typename T = Math::real>
|
||||
class GEOGRAPHICLIB_EXPORT Accumulator {
|
||||
private:
|
||||
// _s + _t accumulators for the sum.
|
||||
T _s, _t;
|
||||
// Same as Math::sum, but requires abs(u) >= abs(v). This isn't currently
|
||||
// used.
|
||||
static T fastsum(T u, T v, T& t) {
|
||||
GEOGRAPHICLIB_VOLATILE T s = u + v;
|
||||
GEOGRAPHICLIB_VOLATILE T vp = s - u;
|
||||
t = v - vp;
|
||||
return s;
|
||||
}
|
||||
void Add(T y) {
|
||||
// Here's Shewchuk's solution...
|
||||
T u; // hold exact sum as [s, t, u]
|
||||
// Accumulate starting at least significant end
|
||||
y = Math::sum(y, _t, u);
|
||||
_s = Math::sum(y, _s, _t);
|
||||
// Start is _s, _t decreasing and non-adjacent. Sum is now (s + t + u)
|
||||
// exactly with s, t, u non-adjacent and in decreasing order (except for
|
||||
// possible zeros). The following code tries to normalize the result.
|
||||
// Ideally, we want _s = round(s+t+u) and _u = round(s+t+u - _s). The
|
||||
// following does an approximate job (and maintains the decreasing
|
||||
// non-adjacent property). Here are two "failures" using 3-bit floats:
|
||||
//
|
||||
// Case 1: _s is not equal to round(s+t+u) -- off by 1 ulp
|
||||
// [12, -1] - 8 -> [4, 0, -1] -> [4, -1] = 3 should be [3, 0] = 3
|
||||
//
|
||||
// Case 2: _s+_t is not as close to s+t+u as it shold be
|
||||
// [64, 5] + 4 -> [64, 8, 1] -> [64, 8] = 72 (off by 1)
|
||||
// should be [80, -7] = 73 (exact)
|
||||
//
|
||||
// "Fixing" these problems is probably not worth the expense. The
|
||||
// representation inevitably leads to small errors in the accumulated
|
||||
// values. The additional errors illustrated here amount to 1 ulp of the
|
||||
// less significant word during each addition to the Accumulator and an
|
||||
// additional possible error of 1 ulp in the reported sum.
|
||||
//
|
||||
// Incidentally, the "ideal" representation described above is not
|
||||
// canonical, because _s = round(_s + _t) may not be true. For example,
|
||||
// with 3-bit floats:
|
||||
//
|
||||
// [128, 16] + 1 -> [160, -16] -- 160 = round(145).
|
||||
// But [160, 0] - 16 -> [128, 16] -- 128 = round(144).
|
||||
//
|
||||
if (_s == 0) // This implies t == 0,
|
||||
_s = u; // so result is u
|
||||
else
|
||||
_t += u; // otherwise just accumulate u to t.
|
||||
}
|
||||
T Sum(T y) const {
|
||||
Accumulator a(*this);
|
||||
a.Add(y);
|
||||
return a._s;
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* Construct from a \e T. This is not declared explicit, so that you can
|
||||
* write <code>Accumulator<double> a = 5;</code>.
|
||||
*
|
||||
* @param[in] y set \e sum = \e y.
|
||||
**********************************************************************/
|
||||
Accumulator(T y = T(0)) : _s(y), _t(0) {
|
||||
static_assert(!std::numeric_limits<T>::is_integer,
|
||||
"Accumulator type is not floating point");
|
||||
}
|
||||
/**
|
||||
* Set the accumulator to a number.
|
||||
*
|
||||
* @param[in] y set \e sum = \e y.
|
||||
**********************************************************************/
|
||||
Accumulator& operator=(T y) { _s = y; _t = 0; return *this; }
|
||||
/**
|
||||
* Return the value held in the accumulator.
|
||||
*
|
||||
* @return \e sum.
|
||||
**********************************************************************/
|
||||
T operator()() const { return _s; }
|
||||
/**
|
||||
* Return the result of adding a number to \e sum (but don't change \e
|
||||
* sum).
|
||||
*
|
||||
* @param[in] y the number to be added to the sum.
|
||||
* @return \e sum + \e y.
|
||||
**********************************************************************/
|
||||
T operator()(T y) const { return Sum(y); }
|
||||
/**
|
||||
* Add a number to the accumulator.
|
||||
*
|
||||
* @param[in] y set \e sum += \e y.
|
||||
**********************************************************************/
|
||||
Accumulator& operator+=(T y) { Add(y); return *this; }
|
||||
/**
|
||||
* Subtract a number from the accumulator.
|
||||
*
|
||||
* @param[in] y set \e sum -= \e y.
|
||||
**********************************************************************/
|
||||
Accumulator& operator-=(T y) { Add(-y); return *this; }
|
||||
/**
|
||||
* Multiply accumulator by an integer. To avoid loss of accuracy, use only
|
||||
* integers such that \e n × \e T is exactly representable as a \e T
|
||||
* (i.e., ± powers of two). Use \e n = −1 to negate \e sum.
|
||||
*
|
||||
* @param[in] n set \e sum *= \e n.
|
||||
**********************************************************************/
|
||||
Accumulator& operator*=(int n) { _s *= n; _t *= n; return *this; }
|
||||
/**
|
||||
* Multiply accumulator by a number. The fma (fused multiply and add)
|
||||
* instruction is used (if available) in order to maintain accuracy.
|
||||
*
|
||||
* @param[in] y set \e sum *= \e y.
|
||||
**********************************************************************/
|
||||
Accumulator& operator*=(T y) {
|
||||
using std::fma;
|
||||
T d = _s; _s *= y;
|
||||
d = fma(y, d, -_s); // the error in the first multiplication
|
||||
_t = fma(y, _t, d); // add error to the second term
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Reduce accumulator to the range [-y/2, y/2].
|
||||
*
|
||||
* @param[in] y the modulus.
|
||||
**********************************************************************/
|
||||
Accumulator& remainder(T y) {
|
||||
using std::remainder;
|
||||
_s = remainder(_s, y);
|
||||
Add(0); // This renormalizes the result.
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* Test equality of an Accumulator with a number.
|
||||
**********************************************************************/
|
||||
bool operator==(T y) const { return _s == y; }
|
||||
/**
|
||||
* Test inequality of an Accumulator with a number.
|
||||
**********************************************************************/
|
||||
bool operator!=(T y) const { return _s != y; }
|
||||
/**
|
||||
* Less operator on an Accumulator and a number.
|
||||
**********************************************************************/
|
||||
bool operator<(T y) const { return _s < y; }
|
||||
/**
|
||||
* Less or equal operator on an Accumulator and a number.
|
||||
**********************************************************************/
|
||||
bool operator<=(T y) const { return _s <= y; }
|
||||
/**
|
||||
* Greater operator on an Accumulator and a number.
|
||||
**********************************************************************/
|
||||
bool operator>(T y) const { return _s > y; }
|
||||
/**
|
||||
* Greater or equal operator on an Accumulator and a number.
|
||||
**********************************************************************/
|
||||
bool operator>=(T y) const { return _s >= y; }
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_ACCUMULATOR_HPP
|
||||
321
external/include/GeographicLib/AlbersEqualArea.hpp
vendored
Normal file
321
external/include/GeographicLib/AlbersEqualArea.hpp
vendored
Normal file
@@ -0,0 +1,321 @@
|
||||
/**
|
||||
* \file AlbersEqualArea.hpp
|
||||
* \brief Header for GeographicLib::AlbersEqualArea class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2010-2021) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_ALBERSEQUALAREA_HPP)
|
||||
#define GEOGRAPHICLIB_ALBERSEQUALAREA_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Albers equal area conic projection
|
||||
*
|
||||
* Implementation taken from the report,
|
||||
* - J. P. Snyder,
|
||||
* <a href="http://pubs.er.usgs.gov/usgspubs/pp/pp1395"> Map Projections: A
|
||||
* Working Manual</a>, USGS Professional Paper 1395 (1987),
|
||||
* pp. 101--102.
|
||||
*
|
||||
* This is a implementation of the equations in Snyder except that divided
|
||||
* differences will be [have been] used to transform the expressions into
|
||||
* ones which may be evaluated accurately. [In this implementation, the
|
||||
* projection correctly becomes the cylindrical equal area or the azimuthal
|
||||
* equal area projection when the standard latitude is the equator or a
|
||||
* pole.]
|
||||
*
|
||||
* The ellipsoid parameters, the standard parallels, and the scale on the
|
||||
* standard parallels are set in the constructor. Internally, the case with
|
||||
* two standard parallels is converted into a single standard parallel, the
|
||||
* latitude of minimum azimuthal scale, with an azimuthal scale specified on
|
||||
* this parallel. This latitude is also used as the latitude of origin which
|
||||
* is returned by AlbersEqualArea::OriginLatitude. The azimuthal scale on
|
||||
* the latitude of origin is given by AlbersEqualArea::CentralScale. The
|
||||
* case with two standard parallels at opposite poles is singular and is
|
||||
* disallowed. The central meridian (which is a trivial shift of the
|
||||
* longitude) is specified as the \e lon0 argument of the
|
||||
* AlbersEqualArea::Forward and AlbersEqualArea::Reverse functions.
|
||||
* AlbersEqualArea::Forward and AlbersEqualArea::Reverse also return the
|
||||
* meridian convergence, γ, and azimuthal scale, \e k. A small square
|
||||
* aligned with the cardinal directions is projected to a rectangle with
|
||||
* dimensions \e k (in the E-W direction) and 1/\e k (in the N-S direction).
|
||||
* The E-W sides of the rectangle are oriented γ degrees
|
||||
* counter-clockwise from the \e x axis. There is no provision in this class
|
||||
* for specifying a false easting or false northing or a different latitude
|
||||
* of origin.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-AlbersEqualArea.cpp
|
||||
*
|
||||
* <a href="ConicProj.1.html">ConicProj</a> is a command-line utility
|
||||
* providing access to the functionality of LambertConformalConic and
|
||||
* AlbersEqualArea.
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT AlbersEqualArea {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
real eps_, epsx_, epsx2_, tol_, tol0_;
|
||||
real _a, _f, _fm, _e2, _e, _e2m, _qZ, _qx;
|
||||
real _sign, _lat0, _k0;
|
||||
real _n0, _m02, _nrho0, _k2, _txi0, _scxi0, _sxi0;
|
||||
static const int numit_ = 5; // Newton iterations in Reverse
|
||||
static const int numit0_ = 20; // Newton iterations in Init
|
||||
static real hyp(real x) {
|
||||
using std::hypot;
|
||||
return hypot(real(1), x);
|
||||
}
|
||||
// atanh( e * x)/ e if f > 0
|
||||
// atan (sqrt(-e2) * x)/sqrt(-e2) if f < 0
|
||||
// x if f = 0
|
||||
real atanhee(real x) const {
|
||||
using std::atan; using std::abs; using std::atanh;
|
||||
return _f > 0 ? atanh(_e * x)/_e : (_f < 0 ? (atan(_e * x)/_e) : x);
|
||||
}
|
||||
// return atanh(sqrt(x))/sqrt(x) - 1, accurate for small x
|
||||
static real atanhxm1(real x);
|
||||
|
||||
// Divided differences
|
||||
// Definition: Df(x,y) = (f(x)-f(y))/(x-y)
|
||||
// See:
|
||||
// W. M. Kahan and R. J. Fateman,
|
||||
// Symbolic computation of divided differences,
|
||||
// SIGSAM Bull. 33(3), 7-28 (1999)
|
||||
// https://doi.org/10.1145/334714.334716
|
||||
// http://www.cs.berkeley.edu/~fateman/papers/divdiff.pdf
|
||||
//
|
||||
// General rules
|
||||
// h(x) = f(g(x)): Dh(x,y) = Df(g(x),g(y))*Dg(x,y)
|
||||
// h(x) = f(x)*g(x):
|
||||
// Dh(x,y) = Df(x,y)*g(x) + Dg(x,y)*f(y)
|
||||
// = Df(x,y)*g(y) + Dg(x,y)*f(x)
|
||||
// = Df(x,y)*(g(x)+g(y))/2 + Dg(x,y)*(f(x)+f(y))/2
|
||||
//
|
||||
// sn(x) = x/sqrt(1+x^2): Dsn(x,y) = (x+y)/((sn(x)+sn(y))*(1+x^2)*(1+y^2))
|
||||
static real Dsn(real x, real y, real sx, real sy) {
|
||||
// sx = x/hyp(x)
|
||||
real t = x * y;
|
||||
return t > 0 ? (x + y) * Math::sq( (sx * sy)/t ) / (sx + sy) :
|
||||
(x - y != 0 ? (sx - sy) / (x - y) : 1);
|
||||
}
|
||||
// Datanhee(x,y) = (atanee(x)-atanee(y))/(x-y)
|
||||
// = atanhee((x-y)/(1-e^2*x*y))/(x-y)
|
||||
real Datanhee(real x, real y) const {
|
||||
real t = x - y, d = 1 - _e2 * x * y;
|
||||
return t == 0 ? 1 / d :
|
||||
(x*y < 0 ? atanhee(x) - atanhee(y) : atanhee(t / d)) / t;
|
||||
}
|
||||
// DDatanhee(x,y) = (Datanhee(1,y) - Datanhee(1,x))/(y-x)
|
||||
real DDatanhee(real x, real y) const;
|
||||
real DDatanhee0(real x, real y) const;
|
||||
real DDatanhee1(real x, real y) const;
|
||||
real DDatanhee2(real x, real y) const;
|
||||
void Init(real sphi1, real cphi1, real sphi2, real cphi2, real k1);
|
||||
real txif(real tphi) const;
|
||||
real tphif(real txi) const;
|
||||
|
||||
friend class Ellipsoid; // For access to txif, tphif, etc.
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor with a single standard parallel.
|
||||
*
|
||||
* @param[in] a equatorial radius of ellipsoid (meters).
|
||||
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
|
||||
* Negative \e f gives a prolate ellipsoid.
|
||||
* @param[in] stdlat standard parallel (degrees), the circle of tangency.
|
||||
* @param[in] k0 azimuthal scale on the standard parallel.
|
||||
* @exception GeographicErr if \e a, (1 − \e f) \e a, or \e k0 is
|
||||
* not positive.
|
||||
* @exception GeographicErr if \e stdlat is not in [−90°,
|
||||
* 90°].
|
||||
**********************************************************************/
|
||||
AlbersEqualArea(real a, real f, real stdlat, real k0);
|
||||
|
||||
/**
|
||||
* Constructor with two standard parallels.
|
||||
*
|
||||
* @param[in] a equatorial radius of ellipsoid (meters).
|
||||
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
|
||||
* Negative \e f gives a prolate ellipsoid.
|
||||
* @param[in] stdlat1 first standard parallel (degrees).
|
||||
* @param[in] stdlat2 second standard parallel (degrees).
|
||||
* @param[in] k1 azimuthal scale on the standard parallels.
|
||||
* @exception GeographicErr if \e a, (1 − \e f) \e a, or \e k1 is
|
||||
* not positive.
|
||||
* @exception GeographicErr if \e stdlat1 or \e stdlat2 is not in
|
||||
* [−90°, 90°], or if \e stdlat1 and \e stdlat2 are
|
||||
* opposite poles.
|
||||
**********************************************************************/
|
||||
AlbersEqualArea(real a, real f, real stdlat1, real stdlat2, real k1);
|
||||
|
||||
/**
|
||||
* Constructor with two standard parallels specified by sines and cosines.
|
||||
*
|
||||
* @param[in] a equatorial radius of ellipsoid (meters).
|
||||
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
|
||||
* Negative \e f gives a prolate ellipsoid.
|
||||
* @param[in] sinlat1 sine of first standard parallel.
|
||||
* @param[in] coslat1 cosine of first standard parallel.
|
||||
* @param[in] sinlat2 sine of second standard parallel.
|
||||
* @param[in] coslat2 cosine of second standard parallel.
|
||||
* @param[in] k1 azimuthal scale on the standard parallels.
|
||||
* @exception GeographicErr if \e a, (1 − \e f) \e a, or \e k1 is
|
||||
* not positive.
|
||||
* @exception GeographicErr if \e stdlat1 or \e stdlat2 is not in
|
||||
* [−90°, 90°], or if \e stdlat1 and \e stdlat2 are
|
||||
* opposite poles.
|
||||
*
|
||||
* This allows parallels close to the poles to be specified accurately.
|
||||
* This routine computes the latitude of origin and the azimuthal scale at
|
||||
* this latitude. If \e dlat = abs(\e lat2 − \e lat1) ≤ 160°,
|
||||
* then the error in the latitude of origin is less than 4.5 ×
|
||||
* 10<sup>−14</sup>d;.
|
||||
**********************************************************************/
|
||||
AlbersEqualArea(real a, real f,
|
||||
real sinlat1, real coslat1,
|
||||
real sinlat2, real coslat2,
|
||||
real k1);
|
||||
|
||||
/**
|
||||
* Set the azimuthal scale for the projection.
|
||||
*
|
||||
* @param[in] lat (degrees).
|
||||
* @param[in] k azimuthal scale at latitude \e lat (default 1).
|
||||
* @exception GeographicErr \e k is not positive.
|
||||
* @exception GeographicErr if \e lat is not in (−90°,
|
||||
* 90°).
|
||||
*
|
||||
* This allows a "latitude of conformality" to be specified.
|
||||
**********************************************************************/
|
||||
void SetScale(real lat, real k = real(1));
|
||||
|
||||
/**
|
||||
* Forward projection, from geographic to Lambert conformal conic.
|
||||
*
|
||||
* @param[in] lon0 central meridian longitude (degrees).
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[out] x easting of point (meters).
|
||||
* @param[out] y northing of point (meters).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k azimuthal scale of projection at point; the radial
|
||||
* scale is the 1/\e k.
|
||||
*
|
||||
* The latitude origin is given by AlbersEqualArea::LatitudeOrigin(). No
|
||||
* false easting or northing is added and \e lat should be in the range
|
||||
* [−90°, 90°]. The values of \e x and \e y returned for
|
||||
* points which project to infinity (i.e., one or both of the poles) will
|
||||
* be large but finite.
|
||||
**********************************************************************/
|
||||
void Forward(real lon0, real lat, real lon,
|
||||
real& x, real& y, real& gamma, real& k) const;
|
||||
|
||||
/**
|
||||
* Reverse projection, from Lambert conformal conic to geographic.
|
||||
*
|
||||
* @param[in] lon0 central meridian longitude (degrees).
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k azimuthal scale of projection at point; the radial
|
||||
* scale is the 1/\e k.
|
||||
*
|
||||
* The latitude origin is given by AlbersEqualArea::LatitudeOrigin(). No
|
||||
* false easting or northing is added. The value of \e lon returned is in
|
||||
* the range [−180°, 180°]. The value of \e lat returned is
|
||||
* in the range [−90°, 90°]. If the input point is outside
|
||||
* the legal projected space the nearest pole is returned.
|
||||
**********************************************************************/
|
||||
void Reverse(real lon0, real x, real y,
|
||||
real& lat, real& lon, real& gamma, real& k) const;
|
||||
|
||||
/**
|
||||
* AlbersEqualArea::Forward without returning the convergence and
|
||||
* scale.
|
||||
**********************************************************************/
|
||||
void Forward(real lon0, real lat, real lon,
|
||||
real& x, real& y) const {
|
||||
real gamma, k;
|
||||
Forward(lon0, lat, lon, x, y, gamma, k);
|
||||
}
|
||||
|
||||
/**
|
||||
* AlbersEqualArea::Reverse without returning the convergence and
|
||||
* scale.
|
||||
**********************************************************************/
|
||||
void Reverse(real lon0, real x, real y,
|
||||
real& lat, real& lon) const {
|
||||
real gamma, k;
|
||||
Reverse(lon0, x, y, lat, lon, gamma, k);
|
||||
}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _a; }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value used in
|
||||
* the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _f; }
|
||||
|
||||
/**
|
||||
* @return latitude of the origin for the projection (degrees).
|
||||
*
|
||||
* This is the latitude of minimum azimuthal scale and equals the \e stdlat
|
||||
* in the 1-parallel constructor and lies between \e stdlat1 and \e stdlat2
|
||||
* in the 2-parallel constructors.
|
||||
**********************************************************************/
|
||||
Math::real OriginLatitude() const { return _lat0; }
|
||||
|
||||
/**
|
||||
* @return central scale for the projection. This is the azimuthal scale
|
||||
* on the latitude of origin.
|
||||
**********************************************************************/
|
||||
Math::real CentralScale() const { return _k0; }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* A global instantiation of AlbersEqualArea with the WGS84 ellipsoid, \e
|
||||
* stdlat = 0, and \e k0 = 1. This degenerates to the cylindrical equal
|
||||
* area projection.
|
||||
**********************************************************************/
|
||||
static const AlbersEqualArea& CylindricalEqualArea();
|
||||
|
||||
/**
|
||||
* A global instantiation of AlbersEqualArea with the WGS84 ellipsoid, \e
|
||||
* stdlat = 90°, and \e k0 = 1. This degenerates to the
|
||||
* Lambert azimuthal equal area projection.
|
||||
**********************************************************************/
|
||||
static const AlbersEqualArea& AzimuthalEqualAreaNorth();
|
||||
|
||||
/**
|
||||
* A global instantiation of AlbersEqualArea with the WGS84 ellipsoid, \e
|
||||
* stdlat = −90°, and \e k0 = 1. This degenerates to the
|
||||
* Lambert azimuthal equal area projection.
|
||||
**********************************************************************/
|
||||
static const AlbersEqualArea& AzimuthalEqualAreaSouth();
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_ALBERSEQUALAREA_HPP
|
||||
145
external/include/GeographicLib/AzimuthalEquidistant.hpp
vendored
Normal file
145
external/include/GeographicLib/AzimuthalEquidistant.hpp
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* \file AzimuthalEquidistant.hpp
|
||||
* \brief Header for GeographicLib::AzimuthalEquidistant class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2009-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_AZIMUTHALEQUIDISTANT_HPP)
|
||||
#define GEOGRAPHICLIB_AZIMUTHALEQUIDISTANT_HPP 1
|
||||
|
||||
#include <GeographicLib/Geodesic.hpp>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Azimuthal equidistant projection
|
||||
*
|
||||
* Azimuthal equidistant projection centered at an arbitrary position on the
|
||||
* ellipsoid. For a point in projected space (\e x, \e y), the geodesic
|
||||
* distance from the center position is hypot(\e x, \e y) and the azimuth of
|
||||
* the geodesic from the center point is atan2(\e x, \e y). The Forward and
|
||||
* Reverse methods also return the azimuth \e azi of the geodesic at (\e x,
|
||||
* \e y) and reciprocal scale \e rk in the azimuthal direction which,
|
||||
* together with the basic properties of the projection, serve to specify
|
||||
* completely the local affine transformation between geographic and
|
||||
* projected coordinates.
|
||||
*
|
||||
* The conversions all take place using a Geodesic object (by default
|
||||
* Geodesic::WGS84()). For more information on geodesics see \ref geodesic.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-AzimuthalEquidistant.cpp
|
||||
*
|
||||
* <a href="GeodesicProj.1.html">GeodesicProj</a> is a command-line utility
|
||||
* providing access to the functionality of AzimuthalEquidistant, Gnomonic,
|
||||
* and CassiniSoldner.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT AzimuthalEquidistant {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
real eps_;
|
||||
Geodesic _earth;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for AzimuthalEquidistant.
|
||||
*
|
||||
* @param[in] earth the Geodesic object to use for geodesic calculations.
|
||||
* By default this uses the WGS84 ellipsoid.
|
||||
**********************************************************************/
|
||||
explicit AzimuthalEquidistant(const Geodesic& earth = Geodesic::WGS84());
|
||||
|
||||
/**
|
||||
* Forward projection, from geographic to azimuthal equidistant.
|
||||
*
|
||||
* @param[in] lat0 latitude of center point of projection (degrees).
|
||||
* @param[in] lon0 longitude of center point of projection (degrees).
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[out] x easting of point (meters).
|
||||
* @param[out] y northing of point (meters).
|
||||
* @param[out] azi azimuth of geodesic at point (degrees).
|
||||
* @param[out] rk reciprocal of azimuthal scale at point.
|
||||
*
|
||||
* \e lat0 and \e lat should be in the range [−90°, 90°].
|
||||
* The scale of the projection is 1 in the "radial" direction, \e azi
|
||||
* clockwise from true north, and is 1/\e rk in the direction perpendicular
|
||||
* to this. A call to Forward followed by a call to Reverse will return
|
||||
* the original (\e lat, \e lon) (to within roundoff).
|
||||
**********************************************************************/
|
||||
void Forward(real lat0, real lon0, real lat, real lon,
|
||||
real& x, real& y, real& azi, real& rk) const;
|
||||
|
||||
/**
|
||||
* Reverse projection, from azimuthal equidistant to geographic.
|
||||
*
|
||||
* @param[in] lat0 latitude of center point of projection (degrees).
|
||||
* @param[in] lon0 longitude of center point of projection (degrees).
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] azi azimuth of geodesic at point (degrees).
|
||||
* @param[out] rk reciprocal of azimuthal scale at point.
|
||||
*
|
||||
* \e lat0 should be in the range [−90°, 90°]. \e lat will
|
||||
* be in the range [−90°, 90°] and \e lon will be in the
|
||||
* range [−180°, 180°]. The scale of the projection is 1 in
|
||||
* the "radial" direction, \e azi clockwise from true north, and is 1/\e rk
|
||||
* in the direction perpendicular to this. A call to Reverse followed by a
|
||||
* call to Forward will return the original (\e x, \e y) (to roundoff) only
|
||||
* if the geodesic to (\e x, \e y) is a shortest path.
|
||||
**********************************************************************/
|
||||
void Reverse(real lat0, real lon0, real x, real y,
|
||||
real& lat, real& lon, real& azi, real& rk) const;
|
||||
|
||||
/**
|
||||
* AzimuthalEquidistant::Forward without returning the azimuth and scale.
|
||||
**********************************************************************/
|
||||
void Forward(real lat0, real lon0, real lat, real lon,
|
||||
real& x, real& y) const {
|
||||
real azi, rk;
|
||||
Forward(lat0, lon0, lat, lon, x, y, azi, rk);
|
||||
}
|
||||
|
||||
/**
|
||||
* AzimuthalEquidistant::Reverse without returning the azimuth and scale.
|
||||
**********************************************************************/
|
||||
void Reverse(real lat0, real lon0, real x, real y,
|
||||
real& lat, real& lon) const {
|
||||
real azi, rk;
|
||||
Reverse(lat0, lon0, x, y, lat, lon, azi, rk);
|
||||
}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value inherited from the Geodesic object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _earth.EquatorialRadius(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value
|
||||
* inherited from the Geodesic object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _earth.Flattening(); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_AZIMUTHALEQUIDISTANT_HPP
|
||||
210
external/include/GeographicLib/CassiniSoldner.hpp
vendored
Normal file
210
external/include/GeographicLib/CassiniSoldner.hpp
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* \file CassiniSoldner.hpp
|
||||
* \brief Header for GeographicLib::CassiniSoldner class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2009-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_CASSINISOLDNER_HPP)
|
||||
#define GEOGRAPHICLIB_CASSINISOLDNER_HPP 1
|
||||
|
||||
#include <GeographicLib/Geodesic.hpp>
|
||||
#include <GeographicLib/GeodesicLine.hpp>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Cassini-Soldner projection
|
||||
*
|
||||
* Cassini-Soldner projection centered at an arbitrary position, \e lat0, \e
|
||||
* lon0, on the ellipsoid. This projection is a transverse cylindrical
|
||||
* equidistant projection. The projection from (\e lat, \e lon) to easting
|
||||
* and northing (\e x, \e y) is defined by geodesics as follows. Go north
|
||||
* along a geodesic a distance \e y from the central point; then turn
|
||||
* clockwise 90° and go a distance \e x along a geodesic.
|
||||
* (Although the initial heading is north, this changes to south if the pole
|
||||
* is crossed.) This procedure uniquely defines the reverse projection. The
|
||||
* forward projection is constructed as follows. Find the point (\e lat1, \e
|
||||
* lon1) on the meridian closest to (\e lat, \e lon). Here we consider the
|
||||
* full meridian so that \e lon1 may be either \e lon0 or \e lon0 +
|
||||
* 180°. \e x is the geodesic distance from (\e lat1, \e lon1) to
|
||||
* (\e lat, \e lon), appropriately signed according to which side of the
|
||||
* central meridian (\e lat, \e lon) lies. \e y is the shortest distance
|
||||
* along the meridian from (\e lat0, \e lon0) to (\e lat1, \e lon1), again,
|
||||
* appropriately signed according to the initial heading. [Note that, in the
|
||||
* case of prolate ellipsoids, the shortest meridional path from (\e lat0, \e
|
||||
* lon0) to (\e lat1, \e lon1) may not be the shortest path.] This procedure
|
||||
* uniquely defines the forward projection except for a small class of points
|
||||
* for which there may be two equally short routes for either leg of the
|
||||
* path.
|
||||
*
|
||||
* Because of the properties of geodesics, the (\e x, \e y) grid is
|
||||
* orthogonal. The scale in the easting direction is unity. The scale, \e
|
||||
* k, in the northing direction is unity on the central meridian and
|
||||
* increases away from the central meridian. The projection routines return
|
||||
* \e azi, the true bearing of the easting direction, and \e rk = 1/\e k, the
|
||||
* reciprocal of the scale in the northing direction.
|
||||
*
|
||||
* The conversions all take place using a Geodesic object (by default
|
||||
* Geodesic::WGS84()). For more information on geodesics see \ref geodesic.
|
||||
* The determination of (\e lat1, \e lon1) in the forward projection is by
|
||||
* solving the inverse geodesic problem for (\e lat, \e lon) and its twin
|
||||
* obtained by reflection in the meridional plane. The scale is found by
|
||||
* determining where two neighboring geodesics intersecting the central
|
||||
* meridian at \e lat1 and \e lat1 + \e dlat1 intersect and taking the ratio
|
||||
* of the reduced lengths for the two geodesics between that point and,
|
||||
* respectively, (\e lat1, \e lon1) and (\e lat, \e lon).
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-CassiniSoldner.cpp
|
||||
*
|
||||
* <a href="GeodesicProj.1.html">GeodesicProj</a> is a command-line utility
|
||||
* providing access to the functionality of AzimuthalEquidistant, Gnomonic,
|
||||
* and CassiniSoldner.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT CassiniSoldner {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
Geodesic _earth;
|
||||
GeodesicLine _meridian;
|
||||
real _sbet0, _cbet0;
|
||||
static const unsigned maxit_ = 10;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for CassiniSoldner.
|
||||
*
|
||||
* @param[in] earth the Geodesic object to use for geodesic calculations.
|
||||
* By default this uses the WGS84 ellipsoid.
|
||||
*
|
||||
* This constructor makes an "uninitialized" object. Call Reset to set the
|
||||
* central latitude and longitude, prior to calling Forward and Reverse.
|
||||
**********************************************************************/
|
||||
explicit CassiniSoldner(const Geodesic& earth = Geodesic::WGS84());
|
||||
|
||||
/**
|
||||
* Constructor for CassiniSoldner specifying a center point.
|
||||
*
|
||||
* @param[in] lat0 latitude of center point of projection (degrees).
|
||||
* @param[in] lon0 longitude of center point of projection (degrees).
|
||||
* @param[in] earth the Geodesic object to use for geodesic calculations.
|
||||
* By default this uses the WGS84 ellipsoid.
|
||||
*
|
||||
* \e lat0 should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
CassiniSoldner(real lat0, real lon0,
|
||||
const Geodesic& earth = Geodesic::WGS84());
|
||||
|
||||
/**
|
||||
* Set the central point of the projection
|
||||
*
|
||||
* @param[in] lat0 latitude of center point of projection (degrees).
|
||||
* @param[in] lon0 longitude of center point of projection (degrees).
|
||||
*
|
||||
* \e lat0 should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
void Reset(real lat0, real lon0);
|
||||
|
||||
/**
|
||||
* Forward projection, from geographic to Cassini-Soldner.
|
||||
*
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[out] x easting of point (meters).
|
||||
* @param[out] y northing of point (meters).
|
||||
* @param[out] azi azimuth of easting direction at point (degrees).
|
||||
* @param[out] rk reciprocal of azimuthal northing scale at point.
|
||||
*
|
||||
* \e lat should be in the range [−90°, 90°]. A call to
|
||||
* Forward followed by a call to Reverse will return the original (\e lat,
|
||||
* \e lon) (to within roundoff). The routine does nothing if the origin
|
||||
* has not been set.
|
||||
**********************************************************************/
|
||||
void Forward(real lat, real lon,
|
||||
real& x, real& y, real& azi, real& rk) const;
|
||||
|
||||
/**
|
||||
* Reverse projection, from Cassini-Soldner to geographic.
|
||||
*
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] azi azimuth of easting direction at point (degrees).
|
||||
* @param[out] rk reciprocal of azimuthal northing scale at point.
|
||||
*
|
||||
* A call to Reverse followed by a call to Forward will return the original
|
||||
* (\e x, \e y) (to within roundoff), provided that \e x and \e y are
|
||||
* sufficiently small not to "wrap around" the earth. The routine does
|
||||
* nothing if the origin has not been set.
|
||||
**********************************************************************/
|
||||
void Reverse(real x, real y,
|
||||
real& lat, real& lon, real& azi, real& rk) const;
|
||||
|
||||
/**
|
||||
* CassiniSoldner::Forward without returning the azimuth and scale.
|
||||
**********************************************************************/
|
||||
void Forward(real lat, real lon,
|
||||
real& x, real& y) const {
|
||||
real azi, rk;
|
||||
Forward(lat, lon, x, y, azi, rk);
|
||||
}
|
||||
|
||||
/**
|
||||
* CassiniSoldner::Reverse without returning the azimuth and scale.
|
||||
**********************************************************************/
|
||||
void Reverse(real x, real y,
|
||||
real& lat, real& lon) const {
|
||||
real azi, rk;
|
||||
Reverse(x, y, lat, lon, azi, rk);
|
||||
}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return true if the object has been initialized.
|
||||
**********************************************************************/
|
||||
bool Init() const { return _meridian.Init(); }
|
||||
|
||||
/**
|
||||
* @return \e lat0 the latitude of origin (degrees).
|
||||
**********************************************************************/
|
||||
Math::real LatitudeOrigin() const
|
||||
{ return _meridian.Latitude(); }
|
||||
|
||||
/**
|
||||
* @return \e lon0 the longitude of origin (degrees).
|
||||
**********************************************************************/
|
||||
Math::real LongitudeOrigin() const
|
||||
{ return _meridian.Longitude(); }
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value inherited from the Geodesic object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _earth.EquatorialRadius(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value
|
||||
* inherited from the Geodesic object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _earth.Flattening(); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_CASSINISOLDNER_HPP
|
||||
195
external/include/GeographicLib/CircularEngine.hpp
vendored
Normal file
195
external/include/GeographicLib/CircularEngine.hpp
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* \file CircularEngine.hpp
|
||||
* \brief Header for GeographicLib::CircularEngine class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2011-2015) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_CIRCULARENGINE_HPP)
|
||||
#define GEOGRAPHICLIB_CIRCULARENGINE_HPP 1
|
||||
|
||||
#include <vector>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/SphericalEngine.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about dll vs vector
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4251)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Spherical harmonic sums for a circle
|
||||
*
|
||||
* The class is a companion to SphericalEngine. If the results of a
|
||||
* spherical harmonic sum are needed for several points on a circle of
|
||||
* constant latitude \e lat and height \e h, then SphericalEngine::Circle can
|
||||
* compute the inner sum, which is independent of longitude \e lon, and
|
||||
* produce a CircularEngine object. CircularEngine::operator()() can
|
||||
* then be used to perform the outer sum for particular vales of \e lon.
|
||||
* This can lead to substantial improvements in computational speed for high
|
||||
* degree sum (approximately by a factor of \e N / 2 where \e N is the
|
||||
* maximum degree).
|
||||
*
|
||||
* CircularEngine is tightly linked to the internals of SphericalEngine. For
|
||||
* that reason, the constructor for this class is private. Use
|
||||
* SphericalHarmonic::Circle, SphericalHarmonic1::Circle, and
|
||||
* SphericalHarmonic2::Circle to create instances of this class.
|
||||
*
|
||||
* CircularEngine stores the coefficients needed to allow the summation over
|
||||
* order to be performed in 2 or 6 vectors of length \e M + 1 (depending on
|
||||
* whether gradients are to be calculated). For this reason the constructor
|
||||
* may throw a std::bad_alloc exception.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-CircularEngine.cpp
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT CircularEngine {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
enum normalization {
|
||||
FULL = SphericalEngine::FULL,
|
||||
SCHMIDT = SphericalEngine::SCHMIDT,
|
||||
};
|
||||
int _M;
|
||||
bool _gradp;
|
||||
unsigned _norm;
|
||||
real _a, _r, _u, _t;
|
||||
std::vector<real> _wc, _ws, _wrc, _wrs, _wtc, _wts;
|
||||
real _q, _uq, _uq2;
|
||||
|
||||
Math::real Value(bool gradp, real sl, real cl,
|
||||
real& gradx, real& grady, real& gradz) const;
|
||||
|
||||
friend class SphericalEngine;
|
||||
CircularEngine(int M, bool gradp, unsigned norm,
|
||||
real a, real r, real u, real t)
|
||||
: _M(M)
|
||||
, _gradp(gradp)
|
||||
, _norm(norm)
|
||||
, _a(a)
|
||||
, _r(r)
|
||||
, _u(u)
|
||||
, _t(t)
|
||||
, _wc(std::vector<real>(_M + 1, 0))
|
||||
, _ws(std::vector<real>(_M + 1, 0))
|
||||
, _wrc(std::vector<real>(_gradp ? _M + 1 : 0, 0))
|
||||
, _wrs(std::vector<real>(_gradp ? _M + 1 : 0, 0))
|
||||
, _wtc(std::vector<real>(_gradp ? _M + 1 : 0, 0))
|
||||
, _wts(std::vector<real>(_gradp ? _M + 1 : 0, 0))
|
||||
{
|
||||
_q = _a / _r;
|
||||
_uq = _u * _q;
|
||||
_uq2 = Math::sq(_uq);
|
||||
}
|
||||
|
||||
void SetCoeff(int m, real wc, real ws)
|
||||
{ _wc[m] = wc; _ws[m] = ws; }
|
||||
|
||||
void SetCoeff(int m, real wc, real ws,
|
||||
real wrc, real wrs, real wtc, real wts) {
|
||||
_wc[m] = wc; _ws[m] = ws;
|
||||
if (_gradp) {
|
||||
_wrc[m] = wrc; _wrs[m] = wrs;
|
||||
_wtc[m] = wtc; _wts[m] = wts;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* A default constructor. CircularEngine::operator()() on the resulting
|
||||
* object returns zero. The resulting object can be assigned to the result
|
||||
* of SphericalHarmonic::Circle.
|
||||
**********************************************************************/
|
||||
CircularEngine()
|
||||
: _M(-1)
|
||||
, _gradp(true)
|
||||
, _u(0)
|
||||
, _t(1)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Evaluate the sum for a particular longitude given in terms of its
|
||||
* sine and cosine.
|
||||
*
|
||||
* @param[in] sinlon the sine of the longitude.
|
||||
* @param[in] coslon the cosine of the longitude.
|
||||
* @return \e V the value of the sum.
|
||||
*
|
||||
* The arguments must satisfy <i>sinlon</i><sup>2</sup> +
|
||||
* <i>coslon</i><sup>2</sup> = 1.
|
||||
**********************************************************************/
|
||||
Math::real operator()(real sinlon, real coslon) const {
|
||||
real dummy;
|
||||
return Value(false, sinlon, coslon, dummy, dummy, dummy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the sum for a particular longitude.
|
||||
*
|
||||
* @param[in] lon the longitude (degrees).
|
||||
* @return \e V the value of the sum.
|
||||
**********************************************************************/
|
||||
Math::real operator()(real lon) const {
|
||||
real sinlon, coslon;
|
||||
Math::sincosd(lon, sinlon, coslon);
|
||||
return (*this)(sinlon, coslon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the sum and its gradient for a particular longitude given in
|
||||
* terms of its sine and cosine.
|
||||
*
|
||||
* @param[in] sinlon the sine of the longitude.
|
||||
* @param[in] coslon the cosine of the longitude.
|
||||
* @param[out] gradx \e x component of the gradient.
|
||||
* @param[out] grady \e y component of the gradient.
|
||||
* @param[out] gradz \e z component of the gradient.
|
||||
* @return \e V the value of the sum.
|
||||
*
|
||||
* The gradients will only be computed if the CircularEngine object was
|
||||
* created with this capability (e.g., via \e gradp = true in
|
||||
* SphericalHarmonic::Circle). If not, \e gradx, etc., will not be
|
||||
* touched. The arguments must satisfy <i>sinlon</i><sup>2</sup> +
|
||||
* <i>coslon</i><sup>2</sup> = 1.
|
||||
**********************************************************************/
|
||||
Math::real operator()(real sinlon, real coslon,
|
||||
real& gradx, real& grady, real& gradz) const {
|
||||
return Value(true, sinlon, coslon, gradx, grady, gradz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the sum and its gradient for a particular longitude.
|
||||
*
|
||||
* @param[in] lon the longitude (degrees).
|
||||
* @param[out] gradx \e x component of the gradient.
|
||||
* @param[out] grady \e y component of the gradient.
|
||||
* @param[out] gradz \e z component of the gradient.
|
||||
* @return \e V the value of the sum.
|
||||
*
|
||||
* The gradients will only be computed if the CircularEngine object was
|
||||
* created with this capability (e.g., via \e gradp = true in
|
||||
* SphericalHarmonic::Circle). If not, \e gradx, etc., will not be
|
||||
* touched.
|
||||
**********************************************************************/
|
||||
Math::real operator()(real lon,
|
||||
real& gradx, real& grady, real& gradz) const {
|
||||
real sinlon, coslon;
|
||||
Math::sincosd(lon, sinlon, coslon);
|
||||
return (*this)(sinlon, coslon, gradx, grady, gradz);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_CIRCULARENGINE_HPP
|
||||
25
external/include/GeographicLib/Config.h
vendored
Normal file
25
external/include/GeographicLib/Config.h
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
#define GEOGRAPHICLIB_VERSION_STRING "1.52"
|
||||
#define GEOGRAPHICLIB_VERSION_MAJOR 1
|
||||
#define GEOGRAPHICLIB_VERSION_MINOR 52
|
||||
#define GEOGRAPHICLIB_VERSION_PATCH 0
|
||||
#define GEOGRAPHICLIB_DATA "C:/Users/sven/Documents/Visual Studio 2019/Projects/TST/install"
|
||||
|
||||
// These are macros which affect the building of the library
|
||||
#define GEOGRAPHICLIB_HAVE_LONG_DOUBLE 0
|
||||
#define GEOGRAPHICLIB_WORDS_BIGENDIAN 0
|
||||
#define GEOGRAPHICLIB_PRECISION 1
|
||||
|
||||
// Specify whether GeographicLib is a shared or static library. When compiling
|
||||
// under Visual Studio it is necessary to specify whether GeographicLib is a
|
||||
// shared library. This is done with the macro GEOGRAPHICLIB_SHARED_LIB, which
|
||||
// cmake will correctly define as 0 or 1 when only one type of library is in
|
||||
// the package. If both shared and static libraries are available,
|
||||
// GEOGRAPHICLIB_SHARED_LIB is set to 2 which triggers a preprocessor error in
|
||||
// Constants.hpp. In this case, the appropriate value (0 or 1) for
|
||||
// GEOGRAPHICLIB_SHARED_LIB must be specified when compiling any program that
|
||||
// includes GeographicLib headers. This is done automatically if GeographicLib
|
||||
// and the user's code were built with cmake version 2.8.11 (which introduced
|
||||
// the command target_compile_definitions) or later.
|
||||
#if !defined(GEOGRAPHICLIB_SHARED_LIB)
|
||||
#define GEOGRAPHICLIB_SHARED_LIB 0
|
||||
#endif
|
||||
329
external/include/GeographicLib/Constants.hpp
vendored
Normal file
329
external/include/GeographicLib/Constants.hpp
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
/**
|
||||
* \file Constants.hpp
|
||||
* \brief Header for GeographicLib::Constants class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_CONSTANTS_HPP)
|
||||
#define GEOGRAPHICLIB_CONSTANTS_HPP 1
|
||||
|
||||
#include <GeographicLib/Config.h>
|
||||
|
||||
/**
|
||||
* @relates GeographicLib::Constants
|
||||
* Pack the version components into a single integer. Users should not rely on
|
||||
* this particular packing of the components of the version number; see the
|
||||
* documentation for GEOGRAPHICLIB_VERSION, below.
|
||||
**********************************************************************/
|
||||
#define GEOGRAPHICLIB_VERSION_NUM(a,b,c) ((((a) * 10000 + (b)) * 100) + (c))
|
||||
|
||||
/**
|
||||
* @relates GeographicLib::Constants
|
||||
* The version of GeographicLib as a single integer, packed as MMmmmmpp where
|
||||
* MM is the major version, mmmm is the minor version, and pp is the patch
|
||||
* level. Users should not rely on this particular packing of the components
|
||||
* of the version number. Instead they should use a test such as \code
|
||||
#if GEOGRAPHICLIB_VERSION >= GEOGRAPHICLIB_VERSION_NUM(1,37,0)
|
||||
...
|
||||
#endif
|
||||
* \endcode
|
||||
**********************************************************************/
|
||||
#define GEOGRAPHICLIB_VERSION \
|
||||
GEOGRAPHICLIB_VERSION_NUM(GEOGRAPHICLIB_VERSION_MAJOR, \
|
||||
GEOGRAPHICLIB_VERSION_MINOR, \
|
||||
GEOGRAPHICLIB_VERSION_PATCH)
|
||||
|
||||
// For reference, here is a table of Visual Studio and _MSC_VER
|
||||
// correspondences:
|
||||
//
|
||||
// _MSC_VER Visual Studio
|
||||
// 1100 vc5
|
||||
// 1200 vc6
|
||||
// 1300 vc7
|
||||
// 1310 vc7.1 (2003)
|
||||
// 1400 vc8 (2005)
|
||||
// 1500 vc9 (2008)
|
||||
// 1600 vc10 (2010)
|
||||
// 1700 vc11 (2012)
|
||||
// 1800 vc12 (2013)
|
||||
// 1900 vc14 (2015) First version of VS to include enough C++11 support
|
||||
// 191[0-9] vc15 (2017)
|
||||
// 192[0-9] vc16 (2019)
|
||||
|
||||
#if defined(_MSC_VER) && defined(GEOGRAPHICLIB_SHARED_LIB) && \
|
||||
GEOGRAPHICLIB_SHARED_LIB
|
||||
# if GEOGRAPHICLIB_SHARED_LIB > 1
|
||||
# error GEOGRAPHICLIB_SHARED_LIB must be 0 or 1
|
||||
# elif defined(GeographicLib_SHARED_EXPORTS)
|
||||
# define GEOGRAPHICLIB_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define GEOGRAPHICLIB_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# define GEOGRAPHICLIB_EXPORT
|
||||
#endif
|
||||
|
||||
// Use GEOGRAPHICLIB_DEPRECATED to mark functions, types or variables as
|
||||
// deprecated. Code inspired by Apache Subversion's svn_types.h file (via
|
||||
// MPFR).
|
||||
#if defined(__GNUC__)
|
||||
# if __GNUC__ > 4
|
||||
# define GEOGRAPHICLIB_DEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||
# else
|
||||
# define GEOGRAPHICLIB_DEPRECATED(msg) __attribute__((deprecated))
|
||||
# endif
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1300
|
||||
# define GEOGRAPHICLIB_DEPRECATED(msg) __declspec(deprecated(msg))
|
||||
#else
|
||||
# define GEOGRAPHICLIB_DEPRECATED(msg)
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <GeographicLib/Math.hpp>
|
||||
|
||||
/**
|
||||
* \brief Namespace for %GeographicLib
|
||||
*
|
||||
* All of %GeographicLib is defined within the GeographicLib namespace. In
|
||||
* addition all the header files are included via %GeographicLib/Class.hpp.
|
||||
* This minimizes the likelihood of conflicts with other packages.
|
||||
**********************************************************************/
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief %Constants needed by %GeographicLib
|
||||
*
|
||||
* Define constants specifying the WGS84 ellipsoid, the UTM and UPS
|
||||
* projections, and various unit conversions.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-Constants.cpp
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT Constants {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
Constants(); // Disable constructor
|
||||
|
||||
public:
|
||||
/**
|
||||
* A synonym for Math::degree<real>().
|
||||
**********************************************************************/
|
||||
static Math::real degree() { return Math::degree(); }
|
||||
/**
|
||||
* @return the number of radians in an arcminute.
|
||||
**********************************************************************/
|
||||
static Math::real arcminute()
|
||||
{ return Math::degree() / 60; }
|
||||
/**
|
||||
* @return the number of radians in an arcsecond.
|
||||
**********************************************************************/
|
||||
static Math::real arcsecond()
|
||||
{ return Math::degree() / 3600; }
|
||||
|
||||
/** \name Ellipsoid parameters
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return the equatorial radius of WGS84 ellipsoid (6378137 m).
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T WGS84_a()
|
||||
{ return 6378137 * meter<T>(); }
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return the flattening of WGS84 ellipsoid (1/298.257223563).
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T WGS84_f() {
|
||||
// Evaluating this as 1000000000 / T(298257223563LL) reduces the
|
||||
// round-off error by about 10%. However, expressing the flattening as
|
||||
// 1/298.257223563 is well ingrained.
|
||||
return 1 / ( T(298257223563LL) / 1000000000 );
|
||||
}
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return the gravitational constant of the WGS84 ellipsoid, \e GM, in
|
||||
* m<sup>3</sup> s<sup>−2</sup>.
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T WGS84_GM()
|
||||
{ return T(3986004) * 100000000 + 41800000; }
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return the angular velocity of the WGS84 ellipsoid, ω, in rad
|
||||
* s<sup>−1</sup>.
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T WGS84_omega()
|
||||
{ return 7292115 / (T(1000000) * 100000); }
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return the equatorial radius of GRS80 ellipsoid, \e a, in m.
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T GRS80_a()
|
||||
{ return 6378137 * meter<T>(); }
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return the gravitational constant of the GRS80 ellipsoid, \e GM, in
|
||||
* m<sup>3</sup> s<sup>−2</sup>.
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T GRS80_GM()
|
||||
{ return T(3986005) * 100000000; }
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return the angular velocity of the GRS80 ellipsoid, ω, in rad
|
||||
* s<sup>−1</sup>.
|
||||
*
|
||||
* This is about 2 π 366.25 / (365.25 × 24 × 3600) rad
|
||||
* s<sup>−1</sup>. 365.25 is the number of days in a Julian year and
|
||||
* 365.35/366.25 converts from solar days to sidereal days. Using the
|
||||
* number of days in a Gregorian year (365.2425) results in a worse
|
||||
* approximation (because the Gregorian year includes the precession of the
|
||||
* earth's axis).
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T GRS80_omega()
|
||||
{ return 7292115 / (T(1000000) * 100000); }
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return the dynamical form factor of the GRS80 ellipsoid,
|
||||
* <i>J</i><sub>2</sub>.
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T GRS80_J2()
|
||||
{ return T(108263) / 100000000; }
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return the central scale factor for UTM (0.9996).
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T UTM_k0()
|
||||
{return T(9996) / 10000; }
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return the central scale factor for UPS (0.994).
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T UPS_k0()
|
||||
{ return T(994) / 1000; }
|
||||
///@}
|
||||
|
||||
/** \name SI units
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return the number of meters in a meter.
|
||||
*
|
||||
* This is unity, but this lets the internal system of units be changed if
|
||||
* necessary.
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T meter() { return T(1); }
|
||||
/**
|
||||
* @return the number of meters in a kilometer.
|
||||
**********************************************************************/
|
||||
static Math::real kilometer()
|
||||
{ return 1000 * meter<real>(); }
|
||||
/**
|
||||
* @return the number of meters in a nautical mile (approximately 1 arc
|
||||
* minute)
|
||||
**********************************************************************/
|
||||
static Math::real nauticalmile()
|
||||
{ return 1852 * meter<real>(); }
|
||||
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return the number of square meters in a square meter.
|
||||
*
|
||||
* This is unity, but this lets the internal system of units be changed if
|
||||
* necessary.
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T square_meter()
|
||||
{ return meter<T>() * meter<T>(); }
|
||||
/**
|
||||
* @return the number of square meters in a hectare.
|
||||
**********************************************************************/
|
||||
static Math::real hectare()
|
||||
{ return 10000 * square_meter<real>(); }
|
||||
/**
|
||||
* @return the number of square meters in a square kilometer.
|
||||
**********************************************************************/
|
||||
static Math::real square_kilometer()
|
||||
{ return kilometer() * kilometer(); }
|
||||
/**
|
||||
* @return the number of square meters in a square nautical mile.
|
||||
**********************************************************************/
|
||||
static Math::real square_nauticalmile()
|
||||
{ return nauticalmile() * nauticalmile(); }
|
||||
///@}
|
||||
|
||||
/** \name Anachronistic British units
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return the number of meters in an international foot.
|
||||
**********************************************************************/
|
||||
static Math::real foot()
|
||||
{ return real(254 * 12) / 10000 * meter<real>(); }
|
||||
/**
|
||||
* @return the number of meters in a yard.
|
||||
**********************************************************************/
|
||||
static Math::real yard() { return 3 * foot(); }
|
||||
/**
|
||||
* @return the number of meters in a fathom.
|
||||
**********************************************************************/
|
||||
static Math::real fathom() { return 2 * yard(); }
|
||||
/**
|
||||
* @return the number of meters in a chain.
|
||||
**********************************************************************/
|
||||
static Math::real chain() { return 22 * yard(); }
|
||||
/**
|
||||
* @return the number of meters in a furlong.
|
||||
**********************************************************************/
|
||||
static Math::real furlong() { return 10 * chain(); }
|
||||
/**
|
||||
* @return the number of meters in a statute mile.
|
||||
**********************************************************************/
|
||||
static Math::real mile() { return 8 * furlong(); }
|
||||
/**
|
||||
* @return the number of square meters in an acre.
|
||||
**********************************************************************/
|
||||
static Math::real acre() { return chain() * furlong(); }
|
||||
/**
|
||||
* @return the number of square meters in a square statute mile.
|
||||
**********************************************************************/
|
||||
static Math::real square_mile() { return mile() * mile(); }
|
||||
///@}
|
||||
|
||||
/** \name Anachronistic US units
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return the number of meters in a US survey foot.
|
||||
**********************************************************************/
|
||||
static Math::real surveyfoot()
|
||||
{ return real(1200) / 3937 * meter<real>(); }
|
||||
///@}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Exception handling for %GeographicLib
|
||||
*
|
||||
* A class to handle exceptions. It's derived from std::runtime_error so it
|
||||
* can be caught by the usual catch clauses.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-GeographicErr.cpp
|
||||
**********************************************************************/
|
||||
class GeographicErr : public std::runtime_error {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] msg a string message, which is accessible in the catch
|
||||
* clause via what().
|
||||
**********************************************************************/
|
||||
GeographicErr(const std::string& msg) : std::runtime_error(msg) {}
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_CONSTANTS_HPP
|
||||
405
external/include/GeographicLib/DMS.hpp
vendored
Normal file
405
external/include/GeographicLib/DMS.hpp
vendored
Normal file
@@ -0,0 +1,405 @@
|
||||
/**
|
||||
* \file DMS.hpp
|
||||
* \brief Header for GeographicLib::DMS class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_DMS_HPP)
|
||||
#define GEOGRAPHICLIB_DMS_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/Utility.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about dll vs vector and constant conditional expressions
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4251 4127)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Convert between degrees and the %DMS representation
|
||||
*
|
||||
* Parse a string representing degree, minutes, and seconds and return the
|
||||
* angle in degrees and format an angle in degrees as degree, minutes, and
|
||||
* seconds. In addition, handle NANs and infinities on input and output.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-DMS.cpp
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT DMS {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Indicator for presence of hemisphere indicator (N/S/E/W) on latitudes
|
||||
* and longitudes.
|
||||
**********************************************************************/
|
||||
enum flag {
|
||||
/**
|
||||
* No indicator present.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
NONE = 0,
|
||||
/**
|
||||
* Latitude indicator (N/S) present.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LATITUDE = 1,
|
||||
/**
|
||||
* Longitude indicator (E/W) present.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONGITUDE = 2,
|
||||
/**
|
||||
* Used in Encode to indicate output of an azimuth in [000, 360) with no
|
||||
* letter indicator.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AZIMUTH = 3,
|
||||
/**
|
||||
* Used in Encode to indicate output of a plain number.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
NUMBER = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicator for trailing units on an angle.
|
||||
**********************************************************************/
|
||||
enum component {
|
||||
/**
|
||||
* Trailing unit is degrees.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DEGREE = 0,
|
||||
/**
|
||||
* Trailing unit is arc minutes.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
MINUTE = 1,
|
||||
/**
|
||||
* Trailing unit is arc seconds.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
SECOND = 2,
|
||||
};
|
||||
|
||||
private:
|
||||
typedef Math::real real;
|
||||
// Replace all occurrences of pat by c. If c is NULL remove pat.
|
||||
static void replace(std::string& s, const std::string& pat, char c) {
|
||||
std::string::size_type p = 0;
|
||||
int count = c ? 1 : 0;
|
||||
while (true) {
|
||||
p = s.find(pat, p);
|
||||
if (p == std::string::npos)
|
||||
break;
|
||||
s.replace(p, pat.length(), count, c);
|
||||
}
|
||||
}
|
||||
static const char* const hemispheres_;
|
||||
static const char* const signs_;
|
||||
static const char* const digits_;
|
||||
static const char* const dmsindicators_;
|
||||
static const char* const components_[3];
|
||||
static Math::real NumMatch(const std::string& s);
|
||||
static Math::real InternalDecode(const std::string& dmsa, flag& ind);
|
||||
DMS(); // Disable constructor
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Convert a string in DMS to an angle.
|
||||
*
|
||||
* @param[in] dms string input.
|
||||
* @param[out] ind a DMS::flag value signaling the presence of a
|
||||
* hemisphere indicator.
|
||||
* @exception GeographicErr if \e dms is malformed (see below).
|
||||
* @return angle (degrees).
|
||||
*
|
||||
* Degrees, minutes, and seconds are indicated by the characters d, '
|
||||
* (single quote), " (double quote), and these components may only be
|
||||
* given in this order. Any (but not all) components may be omitted and
|
||||
* other symbols (e.g., the ° symbol for degrees and the unicode prime
|
||||
* and double prime symbols for minutes and seconds) may be substituted;
|
||||
* two single quotes can be used instead of ". The last component
|
||||
* indicator may be omitted and is assumed to be the next smallest unit
|
||||
* (thus 33d10 is interpreted as 33d10'). The final component may be a
|
||||
* decimal fraction but the non-final components must be integers. Instead
|
||||
* of using d, ', and " to indicate degrees, minutes, and seconds, :
|
||||
* (colon) may be used to <i>separate</i> these components (numbers must
|
||||
* appear before and after each colon); thus 50d30'10.3" may be
|
||||
* written as 50:30:10.3, 5.5' may be written 0:5.5, and so on. The
|
||||
* integer parts of the minutes and seconds components must be less
|
||||
* than 60. A single leading sign is permitted. A hemisphere designator
|
||||
* (N, E, W, S) may be added to the beginning or end of the string. The
|
||||
* result is multiplied by the implied sign of the hemisphere designator
|
||||
* (negative for S and W). In addition \e ind is set to DMS::LATITUDE if N
|
||||
* or S is present, to DMS::LONGITUDE if E or W is present, and to
|
||||
* DMS::NONE otherwise. Throws an error on a malformed string. No check
|
||||
* is performed on the range of the result. Examples of legal and illegal
|
||||
* strings are
|
||||
* - <i>LEGAL</i> (all the entries on each line are equivalent)
|
||||
* - -20.51125, 20d30'40.5"S, -20°30'40.5, -20d30.675,
|
||||
* N-20d30'40.5", -20:30:40.5
|
||||
* - 4d0'9, 4d9", 4d9'', 4:0:9, 004:00:09, 4.0025, 4.0025d, 4d0.15,
|
||||
* 04:.15
|
||||
* - 4:59.99999999999999, 4:60.0, 4:59:59.9999999999999, 4:59:60.0, 5
|
||||
* - <i>ILLEGAL</i> (the exception thrown explains the problem)
|
||||
* - 4d5"4', 4::5, 4:5:, :4:5, 4d4.5'4", -N20.5, 1.8e2d, 4:60,
|
||||
* 4:59:60
|
||||
*
|
||||
* The decoding operation can also perform addition and subtraction
|
||||
* operations. If the string includes <i>internal</i> signs (i.e., not at
|
||||
* the beginning nor immediately after an initial hemisphere designator),
|
||||
* then the string is split immediately before such signs and each piece is
|
||||
* decoded according to the above rules and the results added; thus
|
||||
* <code>S3-2.5+4.1N</code> is parsed as the sum of <code>S3</code>,
|
||||
* <code>-2.5</code>, <code>+4.1N</code>. Any piece can include a
|
||||
* hemisphere designator; however, if multiple designators are given, they
|
||||
* must compatible; e.g., you cannot mix N and E. In addition, the
|
||||
* designator can appear at the beginning or end of the first piece, but
|
||||
* must be at the end of all subsequent pieces (a hemisphere designator is
|
||||
* not allowed after the initial sign). Examples of legal and illegal
|
||||
* combinations are
|
||||
* - <i>LEGAL</i> (these are all equivalent)
|
||||
* - 070:00:45, 70:01:15W+0:0.5, 70:01:15W-0:0:30W, W70:01:15+0:0:30E
|
||||
* - <i>ILLEGAL</i> (the exception thrown explains the problem)
|
||||
* - 70:01:15W+0:0:15N, W70:01:15+W0:0:15
|
||||
*
|
||||
* \warning The "exponential" notation is not recognized. Thus
|
||||
* <code>7.0E1</code> is illegal, while <code>7.0E+1</code> is parsed as
|
||||
* <code>(7.0E) + (+1)</code>, yielding the same result as
|
||||
* <code>8.0E</code>.
|
||||
*
|
||||
* \note At present, all the string handling in the C++ implementation of
|
||||
* %GeographicLib is with 8-bit characters. The support for unicode
|
||||
* symbols for degrees, minutes, and seconds is therefore via the
|
||||
* <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a> encoding. (The
|
||||
* JavaScript implementation of this class uses unicode natively, of
|
||||
* course.)
|
||||
*
|
||||
* Here is the list of Unicode symbols supported for degrees, minutes,
|
||||
* seconds, and the plus and minus signs; various symbols denoting variants
|
||||
* of a space, which may separate the components of a DMS string, are
|
||||
* removed:
|
||||
* - degrees:
|
||||
* - d, D lower and upper case letters
|
||||
* - U+00b0 degree symbol (°)
|
||||
* - U+00ba masculine ordinal indicator (º)
|
||||
* - U+2070 superscript zero (⁰)
|
||||
* - U+02da ring above (˚)
|
||||
* - U+2218 compose function (∘)
|
||||
* - * the <a href="https://grid.nga.mil">GRiD</a> symbol for degrees
|
||||
* - minutes:
|
||||
* - ' apostrophe
|
||||
* - ` grave accent
|
||||
* - U+2032 prime (′)
|
||||
* - U+2035 back prime (‵)
|
||||
* - U+00b4 acute accent (´)
|
||||
* - U+2018 left single quote (‘)
|
||||
* - U+2019 right single quote (’)
|
||||
* - U+201b reversed-9 single quote (‛)
|
||||
* - U+02b9 modifier letter prime (ʹ)
|
||||
* - U+02ca modifier letter acute accent (ˊ)
|
||||
* - U+02cb modifier letter grave accent (ˋ)
|
||||
* - seconds:
|
||||
* - " quotation mark
|
||||
* - U+2033 double prime (″)
|
||||
* - U+2036 reversed double prime (‶)
|
||||
* + U+02dd double acute accent (˝)
|
||||
* - U+201c left double quote (“)
|
||||
* - U+201d right double quote (”)
|
||||
* - U+201f reversed-9 double quote (‟)
|
||||
* - U+02ba modifier letter double prime (ʺ)
|
||||
* - ' ' any two consecutive symbols for minutes
|
||||
* - plus sign:
|
||||
* - + plus
|
||||
* - U+2795 heavy plus (➕)
|
||||
* - U+2064 invisible plus (||)
|
||||
* - minus sign:
|
||||
* - - hyphen
|
||||
* - U+2010 dash (‐)
|
||||
* - U+2011 non-breaking hyphen (‑)
|
||||
* - U+2013 en dash (–)
|
||||
* - U+2014 em dash (—)
|
||||
* - U+2212 minus sign (−)
|
||||
* - U+2796 heavy minus (➖)
|
||||
* - ignored spaces:
|
||||
* - U+00a0 non-breaking space
|
||||
* - U+2007 figure space (| |)
|
||||
* - U+2009 thin space (| |)
|
||||
* - U+200a hair space ( | |)
|
||||
* - U+200b invisible space (||)
|
||||
* - U+202f narrow space ( | |)
|
||||
* - U+2063 invisible separator (||)
|
||||
* .
|
||||
* The codes with a leading zero byte, e.g., U+00b0, are accepted in their
|
||||
* UTF-8 coded form 0xc2 0xb0 and as a single byte 0xb0.
|
||||
**********************************************************************/
|
||||
static Math::real Decode(const std::string& dms, flag& ind);
|
||||
|
||||
/**
|
||||
* Convert DMS to an angle.
|
||||
*
|
||||
* @param[in] d degrees.
|
||||
* @param[in] m arc minutes.
|
||||
* @param[in] s arc seconds.
|
||||
* @return angle (degrees)
|
||||
*
|
||||
* This does not propagate the sign on \e d to the other components,
|
||||
* so -3d20' would need to be represented as - DMS::Decode(3.0, 20.0) or
|
||||
* DMS::Decode(-3.0, -20.0).
|
||||
**********************************************************************/
|
||||
static Math::real Decode(real d, real m = 0, real s = 0)
|
||||
{ return d + (m + s / 60) / 60; }
|
||||
|
||||
/**
|
||||
* Convert a pair of strings to latitude and longitude.
|
||||
*
|
||||
* @param[in] dmsa first string.
|
||||
* @param[in] dmsb second string.
|
||||
* @param[out] lat latitude (degrees).
|
||||
* @param[out] lon longitude (degrees).
|
||||
* @param[in] longfirst if true assume longitude is given before latitude
|
||||
* in the absence of hemisphere designators (default false).
|
||||
* @exception GeographicErr if \e dmsa or \e dmsb is malformed.
|
||||
* @exception GeographicErr if \e dmsa and \e dmsb are both interpreted as
|
||||
* latitudes.
|
||||
* @exception GeographicErr if \e dmsa and \e dmsb are both interpreted as
|
||||
* longitudes.
|
||||
* @exception GeographicErr if decoded latitude is not in [−90°,
|
||||
* 90°].
|
||||
*
|
||||
* By default, the \e lat (resp., \e lon) is assigned to the results of
|
||||
* decoding \e dmsa (resp., \e dmsb). However this is overridden if either
|
||||
* \e dmsa or \e dmsb contain a latitude or longitude hemisphere designator
|
||||
* (N, S, E, W). If an exception is thrown, \e lat and \e lon are
|
||||
* unchanged.
|
||||
**********************************************************************/
|
||||
static void DecodeLatLon(const std::string& dmsa, const std::string& dmsb,
|
||||
real& lat, real& lon,
|
||||
bool longfirst = false);
|
||||
|
||||
/**
|
||||
* Convert a string to an angle in degrees.
|
||||
*
|
||||
* @param[in] angstr input string.
|
||||
* @exception GeographicErr if \e angstr is malformed.
|
||||
* @exception GeographicErr if \e angstr includes a hemisphere designator.
|
||||
* @return angle (degrees)
|
||||
*
|
||||
* No hemisphere designator is allowed and no check is done on the range of
|
||||
* the result.
|
||||
**********************************************************************/
|
||||
static Math::real DecodeAngle(const std::string& angstr);
|
||||
|
||||
/**
|
||||
* Convert a string to an azimuth in degrees.
|
||||
*
|
||||
* @param[in] azistr input string.
|
||||
* @exception GeographicErr if \e azistr is malformed.
|
||||
* @exception GeographicErr if \e azistr includes a N/S designator.
|
||||
* @return azimuth (degrees) reduced to the range [−180°,
|
||||
* 180°].
|
||||
*
|
||||
* A hemisphere designator E/W can be used; the result is multiplied by
|
||||
* −1 if W is present.
|
||||
**********************************************************************/
|
||||
static Math::real DecodeAzimuth(const std::string& azistr);
|
||||
|
||||
/**
|
||||
* Convert angle (in degrees) into a DMS string (using d, ', and ").
|
||||
*
|
||||
* @param[in] angle input angle (degrees)
|
||||
* @param[in] trailing DMS::component value indicating the trailing units
|
||||
* of the string (this component is given as a decimal number if
|
||||
* necessary).
|
||||
* @param[in] prec the number of digits after the decimal point for the
|
||||
* trailing component.
|
||||
* @param[in] ind DMS::flag value indicating additional formatting.
|
||||
* @param[in] dmssep if non-null, use as the DMS separator character
|
||||
* (instead of d, ', " delimiters).
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return formatted string
|
||||
*
|
||||
* The interpretation of \e ind is as follows:
|
||||
* - ind == DMS::NONE, signed result no leading zeros on degrees except in
|
||||
* the units place, e.g., -8d03'.
|
||||
* - ind == DMS::LATITUDE, trailing N or S hemisphere designator, no sign,
|
||||
* pad degrees to 2 digits, e.g., 08d03'S.
|
||||
* - ind == DMS::LONGITUDE, trailing E or W hemisphere designator, no
|
||||
* sign, pad degrees to 3 digits, e.g., 008d03'W.
|
||||
* - ind == DMS::AZIMUTH, convert to the range [0, 360°), no
|
||||
* sign, pad degrees to 3 digits, e.g., 351d57'.
|
||||
* .
|
||||
* The integer parts of the minutes and seconds components are always given
|
||||
* with 2 digits.
|
||||
**********************************************************************/
|
||||
static std::string Encode(real angle, component trailing, unsigned prec,
|
||||
flag ind = NONE, char dmssep = char(0));
|
||||
|
||||
/**
|
||||
* Convert angle into a DMS string (using d, ', and ") selecting the
|
||||
* trailing component based on the precision.
|
||||
*
|
||||
* @param[in] angle input angle (degrees)
|
||||
* @param[in] prec the precision relative to 1 degree.
|
||||
* @param[in] ind DMS::flag value indicated additional formatting.
|
||||
* @param[in] dmssep if non-null, use as the DMS separator character
|
||||
* (instead of d, ', " delimiters).
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return formatted string
|
||||
*
|
||||
* \e prec indicates the precision relative to 1 degree, e.g., \e prec = 3
|
||||
* gives a result accurate to 0.1' and \e prec = 4 gives a result accurate
|
||||
* to 1". \e ind is interpreted as in DMS::Encode with the additional
|
||||
* facility that DMS::NUMBER represents \e angle as a number in fixed
|
||||
* format with precision \e prec.
|
||||
**********************************************************************/
|
||||
static std::string Encode(real angle, unsigned prec, flag ind = NONE,
|
||||
char dmssep = char(0)) {
|
||||
return ind == NUMBER ? Utility::str(angle, int(prec)) :
|
||||
Encode(angle,
|
||||
prec < 2 ? DEGREE : (prec < 4 ? MINUTE : SECOND),
|
||||
prec < 2 ? prec : (prec < 4 ? prec - 2 : prec - 4),
|
||||
ind, dmssep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split angle into degrees and minutes
|
||||
*
|
||||
* @param[in] ang angle (degrees)
|
||||
* @param[out] d degrees (an integer returned as a real)
|
||||
* @param[out] m arc minutes.
|
||||
**********************************************************************/
|
||||
static void Encode(real ang, real& d, real& m) {
|
||||
d = int(ang); m = 60 * (ang - d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split angle into degrees and minutes and seconds.
|
||||
*
|
||||
* @param[in] ang angle (degrees)
|
||||
* @param[out] d degrees (an integer returned as a real)
|
||||
* @param[out] m arc minutes (an integer returned as a real)
|
||||
* @param[out] s arc seconds.
|
||||
**********************************************************************/
|
||||
static void Encode(real ang, real& d, real& m, real& s) {
|
||||
d = int(ang); ang = 60 * (ang - d);
|
||||
m = int(ang); s = 60 * (ang - m);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_DMS_HPP
|
||||
542
external/include/GeographicLib/Ellipsoid.hpp
vendored
Normal file
542
external/include/GeographicLib/Ellipsoid.hpp
vendored
Normal file
@@ -0,0 +1,542 @@
|
||||
/**
|
||||
* \file Ellipsoid.hpp
|
||||
* \brief Header for GeographicLib::Ellipsoid class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2012-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_ELLIPSOID_HPP)
|
||||
#define GEOGRAPHICLIB_ELLIPSOID_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/TransverseMercator.hpp>
|
||||
#include <GeographicLib/EllipticFunction.hpp>
|
||||
#include <GeographicLib/AlbersEqualArea.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Properties of an ellipsoid
|
||||
*
|
||||
* This class returns various properties of the ellipsoid and converts
|
||||
* between various types of latitudes. The latitude conversions are also
|
||||
* possible using the various projections supported by %GeographicLib; but
|
||||
* Ellipsoid provides more direct access (sometimes using private functions
|
||||
* of the projection classes). Ellipsoid::RectifyingLatitude,
|
||||
* Ellipsoid::InverseRectifyingLatitude, and Ellipsoid::MeridianDistance
|
||||
* provide functionality which can be provided by the Geodesic class.
|
||||
* However Geodesic uses a series approximation (valid for abs \e f < 1/150),
|
||||
* whereas Ellipsoid computes these quantities using EllipticFunction which
|
||||
* provides accurate results even when \e f is large. Use of this class
|
||||
* should be limited to −3 < \e f < 3/4 (i.e., 1/4 < b/a < 4).
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-Ellipsoid.cpp
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT Ellipsoid {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
static const int numit_ = 10;
|
||||
real stol_;
|
||||
real _a, _f, _f1, _f12, _e2, _es, _e12, _n, _b;
|
||||
TransverseMercator _tm;
|
||||
EllipticFunction _ell;
|
||||
AlbersEqualArea _au;
|
||||
|
||||
// These are the alpha and beta coefficients in the Krueger series from
|
||||
// TransverseMercator. Thy are used by RhumbSolve to compute
|
||||
// (psi2-psi1)/(mu2-mu1).
|
||||
const Math::real* ConformalToRectifyingCoeffs() const { return _tm._alp; }
|
||||
const Math::real* RectifyingToConformalCoeffs() const { return _tm._bet; }
|
||||
friend class Rhumb; friend class RhumbLine;
|
||||
public:
|
||||
/** \name Constructor
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Constructor for a ellipsoid with
|
||||
*
|
||||
* @param[in] a equatorial radius (meters).
|
||||
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
|
||||
* Negative \e f gives a prolate ellipsoid.
|
||||
* @exception GeographicErr if \e a or (1 − \e f) \e a is not
|
||||
* positive.
|
||||
**********************************************************************/
|
||||
Ellipsoid(real a, real f);
|
||||
///@}
|
||||
|
||||
/** \name %Ellipsoid dimensions.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _a; }
|
||||
|
||||
/**
|
||||
* @return \e b the polar semi-axis (meters).
|
||||
**********************************************************************/
|
||||
Math::real MinorRadius() const { return _b; }
|
||||
|
||||
/**
|
||||
* @return \e L the distance between the equator and a pole along a
|
||||
* meridian (meters). For a sphere \e L = (π/2) \e a. The radius
|
||||
* of a sphere with the same meridian length is \e L / (π/2).
|
||||
**********************************************************************/
|
||||
Math::real QuarterMeridian() const;
|
||||
|
||||
/**
|
||||
* @return \e A the total area of the ellipsoid (meters<sup>2</sup>). For
|
||||
* a sphere \e A = 4π <i>a</i><sup>2</sup>. The radius of a sphere
|
||||
* with the same area is sqrt(\e A / (4π)).
|
||||
**********************************************************************/
|
||||
Math::real Area() const;
|
||||
|
||||
/**
|
||||
* @return \e V the total volume of the ellipsoid (meters<sup>3</sup>).
|
||||
* For a sphere \e V = (4π / 3) <i>a</i><sup>3</sup>. The radius of
|
||||
* a sphere with the same volume is cbrt(\e V / (4π/3)).
|
||||
**********************************************************************/
|
||||
Math::real Volume() const
|
||||
{ return (4 * Math::pi()) * Math::sq(_a) * _b / 3; }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/** \name %Ellipsoid shape
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @return \e f = (\e a − \e b) / \e a, the flattening of the
|
||||
* ellipsoid. This is the value used in the constructor. This is zero,
|
||||
* positive, or negative for a sphere, oblate ellipsoid, or prolate
|
||||
* ellipsoid.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _f; }
|
||||
|
||||
/**
|
||||
* @return \e f ' = (\e a − \e b) / \e b, the second flattening of
|
||||
* the ellipsoid. This is zero, positive, or negative for a sphere,
|
||||
* oblate ellipsoid, or prolate ellipsoid.
|
||||
**********************************************************************/
|
||||
Math::real SecondFlattening() const { return _f / (1 - _f); }
|
||||
|
||||
/**
|
||||
* @return \e n = (\e a − \e b) / (\e a + \e b), the third flattening
|
||||
* of the ellipsoid. This is zero, positive, or negative for a sphere,
|
||||
* oblate ellipsoid, or prolate ellipsoid.
|
||||
**********************************************************************/
|
||||
Math::real ThirdFlattening() const { return _n; }
|
||||
|
||||
/**
|
||||
* @return <i>e</i><sup>2</sup> = (<i>a</i><sup>2</sup> −
|
||||
* <i>b</i><sup>2</sup>) / <i>a</i><sup>2</sup>, the eccentricity squared
|
||||
* of the ellipsoid. This is zero, positive, or negative for a sphere,
|
||||
* oblate ellipsoid, or prolate ellipsoid.
|
||||
**********************************************************************/
|
||||
Math::real EccentricitySq() const { return _e2; }
|
||||
|
||||
/**
|
||||
* @return <i>e'</i> <sup>2</sup> = (<i>a</i><sup>2</sup> −
|
||||
* <i>b</i><sup>2</sup>) / <i>b</i><sup>2</sup>, the second eccentricity
|
||||
* squared of the ellipsoid. This is zero, positive, or negative for a
|
||||
* sphere, oblate ellipsoid, or prolate ellipsoid.
|
||||
**********************************************************************/
|
||||
Math::real SecondEccentricitySq() const { return _e12; }
|
||||
|
||||
/**
|
||||
* @return <i>e''</i> <sup>2</sup> = (<i>a</i><sup>2</sup> −
|
||||
* <i>b</i><sup>2</sup>) / (<i>a</i><sup>2</sup> + <i>b</i><sup>2</sup>),
|
||||
* the third eccentricity squared of the ellipsoid. This is zero,
|
||||
* positive, or negative for a sphere, oblate ellipsoid, or prolate
|
||||
* ellipsoid.
|
||||
**********************************************************************/
|
||||
Math::real ThirdEccentricitySq() const { return _e2 / (2 - _e2); }
|
||||
///@}
|
||||
|
||||
/** \name Latitude conversion.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @param[in] phi the geographic latitude (degrees).
|
||||
* @return β the parametric latitude (degrees).
|
||||
*
|
||||
* The geographic latitude, φ, is the angle between the equatorial
|
||||
* plane and a vector normal to the surface of the ellipsoid.
|
||||
*
|
||||
* The parametric latitude (also called the reduced latitude), β,
|
||||
* allows the cartesian coordinated of a meridian to be expressed
|
||||
* conveniently in parametric form as
|
||||
* - \e R = \e a cos β
|
||||
* - \e Z = \e b sin β
|
||||
* .
|
||||
* where \e a and \e b are the equatorial radius and the polar semi-axis.
|
||||
* For a sphere β = φ.
|
||||
*
|
||||
* φ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold. The returned value
|
||||
* β lies in [−90°, 90°].
|
||||
**********************************************************************/
|
||||
Math::real ParametricLatitude(real phi) const;
|
||||
|
||||
/**
|
||||
* @param[in] beta the parametric latitude (degrees).
|
||||
* @return φ the geographic latitude (degrees).
|
||||
*
|
||||
* β must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold. The returned value
|
||||
* φ lies in [−90°, 90°].
|
||||
**********************************************************************/
|
||||
Math::real InverseParametricLatitude(real beta) const;
|
||||
|
||||
/**
|
||||
* @param[in] phi the geographic latitude (degrees).
|
||||
* @return θ the geocentric latitude (degrees).
|
||||
*
|
||||
* The geocentric latitude, θ, is the angle between the equatorial
|
||||
* plane and a line between the center of the ellipsoid and a point on the
|
||||
* ellipsoid. For a sphere θ = φ.
|
||||
*
|
||||
* φ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold. The returned value
|
||||
* θ lies in [−90°, 90°].
|
||||
**********************************************************************/
|
||||
Math::real GeocentricLatitude(real phi) const;
|
||||
|
||||
/**
|
||||
* @param[in] theta the geocentric latitude (degrees).
|
||||
* @return φ the geographic latitude (degrees).
|
||||
*
|
||||
* θ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold. The returned value
|
||||
* φ lies in [−90°, 90°].
|
||||
**********************************************************************/
|
||||
Math::real InverseGeocentricLatitude(real theta) const;
|
||||
|
||||
/**
|
||||
* @param[in] phi the geographic latitude (degrees).
|
||||
* @return μ the rectifying latitude (degrees).
|
||||
*
|
||||
* The rectifying latitude, μ, has the property that the distance along
|
||||
* a meridian of the ellipsoid between two points with rectifying latitudes
|
||||
* μ<sub>1</sub> and μ<sub>2</sub> is equal to
|
||||
* (μ<sub>2</sub> - μ<sub>1</sub>) \e L / 90°,
|
||||
* where \e L = QuarterMeridian(). For a sphere μ = φ.
|
||||
*
|
||||
* φ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold. The returned value
|
||||
* μ lies in [−90°, 90°].
|
||||
**********************************************************************/
|
||||
Math::real RectifyingLatitude(real phi) const;
|
||||
|
||||
/**
|
||||
* @param[in] mu the rectifying latitude (degrees).
|
||||
* @return φ the geographic latitude (degrees).
|
||||
*
|
||||
* μ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold. The returned value
|
||||
* φ lies in [−90°, 90°].
|
||||
**********************************************************************/
|
||||
Math::real InverseRectifyingLatitude(real mu) const;
|
||||
|
||||
/**
|
||||
* @param[in] phi the geographic latitude (degrees).
|
||||
* @return ξ the authalic latitude (degrees).
|
||||
*
|
||||
* The authalic latitude, ξ, has the property that the area of the
|
||||
* ellipsoid between two circles with authalic latitudes
|
||||
* ξ<sub>1</sub> and ξ<sub>2</sub> is equal to (sin
|
||||
* ξ<sub>2</sub> - sin ξ<sub>1</sub>) \e A / 2, where \e A
|
||||
* = Area(). For a sphere ξ = φ.
|
||||
*
|
||||
* φ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold. The returned value
|
||||
* ξ lies in [−90°, 90°].
|
||||
**********************************************************************/
|
||||
Math::real AuthalicLatitude(real phi) const;
|
||||
|
||||
/**
|
||||
* @param[in] xi the authalic latitude (degrees).
|
||||
* @return φ the geographic latitude (degrees).
|
||||
*
|
||||
* ξ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold. The returned value
|
||||
* φ lies in [−90°, 90°].
|
||||
**********************************************************************/
|
||||
Math::real InverseAuthalicLatitude(real xi) const;
|
||||
|
||||
/**
|
||||
* @param[in] phi the geographic latitude (degrees).
|
||||
* @return χ the conformal latitude (degrees).
|
||||
*
|
||||
* The conformal latitude, χ, gives the mapping of the ellipsoid to a
|
||||
* sphere which which is conformal (angles are preserved) and in which the
|
||||
* equator of the ellipsoid maps to the equator of the sphere. For a
|
||||
* sphere χ = φ.
|
||||
*
|
||||
* φ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold. The returned value
|
||||
* χ lies in [−90°, 90°].
|
||||
**********************************************************************/
|
||||
Math::real ConformalLatitude(real phi) const;
|
||||
|
||||
/**
|
||||
* @param[in] chi the conformal latitude (degrees).
|
||||
* @return φ the geographic latitude (degrees).
|
||||
*
|
||||
* χ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold. The returned value
|
||||
* φ lies in [−90°, 90°].
|
||||
**********************************************************************/
|
||||
Math::real InverseConformalLatitude(real chi) const;
|
||||
|
||||
/**
|
||||
* @param[in] phi the geographic latitude (degrees).
|
||||
* @return ψ the isometric latitude (degrees).
|
||||
*
|
||||
* The isometric latitude gives the mapping of the ellipsoid to a plane
|
||||
* which which is conformal (angles are preserved) and in which the equator
|
||||
* of the ellipsoid maps to a straight line of constant scale; this mapping
|
||||
* defines the Mercator projection. For a sphere ψ =
|
||||
* sinh<sup>−1</sup> tan φ.
|
||||
*
|
||||
* φ must lie in the range [−90°, 90°]; the result is
|
||||
* undefined if this condition does not hold. The value returned for φ
|
||||
* = ±90° is some (positive or negative) large but finite value,
|
||||
* such that InverseIsometricLatitude returns the original value of φ.
|
||||
**********************************************************************/
|
||||
Math::real IsometricLatitude(real phi) const;
|
||||
|
||||
/**
|
||||
* @param[in] psi the isometric latitude (degrees).
|
||||
* @return φ the geographic latitude (degrees).
|
||||
*
|
||||
* The returned value φ lies in [−90°, 90°]. For a
|
||||
* sphere φ = tan<sup>−1</sup> sinh ψ.
|
||||
**********************************************************************/
|
||||
Math::real InverseIsometricLatitude(real psi) const;
|
||||
///@}
|
||||
|
||||
/** \name Other quantities.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @param[in] phi the geographic latitude (degrees).
|
||||
* @return \e R = \e a cos β the radius of a circle of latitude
|
||||
* φ (meters). \e R (π/180°) gives meters per degree
|
||||
* longitude measured along a circle of latitude.
|
||||
*
|
||||
* φ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold.
|
||||
**********************************************************************/
|
||||
Math::real CircleRadius(real phi) const;
|
||||
|
||||
/**
|
||||
* @param[in] phi the geographic latitude (degrees).
|
||||
* @return \e Z = \e b sin β the distance of a circle of latitude
|
||||
* φ from the equator measured parallel to the ellipsoid axis
|
||||
* (meters).
|
||||
*
|
||||
* φ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold.
|
||||
**********************************************************************/
|
||||
Math::real CircleHeight(real phi) const;
|
||||
|
||||
/**
|
||||
* @param[in] phi the geographic latitude (degrees).
|
||||
* @return \e s the distance along a meridian
|
||||
* between the equator and a point of latitude φ (meters). \e s is
|
||||
* given by \e s = μ \e L / 90°, where \e L =
|
||||
* QuarterMeridian()).
|
||||
*
|
||||
* φ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold.
|
||||
**********************************************************************/
|
||||
Math::real MeridianDistance(real phi) const;
|
||||
|
||||
/**
|
||||
* @param[in] phi the geographic latitude (degrees).
|
||||
* @return ρ the meridional radius of curvature of the ellipsoid at
|
||||
* latitude φ (meters); this is the curvature of the meridian. \e
|
||||
* rho is given by ρ = (180°/π) d\e s / dφ,
|
||||
* where \e s = MeridianDistance(); thus ρ (π/180°)
|
||||
* gives meters per degree latitude measured along a meridian.
|
||||
*
|
||||
* φ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold.
|
||||
**********************************************************************/
|
||||
Math::real MeridionalCurvatureRadius(real phi) const;
|
||||
|
||||
/**
|
||||
* @param[in] phi the geographic latitude (degrees).
|
||||
* @return ν the transverse radius of curvature of the ellipsoid at
|
||||
* latitude φ (meters); this is the curvature of a curve on the
|
||||
* ellipsoid which also lies in a plane perpendicular to the ellipsoid
|
||||
* and to the meridian. ν is related to \e R = CircleRadius() by \e
|
||||
* R = ν cos φ.
|
||||
*
|
||||
* φ must lie in the range [−90°, 90°]; the
|
||||
* result is undefined if this condition does not hold.
|
||||
**********************************************************************/
|
||||
Math::real TransverseCurvatureRadius(real phi) const;
|
||||
|
||||
/**
|
||||
* @param[in] phi the geographic latitude (degrees).
|
||||
* @param[in] azi the angle between the meridian and the normal section
|
||||
* (degrees).
|
||||
* @return the radius of curvature of the ellipsoid in the normal
|
||||
* section at latitude φ inclined at an angle \e azi to the
|
||||
* meridian (meters).
|
||||
*
|
||||
* φ must lie in the range [−90°, 90°]; the result is
|
||||
* undefined this condition does not hold.
|
||||
**********************************************************************/
|
||||
Math::real NormalCurvatureRadius(real phi, real azi) const;
|
||||
///@}
|
||||
|
||||
/** \name Eccentricity conversions.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @param[in] fp = \e f ' = (\e a − \e b) / \e b, the second
|
||||
* flattening.
|
||||
* @return \e f = (\e a − \e b) / \e a, the flattening.
|
||||
*
|
||||
* \e f ' should lie in (−1, ∞).
|
||||
* The returned value \e f lies in (−∞, 1).
|
||||
**********************************************************************/
|
||||
static Math::real SecondFlatteningToFlattening(real fp)
|
||||
{ return fp / (1 + fp); }
|
||||
|
||||
/**
|
||||
* @param[in] f = (\e a − \e b) / \e a, the flattening.
|
||||
* @return \e f ' = (\e a − \e b) / \e b, the second flattening.
|
||||
*
|
||||
* \e f should lie in (−∞, 1).
|
||||
* The returned value \e f ' lies in (−1, ∞).
|
||||
**********************************************************************/
|
||||
static Math::real FlatteningToSecondFlattening(real f)
|
||||
{ return f / (1 - f); }
|
||||
|
||||
/**
|
||||
* @param[in] n = (\e a − \e b) / (\e a + \e b), the third
|
||||
* flattening.
|
||||
* @return \e f = (\e a − \e b) / \e a, the flattening.
|
||||
*
|
||||
* \e n should lie in (−1, 1).
|
||||
* The returned value \e f lies in (−∞, 1).
|
||||
**********************************************************************/
|
||||
static Math::real ThirdFlatteningToFlattening(real n)
|
||||
{ return 2 * n / (1 + n); }
|
||||
|
||||
/**
|
||||
* @param[in] f = (\e a − \e b) / \e a, the flattening.
|
||||
* @return \e n = (\e a − \e b) / (\e a + \e b), the third
|
||||
* flattening.
|
||||
*
|
||||
* \e f should lie in (−∞, 1).
|
||||
* The returned value \e n lies in (−1, 1).
|
||||
**********************************************************************/
|
||||
static Math::real FlatteningToThirdFlattening(real f)
|
||||
{ return f / (2 - f); }
|
||||
|
||||
/**
|
||||
* @param[in] e2 = <i>e</i><sup>2</sup> = (<i>a</i><sup>2</sup> −
|
||||
* <i>b</i><sup>2</sup>) / <i>a</i><sup>2</sup>, the eccentricity
|
||||
* squared.
|
||||
* @return \e f = (\e a − \e b) / \e a, the flattening.
|
||||
*
|
||||
* <i>e</i><sup>2</sup> should lie in (−∞, 1).
|
||||
* The returned value \e f lies in (−∞, 1).
|
||||
**********************************************************************/
|
||||
static Math::real EccentricitySqToFlattening(real e2)
|
||||
{ using std::sqrt; return e2 / (sqrt(1 - e2) + 1); }
|
||||
|
||||
/**
|
||||
* @param[in] f = (\e a − \e b) / \e a, the flattening.
|
||||
* @return <i>e</i><sup>2</sup> = (<i>a</i><sup>2</sup> −
|
||||
* <i>b</i><sup>2</sup>) / <i>a</i><sup>2</sup>, the eccentricity
|
||||
* squared.
|
||||
*
|
||||
* \e f should lie in (−∞, 1).
|
||||
* The returned value <i>e</i><sup>2</sup> lies in (−∞, 1).
|
||||
**********************************************************************/
|
||||
static Math::real FlatteningToEccentricitySq(real f)
|
||||
{ return f * (2 - f); }
|
||||
|
||||
/**
|
||||
* @param[in] ep2 = <i>e'</i> <sup>2</sup> = (<i>a</i><sup>2</sup> −
|
||||
* <i>b</i><sup>2</sup>) / <i>b</i><sup>2</sup>, the second eccentricity
|
||||
* squared.
|
||||
* @return \e f = (\e a − \e b) / \e a, the flattening.
|
||||
*
|
||||
* <i>e'</i> <sup>2</sup> should lie in (−1, ∞).
|
||||
* The returned value \e f lies in (−∞, 1).
|
||||
**********************************************************************/
|
||||
static Math::real SecondEccentricitySqToFlattening(real ep2)
|
||||
{ using std::sqrt; return ep2 / (sqrt(1 + ep2) + 1 + ep2); }
|
||||
|
||||
/**
|
||||
* @param[in] f = (\e a − \e b) / \e a, the flattening.
|
||||
* @return <i>e'</i> <sup>2</sup> = (<i>a</i><sup>2</sup> −
|
||||
* <i>b</i><sup>2</sup>) / <i>b</i><sup>2</sup>, the second eccentricity
|
||||
* squared.
|
||||
*
|
||||
* \e f should lie in (−∞, 1).
|
||||
* The returned value <i>e'</i> <sup>2</sup> lies in (−1, ∞).
|
||||
**********************************************************************/
|
||||
static Math::real FlatteningToSecondEccentricitySq(real f)
|
||||
{ return f * (2 - f) / Math::sq(1 - f); }
|
||||
|
||||
/**
|
||||
* @param[in] epp2 = <i>e''</i> <sup>2</sup> = (<i>a</i><sup>2</sup>
|
||||
* − <i>b</i><sup>2</sup>) / (<i>a</i><sup>2</sup> +
|
||||
* <i>b</i><sup>2</sup>), the third eccentricity squared.
|
||||
* @return \e f = (\e a − \e b) / \e a, the flattening.
|
||||
*
|
||||
* <i>e''</i> <sup>2</sup> should lie in (−1, 1).
|
||||
* The returned value \e f lies in (−∞, 1).
|
||||
**********************************************************************/
|
||||
static Math::real ThirdEccentricitySqToFlattening(real epp2) {
|
||||
using std::sqrt;
|
||||
return 2 * epp2 / (sqrt((1 - epp2) * (1 + epp2)) + 1 + epp2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param[in] f = (\e a − \e b) / \e a, the flattening.
|
||||
* @return <i>e''</i> <sup>2</sup> = (<i>a</i><sup>2</sup> −
|
||||
* <i>b</i><sup>2</sup>) / (<i>a</i><sup>2</sup> + <i>b</i><sup>2</sup>),
|
||||
* the third eccentricity squared.
|
||||
*
|
||||
* \e f should lie in (−∞, 1).
|
||||
* The returned value <i>e''</i> <sup>2</sup> lies in (−1, 1).
|
||||
**********************************************************************/
|
||||
static Math::real FlatteningToThirdEccentricitySq(real f)
|
||||
{ return f * (2 - f) / (1 + Math::sq(1 - f)); }
|
||||
|
||||
///@}
|
||||
|
||||
/**
|
||||
* A global instantiation of Ellipsoid with the parameters for the WGS84
|
||||
* ellipsoid.
|
||||
**********************************************************************/
|
||||
static const Ellipsoid& WGS84();
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_ELLIPSOID_HPP
|
||||
702
external/include/GeographicLib/EllipticFunction.hpp
vendored
Normal file
702
external/include/GeographicLib/EllipticFunction.hpp
vendored
Normal file
@@ -0,0 +1,702 @@
|
||||
/**
|
||||
* \file EllipticFunction.hpp
|
||||
* \brief Header for GeographicLib::EllipticFunction class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2021) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_ELLIPTICFUNCTION_HPP)
|
||||
#define GEOGRAPHICLIB_ELLIPTICFUNCTION_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Elliptic integrals and functions
|
||||
*
|
||||
* This provides the elliptic functions and integrals needed for Ellipsoid,
|
||||
* GeodesicExact, and TransverseMercatorExact. Two categories of function
|
||||
* are provided:
|
||||
* - \e static functions to compute symmetric elliptic integrals
|
||||
* (https://dlmf.nist.gov/19.16.i)
|
||||
* - \e member functions to compute Legrendre's elliptic
|
||||
* integrals (https://dlmf.nist.gov/19.2.ii) and the
|
||||
* Jacobi elliptic functions (https://dlmf.nist.gov/22.2).
|
||||
* .
|
||||
* In the latter case, an object is constructed giving the modulus \e k (and
|
||||
* optionally the parameter α<sup>2</sup>). The modulus is always
|
||||
* passed as its square <i>k</i><sup>2</sup> which allows \e k to be pure
|
||||
* imaginary (<i>k</i><sup>2</sup> < 0). (Confusingly, Abramowitz and
|
||||
* Stegun call \e m = <i>k</i><sup>2</sup> the "parameter" and \e n =
|
||||
* α<sup>2</sup> the "characteristic".)
|
||||
*
|
||||
* In geodesic applications, it is convenient to separate the incomplete
|
||||
* integrals into secular and periodic components, e.g.,
|
||||
* \f[
|
||||
* E(\phi, k) = (2 E(k) / \pi) [ \phi + \delta E(\phi, k) ]
|
||||
* \f]
|
||||
* where δ\e E(φ, \e k) is an odd periodic function with period
|
||||
* π.
|
||||
*
|
||||
* The computation of the elliptic integrals uses the algorithms given in
|
||||
* - B. C. Carlson,
|
||||
* <a href="https://doi.org/10.1007/BF02198293"> Computation of real or
|
||||
* complex elliptic integrals</a>, Numerical Algorithms 10, 13--26 (1995)
|
||||
* .
|
||||
* with the additional optimizations given in https://dlmf.nist.gov/19.36.i.
|
||||
* The computation of the Jacobi elliptic functions uses the algorithm given
|
||||
* in
|
||||
* - R. Bulirsch,
|
||||
* <a href="https://doi.org/10.1007/BF01397975"> Numerical Calculation of
|
||||
* Elliptic Integrals and Elliptic Functions</a>, Numericshe Mathematik 7,
|
||||
* 78--90 (1965).
|
||||
* .
|
||||
* The notation follows https://dlmf.nist.gov/19 and https://dlmf.nist.gov/22
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-EllipticFunction.cpp
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT EllipticFunction {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
|
||||
enum { num_ = 13 }; // Max depth required for sncndn; probably 5 is enough.
|
||||
real _k2, _kp2, _alpha2, _alphap2, _eps;
|
||||
real _Kc, _Ec, _Dc, _Pic, _Gc, _Hc;
|
||||
public:
|
||||
/** \name Constructor
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Constructor specifying the modulus and parameter.
|
||||
*
|
||||
* @param[in] k2 the square of the modulus <i>k</i><sup>2</sup>.
|
||||
* <i>k</i><sup>2</sup> must lie in (−∞, 1].
|
||||
* @param[in] alpha2 the parameter α<sup>2</sup>.
|
||||
* α<sup>2</sup> must lie in (−∞, 1].
|
||||
* @exception GeographicErr if \e k2 or \e alpha2 is out of its legal
|
||||
* range.
|
||||
*
|
||||
* If only elliptic integrals of the first and second kinds are needed,
|
||||
* then set α<sup>2</sup> = 0 (the default value); in this case, we
|
||||
* have Π(φ, 0, \e k) = \e F(φ, \e k), \e G(φ, 0, \e k) = \e
|
||||
* E(φ, \e k), and \e H(φ, 0, \e k) = \e F(φ, \e k) - \e
|
||||
* D(φ, \e k).
|
||||
**********************************************************************/
|
||||
EllipticFunction(real k2 = 0, real alpha2 = 0)
|
||||
{ Reset(k2, alpha2); }
|
||||
|
||||
/**
|
||||
* Constructor specifying the modulus and parameter and their complements.
|
||||
*
|
||||
* @param[in] k2 the square of the modulus <i>k</i><sup>2</sup>.
|
||||
* <i>k</i><sup>2</sup> must lie in (−∞, 1].
|
||||
* @param[in] alpha2 the parameter α<sup>2</sup>.
|
||||
* α<sup>2</sup> must lie in (−∞, 1].
|
||||
* @param[in] kp2 the complementary modulus squared <i>k'</i><sup>2</sup> =
|
||||
* 1 − <i>k</i><sup>2</sup>. This must lie in [0, ∞).
|
||||
* @param[in] alphap2 the complementary parameter α'<sup>2</sup> = 1
|
||||
* − α<sup>2</sup>. This must lie in [0, ∞).
|
||||
* @exception GeographicErr if \e k2, \e alpha2, \e kp2, or \e alphap2 is
|
||||
* out of its legal range.
|
||||
*
|
||||
* The arguments must satisfy \e k2 + \e kp2 = 1 and \e alpha2 + \e alphap2
|
||||
* = 1. (No checking is done that these conditions are met.) This
|
||||
* constructor is provided to enable accuracy to be maintained, e.g., when
|
||||
* \e k is very close to unity.
|
||||
**********************************************************************/
|
||||
EllipticFunction(real k2, real alpha2, real kp2, real alphap2)
|
||||
{ Reset(k2, alpha2, kp2, alphap2); }
|
||||
|
||||
/**
|
||||
* Reset the modulus and parameter.
|
||||
*
|
||||
* @param[in] k2 the new value of square of the modulus
|
||||
* <i>k</i><sup>2</sup> which must lie in (−∞, ].
|
||||
* done.)
|
||||
* @param[in] alpha2 the new value of parameter α<sup>2</sup>.
|
||||
* α<sup>2</sup> must lie in (−∞, 1].
|
||||
* @exception GeographicErr if \e k2 or \e alpha2 is out of its legal
|
||||
* range.
|
||||
**********************************************************************/
|
||||
void Reset(real k2 = 0, real alpha2 = 0)
|
||||
{ Reset(k2, alpha2, 1 - k2, 1 - alpha2); }
|
||||
|
||||
/**
|
||||
* Reset the modulus and parameter supplying also their complements.
|
||||
*
|
||||
* @param[in] k2 the square of the modulus <i>k</i><sup>2</sup>.
|
||||
* <i>k</i><sup>2</sup> must lie in (−∞, 1].
|
||||
* @param[in] alpha2 the parameter α<sup>2</sup>.
|
||||
* α<sup>2</sup> must lie in (−∞, 1].
|
||||
* @param[in] kp2 the complementary modulus squared <i>k'</i><sup>2</sup> =
|
||||
* 1 − <i>k</i><sup>2</sup>. This must lie in [0, ∞).
|
||||
* @param[in] alphap2 the complementary parameter α'<sup>2</sup> = 1
|
||||
* − α<sup>2</sup>. This must lie in [0, ∞).
|
||||
* @exception GeographicErr if \e k2, \e alpha2, \e kp2, or \e alphap2 is
|
||||
* out of its legal range.
|
||||
*
|
||||
* The arguments must satisfy \e k2 + \e kp2 = 1 and \e alpha2 + \e alphap2
|
||||
* = 1. (No checking is done that these conditions are met.) This
|
||||
* constructor is provided to enable accuracy to be maintained, e.g., when
|
||||
* is very small.
|
||||
**********************************************************************/
|
||||
void Reset(real k2, real alpha2, real kp2, real alphap2);
|
||||
|
||||
///@}
|
||||
|
||||
/** \name Inspector functions.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return the square of the modulus <i>k</i><sup>2</sup>.
|
||||
**********************************************************************/
|
||||
Math::real k2() const { return _k2; }
|
||||
|
||||
/**
|
||||
* @return the square of the complementary modulus <i>k'</i><sup>2</sup> =
|
||||
* 1 − <i>k</i><sup>2</sup>.
|
||||
**********************************************************************/
|
||||
Math::real kp2() const { return _kp2; }
|
||||
|
||||
/**
|
||||
* @return the parameter α<sup>2</sup>.
|
||||
**********************************************************************/
|
||||
Math::real alpha2() const { return _alpha2; }
|
||||
|
||||
/**
|
||||
* @return the complementary parameter α'<sup>2</sup> = 1 −
|
||||
* α<sup>2</sup>.
|
||||
**********************************************************************/
|
||||
Math::real alphap2() const { return _alphap2; }
|
||||
///@}
|
||||
|
||||
/** \name Complete elliptic integrals.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* The complete integral of the first kind.
|
||||
*
|
||||
* @return \e K(\e k).
|
||||
*
|
||||
* \e K(\e k) is defined in https://dlmf.nist.gov/19.2.E4
|
||||
* \f[
|
||||
* K(k) = \int_0^{\pi/2} \frac1{\sqrt{1-k^2\sin^2\phi}}\,d\phi.
|
||||
* \f]
|
||||
**********************************************************************/
|
||||
Math::real K() const { return _Kc; }
|
||||
|
||||
/**
|
||||
* The complete integral of the second kind.
|
||||
*
|
||||
* @return \e E(\e k).
|
||||
*
|
||||
* \e E(\e k) is defined in https://dlmf.nist.gov/19.2.E5
|
||||
* \f[
|
||||
* E(k) = \int_0^{\pi/2} \sqrt{1-k^2\sin^2\phi}\,d\phi.
|
||||
* \f]
|
||||
**********************************************************************/
|
||||
Math::real E() const { return _Ec; }
|
||||
|
||||
/**
|
||||
* Jahnke's complete integral.
|
||||
*
|
||||
* @return \e D(\e k).
|
||||
*
|
||||
* \e D(\e k) is defined in https://dlmf.nist.gov/19.2.E6
|
||||
* \f[
|
||||
* D(k) =
|
||||
* \int_0^{\pi/2} \frac{\sin^2\phi}{\sqrt{1-k^2\sin^2\phi}}\,d\phi.
|
||||
* \f]
|
||||
**********************************************************************/
|
||||
Math::real D() const { return _Dc; }
|
||||
|
||||
/**
|
||||
* The difference between the complete integrals of the first and second
|
||||
* kinds.
|
||||
*
|
||||
* @return \e K(\e k) − \e E(\e k).
|
||||
**********************************************************************/
|
||||
Math::real KE() const { return _k2 * _Dc; }
|
||||
|
||||
/**
|
||||
* The complete integral of the third kind.
|
||||
*
|
||||
* @return Π(α<sup>2</sup>, \e k).
|
||||
*
|
||||
* Π(α<sup>2</sup>, \e k) is defined in
|
||||
* https://dlmf.nist.gov/19.2.E7
|
||||
* \f[
|
||||
* \Pi(\alpha^2, k) = \int_0^{\pi/2}
|
||||
* \frac1{\sqrt{1-k^2\sin^2\phi}(1 - \alpha^2\sin^2\phi)}\,d\phi.
|
||||
* \f]
|
||||
**********************************************************************/
|
||||
Math::real Pi() const { return _Pic; }
|
||||
|
||||
/**
|
||||
* Legendre's complete geodesic longitude integral.
|
||||
*
|
||||
* @return \e G(α<sup>2</sup>, \e k).
|
||||
*
|
||||
* \e G(α<sup>2</sup>, \e k) is given by
|
||||
* \f[
|
||||
* G(\alpha^2, k) = \int_0^{\pi/2}
|
||||
* \frac{\sqrt{1-k^2\sin^2\phi}}{1 - \alpha^2\sin^2\phi}\,d\phi.
|
||||
* \f]
|
||||
**********************************************************************/
|
||||
Math::real G() const { return _Gc; }
|
||||
|
||||
/**
|
||||
* Cayley's complete geodesic longitude difference integral.
|
||||
*
|
||||
* @return \e H(α<sup>2</sup>, \e k).
|
||||
*
|
||||
* \e H(α<sup>2</sup>, \e k) is given by
|
||||
* \f[
|
||||
* H(\alpha^2, k) = \int_0^{\pi/2}
|
||||
* \frac{\cos^2\phi}{(1-\alpha^2\sin^2\phi)\sqrt{1-k^2\sin^2\phi}}
|
||||
* \,d\phi.
|
||||
* \f]
|
||||
**********************************************************************/
|
||||
Math::real H() const { return _Hc; }
|
||||
///@}
|
||||
|
||||
/** \name Incomplete elliptic integrals.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* The incomplete integral of the first kind.
|
||||
*
|
||||
* @param[in] phi
|
||||
* @return \e F(φ, \e k).
|
||||
*
|
||||
* \e F(φ, \e k) is defined in https://dlmf.nist.gov/19.2.E4
|
||||
* \f[
|
||||
* F(\phi, k) = \int_0^\phi \frac1{\sqrt{1-k^2\sin^2\theta}}\,d\theta.
|
||||
* \f]
|
||||
**********************************************************************/
|
||||
Math::real F(real phi) const;
|
||||
|
||||
/**
|
||||
* The incomplete integral of the second kind.
|
||||
*
|
||||
* @param[in] phi
|
||||
* @return \e E(φ, \e k).
|
||||
*
|
||||
* \e E(φ, \e k) is defined in https://dlmf.nist.gov/19.2.E5
|
||||
* \f[
|
||||
* E(\phi, k) = \int_0^\phi \sqrt{1-k^2\sin^2\theta}\,d\theta.
|
||||
* \f]
|
||||
**********************************************************************/
|
||||
Math::real E(real phi) const;
|
||||
|
||||
/**
|
||||
* The incomplete integral of the second kind with the argument given in
|
||||
* degrees.
|
||||
*
|
||||
* @param[in] ang in <i>degrees</i>.
|
||||
* @return \e E(π <i>ang</i>/180, \e k).
|
||||
**********************************************************************/
|
||||
Math::real Ed(real ang) const;
|
||||
|
||||
/**
|
||||
* The inverse of the incomplete integral of the second kind.
|
||||
*
|
||||
* @param[in] x
|
||||
* @return φ = <i>E</i><sup>−1</sup>(\e x, \e k); i.e., the
|
||||
* solution of such that \e E(φ, \e k) = \e x.
|
||||
**********************************************************************/
|
||||
Math::real Einv(real x) const;
|
||||
|
||||
/**
|
||||
* The incomplete integral of the third kind.
|
||||
*
|
||||
* @param[in] phi
|
||||
* @return Π(φ, α<sup>2</sup>, \e k).
|
||||
*
|
||||
* Π(φ, α<sup>2</sup>, \e k) is defined in
|
||||
* https://dlmf.nist.gov/19.2.E7
|
||||
* \f[
|
||||
* \Pi(\phi, \alpha^2, k) = \int_0^\phi
|
||||
* \frac1{\sqrt{1-k^2\sin^2\theta}(1 - \alpha^2\sin^2\theta)}\,d\theta.
|
||||
* \f]
|
||||
**********************************************************************/
|
||||
Math::real Pi(real phi) const;
|
||||
|
||||
/**
|
||||
* Jahnke's incomplete elliptic integral.
|
||||
*
|
||||
* @param[in] phi
|
||||
* @return \e D(φ, \e k).
|
||||
*
|
||||
* \e D(φ, \e k) is defined in https://dlmf.nist.gov/19.2.E4
|
||||
* \f[
|
||||
* D(\phi, k) = \int_0^\phi
|
||||
* \frac{\sin^2\theta}{\sqrt{1-k^2\sin^2\theta}}\,d\theta.
|
||||
* \f]
|
||||
**********************************************************************/
|
||||
Math::real D(real phi) const;
|
||||
|
||||
/**
|
||||
* Legendre's geodesic longitude integral.
|
||||
*
|
||||
* @param[in] phi
|
||||
* @return \e G(φ, α<sup>2</sup>, \e k).
|
||||
*
|
||||
* \e G(φ, α<sup>2</sup>, \e k) is defined by
|
||||
* \f[
|
||||
* \begin{align}
|
||||
* G(\phi, \alpha^2, k) &=
|
||||
* \frac{k^2}{\alpha^2} F(\phi, k) +
|
||||
* \biggl(1 - \frac{k^2}{\alpha^2}\biggr) \Pi(\phi, \alpha^2, k) \\
|
||||
* &= \int_0^\phi
|
||||
* \frac{\sqrt{1-k^2\sin^2\theta}}{1 - \alpha^2\sin^2\theta}\,d\theta.
|
||||
* \end{align}
|
||||
* \f]
|
||||
*
|
||||
* Legendre expresses the longitude of a point on the geodesic in terms of
|
||||
* this combination of elliptic integrals in Exercices de Calcul
|
||||
* Intégral, Vol. 1 (1811), p. 181,
|
||||
* https://books.google.com/books?id=riIOAAAAQAAJ&pg=PA181.
|
||||
*
|
||||
* See \ref geodellip for the expression for the longitude in terms of this
|
||||
* function.
|
||||
**********************************************************************/
|
||||
Math::real G(real phi) const;
|
||||
|
||||
/**
|
||||
* Cayley's geodesic longitude difference integral.
|
||||
*
|
||||
* @param[in] phi
|
||||
* @return \e H(φ, α<sup>2</sup>, \e k).
|
||||
*
|
||||
* \e H(φ, α<sup>2</sup>, \e k) is defined by
|
||||
* \f[
|
||||
* \begin{align}
|
||||
* H(\phi, \alpha^2, k) &=
|
||||
* \frac1{\alpha^2} F(\phi, k) +
|
||||
* \biggl(1 - \frac1{\alpha^2}\biggr) \Pi(\phi, \alpha^2, k) \\
|
||||
* &= \int_0^\phi
|
||||
* \frac{\cos^2\theta}
|
||||
* {(1-\alpha^2\sin^2\theta)\sqrt{1-k^2\sin^2\theta}}
|
||||
* \,d\theta.
|
||||
* \end{align}
|
||||
* \f]
|
||||
*
|
||||
* Cayley expresses the longitude difference of a point on the geodesic in
|
||||
* terms of this combination of elliptic integrals in Phil. Mag. <b>40</b>
|
||||
* (1870), p. 333, https://books.google.com/books?id=Zk0wAAAAIAAJ&pg=PA333.
|
||||
*
|
||||
* See \ref geodellip for the expression for the longitude in terms of this
|
||||
* function.
|
||||
**********************************************************************/
|
||||
Math::real H(real phi) const;
|
||||
///@}
|
||||
|
||||
/** \name Incomplete integrals in terms of Jacobi elliptic functions.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* The incomplete integral of the first kind in terms of Jacobi elliptic
|
||||
* functions.
|
||||
*
|
||||
* @param[in] sn = sinφ.
|
||||
* @param[in] cn = cosφ.
|
||||
* @param[in] dn = sqrt(1 − <i>k</i><sup>2</sup>
|
||||
* sin<sup>2</sup>φ).
|
||||
* @return \e F(φ, \e k) as though φ ∈ (−π, π].
|
||||
**********************************************************************/
|
||||
Math::real F(real sn, real cn, real dn) const;
|
||||
|
||||
/**
|
||||
* The incomplete integral of the second kind in terms of Jacobi elliptic
|
||||
* functions.
|
||||
*
|
||||
* @param[in] sn = sinφ.
|
||||
* @param[in] cn = cosφ.
|
||||
* @param[in] dn = sqrt(1 − <i>k</i><sup>2</sup>
|
||||
* sin<sup>2</sup>φ).
|
||||
* @return \e E(φ, \e k) as though φ ∈ (−π, π].
|
||||
**********************************************************************/
|
||||
Math::real E(real sn, real cn, real dn) const;
|
||||
|
||||
/**
|
||||
* The incomplete integral of the third kind in terms of Jacobi elliptic
|
||||
* functions.
|
||||
*
|
||||
* @param[in] sn = sinφ.
|
||||
* @param[in] cn = cosφ.
|
||||
* @param[in] dn = sqrt(1 − <i>k</i><sup>2</sup>
|
||||
* sin<sup>2</sup>φ).
|
||||
* @return Π(φ, α<sup>2</sup>, \e k) as though φ ∈
|
||||
* (−π, π].
|
||||
**********************************************************************/
|
||||
Math::real Pi(real sn, real cn, real dn) const;
|
||||
|
||||
/**
|
||||
* Jahnke's incomplete elliptic integral in terms of Jacobi elliptic
|
||||
* functions.
|
||||
*
|
||||
* @param[in] sn = sinφ.
|
||||
* @param[in] cn = cosφ.
|
||||
* @param[in] dn = sqrt(1 − <i>k</i><sup>2</sup>
|
||||
* sin<sup>2</sup>φ).
|
||||
* @return \e D(φ, \e k) as though φ ∈ (−π, π].
|
||||
**********************************************************************/
|
||||
Math::real D(real sn, real cn, real dn) const;
|
||||
|
||||
/**
|
||||
* Legendre's geodesic longitude integral in terms of Jacobi elliptic
|
||||
* functions.
|
||||
*
|
||||
* @param[in] sn = sinφ.
|
||||
* @param[in] cn = cosφ.
|
||||
* @param[in] dn = sqrt(1 − <i>k</i><sup>2</sup>
|
||||
* sin<sup>2</sup>φ).
|
||||
* @return \e G(φ, α<sup>2</sup>, \e k) as though φ ∈
|
||||
* (−π, π].
|
||||
**********************************************************************/
|
||||
Math::real G(real sn, real cn, real dn) const;
|
||||
|
||||
/**
|
||||
* Cayley's geodesic longitude difference integral in terms of Jacobi
|
||||
* elliptic functions.
|
||||
*
|
||||
* @param[in] sn = sinφ.
|
||||
* @param[in] cn = cosφ.
|
||||
* @param[in] dn = sqrt(1 − <i>k</i><sup>2</sup>
|
||||
* sin<sup>2</sup>φ).
|
||||
* @return \e H(φ, α<sup>2</sup>, \e k) as though φ ∈
|
||||
* (−π, π].
|
||||
**********************************************************************/
|
||||
Math::real H(real sn, real cn, real dn) const;
|
||||
///@}
|
||||
|
||||
/** \name Periodic versions of incomplete elliptic integrals.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* The periodic incomplete integral of the first kind.
|
||||
*
|
||||
* @param[in] sn = sinφ.
|
||||
* @param[in] cn = cosφ.
|
||||
* @param[in] dn = sqrt(1 − <i>k</i><sup>2</sup>
|
||||
* sin<sup>2</sup>φ).
|
||||
* @return the periodic function π \e F(φ, \e k) / (2 \e K(\e k)) -
|
||||
* φ.
|
||||
**********************************************************************/
|
||||
Math::real deltaF(real sn, real cn, real dn) const;
|
||||
|
||||
/**
|
||||
* The periodic incomplete integral of the second kind.
|
||||
*
|
||||
* @param[in] sn = sinφ.
|
||||
* @param[in] cn = cosφ.
|
||||
* @param[in] dn = sqrt(1 − <i>k</i><sup>2</sup>
|
||||
* sin<sup>2</sup>φ).
|
||||
* @return the periodic function π \e E(φ, \e k) / (2 \e E(\e k)) -
|
||||
* φ.
|
||||
**********************************************************************/
|
||||
Math::real deltaE(real sn, real cn, real dn) const;
|
||||
|
||||
/**
|
||||
* The periodic inverse of the incomplete integral of the second kind.
|
||||
*
|
||||
* @param[in] stau = sinτ.
|
||||
* @param[in] ctau = sinτ.
|
||||
* @return the periodic function <i>E</i><sup>−1</sup>(τ (2 \e
|
||||
* E(\e k)/π), \e k) - τ.
|
||||
**********************************************************************/
|
||||
Math::real deltaEinv(real stau, real ctau) const;
|
||||
|
||||
/**
|
||||
* The periodic incomplete integral of the third kind.
|
||||
*
|
||||
* @param[in] sn = sinφ.
|
||||
* @param[in] cn = cosφ.
|
||||
* @param[in] dn = sqrt(1 − <i>k</i><sup>2</sup>
|
||||
* sin<sup>2</sup>φ).
|
||||
* @return the periodic function π Π(φ, α<sup>2</sup>,
|
||||
* \e k) / (2 Π(α<sup>2</sup>, \e k)) - φ.
|
||||
**********************************************************************/
|
||||
Math::real deltaPi(real sn, real cn, real dn) const;
|
||||
|
||||
/**
|
||||
* The periodic Jahnke's incomplete elliptic integral.
|
||||
*
|
||||
* @param[in] sn = sinφ.
|
||||
* @param[in] cn = cosφ.
|
||||
* @param[in] dn = sqrt(1 − <i>k</i><sup>2</sup>
|
||||
* sin<sup>2</sup>φ).
|
||||
* @return the periodic function π \e D(φ, \e k) / (2 \e D(\e k)) -
|
||||
* φ.
|
||||
**********************************************************************/
|
||||
Math::real deltaD(real sn, real cn, real dn) const;
|
||||
|
||||
/**
|
||||
* Legendre's periodic geodesic longitude integral.
|
||||
*
|
||||
* @param[in] sn = sinφ.
|
||||
* @param[in] cn = cosφ.
|
||||
* @param[in] dn = sqrt(1 − <i>k</i><sup>2</sup>
|
||||
* sin<sup>2</sup>φ).
|
||||
* @return the periodic function π \e G(φ, \e k) / (2 \e G(\e k)) -
|
||||
* φ.
|
||||
**********************************************************************/
|
||||
Math::real deltaG(real sn, real cn, real dn) const;
|
||||
|
||||
/**
|
||||
* Cayley's periodic geodesic longitude difference integral.
|
||||
*
|
||||
* @param[in] sn = sinφ.
|
||||
* @param[in] cn = cosφ.
|
||||
* @param[in] dn = sqrt(1 − <i>k</i><sup>2</sup>
|
||||
* sin<sup>2</sup>φ).
|
||||
* @return the periodic function π \e H(φ, \e k) / (2 \e H(\e k)) -
|
||||
* φ.
|
||||
**********************************************************************/
|
||||
Math::real deltaH(real sn, real cn, real dn) const;
|
||||
///@}
|
||||
|
||||
/** \name Elliptic functions.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* The Jacobi elliptic functions.
|
||||
*
|
||||
* @param[in] x the argument.
|
||||
* @param[out] sn sn(\e x, \e k).
|
||||
* @param[out] cn cn(\e x, \e k).
|
||||
* @param[out] dn dn(\e x, \e k).
|
||||
**********************************************************************/
|
||||
void sncndn(real x, real& sn, real& cn, real& dn) const;
|
||||
|
||||
/**
|
||||
* The Δ amplitude function.
|
||||
*
|
||||
* @param[in] sn sinφ.
|
||||
* @param[in] cn cosφ.
|
||||
* @return Δ = sqrt(1 − <i>k</i><sup>2</sup>
|
||||
* sin<sup>2</sup>φ).
|
||||
**********************************************************************/
|
||||
Math::real Delta(real sn, real cn) const {
|
||||
using std::sqrt;
|
||||
return sqrt(_k2 < 0 ? 1 - _k2 * sn*sn : _kp2 + _k2 * cn*cn);
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name Symmetric elliptic integrals.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Symmetric integral of the first kind <i>R</i><sub><i>F</i></sub>.
|
||||
*
|
||||
* @param[in] x
|
||||
* @param[in] y
|
||||
* @param[in] z
|
||||
* @return <i>R</i><sub><i>F</i></sub>(\e x, \e y, \e z).
|
||||
*
|
||||
* <i>R</i><sub><i>F</i></sub> is defined in https://dlmf.nist.gov/19.16.E1
|
||||
* \f[ R_F(x, y, z) = \frac12
|
||||
* \int_0^\infty\frac1{\sqrt{(t + x) (t + y) (t + z)}}\, dt \f]
|
||||
* If one of the arguments is zero, it is more efficient to call the
|
||||
* two-argument version of this function with the non-zero arguments.
|
||||
**********************************************************************/
|
||||
static real RF(real x, real y, real z);
|
||||
|
||||
/**
|
||||
* Complete symmetric integral of the first kind,
|
||||
* <i>R</i><sub><i>F</i></sub> with one argument zero.
|
||||
*
|
||||
* @param[in] x
|
||||
* @param[in] y
|
||||
* @return <i>R</i><sub><i>F</i></sub>(\e x, \e y, 0).
|
||||
**********************************************************************/
|
||||
static real RF(real x, real y);
|
||||
|
||||
/**
|
||||
* Degenerate symmetric integral of the first kind
|
||||
* <i>R</i><sub><i>C</i></sub>.
|
||||
*
|
||||
* @param[in] x
|
||||
* @param[in] y
|
||||
* @return <i>R</i><sub><i>C</i></sub>(\e x, \e y) =
|
||||
* <i>R</i><sub><i>F</i></sub>(\e x, \e y, \e y).
|
||||
*
|
||||
* <i>R</i><sub><i>C</i></sub> is defined in https://dlmf.nist.gov/19.2.E17
|
||||
* \f[ R_C(x, y) = \frac12
|
||||
* \int_0^\infty\frac1{\sqrt{t + x}(t + y)}\,dt \f]
|
||||
**********************************************************************/
|
||||
static real RC(real x, real y);
|
||||
|
||||
/**
|
||||
* Symmetric integral of the second kind <i>R</i><sub><i>G</i></sub>.
|
||||
*
|
||||
* @param[in] x
|
||||
* @param[in] y
|
||||
* @param[in] z
|
||||
* @return <i>R</i><sub><i>G</i></sub>(\e x, \e y, \e z).
|
||||
*
|
||||
* <i>R</i><sub><i>G</i></sub> is defined in Carlson, eq 1.5
|
||||
* \f[ R_G(x, y, z) = \frac14
|
||||
* \int_0^\infty[(t + x) (t + y) (t + z)]^{-1/2}
|
||||
* \biggl(
|
||||
* \frac x{t + x} + \frac y{t + y} + \frac z{t + z}
|
||||
* \biggr)t\,dt \f]
|
||||
* See also https://dlmf.nist.gov/19.16.E3.
|
||||
* If one of the arguments is zero, it is more efficient to call the
|
||||
* two-argument version of this function with the non-zero arguments.
|
||||
**********************************************************************/
|
||||
static real RG(real x, real y, real z);
|
||||
|
||||
/**
|
||||
* Complete symmetric integral of the second kind,
|
||||
* <i>R</i><sub><i>G</i></sub> with one argument zero.
|
||||
*
|
||||
* @param[in] x
|
||||
* @param[in] y
|
||||
* @return <i>R</i><sub><i>G</i></sub>(\e x, \e y, 0).
|
||||
**********************************************************************/
|
||||
static real RG(real x, real y);
|
||||
|
||||
/**
|
||||
* Symmetric integral of the third kind <i>R</i><sub><i>J</i></sub>.
|
||||
*
|
||||
* @param[in] x
|
||||
* @param[in] y
|
||||
* @param[in] z
|
||||
* @param[in] p
|
||||
* @return <i>R</i><sub><i>J</i></sub>(\e x, \e y, \e z, \e p).
|
||||
*
|
||||
* <i>R</i><sub><i>J</i></sub> is defined in https://dlmf.nist.gov/19.16.E2
|
||||
* \f[ R_J(x, y, z, p) = \frac32
|
||||
* \int_0^\infty
|
||||
* [(t + x) (t + y) (t + z)]^{-1/2} (t + p)^{-1}\, dt \f]
|
||||
**********************************************************************/
|
||||
static real RJ(real x, real y, real z, real p);
|
||||
|
||||
/**
|
||||
* Degenerate symmetric integral of the third kind
|
||||
* <i>R</i><sub><i>D</i></sub>.
|
||||
*
|
||||
* @param[in] x
|
||||
* @param[in] y
|
||||
* @param[in] z
|
||||
* @return <i>R</i><sub><i>D</i></sub>(\e x, \e y, \e z) =
|
||||
* <i>R</i><sub><i>J</i></sub>(\e x, \e y, \e z, \e z).
|
||||
*
|
||||
* <i>R</i><sub><i>D</i></sub> is defined in https://dlmf.nist.gov/19.16.E5
|
||||
* \f[ R_D(x, y, z) = \frac32
|
||||
* \int_0^\infty[(t + x) (t + y)]^{-1/2} (t + z)^{-3/2}\, dt \f]
|
||||
**********************************************************************/
|
||||
static real RD(real x, real y, real z);
|
||||
///@}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_ELLIPTICFUNCTION_HPP
|
||||
143
external/include/GeographicLib/GARS.hpp
vendored
Normal file
143
external/include/GeographicLib/GARS.hpp
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* \file GARS.hpp
|
||||
* \brief Header for GeographicLib::GARS class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2015-2021) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GARS_HPP)
|
||||
#define GEOGRAPHICLIB_GARS_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about dll vs string
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4251)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Conversions for the Global Area Reference System (GARS)
|
||||
*
|
||||
* The Global Area Reference System is described in
|
||||
* - https://en.wikipedia.org/wiki/Global_Area_Reference_System
|
||||
* - https://earth-info.nga.mil/index.php?dir=coordsys&action=coordsys#tab_gars
|
||||
* .
|
||||
* It provides a compact string representation of a geographic area
|
||||
* (expressed as latitude and longitude). The classes Georef and Geohash
|
||||
* implement similar compact representations.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-GARS.cpp
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT GARS {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
static const char* const digits_;
|
||||
static const char* const letters_;
|
||||
enum {
|
||||
lonorig_ = -180, // Origin for longitude
|
||||
latorig_ = -90, // Origin for latitude
|
||||
baselon_ = 10, // Base for longitude tiles
|
||||
baselat_ = 24, // Base for latitude tiles
|
||||
lonlen_ = 3,
|
||||
latlen_ = 2,
|
||||
baselen_ = lonlen_ + latlen_,
|
||||
mult1_ = 2, // base precision = 1/2 degree
|
||||
mult2_ = 2, // 6th char gives 2x more precision
|
||||
mult3_ = 3, // 7th char gives 3x more precision
|
||||
m_ = mult1_ * mult2_ * mult3_,
|
||||
maxprec_ = 2,
|
||||
maxlen_ = baselen_ + maxprec_,
|
||||
};
|
||||
GARS(); // Disable constructor
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Convert from geographic coordinates to GARS.
|
||||
*
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[in] prec the precision of the resulting GARS.
|
||||
* @param[out] gars the GARS string.
|
||||
* @exception GeographicErr if \e lat is not in [−90°,
|
||||
* 90°].
|
||||
* @exception std::bad_alloc if memory for \e gars can't be allocated.
|
||||
*
|
||||
* \e prec specifies the precision of \e gars as follows:
|
||||
* - \e prec = 0 (min), 30' precision, e.g., 006AG;
|
||||
* - \e prec = 1, 15' precision, e.g., 006AG3;
|
||||
* - \e prec = 2 (max), 5' precision, e.g., 006AG39.
|
||||
*
|
||||
* If \e lat or \e lon is NaN, then \e gars is set to "INVALID".
|
||||
**********************************************************************/
|
||||
static void Forward(real lat, real lon, int prec, std::string& gars);
|
||||
|
||||
/**
|
||||
* Convert from GARS to geographic coordinates.
|
||||
*
|
||||
* @param[in] gars the GARS.
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] prec the precision of \e gars.
|
||||
* @param[in] centerp if true (the default) return the center of the
|
||||
* \e gars, otherwise return the south-west corner.
|
||||
* @exception GeographicErr if \e gars is illegal.
|
||||
*
|
||||
* The case of the letters in \e gars is ignored. \e prec is in the range
|
||||
* [0, 2] and gives the precision of \e gars as follows:
|
||||
* - \e prec = 0 (min), 30' precision, e.g., 006AG;
|
||||
* - \e prec = 1, 15' precision, e.g., 006AG3;
|
||||
* - \e prec = 2 (max), 5' precision, e.g., 006AG39.
|
||||
*
|
||||
* If the first 3 characters of \e gars are "INV", then \e lat and \e lon
|
||||
* are set to NaN and \e prec is unchanged.
|
||||
**********************************************************************/
|
||||
static void Reverse(const std::string& gars, real& lat, real& lon,
|
||||
int& prec, bool centerp = true);
|
||||
|
||||
/**
|
||||
* The angular resolution of a GARS.
|
||||
*
|
||||
* @param[in] prec the precision of the GARS.
|
||||
* @return the latitude-longitude resolution (degrees).
|
||||
*
|
||||
* Internally, \e prec is first put in the range [0, 2].
|
||||
**********************************************************************/
|
||||
static Math::real Resolution(int prec) {
|
||||
return 1/real(prec <= 0 ? mult1_ : (prec == 1 ? mult1_ * mult2_ :
|
||||
mult1_ * mult2_ * mult3_));
|
||||
}
|
||||
|
||||
/**
|
||||
* The GARS precision required to meet a given geographic resolution.
|
||||
*
|
||||
* @param[in] res the minimum of resolution in latitude and longitude
|
||||
* (degrees).
|
||||
* @return GARS precision.
|
||||
*
|
||||
* The returned length is in the range [0, 2].
|
||||
**********************************************************************/
|
||||
static int Precision(real res) {
|
||||
using std::abs; res = abs(res);
|
||||
for (int prec = 0; prec < maxprec_; ++prec)
|
||||
if (Resolution(prec) <= res)
|
||||
return prec;
|
||||
return maxprec_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_GARS_HPP
|
||||
553
external/include/GeographicLib/GeoCoords.hpp
vendored
Normal file
553
external/include/GeographicLib/GeoCoords.hpp
vendored
Normal file
@@ -0,0 +1,553 @@
|
||||
/**
|
||||
* \file GeoCoords.hpp
|
||||
* \brief Header for GeographicLib::GeoCoords class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GEOCOORDS_HPP)
|
||||
#define GEOGRAPHICLIB_GEOCOORDS_HPP 1
|
||||
|
||||
#include <GeographicLib/UTMUPS.hpp>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Conversion between geographic coordinates
|
||||
*
|
||||
* This class stores a geographic position which may be set via the
|
||||
* constructors or Reset via
|
||||
* - latitude and longitude
|
||||
* - UTM or UPS coordinates
|
||||
* - a string representation of these or an MGRS coordinate string
|
||||
*
|
||||
* The state consists of the latitude and longitude and the supplied UTM or
|
||||
* UPS coordinates (possibly derived from the MGRS coordinates). If latitude
|
||||
* and longitude were given then the UTM/UPS coordinates follows the standard
|
||||
* conventions.
|
||||
*
|
||||
* The mutable state consists of the UTM or UPS coordinates for a alternate
|
||||
* zone. A method SetAltZone is provided to set the alternate UPS/UTM zone.
|
||||
*
|
||||
* Methods are provided to return the geographic coordinates, the input UTM
|
||||
* or UPS coordinates (and associated meridian convergence and scale), or
|
||||
* alternate UTM or UPS coordinates (and their associated meridian
|
||||
* convergence and scale).
|
||||
*
|
||||
* Once the input string has been parsed, you can print the result out in any
|
||||
* of the formats, decimal degrees, degrees minutes seconds, MGRS, UTM/UPS.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-GeoCoords.cpp
|
||||
*
|
||||
* <a href="GeoConvert.1.html">GeoConvert</a> is a command-line utility
|
||||
* providing access to the functionality of GeoCoords.
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT GeoCoords {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
real _lat, _long, _easting, _northing, _gamma, _k;
|
||||
bool _northp;
|
||||
int _zone; // See UTMUPS::zonespec
|
||||
mutable real _alt_easting, _alt_northing, _alt_gamma, _alt_k;
|
||||
mutable int _alt_zone;
|
||||
|
||||
void CopyToAlt() const {
|
||||
_alt_easting = _easting;
|
||||
_alt_northing = _northing;
|
||||
_alt_gamma = _gamma;
|
||||
_alt_k = _k;
|
||||
_alt_zone = _zone;
|
||||
}
|
||||
static void UTMUPSString(int zone, bool northp,
|
||||
real easting, real northing,
|
||||
int prec, bool abbrev, std::string& utm);
|
||||
void FixHemisphere();
|
||||
public:
|
||||
|
||||
/** \name Initializing the GeoCoords object
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* The default constructor sets the coordinate as undefined.
|
||||
**********************************************************************/
|
||||
GeoCoords()
|
||||
: _lat(Math::NaN())
|
||||
, _long(Math::NaN())
|
||||
, _easting(Math::NaN())
|
||||
, _northing(Math::NaN())
|
||||
, _gamma(Math::NaN())
|
||||
, _k(Math::NaN())
|
||||
, _northp(false)
|
||||
, _zone(UTMUPS::INVALID)
|
||||
{ CopyToAlt(); }
|
||||
|
||||
/**
|
||||
* Construct from a string.
|
||||
*
|
||||
* @param[in] s 1-element, 2-element, or 3-element string representation of
|
||||
* the position.
|
||||
* @param[in] centerp governs the interpretation of MGRS coordinates (see
|
||||
* below).
|
||||
* @param[in] longfirst governs the interpretation of geographic
|
||||
* coordinates (see below).
|
||||
* @exception GeographicErr if the \e s is malformed (see below).
|
||||
*
|
||||
* Parse as a string and interpret it as a geographic position. The input
|
||||
* string is broken into space (or comma) separated pieces and Basic
|
||||
* decision on which format is based on number of components
|
||||
* -# MGRS
|
||||
* -# "Lat Long" or "Long Lat"
|
||||
* -# "Zone Easting Northing" or "Easting Northing Zone"
|
||||
*
|
||||
* The following inputs are approximately the same (Ar Ramadi Bridge, Iraq)
|
||||
* - Latitude and Longitude
|
||||
* - 33.44 43.27
|
||||
* - N33d26.4' E43d16.2'
|
||||
* - 43d16'12"E 33d26'24"N
|
||||
* - 43:16:12E 33:26:24
|
||||
* - MGRS
|
||||
* - 38SLC30
|
||||
* - 38SLC391014
|
||||
* - 38SLC3918701405
|
||||
* - 37SHT9708
|
||||
* - UTM
|
||||
* - 38n 339188 3701405
|
||||
* - 897039 3708229 37n
|
||||
*
|
||||
* <b>Latitude and Longitude parsing</b>: Latitude precedes longitude,
|
||||
* unless a N, S, E, W hemisphere designator is used on one or both
|
||||
* coordinates. If \e longfirst = true (default is false), then
|
||||
* longitude precedes latitude in the absence of a hemisphere designator.
|
||||
* Thus (with \e longfirst = false)
|
||||
* - 40 -75
|
||||
* - N40 W75
|
||||
* - -75 N40
|
||||
* - 75W 40N
|
||||
* - E-75 -40S
|
||||
* .
|
||||
* are all the same position. The coordinates may be given in
|
||||
* decimal degrees, degrees and decimal minutes, degrees, minutes,
|
||||
* seconds, etc. Use d, ', and " to mark off the degrees,
|
||||
* minutes and seconds. Various alternative symbols for degrees, minutes,
|
||||
* and seconds are allowed. Alternatively, use : to separate these
|
||||
* components. A single addition or subtraction is allowed. (See
|
||||
* DMS::Decode for details.) Thus
|
||||
* - 40d30'30"
|
||||
* - 40d30'30
|
||||
* - 40°30'30
|
||||
* - 40d30.5'
|
||||
* - 40d30.5
|
||||
* - 40:30:30
|
||||
* - 40:30.5
|
||||
* - 40.508333333
|
||||
* - 40:30+0:0:30
|
||||
* - 40:31-0:0.5
|
||||
* .
|
||||
* all specify the same angle. The leading sign applies to the following
|
||||
* components so -1d30 is -(1+30/60) = −1.5. However, note
|
||||
* that -1:30-0:0:15 is parsed as (-1:30) + (-0:0:15) = −(1+30/60)
|
||||
* − (15/3600). Latitudes must be in the range [−90°,
|
||||
* 90°]. Internally longitudes are reduced to the range
|
||||
* [−180°, 180°].
|
||||
*
|
||||
* <b>UTM/UPS parsing</b>: For UTM zones (−80° ≤ Lat <
|
||||
* 84°), the zone designator is made up of a zone number (for 1 to 60)
|
||||
* and a hemisphere letter (n or s), e.g., 38n (38north can also be used).
|
||||
* The latitude band designer ([C--M] in the southern hemisphere and [N--X]
|
||||
* in the northern) should NOT be used. (This is part of the MGRS
|
||||
* coordinate.) The zone designator for the poles (where UPS is employed)
|
||||
* is a hemisphere letter by itself, i.e., n or s (north or south can also
|
||||
* be used).
|
||||
*
|
||||
* <b>MGRS parsing</b> interprets the grid references as square area at the
|
||||
* specified precision (1m, 10m, 100m, etc.). If \e centerp = true (the
|
||||
* default), the center of this square is then taken to be the precise
|
||||
* position; thus:
|
||||
* - 38SMB = 38n 450000 3650000
|
||||
* - 38SMB4484 = 38n 444500 3684500
|
||||
* - 38SMB44148470 = 38n 444145 3684705
|
||||
* .
|
||||
* Otherwise, the "south-west" corner of the square is used, i.e.,
|
||||
* - 38SMB = 38n 400000 3600000
|
||||
* - 38SMB4484 = 38n 444000 3684000
|
||||
* - 38SMB44148470 = 38n 444140 3684700
|
||||
**********************************************************************/
|
||||
explicit GeoCoords(const std::string& s,
|
||||
bool centerp = true, bool longfirst = false)
|
||||
{ Reset(s, centerp, longfirst); }
|
||||
|
||||
/**
|
||||
* Construct from geographic coordinates.
|
||||
*
|
||||
* @param[in] latitude (degrees).
|
||||
* @param[in] longitude (degrees).
|
||||
* @param[in] zone if specified, force the UTM/UPS representation to use a
|
||||
* specified zone using the rules given in UTMUPS::zonespec.
|
||||
* @exception GeographicErr if \e latitude is not in [−90°,
|
||||
* 90°].
|
||||
* @exception GeographicErr if \e zone cannot be used for this location.
|
||||
**********************************************************************/
|
||||
GeoCoords(real latitude, real longitude, int zone = UTMUPS::STANDARD) {
|
||||
Reset(latitude, longitude, zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct from UTM/UPS coordinates.
|
||||
*
|
||||
* @param[in] zone UTM zone (zero means UPS).
|
||||
* @param[in] northp hemisphere (true means north, false means south).
|
||||
* @param[in] easting (meters).
|
||||
* @param[in] northing (meters).
|
||||
* @exception GeographicErr if \e zone, \e easting, or \e northing is
|
||||
* outside its allowed range.
|
||||
**********************************************************************/
|
||||
GeoCoords(int zone, bool northp, real easting, real northing) {
|
||||
Reset(zone, northp, easting, northing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the location from a string. See
|
||||
* GeoCoords(const std::string& s, bool centerp, bool longfirst).
|
||||
*
|
||||
* @param[in] s 1-element, 2-element, or 3-element string representation of
|
||||
* the position.
|
||||
* @param[in] centerp governs the interpretation of MGRS coordinates.
|
||||
* @param[in] longfirst governs the interpretation of geographic
|
||||
* coordinates.
|
||||
* @exception GeographicErr if the \e s is malformed.
|
||||
**********************************************************************/
|
||||
void Reset(const std::string& s,
|
||||
bool centerp = true, bool longfirst = false);
|
||||
|
||||
/**
|
||||
* Reset the location in terms of geographic coordinates. See
|
||||
* GeoCoords(real latitude, real longitude, int zone).
|
||||
*
|
||||
* @param[in] latitude (degrees).
|
||||
* @param[in] longitude (degrees).
|
||||
* @param[in] zone if specified, force the UTM/UPS representation to use a
|
||||
* specified zone using the rules given in UTMUPS::zonespec.
|
||||
* @exception GeographicErr if \e latitude is not in [−90°,
|
||||
* 90°].
|
||||
* @exception GeographicErr if \e zone cannot be used for this location.
|
||||
**********************************************************************/
|
||||
void Reset(real latitude, real longitude, int zone = UTMUPS::STANDARD) {
|
||||
UTMUPS::Forward(latitude, longitude,
|
||||
_zone, _northp, _easting, _northing, _gamma, _k,
|
||||
zone);
|
||||
_lat = latitude;
|
||||
_long = longitude;
|
||||
if (_long >= 180) _long -= 360;
|
||||
else if (_long < -180) _long += 360;
|
||||
CopyToAlt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the location in terms of UPS/UPS coordinates. See
|
||||
* GeoCoords(int zone, bool northp, real easting, real northing).
|
||||
*
|
||||
* @param[in] zone UTM zone (zero means UPS).
|
||||
* @param[in] northp hemisphere (true means north, false means south).
|
||||
* @param[in] easting (meters).
|
||||
* @param[in] northing (meters).
|
||||
* @exception GeographicErr if \e zone, \e easting, or \e northing is
|
||||
* outside its allowed range.
|
||||
**********************************************************************/
|
||||
void Reset(int zone, bool northp, real easting, real northing) {
|
||||
UTMUPS::Reverse(zone, northp, easting, northing,
|
||||
_lat, _long, _gamma, _k);
|
||||
_zone = zone;
|
||||
_northp = northp;
|
||||
_easting = easting;
|
||||
_northing = northing;
|
||||
FixHemisphere();
|
||||
CopyToAlt();
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name Querying the GeoCoords object
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return latitude (degrees)
|
||||
**********************************************************************/
|
||||
Math::real Latitude() const { return _lat; }
|
||||
|
||||
/**
|
||||
* @return longitude (degrees)
|
||||
**********************************************************************/
|
||||
Math::real Longitude() const { return _long; }
|
||||
|
||||
/**
|
||||
* @return easting (meters)
|
||||
**********************************************************************/
|
||||
Math::real Easting() const { return _easting; }
|
||||
|
||||
/**
|
||||
* @return northing (meters)
|
||||
**********************************************************************/
|
||||
Math::real Northing() const { return _northing; }
|
||||
|
||||
/**
|
||||
* @return meridian convergence (degrees) for the UTM/UPS projection.
|
||||
**********************************************************************/
|
||||
Math::real Convergence() const { return _gamma; }
|
||||
|
||||
/**
|
||||
* @return scale for the UTM/UPS projection.
|
||||
**********************************************************************/
|
||||
Math::real Scale() const { return _k; }
|
||||
|
||||
/**
|
||||
* @return hemisphere (false means south, true means north).
|
||||
**********************************************************************/
|
||||
bool Northp() const { return _northp; }
|
||||
|
||||
/**
|
||||
* @return hemisphere letter n or s.
|
||||
**********************************************************************/
|
||||
char Hemisphere() const { return _northp ? 'n' : 's'; }
|
||||
|
||||
/**
|
||||
* @return the zone corresponding to the input (return 0 for UPS).
|
||||
**********************************************************************/
|
||||
int Zone() const { return _zone; }
|
||||
|
||||
///@}
|
||||
|
||||
/** \name Setting and querying the alternate zone
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Specify alternate zone number.
|
||||
*
|
||||
* @param[in] zone zone number for the alternate representation.
|
||||
* @exception GeographicErr if \e zone cannot be used for this location.
|
||||
*
|
||||
* See UTMUPS::zonespec for more information on the interpretation of \e
|
||||
* zone. Note that \e zone == UTMUPS::STANDARD (the default) use the
|
||||
* standard UPS or UTM zone, UTMUPS::MATCH does nothing retaining the
|
||||
* existing alternate representation. Before this is called the alternate
|
||||
* zone is the input zone.
|
||||
**********************************************************************/
|
||||
void SetAltZone(int zone = UTMUPS::STANDARD) const {
|
||||
if (zone == UTMUPS::MATCH)
|
||||
return;
|
||||
zone = UTMUPS::StandardZone(_lat, _long, zone);
|
||||
if (zone == _zone)
|
||||
CopyToAlt();
|
||||
else {
|
||||
bool northp;
|
||||
UTMUPS::Forward(_lat, _long,
|
||||
_alt_zone, northp,
|
||||
_alt_easting, _alt_northing, _alt_gamma, _alt_k,
|
||||
zone);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return current alternate zone (return 0 for UPS).
|
||||
**********************************************************************/
|
||||
int AltZone() const { return _alt_zone; }
|
||||
|
||||
/**
|
||||
* @return easting (meters) for alternate zone.
|
||||
**********************************************************************/
|
||||
Math::real AltEasting() const { return _alt_easting; }
|
||||
|
||||
/**
|
||||
* @return northing (meters) for alternate zone.
|
||||
**********************************************************************/
|
||||
Math::real AltNorthing() const { return _alt_northing; }
|
||||
|
||||
/**
|
||||
* @return meridian convergence (degrees) for alternate zone.
|
||||
**********************************************************************/
|
||||
Math::real AltConvergence() const { return _alt_gamma; }
|
||||
|
||||
/**
|
||||
* @return scale for alternate zone.
|
||||
**********************************************************************/
|
||||
Math::real AltScale() const { return _alt_k; }
|
||||
///@}
|
||||
|
||||
/** \name String representations of the GeoCoords object
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* String representation with latitude and longitude as signed decimal
|
||||
* degrees.
|
||||
*
|
||||
* @param[in] prec precision (relative to about 1m).
|
||||
* @param[in] longfirst if true give longitude first (default = false)
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return decimal latitude/longitude string representation.
|
||||
*
|
||||
* Precision specifies accuracy of representation as follows:
|
||||
* - prec = −5 (min), 1°
|
||||
* - prec = 0, 10<sup>−5</sup>° (about 1m)
|
||||
* - prec = 3, 10<sup>−8</sup>°
|
||||
* - prec = 9 (max), 10<sup>−14</sup>°
|
||||
**********************************************************************/
|
||||
std::string GeoRepresentation(int prec = 0, bool longfirst = false) const;
|
||||
|
||||
/**
|
||||
* String representation with latitude and longitude as degrees, minutes,
|
||||
* seconds, and hemisphere.
|
||||
*
|
||||
* @param[in] prec precision (relative to about 1m)
|
||||
* @param[in] longfirst if true give longitude first (default = false)
|
||||
* @param[in] dmssep if non-null, use as the DMS separator character
|
||||
* (instead of d, ', " delimiters).
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return DMS latitude/longitude string representation.
|
||||
*
|
||||
* Precision specifies accuracy of representation as follows:
|
||||
* - prec = −5 (min), 1°
|
||||
* - prec = −4, 0.1°
|
||||
* - prec = −3, 1'
|
||||
* - prec = −2, 0.1'
|
||||
* - prec = −1, 1"
|
||||
* - prec = 0, 0.1" (about 3m)
|
||||
* - prec = 1, 0.01"
|
||||
* - prec = 10 (max), 10<sup>−11</sup>"
|
||||
**********************************************************************/
|
||||
std::string DMSRepresentation(int prec = 0, bool longfirst = false,
|
||||
char dmssep = char(0))
|
||||
const;
|
||||
|
||||
/**
|
||||
* MGRS string.
|
||||
*
|
||||
* @param[in] prec precision (relative to about 1m).
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return MGRS string.
|
||||
*
|
||||
* This gives the coordinates of the enclosing grid square with size given
|
||||
* by the precision. Thus 38n 444180 3684790 converted to a MGRS
|
||||
* coordinate at precision −2 (100m) is 38SMB441847 and not
|
||||
* 38SMB442848. \e prec specifies the precision of the MGRS string as
|
||||
* follows:
|
||||
* - prec = −6 (min), only the grid zone is returned, e.g., 38S
|
||||
* - prec = −5, 100km, e.g., 38SMB
|
||||
* - prec = −4, 10km
|
||||
* - prec = −3, 1km
|
||||
* - prec = −2, 100m
|
||||
* - prec = −1, 10m
|
||||
* - prec = 0, 1m
|
||||
* - prec = 1, 0.1m
|
||||
* - prec = 6 (max), 1μm
|
||||
**********************************************************************/
|
||||
std::string MGRSRepresentation(int prec = 0) const;
|
||||
|
||||
/**
|
||||
* UTM/UPS string.
|
||||
*
|
||||
* @param[in] prec precision (relative to about 1m)
|
||||
* @param[in] abbrev if true (the default) use abbreviated (n/s) notation
|
||||
* for hemisphere; otherwise spell out the hemisphere (north/south)
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return UTM/UPS string representation: zone designator, easting, and
|
||||
* northing.
|
||||
*
|
||||
* Precision specifies accuracy of representation as follows:
|
||||
* - prec = −5 (min), 100km
|
||||
* - prec = −3, 1km
|
||||
* - prec = 0, 1m
|
||||
* - prec = 3, 1mm
|
||||
* - prec = 6, 1μm
|
||||
* - prec = 9 (max), 1nm
|
||||
**********************************************************************/
|
||||
std::string UTMUPSRepresentation(int prec = 0, bool abbrev = true) const;
|
||||
|
||||
/**
|
||||
* UTM/UPS string with hemisphere override.
|
||||
*
|
||||
* @param[in] northp hemisphere override
|
||||
* @param[in] prec precision (relative to about 1m)
|
||||
* @param[in] abbrev if true (the default) use abbreviated (n/s) notation
|
||||
* for hemisphere; otherwise spell out the hemisphere (north/south)
|
||||
* @exception GeographicErr if the hemisphere override attempts to change
|
||||
* UPS N to UPS S or vice versa.
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return UTM/UPS string representation: zone designator, easting, and
|
||||
* northing.
|
||||
**********************************************************************/
|
||||
std::string UTMUPSRepresentation(bool northp, int prec = 0,
|
||||
bool abbrev = true) const;
|
||||
|
||||
/**
|
||||
* MGRS string for the alternate zone. See GeoCoords::MGRSRepresentation.
|
||||
*
|
||||
* @param[in] prec precision (relative to about 1m).
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return MGRS string.
|
||||
**********************************************************************/
|
||||
std::string AltMGRSRepresentation(int prec = 0) const;
|
||||
|
||||
/**
|
||||
* UTM/UPS string for the alternate zone. See
|
||||
* GeoCoords::UTMUPSRepresentation.
|
||||
*
|
||||
* @param[in] prec precision (relative to about 1m)
|
||||
* @param[in] abbrev if true (the default) use abbreviated (n/s) notation
|
||||
* for hemisphere; otherwise spell out the hemisphere (north/south)
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return UTM/UPS string representation: zone designator, easting, and
|
||||
* northing.
|
||||
**********************************************************************/
|
||||
std::string AltUTMUPSRepresentation(int prec = 0, bool abbrev = true)
|
||||
const;
|
||||
|
||||
/**
|
||||
* UTM/UPS string for the alternate zone, with hemisphere override.
|
||||
*
|
||||
* @param[in] northp hemisphere override
|
||||
* @param[in] prec precision (relative to about 1m)
|
||||
* @param[in] abbrev if true (the default) use abbreviated (n/s) notation
|
||||
* for hemisphere; otherwise spell out the hemisphere (north/south)
|
||||
* @exception GeographicErr if the hemisphere override attempts to change
|
||||
* UPS n to UPS s or vice verse.
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return UTM/UPS string representation: zone designator, easting, and
|
||||
* northing.
|
||||
**********************************************************************/
|
||||
std::string AltUTMUPSRepresentation(bool northp, int prec = 0,
|
||||
bool abbrev = true) const;
|
||||
///@}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return \e a the equatorial radius of the WGS84 ellipsoid (meters).
|
||||
*
|
||||
* (The WGS84 value is returned because the UTM and UPS projections are
|
||||
* based on this ellipsoid.)
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return UTMUPS::EquatorialRadius(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the WGS84 ellipsoid.
|
||||
*
|
||||
* (The WGS84 value is returned because the UTM and UPS projections are
|
||||
* based on this ellipsoid.)
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return UTMUPS::Flattening(); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_GEOCOORDS_HPP
|
||||
274
external/include/GeographicLib/Geocentric.hpp
vendored
Normal file
274
external/include/GeographicLib/Geocentric.hpp
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
/**
|
||||
* \file Geocentric.hpp
|
||||
* \brief Header for GeographicLib::Geocentric class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GEOCENTRIC_HPP)
|
||||
#define GEOGRAPHICLIB_GEOCENTRIC_HPP 1
|
||||
|
||||
#include <vector>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief %Geocentric coordinates
|
||||
*
|
||||
* Convert between geodetic coordinates latitude = \e lat, longitude = \e
|
||||
* lon, height = \e h (measured vertically from the surface of the ellipsoid)
|
||||
* to geocentric coordinates (\e X, \e Y, \e Z). The origin of geocentric
|
||||
* coordinates is at the center of the earth. The \e Z axis goes thru the
|
||||
* north pole, \e lat = 90°. The \e X axis goes thru \e lat = 0,
|
||||
* \e lon = 0. %Geocentric coordinates are also known as earth centered,
|
||||
* earth fixed (ECEF) coordinates.
|
||||
*
|
||||
* The conversion from geographic to geocentric coordinates is
|
||||
* straightforward. For the reverse transformation we use
|
||||
* - H. Vermeille,
|
||||
* <a href="https://doi.org/10.1007/s00190-002-0273-6"> Direct
|
||||
* transformation from geocentric coordinates to geodetic coordinates</a>,
|
||||
* J. Geodesy 76, 451--454 (2002).
|
||||
* .
|
||||
* Several changes have been made to ensure that the method returns accurate
|
||||
* results for all finite inputs (even if \e h is infinite). The changes are
|
||||
* described in Appendix B of
|
||||
* - C. F. F. Karney,
|
||||
* <a href="https://arxiv.org/abs/1102.1215v1">Geodesics
|
||||
* on an ellipsoid of revolution</a>,
|
||||
* Feb. 2011;
|
||||
* preprint
|
||||
* <a href="https://arxiv.org/abs/1102.1215v1">arxiv:1102.1215v1</a>.
|
||||
* .
|
||||
* Vermeille similarly updated his method in
|
||||
* - H. Vermeille,
|
||||
* <a href="https://doi.org/10.1007/s00190-010-0419-x">
|
||||
* An analytical method to transform geocentric into
|
||||
* geodetic coordinates</a>, J. Geodesy 85, 105--117 (2011).
|
||||
* .
|
||||
* See \ref geocentric for more information.
|
||||
*
|
||||
* The errors in these routines are close to round-off. Specifically, for
|
||||
* points within 5000 km of the surface of the ellipsoid (either inside or
|
||||
* outside the ellipsoid), the error is bounded by 7 nm (7 nanometers) for
|
||||
* the WGS84 ellipsoid. See \ref geocentric for further information on the
|
||||
* errors.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-Geocentric.cpp
|
||||
*
|
||||
* <a href="CartConvert.1.html">CartConvert</a> is a command-line utility
|
||||
* providing access to the functionality of Geocentric and LocalCartesian.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT Geocentric {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
friend class LocalCartesian;
|
||||
friend class MagneticCircle; // MagneticCircle uses Rotation
|
||||
friend class MagneticModel; // MagneticModel uses IntForward
|
||||
friend class GravityCircle; // GravityCircle uses Rotation
|
||||
friend class GravityModel; // GravityModel uses IntForward
|
||||
friend class NormalGravity; // NormalGravity uses IntForward
|
||||
static const size_t dim_ = 3;
|
||||
static const size_t dim2_ = dim_ * dim_;
|
||||
real _a, _f, _e2, _e2m, _e2a, _e4a, _maxrad;
|
||||
static void Rotation(real sphi, real cphi, real slam, real clam,
|
||||
real M[dim2_]);
|
||||
static void Rotate(const real M[dim2_], real x, real y, real z,
|
||||
real& X, real& Y, real& Z) {
|
||||
// Perform [X,Y,Z]^t = M.[x,y,z]^t
|
||||
// (typically local cartesian to geocentric)
|
||||
X = M[0] * x + M[1] * y + M[2] * z;
|
||||
Y = M[3] * x + M[4] * y + M[5] * z;
|
||||
Z = M[6] * x + M[7] * y + M[8] * z;
|
||||
}
|
||||
static void Unrotate(const real M[dim2_], real X, real Y, real Z,
|
||||
real& x, real& y, real& z) {
|
||||
// Perform [x,y,z]^t = M^t.[X,Y,Z]^t
|
||||
// (typically geocentric to local cartesian)
|
||||
x = M[0] * X + M[3] * Y + M[6] * Z;
|
||||
y = M[1] * X + M[4] * Y + M[7] * Z;
|
||||
z = M[2] * X + M[5] * Y + M[8] * Z;
|
||||
}
|
||||
void IntForward(real lat, real lon, real h, real& X, real& Y, real& Z,
|
||||
real M[dim2_]) const;
|
||||
void IntReverse(real X, real Y, real Z, real& lat, real& lon, real& h,
|
||||
real M[dim2_]) const;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for a ellipsoid with
|
||||
*
|
||||
* @param[in] a equatorial radius (meters).
|
||||
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
|
||||
* Negative \e f gives a prolate ellipsoid.
|
||||
* @exception GeographicErr if \e a or (1 − \e f) \e a is not
|
||||
* positive.
|
||||
**********************************************************************/
|
||||
Geocentric(real a, real f);
|
||||
|
||||
/**
|
||||
* A default constructor (for use by NormalGravity).
|
||||
**********************************************************************/
|
||||
Geocentric() : _a(-1) {}
|
||||
|
||||
/**
|
||||
* Convert from geodetic to geocentric coordinates.
|
||||
*
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[in] h height of point above the ellipsoid (meters).
|
||||
* @param[out] X geocentric coordinate (meters).
|
||||
* @param[out] Y geocentric coordinate (meters).
|
||||
* @param[out] Z geocentric coordinate (meters).
|
||||
*
|
||||
* \e lat should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
void Forward(real lat, real lon, real h, real& X, real& Y, real& Z)
|
||||
const {
|
||||
if (Init())
|
||||
IntForward(lat, lon, h, X, Y, Z, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from geodetic to geocentric coordinates and return rotation
|
||||
* matrix.
|
||||
*
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[in] h height of point above the ellipsoid (meters).
|
||||
* @param[out] X geocentric coordinate (meters).
|
||||
* @param[out] Y geocentric coordinate (meters).
|
||||
* @param[out] Z geocentric coordinate (meters).
|
||||
* @param[out] M if the length of the vector is 9, fill with the rotation
|
||||
* matrix in row-major order.
|
||||
*
|
||||
* Let \e v be a unit vector located at (\e lat, \e lon, \e h). We can
|
||||
* express \e v as \e column vectors in one of two ways
|
||||
* - in east, north, up coordinates (where the components are relative to a
|
||||
* local coordinate system at (\e lat, \e lon, \e h)); call this
|
||||
* representation \e v1.
|
||||
* - in geocentric \e X, \e Y, \e Z coordinates; call this representation
|
||||
* \e v0.
|
||||
* .
|
||||
* Then we have \e v0 = \e M ⋅ \e v1.
|
||||
**********************************************************************/
|
||||
void Forward(real lat, real lon, real h, real& X, real& Y, real& Z,
|
||||
std::vector<real>& M)
|
||||
const {
|
||||
if (!Init())
|
||||
return;
|
||||
if (M.end() == M.begin() + dim2_) {
|
||||
real t[dim2_];
|
||||
IntForward(lat, lon, h, X, Y, Z, t);
|
||||
std::copy(t, t + dim2_, M.begin());
|
||||
} else
|
||||
IntForward(lat, lon, h, X, Y, Z, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from geocentric to geodetic to coordinates.
|
||||
*
|
||||
* @param[in] X geocentric coordinate (meters).
|
||||
* @param[in] Y geocentric coordinate (meters).
|
||||
* @param[in] Z geocentric coordinate (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] h height of point above the ellipsoid (meters).
|
||||
*
|
||||
* In general, there are multiple solutions and the result which minimizes
|
||||
* |<i>h</i> |is returned, i.e., (<i>lat</i>, <i>lon</i>) corresponds to
|
||||
* the closest point on the ellipsoid. If there are still multiple
|
||||
* solutions with different latitudes (applies only if \e Z = 0), then the
|
||||
* solution with \e lat > 0 is returned. If there are still multiple
|
||||
* solutions with different longitudes (applies only if \e X = \e Y = 0)
|
||||
* then \e lon = 0 is returned. The value of \e h returned satisfies \e h
|
||||
* ≥ − \e a (1 − <i>e</i><sup>2</sup>) / sqrt(1 −
|
||||
* <i>e</i><sup>2</sup> sin<sup>2</sup>\e lat). The value of \e lon
|
||||
* returned is in the range [−180°, 180°].
|
||||
**********************************************************************/
|
||||
void Reverse(real X, real Y, real Z, real& lat, real& lon, real& h)
|
||||
const {
|
||||
if (Init())
|
||||
IntReverse(X, Y, Z, lat, lon, h, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from geocentric to geodetic to coordinates.
|
||||
*
|
||||
* @param[in] X geocentric coordinate (meters).
|
||||
* @param[in] Y geocentric coordinate (meters).
|
||||
* @param[in] Z geocentric coordinate (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] h height of point above the ellipsoid (meters).
|
||||
* @param[out] M if the length of the vector is 9, fill with the rotation
|
||||
* matrix in row-major order.
|
||||
*
|
||||
* Let \e v be a unit vector located at (\e lat, \e lon, \e h). We can
|
||||
* express \e v as \e column vectors in one of two ways
|
||||
* - in east, north, up coordinates (where the components are relative to a
|
||||
* local coordinate system at (\e lat, \e lon, \e h)); call this
|
||||
* representation \e v1.
|
||||
* - in geocentric \e X, \e Y, \e Z coordinates; call this representation
|
||||
* \e v0.
|
||||
* .
|
||||
* Then we have \e v1 = <i>M</i><sup>T</sup> ⋅ \e v0, where
|
||||
* <i>M</i><sup>T</sup> is the transpose of \e M.
|
||||
**********************************************************************/
|
||||
void Reverse(real X, real Y, real Z, real& lat, real& lon, real& h,
|
||||
std::vector<real>& M)
|
||||
const {
|
||||
if (!Init())
|
||||
return;
|
||||
if (M.end() == M.begin() + dim2_) {
|
||||
real t[dim2_];
|
||||
IntReverse(X, Y, Z, lat, lon, h, t);
|
||||
std::copy(t, t + dim2_, M.begin());
|
||||
} else
|
||||
IntReverse(X, Y, Z, lat, lon, h, NULL);
|
||||
}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return true if the object has been initialized.
|
||||
**********************************************************************/
|
||||
bool Init() const { return _a > 0; }
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const
|
||||
{ return Init() ? _a : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the
|
||||
* value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const
|
||||
{ return Init() ? _f : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* A global instantiation of Geocentric with the parameters for the WGS84
|
||||
* ellipsoid.
|
||||
**********************************************************************/
|
||||
static const Geocentric& WGS84();
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_GEOCENTRIC_HPP
|
||||
977
external/include/GeographicLib/Geodesic.hpp
vendored
Normal file
977
external/include/GeographicLib/Geodesic.hpp
vendored
Normal file
@@ -0,0 +1,977 @@
|
||||
/**
|
||||
* \file Geodesic.hpp
|
||||
* \brief Header for GeographicLib::Geodesic class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2009-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GEODESIC_HPP)
|
||||
#define GEOGRAPHICLIB_GEODESIC_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GEODESIC_ORDER)
|
||||
/**
|
||||
* The order of the expansions used by Geodesic.
|
||||
* GEOGRAPHICLIB_GEODESIC_ORDER can be set to any integer in [3, 8].
|
||||
**********************************************************************/
|
||||
# define GEOGRAPHICLIB_GEODESIC_ORDER \
|
||||
(GEOGRAPHICLIB_PRECISION == 2 ? 6 : \
|
||||
(GEOGRAPHICLIB_PRECISION == 1 ? 3 : \
|
||||
(GEOGRAPHICLIB_PRECISION == 3 ? 7 : 8)))
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
class GeodesicLine;
|
||||
|
||||
/**
|
||||
* \brief %Geodesic calculations
|
||||
*
|
||||
* The shortest path between two points on a ellipsoid at (\e lat1, \e lon1)
|
||||
* and (\e lat2, \e lon2) is called the geodesic. Its length is \e s12 and
|
||||
* the geodesic from point 1 to point 2 has azimuths \e azi1 and \e azi2 at
|
||||
* the two end points. (The azimuth is the heading measured clockwise from
|
||||
* north. \e azi2 is the "forward" azimuth, i.e., the heading that takes you
|
||||
* beyond point 2 not back to point 1.) In the figure below, latitude if
|
||||
* labeled φ, longitude λ (with λ<sub>12</sub> =
|
||||
* λ<sub>2</sub> − λ<sub>1</sub>), and azimuth α.
|
||||
*
|
||||
* <img src="https://upload.wikimedia.org/wikipedia/commons/c/cb/Geodesic_problem_on_an_ellipsoid.svg" width=250 alt="spheroidal triangle">
|
||||
*
|
||||
* Given \e lat1, \e lon1, \e azi1, and \e s12, we can determine \e lat2, \e
|
||||
* lon2, and \e azi2. This is the \e direct geodesic problem and its
|
||||
* solution is given by the function Geodesic::Direct. (If \e s12 is
|
||||
* sufficiently large that the geodesic wraps more than halfway around the
|
||||
* earth, there will be another geodesic between the points with a smaller \e
|
||||
* s12.)
|
||||
*
|
||||
* Given \e lat1, \e lon1, \e lat2, and \e lon2, we can determine \e azi1, \e
|
||||
* azi2, and \e s12. This is the \e inverse geodesic problem, whose solution
|
||||
* is given by Geodesic::Inverse. Usually, the solution to the inverse
|
||||
* problem is unique. In cases where there are multiple solutions (all with
|
||||
* the same \e s12, of course), all the solutions can be easily generated
|
||||
* once a particular solution is provided.
|
||||
*
|
||||
* The standard way of specifying the direct problem is the specify the
|
||||
* distance \e s12 to the second point. However it is sometimes useful
|
||||
* instead to specify the arc length \e a12 (in degrees) on the auxiliary
|
||||
* sphere. This is a mathematical construct used in solving the geodesic
|
||||
* problems. The solution of the direct problem in this form is provided by
|
||||
* Geodesic::ArcDirect. An arc length in excess of 180° indicates that
|
||||
* the geodesic is not a shortest path. In addition, the arc length between
|
||||
* an equatorial crossing and the next extremum of latitude for a geodesic is
|
||||
* 90°.
|
||||
*
|
||||
* This class can also calculate several other quantities related to
|
||||
* geodesics. These are:
|
||||
* - <i>reduced length</i>. If we fix the first point and increase \e azi1
|
||||
* by \e dazi1 (radians), the second point is displaced \e m12 \e dazi1 in
|
||||
* the direction \e azi2 + 90°. The quantity \e m12 is called
|
||||
* the "reduced length" and is symmetric under interchange of the two
|
||||
* points. On a curved surface the reduced length obeys a symmetry
|
||||
* relation, \e m12 + \e m21 = 0. On a flat surface, we have \e m12 = \e
|
||||
* s12. The ratio <i>s12</i>/\e m12 gives the azimuthal scale for an
|
||||
* azimuthal equidistant projection.
|
||||
* - <i>geodesic scale</i>. Consider a reference geodesic and a second
|
||||
* geodesic parallel to this one at point 1 and separated by a small
|
||||
* distance \e dt. The separation of the two geodesics at point 2 is \e
|
||||
* M12 \e dt where \e M12 is called the "geodesic scale". \e M21 is
|
||||
* defined similarly (with the geodesics being parallel at point 2). On a
|
||||
* flat surface, we have \e M12 = \e M21 = 1. The quantity 1/\e M12 gives
|
||||
* the scale of the Cassini-Soldner projection.
|
||||
* - <i>area</i>. The area between the geodesic from point 1 to point 2 and
|
||||
* the equation is represented by \e S12; it is the area, measured
|
||||
* counter-clockwise, of the geodesic quadrilateral with corners
|
||||
* (<i>lat1</i>,<i>lon1</i>), (0,<i>lon1</i>), (0,<i>lon2</i>), and
|
||||
* (<i>lat2</i>,<i>lon2</i>). It can be used to compute the area of any
|
||||
* geodesic polygon.
|
||||
*
|
||||
* Overloaded versions of Geodesic::Direct, Geodesic::ArcDirect, and
|
||||
* Geodesic::Inverse allow these quantities to be returned. In addition
|
||||
* there are general functions Geodesic::GenDirect, and Geodesic::GenInverse
|
||||
* which allow an arbitrary set of results to be computed. The quantities \e
|
||||
* m12, \e M12, \e M21 which all specify the behavior of nearby geodesics
|
||||
* obey addition rules. If points 1, 2, and 3 all lie on a single geodesic,
|
||||
* then the following rules hold:
|
||||
* - \e s13 = \e s12 + \e s23
|
||||
* - \e a13 = \e a12 + \e a23
|
||||
* - \e S13 = \e S12 + \e S23
|
||||
* - \e m13 = \e m12 \e M23 + \e m23 \e M21
|
||||
* - \e M13 = \e M12 \e M23 − (1 − \e M12 \e M21) \e m23 / \e m12
|
||||
* - \e M31 = \e M32 \e M21 − (1 − \e M23 \e M32) \e m12 / \e m23
|
||||
*
|
||||
* Additional functionality is provided by the GeodesicLine class, which
|
||||
* allows a sequence of points along a geodesic to be computed.
|
||||
*
|
||||
* The shortest distance returned by the solution of the inverse problem is
|
||||
* (obviously) uniquely defined. However, in a few special cases there are
|
||||
* multiple azimuths which yield the same shortest distance. Here is a
|
||||
* catalog of those cases:
|
||||
* - \e lat1 = −\e lat2 (with neither point at a pole). If \e azi1 =
|
||||
* \e azi2, the geodesic is unique. Otherwise there are two geodesics and
|
||||
* the second one is obtained by setting [\e azi1, \e azi2] → [\e
|
||||
* azi2, \e azi1], [\e M12, \e M21] → [\e M21, \e M12], \e S12 →
|
||||
* −\e S12. (This occurs when the longitude difference is near
|
||||
* ±180° for oblate ellipsoids.)
|
||||
* - \e lon2 = \e lon1 ± 180° (with neither point at a pole). If
|
||||
* \e azi1 = 0° or ±180°, the geodesic is unique. Otherwise
|
||||
* there are two geodesics and the second one is obtained by setting [\e
|
||||
* azi1, \e azi2] → [−\e azi1, −\e azi2], \e S12 →
|
||||
* −\e S12. (This occurs when \e lat2 is near −\e lat1 for
|
||||
* prolate ellipsoids.)
|
||||
* - Points 1 and 2 at opposite poles. There are infinitely many geodesics
|
||||
* which can be generated by setting [\e azi1, \e azi2] → [\e azi1, \e
|
||||
* azi2] + [\e d, −\e d], for arbitrary \e d. (For spheres, this
|
||||
* prescription applies when points 1 and 2 are antipodal.)
|
||||
* - \e s12 = 0 (coincident points). There are infinitely many geodesics
|
||||
* which can be generated by setting [\e azi1, \e azi2] →
|
||||
* [\e azi1, \e azi2] + [\e d, \e d], for arbitrary \e d.
|
||||
*
|
||||
* The calculations are accurate to better than 15 nm (15 nanometers) for the
|
||||
* WGS84 ellipsoid. See Sec. 9 of
|
||||
* <a href="https://arxiv.org/abs/1102.1215v1">arXiv:1102.1215v1</a> for
|
||||
* details. The algorithms used by this class are based on series expansions
|
||||
* using the flattening \e f as a small parameter. These are only accurate
|
||||
* for |<i>f</i>| < 0.02; however reasonably accurate results will be
|
||||
* obtained for |<i>f</i>| < 0.2. Here is a table of the approximate
|
||||
* maximum error (expressed as a distance) for an ellipsoid with the same
|
||||
* equatorial radius as the WGS84 ellipsoid and different values of the
|
||||
* flattening.<pre>
|
||||
* |f| error
|
||||
* 0.01 25 nm
|
||||
* 0.02 30 nm
|
||||
* 0.05 10 um
|
||||
* 0.1 1.5 mm
|
||||
* 0.2 300 mm
|
||||
* </pre>
|
||||
* For very eccentric ellipsoids, use GeodesicExact instead.
|
||||
*
|
||||
* The algorithms are described in
|
||||
* - C. F. F. Karney,
|
||||
* <a href="https://doi.org/10.1007/s00190-012-0578-z">
|
||||
* Algorithms for geodesics</a>,
|
||||
* J. Geodesy <b>87</b>, 43--55 (2013);
|
||||
* DOI: <a href="https://doi.org/10.1007/s00190-012-0578-z">
|
||||
* 10.1007/s00190-012-0578-z</a>;
|
||||
* addenda:
|
||||
* <a href="https://geographiclib.sourceforge.io/geod-addenda.html">
|
||||
* geod-addenda.html</a>.
|
||||
* .
|
||||
* For more information on geodesics see \ref geodesic.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-Geodesic.cpp
|
||||
*
|
||||
* <a href="GeodSolve.1.html">GeodSolve</a> is a command-line utility
|
||||
* providing access to the functionality of Geodesic and GeodesicLine.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT Geodesic {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
friend class GeodesicLine;
|
||||
static const int nA1_ = GEOGRAPHICLIB_GEODESIC_ORDER;
|
||||
static const int nC1_ = GEOGRAPHICLIB_GEODESIC_ORDER;
|
||||
static const int nC1p_ = GEOGRAPHICLIB_GEODESIC_ORDER;
|
||||
static const int nA2_ = GEOGRAPHICLIB_GEODESIC_ORDER;
|
||||
static const int nC2_ = GEOGRAPHICLIB_GEODESIC_ORDER;
|
||||
static const int nA3_ = GEOGRAPHICLIB_GEODESIC_ORDER;
|
||||
static const int nA3x_ = nA3_;
|
||||
static const int nC3_ = GEOGRAPHICLIB_GEODESIC_ORDER;
|
||||
static const int nC3x_ = (nC3_ * (nC3_ - 1)) / 2;
|
||||
static const int nC4_ = GEOGRAPHICLIB_GEODESIC_ORDER;
|
||||
static const int nC4x_ = (nC4_ * (nC4_ + 1)) / 2;
|
||||
// Size for temporary array
|
||||
// nC = max(max(nC1_, nC1p_, nC2_) + 1, max(nC3_, nC4_))
|
||||
static const int nC_ = GEOGRAPHICLIB_GEODESIC_ORDER + 1;
|
||||
static const unsigned maxit1_ = 20;
|
||||
unsigned maxit2_;
|
||||
real tiny_, tol0_, tol1_, tol2_, tolb_, xthresh_;
|
||||
|
||||
enum captype {
|
||||
CAP_NONE = 0U,
|
||||
CAP_C1 = 1U<<0,
|
||||
CAP_C1p = 1U<<1,
|
||||
CAP_C2 = 1U<<2,
|
||||
CAP_C3 = 1U<<3,
|
||||
CAP_C4 = 1U<<4,
|
||||
CAP_ALL = 0x1FU,
|
||||
CAP_MASK = CAP_ALL,
|
||||
OUT_ALL = 0x7F80U,
|
||||
OUT_MASK = 0xFF80U, // Includes LONG_UNROLL
|
||||
};
|
||||
|
||||
static real SinCosSeries(bool sinp,
|
||||
real sinx, real cosx, const real c[], int n);
|
||||
static real Astroid(real x, real y);
|
||||
|
||||
real _a, _f, _f1, _e2, _ep2, _n, _b, _c2, _etol2;
|
||||
real _A3x[nA3x_], _C3x[nC3x_], _C4x[nC4x_];
|
||||
|
||||
void Lengths(real eps, real sig12,
|
||||
real ssig1, real csig1, real dn1,
|
||||
real ssig2, real csig2, real dn2,
|
||||
real cbet1, real cbet2, unsigned outmask,
|
||||
real& s12s, real& m12a, real& m0,
|
||||
real& M12, real& M21, real Ca[]) const;
|
||||
real InverseStart(real sbet1, real cbet1, real dn1,
|
||||
real sbet2, real cbet2, real dn2,
|
||||
real lam12, real slam12, real clam12,
|
||||
real& salp1, real& calp1,
|
||||
real& salp2, real& calp2, real& dnm,
|
||||
real Ca[]) const;
|
||||
real Lambda12(real sbet1, real cbet1, real dn1,
|
||||
real sbet2, real cbet2, real dn2,
|
||||
real salp1, real calp1, real slam120, real clam120,
|
||||
real& salp2, real& calp2, real& sig12,
|
||||
real& ssig1, real& csig1, real& ssig2, real& csig2,
|
||||
real& eps, real& domg12,
|
||||
bool diffp, real& dlam12, real Ca[]) const;
|
||||
real GenInverse(real lat1, real lon1, real lat2, real lon2,
|
||||
unsigned outmask, real& s12,
|
||||
real& salp1, real& calp1, real& salp2, real& calp2,
|
||||
real& m12, real& M12, real& M21, real& S12) const;
|
||||
|
||||
// These are Maxima generated functions to provide series approximations to
|
||||
// the integrals for the ellipsoidal geodesic.
|
||||
static real A1m1f(real eps);
|
||||
static void C1f(real eps, real c[]);
|
||||
static void C1pf(real eps, real c[]);
|
||||
static real A2m1f(real eps);
|
||||
static void C2f(real eps, real c[]);
|
||||
|
||||
void A3coeff();
|
||||
real A3f(real eps) const;
|
||||
void C3coeff();
|
||||
void C3f(real eps, real c[]) const;
|
||||
void C4coeff();
|
||||
void C4f(real k2, real c[]) const;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Bit masks for what calculations to do. These masks do double duty.
|
||||
* They signify to the GeodesicLine::GeodesicLine constructor and to
|
||||
* Geodesic::Line what capabilities should be included in the GeodesicLine
|
||||
* object. They also specify which results to return in the general
|
||||
* routines Geodesic::GenDirect and Geodesic::GenInverse routines.
|
||||
* GeodesicLine::mask is a duplication of this enum.
|
||||
**********************************************************************/
|
||||
enum mask {
|
||||
/**
|
||||
* No capabilities, no output.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
NONE = 0U,
|
||||
/**
|
||||
* Calculate latitude \e lat2. (It's not necessary to include this as a
|
||||
* capability to GeodesicLine because this is included by default.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LATITUDE = 1U<<7 | CAP_NONE,
|
||||
/**
|
||||
* Calculate longitude \e lon2.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONGITUDE = 1U<<8 | CAP_C3,
|
||||
/**
|
||||
* Calculate azimuths \e azi1 and \e azi2. (It's not necessary to
|
||||
* include this as a capability to GeodesicLine because this is included
|
||||
* by default.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AZIMUTH = 1U<<9 | CAP_NONE,
|
||||
/**
|
||||
* Calculate distance \e s12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DISTANCE = 1U<<10 | CAP_C1,
|
||||
/**
|
||||
* Allow distance \e s12 to be used as input in the direct geodesic
|
||||
* problem.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DISTANCE_IN = 1U<<11 | CAP_C1 | CAP_C1p,
|
||||
/**
|
||||
* Calculate reduced length \e m12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
REDUCEDLENGTH = 1U<<12 | CAP_C1 | CAP_C2,
|
||||
/**
|
||||
* Calculate geodesic scales \e M12 and \e M21.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
GEODESICSCALE = 1U<<13 | CAP_C1 | CAP_C2,
|
||||
/**
|
||||
* Calculate area \e S12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AREA = 1U<<14 | CAP_C4,
|
||||
/**
|
||||
* Unroll \e lon2 in the direct calculation.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONG_UNROLL = 1U<<15,
|
||||
/**
|
||||
* All capabilities, calculate everything. (LONG_UNROLL is not
|
||||
* included in this mask.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
ALL = OUT_ALL| CAP_ALL,
|
||||
};
|
||||
|
||||
/** \name Constructor
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Constructor for a ellipsoid with
|
||||
*
|
||||
* @param[in] a equatorial radius (meters).
|
||||
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
|
||||
* Negative \e f gives a prolate ellipsoid.
|
||||
* @exception GeographicErr if \e a or (1 − \e f) \e a is not
|
||||
* positive.
|
||||
**********************************************************************/
|
||||
Geodesic(real a, real f);
|
||||
///@}
|
||||
|
||||
/** \name Direct geodesic problem specified in terms of distance.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Solve the direct geodesic problem where the length of the geodesic
|
||||
* is specified in terms of distance.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] s12 distance between point 1 and point 2 (meters); it can be
|
||||
* negative.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees).
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] m12 reduced length of geodesic (meters).
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless).
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless).
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
|
||||
* @return \e a12 arc length of between point 1 and point 2 (degrees).
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°]. The values of
|
||||
* \e lon2 and \e azi2 returned are in the range [−180°,
|
||||
* 180°].
|
||||
*
|
||||
* If either point is at a pole, the azimuth is defined by keeping the
|
||||
* longitude fixed, writing \e lat = ±(90° − ε),
|
||||
* and taking the limit ε → 0+. An arc length greater that
|
||||
* 180° signifies a geodesic which is not a shortest path. (For a
|
||||
* prolate ellipsoid, an additional condition is necessary for a shortest
|
||||
* path: the longitudinal extent must not exceed of 180°.)
|
||||
*
|
||||
* The following functions are overloaded versions of Geodesic::Direct
|
||||
* which omit some of the output parameters. Note, however, that the arc
|
||||
* length is always computed and returned as the function value.
|
||||
**********************************************************************/
|
||||
Math::real Direct(real lat1, real lon1, real azi1, real s12,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& m12, real& M12, real& M21, real& S12)
|
||||
const {
|
||||
real t;
|
||||
return GenDirect(lat1, lon1, azi1, false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
REDUCEDLENGTH | GEODESICSCALE | AREA,
|
||||
lat2, lon2, azi2, t, m12, M12, M21, S12);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::Direct.
|
||||
**********************************************************************/
|
||||
Math::real Direct(real lat1, real lon1, real azi1, real s12,
|
||||
real& lat2, real& lon2)
|
||||
const {
|
||||
real t;
|
||||
return GenDirect(lat1, lon1, azi1, false, s12,
|
||||
LATITUDE | LONGITUDE,
|
||||
lat2, lon2, t, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::Direct.
|
||||
**********************************************************************/
|
||||
Math::real Direct(real lat1, real lon1, real azi1, real s12,
|
||||
real& lat2, real& lon2, real& azi2)
|
||||
const {
|
||||
real t;
|
||||
return GenDirect(lat1, lon1, azi1, false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH,
|
||||
lat2, lon2, azi2, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::Direct.
|
||||
**********************************************************************/
|
||||
Math::real Direct(real lat1, real lon1, real azi1, real s12,
|
||||
real& lat2, real& lon2, real& azi2, real& m12)
|
||||
const {
|
||||
real t;
|
||||
return GenDirect(lat1, lon1, azi1, false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH,
|
||||
lat2, lon2, azi2, t, m12, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::Direct.
|
||||
**********************************************************************/
|
||||
Math::real Direct(real lat1, real lon1, real azi1, real s12,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& M12, real& M21)
|
||||
const {
|
||||
real t;
|
||||
return GenDirect(lat1, lon1, azi1, false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | GEODESICSCALE,
|
||||
lat2, lon2, azi2, t, t, M12, M21, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::Direct.
|
||||
**********************************************************************/
|
||||
Math::real Direct(real lat1, real lon1, real azi1, real s12,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& m12, real& M12, real& M21)
|
||||
const {
|
||||
real t;
|
||||
return GenDirect(lat1, lon1, azi1, false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
REDUCEDLENGTH | GEODESICSCALE,
|
||||
lat2, lon2, azi2, t, m12, M12, M21, t);
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name Direct geodesic problem specified in terms of arc length.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Solve the direct geodesic problem where the length of the geodesic
|
||||
* is specified in terms of arc length.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] a12 arc length between point 1 and point 2 (degrees); it can
|
||||
* be negative.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees).
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] s12 distance between point 1 and point 2 (meters).
|
||||
* @param[out] m12 reduced length of geodesic (meters).
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless).
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless).
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°]. The values of
|
||||
* \e lon2 and \e azi2 returned are in the range [−180°,
|
||||
* 180°].
|
||||
*
|
||||
* If either point is at a pole, the azimuth is defined by keeping the
|
||||
* longitude fixed, writing \e lat = ±(90° − ε),
|
||||
* and taking the limit ε → 0+. An arc length greater that
|
||||
* 180° signifies a geodesic which is not a shortest path. (For a
|
||||
* prolate ellipsoid, an additional condition is necessary for a shortest
|
||||
* path: the longitudinal extent must not exceed of 180°.)
|
||||
*
|
||||
* The following functions are overloaded versions of Geodesic::Direct
|
||||
* which omit some of the output parameters.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2, real& azi2, real& s12,
|
||||
real& m12, real& M12, real& M21, real& S12)
|
||||
const {
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
|
||||
REDUCEDLENGTH | GEODESICSCALE | AREA,
|
||||
lat2, lon2, azi2, s12, m12, M12, M21, S12);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::ArcDirect.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2) const {
|
||||
real t;
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE,
|
||||
lat2, lon2, t, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::ArcDirect.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2, real& azi2) const {
|
||||
real t;
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH,
|
||||
lat2, lon2, azi2, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::ArcDirect.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2, real& azi2, real& s12)
|
||||
const {
|
||||
real t;
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE,
|
||||
lat2, lon2, azi2, s12, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::ArcDirect.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& m12) const {
|
||||
real t;
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
|
||||
REDUCEDLENGTH,
|
||||
lat2, lon2, azi2, s12, m12, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::ArcDirect.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2, real& azi2, real& s12,
|
||||
real& M12, real& M21) const {
|
||||
real t;
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
|
||||
GEODESICSCALE,
|
||||
lat2, lon2, azi2, s12, t, M12, M21, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::ArcDirect.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2, real& azi2, real& s12,
|
||||
real& m12, real& M12, real& M21) const {
|
||||
real t;
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
|
||||
REDUCEDLENGTH | GEODESICSCALE,
|
||||
lat2, lon2, azi2, s12, m12, M12, M21, t);
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name General version of the direct geodesic solution.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* The general direct geodesic problem. Geodesic::Direct and
|
||||
* Geodesic::ArcDirect are defined in terms of this function.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] arcmode boolean flag determining the meaning of the \e
|
||||
* s12_a12.
|
||||
* @param[in] s12_a12 if \e arcmode is false, this is the distance between
|
||||
* point 1 and point 2 (meters); otherwise it is the arc length between
|
||||
* point 1 and point 2 (degrees); it can be negative.
|
||||
* @param[in] outmask a bitor'ed combination of Geodesic::mask values
|
||||
* specifying which of the following parameters should be set.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees).
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] s12 distance between point 1 and point 2 (meters).
|
||||
* @param[out] m12 reduced length of geodesic (meters).
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless).
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless).
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
|
||||
* @return \e a12 arc length of between point 1 and point 2 (degrees).
|
||||
*
|
||||
* The Geodesic::mask values possible for \e outmask are
|
||||
* - \e outmask |= Geodesic::LATITUDE for the latitude \e lat2;
|
||||
* - \e outmask |= Geodesic::LONGITUDE for the latitude \e lon2;
|
||||
* - \e outmask |= Geodesic::AZIMUTH for the latitude \e azi2;
|
||||
* - \e outmask |= Geodesic::DISTANCE for the distance \e s12;
|
||||
* - \e outmask |= Geodesic::REDUCEDLENGTH for the reduced length \e
|
||||
* m12;
|
||||
* - \e outmask |= Geodesic::GEODESICSCALE for the geodesic scales \e
|
||||
* M12 and \e M21;
|
||||
* - \e outmask |= Geodesic::AREA for the area \e S12;
|
||||
* - \e outmask |= Geodesic::ALL for all of the above;
|
||||
* - \e outmask |= Geodesic::LONG_UNROLL to unroll \e lon2 instead of
|
||||
* wrapping it into the range [−180°, 180°].
|
||||
* .
|
||||
* The function value \e a12 is always computed and returned and this
|
||||
* equals \e s12_a12 is \e arcmode is true. If \e outmask includes
|
||||
* Geodesic::DISTANCE and \e arcmode is false, then \e s12 = \e s12_a12.
|
||||
* It is not necessary to include Geodesic::DISTANCE_IN in \e outmask; this
|
||||
* is automatically included is \e arcmode is false.
|
||||
*
|
||||
* With the Geodesic::LONG_UNROLL bit set, the quantity \e lon2 − \e
|
||||
* lon1 indicates how many times and in what sense the geodesic encircles
|
||||
* the ellipsoid.
|
||||
**********************************************************************/
|
||||
Math::real GenDirect(real lat1, real lon1, real azi1,
|
||||
bool arcmode, real s12_a12, unsigned outmask,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& m12, real& M12, real& M21,
|
||||
real& S12) const;
|
||||
///@}
|
||||
|
||||
/** \name Inverse geodesic problem.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Solve the inverse geodesic problem.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] lat2 latitude of point 2 (degrees).
|
||||
* @param[in] lon2 longitude of point 2 (degrees).
|
||||
* @param[out] s12 distance between point 1 and point 2 (meters).
|
||||
* @param[out] azi1 azimuth at point 1 (degrees).
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] m12 reduced length of geodesic (meters).
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless).
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless).
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
|
||||
* @return \e a12 arc length of between point 1 and point 2 (degrees).
|
||||
*
|
||||
* \e lat1 and \e lat2 should be in the range [−90°, 90°].
|
||||
* The values of \e azi1 and \e azi2 returned are in the range
|
||||
* [−180°, 180°].
|
||||
*
|
||||
* If either point is at a pole, the azimuth is defined by keeping the
|
||||
* longitude fixed, writing \e lat = ±(90° − ε),
|
||||
* and taking the limit ε → 0+.
|
||||
*
|
||||
* The solution to the inverse problem is found using Newton's method. If
|
||||
* this fails to converge (this is very unlikely in geodetic applications
|
||||
* but does occur for very eccentric ellipsoids), then the bisection method
|
||||
* is used to refine the solution.
|
||||
*
|
||||
* The following functions are overloaded versions of Geodesic::Inverse
|
||||
* which omit some of the output parameters. Note, however, that the arc
|
||||
* length is always computed and returned as the function value.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12, real& azi1, real& azi2, real& m12,
|
||||
real& M12, real& M21, real& S12) const {
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
DISTANCE | AZIMUTH |
|
||||
REDUCEDLENGTH | GEODESICSCALE | AREA,
|
||||
s12, azi1, azi2, m12, M12, M21, S12);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::Inverse.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12) const {
|
||||
real t;
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
DISTANCE,
|
||||
s12, t, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::Inverse.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& azi1, real& azi2) const {
|
||||
real t;
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
AZIMUTH,
|
||||
t, azi1, azi2, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::Inverse.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12, real& azi1, real& azi2)
|
||||
const {
|
||||
real t;
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
DISTANCE | AZIMUTH,
|
||||
s12, azi1, azi2, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::Inverse.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12, real& azi1, real& azi2, real& m12)
|
||||
const {
|
||||
real t;
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
DISTANCE | AZIMUTH | REDUCEDLENGTH,
|
||||
s12, azi1, azi2, m12, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::Inverse.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12, real& azi1, real& azi2,
|
||||
real& M12, real& M21) const {
|
||||
real t;
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
DISTANCE | AZIMUTH | GEODESICSCALE,
|
||||
s12, azi1, azi2, t, M12, M21, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for Geodesic::Inverse.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12, real& azi1, real& azi2, real& m12,
|
||||
real& M12, real& M21) const {
|
||||
real t;
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
DISTANCE | AZIMUTH |
|
||||
REDUCEDLENGTH | GEODESICSCALE,
|
||||
s12, azi1, azi2, m12, M12, M21, t);
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name General version of inverse geodesic solution.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* The general inverse geodesic calculation. Geodesic::Inverse is defined
|
||||
* in terms of this function.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] lat2 latitude of point 2 (degrees).
|
||||
* @param[in] lon2 longitude of point 2 (degrees).
|
||||
* @param[in] outmask a bitor'ed combination of Geodesic::mask values
|
||||
* specifying which of the following parameters should be set.
|
||||
* @param[out] s12 distance between point 1 and point 2 (meters).
|
||||
* @param[out] azi1 azimuth at point 1 (degrees).
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] m12 reduced length of geodesic (meters).
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless).
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless).
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
|
||||
* @return \e a12 arc length of between point 1 and point 2 (degrees).
|
||||
*
|
||||
* The Geodesic::mask values possible for \e outmask are
|
||||
* - \e outmask |= Geodesic::DISTANCE for the distance \e s12;
|
||||
* - \e outmask |= Geodesic::AZIMUTH for the latitude \e azi2;
|
||||
* - \e outmask |= Geodesic::REDUCEDLENGTH for the reduced length \e
|
||||
* m12;
|
||||
* - \e outmask |= Geodesic::GEODESICSCALE for the geodesic scales \e
|
||||
* M12 and \e M21;
|
||||
* - \e outmask |= Geodesic::AREA for the area \e S12;
|
||||
* - \e outmask |= Geodesic::ALL for all of the above.
|
||||
* .
|
||||
* The arc length is always computed and returned as the function value.
|
||||
**********************************************************************/
|
||||
Math::real GenInverse(real lat1, real lon1, real lat2, real lon2,
|
||||
unsigned outmask,
|
||||
real& s12, real& azi1, real& azi2,
|
||||
real& m12, real& M12, real& M21, real& S12) const;
|
||||
///@}
|
||||
|
||||
/** \name Interface to GeodesicLine.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Set up to compute several points on a single geodesic.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] caps bitor'ed combination of Geodesic::mask values
|
||||
* specifying the capabilities the GeodesicLine object should possess,
|
||||
* i.e., which quantities can be returned in calls to
|
||||
* GeodesicLine::Position.
|
||||
* @return a GeodesicLine object.
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°].
|
||||
*
|
||||
* The Geodesic::mask values are
|
||||
* - \e caps |= Geodesic::LATITUDE for the latitude \e lat2; this is
|
||||
* added automatically;
|
||||
* - \e caps |= Geodesic::LONGITUDE for the latitude \e lon2;
|
||||
* - \e caps |= Geodesic::AZIMUTH for the azimuth \e azi2; this is
|
||||
* added automatically;
|
||||
* - \e caps |= Geodesic::DISTANCE for the distance \e s12;
|
||||
* - \e caps |= Geodesic::REDUCEDLENGTH for the reduced length \e m12;
|
||||
* - \e caps |= Geodesic::GEODESICSCALE for the geodesic scales \e M12
|
||||
* and \e M21;
|
||||
* - \e caps |= Geodesic::AREA for the area \e S12;
|
||||
* - \e caps |= Geodesic::DISTANCE_IN permits the length of the
|
||||
* geodesic to be given in terms of \e s12; without this capability the
|
||||
* length can only be specified in terms of arc length;
|
||||
* - \e caps |= Geodesic::ALL for all of the above.
|
||||
* .
|
||||
* The default value of \e caps is Geodesic::ALL.
|
||||
*
|
||||
* If the point is at a pole, the azimuth is defined by keeping \e lon1
|
||||
* fixed, writing \e lat1 = ±(90 − ε), and taking the
|
||||
* limit ε → 0+.
|
||||
**********************************************************************/
|
||||
GeodesicLine Line(real lat1, real lon1, real azi1, unsigned caps = ALL)
|
||||
const;
|
||||
|
||||
/**
|
||||
* Define a GeodesicLine in terms of the inverse geodesic problem.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] lat2 latitude of point 2 (degrees).
|
||||
* @param[in] lon2 longitude of point 2 (degrees).
|
||||
* @param[in] caps bitor'ed combination of Geodesic::mask values
|
||||
* specifying the capabilities the GeodesicLine object should possess,
|
||||
* i.e., which quantities can be returned in calls to
|
||||
* GeodesicLine::Position.
|
||||
* @return a GeodesicLine object.
|
||||
*
|
||||
* This function sets point 3 of the GeodesicLine to correspond to point 2
|
||||
* of the inverse geodesic problem.
|
||||
*
|
||||
* \e lat1 and \e lat2 should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
GeodesicLine InverseLine(real lat1, real lon1, real lat2, real lon2,
|
||||
unsigned caps = ALL) const;
|
||||
|
||||
/**
|
||||
* Define a GeodesicLine in terms of the direct geodesic problem specified
|
||||
* in terms of distance.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] s12 distance between point 1 and point 2 (meters); it can be
|
||||
* negative.
|
||||
* @param[in] caps bitor'ed combination of Geodesic::mask values
|
||||
* specifying the capabilities the GeodesicLine object should possess,
|
||||
* i.e., which quantities can be returned in calls to
|
||||
* GeodesicLine::Position.
|
||||
* @return a GeodesicLine object.
|
||||
*
|
||||
* This function sets point 3 of the GeodesicLine to correspond to point 2
|
||||
* of the direct geodesic problem.
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
GeodesicLine DirectLine(real lat1, real lon1, real azi1, real s12,
|
||||
unsigned caps = ALL) const;
|
||||
|
||||
/**
|
||||
* Define a GeodesicLine in terms of the direct geodesic problem specified
|
||||
* in terms of arc length.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] a12 arc length between point 1 and point 2 (degrees); it can
|
||||
* be negative.
|
||||
* @param[in] caps bitor'ed combination of Geodesic::mask values
|
||||
* specifying the capabilities the GeodesicLine object should possess,
|
||||
* i.e., which quantities can be returned in calls to
|
||||
* GeodesicLine::Position.
|
||||
* @return a GeodesicLine object.
|
||||
*
|
||||
* This function sets point 3 of the GeodesicLine to correspond to point 2
|
||||
* of the direct geodesic problem.
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
GeodesicLine ArcDirectLine(real lat1, real lon1, real azi1, real a12,
|
||||
unsigned caps = ALL) const;
|
||||
|
||||
/**
|
||||
* Define a GeodesicLine in terms of the direct geodesic problem specified
|
||||
* in terms of either distance or arc length.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] arcmode boolean flag determining the meaning of the \e
|
||||
* s12_a12.
|
||||
* @param[in] s12_a12 if \e arcmode is false, this is the distance between
|
||||
* point 1 and point 2 (meters); otherwise it is the arc length between
|
||||
* point 1 and point 2 (degrees); it can be negative.
|
||||
* @param[in] caps bitor'ed combination of Geodesic::mask values
|
||||
* specifying the capabilities the GeodesicLine object should possess,
|
||||
* i.e., which quantities can be returned in calls to
|
||||
* GeodesicLine::Position.
|
||||
* @return a GeodesicLine object.
|
||||
*
|
||||
* This function sets point 3 of the GeodesicLine to correspond to point 2
|
||||
* of the direct geodesic problem.
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
GeodesicLine GenDirectLine(real lat1, real lon1, real azi1,
|
||||
bool arcmode, real s12_a12,
|
||||
unsigned caps = ALL) const;
|
||||
///@}
|
||||
|
||||
/** \name Inspector functions.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _a; }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the
|
||||
* value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _f; }
|
||||
|
||||
/**
|
||||
* @return total area of ellipsoid in meters<sup>2</sup>. The area of a
|
||||
* polygon encircling a pole can be found by adding
|
||||
* Geodesic::EllipsoidArea()/2 to the sum of \e S12 for each side of the
|
||||
* polygon.
|
||||
**********************************************************************/
|
||||
Math::real EllipsoidArea() const
|
||||
{ return 4 * Math::pi() * _c2; }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* A global instantiation of Geodesic with the parameters for the WGS84
|
||||
* ellipsoid.
|
||||
**********************************************************************/
|
||||
static const Geodesic& WGS84();
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_GEODESIC_HPP
|
||||
869
external/include/GeographicLib/GeodesicExact.hpp
vendored
Normal file
869
external/include/GeographicLib/GeodesicExact.hpp
vendored
Normal file
@@ -0,0 +1,869 @@
|
||||
/**
|
||||
* \file GeodesicExact.hpp
|
||||
* \brief Header for GeographicLib::GeodesicExact class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2012-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GEODESICEXACT_HPP)
|
||||
#define GEOGRAPHICLIB_GEODESICEXACT_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/EllipticFunction.hpp>
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GEODESICEXACT_ORDER)
|
||||
/**
|
||||
* The order of the expansions used by GeodesicExact.
|
||||
**********************************************************************/
|
||||
# define GEOGRAPHICLIB_GEODESICEXACT_ORDER 30
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
class GeodesicLineExact;
|
||||
|
||||
/**
|
||||
* \brief Exact geodesic calculations
|
||||
*
|
||||
* The equations for geodesics on an ellipsoid can be expressed in terms of
|
||||
* incomplete elliptic integrals. The Geodesic class expands these integrals
|
||||
* in a series in the flattening \e f and this provides an accurate solution
|
||||
* for \e f ∈ [-0.01, 0.01]. The GeodesicExact class computes the
|
||||
* ellitpic integrals directly and so provides a solution which is valid for
|
||||
* all \e f. However, in practice, its use should be limited to about
|
||||
* <i>b</i>/\e a ∈ [0.01, 100] or \e f ∈ [−99, 0.99].
|
||||
*
|
||||
* For the WGS84 ellipsoid, these classes are 2--3 times \e slower than the
|
||||
* series solution and 2--3 times \e less \e accurate (because it's less easy
|
||||
* to control round-off errors with the elliptic integral formulation); i.e.,
|
||||
* the error is about 40 nm (40 nanometers) instead of 15 nm. However the
|
||||
* error in the series solution scales as <i>f</i><sup>7</sup> while the
|
||||
* error in the elliptic integral solution depends weakly on \e f. If the
|
||||
* quarter meridian distance is 10000 km and the ratio <i>b</i>/\e a = 1
|
||||
* − \e f is varied then the approximate maximum error (expressed as a
|
||||
* distance) is <pre>
|
||||
* 1 - f error (nm)
|
||||
* 1/128 387
|
||||
* 1/64 345
|
||||
* 1/32 269
|
||||
* 1/16 210
|
||||
* 1/8 115
|
||||
* 1/4 69
|
||||
* 1/2 36
|
||||
* 1 15
|
||||
* 2 25
|
||||
* 4 96
|
||||
* 8 318
|
||||
* 16 985
|
||||
* 32 2352
|
||||
* 64 6008
|
||||
* 128 19024
|
||||
* </pre>
|
||||
*
|
||||
* The computation of the area in these classes is via a 30th order series.
|
||||
* This gives accurate results for <i>b</i>/\e a ∈ [1/2, 2]; the
|
||||
* accuracy is about 8 decimal digits for <i>b</i>/\e a ∈ [1/4, 4].
|
||||
*
|
||||
* See \ref geodellip for the formulation. See the documentation on the
|
||||
* Geodesic class for additional information on the geodesic problems.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-GeodesicExact.cpp
|
||||
*
|
||||
* <a href="GeodSolve.1.html">GeodSolve</a> is a command-line utility
|
||||
* providing access to the functionality of GeodesicExact and
|
||||
* GeodesicLineExact (via the -E option).
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT GeodesicExact {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
friend class GeodesicLineExact;
|
||||
static const int nC4_ = GEOGRAPHICLIB_GEODESICEXACT_ORDER;
|
||||
static const int nC4x_ = (nC4_ * (nC4_ + 1)) / 2;
|
||||
static const unsigned maxit1_ = 20;
|
||||
unsigned maxit2_;
|
||||
real tiny_, tol0_, tol1_, tol2_, tolb_, xthresh_;
|
||||
|
||||
enum captype {
|
||||
CAP_NONE = 0U,
|
||||
CAP_E = 1U<<0,
|
||||
// Skip 1U<<1 for compatibility with Geodesic (not required)
|
||||
CAP_D = 1U<<2,
|
||||
CAP_H = 1U<<3,
|
||||
CAP_C4 = 1U<<4,
|
||||
CAP_ALL = 0x1FU,
|
||||
CAP_MASK = CAP_ALL,
|
||||
OUT_ALL = 0x7F80U,
|
||||
OUT_MASK = 0xFF80U, // Includes LONG_UNROLL
|
||||
};
|
||||
|
||||
static real CosSeries(real sinx, real cosx, const real c[], int n);
|
||||
static real Astroid(real x, real y);
|
||||
|
||||
real _a, _f, _f1, _e2, _ep2, _n, _b, _c2, _etol2;
|
||||
real _C4x[nC4x_];
|
||||
|
||||
void Lengths(const EllipticFunction& E,
|
||||
real sig12,
|
||||
real ssig1, real csig1, real dn1,
|
||||
real ssig2, real csig2, real dn2,
|
||||
real cbet1, real cbet2, unsigned outmask,
|
||||
real& s12s, real& m12a, real& m0,
|
||||
real& M12, real& M21) const;
|
||||
real InverseStart(EllipticFunction& E,
|
||||
real sbet1, real cbet1, real dn1,
|
||||
real sbet2, real cbet2, real dn2,
|
||||
real lam12, real slam12, real clam12,
|
||||
real& salp1, real& calp1,
|
||||
real& salp2, real& calp2, real& dnm) const;
|
||||
real Lambda12(real sbet1, real cbet1, real dn1,
|
||||
real sbet2, real cbet2, real dn2,
|
||||
real salp1, real calp1, real slam120, real clam120,
|
||||
real& salp2, real& calp2, real& sig12,
|
||||
real& ssig1, real& csig1, real& ssig2, real& csig2,
|
||||
EllipticFunction& E,
|
||||
real& domg12, bool diffp, real& dlam12) const;
|
||||
real GenInverse(real lat1, real lon1, real lat2, real lon2,
|
||||
unsigned outmask, real& s12,
|
||||
real& salp1, real& calp1, real& salp2, real& calp2,
|
||||
real& m12, real& M12, real& M21, real& S12) const;
|
||||
|
||||
// These are Maxima generated functions to provide series approximations to
|
||||
// the integrals for the area.
|
||||
void C4coeff();
|
||||
void C4f(real k2, real c[]) const;
|
||||
// Large coefficients are split so that lo contains the low 52 bits and hi
|
||||
// the rest. This choice avoids double rounding with doubles and higher
|
||||
// precision types. float coefficients will suffer double rounding;
|
||||
// however the accuracy is already lousy for floats.
|
||||
static Math::real reale(long long hi, long long lo) {
|
||||
using std::ldexp;
|
||||
return ldexp(real(hi), 52) + lo;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Bit masks for what calculations to do. These masks do double duty.
|
||||
* They signify to the GeodesicLineExact::GeodesicLineExact constructor and
|
||||
* to GeodesicExact::Line what capabilities should be included in the
|
||||
* GeodesicLineExact object. They also specify which results to return in
|
||||
* the general routines GeodesicExact::GenDirect and
|
||||
* GeodesicExact::GenInverse routines. GeodesicLineExact::mask is a
|
||||
* duplication of this enum.
|
||||
**********************************************************************/
|
||||
enum mask {
|
||||
/**
|
||||
* No capabilities, no output.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
NONE = 0U,
|
||||
/**
|
||||
* Calculate latitude \e lat2. (It's not necessary to include this as a
|
||||
* capability to GeodesicLineExact because this is included by default.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LATITUDE = 1U<<7 | CAP_NONE,
|
||||
/**
|
||||
* Calculate longitude \e lon2.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONGITUDE = 1U<<8 | CAP_H,
|
||||
/**
|
||||
* Calculate azimuths \e azi1 and \e azi2. (It's not necessary to
|
||||
* include this as a capability to GeodesicLineExact because this is
|
||||
* included by default.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AZIMUTH = 1U<<9 | CAP_NONE,
|
||||
/**
|
||||
* Calculate distance \e s12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DISTANCE = 1U<<10 | CAP_E,
|
||||
/**
|
||||
* Allow distance \e s12 to be used as input in the direct geodesic
|
||||
* problem.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DISTANCE_IN = 1U<<11 | CAP_E,
|
||||
/**
|
||||
* Calculate reduced length \e m12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
REDUCEDLENGTH = 1U<<12 | CAP_D,
|
||||
/**
|
||||
* Calculate geodesic scales \e M12 and \e M21.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
GEODESICSCALE = 1U<<13 | CAP_D,
|
||||
/**
|
||||
* Calculate area \e S12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AREA = 1U<<14 | CAP_C4,
|
||||
/**
|
||||
* Unroll \e lon2 in the direct calculation.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONG_UNROLL = 1U<<15,
|
||||
/**
|
||||
* All capabilities, calculate everything. (LONG_UNROLL is not
|
||||
* included in this mask.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
ALL = OUT_ALL| CAP_ALL,
|
||||
};
|
||||
|
||||
/** \name Constructor
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Constructor for a ellipsoid with
|
||||
*
|
||||
* @param[in] a equatorial radius (meters).
|
||||
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
|
||||
* Negative \e f gives a prolate ellipsoid.
|
||||
* @exception GeographicErr if \e a or (1 − \e f) \e a is not
|
||||
* positive.
|
||||
**********************************************************************/
|
||||
GeodesicExact(real a, real f);
|
||||
///@}
|
||||
|
||||
/** \name Direct geodesic problem specified in terms of distance.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Perform the direct geodesic calculation where the length of the geodesic
|
||||
* is specified in terms of distance.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] s12 distance between point 1 and point 2 (meters); it can be
|
||||
* signed.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees).
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] m12 reduced length of geodesic (meters).
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless).
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless).
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
|
||||
* @return \e a12 arc length of between point 1 and point 2 (degrees).
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°]. The values of
|
||||
* \e lon2 and \e azi2 returned are in the range [−180°,
|
||||
* 180°].
|
||||
*
|
||||
* If either point is at a pole, the azimuth is defined by keeping the
|
||||
* longitude fixed, writing \e lat = ±(90° − ε),
|
||||
* and taking the limit ε → 0+. An arc length greater that
|
||||
* 180° signifies a geodesic which is not a shortest path. (For a
|
||||
* prolate ellipsoid, an additional condition is necessary for a shortest
|
||||
* path: the longitudinal extent must not exceed of 180°.)
|
||||
*
|
||||
* The following functions are overloaded versions of GeodesicExact::Direct
|
||||
* which omit some of the output parameters. Note, however, that the arc
|
||||
* length is always computed and returned as the function value.
|
||||
**********************************************************************/
|
||||
Math::real Direct(real lat1, real lon1, real azi1, real s12,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& m12, real& M12, real& M21, real& S12)
|
||||
const {
|
||||
real t;
|
||||
return GenDirect(lat1, lon1, azi1, false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
REDUCEDLENGTH | GEODESICSCALE | AREA,
|
||||
lat2, lon2, azi2, t, m12, M12, M21, S12);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::Direct.
|
||||
**********************************************************************/
|
||||
Math::real Direct(real lat1, real lon1, real azi1, real s12,
|
||||
real& lat2, real& lon2)
|
||||
const {
|
||||
real t;
|
||||
return GenDirect(lat1, lon1, azi1, false, s12,
|
||||
LATITUDE | LONGITUDE,
|
||||
lat2, lon2, t, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::Direct.
|
||||
**********************************************************************/
|
||||
Math::real Direct(real lat1, real lon1, real azi1, real s12,
|
||||
real& lat2, real& lon2, real& azi2)
|
||||
const {
|
||||
real t;
|
||||
return GenDirect(lat1, lon1, azi1, false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH,
|
||||
lat2, lon2, azi2, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::Direct.
|
||||
**********************************************************************/
|
||||
Math::real Direct(real lat1, real lon1, real azi1, real s12,
|
||||
real& lat2, real& lon2, real& azi2, real& m12)
|
||||
const {
|
||||
real t;
|
||||
return GenDirect(lat1, lon1, azi1, false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | REDUCEDLENGTH,
|
||||
lat2, lon2, azi2, t, m12, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::Direct.
|
||||
**********************************************************************/
|
||||
Math::real Direct(real lat1, real lon1, real azi1, real s12,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& M12, real& M21)
|
||||
const {
|
||||
real t;
|
||||
return GenDirect(lat1, lon1, azi1, false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | GEODESICSCALE,
|
||||
lat2, lon2, azi2, t, t, M12, M21, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::Direct.
|
||||
**********************************************************************/
|
||||
Math::real Direct(real lat1, real lon1, real azi1, real s12,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& m12, real& M12, real& M21)
|
||||
const {
|
||||
real t;
|
||||
return GenDirect(lat1, lon1, azi1, false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
REDUCEDLENGTH | GEODESICSCALE,
|
||||
lat2, lon2, azi2, t, m12, M12, M21, t);
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name Direct geodesic problem specified in terms of arc length.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Perform the direct geodesic calculation where the length of the geodesic
|
||||
* is specified in terms of arc length.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] a12 arc length between point 1 and point 2 (degrees); it can
|
||||
* be signed.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees).
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] s12 distance between point 1 and point 2 (meters).
|
||||
* @param[out] m12 reduced length of geodesic (meters).
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless).
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless).
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°]. The values of
|
||||
* \e lon2 and \e azi2 returned are in the range [−180°,
|
||||
* 180°].
|
||||
*
|
||||
* If either point is at a pole, the azimuth is defined by keeping the
|
||||
* longitude fixed, writing \e lat = ±(90° − ε),
|
||||
* and taking the limit ε → 0+. An arc length greater that
|
||||
* 180° signifies a geodesic which is not a shortest path. (For a
|
||||
* prolate ellipsoid, an additional condition is necessary for a shortest
|
||||
* path: the longitudinal extent must not exceed of 180°.)
|
||||
*
|
||||
* The following functions are overloaded versions of GeodesicExact::Direct
|
||||
* which omit some of the output parameters.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2, real& azi2, real& s12,
|
||||
real& m12, real& M12, real& M21, real& S12)
|
||||
const {
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
|
||||
REDUCEDLENGTH | GEODESICSCALE | AREA,
|
||||
lat2, lon2, azi2, s12, m12, M12, M21, S12);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::ArcDirect.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2) const {
|
||||
real t;
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE,
|
||||
lat2, lon2, t, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::ArcDirect.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2, real& azi2) const {
|
||||
real t;
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH,
|
||||
lat2, lon2, azi2, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::ArcDirect.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2, real& azi2, real& s12)
|
||||
const {
|
||||
real t;
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE,
|
||||
lat2, lon2, azi2, s12, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::ArcDirect.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& m12) const {
|
||||
real t;
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
|
||||
REDUCEDLENGTH,
|
||||
lat2, lon2, azi2, s12, m12, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::ArcDirect.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2, real& azi2, real& s12,
|
||||
real& M12, real& M21) const {
|
||||
real t;
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
|
||||
GEODESICSCALE,
|
||||
lat2, lon2, azi2, s12, t, M12, M21, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::ArcDirect.
|
||||
**********************************************************************/
|
||||
void ArcDirect(real lat1, real lon1, real azi1, real a12,
|
||||
real& lat2, real& lon2, real& azi2, real& s12,
|
||||
real& m12, real& M12, real& M21) const {
|
||||
real t;
|
||||
GenDirect(lat1, lon1, azi1, true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
|
||||
REDUCEDLENGTH | GEODESICSCALE,
|
||||
lat2, lon2, azi2, s12, m12, M12, M21, t);
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name General version of the direct geodesic solution.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* The general direct geodesic calculation. GeodesicExact::Direct and
|
||||
* GeodesicExact::ArcDirect are defined in terms of this function.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] arcmode boolean flag determining the meaning of the second
|
||||
* parameter.
|
||||
* @param[in] s12_a12 if \e arcmode is false, this is the distance between
|
||||
* point 1 and point 2 (meters); otherwise it is the arc length between
|
||||
* point 1 and point 2 (degrees); it can be signed.
|
||||
* @param[in] outmask a bitor'ed combination of GeodesicExact::mask values
|
||||
* specifying which of the following parameters should be set.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees).
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] s12 distance between point 1 and point 2 (meters).
|
||||
* @param[out] m12 reduced length of geodesic (meters).
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless).
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless).
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
|
||||
* @return \e a12 arc length of between point 1 and point 2 (degrees).
|
||||
*
|
||||
* The GeodesicExact::mask values possible for \e outmask are
|
||||
* - \e outmask |= GeodesicExact::LATITUDE for the latitude \e lat2;
|
||||
* - \e outmask |= GeodesicExact::LONGITUDE for the latitude \e lon2;
|
||||
* - \e outmask |= GeodesicExact::AZIMUTH for the latitude \e azi2;
|
||||
* - \e outmask |= GeodesicExact::DISTANCE for the distance \e s12;
|
||||
* - \e outmask |= GeodesicExact::REDUCEDLENGTH for the reduced length \e
|
||||
* m12;
|
||||
* - \e outmask |= GeodesicExact::GEODESICSCALE for the geodesic scales \e
|
||||
* M12 and \e M21;
|
||||
* - \e outmask |= GeodesicExact::AREA for the area \e S12;
|
||||
* - \e outmask |= GeodesicExact::ALL for all of the above;
|
||||
* - \e outmask |= GeodesicExact::LONG_UNROLL to unroll \e lon2 instead of
|
||||
* wrapping it into the range [−180°, 180°].
|
||||
* .
|
||||
* The function value \e a12 is always computed and returned and this
|
||||
* equals \e s12_a12 is \e arcmode is true. If \e outmask includes
|
||||
* GeodesicExact::DISTANCE and \e arcmode is false, then \e s12 = \e
|
||||
* s12_a12. It is not necessary to include GeodesicExact::DISTANCE_IN in
|
||||
* \e outmask; this is automatically included is \e arcmode is false.
|
||||
*
|
||||
* With the GeodesicExact::LONG_UNROLL bit set, the quantity \e lon2
|
||||
* − \e lon1 indicates how many times and in what sense the geodesic
|
||||
* encircles the ellipsoid.
|
||||
**********************************************************************/
|
||||
Math::real GenDirect(real lat1, real lon1, real azi1,
|
||||
bool arcmode, real s12_a12, unsigned outmask,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& m12, real& M12, real& M21,
|
||||
real& S12) const;
|
||||
///@}
|
||||
|
||||
/** \name Inverse geodesic problem.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Perform the inverse geodesic calculation.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] lat2 latitude of point 2 (degrees).
|
||||
* @param[in] lon2 longitude of point 2 (degrees).
|
||||
* @param[out] s12 distance between point 1 and point 2 (meters).
|
||||
* @param[out] azi1 azimuth at point 1 (degrees).
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] m12 reduced length of geodesic (meters).
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless).
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless).
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
|
||||
* @return \e a12 arc length of between point 1 and point 2 (degrees).
|
||||
*
|
||||
* \e lat1 and \e lat2 should be in the range [−90°, 90°].
|
||||
* The values of \e azi1 and \e azi2 returned are in the range
|
||||
* [−180°, 180°].
|
||||
*
|
||||
* If either point is at a pole, the azimuth is defined by keeping the
|
||||
* longitude fixed, writing \e lat = ±(90° − ε),
|
||||
* and taking the limit ε → 0+.
|
||||
*
|
||||
* The following functions are overloaded versions of
|
||||
* GeodesicExact::Inverse which omit some of the output parameters. Note,
|
||||
* however, that the arc length is always computed and returned as the
|
||||
* function value.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12, real& azi1, real& azi2, real& m12,
|
||||
real& M12, real& M21, real& S12) const {
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
DISTANCE | AZIMUTH |
|
||||
REDUCEDLENGTH | GEODESICSCALE | AREA,
|
||||
s12, azi1, azi2, m12, M12, M21, S12);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::Inverse.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12) const {
|
||||
real t;
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
DISTANCE,
|
||||
s12, t, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::Inverse.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& azi1, real& azi2) const {
|
||||
real t;
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
AZIMUTH,
|
||||
t, azi1, azi2, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::Inverse.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12, real& azi1, real& azi2)
|
||||
const {
|
||||
real t;
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
DISTANCE | AZIMUTH,
|
||||
s12, azi1, azi2, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::Inverse.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12, real& azi1, real& azi2, real& m12)
|
||||
const {
|
||||
real t;
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
DISTANCE | AZIMUTH | REDUCEDLENGTH,
|
||||
s12, azi1, azi2, m12, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::Inverse.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12, real& azi1, real& azi2,
|
||||
real& M12, real& M21) const {
|
||||
real t;
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
DISTANCE | AZIMUTH | GEODESICSCALE,
|
||||
s12, azi1, azi2, t, M12, M21, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicExact::Inverse.
|
||||
**********************************************************************/
|
||||
Math::real Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12, real& azi1, real& azi2, real& m12,
|
||||
real& M12, real& M21) const {
|
||||
real t;
|
||||
return GenInverse(lat1, lon1, lat2, lon2,
|
||||
DISTANCE | AZIMUTH |
|
||||
REDUCEDLENGTH | GEODESICSCALE,
|
||||
s12, azi1, azi2, m12, M12, M21, t);
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name General version of inverse geodesic solution.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* The general inverse geodesic calculation. GeodesicExact::Inverse is
|
||||
* defined in terms of this function.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] lat2 latitude of point 2 (degrees).
|
||||
* @param[in] lon2 longitude of point 2 (degrees).
|
||||
* @param[in] outmask a bitor'ed combination of GeodesicExact::mask values
|
||||
* specifying which of the following parameters should be set.
|
||||
* @param[out] s12 distance between point 1 and point 2 (meters).
|
||||
* @param[out] azi1 azimuth at point 1 (degrees).
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] m12 reduced length of geodesic (meters).
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless).
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless).
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>).
|
||||
* @return \e a12 arc length of between point 1 and point 2 (degrees).
|
||||
*
|
||||
* The GeodesicExact::mask values possible for \e outmask are
|
||||
* - \e outmask |= GeodesicExact::DISTANCE for the distance \e s12;
|
||||
* - \e outmask |= GeodesicExact::AZIMUTH for the latitude \e azi2;
|
||||
* - \e outmask |= GeodesicExact::REDUCEDLENGTH for the reduced length \e
|
||||
* m12;
|
||||
* - \e outmask |= GeodesicExact::GEODESICSCALE for the geodesic scales \e
|
||||
* M12 and \e M21;
|
||||
* - \e outmask |= GeodesicExact::AREA for the area \e S12;
|
||||
* - \e outmask |= GeodesicExact::ALL for all of the above.
|
||||
* .
|
||||
* The arc length is always computed and returned as the function value.
|
||||
**********************************************************************/
|
||||
Math::real GenInverse(real lat1, real lon1, real lat2, real lon2,
|
||||
unsigned outmask,
|
||||
real& s12, real& azi1, real& azi2,
|
||||
real& m12, real& M12, real& M21, real& S12) const;
|
||||
///@}
|
||||
|
||||
/** \name Interface to GeodesicLineExact.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Set up to compute several points on a single geodesic.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] caps bitor'ed combination of GeodesicExact::mask values
|
||||
* specifying the capabilities the GeodesicLineExact object should
|
||||
* possess, i.e., which quantities can be returned in calls to
|
||||
* GeodesicLineExact::Position.
|
||||
* @return a GeodesicLineExact object.
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°].
|
||||
*
|
||||
* The GeodesicExact::mask values are
|
||||
* - \e caps |= GeodesicExact::LATITUDE for the latitude \e lat2; this is
|
||||
* added automatically;
|
||||
* - \e caps |= GeodesicExact::LONGITUDE for the latitude \e lon2;
|
||||
* - \e caps |= GeodesicExact::AZIMUTH for the azimuth \e azi2; this is
|
||||
* added automatically;
|
||||
* - \e caps |= GeodesicExact::DISTANCE for the distance \e s12;
|
||||
* - \e caps |= GeodesicExact::REDUCEDLENGTH for the reduced length \e m12;
|
||||
* - \e caps |= GeodesicExact::GEODESICSCALE for the geodesic scales \e M12
|
||||
* and \e M21;
|
||||
* - \e caps |= GeodesicExact::AREA for the area \e S12;
|
||||
* - \e caps |= GeodesicExact::DISTANCE_IN permits the length of the
|
||||
* geodesic to be given in terms of \e s12; without this capability the
|
||||
* length can only be specified in terms of arc length;
|
||||
* - \e caps |= GeodesicExact::ALL for all of the above.
|
||||
* .
|
||||
* The default value of \e caps is GeodesicExact::ALL which turns on all
|
||||
* the capabilities.
|
||||
*
|
||||
* If the point is at a pole, the azimuth is defined by keeping \e lon1
|
||||
* fixed, writing \e lat1 = ±(90 − ε), and taking the
|
||||
* limit ε → 0+.
|
||||
**********************************************************************/
|
||||
GeodesicLineExact Line(real lat1, real lon1, real azi1,
|
||||
unsigned caps = ALL) const;
|
||||
|
||||
/**
|
||||
* Define a GeodesicLineExact in terms of the inverse geodesic problem.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] lat2 latitude of point 2 (degrees).
|
||||
* @param[in] lon2 longitude of point 2 (degrees).
|
||||
* @param[in] caps bitor'ed combination of GeodesicExact::mask values
|
||||
* specifying the capabilities the GeodesicLineExact object should
|
||||
* possess, i.e., which quantities can be returned in calls to
|
||||
* GeodesicLineExact::Position.
|
||||
* @return a GeodesicLineExact object.
|
||||
*
|
||||
* This function sets point 3 of the GeodesicLineExact to correspond to
|
||||
* point 2 of the inverse geodesic problem.
|
||||
*
|
||||
* \e lat1 and \e lat2 should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
GeodesicLineExact InverseLine(real lat1, real lon1, real lat2, real lon2,
|
||||
unsigned caps = ALL) const;
|
||||
|
||||
/**
|
||||
* Define a GeodesicLineExact in terms of the direct geodesic problem
|
||||
* specified in terms of distance.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] s12 distance between point 1 and point 2 (meters); it can be
|
||||
* negative.
|
||||
* @param[in] caps bitor'ed combination of GeodesicExact::mask values
|
||||
* specifying the capabilities the GeodesicLineExact object should
|
||||
* possess, i.e., which quantities can be returned in calls to
|
||||
* GeodesicLineExact::Position.
|
||||
* @return a GeodesicLineExact object.
|
||||
*
|
||||
* This function sets point 3 of the GeodesicLineExact to correspond to
|
||||
* point 2 of the direct geodesic problem.
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
GeodesicLineExact DirectLine(real lat1, real lon1, real azi1, real s12,
|
||||
unsigned caps = ALL) const;
|
||||
|
||||
/**
|
||||
* Define a GeodesicLineExact in terms of the direct geodesic problem
|
||||
* specified in terms of arc length.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] a12 arc length between point 1 and point 2 (degrees); it can
|
||||
* be negative.
|
||||
* @param[in] caps bitor'ed combination of GeodesicExact::mask values
|
||||
* specifying the capabilities the GeodesicLineExact object should
|
||||
* possess, i.e., which quantities can be returned in calls to
|
||||
* GeodesicLineExact::Position.
|
||||
* @return a GeodesicLineExact object.
|
||||
*
|
||||
* This function sets point 3 of the GeodesicLineExact to correspond to
|
||||
* point 2 of the direct geodesic problem.
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
GeodesicLineExact ArcDirectLine(real lat1, real lon1, real azi1, real a12,
|
||||
unsigned caps = ALL) const;
|
||||
|
||||
/**
|
||||
* Define a GeodesicLineExact in terms of the direct geodesic problem
|
||||
* specified in terms of either distance or arc length.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] arcmode boolean flag determining the meaning of the \e
|
||||
* s12_a12.
|
||||
* @param[in] s12_a12 if \e arcmode is false, this is the distance between
|
||||
* point 1 and point 2 (meters); otherwise it is the arc length between
|
||||
* point 1 and point 2 (degrees); it can be negative.
|
||||
* @param[in] caps bitor'ed combination of GeodesicExact::mask values
|
||||
* specifying the capabilities the GeodesicLineExact object should
|
||||
* possess, i.e., which quantities can be returned in calls to
|
||||
* GeodesicLineExact::Position.
|
||||
* @return a GeodesicLineExact object.
|
||||
*
|
||||
* This function sets point 3 of the GeodesicLineExact to correspond to
|
||||
* point 2 of the direct geodesic problem.
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
GeodesicLineExact GenDirectLine(real lat1, real lon1, real azi1,
|
||||
bool arcmode, real s12_a12,
|
||||
unsigned caps = ALL) const;
|
||||
///@}
|
||||
|
||||
/** \name Inspector functions.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _a; }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the
|
||||
* value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _f; }
|
||||
|
||||
/**
|
||||
* @return total area of ellipsoid in meters<sup>2</sup>. The area of a
|
||||
* polygon encircling a pole can be found by adding
|
||||
* GeodesicExact::EllipsoidArea()/2 to the sum of \e S12 for each side of
|
||||
* the polygon.
|
||||
**********************************************************************/
|
||||
Math::real EllipsoidArea() const
|
||||
{ return 4 * Math::pi() * _c2; }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* A global instantiation of GeodesicExact with the parameters for the
|
||||
* WGS84 ellipsoid.
|
||||
**********************************************************************/
|
||||
static const GeodesicExact& WGS84();
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_GEODESICEXACT_HPP
|
||||
708
external/include/GeographicLib/GeodesicLine.hpp
vendored
Normal file
708
external/include/GeographicLib/GeodesicLine.hpp
vendored
Normal file
@@ -0,0 +1,708 @@
|
||||
/**
|
||||
* \file GeodesicLine.hpp
|
||||
* \brief Header for GeographicLib::GeodesicLine class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2009-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GEODESICLINE_HPP)
|
||||
#define GEOGRAPHICLIB_GEODESICLINE_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/Geodesic.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief A geodesic line
|
||||
*
|
||||
* GeodesicLine facilitates the determination of a series of points on a
|
||||
* single geodesic. The starting point (\e lat1, \e lon1) and the azimuth \e
|
||||
* azi1 are specified in the constructor; alternatively, the Geodesic::Line
|
||||
* method can be used to create a GeodesicLine. GeodesicLine.Position
|
||||
* returns the location of point 2 a distance \e s12 along the geodesic. In
|
||||
* addition, GeodesicLine.ArcPosition gives the position of point 2 an arc
|
||||
* length \e a12 along the geodesic.
|
||||
*
|
||||
* You can register the position of a reference point 3 a distance (arc
|
||||
* length), \e s13 (\e a13) along the geodesic with the
|
||||
* GeodesicLine.SetDistance (GeodesicLine.SetArc) functions. Points a
|
||||
* fractional distance along the line can be found by providing, for example,
|
||||
* 0.5 * Distance() as an argument to GeodesicLine.Position. The
|
||||
* Geodesic::InverseLine or Geodesic::DirectLine methods return GeodesicLine
|
||||
* objects with point 3 set to the point 2 of the corresponding geodesic
|
||||
* problem. GeodesicLine objects created with the public constructor or with
|
||||
* Geodesic::Line have \e s13 and \e a13 set to NaNs.
|
||||
*
|
||||
* The default copy constructor and assignment operators work with this
|
||||
* class. Similarly, a vector can be used to hold GeodesicLine objects.
|
||||
*
|
||||
* The calculations are accurate to better than 15 nm (15 nanometers). See
|
||||
* Sec. 9 of
|
||||
* <a href="https://arxiv.org/abs/1102.1215v1">arXiv:1102.1215v1</a> for
|
||||
* details. The algorithms used by this class are based on series expansions
|
||||
* using the flattening \e f as a small parameter. These are only accurate
|
||||
* for |<i>f</i>| < 0.02; however reasonably accurate results will be
|
||||
* obtained for |<i>f</i>| < 0.2. For very eccentric ellipsoids, use
|
||||
* GeodesicLineExact instead.
|
||||
*
|
||||
* The algorithms are described in
|
||||
* - C. F. F. Karney,
|
||||
* <a href="https://doi.org/10.1007/s00190-012-0578-z">
|
||||
* Algorithms for geodesics</a>,
|
||||
* J. Geodesy <b>87</b>, 43--55 (2013);
|
||||
* DOI: <a href="https://doi.org/10.1007/s00190-012-0578-z">
|
||||
* 10.1007/s00190-012-0578-z</a>;
|
||||
* addenda:
|
||||
* <a href="https://geographiclib.sourceforge.io/geod-addenda.html">
|
||||
* geod-addenda.html</a>.
|
||||
* .
|
||||
* For more information on geodesics see \ref geodesic.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-GeodesicLine.cpp
|
||||
*
|
||||
* <a href="GeodSolve.1.html">GeodSolve</a> is a command-line utility
|
||||
* providing access to the functionality of Geodesic and GeodesicLine.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT GeodesicLine {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
friend class Geodesic;
|
||||
static const int nC1_ = Geodesic::nC1_;
|
||||
static const int nC1p_ = Geodesic::nC1p_;
|
||||
static const int nC2_ = Geodesic::nC2_;
|
||||
static const int nC3_ = Geodesic::nC3_;
|
||||
static const int nC4_ = Geodesic::nC4_;
|
||||
|
||||
real tiny_;
|
||||
real _lat1, _lon1, _azi1;
|
||||
real _a, _f, _b, _c2, _f1, _salp0, _calp0, _k2,
|
||||
_salp1, _calp1, _ssig1, _csig1, _dn1, _stau1, _ctau1, _somg1, _comg1,
|
||||
_A1m1, _A2m1, _A3c, _B11, _B21, _B31, _A4, _B41;
|
||||
real _a13, _s13;
|
||||
// index zero elements of _C1a, _C1pa, _C2a, _C3a are unused
|
||||
real _C1a[nC1_ + 1], _C1pa[nC1p_ + 1], _C2a[nC2_ + 1], _C3a[nC3_],
|
||||
_C4a[nC4_]; // all the elements of _C4a are used
|
||||
unsigned _caps;
|
||||
|
||||
void LineInit(const Geodesic& g,
|
||||
real lat1, real lon1,
|
||||
real azi1, real salp1, real calp1,
|
||||
unsigned caps);
|
||||
GeodesicLine(const Geodesic& g,
|
||||
real lat1, real lon1,
|
||||
real azi1, real salp1, real calp1,
|
||||
unsigned caps, bool arcmode, real s13_a13);
|
||||
|
||||
enum captype {
|
||||
CAP_NONE = Geodesic::CAP_NONE,
|
||||
CAP_C1 = Geodesic::CAP_C1,
|
||||
CAP_C1p = Geodesic::CAP_C1p,
|
||||
CAP_C2 = Geodesic::CAP_C2,
|
||||
CAP_C3 = Geodesic::CAP_C3,
|
||||
CAP_C4 = Geodesic::CAP_C4,
|
||||
CAP_ALL = Geodesic::CAP_ALL,
|
||||
CAP_MASK = Geodesic::CAP_MASK,
|
||||
OUT_ALL = Geodesic::OUT_ALL,
|
||||
OUT_MASK = Geodesic::OUT_MASK,
|
||||
};
|
||||
public:
|
||||
|
||||
/**
|
||||
* Bit masks for what calculations to do. They signify to the
|
||||
* GeodesicLine::GeodesicLine constructor and to Geodesic::Line what
|
||||
* capabilities should be included in the GeodesicLine object. This is
|
||||
* merely a duplication of Geodesic::mask.
|
||||
**********************************************************************/
|
||||
enum mask {
|
||||
/**
|
||||
* No capabilities, no output.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
NONE = Geodesic::NONE,
|
||||
/**
|
||||
* Calculate latitude \e lat2. (It's not necessary to include this as a
|
||||
* capability to GeodesicLine because this is included by default.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LATITUDE = Geodesic::LATITUDE,
|
||||
/**
|
||||
* Calculate longitude \e lon2.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONGITUDE = Geodesic::LONGITUDE,
|
||||
/**
|
||||
* Calculate azimuths \e azi1 and \e azi2. (It's not necessary to
|
||||
* include this as a capability to GeodesicLine because this is included
|
||||
* by default.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AZIMUTH = Geodesic::AZIMUTH,
|
||||
/**
|
||||
* Calculate distance \e s12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DISTANCE = Geodesic::DISTANCE,
|
||||
/**
|
||||
* Allow distance \e s12 to be used as input in the direct geodesic
|
||||
* problem.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DISTANCE_IN = Geodesic::DISTANCE_IN,
|
||||
/**
|
||||
* Calculate reduced length \e m12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
REDUCEDLENGTH = Geodesic::REDUCEDLENGTH,
|
||||
/**
|
||||
* Calculate geodesic scales \e M12 and \e M21.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
GEODESICSCALE = Geodesic::GEODESICSCALE,
|
||||
/**
|
||||
* Calculate area \e S12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AREA = Geodesic::AREA,
|
||||
/**
|
||||
* Unroll \e lon2 in the direct calculation.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONG_UNROLL = Geodesic::LONG_UNROLL,
|
||||
/**
|
||||
* All capabilities, calculate everything. (LONG_UNROLL is not
|
||||
* included in this mask.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
ALL = Geodesic::ALL,
|
||||
};
|
||||
|
||||
/** \name Constructors
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Constructor for a geodesic line staring at latitude \e lat1, longitude
|
||||
* \e lon1, and azimuth \e azi1 (all in degrees).
|
||||
*
|
||||
* @param[in] g A Geodesic object used to compute the necessary information
|
||||
* about the GeodesicLine.
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] caps bitor'ed combination of GeodesicLine::mask values
|
||||
* specifying the capabilities the GeodesicLine object should possess,
|
||||
* i.e., which quantities can be returned in calls to
|
||||
* GeodesicLine::Position.
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°].
|
||||
*
|
||||
* The GeodesicLine::mask values are
|
||||
* - \e caps |= GeodesicLine::LATITUDE for the latitude \e lat2; this is
|
||||
* added automatically;
|
||||
* - \e caps |= GeodesicLine::LONGITUDE for the latitude \e lon2;
|
||||
* - \e caps |= GeodesicLine::AZIMUTH for the latitude \e azi2; this is
|
||||
* added automatically;
|
||||
* - \e caps |= GeodesicLine::DISTANCE for the distance \e s12;
|
||||
* - \e caps |= GeodesicLine::REDUCEDLENGTH for the reduced length \e m12;
|
||||
* - \e caps |= GeodesicLine::GEODESICSCALE for the geodesic scales \e M12
|
||||
* and \e M21;
|
||||
* - \e caps |= GeodesicLine::AREA for the area \e S12;
|
||||
* - \e caps |= GeodesicLine::DISTANCE_IN permits the length of the
|
||||
* geodesic to be given in terms of \e s12; without this capability the
|
||||
* length can only be specified in terms of arc length;
|
||||
* - \e caps |= GeodesicLine::ALL for all of the above.
|
||||
* .
|
||||
* The default value of \e caps is GeodesicLine::ALL.
|
||||
*
|
||||
* If the point is at a pole, the azimuth is defined by keeping \e lon1
|
||||
* fixed, writing \e lat1 = ±(90° − ε), and taking
|
||||
* the limit ε → 0+.
|
||||
**********************************************************************/
|
||||
GeodesicLine(const Geodesic& g, real lat1, real lon1, real azi1,
|
||||
unsigned caps = ALL);
|
||||
|
||||
/**
|
||||
* A default constructor. If GeodesicLine::Position is called on the
|
||||
* resulting object, it returns immediately (without doing any
|
||||
* calculations). The object can be set with a call to Geodesic::Line.
|
||||
* Use Init() to test whether object is still in this uninitialized state.
|
||||
**********************************************************************/
|
||||
GeodesicLine() : _caps(0U) {}
|
||||
///@}
|
||||
|
||||
/** \name Position in terms of distance
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Compute the position of point 2 which is a distance \e s12 (meters) from
|
||||
* point 1.
|
||||
*
|
||||
* @param[in] s12 distance from point 1 to point 2 (meters); it can be
|
||||
* negative.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees); requires that the
|
||||
* GeodesicLine object was constructed with \e caps |=
|
||||
* GeodesicLine::LONGITUDE.
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] m12 reduced length of geodesic (meters); requires that the
|
||||
* GeodesicLine object was constructed with \e caps |=
|
||||
* GeodesicLine::REDUCEDLENGTH.
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless); requires that the GeodesicLine object was constructed
|
||||
* with \e caps |= GeodesicLine::GEODESICSCALE.
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless); requires that the GeodesicLine object was constructed
|
||||
* with \e caps |= GeodesicLine::GEODESICSCALE.
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>); requires
|
||||
* that the GeodesicLine object was constructed with \e caps |=
|
||||
* GeodesicLine::AREA.
|
||||
* @return \e a12 arc length from point 1 to point 2 (degrees).
|
||||
*
|
||||
* The values of \e lon2 and \e azi2 returned are in the range
|
||||
* [−180°, 180°].
|
||||
*
|
||||
* The GeodesicLine object \e must have been constructed with \e caps |=
|
||||
* GeodesicLine::DISTANCE_IN; otherwise Math::NaN() is returned and no
|
||||
* parameters are set. Requesting a value which the GeodesicLine object is
|
||||
* not capable of computing is not an error; the corresponding argument
|
||||
* will not be altered.
|
||||
*
|
||||
* The following functions are overloaded versions of
|
||||
* GeodesicLine::Position which omit some of the output parameters. Note,
|
||||
* however, that the arc length is always computed and returned as the
|
||||
* function value.
|
||||
**********************************************************************/
|
||||
Math::real Position(real s12,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& m12, real& M12, real& M21,
|
||||
real& S12) const {
|
||||
real t;
|
||||
return GenPosition(false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
REDUCEDLENGTH | GEODESICSCALE | AREA,
|
||||
lat2, lon2, azi2, t, m12, M12, M21, S12);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLine::Position.
|
||||
**********************************************************************/
|
||||
Math::real Position(real s12, real& lat2, real& lon2) const {
|
||||
real t;
|
||||
return GenPosition(false, s12,
|
||||
LATITUDE | LONGITUDE,
|
||||
lat2, lon2, t, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLine::Position.
|
||||
**********************************************************************/
|
||||
Math::real Position(real s12, real& lat2, real& lon2,
|
||||
real& azi2) const {
|
||||
real t;
|
||||
return GenPosition(false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH,
|
||||
lat2, lon2, azi2, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLine::Position.
|
||||
**********************************************************************/
|
||||
Math::real Position(real s12, real& lat2, real& lon2,
|
||||
real& azi2, real& m12) const {
|
||||
real t;
|
||||
return GenPosition(false, s12,
|
||||
LATITUDE | LONGITUDE |
|
||||
AZIMUTH | REDUCEDLENGTH,
|
||||
lat2, lon2, azi2, t, m12, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLine::Position.
|
||||
**********************************************************************/
|
||||
Math::real Position(real s12, real& lat2, real& lon2,
|
||||
real& azi2, real& M12, real& M21)
|
||||
const {
|
||||
real t;
|
||||
return GenPosition(false, s12,
|
||||
LATITUDE | LONGITUDE |
|
||||
AZIMUTH | GEODESICSCALE,
|
||||
lat2, lon2, azi2, t, t, M12, M21, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLine::Position.
|
||||
**********************************************************************/
|
||||
Math::real Position(real s12,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& m12, real& M12, real& M21)
|
||||
const {
|
||||
real t;
|
||||
return GenPosition(false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
REDUCEDLENGTH | GEODESICSCALE,
|
||||
lat2, lon2, azi2, t, m12, M12, M21, t);
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name Position in terms of arc length
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Compute the position of point 2 which is an arc length \e a12 (degrees)
|
||||
* from point 1.
|
||||
*
|
||||
* @param[in] a12 arc length from point 1 to point 2 (degrees); it can
|
||||
* be negative.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees); requires that the
|
||||
* GeodesicLine object was constructed with \e caps |=
|
||||
* GeodesicLine::LONGITUDE.
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] s12 distance from point 1 to point 2 (meters); requires
|
||||
* that the GeodesicLine object was constructed with \e caps |=
|
||||
* GeodesicLine::DISTANCE.
|
||||
* @param[out] m12 reduced length of geodesic (meters); requires that the
|
||||
* GeodesicLine object was constructed with \e caps |=
|
||||
* GeodesicLine::REDUCEDLENGTH.
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless); requires that the GeodesicLine object was constructed
|
||||
* with \e caps |= GeodesicLine::GEODESICSCALE.
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless); requires that the GeodesicLine object was constructed
|
||||
* with \e caps |= GeodesicLine::GEODESICSCALE.
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>); requires
|
||||
* that the GeodesicLine object was constructed with \e caps |=
|
||||
* GeodesicLine::AREA.
|
||||
*
|
||||
* The values of \e lon2 and \e azi2 returned are in the range
|
||||
* [−180°, 180°].
|
||||
*
|
||||
* Requesting a value which the GeodesicLine object is not capable of
|
||||
* computing is not an error; the corresponding argument will not be
|
||||
* altered.
|
||||
*
|
||||
* The following functions are overloaded versions of
|
||||
* GeodesicLine::ArcPosition which omit some of the output parameters.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& m12, real& M12, real& M21,
|
||||
real& S12) const {
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
|
||||
REDUCEDLENGTH | GEODESICSCALE | AREA,
|
||||
lat2, lon2, azi2, s12, m12, M12, M21, S12);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLine::ArcPosition.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12, real& lat2, real& lon2)
|
||||
const {
|
||||
real t;
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE,
|
||||
lat2, lon2, t, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLine::ArcPosition.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12,
|
||||
real& lat2, real& lon2, real& azi2)
|
||||
const {
|
||||
real t;
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH,
|
||||
lat2, lon2, azi2, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLine::ArcPosition.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
|
||||
real& s12) const {
|
||||
real t;
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE,
|
||||
lat2, lon2, azi2, s12, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLine::ArcPosition.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& m12) const {
|
||||
real t;
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
DISTANCE | REDUCEDLENGTH,
|
||||
lat2, lon2, azi2, s12, m12, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLine::ArcPosition.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& M12, real& M21)
|
||||
const {
|
||||
real t;
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
DISTANCE | GEODESICSCALE,
|
||||
lat2, lon2, azi2, s12, t, M12, M21, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLine::ArcPosition.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& m12, real& M12, real& M21)
|
||||
const {
|
||||
real t;
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
DISTANCE | REDUCEDLENGTH | GEODESICSCALE,
|
||||
lat2, lon2, azi2, s12, m12, M12, M21, t);
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name The general position function.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* The general position function. GeodesicLine::Position and
|
||||
* GeodesicLine::ArcPosition are defined in terms of this function.
|
||||
*
|
||||
* @param[in] arcmode boolean flag determining the meaning of the second
|
||||
* parameter; if \e arcmode is false, then the GeodesicLine object must
|
||||
* have been constructed with \e caps |= GeodesicLine::DISTANCE_IN.
|
||||
* @param[in] s12_a12 if \e arcmode is false, this is the distance between
|
||||
* point 1 and point 2 (meters); otherwise it is the arc length between
|
||||
* point 1 and point 2 (degrees); it can be negative.
|
||||
* @param[in] outmask a bitor'ed combination of GeodesicLine::mask values
|
||||
* specifying which of the following parameters should be set.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees); requires that the
|
||||
* GeodesicLine object was constructed with \e caps |=
|
||||
* GeodesicLine::LONGITUDE.
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] s12 distance from point 1 to point 2 (meters); requires
|
||||
* that the GeodesicLine object was constructed with \e caps |=
|
||||
* GeodesicLine::DISTANCE.
|
||||
* @param[out] m12 reduced length of geodesic (meters); requires that the
|
||||
* GeodesicLine object was constructed with \e caps |=
|
||||
* GeodesicLine::REDUCEDLENGTH.
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless); requires that the GeodesicLine object was constructed
|
||||
* with \e caps |= GeodesicLine::GEODESICSCALE.
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless); requires that the GeodesicLine object was constructed
|
||||
* with \e caps |= GeodesicLine::GEODESICSCALE.
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>); requires
|
||||
* that the GeodesicLine object was constructed with \e caps |=
|
||||
* GeodesicLine::AREA.
|
||||
* @return \e a12 arc length from point 1 to point 2 (degrees).
|
||||
*
|
||||
* The GeodesicLine::mask values possible for \e outmask are
|
||||
* - \e outmask |= GeodesicLine::LATITUDE for the latitude \e lat2;
|
||||
* - \e outmask |= GeodesicLine::LONGITUDE for the latitude \e lon2;
|
||||
* - \e outmask |= GeodesicLine::AZIMUTH for the latitude \e azi2;
|
||||
* - \e outmask |= GeodesicLine::DISTANCE for the distance \e s12;
|
||||
* - \e outmask |= GeodesicLine::REDUCEDLENGTH for the reduced length \e
|
||||
* m12;
|
||||
* - \e outmask |= GeodesicLine::GEODESICSCALE for the geodesic scales \e
|
||||
* M12 and \e M21;
|
||||
* - \e outmask |= GeodesicLine::AREA for the area \e S12;
|
||||
* - \e outmask |= GeodesicLine::ALL for all of the above;
|
||||
* - \e outmask |= GeodesicLine::LONG_UNROLL to unroll \e lon2 instead of
|
||||
* reducing it into the range [−180°, 180°].
|
||||
* .
|
||||
* Requesting a value which the GeodesicLine object is not capable of
|
||||
* computing is not an error; the corresponding argument will not be
|
||||
* altered. Note, however, that the arc length is always computed and
|
||||
* returned as the function value.
|
||||
*
|
||||
* With the GeodesicLine::LONG_UNROLL bit set, the quantity \e lon2 −
|
||||
* \e lon1 indicates how many times and in what sense the geodesic
|
||||
* encircles the ellipsoid.
|
||||
**********************************************************************/
|
||||
Math::real GenPosition(bool arcmode, real s12_a12, unsigned outmask,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& m12, real& M12, real& M21,
|
||||
real& S12) const;
|
||||
///@}
|
||||
|
||||
/** \name Setting point 3
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Specify position of point 3 in terms of distance.
|
||||
*
|
||||
* @param[in] s13 the distance from point 1 to point 3 (meters); it
|
||||
* can be negative.
|
||||
*
|
||||
* This is only useful if the GeodesicLine object has been constructed
|
||||
* with \e caps |= GeodesicLine::DISTANCE_IN.
|
||||
**********************************************************************/
|
||||
void SetDistance(real s13);
|
||||
|
||||
/**
|
||||
* Specify position of point 3 in terms of arc length.
|
||||
*
|
||||
* @param[in] a13 the arc length from point 1 to point 3 (degrees); it
|
||||
* can be negative.
|
||||
*
|
||||
* The distance \e s13 is only set if the GeodesicLine object has been
|
||||
* constructed with \e caps |= GeodesicLine::DISTANCE.
|
||||
**********************************************************************/
|
||||
void SetArc(real a13);
|
||||
|
||||
/**
|
||||
* Specify position of point 3 in terms of either distance or arc length.
|
||||
*
|
||||
* @param[in] arcmode boolean flag determining the meaning of the second
|
||||
* parameter; if \e arcmode is false, then the GeodesicLine object must
|
||||
* have been constructed with \e caps |= GeodesicLine::DISTANCE_IN.
|
||||
* @param[in] s13_a13 if \e arcmode is false, this is the distance from
|
||||
* point 1 to point 3 (meters); otherwise it is the arc length from
|
||||
* point 1 to point 3 (degrees); it can be negative.
|
||||
**********************************************************************/
|
||||
void GenSetDistance(bool arcmode, real s13_a13);
|
||||
///@}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @return true if the object has been initialized.
|
||||
**********************************************************************/
|
||||
bool Init() const { return _caps != 0U; }
|
||||
|
||||
/**
|
||||
* @return \e lat1 the latitude of point 1 (degrees).
|
||||
**********************************************************************/
|
||||
Math::real Latitude() const
|
||||
{ return Init() ? _lat1 : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e lon1 the longitude of point 1 (degrees).
|
||||
**********************************************************************/
|
||||
Math::real Longitude() const
|
||||
{ return Init() ? _lon1 : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e azi1 the azimuth (degrees) of the geodesic line at point 1.
|
||||
**********************************************************************/
|
||||
Math::real Azimuth() const
|
||||
{ return Init() ? _azi1 : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* The sine and cosine of \e azi1.
|
||||
*
|
||||
* @param[out] sazi1 the sine of \e azi1.
|
||||
* @param[out] cazi1 the cosine of \e azi1.
|
||||
**********************************************************************/
|
||||
void Azimuth(real& sazi1, real& cazi1) const
|
||||
{ if (Init()) { sazi1 = _salp1; cazi1 = _calp1; } }
|
||||
|
||||
/**
|
||||
* @return \e azi0 the azimuth (degrees) of the geodesic line as it crosses
|
||||
* the equator in a northward direction.
|
||||
*
|
||||
* The result lies in [−90°, 90°].
|
||||
**********************************************************************/
|
||||
Math::real EquatorialAzimuth() const
|
||||
{ return Init() ? Math::atan2d(_salp0, _calp0) : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* The sine and cosine of \e azi0.
|
||||
*
|
||||
* @param[out] sazi0 the sine of \e azi0.
|
||||
* @param[out] cazi0 the cosine of \e azi0.
|
||||
**********************************************************************/
|
||||
void EquatorialAzimuth(real& sazi0, real& cazi0) const
|
||||
{ if (Init()) { sazi0 = _salp0; cazi0 = _calp0; } }
|
||||
|
||||
/**
|
||||
* @return \e a1 the arc length (degrees) between the northward equatorial
|
||||
* crossing and point 1.
|
||||
*
|
||||
* The result lies in (−180°, 180°].
|
||||
**********************************************************************/
|
||||
Math::real EquatorialArc() const {
|
||||
return Init() ? Math::atan2d(_ssig1, _csig1) : Math::NaN();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value inherited from the Geodesic object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const
|
||||
{ return Init() ? _a : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value
|
||||
* inherited from the Geodesic object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const
|
||||
{ return Init() ? _f : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e caps the computational capabilities that this object was
|
||||
* constructed with. LATITUDE and AZIMUTH are always included.
|
||||
**********************************************************************/
|
||||
unsigned Capabilities() const { return _caps; }
|
||||
|
||||
/**
|
||||
* Test what capabilities are available.
|
||||
*
|
||||
* @param[in] testcaps a set of bitor'ed GeodesicLine::mask values.
|
||||
* @return true if the GeodesicLine object has all these capabilities.
|
||||
**********************************************************************/
|
||||
bool Capabilities(unsigned testcaps) const {
|
||||
testcaps &= OUT_ALL;
|
||||
return (_caps & testcaps) == testcaps;
|
||||
}
|
||||
|
||||
/**
|
||||
* The distance or arc length to point 3.
|
||||
*
|
||||
* @param[in] arcmode boolean flag determining the meaning of returned
|
||||
* value.
|
||||
* @return \e s13 if \e arcmode is false; \e a13 if \e arcmode is true.
|
||||
**********************************************************************/
|
||||
Math::real GenDistance(bool arcmode) const
|
||||
{ return Init() ? (arcmode ? _a13 : _s13) : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e s13, the distance to point 3 (meters).
|
||||
**********************************************************************/
|
||||
Math::real Distance() const { return GenDistance(false); }
|
||||
|
||||
/**
|
||||
* @return \e a13, the arc length to point 3 (degrees).
|
||||
**********************************************************************/
|
||||
Math::real Arc() const { return GenDistance(true); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_GEODESICLINE_HPP
|
||||
673
external/include/GeographicLib/GeodesicLineExact.hpp
vendored
Normal file
673
external/include/GeographicLib/GeodesicLineExact.hpp
vendored
Normal file
@@ -0,0 +1,673 @@
|
||||
/**
|
||||
* \file GeodesicLineExact.hpp
|
||||
* \brief Header for GeographicLib::GeodesicLineExact class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2012-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GEODESICLINEEXACT_HPP)
|
||||
#define GEOGRAPHICLIB_GEODESICLINEEXACT_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/GeodesicExact.hpp>
|
||||
#include <GeographicLib/EllipticFunction.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief An exact geodesic line
|
||||
*
|
||||
* GeodesicLineExact facilitates the determination of a series of points on a
|
||||
* single geodesic. This is a companion to the GeodesicExact class. For
|
||||
* additional information on this class see the documentation on the
|
||||
* GeodesicLine class.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-GeodesicLineExact.cpp
|
||||
*
|
||||
* <a href="GeodSolve.1.html">GeodSolve</a> is a command-line utility
|
||||
* providing access to the functionality of GeodesicExact and
|
||||
* GeodesicLineExact (via the -E option).
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT GeodesicLineExact {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
friend class GeodesicExact;
|
||||
static const int nC4_ = GeodesicExact::nC4_;
|
||||
|
||||
real tiny_;
|
||||
real _lat1, _lon1, _azi1;
|
||||
real _a, _f, _b, _c2, _f1, _e2, _salp0, _calp0, _k2,
|
||||
_salp1, _calp1, _ssig1, _csig1, _dn1, _stau1, _ctau1,
|
||||
_somg1, _comg1, _cchi1,
|
||||
_A4, _B41, _E0, _D0, _H0, _E1, _D1, _H1;
|
||||
real _a13, _s13;
|
||||
real _C4a[nC4_]; // all the elements of _C4a are used
|
||||
EllipticFunction _E;
|
||||
unsigned _caps;
|
||||
|
||||
void LineInit(const GeodesicExact& g,
|
||||
real lat1, real lon1,
|
||||
real azi1, real salp1, real calp1,
|
||||
unsigned caps);
|
||||
GeodesicLineExact(const GeodesicExact& g,
|
||||
real lat1, real lon1,
|
||||
real azi1, real salp1, real calp1,
|
||||
unsigned caps, bool arcmode, real s13_a13);
|
||||
|
||||
enum captype {
|
||||
CAP_NONE = GeodesicExact::CAP_NONE,
|
||||
CAP_E = GeodesicExact::CAP_E,
|
||||
CAP_D = GeodesicExact::CAP_D,
|
||||
CAP_H = GeodesicExact::CAP_H,
|
||||
CAP_C4 = GeodesicExact::CAP_C4,
|
||||
CAP_ALL = GeodesicExact::CAP_ALL,
|
||||
CAP_MASK = GeodesicExact::CAP_MASK,
|
||||
OUT_ALL = GeodesicExact::OUT_ALL,
|
||||
OUT_MASK = GeodesicExact::OUT_MASK,
|
||||
};
|
||||
public:
|
||||
|
||||
/**
|
||||
* Bit masks for what calculations to do. They signify to the
|
||||
* GeodesicLineExact::GeodesicLineExact constructor and to
|
||||
* GeodesicExact::Line what capabilities should be included in the
|
||||
* GeodesicLineExact object. This is merely a duplication of
|
||||
* GeodesicExact::mask.
|
||||
**********************************************************************/
|
||||
enum mask {
|
||||
/**
|
||||
* No capabilities, no output.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
NONE = GeodesicExact::NONE,
|
||||
/**
|
||||
* Calculate latitude \e lat2. (It's not necessary to include this as a
|
||||
* capability to GeodesicLineExact because this is included by default.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LATITUDE = GeodesicExact::LATITUDE,
|
||||
/**
|
||||
* Calculate longitude \e lon2.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONGITUDE = GeodesicExact::LONGITUDE,
|
||||
/**
|
||||
* Calculate azimuths \e azi1 and \e azi2. (It's not necessary to
|
||||
* include this as a capability to GeodesicLineExact because this is
|
||||
* included by default.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AZIMUTH = GeodesicExact::AZIMUTH,
|
||||
/**
|
||||
* Calculate distance \e s12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DISTANCE = GeodesicExact::DISTANCE,
|
||||
/**
|
||||
* Allow distance \e s12 to be used as input in the direct geodesic
|
||||
* problem.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DISTANCE_IN = GeodesicExact::DISTANCE_IN,
|
||||
/**
|
||||
* Calculate reduced length \e m12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
REDUCEDLENGTH = GeodesicExact::REDUCEDLENGTH,
|
||||
/**
|
||||
* Calculate geodesic scales \e M12 and \e M21.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
GEODESICSCALE = GeodesicExact::GEODESICSCALE,
|
||||
/**
|
||||
* Calculate area \e S12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AREA = GeodesicExact::AREA,
|
||||
/**
|
||||
* Unroll \e lon2 in the direct calculation.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONG_UNROLL = GeodesicExact::LONG_UNROLL,
|
||||
/**
|
||||
* All capabilities, calculate everything. (LONG_UNROLL is not
|
||||
* included in this mask.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
ALL = GeodesicExact::ALL,
|
||||
};
|
||||
|
||||
/** \name Constructors
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Constructor for a geodesic line staring at latitude \e lat1, longitude
|
||||
* \e lon1, and azimuth \e azi1 (all in degrees).
|
||||
*
|
||||
* @param[in] g A GeodesicExact object used to compute the necessary
|
||||
* information about the GeodesicLineExact.
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi1 azimuth at point 1 (degrees).
|
||||
* @param[in] caps bitor'ed combination of GeodesicLineExact::mask values
|
||||
* specifying the capabilities the GeodesicLineExact object should
|
||||
* possess, i.e., which quantities can be returned in calls to
|
||||
* GeodesicLine::Position.
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°].
|
||||
*
|
||||
* The GeodesicLineExact::mask values are
|
||||
* - \e caps |= GeodesicLineExact::LATITUDE for the latitude \e lat2; this
|
||||
* is added automatically;
|
||||
* - \e caps |= GeodesicLineExact::LONGITUDE for the latitude \e lon2;
|
||||
* - \e caps |= GeodesicLineExact::AZIMUTH for the latitude \e azi2; this
|
||||
* is added automatically;
|
||||
* - \e caps |= GeodesicLineExact::DISTANCE for the distance \e s12;
|
||||
* - \e caps |= GeodesicLineExact::REDUCEDLENGTH for the reduced length \e
|
||||
m12;
|
||||
* - \e caps |= GeodesicLineExact::GEODESICSCALE for the geodesic scales \e
|
||||
* M12 and \e M21;
|
||||
* - \e caps |= GeodesicLineExact::AREA for the area \e S12;
|
||||
* - \e caps |= GeodesicLineExact::DISTANCE_IN permits the length of the
|
||||
* geodesic to be given in terms of \e s12; without this capability the
|
||||
* length can only be specified in terms of arc length;
|
||||
* - \e caps |= GeodesicLineExact::ALL for all of the above.
|
||||
* .
|
||||
* The default value of \e caps is GeodesicLineExact::ALL.
|
||||
*
|
||||
* If the point is at a pole, the azimuth is defined by keeping \e lon1
|
||||
* fixed, writing \e lat1 = ±(90° − ε), and taking
|
||||
* the limit ε → 0+.
|
||||
**********************************************************************/
|
||||
GeodesicLineExact(const GeodesicExact& g, real lat1, real lon1, real azi1,
|
||||
unsigned caps = ALL);
|
||||
|
||||
/**
|
||||
* A default constructor. If GeodesicLineExact::Position is called on the
|
||||
* resulting object, it returns immediately (without doing any
|
||||
* calculations). The object can be set with a call to
|
||||
* GeodesicExact::Line. Use Init() to test whether object is still in this
|
||||
* uninitialized state.
|
||||
**********************************************************************/
|
||||
GeodesicLineExact() : _caps(0U) {}
|
||||
///@}
|
||||
|
||||
/** \name Position in terms of distance
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Compute the position of point 2 which is a distance \e s12 (meters)
|
||||
* from point 1.
|
||||
*
|
||||
* @param[in] s12 distance from point 1 to point 2 (meters); it can be
|
||||
* signed.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees); requires that the
|
||||
* GeodesicLineExact object was constructed with \e caps |=
|
||||
* GeodesicLineExact::LONGITUDE.
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] m12 reduced length of geodesic (meters); requires that the
|
||||
* GeodesicLineExact object was constructed with \e caps |=
|
||||
* GeodesicLineExact::REDUCEDLENGTH.
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless); requires that the GeodesicLineExact object was
|
||||
* constructed with \e caps |= GeodesicLineExact::GEODESICSCALE.
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless); requires that the GeodesicLineExact object was
|
||||
* constructed with \e caps |= GeodesicLineExact::GEODESICSCALE.
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>); requires
|
||||
* that the GeodesicLineExact object was constructed with \e caps |=
|
||||
* GeodesicLineExact::AREA.
|
||||
* @return \e a12 arc length from point 1 to point 2 (degrees).
|
||||
*
|
||||
* The values of \e lon2 and \e azi2 returned are in the range
|
||||
* [−180°, 180°].
|
||||
*
|
||||
* The GeodesicLineExact object \e must have been constructed with \e caps
|
||||
* |= GeodesicLineExact::DISTANCE_IN; otherwise Math::NaN() is returned and
|
||||
* no parameters are set. Requesting a value which the GeodesicLineExact
|
||||
* object is not capable of computing is not an error; the corresponding
|
||||
* argument will not be altered.
|
||||
*
|
||||
* The following functions are overloaded versions of
|
||||
* GeodesicLineExact::Position which omit some of the output parameters.
|
||||
* Note, however, that the arc length is always computed and returned as
|
||||
* the function value.
|
||||
**********************************************************************/
|
||||
Math::real Position(real s12,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& m12, real& M12, real& M21,
|
||||
real& S12) const {
|
||||
real t;
|
||||
return GenPosition(false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
REDUCEDLENGTH | GEODESICSCALE | AREA,
|
||||
lat2, lon2, azi2, t, m12, M12, M21, S12);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLineExact::Position.
|
||||
**********************************************************************/
|
||||
Math::real Position(real s12, real& lat2, real& lon2) const {
|
||||
real t;
|
||||
return GenPosition(false, s12,
|
||||
LATITUDE | LONGITUDE,
|
||||
lat2, lon2, t, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLineExact::Position.
|
||||
**********************************************************************/
|
||||
Math::real Position(real s12, real& lat2, real& lon2,
|
||||
real& azi2) const {
|
||||
real t;
|
||||
return GenPosition(false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH,
|
||||
lat2, lon2, azi2, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLineExact::Position.
|
||||
**********************************************************************/
|
||||
Math::real Position(real s12, real& lat2, real& lon2,
|
||||
real& azi2, real& m12) const {
|
||||
real t;
|
||||
return GenPosition(false, s12,
|
||||
LATITUDE | LONGITUDE |
|
||||
AZIMUTH | REDUCEDLENGTH,
|
||||
lat2, lon2, azi2, t, m12, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLineExact::Position.
|
||||
**********************************************************************/
|
||||
Math::real Position(real s12, real& lat2, real& lon2,
|
||||
real& azi2, real& M12, real& M21)
|
||||
const {
|
||||
real t;
|
||||
return GenPosition(false, s12,
|
||||
LATITUDE | LONGITUDE |
|
||||
AZIMUTH | GEODESICSCALE,
|
||||
lat2, lon2, azi2, t, t, M12, M21, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLineExact::Position.
|
||||
**********************************************************************/
|
||||
Math::real Position(real s12,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& m12, real& M12, real& M21)
|
||||
const {
|
||||
real t;
|
||||
return GenPosition(false, s12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
REDUCEDLENGTH | GEODESICSCALE,
|
||||
lat2, lon2, azi2, t, m12, M12, M21, t);
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name Position in terms of arc length
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Compute the position of point 2 which is an arc length \e a12 (degrees)
|
||||
* from point 1.
|
||||
*
|
||||
* @param[in] a12 arc length from point 1 to point 2 (degrees); it can
|
||||
* be signed.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees); requires that the
|
||||
* GeodesicLineExact object was constructed with \e caps |=
|
||||
* GeodesicLineExact::LONGITUDE.
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] s12 distance from point 1 to point 2 (meters); requires
|
||||
* that the GeodesicLineExact object was constructed with \e caps |=
|
||||
* GeodesicLineExact::DISTANCE.
|
||||
* @param[out] m12 reduced length of geodesic (meters); requires that the
|
||||
* GeodesicLineExact object was constructed with \e caps |=
|
||||
* GeodesicLineExact::REDUCEDLENGTH.
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless); requires that the GeodesicLineExact object was
|
||||
* constructed with \e caps |= GeodesicLineExact::GEODESICSCALE.
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless); requires that the GeodesicLineExact object was
|
||||
* constructed with \e caps |= GeodesicLineExact::GEODESICSCALE.
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>); requires
|
||||
* that the GeodesicLineExact object was constructed with \e caps |=
|
||||
* GeodesicLineExact::AREA.
|
||||
*
|
||||
* The values of \e lon2 and \e azi2 returned are in the range
|
||||
* [−180°, 180°].
|
||||
*
|
||||
* Requesting a value which the GeodesicLineExact object is not capable of
|
||||
* computing is not an error; the corresponding argument will not be
|
||||
* altered.
|
||||
*
|
||||
* The following functions are overloaded versions of
|
||||
* GeodesicLineExact::ArcPosition which omit some of the output parameters.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& m12, real& M12, real& M21,
|
||||
real& S12) const {
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE |
|
||||
REDUCEDLENGTH | GEODESICSCALE | AREA,
|
||||
lat2, lon2, azi2, s12, m12, M12, M21, S12);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLineExact::ArcPosition.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12, real& lat2, real& lon2)
|
||||
const {
|
||||
real t;
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE,
|
||||
lat2, lon2, t, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLineExact::ArcPosition.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12,
|
||||
real& lat2, real& lon2, real& azi2)
|
||||
const {
|
||||
real t;
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH,
|
||||
lat2, lon2, azi2, t, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLineExact::ArcPosition.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
|
||||
real& s12) const {
|
||||
real t;
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH | DISTANCE,
|
||||
lat2, lon2, azi2, s12, t, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLineExact::ArcPosition.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& m12) const {
|
||||
real t;
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
DISTANCE | REDUCEDLENGTH,
|
||||
lat2, lon2, azi2, s12, m12, t, t, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLineExact::ArcPosition.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& M12, real& M21)
|
||||
const {
|
||||
real t;
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
DISTANCE | GEODESICSCALE,
|
||||
lat2, lon2, azi2, s12, t, M12, M21, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* See the documentation for GeodesicLineExact::ArcPosition.
|
||||
**********************************************************************/
|
||||
void ArcPosition(real a12, real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& m12, real& M12, real& M21)
|
||||
const {
|
||||
real t;
|
||||
GenPosition(true, a12,
|
||||
LATITUDE | LONGITUDE | AZIMUTH |
|
||||
DISTANCE | REDUCEDLENGTH | GEODESICSCALE,
|
||||
lat2, lon2, azi2, s12, m12, M12, M21, t);
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name The general position function.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* The general position function. GeodesicLineExact::Position and
|
||||
* GeodesicLineExact::ArcPosition are defined in terms of this function.
|
||||
*
|
||||
* @param[in] arcmode boolean flag determining the meaning of the second
|
||||
* parameter; if \e arcmode is false, then the GeodesicLineExact object
|
||||
* must have been constructed with \e caps |=
|
||||
* GeodesicLineExact::DISTANCE_IN.
|
||||
* @param[in] s12_a12 if \e arcmode is false, this is the distance between
|
||||
* point 1 and point 2 (meters); otherwise it is the arc length between
|
||||
* point 1 and point 2 (degrees); it can be signed.
|
||||
* @param[in] outmask a bitor'ed combination of GeodesicLineExact::mask
|
||||
* values specifying which of the following parameters should be set.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees); requires that the
|
||||
* GeodesicLineExact object was constructed with \e caps |=
|
||||
* GeodesicLineExact::LONGITUDE.
|
||||
* @param[out] azi2 (forward) azimuth at point 2 (degrees).
|
||||
* @param[out] s12 distance from point 1 to point 2 (meters); requires
|
||||
* that the GeodesicLineExact object was constructed with \e caps |=
|
||||
* GeodesicLineExact::DISTANCE.
|
||||
* @param[out] m12 reduced length of geodesic (meters); requires that the
|
||||
* GeodesicLineExact object was constructed with \e caps |=
|
||||
* GeodesicLineExact::REDUCEDLENGTH.
|
||||
* @param[out] M12 geodesic scale of point 2 relative to point 1
|
||||
* (dimensionless); requires that the GeodesicLineExact object was
|
||||
* constructed with \e caps |= GeodesicLineExact::GEODESICSCALE.
|
||||
* @param[out] M21 geodesic scale of point 1 relative to point 2
|
||||
* (dimensionless); requires that the GeodesicLineExact object was
|
||||
* constructed with \e caps |= GeodesicLineExact::GEODESICSCALE.
|
||||
* @param[out] S12 area under the geodesic (meters<sup>2</sup>); requires
|
||||
* that the GeodesicLineExact object was constructed with \e caps |=
|
||||
* GeodesicLineExact::AREA.
|
||||
* @return \e a12 arc length from point 1 to point 2 (degrees).
|
||||
*
|
||||
* The GeodesicLineExact::mask values possible for \e outmask are
|
||||
* - \e outmask |= GeodesicLineExact::LATITUDE for the latitude \e lat2;
|
||||
* - \e outmask |= GeodesicLineExact::LONGITUDE for the latitude \e lon2;
|
||||
* - \e outmask |= GeodesicLineExact::AZIMUTH for the latitude \e azi2;
|
||||
* - \e outmask |= GeodesicLineExact::DISTANCE for the distance \e s12;
|
||||
* - \e outmask |= GeodesicLineExact::REDUCEDLENGTH for the reduced length
|
||||
* \e m12;
|
||||
* - \e outmask |= GeodesicLineExact::GEODESICSCALE for the geodesic scales
|
||||
* \e M12 and \e M21;
|
||||
* - \e outmask |= GeodesicLineExact::AREA for the area \e S12;
|
||||
* - \e outmask |= GeodesicLineExact::ALL for all of the above;
|
||||
* - \e outmask |= GeodesicLineExact::LONG_UNROLL to unroll \e lon2 instead
|
||||
* of wrapping it into the range [−180°, 180°].
|
||||
* .
|
||||
* Requesting a value which the GeodesicLineExact object is not capable of
|
||||
* computing is not an error; the corresponding argument will not be
|
||||
* altered. Note, however, that the arc length is always computed and
|
||||
* returned as the function value.
|
||||
*
|
||||
* With the GeodesicLineExact::LONG_UNROLL bit set, the quantity \e lon2
|
||||
* − \e lon1 indicates how many times and in what sense the geodesic
|
||||
* encircles the ellipsoid.
|
||||
**********************************************************************/
|
||||
Math::real GenPosition(bool arcmode, real s12_a12, unsigned outmask,
|
||||
real& lat2, real& lon2, real& azi2,
|
||||
real& s12, real& m12, real& M12, real& M21,
|
||||
real& S12) const;
|
||||
///@}
|
||||
|
||||
/** \name Setting point 3
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Specify position of point 3 in terms of distance.
|
||||
*
|
||||
* @param[in] s13 the distance from point 1 to point 3 (meters); it
|
||||
* can be negative.
|
||||
*
|
||||
* This is only useful if the GeodesicLineExact object has been constructed
|
||||
* with \e caps |= GeodesicLineExact::DISTANCE_IN.
|
||||
**********************************************************************/
|
||||
void SetDistance(real s13);
|
||||
|
||||
/**
|
||||
* Specify position of point 3 in terms of arc length.
|
||||
*
|
||||
* @param[in] a13 the arc length from point 1 to point 3 (degrees); it
|
||||
* can be negative.
|
||||
*
|
||||
* The distance \e s13 is only set if the GeodesicLineExact object has been
|
||||
* constructed with \e caps |= GeodesicLineExact::DISTANCE.
|
||||
**********************************************************************/
|
||||
void SetArc(real a13);
|
||||
|
||||
/**
|
||||
* Specify position of point 3 in terms of either distance or arc length.
|
||||
*
|
||||
* @param[in] arcmode boolean flag determining the meaning of the second
|
||||
* parameter; if \e arcmode is false, then the GeodesicLineExact object
|
||||
* must have been constructed with \e caps |=
|
||||
* GeodesicLineExact::DISTANCE_IN.
|
||||
* @param[in] s13_a13 if \e arcmode is false, this is the distance from
|
||||
* point 1 to point 3 (meters); otherwise it is the arc length from
|
||||
* point 1 to point 3 (degrees); it can be negative.
|
||||
**********************************************************************/
|
||||
void GenSetDistance(bool arcmode, real s13_a13);
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @return true if the object has been initialized.
|
||||
**********************************************************************/
|
||||
bool Init() const { return _caps != 0U; }
|
||||
|
||||
/**
|
||||
* @return \e lat1 the latitude of point 1 (degrees).
|
||||
**********************************************************************/
|
||||
Math::real Latitude() const
|
||||
{ return Init() ? _lat1 : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e lon1 the longitude of point 1 (degrees).
|
||||
**********************************************************************/
|
||||
Math::real Longitude() const
|
||||
{ return Init() ? _lon1 : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e azi1 the azimuth (degrees) of the geodesic line at point 1.
|
||||
**********************************************************************/
|
||||
Math::real Azimuth() const
|
||||
{ return Init() ? _azi1 : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* The sine and cosine of \e azi1.
|
||||
*
|
||||
* @param[out] sazi1 the sine of \e azi1.
|
||||
* @param[out] cazi1 the cosine of \e azi1.
|
||||
**********************************************************************/
|
||||
void Azimuth(real& sazi1, real& cazi1) const
|
||||
{ if (Init()) { sazi1 = _salp1; cazi1 = _calp1; } }
|
||||
|
||||
/**
|
||||
* @return \e azi0 the azimuth (degrees) of the geodesic line as it crosses
|
||||
* the equator in a northward direction.
|
||||
*
|
||||
* The result lies in [−90°, 90°].
|
||||
**********************************************************************/
|
||||
Math::real EquatorialAzimuth() const
|
||||
{ return Init() ? Math::atan2d(_salp0, _calp0) : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* The sine and cosine of \e azi0.
|
||||
*
|
||||
* @param[out] sazi0 the sine of \e azi0.
|
||||
* @param[out] cazi0 the cosine of \e azi0.
|
||||
**********************************************************************/
|
||||
void EquatorialAzimuth(real& sazi0, real& cazi0) const
|
||||
{ if (Init()) { sazi0 = _salp0; cazi0 = _calp0; } }
|
||||
|
||||
/**
|
||||
* @return \e a1 the arc length (degrees) between the northward equatorial
|
||||
* crossing and point 1.
|
||||
*
|
||||
* The result lies in (−180°, 180°].
|
||||
**********************************************************************/
|
||||
Math::real EquatorialArc() const {
|
||||
using std::atan2;
|
||||
return Init() ? atan2(_ssig1, _csig1) / Math::degree() : Math::NaN();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value inherited from the GeodesicExact object used in the
|
||||
* constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const
|
||||
{ return Init() ? _a : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value
|
||||
* inherited from the GeodesicExact object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const
|
||||
{ return Init() ? _f : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e caps the computational capabilities that this object was
|
||||
* constructed with. LATITUDE and AZIMUTH are always included.
|
||||
**********************************************************************/
|
||||
unsigned Capabilities() const { return _caps; }
|
||||
|
||||
/**
|
||||
* Test what capabilities are available.
|
||||
*
|
||||
* @param[in] testcaps a set of bitor'ed GeodesicLineExact::mask values.
|
||||
* @return true if the GeodesicLineExact object has all these capabilities.
|
||||
**********************************************************************/
|
||||
bool Capabilities(unsigned testcaps) const {
|
||||
testcaps &= OUT_ALL;
|
||||
return (_caps & testcaps) == testcaps;
|
||||
}
|
||||
|
||||
/**
|
||||
* The distance or arc length to point 3.
|
||||
*
|
||||
* @param[in] arcmode boolean flag determining the meaning of returned
|
||||
* value.
|
||||
* @return \e s13 if \e arcmode is false; \e a13 if \e arcmode is true.
|
||||
**********************************************************************/
|
||||
Math::real GenDistance(bool arcmode) const
|
||||
{ return Init() ? (arcmode ? _a13 : _s13) : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e s13, the distance to point 3 (meters).
|
||||
**********************************************************************/
|
||||
Math::real Distance() const { return GenDistance(false); }
|
||||
|
||||
/**
|
||||
* @return \e a13, the arc length to point 3 (degrees).
|
||||
**********************************************************************/
|
||||
Math::real Arc() const { return GenDistance(true); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_GEODESICLINEEXACT_HPP
|
||||
180
external/include/GeographicLib/Geohash.hpp
vendored
Normal file
180
external/include/GeographicLib/Geohash.hpp
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* \file Geohash.hpp
|
||||
* \brief Header for GeographicLib::Geohash class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2012-2017) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GEOHASH_HPP)
|
||||
#define GEOGRAPHICLIB_GEOHASH_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about dll vs string
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4251)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Conversions for geohashes
|
||||
*
|
||||
* Geohashes are described in
|
||||
* - https://en.wikipedia.org/wiki/Geohash
|
||||
* - http://geohash.org/
|
||||
* .
|
||||
* They provide a compact string representation of a particular geographic
|
||||
* location (expressed as latitude and longitude), with the property that if
|
||||
* trailing characters are dropped from the string the geographic location
|
||||
* remains nearby. The classes Georef and GARS implement similar compact
|
||||
* representations.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-Geohash.cpp
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT Geohash {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
static const int maxlen_ = 18;
|
||||
static const unsigned long long mask_ = 1ULL << 45;
|
||||
static const char* const lcdigits_;
|
||||
static const char* const ucdigits_;
|
||||
Geohash(); // Disable constructor
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Convert from geographic coordinates to a geohash.
|
||||
*
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[in] len the length of the resulting geohash.
|
||||
* @param[out] geohash the geohash.
|
||||
* @exception GeographicErr if \e lat is not in [−90°,
|
||||
* 90°].
|
||||
* @exception std::bad_alloc if memory for \e geohash can't be allocated.
|
||||
*
|
||||
* Internally, \e len is first put in the range [0, 18]. (\e len = 18
|
||||
* provides approximately 1μm precision.)
|
||||
*
|
||||
* If \e lat or \e lon is NaN, the returned geohash is "invalid".
|
||||
**********************************************************************/
|
||||
static void Forward(real lat, real lon, int len, std::string& geohash);
|
||||
|
||||
/**
|
||||
* Convert from a geohash to geographic coordinates.
|
||||
*
|
||||
* @param[in] geohash the geohash.
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] len the length of the geohash.
|
||||
* @param[in] centerp if true (the default) return the center of the
|
||||
* geohash location, otherwise return the south-west corner.
|
||||
* @exception GeographicErr if \e geohash contains illegal characters.
|
||||
*
|
||||
* Only the first 18 characters for \e geohash are considered. (18
|
||||
* characters provides approximately 1μm precision.) The case of the
|
||||
* letters in \e geohash is ignored.
|
||||
*
|
||||
* If the first 3 characters of \e geohash are "inv", then \e lat and \e
|
||||
* lon are set to NaN and \e len is unchanged. ("nan" is treated
|
||||
* similarly.)
|
||||
**********************************************************************/
|
||||
static void Reverse(const std::string& geohash, real& lat, real& lon,
|
||||
int& len, bool centerp = true);
|
||||
|
||||
/**
|
||||
* The latitude resolution of a geohash.
|
||||
*
|
||||
* @param[in] len the length of the geohash.
|
||||
* @return the latitude resolution (degrees).
|
||||
*
|
||||
* Internally, \e len is first put in the range [0, 18].
|
||||
**********************************************************************/
|
||||
static Math::real LatitudeResolution(int len) {
|
||||
using std::ldexp;
|
||||
len = (std::max)(0, (std::min)(int(maxlen_), len));
|
||||
return ldexp(real(180), -(5 * len / 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* The longitude resolution of a geohash.
|
||||
*
|
||||
* @param[in] len the length of the geohash.
|
||||
* @return the longitude resolution (degrees).
|
||||
*
|
||||
* Internally, \e len is first put in the range [0, 18].
|
||||
**********************************************************************/
|
||||
static Math::real LongitudeResolution(int len) {
|
||||
using std::ldexp;
|
||||
len = (std::max)(0, (std::min)(int(maxlen_), len));
|
||||
return ldexp(real(360), -(5 * len - 5 * len / 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* The geohash length required to meet a given geographic resolution.
|
||||
*
|
||||
* @param[in] res the minimum of resolution in latitude and longitude
|
||||
* (degrees).
|
||||
* @return geohash length.
|
||||
*
|
||||
* The returned length is in the range [0, 18].
|
||||
**********************************************************************/
|
||||
static int GeohashLength(real res) {
|
||||
using std::abs; res = abs(res);
|
||||
for (int len = 0; len < maxlen_; ++len)
|
||||
if (LongitudeResolution(len) <= res)
|
||||
return len;
|
||||
return maxlen_;
|
||||
}
|
||||
|
||||
/**
|
||||
* The geohash length required to meet a given geographic resolution.
|
||||
*
|
||||
* @param[in] latres the resolution in latitude (degrees).
|
||||
* @param[in] lonres the resolution in longitude (degrees).
|
||||
* @return geohash length.
|
||||
*
|
||||
* The returned length is in the range [0, 18].
|
||||
**********************************************************************/
|
||||
static int GeohashLength(real latres, real lonres) {
|
||||
using std::abs;
|
||||
latres = abs(latres);
|
||||
lonres = abs(lonres);
|
||||
for (int len = 0; len < maxlen_; ++len)
|
||||
if (LatitudeResolution(len) <= latres &&
|
||||
LongitudeResolution(len) <= lonres)
|
||||
return len;
|
||||
return maxlen_;
|
||||
}
|
||||
|
||||
/**
|
||||
* The decimal geographic precision required to match a given geohash
|
||||
* length. This is the number of digits needed after decimal point in a
|
||||
* decimal degrees representation.
|
||||
*
|
||||
* @param[in] len the length of the geohash.
|
||||
* @return the decimal precision (may be negative).
|
||||
*
|
||||
* Internally, \e len is first put in the range [0, 18]. The returned
|
||||
* decimal precision is in the range [−2, 12].
|
||||
**********************************************************************/
|
||||
static int DecimalPrecision(int len) {
|
||||
using std::floor; using std::log;
|
||||
return -int(floor(log(LatitudeResolution(len))/log(Math::real(10))));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_GEOHASH_HPP
|
||||
478
external/include/GeographicLib/Geoid.hpp
vendored
Normal file
478
external/include/GeographicLib/Geoid.hpp
vendored
Normal file
@@ -0,0 +1,478 @@
|
||||
/**
|
||||
* \file Geoid.hpp
|
||||
* \brief Header for GeographicLib::Geoid class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2009-2021) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GEOID_HPP)
|
||||
#define GEOGRAPHICLIB_GEOID_HPP 1
|
||||
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about dll vs vector and constant conditional expressions
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4251 4127)
|
||||
#endif
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GEOID_PGM_PIXEL_WIDTH)
|
||||
/**
|
||||
* The size of the pixel data in the pgm data files for the geoids. 2 is the
|
||||
* standard size corresponding to a maxval 2<sup>16</sup>−1. Setting it
|
||||
* to 4 uses a maxval of 2<sup>32</sup>−1 and changes the extension for
|
||||
* the data files from .pgm to .pgm4. Note that the format of these pgm4 files
|
||||
* is a non-standard extension of the pgm format.
|
||||
**********************************************************************/
|
||||
# define GEOGRAPHICLIB_GEOID_PGM_PIXEL_WIDTH 2
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Looking up the height of the geoid above the ellipsoid
|
||||
*
|
||||
* This class evaluates the height of one of the standard geoids, EGM84,
|
||||
* EGM96, or EGM2008 by bilinear or cubic interpolation into a rectangular
|
||||
* grid of data. These geoid models are documented in
|
||||
* - EGM84:
|
||||
* https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_egm84
|
||||
* - EGM96:
|
||||
* https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_egm96
|
||||
* - EGM2008:
|
||||
* https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_egm2008
|
||||
*
|
||||
* The geoids are defined in terms of spherical harmonics. However in order
|
||||
* to provide a quick and flexible method of evaluating the geoid heights,
|
||||
* this class evaluates the height by interpolation into a grid of
|
||||
* precomputed values.
|
||||
*
|
||||
* The height of the geoid above the ellipsoid, \e N, is sometimes called the
|
||||
* geoid undulation. It can be used to convert a height above the ellipsoid,
|
||||
* \e h, to the corresponding height above the geoid (the orthometric height,
|
||||
* roughly the height above mean sea level), \e H, using the relations
|
||||
*
|
||||
* \e h = \e N + \e H;
|
||||
* \e H = −\e N + \e h.
|
||||
*
|
||||
* See \ref geoid for details of how to install the data sets, the data
|
||||
* format, estimates of the interpolation errors, and how to use caching.
|
||||
*
|
||||
* This class is typically \e not thread safe in that a single instantiation
|
||||
* cannot be safely used by multiple threads because of the way the object
|
||||
* reads the data set and because it maintains a single-cell cache. If
|
||||
* multiple threads need to calculate geoid heights they should all construct
|
||||
* thread-local instantiations. Alternatively, set the optional \e
|
||||
* threadsafe parameter to true in the constructor. This causes the
|
||||
* constructor to read all the data into memory and to turn off the
|
||||
* single-cell caching which results in a Geoid object which \e is thread
|
||||
* safe.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-Geoid.cpp
|
||||
*
|
||||
* <a href="GeoidEval.1.html">GeoidEval</a> is a command-line utility
|
||||
* providing access to the functionality of Geoid.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT Geoid {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
#if GEOGRAPHICLIB_GEOID_PGM_PIXEL_WIDTH != 4
|
||||
typedef unsigned short pixel_t;
|
||||
static const unsigned pixel_size_ = 2;
|
||||
static const unsigned pixel_max_ = 0xffffu;
|
||||
#else
|
||||
typedef unsigned pixel_t;
|
||||
static const unsigned pixel_size_ = 4;
|
||||
static const unsigned pixel_max_ = 0xffffffffu;
|
||||
#endif
|
||||
static const unsigned stencilsize_ = 12;
|
||||
static const unsigned nterms_ = ((3 + 1) * (3 + 2))/2; // for a cubic fit
|
||||
static const int c0_;
|
||||
static const int c0n_;
|
||||
static const int c0s_;
|
||||
static const int c3_[stencilsize_ * nterms_];
|
||||
static const int c3n_[stencilsize_ * nterms_];
|
||||
static const int c3s_[stencilsize_ * nterms_];
|
||||
|
||||
std::string _name, _dir, _filename;
|
||||
const bool _cubic;
|
||||
const real _a, _e2, _degree, _eps;
|
||||
mutable std::ifstream _file;
|
||||
real _rlonres, _rlatres;
|
||||
std::string _description, _datetime;
|
||||
real _offset, _scale, _maxerror, _rmserror;
|
||||
int _width, _height;
|
||||
unsigned long long _datastart, _swidth;
|
||||
bool _threadsafe;
|
||||
// Area cache
|
||||
mutable std::vector< std::vector<pixel_t> > _data;
|
||||
mutable bool _cache;
|
||||
// NE corner and extent of cache
|
||||
mutable int _xoffset, _yoffset, _xsize, _ysize;
|
||||
// Cell cache
|
||||
mutable int _ix, _iy;
|
||||
mutable real _v00, _v01, _v10, _v11;
|
||||
mutable real _t[nterms_];
|
||||
void filepos(int ix, int iy) const {
|
||||
_file.seekg(std::streamoff
|
||||
(_datastart +
|
||||
pixel_size_ * (unsigned(iy)*_swidth + unsigned(ix))));
|
||||
}
|
||||
real rawval(int ix, int iy) const {
|
||||
if (ix < 0)
|
||||
ix += _width;
|
||||
else if (ix >= _width)
|
||||
ix -= _width;
|
||||
if (_cache && iy >= _yoffset && iy < _yoffset + _ysize &&
|
||||
((ix >= _xoffset && ix < _xoffset + _xsize) ||
|
||||
(ix + _width >= _xoffset && ix + _width < _xoffset + _xsize))) {
|
||||
return real(_data[iy - _yoffset]
|
||||
[ix >= _xoffset ? ix - _xoffset : ix + _width - _xoffset]);
|
||||
} else {
|
||||
if (iy < 0 || iy >= _height) {
|
||||
iy = iy < 0 ? -iy : 2 * (_height - 1) - iy;
|
||||
ix += (ix < _width/2 ? 1 : -1) * _width/2;
|
||||
}
|
||||
try {
|
||||
filepos(ix, iy);
|
||||
// initial values to suppress warnings in case get fails
|
||||
char a = 0, b = 0;
|
||||
_file.get(a);
|
||||
_file.get(b);
|
||||
unsigned r = ((unsigned char)(a) << 8) | (unsigned char)(b);
|
||||
if (pixel_size_ == 4) {
|
||||
_file.get(a);
|
||||
_file.get(b);
|
||||
r = (r << 16) | ((unsigned char)(a) << 8) | (unsigned char)(b);
|
||||
}
|
||||
return real(r);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
// throw GeographicErr("Error reading " + _filename + ": "
|
||||
// + e.what());
|
||||
// triggers complaints about the "binary '+'" under Visual Studio.
|
||||
// So use '+=' instead.
|
||||
std::string err("Error reading ");
|
||||
err += _filename;
|
||||
err += ": ";
|
||||
err += e.what();
|
||||
throw GeographicErr(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
real height(real lat, real lon) const;
|
||||
Geoid(const Geoid&) = delete; // copy constructor not allowed
|
||||
Geoid& operator=(const Geoid&) = delete; // copy assignment not allowed
|
||||
public:
|
||||
|
||||
/**
|
||||
* Flags indicating conversions between heights above the geoid and heights
|
||||
* above the ellipsoid.
|
||||
**********************************************************************/
|
||||
enum convertflag {
|
||||
/**
|
||||
* The multiplier for converting from heights above the geoid to heights
|
||||
* above the ellipsoid.
|
||||
**********************************************************************/
|
||||
ELLIPSOIDTOGEOID = -1,
|
||||
/**
|
||||
* No conversion.
|
||||
**********************************************************************/
|
||||
NONE = 0,
|
||||
/**
|
||||
* The multiplier for converting from heights above the ellipsoid to
|
||||
* heights above the geoid.
|
||||
**********************************************************************/
|
||||
GEOIDTOELLIPSOID = 1,
|
||||
};
|
||||
|
||||
/** \name Setting up the geoid
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Construct a geoid.
|
||||
*
|
||||
* @param[in] name the name of the geoid.
|
||||
* @param[in] path (optional) directory for data file.
|
||||
* @param[in] cubic (optional) interpolation method; false means bilinear,
|
||||
* true (the default) means cubic.
|
||||
* @param[in] threadsafe (optional), if true, construct a thread safe
|
||||
* object. The default is false
|
||||
* @exception GeographicErr if the data file cannot be found, is
|
||||
* unreadable, or is corrupt.
|
||||
* @exception GeographicErr if \e threadsafe is true but the memory
|
||||
* necessary for caching the data can't be allocated.
|
||||
*
|
||||
* The data file is formed by appending ".pgm" to the name. If \e path is
|
||||
* specified (and is non-empty), then the file is loaded from directory, \e
|
||||
* path. Otherwise the path is given by DefaultGeoidPath(). If the \e
|
||||
* threadsafe parameter is true, the data set is read into memory, the data
|
||||
* file is closed, and single-cell caching is turned off; this results in a
|
||||
* Geoid object which \e is thread safe.
|
||||
**********************************************************************/
|
||||
explicit Geoid(const std::string& name, const std::string& path = "",
|
||||
bool cubic = true, bool threadsafe = false);
|
||||
|
||||
/**
|
||||
* Set up a cache.
|
||||
*
|
||||
* @param[in] south latitude (degrees) of the south edge of the cached
|
||||
* area.
|
||||
* @param[in] west longitude (degrees) of the west edge of the cached area.
|
||||
* @param[in] north latitude (degrees) of the north edge of the cached
|
||||
* area.
|
||||
* @param[in] east longitude (degrees) of the east edge of the cached area.
|
||||
* @exception GeographicErr if the memory necessary for caching the data
|
||||
* can't be allocated (in this case, you will have no cache and can try
|
||||
* again with a smaller area).
|
||||
* @exception GeographicErr if there's a problem reading the data.
|
||||
* @exception GeographicErr if this is called on a threadsafe Geoid.
|
||||
*
|
||||
* Cache the data for the specified "rectangular" area bounded by the
|
||||
* parallels \e south and \e north and the meridians \e west and \e east.
|
||||
* \e east is always interpreted as being east of \e west, if necessary by
|
||||
* adding 360° to its value. \e south and \e north should be in
|
||||
* the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
void CacheArea(real south, real west, real north, real east) const;
|
||||
|
||||
/**
|
||||
* Cache all the data.
|
||||
*
|
||||
* @exception GeographicErr if the memory necessary for caching the data
|
||||
* can't be allocated (in this case, you will have no cache and can try
|
||||
* again with a smaller area).
|
||||
* @exception GeographicErr if there's a problem reading the data.
|
||||
* @exception GeographicErr if this is called on a threadsafe Geoid.
|
||||
*
|
||||
* On most computers, this is fast for data sets with grid resolution of 5'
|
||||
* or coarser. For a 1' grid, the required RAM is 450MB; a 2.5' grid needs
|
||||
* 72MB; and a 5' grid needs 18MB.
|
||||
**********************************************************************/
|
||||
void CacheAll() const { CacheArea(real(-90), real(0),
|
||||
real(90), real(360)); }
|
||||
|
||||
/**
|
||||
* Clear the cache. This never throws an error. (This does nothing with a
|
||||
* thread safe Geoid.)
|
||||
**********************************************************************/
|
||||
void CacheClear() const;
|
||||
|
||||
///@}
|
||||
|
||||
/** \name Compute geoid heights
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Compute the geoid height at a point
|
||||
*
|
||||
* @param[in] lat latitude of the point (degrees).
|
||||
* @param[in] lon longitude of the point (degrees).
|
||||
* @exception GeographicErr if there's a problem reading the data; this
|
||||
* never happens if (\e lat, \e lon) is within a successfully cached
|
||||
* area.
|
||||
* @return the height of the geoid above the ellipsoid (meters).
|
||||
*
|
||||
* The latitude should be in [−90°, 90°].
|
||||
**********************************************************************/
|
||||
Math::real operator()(real lat, real lon) const {
|
||||
return height(lat, lon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a height above the geoid to a height above the ellipsoid and
|
||||
* vice versa.
|
||||
*
|
||||
* @param[in] lat latitude of the point (degrees).
|
||||
* @param[in] lon longitude of the point (degrees).
|
||||
* @param[in] h height of the point (degrees).
|
||||
* @param[in] d a Geoid::convertflag specifying the direction of the
|
||||
* conversion; Geoid::GEOIDTOELLIPSOID means convert a height above the
|
||||
* geoid to a height above the ellipsoid; Geoid::ELLIPSOIDTOGEOID means
|
||||
* convert a height above the ellipsoid to a height above the geoid.
|
||||
* @exception GeographicErr if there's a problem reading the data; this
|
||||
* never happens if (\e lat, \e lon) is within a successfully cached
|
||||
* area.
|
||||
* @return converted height (meters).
|
||||
**********************************************************************/
|
||||
Math::real ConvertHeight(real lat, real lon, real h,
|
||||
convertflag d) const {
|
||||
return h + real(d) * height(lat, lon);
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return geoid description, if available, in the data file; if
|
||||
* absent, return "NONE".
|
||||
**********************************************************************/
|
||||
const std::string& Description() const { return _description; }
|
||||
|
||||
/**
|
||||
* @return date of the data file; if absent, return "UNKNOWN".
|
||||
**********************************************************************/
|
||||
const std::string& DateTime() const { return _datetime; }
|
||||
|
||||
/**
|
||||
* @return full file name used to load the geoid data.
|
||||
**********************************************************************/
|
||||
const std::string& GeoidFile() const { return _filename; }
|
||||
|
||||
/**
|
||||
* @return "name" used to load the geoid data (from the first argument of
|
||||
* the constructor).
|
||||
**********************************************************************/
|
||||
const std::string& GeoidName() const { return _name; }
|
||||
|
||||
/**
|
||||
* @return directory used to load the geoid data.
|
||||
**********************************************************************/
|
||||
const std::string& GeoidDirectory() const { return _dir; }
|
||||
|
||||
/**
|
||||
* @return interpolation method ("cubic" or "bilinear").
|
||||
**********************************************************************/
|
||||
const std::string Interpolation() const
|
||||
{ return std::string(_cubic ? "cubic" : "bilinear"); }
|
||||
|
||||
/**
|
||||
* @return estimate of the maximum interpolation and quantization error
|
||||
* (meters).
|
||||
*
|
||||
* This relies on the value being stored in the data file. If the value is
|
||||
* absent, return −1.
|
||||
**********************************************************************/
|
||||
Math::real MaxError() const { return _maxerror; }
|
||||
|
||||
/**
|
||||
* @return estimate of the RMS interpolation and quantization error
|
||||
* (meters).
|
||||
*
|
||||
* This relies on the value being stored in the data file. If the value is
|
||||
* absent, return −1.
|
||||
**********************************************************************/
|
||||
Math::real RMSError() const { return _rmserror; }
|
||||
|
||||
/**
|
||||
* @return offset (meters).
|
||||
*
|
||||
* This in used in converting from the pixel values in the data file to
|
||||
* geoid heights.
|
||||
**********************************************************************/
|
||||
Math::real Offset() const { return _offset; }
|
||||
|
||||
/**
|
||||
* @return scale (meters).
|
||||
*
|
||||
* This in used in converting from the pixel values in the data file to
|
||||
* geoid heights.
|
||||
**********************************************************************/
|
||||
Math::real Scale() const { return _scale; }
|
||||
|
||||
/**
|
||||
* @return true if the object is constructed to be thread safe.
|
||||
**********************************************************************/
|
||||
bool ThreadSafe() const { return _threadsafe; }
|
||||
|
||||
/**
|
||||
* @return true if a data cache is active.
|
||||
**********************************************************************/
|
||||
bool Cache() const { return _cache; }
|
||||
|
||||
/**
|
||||
* @return west edge of the cached area; the cache includes this edge.
|
||||
**********************************************************************/
|
||||
Math::real CacheWest() const {
|
||||
return _cache ? ((_xoffset + (_xsize == _width ? 0 : _cubic)
|
||||
+ _width/2) % _width - _width/2) / _rlonres :
|
||||
0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return east edge of the cached area; the cache excludes this edge.
|
||||
**********************************************************************/
|
||||
Math::real CacheEast() const {
|
||||
return _cache ?
|
||||
CacheWest() +
|
||||
(_xsize - (_xsize == _width ? 0 : 1 + 2 * _cubic)) / _rlonres :
|
||||
0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return north edge of the cached area; the cache includes this edge.
|
||||
**********************************************************************/
|
||||
Math::real CacheNorth() const {
|
||||
return _cache ? 90 - (_yoffset + _cubic) / _rlatres : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return south edge of the cached area; the cache excludes this edge
|
||||
* unless it's the south pole.
|
||||
**********************************************************************/
|
||||
Math::real CacheSouth() const {
|
||||
return _cache ? 90 - ( _yoffset + _ysize - 1 - _cubic) / _rlatres : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the WGS84 ellipsoid (meters).
|
||||
*
|
||||
* (The WGS84 value is returned because the supported geoid models are all
|
||||
* based on this ellipsoid.)
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const
|
||||
{ return Constants::WGS84_a(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the WGS84 ellipsoid.
|
||||
*
|
||||
* (The WGS84 value is returned because the supported geoid models are all
|
||||
* based on this ellipsoid.)
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return Constants::WGS84_f(); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* @return the default path for geoid data files.
|
||||
*
|
||||
* This is the value of the environment variable GEOGRAPHICLIB_GEOID_PATH,
|
||||
* if set; otherwise, it is $GEOGRAPHICLIB_DATA/geoids if the environment
|
||||
* variable GEOGRAPHICLIB_DATA is set; otherwise, it is a compile-time
|
||||
* default (/usr/local/share/GeographicLib/geoids on non-Windows systems
|
||||
* and C:/ProgramData/GeographicLib/geoids on Windows systems).
|
||||
**********************************************************************/
|
||||
static std::string DefaultGeoidPath();
|
||||
|
||||
/**
|
||||
* @return the default name for the geoid.
|
||||
*
|
||||
* This is the value of the environment variable GEOGRAPHICLIB_GEOID_NAME,
|
||||
* if set; otherwise, it is "egm96-5". The Geoid class does not use this
|
||||
* function; it is just provided as a convenience for a calling program
|
||||
* when constructing a Geoid object.
|
||||
**********************************************************************/
|
||||
static std::string DefaultGeoidName();
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_GEOID_HPP
|
||||
161
external/include/GeographicLib/Georef.hpp
vendored
Normal file
161
external/include/GeographicLib/Georef.hpp
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* \file Georef.hpp
|
||||
* \brief Header for GeographicLib::Georef class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2015-2021) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GEOREF_HPP)
|
||||
#define GEOGRAPHICLIB_GEOREF_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about dll vs string
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4251)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Conversions for the World Geographic Reference System (georef)
|
||||
*
|
||||
* The World Geographic Reference System is described in
|
||||
* - https://en.wikipedia.org/wiki/Georef
|
||||
* - https://web.archive.org/web/20161214054445/http://earth-info.nga.mil/GandG/coordsys/grids/georef.pdf
|
||||
* .
|
||||
* It provides a compact string representation of a geographic area
|
||||
* (expressed as latitude and longitude). The classes GARS and Geohash
|
||||
* implement similar compact representations.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-Georef.cpp
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT Georef {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
static const char* const digits_;
|
||||
static const char* const lontile_;
|
||||
static const char* const lattile_;
|
||||
static const char* const degrees_;
|
||||
enum {
|
||||
tile_ = 15, // The size of tile in degrees
|
||||
lonorig_ = -180, // Origin for longitude
|
||||
latorig_ = -90, // Origin for latitude
|
||||
base_ = 10, // Base for minutes
|
||||
baselen_ = 4,
|
||||
maxprec_ = 11, // approximately equivalent to MGRS class
|
||||
maxlen_ = baselen_ + 2 * maxprec_,
|
||||
};
|
||||
Georef(); // Disable constructor
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Convert from geographic coordinates to georef.
|
||||
*
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[in] prec the precision of the resulting georef.
|
||||
* @param[out] georef the georef string.
|
||||
* @exception GeographicErr if \e lat is not in [−90°,
|
||||
* 90°].
|
||||
* @exception std::bad_alloc if memory for \e georef can't be allocated.
|
||||
*
|
||||
* \e prec specifies the precision of \e georef as follows:
|
||||
* - \e prec = −1 (min), 15°
|
||||
* - \e prec = 0, 1°
|
||||
* - \e prec = 1, converted to \e prec = 2
|
||||
* - \e prec = 2, 1'
|
||||
* - \e prec = 3, 0.1'
|
||||
* - \e prec = 4, 0.01'
|
||||
* - \e prec = 5, 0.001'
|
||||
* - …
|
||||
* - \e prec = 11 (max), 10<sup>−9</sup>'
|
||||
*
|
||||
* If \e lat or \e lon is NaN, then \e georef is set to "INVALID".
|
||||
**********************************************************************/
|
||||
static void Forward(real lat, real lon, int prec, std::string& georef);
|
||||
|
||||
/**
|
||||
* Convert from Georef to geographic coordinates.
|
||||
*
|
||||
* @param[in] georef the Georef.
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] prec the precision of \e georef.
|
||||
* @param[in] centerp if true (the default) return the center
|
||||
* \e georef, otherwise return the south-west corner.
|
||||
* @exception GeographicErr if \e georef is illegal.
|
||||
*
|
||||
* The case of the letters in \e georef is ignored. \e prec is in the
|
||||
* range [−1, 11] and gives the precision of \e georef as follows:
|
||||
* - \e prec = −1 (min), 15°
|
||||
* - \e prec = 0, 1°
|
||||
* - \e prec = 1, not returned
|
||||
* - \e prec = 2, 1'
|
||||
* - \e prec = 3, 0.1'
|
||||
* - \e prec = 4, 0.01'
|
||||
* - \e prec = 5, 0.001'
|
||||
* - …
|
||||
* - \e prec = 11 (max), 10<sup>−9</sup>'
|
||||
*
|
||||
* If the first 3 characters of \e georef are "INV", then \e lat and \e lon
|
||||
* are set to NaN and \e prec is unchanged.
|
||||
**********************************************************************/
|
||||
static void Reverse(const std::string& georef, real& lat, real& lon,
|
||||
int& prec, bool centerp = true);
|
||||
|
||||
/**
|
||||
* The angular resolution of a Georef.
|
||||
*
|
||||
* @param[in] prec the precision of the Georef.
|
||||
* @return the latitude-longitude resolution (degrees).
|
||||
*
|
||||
* Internally, \e prec is first put in the range [−1, 11].
|
||||
**********************************************************************/
|
||||
static Math::real Resolution(int prec) {
|
||||
if (prec < 1)
|
||||
return real(prec < 0 ? 15 : 1);
|
||||
else {
|
||||
using std::pow;
|
||||
// Treat prec = 1 as 2.
|
||||
prec = (std::max)(2, (std::min)(int(maxprec_), prec));
|
||||
// Need extra real because, since C++11, pow(float, int) returns double
|
||||
return 1/(60 * real(pow(real(base_), prec - 2)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Georef precision required to meet a given geographic resolution.
|
||||
*
|
||||
* @param[in] res the minimum of resolution in latitude and longitude
|
||||
* (degrees).
|
||||
* @return Georef precision.
|
||||
*
|
||||
* The returned length is in the range [0, 11].
|
||||
**********************************************************************/
|
||||
static int Precision(real res) {
|
||||
using std::abs; res = abs(res);
|
||||
for (int prec = 0; prec < maxprec_; ++prec) {
|
||||
if (prec == 1)
|
||||
continue;
|
||||
if (Resolution(prec) <= res)
|
||||
return prec;
|
||||
}
|
||||
return maxprec_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_GEOREF_HPP
|
||||
221
external/include/GeographicLib/Gnomonic.hpp
vendored
Normal file
221
external/include/GeographicLib/Gnomonic.hpp
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
* \file Gnomonic.hpp
|
||||
* \brief Header for GeographicLib::Gnomonic class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2010-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GNOMONIC_HPP)
|
||||
#define GEOGRAPHICLIB_GNOMONIC_HPP 1
|
||||
|
||||
#include <GeographicLib/Geodesic.hpp>
|
||||
#include <GeographicLib/GeodesicLine.hpp>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief %Gnomonic projection
|
||||
*
|
||||
* %Gnomonic projection centered at an arbitrary position \e C on the
|
||||
* ellipsoid. This projection is derived in Section 8 of
|
||||
* - C. F. F. Karney,
|
||||
* <a href="https://doi.org/10.1007/s00190-012-0578-z">
|
||||
* Algorithms for geodesics</a>,
|
||||
* J. Geodesy <b>87</b>, 43--55 (2013);
|
||||
* DOI: <a href="https://doi.org/10.1007/s00190-012-0578-z">
|
||||
* 10.1007/s00190-012-0578-z</a>;
|
||||
* addenda:
|
||||
* <a href="https://geographiclib.sourceforge.io/geod-addenda.html">
|
||||
* geod-addenda.html</a>.
|
||||
* .
|
||||
* The projection of \e P is defined as follows: compute the geodesic line
|
||||
* from \e C to \e P; compute the reduced length \e m12, geodesic scale \e
|
||||
* M12, and ρ = <i>m12</i>/\e M12; finally \e x = ρ sin \e azi1; \e
|
||||
* y = ρ cos \e azi1, where \e azi1 is the azimuth of the geodesic at \e
|
||||
* C. The Gnomonic::Forward and Gnomonic::Reverse methods also return the
|
||||
* azimuth \e azi of the geodesic at \e P and reciprocal scale \e rk in the
|
||||
* azimuthal direction. The scale in the radial direction if
|
||||
* 1/<i>rk</i><sup>2</sup>.
|
||||
*
|
||||
* For a sphere, ρ is reduces to \e a tan(<i>s12</i>/<i>a</i>), where \e
|
||||
* s12 is the length of the geodesic from \e C to \e P, and the gnomonic
|
||||
* projection has the property that all geodesics appear as straight lines.
|
||||
* For an ellipsoid, this property holds only for geodesics interesting the
|
||||
* centers. However geodesic segments close to the center are approximately
|
||||
* straight.
|
||||
*
|
||||
* Consider a geodesic segment of length \e l. Let \e T be the point on the
|
||||
* geodesic (extended if necessary) closest to \e C the center of the
|
||||
* projection and \e t be the distance \e CT. To lowest order, the maximum
|
||||
* deviation (as a true distance) of the corresponding gnomonic line segment
|
||||
* (i.e., with the same end points) from the geodesic is<br>
|
||||
* <br>
|
||||
* (<i>K</i>(<i>T</i>) - <i>K</i>(<i>C</i>))
|
||||
* <i>l</i><sup>2</sup> \e t / 32.<br>
|
||||
* <br>
|
||||
* where \e K is the Gaussian curvature.
|
||||
*
|
||||
* This result applies for any surface. For an ellipsoid of revolution,
|
||||
* consider all geodesics whose end points are within a distance \e r of \e
|
||||
* C. For a given \e r, the deviation is maximum when the latitude of \e C
|
||||
* is 45°, when endpoints are a distance \e r away, and when their
|
||||
* azimuths from the center are ± 45° or ± 135°.
|
||||
* To lowest order in \e r and the flattening \e f, the deviation is \e f
|
||||
* (<i>r</i>/2<i>a</i>)<sup>3</sup> \e r.
|
||||
*
|
||||
* The conversions all take place using a Geodesic object (by default
|
||||
* Geodesic::WGS84()). For more information on geodesics see \ref geodesic.
|
||||
*
|
||||
* \warning The definition of this projection for a sphere is
|
||||
* standard. However, there is no standard for how it should be extended to
|
||||
* an ellipsoid. The choices are:
|
||||
* - Declare that the projection is undefined for an ellipsoid.
|
||||
* - Project to a tangent plane from the center of the ellipsoid. This
|
||||
* causes great ellipses to appear as straight lines in the projection;
|
||||
* i.e., it generalizes the spherical great circle to a great ellipse.
|
||||
* This was proposed by independently by Bowring and Williams in 1997.
|
||||
* - Project to the conformal sphere with the constant of integration chosen
|
||||
* so that the values of the latitude match for the center point and
|
||||
* perform a central projection onto the plane tangent to the conformal
|
||||
* sphere at the center point. This causes normal sections through the
|
||||
* center point to appear as straight lines in the projection; i.e., it
|
||||
* generalizes the spherical great circle to a normal section. This was
|
||||
* proposed by I. G. Letoval'tsev, Generalization of the gnomonic
|
||||
* projection for a spheroid and the principal geodetic problems involved
|
||||
* in the alignment of surface routes, Geodesy and Aerophotography (5),
|
||||
* 271--274 (1963).
|
||||
* - The projection given here. This causes geodesics close to the center
|
||||
* point to appear as straight lines in the projection; i.e., it
|
||||
* generalizes the spherical great circle to a geodesic.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-Gnomonic.cpp
|
||||
*
|
||||
* <a href="GeodesicProj.1.html">GeodesicProj</a> is a command-line utility
|
||||
* providing access to the functionality of AzimuthalEquidistant, Gnomonic,
|
||||
* and CassiniSoldner.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT Gnomonic {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
real eps0_, eps_;
|
||||
Geodesic _earth;
|
||||
real _a, _f;
|
||||
// numit_ increased from 10 to 20 to fix convergence failure with high
|
||||
// precision (e.g., GEOGRAPHICLIB_DIGITS=2000) calculations. Reverse uses
|
||||
// Newton's method which converges quadratically and so numit_ = 10 would
|
||||
// normally be big enough. However, since the Geodesic class is based on a
|
||||
// series it is of limited accuracy; in particular, the derivative rules
|
||||
// used by Reverse only hold approximately. Consequently, after a few
|
||||
// iterations, the convergence in the Reverse falls back to improvements in
|
||||
// each step by a constant (albeit small) factor.
|
||||
static const int numit_ = 20;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for Gnomonic.
|
||||
*
|
||||
* @param[in] earth the Geodesic object to use for geodesic calculations.
|
||||
* By default this uses the WGS84 ellipsoid.
|
||||
**********************************************************************/
|
||||
explicit Gnomonic(const Geodesic& earth = Geodesic::WGS84());
|
||||
|
||||
/**
|
||||
* Forward projection, from geographic to gnomonic.
|
||||
*
|
||||
* @param[in] lat0 latitude of center point of projection (degrees).
|
||||
* @param[in] lon0 longitude of center point of projection (degrees).
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[out] x easting of point (meters).
|
||||
* @param[out] y northing of point (meters).
|
||||
* @param[out] azi azimuth of geodesic at point (degrees).
|
||||
* @param[out] rk reciprocal of azimuthal scale at point.
|
||||
*
|
||||
* \e lat0 and \e lat should be in the range [−90°, 90°].
|
||||
* The scale of the projection is 1/<i>rk</i><sup>2</sup> in the "radial"
|
||||
* direction, \e azi clockwise from true north, and is 1/\e rk in the
|
||||
* direction perpendicular to this. If the point lies "over the horizon",
|
||||
* i.e., if \e rk ≤ 0, then NaNs are returned for \e x and \e y (the
|
||||
* correct values are returned for \e azi and \e rk). A call to Forward
|
||||
* followed by a call to Reverse will return the original (\e lat, \e lon)
|
||||
* (to within roundoff) provided the point in not over the horizon.
|
||||
**********************************************************************/
|
||||
void Forward(real lat0, real lon0, real lat, real lon,
|
||||
real& x, real& y, real& azi, real& rk) const;
|
||||
|
||||
/**
|
||||
* Reverse projection, from gnomonic to geographic.
|
||||
*
|
||||
* @param[in] lat0 latitude of center point of projection (degrees).
|
||||
* @param[in] lon0 longitude of center point of projection (degrees).
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] azi azimuth of geodesic at point (degrees).
|
||||
* @param[out] rk reciprocal of azimuthal scale at point.
|
||||
*
|
||||
* \e lat0 should be in the range [−90°, 90°]. \e lat will
|
||||
* be in the range [−90°, 90°] and \e lon will be in the
|
||||
* range [−180°, 180°]. The scale of the projection is
|
||||
* 1/<i>rk</i><sup>2</sup> in the "radial" direction, \e azi clockwise from
|
||||
* true north, and is 1/\e rk in the direction perpendicular to this. Even
|
||||
* though all inputs should return a valid \e lat and \e lon, it's possible
|
||||
* that the procedure fails to converge for very large \e x or \e y; in
|
||||
* this case NaNs are returned for all the output arguments. A call to
|
||||
* Reverse followed by a call to Forward will return the original (\e x, \e
|
||||
* y) (to roundoff).
|
||||
**********************************************************************/
|
||||
void Reverse(real lat0, real lon0, real x, real y,
|
||||
real& lat, real& lon, real& azi, real& rk) const;
|
||||
|
||||
/**
|
||||
* Gnomonic::Forward without returning the azimuth and scale.
|
||||
**********************************************************************/
|
||||
void Forward(real lat0, real lon0, real lat, real lon,
|
||||
real& x, real& y) const {
|
||||
real azi, rk;
|
||||
Forward(lat0, lon0, lat, lon, x, y, azi, rk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gnomonic::Reverse without returning the azimuth and scale.
|
||||
**********************************************************************/
|
||||
void Reverse(real lat0, real lon0, real x, real y,
|
||||
real& lat, real& lon) const {
|
||||
real azi, rk;
|
||||
Reverse(lat0, lon0, x, y, lat, lon, azi, rk);
|
||||
}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value inherited from the Geodesic object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _earth.EquatorialRadius(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value
|
||||
* inherited from the Geodesic object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _earth.Flattening(); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_GNOMONIC_HPP
|
||||
287
external/include/GeographicLib/GravityCircle.hpp
vendored
Normal file
287
external/include/GeographicLib/GravityCircle.hpp
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
/**
|
||||
* \file GravityCircle.hpp
|
||||
* \brief Header for GeographicLib::GravityCircle class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2011-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GRAVITYCIRCLE_HPP)
|
||||
#define GEOGRAPHICLIB_GRAVITYCIRCLE_HPP 1
|
||||
|
||||
#include <vector>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/CircularEngine.hpp>
|
||||
#include <GeographicLib/GravityModel.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Gravity on a circle of latitude
|
||||
*
|
||||
* Evaluate the earth's gravity field on a circle of constant height and
|
||||
* latitude. This uses a CircularEngine to pre-evaluate the inner sum of the
|
||||
* spherical harmonic sum, allowing the values of the field at several
|
||||
* different longitudes to be evaluated rapidly.
|
||||
*
|
||||
* Use GravityModel::Circle to create a GravityCircle object. (The
|
||||
* constructor for this class is private.)
|
||||
*
|
||||
* See \ref gravityparallel for an example of using GravityCircle (together
|
||||
* with OpenMP) to speed up the computation of geoid heights.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-GravityCircle.cpp
|
||||
*
|
||||
* <a href="Gravity.1.html">Gravity</a> is a command-line utility providing
|
||||
* access to the functionality of GravityModel and GravityCircle.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT GravityCircle {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
enum mask {
|
||||
NONE = GravityModel::NONE,
|
||||
GRAVITY = GravityModel::GRAVITY,
|
||||
DISTURBANCE = GravityModel::DISTURBANCE,
|
||||
DISTURBING_POTENTIAL = GravityModel::DISTURBING_POTENTIAL,
|
||||
GEOID_HEIGHT = GravityModel::GEOID_HEIGHT,
|
||||
SPHERICAL_ANOMALY = GravityModel::SPHERICAL_ANOMALY,
|
||||
ALL = GravityModel::ALL,
|
||||
};
|
||||
|
||||
unsigned _caps;
|
||||
real _a, _f, _lat, _h, _Z, _Px, _invR, _cpsi, _spsi,
|
||||
_cphi, _sphi, _amodel, _GMmodel, _dzonal0,
|
||||
_corrmult, _gamma0, _gamma, _frot;
|
||||
CircularEngine _gravitational, _disturbing, _correction;
|
||||
|
||||
GravityCircle(mask caps, real a, real f, real lat, real h,
|
||||
real Z, real P, real cphi, real sphi,
|
||||
real amodel, real GMmodel,
|
||||
real dzonal0, real corrmult,
|
||||
real gamma0, real gamma, real frot,
|
||||
const CircularEngine& gravitational,
|
||||
const CircularEngine& disturbing,
|
||||
const CircularEngine& correction);
|
||||
|
||||
friend class GravityModel; // GravityModel calls the private constructor
|
||||
Math::real W(real slam, real clam,
|
||||
real& gX, real& gY, real& gZ) const;
|
||||
Math::real V(real slam, real clam,
|
||||
real& gX, real& gY, real& gZ) const;
|
||||
Math::real InternalT(real slam, real clam,
|
||||
real& deltaX, real& deltaY, real& deltaZ,
|
||||
bool gradp, bool correct) const;
|
||||
public:
|
||||
/**
|
||||
* A default constructor for the normal gravity. This sets up an
|
||||
* uninitialized object which can be later replaced by the
|
||||
* GravityModel::Circle.
|
||||
**********************************************************************/
|
||||
GravityCircle() : _a(-1) {}
|
||||
|
||||
/** \name Compute the gravitational field
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Evaluate the gravity.
|
||||
*
|
||||
* @param[in] lon the geographic longitude (degrees).
|
||||
* @param[out] gx the easterly component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] gy the northerly component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] gz the upward component of the acceleration
|
||||
* (m s<sup>−2</sup>); this is usually negative.
|
||||
* @return \e W the sum of the gravitational and centrifugal potentials
|
||||
* (m<sup>2</sup> s<sup>−2</sup>).
|
||||
*
|
||||
* The function includes the effects of the earth's rotation.
|
||||
**********************************************************************/
|
||||
Math::real Gravity(real lon, real& gx, real& gy, real& gz) const;
|
||||
|
||||
/**
|
||||
* Evaluate the gravity disturbance vector.
|
||||
*
|
||||
* @param[in] lon the geographic longitude (degrees).
|
||||
* @param[out] deltax the easterly component of the disturbance vector
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] deltay the northerly component of the disturbance vector
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] deltaz the upward component of the disturbance vector
|
||||
* (m s<sup>−2</sup>).
|
||||
* @return \e T the corresponding disturbing potential
|
||||
* (m<sup>2</sup> s<sup>−2</sup>).
|
||||
**********************************************************************/
|
||||
Math::real Disturbance(real lon, real& deltax, real& deltay, real& deltaz)
|
||||
const;
|
||||
|
||||
/**
|
||||
* Evaluate the geoid height.
|
||||
*
|
||||
* @param[in] lon the geographic longitude (degrees).
|
||||
* @return \e N the height of the geoid above the reference ellipsoid
|
||||
* (meters).
|
||||
*
|
||||
* Some approximations are made in computing the geoid height so that the
|
||||
* results of the NGA codes are reproduced accurately. Details are given
|
||||
* in \ref gravitygeoid.
|
||||
**********************************************************************/
|
||||
Math::real GeoidHeight(real lon) const;
|
||||
|
||||
/**
|
||||
* Evaluate the components of the gravity anomaly vector using the
|
||||
* spherical approximation.
|
||||
*
|
||||
* @param[in] lon the geographic longitude (degrees).
|
||||
* @param[out] Dg01 the gravity anomaly (m s<sup>−2</sup>).
|
||||
* @param[out] xi the northerly component of the deflection of the vertical
|
||||
* (degrees).
|
||||
* @param[out] eta the easterly component of the deflection of the vertical
|
||||
* (degrees).
|
||||
*
|
||||
* The spherical approximation (see Heiskanen and Moritz, Sec 2-14) is used
|
||||
* so that the results of the NGA codes are reproduced accurately.
|
||||
* approximations used here. Details are given in \ref gravitygeoid.
|
||||
**********************************************************************/
|
||||
void SphericalAnomaly(real lon, real& Dg01, real& xi, real& eta)
|
||||
const;
|
||||
|
||||
/**
|
||||
* Evaluate the components of the acceleration due to gravity and the
|
||||
* centrifugal acceleration in geocentric coordinates.
|
||||
*
|
||||
* @param[in] lon the geographic longitude (degrees).
|
||||
* @param[out] gX the \e X component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] gY the \e Y component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] gZ the \e Z component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @return \e W = \e V + Φ the sum of the gravitational and
|
||||
* centrifugal potentials (m<sup>2</sup> s<sup>−2</sup>).
|
||||
**********************************************************************/
|
||||
Math::real W(real lon, real& gX, real& gY, real& gZ) const {
|
||||
real slam, clam;
|
||||
Math::sincosd(lon, slam, clam);
|
||||
return W(slam, clam, gX, gY, gZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the components of the acceleration due to gravity in geocentric
|
||||
* coordinates.
|
||||
*
|
||||
* @param[in] lon the geographic longitude (degrees).
|
||||
* @param[out] GX the \e X component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] GY the \e Y component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] GZ the \e Z component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @return \e V = \e W - Φ the gravitational potential
|
||||
* (m<sup>2</sup> s<sup>−2</sup>).
|
||||
**********************************************************************/
|
||||
Math::real V(real lon, real& GX, real& GY, real& GZ) const {
|
||||
real slam, clam;
|
||||
Math::sincosd(lon, slam, clam);
|
||||
return V(slam, clam, GX, GY, GZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the components of the gravity disturbance in geocentric
|
||||
* coordinates.
|
||||
*
|
||||
* @param[in] lon the geographic longitude (degrees).
|
||||
* @param[out] deltaX the \e X component of the gravity disturbance
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] deltaY the \e Y component of the gravity disturbance
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] deltaZ the \e Z component of the gravity disturbance
|
||||
* (m s<sup>−2</sup>).
|
||||
* @return \e T = \e W - \e U the disturbing potential (also called the
|
||||
* anomalous potential) (m<sup>2</sup> s<sup>−2</sup>).
|
||||
**********************************************************************/
|
||||
Math::real T(real lon, real& deltaX, real& deltaY, real& deltaZ)
|
||||
const {
|
||||
real slam, clam;
|
||||
Math::sincosd(lon, slam, clam);
|
||||
return InternalT(slam, clam, deltaX, deltaY, deltaZ, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate disturbing potential in geocentric coordinates.
|
||||
*
|
||||
* @param[in] lon the geographic longitude (degrees).
|
||||
* @return \e T = \e W - \e U the disturbing potential (also called the
|
||||
* anomalous potential) (m<sup>2</sup> s<sup>−2</sup>).
|
||||
**********************************************************************/
|
||||
Math::real T(real lon) const {
|
||||
real slam, clam, dummy;
|
||||
Math::sincosd(lon, slam, clam);
|
||||
return InternalT(slam, clam, dummy, dummy, dummy, false, true);
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return true if the object has been initialized.
|
||||
**********************************************************************/
|
||||
bool Init() const { return _a > 0; }
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value inherited from the GravityModel object used in the
|
||||
* constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const
|
||||
{ return Init() ? _a : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value
|
||||
* inherited from the GravityModel object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const
|
||||
{ return Init() ? _f : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return the latitude of the circle (degrees).
|
||||
**********************************************************************/
|
||||
Math::real Latitude() const
|
||||
{ return Init() ? _lat : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return the height of the circle (meters).
|
||||
**********************************************************************/
|
||||
Math::real Height() const
|
||||
{ return Init() ? _h : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e caps the computational capabilities that this object was
|
||||
* constructed with.
|
||||
**********************************************************************/
|
||||
unsigned Capabilities() const { return _caps; }
|
||||
|
||||
/**
|
||||
* @param[in] testcaps a set of bitor'ed GravityModel::mask values.
|
||||
* @return true if the GravityCircle object has all these capabilities.
|
||||
**********************************************************************/
|
||||
bool Capabilities(unsigned testcaps) const {
|
||||
return (_caps & testcaps) == testcaps;
|
||||
}
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_GRAVITYCIRCLE_HPP
|
||||
549
external/include/GeographicLib/GravityModel.hpp
vendored
Normal file
549
external/include/GeographicLib/GravityModel.hpp
vendored
Normal file
@@ -0,0 +1,549 @@
|
||||
/**
|
||||
* \file GravityModel.hpp
|
||||
* \brief Header for GeographicLib::GravityModel class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2011-2021) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_GRAVITYMODEL_HPP)
|
||||
#define GEOGRAPHICLIB_GRAVITYMODEL_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/NormalGravity.hpp>
|
||||
#include <GeographicLib/SphericalHarmonic.hpp>
|
||||
#include <GeographicLib/SphericalHarmonic1.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about dll vs vector
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4251)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
class GravityCircle;
|
||||
|
||||
/**
|
||||
* \brief Model of the earth's gravity field
|
||||
*
|
||||
* Evaluate the earth's gravity field according to a model. The supported
|
||||
* models treat only the gravitational field exterior to the mass of the
|
||||
* earth. When computing the field at points near (but above) the surface of
|
||||
* the earth a small correction can be applied to account for the mass of the
|
||||
* atmosphere above the point in question; see \ref gravityatmos.
|
||||
* Determining the height of the geoid above the ellipsoid entails correcting
|
||||
* for the mass of the earth above the geoid. The egm96 and egm2008 include
|
||||
* separate correction terms to account for this mass.
|
||||
*
|
||||
* Definitions and terminology (from Heiskanen and Moritz, Sec 2-13):
|
||||
* - \e V = gravitational potential;
|
||||
* - Φ = rotational potential;
|
||||
* - \e W = \e V + Φ = \e T + \e U = total potential;
|
||||
* - <i>V</i><sub>0</sub> = normal gravitation potential;
|
||||
* - \e U = <i>V</i><sub>0</sub> + Φ = total normal potential;
|
||||
* - \e T = \e W − \e U = \e V − <i>V</i><sub>0</sub> = anomalous
|
||||
* or disturbing potential;
|
||||
* - <b>g</b> = ∇\e W = <b>γ</b> + <b>δ</b>;
|
||||
* - <b>f</b> = ∇Φ;
|
||||
* - <b>Γ</b> = ∇<i>V</i><sub>0</sub>;
|
||||
* - <b>γ</b> = ∇\e U;
|
||||
* - <b>δ</b> = ∇\e T = gravity disturbance vector
|
||||
* = <b>g</b><sub><i>P</i></sub> − <b>γ</b><sub><i>P</i></sub>;
|
||||
* - δ\e g = gravity disturbance = <i>g</i><sub><i>P</i></sub> −
|
||||
* γ<sub><i>P</i></sub>;
|
||||
* - Δ<b>g</b> = gravity anomaly vector = <b>g</b><sub><i>P</i></sub>
|
||||
* − <b>γ</b><sub><i>Q</i></sub>; here the line \e PQ is
|
||||
* perpendicular to ellipsoid and the potential at \e P equals the normal
|
||||
* potential at \e Q;
|
||||
* - Δ\e g = gravity anomaly = <i>g</i><sub><i>P</i></sub> −
|
||||
* γ<sub><i>Q</i></sub>;
|
||||
* - (ξ, η) deflection of the vertical, the difference in
|
||||
* directions of <b>g</b><sub><i>P</i></sub> and
|
||||
* <b>γ</b><sub><i>Q</i></sub>, ξ = NS, η = EW.
|
||||
* - \e X, \e Y, \e Z, geocentric coordinates;
|
||||
* - \e x, \e y, \e z, local cartesian coordinates used to denote the east,
|
||||
* north and up directions.
|
||||
*
|
||||
* See \ref gravity for details of how to install the gravity models and the
|
||||
* data format.
|
||||
*
|
||||
* References:
|
||||
* - W. A. Heiskanen and H. Moritz, Physical Geodesy (Freeman, San
|
||||
* Francisco, 1967).
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-GravityModel.cpp
|
||||
*
|
||||
* <a href="Gravity.1.html">Gravity</a> is a command-line utility providing
|
||||
* access to the functionality of GravityModel and GravityCircle.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT GravityModel {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
friend class GravityCircle;
|
||||
static const int idlength_ = 8;
|
||||
std::string _name, _dir, _description, _date, _filename, _id;
|
||||
real _amodel, _GMmodel, _zeta0, _corrmult;
|
||||
int _nmx, _mmx;
|
||||
SphericalHarmonic::normalization _norm;
|
||||
NormalGravity _earth;
|
||||
std::vector<real> _Cx, _Sx, _CC, _CS, _zonal;
|
||||
real _dzonal0; // A left over contribution to _zonal.
|
||||
SphericalHarmonic _gravitational;
|
||||
SphericalHarmonic1 _disturbing;
|
||||
SphericalHarmonic _correction;
|
||||
void ReadMetadata(const std::string& name);
|
||||
Math::real InternalT(real X, real Y, real Z,
|
||||
real& deltaX, real& deltaY, real& deltaZ,
|
||||
bool gradp, bool correct) const;
|
||||
GravityModel(const GravityModel&) = delete; // copy constructor not allowed
|
||||
// nor copy assignment
|
||||
GravityModel& operator=(const GravityModel&) = delete;
|
||||
|
||||
enum captype {
|
||||
CAP_NONE = 0U,
|
||||
CAP_G = 1U<<0, // implies potentials W and V
|
||||
CAP_T = 1U<<1,
|
||||
CAP_DELTA = 1U<<2 | CAP_T, // delta implies T?
|
||||
CAP_C = 1U<<3,
|
||||
CAP_GAMMA0 = 1U<<4,
|
||||
CAP_GAMMA = 1U<<5,
|
||||
CAP_ALL = 0x3FU,
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Bit masks for the capabilities to be given to the GravityCircle object
|
||||
* produced by Circle.
|
||||
**********************************************************************/
|
||||
enum mask {
|
||||
/**
|
||||
* No capabilities.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
NONE = 0U,
|
||||
/**
|
||||
* Allow calls to GravityCircle::Gravity, GravityCircle::W, and
|
||||
* GravityCircle::V.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
GRAVITY = CAP_G,
|
||||
/**
|
||||
* Allow calls to GravityCircle::Disturbance and GravityCircle::T.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DISTURBANCE = CAP_DELTA,
|
||||
/**
|
||||
* Allow calls to GravityCircle::T(real lon) (i.e., computing the
|
||||
* disturbing potential and not the gravity disturbance vector).
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DISTURBING_POTENTIAL = CAP_T,
|
||||
/**
|
||||
* Allow calls to GravityCircle::SphericalAnomaly.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
SPHERICAL_ANOMALY = CAP_DELTA | CAP_GAMMA,
|
||||
/**
|
||||
* Allow calls to GravityCircle::GeoidHeight.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
GEOID_HEIGHT = CAP_T | CAP_C | CAP_GAMMA0,
|
||||
/**
|
||||
* All capabilities.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
ALL = CAP_ALL,
|
||||
};
|
||||
/** \name Setting up the gravity model
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Construct a gravity model.
|
||||
*
|
||||
* @param[in] name the name of the model.
|
||||
* @param[in] path (optional) directory for data file.
|
||||
* @param[in] Nmax (optional) if non-negative, truncate the degree of the
|
||||
* model this value.
|
||||
* @param[in] Mmax (optional) if non-negative, truncate the order of the
|
||||
* model this value.
|
||||
* @exception GeographicErr if the data file cannot be found, is
|
||||
* unreadable, or is corrupt, or if \e Mmax > \e Nmax.
|
||||
* @exception std::bad_alloc if the memory necessary for storing the model
|
||||
* can't be allocated.
|
||||
*
|
||||
* A filename is formed by appending ".egm" (World Gravity Model) to the
|
||||
* name. If \e path is specified (and is non-empty), then the file is
|
||||
* loaded from directory, \e path. Otherwise the path is given by
|
||||
* DefaultGravityPath().
|
||||
*
|
||||
* This file contains the metadata which specifies the properties of the
|
||||
* model. The coefficients for the spherical harmonic sums are obtained
|
||||
* from a file obtained by appending ".cof" to metadata file (so the
|
||||
* filename ends in ".egm.cof").
|
||||
*
|
||||
* If \e Nmax ≥ 0 and \e Mmax < 0, then \e Mmax is set to \e Nmax.
|
||||
* After the model is loaded, the maximum degree and order of the model can
|
||||
* be found by the Degree() and Order() methods.
|
||||
**********************************************************************/
|
||||
explicit GravityModel(const std::string& name,
|
||||
const std::string& path = "",
|
||||
int Nmax = -1, int Mmax = -1);
|
||||
///@}
|
||||
|
||||
/** \name Compute gravity in geodetic coordinates
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Evaluate the gravity at an arbitrary point above (or below) the
|
||||
* ellipsoid.
|
||||
*
|
||||
* @param[in] lat the geographic latitude (degrees).
|
||||
* @param[in] lon the geographic longitude (degrees).
|
||||
* @param[in] h the height above the ellipsoid (meters).
|
||||
* @param[out] gx the easterly component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] gy the northerly component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] gz the upward component of the acceleration
|
||||
* (m s<sup>−2</sup>); this is usually negative.
|
||||
* @return \e W the sum of the gravitational and centrifugal potentials
|
||||
* (m<sup>2</sup> s<sup>−2</sup>).
|
||||
*
|
||||
* The function includes the effects of the earth's rotation.
|
||||
**********************************************************************/
|
||||
Math::real Gravity(real lat, real lon, real h,
|
||||
real& gx, real& gy, real& gz) const;
|
||||
|
||||
/**
|
||||
* Evaluate the gravity disturbance vector at an arbitrary point above (or
|
||||
* below) the ellipsoid.
|
||||
*
|
||||
* @param[in] lat the geographic latitude (degrees).
|
||||
* @param[in] lon the geographic longitude (degrees).
|
||||
* @param[in] h the height above the ellipsoid (meters).
|
||||
* @param[out] deltax the easterly component of the disturbance vector
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] deltay the northerly component of the disturbance vector
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] deltaz the upward component of the disturbance vector
|
||||
* (m s<sup>−2</sup>).
|
||||
* @return \e T the corresponding disturbing potential
|
||||
* (m<sup>2</sup> s<sup>−2</sup>).
|
||||
**********************************************************************/
|
||||
Math::real Disturbance(real lat, real lon, real h,
|
||||
real& deltax, real& deltay, real& deltaz)
|
||||
const;
|
||||
|
||||
/**
|
||||
* Evaluate the geoid height.
|
||||
*
|
||||
* @param[in] lat the geographic latitude (degrees).
|
||||
* @param[in] lon the geographic longitude (degrees).
|
||||
* @return \e N the height of the geoid above the ReferenceEllipsoid()
|
||||
* (meters).
|
||||
*
|
||||
* This calls NormalGravity::U for ReferenceEllipsoid(). Some
|
||||
* approximations are made in computing the geoid height so that the
|
||||
* results of the NGA codes are reproduced accurately. Details are given
|
||||
* in \ref gravitygeoid.
|
||||
**********************************************************************/
|
||||
Math::real GeoidHeight(real lat, real lon) const;
|
||||
|
||||
/**
|
||||
* Evaluate the components of the gravity anomaly vector using the
|
||||
* spherical approximation.
|
||||
*
|
||||
* @param[in] lat the geographic latitude (degrees).
|
||||
* @param[in] lon the geographic longitude (degrees).
|
||||
* @param[in] h the height above the ellipsoid (meters).
|
||||
* @param[out] Dg01 the gravity anomaly (m s<sup>−2</sup>).
|
||||
* @param[out] xi the northerly component of the deflection of the vertical
|
||||
* (degrees).
|
||||
* @param[out] eta the easterly component of the deflection of the vertical
|
||||
* (degrees).
|
||||
*
|
||||
* The spherical approximation (see Heiskanen and Moritz, Sec 2-14) is used
|
||||
* so that the results of the NGA codes are reproduced accurately.
|
||||
* approximations used here. Details are given in \ref gravitygeoid.
|
||||
**********************************************************************/
|
||||
void SphericalAnomaly(real lat, real lon, real h,
|
||||
real& Dg01, real& xi, real& eta) const;
|
||||
///@}
|
||||
|
||||
/** \name Compute gravity in geocentric coordinates
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Evaluate the components of the acceleration due to gravity and the
|
||||
* centrifugal acceleration in geocentric coordinates.
|
||||
*
|
||||
* @param[in] X geocentric coordinate of point (meters).
|
||||
* @param[in] Y geocentric coordinate of point (meters).
|
||||
* @param[in] Z geocentric coordinate of point (meters).
|
||||
* @param[out] gX the \e X component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] gY the \e Y component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] gZ the \e Z component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @return \e W = \e V + Φ the sum of the gravitational and
|
||||
* centrifugal potentials (m<sup>2</sup> s<sup>−2</sup>).
|
||||
*
|
||||
* This calls NormalGravity::U for ReferenceEllipsoid().
|
||||
**********************************************************************/
|
||||
Math::real W(real X, real Y, real Z,
|
||||
real& gX, real& gY, real& gZ) const;
|
||||
|
||||
/**
|
||||
* Evaluate the components of the acceleration due to gravity in geocentric
|
||||
* coordinates.
|
||||
*
|
||||
* @param[in] X geocentric coordinate of point (meters).
|
||||
* @param[in] Y geocentric coordinate of point (meters).
|
||||
* @param[in] Z geocentric coordinate of point (meters).
|
||||
* @param[out] GX the \e X component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] GY the \e Y component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] GZ the \e Z component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @return \e V = \e W - Φ the gravitational potential
|
||||
* (m<sup>2</sup> s<sup>−2</sup>).
|
||||
**********************************************************************/
|
||||
Math::real V(real X, real Y, real Z,
|
||||
real& GX, real& GY, real& GZ) const;
|
||||
|
||||
/**
|
||||
* Evaluate the components of the gravity disturbance in geocentric
|
||||
* coordinates.
|
||||
*
|
||||
* @param[in] X geocentric coordinate of point (meters).
|
||||
* @param[in] Y geocentric coordinate of point (meters).
|
||||
* @param[in] Z geocentric coordinate of point (meters).
|
||||
* @param[out] deltaX the \e X component of the gravity disturbance
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] deltaY the \e Y component of the gravity disturbance
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] deltaZ the \e Z component of the gravity disturbance
|
||||
* (m s<sup>−2</sup>).
|
||||
* @return \e T = \e W - \e U the disturbing potential (also called the
|
||||
* anomalous potential) (m<sup>2</sup> s<sup>−2</sup>).
|
||||
**********************************************************************/
|
||||
Math::real T(real X, real Y, real Z,
|
||||
real& deltaX, real& deltaY, real& deltaZ) const
|
||||
{ return InternalT(X, Y, Z, deltaX, deltaY, deltaZ, true, true); }
|
||||
|
||||
/**
|
||||
* Evaluate disturbing potential in geocentric coordinates.
|
||||
*
|
||||
* @param[in] X geocentric coordinate of point (meters).
|
||||
* @param[in] Y geocentric coordinate of point (meters).
|
||||
* @param[in] Z geocentric coordinate of point (meters).
|
||||
* @return \e T = \e W - \e U the disturbing potential (also called the
|
||||
* anomalous potential) (m<sup>2</sup> s<sup>−2</sup>).
|
||||
**********************************************************************/
|
||||
Math::real T(real X, real Y, real Z) const {
|
||||
real dummy;
|
||||
return InternalT(X, Y, Z, dummy, dummy, dummy, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the components of the acceleration due to normal gravity and
|
||||
* the centrifugal acceleration in geocentric coordinates.
|
||||
*
|
||||
* @param[in] X geocentric coordinate of point (meters).
|
||||
* @param[in] Y geocentric coordinate of point (meters).
|
||||
* @param[in] Z geocentric coordinate of point (meters).
|
||||
* @param[out] gammaX the \e X component of the normal acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] gammaY the \e Y component of the normal acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] gammaZ the \e Z component of the normal acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @return \e U = <i>V</i><sub>0</sub> + Φ the sum of the
|
||||
* normal gravitational and centrifugal potentials
|
||||
* (m<sup>2</sup> s<sup>−2</sup>).
|
||||
*
|
||||
* This calls NormalGravity::U for ReferenceEllipsoid().
|
||||
**********************************************************************/
|
||||
Math::real U(real X, real Y, real Z,
|
||||
real& gammaX, real& gammaY, real& gammaZ) const
|
||||
{ return _earth.U(X, Y, Z, gammaX, gammaY, gammaZ); }
|
||||
|
||||
/**
|
||||
* Evaluate the centrifugal acceleration in geocentric coordinates.
|
||||
*
|
||||
* @param[in] X geocentric coordinate of point (meters).
|
||||
* @param[in] Y geocentric coordinate of point (meters).
|
||||
* @param[out] fX the \e X component of the centrifugal acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] fY the \e Y component of the centrifugal acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @return Φ the centrifugal potential (m<sup>2</sup>
|
||||
* s<sup>−2</sup>).
|
||||
*
|
||||
* This calls NormalGravity::Phi for ReferenceEllipsoid().
|
||||
**********************************************************************/
|
||||
Math::real Phi(real X, real Y, real& fX, real& fY) const
|
||||
{ return _earth.Phi(X, Y, fX, fY); }
|
||||
///@}
|
||||
|
||||
/** \name Compute gravity on a circle of constant latitude
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Create a GravityCircle object to allow the gravity field at many points
|
||||
* with constant \e lat and \e h and varying \e lon to be computed
|
||||
* efficiently.
|
||||
*
|
||||
* @param[in] lat latitude of the point (degrees).
|
||||
* @param[in] h the height of the point above the ellipsoid (meters).
|
||||
* @param[in] caps bitor'ed combination of GravityModel::mask values
|
||||
* specifying the capabilities of the resulting GravityCircle object.
|
||||
* @exception std::bad_alloc if the memory necessary for creating a
|
||||
* GravityCircle can't be allocated.
|
||||
* @return a GravityCircle object whose member functions computes the
|
||||
* gravitational field at a particular values of \e lon.
|
||||
*
|
||||
* The GravityModel::mask values are
|
||||
* - \e caps |= GravityModel::GRAVITY
|
||||
* - \e caps |= GravityModel::DISTURBANCE
|
||||
* - \e caps |= GravityModel::DISTURBING_POTENTIAL
|
||||
* - \e caps |= GravityModel::SPHERICAL_ANOMALY
|
||||
* - \e caps |= GravityModel::GEOID_HEIGHT
|
||||
* .
|
||||
* The default value of \e caps is GravityModel::ALL which turns on all the
|
||||
* capabilities. If an unsupported function is invoked, it will return
|
||||
* NaNs. Note that GravityModel::GEOID_HEIGHT will only be honored if \e h
|
||||
* = 0.
|
||||
*
|
||||
* If the field at several points on a circle of latitude need to be
|
||||
* calculated then creating a GravityCircle object and using its member
|
||||
* functions will be substantially faster, especially for high-degree
|
||||
* models. See \ref gravityparallel for an example of using GravityCircle
|
||||
* (together with OpenMP) to speed up the computation of geoid heights.
|
||||
**********************************************************************/
|
||||
GravityCircle Circle(real lat, real h, unsigned caps = ALL) const;
|
||||
///@}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @return the NormalGravity object for the reference ellipsoid.
|
||||
**********************************************************************/
|
||||
const NormalGravity& ReferenceEllipsoid() const { return _earth; }
|
||||
|
||||
/**
|
||||
* @return the description of the gravity model, if available, in the data
|
||||
* file; if absent, return "NONE".
|
||||
**********************************************************************/
|
||||
const std::string& Description() const { return _description; }
|
||||
|
||||
/**
|
||||
* @return date of the model; if absent, return "UNKNOWN".
|
||||
**********************************************************************/
|
||||
const std::string& DateTime() const { return _date; }
|
||||
|
||||
/**
|
||||
* @return full file name used to load the gravity model.
|
||||
**********************************************************************/
|
||||
const std::string& GravityFile() const { return _filename; }
|
||||
|
||||
/**
|
||||
* @return "name" used to load the gravity model (from the first argument
|
||||
* of the constructor, but this may be overridden by the model file).
|
||||
**********************************************************************/
|
||||
const std::string& GravityModelName() const { return _name; }
|
||||
|
||||
/**
|
||||
* @return directory used to load the gravity model.
|
||||
**********************************************************************/
|
||||
const std::string& GravityModelDirectory() const { return _dir; }
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters).
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _earth.EquatorialRadius(); }
|
||||
|
||||
/**
|
||||
* @return \e GM the mass constant of the model (m<sup>3</sup>
|
||||
* s<sup>−2</sup>); this is the product of \e G the gravitational
|
||||
* constant and \e M the mass of the earth (usually including the mass of
|
||||
* the earth's atmosphere).
|
||||
**********************************************************************/
|
||||
Math::real MassConstant() const { return _GMmodel; }
|
||||
|
||||
/**
|
||||
* @return \e GM the mass constant of the ReferenceEllipsoid()
|
||||
* (m<sup>3</sup> s<sup>−2</sup>).
|
||||
**********************************************************************/
|
||||
Math::real ReferenceMassConstant() const
|
||||
{ return _earth.MassConstant(); }
|
||||
|
||||
/**
|
||||
* @return ω the angular velocity of the model and the
|
||||
* ReferenceEllipsoid() (rad s<sup>−1</sup>).
|
||||
**********************************************************************/
|
||||
Math::real AngularVelocity() const
|
||||
{ return _earth.AngularVelocity(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _earth.Flattening(); }
|
||||
|
||||
/**
|
||||
* @return \e Nmax the maximum degree of the components of the model.
|
||||
**********************************************************************/
|
||||
int Degree() const { return _nmx; }
|
||||
|
||||
/**
|
||||
* @return \e Mmax the maximum order of the components of the model.
|
||||
**********************************************************************/
|
||||
int Order() const { return _mmx; }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* @return the default path for gravity model data files.
|
||||
*
|
||||
* This is the value of the environment variable
|
||||
* GEOGRAPHICLIB_GRAVITY_PATH, if set; otherwise, it is
|
||||
* $GEOGRAPHICLIB_DATA/gravity if the environment variable
|
||||
* GEOGRAPHICLIB_DATA is set; otherwise, it is a compile-time default
|
||||
* (/usr/local/share/GeographicLib/gravity on non-Windows systems and
|
||||
* C:/ProgramData/GeographicLib/gravity on Windows systems).
|
||||
**********************************************************************/
|
||||
static std::string DefaultGravityPath();
|
||||
|
||||
/**
|
||||
* @return the default name for the gravity model.
|
||||
*
|
||||
* This is the value of the environment variable
|
||||
* GEOGRAPHICLIB_GRAVITY_NAME, if set; otherwise, it is "egm96". The
|
||||
* GravityModel class does not use this function; it is just provided as a
|
||||
* convenience for a calling program when constructing a GravityModel
|
||||
* object.
|
||||
**********************************************************************/
|
||||
static std::string DefaultGravityName();
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_GRAVITYMODEL_HPP
|
||||
330
external/include/GeographicLib/LambertConformalConic.hpp
vendored
Normal file
330
external/include/GeographicLib/LambertConformalConic.hpp
vendored
Normal file
@@ -0,0 +1,330 @@
|
||||
/**
|
||||
* \file LambertConformalConic.hpp
|
||||
* \brief Header for GeographicLib::LambertConformalConic class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2010-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_LAMBERTCONFORMALCONIC_HPP)
|
||||
#define GEOGRAPHICLIB_LAMBERTCONFORMALCONIC_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Lambert conformal conic projection
|
||||
*
|
||||
* Implementation taken from the report,
|
||||
* - J. P. Snyder,
|
||||
* <a href="http://pubs.er.usgs.gov/usgspubs/pp/pp1395"> Map Projections: A
|
||||
* Working Manual</a>, USGS Professional Paper 1395 (1987),
|
||||
* pp. 107--109.
|
||||
*
|
||||
* This is a implementation of the equations in Snyder except that divided
|
||||
* differences have been used to transform the expressions into ones which
|
||||
* may be evaluated accurately and that Newton's method is used to invert the
|
||||
* projection. In this implementation, the projection correctly becomes the
|
||||
* Mercator projection or the polar stereographic projection when the
|
||||
* standard latitude is the equator or a pole. The accuracy of the
|
||||
* projections is about 10 nm (10 nanometers).
|
||||
*
|
||||
* The ellipsoid parameters, the standard parallels, and the scale on the
|
||||
* standard parallels are set in the constructor. Internally, the case with
|
||||
* two standard parallels is converted into a single standard parallel, the
|
||||
* latitude of tangency (also the latitude of minimum scale), with a scale
|
||||
* specified on this parallel. This latitude is also used as the latitude of
|
||||
* origin which is returned by LambertConformalConic::OriginLatitude. The
|
||||
* scale on the latitude of origin is given by
|
||||
* LambertConformalConic::CentralScale. The case with two distinct standard
|
||||
* parallels where one is a pole is singular and is disallowed. The central
|
||||
* meridian (which is a trivial shift of the longitude) is specified as the
|
||||
* \e lon0 argument of the LambertConformalConic::Forward and
|
||||
* LambertConformalConic::Reverse functions.
|
||||
*
|
||||
* This class also returns the meridian convergence \e gamma and scale \e k.
|
||||
* The meridian convergence is the bearing of grid north (the \e y axis)
|
||||
* measured clockwise from true north.
|
||||
*
|
||||
* There is no provision in this
|
||||
* class for specifying a false easting or false northing or a different
|
||||
* latitude of origin. However these are can be simply included by the
|
||||
* calling function. For example the Pennsylvania South state coordinate
|
||||
* system (<a href="https://www.spatialreference.org/ref/epsg/3364/">
|
||||
* EPSG:3364</a>) is obtained by:
|
||||
* \include example-LambertConformalConic.cpp
|
||||
*
|
||||
* <a href="ConicProj.1.html">ConicProj</a> is a command-line utility
|
||||
* providing access to the functionality of LambertConformalConic and
|
||||
* AlbersEqualArea.
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT LambertConformalConic {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
real eps_, epsx_, ahypover_;
|
||||
real _a, _f, _fm, _e2, _es;
|
||||
real _sign, _n, _nc, _t0nm1, _scale, _lat0, _k0;
|
||||
real _scbet0, _tchi0, _scchi0, _psi0, _nrho0, _drhomax;
|
||||
static const int numit_ = 5;
|
||||
static real hyp(real x) {
|
||||
using std::hypot;
|
||||
return hypot(real(1), x);
|
||||
}
|
||||
// Divided differences
|
||||
// Definition: Df(x,y) = (f(x)-f(y))/(x-y)
|
||||
// See:
|
||||
// W. M. Kahan and R. J. Fateman,
|
||||
// Symbolic computation of divided differences,
|
||||
// SIGSAM Bull. 33(3), 7-28 (1999)
|
||||
// https://doi.org/10.1145/334714.334716
|
||||
// http://www.cs.berkeley.edu/~fateman/papers/divdiff.pdf
|
||||
//
|
||||
// General rules
|
||||
// h(x) = f(g(x)): Dh(x,y) = Df(g(x),g(y))*Dg(x,y)
|
||||
// h(x) = f(x)*g(x):
|
||||
// Dh(x,y) = Df(x,y)*g(x) + Dg(x,y)*f(y)
|
||||
// = Df(x,y)*g(y) + Dg(x,y)*f(x)
|
||||
// = Df(x,y)*(g(x)+g(y))/2 + Dg(x,y)*(f(x)+f(y))/2
|
||||
//
|
||||
// hyp(x) = sqrt(1+x^2): Dhyp(x,y) = (x+y)/(hyp(x)+hyp(y))
|
||||
static real Dhyp(real x, real y, real hx, real hy)
|
||||
// hx = hyp(x)
|
||||
{ return (x + y) / (hx + hy); }
|
||||
// sn(x) = x/sqrt(1+x^2): Dsn(x,y) = (x+y)/((sn(x)+sn(y))*(1+x^2)*(1+y^2))
|
||||
static real Dsn(real x, real y, real sx, real sy) {
|
||||
// sx = x/hyp(x)
|
||||
real t = x * y;
|
||||
return t > 0 ? (x + y) * Math::sq( (sx * sy)/t ) / (sx + sy) :
|
||||
(x - y != 0 ? (sx - sy) / (x - y) : 1);
|
||||
}
|
||||
// Dlog1p(x,y) = log1p((x-y)/(1+y))/(x-y)
|
||||
static real Dlog1p(real x, real y) {
|
||||
using std::log1p;
|
||||
real t = x - y; if (t < 0) { t = -t; y = x; }
|
||||
return t != 0 ? log1p(t / (1 + y)) / t : 1 / (1 + x);
|
||||
}
|
||||
// Dexp(x,y) = exp((x+y)/2) * 2*sinh((x-y)/2)/(x-y)
|
||||
static real Dexp(real x, real y) {
|
||||
using std::sinh; using std::exp;
|
||||
real t = (x - y)/2;
|
||||
return (t != 0 ? sinh(t)/t : 1) * exp((x + y)/2);
|
||||
}
|
||||
// Dsinh(x,y) = 2*sinh((x-y)/2)/(x-y) * cosh((x+y)/2)
|
||||
// cosh((x+y)/2) = (c+sinh(x)*sinh(y)/c)/2
|
||||
// c=sqrt((1+cosh(x))*(1+cosh(y)))
|
||||
// cosh((x+y)/2) = sqrt( (sinh(x)*sinh(y) + cosh(x)*cosh(y) + 1)/2 )
|
||||
static real Dsinh(real x, real y, real sx, real sy, real cx, real cy)
|
||||
// sx = sinh(x), cx = cosh(x)
|
||||
{
|
||||
// real t = (x - y)/2, c = sqrt((1 + cx) * (1 + cy));
|
||||
// return (t ? sinh(t)/t : real(1)) * (c + sx * sy / c) /2;
|
||||
using std::sinh; using std::sqrt;
|
||||
real t = (x - y)/2;
|
||||
return (t != 0 ? sinh(t)/t : 1) * sqrt((sx * sy + cx * cy + 1) /2);
|
||||
}
|
||||
// Dasinh(x,y) = asinh((x-y)*(x+y)/(x*sqrt(1+y^2)+y*sqrt(1+x^2)))/(x-y)
|
||||
// = asinh((x*sqrt(1+y^2)-y*sqrt(1+x^2)))/(x-y)
|
||||
static real Dasinh(real x, real y, real hx, real hy) {
|
||||
// hx = hyp(x)
|
||||
using std::asinh;
|
||||
real t = x - y;
|
||||
return t != 0 ?
|
||||
asinh(x*y > 0 ? t * (x + y) / (x*hy + y*hx) : x*hy - y*hx) / t :
|
||||
1 / hx;
|
||||
}
|
||||
// Deatanhe(x,y) = eatanhe((x-y)/(1-e^2*x*y))/(x-y)
|
||||
real Deatanhe(real x, real y) const {
|
||||
real t = x - y, d = 1 - _e2 * x * y;
|
||||
return t != 0 ? Math::eatanhe(t / d, _es) / t : _e2 / d;
|
||||
}
|
||||
void Init(real sphi1, real cphi1, real sphi2, real cphi2, real k1);
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor with a single standard parallel.
|
||||
*
|
||||
* @param[in] a equatorial radius of ellipsoid (meters).
|
||||
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
|
||||
* Negative \e f gives a prolate ellipsoid.
|
||||
* @param[in] stdlat standard parallel (degrees), the circle of tangency.
|
||||
* @param[in] k0 scale on the standard parallel.
|
||||
* @exception GeographicErr if \e a, (1 − \e f) \e a, or \e k0 is
|
||||
* not positive.
|
||||
* @exception GeographicErr if \e stdlat is not in [−90°,
|
||||
* 90°].
|
||||
**********************************************************************/
|
||||
LambertConformalConic(real a, real f, real stdlat, real k0);
|
||||
|
||||
/**
|
||||
* Constructor with two standard parallels.
|
||||
*
|
||||
* @param[in] a equatorial radius of ellipsoid (meters).
|
||||
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
|
||||
* Negative \e f gives a prolate ellipsoid.
|
||||
* @param[in] stdlat1 first standard parallel (degrees).
|
||||
* @param[in] stdlat2 second standard parallel (degrees).
|
||||
* @param[in] k1 scale on the standard parallels.
|
||||
* @exception GeographicErr if \e a, (1 − \e f) \e a, or \e k1 is
|
||||
* not positive.
|
||||
* @exception GeographicErr if \e stdlat1 or \e stdlat2 is not in
|
||||
* [−90°, 90°], or if either \e stdlat1 or \e
|
||||
* stdlat2 is a pole and \e stdlat1 is not equal \e stdlat2.
|
||||
**********************************************************************/
|
||||
LambertConformalConic(real a, real f, real stdlat1, real stdlat2, real k1);
|
||||
|
||||
/**
|
||||
* Constructor with two standard parallels specified by sines and cosines.
|
||||
*
|
||||
* @param[in] a equatorial radius of ellipsoid (meters).
|
||||
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
|
||||
* Negative \e f gives a prolate ellipsoid.
|
||||
* @param[in] sinlat1 sine of first standard parallel.
|
||||
* @param[in] coslat1 cosine of first standard parallel.
|
||||
* @param[in] sinlat2 sine of second standard parallel.
|
||||
* @param[in] coslat2 cosine of second standard parallel.
|
||||
* @param[in] k1 scale on the standard parallels.
|
||||
* @exception GeographicErr if \e a, (1 − \e f) \e a, or \e k1 is
|
||||
* not positive.
|
||||
* @exception GeographicErr if \e stdlat1 or \e stdlat2 is not in
|
||||
* [−90°, 90°], or if either \e stdlat1 or \e
|
||||
* stdlat2 is a pole and \e stdlat1 is not equal \e stdlat2.
|
||||
*
|
||||
* This allows parallels close to the poles to be specified accurately.
|
||||
* This routine computes the latitude of origin and the scale at this
|
||||
* latitude. In the case where \e lat1 and \e lat2 are different, the
|
||||
* errors in this routines are as follows: if \e dlat = abs(\e lat2 −
|
||||
* \e lat1) ≤ 160° and max(abs(\e lat1), abs(\e lat2)) ≤ 90
|
||||
* − min(0.0002, 2.2 × 10<sup>−6</sup>(180 − \e
|
||||
* dlat), 6 × 10<sup>−8</sup> <i>dlat</i><sup>2</sup>) (in
|
||||
* degrees), then the error in the latitude of origin is less than 4.5
|
||||
* × 10<sup>−14</sup>d and the relative error in the scale is
|
||||
* less than 7 × 10<sup>−15</sup>.
|
||||
**********************************************************************/
|
||||
LambertConformalConic(real a, real f,
|
||||
real sinlat1, real coslat1,
|
||||
real sinlat2, real coslat2,
|
||||
real k1);
|
||||
|
||||
/**
|
||||
* Set the scale for the projection.
|
||||
*
|
||||
* @param[in] lat (degrees).
|
||||
* @param[in] k scale at latitude \e lat (default 1).
|
||||
* @exception GeographicErr \e k is not positive.
|
||||
* @exception GeographicErr if \e lat is not in [−90°,
|
||||
* 90°].
|
||||
**********************************************************************/
|
||||
void SetScale(real lat, real k = real(1));
|
||||
|
||||
/**
|
||||
* Forward projection, from geographic to Lambert conformal conic.
|
||||
*
|
||||
* @param[in] lon0 central meridian longitude (degrees).
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[out] x easting of point (meters).
|
||||
* @param[out] y northing of point (meters).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k scale of projection at point.
|
||||
*
|
||||
* The latitude origin is given by LambertConformalConic::LatitudeOrigin().
|
||||
* No false easting or northing is added and \e lat should be in the range
|
||||
* [−90°, 90°]. The error in the projection is less than
|
||||
* about 10 nm (10 nanometers), true distance, and the errors in the
|
||||
* meridian convergence and scale are consistent with this. The values of
|
||||
* \e x and \e y returned for points which project to infinity (i.e., one
|
||||
* or both of the poles) will be large but finite.
|
||||
**********************************************************************/
|
||||
void Forward(real lon0, real lat, real lon,
|
||||
real& x, real& y, real& gamma, real& k) const;
|
||||
|
||||
/**
|
||||
* Reverse projection, from Lambert conformal conic to geographic.
|
||||
*
|
||||
* @param[in] lon0 central meridian longitude (degrees).
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k scale of projection at point.
|
||||
*
|
||||
* The latitude origin is given by LambertConformalConic::LatitudeOrigin().
|
||||
* No false easting or northing is added. The value of \e lon returned is
|
||||
* in the range [−180°, 180°]. The error in the projection
|
||||
* is less than about 10 nm (10 nanometers), true distance, and the errors
|
||||
* in the meridian convergence and scale are consistent with this.
|
||||
**********************************************************************/
|
||||
void Reverse(real lon0, real x, real y,
|
||||
real& lat, real& lon, real& gamma, real& k) const;
|
||||
|
||||
/**
|
||||
* LambertConformalConic::Forward without returning the convergence and
|
||||
* scale.
|
||||
**********************************************************************/
|
||||
void Forward(real lon0, real lat, real lon,
|
||||
real& x, real& y) const {
|
||||
real gamma, k;
|
||||
Forward(lon0, lat, lon, x, y, gamma, k);
|
||||
}
|
||||
|
||||
/**
|
||||
* LambertConformalConic::Reverse without returning the convergence and
|
||||
* scale.
|
||||
**********************************************************************/
|
||||
void Reverse(real lon0, real x, real y,
|
||||
real& lat, real& lon) const {
|
||||
real gamma, k;
|
||||
Reverse(lon0, x, y, lat, lon, gamma, k);
|
||||
}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _a; }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the
|
||||
* value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _f; }
|
||||
|
||||
/**
|
||||
* @return latitude of the origin for the projection (degrees).
|
||||
*
|
||||
* This is the latitude of minimum scale and equals the \e stdlat in the
|
||||
* 1-parallel constructor and lies between \e stdlat1 and \e stdlat2 in the
|
||||
* 2-parallel constructors.
|
||||
**********************************************************************/
|
||||
Math::real OriginLatitude() const { return _lat0; }
|
||||
|
||||
/**
|
||||
* @return central scale for the projection. This is the scale on the
|
||||
* latitude of origin.
|
||||
**********************************************************************/
|
||||
Math::real CentralScale() const { return _k0; }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* A global instantiation of LambertConformalConic with the WGS84
|
||||
* ellipsoid, \e stdlat = 0, and \e k0 = 1. This degenerates to the
|
||||
* Mercator projection.
|
||||
**********************************************************************/
|
||||
static const LambertConformalConic& Mercator();
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_LAMBERTCONFORMALCONIC_HPP
|
||||
244
external/include/GeographicLib/LocalCartesian.hpp
vendored
Normal file
244
external/include/GeographicLib/LocalCartesian.hpp
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* \file LocalCartesian.hpp
|
||||
* \brief Header for GeographicLib::LocalCartesian class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_LOCALCARTESIAN_HPP)
|
||||
#define GEOGRAPHICLIB_LOCALCARTESIAN_HPP 1
|
||||
|
||||
#include <GeographicLib/Geocentric.hpp>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Local cartesian coordinates
|
||||
*
|
||||
* Convert between geodetic coordinates latitude = \e lat, longitude = \e
|
||||
* lon, height = \e h (measured vertically from the surface of the ellipsoid)
|
||||
* to local cartesian coordinates (\e x, \e y, \e z). The origin of local
|
||||
* cartesian coordinate system is at \e lat = \e lat0, \e lon = \e lon0, \e h
|
||||
* = \e h0. The \e z axis is normal to the ellipsoid; the \e y axis points
|
||||
* due north. The plane \e z = - \e h0 is tangent to the ellipsoid.
|
||||
*
|
||||
* The conversions all take place via geocentric coordinates using a
|
||||
* Geocentric object (by default Geocentric::WGS84()).
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-LocalCartesian.cpp
|
||||
*
|
||||
* <a href="CartConvert.1.html">CartConvert</a> is a command-line utility
|
||||
* providing access to the functionality of Geocentric and LocalCartesian.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT LocalCartesian {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
static const size_t dim_ = 3;
|
||||
static const size_t dim2_ = dim_ * dim_;
|
||||
Geocentric _earth;
|
||||
real _lat0, _lon0, _h0;
|
||||
real _x0, _y0, _z0, _r[dim2_];
|
||||
void IntForward(real lat, real lon, real h, real& x, real& y, real& z,
|
||||
real M[dim2_]) const;
|
||||
void IntReverse(real x, real y, real z, real& lat, real& lon, real& h,
|
||||
real M[dim2_]) const;
|
||||
void MatrixMultiply(real M[dim2_]) const;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor setting the origin.
|
||||
*
|
||||
* @param[in] lat0 latitude at origin (degrees).
|
||||
* @param[in] lon0 longitude at origin (degrees).
|
||||
* @param[in] h0 height above ellipsoid at origin (meters); default 0.
|
||||
* @param[in] earth Geocentric object for the transformation; default
|
||||
* Geocentric::WGS84().
|
||||
*
|
||||
* \e lat0 should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
LocalCartesian(real lat0, real lon0, real h0 = 0,
|
||||
const Geocentric& earth = Geocentric::WGS84())
|
||||
: _earth(earth)
|
||||
{ Reset(lat0, lon0, h0); }
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* @param[in] earth Geocentric object for the transformation; default
|
||||
* Geocentric::WGS84().
|
||||
*
|
||||
* Sets \e lat0 = 0, \e lon0 = 0, \e h0 = 0.
|
||||
**********************************************************************/
|
||||
explicit LocalCartesian(const Geocentric& earth = Geocentric::WGS84())
|
||||
: _earth(earth)
|
||||
{ Reset(real(0), real(0), real(0)); }
|
||||
|
||||
/**
|
||||
* Reset the origin.
|
||||
*
|
||||
* @param[in] lat0 latitude at origin (degrees).
|
||||
* @param[in] lon0 longitude at origin (degrees).
|
||||
* @param[in] h0 height above ellipsoid at origin (meters); default 0.
|
||||
*
|
||||
* \e lat0 should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
void Reset(real lat0, real lon0, real h0 = 0);
|
||||
|
||||
/**
|
||||
* Convert from geodetic to local cartesian coordinates.
|
||||
*
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[in] h height of point above the ellipsoid (meters).
|
||||
* @param[out] x local cartesian coordinate (meters).
|
||||
* @param[out] y local cartesian coordinate (meters).
|
||||
* @param[out] z local cartesian coordinate (meters).
|
||||
*
|
||||
* \e lat should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
void Forward(real lat, real lon, real h, real& x, real& y, real& z)
|
||||
const {
|
||||
IntForward(lat, lon, h, x, y, z, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from geodetic to local cartesian coordinates and return rotation
|
||||
* matrix.
|
||||
*
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[in] h height of point above the ellipsoid (meters).
|
||||
* @param[out] x local cartesian coordinate (meters).
|
||||
* @param[out] y local cartesian coordinate (meters).
|
||||
* @param[out] z local cartesian coordinate (meters).
|
||||
* @param[out] M if the length of the vector is 9, fill with the rotation
|
||||
* matrix in row-major order.
|
||||
*
|
||||
* \e lat should be in the range [−90°, 90°].
|
||||
*
|
||||
* Let \e v be a unit vector located at (\e lat, \e lon, \e h). We can
|
||||
* express \e v as \e column vectors in one of two ways
|
||||
* - in east, north, up coordinates (where the components are relative to a
|
||||
* local coordinate system at (\e lat, \e lon, \e h)); call this
|
||||
* representation \e v1.
|
||||
* - in \e x, \e y, \e z coordinates (where the components are relative to
|
||||
* the local coordinate system at (\e lat0, \e lon0, \e h0)); call this
|
||||
* representation \e v0.
|
||||
* .
|
||||
* Then we have \e v0 = \e M ⋅ \e v1.
|
||||
**********************************************************************/
|
||||
void Forward(real lat, real lon, real h, real& x, real& y, real& z,
|
||||
std::vector<real>& M)
|
||||
const {
|
||||
if (M.end() == M.begin() + dim2_) {
|
||||
real t[dim2_];
|
||||
IntForward(lat, lon, h, x, y, z, t);
|
||||
std::copy(t, t + dim2_, M.begin());
|
||||
} else
|
||||
IntForward(lat, lon, h, x, y, z, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from local cartesian to geodetic coordinates.
|
||||
*
|
||||
* @param[in] x local cartesian coordinate (meters).
|
||||
* @param[in] y local cartesian coordinate (meters).
|
||||
* @param[in] z local cartesian coordinate (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] h height of point above the ellipsoid (meters).
|
||||
*
|
||||
* In general, there are multiple solutions and the result which minimizes
|
||||
* |<i>h</i> |is returned, i.e., (<i>lat</i>, <i>lon</i>) corresponds to
|
||||
* the closest point on the ellipsoid. The value of \e lon returned is in
|
||||
* the range [−180°, 180°].
|
||||
**********************************************************************/
|
||||
void Reverse(real x, real y, real z, real& lat, real& lon, real& h)
|
||||
const {
|
||||
IntReverse(x, y, z, lat, lon, h, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert from local cartesian to geodetic coordinates and return rotation
|
||||
* matrix.
|
||||
*
|
||||
* @param[in] x local cartesian coordinate (meters).
|
||||
* @param[in] y local cartesian coordinate (meters).
|
||||
* @param[in] z local cartesian coordinate (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] h height of point above the ellipsoid (meters).
|
||||
* @param[out] M if the length of the vector is 9, fill with the rotation
|
||||
* matrix in row-major order.
|
||||
*
|
||||
* Let \e v be a unit vector located at (\e lat, \e lon, \e h). We can
|
||||
* express \e v as \e column vectors in one of two ways
|
||||
* - in east, north, up coordinates (where the components are relative to a
|
||||
* local coordinate system at (\e lat, \e lon, \e h)); call this
|
||||
* representation \e v1.
|
||||
* - in \e x, \e y, \e z coordinates (where the components are relative to
|
||||
* the local coordinate system at (\e lat0, \e lon0, \e h0)); call this
|
||||
* representation \e v0.
|
||||
* .
|
||||
* Then we have \e v1 = <i>M</i><sup>T</sup> ⋅ \e v0, where
|
||||
* <i>M</i><sup>T</sup> is the transpose of \e M.
|
||||
**********************************************************************/
|
||||
void Reverse(real x, real y, real z, real& lat, real& lon, real& h,
|
||||
std::vector<real>& M)
|
||||
const {
|
||||
if (M.end() == M.begin() + dim2_) {
|
||||
real t[dim2_];
|
||||
IntReverse(x, y, z, lat, lon, h, t);
|
||||
std::copy(t, t + dim2_, M.begin());
|
||||
} else
|
||||
IntReverse(x, y, z, lat, lon, h, NULL);
|
||||
}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return latitude of the origin (degrees).
|
||||
**********************************************************************/
|
||||
Math::real LatitudeOrigin() const { return _lat0; }
|
||||
|
||||
/**
|
||||
* @return longitude of the origin (degrees).
|
||||
**********************************************************************/
|
||||
Math::real LongitudeOrigin() const { return _lon0; }
|
||||
|
||||
/**
|
||||
* @return height of the origin (meters).
|
||||
**********************************************************************/
|
||||
Math::real HeightOrigin() const { return _h0; }
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value of \e a inherited from the Geocentric object used in the
|
||||
* constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _earth.EquatorialRadius(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value
|
||||
* inherited from the Geocentric object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _earth.Flattening(); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_LOCALCARTESIAN_HPP
|
||||
361
external/include/GeographicLib/MGRS.hpp
vendored
Normal file
361
external/include/GeographicLib/MGRS.hpp
vendored
Normal file
@@ -0,0 +1,361 @@
|
||||
/**
|
||||
* \file MGRS.hpp
|
||||
* \brief Header for GeographicLib::MGRS class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_MGRS_HPP)
|
||||
#define GEOGRAPHICLIB_MGRS_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/UTMUPS.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about dll vs string
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4251)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Convert between UTM/UPS and %MGRS
|
||||
*
|
||||
* MGRS is defined in Chapter 3 of
|
||||
* - J. W. Hager, L. L. Fry, S. S. Jacks, D. R. Hill,
|
||||
* <a href="https://web.archive.org/web/20161214054445/http://earth-info.nga.mil/GandG/publications/tm8358.1/pdf/TM8358_1.pdf">
|
||||
* Datums, Ellipsoids, Grids, and Grid Reference Systems</a>,
|
||||
* Defense Mapping Agency, Technical Manual TM8358.1 (1990).
|
||||
* .
|
||||
* This document has been updated by the two NGA documents
|
||||
* - <a href="https://earth-info.nga.mil/php/download.php?file=coord-grids">
|
||||
* Universal Grids and Grid Reference Systems</a>,
|
||||
* NGA.STND.0037 (2014).
|
||||
* - <a href="https://earth-info.nga.mil/php/download.php?file=coord-utmups">
|
||||
* The Universal Grids and the Transverse Mercator and Polar Stereographic
|
||||
* Map Projections</a>, NGA.SIG.0012 (2014).
|
||||
*
|
||||
* This implementation has the following properties:
|
||||
* - The conversions are closed, i.e., output from Forward is legal input for
|
||||
* Reverse and vice versa. Conversion in both directions preserve the
|
||||
* UTM/UPS selection and the UTM zone.
|
||||
* - Forward followed by Reverse and vice versa is approximately the
|
||||
* identity. (This is affected in predictable ways by errors in
|
||||
* determining the latitude band and by loss of precision in the MGRS
|
||||
* coordinates.)
|
||||
* - The trailing digits produced by Forward are consistent as the precision
|
||||
* is varied. Specifically, the digits are obtained by operating on the
|
||||
* easting with ⌊10<sup>6</sup> <i>x</i>⌋ and extracting the
|
||||
* required digits from the resulting number (and similarly for the
|
||||
* northing).
|
||||
* - All MGRS coordinates truncate to legal 100 km blocks. All MGRS
|
||||
* coordinates with a legal 100 km block prefix are legal (even though the
|
||||
* latitude band letter may now belong to a neighboring band).
|
||||
* - The range of UTM/UPS coordinates allowed for conversion to MGRS
|
||||
* coordinates is the maximum consistent with staying within the letter
|
||||
* ranges of the MGRS scheme.
|
||||
* - All the transformations are implemented as static methods in the MGRS
|
||||
* class.
|
||||
*
|
||||
* The <a href="http://www.nga.mil">NGA</a> software package
|
||||
* <a href="https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_geotrans">geotrans</a>
|
||||
* also provides conversions to and from MGRS. Version 3.0 (and earlier)
|
||||
* suffers from some drawbacks:
|
||||
* - Inconsistent rules are used to determine the whether a particular MGRS
|
||||
* coordinate is legal. A more systematic approach is taken here.
|
||||
* - The underlying projections are not very accurately implemented.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-MGRS.cpp
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT MGRS {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
static const char* const hemispheres_;
|
||||
static const char* const utmcols_[3];
|
||||
static const char* const utmrow_;
|
||||
static const char* const upscols_[4];
|
||||
static const char* const upsrows_[2];
|
||||
static const char* const latband_;
|
||||
static const char* const upsband_;
|
||||
static const char* const digits_;
|
||||
|
||||
static const int mineasting_[4];
|
||||
static const int maxeasting_[4];
|
||||
static const int minnorthing_[4];
|
||||
static const int maxnorthing_[4];
|
||||
enum {
|
||||
base_ = 10,
|
||||
// Top-level tiles are 10^5 m = 100 km on a side
|
||||
tilelevel_ = 5,
|
||||
// Period of UTM row letters
|
||||
utmrowperiod_ = 20,
|
||||
// Row letters are shifted by 5 for even zones
|
||||
utmevenrowshift_ = 5,
|
||||
// Maximum precision is um
|
||||
maxprec_ = 5 + 6,
|
||||
// For generating digits at maxprec
|
||||
mult_ = 1000000,
|
||||
};
|
||||
static void CheckCoords(bool utmp, bool& northp, real& x, real& y);
|
||||
static int UTMRow(int iband, int icol, int irow);
|
||||
|
||||
friend class UTMUPS; // UTMUPS::StandardZone calls LatitudeBand
|
||||
// Return latitude band number [-10, 10) for the given latitude (degrees).
|
||||
// The bands are reckoned in include their southern edges.
|
||||
static int LatitudeBand(real lat) {
|
||||
using std::floor;
|
||||
int ilat = int(floor(lat));
|
||||
return (std::max)(-10, (std::min)(9, (ilat + 80)/8 - 10));
|
||||
}
|
||||
// Return approximate latitude band number [-10, 10) for the given northing
|
||||
// (meters). With this rule, each 100km tile would have a unique band
|
||||
// letter corresponding to the latitude at the center of the tile. This
|
||||
// function isn't currently used.
|
||||
static int ApproxLatitudeBand(real y) {
|
||||
// northing at tile center in units of tile = 100km
|
||||
using std::floor; using std::abs;
|
||||
real ya = floor( (std::min)(real(88), abs(y/tile_)) ) +
|
||||
real(0.5);
|
||||
// convert to lat (mult by 90/100) and then to band (divide by 8)
|
||||
// the +1 fine tunes the boundary between bands 3 and 4
|
||||
int b = int(floor( ((ya * 9 + 1) / 10) / 8 ));
|
||||
// For the northern hemisphere we have
|
||||
// band rows num
|
||||
// N 0 0:8 9
|
||||
// P 1 9:17 9
|
||||
// Q 2 18:26 9
|
||||
// R 3 27:34 8
|
||||
// S 4 35:43 9
|
||||
// T 5 44:52 9
|
||||
// U 6 53:61 9
|
||||
// V 7 62:70 9
|
||||
// W 8 71:79 9
|
||||
// X 9 80:94 15
|
||||
return y >= 0 ? b : -(b + 1);
|
||||
}
|
||||
// UTMUPS access these enums
|
||||
enum {
|
||||
tile_ = 100000, // Size MGRS blocks
|
||||
minutmcol_ = 1,
|
||||
maxutmcol_ = 9,
|
||||
minutmSrow_ = 10,
|
||||
maxutmSrow_ = 100, // Also used for UTM S false northing
|
||||
minutmNrow_ = 0, // Also used for UTM N false northing
|
||||
maxutmNrow_ = 95,
|
||||
minupsSind_ = 8, // These 4 ind's apply to easting and northing
|
||||
maxupsSind_ = 32,
|
||||
minupsNind_ = 13,
|
||||
maxupsNind_ = 27,
|
||||
upseasting_ = 20, // Also used for UPS false northing
|
||||
utmeasting_ = 5, // UTM false easting
|
||||
// Difference between S hemisphere northing and N hemisphere northing
|
||||
utmNshift_ = (maxutmSrow_ - minutmNrow_) * tile_
|
||||
};
|
||||
MGRS(); // Disable constructor
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Convert UTM or UPS coordinate to an MGRS coordinate.
|
||||
*
|
||||
* @param[in] zone UTM zone (zero means UPS).
|
||||
* @param[in] northp hemisphere (true means north, false means south).
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[in] prec precision relative to 100 km.
|
||||
* @param[out] mgrs MGRS string.
|
||||
* @exception GeographicErr if \e zone, \e x, or \e y is outside its
|
||||
* allowed range.
|
||||
* @exception GeographicErr if the memory for the MGRS string can't be
|
||||
* allocated.
|
||||
*
|
||||
* \e prec specifies the precision of the MGRS string as follows:
|
||||
* - \e prec = −1 (min), only the grid zone is returned
|
||||
* - \e prec = 0, 100 km
|
||||
* - \e prec = 1, 10 km
|
||||
* - \e prec = 2, 1 km
|
||||
* - \e prec = 3, 100 m
|
||||
* - \e prec = 4, 10 m
|
||||
* - \e prec = 5, 1 m
|
||||
* - \e prec = 6, 0.1 m
|
||||
* - …
|
||||
* - \e prec = 11 (max), 1 μm
|
||||
*
|
||||
* UTM eastings are allowed to be in the range [100 km, 900 km], northings
|
||||
* are allowed to be in in [0 km, 9500 km] for the northern hemisphere and
|
||||
* in [1000 km, 10000 km] for the southern hemisphere. (However UTM
|
||||
* northings can be continued across the equator. So the actual limits on
|
||||
* the northings are [−9000 km, 9500 km] for the "northern"
|
||||
* hemisphere and [1000 km, 19500 km] for the "southern" hemisphere.)
|
||||
*
|
||||
* UPS eastings/northings are allowed to be in the range [1300 km, 2700 km]
|
||||
* in the northern hemisphere and in [800 km, 3200 km] in the southern
|
||||
* hemisphere.
|
||||
*
|
||||
* The ranges are 100 km more restrictive than for the conversion between
|
||||
* geographic coordinates and UTM and UPS given by UTMUPS. These
|
||||
* restrictions are dictated by the allowed letters in MGRS coordinates.
|
||||
* The choice of 9500 km for the maximum northing for northern hemisphere
|
||||
* and of 1000 km as the minimum northing for southern hemisphere provide
|
||||
* at least 0.5 degree extension into standard UPS zones. The upper ends
|
||||
* of the ranges for the UPS coordinates is dictated by requiring symmetry
|
||||
* about the meridians 0E and 90E.
|
||||
*
|
||||
* All allowed UTM and UPS coordinates may now be converted to legal MGRS
|
||||
* coordinates with the proviso that eastings and northings on the upper
|
||||
* boundaries are silently reduced by about 4 nm (4 nanometers) to place
|
||||
* them \e within the allowed range. (This includes reducing a southern
|
||||
* hemisphere northing of 10000 km by 4 nm so that it is placed in latitude
|
||||
* band M.) The UTM or UPS coordinates are truncated to requested
|
||||
* precision to determine the MGRS coordinate. Thus in UTM zone 38n, the
|
||||
* square area with easting in [444 km, 445 km) and northing in [3688 km,
|
||||
* 3689 km) maps to MGRS coordinate 38SMB4488 (at \e prec = 2, 1 km),
|
||||
* Khulani Sq., Baghdad.
|
||||
*
|
||||
* The UTM/UPS selection and the UTM zone is preserved in the conversion to
|
||||
* MGRS coordinate. Thus for \e zone > 0, the MGRS coordinate begins with
|
||||
* the zone number followed by one of [C--M] for the southern
|
||||
* hemisphere and [N--X] for the northern hemisphere. For \e zone =
|
||||
* 0, the MGRS coordinates begins with one of [AB] for the southern
|
||||
* hemisphere and [XY] for the northern hemisphere.
|
||||
*
|
||||
* The conversion to the MGRS is exact for prec in [0, 5] except that a
|
||||
* neighboring latitude band letter may be given if the point is within 5nm
|
||||
* of a band boundary. For prec in [6, 11], the conversion is accurate to
|
||||
* roundoff.
|
||||
*
|
||||
* If \e prec = −1, then the "grid zone designation", e.g., 18T, is
|
||||
* returned. This consists of the UTM zone number (absent for UPS) and the
|
||||
* first letter of the MGRS string which labels the latitude band for UTM
|
||||
* and the hemisphere for UPS.
|
||||
*
|
||||
* If \e x or \e y is NaN or if \e zone is UTMUPS::INVALID, the returned
|
||||
* MGRS string is "INVALID".
|
||||
*
|
||||
* Return the result via a reference argument to avoid the overhead of
|
||||
* allocating a potentially large number of small strings. If an error is
|
||||
* thrown, then \e mgrs is unchanged.
|
||||
**********************************************************************/
|
||||
static void Forward(int zone, bool northp, real x, real y,
|
||||
int prec, std::string& mgrs);
|
||||
|
||||
/**
|
||||
* Convert UTM or UPS coordinate to an MGRS coordinate when the latitude is
|
||||
* known.
|
||||
*
|
||||
* @param[in] zone UTM zone (zero means UPS).
|
||||
* @param[in] northp hemisphere (true means north, false means south).
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[in] lat latitude (degrees).
|
||||
* @param[in] prec precision relative to 100 km.
|
||||
* @param[out] mgrs MGRS string.
|
||||
* @exception GeographicErr if \e zone, \e x, or \e y is outside its
|
||||
* allowed range.
|
||||
* @exception GeographicErr if \e lat is inconsistent with the given UTM
|
||||
* coordinates.
|
||||
* @exception std::bad_alloc if the memory for \e mgrs can't be allocated.
|
||||
*
|
||||
* The latitude is ignored for \e zone = 0 (UPS); otherwise the latitude is
|
||||
* used to determine the latitude band and this is checked for consistency
|
||||
* using the same tests as Reverse.
|
||||
**********************************************************************/
|
||||
static void Forward(int zone, bool northp, real x, real y, real lat,
|
||||
int prec, std::string& mgrs);
|
||||
|
||||
/**
|
||||
* Convert a MGRS coordinate to UTM or UPS coordinates.
|
||||
*
|
||||
* @param[in] mgrs MGRS string.
|
||||
* @param[out] zone UTM zone (zero means UPS).
|
||||
* @param[out] northp hemisphere (true means north, false means south).
|
||||
* @param[out] x easting of point (meters).
|
||||
* @param[out] y northing of point (meters).
|
||||
* @param[out] prec precision relative to 100 km.
|
||||
* @param[in] centerp if true (default), return center of the MGRS square,
|
||||
* else return SW (lower left) corner.
|
||||
* @exception GeographicErr if \e mgrs is illegal.
|
||||
*
|
||||
* All conversions from MGRS to UTM/UPS are permitted provided the MGRS
|
||||
* coordinate is a possible result of a conversion in the other direction.
|
||||
* (The leading 0 may be dropped from an input MGRS coordinate for UTM
|
||||
* zones 1--9.) In addition, MGRS coordinates with a neighboring
|
||||
* latitude band letter are permitted provided that some portion of the
|
||||
* 100 km block is within the given latitude band. Thus
|
||||
* - 38VLS and 38WLS are allowed (latitude 64N intersects the square
|
||||
* 38[VW]LS); but 38VMS is not permitted (all of 38WMS is north of 64N)
|
||||
* - 38MPE and 38NPF are permitted (they straddle the equator); but 38NPE
|
||||
* and 38MPF are not permitted (the equator does not intersect either
|
||||
* block).
|
||||
* - Similarly ZAB and YZB are permitted (they straddle the prime
|
||||
* meridian); but YAB and ZZB are not (the prime meridian does not
|
||||
* intersect either block).
|
||||
*
|
||||
* The UTM/UPS selection and the UTM zone is preserved in the conversion
|
||||
* from MGRS coordinate. The conversion is exact for prec in [0, 5]. With
|
||||
* \e centerp = true, the conversion from MGRS to geographic and back is
|
||||
* stable. This is not assured if \e centerp = false.
|
||||
*
|
||||
* If a "grid zone designation" (for example, 18T or A) is given, then some
|
||||
* suitable (but essentially arbitrary) point within that grid zone is
|
||||
* returned. The main utility of the conversion is to allow \e zone and \e
|
||||
* northp to be determined. In this case, the \e centerp parameter is
|
||||
* ignored and \e prec is set to −1.
|
||||
*
|
||||
* If the first 3 characters of \e mgrs are "INV", then \e x and \e y are
|
||||
* set to NaN, \e zone is set to UTMUPS::INVALID, and \e prec is set to
|
||||
* −2.
|
||||
*
|
||||
* If an exception is thrown, then the arguments are unchanged.
|
||||
**********************************************************************/
|
||||
static void Reverse(const std::string& mgrs,
|
||||
int& zone, bool& northp, real& x, real& y,
|
||||
int& prec, bool centerp = true);
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return \e a the equatorial radius of the WGS84 ellipsoid (meters).
|
||||
*
|
||||
* (The WGS84 value is returned because the UTM and UPS projections are
|
||||
* based on this ellipsoid.)
|
||||
**********************************************************************/
|
||||
static Math::real EquatorialRadius() { return UTMUPS::EquatorialRadius(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the WGS84 ellipsoid.
|
||||
*
|
||||
* (The WGS84 value is returned because the UTM and UPS projections are
|
||||
* based on this ellipsoid.)
|
||||
**********************************************************************/
|
||||
static Math::real Flattening() { return UTMUPS::Flattening(); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
static Math::real MajorRadius() { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* Perform some checks on the UTMUPS coordinates on this ellipsoid. Throw
|
||||
* an error if any of the assumptions made in the MGRS class is not true.
|
||||
* This check needs to be carried out if the ellipsoid parameters (or the
|
||||
* UTM/UPS scales) are ever changed.
|
||||
**********************************************************************/
|
||||
static void Check();
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_MGRS_HPP
|
||||
204
external/include/GeographicLib/MagneticCircle.hpp
vendored
Normal file
204
external/include/GeographicLib/MagneticCircle.hpp
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* \file MagneticCircle.hpp
|
||||
* \brief Header for GeographicLib::MagneticCircle class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2011-2021) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_MAGNETICCIRCLE_HPP)
|
||||
#define GEOGRAPHICLIB_MAGNETICCIRCLE_HPP 1
|
||||
|
||||
#include <vector>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/CircularEngine.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Geomagnetic field on a circle of latitude
|
||||
*
|
||||
* Evaluate the earth's magnetic field on a circle of constant height and
|
||||
* latitude. This uses a CircularEngine to pre-evaluate the inner sum of the
|
||||
* spherical harmonic sum, allowing the values of the field at several
|
||||
* different longitudes to be evaluated rapidly.
|
||||
*
|
||||
* Use MagneticModel::Circle to create a MagneticCircle object. (The
|
||||
* constructor for this class is private.)
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-MagneticCircle.cpp
|
||||
*
|
||||
* <a href="MagneticField.1.html">MagneticField</a> is a command-line utility
|
||||
* providing access to the functionality of MagneticModel and MagneticCircle.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT MagneticCircle {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
|
||||
real _a, _f, _lat, _h, _t, _cphi, _sphi, _t1, _dt0;
|
||||
bool _interpolate, _constterm;
|
||||
CircularEngine _circ0, _circ1, _circ2;
|
||||
|
||||
MagneticCircle(real a, real f, real lat, real h, real t,
|
||||
real cphi, real sphi, real t1, real dt0,
|
||||
bool interpolate,
|
||||
const CircularEngine& circ0, const CircularEngine& circ1)
|
||||
: _a(a)
|
||||
, _f(f)
|
||||
, _lat(Math::LatFix(lat))
|
||||
, _h(h)
|
||||
, _t(t)
|
||||
, _cphi(cphi)
|
||||
, _sphi(sphi)
|
||||
, _t1(t1)
|
||||
, _dt0(dt0)
|
||||
, _interpolate(interpolate)
|
||||
, _constterm(false)
|
||||
, _circ0(circ0)
|
||||
, _circ1(circ1)
|
||||
{}
|
||||
|
||||
MagneticCircle(real a, real f, real lat, real h, real t,
|
||||
real cphi, real sphi, real t1, real dt0,
|
||||
bool interpolate,
|
||||
const CircularEngine& circ0, const CircularEngine& circ1,
|
||||
const CircularEngine& circ2)
|
||||
: _a(a)
|
||||
, _f(f)
|
||||
, _lat(lat)
|
||||
, _h(h)
|
||||
, _t(t)
|
||||
, _cphi(cphi)
|
||||
, _sphi(sphi)
|
||||
, _t1(t1)
|
||||
, _dt0(dt0)
|
||||
, _interpolate(interpolate)
|
||||
, _constterm(true)
|
||||
, _circ0(circ0)
|
||||
, _circ1(circ1)
|
||||
, _circ2(circ2)
|
||||
{}
|
||||
|
||||
void Field(real lon, bool diffp,
|
||||
real& Bx, real& By, real& Bz,
|
||||
real& Bxt, real& Byt, real& Bzt) const;
|
||||
|
||||
void FieldGeocentric(real slam, real clam,
|
||||
real& BX, real& BY, real& BZ,
|
||||
real& BXt, real& BYt, real& BZt) const;
|
||||
|
||||
friend class MagneticModel; // MagneticModel calls the private constructor
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* A default constructor for the normal gravity. This sets up an
|
||||
* uninitialized object which can be later replaced by the
|
||||
* MagneticModel::Circle.
|
||||
**********************************************************************/
|
||||
MagneticCircle() : _a(-1) {}
|
||||
|
||||
/** \name Compute the magnetic field
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Evaluate the components of the geomagnetic field at a particular
|
||||
* longitude.
|
||||
*
|
||||
* @param[in] lon longitude of the point (degrees).
|
||||
* @param[out] Bx the easterly component of the magnetic field (nanotesla).
|
||||
* @param[out] By the northerly component of the magnetic field
|
||||
* (nanotesla).
|
||||
* @param[out] Bz the vertical (up) component of the magnetic field
|
||||
* (nanotesla).
|
||||
**********************************************************************/
|
||||
void operator()(real lon, real& Bx, real& By, real& Bz) const {
|
||||
real dummy;
|
||||
Field(lon, false, Bx, By, Bz, dummy, dummy, dummy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the components of the geomagnetic field and their time
|
||||
* derivatives at a particular longitude.
|
||||
*
|
||||
* @param[in] lon longitude of the point (degrees).
|
||||
* @param[out] Bx the easterly component of the magnetic field (nanotesla).
|
||||
* @param[out] By the northerly component of the magnetic field
|
||||
* (nanotesla).
|
||||
* @param[out] Bz the vertical (up) component of the magnetic field
|
||||
* (nanotesla).
|
||||
* @param[out] Bxt the rate of change of \e Bx (nT/yr).
|
||||
* @param[out] Byt the rate of change of \e By (nT/yr).
|
||||
* @param[out] Bzt the rate of change of \e Bz (nT/yr).
|
||||
**********************************************************************/
|
||||
void operator()(real lon, real& Bx, real& By, real& Bz,
|
||||
real& Bxt, real& Byt, real& Bzt) const {
|
||||
Field(lon, true, Bx, By, Bz, Bxt, Byt, Bzt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the components of the geomagnetic field and their time
|
||||
* derivatives at a particular longitude.
|
||||
*
|
||||
* @param[in] lon longitude of the point (degrees).
|
||||
* @param[out] BX the \e X component of the magnetic field (nT).
|
||||
* @param[out] BY the \e Y component of the magnetic field (nT).
|
||||
* @param[out] BZ the \e Z component of the magnetic field (nT).
|
||||
* @param[out] BXt the rate of change of \e BX (nT/yr).
|
||||
* @param[out] BYt the rate of change of \e BY (nT/yr).
|
||||
* @param[out] BZt the rate of change of \e BZ (nT/yr).
|
||||
**********************************************************************/
|
||||
void FieldGeocentric(real lon, real& BX, real& BY, real& BZ,
|
||||
real& BXt, real& BYt, real& BZt) const;
|
||||
///@}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return true if the object has been initialized.
|
||||
**********************************************************************/
|
||||
bool Init() const { return _a > 0; }
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value inherited from the MagneticModel object used in the
|
||||
* constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const
|
||||
{ return Init() ? _a : Math::NaN(); }
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value
|
||||
* inherited from the MagneticModel object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const
|
||||
{ return Init() ? _f : Math::NaN(); }
|
||||
/**
|
||||
* @return the latitude of the circle (degrees).
|
||||
**********************************************************************/
|
||||
Math::real Latitude() const
|
||||
{ return Init() ? _lat : Math::NaN(); }
|
||||
/**
|
||||
* @return the height of the circle (meters).
|
||||
**********************************************************************/
|
||||
Math::real Height() const
|
||||
{ return Init() ? _h : Math::NaN(); }
|
||||
/**
|
||||
* @return the time (fractional years).
|
||||
**********************************************************************/
|
||||
Math::real Time() const
|
||||
{ return Init() ? _t : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_MAGNETICCIRCLE_HPP
|
||||
406
external/include/GeographicLib/MagneticModel.hpp
vendored
Normal file
406
external/include/GeographicLib/MagneticModel.hpp
vendored
Normal file
@@ -0,0 +1,406 @@
|
||||
/**
|
||||
* \file MagneticModel.hpp
|
||||
* \brief Header for GeographicLib::MagneticModel class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2011-2021) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_MAGNETICMODEL_HPP)
|
||||
#define GEOGRAPHICLIB_MAGNETICMODEL_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/Geocentric.hpp>
|
||||
#include <GeographicLib/SphericalHarmonic.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about dll vs vector
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4251)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
class MagneticCircle;
|
||||
|
||||
/**
|
||||
* \brief Model of the earth's magnetic field
|
||||
*
|
||||
* Evaluate the earth's magnetic field according to a model. At present only
|
||||
* internal magnetic fields are handled. These are due to the earth's code
|
||||
* and crust; these vary slowly (over many years). Excluded are the effects
|
||||
* of currents in the ionosphere and magnetosphere which have daily and
|
||||
* annual variations.
|
||||
*
|
||||
* See \ref magnetic for details of how to install the magnetic models and
|
||||
* the data format.
|
||||
*
|
||||
* See
|
||||
* - General information:
|
||||
* - http://geomag.org/models/index.html
|
||||
* - WMM2010:
|
||||
* - https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml
|
||||
* - https://ngdc.noaa.gov/geomag/WMM/data/WMM2010/WMM2010COF.zip
|
||||
* - WMM2015 (deprecated):
|
||||
* - https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml
|
||||
* - https://ngdc.noaa.gov/geomag/WMM/data/WMM2015/WMM2015COF.zip
|
||||
* - WMM2015V2:
|
||||
* - https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml
|
||||
* - https://ngdc.noaa.gov/geomag/WMM/data/WMM2015/WMM2015v2COF.zip
|
||||
* - WMM2020:
|
||||
* - https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml
|
||||
* - https://ngdc.noaa.gov/geomag/WMM/data/WMM2020/WMM2020COF.zip
|
||||
* - IGRF11:
|
||||
* - https://ngdc.noaa.gov/IAGA/vmod/igrf.html
|
||||
* - https://ngdc.noaa.gov/IAGA/vmod/igrf11coeffs.txt
|
||||
* - https://ngdc.noaa.gov/IAGA/vmod/geomag70_linux.tar.gz
|
||||
* - EMM2010:
|
||||
* - https://ngdc.noaa.gov/geomag/EMM/index.html
|
||||
* - https://ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2010_Sph_Windows_Linux.zip
|
||||
* - EMM2015:
|
||||
* - https://ngdc.noaa.gov/geomag/EMM/index.html
|
||||
* - https://www.ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2015_Sph_Linux.zip
|
||||
* - EMM2017:
|
||||
* - https://ngdc.noaa.gov/geomag/EMM/index.html
|
||||
* - https://www.ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2017_Sph_Linux.zip
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-MagneticModel.cpp
|
||||
*
|
||||
* <a href="MagneticField.1.html">MagneticField</a> is a command-line utility
|
||||
* providing access to the functionality of MagneticModel and MagneticCircle.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT MagneticModel {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
static const int idlength_ = 8;
|
||||
std::string _name, _dir, _description, _date, _filename, _id;
|
||||
real _t0, _dt0, _tmin, _tmax, _a, _hmin, _hmax;
|
||||
int _Nmodels, _Nconstants, _nmx, _mmx;
|
||||
SphericalHarmonic::normalization _norm;
|
||||
Geocentric _earth;
|
||||
std::vector< std::vector<real> > _G;
|
||||
std::vector< std::vector<real> > _H;
|
||||
std::vector<SphericalHarmonic> _harm;
|
||||
void Field(real t, real lat, real lon, real h, bool diffp,
|
||||
real& Bx, real& By, real& Bz,
|
||||
real& Bxt, real& Byt, real& Bzt) const;
|
||||
void ReadMetadata(const std::string& name);
|
||||
// copy constructor not allowed
|
||||
MagneticModel(const MagneticModel&) = delete;
|
||||
// nor copy assignment
|
||||
MagneticModel& operator=(const MagneticModel&) = delete;
|
||||
public:
|
||||
|
||||
/** \name Setting up the magnetic model
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Construct a magnetic model.
|
||||
*
|
||||
* @param[in] name the name of the model.
|
||||
* @param[in] path (optional) directory for data file.
|
||||
* @param[in] earth (optional) Geocentric object for converting
|
||||
* coordinates; default Geocentric::WGS84().
|
||||
* @param[in] Nmax (optional) if non-negative, truncate the degree of the
|
||||
* model this value.
|
||||
* @param[in] Mmax (optional) if non-negative, truncate the order of the
|
||||
* model this value.
|
||||
* @exception GeographicErr if the data file cannot be found, is
|
||||
* unreadable, or is corrupt, or if \e Mmax > \e Nmax.
|
||||
* @exception std::bad_alloc if the memory necessary for storing the model
|
||||
* can't be allocated.
|
||||
*
|
||||
* A filename is formed by appending ".wmm" (World Magnetic Model) to the
|
||||
* name. If \e path is specified (and is non-empty), then the file is
|
||||
* loaded from directory, \e path. Otherwise the path is given by the
|
||||
* DefaultMagneticPath().
|
||||
*
|
||||
* This file contains the metadata which specifies the properties of the
|
||||
* model. The coefficients for the spherical harmonic sums are obtained
|
||||
* from a file obtained by appending ".cof" to metadata file (so the
|
||||
* filename ends in ".wwm.cof").
|
||||
*
|
||||
* The model is not tied to a particular ellipsoidal model of the earth.
|
||||
* The final earth argument to the constructor specifies an ellipsoid to
|
||||
* allow geodetic coordinates to the transformed into the spherical
|
||||
* coordinates used in the spherical harmonic sum.
|
||||
*
|
||||
* If \e Nmax ≥ 0 and \e Mmax < 0, then \e Mmax is set to \e Nmax.
|
||||
* After the model is loaded, the maximum degree and order of the model can
|
||||
* be found by the Degree() and Order() methods.
|
||||
**********************************************************************/
|
||||
explicit MagneticModel(const std::string& name,
|
||||
const std::string& path = "",
|
||||
const Geocentric& earth = Geocentric::WGS84(),
|
||||
int Nmax = -1, int Mmax = -1);
|
||||
///@}
|
||||
|
||||
/** \name Compute the magnetic field
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Evaluate the components of the geomagnetic field.
|
||||
*
|
||||
* @param[in] t the time (years).
|
||||
* @param[in] lat latitude of the point (degrees).
|
||||
* @param[in] lon longitude of the point (degrees).
|
||||
* @param[in] h the height of the point above the ellipsoid (meters).
|
||||
* @param[out] Bx the easterly component of the magnetic field (nanotesla).
|
||||
* @param[out] By the northerly component of the magnetic field
|
||||
* (nanotesla).
|
||||
* @param[out] Bz the vertical (up) component of the magnetic field
|
||||
* (nanotesla).
|
||||
**********************************************************************/
|
||||
void operator()(real t, real lat, real lon, real h,
|
||||
real& Bx, real& By, real& Bz) const {
|
||||
real dummy;
|
||||
Field(t, lat, lon, h, false, Bx, By, Bz, dummy, dummy, dummy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the components of the geomagnetic field and their time
|
||||
* derivatives
|
||||
*
|
||||
* @param[in] t the time (years).
|
||||
* @param[in] lat latitude of the point (degrees).
|
||||
* @param[in] lon longitude of the point (degrees).
|
||||
* @param[in] h the height of the point above the ellipsoid (meters).
|
||||
* @param[out] Bx the easterly component of the magnetic field (nanotesla).
|
||||
* @param[out] By the northerly component of the magnetic field
|
||||
* (nanotesla).
|
||||
* @param[out] Bz the vertical (up) component of the magnetic field
|
||||
* (nanotesla).
|
||||
* @param[out] Bxt the rate of change of \e Bx (nT/yr).
|
||||
* @param[out] Byt the rate of change of \e By (nT/yr).
|
||||
* @param[out] Bzt the rate of change of \e Bz (nT/yr).
|
||||
**********************************************************************/
|
||||
void operator()(real t, real lat, real lon, real h,
|
||||
real& Bx, real& By, real& Bz,
|
||||
real& Bxt, real& Byt, real& Bzt) const {
|
||||
Field(t, lat, lon, h, true, Bx, By, Bz, Bxt, Byt, Bzt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a MagneticCircle object to allow the geomagnetic field at many
|
||||
* points with constant \e lat, \e h, and \e t and varying \e lon to be
|
||||
* computed efficiently.
|
||||
*
|
||||
* @param[in] t the time (years).
|
||||
* @param[in] lat latitude of the point (degrees).
|
||||
* @param[in] h the height of the point above the ellipsoid (meters).
|
||||
* @exception std::bad_alloc if the memory necessary for creating a
|
||||
* MagneticCircle can't be allocated.
|
||||
* @return a MagneticCircle object whose MagneticCircle::operator()(real
|
||||
* lon) member function computes the field at particular values of \e
|
||||
* lon.
|
||||
*
|
||||
* If the field at several points on a circle of latitude need to be
|
||||
* calculated then creating a MagneticCircle and using its member functions
|
||||
* will be substantially faster, especially for high-degree models.
|
||||
**********************************************************************/
|
||||
MagneticCircle Circle(real t, real lat, real h) const;
|
||||
|
||||
/**
|
||||
* Compute the magnetic field in geocentric coordinate.
|
||||
*
|
||||
* @param[in] t the time (years).
|
||||
* @param[in] X geocentric coordinate (meters).
|
||||
* @param[in] Y geocentric coordinate (meters).
|
||||
* @param[in] Z geocentric coordinate (meters).
|
||||
* @param[out] BX the \e X component of the magnetic field (nT).
|
||||
* @param[out] BY the \e Y component of the magnetic field (nT).
|
||||
* @param[out] BZ the \e Z component of the magnetic field (nT).
|
||||
* @param[out] BXt the rate of change of \e BX (nT/yr).
|
||||
* @param[out] BYt the rate of change of \e BY (nT/yr).
|
||||
* @param[out] BZt the rate of change of \e BZ (nT/yr).
|
||||
**********************************************************************/
|
||||
void FieldGeocentric(real t, real X, real Y, real Z,
|
||||
real& BX, real& BY, real& BZ,
|
||||
real& BXt, real& BYt, real& BZt) const;
|
||||
|
||||
/**
|
||||
* Compute various quantities dependent on the magnetic field.
|
||||
*
|
||||
* @param[in] Bx the \e x (easterly) component of the magnetic field (nT).
|
||||
* @param[in] By the \e y (northerly) component of the magnetic field (nT).
|
||||
* @param[in] Bz the \e z (vertical, up positive) component of the magnetic
|
||||
* field (nT).
|
||||
* @param[out] H the horizontal magnetic field (nT).
|
||||
* @param[out] F the total magnetic field (nT).
|
||||
* @param[out] D the declination of the field (degrees east of north).
|
||||
* @param[out] I the inclination of the field (degrees down from
|
||||
* horizontal).
|
||||
**********************************************************************/
|
||||
static void FieldComponents(real Bx, real By, real Bz,
|
||||
real& H, real& F, real& D, real& I) {
|
||||
real Ht, Ft, Dt, It;
|
||||
FieldComponents(Bx, By, Bz, real(0), real(1), real(0),
|
||||
H, F, D, I, Ht, Ft, Dt, It);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute various quantities dependent on the magnetic field and its rate
|
||||
* of change.
|
||||
*
|
||||
* @param[in] Bx the \e x (easterly) component of the magnetic field (nT).
|
||||
* @param[in] By the \e y (northerly) component of the magnetic field (nT).
|
||||
* @param[in] Bz the \e z (vertical, up positive) component of the magnetic
|
||||
* field (nT).
|
||||
* @param[in] Bxt the rate of change of \e Bx (nT/yr).
|
||||
* @param[in] Byt the rate of change of \e By (nT/yr).
|
||||
* @param[in] Bzt the rate of change of \e Bz (nT/yr).
|
||||
* @param[out] H the horizontal magnetic field (nT).
|
||||
* @param[out] F the total magnetic field (nT).
|
||||
* @param[out] D the declination of the field (degrees east of north).
|
||||
* @param[out] I the inclination of the field (degrees down from
|
||||
* horizontal).
|
||||
* @param[out] Ht the rate of change of \e H (nT/yr).
|
||||
* @param[out] Ft the rate of change of \e F (nT/yr).
|
||||
* @param[out] Dt the rate of change of \e D (degrees/yr).
|
||||
* @param[out] It the rate of change of \e I (degrees/yr).
|
||||
**********************************************************************/
|
||||
static void FieldComponents(real Bx, real By, real Bz,
|
||||
real Bxt, real Byt, real Bzt,
|
||||
real& H, real& F, real& D, real& I,
|
||||
real& Ht, real& Ft, real& Dt, real& It);
|
||||
///@}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return the description of the magnetic model, if available, from the
|
||||
* Description file in the data file; if absent, return "NONE".
|
||||
**********************************************************************/
|
||||
const std::string& Description() const { return _description; }
|
||||
|
||||
/**
|
||||
* @return date of the model, if available, from the ReleaseDate field in
|
||||
* the data file; if absent, return "UNKNOWN".
|
||||
**********************************************************************/
|
||||
const std::string& DateTime() const { return _date; }
|
||||
|
||||
/**
|
||||
* @return full file name used to load the magnetic model.
|
||||
**********************************************************************/
|
||||
const std::string& MagneticFile() const { return _filename; }
|
||||
|
||||
/**
|
||||
* @return "name" used to load the magnetic model (from the first argument
|
||||
* of the constructor, but this may be overridden by the model file).
|
||||
**********************************************************************/
|
||||
const std::string& MagneticModelName() const { return _name; }
|
||||
|
||||
/**
|
||||
* @return directory used to load the magnetic model.
|
||||
**********************************************************************/
|
||||
const std::string& MagneticModelDirectory() const { return _dir; }
|
||||
|
||||
/**
|
||||
* @return the minimum height above the ellipsoid (in meters) for which
|
||||
* this MagneticModel should be used.
|
||||
*
|
||||
* Because the model will typically provide useful results
|
||||
* slightly outside the range of allowed heights, no check of \e t
|
||||
* argument is made by MagneticModel::operator()() or
|
||||
* MagneticModel::Circle.
|
||||
**********************************************************************/
|
||||
Math::real MinHeight() const { return _hmin; }
|
||||
|
||||
/**
|
||||
* @return the maximum height above the ellipsoid (in meters) for which
|
||||
* this MagneticModel should be used.
|
||||
*
|
||||
* Because the model will typically provide useful results
|
||||
* slightly outside the range of allowed heights, no check of \e t
|
||||
* argument is made by MagneticModel::operator()() or
|
||||
* MagneticModel::Circle.
|
||||
**********************************************************************/
|
||||
Math::real MaxHeight() const { return _hmax; }
|
||||
|
||||
/**
|
||||
* @return the minimum time (in years) for which this MagneticModel should
|
||||
* be used.
|
||||
*
|
||||
* Because the model will typically provide useful results
|
||||
* slightly outside the range of allowed times, no check of \e t
|
||||
* argument is made by MagneticModel::operator()() or
|
||||
* MagneticModel::Circle.
|
||||
**********************************************************************/
|
||||
Math::real MinTime() const { return _tmin; }
|
||||
|
||||
/**
|
||||
* @return the maximum time (in years) for which this MagneticModel should
|
||||
* be used.
|
||||
*
|
||||
* Because the model will typically provide useful results
|
||||
* slightly outside the range of allowed times, no check of \e t
|
||||
* argument is made by MagneticModel::operator()() or
|
||||
* MagneticModel::Circle.
|
||||
**********************************************************************/
|
||||
Math::real MaxTime() const { return _tmax; }
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value of \e a inherited from the Geocentric object used in the
|
||||
* constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _earth.EquatorialRadius(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value
|
||||
* inherited from the Geocentric object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _earth.Flattening(); }
|
||||
|
||||
/**
|
||||
* @return \e Nmax the maximum degree of the components of the model.
|
||||
**********************************************************************/
|
||||
int Degree() const { return _nmx; }
|
||||
|
||||
/**
|
||||
* @return \e Mmax the maximum order of the components of the model.
|
||||
**********************************************************************/
|
||||
int Order() const { return _mmx; }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* @return the default path for magnetic model data files.
|
||||
*
|
||||
* This is the value of the environment variable
|
||||
* GEOGRAPHICLIB_MAGNETIC_PATH, if set; otherwise, it is
|
||||
* $GEOGRAPHICLIB_DATA/magnetic if the environment variable
|
||||
* GEOGRAPHICLIB_DATA is set; otherwise, it is a compile-time default
|
||||
* (/usr/local/share/GeographicLib/magnetic on non-Windows systems and
|
||||
* C:/ProgramData/GeographicLib/magnetic on Windows systems).
|
||||
**********************************************************************/
|
||||
static std::string DefaultMagneticPath();
|
||||
|
||||
/**
|
||||
* @return the default name for the magnetic model.
|
||||
*
|
||||
* This is the value of the environment variable
|
||||
* GEOGRAPHICLIB_MAGNETIC_NAME, if set; otherwise, it is "wmm2020". The
|
||||
* MagneticModel class does not use this function; it is just provided as a
|
||||
* convenience for a calling program when constructing a MagneticModel
|
||||
* object.
|
||||
**********************************************************************/
|
||||
static std::string DefaultMagneticName();
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_MAGNETICMODEL_HPP
|
||||
684
external/include/GeographicLib/Math.hpp
vendored
Normal file
684
external/include/GeographicLib/Math.hpp
vendored
Normal file
@@ -0,0 +1,684 @@
|
||||
/**
|
||||
* \file Math.hpp
|
||||
* \brief Header for GeographicLib::Math class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
// Constants.hpp includes Math.hpp. Place this include outside Math.hpp's
|
||||
// include guard to enforce this ordering.
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_MATH_HPP)
|
||||
#define GEOGRAPHICLIB_MATH_HPP 1
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_WORDS_BIGENDIAN)
|
||||
# define GEOGRAPHICLIB_WORDS_BIGENDIAN 0
|
||||
#endif
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_HAVE_LONG_DOUBLE)
|
||||
# define GEOGRAPHICLIB_HAVE_LONG_DOUBLE 0
|
||||
#endif
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_PRECISION)
|
||||
/**
|
||||
* The precision of floating point numbers used in %GeographicLib. 1 means
|
||||
* float (single precision); 2 (the default) means double; 3 means long double;
|
||||
* 4 is reserved for quadruple precision. Nearly all the testing has been
|
||||
* carried out with doubles and that's the recommended configuration. In order
|
||||
* for long double to be used, GEOGRAPHICLIB_HAVE_LONG_DOUBLE needs to be
|
||||
* defined. Note that with Microsoft Visual Studio, long double is the same as
|
||||
* double.
|
||||
**********************************************************************/
|
||||
# define GEOGRAPHICLIB_PRECISION 2
|
||||
#endif
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#if GEOGRAPHICLIB_PRECISION == 4
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/multiprecision/float128.hpp>
|
||||
#include <boost/math/special_functions.hpp>
|
||||
#elif GEOGRAPHICLIB_PRECISION == 5
|
||||
#include <mpreal.h>
|
||||
#endif
|
||||
|
||||
#if GEOGRAPHICLIB_PRECISION > 3
|
||||
// volatile keyword makes no sense for multiprec types
|
||||
#define GEOGRAPHICLIB_VOLATILE
|
||||
// Signal a convergence failure with multiprec types by throwing an exception
|
||||
// at loop exit.
|
||||
#define GEOGRAPHICLIB_PANIC \
|
||||
(throw GeographicLib::GeographicErr("Convergence failure"), false)
|
||||
#else
|
||||
#define GEOGRAPHICLIB_VOLATILE volatile
|
||||
// Ignore convergence failures with standard floating points types by allowing
|
||||
// loop to exit cleanly.
|
||||
#define GEOGRAPHICLIB_PANIC false
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Mathematical functions needed by %GeographicLib
|
||||
*
|
||||
* Define mathematical functions in order to localize system dependencies and
|
||||
* to provide generic versions of the functions. In addition define a real
|
||||
* type to be used by %GeographicLib.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-Math.cpp
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT Math {
|
||||
private:
|
||||
void dummy(); // Static check for GEOGRAPHICLIB_PRECISION
|
||||
Math(); // Disable constructor
|
||||
public:
|
||||
|
||||
#if GEOGRAPHICLIB_HAVE_LONG_DOUBLE
|
||||
/**
|
||||
* The extended precision type for real numbers, used for some testing.
|
||||
* This is long double on computers with this type; otherwise it is double.
|
||||
**********************************************************************/
|
||||
typedef long double extended;
|
||||
#else
|
||||
typedef double extended;
|
||||
#endif
|
||||
|
||||
#if GEOGRAPHICLIB_PRECISION == 2
|
||||
/**
|
||||
* The real type for %GeographicLib. Nearly all the testing has been done
|
||||
* with \e real = double. However, the algorithms should also work with
|
||||
* float and long double (where available). (<b>CAUTION</b>: reasonable
|
||||
* accuracy typically cannot be obtained using floats.)
|
||||
**********************************************************************/
|
||||
typedef double real;
|
||||
#elif GEOGRAPHICLIB_PRECISION == 1
|
||||
typedef float real;
|
||||
#elif GEOGRAPHICLIB_PRECISION == 3
|
||||
typedef extended real;
|
||||
#elif GEOGRAPHICLIB_PRECISION == 4
|
||||
typedef boost::multiprecision::float128 real;
|
||||
#elif GEOGRAPHICLIB_PRECISION == 5
|
||||
typedef mpfr::mpreal real;
|
||||
#else
|
||||
typedef double real;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @return the number of bits of precision in a real number.
|
||||
**********************************************************************/
|
||||
static int digits();
|
||||
|
||||
/**
|
||||
* Set the binary precision of a real number.
|
||||
*
|
||||
* @param[in] ndigits the number of bits of precision.
|
||||
* @return the resulting number of bits of precision.
|
||||
*
|
||||
* This only has an effect when GEOGRAPHICLIB_PRECISION = 5. See also
|
||||
* Utility::set_digits for caveats about when this routine should be
|
||||
* called.
|
||||
**********************************************************************/
|
||||
static int set_digits(int ndigits);
|
||||
|
||||
/**
|
||||
* @return the number of decimal digits of precision in a real number.
|
||||
**********************************************************************/
|
||||
static int digits10();
|
||||
|
||||
/**
|
||||
* Number of additional decimal digits of precision for real relative to
|
||||
* double (0 for float).
|
||||
**********************************************************************/
|
||||
static int extra_digits();
|
||||
|
||||
/**
|
||||
* true if the machine is big-endian.
|
||||
**********************************************************************/
|
||||
static const bool bigendian = GEOGRAPHICLIB_WORDS_BIGENDIAN;
|
||||
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return π.
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T pi() {
|
||||
using std::atan2;
|
||||
static const T pi = atan2(T(0), T(-1));
|
||||
return pi;
|
||||
}
|
||||
|
||||
/**
|
||||
* @tparam T the type of the returned value.
|
||||
* @return the number of radians in a degree.
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T degree() {
|
||||
static const T degree = pi<T>() / 180;
|
||||
return degree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Square a number.
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] x
|
||||
* @return <i>x</i><sup>2</sup>.
|
||||
**********************************************************************/
|
||||
template<typename T> static T sq(T x)
|
||||
{ return x * x; }
|
||||
|
||||
/**
|
||||
* The hypotenuse function avoiding underflow and overflow.
|
||||
*
|
||||
* @tparam T the type of the arguments and the returned value.
|
||||
* @param[in] x
|
||||
* @param[in] y
|
||||
* @return sqrt(<i>x</i><sup>2</sup> + <i>y</i><sup>2</sup>).
|
||||
*
|
||||
* \deprecated Use std::hypot(x, y).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::hypot(x, y)")
|
||||
static T hypot(T x, T y);
|
||||
|
||||
/**
|
||||
* exp(\e x) − 1 accurate near \e x = 0.
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] x
|
||||
* @return exp(\e x) − 1.
|
||||
*
|
||||
* \deprecated Use std::expm1(x).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::expm1(x)")
|
||||
static T expm1(T x);
|
||||
|
||||
/**
|
||||
* log(1 + \e x) accurate near \e x = 0.
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] x
|
||||
* @return log(1 + \e x).
|
||||
*
|
||||
* \deprecated Use std::log1p(x).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::log1p(x)")
|
||||
static T log1p(T x);
|
||||
|
||||
/**
|
||||
* The inverse hyperbolic sine function.
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] x
|
||||
* @return asinh(\e x).
|
||||
*
|
||||
* \deprecated Use std::asinh(x).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::asinh(x)")
|
||||
static T asinh(T x);
|
||||
|
||||
/**
|
||||
* The inverse hyperbolic tangent function.
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] x
|
||||
* @return atanh(\e x).
|
||||
*
|
||||
* \deprecated Use std::atanh(x).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::atanh(x)")
|
||||
static T atanh(T x);
|
||||
|
||||
/**
|
||||
* Copy the sign.
|
||||
*
|
||||
* @tparam T the type of the argument.
|
||||
* @param[in] x gives the magitude of the result.
|
||||
* @param[in] y gives the sign of the result.
|
||||
* @return value with the magnitude of \e x and with the sign of \e y.
|
||||
*
|
||||
* This routine correctly handles the case \e y = −0, returning
|
||||
* &minus|<i>x</i>|.
|
||||
*
|
||||
* \deprecated Use std::copysign(x, y).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::copysign(x, y)")
|
||||
static T copysign(T x, T y);
|
||||
|
||||
/**
|
||||
* The cube root function.
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] x
|
||||
* @return the real cube root of \e x.
|
||||
*
|
||||
* \deprecated Use std::cbrt(x).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::cbrt(x)")
|
||||
static T cbrt(T x);
|
||||
|
||||
/**
|
||||
* The remainder function.
|
||||
*
|
||||
* @tparam T the type of the arguments and the returned value.
|
||||
* @param[in] x
|
||||
* @param[in] y
|
||||
* @return the remainder of \e x/\e y in the range [−\e y/2, \e y/2].
|
||||
*
|
||||
* \deprecated Use std::remainder(x).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::remainder(x)")
|
||||
static T remainder(T x, T y);
|
||||
|
||||
/**
|
||||
* The remquo function.
|
||||
*
|
||||
* @tparam T the type of the arguments and the returned value.
|
||||
* @param[in] x
|
||||
* @param[in] y
|
||||
* @param[out] n the low 3 bits of the quotient
|
||||
* @return the remainder of \e x/\e y in the range [−\e y/2, \e y/2].
|
||||
*
|
||||
* \deprecated Use std::remquo(x, y, n).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::remquo(x, y, n)")
|
||||
static T remquo(T x, T y, int* n);
|
||||
|
||||
/**
|
||||
* The round function.
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] x
|
||||
* @return \e x round to the nearest integer (ties round away from 0).
|
||||
*
|
||||
* \deprecated Use std::round(x).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::round(x)")
|
||||
static T round(T x);
|
||||
|
||||
/**
|
||||
* The lround function.
|
||||
*
|
||||
* @tparam T the type of the argument.
|
||||
* @param[in] x
|
||||
* @return \e x round to the nearest integer as a long int (ties round away
|
||||
* from 0).
|
||||
*
|
||||
* If the result does not fit in a long int, the return value is undefined.
|
||||
*
|
||||
* \deprecated Use std::lround(x).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::lround(x)")
|
||||
static long lround(T x);
|
||||
|
||||
/**
|
||||
* Fused multiply and add.
|
||||
*
|
||||
* @tparam T the type of the arguments and the returned value.
|
||||
* @param[in] x
|
||||
* @param[in] y
|
||||
* @param[in] z
|
||||
* @return <i>xy</i> + <i>z</i>, correctly rounded (on those platforms with
|
||||
* support for the <code>fma</code> instruction).
|
||||
*
|
||||
* On platforms without the <code>fma</code> instruction, no attempt is
|
||||
* made to improve on the result of a rounded multiplication followed by a
|
||||
* rounded addition.
|
||||
*
|
||||
* \deprecated Use std::fma(x, y, z).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::fma(x, y, z)")
|
||||
static T fma(T x, T y, T z);
|
||||
|
||||
/**
|
||||
* Normalize a two-vector.
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in,out] x on output set to <i>x</i>/hypot(<i>x</i>, <i>y</i>).
|
||||
* @param[in,out] y on output set to <i>y</i>/hypot(<i>x</i>, <i>y</i>).
|
||||
**********************************************************************/
|
||||
template<typename T> static void norm(T& x, T& y) {
|
||||
#if defined(_MSC_VER) && defined(_M_IX86)
|
||||
// hypot for Visual Studio (A=win32) fails monotonicity, e.g., with
|
||||
// x = 0.6102683302836215
|
||||
// y1 = 0.7906090004346522
|
||||
// y2 = y1 + 1e-16
|
||||
// the test
|
||||
// hypot(x, y2) >= hypot(x, y1)
|
||||
// fails. Reported 2021-03-14:
|
||||
// https://developercommunity.visualstudio.com/t/1369259
|
||||
// See also:
|
||||
// https://bugs.python.org/issue43088
|
||||
using std::sqrt; T h = sqrt(x * x + y * y);
|
||||
#else
|
||||
using std::hypot; T h = hypot(x, y);
|
||||
#endif
|
||||
x /= h; y /= h;
|
||||
}
|
||||
|
||||
/**
|
||||
* The error-free sum of two numbers.
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] u
|
||||
* @param[in] v
|
||||
* @param[out] t the exact error given by (\e u + \e v) - \e s.
|
||||
* @return \e s = round(\e u + \e v).
|
||||
*
|
||||
* See D. E. Knuth, TAOCP, Vol 2, 4.2.2, Theorem B. (Note that \e t can be
|
||||
* the same as one of the first two arguments.)
|
||||
**********************************************************************/
|
||||
template<typename T> static T sum(T u, T v, T& t);
|
||||
|
||||
/**
|
||||
* Evaluate a polynomial.
|
||||
*
|
||||
* @tparam T the type of the arguments and returned value.
|
||||
* @param[in] N the order of the polynomial.
|
||||
* @param[in] p the coefficient array (of size \e N + 1).
|
||||
* @param[in] x the variable.
|
||||
* @return the value of the polynomial.
|
||||
*
|
||||
* Evaluate <i>y</i> = ∑<sub><i>n</i>=0..<i>N</i></sub>
|
||||
* <i>p</i><sub><i>n</i></sub> <i>x</i><sup><i>N</i>−<i>n</i></sup>.
|
||||
* Return 0 if \e N < 0. Return <i>p</i><sub>0</sub>, if \e N = 0 (even
|
||||
* if \e x is infinite or a nan). The evaluation uses Horner's method.
|
||||
**********************************************************************/
|
||||
template<typename T> static T polyval(int N, const T p[], T x) {
|
||||
// This used to employ Math::fma; but that's too slow and it seemed not to
|
||||
// improve the accuracy noticeably. This might change when there's direct
|
||||
// hardware support for fma.
|
||||
T y = N < 0 ? 0 : *p++;
|
||||
while (--N >= 0) y = y * x + *p++;
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize an angle.
|
||||
*
|
||||
* @tparam T the type of the argument and returned value.
|
||||
* @param[in] x the angle in degrees.
|
||||
* @return the angle reduced to the range (−180°, 180°].
|
||||
*
|
||||
* The range of \e x is unrestricted.
|
||||
**********************************************************************/
|
||||
template<typename T> static T AngNormalize(T x) {
|
||||
using std::remainder;
|
||||
x = remainder(x, T(360)); return x != -180 ? x : 180;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a latitude.
|
||||
*
|
||||
* @tparam T the type of the argument and returned value.
|
||||
* @param[in] x the angle in degrees.
|
||||
* @return x if it is in the range [−90°, 90°], otherwise
|
||||
* return NaN.
|
||||
**********************************************************************/
|
||||
template<typename T> static T LatFix(T x)
|
||||
{ using std::abs; return abs(x) > 90 ? NaN<T>() : x; }
|
||||
|
||||
/**
|
||||
* The exact difference of two angles reduced to
|
||||
* (−180°, 180°].
|
||||
*
|
||||
* @tparam T the type of the arguments and returned value.
|
||||
* @param[in] x the first angle in degrees.
|
||||
* @param[in] y the second angle in degrees.
|
||||
* @param[out] e the error term in degrees.
|
||||
* @return \e d, the truncated value of \e y − \e x.
|
||||
*
|
||||
* This computes \e z = \e y − \e x exactly, reduced to
|
||||
* (−180°, 180°]; and then sets \e z = \e d + \e e where \e d
|
||||
* is the nearest representable number to \e z and \e e is the truncation
|
||||
* error. If \e d = −180, then \e e > 0; If \e d = 180, then \e e
|
||||
* ≤ 0.
|
||||
**********************************************************************/
|
||||
template<typename T> static T AngDiff(T x, T y, T& e) {
|
||||
using std::remainder;
|
||||
T t, d = AngNormalize(sum(remainder(-x, T(360)),
|
||||
remainder( y, T(360)), t));
|
||||
// Here y - x = d + t (mod 360), exactly, where d is in (-180,180] and
|
||||
// abs(t) <= eps (eps = 2^-45 for doubles). The only case where the
|
||||
// addition of t takes the result outside the range (-180,180] is d = 180
|
||||
// and t > 0. The case, d = -180 + eps, t = -eps, can't happen, since
|
||||
// sum would have returned the exact result in such a case (i.e., given t
|
||||
// = 0).
|
||||
return sum(d == 180 && t > 0 ? -180 : d, t, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Difference of two angles reduced to [−180°, 180°]
|
||||
*
|
||||
* @tparam T the type of the arguments and returned value.
|
||||
* @param[in] x the first angle in degrees.
|
||||
* @param[in] y the second angle in degrees.
|
||||
* @return \e y − \e x, reduced to the range [−180°,
|
||||
* 180°].
|
||||
*
|
||||
* The result is equivalent to computing the difference exactly, reducing
|
||||
* it to (−180°, 180°] and rounding the result. Note that
|
||||
* this prescription allows −180° to be returned (e.g., if \e x
|
||||
* is tiny and negative and \e y = 180°).
|
||||
**********************************************************************/
|
||||
template<typename T> static T AngDiff(T x, T y)
|
||||
{ T e; return AngDiff(x, y, e); }
|
||||
|
||||
/**
|
||||
* Coarsen a value close to zero.
|
||||
*
|
||||
* @tparam T the type of the argument and returned value.
|
||||
* @param[in] x
|
||||
* @return the coarsened value.
|
||||
*
|
||||
* The makes the smallest gap in \e x = 1/16 − nextafter(1/16, 0) =
|
||||
* 1/2<sup>57</sup> for reals = 0.7 pm on the earth if \e x is an angle in
|
||||
* degrees. (This is about 1000 times more resolution than we get with
|
||||
* angles around 90°.) We use this to avoid having to deal with near
|
||||
* singular cases when \e x is non-zero but tiny (e.g.,
|
||||
* 10<sup>−200</sup>). This converts −0 to +0; however tiny
|
||||
* negative numbers get converted to −0.
|
||||
**********************************************************************/
|
||||
template<typename T> static T AngRound(T x);
|
||||
|
||||
/**
|
||||
* Evaluate the sine and cosine function with the argument in degrees
|
||||
*
|
||||
* @tparam T the type of the arguments.
|
||||
* @param[in] x in degrees.
|
||||
* @param[out] sinx sin(<i>x</i>).
|
||||
* @param[out] cosx cos(<i>x</i>).
|
||||
*
|
||||
* The results obey exactly the elementary properties of the trigonometric
|
||||
* functions, e.g., sin 9° = cos 81° = − sin 123456789°.
|
||||
* If x = −0, then \e sinx = −0; this is the only case where
|
||||
* −0 is returned.
|
||||
**********************************************************************/
|
||||
template<typename T> static void sincosd(T x, T& sinx, T& cosx);
|
||||
|
||||
/**
|
||||
* Evaluate the sine function with the argument in degrees
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] x in degrees.
|
||||
* @return sin(<i>x</i>).
|
||||
**********************************************************************/
|
||||
template<typename T> static T sind(T x);
|
||||
|
||||
/**
|
||||
* Evaluate the cosine function with the argument in degrees
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] x in degrees.
|
||||
* @return cos(<i>x</i>).
|
||||
**********************************************************************/
|
||||
template<typename T> static T cosd(T x);
|
||||
|
||||
/**
|
||||
* Evaluate the tangent function with the argument in degrees
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] x in degrees.
|
||||
* @return tan(<i>x</i>).
|
||||
*
|
||||
* If \e x = ±90°, then a suitably large (but finite) value is
|
||||
* returned.
|
||||
**********************************************************************/
|
||||
template<typename T> static T tand(T x);
|
||||
|
||||
/**
|
||||
* Evaluate the atan2 function with the result in degrees
|
||||
*
|
||||
* @tparam T the type of the arguments and the returned value.
|
||||
* @param[in] y
|
||||
* @param[in] x
|
||||
* @return atan2(<i>y</i>, <i>x</i>) in degrees.
|
||||
*
|
||||
* The result is in the range (−180° 180°]. N.B.,
|
||||
* atan2d(±0, −1) = +180°; atan2d(−ε,
|
||||
* −1) = −180°, for ε positive and tiny;
|
||||
* atan2d(±0, +1) = ±0°.
|
||||
**********************************************************************/
|
||||
template<typename T> static T atan2d(T y, T x);
|
||||
|
||||
/**
|
||||
* Evaluate the atan function with the result in degrees
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] x
|
||||
* @return atan(<i>x</i>) in degrees.
|
||||
**********************************************************************/
|
||||
template<typename T> static T atand(T x);
|
||||
|
||||
/**
|
||||
* Evaluate <i>e</i> atanh(<i>e x</i>)
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] x
|
||||
* @param[in] es the signed eccentricity = sign(<i>e</i><sup>2</sup>)
|
||||
* sqrt(|<i>e</i><sup>2</sup>|)
|
||||
* @return <i>e</i> atanh(<i>e x</i>)
|
||||
*
|
||||
* If <i>e</i><sup>2</sup> is negative (<i>e</i> is imaginary), the
|
||||
* expression is evaluated in terms of atan.
|
||||
**********************************************************************/
|
||||
template<typename T> static T eatanhe(T x, T es);
|
||||
|
||||
/**
|
||||
* tanχ in terms of tanφ
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] tau τ = tanφ
|
||||
* @param[in] es the signed eccentricity = sign(<i>e</i><sup>2</sup>)
|
||||
* sqrt(|<i>e</i><sup>2</sup>|)
|
||||
* @return τ′ = tanχ
|
||||
*
|
||||
* See Eqs. (7--9) of
|
||||
* C. F. F. Karney,
|
||||
* <a href="https://doi.org/10.1007/s00190-011-0445-3">
|
||||
* Transverse Mercator with an accuracy of a few nanometers,</a>
|
||||
* J. Geodesy 85(8), 475--485 (Aug. 2011)
|
||||
* (preprint
|
||||
* <a href="https://arxiv.org/abs/1002.1417">arXiv:1002.1417</a>).
|
||||
**********************************************************************/
|
||||
template<typename T> static T taupf(T tau, T es);
|
||||
|
||||
/**
|
||||
* tanφ in terms of tanχ
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] taup τ′ = tanχ
|
||||
* @param[in] es the signed eccentricity = sign(<i>e</i><sup>2</sup>)
|
||||
* sqrt(|<i>e</i><sup>2</sup>|)
|
||||
* @return τ = tanφ
|
||||
*
|
||||
* See Eqs. (19--21) of
|
||||
* C. F. F. Karney,
|
||||
* <a href="https://doi.org/10.1007/s00190-011-0445-3">
|
||||
* Transverse Mercator with an accuracy of a few nanometers,</a>
|
||||
* J. Geodesy 85(8), 475--485 (Aug. 2011)
|
||||
* (preprint
|
||||
* <a href="https://arxiv.org/abs/1002.1417">arXiv:1002.1417</a>).
|
||||
**********************************************************************/
|
||||
template<typename T> static T tauf(T taup, T es);
|
||||
|
||||
/**
|
||||
* Test for finiteness.
|
||||
*
|
||||
* @tparam T the type of the argument.
|
||||
* @param[in] x
|
||||
* @return true if number is finite, false if NaN or infinite.
|
||||
*
|
||||
* \deprecated Use std::isfinite(x).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::isfinite(x)")
|
||||
static bool isfinite(T x);
|
||||
|
||||
/**
|
||||
* The NaN (not a number)
|
||||
*
|
||||
* @tparam T the type of the returned value.
|
||||
* @return NaN if available, otherwise return the max real of type T.
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T NaN();
|
||||
|
||||
/**
|
||||
* Test for NaN.
|
||||
*
|
||||
* @tparam T the type of the argument.
|
||||
* @param[in] x
|
||||
* @return true if argument is a NaN.
|
||||
*
|
||||
* \deprecated Use std::isnan(x).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use std::isnan(x)")
|
||||
static bool isnan(T x);
|
||||
|
||||
/**
|
||||
* Infinity
|
||||
*
|
||||
* @tparam T the type of the returned value.
|
||||
* @return infinity if available, otherwise return the max real.
|
||||
**********************************************************************/
|
||||
template<typename T = real> static T infinity();
|
||||
|
||||
/**
|
||||
* Swap the bytes of a quantity
|
||||
*
|
||||
* @tparam T the type of the argument and the returned value.
|
||||
* @param[in] x
|
||||
* @return x with its bytes swapped.
|
||||
**********************************************************************/
|
||||
template<typename T> static T swab(T x) {
|
||||
union {
|
||||
T r;
|
||||
unsigned char c[sizeof(T)];
|
||||
} b;
|
||||
b.r = x;
|
||||
for (int i = sizeof(T)/2; i--; )
|
||||
std::swap(b.c[i], b.c[sizeof(T) - 1 - i]);
|
||||
return b.r;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_MATH_HPP
|
||||
837
external/include/GeographicLib/NearestNeighbor.hpp
vendored
Normal file
837
external/include/GeographicLib/NearestNeighbor.hpp
vendored
Normal file
@@ -0,0 +1,837 @@
|
||||
/**
|
||||
* \file NearestNeighbor.hpp
|
||||
* \brief Header for GeographicLib::NearestNeighbor class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2016-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_NEARESTNEIGHBOR_HPP)
|
||||
#define GEOGRAPHICLIB_NEARESTNEIGHBOR_HPP 1
|
||||
|
||||
#include <algorithm> // for nth_element, max_element, etc.
|
||||
#include <vector>
|
||||
#include <queue> // for priority_queue
|
||||
#include <utility> // for swap + pair
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
// Only for GeographicLib::GeographicErr
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
#if defined(GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION) && \
|
||||
GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION
|
||||
#include <boost/serialization/nvp.hpp>
|
||||
#include <boost/serialization/split_member.hpp>
|
||||
#include <boost/serialization/array.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about constant conditional expressions
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4127)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Nearest-neighbor calculations
|
||||
*
|
||||
* This class solves the nearest-neighbor problm using a vantage-point tree
|
||||
* as described in \ref nearest.
|
||||
*
|
||||
* This class is templated so that it can handle arbitrary metric spaces as
|
||||
* follows:
|
||||
*
|
||||
* @tparam dist_t the type used for measuring distances; it can be a real or
|
||||
* signed integer type; in typical geodetic applications, \e dist_t might
|
||||
* be <code>double</code>.
|
||||
* @tparam pos_t the type for specifying the positions of points; geodetic
|
||||
* application might bundled the latitude and longitude into a
|
||||
* <code>std::pair<dist_t, dist_t></code>.
|
||||
* @tparam distfun_t the type of a function object which takes takes two
|
||||
* positions (of type \e pos_t) and returns the distance (of type \e
|
||||
* dist_t); in geodetic applications, this might be a class which is
|
||||
* constructed with a Geodesic object and which implements a member
|
||||
* function with a signature <code>dist_t operator() (const pos_t&, const
|
||||
* pos_t&) const</code>, which returns the geodesic distance between two
|
||||
* points.
|
||||
*
|
||||
* \note The distance measure must satisfy the triangle inequality, \f$
|
||||
* d(a,c) \le d(a,b) + d(b,c) \f$ for all points \e a, \e b, \e c. The
|
||||
* geodesic distance (given by Geodesic::Inverse) does, while the great
|
||||
* ellipse distance and the rhumb line distance <i>do not</i>. If you use
|
||||
* the ordinary Euclidean distance, i.e., \f$ \sqrt{(x_a-x_b)^2 +
|
||||
* (y_a-y_b)^2} \f$ for two dimensions, don't be tempted to leave out the
|
||||
* square root in the interests of "efficiency"; the squared distance does
|
||||
* not satisfy the triangle inequality!
|
||||
*
|
||||
* \note This is a "header-only" implementation and, as such, depends in a
|
||||
* minimal way on the rest of GeographicLib (the only dependency is through
|
||||
* the use of GeographicLib::GeographicErr for handling compile-time and
|
||||
* run-time exceptions). Therefore, it is easy to extract this class from
|
||||
* the rest of GeographicLib and use it as a stand-alone facility.
|
||||
*
|
||||
* The \e dist_t type must support numeric_limits queries (specifically:
|
||||
* is_signed, is_integer, max(), digits).
|
||||
*
|
||||
* The NearestNeighbor object is constructed with a vector of points (type \e
|
||||
* pos_t) and a distance function (type \e distfun_t). However the object
|
||||
* does \e not store the points. When querying the object with Search(),
|
||||
* it's necessary to supply the same vector of points and the same distance
|
||||
* function.
|
||||
*
|
||||
* There's no capability in this implementation to add or remove points from
|
||||
* the set. Instead Initialize() should be called to re-initialize the
|
||||
* object with the modified vector of points.
|
||||
*
|
||||
* Because of the overhead in constructing a NearestNeighbor object for a
|
||||
* large set of points, functions Save() and Load() are provided to save the
|
||||
* object to an external file. operator<<(), operator>>() and <a
|
||||
* href="https://www.boost.org/libs/serialization/doc"> Boost
|
||||
* serialization</a> can also be used to save and restore a NearestNeighbor
|
||||
* object. This is illustrated in the example.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-NearestNeighbor.cpp
|
||||
**********************************************************************/
|
||||
template <typename dist_t, typename pos_t, class distfun_t>
|
||||
class NearestNeighbor {
|
||||
// For tracking changes to the I/O format
|
||||
static const int version = 1;
|
||||
// This is what we get "free"; but if sizeof(dist_t) = 1 (unlikely), allow
|
||||
// 4 slots (and this accommodates the default value bucket = 4).
|
||||
static const int maxbucket =
|
||||
(2 + ((4 * sizeof(dist_t)) / sizeof(int) >= 2 ?
|
||||
(4 * sizeof(dist_t)) / sizeof(int) : 2));
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default constructor for NearestNeighbor.
|
||||
*
|
||||
* This is equivalent to specifying an empty set of points.
|
||||
**********************************************************************/
|
||||
NearestNeighbor() : _numpoints(0), _bucket(0), _cost(0) {}
|
||||
|
||||
/**
|
||||
* Constructor for NearestNeighbor.
|
||||
*
|
||||
* @param[in] pts a vector of points to include in the set.
|
||||
* @param[in] dist the distance function object.
|
||||
* @param[in] bucket the size of the buckets at the leaf nodes; this must
|
||||
* lie in [0, 2 + 4*sizeof(dist_t)/sizeof(int)] (default 4).
|
||||
* @exception GeographicErr if the value of \e bucket is out of bounds or
|
||||
* the size of \e pts is too big for an int.
|
||||
* @exception std::bad_alloc if memory for the tree can't be allocated.
|
||||
*
|
||||
* \e pts may contain coincident points (i.e., the distance between them
|
||||
* vanishes); these are treated as distinct.
|
||||
*
|
||||
* The choice of \e bucket is a tradeoff between space and efficiency. A
|
||||
* larger \e bucket decreases the size of the NearestNeighbor object which
|
||||
* scales as pts.size() / max(1, bucket) and reduces the number of distance
|
||||
* calculations to construct the object by log2(bucket) * pts.size().
|
||||
* However each search then requires about bucket additional distance
|
||||
* calculations.
|
||||
*
|
||||
* \warning The distances computed by \e dist must satisfy the standard
|
||||
* metric conditions. If not, the results are undefined. Neither the data
|
||||
* in \e pts nor the query points should contain NaNs or infinities because
|
||||
* such data violates the metric conditions.
|
||||
*
|
||||
* \warning The same arguments \e pts and \e dist must be provided
|
||||
* to the Search() function.
|
||||
**********************************************************************/
|
||||
NearestNeighbor(const std::vector<pos_t>& pts, const distfun_t& dist,
|
||||
int bucket = 4) {
|
||||
Initialize(pts, dist, bucket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize or re-initialize NearestNeighbor.
|
||||
*
|
||||
* @param[in] pts a vector of points to include in the tree.
|
||||
* @param[in] dist the distance function object.
|
||||
* @param[in] bucket the size of the buckets at the leaf nodes; this must
|
||||
* lie in [0, 2 + 4*sizeof(dist_t)/sizeof(int)] (default 4).
|
||||
* @exception GeographicErr if the value of \e bucket is out of bounds or
|
||||
* the size of \e pts is too big for an int.
|
||||
* @exception std::bad_alloc if memory for the tree can't be allocated.
|
||||
*
|
||||
* See also the documentation on the constructor.
|
||||
*
|
||||
* If an exception is thrown, the state of the NearestNeighbor is
|
||||
* unchanged.
|
||||
**********************************************************************/
|
||||
void Initialize(const std::vector<pos_t>& pts, const distfun_t& dist,
|
||||
int bucket = 4) {
|
||||
static_assert(std::numeric_limits<dist_t>::is_signed,
|
||||
"dist_t must be a signed type");
|
||||
if (!( 0 <= bucket && bucket <= maxbucket ))
|
||||
throw GeographicLib::GeographicErr
|
||||
("bucket must lie in [0, 2 + 4*sizeof(dist_t)/sizeof(int)]");
|
||||
if (pts.size() > size_t(std::numeric_limits<int>::max()))
|
||||
throw GeographicLib::GeographicErr("pts array too big");
|
||||
// the pair contains distance+id
|
||||
std::vector<item> ids(pts.size());
|
||||
for (int k = int(ids.size()); k--;)
|
||||
ids[k] = std::make_pair(dist_t(0), k);
|
||||
int cost = 0;
|
||||
std::vector<Node> tree;
|
||||
init(pts, dist, bucket, tree, ids, cost,
|
||||
0, int(ids.size()), int(ids.size()/2));
|
||||
_tree.swap(tree);
|
||||
_numpoints = int(pts.size());
|
||||
_bucket = bucket;
|
||||
_mc = _sc = 0;
|
||||
_cost = cost; _c1 = _k = _cmax = 0;
|
||||
_cmin = std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the NearestNeighbor.
|
||||
*
|
||||
* @param[in] pts the vector of points used for initialization.
|
||||
* @param[in] dist the distance function object used for initialization.
|
||||
* @param[in] query the query point.
|
||||
* @param[out] ind a vector of indices to the closest points found.
|
||||
* @param[in] k the number of points to search for (default = 1).
|
||||
* @param[in] maxdist only return points with distances of \e maxdist or
|
||||
* less from \e query (default is the maximum \e dist_t).
|
||||
* @param[in] mindist only return points with distances of more than
|
||||
* \e mindist from \e query (default = −1).
|
||||
* @param[in] exhaustive whether to do an exhaustive search (default true).
|
||||
* @param[in] tol the tolerance on the results (default 0).
|
||||
* @return the distance to the closest point found (−1 if no points
|
||||
* are found).
|
||||
* @exception GeographicErr if \e pts has a different size from that used
|
||||
* to construct the object.
|
||||
*
|
||||
* The indices returned in \e ind are sorted by distance from \e query
|
||||
* (closest first).
|
||||
*
|
||||
* The simplest invocation is with just the 4 non-optional arguments. This
|
||||
* returns the closest distance and the index to the closest point in
|
||||
* <i>ind</i><sub>0</sub>. If there are several points equally close, then
|
||||
* <i>ind</i><sub>0</sub> gives the index of an arbirary one of them. If
|
||||
* there's no closest point (because the set of points is empty), then \e
|
||||
* ind is empty and −1 is returned.
|
||||
*
|
||||
* With \e exhaustive = true and \e tol = 0 (their default values), this
|
||||
* finds the indices of \e k closest neighbors to \e query whose distances
|
||||
* to \e query are in (\e mindist, \e maxdist]. If \e mindist and \e
|
||||
* maxdist have their default values, then these bounds have no effect. If
|
||||
* \e query is one of the points in the tree, then set \e mindist = 0 to
|
||||
* prevent this point (and other coincident points) from being returned.
|
||||
*
|
||||
* If \e exhaustive = false, exit as soon as \e k results satisfying the
|
||||
* distance criteria are found. If less than \e k results are returned
|
||||
* then the search was exhaustive even if \e exhaustive = false.
|
||||
*
|
||||
* If \e tol is positive, do an approximate search; in this case the
|
||||
* results are to be interpreted as follows: if the <i>k</i>'th distance is
|
||||
* \e dk, then all results with distances less than or equal \e dk −
|
||||
* \e tol are correct; all others are suspect — there may be other
|
||||
* closer results with distances greater or equal to \e dk − \e tol.
|
||||
* If less than \e k results are found, then the search is exact.
|
||||
*
|
||||
* \e mindist should be used to exclude a "small" neighborhood of the query
|
||||
* point (relative to the average spacing of the data). If \e mindist is
|
||||
* large, the efficiency of the search deteriorates.
|
||||
*
|
||||
* \note Only the shortest distance is returned (as as the function value).
|
||||
* The distances to other points (indexed by <i>ind</i><sub><i>j</i></sub>
|
||||
* for \e j > 0) can be found by invoking \e dist again.
|
||||
*
|
||||
* \warning The arguments \e pts and \e dist must be identical to those
|
||||
* used to initialize the NearestNeighbor; if not, this function will
|
||||
* return some meaningless result (however, if the size of \e pts is wrong,
|
||||
* this function throw an exception).
|
||||
*
|
||||
* \warning The query point cannot be a NaN or infinite because then the
|
||||
* metric conditions are violated.
|
||||
**********************************************************************/
|
||||
dist_t Search(const std::vector<pos_t>& pts, const distfun_t& dist,
|
||||
const pos_t& query,
|
||||
std::vector<int>& ind,
|
||||
int k = 1,
|
||||
dist_t maxdist = std::numeric_limits<dist_t>::max(),
|
||||
dist_t mindist = -1,
|
||||
bool exhaustive = true,
|
||||
dist_t tol = 0) const {
|
||||
if (_numpoints != int(pts.size()))
|
||||
throw GeographicLib::GeographicErr("pts array has wrong size");
|
||||
std::priority_queue<item> results;
|
||||
if (_numpoints > 0 && k > 0 && maxdist > mindist) {
|
||||
// distance to the kth closest point so far
|
||||
dist_t tau = maxdist;
|
||||
// first is negative of how far query is outside boundary of node
|
||||
// +1 if on boundary or inside
|
||||
// second is node index
|
||||
std::priority_queue<item> todo;
|
||||
todo.push(std::make_pair(dist_t(1), int(_tree.size()) - 1));
|
||||
int c = 0;
|
||||
while (!todo.empty()) {
|
||||
int n = todo.top().second;
|
||||
dist_t d = -todo.top().first;
|
||||
todo.pop();
|
||||
dist_t tau1 = tau - tol;
|
||||
// compare tau and d again since tau may have become smaller.
|
||||
if (!( n >= 0 && tau1 >= d )) continue;
|
||||
const Node& current = _tree[n];
|
||||
dist_t dst = 0; // to suppress warning about uninitialized variable
|
||||
bool exitflag = false, leaf = current.index < 0;
|
||||
for (int i = 0; i < (leaf ? _bucket : 1); ++i) {
|
||||
int index = leaf ? current.leaves[i] : current.index;
|
||||
if (index < 0) break;
|
||||
dst = dist(pts[index], query);
|
||||
++c;
|
||||
|
||||
if (dst > mindist && dst <= tau) {
|
||||
if (int(results.size()) == k) results.pop();
|
||||
results.push(std::make_pair(dst, index));
|
||||
if (int(results.size()) == k) {
|
||||
if (exhaustive)
|
||||
tau = results.top().first;
|
||||
else {
|
||||
exitflag = true;
|
||||
break;
|
||||
}
|
||||
if (tau <= tol) {
|
||||
exitflag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exitflag) break;
|
||||
|
||||
if (current.index < 0) continue;
|
||||
tau1 = tau - tol;
|
||||
for (int l = 0; l < 2; ++l) {
|
||||
if (current.data.child[l] >= 0 &&
|
||||
dst + current.data.upper[l] >= mindist) {
|
||||
if (dst < current.data.lower[l]) {
|
||||
d = current.data.lower[l] - dst;
|
||||
if (tau1 >= d)
|
||||
todo.push(std::make_pair(-d, current.data.child[l]));
|
||||
} else if (dst > current.data.upper[l]) {
|
||||
d = dst - current.data.upper[l];
|
||||
if (tau1 >= d)
|
||||
todo.push(std::make_pair(-d, current.data.child[l]));
|
||||
} else
|
||||
todo.push(std::make_pair(dist_t(1), current.data.child[l]));
|
||||
}
|
||||
}
|
||||
}
|
||||
++_k;
|
||||
_c1 += c;
|
||||
double omc = _mc;
|
||||
_mc += (c - omc) / _k;
|
||||
_sc += (c - omc) * (c - _mc);
|
||||
if (c > _cmax) _cmax = c;
|
||||
if (c < _cmin) _cmin = c;
|
||||
}
|
||||
|
||||
dist_t d = -1;
|
||||
ind.resize(results.size());
|
||||
|
||||
for (int i = int(ind.size()); i--;) {
|
||||
ind[i] = int(results.top().second);
|
||||
if (i == 0) d = results.top().first;
|
||||
results.pop();
|
||||
}
|
||||
return d;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the total number of points in the set.
|
||||
**********************************************************************/
|
||||
int NumPoints() const { return _numpoints; }
|
||||
|
||||
/**
|
||||
* Write the object to an I/O stream.
|
||||
*
|
||||
* @param[in,out] os the stream to write to.
|
||||
* @param[in] bin if true (the default) save in binary mode.
|
||||
* @exception std::bad_alloc if memory for the string representation of the
|
||||
* object can't be allocated.
|
||||
*
|
||||
* The counters tracking the statistics of searches are not saved; however
|
||||
* the initializtion cost is saved. The format of the binary saves is \e
|
||||
* not portable.
|
||||
*
|
||||
* \note <a href="https://www.boost.org/libs/serialization/doc">
|
||||
* Boost serialization</a> can also be used to save and restore a
|
||||
* NearestNeighbor object. This requires that the
|
||||
* GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION macro be defined.
|
||||
**********************************************************************/
|
||||
void Save(std::ostream& os, bool bin = true) const {
|
||||
int realspec = std::numeric_limits<dist_t>::digits *
|
||||
(std::numeric_limits<dist_t>::is_integer ? -1 : 1);
|
||||
if (bin) {
|
||||
char id[] = "NearestNeighbor_";
|
||||
os.write(id, 16);
|
||||
int buf[6];
|
||||
buf[0] = version;
|
||||
buf[1] = realspec;
|
||||
buf[2] = _bucket;
|
||||
buf[3] = _numpoints;
|
||||
buf[4] = int(_tree.size());
|
||||
buf[5] = _cost;
|
||||
os.write(reinterpret_cast<const char *>(buf), 6 * sizeof(int));
|
||||
for (int i = 0; i < int(_tree.size()); ++i) {
|
||||
const Node& node = _tree[i];
|
||||
os.write(reinterpret_cast<const char *>(&node.index), sizeof(int));
|
||||
if (node.index >= 0) {
|
||||
os.write(reinterpret_cast<const char *>(node.data.lower),
|
||||
2 * sizeof(dist_t));
|
||||
os.write(reinterpret_cast<const char *>(node.data.upper),
|
||||
2 * sizeof(dist_t));
|
||||
os.write(reinterpret_cast<const char *>(node.data.child),
|
||||
2 * sizeof(int));
|
||||
} else {
|
||||
os.write(reinterpret_cast<const char *>(node.leaves),
|
||||
_bucket * sizeof(int));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::stringstream ostring;
|
||||
// Ensure enough precision for type dist_t. With C++11, max_digits10
|
||||
// can be used instead.
|
||||
if (!std::numeric_limits<dist_t>::is_integer) {
|
||||
static const int prec
|
||||
= int(std::ceil(std::numeric_limits<dist_t>::digits *
|
||||
std::log10(2.0) + 1));
|
||||
ostring.precision(prec);
|
||||
}
|
||||
ostring << version << " " << realspec << " " << _bucket << " "
|
||||
<< _numpoints << " " << _tree.size() << " " << _cost;
|
||||
for (int i = 0; i < int(_tree.size()); ++i) {
|
||||
const Node& node = _tree[i];
|
||||
ostring << "\n" << node.index;
|
||||
if (node.index >= 0) {
|
||||
for (int l = 0; l < 2; ++l)
|
||||
ostring << " " << node.data.lower[l] << " " << node.data.upper[l]
|
||||
<< " " << node.data.child[l];
|
||||
} else {
|
||||
for (int l = 0; l < _bucket; ++l)
|
||||
ostring << " " << node.leaves[l];
|
||||
}
|
||||
}
|
||||
os << ostring.str();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the object from an I/O stream.
|
||||
*
|
||||
* @param[in,out] is the stream to read from
|
||||
* @param[in] bin if true (the default) load in binary mode.
|
||||
* @exception GeographicErr if the state read from \e is is illegal.
|
||||
* @exception std::bad_alloc if memory for the tree can't be allocated.
|
||||
*
|
||||
* The counters tracking the statistics of searches are reset by this
|
||||
* operation. Binary data must have been saved on a machine with the same
|
||||
* architecture. If an exception is thrown, the state of the
|
||||
* NearestNeighbor is unchanged.
|
||||
*
|
||||
* \note <a href="https://www.boost.org/libs/serialization/doc">
|
||||
* Boost serialization</a> can also be used to save and restore a
|
||||
* NearestNeighbor object. This requires that the
|
||||
* GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION macro be defined.
|
||||
*
|
||||
* \warning The same arguments \e pts and \e dist used for
|
||||
* initialization must be provided to the Search() function.
|
||||
**********************************************************************/
|
||||
void Load(std::istream& is, bool bin = true) {
|
||||
int version1, realspec, bucket, numpoints, treesize, cost;
|
||||
if (bin) {
|
||||
char id[17];
|
||||
is.read(id, 16);
|
||||
id[16] = '\0';
|
||||
if (!(std::strcmp(id, "NearestNeighbor_") == 0))
|
||||
throw GeographicLib::GeographicErr("Bad ID");
|
||||
is.read(reinterpret_cast<char *>(&version1), sizeof(int));
|
||||
is.read(reinterpret_cast<char *>(&realspec), sizeof(int));
|
||||
is.read(reinterpret_cast<char *>(&bucket), sizeof(int));
|
||||
is.read(reinterpret_cast<char *>(&numpoints), sizeof(int));
|
||||
is.read(reinterpret_cast<char *>(&treesize), sizeof(int));
|
||||
is.read(reinterpret_cast<char *>(&cost), sizeof(int));
|
||||
} else {
|
||||
if (!( is >> version1 >> realspec >> bucket >> numpoints >> treesize
|
||||
>> cost ))
|
||||
throw GeographicLib::GeographicErr("Bad header");
|
||||
}
|
||||
if (!( version1 == version ))
|
||||
throw GeographicLib::GeographicErr("Incompatible version");
|
||||
if (!( realspec == std::numeric_limits<dist_t>::digits *
|
||||
(std::numeric_limits<dist_t>::is_integer ? -1 : 1) ))
|
||||
throw GeographicLib::GeographicErr("Different dist_t types");
|
||||
if (!( 0 <= bucket && bucket <= maxbucket ))
|
||||
throw GeographicLib::GeographicErr("Bad bucket size");
|
||||
if (!( 0 <= treesize && treesize <= numpoints ))
|
||||
throw
|
||||
GeographicLib::GeographicErr("Bad number of points or tree size");
|
||||
if (!( 0 <= cost ))
|
||||
throw GeographicLib::GeographicErr("Bad value for cost");
|
||||
std::vector<Node> tree;
|
||||
tree.reserve(treesize);
|
||||
for (int i = 0; i < treesize; ++i) {
|
||||
Node node;
|
||||
if (bin) {
|
||||
is.read(reinterpret_cast<char *>(&node.index), sizeof(int));
|
||||
if (node.index >= 0) {
|
||||
is.read(reinterpret_cast<char *>(node.data.lower),
|
||||
2 * sizeof(dist_t));
|
||||
is.read(reinterpret_cast<char *>(node.data.upper),
|
||||
2 * sizeof(dist_t));
|
||||
is.read(reinterpret_cast<char *>(node.data.child),
|
||||
2 * sizeof(int));
|
||||
} else {
|
||||
is.read(reinterpret_cast<char *>(node.leaves),
|
||||
bucket * sizeof(int));
|
||||
for (int l = bucket; l < maxbucket; ++l)
|
||||
node.leaves[l] = 0;
|
||||
}
|
||||
} else {
|
||||
if (!( is >> node.index ))
|
||||
throw GeographicLib::GeographicErr("Bad index");
|
||||
if (node.index >= 0) {
|
||||
for (int l = 0; l < 2; ++l) {
|
||||
if (!( is >> node.data.lower[l] >> node.data.upper[l]
|
||||
>> node.data.child[l] ))
|
||||
throw GeographicLib::GeographicErr("Bad node data");
|
||||
}
|
||||
} else {
|
||||
// Must be at least one valid leaf followed by a sequence end
|
||||
// markers (-1).
|
||||
for (int l = 0; l < bucket; ++l) {
|
||||
if (!( is >> node.leaves[l] ))
|
||||
throw GeographicLib::GeographicErr("Bad leaf data");
|
||||
}
|
||||
for (int l = bucket; l < maxbucket; ++l)
|
||||
node.leaves[l] = 0;
|
||||
}
|
||||
}
|
||||
node.Check(numpoints, treesize, bucket);
|
||||
tree.push_back(node);
|
||||
}
|
||||
_tree.swap(tree);
|
||||
_numpoints = numpoints;
|
||||
_bucket = bucket;
|
||||
_mc = _sc = 0;
|
||||
_cost = cost; _c1 = _k = _cmax = 0;
|
||||
_cmin = std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the object to stream \e os as text.
|
||||
*
|
||||
* @param[in,out] os the output stream.
|
||||
* @param[in] t the NearestNeighbor object to be saved.
|
||||
* @exception std::bad_alloc if memory for the string representation of the
|
||||
* object can't be allocated.
|
||||
**********************************************************************/
|
||||
friend std::ostream& operator<<(std::ostream& os, const NearestNeighbor& t)
|
||||
{ t.Save(os, false); return os; }
|
||||
|
||||
/**
|
||||
* Read the object from stream \e is as text.
|
||||
*
|
||||
* @param[in,out] is the input stream.
|
||||
* @param[out] t the NearestNeighbor object to be loaded.
|
||||
* @exception GeographicErr if the state read from \e is is illegal.
|
||||
* @exception std::bad_alloc if memory for the tree can't be allocated.
|
||||
**********************************************************************/
|
||||
friend std::istream& operator>>(std::istream& is, NearestNeighbor& t)
|
||||
{ t.Load(is, false); return is; }
|
||||
|
||||
/**
|
||||
* Swap with another NearestNeighbor object.
|
||||
*
|
||||
* @param[in,out] t the NearestNeighbor object to swap with.
|
||||
**********************************************************************/
|
||||
void swap(NearestNeighbor& t) {
|
||||
std::swap(_numpoints, t._numpoints);
|
||||
std::swap(_bucket, t._bucket);
|
||||
std::swap(_cost, t._cost);
|
||||
_tree.swap(t._tree);
|
||||
std::swap(_mc, t._mc);
|
||||
std::swap(_sc, t._sc);
|
||||
std::swap(_c1, t._c1);
|
||||
std::swap(_k, t._k);
|
||||
std::swap(_cmin, t._cmin);
|
||||
std::swap(_cmax, t._cmax);
|
||||
}
|
||||
|
||||
/**
|
||||
* The accumulated statistics on the searches so far.
|
||||
*
|
||||
* @param[out] setupcost the cost of initializing the NearestNeighbor.
|
||||
* @param[out] numsearches the number of calls to Search().
|
||||
* @param[out] searchcost the total cost of the calls to Search().
|
||||
* @param[out] mincost the minimum cost of a Search().
|
||||
* @param[out] maxcost the maximum cost of a Search().
|
||||
* @param[out] mean the mean cost of a Search().
|
||||
* @param[out] sd the standard deviation in the cost of a Search().
|
||||
*
|
||||
* Here "cost" measures the number of distance calculations needed. Note
|
||||
* that the accumulation of statistics is \e not thread safe.
|
||||
**********************************************************************/
|
||||
void Statistics(int& setupcost, int& numsearches, int& searchcost,
|
||||
int& mincost, int& maxcost,
|
||||
double& mean, double& sd) const {
|
||||
setupcost = _cost; numsearches = _k; searchcost = _c1;
|
||||
mincost = _cmin; maxcost = _cmax;
|
||||
mean = _mc; sd = std::sqrt(_sc / (_k - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the counters for the accumulated statistics on the searches so
|
||||
* far.
|
||||
**********************************************************************/
|
||||
void ResetStatistics() const {
|
||||
_mc = _sc = 0;
|
||||
_c1 = _k = _cmax = 0;
|
||||
_cmin = std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
private:
|
||||
// Package up a dist_t and an int. We will want to sort on the dist_t so
|
||||
// put it first.
|
||||
typedef std::pair<dist_t, int> item;
|
||||
// \cond SKIP
|
||||
class Node {
|
||||
public:
|
||||
struct bounds {
|
||||
dist_t lower[2], upper[2]; // bounds on inner/outer distances
|
||||
int child[2];
|
||||
};
|
||||
union {
|
||||
bounds data;
|
||||
int leaves[maxbucket];
|
||||
};
|
||||
int index;
|
||||
|
||||
Node()
|
||||
: index(-1)
|
||||
{
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
data.lower[i] = data.upper[i] = 0;
|
||||
data.child[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity check on a Node
|
||||
void Check(int numpoints, int treesize, int bucket) const {
|
||||
if (!( -1 <= index && index < numpoints ))
|
||||
throw GeographicLib::GeographicErr("Bad index");
|
||||
if (index >= 0) {
|
||||
if (!( -1 <= data.child[0] && data.child[0] < treesize &&
|
||||
-1 <= data.child[1] && data.child[1] < treesize ))
|
||||
throw GeographicLib::GeographicErr("Bad child pointers");
|
||||
if (!( 0 <= data.lower[0] && data.lower[0] <= data.upper[0] &&
|
||||
data.upper[0] <= data.lower[1] &&
|
||||
data.lower[1] <= data.upper[1] ))
|
||||
throw GeographicLib::GeographicErr("Bad bounds");
|
||||
} else {
|
||||
// Must be at least one valid leaf followed by a sequence end markers
|
||||
// (-1).
|
||||
bool start = true;
|
||||
for (int l = 0; l < bucket; ++l) {
|
||||
if (!( (start ?
|
||||
((l == 0 ? 0 : -1) <= leaves[l] && leaves[l] < numpoints) :
|
||||
leaves[l] == -1) ))
|
||||
throw GeographicLib::GeographicErr("Bad leaf data");
|
||||
start = leaves[l] >= 0;
|
||||
}
|
||||
for (int l = bucket; l < maxbucket; ++l) {
|
||||
if (leaves[l] != 0)
|
||||
throw GeographicLib::GeographicErr("Bad leaf data");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION) && \
|
||||
GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION
|
||||
friend class boost::serialization::access;
|
||||
template<class Archive>
|
||||
void save(Archive& ar, const unsigned int) const {
|
||||
ar & boost::serialization::make_nvp("index", index);
|
||||
if (index < 0)
|
||||
ar & boost::serialization::make_nvp("leaves", leaves);
|
||||
else
|
||||
ar & boost::serialization::make_nvp("lower", data.lower)
|
||||
& boost::serialization::make_nvp("upper", data.upper)
|
||||
& boost::serialization::make_nvp("child", data.child);
|
||||
}
|
||||
template<class Archive>
|
||||
void load(Archive& ar, const unsigned int) {
|
||||
ar & boost::serialization::make_nvp("index", index);
|
||||
if (index < 0)
|
||||
ar & boost::serialization::make_nvp("leaves", leaves);
|
||||
else
|
||||
ar & boost::serialization::make_nvp("lower", data.lower)
|
||||
& boost::serialization::make_nvp("upper", data.upper)
|
||||
& boost::serialization::make_nvp("child", data.child);
|
||||
}
|
||||
template<class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version)
|
||||
{ boost::serialization::split_member(ar, *this, file_version); }
|
||||
#endif
|
||||
};
|
||||
// \endcond
|
||||
#if defined(GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION) && \
|
||||
GEOGRAPHICLIB_HAVE_BOOST_SERIALIZATION
|
||||
friend class boost::serialization::access;
|
||||
template<class Archive> void save(Archive& ar, const unsigned) const {
|
||||
int realspec = std::numeric_limits<dist_t>::digits *
|
||||
(std::numeric_limits<dist_t>::is_integer ? -1 : 1);
|
||||
// Need to use version1, otherwise load error in debug mode on Linux:
|
||||
// undefined reference to GeographicLib::NearestNeighbor<...>::version.
|
||||
int version1 = version;
|
||||
ar & boost::serialization::make_nvp("version", version1)
|
||||
& boost::serialization::make_nvp("realspec", realspec)
|
||||
& boost::serialization::make_nvp("bucket", _bucket)
|
||||
& boost::serialization::make_nvp("numpoints", _numpoints)
|
||||
& boost::serialization::make_nvp("cost", _cost)
|
||||
& boost::serialization::make_nvp("tree", _tree);
|
||||
}
|
||||
template<class Archive> void load(Archive& ar, const unsigned) {
|
||||
int version1, realspec, bucket, numpoints, cost;
|
||||
ar & boost::serialization::make_nvp("version", version1);
|
||||
if (version1 != version)
|
||||
throw GeographicLib::GeographicErr("Incompatible version");
|
||||
std::vector<Node> tree;
|
||||
ar & boost::serialization::make_nvp("realspec", realspec);
|
||||
if (!( realspec == std::numeric_limits<dist_t>::digits *
|
||||
(std::numeric_limits<dist_t>::is_integer ? -1 : 1) ))
|
||||
throw GeographicLib::GeographicErr("Different dist_t types");
|
||||
ar & boost::serialization::make_nvp("bucket", bucket);
|
||||
if (!( 0 <= bucket && bucket <= maxbucket ))
|
||||
throw GeographicLib::GeographicErr("Bad bucket size");
|
||||
ar & boost::serialization::make_nvp("numpoints", numpoints)
|
||||
& boost::serialization::make_nvp("cost", cost)
|
||||
& boost::serialization::make_nvp("tree", tree);
|
||||
if (!( 0 <= int(tree.size()) && int(tree.size()) <= numpoints ))
|
||||
throw
|
||||
GeographicLib::GeographicErr("Bad number of points or tree size");
|
||||
for (int i = 0; i < int(tree.size()); ++i)
|
||||
tree[i].Check(numpoints, int(tree.size()), bucket);
|
||||
_tree.swap(tree);
|
||||
_numpoints = numpoints;
|
||||
_bucket = bucket;
|
||||
_mc = _sc = 0;
|
||||
_cost = cost; _c1 = _k = _cmax = 0;
|
||||
_cmin = std::numeric_limits<int>::max();
|
||||
}
|
||||
template<class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version)
|
||||
{ boost::serialization::split_member(ar, *this, file_version); }
|
||||
#endif
|
||||
|
||||
int _numpoints, _bucket, _cost;
|
||||
std::vector<Node> _tree;
|
||||
// Counters to track stastistics on the cost of searches
|
||||
mutable double _mc, _sc;
|
||||
mutable int _c1, _k, _cmin, _cmax;
|
||||
|
||||
int init(const std::vector<pos_t>& pts, const distfun_t& dist, int bucket,
|
||||
std::vector<Node>& tree, std::vector<item>& ids, int& cost,
|
||||
int l, int u, int vp) {
|
||||
|
||||
if (u == l)
|
||||
return -1;
|
||||
Node node;
|
||||
|
||||
if (u - l > (bucket == 0 ? 1 : bucket)) {
|
||||
|
||||
// choose a vantage point and move it to the start
|
||||
int i = vp;
|
||||
std::swap(ids[l], ids[i]);
|
||||
|
||||
int m = (u + l + 1) / 2;
|
||||
|
||||
for (int k = l + 1; k < u; ++k) {
|
||||
ids[k].first = dist(pts[ids[l].second], pts[ids[k].second]);
|
||||
++cost;
|
||||
}
|
||||
// partition around the median distance
|
||||
std::nth_element(ids.begin() + l + 1,
|
||||
ids.begin() + m,
|
||||
ids.begin() + u);
|
||||
node.index = ids[l].second;
|
||||
if (m > l + 1) { // node.child[0] is possibly empty
|
||||
typename std::vector<item>::iterator
|
||||
t = std::min_element(ids.begin() + l + 1, ids.begin() + m);
|
||||
node.data.lower[0] = t->first;
|
||||
t = std::max_element(ids.begin() + l + 1, ids.begin() + m);
|
||||
node.data.upper[0] = t->first;
|
||||
// Use point with max distance as vantage point; this point act as a
|
||||
// "corner" point and leads to a good partition.
|
||||
node.data.child[0] = init(pts, dist, bucket, tree, ids, cost,
|
||||
l + 1, m, int(t - ids.begin()));
|
||||
}
|
||||
typename std::vector<item>::iterator
|
||||
t = std::max_element(ids.begin() + m, ids.begin() + u);
|
||||
node.data.lower[1] = ids[m].first;
|
||||
node.data.upper[1] = t->first;
|
||||
// Use point with max distance as vantage point here too
|
||||
node.data.child[1] = init(pts, dist, bucket, tree, ids, cost,
|
||||
m, u, int(t - ids.begin()));
|
||||
} else {
|
||||
if (bucket == 0)
|
||||
node.index = ids[l].second;
|
||||
else {
|
||||
node.index = -1;
|
||||
// Sort the bucket entries so that the tree is independent of the
|
||||
// implementation of nth_element.
|
||||
std::sort(ids.begin() + l, ids.begin() + u);
|
||||
for (int i = l; i < u; ++i)
|
||||
node.leaves[i-l] = ids[i].second;
|
||||
for (int i = u - l; i < bucket; ++i)
|
||||
node.leaves[i] = -1;
|
||||
for (int i = bucket; i < maxbucket; ++i)
|
||||
node.leaves[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
tree.push_back(node);
|
||||
return int(tree.size()) - 1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
namespace std {
|
||||
|
||||
/**
|
||||
* Swap two GeographicLib::NearestNeighbor objects.
|
||||
*
|
||||
* @tparam dist_t the type used for measuring distances.
|
||||
* @tparam pos_t the type for specifying the positions of points.
|
||||
* @tparam distfun_t the type for a function object which calculates
|
||||
* distances between points.
|
||||
* @param[in,out] a the first GeographicLib::NearestNeighbor to swap.
|
||||
* @param[in,out] b the second GeographicLib::NearestNeighbor to swap.
|
||||
**********************************************************************/
|
||||
template <typename dist_t, typename pos_t, class distfun_t>
|
||||
void swap(GeographicLib::NearestNeighbor<dist_t, pos_t, distfun_t>& a,
|
||||
GeographicLib::NearestNeighbor<dist_t, pos_t, distfun_t>& b) {
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_NEARESTNEIGHBOR_HPP
|
||||
400
external/include/GeographicLib/NormalGravity.hpp
vendored
Normal file
400
external/include/GeographicLib/NormalGravity.hpp
vendored
Normal file
@@ -0,0 +1,400 @@
|
||||
/**
|
||||
* \file NormalGravity.hpp
|
||||
* \brief Header for GeographicLib::NormalGravity class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2011-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_NORMALGRAVITY_HPP)
|
||||
#define GEOGRAPHICLIB_NORMALGRAVITY_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/Geocentric.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief The normal gravity of the earth
|
||||
*
|
||||
* "Normal" gravity refers to an idealization of the earth which is modeled
|
||||
* as an rotating ellipsoid. The eccentricity of the ellipsoid, the rotation
|
||||
* speed, and the distribution of mass within the ellipsoid are such that the
|
||||
* ellipsoid is a "level ellipoid", a surface of constant potential
|
||||
* (gravitational plus centrifugal). The acceleration due to gravity is
|
||||
* therefore perpendicular to the surface of the ellipsoid.
|
||||
*
|
||||
* Because the distribution of mass within the ellipsoid is unspecified, only
|
||||
* the potential exterior to the ellipsoid is well defined. In this class,
|
||||
* the mass is assumed to be to concentrated on a "focal disc" of radius,
|
||||
* (<i>a</i><sup>2</sup> − <i>b</i><sup>2</sup>)<sup>1/2</sup>, where
|
||||
* \e a is the equatorial radius of the ellipsoid and \e b is its polar
|
||||
* semi-axis. In the case of an oblate ellipsoid, the mass is concentrated
|
||||
* on a "focal rod" of length 2(<i>b</i><sup>2</sup> −
|
||||
* <i>a</i><sup>2</sup>)<sup>1/2</sup>. As a result the potential is well
|
||||
* defined everywhere.
|
||||
*
|
||||
* There is a closed solution to this problem which is implemented here.
|
||||
* Series "approximations" are only used to evaluate certain combinations of
|
||||
* elementary functions where use of the closed expression results in a loss
|
||||
* of accuracy for small arguments due to cancellation of the leading terms.
|
||||
* However these series include sufficient terms to give full machine
|
||||
* precision.
|
||||
*
|
||||
* Although the formulation used in this class applies to ellipsoids with
|
||||
* arbitrary flattening, in practice, its use should be limited to about
|
||||
* <i>b</i>/\e a ∈ [0.01, 100] or \e f ∈ [−99, 0.99].
|
||||
*
|
||||
* Definitions:
|
||||
* - <i>V</i><sub>0</sub>, the gravitational contribution to the normal
|
||||
* potential;
|
||||
* - Φ, the rotational contribution to the normal potential;
|
||||
* - \e U = <i>V</i><sub>0</sub> + Φ, the total potential;
|
||||
* - <b>Γ</b> = ∇<i>V</i><sub>0</sub>, the acceleration due to
|
||||
* mass of the earth;
|
||||
* - <b>f</b> = ∇Φ, the centrifugal acceleration;
|
||||
* - <b>γ</b> = ∇\e U = <b>Γ</b> + <b>f</b>, the normal
|
||||
* acceleration;
|
||||
* - \e X, \e Y, \e Z, geocentric coordinates;
|
||||
* - \e x, \e y, \e z, local cartesian coordinates used to denote the east,
|
||||
* north and up directions.
|
||||
*
|
||||
* References:
|
||||
* - C. Somigliana, Teoria generale del campo gravitazionale dell'ellissoide
|
||||
* di rotazione, Mem. Soc. Astron. Ital, <b>4</b>, 541--599 (1929).
|
||||
* - W. A. Heiskanen and H. Moritz, Physical Geodesy (Freeman, San
|
||||
* Francisco, 1967), Secs. 1-19, 2-7, 2-8 (2-9, 2-10), 6-2 (6-3).
|
||||
* - B. Hofmann-Wellenhof, H. Moritz, Physical Geodesy (Second edition,
|
||||
* Springer, 2006) https://doi.org/10.1007/978-3-211-33545-1
|
||||
* - H. Moritz, Geodetic Reference System 1980, J. Geodesy 54(3), 395-405
|
||||
* (1980) https://doi.org/10.1007/BF02521480
|
||||
*
|
||||
* For more information on normal gravity see \ref normalgravity.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-NormalGravity.cpp
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT NormalGravity {
|
||||
private:
|
||||
static const int maxit_ = 20;
|
||||
typedef Math::real real;
|
||||
friend class GravityModel;
|
||||
real _a, _GM, _omega, _f, _J2, _omega2, _aomega2;
|
||||
real _e2, _ep2, _b, _E, _U0, _gammae, _gammap, _Q0, _k, _fstar;
|
||||
Geocentric _earth;
|
||||
static real atanzz(real x, bool alt) {
|
||||
// This routine obeys the identity
|
||||
// atanzz(x, alt) = atanzz(-x/(1+x), !alt)
|
||||
//
|
||||
// Require x >= -1. Best to call with alt, s.t. x >= 0; this results in
|
||||
// a call to atan, instead of asin, or to asinh, instead of atanh.
|
||||
using std::sqrt; using std::abs; using std::atan; using std::asin;
|
||||
using std::asinh; using std::atanh;
|
||||
real z = sqrt(abs(x));
|
||||
return x == 0 ? 1 :
|
||||
(alt ?
|
||||
(!(x < 0) ? asinh(z) : asin(z)) / sqrt(abs(x) / (1 + x)) :
|
||||
(!(x < 0) ? atan(z) : atanh(z)) / z);
|
||||
}
|
||||
static real atan7series(real x);
|
||||
static real atan5series(real x);
|
||||
static real Qf(real x, bool alt);
|
||||
static real Hf(real x, bool alt);
|
||||
static real QH3f(real x, bool alt);
|
||||
real Jn(int n) const;
|
||||
void Initialize(real a, real GM, real omega, real f_J2, bool geometricp);
|
||||
public:
|
||||
|
||||
/** \name Setting up the normal gravity
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Constructor for the normal gravity.
|
||||
*
|
||||
* @param[in] a equatorial radius (meters).
|
||||
* @param[in] GM mass constant of the ellipsoid
|
||||
* (meters<sup>3</sup>/seconds<sup>2</sup>); this is the product of \e G
|
||||
* the gravitational constant and \e M the mass of the earth (usually
|
||||
* including the mass of the earth's atmosphere).
|
||||
* @param[in] omega the angular velocity (rad s<sup>−1</sup>).
|
||||
* @param[in] f_J2 either the flattening of the ellipsoid \e f or the
|
||||
* the dynamical form factor \e J2.
|
||||
* @param[out] geometricp if true (the default), then \e f_J2 denotes the
|
||||
* flattening, else it denotes the dynamical form factor \e J2.
|
||||
* @exception if \e a is not positive or if the other parameters do not
|
||||
* obey the restrictions given below.
|
||||
*
|
||||
* The shape of the ellipsoid can be given in one of two ways:
|
||||
* - geometrically (\e geomtricp = true), the ellipsoid is defined by the
|
||||
* flattening \e f = (\e a − \e b) / \e a, where \e a and \e b are
|
||||
* the equatorial radius and the polar semi-axis. The parameters should
|
||||
* obey \e a > 0, \e f < 1. There are no restrictions on \e GM or
|
||||
* \e omega, in particular, \e GM need not be positive.
|
||||
* - physically (\e geometricp = false), the ellipsoid is defined by the
|
||||
* dynamical form factor <i>J</i><sub>2</sub> = (\e C − \e A) /
|
||||
* <i>Ma</i><sup>2</sup>, where \e A and \e C are the equatorial and
|
||||
* polar moments of inertia and \e M is the mass of the earth. The
|
||||
* parameters should obey \e a > 0, \e GM > 0 and \e J2 < 1/3
|
||||
* − (<i>omega</i><sup>2</sup><i>a</i><sup>3</sup>/<i>GM</i>)
|
||||
* 8/(45π). There is no restriction on \e omega.
|
||||
**********************************************************************/
|
||||
NormalGravity(real a, real GM, real omega, real f_J2,
|
||||
bool geometricp = true);
|
||||
|
||||
/**
|
||||
* A default constructor for the normal gravity. This sets up an
|
||||
* uninitialized object and is used by GravityModel which constructs this
|
||||
* object before it has read in the parameters for the reference ellipsoid.
|
||||
**********************************************************************/
|
||||
NormalGravity() : _a(-1) {}
|
||||
///@}
|
||||
|
||||
/** \name Compute the gravity
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* Evaluate the gravity on the surface of the ellipsoid.
|
||||
*
|
||||
* @param[in] lat the geographic latitude (degrees).
|
||||
* @return γ the acceleration due to gravity, positive downwards
|
||||
* (m s<sup>−2</sup>).
|
||||
*
|
||||
* Due to the axial symmetry of the ellipsoid, the result is independent of
|
||||
* the value of the longitude. This acceleration is perpendicular to the
|
||||
* surface of the ellipsoid. It includes the effects of the earth's
|
||||
* rotation.
|
||||
**********************************************************************/
|
||||
Math::real SurfaceGravity(real lat) const;
|
||||
|
||||
/**
|
||||
* Evaluate the gravity at an arbitrary point above (or below) the
|
||||
* ellipsoid.
|
||||
*
|
||||
* @param[in] lat the geographic latitude (degrees).
|
||||
* @param[in] h the height above the ellipsoid (meters).
|
||||
* @param[out] gammay the northerly component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] gammaz the upward component of the acceleration
|
||||
* (m s<sup>−2</sup>); this is usually negative.
|
||||
* @return \e U the corresponding normal potential
|
||||
* (m<sup>2</sup> s<sup>−2</sup>).
|
||||
*
|
||||
* Due to the axial symmetry of the ellipsoid, the result is independent of
|
||||
* the value of the longitude and the easterly component of the
|
||||
* acceleration vanishes, \e gammax = 0. The function includes the effects
|
||||
* of the earth's rotation. When \e h = 0, this function gives \e gammay =
|
||||
* 0 and the returned value matches that of NormalGravity::SurfaceGravity.
|
||||
**********************************************************************/
|
||||
Math::real Gravity(real lat, real h, real& gammay, real& gammaz)
|
||||
const;
|
||||
|
||||
/**
|
||||
* Evaluate the components of the acceleration due to gravity and the
|
||||
* centrifugal acceleration in geocentric coordinates.
|
||||
*
|
||||
* @param[in] X geocentric coordinate of point (meters).
|
||||
* @param[in] Y geocentric coordinate of point (meters).
|
||||
* @param[in] Z geocentric coordinate of point (meters).
|
||||
* @param[out] gammaX the \e X component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] gammaY the \e Y component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] gammaZ the \e Z component of the acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @return \e U = <i>V</i><sub>0</sub> + Φ the sum of the
|
||||
* gravitational and centrifugal potentials
|
||||
* (m<sup>2</sup> s<sup>−2</sup>).
|
||||
*
|
||||
* The acceleration given by <b>γ</b> = ∇\e U =
|
||||
* ∇<i>V</i><sub>0</sub> + ∇Φ = <b>Γ</b> + <b>f</b>.
|
||||
**********************************************************************/
|
||||
Math::real U(real X, real Y, real Z,
|
||||
real& gammaX, real& gammaY, real& gammaZ) const;
|
||||
|
||||
/**
|
||||
* Evaluate the components of the acceleration due to the gravitational
|
||||
* force in geocentric coordinates.
|
||||
*
|
||||
* @param[in] X geocentric coordinate of point (meters).
|
||||
* @param[in] Y geocentric coordinate of point (meters).
|
||||
* @param[in] Z geocentric coordinate of point (meters).
|
||||
* @param[out] GammaX the \e X component of the acceleration due to the
|
||||
* gravitational force (m s<sup>−2</sup>).
|
||||
* @param[out] GammaY the \e Y component of the acceleration due to the
|
||||
* @param[out] GammaZ the \e Z component of the acceleration due to the
|
||||
* gravitational force (m s<sup>−2</sup>).
|
||||
* @return <i>V</i><sub>0</sub> the gravitational potential
|
||||
* (m<sup>2</sup> s<sup>−2</sup>).
|
||||
*
|
||||
* This function excludes the centrifugal acceleration and is appropriate
|
||||
* to use for space applications. In terrestrial applications, the
|
||||
* function NormalGravity::U (which includes this effect) should usually be
|
||||
* used.
|
||||
**********************************************************************/
|
||||
Math::real V0(real X, real Y, real Z,
|
||||
real& GammaX, real& GammaY, real& GammaZ) const;
|
||||
|
||||
/**
|
||||
* Evaluate the centrifugal acceleration in geocentric coordinates.
|
||||
*
|
||||
* @param[in] X geocentric coordinate of point (meters).
|
||||
* @param[in] Y geocentric coordinate of point (meters).
|
||||
* @param[out] fX the \e X component of the centrifugal acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @param[out] fY the \e Y component of the centrifugal acceleration
|
||||
* (m s<sup>−2</sup>).
|
||||
* @return Φ the centrifugal potential (m<sup>2</sup>
|
||||
* s<sup>−2</sup>).
|
||||
*
|
||||
* Φ is independent of \e Z, thus \e fZ = 0. This function
|
||||
* NormalGravity::U sums the results of NormalGravity::V0 and
|
||||
* NormalGravity::Phi.
|
||||
**********************************************************************/
|
||||
Math::real Phi(real X, real Y, real& fX, real& fY) const;
|
||||
///@}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return true if the object has been initialized.
|
||||
**********************************************************************/
|
||||
bool Init() const { return _a > 0; }
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const
|
||||
{ return Init() ? _a : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return \e GM the mass constant of the ellipsoid
|
||||
* (m<sup>3</sup> s<sup>−2</sup>). This is the value used in the
|
||||
* constructor.
|
||||
**********************************************************************/
|
||||
Math::real MassConstant() const
|
||||
{ return Init() ? _GM : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return <i>J</i><sub><i>n</i></sub> the dynamical form factors of the
|
||||
* ellipsoid.
|
||||
*
|
||||
* If \e n = 2 (the default), this is the value of <i>J</i><sub>2</sub>
|
||||
* used in the constructor. Otherwise it is the zonal coefficient of the
|
||||
* Legendre harmonic sum of the normal gravitational potential. Note that
|
||||
* <i>J</i><sub><i>n</i></sub> = 0 if \e n is odd. In most gravity
|
||||
* applications, fully normalized Legendre functions are used and the
|
||||
* corresponding coefficient is <i>C</i><sub><i>n</i>0</sub> =
|
||||
* −<i>J</i><sub><i>n</i></sub> / sqrt(2 \e n + 1).
|
||||
**********************************************************************/
|
||||
Math::real DynamicalFormFactor(int n = 2) const
|
||||
{ return Init() ? ( n == 2 ? _J2 : Jn(n)) : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return ω the angular velocity of the ellipsoid (rad
|
||||
* s<sup>−1</sup>). This is the value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real AngularVelocity() const
|
||||
{ return Init() ? _omega : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return <i>f</i> the flattening of the ellipsoid (\e a − \e b)/\e
|
||||
* a.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const
|
||||
{ return Init() ? _f : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return γ<sub>e</sub> the normal gravity at equator (m
|
||||
* s<sup>−2</sup>).
|
||||
**********************************************************************/
|
||||
Math::real EquatorialGravity() const
|
||||
{ return Init() ? _gammae : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return γ<sub>p</sub> the normal gravity at poles (m
|
||||
* s<sup>−2</sup>).
|
||||
**********************************************************************/
|
||||
Math::real PolarGravity() const
|
||||
{ return Init() ? _gammap : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return <i>f*</i> the gravity flattening (γ<sub>p</sub> −
|
||||
* γ<sub>e</sub>) / γ<sub>e</sub>.
|
||||
**********************************************************************/
|
||||
Math::real GravityFlattening() const
|
||||
{ return Init() ? _fstar : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return <i>U</i><sub>0</sub> the constant normal potential for the
|
||||
* surface of the ellipsoid (m<sup>2</sup> s<sup>−2</sup>).
|
||||
**********************************************************************/
|
||||
Math::real SurfacePotential() const
|
||||
{ return Init() ? _U0 : Math::NaN(); }
|
||||
|
||||
/**
|
||||
* @return the Geocentric object used by this instance.
|
||||
**********************************************************************/
|
||||
const Geocentric& Earth() const { return _earth; }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* A global instantiation of NormalGravity for the WGS84 ellipsoid.
|
||||
**********************************************************************/
|
||||
static const NormalGravity& WGS84();
|
||||
|
||||
/**
|
||||
* A global instantiation of NormalGravity for the GRS80 ellipsoid.
|
||||
**********************************************************************/
|
||||
static const NormalGravity& GRS80();
|
||||
|
||||
/**
|
||||
* Compute the flattening from the dynamical form factor.
|
||||
*
|
||||
* @param[in] a equatorial radius (meters).
|
||||
* @param[in] GM mass constant of the ellipsoid
|
||||
* (meters<sup>3</sup>/seconds<sup>2</sup>); this is the product of \e G
|
||||
* the gravitational constant and \e M the mass of the earth (usually
|
||||
* including the mass of the earth's atmosphere).
|
||||
* @param[in] omega the angular velocity (rad s<sup>−1</sup>).
|
||||
* @param[in] J2 the dynamical form factor.
|
||||
* @return \e f the flattening of the ellipsoid.
|
||||
*
|
||||
* This routine requires \e a > 0, \e GM > 0, \e J2 < 1/3 −
|
||||
* <i>omega</i><sup>2</sup><i>a</i><sup>3</sup>/<i>GM</i> 8/(45π). A
|
||||
* NaN is returned if these conditions do not hold. The restriction to
|
||||
* positive \e GM is made because for negative \e GM two solutions are
|
||||
* possible.
|
||||
**********************************************************************/
|
||||
static Math::real J2ToFlattening(real a, real GM, real omega, real J2);
|
||||
|
||||
/**
|
||||
* Compute the dynamical form factor from the flattening.
|
||||
*
|
||||
* @param[in] a equatorial radius (meters).
|
||||
* @param[in] GM mass constant of the ellipsoid
|
||||
* (meters<sup>3</sup>/seconds<sup>2</sup>); this is the product of \e G
|
||||
* the gravitational constant and \e M the mass of the earth (usually
|
||||
* including the mass of the earth's atmosphere).
|
||||
* @param[in] omega the angular velocity (rad s<sup>−1</sup>).
|
||||
* @param[in] f the flattening of the ellipsoid.
|
||||
* @return \e J2 the dynamical form factor.
|
||||
*
|
||||
* This routine requires \e a > 0, \e GM ≠ 0, \e f < 1. The
|
||||
* values of these parameters are not checked.
|
||||
**********************************************************************/
|
||||
static Math::real FlatteningToJ2(real a, real GM, real omega, real f);
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_NORMALGRAVITY_HPP
|
||||
255
external/include/GeographicLib/OSGB.hpp
vendored
Normal file
255
external/include/GeographicLib/OSGB.hpp
vendored
Normal file
@@ -0,0 +1,255 @@
|
||||
/**
|
||||
* \file OSGB.hpp
|
||||
* \brief Header for GeographicLib::OSGB class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2010-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_OSGB_HPP)
|
||||
#define GEOGRAPHICLIB_OSGB_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/TransverseMercator.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about dll vs string
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4251)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Ordnance Survey grid system for Great Britain
|
||||
*
|
||||
* The class implements the coordinate system used by the Ordnance Survey for
|
||||
* maps of Great Britain and conversions to the grid reference system.
|
||||
*
|
||||
* See
|
||||
* - <a href="http://www.ordnancesurvey.co.uk/docs/support/guide-coordinate-systems-great-britain.pdf">
|
||||
* A guide to coordinate systems in Great Britain</a>
|
||||
* - <a href="http://www.ordnancesurvey.co.uk/docs/support/national-grid.pdf">
|
||||
* Guide to the National Grid</a>
|
||||
*
|
||||
* \warning the latitudes and longitudes for the Ordnance Survey grid
|
||||
* system do not use the WGS84 datum. Do not use the values returned by this
|
||||
* class in the UTMUPS, MGRS, or Geoid classes without first converting the
|
||||
* datum (and vice versa).
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-OSGB.cpp
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT OSGB {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
static const char* const letters_;
|
||||
static const char* const digits_;
|
||||
static const TransverseMercator& OSGBTM();
|
||||
enum {
|
||||
base_ = 10,
|
||||
tile_ = 100000,
|
||||
tilelevel_ = 5,
|
||||
tilegrid_ = 5,
|
||||
tileoffx_ = 2 * tilegrid_,
|
||||
tileoffy_ = 1 * tilegrid_,
|
||||
minx_ = - tileoffx_ * tile_,
|
||||
miny_ = - tileoffy_ * tile_,
|
||||
maxx_ = (tilegrid_*tilegrid_ - tileoffx_) * tile_,
|
||||
maxy_ = (tilegrid_*tilegrid_ - tileoffy_) * tile_,
|
||||
// Maximum precision is um
|
||||
maxprec_ = 5 + 6,
|
||||
};
|
||||
static real computenorthoffset();
|
||||
static void CheckCoords(real x, real y);
|
||||
OSGB(); // Disable constructor
|
||||
public:
|
||||
|
||||
/**
|
||||
* Forward projection, from geographic to OSGB coordinates.
|
||||
*
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[out] x easting of point (meters).
|
||||
* @param[out] y northing of point (meters).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k scale of projection at point.
|
||||
*
|
||||
* \e lat should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
static void Forward(real lat, real lon,
|
||||
real& x, real& y, real& gamma, real& k) {
|
||||
OSGBTM().Forward(OriginLongitude(), lat, lon, x, y, gamma, k);
|
||||
x += FalseEasting();
|
||||
y += computenorthoffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse projection, from OSGB coordinates to geographic.
|
||||
*
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k scale of projection at point.
|
||||
*
|
||||
* The value of \e lon returned is in the range [−180°,
|
||||
* 180°].
|
||||
**********************************************************************/
|
||||
|
||||
static void Reverse(real x, real y,
|
||||
real& lat, real& lon, real& gamma, real& k) {
|
||||
x -= FalseEasting();
|
||||
y -= computenorthoffset();
|
||||
OSGBTM().Reverse(OriginLongitude(), x, y, lat, lon, gamma, k);
|
||||
}
|
||||
|
||||
/**
|
||||
* OSGB::Forward without returning the convergence and scale.
|
||||
**********************************************************************/
|
||||
static void Forward(real lat, real lon, real& x, real& y) {
|
||||
real gamma, k;
|
||||
Forward(lat, lon, x, y, gamma, k);
|
||||
}
|
||||
|
||||
/**
|
||||
* OSGB::Reverse without returning the convergence and scale.
|
||||
**********************************************************************/
|
||||
static void Reverse(real x, real y, real& lat, real& lon) {
|
||||
real gamma, k;
|
||||
Reverse(x, y, lat, lon, gamma, k);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert OSGB coordinates to a grid reference.
|
||||
*
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[in] prec precision relative to 100 km.
|
||||
* @param[out] gridref National Grid reference.
|
||||
* @exception GeographicErr if \e prec, \e x, or \e y is outside its
|
||||
* allowed range.
|
||||
* @exception std::bad_alloc if the memory for \e gridref can't be
|
||||
* allocatied.
|
||||
*
|
||||
* \e prec specifies the precision of the grid reference string as follows:
|
||||
* - prec = 0 (min), 100km
|
||||
* - prec = 1, 10km
|
||||
* - prec = 2, 1km
|
||||
* - prec = 3, 100m
|
||||
* - prec = 4, 10m
|
||||
* - prec = 5, 1m
|
||||
* - prec = 6, 0.1m
|
||||
* - prec = 11 (max), 1μm
|
||||
*
|
||||
* The easting must be in the range [−1000 km, 1500 km) and the
|
||||
* northing must be in the range [−500 km, 2000 km). These bounds
|
||||
* are consistent with rules for the letter designations for the grid
|
||||
* system.
|
||||
*
|
||||
* If \e x or \e y is NaN, the returned grid reference is "INVALID".
|
||||
**********************************************************************/
|
||||
static void GridReference(real x, real y, int prec, std::string& gridref);
|
||||
|
||||
/**
|
||||
* Convert OSGB coordinates to a grid reference.
|
||||
*
|
||||
* @param[in] gridref National Grid reference.
|
||||
* @param[out] x easting of point (meters).
|
||||
* @param[out] y northing of point (meters).
|
||||
* @param[out] prec precision relative to 100 km.
|
||||
* @param[in] centerp if true (default), return center of the grid square,
|
||||
* else return SW (lower left) corner.
|
||||
* @exception GeographicErr if \e gridref is illegal.
|
||||
*
|
||||
* The grid reference must be of the form: two letters (not including I)
|
||||
* followed by an even number of digits (up to 22).
|
||||
*
|
||||
* If the first 2 characters of \e gridref are "IN", then \e x and \e y are
|
||||
* set to NaN and \e prec is set to −2.
|
||||
**********************************************************************/
|
||||
static void GridReference(const std::string& gridref,
|
||||
real& x, real& y, int& prec,
|
||||
bool centerp = true);
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return \e a the equatorial radius of the Airy 1830 ellipsoid (meters).
|
||||
*
|
||||
* This is 20923713 ft converted to meters using the rule 1 ft =
|
||||
* 10<sup>9.48401603−10</sup> m. The Airy 1830 value is returned
|
||||
* because the OSGB projection is based on this ellipsoid. The conversion
|
||||
* factor from feet to meters is the one used for the 1936 retriangulation
|
||||
* of Britain; see Section A.1 (p. 37) of <i>A guide to coordinate systems
|
||||
* in Great Britain</i>, v2.2 (Dec. 2013).
|
||||
**********************************************************************/
|
||||
static Math::real EquatorialRadius() {
|
||||
// result is about 6377563.3960320664406 m
|
||||
using std::pow;
|
||||
return pow(real(10), real(48401603 - 100000000) / 100000000)
|
||||
* real(20923713);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \e f the inverse flattening of the Airy 1830 ellipsoid.
|
||||
*
|
||||
* For the Airy 1830 ellipsoid, \e a = 20923713 ft and \e b = 20853810 ft;
|
||||
* thus the flattening = (20923713 − 20853810)/20923713 =
|
||||
* 7767/2324857 = 1/299.32496459... (The Airy 1830 value is returned
|
||||
* because the OSGB projection is based on this ellipsoid.)
|
||||
**********************************************************************/
|
||||
static Math::real Flattening()
|
||||
{ return real(20923713 - 20853810) / real(20923713); }
|
||||
|
||||
/**
|
||||
* @return \e k0 central scale for the OSGB projection (0.9996012717...).
|
||||
*
|
||||
* C. J. Mugnier, Grids & Datums, PE&RS, Oct. 2003, states that
|
||||
* this is defined as 10<sup>9.9998268−10</sup>.
|
||||
**********************************************************************/
|
||||
static Math::real CentralScale() {
|
||||
using std::pow;
|
||||
return pow(real(10), real(9998268 - 10000000) / 10000000);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return latitude of the origin for the OSGB projection (49 degrees).
|
||||
**********************************************************************/
|
||||
static Math::real OriginLatitude() { return real(49); }
|
||||
|
||||
/**
|
||||
* @return longitude of the origin for the OSGB projection (−2
|
||||
* degrees).
|
||||
**********************************************************************/
|
||||
static Math::real OriginLongitude() { return real(-2); }
|
||||
|
||||
/**
|
||||
* @return false northing the OSGB projection (−100000 meters).
|
||||
**********************************************************************/
|
||||
static Math::real FalseNorthing() { return real(-100000); }
|
||||
|
||||
/**
|
||||
* @return false easting the OSGB projection (400000 meters).
|
||||
**********************************************************************/
|
||||
static Math::real FalseEasting() { return real(400000); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
static Math::real MajorRadius() { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_OSGB_HPP
|
||||
160
external/include/GeographicLib/PolarStereographic.hpp
vendored
Normal file
160
external/include/GeographicLib/PolarStereographic.hpp
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* \file PolarStereographic.hpp
|
||||
* \brief Header for GeographicLib::PolarStereographic class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_POLARSTEREOGRAPHIC_HPP)
|
||||
#define GEOGRAPHICLIB_POLARSTEREOGRAPHIC_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Polar stereographic projection
|
||||
*
|
||||
* Implementation taken from the report,
|
||||
* - J. P. Snyder,
|
||||
* <a href="http://pubs.er.usgs.gov/usgspubs/pp/pp1395"> Map Projections: A
|
||||
* Working Manual</a>, USGS Professional Paper 1395 (1987),
|
||||
* pp. 160--163.
|
||||
*
|
||||
* This is a straightforward implementation of the equations in Snyder except
|
||||
* that Newton's method is used to invert the projection.
|
||||
*
|
||||
* This class also returns the meridian convergence \e gamma and scale \e k.
|
||||
* The meridian convergence is the bearing of grid north (the \e y axis)
|
||||
* measured clockwise from true north.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-PolarStereographic.cpp
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT PolarStereographic {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
real _a, _f, _e2, _es, _e2m, _c;
|
||||
real _k0;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for a ellipsoid with
|
||||
*
|
||||
* @param[in] a equatorial radius (meters).
|
||||
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
|
||||
* Negative \e f gives a prolate ellipsoid.
|
||||
* @param[in] k0 central scale factor.
|
||||
* @exception GeographicErr if \e a, (1 − \e f) \e a, or \e k0 is
|
||||
* not positive.
|
||||
**********************************************************************/
|
||||
PolarStereographic(real a, real f, real k0);
|
||||
|
||||
/**
|
||||
* Set the scale for the projection.
|
||||
*
|
||||
* @param[in] lat (degrees) assuming \e northp = true.
|
||||
* @param[in] k scale at latitude \e lat (default 1).
|
||||
* @exception GeographicErr \e k is not positive.
|
||||
* @exception GeographicErr if \e lat is not in (−90°,
|
||||
* 90°].
|
||||
**********************************************************************/
|
||||
void SetScale(real lat, real k = real(1));
|
||||
|
||||
/**
|
||||
* Forward projection, from geographic to polar stereographic.
|
||||
*
|
||||
* @param[in] northp the pole which is the center of projection (true means
|
||||
* north, false means south).
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[out] x easting of point (meters).
|
||||
* @param[out] y northing of point (meters).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k scale of projection at point.
|
||||
*
|
||||
* No false easting or northing is added. \e lat should be in the range
|
||||
* (−90°, 90°] for \e northp = true and in the range
|
||||
* [−90°, 90°) for \e northp = false.
|
||||
**********************************************************************/
|
||||
void Forward(bool northp, real lat, real lon,
|
||||
real& x, real& y, real& gamma, real& k) const;
|
||||
|
||||
/**
|
||||
* Reverse projection, from polar stereographic to geographic.
|
||||
*
|
||||
* @param[in] northp the pole which is the center of projection (true means
|
||||
* north, false means south).
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k scale of projection at point.
|
||||
*
|
||||
* No false easting or northing is added. The value of \e lon returned is
|
||||
* in the range [−180°, 180°].
|
||||
**********************************************************************/
|
||||
void Reverse(bool northp, real x, real y,
|
||||
real& lat, real& lon, real& gamma, real& k) const;
|
||||
|
||||
/**
|
||||
* PolarStereographic::Forward without returning the convergence and scale.
|
||||
**********************************************************************/
|
||||
void Forward(bool northp, real lat, real lon,
|
||||
real& x, real& y) const {
|
||||
real gamma, k;
|
||||
Forward(northp, lat, lon, x, y, gamma, k);
|
||||
}
|
||||
|
||||
/**
|
||||
* PolarStereographic::Reverse without returning the convergence and scale.
|
||||
**********************************************************************/
|
||||
void Reverse(bool northp, real x, real y,
|
||||
real& lat, real& lon) const {
|
||||
real gamma, k;
|
||||
Reverse(northp, x, y, lat, lon, gamma, k);
|
||||
}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _a; }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value used in
|
||||
* the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _f; }
|
||||
|
||||
/**
|
||||
* The central scale for the projection. This is the value of \e k0 used
|
||||
* in the constructor and is the scale at the pole unless overridden by
|
||||
* PolarStereographic::SetScale.
|
||||
**********************************************************************/
|
||||
Math::real CentralScale() const { return _k0; }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* A global instantiation of PolarStereographic with the WGS84 ellipsoid
|
||||
* and the UPS scale factor. However, unlike UPS, no false easting or
|
||||
* northing is added.
|
||||
**********************************************************************/
|
||||
static const PolarStereographic& UPS();
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_POLARSTEREOGRAPHIC_HPP
|
||||
325
external/include/GeographicLib/PolygonArea.hpp
vendored
Normal file
325
external/include/GeographicLib/PolygonArea.hpp
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
/**
|
||||
* \file PolygonArea.hpp
|
||||
* \brief Header for GeographicLib::PolygonAreaT class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2010-2021) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_POLYGONAREA_HPP)
|
||||
#define GEOGRAPHICLIB_POLYGONAREA_HPP 1
|
||||
|
||||
#include <GeographicLib/Geodesic.hpp>
|
||||
#include <GeographicLib/GeodesicExact.hpp>
|
||||
#include <GeographicLib/Rhumb.hpp>
|
||||
#include <GeographicLib/Accumulator.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Polygon areas
|
||||
*
|
||||
* This computes the area of a polygon whose edges are geodesics using the
|
||||
* method given in Section 6 of
|
||||
* - C. F. F. Karney,
|
||||
* <a href="https://doi.org/10.1007/s00190-012-0578-z">
|
||||
* Algorithms for geodesics</a>,
|
||||
* J. Geodesy <b>87</b>, 43--55 (2013);
|
||||
* DOI: <a href="https://doi.org/10.1007/s00190-012-0578-z">
|
||||
* 10.1007/s00190-012-0578-z</a>;
|
||||
* addenda:
|
||||
* <a href="https://geographiclib.sourceforge.io/geod-addenda.html">
|
||||
* geod-addenda.html</a>.
|
||||
*
|
||||
* Arbitrarily complex polygons are allowed. In the case self-intersecting
|
||||
* of polygons the area is accumulated "algebraically", e.g., the areas of
|
||||
* the 2 loops in a figure-8 polygon will partially cancel.
|
||||
*
|
||||
* This class lets you add vertices and edges one at a time to the polygon.
|
||||
* The sequence must start with a vertex and thereafter vertices and edges
|
||||
* can be added in any order. Any vertex after the first creates a new edge
|
||||
* which is the \e shortest geodesic from the previous vertex. In some
|
||||
* cases there may be two or many such shortest geodesics and the area is
|
||||
* then not uniquely defined. In this case, either add an intermediate
|
||||
* vertex or add the edge \e as an edge (by defining its direction and
|
||||
* length).
|
||||
*
|
||||
* The area and perimeter are accumulated at two times the standard floating
|
||||
* point precision to guard against the loss of accuracy with many-sided
|
||||
* polygons. At any point you can ask for the perimeter and area so far.
|
||||
* There's an option to treat the points as defining a polyline instead of a
|
||||
* polygon; in that case, only the perimeter is computed.
|
||||
*
|
||||
* This is a templated class to allow it to be used with Geodesic,
|
||||
* GeodesicExact, and Rhumb. GeographicLib::PolygonArea,
|
||||
* GeographicLib::PolygonAreaExact, and GeographicLib::PolygonAreaRhumb are
|
||||
* typedefs for these cases.
|
||||
*
|
||||
* For GeographicLib::PolygonArea (edges defined by Geodesic), an upper bound
|
||||
* on the error is about 0.1 m<sup>2</sup> per vertex. However this is a
|
||||
* wildly pessimistic estimate in most cases. A more realistic estimate of
|
||||
* the error is given by a test involving 10<sup>7</sup> approximately
|
||||
* regular polygons on the WGS84 ellipsoid. The centers and the orientations
|
||||
* of the polygons were uniformly distributed, the number of vertices was
|
||||
* log-uniformly distributed in [3, 300], and the center to vertex distance
|
||||
* log-uniformly distributed in [0.1 m, 9000 km].
|
||||
*
|
||||
* Using double precision (the standard precision for GeographicLib), the
|
||||
* maximum error in the perimeter was 200 nm, and the maximum error in the
|
||||
* area was<pre>
|
||||
* 0.0013 m^2 for perimeter < 10 km
|
||||
* 0.0070 m^2 for perimeter < 100 km
|
||||
* 0.070 m^2 for perimeter < 1000 km
|
||||
* 0.11 m^2 for all perimeters
|
||||
* </pre>
|
||||
* The errors are given in terms of the perimeter, because it is expected
|
||||
* that the errors depend mainly on the number of edges and the edge lengths.
|
||||
*
|
||||
* Using long doubles (GEOGRPAHICLIB_PRECISION = 3), the maximum error in the
|
||||
* perimeter was 200 pm, and the maximum error in the area was<pre>
|
||||
* 0.7 mm^2 for perim < 10 km
|
||||
* 3.2 mm^2 for perimeter < 100 km
|
||||
* 21 mm^2 for perimeter < 1000 km
|
||||
* 45 mm^2 for all perimeters
|
||||
* </pre>
|
||||
*
|
||||
* @tparam GeodType the geodesic class to use.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-PolygonArea.cpp
|
||||
*
|
||||
* <a href="Planimeter.1.html">Planimeter</a> is a command-line utility
|
||||
* providing access to the functionality of PolygonAreaT.
|
||||
**********************************************************************/
|
||||
|
||||
template <class GeodType = Geodesic>
|
||||
class PolygonAreaT {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
GeodType _earth;
|
||||
real _area0; // Full ellipsoid area
|
||||
bool _polyline; // Assume polyline (don't close and skip area)
|
||||
unsigned _mask;
|
||||
unsigned _num;
|
||||
int _crossings;
|
||||
Accumulator<> _areasum, _perimetersum;
|
||||
real _lat0, _lon0, _lat1, _lon1;
|
||||
static int transit(real lon1, real lon2) {
|
||||
// Return 1 or -1 if crossing prime meridian in east or west direction.
|
||||
// Otherwise return zero.
|
||||
// Compute lon12 the same way as Geodesic::Inverse.
|
||||
lon1 = Math::AngNormalize(lon1);
|
||||
lon2 = Math::AngNormalize(lon2);
|
||||
real lon12 = Math::AngDiff(lon1, lon2);
|
||||
// Treat 0 as negative in these tests. This balances +/- 180 being
|
||||
// treated as positive, i.e., +180.
|
||||
int cross =
|
||||
lon1 <= 0 && lon2 > 0 && lon12 > 0 ? 1 :
|
||||
(lon2 <= 0 && lon1 > 0 && lon12 < 0 ? -1 : 0);
|
||||
return cross;
|
||||
}
|
||||
// an alternate version of transit to deal with longitudes in the direct
|
||||
// problem.
|
||||
static int transitdirect(real lon1, real lon2) {
|
||||
// Compute exactly the parity of
|
||||
// int(ceil(lon2 / 360)) - int(ceil(lon1 / 360))
|
||||
using std::remainder;
|
||||
lon1 = remainder(lon1, real(720));
|
||||
lon2 = remainder(lon2, real(720));
|
||||
return ( (lon2 <= 0 && lon2 > -360 ? 1 : 0) -
|
||||
(lon1 <= 0 && lon1 > -360 ? 1 : 0) );
|
||||
}
|
||||
void Remainder(Accumulator<>& a) const { a.remainder(_area0); }
|
||||
void Remainder(real& a) const {
|
||||
using std::remainder;
|
||||
a = remainder(a, _area0);
|
||||
}
|
||||
template <typename T>
|
||||
void AreaReduce(T& area, int crossings, bool reverse, bool sign) const;
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for PolygonAreaT.
|
||||
*
|
||||
* @param[in] earth the Geodesic object to use for geodesic calculations.
|
||||
* @param[in] polyline if true that treat the points as defining a polyline
|
||||
* instead of a polygon (default = false).
|
||||
**********************************************************************/
|
||||
PolygonAreaT(const GeodType& earth, bool polyline = false)
|
||||
: _earth(earth)
|
||||
, _area0(_earth.EllipsoidArea())
|
||||
, _polyline(polyline)
|
||||
, _mask(GeodType::LATITUDE | GeodType::LONGITUDE | GeodType::DISTANCE |
|
||||
(_polyline ? GeodType::NONE :
|
||||
GeodType::AREA | GeodType::LONG_UNROLL))
|
||||
{ Clear(); }
|
||||
|
||||
/**
|
||||
* Clear PolygonAreaT, allowing a new polygon to be started.
|
||||
**********************************************************************/
|
||||
void Clear() {
|
||||
_num = 0;
|
||||
_crossings = 0;
|
||||
_areasum = 0;
|
||||
_perimetersum = 0;
|
||||
_lat0 = _lon0 = _lat1 = _lon1 = Math::NaN();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a point to the polygon or polyline.
|
||||
*
|
||||
* @param[in] lat the latitude of the point (degrees).
|
||||
* @param[in] lon the longitude of the point (degrees).
|
||||
*
|
||||
* \e lat should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
void AddPoint(real lat, real lon);
|
||||
|
||||
/**
|
||||
* Add an edge to the polygon or polyline.
|
||||
*
|
||||
* @param[in] azi azimuth at current point (degrees).
|
||||
* @param[in] s distance from current point to next point (meters).
|
||||
*
|
||||
* This does nothing if no points have been added yet. Use
|
||||
* PolygonAreaT::CurrentPoint to determine the position of the new vertex.
|
||||
**********************************************************************/
|
||||
void AddEdge(real azi, real s);
|
||||
|
||||
/**
|
||||
* Return the results so far.
|
||||
*
|
||||
* @param[in] reverse if true then clockwise (instead of counter-clockwise)
|
||||
* traversal counts as a positive area.
|
||||
* @param[in] sign if true then return a signed result for the area if
|
||||
* the polygon is traversed in the "wrong" direction instead of returning
|
||||
* the area for the rest of the earth.
|
||||
* @param[out] perimeter the perimeter of the polygon or length of the
|
||||
* polyline (meters).
|
||||
* @param[out] area the area of the polygon (meters<sup>2</sup>); only set
|
||||
* if \e polyline is false in the constructor.
|
||||
* @return the number of points.
|
||||
*
|
||||
* More points can be added to the polygon after this call.
|
||||
**********************************************************************/
|
||||
unsigned Compute(bool reverse, bool sign,
|
||||
real& perimeter, real& area) const;
|
||||
|
||||
/**
|
||||
* Return the results assuming a tentative final test point is added;
|
||||
* however, the data for the test point is not saved. This lets you report
|
||||
* a running result for the perimeter and area as the user moves the mouse
|
||||
* cursor. Ordinary floating point arithmetic is used to accumulate the
|
||||
* data for the test point; thus the area and perimeter returned are less
|
||||
* accurate than if PolygonAreaT::AddPoint and PolygonAreaT::Compute are
|
||||
* used.
|
||||
*
|
||||
* @param[in] lat the latitude of the test point (degrees).
|
||||
* @param[in] lon the longitude of the test point (degrees).
|
||||
* @param[in] reverse if true then clockwise (instead of counter-clockwise)
|
||||
* traversal counts as a positive area.
|
||||
* @param[in] sign if true then return a signed result for the area if
|
||||
* the polygon is traversed in the "wrong" direction instead of returning
|
||||
* the area for the rest of the earth.
|
||||
* @param[out] perimeter the approximate perimeter of the polygon or length
|
||||
* of the polyline (meters).
|
||||
* @param[out] area the approximate area of the polygon
|
||||
* (meters<sup>2</sup>); only set if polyline is false in the
|
||||
* constructor.
|
||||
* @return the number of points.
|
||||
*
|
||||
* \e lat should be in the range [−90°, 90°].
|
||||
**********************************************************************/
|
||||
unsigned TestPoint(real lat, real lon, bool reverse, bool sign,
|
||||
real& perimeter, real& area) const;
|
||||
|
||||
/**
|
||||
* Return the results assuming a tentative final test point is added via an
|
||||
* azimuth and distance; however, the data for the test point is not saved.
|
||||
* This lets you report a running result for the perimeter and area as the
|
||||
* user moves the mouse cursor. Ordinary floating point arithmetic is used
|
||||
* to accumulate the data for the test point; thus the area and perimeter
|
||||
* returned are less accurate than if PolygonAreaT::AddEdge and
|
||||
* PolygonAreaT::Compute are used.
|
||||
*
|
||||
* @param[in] azi azimuth at current point (degrees).
|
||||
* @param[in] s distance from current point to final test point (meters).
|
||||
* @param[in] reverse if true then clockwise (instead of counter-clockwise)
|
||||
* traversal counts as a positive area.
|
||||
* @param[in] sign if true then return a signed result for the area if
|
||||
* the polygon is traversed in the "wrong" direction instead of returning
|
||||
* the area for the rest of the earth.
|
||||
* @param[out] perimeter the approximate perimeter of the polygon or length
|
||||
* of the polyline (meters).
|
||||
* @param[out] area the approximate area of the polygon
|
||||
* (meters<sup>2</sup>); only set if polyline is false in the
|
||||
* constructor.
|
||||
* @return the number of points.
|
||||
**********************************************************************/
|
||||
unsigned TestEdge(real azi, real s, bool reverse, bool sign,
|
||||
real& perimeter, real& area) const;
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value inherited from the Geodesic object used in the constructor.
|
||||
**********************************************************************/
|
||||
|
||||
Math::real EquatorialRadius() const { return _earth.EquatorialRadius(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value
|
||||
* inherited from the Geodesic object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _earth.Flattening(); }
|
||||
|
||||
/**
|
||||
* Report the previous vertex added to the polygon or polyline.
|
||||
*
|
||||
* @param[out] lat the latitude of the point (degrees).
|
||||
* @param[out] lon the longitude of the point (degrees).
|
||||
*
|
||||
* If no points have been added, then NaNs are returned. Otherwise, \e lon
|
||||
* will be in the range [−180°, 180°].
|
||||
**********************************************************************/
|
||||
void CurrentPoint(real& lat, real& lon) const
|
||||
{ lat = _lat1; lon = _lon1; }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
};
|
||||
|
||||
/**
|
||||
* @relates PolygonAreaT
|
||||
*
|
||||
* Polygon areas using Geodesic. This should be used if the flattening is
|
||||
* small.
|
||||
**********************************************************************/
|
||||
typedef PolygonAreaT<Geodesic> PolygonArea;
|
||||
|
||||
/**
|
||||
* @relates PolygonAreaT
|
||||
*
|
||||
* Polygon areas using GeodesicExact. (But note that the implementation of
|
||||
* areas in GeodesicExact uses a high order series and this is only accurate
|
||||
* for modest flattenings.)
|
||||
**********************************************************************/
|
||||
typedef PolygonAreaT<GeodesicExact> PolygonAreaExact;
|
||||
|
||||
/**
|
||||
* @relates PolygonAreaT
|
||||
*
|
||||
* Polygon areas using Rhumb.
|
||||
**********************************************************************/
|
||||
typedef PolygonAreaT<Rhumb> PolygonAreaRhumb;
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_POLYGONAREA_HPP
|
||||
621
external/include/GeographicLib/Rhumb.hpp
vendored
Normal file
621
external/include/GeographicLib/Rhumb.hpp
vendored
Normal file
@@ -0,0 +1,621 @@
|
||||
/**
|
||||
* \file Rhumb.hpp
|
||||
* \brief Header for GeographicLib::Rhumb and GeographicLib::RhumbLine classes
|
||||
*
|
||||
* Copyright (c) Charles Karney (2014-2021) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_RHUMB_HPP)
|
||||
#define GEOGRAPHICLIB_RHUMB_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/Ellipsoid.hpp>
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_RHUMBAREA_ORDER)
|
||||
/**
|
||||
* The order of the series approximation used in rhumb area calculations.
|
||||
* GEOGRAPHICLIB_RHUMBAREA_ORDER can be set to any integer in [4, 8].
|
||||
**********************************************************************/
|
||||
# define GEOGRAPHICLIB_RHUMBAREA_ORDER \
|
||||
(GEOGRAPHICLIB_PRECISION == 2 ? 6 : \
|
||||
(GEOGRAPHICLIB_PRECISION == 1 ? 4 : 8))
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
class RhumbLine;
|
||||
template <class T> class PolygonAreaT;
|
||||
|
||||
/**
|
||||
* \brief Solve of the direct and inverse rhumb problems.
|
||||
*
|
||||
* The path of constant azimuth between two points on a ellipsoid at (\e
|
||||
* lat1, \e lon1) and (\e lat2, \e lon2) is called the rhumb line (also
|
||||
* called the loxodrome). Its length is \e s12 and its azimuth is \e azi12.
|
||||
* (The azimuth is the heading measured clockwise from north.)
|
||||
*
|
||||
* Given \e lat1, \e lon1, \e azi12, and \e s12, we can determine \e lat2,
|
||||
* and \e lon2. This is the \e direct rhumb problem and its solution is
|
||||
* given by the function Rhumb::Direct.
|
||||
*
|
||||
* Given \e lat1, \e lon1, \e lat2, and \e lon2, we can determine \e azi12
|
||||
* and \e s12. This is the \e inverse rhumb problem, whose solution is given
|
||||
* by Rhumb::Inverse. This finds the shortest such rhumb line, i.e., the one
|
||||
* that wraps no more than half way around the earth. If the end points are
|
||||
* on opposite meridians, there are two shortest rhumb lines and the
|
||||
* east-going one is chosen.
|
||||
*
|
||||
* These routines also optionally calculate the area under the rhumb line, \e
|
||||
* S12. This is the area, measured counter-clockwise, of the rhumb line
|
||||
* quadrilateral with corners (<i>lat1</i>,<i>lon1</i>), (0,<i>lon1</i>),
|
||||
* (0,<i>lon2</i>), and (<i>lat2</i>,<i>lon2</i>).
|
||||
*
|
||||
* Note that rhumb lines may be appreciably longer (up to 50%) than the
|
||||
* corresponding Geodesic. For example the distance between London Heathrow
|
||||
* and Tokyo Narita via the rhumb line is 11400 km which is 18% longer than
|
||||
* the geodesic distance 9600 km.
|
||||
*
|
||||
* For more information on rhumb lines see \ref rhumb.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-Rhumb.cpp
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT Rhumb {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
friend class RhumbLine;
|
||||
template <class T> friend class PolygonAreaT;
|
||||
Ellipsoid _ell;
|
||||
bool _exact;
|
||||
real _c2;
|
||||
static const int tm_maxord = GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER;
|
||||
static const int maxpow_ = GEOGRAPHICLIB_RHUMBAREA_ORDER;
|
||||
// _R[0] unused
|
||||
real _R[maxpow_ + 1];
|
||||
static real gd(real x)
|
||||
{ using std::atan; using std::sinh; return atan(sinh(x)); }
|
||||
|
||||
// Use divided differences to determine (mu2 - mu1) / (psi2 - psi1)
|
||||
// accurately
|
||||
//
|
||||
// Definition: Df(x,y,d) = (f(x) - f(y)) / (x - y)
|
||||
// See:
|
||||
// W. M. Kahan and R. J. Fateman,
|
||||
// Symbolic computation of divided differences,
|
||||
// SIGSAM Bull. 33(3), 7-28 (1999)
|
||||
// https://doi.org/10.1145/334714.334716
|
||||
// http://www.cs.berkeley.edu/~fateman/papers/divdiff.pdf
|
||||
|
||||
static real Dlog(real x, real y) {
|
||||
using std::sqrt; using std::asinh;
|
||||
real t = x - y;
|
||||
// Change
|
||||
//
|
||||
// atanh(t / (x + y))
|
||||
//
|
||||
// to
|
||||
//
|
||||
// asinh(t / (2 * sqrt(x*y)))
|
||||
//
|
||||
// to avoid taking atanh(1) when x is large and y is 1. N.B., this
|
||||
// routine is invoked with positive x and y, so no need to guard against
|
||||
// taking the sqrt of a negative quantity. This fixes bogus results for
|
||||
// the area being returning when an endpoint is at a pole.
|
||||
return t != 0 ? 2 * asinh(t / (2 * sqrt(x*y))) / t : 1 / x;
|
||||
}
|
||||
// N.B., x and y are in degrees
|
||||
static real Dtan(real x, real y) {
|
||||
real d = x - y, tx = Math::tand(x), ty = Math::tand(y), txy = tx * ty;
|
||||
return d != 0 ?
|
||||
(2 * txy > -1 ? (1 + txy) * Math::tand(d) : tx - ty) /
|
||||
(d * Math::degree()) :
|
||||
1 + txy;
|
||||
}
|
||||
static real Datan(real x, real y) {
|
||||
using std::atan;
|
||||
real d = x - y, xy = x * y;
|
||||
return d != 0 ?
|
||||
(2 * xy > -1 ? atan( d / (1 + xy) ) : atan(x) - atan(y)) / d :
|
||||
1 / (1 + xy);
|
||||
}
|
||||
static real Dsin(real x, real y) {
|
||||
using std::sin; using std::cos;
|
||||
real d = (x - y) / 2;
|
||||
return cos((x + y)/2) * (d != 0 ? sin(d) / d : 1);
|
||||
}
|
||||
static real Dsinh(real x, real y) {
|
||||
using std::sinh; using std::cosh;
|
||||
real d = (x - y) / 2;
|
||||
return cosh((x + y) / 2) * (d != 0 ? sinh(d) / d : 1);
|
||||
}
|
||||
static real Dcosh(real x, real y) {
|
||||
using std::sinh;
|
||||
real d = (x - y) / 2;
|
||||
return sinh((x + y) / 2) * (d != 0 ? sinh(d) / d : 1);
|
||||
}
|
||||
static real Dasinh(real x, real y) {
|
||||
using std::asinh; using std::hypot;
|
||||
real d = x - y,
|
||||
hx = hypot(real(1), x), hy = hypot(real(1), y);
|
||||
return d != 0 ?
|
||||
asinh(x*y > 0 ? d * (x + y) / (x*hy + y*hx) : x*hy - y*hx) / d :
|
||||
1 / hx;
|
||||
}
|
||||
static real Dgd(real x, real y) {
|
||||
using std::sinh;
|
||||
return Datan(sinh(x), sinh(y)) * Dsinh(x, y);
|
||||
}
|
||||
// N.B., x and y are the tangents of the angles
|
||||
static real Dgdinv(real x, real y)
|
||||
{ return Dasinh(x, y) / Datan(x, y); }
|
||||
// Copied from LambertConformalConic...
|
||||
// Deatanhe(x,y) = eatanhe((x-y)/(1-e^2*x*y))/(x-y)
|
||||
real Deatanhe(real x, real y) const {
|
||||
real t = x - y, d = 1 - _ell._e2 * x * y;
|
||||
return t != 0 ? Math::eatanhe(t / d, _ell._es) / t : _ell._e2 / d;
|
||||
}
|
||||
// (E(x) - E(y)) / (x - y) -- E = incomplete elliptic integral of 2nd kind
|
||||
real DE(real x, real y) const;
|
||||
// (mux - muy) / (phix - phiy) using elliptic integrals
|
||||
real DRectifying(real latx, real laty) const;
|
||||
// (psix - psiy) / (phix - phiy)
|
||||
real DIsometric(real latx, real laty) const;
|
||||
|
||||
// (sum(c[j]*sin(2*j*x),j=1..n) - sum(c[j]*sin(2*j*x),j=1..n)) / (x - y)
|
||||
static real SinCosSeries(bool sinp,
|
||||
real x, real y, const real c[], int n);
|
||||
// (mux - muy) / (chix - chiy) using Krueger's series
|
||||
real DConformalToRectifying(real chix, real chiy) const;
|
||||
// (chix - chiy) / (mux - muy) using Krueger's series
|
||||
real DRectifyingToConformal(real mux, real muy) const;
|
||||
|
||||
// (mux - muy) / (psix - psiy)
|
||||
// N.B., psix and psiy are in degrees
|
||||
real DIsometricToRectifying(real psix, real psiy) const;
|
||||
// (psix - psiy) / (mux - muy)
|
||||
real DRectifyingToIsometric(real mux, real muy) const;
|
||||
|
||||
real MeanSinXi(real psi1, real psi2) const;
|
||||
|
||||
// The following two functions (with lots of ignored arguments) mimic the
|
||||
// interface to the corresponding Geodesic function. These are needed by
|
||||
// PolygonAreaT.
|
||||
void GenDirect(real lat1, real lon1, real azi12,
|
||||
bool, real s12, unsigned outmask,
|
||||
real& lat2, real& lon2, real&, real&, real&, real&, real&,
|
||||
real& S12) const {
|
||||
GenDirect(lat1, lon1, azi12, s12, outmask, lat2, lon2, S12);
|
||||
}
|
||||
void GenInverse(real lat1, real lon1, real lat2, real lon2,
|
||||
unsigned outmask, real& s12, real& azi12,
|
||||
real&, real& , real& , real& , real& S12) const {
|
||||
GenInverse(lat1, lon1, lat2, lon2, outmask, s12, azi12, S12);
|
||||
}
|
||||
public:
|
||||
|
||||
/**
|
||||
* Bit masks for what calculations to do. They specify which results to
|
||||
* return in the general routines Rhumb::GenDirect and Rhumb::GenInverse
|
||||
* routines. RhumbLine::mask is a duplication of this enum.
|
||||
**********************************************************************/
|
||||
enum mask {
|
||||
/**
|
||||
* No output.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
NONE = 0U,
|
||||
/**
|
||||
* Calculate latitude \e lat2.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LATITUDE = 1U<<7,
|
||||
/**
|
||||
* Calculate longitude \e lon2.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONGITUDE = 1U<<8,
|
||||
/**
|
||||
* Calculate azimuth \e azi12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AZIMUTH = 1U<<9,
|
||||
/**
|
||||
* Calculate distance \e s12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DISTANCE = 1U<<10,
|
||||
/**
|
||||
* Calculate area \e S12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AREA = 1U<<14,
|
||||
/**
|
||||
* Unroll \e lon2 in the direct calculation.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONG_UNROLL = 1U<<15,
|
||||
/**
|
||||
* Calculate everything. (LONG_UNROLL is not included in this mask.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
ALL = 0x7F80U,
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor for a ellipsoid with
|
||||
*
|
||||
* @param[in] a equatorial radius (meters).
|
||||
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
|
||||
* Negative \e f gives a prolate ellipsoid.
|
||||
* @param[in] exact if true (the default) use an addition theorem for
|
||||
* elliptic integrals to compute divided differences; otherwise use
|
||||
* series expansion (accurate for |<i>f</i>| < 0.01).
|
||||
* @exception GeographicErr if \e a or (1 − \e f) \e a is not
|
||||
* positive.
|
||||
*
|
||||
* See \ref rhumb, for a detailed description of the \e exact parameter.
|
||||
**********************************************************************/
|
||||
Rhumb(real a, real f, bool exact = true);
|
||||
|
||||
/**
|
||||
* Solve the direct rhumb problem returning also the area.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi12 azimuth of the rhumb line (degrees).
|
||||
* @param[in] s12 distance between point 1 and point 2 (meters); it can be
|
||||
* negative.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees).
|
||||
* @param[out] S12 area under the rhumb line (meters<sup>2</sup>).
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°]. The value of
|
||||
* \e lon2 returned is in the range [−180°, 180°].
|
||||
*
|
||||
* If point 1 is a pole, the cosine of its latitude is taken to be
|
||||
* 1/ε<sup>2</sup> (where ε is 2<sup>-52</sup>). This
|
||||
* position, which is extremely close to the actual pole, allows the
|
||||
* calculation to be carried out in finite terms. If \e s12 is large
|
||||
* enough that the rhumb line crosses a pole, the longitude of point 2
|
||||
* is indeterminate (a NaN is returned for \e lon2 and \e S12).
|
||||
**********************************************************************/
|
||||
void Direct(real lat1, real lon1, real azi12, real s12,
|
||||
real& lat2, real& lon2, real& S12) const {
|
||||
GenDirect(lat1, lon1, azi12, s12,
|
||||
LATITUDE | LONGITUDE | AREA, lat2, lon2, S12);
|
||||
}
|
||||
|
||||
/**
|
||||
* Solve the direct rhumb problem without the area.
|
||||
**********************************************************************/
|
||||
void Direct(real lat1, real lon1, real azi12, real s12,
|
||||
real& lat2, real& lon2) const {
|
||||
real t;
|
||||
GenDirect(lat1, lon1, azi12, s12, LATITUDE | LONGITUDE, lat2, lon2, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* The general direct rhumb problem. Rhumb::Direct is defined in terms
|
||||
* of this function.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi12 azimuth of the rhumb line (degrees).
|
||||
* @param[in] s12 distance between point 1 and point 2 (meters); it can be
|
||||
* negative.
|
||||
* @param[in] outmask a bitor'ed combination of Rhumb::mask values
|
||||
* specifying which of the following parameters should be set.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees).
|
||||
* @param[out] S12 area under the rhumb line (meters<sup>2</sup>).
|
||||
*
|
||||
* The Rhumb::mask values possible for \e outmask are
|
||||
* - \e outmask |= Rhumb::LATITUDE for the latitude \e lat2;
|
||||
* - \e outmask |= Rhumb::LONGITUDE for the latitude \e lon2;
|
||||
* - \e outmask |= Rhumb::AREA for the area \e S12;
|
||||
* - \e outmask |= Rhumb::ALL for all of the above;
|
||||
* - \e outmask |= Rhumb::LONG_UNROLL to unroll \e lon2 instead of wrapping
|
||||
* it into the range [−180°, 180°].
|
||||
* .
|
||||
* With the Rhumb::LONG_UNROLL bit set, the quantity \e lon2 −
|
||||
* \e lon1 indicates how many times and in what sense the rhumb line
|
||||
* encircles the ellipsoid.
|
||||
**********************************************************************/
|
||||
void GenDirect(real lat1, real lon1, real azi12, real s12,
|
||||
unsigned outmask, real& lat2, real& lon2, real& S12) const;
|
||||
|
||||
/**
|
||||
* Solve the inverse rhumb problem returning also the area.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] lat2 latitude of point 2 (degrees).
|
||||
* @param[in] lon2 longitude of point 2 (degrees).
|
||||
* @param[out] s12 rhumb distance between point 1 and point 2 (meters).
|
||||
* @param[out] azi12 azimuth of the rhumb line (degrees).
|
||||
* @param[out] S12 area under the rhumb line (meters<sup>2</sup>).
|
||||
*
|
||||
* The shortest rhumb line is found. If the end points are on opposite
|
||||
* meridians, there are two shortest rhumb lines and the east-going one is
|
||||
* chosen. \e lat1 and \e lat2 should be in the range [−90°,
|
||||
* 90°]. The value of \e azi12 returned is in the range
|
||||
* [−180°, 180°].
|
||||
*
|
||||
* If either point is a pole, the cosine of its latitude is taken to be
|
||||
* 1/ε<sup>2</sup> (where ε is 2<sup>-52</sup>). This
|
||||
* position, which is extremely close to the actual pole, allows the
|
||||
* calculation to be carried out in finite terms.
|
||||
**********************************************************************/
|
||||
void Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12, real& azi12, real& S12) const {
|
||||
GenInverse(lat1, lon1, lat2, lon2,
|
||||
DISTANCE | AZIMUTH | AREA, s12, azi12, S12);
|
||||
}
|
||||
|
||||
/**
|
||||
* Solve the inverse rhumb problem without the area.
|
||||
**********************************************************************/
|
||||
void Inverse(real lat1, real lon1, real lat2, real lon2,
|
||||
real& s12, real& azi12) const {
|
||||
real t;
|
||||
GenInverse(lat1, lon1, lat2, lon2, DISTANCE | AZIMUTH, s12, azi12, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* The general inverse rhumb problem. Rhumb::Inverse is defined in terms
|
||||
* of this function.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] lat2 latitude of point 2 (degrees).
|
||||
* @param[in] lon2 longitude of point 2 (degrees).
|
||||
* @param[in] outmask a bitor'ed combination of Rhumb::mask values
|
||||
* specifying which of the following parameters should be set.
|
||||
* @param[out] s12 rhumb distance between point 1 and point 2 (meters).
|
||||
* @param[out] azi12 azimuth of the rhumb line (degrees).
|
||||
* @param[out] S12 area under the rhumb line (meters<sup>2</sup>).
|
||||
*
|
||||
* The Rhumb::mask values possible for \e outmask are
|
||||
* - \e outmask |= Rhumb::DISTANCE for the latitude \e s12;
|
||||
* - \e outmask |= Rhumb::AZIMUTH for the latitude \e azi12;
|
||||
* - \e outmask |= Rhumb::AREA for the area \e S12;
|
||||
* - \e outmask |= Rhumb::ALL for all of the above;
|
||||
**********************************************************************/
|
||||
void GenInverse(real lat1, real lon1, real lat2, real lon2,
|
||||
unsigned outmask,
|
||||
real& s12, real& azi12, real& S12) const;
|
||||
|
||||
/**
|
||||
* Set up to compute several points on a single rhumb line.
|
||||
*
|
||||
* @param[in] lat1 latitude of point 1 (degrees).
|
||||
* @param[in] lon1 longitude of point 1 (degrees).
|
||||
* @param[in] azi12 azimuth of the rhumb line (degrees).
|
||||
* @return a RhumbLine object.
|
||||
*
|
||||
* \e lat1 should be in the range [−90°, 90°].
|
||||
*
|
||||
* If point 1 is a pole, the cosine of its latitude is taken to be
|
||||
* 1/ε<sup>2</sup> (where ε is 2<sup>-52</sup>). This
|
||||
* position, which is extremely close to the actual pole, allows the
|
||||
* calculation to be carried out in finite terms.
|
||||
**********************************************************************/
|
||||
RhumbLine Line(real lat1, real lon1, real azi12) const;
|
||||
|
||||
/** \name Inspector functions.
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _ell.EquatorialRadius(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the
|
||||
* value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _ell.Flattening(); }
|
||||
|
||||
/**
|
||||
* @return total area of ellipsoid in meters<sup>2</sup>. The area of a
|
||||
* polygon encircling a pole can be found by adding
|
||||
* Geodesic::EllipsoidArea()/2 to the sum of \e S12 for each side of the
|
||||
* polygon.
|
||||
**********************************************************************/
|
||||
Math::real EllipsoidArea() const { return _ell.Area(); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* A global instantiation of Rhumb with the parameters for the WGS84
|
||||
* ellipsoid.
|
||||
**********************************************************************/
|
||||
static const Rhumb& WGS84();
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Find a sequence of points on a single rhumb line.
|
||||
*
|
||||
* RhumbLine facilitates the determination of a series of points on a single
|
||||
* rhumb line. The starting point (\e lat1, \e lon1) and the azimuth \e
|
||||
* azi12 are specified in the call to Rhumb::Line which returns a RhumbLine
|
||||
* object. RhumbLine.Position returns the location of point 2 (and,
|
||||
* optionally, the corresponding area, \e S12) a distance \e s12 along the
|
||||
* rhumb line.
|
||||
*
|
||||
* There is no public constructor for this class. (Use Rhumb::Line to create
|
||||
* an instance.) The Rhumb object used to create a RhumbLine must stay in
|
||||
* scope as long as the RhumbLine.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-RhumbLine.cpp
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT RhumbLine {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
friend class Rhumb;
|
||||
const Rhumb& _rh;
|
||||
bool _exact; // TODO: RhumbLine::_exact is unused; retire
|
||||
real _lat1, _lon1, _azi12, _salp, _calp, _mu1, _psi1, _r1;
|
||||
// copy assignment not allowed
|
||||
RhumbLine& operator=(const RhumbLine&) = delete;
|
||||
RhumbLine(const Rhumb& rh, real lat1, real lon1, real azi12,
|
||||
bool exact);
|
||||
public:
|
||||
/**
|
||||
* Construction is via default copy constructor.
|
||||
**********************************************************************/
|
||||
RhumbLine(const RhumbLine&) = default;
|
||||
/**
|
||||
* This is a duplication of Rhumb::mask.
|
||||
**********************************************************************/
|
||||
enum mask {
|
||||
/**
|
||||
* No output.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
NONE = Rhumb::NONE,
|
||||
/**
|
||||
* Calculate latitude \e lat2.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LATITUDE = Rhumb::LATITUDE,
|
||||
/**
|
||||
* Calculate longitude \e lon2.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONGITUDE = Rhumb::LONGITUDE,
|
||||
/**
|
||||
* Calculate azimuth \e azi12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AZIMUTH = Rhumb::AZIMUTH,
|
||||
/**
|
||||
* Calculate distance \e s12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
DISTANCE = Rhumb::DISTANCE,
|
||||
/**
|
||||
* Calculate area \e S12.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
AREA = Rhumb::AREA,
|
||||
/**
|
||||
* Unroll \e lon2 in the direct calculation.
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
LONG_UNROLL = Rhumb::LONG_UNROLL,
|
||||
/**
|
||||
* Calculate everything. (LONG_UNROLL is not included in this mask.)
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
ALL = Rhumb::ALL,
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute the position of point 2 which is a distance \e s12 (meters) from
|
||||
* point 1. The area is also computed.
|
||||
*
|
||||
* @param[in] s12 distance between point 1 and point 2 (meters); it can be
|
||||
* negative.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees).
|
||||
* @param[out] S12 area under the rhumb line (meters<sup>2</sup>).
|
||||
*
|
||||
* The value of \e lon2 returned is in the range [−180°,
|
||||
* 180°].
|
||||
*
|
||||
* If \e s12 is large enough that the rhumb line crosses a pole, the
|
||||
* longitude of point 2 is indeterminate (a NaN is returned for \e lon2 and
|
||||
* \e S12).
|
||||
**********************************************************************/
|
||||
void Position(real s12, real& lat2, real& lon2, real& S12) const {
|
||||
GenPosition(s12, LATITUDE | LONGITUDE | AREA, lat2, lon2, S12);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the position of point 2 which is a distance \e s12 (meters) from
|
||||
* point 1. The area is not computed.
|
||||
**********************************************************************/
|
||||
void Position(real s12, real& lat2, real& lon2) const {
|
||||
real t;
|
||||
GenPosition(s12, LATITUDE | LONGITUDE, lat2, lon2, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* The general position routine. RhumbLine::Position is defined in term so
|
||||
* this function.
|
||||
*
|
||||
* @param[in] s12 distance between point 1 and point 2 (meters); it can be
|
||||
* negative.
|
||||
* @param[in] outmask a bitor'ed combination of RhumbLine::mask values
|
||||
* specifying which of the following parameters should be set.
|
||||
* @param[out] lat2 latitude of point 2 (degrees).
|
||||
* @param[out] lon2 longitude of point 2 (degrees).
|
||||
* @param[out] S12 area under the rhumb line (meters<sup>2</sup>).
|
||||
*
|
||||
* The RhumbLine::mask values possible for \e outmask are
|
||||
* - \e outmask |= RhumbLine::LATITUDE for the latitude \e lat2;
|
||||
* - \e outmask |= RhumbLine::LONGITUDE for the latitude \e lon2;
|
||||
* - \e outmask |= RhumbLine::AREA for the area \e S12;
|
||||
* - \e outmask |= RhumbLine::ALL for all of the above;
|
||||
* - \e outmask |= RhumbLine::LONG_UNROLL to unroll \e lon2 instead of
|
||||
* wrapping it into the range [−180°, 180°].
|
||||
* .
|
||||
* With the RhumbLine::LONG_UNROLL bit set, the quantity \e lon2 − \e
|
||||
* lon1 indicates how many times and in what sense the rhumb line encircles
|
||||
* the ellipsoid.
|
||||
*
|
||||
* If \e s12 is large enough that the rhumb line crosses a pole, the
|
||||
* longitude of point 2 is indeterminate (a NaN is returned for \e lon2 and
|
||||
* \e S12).
|
||||
**********************************************************************/
|
||||
void GenPosition(real s12, unsigned outmask,
|
||||
real& lat2, real& lon2, real& S12) const;
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @return \e lat1 the latitude of point 1 (degrees).
|
||||
**********************************************************************/
|
||||
Math::real Latitude() const { return _lat1; }
|
||||
|
||||
/**
|
||||
* @return \e lon1 the longitude of point 1 (degrees).
|
||||
**********************************************************************/
|
||||
Math::real Longitude() const { return _lon1; }
|
||||
|
||||
/**
|
||||
* @return \e azi12 the azimuth of the rhumb line (degrees).
|
||||
**********************************************************************/
|
||||
Math::real Azimuth() const { return _azi12; }
|
||||
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value inherited from the Rhumb object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _rh.EquatorialRadius(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value
|
||||
* inherited from the Rhumb object used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _rh.Flattening(); }
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_RHUMB_HPP
|
||||
384
external/include/GeographicLib/SphericalEngine.hpp
vendored
Normal file
384
external/include/GeographicLib/SphericalEngine.hpp
vendored
Normal file
@@ -0,0 +1,384 @@
|
||||
/**
|
||||
* \file SphericalEngine.hpp
|
||||
* \brief Header for GeographicLib::SphericalEngine class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2011-2019) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_SPHERICALENGINE_HPP)
|
||||
#define GEOGRAPHICLIB_SPHERICALENGINE_HPP 1
|
||||
|
||||
#include <vector>
|
||||
#include <istream>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about dll vs vector
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4251)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
class CircularEngine;
|
||||
|
||||
/**
|
||||
* \brief The evaluation engine for SphericalHarmonic
|
||||
*
|
||||
* This serves as the backend to SphericalHarmonic, SphericalHarmonic1, and
|
||||
* SphericalHarmonic2. Typically end-users will not have to access this
|
||||
* class directly.
|
||||
*
|
||||
* See SphericalEngine.cpp for more information on the implementation.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-SphericalEngine.cpp
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT SphericalEngine {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
// CircularEngine needs access to sqrttable, scale
|
||||
friend class CircularEngine;
|
||||
// Return the table of the square roots of integers
|
||||
static std::vector<real>& sqrttable();
|
||||
// An internal scaling of the coefficients to avoid overflow in
|
||||
// intermediate calculations.
|
||||
static real scale() {
|
||||
using std::pow;
|
||||
static const real
|
||||
// Need extra real because, since C++11, pow(float, int) returns double
|
||||
s = real(pow(real(std::numeric_limits<real>::radix),
|
||||
-3 * (std::numeric_limits<real>::max_exponent < (1<<14) ?
|
||||
std::numeric_limits<real>::max_exponent : (1<<14))
|
||||
/ 5));
|
||||
return s;
|
||||
}
|
||||
// Move latitudes near the pole off the axis by this amount.
|
||||
static real eps() {
|
||||
using std::sqrt;
|
||||
return std::numeric_limits<real>::epsilon() *
|
||||
sqrt(std::numeric_limits<real>::epsilon());
|
||||
}
|
||||
SphericalEngine(); // Disable constructor
|
||||
public:
|
||||
/**
|
||||
* Supported normalizations for associated Legendre polynomials.
|
||||
**********************************************************************/
|
||||
enum normalization {
|
||||
/**
|
||||
* Fully normalized associated Legendre polynomials. See
|
||||
* SphericalHarmonic::FULL for documentation.
|
||||
*
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
FULL = 0,
|
||||
/**
|
||||
* Schmidt semi-normalized associated Legendre polynomials. See
|
||||
* SphericalHarmonic::SCHMIDT for documentation.
|
||||
*
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
SCHMIDT = 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Package up coefficients for SphericalEngine
|
||||
*
|
||||
* This packages up the \e C, \e S coefficients and information about how
|
||||
* the coefficients are stored into a single structure. This allows a
|
||||
* vector of type SphericalEngine::coeff to be passed to
|
||||
* SphericalEngine::Value. This class also includes functions to aid
|
||||
* indexing into \e C and \e S.
|
||||
*
|
||||
* The storage layout of the coefficients is documented in
|
||||
* SphericalHarmonic and SphericalHarmonic::SphericalHarmonic.
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT coeff {
|
||||
private:
|
||||
int _Nx, _nmx, _mmx;
|
||||
std::vector<real>::const_iterator _Cnm;
|
||||
std::vector<real>::const_iterator _Snm;
|
||||
public:
|
||||
/**
|
||||
* A default constructor
|
||||
**********************************************************************/
|
||||
coeff() : _Nx(-1) , _nmx(-1) , _mmx(-1) {}
|
||||
/**
|
||||
* The general constructor.
|
||||
*
|
||||
* @param[in] C a vector of coefficients for the cosine terms.
|
||||
* @param[in] S a vector of coefficients for the sine terms.
|
||||
* @param[in] N the degree giving storage layout for \e C and \e S.
|
||||
* @param[in] nmx the maximum degree to be used.
|
||||
* @param[in] mmx the maximum order to be used.
|
||||
* @exception GeographicErr if \e N, \e nmx, and \e mmx do not satisfy
|
||||
* \e N ≥ \e nmx ≥ \e mmx ≥ −1.
|
||||
* @exception GeographicErr if \e C or \e S is not big enough to hold the
|
||||
* coefficients.
|
||||
* @exception std::bad_alloc if the memory for the square root table
|
||||
* can't be allocated.
|
||||
**********************************************************************/
|
||||
coeff(const std::vector<real>& C,
|
||||
const std::vector<real>& S,
|
||||
int N, int nmx, int mmx)
|
||||
: _Nx(N)
|
||||
, _nmx(nmx)
|
||||
, _mmx(mmx)
|
||||
, _Cnm(C.begin())
|
||||
, _Snm(S.begin())
|
||||
{
|
||||
if (!((_Nx >= _nmx && _nmx >= _mmx && _mmx >= 0) ||
|
||||
// If mmx = -1 then the sums are empty so require nmx = -1 also.
|
||||
(_nmx == -1 && _mmx == -1)))
|
||||
throw GeographicErr("Bad indices for coeff");
|
||||
if (!(index(_nmx, _mmx) < int(C.size()) &&
|
||||
index(_nmx, _mmx) < int(S.size()) + (_Nx + 1)))
|
||||
throw GeographicErr("Arrays too small in coeff");
|
||||
SphericalEngine::RootTable(_nmx);
|
||||
}
|
||||
/**
|
||||
* The constructor for full coefficient vectors.
|
||||
*
|
||||
* @param[in] C a vector of coefficients for the cosine terms.
|
||||
* @param[in] S a vector of coefficients for the sine terms.
|
||||
* @param[in] N the maximum degree and order.
|
||||
* @exception GeographicErr if \e N does not satisfy \e N ≥ −1.
|
||||
* @exception GeographicErr if \e C or \e S is not big enough to hold the
|
||||
* coefficients.
|
||||
* @exception std::bad_alloc if the memory for the square root table
|
||||
* can't be allocated.
|
||||
**********************************************************************/
|
||||
coeff(const std::vector<real>& C,
|
||||
const std::vector<real>& S,
|
||||
int N)
|
||||
: _Nx(N)
|
||||
, _nmx(N)
|
||||
, _mmx(N)
|
||||
, _Cnm(C.begin())
|
||||
, _Snm(S.begin())
|
||||
{
|
||||
if (!(_Nx >= -1))
|
||||
throw GeographicErr("Bad indices for coeff");
|
||||
if (!(index(_nmx, _mmx) < int(C.size()) &&
|
||||
index(_nmx, _mmx) < int(S.size()) + (_Nx + 1)))
|
||||
throw GeographicErr("Arrays too small in coeff");
|
||||
SphericalEngine::RootTable(_nmx);
|
||||
}
|
||||
/**
|
||||
* @return \e N the degree giving storage layout for \e C and \e S.
|
||||
**********************************************************************/
|
||||
int N() const { return _Nx; }
|
||||
/**
|
||||
* @return \e nmx the maximum degree to be used.
|
||||
**********************************************************************/
|
||||
int nmx() const { return _nmx; }
|
||||
/**
|
||||
* @return \e mmx the maximum order to be used.
|
||||
**********************************************************************/
|
||||
int mmx() const { return _mmx; }
|
||||
/**
|
||||
* The one-dimensional index into \e C and \e S.
|
||||
*
|
||||
* @param[in] n the degree.
|
||||
* @param[in] m the order.
|
||||
* @return the one-dimensional index.
|
||||
**********************************************************************/
|
||||
int index(int n, int m) const
|
||||
{ return m * _Nx - m * (m - 1) / 2 + n; }
|
||||
/**
|
||||
* An element of \e C.
|
||||
*
|
||||
* @param[in] k the one-dimensional index.
|
||||
* @return the value of the \e C coefficient.
|
||||
**********************************************************************/
|
||||
Math::real Cv(int k) const { return *(_Cnm + k); }
|
||||
/**
|
||||
* An element of \e S.
|
||||
*
|
||||
* @param[in] k the one-dimensional index.
|
||||
* @return the value of the \e S coefficient.
|
||||
**********************************************************************/
|
||||
Math::real Sv(int k) const { return *(_Snm + (k - (_Nx + 1))); }
|
||||
/**
|
||||
* An element of \e C with checking.
|
||||
*
|
||||
* @param[in] k the one-dimensional index.
|
||||
* @param[in] n the requested degree.
|
||||
* @param[in] m the requested order.
|
||||
* @param[in] f a multiplier.
|
||||
* @return the value of the \e C coefficient multiplied by \e f in \e n
|
||||
* and \e m are in range else 0.
|
||||
**********************************************************************/
|
||||
Math::real Cv(int k, int n, int m, real f) const
|
||||
{ return m > _mmx || n > _nmx ? 0 : *(_Cnm + k) * f; }
|
||||
/**
|
||||
* An element of \e S with checking.
|
||||
*
|
||||
* @param[in] k the one-dimensional index.
|
||||
* @param[in] n the requested degree.
|
||||
* @param[in] m the requested order.
|
||||
* @param[in] f a multiplier.
|
||||
* @return the value of the \e S coefficient multiplied by \e f in \e n
|
||||
* and \e m are in range else 0.
|
||||
**********************************************************************/
|
||||
Math::real Sv(int k, int n, int m, real f) const
|
||||
{ return m > _mmx || n > _nmx ? 0 : *(_Snm + (k - (_Nx + 1))) * f; }
|
||||
|
||||
/**
|
||||
* The size of the coefficient vector for the cosine terms.
|
||||
*
|
||||
* @param[in] N the maximum degree.
|
||||
* @param[in] M the maximum order.
|
||||
* @return the size of the vector of cosine terms as stored in column
|
||||
* major order.
|
||||
**********************************************************************/
|
||||
static int Csize(int N, int M)
|
||||
{ return (M + 1) * (2 * N - M + 2) / 2; }
|
||||
|
||||
/**
|
||||
* The size of the coefficient vector for the sine terms.
|
||||
*
|
||||
* @param[in] N the maximum degree.
|
||||
* @param[in] M the maximum order.
|
||||
* @return the size of the vector of cosine terms as stored in column
|
||||
* major order.
|
||||
**********************************************************************/
|
||||
static int Ssize(int N, int M)
|
||||
{ return Csize(N, M) - (N + 1); }
|
||||
|
||||
/**
|
||||
* Load coefficients from a binary stream.
|
||||
*
|
||||
* @param[in] stream the input stream.
|
||||
* @param[in,out] N The maximum degree of the coefficients.
|
||||
* @param[in,out] M The maximum order of the coefficients.
|
||||
* @param[out] C The vector of cosine coefficients.
|
||||
* @param[out] S The vector of sine coefficients.
|
||||
* @param[in] truncate if false (the default) then \e N and \e M are
|
||||
* determined by the values in the binary stream; otherwise, the input
|
||||
* values of \e N and \e M are used to truncate the coefficients read
|
||||
* from the stream at the given degree and order.
|
||||
* @exception GeographicErr if \e N and \e M do not satisfy \e N ≥
|
||||
* \e M ≥ −1.
|
||||
* @exception GeographicErr if there's an error reading the data.
|
||||
* @exception std::bad_alloc if the memory for \e C or \e S can't be
|
||||
* allocated.
|
||||
*
|
||||
* \e N and \e M are read as 4-byte ints. \e C and \e S are resized to
|
||||
* accommodate all the coefficients (with the \e m = 0 coefficients for
|
||||
* \e S excluded) and the data for these coefficients read as 8-byte
|
||||
* doubles. The coefficients are stored in column major order. The
|
||||
* bytes in the stream should use little-endian ordering. IEEE floating
|
||||
* point is assumed for the coefficients.
|
||||
**********************************************************************/
|
||||
static void readcoeffs(std::istream& stream, int& N, int& M,
|
||||
std::vector<real>& C, std::vector<real>& S,
|
||||
bool truncate = false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Evaluate a spherical harmonic sum and its gradient.
|
||||
*
|
||||
* @tparam gradp should the gradient be calculated.
|
||||
* @tparam norm the normalization for the associated Legendre polynomials.
|
||||
* @tparam L the number of terms in the coefficients.
|
||||
* @param[in] c an array of coeff objects.
|
||||
* @param[in] f array of coefficient multipliers. f[0] should be 1.
|
||||
* @param[in] x the \e x component of the cartesian position.
|
||||
* @param[in] y the \e y component of the cartesian position.
|
||||
* @param[in] z the \e z component of the cartesian position.
|
||||
* @param[in] a the normalizing radius.
|
||||
* @param[out] gradx the \e x component of the gradient.
|
||||
* @param[out] grady the \e y component of the gradient.
|
||||
* @param[out] gradz the \e z component of the gradient.
|
||||
* @result the spherical harmonic sum.
|
||||
*
|
||||
* See the SphericalHarmonic class for the definition of the sum. The
|
||||
* coefficients used by this function are, for example, c[0].Cv + f[1] *
|
||||
* c[1].Cv + ... + f[L−1] * c[L−1].Cv. (Note that f[0] is \e
|
||||
* not used.) The upper limits on the sum are determined by c[0].nmx() and
|
||||
* c[0].mmx(); these limits apply to \e all the components of the
|
||||
* coefficients. The parameters \e gradp, \e norm, and \e L are template
|
||||
* parameters, to allow more optimization to be done at compile time.
|
||||
*
|
||||
* Clenshaw summation is used which permits the evaluation of the sum
|
||||
* without the need to allocate temporary arrays. Thus this function never
|
||||
* throws an exception.
|
||||
**********************************************************************/
|
||||
template<bool gradp, normalization norm, int L>
|
||||
static Math::real Value(const coeff c[], const real f[],
|
||||
real x, real y, real z, real a,
|
||||
real& gradx, real& grady, real& gradz);
|
||||
|
||||
/**
|
||||
* Create a CircularEngine object
|
||||
*
|
||||
* @tparam gradp should the gradient be calculated.
|
||||
* @tparam norm the normalization for the associated Legendre polynomials.
|
||||
* @tparam L the number of terms in the coefficients.
|
||||
* @param[in] c an array of coeff objects.
|
||||
* @param[in] f array of coefficient multipliers. f[0] should be 1.
|
||||
* @param[in] p the radius of the circle = sqrt(<i>x</i><sup>2</sup> +
|
||||
* <i>y</i><sup>2</sup>).
|
||||
* @param[in] z the height of the circle.
|
||||
* @param[in] a the normalizing radius.
|
||||
* @exception std::bad_alloc if the memory for the CircularEngine can't be
|
||||
* allocated.
|
||||
* @result the CircularEngine object.
|
||||
*
|
||||
* If you need to evaluate the spherical harmonic sum for several points
|
||||
* with constant \e f, \e p = sqrt(<i>x</i><sup>2</sup> +
|
||||
* <i>y</i><sup>2</sup>), \e z, and \e a, it is more efficient to construct
|
||||
* call SphericalEngine::Circle to give a CircularEngine object and then
|
||||
* call CircularEngine::operator()() with arguments <i>x</i>/\e p and
|
||||
* <i>y</i>/\e p.
|
||||
**********************************************************************/
|
||||
template<bool gradp, normalization norm, int L>
|
||||
static CircularEngine Circle(const coeff c[], const real f[],
|
||||
real p, real z, real a);
|
||||
/**
|
||||
* Check that the static table of square roots is big enough and enlarge it
|
||||
* if necessary.
|
||||
*
|
||||
* @param[in] N the maximum degree to be used in SphericalEngine.
|
||||
* @exception std::bad_alloc if the memory for the square root table can't
|
||||
* be allocated.
|
||||
*
|
||||
* Typically, there's no need for an end-user to call this routine, because
|
||||
* the constructors for SphericalEngine::coeff do so. However, since this
|
||||
* updates a static table, there's a possible race condition in a
|
||||
* multi-threaded environment. Because this routine does nothing if the
|
||||
* table is already large enough, one way to avoid race conditions is to
|
||||
* call this routine at program start up (when it's still single threaded),
|
||||
* supplying the largest degree that your program will use. E.g., \code
|
||||
GeographicLib::SphericalEngine::RootTable(2190);
|
||||
\endcode
|
||||
* suffices to accommodate extant magnetic and gravity models.
|
||||
**********************************************************************/
|
||||
static void RootTable(int N);
|
||||
|
||||
/**
|
||||
* Clear the static table of square roots and release the memory. Call
|
||||
* this only when you are sure you no longer will be using SphericalEngine.
|
||||
* Your program will crash if you call SphericalEngine after calling this
|
||||
* routine.
|
||||
*
|
||||
* \warning It's safest not to call this routine at all. (The space used
|
||||
* by the table is modest.)
|
||||
**********************************************************************/
|
||||
static void ClearRootTable() {
|
||||
std::vector<real> temp(0);
|
||||
sqrttable().swap(temp);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_SPHERICALENGINE_HPP
|
||||
356
external/include/GeographicLib/SphericalHarmonic.hpp
vendored
Normal file
356
external/include/GeographicLib/SphericalHarmonic.hpp
vendored
Normal file
@@ -0,0 +1,356 @@
|
||||
/**
|
||||
* \file SphericalHarmonic.hpp
|
||||
* \brief Header for GeographicLib::SphericalHarmonic class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2011-2019) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_SPHERICALHARMONIC_HPP)
|
||||
#define GEOGRAPHICLIB_SPHERICALHARMONIC_HPP 1
|
||||
|
||||
#include <vector>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/SphericalEngine.hpp>
|
||||
#include <GeographicLib/CircularEngine.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Spherical harmonic series
|
||||
*
|
||||
* This class evaluates the spherical harmonic sum \verbatim
|
||||
V(x, y, z) = sum(n = 0..N)[ q^(n+1) * sum(m = 0..n)[
|
||||
(C[n,m] * cos(m*lambda) + S[n,m] * sin(m*lambda)) *
|
||||
P[n,m](cos(theta)) ] ]
|
||||
\endverbatim
|
||||
* where
|
||||
* - <i>p</i><sup>2</sup> = <i>x</i><sup>2</sup> + <i>y</i><sup>2</sup>,
|
||||
* - <i>r</i><sup>2</sup> = <i>p</i><sup>2</sup> + <i>z</i><sup>2</sup>,
|
||||
* - \e q = <i>a</i>/<i>r</i>,
|
||||
* - θ = atan2(\e p, \e z) = the spherical \e colatitude,
|
||||
* - λ = atan2(\e y, \e x) = the longitude.
|
||||
* - P<sub><i>nm</i></sub>(\e t) is the associated Legendre polynomial of
|
||||
* degree \e n and order \e m.
|
||||
*
|
||||
* Two normalizations are supported for P<sub><i>nm</i></sub>
|
||||
* - fully normalized denoted by SphericalHarmonic::FULL.
|
||||
* - Schmidt semi-normalized denoted by SphericalHarmonic::SCHMIDT.
|
||||
*
|
||||
* Clenshaw summation is used for the sums over both \e n and \e m. This
|
||||
* allows the computation to be carried out without the need for any
|
||||
* temporary arrays. See SphericalEngine.cpp for more information on the
|
||||
* implementation.
|
||||
*
|
||||
* References:
|
||||
* - C. W. Clenshaw,
|
||||
* <a href="https://doi.org/10.1090/S0025-5718-1955-0071856-0">
|
||||
* A note on the summation of Chebyshev series</a>,
|
||||
* %Math. Tables Aids Comput. 9(51), 118--120 (1955).
|
||||
* - R. E. Deakin, Derivatives of the earth's potentials, Geomatics
|
||||
* Research Australasia 68, 31--60, (June 1998).
|
||||
* - W. A. Heiskanen and H. Moritz, Physical Geodesy, (Freeman, San
|
||||
* Francisco, 1967). (See Sec. 1-14, for a definition of Pbar.)
|
||||
* - S. A. Holmes and W. E. Featherstone,
|
||||
* <a href="https://doi.org/10.1007/s00190-002-0216-2">
|
||||
* A unified approach to the Clenshaw summation and the recursive
|
||||
* computation of very high degree and order normalised associated Legendre
|
||||
* functions</a>, J. Geodesy 76(5), 279--299 (2002).
|
||||
* - C. C. Tscherning and K. Poder,
|
||||
* <a href="http://cct.gfy.ku.dk/publ_cct/cct80.pdf">
|
||||
* Some geodetic applications of Clenshaw summation</a>,
|
||||
* Boll. Geod. Sci. Aff. 41(4), 349--375 (1982).
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-SphericalHarmonic.cpp
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT SphericalHarmonic {
|
||||
public:
|
||||
/**
|
||||
* Supported normalizations for the associated Legendre polynomials.
|
||||
**********************************************************************/
|
||||
enum normalization {
|
||||
/**
|
||||
* Fully normalized associated Legendre polynomials.
|
||||
*
|
||||
* These are defined by
|
||||
* <i>P</i><sub><i>nm</i></sub><sup>full</sup>(\e z)
|
||||
* = (−1)<sup><i>m</i></sup>
|
||||
* sqrt(\e k (2\e n + 1) (\e n − \e m)! / (\e n + \e m)!)
|
||||
* <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z), where
|
||||
* <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z) is Ferrers
|
||||
* function (also known as the Legendre function on the cut or the
|
||||
* associated Legendre polynomial) https://dlmf.nist.gov/14.7.E10 and
|
||||
* \e k = 1 for \e m = 0 and \e k = 2 otherwise.
|
||||
*
|
||||
* The mean squared value of
|
||||
* <i>P</i><sub><i>nm</i></sub><sup>full</sup>(cosθ)
|
||||
* cos(<i>m</i>λ) and
|
||||
* <i>P</i><sub><i>nm</i></sub><sup>full</sup>(cosθ)
|
||||
* sin(<i>m</i>λ) over the sphere is 1.
|
||||
*
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
FULL = SphericalEngine::FULL,
|
||||
/**
|
||||
* Schmidt semi-normalized associated Legendre polynomials.
|
||||
*
|
||||
* These are defined by
|
||||
* <i>P</i><sub><i>nm</i></sub><sup>schmidt</sup>(\e z)
|
||||
* = (−1)<sup><i>m</i></sup>
|
||||
* sqrt(\e k (\e n − \e m)! / (\e n + \e m)!)
|
||||
* <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z), where
|
||||
* <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z) is Ferrers
|
||||
* function (also known as the Legendre function on the cut or the
|
||||
* associated Legendre polynomial) https://dlmf.nist.gov/14.7.E10 and
|
||||
* \e k = 1 for \e m = 0 and \e k = 2 otherwise.
|
||||
*
|
||||
* The mean squared value of
|
||||
* <i>P</i><sub><i>nm</i></sub><sup>schmidt</sup>(cosθ)
|
||||
* cos(<i>m</i>λ) and
|
||||
* <i>P</i><sub><i>nm</i></sub><sup>schmidt</sup>(cosθ)
|
||||
* sin(<i>m</i>λ) over the sphere is 1/(2\e n + 1).
|
||||
*
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
SCHMIDT = SphericalEngine::SCHMIDT,
|
||||
};
|
||||
|
||||
private:
|
||||
typedef Math::real real;
|
||||
SphericalEngine::coeff _c[1];
|
||||
real _a;
|
||||
unsigned _norm;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor with a full set of coefficients specified.
|
||||
*
|
||||
* @param[in] C the coefficients <i>C</i><sub><i>nm</i></sub>.
|
||||
* @param[in] S the coefficients <i>S</i><sub><i>nm</i></sub>.
|
||||
* @param[in] N the maximum degree and order of the sum
|
||||
* @param[in] a the reference radius appearing in the definition of the
|
||||
* sum.
|
||||
* @param[in] norm the normalization for the associated Legendre
|
||||
* polynomials, either SphericalHarmonic::FULL (the default) or
|
||||
* SphericalHarmonic::SCHMIDT.
|
||||
* @exception GeographicErr if \e N does not satisfy \e N ≥ −1.
|
||||
* @exception GeographicErr if \e C or \e S is not big enough to hold the
|
||||
* coefficients.
|
||||
*
|
||||
* The coefficients <i>C</i><sub><i>nm</i></sub> and
|
||||
* <i>S</i><sub><i>nm</i></sub> are stored in the one-dimensional vectors
|
||||
* \e C and \e S which must contain (\e N + 1)(\e N + 2)/2 and \e N (\e N +
|
||||
* 1)/2 elements, respectively, stored in "column-major" order. Thus for
|
||||
* \e N = 3, the order would be:
|
||||
* <i>C</i><sub>00</sub>,
|
||||
* <i>C</i><sub>10</sub>,
|
||||
* <i>C</i><sub>20</sub>,
|
||||
* <i>C</i><sub>30</sub>,
|
||||
* <i>C</i><sub>11</sub>,
|
||||
* <i>C</i><sub>21</sub>,
|
||||
* <i>C</i><sub>31</sub>,
|
||||
* <i>C</i><sub>22</sub>,
|
||||
* <i>C</i><sub>32</sub>,
|
||||
* <i>C</i><sub>33</sub>.
|
||||
* In general the (\e n,\e m) element is at index \e m \e N − \e m
|
||||
* (\e m − 1)/2 + \e n. The layout of \e S is the same except that
|
||||
* the first column is omitted (since the \e m = 0 terms never contribute
|
||||
* to the sum) and the 0th element is <i>S</i><sub>11</sub>
|
||||
*
|
||||
* The class stores <i>pointers</i> to the first elements of \e C and \e S.
|
||||
* These arrays should not be altered or destroyed during the lifetime of a
|
||||
* SphericalHarmonic object.
|
||||
**********************************************************************/
|
||||
SphericalHarmonic(const std::vector<real>& C,
|
||||
const std::vector<real>& S,
|
||||
int N, real a, unsigned norm = FULL)
|
||||
: _a(a)
|
||||
, _norm(norm)
|
||||
{ _c[0] = SphericalEngine::coeff(C, S, N); }
|
||||
|
||||
/**
|
||||
* Constructor with a subset of coefficients specified.
|
||||
*
|
||||
* @param[in] C the coefficients <i>C</i><sub><i>nm</i></sub>.
|
||||
* @param[in] S the coefficients <i>S</i><sub><i>nm</i></sub>.
|
||||
* @param[in] N the degree used to determine the layout of \e C and \e S.
|
||||
* @param[in] nmx the maximum degree used in the sum. The sum over \e n is
|
||||
* from 0 thru \e nmx.
|
||||
* @param[in] mmx the maximum order used in the sum. The sum over \e m is
|
||||
* from 0 thru min(\e n, \e mmx).
|
||||
* @param[in] a the reference radius appearing in the definition of the
|
||||
* sum.
|
||||
* @param[in] norm the normalization for the associated Legendre
|
||||
* polynomials, either SphericalHarmonic::FULL (the default) or
|
||||
* SphericalHarmonic::SCHMIDT.
|
||||
* @exception GeographicErr if \e N, \e nmx, and \e mmx do not satisfy
|
||||
* \e N ≥ \e nmx ≥ \e mmx ≥ −1.
|
||||
* @exception GeographicErr if \e C or \e S is not big enough to hold the
|
||||
* coefficients.
|
||||
*
|
||||
* The class stores <i>pointers</i> to the first elements of \e C and \e S.
|
||||
* These arrays should not be altered or destroyed during the lifetime of a
|
||||
* SphericalHarmonic object.
|
||||
**********************************************************************/
|
||||
SphericalHarmonic(const std::vector<real>& C,
|
||||
const std::vector<real>& S,
|
||||
int N, int nmx, int mmx,
|
||||
real a, unsigned norm = FULL)
|
||||
: _a(a)
|
||||
, _norm(norm)
|
||||
{ _c[0] = SphericalEngine::coeff(C, S, N, nmx, mmx); }
|
||||
|
||||
/**
|
||||
* A default constructor so that the object can be created when the
|
||||
* constructor for another object is initialized. This default object can
|
||||
* then be reset with the default copy assignment operator.
|
||||
**********************************************************************/
|
||||
SphericalHarmonic() {}
|
||||
|
||||
/**
|
||||
* Compute the spherical harmonic sum.
|
||||
*
|
||||
* @param[in] x cartesian coordinate.
|
||||
* @param[in] y cartesian coordinate.
|
||||
* @param[in] z cartesian coordinate.
|
||||
* @return \e V the spherical harmonic sum.
|
||||
*
|
||||
* This routine requires constant memory and thus never throws an
|
||||
* exception.
|
||||
**********************************************************************/
|
||||
Math::real operator()(real x, real y, real z) const {
|
||||
real f[] = {1};
|
||||
real v = 0;
|
||||
real dummy;
|
||||
switch (_norm) {
|
||||
case FULL:
|
||||
v = SphericalEngine::Value<false, SphericalEngine::FULL, 1>
|
||||
(_c, f, x, y, z, _a, dummy, dummy, dummy);
|
||||
break;
|
||||
case SCHMIDT:
|
||||
default: // To avoid compiler warnings
|
||||
v = SphericalEngine::Value<false, SphericalEngine::SCHMIDT, 1>
|
||||
(_c, f, x, y, z, _a, dummy, dummy, dummy);
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a spherical harmonic sum and its gradient.
|
||||
*
|
||||
* @param[in] x cartesian coordinate.
|
||||
* @param[in] y cartesian coordinate.
|
||||
* @param[in] z cartesian coordinate.
|
||||
* @param[out] gradx \e x component of the gradient
|
||||
* @param[out] grady \e y component of the gradient
|
||||
* @param[out] gradz \e z component of the gradient
|
||||
* @return \e V the spherical harmonic sum.
|
||||
*
|
||||
* This is the same as the previous function, except that the components of
|
||||
* the gradients of the sum in the \e x, \e y, and \e z directions are
|
||||
* computed. This routine requires constant memory and thus never throws
|
||||
* an exception.
|
||||
**********************************************************************/
|
||||
Math::real operator()(real x, real y, real z,
|
||||
real& gradx, real& grady, real& gradz) const {
|
||||
real f[] = {1};
|
||||
real v = 0;
|
||||
switch (_norm) {
|
||||
case FULL:
|
||||
v = SphericalEngine::Value<true, SphericalEngine::FULL, 1>
|
||||
(_c, f, x, y, z, _a, gradx, grady, gradz);
|
||||
break;
|
||||
case SCHMIDT:
|
||||
default: // To avoid compiler warnings
|
||||
v = SphericalEngine::Value<true, SphericalEngine::SCHMIDT, 1>
|
||||
(_c, f, x, y, z, _a, gradx, grady, gradz);
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a CircularEngine to allow the efficient evaluation of several
|
||||
* points on a circle of latitude.
|
||||
*
|
||||
* @param[in] p the radius of the circle.
|
||||
* @param[in] z the height of the circle above the equatorial plane.
|
||||
* @param[in] gradp if true the returned object will be able to compute the
|
||||
* gradient of the sum.
|
||||
* @exception std::bad_alloc if the memory for the CircularEngine can't be
|
||||
* allocated.
|
||||
* @return the CircularEngine object.
|
||||
*
|
||||
* SphericalHarmonic::operator()() exchanges the order of the sums in the
|
||||
* definition, i.e., ∑<sub><i>n</i> = 0..<i>N</i></sub>
|
||||
* ∑<sub><i>m</i> = 0..<i>n</i></sub> becomes ∑<sub><i>m</i> =
|
||||
* 0..<i>N</i></sub> ∑<sub><i>n</i> = <i>m</i>..<i>N</i></sub>.
|
||||
* SphericalHarmonic::Circle performs the inner sum over degree \e n (which
|
||||
* entails about <i>N</i><sup>2</sup> operations). Calling
|
||||
* CircularEngine::operator()() on the returned object performs the outer
|
||||
* sum over the order \e m (about \e N operations).
|
||||
*
|
||||
* Here's an example of computing the spherical sum at a sequence of
|
||||
* longitudes without using a CircularEngine object \code
|
||||
SphericalHarmonic h(...); // Create the SphericalHarmonic object
|
||||
double r = 2, lat = 33, lon0 = 44, dlon = 0.01;
|
||||
double
|
||||
phi = lat * Math::degree<double>(),
|
||||
z = r * sin(phi), p = r * cos(phi);
|
||||
for (int i = 0; i <= 100; ++i) {
|
||||
real
|
||||
lon = lon0 + i * dlon,
|
||||
lam = lon * Math::degree<double>();
|
||||
std::cout << lon << " " << h(p * cos(lam), p * sin(lam), z) << "\n";
|
||||
}
|
||||
\endcode
|
||||
* Here is the same calculation done using a CircularEngine object. This
|
||||
* will be about <i>N</i>/2 times faster. \code
|
||||
SphericalHarmonic h(...); // Create the SphericalHarmonic object
|
||||
double r = 2, lat = 33, lon0 = 44, dlon = 0.01;
|
||||
double
|
||||
phi = lat * Math::degree<double>(),
|
||||
z = r * sin(phi), p = r * cos(phi);
|
||||
CircularEngine c(h(p, z, false)); // Create the CircularEngine object
|
||||
for (int i = 0; i <= 100; ++i) {
|
||||
real
|
||||
lon = lon0 + i * dlon;
|
||||
std::cout << lon << " " << c(lon) << "\n";
|
||||
}
|
||||
\endcode
|
||||
**********************************************************************/
|
||||
CircularEngine Circle(real p, real z, bool gradp) const {
|
||||
real f[] = {1};
|
||||
switch (_norm) {
|
||||
case FULL:
|
||||
return gradp ?
|
||||
SphericalEngine::Circle<true, SphericalEngine::FULL, 1>
|
||||
(_c, f, p, z, _a) :
|
||||
SphericalEngine::Circle<false, SphericalEngine::FULL, 1>
|
||||
(_c, f, p, z, _a);
|
||||
break;
|
||||
case SCHMIDT:
|
||||
default: // To avoid compiler warnings
|
||||
return gradp ?
|
||||
SphericalEngine::Circle<true, SphericalEngine::SCHMIDT, 1>
|
||||
(_c, f, p, z, _a) :
|
||||
SphericalEngine::Circle<false, SphericalEngine::SCHMIDT, 1>
|
||||
(_c, f, p, z, _a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the zeroth SphericalEngine::coeff object.
|
||||
**********************************************************************/
|
||||
const SphericalEngine::coeff& Coefficients() const
|
||||
{ return _c[0]; }
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_SPHERICALHARMONIC_HPP
|
||||
283
external/include/GeographicLib/SphericalHarmonic1.hpp
vendored
Normal file
283
external/include/GeographicLib/SphericalHarmonic1.hpp
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
/**
|
||||
* \file SphericalHarmonic1.hpp
|
||||
* \brief Header for GeographicLib::SphericalHarmonic1 class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2011) <charles@karney.com> and licensed under
|
||||
* the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_SPHERICALHARMONIC1_HPP)
|
||||
#define GEOGRAPHICLIB_SPHERICALHARMONIC1_HPP 1
|
||||
|
||||
#include <vector>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/SphericalEngine.hpp>
|
||||
#include <GeographicLib/CircularEngine.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Spherical harmonic series with a correction to the coefficients
|
||||
*
|
||||
* This classes is similar to SphericalHarmonic, except that the coefficients
|
||||
* <i>C</i><sub><i>nm</i></sub> are replaced by
|
||||
* <i>C</i><sub><i>nm</i></sub> + \e tau <i>C'</i><sub><i>nm</i></sub> (and
|
||||
* similarly for <i>S</i><sub><i>nm</i></sub>).
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-SphericalHarmonic1.cpp
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT SphericalHarmonic1 {
|
||||
public:
|
||||
/**
|
||||
* Supported normalizations for associate Legendre polynomials.
|
||||
**********************************************************************/
|
||||
enum normalization {
|
||||
/**
|
||||
* Fully normalized associated Legendre polynomials. See
|
||||
* SphericalHarmonic::FULL for documentation.
|
||||
*
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
FULL = SphericalEngine::FULL,
|
||||
/**
|
||||
* Schmidt semi-normalized associated Legendre polynomials. See
|
||||
* SphericalHarmonic::SCHMIDT for documentation.
|
||||
*
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
SCHMIDT = SphericalEngine::SCHMIDT,
|
||||
};
|
||||
|
||||
private:
|
||||
typedef Math::real real;
|
||||
SphericalEngine::coeff _c[2];
|
||||
real _a;
|
||||
unsigned _norm;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor with a full set of coefficients specified.
|
||||
*
|
||||
* @param[in] C the coefficients <i>C</i><sub><i>nm</i></sub>.
|
||||
* @param[in] S the coefficients <i>S</i><sub><i>nm</i></sub>.
|
||||
* @param[in] N the maximum degree and order of the sum
|
||||
* @param[in] C1 the coefficients <i>C'</i><sub><i>nm</i></sub>.
|
||||
* @param[in] S1 the coefficients <i>S'</i><sub><i>nm</i></sub>.
|
||||
* @param[in] N1 the maximum degree and order of the correction
|
||||
* coefficients <i>C'</i><sub><i>nm</i></sub> and
|
||||
* <i>S'</i><sub><i>nm</i></sub>.
|
||||
* @param[in] a the reference radius appearing in the definition of the
|
||||
* sum.
|
||||
* @param[in] norm the normalization for the associated Legendre
|
||||
* polynomials, either SphericalHarmonic1::FULL (the default) or
|
||||
* SphericalHarmonic1::SCHMIDT.
|
||||
* @exception GeographicErr if \e N and \e N1 do not satisfy \e N ≥
|
||||
* \e N1 ≥ −1.
|
||||
* @exception GeographicErr if any of the vectors of coefficients is not
|
||||
* large enough.
|
||||
*
|
||||
* See SphericalHarmonic for the way the coefficients should be stored.
|
||||
*
|
||||
* The class stores <i>pointers</i> to the first elements of \e C, \e S, \e
|
||||
* C', and \e S'. These arrays should not be altered or destroyed during
|
||||
* the lifetime of a SphericalHarmonic object.
|
||||
**********************************************************************/
|
||||
SphericalHarmonic1(const std::vector<real>& C,
|
||||
const std::vector<real>& S,
|
||||
int N,
|
||||
const std::vector<real>& C1,
|
||||
const std::vector<real>& S1,
|
||||
int N1,
|
||||
real a, unsigned norm = FULL)
|
||||
: _a(a)
|
||||
, _norm(norm) {
|
||||
if (!(N1 <= N))
|
||||
throw GeographicErr("N1 cannot be larger that N");
|
||||
_c[0] = SphericalEngine::coeff(C, S, N);
|
||||
_c[1] = SphericalEngine::coeff(C1, S1, N1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with a subset of coefficients specified.
|
||||
*
|
||||
* @param[in] C the coefficients <i>C</i><sub><i>nm</i></sub>.
|
||||
* @param[in] S the coefficients <i>S</i><sub><i>nm</i></sub>.
|
||||
* @param[in] N the degree used to determine the layout of \e C and \e S.
|
||||
* @param[in] nmx the maximum degree used in the sum. The sum over \e n is
|
||||
* from 0 thru \e nmx.
|
||||
* @param[in] mmx the maximum order used in the sum. The sum over \e m is
|
||||
* from 0 thru min(\e n, \e mmx).
|
||||
* @param[in] C1 the coefficients <i>C'</i><sub><i>nm</i></sub>.
|
||||
* @param[in] S1 the coefficients <i>S'</i><sub><i>nm</i></sub>.
|
||||
* @param[in] N1 the degree used to determine the layout of \e C' and \e
|
||||
* S'.
|
||||
* @param[in] nmx1 the maximum degree used for \e C' and \e S'.
|
||||
* @param[in] mmx1 the maximum order used for \e C' and \e S'.
|
||||
* @param[in] a the reference radius appearing in the definition of the
|
||||
* sum.
|
||||
* @param[in] norm the normalization for the associated Legendre
|
||||
* polynomials, either SphericalHarmonic1::FULL (the default) or
|
||||
* SphericalHarmonic1::SCHMIDT.
|
||||
* @exception GeographicErr if the parameters do not satisfy \e N ≥ \e
|
||||
* nmx ≥ \e mmx ≥ −1; \e N1 ≥ \e nmx1 ≥ \e mmx1 ≥
|
||||
* −1; \e N ≥ \e N1; \e nmx ≥ \e nmx1; \e mmx ≥ \e mmx1.
|
||||
* @exception GeographicErr if any of the vectors of coefficients is not
|
||||
* large enough.
|
||||
*
|
||||
* The class stores <i>pointers</i> to the first elements of \e C, \e S, \e
|
||||
* C', and \e S'. These arrays should not be altered or destroyed during
|
||||
* the lifetime of a SphericalHarmonic object.
|
||||
**********************************************************************/
|
||||
SphericalHarmonic1(const std::vector<real>& C,
|
||||
const std::vector<real>& S,
|
||||
int N, int nmx, int mmx,
|
||||
const std::vector<real>& C1,
|
||||
const std::vector<real>& S1,
|
||||
int N1, int nmx1, int mmx1,
|
||||
real a, unsigned norm = FULL)
|
||||
: _a(a)
|
||||
, _norm(norm) {
|
||||
if (!(nmx1 <= nmx))
|
||||
throw GeographicErr("nmx1 cannot be larger that nmx");
|
||||
if (!(mmx1 <= mmx))
|
||||
throw GeographicErr("mmx1 cannot be larger that mmx");
|
||||
_c[0] = SphericalEngine::coeff(C, S, N, nmx, mmx);
|
||||
_c[1] = SphericalEngine::coeff(C1, S1, N1, nmx1, mmx1);
|
||||
}
|
||||
|
||||
/**
|
||||
* A default constructor so that the object can be created when the
|
||||
* constructor for another object is initialized. This default object can
|
||||
* then be reset with the default copy assignment operator.
|
||||
**********************************************************************/
|
||||
SphericalHarmonic1() {}
|
||||
|
||||
/**
|
||||
* Compute a spherical harmonic sum with a correction term.
|
||||
*
|
||||
* @param[in] tau multiplier for correction coefficients \e C' and \e S'.
|
||||
* @param[in] x cartesian coordinate.
|
||||
* @param[in] y cartesian coordinate.
|
||||
* @param[in] z cartesian coordinate.
|
||||
* @return \e V the spherical harmonic sum.
|
||||
*
|
||||
* This routine requires constant memory and thus never throws
|
||||
* an exception.
|
||||
**********************************************************************/
|
||||
Math::real operator()(real tau, real x, real y, real z) const {
|
||||
real f[] = {1, tau};
|
||||
real v = 0;
|
||||
real dummy;
|
||||
switch (_norm) {
|
||||
case FULL:
|
||||
v = SphericalEngine::Value<false, SphericalEngine::FULL, 2>
|
||||
(_c, f, x, y, z, _a, dummy, dummy, dummy);
|
||||
break;
|
||||
case SCHMIDT:
|
||||
default: // To avoid compiler warnings
|
||||
v = SphericalEngine::Value<false, SphericalEngine::SCHMIDT, 2>
|
||||
(_c, f, x, y, z, _a, dummy, dummy, dummy);
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a spherical harmonic sum with a correction term and its
|
||||
* gradient.
|
||||
*
|
||||
* @param[in] tau multiplier for correction coefficients \e C' and \e S'.
|
||||
* @param[in] x cartesian coordinate.
|
||||
* @param[in] y cartesian coordinate.
|
||||
* @param[in] z cartesian coordinate.
|
||||
* @param[out] gradx \e x component of the gradient
|
||||
* @param[out] grady \e y component of the gradient
|
||||
* @param[out] gradz \e z component of the gradient
|
||||
* @return \e V the spherical harmonic sum.
|
||||
*
|
||||
* This is the same as the previous function, except that the components of
|
||||
* the gradients of the sum in the \e x, \e y, and \e z directions are
|
||||
* computed. This routine requires constant memory and thus never throws
|
||||
* an exception.
|
||||
**********************************************************************/
|
||||
Math::real operator()(real tau, real x, real y, real z,
|
||||
real& gradx, real& grady, real& gradz) const {
|
||||
real f[] = {1, tau};
|
||||
real v = 0;
|
||||
switch (_norm) {
|
||||
case FULL:
|
||||
v = SphericalEngine::Value<true, SphericalEngine::FULL, 2>
|
||||
(_c, f, x, y, z, _a, gradx, grady, gradz);
|
||||
break;
|
||||
case SCHMIDT:
|
||||
default: // To avoid compiler warnings
|
||||
v = SphericalEngine::Value<true, SphericalEngine::SCHMIDT, 2>
|
||||
(_c, f, x, y, z, _a, gradx, grady, gradz);
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a CircularEngine to allow the efficient evaluation of several
|
||||
* points on a circle of latitude at a fixed value of \e tau.
|
||||
*
|
||||
* @param[in] tau the multiplier for the correction coefficients.
|
||||
* @param[in] p the radius of the circle.
|
||||
* @param[in] z the height of the circle above the equatorial plane.
|
||||
* @param[in] gradp if true the returned object will be able to compute the
|
||||
* gradient of the sum.
|
||||
* @exception std::bad_alloc if the memory for the CircularEngine can't be
|
||||
* allocated.
|
||||
* @return the CircularEngine object.
|
||||
*
|
||||
* SphericalHarmonic1::operator()() exchanges the order of the sums in the
|
||||
* definition, i.e., ∑<sub><i>n</i> = 0..<i>N</i></sub>
|
||||
* ∑<sub><i>m</i> = 0..<i>n</i></sub> becomes ∑<sub><i>m</i> =
|
||||
* 0..<i>N</i></sub> ∑<sub><i>n</i> = <i>m</i>..<i>N</i></sub>.
|
||||
* SphericalHarmonic1::Circle performs the inner sum over degree \e n
|
||||
* (which entails about <i>N</i><sup>2</sup> operations). Calling
|
||||
* CircularEngine::operator()() on the returned object performs the outer
|
||||
* sum over the order \e m (about \e N operations).
|
||||
*
|
||||
* See SphericalHarmonic::Circle for an example of its use.
|
||||
**********************************************************************/
|
||||
CircularEngine Circle(real tau, real p, real z, bool gradp) const {
|
||||
real f[] = {1, tau};
|
||||
switch (_norm) {
|
||||
case FULL:
|
||||
return gradp ?
|
||||
SphericalEngine::Circle<true, SphericalEngine::FULL, 2>
|
||||
(_c, f, p, z, _a) :
|
||||
SphericalEngine::Circle<false, SphericalEngine::FULL, 2>
|
||||
(_c, f, p, z, _a);
|
||||
break;
|
||||
case SCHMIDT:
|
||||
default: // To avoid compiler warnings
|
||||
return gradp ?
|
||||
SphericalEngine::Circle<true, SphericalEngine::SCHMIDT, 2>
|
||||
(_c, f, p, z, _a) :
|
||||
SphericalEngine::Circle<false, SphericalEngine::SCHMIDT, 2>
|
||||
(_c, f, p, z, _a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the zeroth SphericalEngine::coeff object.
|
||||
**********************************************************************/
|
||||
const SphericalEngine::coeff& Coefficients() const
|
||||
{ return _c[0]; }
|
||||
/**
|
||||
* @return the first SphericalEngine::coeff object.
|
||||
**********************************************************************/
|
||||
const SphericalEngine::coeff& Coefficients1() const
|
||||
{ return _c[1]; }
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_SPHERICALHARMONIC1_HPP
|
||||
320
external/include/GeographicLib/SphericalHarmonic2.hpp
vendored
Normal file
320
external/include/GeographicLib/SphericalHarmonic2.hpp
vendored
Normal file
@@ -0,0 +1,320 @@
|
||||
/**
|
||||
* \file SphericalHarmonic2.hpp
|
||||
* \brief Header for GeographicLib::SphericalHarmonic2 class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2011-2012) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_SPHERICALHARMONIC2_HPP)
|
||||
#define GEOGRAPHICLIB_SPHERICALHARMONIC2_HPP 1
|
||||
|
||||
#include <vector>
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/SphericalEngine.hpp>
|
||||
#include <GeographicLib/CircularEngine.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Spherical harmonic series with two corrections to the coefficients
|
||||
*
|
||||
* This classes is similar to SphericalHarmonic, except that the coefficients
|
||||
* <i>C</i><sub><i>nm</i></sub> are replaced by
|
||||
* <i>C</i><sub><i>nm</i></sub> + \e tau' <i>C'</i><sub><i>nm</i></sub> + \e
|
||||
* tau'' <i>C''</i><sub><i>nm</i></sub> (and similarly for
|
||||
* <i>S</i><sub><i>nm</i></sub>).
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-SphericalHarmonic2.cpp
|
||||
**********************************************************************/
|
||||
|
||||
// Don't include the GEOGRPAHIC_EXPORT because this header-only class isn't
|
||||
// used by any other classes in the library.
|
||||
class /*GEOGRAPHICLIB_EXPORT*/ SphericalHarmonic2 {
|
||||
public:
|
||||
/**
|
||||
* Supported normalizations for associate Legendre polynomials.
|
||||
**********************************************************************/
|
||||
enum normalization {
|
||||
/**
|
||||
* Fully normalized associated Legendre polynomials. See
|
||||
* SphericalHarmonic::FULL for documentation.
|
||||
*
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
FULL = SphericalEngine::FULL,
|
||||
/**
|
||||
* Schmidt semi-normalized associated Legendre polynomials. See
|
||||
* SphericalHarmonic::SCHMIDT for documentation.
|
||||
*
|
||||
* @hideinitializer
|
||||
**********************************************************************/
|
||||
SCHMIDT = SphericalEngine::SCHMIDT,
|
||||
};
|
||||
|
||||
private:
|
||||
typedef Math::real real;
|
||||
SphericalEngine::coeff _c[3];
|
||||
real _a;
|
||||
unsigned _norm;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor with a full set of coefficients specified.
|
||||
*
|
||||
* @param[in] C the coefficients <i>C</i><sub><i>nm</i></sub>.
|
||||
* @param[in] S the coefficients <i>S</i><sub><i>nm</i></sub>.
|
||||
* @param[in] N the maximum degree and order of the sum
|
||||
* @param[in] C1 the coefficients <i>C'</i><sub><i>nm</i></sub>.
|
||||
* @param[in] S1 the coefficients <i>S'</i><sub><i>nm</i></sub>.
|
||||
* @param[in] N1 the maximum degree and order of the first correction
|
||||
* coefficients <i>C'</i><sub><i>nm</i></sub> and
|
||||
* <i>S'</i><sub><i>nm</i></sub>.
|
||||
* @param[in] C2 the coefficients <i>C''</i><sub><i>nm</i></sub>.
|
||||
* @param[in] S2 the coefficients <i>S''</i><sub><i>nm</i></sub>.
|
||||
* @param[in] N2 the maximum degree and order of the second correction
|
||||
* coefficients <i>C'</i><sub><i>nm</i></sub> and
|
||||
* <i>S'</i><sub><i>nm</i></sub>.
|
||||
* @param[in] a the reference radius appearing in the definition of the
|
||||
* sum.
|
||||
* @param[in] norm the normalization for the associated Legendre
|
||||
* polynomials, either SphericalHarmonic2::FULL (the default) or
|
||||
* SphericalHarmonic2::SCHMIDT.
|
||||
* @exception GeographicErr if \e N and \e N1 do not satisfy \e N ≥
|
||||
* \e N1 ≥ −1, and similarly for \e N2.
|
||||
* @exception GeographicErr if any of the vectors of coefficients is not
|
||||
* large enough.
|
||||
*
|
||||
* See SphericalHarmonic for the way the coefficients should be stored. \e
|
||||
* N1 and \e N2 should satisfy \e N1 ≤ \e N and \e N2 ≤ \e N.
|
||||
*
|
||||
* The class stores <i>pointers</i> to the first elements of \e C, \e S, \e
|
||||
* C', \e S', \e C'', and \e S''. These arrays should not be altered or
|
||||
* destroyed during the lifetime of a SphericalHarmonic object.
|
||||
**********************************************************************/
|
||||
SphericalHarmonic2(const std::vector<real>& C,
|
||||
const std::vector<real>& S,
|
||||
int N,
|
||||
const std::vector<real>& C1,
|
||||
const std::vector<real>& S1,
|
||||
int N1,
|
||||
const std::vector<real>& C2,
|
||||
const std::vector<real>& S2,
|
||||
int N2,
|
||||
real a, unsigned norm = FULL)
|
||||
: _a(a)
|
||||
, _norm(norm) {
|
||||
if (!(N1 <= N && N2 <= N))
|
||||
throw GeographicErr("N1 and N2 cannot be larger that N");
|
||||
_c[0] = SphericalEngine::coeff(C, S, N);
|
||||
_c[1] = SphericalEngine::coeff(C1, S1, N1);
|
||||
_c[2] = SphericalEngine::coeff(C2, S2, N2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with a subset of coefficients specified.
|
||||
*
|
||||
* @param[in] C the coefficients <i>C</i><sub><i>nm</i></sub>.
|
||||
* @param[in] S the coefficients <i>S</i><sub><i>nm</i></sub>.
|
||||
* @param[in] N the degree used to determine the layout of \e C and \e S.
|
||||
* @param[in] nmx the maximum degree used in the sum. The sum over \e n is
|
||||
* from 0 thru \e nmx.
|
||||
* @param[in] mmx the maximum order used in the sum. The sum over \e m is
|
||||
* from 0 thru min(\e n, \e mmx).
|
||||
* @param[in] C1 the coefficients <i>C'</i><sub><i>nm</i></sub>.
|
||||
* @param[in] S1 the coefficients <i>S'</i><sub><i>nm</i></sub>.
|
||||
* @param[in] N1 the degree used to determine the layout of \e C' and \e
|
||||
* S'.
|
||||
* @param[in] nmx1 the maximum degree used for \e C' and \e S'.
|
||||
* @param[in] mmx1 the maximum order used for \e C' and \e S'.
|
||||
* @param[in] C2 the coefficients <i>C''</i><sub><i>nm</i></sub>.
|
||||
* @param[in] S2 the coefficients <i>S''</i><sub><i>nm</i></sub>.
|
||||
* @param[in] N2 the degree used to determine the layout of \e C'' and \e
|
||||
* S''.
|
||||
* @param[in] nmx2 the maximum degree used for \e C'' and \e S''.
|
||||
* @param[in] mmx2 the maximum order used for \e C'' and \e S''.
|
||||
* @param[in] a the reference radius appearing in the definition of the
|
||||
* sum.
|
||||
* @param[in] norm the normalization for the associated Legendre
|
||||
* polynomials, either SphericalHarmonic2::FULL (the default) or
|
||||
* SphericalHarmonic2::SCHMIDT.
|
||||
* @exception GeographicErr if the parameters do not satisfy \e N ≥ \e
|
||||
* nmx ≥ \e mmx ≥ −1; \e N1 ≥ \e nmx1 ≥ \e mmx1 ≥
|
||||
* −1; \e N ≥ \e N1; \e nmx ≥ \e nmx1; \e mmx ≥ \e mmx1;
|
||||
* and similarly for \e N2, \e nmx2, and \e mmx2.
|
||||
* @exception GeographicErr if any of the vectors of coefficients is not
|
||||
* large enough.
|
||||
*
|
||||
* The class stores <i>pointers</i> to the first elements of \e C, \e S, \e
|
||||
* C', \e S', \e C'', and \e S''. These arrays should not be altered or
|
||||
* destroyed during the lifetime of a SphericalHarmonic object.
|
||||
**********************************************************************/
|
||||
SphericalHarmonic2(const std::vector<real>& C,
|
||||
const std::vector<real>& S,
|
||||
int N, int nmx, int mmx,
|
||||
const std::vector<real>& C1,
|
||||
const std::vector<real>& S1,
|
||||
int N1, int nmx1, int mmx1,
|
||||
const std::vector<real>& C2,
|
||||
const std::vector<real>& S2,
|
||||
int N2, int nmx2, int mmx2,
|
||||
real a, unsigned norm = FULL)
|
||||
: _a(a)
|
||||
, _norm(norm) {
|
||||
if (!(nmx1 <= nmx && nmx2 <= nmx))
|
||||
throw GeographicErr("nmx1 and nmx2 cannot be larger that nmx");
|
||||
if (!(mmx1 <= mmx && mmx2 <= mmx))
|
||||
throw GeographicErr("mmx1 and mmx2 cannot be larger that mmx");
|
||||
_c[0] = SphericalEngine::coeff(C, S, N, nmx, mmx);
|
||||
_c[1] = SphericalEngine::coeff(C1, S1, N1, nmx1, mmx1);
|
||||
_c[2] = SphericalEngine::coeff(C2, S2, N2, nmx2, mmx2);
|
||||
}
|
||||
|
||||
/**
|
||||
* A default constructor so that the object can be created when the
|
||||
* constructor for another object is initialized. This default object can
|
||||
* then be reset with the default copy assignment operator.
|
||||
**********************************************************************/
|
||||
SphericalHarmonic2() {}
|
||||
|
||||
/**
|
||||
* Compute a spherical harmonic sum with two correction terms.
|
||||
*
|
||||
* @param[in] tau1 multiplier for correction coefficients \e C' and \e S'.
|
||||
* @param[in] tau2 multiplier for correction coefficients \e C'' and \e
|
||||
* S''.
|
||||
* @param[in] x cartesian coordinate.
|
||||
* @param[in] y cartesian coordinate.
|
||||
* @param[in] z cartesian coordinate.
|
||||
* @return \e V the spherical harmonic sum.
|
||||
*
|
||||
* This routine requires constant memory and thus never throws an
|
||||
* exception.
|
||||
**********************************************************************/
|
||||
Math::real operator()(real tau1, real tau2, real x, real y, real z)
|
||||
const {
|
||||
real f[] = {1, tau1, tau2};
|
||||
real v = 0;
|
||||
real dummy;
|
||||
switch (_norm) {
|
||||
case FULL:
|
||||
v = SphericalEngine::Value<false, SphericalEngine::FULL, 3>
|
||||
(_c, f, x, y, z, _a, dummy, dummy, dummy);
|
||||
break;
|
||||
case SCHMIDT:
|
||||
default: // To avoid compiler warnings
|
||||
v = SphericalEngine::Value<false, SphericalEngine::SCHMIDT, 3>
|
||||
(_c, f, x, y, z, _a, dummy, dummy, dummy);
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a spherical harmonic sum with two correction terms and its
|
||||
* gradient.
|
||||
*
|
||||
* @param[in] tau1 multiplier for correction coefficients \e C' and \e S'.
|
||||
* @param[in] tau2 multiplier for correction coefficients \e C'' and \e
|
||||
* S''.
|
||||
* @param[in] x cartesian coordinate.
|
||||
* @param[in] y cartesian coordinate.
|
||||
* @param[in] z cartesian coordinate.
|
||||
* @param[out] gradx \e x component of the gradient
|
||||
* @param[out] grady \e y component of the gradient
|
||||
* @param[out] gradz \e z component of the gradient
|
||||
* @return \e V the spherical harmonic sum.
|
||||
*
|
||||
* This is the same as the previous function, except that the components of
|
||||
* the gradients of the sum in the \e x, \e y, and \e z directions are
|
||||
* computed. This routine requires constant memory and thus never throws
|
||||
* an exception.
|
||||
**********************************************************************/
|
||||
Math::real operator()(real tau1, real tau2, real x, real y, real z,
|
||||
real& gradx, real& grady, real& gradz) const {
|
||||
real f[] = {1, tau1, tau2};
|
||||
real v = 0;
|
||||
switch (_norm) {
|
||||
case FULL:
|
||||
v = SphericalEngine::Value<true, SphericalEngine::FULL, 3>
|
||||
(_c, f, x, y, z, _a, gradx, grady, gradz);
|
||||
break;
|
||||
case SCHMIDT:
|
||||
default: // To avoid compiler warnings
|
||||
v = SphericalEngine::Value<true, SphericalEngine::SCHMIDT, 3>
|
||||
(_c, f, x, y, z, _a, gradx, grady, gradz);
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a CircularEngine to allow the efficient evaluation of several
|
||||
* points on a circle of latitude at fixed values of \e tau1 and \e tau2.
|
||||
*
|
||||
* @param[in] tau1 multiplier for correction coefficients \e C' and \e S'.
|
||||
* @param[in] tau2 multiplier for correction coefficients \e C'' and \e
|
||||
* S''.
|
||||
* @param[in] p the radius of the circle.
|
||||
* @param[in] z the height of the circle above the equatorial plane.
|
||||
* @param[in] gradp if true the returned object will be able to compute the
|
||||
* gradient of the sum.
|
||||
* @exception std::bad_alloc if the memory for the CircularEngine can't be
|
||||
* allocated.
|
||||
* @return the CircularEngine object.
|
||||
*
|
||||
* SphericalHarmonic2::operator()() exchanges the order of the sums in the
|
||||
* definition, i.e., ∑<sub><i>n</i> = 0..<i>N</i></sub>
|
||||
* ∑<sub><i>m</i> = 0..<i>n</i></sub> becomes ∑<sub><i>m</i> =
|
||||
* 0..<i>N</i></sub> ∑<sub><i>n</i> = <i>m</i>..<i>N</i></sub>..
|
||||
* SphericalHarmonic2::Circle performs the inner sum over degree \e n
|
||||
* (which entails about <i>N</i><sup>2</sup> operations). Calling
|
||||
* CircularEngine::operator()() on the returned object performs the outer
|
||||
* sum over the order \e m (about \e N operations).
|
||||
*
|
||||
* See SphericalHarmonic::Circle for an example of its use.
|
||||
**********************************************************************/
|
||||
CircularEngine Circle(real tau1, real tau2, real p, real z, bool gradp)
|
||||
const {
|
||||
real f[] = {1, tau1, tau2};
|
||||
switch (_norm) {
|
||||
case FULL:
|
||||
return gradp ?
|
||||
SphericalEngine::Circle<true, SphericalEngine::FULL, 3>
|
||||
(_c, f, p, z, _a) :
|
||||
SphericalEngine::Circle<false, SphericalEngine::FULL, 3>
|
||||
(_c, f, p, z, _a);
|
||||
break;
|
||||
case SCHMIDT:
|
||||
default: // To avoid compiler warnings
|
||||
return gradp ?
|
||||
SphericalEngine::Circle<true, SphericalEngine::SCHMIDT, 3>
|
||||
(_c, f, p, z, _a) :
|
||||
SphericalEngine::Circle<false, SphericalEngine::SCHMIDT, 3>
|
||||
(_c, f, p, z, _a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the zeroth SphericalEngine::coeff object.
|
||||
**********************************************************************/
|
||||
const SphericalEngine::coeff& Coefficients() const
|
||||
{ return _c[0]; }
|
||||
/**
|
||||
* @return the first SphericalEngine::coeff object.
|
||||
**********************************************************************/
|
||||
const SphericalEngine::coeff& Coefficients1() const
|
||||
{ return _c[1]; }
|
||||
/**
|
||||
* @return the second SphericalEngine::coeff object.
|
||||
**********************************************************************/
|
||||
const SphericalEngine::coeff& Coefficients2() const
|
||||
{ return _c[2]; }
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_SPHERICALHARMONIC2_HPP
|
||||
206
external/include/GeographicLib/TransverseMercator.hpp
vendored
Normal file
206
external/include/GeographicLib/TransverseMercator.hpp
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* \file TransverseMercator.hpp
|
||||
* \brief Header for GeographicLib::TransverseMercator class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_TRANSVERSEMERCATOR_HPP)
|
||||
#define GEOGRAPHICLIB_TRANSVERSEMERCATOR_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER)
|
||||
/**
|
||||
* The order of the series approximation used in TransverseMercator.
|
||||
* GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER can be set to any integer in [4, 8].
|
||||
**********************************************************************/
|
||||
# define GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER \
|
||||
(GEOGRAPHICLIB_PRECISION == 2 ? 6 : \
|
||||
(GEOGRAPHICLIB_PRECISION == 1 ? 4 : 8))
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Transverse Mercator projection
|
||||
*
|
||||
* This uses Krüger's method which evaluates the projection and its
|
||||
* inverse in terms of a series. See
|
||||
* - L. Krüger,
|
||||
* <a href="https://doi.org/10.2312/GFZ.b103-krueger28"> Konforme
|
||||
* Abbildung des Erdellipsoids in der Ebene</a> (Conformal mapping of the
|
||||
* ellipsoidal earth to the plane), Royal Prussian Geodetic Institute, New
|
||||
* Series 52, 172 pp. (1912).
|
||||
* - C. F. F. Karney,
|
||||
* <a href="https://doi.org/10.1007/s00190-011-0445-3">
|
||||
* Transverse Mercator with an accuracy of a few nanometers,</a>
|
||||
* J. Geodesy 85(8), 475--485 (Aug. 2011);
|
||||
* preprint
|
||||
* <a href="https://arxiv.org/abs/1002.1417">arXiv:1002.1417</a>.
|
||||
*
|
||||
* Krüger's method has been extended from 4th to 6th order. The maximum
|
||||
* error is 5 nm (5 nanometers), ground distance, for all positions within 35
|
||||
* degrees of the central meridian. The error in the convergence is 2
|
||||
* × 10<sup>−15</sup>" and the relative error in the scale
|
||||
* is 6 × 10<sup>−12</sup>%%. See Sec. 4 of
|
||||
* <a href="https://arxiv.org/abs/1002.1417">arXiv:1002.1417</a> for details.
|
||||
* The speed penalty in going to 6th order is only about 1%.
|
||||
*
|
||||
* There's a singularity in the projection at φ = 0°, λ
|
||||
* − λ<sub>0</sub> = ±(1 − \e e)90° (≈
|
||||
* ±82.6° for the WGS84 ellipsoid), where \e e is the
|
||||
* eccentricity. Beyond this point, the series ceases to converge and the
|
||||
* results from this method will be garbage. To be on the safe side, don't
|
||||
* use this method if the angular distance from the central meridian exceeds
|
||||
* (1 − 2e)90° (≈ 75° for the WGS84 ellipsoid)
|
||||
*
|
||||
* TransverseMercatorExact is an alternative implementation of the projection
|
||||
* using exact formulas which yield accurate (to 8 nm) results over the
|
||||
* entire ellipsoid.
|
||||
*
|
||||
* The ellipsoid parameters and the central scale are set in the constructor.
|
||||
* The central meridian (which is a trivial shift of the longitude) is
|
||||
* specified as the \e lon0 argument of the TransverseMercator::Forward and
|
||||
* TransverseMercator::Reverse functions. The latitude of origin is taken to
|
||||
* be the equator. There is no provision in this class for specifying a
|
||||
* false easting or false northing or a different latitude of origin.
|
||||
* However these are can be simply included by the calling function. For
|
||||
* example, the UTMUPS class applies the false easting and false northing for
|
||||
* the UTM projections. A more complicated example is the British National
|
||||
* Grid (<a href="https://www.spatialreference.org/ref/epsg/7405/">
|
||||
* EPSG:7405</a>) which requires the use of a latitude of origin. This is
|
||||
* implemented by the GeographicLib::OSGB class.
|
||||
*
|
||||
* This class also returns the meridian convergence \e gamma and scale \e k.
|
||||
* The meridian convergence is the bearing of grid north (the \e y axis)
|
||||
* measured clockwise from true north.
|
||||
*
|
||||
* See TransverseMercator.cpp for more information on the implementation.
|
||||
*
|
||||
* See \ref transversemercator for a discussion of this projection.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-TransverseMercator.cpp
|
||||
*
|
||||
* <a href="TransverseMercatorProj.1.html">TransverseMercatorProj</a> is a
|
||||
* command-line utility providing access to the functionality of
|
||||
* TransverseMercator and TransverseMercatorExact.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT TransverseMercator {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
static const int maxpow_ = GEOGRAPHICLIB_TRANSVERSEMERCATOR_ORDER;
|
||||
static const int numit_ = 5;
|
||||
real _a, _f, _k0, _e2, _es, _e2m, _c, _n;
|
||||
// _alp[0] and _bet[0] unused
|
||||
real _a1, _b1, _alp[maxpow_ + 1], _bet[maxpow_ + 1];
|
||||
friend class Ellipsoid; // For access to taupf, tauf.
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for a ellipsoid with
|
||||
*
|
||||
* @param[in] a equatorial radius (meters).
|
||||
* @param[in] f flattening of ellipsoid. Setting \e f = 0 gives a sphere.
|
||||
* Negative \e f gives a prolate ellipsoid.
|
||||
* @param[in] k0 central scale factor.
|
||||
* @exception GeographicErr if \e a, (1 − \e f) \e a, or \e k0 is
|
||||
* not positive.
|
||||
**********************************************************************/
|
||||
TransverseMercator(real a, real f, real k0);
|
||||
|
||||
/**
|
||||
* Forward projection, from geographic to transverse Mercator.
|
||||
*
|
||||
* @param[in] lon0 central meridian of the projection (degrees).
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[out] x easting of point (meters).
|
||||
* @param[out] y northing of point (meters).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k scale of projection at point.
|
||||
*
|
||||
* No false easting or northing is added. \e lat should be in the range
|
||||
* [−90°, 90°].
|
||||
**********************************************************************/
|
||||
void Forward(real lon0, real lat, real lon,
|
||||
real& x, real& y, real& gamma, real& k) const;
|
||||
|
||||
/**
|
||||
* Reverse projection, from transverse Mercator to geographic.
|
||||
*
|
||||
* @param[in] lon0 central meridian of the projection (degrees).
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k scale of projection at point.
|
||||
*
|
||||
* No false easting or northing is added. The value of \e lon returned is
|
||||
* in the range [−180°, 180°].
|
||||
**********************************************************************/
|
||||
void Reverse(real lon0, real x, real y,
|
||||
real& lat, real& lon, real& gamma, real& k) const;
|
||||
|
||||
/**
|
||||
* TransverseMercator::Forward without returning the convergence and scale.
|
||||
**********************************************************************/
|
||||
void Forward(real lon0, real lat, real lon,
|
||||
real& x, real& y) const {
|
||||
real gamma, k;
|
||||
Forward(lon0, lat, lon, x, y, gamma, k);
|
||||
}
|
||||
|
||||
/**
|
||||
* TransverseMercator::Reverse without returning the convergence and scale.
|
||||
**********************************************************************/
|
||||
void Reverse(real lon0, real x, real y,
|
||||
real& lat, real& lon) const {
|
||||
real gamma, k;
|
||||
Reverse(lon0, x, y, lat, lon, gamma, k);
|
||||
}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _a; }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value used in
|
||||
* the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _f; }
|
||||
|
||||
/**
|
||||
* @return \e k0 central scale for the projection. This is the value of \e
|
||||
* k0 used in the constructor and is the scale on the central meridian.
|
||||
**********************************************************************/
|
||||
Math::real CentralScale() const { return _k0; }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* A global instantiation of TransverseMercator with the WGS84 ellipsoid
|
||||
* and the UTM scale factor. However, unlike UTM, no false easting or
|
||||
* northing is added.
|
||||
**********************************************************************/
|
||||
static const TransverseMercator& UTM();
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_TRANSVERSEMERCATOR_HPP
|
||||
264
external/include/GeographicLib/TransverseMercatorExact.hpp
vendored
Normal file
264
external/include/GeographicLib/TransverseMercatorExact.hpp
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
/**
|
||||
* \file TransverseMercatorExact.hpp
|
||||
* \brief Header for GeographicLib::TransverseMercatorExact class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_TRANSVERSEMERCATOREXACT_HPP)
|
||||
#define GEOGRAPHICLIB_TRANSVERSEMERCATOREXACT_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <GeographicLib/EllipticFunction.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief An exact implementation of the transverse Mercator projection
|
||||
*
|
||||
* Implementation of the Transverse Mercator Projection given in
|
||||
* - L. P. Lee,
|
||||
* <a href="https://doi.org/10.3138/X687-1574-4325-WM62"> Conformal
|
||||
* Projections Based On Jacobian Elliptic Functions</a>, Part V of
|
||||
* Conformal Projections Based on Elliptic Functions,
|
||||
* (B. V. Gutsell, Toronto, 1976), 128pp.,
|
||||
* ISBN: 0919870163
|
||||
* (also appeared as:
|
||||
* Monograph 16, Suppl. No. 1 to Canadian Cartographer, Vol 13).
|
||||
* - C. F. F. Karney,
|
||||
* <a href="https://doi.org/10.1007/s00190-011-0445-3">
|
||||
* Transverse Mercator with an accuracy of a few nanometers,</a>
|
||||
* J. Geodesy 85(8), 475--485 (Aug. 2011);
|
||||
* preprint
|
||||
* <a href="https://arxiv.org/abs/1002.1417">arXiv:1002.1417</a>.
|
||||
*
|
||||
* Lee gives the correct results for forward and reverse transformations
|
||||
* subject to the branch cut rules (see the description of the \e extendp
|
||||
* argument to the constructor). The maximum error is about 8 nm (8
|
||||
* nanometers), ground distance, for the forward and reverse transformations.
|
||||
* The error in the convergence is 2 × 10<sup>−15</sup>",
|
||||
* the relative error in the scale is 7 × 10<sup>−12</sup>%%.
|
||||
* See Sec. 3 of
|
||||
* <a href="https://arxiv.org/abs/1002.1417">arXiv:1002.1417</a> for details.
|
||||
* The method is "exact" in the sense that the errors are close to the
|
||||
* round-off limit and that no changes are needed in the algorithms for them
|
||||
* to be used with reals of a higher precision. Thus the errors using long
|
||||
* double (with a 64-bit fraction) are about 2000 times smaller than using
|
||||
* double (with a 53-bit fraction).
|
||||
*
|
||||
* This algorithm is about 4.5 times slower than the 6th-order Krüger
|
||||
* method, TransverseMercator, taking about 11 us for a combined forward and
|
||||
* reverse projection on a 2.66 GHz Intel machine (g++, version 4.3.0, -O3).
|
||||
*
|
||||
* The ellipsoid parameters and the central scale are set in the constructor.
|
||||
* The central meridian (which is a trivial shift of the longitude) is
|
||||
* specified as the \e lon0 argument of the TransverseMercatorExact::Forward
|
||||
* and TransverseMercatorExact::Reverse functions. The latitude of origin is
|
||||
* taken to be the equator. See the documentation on TransverseMercator for
|
||||
* how to include a false easting, false northing, or a latitude of origin.
|
||||
*
|
||||
* See <a href="https://geographiclib.sourceforge.io/tm-grid.kmz"
|
||||
* type="application/vnd.google-earth.kmz"> tm-grid.kmz</a>, for an
|
||||
* illustration of the transverse Mercator grid in Google Earth.
|
||||
*
|
||||
* This class also returns the meridian convergence \e gamma and scale \e k.
|
||||
* The meridian convergence is the bearing of grid north (the \e y axis)
|
||||
* measured clockwise from true north.
|
||||
*
|
||||
* See TransverseMercatorExact.cpp for more information on the
|
||||
* implementation.
|
||||
*
|
||||
* See \ref transversemercator for a discussion of this projection.
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-TransverseMercatorExact.cpp
|
||||
*
|
||||
* <a href="TransverseMercatorProj.1.html">TransverseMercatorProj</a> is a
|
||||
* command-line utility providing access to the functionality of
|
||||
* TransverseMercator and TransverseMercatorExact.
|
||||
**********************************************************************/
|
||||
|
||||
class GEOGRAPHICLIB_EXPORT TransverseMercatorExact {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
static const int numit_ = 10;
|
||||
real tol_, tol2_, taytol_;
|
||||
real _a, _f, _k0, _mu, _mv, _e;
|
||||
bool _extendp;
|
||||
EllipticFunction _Eu, _Ev;
|
||||
|
||||
void zeta(real u, real snu, real cnu, real dnu,
|
||||
real v, real snv, real cnv, real dnv,
|
||||
real& taup, real& lam) const;
|
||||
|
||||
void dwdzeta(real u, real snu, real cnu, real dnu,
|
||||
real v, real snv, real cnv, real dnv,
|
||||
real& du, real& dv) const;
|
||||
|
||||
bool zetainv0(real psi, real lam, real& u, real& v) const;
|
||||
void zetainv(real taup, real lam, real& u, real& v) const;
|
||||
|
||||
void sigma(real u, real snu, real cnu, real dnu,
|
||||
real v, real snv, real cnv, real dnv,
|
||||
real& xi, real& eta) const;
|
||||
|
||||
void dwdsigma(real u, real snu, real cnu, real dnu,
|
||||
real v, real snv, real cnv, real dnv,
|
||||
real& du, real& dv) const;
|
||||
|
||||
bool sigmainv0(real xi, real eta, real& u, real& v) const;
|
||||
void sigmainv(real xi, real eta, real& u, real& v) const;
|
||||
|
||||
void Scale(real tau, real lam,
|
||||
real snu, real cnu, real dnu,
|
||||
real snv, real cnv, real dnv,
|
||||
real& gamma, real& k) const;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for a ellipsoid with
|
||||
*
|
||||
* @param[in] a equatorial radius (meters).
|
||||
* @param[in] f flattening of ellipsoid.
|
||||
* @param[in] k0 central scale factor.
|
||||
* @param[in] extendp use extended domain.
|
||||
* @exception GeographicErr if \e a, \e f, or \e k0 is not positive.
|
||||
*
|
||||
* The transverse Mercator projection has a branch point singularity at \e
|
||||
* lat = 0 and \e lon − \e lon0 = 90 (1 − \e e) or (for
|
||||
* TransverseMercatorExact::UTM) x = 18381 km, y = 0m. The \e extendp
|
||||
* argument governs where the branch cut is placed. With \e extendp =
|
||||
* false, the "standard" convention is followed, namely the cut is placed
|
||||
* along \e x > 18381 km, \e y = 0m. Forward can be called with any \e lat
|
||||
* and \e lon then produces the transformation shown in Lee, Fig 46.
|
||||
* Reverse analytically continues this in the ± \e x direction. As
|
||||
* a consequence, Reverse may map multiple points to the same geographic
|
||||
* location; for example, for TransverseMercatorExact::UTM, \e x =
|
||||
* 22051449.037349 m, \e y = −7131237.022729 m and \e x =
|
||||
* 29735142.378357 m, \e y = 4235043.607933 m both map to \e lat =
|
||||
* −2°, \e lon = 88°.
|
||||
*
|
||||
* With \e extendp = true, the branch cut is moved to the lower left
|
||||
* quadrant. The various symmetries of the transverse Mercator projection
|
||||
* can be used to explore the projection on any sheet. In this mode the
|
||||
* domains of \e lat, \e lon, \e x, and \e y are restricted to
|
||||
* - the union of
|
||||
* - \e lat in [0, 90] and \e lon − \e lon0 in [0, 90]
|
||||
* - \e lat in (-90, 0] and \e lon − \e lon0 in [90 (1 − \e
|
||||
e), 90]
|
||||
* - the union of
|
||||
* - <i>x</i>/(\e k0 \e a) in [0, ∞) and
|
||||
* <i>y</i>/(\e k0 \e a) in [0, E(<i>e</i><sup>2</sup>)]
|
||||
* - <i>x</i>/(\e k0 \e a) in [K(1 − <i>e</i><sup>2</sup>) −
|
||||
* E(1 − <i>e</i><sup>2</sup>), ∞) and <i>y</i>/(\e k0 \e
|
||||
* a) in (−∞, 0]
|
||||
* .
|
||||
* See Sec. 5 of
|
||||
* <a href="https://arxiv.org/abs/1002.1417">arXiv:1002.1417</a> for a full
|
||||
* discussion of the treatment of the branch cut.
|
||||
*
|
||||
* The method will work for all ellipsoids used in terrestrial geodesy.
|
||||
* The method cannot be applied directly to the case of a sphere (\e f = 0)
|
||||
* because some the constants characterizing this method diverge in that
|
||||
* limit, and in practice, \e f should be larger than about
|
||||
* numeric_limits<real>::epsilon(). However, TransverseMercator treats the
|
||||
* sphere exactly.
|
||||
**********************************************************************/
|
||||
TransverseMercatorExact(real a, real f, real k0, bool extendp = false);
|
||||
|
||||
/**
|
||||
* Forward projection, from geographic to transverse Mercator.
|
||||
*
|
||||
* @param[in] lon0 central meridian of the projection (degrees).
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[out] x easting of point (meters).
|
||||
* @param[out] y northing of point (meters).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k scale of projection at point.
|
||||
*
|
||||
* No false easting or northing is added. \e lat should be in the range
|
||||
* [−90°, 90°].
|
||||
**********************************************************************/
|
||||
void Forward(real lon0, real lat, real lon,
|
||||
real& x, real& y, real& gamma, real& k) const;
|
||||
|
||||
/**
|
||||
* Reverse projection, from transverse Mercator to geographic.
|
||||
*
|
||||
* @param[in] lon0 central meridian of the projection (degrees).
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k scale of projection at point.
|
||||
*
|
||||
* No false easting or northing is added. The value of \e lon returned is
|
||||
* in the range [−180°, 180°].
|
||||
**********************************************************************/
|
||||
void Reverse(real lon0, real x, real y,
|
||||
real& lat, real& lon, real& gamma, real& k) const;
|
||||
|
||||
/**
|
||||
* TransverseMercatorExact::Forward without returning the convergence and
|
||||
* scale.
|
||||
**********************************************************************/
|
||||
void Forward(real lon0, real lat, real lon,
|
||||
real& x, real& y) const {
|
||||
real gamma, k;
|
||||
Forward(lon0, lat, lon, x, y, gamma, k);
|
||||
}
|
||||
|
||||
/**
|
||||
* TransverseMercatorExact::Reverse without returning the convergence and
|
||||
* scale.
|
||||
**********************************************************************/
|
||||
void Reverse(real lon0, real x, real y,
|
||||
real& lat, real& lon) const {
|
||||
real gamma, k;
|
||||
Reverse(lon0, x, y, lat, lon, gamma, k);
|
||||
}
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
||||
* the value used in the constructor.
|
||||
**********************************************************************/
|
||||
Math::real EquatorialRadius() const { return _a; }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the ellipsoid. This is the value used in
|
||||
* the constructor.
|
||||
**********************************************************************/
|
||||
Math::real Flattening() const { return _f; }
|
||||
|
||||
/**
|
||||
* @return \e k0 central scale for the projection. This is the value of \e
|
||||
* k0 used in the constructor and is the scale on the central meridian.
|
||||
**********************************************************************/
|
||||
Math::real CentralScale() const { return _k0; }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
Math::real MajorRadius() const { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
/**
|
||||
* A global instantiation of TransverseMercatorExact with the WGS84
|
||||
* ellipsoid and the UTM scale factor. However, unlike UTM, no false
|
||||
* easting or northing is added.
|
||||
**********************************************************************/
|
||||
static const TransverseMercatorExact& UTM();
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_TRANSVERSEMERCATOREXACT_HPP
|
||||
428
external/include/GeographicLib/UTMUPS.hpp
vendored
Normal file
428
external/include/GeographicLib/UTMUPS.hpp
vendored
Normal file
@@ -0,0 +1,428 @@
|
||||
/**
|
||||
* \file UTMUPS.hpp
|
||||
* \brief Header for GeographicLib::UTMUPS class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2008-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_UTMUPS_HPP)
|
||||
#define GEOGRAPHICLIB_UTMUPS_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Convert between geographic coordinates and UTM/UPS
|
||||
*
|
||||
* UTM and UPS are defined
|
||||
* - J. W. Hager, J. F. Behensky, and B. W. Drew,
|
||||
* <a href="https://web.archive.org/web/20161214054445/http://earth-info.nga.mil/GandG/publications/tm8358.2/TM8358_2.pdf">
|
||||
* The Universal Grids: Universal Transverse Mercator (UTM) and Universal
|
||||
* Polar Stereographic (UPS)</a>, Defense Mapping Agency, Technical Manual
|
||||
* TM8358.2 (1989).
|
||||
* .
|
||||
* Section 2-3 defines UTM and section 3-2.4 defines UPS. This document also
|
||||
* includes approximate algorithms for the computation of the underlying
|
||||
* transverse Mercator and polar stereographic projections. Here we
|
||||
* substitute much more accurate algorithms given by
|
||||
* GeographicLib:TransverseMercator and GeographicLib:PolarStereographic.
|
||||
* These are the algorithms recommended by the NGA document
|
||||
* - <a href="https://earth-info.nga.mil/php/download.php?file=coord-utmups">
|
||||
* The Universal Grids and the Transverse Mercator and Polar Stereographic
|
||||
* Map Projections</a>, NGA.SIG.0012 (2014).
|
||||
*
|
||||
* In this implementation, the conversions are closed, i.e., output from
|
||||
* Forward is legal input for Reverse and vice versa. The error is about 5nm
|
||||
* in each direction. However, the conversion from legal UTM/UPS coordinates
|
||||
* to geographic coordinates and back might throw an error if the initial
|
||||
* point is within 5nm of the edge of the allowed range for the UTM/UPS
|
||||
* coordinates.
|
||||
*
|
||||
* The simplest way to guarantee the closed property is to define allowed
|
||||
* ranges for the eastings and northings for UTM and UPS coordinates. The
|
||||
* UTM boundaries are the same for all zones. (The only place the
|
||||
* exceptional nature of the zone boundaries is evident is when converting to
|
||||
* UTM/UPS coordinates requesting the standard zone.) The MGRS lettering
|
||||
* scheme imposes natural limits on UTM/UPS coordinates which may be
|
||||
* converted into MGRS coordinates. For the conversion to/from geographic
|
||||
* coordinates these ranges have been extended by 100km in order to provide a
|
||||
* generous overlap between UTM and UPS and between UTM zones.
|
||||
*
|
||||
* The <a href="http://www.nga.mil">NGA</a> software package
|
||||
* <a href="https://earth-info.nga.mil/index.php?dir=wgs84&action=wgs84#tab_geotrans">geotrans</a>
|
||||
* also provides conversions to and from UTM and UPS. Version 2.4.2 (and
|
||||
* earlier) suffers from some drawbacks:
|
||||
* - Inconsistent rules are used to determine the whether a particular UTM or
|
||||
* UPS coordinate is legal. A more systematic approach is taken here.
|
||||
* - The underlying projections are not very accurately implemented.
|
||||
*
|
||||
* The GeographicLib::UTMUPS::EncodeZone encodes the UTM zone and hemisphere
|
||||
* to allow UTM/UPS coordinated to be displayed as, for example, "38N 444500
|
||||
* 3688500". According to NGA.SIG.0012_2.0.0_UTMUPS the use of "N" to denote
|
||||
* "north" in the context is not allowed (since a upper case letter in this
|
||||
* context denotes the MGRS latitude band). Consequently, as of version
|
||||
* 1.36, EncodeZone uses the lower case letters "n" and "s" to denote the
|
||||
* hemisphere. In addition EncodeZone accepts an optional final argument \e
|
||||
* abbrev, which, if false, results in the hemisphere being spelled out as in
|
||||
* "38north".
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-UTMUPS.cpp
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT UTMUPS {
|
||||
private:
|
||||
typedef Math::real real;
|
||||
static const int falseeasting_[4];
|
||||
static const int falsenorthing_[4];
|
||||
static const int mineasting_[4];
|
||||
static const int maxeasting_[4];
|
||||
static const int minnorthing_[4];
|
||||
static const int maxnorthing_[4];
|
||||
static const int epsg01N = 32601; // EPSG code for UTM 01N
|
||||
static const int epsg60N = 32660; // EPSG code for UTM 60N
|
||||
static const int epsgN = 32661; // EPSG code for UPS N
|
||||
static const int epsg01S = 32701; // EPSG code for UTM 01S
|
||||
static const int epsg60S = 32760; // EPSG code for UTM 60S
|
||||
static const int epsgS = 32761; // EPSG code for UPS S
|
||||
static real CentralMeridian(int zone)
|
||||
{ return real(6 * zone - 183); }
|
||||
// Throw an error if easting or northing are outside standard ranges. If
|
||||
// throwp = false, return bool instead.
|
||||
static bool CheckCoords(bool utmp, bool northp, real x, real y,
|
||||
bool msgrlimits = false, bool throwp = true);
|
||||
UTMUPS(); // Disable constructor
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* In this class we bring together the UTM and UPS coordinates systems.
|
||||
* The UTM divides the earth between latitudes −80° and 84°
|
||||
* into 60 zones numbered 1 thru 60. Zone assign zone number 0 to the UPS
|
||||
* regions, covering the two poles. Within UTMUPS, non-negative zone
|
||||
* numbers refer to one of the "physical" zones, 0 for UPS and [1, 60] for
|
||||
* UTM. Negative "pseudo-zone" numbers are used to select one of the
|
||||
* physical zones.
|
||||
**********************************************************************/
|
||||
enum zonespec {
|
||||
/**
|
||||
* The smallest pseudo-zone number.
|
||||
**********************************************************************/
|
||||
MINPSEUDOZONE = -4,
|
||||
/**
|
||||
* A marker for an undefined or invalid zone. Equivalent to NaN.
|
||||
**********************************************************************/
|
||||
INVALID = -4,
|
||||
/**
|
||||
* If a coordinate already include zone information (e.g., it is an MGRS
|
||||
* coordinate), use that, otherwise apply the UTMUPS::STANDARD rules.
|
||||
**********************************************************************/
|
||||
MATCH = -3,
|
||||
/**
|
||||
* Apply the standard rules for UTM zone assigment extending the UTM zone
|
||||
* to each pole to give a zone number in [1, 60]. For example, use UTM
|
||||
* zone 38 for longitude in [42°, 48°). The rules include the
|
||||
* Norway and Svalbard exceptions.
|
||||
**********************************************************************/
|
||||
UTM = -2,
|
||||
/**
|
||||
* Apply the standard rules for zone assignment to give a zone number in
|
||||
* [0, 60]. If the latitude is not in [−80°, 84°), then
|
||||
* use UTMUPS::UPS = 0, otherwise apply the rules for UTMUPS::UTM. The
|
||||
* tests on latitudes and longitudes are all closed on the lower end open
|
||||
* on the upper. Thus for UTM zone 38, latitude is in [−80°,
|
||||
* 84°) and longitude is in [42°, 48°).
|
||||
**********************************************************************/
|
||||
STANDARD = -1,
|
||||
/**
|
||||
* The largest pseudo-zone number.
|
||||
**********************************************************************/
|
||||
MAXPSEUDOZONE = -1,
|
||||
/**
|
||||
* The smallest physical zone number.
|
||||
**********************************************************************/
|
||||
MINZONE = 0,
|
||||
/**
|
||||
* The zone number used for UPS
|
||||
**********************************************************************/
|
||||
UPS = 0,
|
||||
/**
|
||||
* The smallest UTM zone number.
|
||||
**********************************************************************/
|
||||
MINUTMZONE = 1,
|
||||
/**
|
||||
* The largest UTM zone number.
|
||||
**********************************************************************/
|
||||
MAXUTMZONE = 60,
|
||||
/**
|
||||
* The largest physical zone number.
|
||||
**********************************************************************/
|
||||
MAXZONE = 60,
|
||||
};
|
||||
|
||||
/**
|
||||
* The standard zone.
|
||||
*
|
||||
* @param[in] lat latitude (degrees).
|
||||
* @param[in] lon longitude (degrees).
|
||||
* @param[in] setzone zone override (optional). If omitted, use the
|
||||
* standard rules for picking the zone. If \e setzone is given then use
|
||||
* that zone if it is non-negative, otherwise apply the rules given in
|
||||
* UTMUPS::zonespec.
|
||||
* @exception GeographicErr if \e setzone is outside the range
|
||||
* [UTMUPS::MINPSEUDOZONE, UTMUPS::MAXZONE] = [−4, 60].
|
||||
*
|
||||
* This is exact.
|
||||
**********************************************************************/
|
||||
static int StandardZone(real lat, real lon, int setzone = STANDARD);
|
||||
|
||||
/**
|
||||
* Forward projection, from geographic to UTM/UPS.
|
||||
*
|
||||
* @param[in] lat latitude of point (degrees).
|
||||
* @param[in] lon longitude of point (degrees).
|
||||
* @param[out] zone the UTM zone (zero means UPS).
|
||||
* @param[out] northp hemisphere (true means north, false means south).
|
||||
* @param[out] x easting of point (meters).
|
||||
* @param[out] y northing of point (meters).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k scale of projection at point.
|
||||
* @param[in] setzone zone override (optional).
|
||||
* @param[in] mgrslimits if true enforce the stricter MGRS limits on the
|
||||
* coordinates (default = false).
|
||||
* @exception GeographicErr if \e lat is not in [−90°,
|
||||
* 90°].
|
||||
* @exception GeographicErr if the resulting \e x or \e y is out of allowed
|
||||
* range (see Reverse); in this case, these arguments are unchanged.
|
||||
*
|
||||
* If \e setzone is omitted, use the standard rules for picking the zone.
|
||||
* If \e setzone is given then use that zone if it is non-negative,
|
||||
* otherwise apply the rules given in UTMUPS::zonespec. The accuracy of
|
||||
* the conversion is about 5nm.
|
||||
*
|
||||
* The northing \e y jumps by UTMUPS::UTMShift() when crossing the equator
|
||||
* in the southerly direction. Sometimes it is useful to remove this
|
||||
* discontinuity in \e y by extending the "northern" hemisphere using
|
||||
* UTMUPS::Transfer:
|
||||
* \code
|
||||
double lat = -1, lon = 123;
|
||||
int zone;
|
||||
bool northp;
|
||||
double x, y, gamma, k;
|
||||
GeographicLib::UTMUPS::Forward(lat, lon, zone, northp, x, y, gamma, k);
|
||||
GeographicLib::UTMUPS::Transfer(zone, northp, x, y,
|
||||
zone, true, x, y, zone);
|
||||
northp = true;
|
||||
\endcode
|
||||
**********************************************************************/
|
||||
static void Forward(real lat, real lon,
|
||||
int& zone, bool& northp, real& x, real& y,
|
||||
real& gamma, real& k,
|
||||
int setzone = STANDARD, bool mgrslimits = false);
|
||||
|
||||
/**
|
||||
* Reverse projection, from UTM/UPS to geographic.
|
||||
*
|
||||
* @param[in] zone the UTM zone (zero means UPS).
|
||||
* @param[in] northp hemisphere (true means north, false means south).
|
||||
* @param[in] x easting of point (meters).
|
||||
* @param[in] y northing of point (meters).
|
||||
* @param[out] lat latitude of point (degrees).
|
||||
* @param[out] lon longitude of point (degrees).
|
||||
* @param[out] gamma meridian convergence at point (degrees).
|
||||
* @param[out] k scale of projection at point.
|
||||
* @param[in] mgrslimits if true enforce the stricter MGRS limits on the
|
||||
* coordinates (default = false).
|
||||
* @exception GeographicErr if \e zone, \e x, or \e y is out of allowed
|
||||
* range; this this case the arguments are unchanged.
|
||||
*
|
||||
* The accuracy of the conversion is about 5nm.
|
||||
*
|
||||
* UTM eastings are allowed to be in the range [0km, 1000km], northings are
|
||||
* allowed to be in in [0km, 9600km] for the northern hemisphere and in
|
||||
* [900km, 10000km] for the southern hemisphere. However UTM northings
|
||||
* can be continued across the equator. So the actual limits on the
|
||||
* northings are [-9100km, 9600km] for the "northern" hemisphere and
|
||||
* [900km, 19600km] for the "southern" hemisphere.
|
||||
*
|
||||
* UPS eastings and northings are allowed to be in the range [1200km,
|
||||
* 2800km] in the northern hemisphere and in [700km, 3300km] in the
|
||||
* southern hemisphere.
|
||||
*
|
||||
* These ranges are 100km larger than allowed for the conversions to MGRS.
|
||||
* (100km is the maximum extra padding consistent with eastings remaining
|
||||
* non-negative.) This allows generous overlaps between zones and UTM and
|
||||
* UPS. If \e mgrslimits = true, then all the ranges are shrunk by 100km
|
||||
* so that they agree with the stricter MGRS ranges. No checks are
|
||||
* performed besides these (e.g., to limit the distance outside the
|
||||
* standard zone boundaries).
|
||||
**********************************************************************/
|
||||
static void Reverse(int zone, bool northp, real x, real y,
|
||||
real& lat, real& lon, real& gamma, real& k,
|
||||
bool mgrslimits = false);
|
||||
|
||||
/**
|
||||
* UTMUPS::Forward without returning convergence and scale.
|
||||
**********************************************************************/
|
||||
static void Forward(real lat, real lon,
|
||||
int& zone, bool& northp, real& x, real& y,
|
||||
int setzone = STANDARD, bool mgrslimits = false) {
|
||||
real gamma, k;
|
||||
Forward(lat, lon, zone, northp, x, y, gamma, k, setzone, mgrslimits);
|
||||
}
|
||||
|
||||
/**
|
||||
* UTMUPS::Reverse without returning convergence and scale.
|
||||
**********************************************************************/
|
||||
static void Reverse(int zone, bool northp, real x, real y,
|
||||
real& lat, real& lon, bool mgrslimits = false) {
|
||||
real gamma, k;
|
||||
Reverse(zone, northp, x, y, lat, lon, gamma, k, mgrslimits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer UTM/UPS coordinated from one zone to another.
|
||||
*
|
||||
* @param[in] zonein the UTM zone for \e xin and \e yin (or zero for UPS).
|
||||
* @param[in] northpin hemisphere for \e xin and \e yin (true means north,
|
||||
* false means south).
|
||||
* @param[in] xin easting of point (meters) in \e zonein.
|
||||
* @param[in] yin northing of point (meters) in \e zonein.
|
||||
* @param[in] zoneout the requested UTM zone for \e xout and \e yout (or
|
||||
* zero for UPS).
|
||||
* @param[in] northpout hemisphere for \e xout output and \e yout.
|
||||
* @param[out] xout easting of point (meters) in \e zoneout.
|
||||
* @param[out] yout northing of point (meters) in \e zoneout.
|
||||
* @param[out] zone the actual UTM zone for \e xout and \e yout (or zero
|
||||
* for UPS); this equals \e zoneout if \e zoneout ≥ 0.
|
||||
* @exception GeographicErr if \e zonein is out of range (see below).
|
||||
* @exception GeographicErr if \e zoneout is out of range (see below).
|
||||
* @exception GeographicErr if \e xin or \e yin fall outside their allowed
|
||||
* ranges (see UTMUPS::Reverse).
|
||||
* @exception GeographicErr if \e xout or \e yout fall outside their
|
||||
* allowed ranges (see UTMUPS::Reverse).
|
||||
*
|
||||
* \e zonein must be in the range [UTMUPS::MINZONE, UTMUPS::MAXZONE] = [0,
|
||||
* 60] with \e zonein = UTMUPS::UPS, 0, indicating UPS. \e zonein may
|
||||
* also be UTMUPS::INVALID.
|
||||
*
|
||||
* \e zoneout must be in the range [UTMUPS::MINPSEUDOZONE, UTMUPS::MAXZONE]
|
||||
* = [-4, 60]. If \e zoneout < UTMUPS::MINZONE then the rules give in
|
||||
* the documentation of UTMUPS::zonespec are applied, and \e zone is set to
|
||||
* the actual zone used for output.
|
||||
*
|
||||
* (\e xout, \e yout) can overlap with (\e xin, \e yin).
|
||||
**********************************************************************/
|
||||
static void Transfer(int zonein, bool northpin, real xin, real yin,
|
||||
int zoneout, bool northpout, real& xout, real& yout,
|
||||
int& zone);
|
||||
|
||||
/**
|
||||
* Decode a UTM/UPS zone string.
|
||||
*
|
||||
* @param[in] zonestr string representation of zone and hemisphere.
|
||||
* @param[out] zone the UTM zone (zero means UPS).
|
||||
* @param[out] northp hemisphere (true means north, false means south).
|
||||
* @exception GeographicErr if \e zonestr is malformed.
|
||||
*
|
||||
* For UTM, \e zonestr has the form of a zone number in the range
|
||||
* [UTMUPS::MINUTMZONE, UTMUPS::MAXUTMZONE] = [1, 60] followed by a
|
||||
* hemisphere letter, n or s (or "north" or "south" spelled out). For UPS,
|
||||
* it consists just of the hemisphere letter (or the spelled out
|
||||
* hemisphere). The returned value of \e zone is UTMUPS::UPS = 0 for UPS.
|
||||
* Note well that "38s" indicates the southern hemisphere of zone 38 and
|
||||
* not latitude band S, 32° ≤ \e lat < 40°. n, 01s, 2n, 38s,
|
||||
* south, 3north are legal. 0n, 001s, +3n, 61n, 38P are illegal. INV is a
|
||||
* special value for which the returned value of \e is UTMUPS::INVALID.
|
||||
**********************************************************************/
|
||||
static void DecodeZone(const std::string& zonestr,
|
||||
int& zone, bool& northp);
|
||||
|
||||
/**
|
||||
* Encode a UTM/UPS zone string.
|
||||
*
|
||||
* @param[in] zone the UTM zone (zero means UPS).
|
||||
* @param[in] northp hemisphere (true means north, false means south).
|
||||
* @param[in] abbrev if true (the default) use abbreviated (n/s) notation
|
||||
* for hemisphere; otherwise spell out the hemisphere (north/south)
|
||||
* @exception GeographicErr if \e zone is out of range (see below).
|
||||
* @exception std::bad_alloc if memoy for the string can't be allocated.
|
||||
* @return string representation of zone and hemisphere.
|
||||
*
|
||||
* \e zone must be in the range [UTMUPS::MINZONE, UTMUPS::MAXZONE] = [0,
|
||||
* 60] with \e zone = UTMUPS::UPS, 0, indicating UPS (but the resulting
|
||||
* string does not contain "0"). \e zone may also be UTMUPS::INVALID, in
|
||||
* which case the returned string is "inv". This reverses
|
||||
* UTMUPS::DecodeZone.
|
||||
**********************************************************************/
|
||||
static std::string EncodeZone(int zone, bool northp, bool abbrev = true);
|
||||
|
||||
/**
|
||||
* Decode EPSG.
|
||||
*
|
||||
* @param[in] epsg the EPSG code.
|
||||
* @param[out] zone the UTM zone (zero means UPS).
|
||||
* @param[out] northp hemisphere (true means north, false means south).
|
||||
*
|
||||
* EPSG (European Petroleum Survery Group) codes are a way to refer to many
|
||||
* different projections. DecodeEPSG decodes those referring to UTM or UPS
|
||||
* projections for the WGS84 ellipsoid. If the code does not refer to one
|
||||
* of these projections, \e zone is set to UTMUPS::INVALID. See
|
||||
* https://www.spatialreference.org/ref/epsg/
|
||||
**********************************************************************/
|
||||
static void DecodeEPSG(int epsg, int& zone, bool& northp);
|
||||
|
||||
/**
|
||||
* Encode zone as EPSG.
|
||||
*
|
||||
* @param[in] zone the UTM zone (zero means UPS).
|
||||
* @param[in] northp hemisphere (true means north, false means south).
|
||||
* @return EPSG code (or -1 if \e zone is not in the range
|
||||
* [UTMUPS::MINZONE, UTMUPS::MAXZONE] = [0, 60])
|
||||
*
|
||||
* Convert \e zone and \e northp to the corresponding EPSG (European
|
||||
* Petroleum Survery Group) codes
|
||||
**********************************************************************/
|
||||
static int EncodeEPSG(int zone, bool northp);
|
||||
|
||||
/**
|
||||
* @return shift (meters) necessary to align north and south halves of a
|
||||
* UTM zone (10<sup>7</sup>).
|
||||
**********************************************************************/
|
||||
static Math::real UTMShift();
|
||||
|
||||
/** \name Inspector functions
|
||||
**********************************************************************/
|
||||
///@{
|
||||
/**
|
||||
* @return \e a the equatorial radius of the WGS84 ellipsoid (meters).
|
||||
*
|
||||
* (The WGS84 value is returned because the UTM and UPS projections are
|
||||
* based on this ellipsoid.)
|
||||
**********************************************************************/
|
||||
static Math::real EquatorialRadius()
|
||||
{ return Constants::WGS84_a(); }
|
||||
|
||||
/**
|
||||
* @return \e f the flattening of the WGS84 ellipsoid.
|
||||
*
|
||||
* (The WGS84 value is returned because the UTM and UPS projections are
|
||||
* based on this ellipsoid.)
|
||||
**********************************************************************/
|
||||
static Math::real Flattening()
|
||||
{ return Constants::WGS84_f(); }
|
||||
|
||||
/**
|
||||
* \deprecated An old name for EquatorialRadius().
|
||||
**********************************************************************/
|
||||
GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
|
||||
static Math::real MajorRadius() { return EquatorialRadius(); }
|
||||
///@}
|
||||
|
||||
};
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#endif // GEOGRAPHICLIB_UTMUPS_HPP
|
||||
733
external/include/GeographicLib/Utility.hpp
vendored
Normal file
733
external/include/GeographicLib/Utility.hpp
vendored
Normal file
@@ -0,0 +1,733 @@
|
||||
/**
|
||||
* \file Utility.hpp
|
||||
* \brief Header for GeographicLib::Utility class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2011-2020) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#if !defined(GEOGRAPHICLIB_UTILITY_HPP)
|
||||
#define GEOGRAPHICLIB_UTILITY_HPP 1
|
||||
|
||||
#include <GeographicLib/Constants.hpp>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <cctype>
|
||||
#include <ctime>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about constant conditional expressions and unsafe gmtime
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4127 4996)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
/**
|
||||
* \brief Some utility routines for %GeographicLib
|
||||
*
|
||||
* Example of use:
|
||||
* \include example-Utility.cpp
|
||||
**********************************************************************/
|
||||
class GEOGRAPHICLIB_EXPORT Utility {
|
||||
private:
|
||||
static bool gregorian(int y, int m, int d) {
|
||||
// The original cut over to the Gregorian calendar in Pope Gregory XIII's
|
||||
// time had 1582-10-04 followed by 1582-10-15. Here we implement the
|
||||
// switch over used by the English-speaking world where 1752-09-02 was
|
||||
// followed by 1752-09-14. We also assume that the year always begins
|
||||
// with January 1, whereas in reality it often was reckoned to begin in
|
||||
// March.
|
||||
return 100 * (100 * y + m) + d >= 17520914; // or 15821015
|
||||
}
|
||||
static bool gregorian(int s) {
|
||||
return s >= 639799; // 1752-09-14
|
||||
}
|
||||
public:
|
||||
|
||||
/**
|
||||
* Convert a date to the day numbering sequentially starting with
|
||||
* 0001-01-01 as day 1.
|
||||
*
|
||||
* @param[in] y the year (must be positive).
|
||||
* @param[in] m the month, Jan = 1, etc. (must be positive). Default = 1.
|
||||
* @param[in] d the day of the month (must be positive). Default = 1.
|
||||
* @return the sequential day number.
|
||||
**********************************************************************/
|
||||
static int day(int y, int m = 1, int d = 1) {
|
||||
// Convert from date to sequential day and vice versa
|
||||
//
|
||||
// Here is some code to convert a date to sequential day and vice
|
||||
// versa. The sequential day is numbered so that January 1, 1 AD is day 1
|
||||
// (a Saturday). So this is offset from the "Julian" day which starts the
|
||||
// numbering with 4713 BC.
|
||||
//
|
||||
// This is inspired by a talk by John Conway at the John von Neumann
|
||||
// National Supercomputer Center when he described his Doomsday algorithm
|
||||
// for figuring the day of the week. The code avoids explicitly doing ifs
|
||||
// (except for the decision of whether to use the Julian or Gregorian
|
||||
// calendar). Instead the equivalent result is achieved using integer
|
||||
// arithmetic. I got this idea from the routine for the day of the week
|
||||
// in MACLisp (I believe that that routine was written by Guy Steele).
|
||||
//
|
||||
// There are three issues to take care of
|
||||
//
|
||||
// 1. the rules for leap years,
|
||||
// 2. the inconvenient placement of leap days at the end of February,
|
||||
// 3. the irregular pattern of month lengths.
|
||||
//
|
||||
// We deal with these as follows:
|
||||
//
|
||||
// 1. Leap years are given by simple rules which are straightforward to
|
||||
// accommodate.
|
||||
//
|
||||
// 2. We simplify the calculations by moving January and February to the
|
||||
// previous year. Here we internally number the months March–December,
|
||||
// January, February as 0–9, 10, 11.
|
||||
//
|
||||
// 3. The pattern of month lengths from March through January is regular
|
||||
// with a 5-month period—31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31. The
|
||||
// 5-month period is 153 days long. Since February is now at the end of
|
||||
// the year, we don't need to include its length in this part of the
|
||||
// calculation.
|
||||
bool greg = gregorian(y, m, d);
|
||||
y += (m + 9) / 12 - 1; // Move Jan and Feb to previous year,
|
||||
m = (m + 9) % 12; // making March month 0.
|
||||
return
|
||||
(1461 * y) / 4 // Julian years converted to days. Julian year is 365 +
|
||||
// 1/4 = 1461/4 days.
|
||||
// Gregorian leap year corrections. The 2 offset with respect to the
|
||||
// Julian calendar synchronizes the vernal equinox with that at the
|
||||
// time of the Council of Nicea (325 AD).
|
||||
+ (greg ? (y / 100) / 4 - (y / 100) + 2 : 0)
|
||||
+ (153 * m + 2) / 5 // The zero-based start of the m'th month
|
||||
+ d - 1 // The zero-based day
|
||||
- 305; // The number of days between March 1 and December 31.
|
||||
// This makes 0001-01-01 day 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a date to the day numbering sequentially starting with
|
||||
* 0001-01-01 as day 1.
|
||||
*
|
||||
* @param[in] y the year (must be positive).
|
||||
* @param[in] m the month, Jan = 1, etc. (must be positive). Default = 1.
|
||||
* @param[in] d the day of the month (must be positive). Default = 1.
|
||||
* @param[in] check whether to check the date.
|
||||
* @exception GeographicErr if the date is invalid and \e check is true.
|
||||
* @return the sequential day number.
|
||||
**********************************************************************/
|
||||
static int day(int y, int m, int d, bool check) {
|
||||
int s = day(y, m, d);
|
||||
if (!check)
|
||||
return s;
|
||||
int y1, m1, d1;
|
||||
date(s, y1, m1, d1);
|
||||
if (!(s > 0 && y == y1 && m == m1 && d == d1))
|
||||
throw GeographicErr("Invalid date " +
|
||||
str(y) + "-" + str(m) + "-" + str(d)
|
||||
+ (s > 0 ? "; use " +
|
||||
str(y1) + "-" + str(m1) + "-" + str(d1) :
|
||||
" before 0001-01-01"));
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a day (counting from 0001-01-01 as day 1), return the date.
|
||||
*
|
||||
* @param[in] s the sequential day number (must be positive)
|
||||
* @param[out] y the year.
|
||||
* @param[out] m the month, Jan = 1, etc.
|
||||
* @param[out] d the day of the month.
|
||||
**********************************************************************/
|
||||
static void date(int s, int& y, int& m, int& d) {
|
||||
int c = 0;
|
||||
bool greg = gregorian(s);
|
||||
s += 305; // s = 0 on March 1, 1BC
|
||||
if (greg) {
|
||||
s -= 2; // The 2 day Gregorian offset
|
||||
// Determine century with the Gregorian rules for leap years. The
|
||||
// Gregorian year is 365 + 1/4 - 1/100 + 1/400 = 146097/400 days.
|
||||
c = (4 * s + 3) / 146097;
|
||||
s -= (c * 146097) / 4; // s = 0 at beginning of century
|
||||
}
|
||||
y = (4 * s + 3) / 1461; // Determine the year using Julian rules.
|
||||
s -= (1461 * y) / 4; // s = 0 at start of year, i.e., March 1
|
||||
y += c * 100; // Assemble full year
|
||||
m = (5 * s + 2) / 153; // Determine the month
|
||||
s -= (153 * m + 2) / 5; // s = 0 at beginning of month
|
||||
d = s + 1; // Determine day of month
|
||||
y += (m + 2) / 12; // Move Jan and Feb back to original year
|
||||
m = (m + 2) % 12 + 1; // Renumber the months so January = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a date as a string in the format yyyy, yyyy-mm, or yyyy-mm-dd,
|
||||
* return the numeric values for the year, month, and day. No checking is
|
||||
* done on these values. The string "now" is interpreted as the present
|
||||
* date (in UTC).
|
||||
*
|
||||
* @param[in] s the date in string format.
|
||||
* @param[out] y the year.
|
||||
* @param[out] m the month, Jan = 1, etc.
|
||||
* @param[out] d the day of the month.
|
||||
* @exception GeographicErr is \e s is malformed.
|
||||
**********************************************************************/
|
||||
static void date(const std::string& s, int& y, int& m, int& d) {
|
||||
if (s == "now") {
|
||||
std::time_t t = std::time(0);
|
||||
struct tm* now = gmtime(&t);
|
||||
y = now->tm_year + 1900;
|
||||
m = now->tm_mon + 1;
|
||||
d = now->tm_mday;
|
||||
return;
|
||||
}
|
||||
int y1, m1 = 1, d1 = 1;
|
||||
const char* digits = "0123456789";
|
||||
std::string::size_type p1 = s.find_first_not_of(digits);
|
||||
if (p1 == std::string::npos)
|
||||
y1 = val<int>(s);
|
||||
else if (s[p1] != '-')
|
||||
throw GeographicErr("Delimiter not hyphen in date " + s);
|
||||
else if (p1 == 0)
|
||||
throw GeographicErr("Empty year field in date " + s);
|
||||
else {
|
||||
y1 = val<int>(s.substr(0, p1));
|
||||
if (++p1 == s.size())
|
||||
throw GeographicErr("Empty month field in date " + s);
|
||||
std::string::size_type p2 = s.find_first_not_of(digits, p1);
|
||||
if (p2 == std::string::npos)
|
||||
m1 = val<int>(s.substr(p1));
|
||||
else if (s[p2] != '-')
|
||||
throw GeographicErr("Delimiter not hyphen in date " + s);
|
||||
else if (p2 == p1)
|
||||
throw GeographicErr("Empty month field in date " + s);
|
||||
else {
|
||||
m1 = val<int>(s.substr(p1, p2 - p1));
|
||||
if (++p2 == s.size())
|
||||
throw GeographicErr("Empty day field in date " + s);
|
||||
d1 = val<int>(s.substr(p2));
|
||||
}
|
||||
}
|
||||
y = y1; m = m1; d = d1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the date, return the day of the week.
|
||||
*
|
||||
* @param[in] y the year (must be positive).
|
||||
* @param[in] m the month, Jan = 1, etc. (must be positive).
|
||||
* @param[in] d the day of the month (must be positive).
|
||||
* @return the day of the week with Sunday, Monday--Saturday = 0,
|
||||
* 1--6.
|
||||
**********************************************************************/
|
||||
static int dow(int y, int m, int d) { return dow(day(y, m, d)); }
|
||||
|
||||
/**
|
||||
* Given the sequential day, return the day of the week.
|
||||
*
|
||||
* @param[in] s the sequential day (must be positive).
|
||||
* @return the day of the week with Sunday, Monday--Saturday = 0,
|
||||
* 1--6.
|
||||
**********************************************************************/
|
||||
static int dow(int s) {
|
||||
return (s + 5) % 7; // The 5 offset makes day 1 (0001-01-01) a Saturday.
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string representing a date to a fractional year.
|
||||
*
|
||||
* @tparam T the type of the argument.
|
||||
* @param[in] s the string to be converted.
|
||||
* @exception GeographicErr if \e s can't be interpreted as a date.
|
||||
* @return the fractional year.
|
||||
*
|
||||
* The string is first read as an ordinary number (e.g., 2010 or 2012.5);
|
||||
* if this is successful, the value is returned. Otherwise the string
|
||||
* should be of the form yyyy-mm or yyyy-mm-dd and this is converted to a
|
||||
* number with 2010-01-01 giving 2010.0 and 2012-07-03 giving 2012.5.
|
||||
**********************************************************************/
|
||||
template<typename T> static T fractionalyear(const std::string& s) {
|
||||
try {
|
||||
return val<T>(s);
|
||||
}
|
||||
catch (const std::exception&) {}
|
||||
int y, m, d;
|
||||
date(s, y, m, d);
|
||||
int t = day(y, m, d, true);
|
||||
return T(y) + T(t - day(y)) / T(day(y + 1) - day(y));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a object of type T to a string.
|
||||
*
|
||||
* @tparam T the type of the argument.
|
||||
* @param[in] x the value to be converted.
|
||||
* @param[in] p the precision used (default −1).
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return the string representation.
|
||||
*
|
||||
* If \e p ≥ 0, then the number fixed format is used with p bits of
|
||||
* precision. With p < 0, there is no manipulation of the format.
|
||||
**********************************************************************/
|
||||
template<typename T> static std::string str(T x, int p = -1) {
|
||||
std::ostringstream s;
|
||||
if (p >= 0) s << std::fixed << std::setprecision(p);
|
||||
s << x; return s.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Math::real object to a string.
|
||||
*
|
||||
* @param[in] x the value to be converted.
|
||||
* @param[in] p the precision used (default −1).
|
||||
* @exception std::bad_alloc if memory for the string can't be allocated.
|
||||
* @return the string representation.
|
||||
*
|
||||
* If \e p ≥ 0, then the number fixed format is used with p bits of
|
||||
* precision. With p < 0, there is no manipulation of the format. This is
|
||||
* an overload of str<T> which deals with inf and nan.
|
||||
**********************************************************************/
|
||||
static std::string str(Math::real x, int p = -1) {
|
||||
using std::isfinite;
|
||||
if (!isfinite(x))
|
||||
return x < 0 ? std::string("-inf") :
|
||||
(x > 0 ? std::string("inf") : std::string("nan"));
|
||||
std::ostringstream s;
|
||||
#if GEOGRAPHICLIB_PRECISION == 4
|
||||
// boost-quadmath treats precision == 0 as "use as many digits as
|
||||
// necessary" (see https://svn.boost.org/trac/boost/ticket/10103), so...
|
||||
using std::floor; using std::fmod;
|
||||
if (p == 0) {
|
||||
x += Math::real(0.5);
|
||||
Math::real ix = floor(x);
|
||||
// Implement the "round ties to even" rule
|
||||
x = (ix == x && fmod(ix, Math::real(2)) == 1) ? ix - 1 : ix;
|
||||
s << std::fixed << std::setprecision(1) << x;
|
||||
std::string r(s.str());
|
||||
// strip off trailing ".0"
|
||||
return r.substr(0, (std::max)(int(r.size()) - 2, 0));
|
||||
}
|
||||
#endif
|
||||
if (p >= 0) s << std::fixed << std::setprecision(p);
|
||||
s << x; return s.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim the white space from the beginning and end of a string.
|
||||
*
|
||||
* @param[in] s the string to be trimmed
|
||||
* @return the trimmed string
|
||||
**********************************************************************/
|
||||
static std::string trim(const std::string& s) {
|
||||
unsigned
|
||||
beg = 0,
|
||||
end = unsigned(s.size());
|
||||
while (beg < end && isspace(s[beg]))
|
||||
++beg;
|
||||
while (beg < end && isspace(s[end - 1]))
|
||||
--end;
|
||||
return std::string(s, beg, end-beg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string to type T.
|
||||
*
|
||||
* @tparam T the type of the return value.
|
||||
* @param[in] s the string to be converted.
|
||||
* @exception GeographicErr is \e s is not readable as a T.
|
||||
* @return object of type T.
|
||||
*
|
||||
* White space at the beginning and end of \e s is ignored.
|
||||
*
|
||||
* Special handling is provided for some types.
|
||||
*
|
||||
* If T is a floating point type, then inf and nan are recognized.
|
||||
*
|
||||
* If T is bool, then \e s should either be string a representing 0 (false)
|
||||
* or 1 (true) or one of the strings
|
||||
* - "false", "f", "nil", "no", "n", "off", or "" meaning false,
|
||||
* - "true", "t", "yes", "y", or "on" meaning true;
|
||||
* .
|
||||
* case is ignored.
|
||||
*
|
||||
* If T is std::string, then \e s is returned (with the white space at the
|
||||
* beginning and end removed).
|
||||
**********************************************************************/
|
||||
template<typename T> static T val(const std::string& s) {
|
||||
// If T is bool, then the specialization val<bool>() defined below is
|
||||
// used.
|
||||
T x;
|
||||
std::string errmsg, t(trim(s));
|
||||
do { // Executed once (provides the ability to break)
|
||||
std::istringstream is(t);
|
||||
if (!(is >> x)) {
|
||||
errmsg = "Cannot decode " + t;
|
||||
break;
|
||||
}
|
||||
int pos = int(is.tellg()); // Returns -1 at end of string?
|
||||
if (!(pos < 0 || pos == int(t.size()))) {
|
||||
errmsg = "Extra text " + t.substr(pos) + " at end of " + t;
|
||||
break;
|
||||
}
|
||||
return x;
|
||||
} while (false);
|
||||
x = std::numeric_limits<T>::is_integer ? 0 : nummatch<T>(t);
|
||||
if (x == 0)
|
||||
throw GeographicErr(errmsg);
|
||||
return x;
|
||||
}
|
||||
/**
|
||||
* \deprecated An old name for val<T>(s).
|
||||
**********************************************************************/
|
||||
template<typename T>
|
||||
GEOGRAPHICLIB_DEPRECATED("Use Utility::val<T>(s)")
|
||||
static T num(const std::string& s) {
|
||||
return val<T>(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match "nan" and "inf" (and variants thereof) in a string.
|
||||
*
|
||||
* @tparam T the type of the return value (this should be a floating point
|
||||
* type).
|
||||
* @param[in] s the string to be matched.
|
||||
* @return appropriate special value (±∞, nan) or 0 if none is
|
||||
* found.
|
||||
*
|
||||
* White space is not allowed at the beginning or end of \e s.
|
||||
**********************************************************************/
|
||||
template<typename T> static T nummatch(const std::string& s) {
|
||||
if (s.length() < 3)
|
||||
return 0;
|
||||
std::string t(s);
|
||||
for (std::string::iterator p = t.begin(); p != t.end(); ++p)
|
||||
*p = char(std::toupper(*p));
|
||||
for (size_t i = s.length(); i--;)
|
||||
t[i] = char(std::toupper(s[i]));
|
||||
int sign = t[0] == '-' ? -1 : 1;
|
||||
std::string::size_type p0 = t[0] == '-' || t[0] == '+' ? 1 : 0;
|
||||
std::string::size_type p1 = t.find_last_not_of('0');
|
||||
if (p1 == std::string::npos || p1 + 1 < p0 + 3)
|
||||
return 0;
|
||||
// Strip off sign and trailing 0s
|
||||
t = t.substr(p0, p1 + 1 - p0); // Length at least 3
|
||||
if (t == "NAN" || t == "1.#QNAN" || t == "1.#SNAN" || t == "1.#IND" ||
|
||||
t == "1.#R")
|
||||
return Math::NaN<T>();
|
||||
else if (t == "INF" || t == "1.#INF")
|
||||
return sign * Math::infinity<T>();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a simple fraction, e.g., 3/4, from a string to an object of type T.
|
||||
*
|
||||
* @tparam T the type of the return value.
|
||||
* @param[in] s the string to be converted.
|
||||
* @exception GeographicErr is \e s is not readable as a fraction of type
|
||||
* T.
|
||||
* @return object of type T
|
||||
*
|
||||
* \note The msys shell under Windows converts arguments which look like
|
||||
* pathnames into their Windows equivalents. As a result the argument
|
||||
* "-1/300" gets mangled into something unrecognizable. A workaround is to
|
||||
* use a floating point number in the numerator, i.e., "-1.0/300". (Recent
|
||||
* versions of the msys shell appear \e not to have this problem.)
|
||||
**********************************************************************/
|
||||
template<typename T> static T fract(const std::string& s) {
|
||||
std::string::size_type delim = s.find('/');
|
||||
return
|
||||
!(delim != std::string::npos && delim >= 1 && delim + 2 <= s.size()) ?
|
||||
val<T>(s) :
|
||||
// delim in [1, size() - 2]
|
||||
val<T>(s.substr(0, delim)) / val<T>(s.substr(delim + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup up a character in a string.
|
||||
*
|
||||
* @param[in] s the string to be searched.
|
||||
* @param[in] c the character to look for.
|
||||
* @return the index of the first occurrence character in the string or
|
||||
* −1 is the character is not present.
|
||||
*
|
||||
* \e c is converted to upper case before search \e s. Therefore, it is
|
||||
* intended that \e s should not contain any lower case letters.
|
||||
**********************************************************************/
|
||||
static int lookup(const std::string& s, char c) {
|
||||
std::string::size_type r = s.find(char(std::toupper(c)));
|
||||
return r == std::string::npos ? -1 : int(r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup up a character in a char*.
|
||||
*
|
||||
* @param[in] s the char* string to be searched.
|
||||
* @param[in] c the character to look for.
|
||||
* @return the index of the first occurrence character in the string or
|
||||
* −1 is the character is not present.
|
||||
*
|
||||
* \e c is converted to upper case before search \e s. Therefore, it is
|
||||
* intended that \e s should not contain any lower case letters.
|
||||
**********************************************************************/
|
||||
static int lookup(const char* s, char c) {
|
||||
const char* p = std::strchr(s, std::toupper(c));
|
||||
return p != NULL ? int(p - s) : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data of type ExtT from a binary stream to an array of type IntT.
|
||||
* The data in the file is in (bigendp ? big : little)-endian format.
|
||||
*
|
||||
* @tparam ExtT the type of the objects in the binary stream (external).
|
||||
* @tparam IntT the type of the objects in the array (internal).
|
||||
* @tparam bigendp true if the external storage format is big-endian.
|
||||
* @param[in] str the input stream containing the data of type ExtT
|
||||
* (external).
|
||||
* @param[out] array the output array of type IntT (internal).
|
||||
* @param[in] num the size of the array.
|
||||
* @exception GeographicErr if the data cannot be read.
|
||||
**********************************************************************/
|
||||
template<typename ExtT, typename IntT, bool bigendp>
|
||||
static void readarray(std::istream& str, IntT array[], size_t num) {
|
||||
#if GEOGRAPHICLIB_PRECISION < 4
|
||||
if (sizeof(IntT) == sizeof(ExtT) &&
|
||||
std::numeric_limits<IntT>::is_integer ==
|
||||
std::numeric_limits<ExtT>::is_integer)
|
||||
{
|
||||
// Data is compatible (aside from the issue of endian-ness).
|
||||
str.read(reinterpret_cast<char*>(array), num * sizeof(ExtT));
|
||||
if (!str.good())
|
||||
throw GeographicErr("Failure reading data");
|
||||
if (bigendp != Math::bigendian) { // endian mismatch -> swap bytes
|
||||
for (size_t i = num; i--;)
|
||||
array[i] = Math::swab<IntT>(array[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
const int bufsize = 1024; // read this many values at a time
|
||||
ExtT buffer[bufsize]; // temporary buffer
|
||||
int k = int(num); // data values left to read
|
||||
int i = 0; // index into output array
|
||||
while (k) {
|
||||
int n = (std::min)(k, bufsize);
|
||||
str.read(reinterpret_cast<char*>(buffer), n * sizeof(ExtT));
|
||||
if (!str.good())
|
||||
throw GeographicErr("Failure reading data");
|
||||
for (int j = 0; j < n; ++j)
|
||||
// fix endian-ness and cast to IntT
|
||||
array[i++] = IntT(bigendp == Math::bigendian ? buffer[j] :
|
||||
Math::swab<ExtT>(buffer[j]));
|
||||
k -= n;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read data of type ExtT from a binary stream to a vector array of type
|
||||
* IntT. The data in the file is in (bigendp ? big : little)-endian
|
||||
* format.
|
||||
*
|
||||
* @tparam ExtT the type of the objects in the binary stream (external).
|
||||
* @tparam IntT the type of the objects in the array (internal).
|
||||
* @tparam bigendp true if the external storage format is big-endian.
|
||||
* @param[in] str the input stream containing the data of type ExtT
|
||||
* (external).
|
||||
* @param[out] array the output vector of type IntT (internal).
|
||||
* @exception GeographicErr if the data cannot be read.
|
||||
**********************************************************************/
|
||||
template<typename ExtT, typename IntT, bool bigendp>
|
||||
static void readarray(std::istream& str, std::vector<IntT>& array) {
|
||||
if (array.size() > 0)
|
||||
readarray<ExtT, IntT, bigendp>(str, &array[0], array.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data in an array of type IntT as type ExtT to a binary stream.
|
||||
* The data in the file is in (bigendp ? big : little)-endian format.
|
||||
*
|
||||
* @tparam ExtT the type of the objects in the binary stream (external).
|
||||
* @tparam IntT the type of the objects in the array (internal).
|
||||
* @tparam bigendp true if the external storage format is big-endian.
|
||||
* @param[out] str the output stream for the data of type ExtT (external).
|
||||
* @param[in] array the input array of type IntT (internal).
|
||||
* @param[in] num the size of the array.
|
||||
* @exception GeographicErr if the data cannot be written.
|
||||
**********************************************************************/
|
||||
template<typename ExtT, typename IntT, bool bigendp>
|
||||
static void writearray(std::ostream& str, const IntT array[], size_t num)
|
||||
{
|
||||
#if GEOGRAPHICLIB_PRECISION < 4
|
||||
if (sizeof(IntT) == sizeof(ExtT) &&
|
||||
std::numeric_limits<IntT>::is_integer ==
|
||||
std::numeric_limits<ExtT>::is_integer &&
|
||||
bigendp == Math::bigendian)
|
||||
{
|
||||
// Data is compatible (including endian-ness).
|
||||
str.write(reinterpret_cast<const char*>(array), num * sizeof(ExtT));
|
||||
if (!str.good())
|
||||
throw GeographicErr("Failure writing data");
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
const int bufsize = 1024; // write this many values at a time
|
||||
ExtT buffer[bufsize]; // temporary buffer
|
||||
int k = int(num); // data values left to write
|
||||
int i = 0; // index into output array
|
||||
while (k) {
|
||||
int n = (std::min)(k, bufsize);
|
||||
for (int j = 0; j < n; ++j)
|
||||
// cast to ExtT and fix endian-ness
|
||||
buffer[j] = bigendp == Math::bigendian ? ExtT(array[i++]) :
|
||||
Math::swab<ExtT>(ExtT(array[i++]));
|
||||
str.write(reinterpret_cast<const char*>(buffer), n * sizeof(ExtT));
|
||||
if (!str.good())
|
||||
throw GeographicErr("Failure writing data");
|
||||
k -= n;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data in an array of type IntT as type ExtT to a binary stream.
|
||||
* The data in the file is in (bigendp ? big : little)-endian format.
|
||||
*
|
||||
* @tparam ExtT the type of the objects in the binary stream (external).
|
||||
* @tparam IntT the type of the objects in the array (internal).
|
||||
* @tparam bigendp true if the external storage format is big-endian.
|
||||
* @param[out] str the output stream for the data of type ExtT (external).
|
||||
* @param[in] array the input vector of type IntT (internal).
|
||||
* @exception GeographicErr if the data cannot be written.
|
||||
**********************************************************************/
|
||||
template<typename ExtT, typename IntT, bool bigendp>
|
||||
static void writearray(std::ostream& str, std::vector<IntT>& array) {
|
||||
if (array.size() > 0)
|
||||
writearray<ExtT, IntT, bigendp>(str, &array[0], array.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a KEY [=] VALUE line.
|
||||
*
|
||||
* @param[in] line the input line.
|
||||
* @param[out] key the KEY.
|
||||
* @param[out] value the VALUE.
|
||||
* @param[in] delim delimiter to separate KEY and VALUE, if NULL use first
|
||||
* space character.
|
||||
* @exception std::bad_alloc if memory for the internal strings can't be
|
||||
* allocated.
|
||||
* @return whether a key was found.
|
||||
*
|
||||
* A "#" character and everything after it are discarded and the result
|
||||
* trimmed of leading and trailing white space. Use the delimiter
|
||||
* character (or, if it is NULL, the first white space) to separate \e key
|
||||
* and \e value. \e key and \e value are trimmed of leading and trailing
|
||||
* white space. If \e key is empty, then \e value is set to "" and false
|
||||
* is returned.
|
||||
**********************************************************************/
|
||||
static bool ParseLine(const std::string& line,
|
||||
std::string& key, std::string& value,
|
||||
char delim);
|
||||
|
||||
/**
|
||||
* Parse a KEY VALUE line.
|
||||
*
|
||||
* @param[in] line the input line.
|
||||
* @param[out] key the KEY.
|
||||
* @param[out] value the VALUE.
|
||||
* @exception std::bad_alloc if memory for the internal strings can't be
|
||||
* allocated.
|
||||
* @return whether a key was found.
|
||||
*
|
||||
* \note This is a transition routine. At some point \e delim will be made
|
||||
* an optional argument in the previous version of ParseLine and this
|
||||
* version will be removed.
|
||||
**********************************************************************/
|
||||
|
||||
static bool ParseLine(const std::string& line,
|
||||
std::string& key, std::string& value);
|
||||
|
||||
/**
|
||||
* Set the binary precision of a real number.
|
||||
*
|
||||
* @param[in] ndigits the number of bits of precision. If ndigits is 0
|
||||
* (the default), then determine the precision from the environment
|
||||
* variable GEOGRAPHICLIB_DIGITS. If this is undefined, use ndigits =
|
||||
* 256 (i.e., about 77 decimal digits).
|
||||
* @return the resulting number of bits of precision.
|
||||
*
|
||||
* This only has an effect when GEOGRAPHICLIB_PRECISION = 5. The
|
||||
* precision should only be set once and before calls to any other
|
||||
* GeographicLib functions. (Several functions, for example Math::pi(),
|
||||
* cache the return value in a static local variable. The precision needs
|
||||
* to be set before a call to any such functions.) In multi-threaded
|
||||
* applications, it is necessary also to set the precision in each thread
|
||||
* (see the example GeoidToGTX.cpp).
|
||||
**********************************************************************/
|
||||
static int set_digits(int ndigits = 0);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The specialization of Utility::val<T>() for strings.
|
||||
**********************************************************************/
|
||||
template<> inline std::string Utility::val<std::string>(const std::string& s)
|
||||
{ return trim(s); }
|
||||
|
||||
/**
|
||||
* The specialization of Utility::val<T>() for bools.
|
||||
**********************************************************************/
|
||||
template<> inline bool Utility::val<bool>(const std::string& s) {
|
||||
std::string t(trim(s));
|
||||
if (t.empty()) return false;
|
||||
bool x;
|
||||
{
|
||||
std::istringstream is(t);
|
||||
if (is >> x) {
|
||||
int pos = int(is.tellg()); // Returns -1 at end of string?
|
||||
if (!(pos < 0 || pos == int(t.size())))
|
||||
throw GeographicErr("Extra text " + t.substr(pos) +
|
||||
" at end of " + t);
|
||||
return x;
|
||||
}
|
||||
}
|
||||
for (std::string::iterator p = t.begin(); p != t.end(); ++p)
|
||||
*p = char(std::tolower(*p));
|
||||
switch (t[0]) { // already checked that t isn't empty
|
||||
case 'f':
|
||||
if (t == "f" || t == "false") return false;
|
||||
break;
|
||||
case 'n':
|
||||
if (t == "n" || t == "nil" || t == "no") return false;
|
||||
break;
|
||||
case 'o':
|
||||
if (t == "off") return false;
|
||||
else if (t == "on") return true;
|
||||
break;
|
||||
case 't':
|
||||
if (t == "t" || t == "true") return true;
|
||||
break;
|
||||
case 'y':
|
||||
if (t == "y" || t == "yes") return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw GeographicErr("Cannot decode " + t + " as a bool");
|
||||
}
|
||||
|
||||
} // namespace GeographicLib
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif // GEOGRAPHICLIB_UTILITY_HPP
|
||||
Reference in New Issue
Block a user