geographiclib 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/AUTHORS +12 -0
- data/LICENSE +24 -0
- data/ext/geographiclib/Accumulator.cpp +23 -0
- data/ext/geographiclib/AlbersEqualArea.cpp +445 -0
- data/ext/geographiclib/AzimuthalEquidistant.cpp +41 -0
- data/ext/geographiclib/CassiniSoldner.cpp +89 -0
- data/ext/geographiclib/CircularEngine.cpp +96 -0
- data/ext/geographiclib/DMS.cpp +381 -0
- data/ext/geographiclib/Ellipsoid.cpp +125 -0
- data/ext/geographiclib/EllipticFunction.cpp +512 -0
- data/ext/geographiclib/GARS.cpp +122 -0
- data/ext/geographiclib/GeoCoords.cpp +175 -0
- data/ext/geographiclib/Geocentric.cpp +172 -0
- data/ext/geographiclib/Geodesic.cpp +1908 -0
- data/ext/geographiclib/GeodesicExact.cpp +927 -0
- data/ext/geographiclib/GeodesicExactC4.cpp +7879 -0
- data/ext/geographiclib/GeodesicLine.cpp +321 -0
- data/ext/geographiclib/GeodesicLineExact.cpp +289 -0
- data/ext/geographiclib/GeographicLib/Accumulator.hpp +184 -0
- data/ext/geographiclib/GeographicLib/AlbersEqualArea.hpp +312 -0
- data/ext/geographiclib/GeographicLib/AzimuthalEquidistant.hpp +139 -0
- data/ext/geographiclib/GeographicLib/CassiniSoldner.hpp +204 -0
- data/ext/geographiclib/GeographicLib/CircularEngine.hpp +195 -0
- data/ext/geographiclib/GeographicLib/Config.h +12 -0
- data/ext/geographiclib/GeographicLib/Constants.hpp +387 -0
- data/ext/geographiclib/GeographicLib/DMS.hpp +370 -0
- data/ext/geographiclib/GeographicLib/Ellipsoid.hpp +534 -0
- data/ext/geographiclib/GeographicLib/EllipticFunction.hpp +692 -0
- data/ext/geographiclib/GeographicLib/GARS.hpp +143 -0
- data/ext/geographiclib/GeographicLib/GeoCoords.hpp +544 -0
- data/ext/geographiclib/GeographicLib/Geocentric.hpp +267 -0
- data/ext/geographiclib/GeographicLib/Geodesic.hpp +970 -0
- data/ext/geographiclib/GeographicLib/GeodesicExact.hpp +862 -0
- data/ext/geographiclib/GeographicLib/GeodesicLine.hpp +701 -0
- data/ext/geographiclib/GeographicLib/GeodesicLineExact.hpp +667 -0
- data/ext/geographiclib/GeographicLib/Geohash.hpp +180 -0
- data/ext/geographiclib/GeographicLib/Geoid.hpp +472 -0
- data/ext/geographiclib/GeographicLib/Georef.hpp +160 -0
- data/ext/geographiclib/GeographicLib/Gnomonic.hpp +206 -0
- data/ext/geographiclib/GeographicLib/GravityCircle.hpp +301 -0
- data/ext/geographiclib/GeographicLib/GravityModel.hpp +520 -0
- data/ext/geographiclib/GeographicLib/LambertConformalConic.hpp +313 -0
- data/ext/geographiclib/GeographicLib/LocalCartesian.hpp +236 -0
- data/ext/geographiclib/GeographicLib/MGRS.hpp +355 -0
- data/ext/geographiclib/GeographicLib/MagneticCircle.hpp +178 -0
- data/ext/geographiclib/GeographicLib/MagneticModel.hpp +347 -0
- data/ext/geographiclib/GeographicLib/Math.hpp +920 -0
- data/ext/geographiclib/GeographicLib/NormalGravity.hpp +350 -0
- data/ext/geographiclib/GeographicLib/OSGB.hpp +249 -0
- data/ext/geographiclib/GeographicLib/PolarStereographic.hpp +150 -0
- data/ext/geographiclib/GeographicLib/PolygonArea.hpp +288 -0
- data/ext/geographiclib/GeographicLib/Rhumb.hpp +589 -0
- data/ext/geographiclib/GeographicLib/SphericalEngine.hpp +376 -0
- data/ext/geographiclib/GeographicLib/SphericalHarmonic.hpp +354 -0
- data/ext/geographiclib/GeographicLib/SphericalHarmonic1.hpp +281 -0
- data/ext/geographiclib/GeographicLib/SphericalHarmonic2.hpp +315 -0
- data/ext/geographiclib/GeographicLib/TransverseMercator.hpp +196 -0
- data/ext/geographiclib/GeographicLib/TransverseMercatorExact.hpp +254 -0
- data/ext/geographiclib/GeographicLib/UTMUPS.hpp +421 -0
- data/ext/geographiclib/GeographicLib/Utility.hpp +612 -0
- data/ext/geographiclib/Geohash.cpp +102 -0
- data/ext/geographiclib/Geoid.cpp +509 -0
- data/ext/geographiclib/Georef.cpp +135 -0
- data/ext/geographiclib/Gnomonic.cpp +85 -0
- data/ext/geographiclib/GravityCircle.cpp +129 -0
- data/ext/geographiclib/GravityModel.cpp +360 -0
- data/ext/geographiclib/LambertConformalConic.cpp +456 -0
- data/ext/geographiclib/LocalCartesian.cpp +62 -0
- data/ext/geographiclib/MGRS.cpp +461 -0
- data/ext/geographiclib/MagneticCircle.cpp +52 -0
- data/ext/geographiclib/MagneticModel.cpp +269 -0
- data/ext/geographiclib/Math.cpp +63 -0
- data/ext/geographiclib/NormalGravity.cpp +262 -0
- data/ext/geographiclib/OSGB.cpp +167 -0
- data/ext/geographiclib/PolarStereographic.cpp +108 -0
- data/ext/geographiclib/PolygonArea.cpp +204 -0
- data/ext/geographiclib/Rhumb.cpp +383 -0
- data/ext/geographiclib/SphericalEngine.cpp +477 -0
- data/ext/geographiclib/TransverseMercator.cpp +603 -0
- data/ext/geographiclib/TransverseMercatorExact.cpp +464 -0
- data/ext/geographiclib/UTMUPS.cpp +296 -0
- data/ext/geographiclib/Utility.cpp +61 -0
- data/ext/geographiclib/extconf.rb +3 -0
- data/ext/geographiclib/geographiclib.cpp +62 -0
- data/lib/geographiclib.rb +20 -0
- metadata +140 -0
@@ -0,0 +1,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 ≥ \e nmx ≥ \e mmx ≥ −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 ≥ −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 ≥
|
260
|
+
* \e M ≥ −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−1] * c[L−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
|
+
* - θ = atan2(\e p, \e z) = the spherical \e colatitude,
|
33
|
+
* - λ = 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
|
+
* = (−1)<sup><i>m</i></sup>
|
81
|
+
* sqrt(\e k (2\e n + 1) (\e n − \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θ)
|
90
|
+
* cos(<i>m</i>λ) and
|
91
|
+
* <i>P</i><sub><i>nm</i></sub><sup>full</sup>(cosθ)
|
92
|
+
* sin(<i>m</i>λ) 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
|
+
* = (−1)<sup><i>m</i></sup>
|
103
|
+
* sqrt(\e k (\e n − \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θ)
|
112
|
+
* cos(<i>m</i>λ) and
|
113
|
+
* <i>P</i><sub><i>nm</i></sub><sup>schmidt</sup>(cosθ)
|
114
|
+
* sin(<i>m</i>λ) 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 ≥ −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 − \e m
|
159
|
+
* (\e m − 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 ≥ \e nmx ≥ \e mmx ≥ −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., ∑<sub><i>n</i> = 0..<i>N</i></sub>
|
288
|
+
* ∑<sub><i>m</i> = 0..<i>n</i></sub> becomes ∑<sub><i>m</i> =
|
289
|
+
* 0..<i>N</i></sub> ∑<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
|