geographiclib 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/AUTHORS +12 -0
- data/LICENSE +24 -0
- data/ext/geographiclib/Accumulator.cpp +23 -0
- data/ext/geographiclib/AlbersEqualArea.cpp +445 -0
- data/ext/geographiclib/AzimuthalEquidistant.cpp +41 -0
- data/ext/geographiclib/CassiniSoldner.cpp +89 -0
- data/ext/geographiclib/CircularEngine.cpp +96 -0
- data/ext/geographiclib/DMS.cpp +381 -0
- data/ext/geographiclib/Ellipsoid.cpp +125 -0
- data/ext/geographiclib/EllipticFunction.cpp +512 -0
- data/ext/geographiclib/GARS.cpp +122 -0
- data/ext/geographiclib/GeoCoords.cpp +175 -0
- data/ext/geographiclib/Geocentric.cpp +172 -0
- data/ext/geographiclib/Geodesic.cpp +1908 -0
- data/ext/geographiclib/GeodesicExact.cpp +927 -0
- data/ext/geographiclib/GeodesicExactC4.cpp +7879 -0
- data/ext/geographiclib/GeodesicLine.cpp +321 -0
- data/ext/geographiclib/GeodesicLineExact.cpp +289 -0
- data/ext/geographiclib/GeographicLib/Accumulator.hpp +184 -0
- data/ext/geographiclib/GeographicLib/AlbersEqualArea.hpp +312 -0
- data/ext/geographiclib/GeographicLib/AzimuthalEquidistant.hpp +139 -0
- data/ext/geographiclib/GeographicLib/CassiniSoldner.hpp +204 -0
- data/ext/geographiclib/GeographicLib/CircularEngine.hpp +195 -0
- data/ext/geographiclib/GeographicLib/Config.h +12 -0
- data/ext/geographiclib/GeographicLib/Constants.hpp +387 -0
- data/ext/geographiclib/GeographicLib/DMS.hpp +370 -0
- data/ext/geographiclib/GeographicLib/Ellipsoid.hpp +534 -0
- data/ext/geographiclib/GeographicLib/EllipticFunction.hpp +692 -0
- data/ext/geographiclib/GeographicLib/GARS.hpp +143 -0
- data/ext/geographiclib/GeographicLib/GeoCoords.hpp +544 -0
- data/ext/geographiclib/GeographicLib/Geocentric.hpp +267 -0
- data/ext/geographiclib/GeographicLib/Geodesic.hpp +970 -0
- data/ext/geographiclib/GeographicLib/GeodesicExact.hpp +862 -0
- data/ext/geographiclib/GeographicLib/GeodesicLine.hpp +701 -0
- data/ext/geographiclib/GeographicLib/GeodesicLineExact.hpp +667 -0
- data/ext/geographiclib/GeographicLib/Geohash.hpp +180 -0
- data/ext/geographiclib/GeographicLib/Geoid.hpp +472 -0
- data/ext/geographiclib/GeographicLib/Georef.hpp +160 -0
- data/ext/geographiclib/GeographicLib/Gnomonic.hpp +206 -0
- data/ext/geographiclib/GeographicLib/GravityCircle.hpp +301 -0
- data/ext/geographiclib/GeographicLib/GravityModel.hpp +520 -0
- data/ext/geographiclib/GeographicLib/LambertConformalConic.hpp +313 -0
- data/ext/geographiclib/GeographicLib/LocalCartesian.hpp +236 -0
- data/ext/geographiclib/GeographicLib/MGRS.hpp +355 -0
- data/ext/geographiclib/GeographicLib/MagneticCircle.hpp +178 -0
- data/ext/geographiclib/GeographicLib/MagneticModel.hpp +347 -0
- data/ext/geographiclib/GeographicLib/Math.hpp +920 -0
- data/ext/geographiclib/GeographicLib/NormalGravity.hpp +350 -0
- data/ext/geographiclib/GeographicLib/OSGB.hpp +249 -0
- data/ext/geographiclib/GeographicLib/PolarStereographic.hpp +150 -0
- data/ext/geographiclib/GeographicLib/PolygonArea.hpp +288 -0
- data/ext/geographiclib/GeographicLib/Rhumb.hpp +589 -0
- data/ext/geographiclib/GeographicLib/SphericalEngine.hpp +376 -0
- data/ext/geographiclib/GeographicLib/SphericalHarmonic.hpp +354 -0
- data/ext/geographiclib/GeographicLib/SphericalHarmonic1.hpp +281 -0
- data/ext/geographiclib/GeographicLib/SphericalHarmonic2.hpp +315 -0
- data/ext/geographiclib/GeographicLib/TransverseMercator.hpp +196 -0
- data/ext/geographiclib/GeographicLib/TransverseMercatorExact.hpp +254 -0
- data/ext/geographiclib/GeographicLib/UTMUPS.hpp +421 -0
- data/ext/geographiclib/GeographicLib/Utility.hpp +612 -0
- data/ext/geographiclib/Geohash.cpp +102 -0
- data/ext/geographiclib/Geoid.cpp +509 -0
- data/ext/geographiclib/Georef.cpp +135 -0
- data/ext/geographiclib/Gnomonic.cpp +85 -0
- data/ext/geographiclib/GravityCircle.cpp +129 -0
- data/ext/geographiclib/GravityModel.cpp +360 -0
- data/ext/geographiclib/LambertConformalConic.cpp +456 -0
- data/ext/geographiclib/LocalCartesian.cpp +62 -0
- data/ext/geographiclib/MGRS.cpp +461 -0
- data/ext/geographiclib/MagneticCircle.cpp +52 -0
- data/ext/geographiclib/MagneticModel.cpp +269 -0
- data/ext/geographiclib/Math.cpp +63 -0
- data/ext/geographiclib/NormalGravity.cpp +262 -0
- data/ext/geographiclib/OSGB.cpp +167 -0
- data/ext/geographiclib/PolarStereographic.cpp +108 -0
- data/ext/geographiclib/PolygonArea.cpp +204 -0
- data/ext/geographiclib/Rhumb.cpp +383 -0
- data/ext/geographiclib/SphericalEngine.cpp +477 -0
- data/ext/geographiclib/TransverseMercator.cpp +603 -0
- data/ext/geographiclib/TransverseMercatorExact.cpp +464 -0
- data/ext/geographiclib/UTMUPS.cpp +296 -0
- data/ext/geographiclib/Utility.cpp +61 -0
- data/ext/geographiclib/extconf.rb +3 -0
- data/ext/geographiclib/geographiclib.cpp +62 -0
- data/lib/geographiclib.rb +20 -0
- metadata +140 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* \file MagneticModel.hpp
|
|
3
|
+
* \brief Header for GeographicLib::MagneticModel class
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) Charles Karney (2011-2015) <charles@karney.com> and licensed
|
|
6
|
+
* under the MIT/X11 License. For more information, see
|
|
7
|
+
* http://geographiclib.sourceforge.net/
|
|
8
|
+
**********************************************************************/
|
|
9
|
+
|
|
10
|
+
#if !defined(GEOGRAPHICLIB_MAGNETICMODEL_HPP)
|
|
11
|
+
#define GEOGRAPHICLIB_MAGNETICMODEL_HPP 1
|
|
12
|
+
|
|
13
|
+
#include <GeographicLib/Constants.hpp>
|
|
14
|
+
#include <GeographicLib/Geocentric.hpp>
|
|
15
|
+
#include <GeographicLib/SphericalHarmonic.hpp>
|
|
16
|
+
|
|
17
|
+
#if defined(_MSC_VER)
|
|
18
|
+
// Squelch warnings about dll vs vector
|
|
19
|
+
# pragma warning (push)
|
|
20
|
+
# pragma warning (disable: 4251)
|
|
21
|
+
#endif
|
|
22
|
+
|
|
23
|
+
namespace GeographicLib {
|
|
24
|
+
|
|
25
|
+
class MagneticCircle;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* \brief Model of the earth's magnetic field
|
|
29
|
+
*
|
|
30
|
+
* Evaluate the earth's magnetic field according to a model. At present only
|
|
31
|
+
* internal magnetic fields are handled. These are due to the earth's code
|
|
32
|
+
* and crust; these vary slowly (over many years). Excluded are the effects
|
|
33
|
+
* of currents in the ionosphere and magnetosphere which have daily and
|
|
34
|
+
* annual variations.
|
|
35
|
+
*
|
|
36
|
+
* See \ref magnetic for details of how to install the magnetic models and
|
|
37
|
+
* the data format.
|
|
38
|
+
*
|
|
39
|
+
* See
|
|
40
|
+
* - General information:
|
|
41
|
+
* - http://geomag.org/models/index.html
|
|
42
|
+
* - WMM2010:
|
|
43
|
+
* - http://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml
|
|
44
|
+
* - http://ngdc.noaa.gov/geomag/WMM/data/WMM2010/WMM2010COF.zip
|
|
45
|
+
* - WMM2015:
|
|
46
|
+
* - http://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml
|
|
47
|
+
* - http://ngdc.noaa.gov/geomag/WMM/data/WMM2015/WMM2015COF.zip
|
|
48
|
+
* - IGRF11:
|
|
49
|
+
* - http://ngdc.noaa.gov/IAGA/vmod/igrf.html
|
|
50
|
+
* - http://ngdc.noaa.gov/IAGA/vmod/igrf11coeffs.txt
|
|
51
|
+
* - http://ngdc.noaa.gov/IAGA/vmod/geomag70_linux.tar.gz
|
|
52
|
+
* - EMM2010:
|
|
53
|
+
* - http://ngdc.noaa.gov/geomag/EMM/index.html
|
|
54
|
+
* - http://ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2010_Sph_Windows_Linux.zip
|
|
55
|
+
*
|
|
56
|
+
* Example of use:
|
|
57
|
+
* \include example-MagneticModel.cpp
|
|
58
|
+
*
|
|
59
|
+
* <a href="MagneticField.1.html">MagneticField</a> is a command-line utility
|
|
60
|
+
* providing access to the functionality of MagneticModel and MagneticCircle.
|
|
61
|
+
**********************************************************************/
|
|
62
|
+
|
|
63
|
+
class GEOGRAPHICLIB_EXPORT MagneticModel {
|
|
64
|
+
private:
|
|
65
|
+
typedef Math::real real;
|
|
66
|
+
static const int idlength_ = 8;
|
|
67
|
+
std::string _name, _dir, _description, _date, _filename, _id;
|
|
68
|
+
real _t0, _dt0, _tmin, _tmax, _a, _hmin, _hmax;
|
|
69
|
+
int _Nmodels, _Nconstants;
|
|
70
|
+
SphericalHarmonic::normalization _norm;
|
|
71
|
+
Geocentric _earth;
|
|
72
|
+
std::vector< std::vector<real> > _G;
|
|
73
|
+
std::vector< std::vector<real> > _H;
|
|
74
|
+
std::vector<SphericalHarmonic> _harm;
|
|
75
|
+
void Field(real t, real lat, real lon, real h, bool diffp,
|
|
76
|
+
real& Bx, real& By, real& Bz,
|
|
77
|
+
real& Bxt, real& Byt, real& Bzt) const;
|
|
78
|
+
void ReadMetadata(const std::string& name);
|
|
79
|
+
MagneticModel(const MagneticModel&); // copy constructor not allowed
|
|
80
|
+
MagneticModel& operator=(const MagneticModel&); // nor copy assignment
|
|
81
|
+
public:
|
|
82
|
+
|
|
83
|
+
/** \name Setting up the magnetic model
|
|
84
|
+
**********************************************************************/
|
|
85
|
+
///@{
|
|
86
|
+
/**
|
|
87
|
+
* Construct a magnetic model.
|
|
88
|
+
*
|
|
89
|
+
* @param[in] name the name of the model.
|
|
90
|
+
* @param[in] path (optional) directory for data file.
|
|
91
|
+
* @param[in] earth (optional) Geocentric object for converting
|
|
92
|
+
* coordinates; default Geocentric::WGS84().
|
|
93
|
+
* @exception GeographicErr if the data file cannot be found, is
|
|
94
|
+
* unreadable, or is corrupt.
|
|
95
|
+
* @exception std::bad_alloc if the memory necessary for storing the model
|
|
96
|
+
* can't be allocated.
|
|
97
|
+
*
|
|
98
|
+
* A filename is formed by appending ".wmm" (World Magnetic Model) to the
|
|
99
|
+
* name. If \e path is specified (and is non-empty), then the file is
|
|
100
|
+
* loaded from directory, \e path. Otherwise the path is given by the
|
|
101
|
+
* DefaultMagneticPath().
|
|
102
|
+
*
|
|
103
|
+
* This file contains the metadata which specifies the properties of the
|
|
104
|
+
* model. The coefficients for the spherical harmonic sums are obtained
|
|
105
|
+
* from a file obtained by appending ".cof" to metadata file (so the
|
|
106
|
+
* filename ends in ".wwm.cof").
|
|
107
|
+
*
|
|
108
|
+
* The model is not tied to a particular ellipsoidal model of the earth.
|
|
109
|
+
* The final earth argument to the constructor specifies an ellipsoid to
|
|
110
|
+
* allow geodetic coordinates to the transformed into the spherical
|
|
111
|
+
* coordinates used in the spherical harmonic sum.
|
|
112
|
+
**********************************************************************/
|
|
113
|
+
explicit MagneticModel(const std::string& name,
|
|
114
|
+
const std::string& path = "",
|
|
115
|
+
const Geocentric& earth = Geocentric::WGS84());
|
|
116
|
+
///@}
|
|
117
|
+
|
|
118
|
+
/** \name Compute the magnetic field
|
|
119
|
+
**********************************************************************/
|
|
120
|
+
///@{
|
|
121
|
+
/**
|
|
122
|
+
* Evaluate the components of the geomagnetic field.
|
|
123
|
+
*
|
|
124
|
+
* @param[in] t the time (years).
|
|
125
|
+
* @param[in] lat latitude of the point (degrees).
|
|
126
|
+
* @param[in] lon longitude of the point (degrees).
|
|
127
|
+
* @param[in] h the height of the point above the ellipsoid (meters).
|
|
128
|
+
* @param[out] Bx the easterly component of the magnetic field (nanotesla).
|
|
129
|
+
* @param[out] By the northerly component of the magnetic field (nanotesla).
|
|
130
|
+
* @param[out] Bz the vertical (up) component of the magnetic field
|
|
131
|
+
* (nanotesla).
|
|
132
|
+
**********************************************************************/
|
|
133
|
+
void operator()(real t, real lat, real lon, real h,
|
|
134
|
+
real& Bx, real& By, real& Bz) const {
|
|
135
|
+
real dummy;
|
|
136
|
+
Field(t, lat, lon, h, false, Bx, By, Bz, dummy, dummy, dummy);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Evaluate the components of the geomagnetic field and their time
|
|
141
|
+
* derivatives
|
|
142
|
+
*
|
|
143
|
+
* @param[in] t the time (years).
|
|
144
|
+
* @param[in] lat latitude of the point (degrees).
|
|
145
|
+
* @param[in] lon longitude of the point (degrees).
|
|
146
|
+
* @param[in] h the height of the point above the ellipsoid (meters).
|
|
147
|
+
* @param[out] Bx the easterly component of the magnetic field (nanotesla).
|
|
148
|
+
* @param[out] By the northerly component of the magnetic field (nanotesla).
|
|
149
|
+
* @param[out] Bz the vertical (up) component of the magnetic field
|
|
150
|
+
* (nanotesla).
|
|
151
|
+
* @param[out] Bxt the rate of change of \e Bx (nT/yr).
|
|
152
|
+
* @param[out] Byt the rate of change of \e By (nT/yr).
|
|
153
|
+
* @param[out] Bzt the rate of change of \e Bz (nT/yr).
|
|
154
|
+
**********************************************************************/
|
|
155
|
+
void operator()(real t, real lat, real lon, real h,
|
|
156
|
+
real& Bx, real& By, real& Bz,
|
|
157
|
+
real& Bxt, real& Byt, real& Bzt) const {
|
|
158
|
+
Field(t, lat, lon, h, true, Bx, By, Bz, Bxt, Byt, Bzt);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Create a MagneticCircle object to allow the geomagnetic field at many
|
|
163
|
+
* points with constant \e lat, \e h, and \e t and varying \e lon to be
|
|
164
|
+
* computed efficiently.
|
|
165
|
+
*
|
|
166
|
+
* @param[in] t the time (years).
|
|
167
|
+
* @param[in] lat latitude of the point (degrees).
|
|
168
|
+
* @param[in] h the height of the point above the ellipsoid (meters).
|
|
169
|
+
* @exception std::bad_alloc if the memory necessary for creating a
|
|
170
|
+
* MagneticCircle can't be allocated.
|
|
171
|
+
* @return a MagneticCircle object whose MagneticCircle::operator()(real
|
|
172
|
+
* lon) member function computes the field at particular values of \e
|
|
173
|
+
* lon.
|
|
174
|
+
*
|
|
175
|
+
* If the field at several points on a circle of latitude need to be
|
|
176
|
+
* calculated then creating a MagneticCircle and using its member functions
|
|
177
|
+
* will be substantially faster, especially for high-degree models.
|
|
178
|
+
**********************************************************************/
|
|
179
|
+
MagneticCircle Circle(real t, real lat, real h) const;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Compute various quantities dependent on the magnetic field.
|
|
183
|
+
*
|
|
184
|
+
* @param[in] Bx the \e x (easterly) component of the magnetic field (nT).
|
|
185
|
+
* @param[in] By the \e y (northerly) component of the magnetic field (nT).
|
|
186
|
+
* @param[in] Bz the \e z (vertical, up positive) component of the magnetic
|
|
187
|
+
* field (nT).
|
|
188
|
+
* @param[out] H the horizontal magnetic field (nT).
|
|
189
|
+
* @param[out] F the total magnetic field (nT).
|
|
190
|
+
* @param[out] D the declination of the field (degrees east of north).
|
|
191
|
+
* @param[out] I the inclination of the field (degrees down from
|
|
192
|
+
* horizontal).
|
|
193
|
+
**********************************************************************/
|
|
194
|
+
static void FieldComponents(real Bx, real By, real Bz,
|
|
195
|
+
real& H, real& F, real& D, real& I) {
|
|
196
|
+
real Ht, Ft, Dt, It;
|
|
197
|
+
FieldComponents(Bx, By, Bz, real(0), real(1), real(0),
|
|
198
|
+
H, F, D, I, Ht, Ft, Dt, It);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Compute various quantities dependent on the magnetic field and its rate
|
|
203
|
+
* of change.
|
|
204
|
+
*
|
|
205
|
+
* @param[in] Bx the \e x (easterly) component of the magnetic field (nT).
|
|
206
|
+
* @param[in] By the \e y (northerly) component of the magnetic field (nT).
|
|
207
|
+
* @param[in] Bz the \e z (vertical, up positive) component of the magnetic
|
|
208
|
+
* field (nT).
|
|
209
|
+
* @param[in] Bxt the rate of change of \e Bx (nT/yr).
|
|
210
|
+
* @param[in] Byt the rate of change of \e By (nT/yr).
|
|
211
|
+
* @param[in] Bzt the rate of change of \e Bz (nT/yr).
|
|
212
|
+
* @param[out] H the horizontal magnetic field (nT).
|
|
213
|
+
* @param[out] F the total magnetic field (nT).
|
|
214
|
+
* @param[out] D the declination of the field (degrees east of north).
|
|
215
|
+
* @param[out] I the inclination of the field (degrees down from
|
|
216
|
+
* horizontal).
|
|
217
|
+
* @param[out] Ht the rate of change of \e H (nT/yr).
|
|
218
|
+
* @param[out] Ft the rate of change of \e F (nT/yr).
|
|
219
|
+
* @param[out] Dt the rate of change of \e D (degrees/yr).
|
|
220
|
+
* @param[out] It the rate of change of \e I (degrees/yr).
|
|
221
|
+
**********************************************************************/
|
|
222
|
+
static void FieldComponents(real Bx, real By, real Bz,
|
|
223
|
+
real Bxt, real Byt, real Bzt,
|
|
224
|
+
real& H, real& F, real& D, real& I,
|
|
225
|
+
real& Ht, real& Ft, real& Dt, real& It);
|
|
226
|
+
///@}
|
|
227
|
+
|
|
228
|
+
/** \name Inspector functions
|
|
229
|
+
**********************************************************************/
|
|
230
|
+
///@{
|
|
231
|
+
/**
|
|
232
|
+
* @return the description of the magnetic model, if available, from the
|
|
233
|
+
* Description file in the data file; if absent, return "NONE".
|
|
234
|
+
**********************************************************************/
|
|
235
|
+
const std::string& Description() const { return _description; }
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* @return date of the model, if available, from the ReleaseDate field in
|
|
239
|
+
* the data file; if absent, return "UNKNOWN".
|
|
240
|
+
**********************************************************************/
|
|
241
|
+
const std::string& DateTime() const { return _date; }
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* @return full file name used to load the magnetic model.
|
|
245
|
+
**********************************************************************/
|
|
246
|
+
const std::string& MagneticFile() const { return _filename; }
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* @return "name" used to load the magnetic model (from the first argument
|
|
250
|
+
* of the constructor, but this may be overridden by the model file).
|
|
251
|
+
**********************************************************************/
|
|
252
|
+
const std::string& MagneticModelName() const { return _name; }
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @return directory used to load the magnetic model.
|
|
256
|
+
**********************************************************************/
|
|
257
|
+
const std::string& MagneticModelDirectory() const { return _dir; }
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* @return the minimum height above the ellipsoid (in meters) for which
|
|
261
|
+
* this MagneticModel should be used.
|
|
262
|
+
*
|
|
263
|
+
* Because the model will typically provide useful results
|
|
264
|
+
* slightly outside the range of allowed heights, no check of \e t
|
|
265
|
+
* argument is made by MagneticModel::operator()() or
|
|
266
|
+
* MagneticModel::Circle.
|
|
267
|
+
**********************************************************************/
|
|
268
|
+
Math::real MinHeight() const { return _hmin; }
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* @return the maximum height above the ellipsoid (in meters) for which
|
|
272
|
+
* this MagneticModel should be used.
|
|
273
|
+
*
|
|
274
|
+
* Because the model will typically provide useful results
|
|
275
|
+
* slightly outside the range of allowed heights, no check of \e t
|
|
276
|
+
* argument is made by MagneticModel::operator()() or
|
|
277
|
+
* MagneticModel::Circle.
|
|
278
|
+
**********************************************************************/
|
|
279
|
+
Math::real MaxHeight() const { return _hmax; }
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* @return the minimum time (in years) for which this MagneticModel should
|
|
283
|
+
* be used.
|
|
284
|
+
*
|
|
285
|
+
* Because the model will typically provide useful results
|
|
286
|
+
* slightly outside the range of allowed times, no check of \e t
|
|
287
|
+
* argument is made by MagneticModel::operator()() or
|
|
288
|
+
* MagneticModel::Circle.
|
|
289
|
+
**********************************************************************/
|
|
290
|
+
Math::real MinTime() const { return _tmin; }
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @return the maximum time (in years) for which this MagneticModel should
|
|
294
|
+
* be used.
|
|
295
|
+
*
|
|
296
|
+
* Because the model will typically provide useful results
|
|
297
|
+
* slightly outside the range of allowed times, no check of \e t
|
|
298
|
+
* argument is made by MagneticModel::operator()() or
|
|
299
|
+
* MagneticModel::Circle.
|
|
300
|
+
**********************************************************************/
|
|
301
|
+
Math::real MaxTime() const { return _tmax; }
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* @return \e a the equatorial radius of the ellipsoid (meters). This is
|
|
305
|
+
* the value of \e a inherited from the Geocentric object used in the
|
|
306
|
+
* constructor.
|
|
307
|
+
**********************************************************************/
|
|
308
|
+
Math::real MajorRadius() const { return _earth.MajorRadius(); }
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* @return \e f the flattening of the ellipsoid. This is the value
|
|
312
|
+
* inherited from the Geocentric object used in the constructor.
|
|
313
|
+
**********************************************************************/
|
|
314
|
+
Math::real Flattening() const { return _earth.Flattening(); }
|
|
315
|
+
///@}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* @return the default path for magnetic model data files.
|
|
319
|
+
*
|
|
320
|
+
* This is the value of the environment variable
|
|
321
|
+
* GEOGRAPHICLIB_MAGNETIC_PATH, if set; otherwise, it is
|
|
322
|
+
* $GEOGRAPHICLIB_DATA/magnetic if the environment variable
|
|
323
|
+
* GEOGRAPHICLIB_DATA is set; otherwise, it is a compile-time default
|
|
324
|
+
* (/usr/local/share/GeographicLib/magnetic on non-Windows systems and
|
|
325
|
+
* C:/ProgramData/GeographicLib/magnetic on Windows systems).
|
|
326
|
+
**********************************************************************/
|
|
327
|
+
static std::string DefaultMagneticPath();
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* @return the default name for the magnetic model.
|
|
331
|
+
*
|
|
332
|
+
* This is the value of the environment variable
|
|
333
|
+
* GEOGRAPHICLIB_MAGNETIC_NAME, if set; otherwise, it is "wmm2015". The
|
|
334
|
+
* MagneticModel class does not use this function; it is just provided as a
|
|
335
|
+
* convenience for a calling program when constructing a MagneticModel
|
|
336
|
+
* object.
|
|
337
|
+
**********************************************************************/
|
|
338
|
+
static std::string DefaultMagneticName();
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
} // namespace GeographicLib
|
|
342
|
+
|
|
343
|
+
#if defined(_MSC_VER)
|
|
344
|
+
# pragma warning (pop)
|
|
345
|
+
#endif
|
|
346
|
+
|
|
347
|
+
#endif // GEOGRAPHICLIB_MAGNETICMODEL_HPP
|
|
@@ -0,0 +1,920 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* \file Math.hpp
|
|
3
|
+
* \brief Header for GeographicLib::Math class
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) Charles Karney (2008-2016) <charles@karney.com> and licensed
|
|
6
|
+
* under the MIT/X11 License. For more information, see
|
|
7
|
+
* http://geographiclib.sourceforge.net/
|
|
8
|
+
**********************************************************************/
|
|
9
|
+
|
|
10
|
+
// Constants.hpp includes Math.hpp. Place this include outside Math.hpp's
|
|
11
|
+
// include guard to enforce this ordering.
|
|
12
|
+
#include <GeographicLib/Constants.hpp>
|
|
13
|
+
|
|
14
|
+
#if !defined(GEOGRAPHICLIB_MATH_HPP)
|
|
15
|
+
#define GEOGRAPHICLIB_MATH_HPP 1
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Are C++11 math functions available?
|
|
19
|
+
**********************************************************************/
|
|
20
|
+
#if !defined(GEOGRAPHICLIB_CXX11_MATH)
|
|
21
|
+
// Recent versions of g++ -std=c++11 (4.7 and later?) set __cplusplus to 201103
|
|
22
|
+
// and support the new C++11 mathematical functions, std::atanh, etc. However
|
|
23
|
+
// the Android toolchain, which uses g++ -std=c++11 (4.8 as of 2014-03-11,
|
|
24
|
+
// according to Pullan Lu), does not support std::atanh. Android toolchains
|
|
25
|
+
// might define __ANDROID__ or ANDROID; so need to check both. With OSX the
|
|
26
|
+
// version is GNUC version 4.2 and __cplusplus is set to 201103, so remove the
|
|
27
|
+
// version check on GNUC.
|
|
28
|
+
# if defined(__GNUC__) && __cplusplus >= 201103 && \
|
|
29
|
+
!(defined(__ANDROID__) || defined(ANDROID) || defined(__CYGWIN__))
|
|
30
|
+
# define GEOGRAPHICLIB_CXX11_MATH 1
|
|
31
|
+
// Visual C++ 12 supports these functions
|
|
32
|
+
# elif defined(_MSC_VER) && _MSC_VER >= 1800
|
|
33
|
+
# define GEOGRAPHICLIB_CXX11_MATH 1
|
|
34
|
+
# else
|
|
35
|
+
# define GEOGRAPHICLIB_CXX11_MATH 0
|
|
36
|
+
# endif
|
|
37
|
+
#endif
|
|
38
|
+
|
|
39
|
+
#if !defined(GEOGRAPHICLIB_WORDS_BIGENDIAN)
|
|
40
|
+
# define GEOGRAPHICLIB_WORDS_BIGENDIAN 0
|
|
41
|
+
#endif
|
|
42
|
+
|
|
43
|
+
#if !defined(GEOGRAPHICLIB_HAVE_LONG_DOUBLE)
|
|
44
|
+
# define GEOGRAPHICLIB_HAVE_LONG_DOUBLE 0
|
|
45
|
+
#endif
|
|
46
|
+
|
|
47
|
+
#if !defined(GEOGRAPHICLIB_PRECISION)
|
|
48
|
+
/**
|
|
49
|
+
* The precision of floating point numbers used in %GeographicLib. 1 means
|
|
50
|
+
* float (single precision); 2 (the default) means double; 3 means long double;
|
|
51
|
+
* 4 is reserved for quadruple precision. Nearly all the testing has been
|
|
52
|
+
* carried out with doubles and that's the recommended configuration. In order
|
|
53
|
+
* for long double to be used, GEOGRAPHICLIB_HAVE_LONG_DOUBLE needs to be
|
|
54
|
+
* defined. Note that with Microsoft Visual Studio, long double is the same as
|
|
55
|
+
* double.
|
|
56
|
+
**********************************************************************/
|
|
57
|
+
# define GEOGRAPHICLIB_PRECISION 2
|
|
58
|
+
#endif
|
|
59
|
+
|
|
60
|
+
#include <cmath>
|
|
61
|
+
#include <algorithm>
|
|
62
|
+
#include <limits>
|
|
63
|
+
|
|
64
|
+
#if GEOGRAPHICLIB_PRECISION == 4
|
|
65
|
+
#include <boost/version.hpp>
|
|
66
|
+
#if BOOST_VERSION >= 105600
|
|
67
|
+
#include <boost/cstdfloat.hpp>
|
|
68
|
+
#endif
|
|
69
|
+
#include <boost/multiprecision/float128.hpp>
|
|
70
|
+
#include <boost/math/special_functions.hpp>
|
|
71
|
+
__float128 fmaq(__float128, __float128, __float128);
|
|
72
|
+
#elif GEOGRAPHICLIB_PRECISION == 5
|
|
73
|
+
#include <mpreal.h>
|
|
74
|
+
#endif
|
|
75
|
+
|
|
76
|
+
#if GEOGRAPHICLIB_PRECISION > 3
|
|
77
|
+
// volatile keyword makes no sense for multiprec types
|
|
78
|
+
#define GEOGRAPHICLIB_VOLATILE
|
|
79
|
+
// Signal a convergence failure with multiprec types by throwing an exception
|
|
80
|
+
// at loop exit.
|
|
81
|
+
#define GEOGRAPHICLIB_PANIC \
|
|
82
|
+
(throw GeographicLib::GeographicErr("Convergence failure"), false)
|
|
83
|
+
#else
|
|
84
|
+
#define GEOGRAPHICLIB_VOLATILE volatile
|
|
85
|
+
// Ignore convergence failures with standard floating points types by allowing
|
|
86
|
+
// loop to exit cleanly.
|
|
87
|
+
#define GEOGRAPHICLIB_PANIC false
|
|
88
|
+
#endif
|
|
89
|
+
|
|
90
|
+
namespace GeographicLib {
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* \brief Mathematical functions needed by %GeographicLib
|
|
94
|
+
*
|
|
95
|
+
* Define mathematical functions in order to localize system dependencies and
|
|
96
|
+
* to provide generic versions of the functions. In addition define a real
|
|
97
|
+
* type to be used by %GeographicLib.
|
|
98
|
+
*
|
|
99
|
+
* Example of use:
|
|
100
|
+
* \include example-Math.cpp
|
|
101
|
+
**********************************************************************/
|
|
102
|
+
class GEOGRAPHICLIB_EXPORT Math {
|
|
103
|
+
private:
|
|
104
|
+
void dummy() {
|
|
105
|
+
GEOGRAPHICLIB_STATIC_ASSERT(GEOGRAPHICLIB_PRECISION >= 1 &&
|
|
106
|
+
GEOGRAPHICLIB_PRECISION <= 5,
|
|
107
|
+
"Bad value of precision");
|
|
108
|
+
}
|
|
109
|
+
Math(); // Disable constructor
|
|
110
|
+
public:
|
|
111
|
+
|
|
112
|
+
#if GEOGRAPHICLIB_HAVE_LONG_DOUBLE
|
|
113
|
+
/**
|
|
114
|
+
* The extended precision type for real numbers, used for some testing.
|
|
115
|
+
* This is long double on computers with this type; otherwise it is double.
|
|
116
|
+
**********************************************************************/
|
|
117
|
+
typedef long double extended;
|
|
118
|
+
#else
|
|
119
|
+
typedef double extended;
|
|
120
|
+
#endif
|
|
121
|
+
|
|
122
|
+
#if GEOGRAPHICLIB_PRECISION == 2
|
|
123
|
+
/**
|
|
124
|
+
* The real type for %GeographicLib. Nearly all the testing has been done
|
|
125
|
+
* with \e real = double. However, the algorithms should also work with
|
|
126
|
+
* float and long double (where available). (<b>CAUTION</b>: reasonable
|
|
127
|
+
* accuracy typically cannot be obtained using floats.)
|
|
128
|
+
**********************************************************************/
|
|
129
|
+
typedef double real;
|
|
130
|
+
#elif GEOGRAPHICLIB_PRECISION == 1
|
|
131
|
+
typedef float real;
|
|
132
|
+
#elif GEOGRAPHICLIB_PRECISION == 3
|
|
133
|
+
typedef extended real;
|
|
134
|
+
#elif GEOGRAPHICLIB_PRECISION == 4
|
|
135
|
+
typedef boost::multiprecision::float128 real;
|
|
136
|
+
#elif GEOGRAPHICLIB_PRECISION == 5
|
|
137
|
+
typedef mpfr::mpreal real;
|
|
138
|
+
#else
|
|
139
|
+
typedef double real;
|
|
140
|
+
#endif
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* @return the number of bits of precision in a real number.
|
|
144
|
+
**********************************************************************/
|
|
145
|
+
static inline int digits() {
|
|
146
|
+
#if GEOGRAPHICLIB_PRECISION != 5
|
|
147
|
+
return std::numeric_limits<real>::digits;
|
|
148
|
+
#else
|
|
149
|
+
return std::numeric_limits<real>::digits();
|
|
150
|
+
#endif
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Set the binary precision of a real number.
|
|
155
|
+
*
|
|
156
|
+
* @param[in] ndigits the number of bits of precision.
|
|
157
|
+
* @return the resulting number of bits of precision.
|
|
158
|
+
*
|
|
159
|
+
* This only has an effect when GEOGRAPHICLIB_PRECISION == 5. See also
|
|
160
|
+
* Utility::set_digits for caveats about when this routine should be
|
|
161
|
+
* called.
|
|
162
|
+
**********************************************************************/
|
|
163
|
+
static inline int set_digits(int ndigits) {
|
|
164
|
+
#if GEOGRAPHICLIB_PRECISION != 5
|
|
165
|
+
(void)ndigits;
|
|
166
|
+
#else
|
|
167
|
+
mpfr::mpreal::set_default_prec(ndigits >= 2 ? ndigits : 2);
|
|
168
|
+
#endif
|
|
169
|
+
return digits();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @return the number of decimal digits of precision in a real number.
|
|
174
|
+
**********************************************************************/
|
|
175
|
+
static inline int digits10() {
|
|
176
|
+
#if GEOGRAPHICLIB_PRECISION != 5
|
|
177
|
+
return std::numeric_limits<real>::digits10;
|
|
178
|
+
#else
|
|
179
|
+
return std::numeric_limits<real>::digits10();
|
|
180
|
+
#endif
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Number of additional decimal digits of precision for real relative to
|
|
185
|
+
* double (0 for float).
|
|
186
|
+
**********************************************************************/
|
|
187
|
+
static inline int extra_digits() {
|
|
188
|
+
return
|
|
189
|
+
digits10() > std::numeric_limits<double>::digits10 ?
|
|
190
|
+
digits10() - std::numeric_limits<double>::digits10 : 0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* true if the machine is big-endian.
|
|
195
|
+
**********************************************************************/
|
|
196
|
+
static const bool bigendian = GEOGRAPHICLIB_WORDS_BIGENDIAN;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @tparam T the type of the returned value.
|
|
200
|
+
* @return π.
|
|
201
|
+
**********************************************************************/
|
|
202
|
+
template<typename T> static inline T pi() {
|
|
203
|
+
using std::atan2;
|
|
204
|
+
static const T pi = atan2(T(0), T(-1));
|
|
205
|
+
return pi;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* A synonym for pi<real>().
|
|
209
|
+
**********************************************************************/
|
|
210
|
+
static inline real pi() { return pi<real>(); }
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @tparam T the type of the returned value.
|
|
214
|
+
* @return the number of radians in a degree.
|
|
215
|
+
**********************************************************************/
|
|
216
|
+
template<typename T> static inline T degree() {
|
|
217
|
+
static const T degree = pi<T>() / 180;
|
|
218
|
+
return degree;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* A synonym for degree<real>().
|
|
222
|
+
**********************************************************************/
|
|
223
|
+
static inline real degree() { return degree<real>(); }
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Square a number.
|
|
227
|
+
*
|
|
228
|
+
* @tparam T the type of the argument and the returned value.
|
|
229
|
+
* @param[in] x
|
|
230
|
+
* @return <i>x</i><sup>2</sup>.
|
|
231
|
+
**********************************************************************/
|
|
232
|
+
template<typename T> static inline T sq(T x)
|
|
233
|
+
{ return x * x; }
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* The hypotenuse function avoiding underflow and overflow.
|
|
237
|
+
*
|
|
238
|
+
* @tparam T the type of the arguments and the returned value.
|
|
239
|
+
* @param[in] x
|
|
240
|
+
* @param[in] y
|
|
241
|
+
* @return sqrt(<i>x</i><sup>2</sup> + <i>y</i><sup>2</sup>).
|
|
242
|
+
**********************************************************************/
|
|
243
|
+
template<typename T> static inline T hypot(T x, T y) {
|
|
244
|
+
#if GEOGRAPHICLIB_CXX11_MATH
|
|
245
|
+
using std::hypot; return hypot(x, y);
|
|
246
|
+
#else
|
|
247
|
+
using std::abs; using std::sqrt;
|
|
248
|
+
x = abs(x); y = abs(y);
|
|
249
|
+
if (x < y) std::swap(x, y); // Now x >= y >= 0
|
|
250
|
+
y /= (x ? x : 1);
|
|
251
|
+
return x * sqrt(1 + y * y);
|
|
252
|
+
// For an alternative (square-root free) method see
|
|
253
|
+
// C. Moler and D. Morrision (1983) https://dx.doi.org/10.1147/rd.276.0577
|
|
254
|
+
// and A. A. Dubrulle (1983) https://dx.doi.org/10.1147/rd.276.0582
|
|
255
|
+
#endif
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* exp(\e x) − 1 accurate near \e x = 0.
|
|
260
|
+
*
|
|
261
|
+
* @tparam T the type of the argument and the returned value.
|
|
262
|
+
* @param[in] x
|
|
263
|
+
* @return exp(\e x) − 1.
|
|
264
|
+
**********************************************************************/
|
|
265
|
+
template<typename T> static inline T expm1(T x) {
|
|
266
|
+
#if GEOGRAPHICLIB_CXX11_MATH
|
|
267
|
+
using std::expm1; return expm1(x);
|
|
268
|
+
#else
|
|
269
|
+
using std::exp; using std::abs; using std::log;
|
|
270
|
+
GEOGRAPHICLIB_VOLATILE T
|
|
271
|
+
y = exp(x),
|
|
272
|
+
z = y - 1;
|
|
273
|
+
// The reasoning here is similar to that for log1p. The expression
|
|
274
|
+
// mathematically reduces to exp(x) - 1, and the factor z/log(y) = (y -
|
|
275
|
+
// 1)/log(y) is a slowly varying quantity near y = 1 and is accurately
|
|
276
|
+
// computed.
|
|
277
|
+
return abs(x) > 1 ? z : (z == 0 ? x : x * z / log(y));
|
|
278
|
+
#endif
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* log(1 + \e x) accurate near \e x = 0.
|
|
283
|
+
*
|
|
284
|
+
* @tparam T the type of the argument and the returned value.
|
|
285
|
+
* @param[in] x
|
|
286
|
+
* @return log(1 + \e x).
|
|
287
|
+
**********************************************************************/
|
|
288
|
+
template<typename T> static inline T log1p(T x) {
|
|
289
|
+
#if GEOGRAPHICLIB_CXX11_MATH
|
|
290
|
+
using std::log1p; return log1p(x);
|
|
291
|
+
#else
|
|
292
|
+
using std::log;
|
|
293
|
+
GEOGRAPHICLIB_VOLATILE T
|
|
294
|
+
y = 1 + x,
|
|
295
|
+
z = y - 1;
|
|
296
|
+
// Here's the explanation for this magic: y = 1 + z, exactly, and z
|
|
297
|
+
// approx x, thus log(y)/z (which is nearly constant near z = 0) returns
|
|
298
|
+
// a good approximation to the true log(1 + x)/x. The multiplication x *
|
|
299
|
+
// (log(y)/z) introduces little additional error.
|
|
300
|
+
return z == 0 ? x : x * log(y) / z;
|
|
301
|
+
#endif
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* The inverse hyperbolic sine function.
|
|
306
|
+
*
|
|
307
|
+
* @tparam T the type of the argument and the returned value.
|
|
308
|
+
* @param[in] x
|
|
309
|
+
* @return asinh(\e x).
|
|
310
|
+
**********************************************************************/
|
|
311
|
+
template<typename T> static inline T asinh(T x) {
|
|
312
|
+
#if GEOGRAPHICLIB_CXX11_MATH
|
|
313
|
+
using std::asinh; return asinh(x);
|
|
314
|
+
#else
|
|
315
|
+
using std::abs; T y = abs(x); // Enforce odd parity
|
|
316
|
+
y = log1p(y * (1 + y/(hypot(T(1), y) + 1)));
|
|
317
|
+
return x < 0 ? -y : y;
|
|
318
|
+
#endif
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* The inverse hyperbolic tangent function.
|
|
323
|
+
*
|
|
324
|
+
* @tparam T the type of the argument and the returned value.
|
|
325
|
+
* @param[in] x
|
|
326
|
+
* @return atanh(\e x).
|
|
327
|
+
**********************************************************************/
|
|
328
|
+
template<typename T> static inline T atanh(T x) {
|
|
329
|
+
#if GEOGRAPHICLIB_CXX11_MATH
|
|
330
|
+
using std::atanh; return atanh(x);
|
|
331
|
+
#else
|
|
332
|
+
using std::abs; T y = abs(x); // Enforce odd parity
|
|
333
|
+
y = log1p(2 * y/(1 - y))/2;
|
|
334
|
+
return x < 0 ? -y : y;
|
|
335
|
+
#endif
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* The cube root function.
|
|
340
|
+
*
|
|
341
|
+
* @tparam T the type of the argument and the returned value.
|
|
342
|
+
* @param[in] x
|
|
343
|
+
* @return the real cube root of \e x.
|
|
344
|
+
**********************************************************************/
|
|
345
|
+
template<typename T> static inline T cbrt(T x) {
|
|
346
|
+
#if GEOGRAPHICLIB_CXX11_MATH
|
|
347
|
+
using std::cbrt; return cbrt(x);
|
|
348
|
+
#else
|
|
349
|
+
using std::abs; using std::pow;
|
|
350
|
+
T y = pow(abs(x), 1/T(3)); // Return the real cube root
|
|
351
|
+
return x < 0 ? -y : y;
|
|
352
|
+
#endif
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Fused multiply and add.
|
|
357
|
+
*
|
|
358
|
+
* @tparam T the type of the arguments and the returned value.
|
|
359
|
+
* @param[in] x
|
|
360
|
+
* @param[in] y
|
|
361
|
+
* @param[in] z
|
|
362
|
+
* @return <i>xy</i> + <i>z</i>, correctly rounded (on those platforms with
|
|
363
|
+
* support for the <code>fma</code> instruction).
|
|
364
|
+
*
|
|
365
|
+
* On platforms without the <code>fma</code> instruction, no attempt is
|
|
366
|
+
* made to improve on the result of a rounded multiplication followed by a
|
|
367
|
+
* rounded addition.
|
|
368
|
+
**********************************************************************/
|
|
369
|
+
template<typename T> static inline T fma(T x, T y, T z) {
|
|
370
|
+
#if GEOGRAPHICLIB_CXX11_MATH
|
|
371
|
+
using std::fma; return fma(x, y, z);
|
|
372
|
+
#else
|
|
373
|
+
return x * y + z;
|
|
374
|
+
#endif
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Normalize a two-vector.
|
|
379
|
+
*
|
|
380
|
+
* @tparam T the type of the argument and the returned value.
|
|
381
|
+
* @param[in,out] x on output set to <i>x</i>/hypot(<i>x</i>, <i>y</i>).
|
|
382
|
+
* @param[in,out] y on output set to <i>y</i>/hypot(<i>x</i>, <i>y</i>).
|
|
383
|
+
**********************************************************************/
|
|
384
|
+
template<typename T> static inline void norm(T& x, T& y)
|
|
385
|
+
{ T h = hypot(x, y); x /= h; y /= h; }
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* The error-free sum of two numbers.
|
|
389
|
+
*
|
|
390
|
+
* @tparam T the type of the argument and the returned value.
|
|
391
|
+
* @param[in] u
|
|
392
|
+
* @param[in] v
|
|
393
|
+
* @param[out] t the exact error given by (\e u + \e v) - \e s.
|
|
394
|
+
* @return \e s = round(\e u + \e v).
|
|
395
|
+
*
|
|
396
|
+
* See D. E. Knuth, TAOCP, Vol 2, 4.2.2, Theorem B. (Note that \e t can be
|
|
397
|
+
* the same as one of the first two arguments.)
|
|
398
|
+
**********************************************************************/
|
|
399
|
+
template<typename T> static inline T sum(T u, T v, T& t) {
|
|
400
|
+
GEOGRAPHICLIB_VOLATILE T s = u + v;
|
|
401
|
+
GEOGRAPHICLIB_VOLATILE T up = s - v;
|
|
402
|
+
GEOGRAPHICLIB_VOLATILE T vpp = s - up;
|
|
403
|
+
up -= u;
|
|
404
|
+
vpp -= v;
|
|
405
|
+
t = -(up + vpp);
|
|
406
|
+
// u + v = s + t
|
|
407
|
+
// = round(u + v) + t
|
|
408
|
+
return s;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Evaluate a polynomial.
|
|
413
|
+
*
|
|
414
|
+
* @tparam T the type of the arguments and returned value.
|
|
415
|
+
* @param[in] N the order of the polynomial.
|
|
416
|
+
* @param[in] p the coefficient array (of size \e N + 1).
|
|
417
|
+
* @param[in] x the variable.
|
|
418
|
+
* @return the value of the polynomial.
|
|
419
|
+
*
|
|
420
|
+
* Evaluate <i>y</i> = ∑<sub><i>n</i>=0..<i>N</i></sub>
|
|
421
|
+
* <i>p</i><sub><i>n</i></sub> <i>x</i><sup><i>N</i>−<i>n</i></sup>.
|
|
422
|
+
* Return 0 if \e N < 0. Return <i>p</i><sub>0</sub>, if \e N = 0 (even
|
|
423
|
+
* if \e x is infinite or a nan). The evaluation uses Horner's method.
|
|
424
|
+
**********************************************************************/
|
|
425
|
+
template<typename T> static inline T polyval(int N, const T p[], T x)
|
|
426
|
+
{ T y = N < 0 ? 0 : *p++; while (--N >= 0) y = y * x + *p++; return y; }
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Normalize an angle.
|
|
430
|
+
*
|
|
431
|
+
* @tparam T the type of the argument and returned value.
|
|
432
|
+
* @param[in] x the angle in degrees.
|
|
433
|
+
* @return the angle reduced to the range [−180°, 180°).
|
|
434
|
+
*
|
|
435
|
+
* The range of \e x is unrestricted.
|
|
436
|
+
**********************************************************************/
|
|
437
|
+
template<typename T> static inline T AngNormalize(T x) {
|
|
438
|
+
#if GEOGRAPHICLIB_CXX11_MATH && GEOGRAPHICLIB_PRECISION != 4
|
|
439
|
+
using std::remainder;
|
|
440
|
+
x = remainder(x, T(360)); return x != 180 ? x : -180;
|
|
441
|
+
#else
|
|
442
|
+
using std::fmod;
|
|
443
|
+
x = fmod(x, T(360));
|
|
444
|
+
return x < -180 ? x + 360 : (x < 180 ? x : x - 360);
|
|
445
|
+
#endif
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Normalize a latitude.
|
|
450
|
+
*
|
|
451
|
+
* @tparam T the type of the argument and returned value.
|
|
452
|
+
* @param[in] x the angle in degrees.
|
|
453
|
+
* @return x if it is in the range [−90°, 90°], otherwise
|
|
454
|
+
* return NaN.
|
|
455
|
+
**********************************************************************/
|
|
456
|
+
template<typename T> static inline T LatFix(T x)
|
|
457
|
+
{ using std::abs; return abs(x) > 90 ? NaN<T>() : x; }
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* The exact difference of two angles reduced to
|
|
461
|
+
* (−180°, 180°].
|
|
462
|
+
*
|
|
463
|
+
* @tparam T the type of the arguments and returned value.
|
|
464
|
+
* @param[in] x the first angle in degrees.
|
|
465
|
+
* @param[in] y the second angle in degrees.
|
|
466
|
+
* @param[out] e the error term in degrees.
|
|
467
|
+
* @return \e d, the truncated value of \e y − \e x.
|
|
468
|
+
*
|
|
469
|
+
* This computes \e z = \e y − \e x exactly, reduced to
|
|
470
|
+
* (−180°, 180°]; and then sets \e z = \e d + \e e where \e d
|
|
471
|
+
* is the nearest representable number to \e z and \e e is the truncation
|
|
472
|
+
* error. If \e d = −180, then \e e > 0; If \e d = 180, then \e e
|
|
473
|
+
* ≤ 0.
|
|
474
|
+
**********************************************************************/
|
|
475
|
+
template<typename T> static inline T AngDiff(T x, T y, T& e) {
|
|
476
|
+
#if GEOGRAPHICLIB_CXX11_MATH && GEOGRAPHICLIB_PRECISION != 4
|
|
477
|
+
using std::remainder;
|
|
478
|
+
T t, d = - AngNormalize(sum(remainder( x, T(360)),
|
|
479
|
+
remainder(-y, T(360)), t));
|
|
480
|
+
#else
|
|
481
|
+
T t, d = - AngNormalize(sum(AngNormalize(x), AngNormalize(-y), t));
|
|
482
|
+
#endif
|
|
483
|
+
// Here y - x = d - t (mod 360), exactly, where d is in (-180,180] and
|
|
484
|
+
// abs(t) <= eps (eps = 2^-45 for doubles). The only case where the
|
|
485
|
+
// addition of t takes the result outside the range (-180,180] is d = 180
|
|
486
|
+
// and t < 0. The case, d = -180 + eps, t = eps, can't happen, since
|
|
487
|
+
// sum would have returned the exact result in such a case (i.e., given t
|
|
488
|
+
// = 0).
|
|
489
|
+
return sum(d == 180 && t < 0 ? -180 : d, -t, e);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Difference of two angles reduced to [−180°, 180°]
|
|
494
|
+
*
|
|
495
|
+
* @tparam T the type of the arguments and returned value.
|
|
496
|
+
* @param[in] x the first angle in degrees.
|
|
497
|
+
* @param[in] y the second angle in degrees.
|
|
498
|
+
* @return \e y − \e x, reduced to the range [−180°,
|
|
499
|
+
* 180°].
|
|
500
|
+
*
|
|
501
|
+
* The result is equivalent to computing the difference exactly, reducing
|
|
502
|
+
* it to (−180°, 180°] and rounding the result. Note that
|
|
503
|
+
* this prescription allows −180° to be returned (e.g., if \e x
|
|
504
|
+
* is tiny and negative and \e y = 180°).
|
|
505
|
+
**********************************************************************/
|
|
506
|
+
template<typename T> static inline T AngDiff(T x, T y)
|
|
507
|
+
{ T e; return AngDiff(x, y, e); }
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Coarsen a value close to zero.
|
|
511
|
+
*
|
|
512
|
+
* @tparam T the type of the argument and returned value.
|
|
513
|
+
* @param[in] x
|
|
514
|
+
* @return the coarsened value.
|
|
515
|
+
*
|
|
516
|
+
* The makes the smallest gap in \e x = 1/16 - nextafter(1/16, 0) =
|
|
517
|
+
* 1/2<sup>57</sup> for reals = 0.7 pm on the earth if \e x is an angle in
|
|
518
|
+
* degrees. (This is about 1000 times more resolution than we get with
|
|
519
|
+
* angles around 90°.) We use this to avoid having to deal with near
|
|
520
|
+
* singular cases when \e x is non-zero but tiny (e.g.,
|
|
521
|
+
* 10<sup>−200</sup>). This converts -0 to +0; however tiny negative
|
|
522
|
+
* numbers get converted to -0.
|
|
523
|
+
**********************************************************************/
|
|
524
|
+
template<typename T> static inline T AngRound(T x) {
|
|
525
|
+
using std::abs;
|
|
526
|
+
static const T z = 1/T(16);
|
|
527
|
+
if (x == 0) return 0;
|
|
528
|
+
GEOGRAPHICLIB_VOLATILE T y = abs(x);
|
|
529
|
+
// The compiler mustn't "simplify" z - (z - y) to y
|
|
530
|
+
y = y < z ? z - (z - y) : y;
|
|
531
|
+
return x < 0 ? -y : y;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Evaluate the sine and cosine function with the argument in degrees
|
|
536
|
+
*
|
|
537
|
+
* @tparam T the type of the arguments.
|
|
538
|
+
* @param[in] x in degrees.
|
|
539
|
+
* @param[out] sinx sin(<i>x</i>).
|
|
540
|
+
* @param[out] cosx cos(<i>x</i>).
|
|
541
|
+
*
|
|
542
|
+
* The results obey exactly the elementary properties of the trigonometric
|
|
543
|
+
* functions, e.g., sin 9° = cos 81° = − sin 123456789°.
|
|
544
|
+
**********************************************************************/
|
|
545
|
+
template<typename T> static inline void sincosd(T x, T& sinx, T& cosx) {
|
|
546
|
+
// In order to minimize round-off errors, this function exactly reduces
|
|
547
|
+
// the argument to the range [-45, 45] before converting it to radians.
|
|
548
|
+
using std::sin; using std::cos;
|
|
549
|
+
T r; int q;
|
|
550
|
+
#if GEOGRAPHICLIB_CXX11_MATH && GEOGRAPHICLIB_PRECISION <= 3 && \
|
|
551
|
+
!defined(__GNUC__)
|
|
552
|
+
// Disable for gcc because of bug in glibc version < 2.22, see
|
|
553
|
+
// https://sourceware.org/bugzilla/show_bug.cgi?id=17569
|
|
554
|
+
// Once this fix is widely deployed, should insert a runtime test for the
|
|
555
|
+
// glibc version number. For example
|
|
556
|
+
// #include <gnu/libc-version.h>
|
|
557
|
+
// std::string version(gnu_get_libc_version()); => "2.22"
|
|
558
|
+
using std::remquo;
|
|
559
|
+
r = remquo(x, T(90), &q);
|
|
560
|
+
#else
|
|
561
|
+
using std::fmod; using std::floor;
|
|
562
|
+
r = fmod(x, T(360));
|
|
563
|
+
q = int(floor(r / 90 + T(0.5)));
|
|
564
|
+
r -= 90 * q;
|
|
565
|
+
#endif
|
|
566
|
+
// now abs(r) <= 45
|
|
567
|
+
r *= degree();
|
|
568
|
+
// Possibly could call the gnu extension sincos
|
|
569
|
+
T s = sin(r), c = cos(r);
|
|
570
|
+
#if defined(_MSC_VER) && _MSC_VER < 1900
|
|
571
|
+
// Before version 14 (2015), Visual Studio had problems dealing
|
|
572
|
+
// with -0.0. Specifically
|
|
573
|
+
// VC 10,11,12 and 32-bit compile: fmod(-0.0, 360.0) -> +0.0
|
|
574
|
+
// VC 12 and 64-bit compile: sin(-0.0) -> +0.0
|
|
575
|
+
if (x == 0) s = x;
|
|
576
|
+
#endif
|
|
577
|
+
switch (unsigned(q) & 3U) {
|
|
578
|
+
case 0U: sinx = s; cosx = c; break;
|
|
579
|
+
case 1U: sinx = c; cosx = T(0) - s; break;
|
|
580
|
+
case 2U: sinx = T(0) - s; cosx = T(0) - c; break;
|
|
581
|
+
default: sinx = T(0) - c; cosx = s; break; // case 3U
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Evaluate the sine function with the argument in degrees
|
|
587
|
+
*
|
|
588
|
+
* @tparam T the type of the argument and the returned value.
|
|
589
|
+
* @param[in] x in degrees.
|
|
590
|
+
* @return sin(<i>x</i>).
|
|
591
|
+
**********************************************************************/
|
|
592
|
+
template<typename T> static inline T sind(T x) {
|
|
593
|
+
// See sincosd
|
|
594
|
+
using std::sin; using std::cos;
|
|
595
|
+
T r; int q;
|
|
596
|
+
#if GEOGRAPHICLIB_CXX11_MATH && GEOGRAPHICLIB_PRECISION <= 3 && \
|
|
597
|
+
!defined(__GNUC__)
|
|
598
|
+
using std::remquo;
|
|
599
|
+
r = remquo(x, T(90), &q);
|
|
600
|
+
#else
|
|
601
|
+
using std::fmod; using std::floor;
|
|
602
|
+
r = fmod(x, T(360));
|
|
603
|
+
q = int(floor(r / 90 + T(0.5)));
|
|
604
|
+
r -= 90 * q;
|
|
605
|
+
#endif
|
|
606
|
+
// now abs(r) <= 45
|
|
607
|
+
r *= degree();
|
|
608
|
+
unsigned p = unsigned(q);
|
|
609
|
+
r = p & 1U ? cos(r) : sin(r);
|
|
610
|
+
return p & 2U ? T(0) - r : r;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Evaluate the cosine function with the argument in degrees
|
|
615
|
+
*
|
|
616
|
+
* @tparam T the type of the argument and the returned value.
|
|
617
|
+
* @param[in] x in degrees.
|
|
618
|
+
* @return cos(<i>x</i>).
|
|
619
|
+
**********************************************************************/
|
|
620
|
+
template<typename T> static inline T cosd(T x) {
|
|
621
|
+
// See sincosd
|
|
622
|
+
using std::sin; using std::cos;
|
|
623
|
+
T r; int q;
|
|
624
|
+
#if GEOGRAPHICLIB_CXX11_MATH && GEOGRAPHICLIB_PRECISION <= 3 && \
|
|
625
|
+
!defined(__GNUC__)
|
|
626
|
+
using std::remquo;
|
|
627
|
+
r = remquo(x, T(90), &q);
|
|
628
|
+
#else
|
|
629
|
+
using std::fmod; using std::floor;
|
|
630
|
+
r = fmod(x, T(360));
|
|
631
|
+
q = int(floor(r / 90 + T(0.5)));
|
|
632
|
+
r -= 90 * q;
|
|
633
|
+
#endif
|
|
634
|
+
// now abs(r) <= 45
|
|
635
|
+
r *= degree();
|
|
636
|
+
unsigned p = unsigned(q + 1);
|
|
637
|
+
r = p & 1U ? cos(r) : sin(r);
|
|
638
|
+
return p & 2U ? T(0) - r : r;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* Evaluate the tangent function with the argument in degrees
|
|
643
|
+
*
|
|
644
|
+
* @tparam T the type of the argument and the returned value.
|
|
645
|
+
* @param[in] x in degrees.
|
|
646
|
+
* @return tan(<i>x</i>).
|
|
647
|
+
*
|
|
648
|
+
* If \e x = ±90°, then a suitably large (but finite) value is
|
|
649
|
+
* returned.
|
|
650
|
+
**********************************************************************/
|
|
651
|
+
template<typename T> static inline T tand(T x) {
|
|
652
|
+
static const T overflow = 1 / sq(std::numeric_limits<T>::epsilon());
|
|
653
|
+
T s, c;
|
|
654
|
+
sincosd(x, s, c);
|
|
655
|
+
return c ? s / c : (s < 0 ? -overflow : overflow);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Evaluate the atan2 function with the result in degrees
|
|
660
|
+
*
|
|
661
|
+
* @tparam T the type of the arguments and the returned value.
|
|
662
|
+
* @param[in] y
|
|
663
|
+
* @param[in] x
|
|
664
|
+
* @return atan2(<i>y</i>, <i>x</i>) in degrees.
|
|
665
|
+
*
|
|
666
|
+
* The result is in the range [−180° 180°). N.B.,
|
|
667
|
+
* atan2d(±0, −1) = −180°; atan2d(+ε,
|
|
668
|
+
* −1) = +180°, for ε positive and tiny;
|
|
669
|
+
* atan2d(±0, 1) = ±0°.
|
|
670
|
+
**********************************************************************/
|
|
671
|
+
template<typename T> static inline T atan2d(T y, T x) {
|
|
672
|
+
// In order to minimize round-off errors, this function rearranges the
|
|
673
|
+
// arguments so that result of atan2 is in the range [-pi/4, pi/4] before
|
|
674
|
+
// converting it to degrees and mapping the result to the correct
|
|
675
|
+
// quadrant.
|
|
676
|
+
using std::atan2; using std::abs;
|
|
677
|
+
int q = 0;
|
|
678
|
+
if (abs(y) > abs(x)) { std::swap(x, y); q = 2; }
|
|
679
|
+
if (x < 0) { x = -x; ++q; }
|
|
680
|
+
// here x >= 0 and x >= abs(y), so angle is in [-pi/4, pi/4]
|
|
681
|
+
T ang = atan2(y, x) / degree();
|
|
682
|
+
switch (q) {
|
|
683
|
+
// Note that atan2d(-0.0, 1.0) will return -0. However, we expect that
|
|
684
|
+
// atan2d will not be called with y = -0. If need be, include
|
|
685
|
+
//
|
|
686
|
+
// case 0: ang = 0 + ang; break;
|
|
687
|
+
//
|
|
688
|
+
// and handle mpfr as in AngRound.
|
|
689
|
+
case 1: ang = (y > 0 ? 180 : -180) - ang; break;
|
|
690
|
+
case 2: ang = 90 - ang; break;
|
|
691
|
+
case 3: ang = -90 + ang; break;
|
|
692
|
+
}
|
|
693
|
+
return ang;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Evaluate the atan function with the result in degrees
|
|
698
|
+
*
|
|
699
|
+
* @tparam T the type of the argument and the returned value.
|
|
700
|
+
* @param[in] x
|
|
701
|
+
* @return atan(<i>x</i>) in degrees.
|
|
702
|
+
**********************************************************************/
|
|
703
|
+
template<typename T> static inline T atand(T x)
|
|
704
|
+
{ return atan2d(x, T(1)); }
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Evaluate <i>e</i> atanh(<i>e x</i>)
|
|
708
|
+
*
|
|
709
|
+
* @tparam T the type of the argument and the returned value.
|
|
710
|
+
* @param[in] x
|
|
711
|
+
* @param[in] es the signed eccentricity = sign(<i>e</i><sup>2</sup>)
|
|
712
|
+
* sqrt(|<i>e</i><sup>2</sup>|)
|
|
713
|
+
* @return <i>e</i> atanh(<i>e x</i>)
|
|
714
|
+
*
|
|
715
|
+
* If <i>e</i><sup>2</sup> is negative (<i>e</i> is imaginary), the
|
|
716
|
+
* expression is evaluated in terms of atan.
|
|
717
|
+
**********************************************************************/
|
|
718
|
+
template<typename T> static T eatanhe(T x, T es);
|
|
719
|
+
|
|
720
|
+
/**
|
|
721
|
+
* Copy the sign.
|
|
722
|
+
*
|
|
723
|
+
* @tparam T the type of the argument.
|
|
724
|
+
* @param[in] x gives the magitude of the result.
|
|
725
|
+
* @param[in] y gives the sign of the result.
|
|
726
|
+
* @return value with the magnitude of \e x and with the sign of \e y.
|
|
727
|
+
**********************************************************************/
|
|
728
|
+
template<typename T> static inline T copysign(T x, T y) {
|
|
729
|
+
#if GEOGRAPHICLIB_CXX11_MATH
|
|
730
|
+
using std::copysign; return copysign(x, y);
|
|
731
|
+
#else
|
|
732
|
+
using std::abs; using std::atan2;
|
|
733
|
+
// NaN counts as positive
|
|
734
|
+
return abs(x) * (y < 0 || (y == 0 && 1/y < 0) ? -1 : 1);
|
|
735
|
+
#endif
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* tanχ in terms of tanφ
|
|
740
|
+
*
|
|
741
|
+
* @tparam T the type of the argument and the returned value.
|
|
742
|
+
* @param[in] tau τ = tanφ
|
|
743
|
+
* @param[in] es the signed eccentricity = sign(<i>e</i><sup>2</sup>)
|
|
744
|
+
* sqrt(|<i>e</i><sup>2</sup>|)
|
|
745
|
+
* @return τ′ = tanχ
|
|
746
|
+
*
|
|
747
|
+
* See Eqs. (7--9) of
|
|
748
|
+
* C. F. F. Karney,
|
|
749
|
+
* <a href="https://dx.doi.org/10.1007/s00190-011-0445-3">
|
|
750
|
+
* Transverse Mercator with an accuracy of a few nanometers,</a>
|
|
751
|
+
* J. Geodesy 85(8), 475--485 (Aug. 2011)
|
|
752
|
+
* (preprint <a href="http://arxiv.org/abs/1002.1417">arXiv:1002.1417</a>).
|
|
753
|
+
**********************************************************************/
|
|
754
|
+
template<typename T> static T taupf(T tau, T es);
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* tanφ in terms of tanχ
|
|
758
|
+
*
|
|
759
|
+
* @tparam T the type of the argument and the returned value.
|
|
760
|
+
* @param[in] taup τ′ = tanχ
|
|
761
|
+
* @param[in] es the signed eccentricity = sign(<i>e</i><sup>2</sup>)
|
|
762
|
+
* sqrt(|<i>e</i><sup>2</sup>|)
|
|
763
|
+
* @return τ = tanφ
|
|
764
|
+
*
|
|
765
|
+
* See Eqs. (19--21) of
|
|
766
|
+
* C. F. F. Karney,
|
|
767
|
+
* <a href="https://dx.doi.org/10.1007/s00190-011-0445-3">
|
|
768
|
+
* Transverse Mercator with an accuracy of a few nanometers,</a>
|
|
769
|
+
* J. Geodesy 85(8), 475--485 (Aug. 2011)
|
|
770
|
+
* (preprint <a href="http://arxiv.org/abs/1002.1417">arXiv:1002.1417</a>).
|
|
771
|
+
**********************************************************************/
|
|
772
|
+
template<typename T> static T tauf(T taup, T es);
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Test for finiteness.
|
|
776
|
+
*
|
|
777
|
+
* @tparam T the type of the argument.
|
|
778
|
+
* @param[in] x
|
|
779
|
+
* @return true if number is finite, false if NaN or infinite.
|
|
780
|
+
**********************************************************************/
|
|
781
|
+
template<typename T> static inline bool isfinite(T x) {
|
|
782
|
+
#if GEOGRAPHICLIB_CXX11_MATH
|
|
783
|
+
using std::isfinite; return isfinite(x);
|
|
784
|
+
#else
|
|
785
|
+
using std::abs;
|
|
786
|
+
#if defined(_MSC_VER)
|
|
787
|
+
return abs(x) <= (std::numeric_limits<T>::max)();
|
|
788
|
+
#else
|
|
789
|
+
// There's a problem using MPFR C++ 3.6.3 and g++ -std=c++14 (reported on
|
|
790
|
+
// 2015-05-04) with the parens around std::numeric_limits<T>::max. Of
|
|
791
|
+
// course, these parens are only needed to deal with Windows stupidly
|
|
792
|
+
// defining max as a macro. So don't insert the parens on non-Windows
|
|
793
|
+
// platforms.
|
|
794
|
+
return abs(x) <= std::numeric_limits<T>::max();
|
|
795
|
+
#endif
|
|
796
|
+
#endif
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* The NaN (not a number)
|
|
801
|
+
*
|
|
802
|
+
* @tparam T the type of the returned value.
|
|
803
|
+
* @return NaN if available, otherwise return the max real of type T.
|
|
804
|
+
**********************************************************************/
|
|
805
|
+
template<typename T> static inline T NaN() {
|
|
806
|
+
#if defined(_MSC_VER)
|
|
807
|
+
return std::numeric_limits<T>::has_quiet_NaN ?
|
|
808
|
+
std::numeric_limits<T>::quiet_NaN() :
|
|
809
|
+
(std::numeric_limits<T>::max)();
|
|
810
|
+
#else
|
|
811
|
+
return std::numeric_limits<T>::has_quiet_NaN ?
|
|
812
|
+
std::numeric_limits<T>::quiet_NaN() :
|
|
813
|
+
std::numeric_limits<T>::max();
|
|
814
|
+
#endif
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* A synonym for NaN<real>().
|
|
818
|
+
**********************************************************************/
|
|
819
|
+
static inline real NaN() { return NaN<real>(); }
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Test for NaN.
|
|
823
|
+
*
|
|
824
|
+
* @tparam T the type of the argument.
|
|
825
|
+
* @param[in] x
|
|
826
|
+
* @return true if argument is a NaN.
|
|
827
|
+
**********************************************************************/
|
|
828
|
+
template<typename T> static inline bool isnan(T x) {
|
|
829
|
+
#if GEOGRAPHICLIB_CXX11_MATH
|
|
830
|
+
using std::isnan; return isnan(x);
|
|
831
|
+
#else
|
|
832
|
+
return x != x;
|
|
833
|
+
#endif
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Infinity
|
|
838
|
+
*
|
|
839
|
+
* @tparam T the type of the returned value.
|
|
840
|
+
* @return infinity if available, otherwise return the max real.
|
|
841
|
+
**********************************************************************/
|
|
842
|
+
template<typename T> static inline T infinity() {
|
|
843
|
+
#if defined(_MSC_VER)
|
|
844
|
+
return std::numeric_limits<T>::has_infinity ?
|
|
845
|
+
std::numeric_limits<T>::infinity() :
|
|
846
|
+
(std::numeric_limits<T>::max)();
|
|
847
|
+
#else
|
|
848
|
+
return std::numeric_limits<T>::has_infinity ?
|
|
849
|
+
std::numeric_limits<T>::infinity() :
|
|
850
|
+
std::numeric_limits<T>::max();
|
|
851
|
+
#endif
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* A synonym for infinity<real>().
|
|
855
|
+
**********************************************************************/
|
|
856
|
+
static inline real infinity() { return infinity<real>(); }
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Swap the bytes of a quantity
|
|
860
|
+
*
|
|
861
|
+
* @tparam T the type of the argument and the returned value.
|
|
862
|
+
* @param[in] x
|
|
863
|
+
* @return x with its bytes swapped.
|
|
864
|
+
**********************************************************************/
|
|
865
|
+
template<typename T> static inline T swab(T x) {
|
|
866
|
+
union {
|
|
867
|
+
T r;
|
|
868
|
+
unsigned char c[sizeof(T)];
|
|
869
|
+
} b;
|
|
870
|
+
b.r = x;
|
|
871
|
+
for (int i = sizeof(T)/2; i--; )
|
|
872
|
+
std::swap(b.c[i], b.c[sizeof(T) - 1 - i]);
|
|
873
|
+
return b.r;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
#if GEOGRAPHICLIB_PRECISION == 4
|
|
877
|
+
typedef boost::math::policies::policy
|
|
878
|
+
< boost::math::policies::domain_error
|
|
879
|
+
<boost::math::policies::errno_on_error>,
|
|
880
|
+
boost::math::policies::pole_error
|
|
881
|
+
<boost::math::policies::errno_on_error>,
|
|
882
|
+
boost::math::policies::overflow_error
|
|
883
|
+
<boost::math::policies::errno_on_error>,
|
|
884
|
+
boost::math::policies::evaluation_error
|
|
885
|
+
<boost::math::policies::errno_on_error> >
|
|
886
|
+
boost_special_functions_policy;
|
|
887
|
+
|
|
888
|
+
static inline real hypot(real x, real y)
|
|
889
|
+
{ return boost::math::hypot(x, y, boost_special_functions_policy()); }
|
|
890
|
+
|
|
891
|
+
static inline real expm1(real x)
|
|
892
|
+
{ return boost::math::expm1(x, boost_special_functions_policy()); }
|
|
893
|
+
|
|
894
|
+
static inline real log1p(real x)
|
|
895
|
+
{ return boost::math::log1p(x, boost_special_functions_policy()); }
|
|
896
|
+
|
|
897
|
+
static inline real asinh(real x)
|
|
898
|
+
{ return boost::math::asinh(x, boost_special_functions_policy()); }
|
|
899
|
+
|
|
900
|
+
static inline real atanh(real x)
|
|
901
|
+
{ return boost::math::atanh(x, boost_special_functions_policy()); }
|
|
902
|
+
|
|
903
|
+
static inline real cbrt(real x)
|
|
904
|
+
{ return boost::math::cbrt(x, boost_special_functions_policy()); }
|
|
905
|
+
|
|
906
|
+
static inline real fma(real x, real y, real z)
|
|
907
|
+
{ return fmaq(__float128(x), __float128(y), __float128(z)); }
|
|
908
|
+
|
|
909
|
+
static inline real copysign(real x, real y)
|
|
910
|
+
{ return boost::math::copysign(x, y); }
|
|
911
|
+
|
|
912
|
+
static inline bool isnan(real x) { return boost::math::isnan(x); }
|
|
913
|
+
|
|
914
|
+
static inline bool isfinite(real x) { return boost::math::isfinite(x); }
|
|
915
|
+
#endif
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
} // namespace GeographicLib
|
|
919
|
+
|
|
920
|
+
#endif // GEOGRAPHICLIB_MATH_HPP
|