/** * \file CircularEngine.hpp * \brief Header for GeographicLib::CircularEngine class * * Copyright (c) Charles Karney (2011-2015) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_CIRCULARENGINE_HPP) #define GEOGRAPHICLIB_CIRCULARENGINE_HPP 1 #include #include #include #if defined(_MSC_VER) // Squelch warnings about dll vs vector # pragma warning (push) # pragma warning (disable: 4251) #endif namespace GeographicLib { /** * \brief Spherical harmonic sums for a circle * * The class is a companion to SphericalEngine. If the results of a * spherical harmonic sum are needed for several points on a circle of * constant latitude \e lat and height \e h, then SphericalEngine::Circle can * compute the inner sum, which is independent of longitude \e lon, and * produce a CircularEngine object. CircularEngine::operator()() can * then be used to perform the outer sum for particular vales of \e lon. * This can lead to substantial improvements in computational speed for high * degree sum (approximately by a factor of \e N / 2 where \e N is the * maximum degree). * * CircularEngine is tightly linked to the internals of SphericalEngine. For * that reason, the constructor for this class is private. Use * SphericalHarmonic::Circle, SphericalHarmonic1::Circle, and * SphericalHarmonic2::Circle to create instances of this class. * * CircularEngine stores the coefficients needed to allow the summation over * order to be performed in 2 or 6 vectors of length \e M + 1 (depending on * whether gradients are to be calculated). For this reason the constructor * may throw a std::bad_alloc exception. * * Example of use: * \include example-CircularEngine.cpp **********************************************************************/ class GEOGRAPHICLIB_EXPORT CircularEngine { private: typedef Math::real real; enum normalization { FULL = SphericalEngine::FULL, SCHMIDT = SphericalEngine::SCHMIDT, }; int _M; bool _gradp; unsigned _norm; real _a, _r, _u, _t; std::vector _wc, _ws, _wrc, _wrs, _wtc, _wts; real _q, _uq, _uq2; Math::real Value(bool gradp, real sl, real cl, real& gradx, real& grady, real& gradz) const; friend class SphericalEngine; CircularEngine(int M, bool gradp, unsigned norm, real a, real r, real u, real t) : _M(M) , _gradp(gradp) , _norm(norm) , _a(a) , _r(r) , _u(u) , _t(t) , _wc(std::vector(_M + 1, 0)) , _ws(std::vector(_M + 1, 0)) , _wrc(std::vector(_gradp ? _M + 1 : 0, 0)) , _wrs(std::vector(_gradp ? _M + 1 : 0, 0)) , _wtc(std::vector(_gradp ? _M + 1 : 0, 0)) , _wts(std::vector(_gradp ? _M + 1 : 0, 0)) { _q = _a / _r; _uq = _u * _q; _uq2 = Math::sq(_uq); } void SetCoeff(int m, real wc, real ws) { _wc[m] = wc; _ws[m] = ws; } void SetCoeff(int m, real wc, real ws, real wrc, real wrs, real wtc, real wts) { _wc[m] = wc; _ws[m] = ws; if (_gradp) { _wrc[m] = wrc; _wrs[m] = wrs; _wtc[m] = wtc; _wts[m] = wts; } } public: /** * A default constructor. CircularEngine::operator()() on the resulting * object returns zero. The resulting object can be assigned to the result * of SphericalHarmonic::Circle. **********************************************************************/ CircularEngine() : _M(-1) , _gradp(true) , _u(0) , _t(1) {} /** * Evaluate the sum for a particular longitude given in terms of its * sine and cosine. * * @param[in] sinlon the sine of the longitude. * @param[in] coslon the cosine of the longitude. * @return \e V the value of the sum. * * The arguments must satisfy sinlon2 + * coslon2 = 1. **********************************************************************/ Math::real operator()(real sinlon, real coslon) const { real dummy; return Value(false, sinlon, coslon, dummy, dummy, dummy); } /** * Evaluate the sum for a particular longitude. * * @param[in] lon the longitude (degrees). * @return \e V the value of the sum. **********************************************************************/ Math::real operator()(real lon) const { real sinlon, coslon; Math::sincosd(lon, sinlon, coslon); return (*this)(sinlon, coslon); } /** * Evaluate the sum and its gradient for a particular longitude given in * terms of its sine and cosine. * * @param[in] sinlon the sine of the longitude. * @param[in] coslon the cosine of the longitude. * @param[out] gradx \e x component of the gradient. * @param[out] grady \e y component of the gradient. * @param[out] gradz \e z component of the gradient. * @return \e V the value of the sum. * * The gradients will only be computed if the CircularEngine object was * created with this capability (e.g., via \e gradp = true in * SphericalHarmonic::Circle). If not, \e gradx, etc., will not be * touched. The arguments must satisfy sinlon2 + * coslon2 = 1. **********************************************************************/ Math::real operator()(real sinlon, real coslon, real& gradx, real& grady, real& gradz) const { return Value(true, sinlon, coslon, gradx, grady, gradz); } /** * Evaluate the sum and its gradient for a particular longitude. * * @param[in] lon the longitude (degrees). * @param[out] gradx \e x component of the gradient. * @param[out] grady \e y component of the gradient. * @param[out] gradz \e z component of the gradient. * @return \e V the value of the sum. * * The gradients will only be computed if the CircularEngine object was * created with this capability (e.g., via \e gradp = true in * SphericalHarmonic::Circle). If not, \e gradx, etc., will not be * touched. **********************************************************************/ Math::real operator()(real lon, real& gradx, real& grady, real& gradz) const { real sinlon, coslon; Math::sincosd(lon, sinlon, coslon); return (*this)(sinlon, coslon, gradx, grady, gradz); } }; } // namespace GeographicLib #if defined(_MSC_VER) # pragma warning (pop) #endif #endif // GEOGRAPHICLIB_CIRCULARENGINE_HPP