1 #pragma once 2 /** 3 * \file NETGeographicLib/SphericalHarmonic.h 4 * \brief Header for NETGeographicLib::SphericalHarmonic class 5 * 6 * NETGeographicLib is copyright (c) Scott Heiman (2013) 7 * GeographicLib is Copyright (c) Charles Karney (2010-2012) 8 * <charles@karney.com> and licensed under the MIT/X11 License. 9 * For more information, see 10 * https://geographiclib.sourceforge.io/ 11 **********************************************************************/ 12 13 namespace NETGeographicLib 14 { 15 ref class CircularEngine; 16 ref class SphericalCoefficients; 17 /** 18 * \brief .NET wrapper for GeographicLib::SphericalHarmonic. 19 * 20 * This class allows .NET applications to access GeographicLib::SphericalHarmonic. 21 * 22 * This class evaluates the spherical harmonic sum \verbatim 23 V(x, y, z) = sum(n = 0..N)[ q^(n+1) * sum(m = 0..n)[ 24 (C[n,m] * cos(m*lambda) + S[n,m] * sin(m*lambda)) * 25 P[n,m](cos(theta)) ] ] 26 \endverbatim 27 * where 28 * - <i>p</i><sup>2</sup> = <i>x</i><sup>2</sup> + <i>y</i><sup>2</sup>, 29 * - <i>r</i><sup>2</sup> = <i>p</i><sup>2</sup> + <i>z</i><sup>2</sup>, 30 * - \e q = <i>a</i>/<i>r</i>, 31 * - θ = atan2(\e p, \e z) = the spherical \e colatitude, 32 * - λ = atan2(\e y, \e x) = the longitude. 33 * - P<sub>\e nm</sub>(\e t) is the associated Legendre polynomial of degree 34 * \e n and order \e m. 35 * 36 * Two normalizations are supported for P<sub>\e nm</sub> 37 * - fully normalized denoted by SphericalHarmonic::FULL. 38 * - Schmidt semi-normalized denoted by SphericalHarmonic::SCHMIDT. 39 * 40 * Clenshaw summation is used for the sums over both \e n and \e m. This 41 * allows the computation to be carried out without the need for any 42 * temporary arrays. See GeographicLib::SphericalEngine.cpp for more 43 * information on the implementation. 44 * 45 * References: 46 * - C. W. Clenshaw, A note on the summation of Chebyshev series, 47 * %Math. Tables Aids Comput. 9(51), 118--120 (1955). 48 * - R. E. Deakin, Derivatives of the earth's potentials, Geomatics 49 * Research Australasia 68, 31--60, (June 1998). 50 * - W. A. Heiskanen and H. Moritz, Physical Geodesy, (Freeman, San 51 * Francisco, 1967). (See Sec. 1-14, for a definition of Pbar.) 52 * - S. A. Holmes and W. E. Featherstone, A unified approach to the Clenshaw 53 * summation and the recursive computation of very high degree and order 54 * normalised associated Legendre functions, J. Geodesy 76(5), 55 * 279--299 (2002). 56 * - C. C. Tscherning and K. Poder, Some geodetic applications of Clenshaw 57 * summation, Boll. Geod. Sci. Aff. 41(4), 349--375 (1982). 58 * 59 * C# Example: 60 * \include example-SphericalHarmonic.cs 61 * Managed C++ Example: 62 * \include example-SphericalHarmonic.cpp 63 * Visual Basic Example: 64 * \include example-SphericalHarmonic.vb 65 * 66 * <B>INTERFACE DIFFERENCES:</B><BR> 67 * This class replaces the GeographicLib::SphericalHarmonic::operator() with 68 * HarmonicSum. 69 * 70 * Coefficients returns a SphericalCoefficients object. 71 * 72 * The Normalization parameter in the constructors is passed in as an 73 * enumeration rather than an unsigned. 74 **********************************************************************/ 75 public ref class SphericalHarmonic 76 { 77 private: 78 // a pointer to the unmanaged GeographicLib::SphericalHarmonic 79 const GeographicLib::SphericalHarmonic* m_pSphericalHarmonic; 80 // the finalizer frees the unmanaged memory when the object is destroyed. 81 !SphericalHarmonic(); 82 // local containers for the cosine and sine coefficients. The 83 // GeographicLib::SphericalEngine::coeffs class uses a 84 // std::vector::iterator to access these vectors. 85 std::vector<double> *m_C, *m_S; 86 public: 87 /** 88 * Supported normalizations for the associated Legendre polynomials. 89 **********************************************************************/ 90 enum class Normalization { 91 /** 92 * Fully normalized associated Legendre polynomials. 93 * 94 * These are defined by <i>P</i><sub><i>nm</i></sub><sup>full</sup>(\e z) 95 * = (−1)<sup><i>m</i></sup> sqrt(\e k (2\e n + 1) (\e n − \e 96 * m)! / (\e n + \e m)!) 97 * <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z), where 98 * <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z) is Ferrers 99 * function (also known as the Legendre function on the cut or the 100 * associated Legendre polynomial) https://dlmf.nist.gov/14.7.E10 and \e k 101 * = 1 for \e m = 0 and \e k = 2 otherwise. 102 * 103 * The mean squared value of 104 * <i>P</i><sub><i>nm</i></sub><sup>full</sup>(cosθ) 105 * cos(<i>m</i>λ) and 106 * <i>P</i><sub><i>nm</i></sub><sup>full</sup>(cosθ) 107 * sin(<i>m</i>λ) over the sphere is 1. 108 * 109 * @hideinitializer 110 **********************************************************************/ 111 FULL = GeographicLib::SphericalEngine::FULL, 112 /** 113 * Schmidt semi-normalized associated Legendre polynomials. 114 * 115 * These are defined by <i>P</i><sub><i>nm</i></sub><sup>schmidt</sup>(\e 116 * z) = (−1)<sup><i>m</i></sup> sqrt(\e k (\e n − \e m)! / 117 * (\e n + \e m)!) <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z), 118 * where <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z) is Ferrers 119 * function (also known as the Legendre function on the cut or the 120 * associated Legendre polynomial) https://dlmf.nist.gov/14.7.E10 and \e k 121 * = 1 for \e m = 0 and \e k = 2 otherwise. 122 * 123 * The mean squared value of 124 * <i>P</i><sub><i>nm</i></sub><sup>schmidt</sup>(cosθ) 125 * cos(<i>m</i>λ) and 126 * <i>P</i><sub><i>nm</i></sub><sup>schmidt</sup>(cosθ) 127 * sin(<i>m</i>λ) over the sphere is 1/(2\e n + 1). 128 * 129 * @hideinitializer 130 **********************************************************************/ 131 SCHMIDT = GeographicLib::SphericalEngine::SCHMIDT, 132 }; 133 134 /** 135 * Constructor with a full set of coefficients specified. 136 * 137 * @param[in] C the coefficients \e C<sub>\e nm</sub>. 138 * @param[in] S the coefficients \e S<sub>\e nm</sub>. 139 * @param[in] N the maximum degree and order of the sum 140 * @param[in] a the reference radius appearing in the definition of the 141 * sum. 142 * @param[in] norm the normalization for the associated Legendre 143 * polynomials, either SphericalHarmonic::full (the default) or 144 * SphericalHarmonic::schmidt. 145 * @exception GeographicErr if \e N does not satisfy \e N ≥ −1. 146 * @exception GeographicErr if \e C or \e S is not big enough to hold the 147 * coefficients. 148 * 149 * The coefficients \e C<sub>\e nm</sub> and \e S<sub>\e nm</sub> are 150 * stored in the one-dimensional vectors \e C and \e S which must contain 151 * (\e N + 1)(\e N + 2)/2 and N (\e N + 1)/2 elements, respectively, stored 152 * in "column-major" order. Thus for \e N = 3, the order would be: 153 * <i>C</i><sub>00</sub>, 154 * <i>C</i><sub>10</sub>, 155 * <i>C</i><sub>20</sub>, 156 * <i>C</i><sub>30</sub>, 157 * <i>C</i><sub>11</sub>, 158 * <i>C</i><sub>21</sub>, 159 * <i>C</i><sub>31</sub>, 160 * <i>C</i><sub>22</sub>, 161 * <i>C</i><sub>32</sub>, 162 * <i>C</i><sub>33</sub>. 163 * In general the (\e n,\e m) element is at index \e m \e N − \e m 164 * (\e m − 1)/2 + \e n. The layout of \e S is the same except that 165 * the first column is omitted (since the \e m = 0 terms never contribute 166 * to the sum) and the 0th element is <i>S</i><sub>11</sub> 167 * 168 * The class stores <i>pointers</i> to the first elements of \e C and \e S. 169 * These arrays should not be altered or destroyed during the lifetime of a 170 * SphericalHarmonic object. 171 **********************************************************************/ 172 SphericalHarmonic(array<double>^ C, 173 array<double>^ S, 174 int N, double a, Normalization norm ); 175 176 /** 177 * Constructor with a subset of coefficients specified. 178 * 179 * @param[in] C the coefficients \e C<sub>\e nm</sub>. 180 * @param[in] S the coefficients \e S<sub>\e nm</sub>. 181 * @param[in] N the degree used to determine the layout of \e C and \e S. 182 * @param[in] nmx the maximum degree used in the sum. The sum over \e n is 183 * from 0 thru \e nmx. 184 * @param[in] mmx the maximum order used in the sum. The sum over \e m is 185 * from 0 thru min(\e n, \e mmx). 186 * @param[in] a the reference radius appearing in the definition of the 187 * sum. 188 * @param[in] norm the normalization for the associated Legendre 189 * polynomials, either SphericalHarmonic::FULL (the default) or 190 * SphericalHarmonic::SCHMIDT. 191 * @exception GeographicErr if \e N, \e nmx, and \e mmx do not satisfy 192 * \e N ≥ \e nmx ≥ \e mmx ≥ −1. 193 * @exception GeographicErr if \e C or \e S is not big enough to hold the 194 * coefficients. 195 * 196 * The class stores <i>pointers</i> to the first elements of \e C and \e S. 197 * These arrays should not be altered or destroyed during the lifetime of a 198 * SphericalHarmonic object. 199 **********************************************************************/ 200 SphericalHarmonic(array<double>^ C, 201 array<double>^ S, 202 int N, int nmx, int mmx, 203 double a, Normalization norm); 204 205 /** 206 * The destructor calls the finalizer 207 **********************************************************************/ ~SphericalHarmonic()208 ~SphericalHarmonic() { this->!SphericalHarmonic(); } 209 210 /** 211 * Compute the spherical harmonic sum. 212 * 213 * @param[in] x cartesian coordinate. 214 * @param[in] y cartesian coordinate. 215 * @param[in] z cartesian coordinate. 216 * @return \e V the spherical harmonic sum. 217 * 218 * This routine requires constant memory and thus never throws an 219 * exception. 220 **********************************************************************/ 221 double HarmonicSum(double x, double y, double z); 222 223 /** 224 * Compute a spherical harmonic sum and its gradient. 225 * 226 * @param[in] x cartesian coordinate. 227 * @param[in] y cartesian coordinate. 228 * @param[in] z cartesian coordinate. 229 * @param[out] gradx \e x component of the gradient 230 * @param[out] grady \e y component of the gradient 231 * @param[out] gradz \e z component of the gradient 232 * @return \e V the spherical harmonic sum. 233 * 234 * This is the same as the previous function, except that the components of 235 * the gradients of the sum in the \e x, \e y, and \e z directions are 236 * computed. This routine requires constant memory and thus never throws 237 * an exception. 238 **********************************************************************/ 239 double HarmonicSum(double x, double y, double z, 240 [System::Runtime::InteropServices::Out] double% gradx, 241 [System::Runtime::InteropServices::Out] double% grady, 242 [System::Runtime::InteropServices::Out] double% gradz); 243 244 /** 245 * Create a CircularEngine to allow the efficient evaluation of several 246 * points on a circle of latitude. 247 * 248 * @param[in] p the radius of the circle. 249 * @param[in] z the height of the circle above the equatorial plane. 250 * @param[in] gradp if true the returned object will be able to compute the 251 * gradient of the sum. 252 * @exception std::bad_alloc if the memory for the CircularEngine can't be 253 * allocated. 254 * @return the CircularEngine object. 255 * 256 * SphericalHarmonic::operator()() exchanges the order of the sums in the 257 * definition, i.e., ∑<sub>n = 0..N</sub> ∑<sub>m = 0..n</sub> 258 * becomes ∑<sub>m = 0..N</sub> ∑<sub>n = m..N</sub>. 259 * SphericalHarmonic::Circle performs the inner sum over degree \e n (which 260 * entails about <i>N</i><sup>2</sup> operations). Calling 261 * CircularEngine::operator()() on the returned object performs the outer 262 * sum over the order \e m (about \e N operations). 263 **********************************************************************/ 264 CircularEngine^ Circle(double p, double z, bool gradp); 265 266 /** 267 * @return the zeroth SphericalCoefficients object. 268 **********************************************************************/ 269 SphericalCoefficients^ Coefficients(); 270 }; 271 } // namespace NETGeographicLib 272