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,376 @@
1
+ /**
2
+ * \file SphericalEngine.hpp
3
+ * \brief Header for GeographicLib::SphericalEngine class
4
+ *
5
+ * Copyright (c) Charles Karney (2011-2012) <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_SPHERICALENGINE_HPP)
11
+ #define GEOGRAPHICLIB_SPHERICALENGINE_HPP 1
12
+
13
+ #include <vector>
14
+ #include <istream>
15
+ #include <GeographicLib/Constants.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 CircularEngine;
26
+
27
+ /**
28
+ * \brief The evaluation engine for SphericalHarmonic
29
+ *
30
+ * This serves as the backend to SphericalHarmonic, SphericalHarmonic1, and
31
+ * SphericalHarmonic2. Typically end-users will not have to access this
32
+ * class directly.
33
+ *
34
+ * See SphericalEngine.cpp for more information on the implementation.
35
+ *
36
+ * Example of use:
37
+ * \include example-SphericalEngine.cpp
38
+ **********************************************************************/
39
+
40
+ class GEOGRAPHICLIB_EXPORT SphericalEngine {
41
+ private:
42
+ typedef Math::real real;
43
+ // A table of the square roots of integers
44
+ static std::vector<real> root_;
45
+ friend class CircularEngine; // CircularEngine needs access to root_, scale_
46
+ // An internal scaling of the coefficients to avoid overflow in
47
+ // intermediate calculations.
48
+ static real scale() {
49
+ using std::pow;
50
+ return pow(real(std::numeric_limits<real>::radix),
51
+ -3 * (std::numeric_limits<real>::max_exponent < (1<<14) ?
52
+ std::numeric_limits<real>::max_exponent : (1<<14)) / 5);
53
+ }
54
+ // Move latitudes near the pole off the axis by this amount.
55
+ static real eps() {
56
+ using std::sqrt;
57
+ return std::numeric_limits<real>::epsilon() *
58
+ sqrt(std::numeric_limits<real>::epsilon());
59
+ }
60
+ static const std::vector<real> Z_;
61
+ SphericalEngine(); // Disable constructor
62
+ public:
63
+ /**
64
+ * Supported normalizations for associated Legendre polynomials.
65
+ **********************************************************************/
66
+ enum normalization {
67
+ /**
68
+ * Fully normalized associated Legendre polynomials. See
69
+ * SphericalHarmonic::FULL for documentation.
70
+ *
71
+ * @hideinitializer
72
+ **********************************************************************/
73
+ FULL = 0,
74
+ /**
75
+ * Schmidt semi-normalized associated Legendre polynomials. See
76
+ * SphericalHarmonic::SCHMIDT for documentation.
77
+ *
78
+ * @hideinitializer
79
+ **********************************************************************/
80
+ SCHMIDT = 1,
81
+ };
82
+
83
+ /**
84
+ * \brief Package up coefficients for SphericalEngine
85
+ *
86
+ * This packages up the \e C, \e S coefficients and information about how
87
+ * the coefficients are stored into a single structure. This allows a
88
+ * vector of type SphericalEngine::coeff to be passed to
89
+ * SphericalEngine::Value. This class also includes functions to aid
90
+ * indexing into \e C and \e S.
91
+ *
92
+ * The storage layout of the coefficients is documented in
93
+ * SphericalHarmonic and SphericalHarmonic::SphericalHarmonic.
94
+ **********************************************************************/
95
+ class GEOGRAPHICLIB_EXPORT coeff {
96
+ private:
97
+ int _Nx, _nmx, _mmx;
98
+ std::vector<real>::const_iterator _Cnm;
99
+ std::vector<real>::const_iterator _Snm;
100
+ public:
101
+ /**
102
+ * A default constructor
103
+ **********************************************************************/
104
+ coeff()
105
+ : _Nx(-1)
106
+ , _nmx(-1)
107
+ , _mmx(-1)
108
+ , _Cnm(Z_.begin())
109
+ , _Snm(Z_.begin()) {}
110
+ /**
111
+ * The general constructor.
112
+ *
113
+ * @param[in] C a vector of coefficients for the cosine terms.
114
+ * @param[in] S a vector of coefficients for the sine terms.
115
+ * @param[in] N the degree giving storage layout for \e C and \e S.
116
+ * @param[in] nmx the maximum degree to be used.
117
+ * @param[in] mmx the maximum order to be used.
118
+ * @exception GeographicErr if \e N, \e nmx, and \e mmx do not satisfy
119
+ * \e N &ge; \e nmx &ge; \e mmx &ge; &minus;1.
120
+ * @exception GeographicErr if \e C or \e S is not big enough to hold the
121
+ * coefficients.
122
+ * @exception std::bad_alloc if the memory for the square root table
123
+ * can't be allocated.
124
+ **********************************************************************/
125
+ coeff(const std::vector<real>& C,
126
+ const std::vector<real>& S,
127
+ int N, int nmx, int mmx)
128
+ : _Nx(N)
129
+ , _nmx(nmx)
130
+ , _mmx(mmx)
131
+ , _Cnm(C.begin())
132
+ , _Snm(S.begin())
133
+ {
134
+ if (!(_Nx >= _nmx && _nmx >= _mmx && _mmx >= -1))
135
+ throw GeographicErr("Bad indices for coeff");
136
+ if (!(index(_nmx, _mmx) < int(C.size()) &&
137
+ index(_nmx, _mmx) < int(S.size()) + (_Nx + 1)))
138
+ throw GeographicErr("Arrays too small in coeff");
139
+ SphericalEngine::RootTable(_nmx);
140
+ }
141
+ /**
142
+ * The constructor for full coefficient vectors.
143
+ *
144
+ * @param[in] C a vector of coefficients for the cosine terms.
145
+ * @param[in] S a vector of coefficients for the sine terms.
146
+ * @param[in] N the maximum degree and order.
147
+ * @exception GeographicErr if \e N does not satisfy \e N &ge; &minus;1.
148
+ * @exception GeographicErr if \e C or \e S is not big enough to hold the
149
+ * coefficients.
150
+ * @exception std::bad_alloc if the memory for the square root table
151
+ * can't be allocated.
152
+ **********************************************************************/
153
+ coeff(const std::vector<real>& C,
154
+ const std::vector<real>& S,
155
+ int N)
156
+ : _Nx(N)
157
+ , _nmx(N)
158
+ , _mmx(N)
159
+ , _Cnm(C.begin())
160
+ , _Snm(S.begin())
161
+ {
162
+ if (!(_Nx >= -1))
163
+ throw GeographicErr("Bad indices for coeff");
164
+ if (!(index(_nmx, _mmx) < int(C.size()) &&
165
+ index(_nmx, _mmx) < int(S.size()) + (_Nx + 1)))
166
+ throw GeographicErr("Arrays too small in coeff");
167
+ SphericalEngine::RootTable(_nmx);
168
+ }
169
+ /**
170
+ * @return \e N the degree giving storage layout for \e C and \e S.
171
+ **********************************************************************/
172
+ inline int N() const { return _Nx; }
173
+ /**
174
+ * @return \e nmx the maximum degree to be used.
175
+ **********************************************************************/
176
+ inline int nmx() const { return _nmx; }
177
+ /**
178
+ * @return \e mmx the maximum order to be used.
179
+ **********************************************************************/
180
+ inline int mmx() const { return _mmx; }
181
+ /**
182
+ * The one-dimensional index into \e C and \e S.
183
+ *
184
+ * @param[in] n the degree.
185
+ * @param[in] m the order.
186
+ * @return the one-dimensional index.
187
+ **********************************************************************/
188
+ inline int index(int n, int m) const
189
+ { return m * _Nx - m * (m - 1) / 2 + n; }
190
+ /**
191
+ * An element of \e C.
192
+ *
193
+ * @param[in] k the one-dimensional index.
194
+ * @return the value of the \e C coefficient.
195
+ **********************************************************************/
196
+ inline Math::real Cv(int k) const { return *(_Cnm + k); }
197
+ /**
198
+ * An element of \e S.
199
+ *
200
+ * @param[in] k the one-dimensional index.
201
+ * @return the value of the \e S coefficient.
202
+ **********************************************************************/
203
+ inline Math::real Sv(int k) const { return *(_Snm + (k - (_Nx + 1))); }
204
+ /**
205
+ * An element of \e C with checking.
206
+ *
207
+ * @param[in] k the one-dimensional index.
208
+ * @param[in] n the requested degree.
209
+ * @param[in] m the requested order.
210
+ * @param[in] f a multiplier.
211
+ * @return the value of the \e C coefficient multiplied by \e f in \e n
212
+ * and \e m are in range else 0.
213
+ **********************************************************************/
214
+ inline Math::real Cv(int k, int n, int m, real f) const
215
+ { return m > _mmx || n > _nmx ? 0 : *(_Cnm + k) * f; }
216
+ /**
217
+ * An element of \e S with checking.
218
+ *
219
+ * @param[in] k the one-dimensional index.
220
+ * @param[in] n the requested degree.
221
+ * @param[in] m the requested order.
222
+ * @param[in] f a multiplier.
223
+ * @return the value of the \e S coefficient multiplied by \e f in \e n
224
+ * and \e m are in range else 0.
225
+ **********************************************************************/
226
+ inline Math::real Sv(int k, int n, int m, real f) const
227
+ { return m > _mmx || n > _nmx ? 0 : *(_Snm + (k - (_Nx + 1))) * f; }
228
+
229
+ /**
230
+ * The size of the coefficient vector for the cosine terms.
231
+ *
232
+ * @param[in] N the maximum degree.
233
+ * @param[in] M the maximum order.
234
+ * @return the size of the vector of cosine terms as stored in column
235
+ * major order.
236
+ **********************************************************************/
237
+ static inline int Csize(int N, int M)
238
+ { return (M + 1) * (2 * N - M + 2) / 2; }
239
+
240
+ /**
241
+ * The size of the coefficient vector for the sine terms.
242
+ *
243
+ * @param[in] N the maximum degree.
244
+ * @param[in] M the maximum order.
245
+ * @return the size of the vector of cosine terms as stored in column
246
+ * major order.
247
+ **********************************************************************/
248
+ static inline int Ssize(int N, int M)
249
+ { return Csize(N, M) - (N + 1); }
250
+
251
+ /**
252
+ * Load coefficients from a binary stream.
253
+ *
254
+ * @param[in] stream the input stream.
255
+ * @param[out] N The maximum degree of the coefficients.
256
+ * @param[out] M The maximum order of the coefficients.
257
+ * @param[out] C The vector of cosine coefficients.
258
+ * @param[out] S The vector of sine coefficients.
259
+ * @exception GeographicErr if \e N and \e M do not satisfy \e N &ge;
260
+ * \e M &ge; &minus;1.
261
+ * @exception GeographicErr if there's an error reading the data.
262
+ * @exception std::bad_alloc if the memory for \e C or \e S can't be
263
+ * allocated.
264
+ *
265
+ * \e N and \e M are read as 4-byte ints. \e C and \e S are resized to
266
+ * accommodate all the coefficients (with the \e m = 0 coefficients for
267
+ * \e S excluded) and the data for these coefficients read as 8-byte
268
+ * doubles. The coefficients are stored in column major order. The
269
+ * bytes in the stream should use little-endian ordering. IEEE floating
270
+ * point is assumed for the coefficients.
271
+ **********************************************************************/
272
+ static void readcoeffs(std::istream& stream, int& N, int& M,
273
+ std::vector<real>& C, std::vector<real>& S);
274
+ };
275
+
276
+ /**
277
+ * Evaluate a spherical harmonic sum and its gradient.
278
+ *
279
+ * @tparam gradp should the gradient be calculated.
280
+ * @tparam norm the normalization for the associated Legendre polynomials.
281
+ * @tparam L the number of terms in the coefficients.
282
+ * @param[in] c an array of coeff objects.
283
+ * @param[in] f array of coefficient multipliers. f[0] should be 1.
284
+ * @param[in] x the \e x component of the cartesian position.
285
+ * @param[in] y the \e y component of the cartesian position.
286
+ * @param[in] z the \e z component of the cartesian position.
287
+ * @param[in] a the normalizing radius.
288
+ * @param[out] gradx the \e x component of the gradient.
289
+ * @param[out] grady the \e y component of the gradient.
290
+ * @param[out] gradz the \e z component of the gradient.
291
+ * @result the spherical harmonic sum.
292
+ *
293
+ * See the SphericalHarmonic class for the definition of the sum. The
294
+ * coefficients used by this function are, for example, c[0].Cv + f[1] *
295
+ * c[1].Cv + ... + f[L&minus;1] * c[L&minus;1].Cv. (Note that f[0] is \e
296
+ * not used.) The upper limits on the sum are determined by c[0].nmx() and
297
+ * c[0].mmx(); these limits apply to \e all the components of the
298
+ * coefficients. The parameters \e gradp, \e norm, and \e L are template
299
+ * parameters, to allow more optimization to be done at compile time.
300
+ *
301
+ * Clenshaw summation is used which permits the evaluation of the sum
302
+ * without the need to allocate temporary arrays. Thus this function never
303
+ * throws an exception.
304
+ **********************************************************************/
305
+ template<bool gradp, normalization norm, int L>
306
+ static Math::real Value(const coeff c[], const real f[],
307
+ real x, real y, real z, real a,
308
+ real& gradx, real& grady, real& gradz);
309
+
310
+ /**
311
+ * Create a CircularEngine object
312
+ *
313
+ * @tparam gradp should the gradient be calculated.
314
+ * @tparam norm the normalization for the associated Legendre polynomials.
315
+ * @tparam L the number of terms in the coefficients.
316
+ * @param[in] c an array of coeff objects.
317
+ * @param[in] f array of coefficient multipliers. f[0] should be 1.
318
+ * @param[in] p the radius of the circle = sqrt(<i>x</i><sup>2</sup> +
319
+ * <i>y</i><sup>2</sup>).
320
+ * @param[in] z the height of the circle.
321
+ * @param[in] a the normalizing radius.
322
+ * @exception std::bad_alloc if the memory for the CircularEngine can't be
323
+ * allocated.
324
+ * @result the CircularEngine object.
325
+ *
326
+ * If you need to evaluate the spherical harmonic sum for several points
327
+ * with constant \e f, \e p = sqrt(<i>x</i><sup>2</sup> +
328
+ * <i>y</i><sup>2</sup>), \e z, and \e a, it is more efficient to construct
329
+ * call SphericalEngine::Circle to give a CircularEngine object and then
330
+ * call CircularEngine::operator()() with arguments <i>x</i>/\e p and
331
+ * <i>y</i>/\e p.
332
+ **********************************************************************/
333
+ template<bool gradp, normalization norm, int L>
334
+ static CircularEngine Circle(const coeff c[], const real f[],
335
+ real p, real z, real a);
336
+ /**
337
+ * Check that the static table of square roots is big enough and enlarge it
338
+ * if necessary.
339
+ *
340
+ * @param[in] N the maximum degree to be used in SphericalEngine.
341
+ * @exception std::bad_alloc if the memory for the square root table can't
342
+ * be allocated.
343
+ *
344
+ * Typically, there's no need for an end-user to call this routine, because
345
+ * the constructors for SphericalEngine::coeff do so. However, since this
346
+ * updates a static table, there's a possible race condition in a
347
+ * multi-threaded environment. Because this routine does nothing if the
348
+ * table is already large enough, one way to avoid race conditions is to
349
+ * call this routine at program start up (when it's still single threaded),
350
+ * supplying the largest degree that your program will use. E.g., \code
351
+ GeographicLib::SphericalEngine::RootTable(2190);
352
+ \endcode
353
+ * suffices to accommodate extant magnetic and gravity models.
354
+ **********************************************************************/
355
+ static void RootTable(int N);
356
+
357
+ /**
358
+ * Clear the static table of square roots and release the memory. Call
359
+ * this only when you are sure you no longer will be using SphericalEngine.
360
+ * Your program will crash if you call SphericalEngine after calling this
361
+ * routine. <b>It's safest not to call this routine at all.</b> (The space
362
+ * used by the table is modest.)
363
+ **********************************************************************/
364
+ static void ClearRootTable() {
365
+ std::vector<real> temp(0);
366
+ root_.swap(temp);
367
+ }
368
+ };
369
+
370
+ } // namespace GeographicLib
371
+
372
+ #if defined(_MSC_VER)
373
+ # pragma warning (pop)
374
+ #endif
375
+
376
+ #endif // GEOGRAPHICLIB_SPHERICALENGINE_HPP
@@ -0,0 +1,354 @@
1
+ /**
2
+ * \file SphericalHarmonic.hpp
3
+ * \brief Header for GeographicLib::SphericalHarmonic class
4
+ *
5
+ * Copyright (c) Charles Karney (2011) <charles@karney.com> and licensed under
6
+ * the MIT/X11 License. For more information, see
7
+ * http://geographiclib.sourceforge.net/
8
+ **********************************************************************/
9
+
10
+ #if !defined(GEOGRAPHICLIB_SPHERICALHARMONIC_HPP)
11
+ #define GEOGRAPHICLIB_SPHERICALHARMONIC_HPP 1
12
+
13
+ #include <vector>
14
+ #include <GeographicLib/Constants.hpp>
15
+ #include <GeographicLib/SphericalEngine.hpp>
16
+ #include <GeographicLib/CircularEngine.hpp>
17
+
18
+ namespace GeographicLib {
19
+
20
+ /**
21
+ * \brief Spherical harmonic series
22
+ *
23
+ * This class evaluates the spherical harmonic sum \verbatim
24
+ V(x, y, z) = sum(n = 0..N)[ q^(n+1) * sum(m = 0..n)[
25
+ (C[n,m] * cos(m*lambda) + S[n,m] * sin(m*lambda)) *
26
+ P[n,m](cos(theta)) ] ]
27
+ \endverbatim
28
+ * where
29
+ * - <i>p</i><sup>2</sup> = <i>x</i><sup>2</sup> + <i>y</i><sup>2</sup>,
30
+ * - <i>r</i><sup>2</sup> = <i>p</i><sup>2</sup> + <i>z</i><sup>2</sup>,
31
+ * - \e q = <i>a</i>/<i>r</i>,
32
+ * - &theta; = atan2(\e p, \e z) = the spherical \e colatitude,
33
+ * - &lambda; = atan2(\e y, \e x) = the longitude.
34
+ * - P<sub><i>nm</i></sub>(\e t) is the associated Legendre polynomial of
35
+ * degree \e n and order \e m.
36
+ *
37
+ * Two normalizations are supported for P<sub><i>nm</i></sub>
38
+ * - fully normalized denoted by SphericalHarmonic::FULL.
39
+ * - Schmidt semi-normalized denoted by SphericalHarmonic::SCHMIDT.
40
+ *
41
+ * Clenshaw summation is used for the sums over both \e n and \e m. This
42
+ * allows the computation to be carried out without the need for any
43
+ * temporary arrays. See SphericalEngine.cpp for more information on the
44
+ * implementation.
45
+ *
46
+ * References:
47
+ * - C. W. Clenshaw,
48
+ * <a href="https://dx.doi.org/10.1090/S0025-5718-1955-0071856-0">
49
+ * A note on the summation of Chebyshev series</a>,
50
+ * %Math. Tables Aids Comput. 9(51), 118--120 (1955).
51
+ * - R. E. Deakin, Derivatives of the earth's potentials, Geomatics
52
+ * Research Australasia 68, 31--60, (June 1998).
53
+ * - W. A. Heiskanen and H. Moritz, Physical Geodesy, (Freeman, San
54
+ * Francisco, 1967). (See Sec. 1-14, for a definition of Pbar.)
55
+ * - S. A. Holmes and W. E. Featherstone,
56
+ * <a href="https://dx.doi.org/10.1007/s00190-002-0216-2">
57
+ * A unified approach to the Clenshaw summation and the recursive
58
+ * computation of very high degree and order normalised associated Legendre
59
+ * functions</a>, J. Geodesy 76(5), 279--299 (2002).
60
+ * - C. C. Tscherning and K. Poder,
61
+ * <a href="http://cct.gfy.ku.dk/publ_cct/cct80.pdf">
62
+ * Some geodetic applications of Clenshaw summation</a>,
63
+ * Boll. Geod. Sci. Aff. 41(4), 349--375 (1982).
64
+ *
65
+ * Example of use:
66
+ * \include example-SphericalHarmonic.cpp
67
+ **********************************************************************/
68
+
69
+ class GEOGRAPHICLIB_EXPORT SphericalHarmonic {
70
+ public:
71
+ /**
72
+ * Supported normalizations for the associated Legendre polynomials.
73
+ **********************************************************************/
74
+ enum normalization {
75
+ /**
76
+ * Fully normalized associated Legendre polynomials.
77
+ *
78
+ * These are defined by
79
+ * <i>P</i><sub><i>nm</i></sub><sup>full</sup>(\e z)
80
+ * = (&minus;1)<sup><i>m</i></sup>
81
+ * sqrt(\e k (2\e n + 1) (\e n &minus; \e m)! / (\e n + \e m)!)
82
+ * <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z), where
83
+ * <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z) is Ferrers
84
+ * function (also known as the Legendre function on the cut or the
85
+ * associated Legendre polynomial) http://dlmf.nist.gov/14.7.E10 and \e k
86
+ * = 1 for \e m = 0 and \e k = 2 otherwise.
87
+ *
88
+ * The mean squared value of
89
+ * <i>P</i><sub><i>nm</i></sub><sup>full</sup>(cos&theta;)
90
+ * cos(<i>m</i>&lambda;) and
91
+ * <i>P</i><sub><i>nm</i></sub><sup>full</sup>(cos&theta;)
92
+ * sin(<i>m</i>&lambda;) over the sphere is 1.
93
+ *
94
+ * @hideinitializer
95
+ **********************************************************************/
96
+ FULL = SphericalEngine::FULL,
97
+ /**
98
+ * Schmidt semi-normalized associated Legendre polynomials.
99
+ *
100
+ * These are defined by
101
+ * <i>P</i><sub><i>nm</i></sub><sup>schmidt</sup>(\e z)
102
+ * = (&minus;1)<sup><i>m</i></sup>
103
+ * sqrt(\e k (\e n &minus; \e m)! / (\e n + \e m)!)
104
+ * <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z), where
105
+ * <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z) is Ferrers
106
+ * function (also known as the Legendre function on the cut or the
107
+ * associated Legendre polynomial) http://dlmf.nist.gov/14.7.E10 and \e k
108
+ * = 1 for \e m = 0 and \e k = 2 otherwise.
109
+ *
110
+ * The mean squared value of
111
+ * <i>P</i><sub><i>nm</i></sub><sup>schmidt</sup>(cos&theta;)
112
+ * cos(<i>m</i>&lambda;) and
113
+ * <i>P</i><sub><i>nm</i></sub><sup>schmidt</sup>(cos&theta;)
114
+ * sin(<i>m</i>&lambda;) over the sphere is 1/(2\e n + 1).
115
+ *
116
+ * @hideinitializer
117
+ **********************************************************************/
118
+ SCHMIDT = SphericalEngine::SCHMIDT,
119
+ };
120
+
121
+ private:
122
+ typedef Math::real real;
123
+ SphericalEngine::coeff _c[1];
124
+ real _a;
125
+ unsigned _norm;
126
+
127
+ public:
128
+ /**
129
+ * Constructor with a full set of coefficients specified.
130
+ *
131
+ * @param[in] C the coefficients <i>C</i><sub><i>nm</i></sub>.
132
+ * @param[in] S the coefficients <i>S</i><sub><i>nm</i></sub>.
133
+ * @param[in] N the maximum degree and order of the sum
134
+ * @param[in] a the reference radius appearing in the definition of the
135
+ * sum.
136
+ * @param[in] norm the normalization for the associated Legendre
137
+ * polynomials, either SphericalHarmonic::FULL (the default) or
138
+ * SphericalHarmonic::SCHMIDT.
139
+ * @exception GeographicErr if \e N does not satisfy \e N &ge; &minus;1.
140
+ * @exception GeographicErr if \e C or \e S is not big enough to hold the
141
+ * coefficients.
142
+ *
143
+ * The coefficients <i>C</i><sub><i>nm</i></sub> and
144
+ * <i>S</i><sub><i>nm</i></sub> are stored in the one-dimensional vectors
145
+ * \e C and \e S which must contain (\e N + 1)(\e N + 2)/2 and \e N (\e N +
146
+ * 1)/2 elements, respectively, stored in "column-major" order. Thus for
147
+ * \e N = 3, the order would be:
148
+ * <i>C</i><sub>00</sub>,
149
+ * <i>C</i><sub>10</sub>,
150
+ * <i>C</i><sub>20</sub>,
151
+ * <i>C</i><sub>30</sub>,
152
+ * <i>C</i><sub>11</sub>,
153
+ * <i>C</i><sub>21</sub>,
154
+ * <i>C</i><sub>31</sub>,
155
+ * <i>C</i><sub>22</sub>,
156
+ * <i>C</i><sub>32</sub>,
157
+ * <i>C</i><sub>33</sub>.
158
+ * In general the (\e n,\e m) element is at index \e m \e N &minus; \e m
159
+ * (\e m &minus; 1)/2 + \e n. The layout of \e S is the same except that
160
+ * the first column is omitted (since the \e m = 0 terms never contribute
161
+ * to the sum) and the 0th element is <i>S</i><sub>11</sub>
162
+ *
163
+ * The class stores <i>pointers</i> to the first elements of \e C and \e S.
164
+ * These arrays should not be altered or destroyed during the lifetime of a
165
+ * SphericalHarmonic object.
166
+ **********************************************************************/
167
+ SphericalHarmonic(const std::vector<real>& C,
168
+ const std::vector<real>& S,
169
+ int N, real a, unsigned norm = FULL)
170
+ : _a(a)
171
+ , _norm(norm)
172
+ { _c[0] = SphericalEngine::coeff(C, S, N); }
173
+
174
+ /**
175
+ * Constructor with a subset of coefficients specified.
176
+ *
177
+ * @param[in] C the coefficients <i>C</i><sub><i>nm</i></sub>.
178
+ * @param[in] S the coefficients <i>S</i><sub><i>nm</i></sub>.
179
+ * @param[in] N the degree used to determine the layout of \e C and \e S.
180
+ * @param[in] nmx the maximum degree used in the sum. The sum over \e n is
181
+ * from 0 thru \e nmx.
182
+ * @param[in] mmx the maximum order used in the sum. The sum over \e m is
183
+ * from 0 thru min(\e n, \e mmx).
184
+ * @param[in] a the reference radius appearing in the definition of the
185
+ * sum.
186
+ * @param[in] norm the normalization for the associated Legendre
187
+ * polynomials, either SphericalHarmonic::FULL (the default) or
188
+ * SphericalHarmonic::SCHMIDT.
189
+ * @exception GeographicErr if \e N, \e nmx, and \e mmx do not satisfy
190
+ * \e N &ge; \e nmx &ge; \e mmx &ge; &minus;1.
191
+ * @exception GeographicErr if \e C or \e S is not big enough to hold the
192
+ * coefficients.
193
+ *
194
+ * The class stores <i>pointers</i> to the first elements of \e C and \e S.
195
+ * These arrays should not be altered or destroyed during the lifetime of a
196
+ * SphericalHarmonic object.
197
+ **********************************************************************/
198
+ SphericalHarmonic(const std::vector<real>& C,
199
+ const std::vector<real>& S,
200
+ int N, int nmx, int mmx,
201
+ real a, unsigned norm = FULL)
202
+ : _a(a)
203
+ , _norm(norm)
204
+ { _c[0] = SphericalEngine::coeff(C, S, N, nmx, mmx); }
205
+
206
+ /**
207
+ * A default constructor so that the object can be created when the
208
+ * constructor for another object is initialized. This default object can
209
+ * then be reset with the default copy assignment operator.
210
+ **********************************************************************/
211
+ SphericalHarmonic() {}
212
+
213
+ /**
214
+ * Compute the spherical harmonic sum.
215
+ *
216
+ * @param[in] x cartesian coordinate.
217
+ * @param[in] y cartesian coordinate.
218
+ * @param[in] z cartesian coordinate.
219
+ * @return \e V the spherical harmonic sum.
220
+ *
221
+ * This routine requires constant memory and thus never throws an
222
+ * exception.
223
+ **********************************************************************/
224
+ Math::real operator()(real x, real y, real z) const {
225
+ real f[] = {1};
226
+ real v = 0;
227
+ real dummy;
228
+ switch (_norm) {
229
+ case FULL:
230
+ v = SphericalEngine::Value<false, SphericalEngine::FULL, 1>
231
+ (_c, f, x, y, z, _a, dummy, dummy, dummy);
232
+ break;
233
+ case SCHMIDT:
234
+ v = SphericalEngine::Value<false, SphericalEngine::SCHMIDT, 1>
235
+ (_c, f, x, y, z, _a, dummy, dummy, dummy);
236
+ break;
237
+ }
238
+ return v;
239
+ }
240
+
241
+ /**
242
+ * Compute a spherical harmonic sum and its gradient.
243
+ *
244
+ * @param[in] x cartesian coordinate.
245
+ * @param[in] y cartesian coordinate.
246
+ * @param[in] z cartesian coordinate.
247
+ * @param[out] gradx \e x component of the gradient
248
+ * @param[out] grady \e y component of the gradient
249
+ * @param[out] gradz \e z component of the gradient
250
+ * @return \e V the spherical harmonic sum.
251
+ *
252
+ * This is the same as the previous function, except that the components of
253
+ * the gradients of the sum in the \e x, \e y, and \e z directions are
254
+ * computed. This routine requires constant memory and thus never throws
255
+ * an exception.
256
+ **********************************************************************/
257
+ Math::real operator()(real x, real y, real z,
258
+ real& gradx, real& grady, real& gradz) const {
259
+ real f[] = {1};
260
+ real v = 0;
261
+ switch (_norm) {
262
+ case FULL:
263
+ v = SphericalEngine::Value<true, SphericalEngine::FULL, 1>
264
+ (_c, f, x, y, z, _a, gradx, grady, gradz);
265
+ break;
266
+ case SCHMIDT:
267
+ v = SphericalEngine::Value<true, SphericalEngine::SCHMIDT, 1>
268
+ (_c, f, x, y, z, _a, gradx, grady, gradz);
269
+ break;
270
+ }
271
+ return v;
272
+ }
273
+
274
+ /**
275
+ * Create a CircularEngine to allow the efficient evaluation of several
276
+ * points on a circle of latitude.
277
+ *
278
+ * @param[in] p the radius of the circle.
279
+ * @param[in] z the height of the circle above the equatorial plane.
280
+ * @param[in] gradp if true the returned object will be able to compute the
281
+ * gradient of the sum.
282
+ * @exception std::bad_alloc if the memory for the CircularEngine can't be
283
+ * allocated.
284
+ * @return the CircularEngine object.
285
+ *
286
+ * SphericalHarmonic::operator()() exchanges the order of the sums in the
287
+ * definition, i.e., &sum;<sub><i>n</i> = 0..<i>N</i></sub>
288
+ * &sum;<sub><i>m</i> = 0..<i>n</i></sub> becomes &sum;<sub><i>m</i> =
289
+ * 0..<i>N</i></sub> &sum;<sub><i>n</i> = <i>m</i>..<i>N</i></sub>.
290
+ * SphericalHarmonic::Circle performs the inner sum over degree \e n (which
291
+ * entails about <i>N</i><sup>2</sup> operations). Calling
292
+ * CircularEngine::operator()() on the returned object performs the outer
293
+ * sum over the order \e m (about \e N operations).
294
+ *
295
+ * Here's an example of computing the spherical sum at a sequence of
296
+ * longitudes without using a CircularEngine object \code
297
+ SphericalHarmonic h(...); // Create the SphericalHarmonic object
298
+ double r = 2, lat = 33, lon0 = 44, dlon = 0.01;
299
+ double
300
+ phi = lat * Math::degree<double>(),
301
+ z = r * sin(phi), p = r * cos(phi);
302
+ for (int i = 0; i <= 100; ++i) {
303
+ real
304
+ lon = lon0 + i * dlon,
305
+ lam = lon * Math::degree<double>();
306
+ std::cout << lon << " " << h(p * cos(lam), p * sin(lam), z) << "\n";
307
+ }
308
+ \endcode
309
+ * Here is the same calculation done using a CircularEngine object. This
310
+ * will be about <i>N</i>/2 times faster. \code
311
+ SphericalHarmonic h(...); // Create the SphericalHarmonic object
312
+ double r = 2, lat = 33, lon0 = 44, dlon = 0.01;
313
+ double
314
+ phi = lat * Math::degree<double>(),
315
+ z = r * sin(phi), p = r * cos(phi);
316
+ CircularEngine c(h(p, z, false)); // Create the CircularEngine object
317
+ for (int i = 0; i <= 100; ++i) {
318
+ real
319
+ lon = lon0 + i * dlon;
320
+ std::cout << lon << " " << c(lon) << "\n";
321
+ }
322
+ \endcode
323
+ **********************************************************************/
324
+ CircularEngine Circle(real p, real z, bool gradp) const {
325
+ real f[] = {1};
326
+ switch (_norm) {
327
+ case FULL:
328
+ return gradp ?
329
+ SphericalEngine::Circle<true, SphericalEngine::FULL, 1>
330
+ (_c, f, p, z, _a) :
331
+ SphericalEngine::Circle<false, SphericalEngine::FULL, 1>
332
+ (_c, f, p, z, _a);
333
+ break;
334
+ case SCHMIDT:
335
+ default: // To avoid compiler warnings
336
+ return gradp ?
337
+ SphericalEngine::Circle<true, SphericalEngine::SCHMIDT, 1>
338
+ (_c, f, p, z, _a) :
339
+ SphericalEngine::Circle<false, SphericalEngine::SCHMIDT, 1>
340
+ (_c, f, p, z, _a);
341
+ break;
342
+ }
343
+ }
344
+
345
+ /**
346
+ * @return the zeroth SphericalEngine::coeff object.
347
+ **********************************************************************/
348
+ const SphericalEngine::coeff& Coefficients() const
349
+ { return _c[0]; }
350
+ };
351
+
352
+ } // namespace GeographicLib
353
+
354
+ #endif // GEOGRAPHICLIB_SPHERICALHARMONIC_HPP