00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "GeographicLib/EllipticFunction.hpp"
00011 #include "GeographicLib/Constants.hpp"
00012 #include <limits>
00013 #include <cmath>
00014 #include <algorithm>
00015
00016 namespace {
00017 char RCSID[] = "$Id: EllipticFunction.cpp 6568 2009-03-01 17:58:41Z ckarney $";
00018 char RCSID_H[] = ELLIPTICFUNCTION_HPP;
00019 }
00020
00021 namespace GeographicLib {
00022
00023 using namespace std;
00024
00025 const double EllipticFunction::tol =
00026 numeric_limits<double>::epsilon() * 0.01;
00027 const double EllipticFunction::tolRF = pow(3 * tol, 1/6.0);
00028 const double EllipticFunction::tolRD = pow(0.25 * tol, 1/6.0);
00029 const double EllipticFunction::tolRG0 = 2.7 * sqrt(tol);
00030 const double EllipticFunction::tolJAC = sqrt(tol);
00031 const double EllipticFunction::tolJAC1 = sqrt(6 * tol);
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 double EllipticFunction::RF(double x, double y, double z) throw() {
00042
00043 double
00044 a0 = (x + y + z)/3,
00045 an = a0,
00046 q = max(max(abs(a0-x), abs(a0-y)), abs(a0-z)) / tolRF,
00047 x0 = x,
00048 y0 = y,
00049 z0 = z,
00050 mul = 1;
00051 while (q >= mul * abs(an)) {
00052
00053 double ln = sqrt(x0)*sqrt(y0) + sqrt(y0)*sqrt(z0) + sqrt(z0)*sqrt(x0);
00054 an = (an + ln)/4;
00055 x0 = (x0 + ln)/4;
00056 y0 = (y0 + ln)/4;
00057 z0 = (z0 + ln)/4;
00058 mul *= 4;
00059 }
00060 double
00061 xx = (a0 - x) / (mul * an),
00062 yy = (a0 - y) / (mul * an),
00063 zz = - xx - yy,
00064 e2 = xx * yy - zz * zz,
00065 e3 = xx * yy * zz;
00066 return (1 - e2 / 10 + e3 / 14 + e2 * e2 / 24 - 3 * e2 * e3 / 44) / sqrt(an);
00067 }
00068
00069
00070 double EllipticFunction::RD(double x, double y, double z) throw() {
00071
00072 double
00073 a0 = (x + y + 3 * z)/5,
00074 an = a0,
00075 q = max(max(abs(a0-x), abs(a0-y)), abs(a0-z)) / tolRD,
00076 x0 = x,
00077 y0 = y,
00078 z0 = z,
00079 mul = 1,
00080 s = 0;
00081 while (q >= mul * abs(an)) {
00082
00083 double ln = sqrt(x0)*sqrt(y0) +
00084 sqrt(y0)*sqrt(z0) +
00085 sqrt(z0)*sqrt(x0);
00086 s += 1/(mul * sqrt(z0) * (z0 + ln ));
00087 an = (an + ln)/4;
00088 x0 = (x0 + ln)/4;
00089 y0 = (y0 + ln)/4;
00090 z0 = (z0 + ln)/4;
00091 mul *= 4;
00092 }
00093 double
00094 xx = (a0 - x) / (mul * an),
00095 yy = (a0 - y) / (mul * an),
00096 zz = -(xx + yy) / 3,
00097 e2 = xx * yy - 6 * zz * zz,
00098 e3 = (3 * xx * yy - 8 * zz * zz)*zz,
00099 e4 = 3 * (xx * yy - zz * zz) * zz * zz,
00100 e5 = xx * yy * zz * zz * zz;
00101 return (1 - 3 * e2 / 14 + e3 / 6 + 9 * e2 * e2 / 88 - 3 * e4 / 22
00102 - 9 * e2 * e3 / 52 + 3 * e5 / 26) / (mul * an * sqrt(an))
00103 + 3 * s;
00104 }
00105
00106 double EllipticFunction::RG0(double x, double y) throw() {
00107
00108 double
00109 x0 = sqrt(x),
00110 y0 = sqrt(y),
00111 xn = x0,
00112 yn = y0,
00113 s = 0,
00114 mul = 0.25;
00115 while (abs(xn-yn) >= tolRG0 * abs(xn)) {
00116
00117 double t = (xn + yn) /2;
00118 yn = sqrt(xn * yn);
00119 xn = t;
00120 mul *= 2;
00121 t = xn - yn;
00122 s += mul * t * t;
00123 }
00124 x0 = (x0 + y0)/2;
00125 return (x0 * x0 - s) * Constants::pi() / (2 * (xn + yn));
00126 }
00127
00128 EllipticFunction::EllipticFunction(double m) throw()
00129 : _m(m)
00130 , _m1(1 - m)
00131
00132
00133 , _init(false)
00134 {}
00135
00136 bool EllipticFunction::Init() const throw() {
00137
00138 _kc = RF(0.0, _m1, 1.0);
00139
00140 _ec = 2 * RG0(_m1, 1.0);
00141
00142 _kec = _m / 3 * RD(0.0, _m1, 1.0);
00143 return _init = true;
00144 }
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 void EllipticFunction::sncndn(double x,
00155 double& sn, double& cn, double& dn)
00156 const throw() {
00157
00158
00159
00160
00161 if (_m1 != 0) {
00162 double mc = _m1;
00163 double c;
00164 double m[num], n[num];
00165 unsigned l = 0;
00166 for (double a = 1; l < num; ++l) {
00167
00168 m[l] = a;
00169 n[l] = mc = sqrt(mc);
00170 c = (a + mc) / 2;
00171 if (abs(a - mc) <= tolJAC * a) {
00172 ++l;
00173 break;
00174 }
00175 mc = a * mc;
00176 a = c;
00177 }
00178 x = c * x;
00179 sn = sin(x);
00180 cn = cos(x);
00181 dn = 1;
00182 if (sn != 0) {
00183 double a = cn / sn;
00184 c = a * c;
00185 while (l--) {
00186 double b = m[l];
00187 a = c * a;
00188 c = dn * c;
00189 dn = (n[l] + a) / (b + a);
00190 a = c / b;
00191 }
00192 a = 1 / sqrt(c * c + 1);
00193 sn = sn < 0 ? -a : a;
00194 cn = c * sn;
00195 }
00196 } else {
00197 sn = tanh(x);
00198 dn = cn = 1 / cosh(x);
00199 }
00200 }
00201
00202 double EllipticFunction::E(double sn, double cn, double dn) const throw() {
00203 double ei;
00204 if (abs(sn) > tolJAC1) {
00205 double
00206 s = 1 / sn,
00207 c = cn * s,
00208 d = dn * s;
00209 s *= s;
00210 c *= c;
00211 d *= d;
00212
00213 ei = RF(c, d, s) - _m / 3 * RD(c, d, s);
00214 } else
00215
00216
00217
00218
00219
00220
00221 ei = abs(sn);
00222
00223 if (cn < 0) {
00224 ei = 2 * E() - ei;
00225 }
00226 if (sn < 0)
00227 ei = -ei;
00228 return ei;
00229 }
00230
00231 }