geographiclib 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|