geographiclib 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +12 -0
  3. data/LICENSE +24 -0
  4. data/ext/geographiclib/Accumulator.cpp +23 -0
  5. data/ext/geographiclib/AlbersEqualArea.cpp +445 -0
  6. data/ext/geographiclib/AzimuthalEquidistant.cpp +41 -0
  7. data/ext/geographiclib/CassiniSoldner.cpp +89 -0
  8. data/ext/geographiclib/CircularEngine.cpp +96 -0
  9. data/ext/geographiclib/DMS.cpp +381 -0
  10. data/ext/geographiclib/Ellipsoid.cpp +125 -0
  11. data/ext/geographiclib/EllipticFunction.cpp +512 -0
  12. data/ext/geographiclib/GARS.cpp +122 -0
  13. data/ext/geographiclib/GeoCoords.cpp +175 -0
  14. data/ext/geographiclib/Geocentric.cpp +172 -0
  15. data/ext/geographiclib/Geodesic.cpp +1908 -0
  16. data/ext/geographiclib/GeodesicExact.cpp +927 -0
  17. data/ext/geographiclib/GeodesicExactC4.cpp +7879 -0
  18. data/ext/geographiclib/GeodesicLine.cpp +321 -0
  19. data/ext/geographiclib/GeodesicLineExact.cpp +289 -0
  20. data/ext/geographiclib/GeographicLib/Accumulator.hpp +184 -0
  21. data/ext/geographiclib/GeographicLib/AlbersEqualArea.hpp +312 -0
  22. data/ext/geographiclib/GeographicLib/AzimuthalEquidistant.hpp +139 -0
  23. data/ext/geographiclib/GeographicLib/CassiniSoldner.hpp +204 -0
  24. data/ext/geographiclib/GeographicLib/CircularEngine.hpp +195 -0
  25. data/ext/geographiclib/GeographicLib/Config.h +12 -0
  26. data/ext/geographiclib/GeographicLib/Constants.hpp +387 -0
  27. data/ext/geographiclib/GeographicLib/DMS.hpp +370 -0
  28. data/ext/geographiclib/GeographicLib/Ellipsoid.hpp +534 -0
  29. data/ext/geographiclib/GeographicLib/EllipticFunction.hpp +692 -0
  30. data/ext/geographiclib/GeographicLib/GARS.hpp +143 -0
  31. data/ext/geographiclib/GeographicLib/GeoCoords.hpp +544 -0
  32. data/ext/geographiclib/GeographicLib/Geocentric.hpp +267 -0
  33. data/ext/geographiclib/GeographicLib/Geodesic.hpp +970 -0
  34. data/ext/geographiclib/GeographicLib/GeodesicExact.hpp +862 -0
  35. data/ext/geographiclib/GeographicLib/GeodesicLine.hpp +701 -0
  36. data/ext/geographiclib/GeographicLib/GeodesicLineExact.hpp +667 -0
  37. data/ext/geographiclib/GeographicLib/Geohash.hpp +180 -0
  38. data/ext/geographiclib/GeographicLib/Geoid.hpp +472 -0
  39. data/ext/geographiclib/GeographicLib/Georef.hpp +160 -0
  40. data/ext/geographiclib/GeographicLib/Gnomonic.hpp +206 -0
  41. data/ext/geographiclib/GeographicLib/GravityCircle.hpp +301 -0
  42. data/ext/geographiclib/GeographicLib/GravityModel.hpp +520 -0
  43. data/ext/geographiclib/GeographicLib/LambertConformalConic.hpp +313 -0
  44. data/ext/geographiclib/GeographicLib/LocalCartesian.hpp +236 -0
  45. data/ext/geographiclib/GeographicLib/MGRS.hpp +355 -0
  46. data/ext/geographiclib/GeographicLib/MagneticCircle.hpp +178 -0
  47. data/ext/geographiclib/GeographicLib/MagneticModel.hpp +347 -0
  48. data/ext/geographiclib/GeographicLib/Math.hpp +920 -0
  49. data/ext/geographiclib/GeographicLib/NormalGravity.hpp +350 -0
  50. data/ext/geographiclib/GeographicLib/OSGB.hpp +249 -0
  51. data/ext/geographiclib/GeographicLib/PolarStereographic.hpp +150 -0
  52. data/ext/geographiclib/GeographicLib/PolygonArea.hpp +288 -0
  53. data/ext/geographiclib/GeographicLib/Rhumb.hpp +589 -0
  54. data/ext/geographiclib/GeographicLib/SphericalEngine.hpp +376 -0
  55. data/ext/geographiclib/GeographicLib/SphericalHarmonic.hpp +354 -0
  56. data/ext/geographiclib/GeographicLib/SphericalHarmonic1.hpp +281 -0
  57. data/ext/geographiclib/GeographicLib/SphericalHarmonic2.hpp +315 -0
  58. data/ext/geographiclib/GeographicLib/TransverseMercator.hpp +196 -0
  59. data/ext/geographiclib/GeographicLib/TransverseMercatorExact.hpp +254 -0
  60. data/ext/geographiclib/GeographicLib/UTMUPS.hpp +421 -0
  61. data/ext/geographiclib/GeographicLib/Utility.hpp +612 -0
  62. data/ext/geographiclib/Geohash.cpp +102 -0
  63. data/ext/geographiclib/Geoid.cpp +509 -0
  64. data/ext/geographiclib/Georef.cpp +135 -0
  65. data/ext/geographiclib/Gnomonic.cpp +85 -0
  66. data/ext/geographiclib/GravityCircle.cpp +129 -0
  67. data/ext/geographiclib/GravityModel.cpp +360 -0
  68. data/ext/geographiclib/LambertConformalConic.cpp +456 -0
  69. data/ext/geographiclib/LocalCartesian.cpp +62 -0
  70. data/ext/geographiclib/MGRS.cpp +461 -0
  71. data/ext/geographiclib/MagneticCircle.cpp +52 -0
  72. data/ext/geographiclib/MagneticModel.cpp +269 -0
  73. data/ext/geographiclib/Math.cpp +63 -0
  74. data/ext/geographiclib/NormalGravity.cpp +262 -0
  75. data/ext/geographiclib/OSGB.cpp +167 -0
  76. data/ext/geographiclib/PolarStereographic.cpp +108 -0
  77. data/ext/geographiclib/PolygonArea.cpp +204 -0
  78. data/ext/geographiclib/Rhumb.cpp +383 -0
  79. data/ext/geographiclib/SphericalEngine.cpp +477 -0
  80. data/ext/geographiclib/TransverseMercator.cpp +603 -0
  81. data/ext/geographiclib/TransverseMercatorExact.cpp +464 -0
  82. data/ext/geographiclib/UTMUPS.cpp +296 -0
  83. data/ext/geographiclib/Utility.cpp +61 -0
  84. data/ext/geographiclib/extconf.rb +3 -0
  85. data/ext/geographiclib/geographiclib.cpp +62 -0
  86. data/lib/geographiclib.rb +20 -0
  87. 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 &pi;.
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) &minus; 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) &minus; 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> = &sum;<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>&minus;<i>n</i></sup>.
422
+ * Return 0 if \e N &lt; 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 [&minus;180&deg;, 180&deg;).
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 [&minus;90&deg;, 90&deg;], 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
+ * (&minus;180&deg;, 180&deg;].
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 &minus; \e x.
468
+ *
469
+ * This computes \e z = \e y &minus; \e x exactly, reduced to
470
+ * (&minus;180&deg;, 180&deg;]; 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 = &minus;180, then \e e &gt; 0; If \e d = 180, then \e e
473
+ * &le; 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 [&minus;180&deg;, 180&deg;]
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 &minus; \e x, reduced to the range [&minus;180&deg;,
499
+ * 180&deg;].
500
+ *
501
+ * The result is equivalent to computing the difference exactly, reducing
502
+ * it to (&minus;180&deg;, 180&deg;] and rounding the result. Note that
503
+ * this prescription allows &minus;180&deg; to be returned (e.g., if \e x
504
+ * is tiny and negative and \e y = 180&deg;).
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&deg;.) 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>&minus;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&deg; = cos 81&deg; = &minus; sin 123456789&deg;.
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 = &plusmn;90&deg;, 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 [&minus;180&deg; 180&deg;). N.B.,
667
+ * atan2d(&plusmn;0, &minus;1) = &minus;180&deg;; atan2d(+&epsilon;,
668
+ * &minus;1) = +180&deg;, for &epsilon; positive and tiny;
669
+ * atan2d(&plusmn;0, 1) = &plusmn;0&deg;.
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&chi; in terms of tan&phi;
740
+ *
741
+ * @tparam T the type of the argument and the returned value.
742
+ * @param[in] tau &tau; = tan&phi;
743
+ * @param[in] es the signed eccentricity = sign(<i>e</i><sup>2</sup>)
744
+ * sqrt(|<i>e</i><sup>2</sup>|)
745
+ * @return &tau;&prime; = tan&chi;
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&phi; in terms of tan&chi;
758
+ *
759
+ * @tparam T the type of the argument and the returned value.
760
+ * @param[in] taup &tau;&prime; = tan&chi;
761
+ * @param[in] es the signed eccentricity = sign(<i>e</i><sup>2</sup>)
762
+ * sqrt(|<i>e</i><sup>2</sup>|)
763
+ * @return &tau; = tan&phi;
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