File indexing completed on 2024-04-21 03:44:42

0001 /*
0002     SPDX-FileCopyrightText: 2009 Jerome SONRIER <jsid@emor3j.fr.eu.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "satellite.h"
0008 
0009 #include "ksplanetbase.h"
0010 #ifndef KSTARS_LITE
0011 #include "kspopupmenu.h"
0012 #endif
0013 #include "kstarsdata.h"
0014 #include "kssun.h"
0015 #include "Options.h"
0016 #include "skymapcomposite.h"
0017 
0018 #include <QDebug>
0019 
0020 #include <cmath>
0021 #include <typeinfo>
0022 
0023 // Define some constants
0024 //  WGS-72 constants
0025 #define RADIUSEARTHKM 6378.135          // Earth radius (km)
0026 #define XKE           0.07436691613317  // 60.0 / sqrt(RADIUSEARTHKM^3/MU)
0027 #define J2            0.001082616       // The second gravitational zonal harmonic of the Earth
0028 #define J4            -0.00000165597    // The fourth gravitational zonal harmonic of the Earth
0029 #define J3OJ2         -2.34506972e-3    // J3 / J2
0030 
0031 // Mathematical constants
0032 #define TWOPI   6.2831853071795864769 // 2*PI
0033 #define PIO2    1.5707963267948966192 // PI/2
0034 #define X2O3    .66666666666666666667 // 2/3
0035 #define DEG2RAD 1.745329251994330e-2  // Deg -> Rad
0036 
0037 // Other constants
0038 #define MINPD   1440                     // Minutes per day
0039 #define MEANALT 0.84                     // Mean altitude (km)
0040 #define SR      6.96000e5                // Solar radius - km (IAU 76)
0041 #define AU      1.49597870691e8          // Astronomical unit - km (IAU 76)
0042 #define XPDOTP  229.1831180523293        // 1440.0 / (2.0 * pi)
0043 #define SS      1.0122292801892716288    // Parameter for the SGP4 density function
0044 #define QZMS2T  1.8802791590152706439e-9 // (( 120.0 - 78.0) / RADIUSEARTHKM )^4
0045 #define F       3.35281066474748e-3      // Flattening factor
0046 #define MFACTOR 7.292115e-5
0047 
0048 Satellite::Satellite(const QString &name, const QString &line1, const QString &line2)
0049 {
0050     //m_name          = name;
0051     m_number      = line1.midRef(2, 5).toInt();
0052     m_class       = line1.at(7);
0053     m_id          = line1.mid(9, 8);
0054     m_epoch       = line1.midRef(18, 14).toDouble();
0055     m_first_deriv = line1.midRef(33, 10).toDouble() / (XPDOTP * MINPD);
0056     m_second_deriv =
0057         line1.midRef(44, 6).toDouble() * (1.0e-5 / pow(10.0, line1.midRef(51, 1).toDouble())) / (XPDOTP * MINPD * MINPD);
0058     m_bstar         = line1.midRef(53, 6).toDouble() * 1.0e-5 / pow(10.0, line1.midRef(60, 1).toDouble());
0059     m_ephem_type    = line1.midRef(62, 1).toInt();
0060     m_elem_number   = line1.midRef(64, 4).toInt();
0061     m_inclination   = line2.midRef(8, 8).toDouble() * DEG2RAD;
0062     m_ra            = line2.midRef(17, 8).toDouble() * DEG2RAD;
0063     m_eccentricity  = line2.midRef(26, 7).toDouble() * 1.0e-7;
0064     m_arg_perigee   = line2.midRef(34, 8).toDouble() * DEG2RAD;
0065     m_mean_anomaly  = line2.midRef(43, 8).toDouble() * DEG2RAD;
0066     m_mean_motion   = line2.midRef(52, 11).toDouble() * TWOPI / MINPD;
0067     m_nb_revolution = line2.midRef(63, 5).toInt();
0068     m_tle           = name + "\n" + line1 + "\n" + line2;
0069 
0070     setName(name);
0071     setName2(name);
0072     setLongName(name + " (" + m_id + ')');
0073     setType(SkyObject::SATELLITE);
0074     setMag(0.0);
0075 
0076     m_is_selected = Options::selectedSatellites().contains(name);
0077 
0078     // Convert TLE epoch to Julian date
0079     double day = modf(m_epoch * 1.e-3, &m_epoch_year) * 1.e3;
0080     if (m_epoch_year < 57.)
0081         m_epoch_year += 2000.;
0082     else
0083         m_epoch_year += 1900.;
0084     double year = m_epoch_year - 1.;
0085     long i      = year / 100;
0086     long A      = i;
0087     i           = A / 4;
0088     long B      = 2 - A + i;
0089     i           = 365.25 * year;
0090     i += 30.6001 * 14;
0091     m_tle_jd = i + 1720994.5 + B + day;
0092 
0093     init();
0094 }
0095 
0096 Satellite *Satellite::clone() const
0097 {
0098     Q_ASSERT(typeid(this) == typeid(static_cast<const Satellite *>(this))); // Ensure we are not slicing a derived class
0099     return new Satellite(*this);
0100 }
0101 
0102 void Satellite::init()
0103 {
0104     double ao, cosio, sinio, cosio2, omeosq, posq, rp, rteosq, eccsq, con42, cnodm, snodm, cosim, sinim, cosomm, sinomm,
0105            cc1sq, cc2, cc3, coef, coef1, cosio4, day, em, emsq, eeta, etasq, gam, inclm, nm, perige, pinvsq, psisq,
0106            qzms24, rtemsq, s1, s2, s3, s4, s5, s6, s7, sfour, ss1(0), ss2(0), ss3(0), ss4(0), ss5(0), ss6(0), ss7(0),
0107            sz1(0), sz2(0), sz3(0), sz11(0), sz12(0), sz13(0), sz21(0), sz22(0), sz23(0), sz31(0), sz32(0), sz33(0), tc,
0108            temp, temp1, temp2, temp3, tsi, xpidot, xhdot1, z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33, ak, d1,
0109            del, adel, po, ds70, ts70, tfrac, c1, thgr70, fk5r, c1p2p;
0110     //    double dndt;
0111 
0112     // Init near earth variables
0113     isimp   = false;
0114     aycof   = 0.;
0115     con41   = 0.;
0116     cc1     = 0.;
0117     cc4     = 0.;
0118     cc5     = 0.;
0119     d2      = 0.;
0120     d3      = 0.;
0121     d4      = 0.;
0122     delmo   = 0.;
0123     eta     = 0.;
0124     argpdot = 0.;
0125     omgcof  = 0.;
0126     sinmao  = 0.;
0127     t       = 0.;
0128     t2cof   = 0.;
0129     t3cof   = 0.;
0130     t4cof   = 0.;
0131     t5cof   = 0.;
0132     x1mth2  = 0.;
0133     x7thm1  = 0.;
0134     mdot    = 0.;
0135     nodedot = 0.;
0136     xlcof   = 0.;
0137     xmcof   = 0.;
0138     nodecf  = 0.;
0139 
0140     // Init deep space variables
0141     irez  = 0;
0142     d2201 = 0.;
0143     d2211 = 0.;
0144     d3210 = 0.;
0145     d3222 = 0.;
0146     d4410 = 0.;
0147     d4422 = 0.;
0148     d5220 = 0.;
0149     d5232 = 0.;
0150     d5421 = 0.;
0151     d5433 = 0.;
0152     dedt  = 0.;
0153     del1  = 0.;
0154     del2  = 0.;
0155     del3  = 0.;
0156     didt  = 0.;
0157     dmdt  = 0.;
0158     dnodt = 0.;
0159     domdt = 0.;
0160     e3    = 0.;
0161     ee2   = 0.;
0162     peo   = 0.;
0163     pgho  = 0.;
0164     pho   = 0.;
0165     pinco = 0.;
0166     plo   = 0.;
0167     se2   = 0.;
0168     se3   = 0.;
0169     sgh2  = 0.;
0170     sgh3  = 0.;
0171     sgh4  = 0.;
0172     sh2   = 0.;
0173     sh3   = 0.;
0174     si2   = 0.;
0175     si3   = 0.;
0176     sl2   = 0.;
0177     sl3   = 0.;
0178     sl4   = 0.;
0179     gsto  = 0.;
0180     xfact = 0.;
0181     xgh2  = 0.;
0182     xgh3  = 0.;
0183     xgh4  = 0.;
0184     xh2   = 0.;
0185     xh3   = 0.;
0186     xi2   = 0.;
0187     xi3   = 0.;
0188     xl2   = 0.;
0189     xl3   = 0.;
0190     xl4   = 0.;
0191     xlamo = 0.;
0192     zmol  = 0.;
0193     zmos  = 0.;
0194     atime = 0.;
0195     xli   = 0.;
0196     xni   = 0.;
0197 
0198     method = 'n';
0199 
0200     m_is_visible = false;
0201 
0202     // Divisor for divide by zero check on inclination
0203     const double temp4 = 1.5e-12;
0204 
0205     /*----- Initializes variables for sgp4 -----*/
0206     // Calculate auxiliary epoch quantities
0207     eccsq  = m_eccentricity * m_eccentricity;
0208     omeosq = 1.0 - eccsq;
0209     rteosq = sqrt(omeosq);
0210     cosio  = cos(m_inclination);
0211     cosio2 = cosio * cosio;
0212 
0213     // Un-kozai the mean motion
0214     ak            = pow(XKE / m_mean_motion, X2O3);
0215     d1            = 0.75 * J2 * (3.0 * cosio2 - 1.0) / (rteosq * omeosq);
0216     del           = d1 / (ak * ak);
0217     adel          = ak * (1.0 - del * del - del * (1.0 / 3.0 + 134.0 * del * del / 81.0));
0218     del           = d1 / (adel * adel);
0219     m_mean_motion = m_mean_motion / (1.0 + del);
0220 
0221     ao     = pow(XKE / m_mean_motion, X2O3);
0222     sinio  = sin(m_inclination);
0223     po     = ao * omeosq;
0224     con42  = 1.0 - 5.0 * cosio2;
0225     con41  = -con42 - (2.0 * cosio2);
0226     posq   = po * po;
0227     rp     = ao * (1.0 - m_eccentricity);
0228     method = 'n';
0229 
0230     // Find sidereal time
0231     ts70  = m_tle_jd - 2433281.5 - 7305.0;
0232     ds70  = floor(ts70 + 1.0e-8);
0233     tfrac = ts70 - ds70;
0234     // find greenwich location at epoch
0235     c1     = 1.72027916940703639e-2;
0236     thgr70 = 1.7321343856509374;
0237     fk5r   = 5.07551419432269442e-15;
0238     c1p2p  = c1 + TWOPI;
0239     gsto   = fmod(thgr70 + c1 * ds70 + c1p2p * tfrac + ts70 * ts70 * fk5r, TWOPI);
0240     if (gsto < 0.0)
0241         gsto = gsto + TWOPI;
0242 
0243     if ((omeosq >= 0.0) || (m_mean_motion >= 0.0))
0244     {
0245         if (rp < (220.0 / RADIUSEARTHKM + 1.0))
0246             isimp = true;
0247         sfour  = SS;
0248         qzms24 = QZMS2T;
0249         perige = (rp - 1.0) * RADIUSEARTHKM;
0250 
0251         // For perigees below 156 km, s and qoms2t are altered
0252         if (perige < 156.0)
0253         {
0254             sfour = perige - 78.0;
0255             if (perige < 98.0)
0256                 sfour = 20.0;
0257             qzms24 = pow(((120.0 - sfour) / RADIUSEARTHKM), 4.0);
0258             sfour  = sfour / RADIUSEARTHKM + 1.0;
0259         }
0260         pinvsq = 1.0 / posq;
0261 
0262         tsi   = 1.0 / (ao - sfour);
0263         eta   = ao * m_eccentricity * tsi;
0264         etasq = eta * eta;
0265         eeta  = m_eccentricity * eta;
0266         psisq = fabs(1.0 - etasq);
0267         coef  = qzms24 * pow(tsi, 4.0);
0268         coef1 = coef / pow(psisq, 3.5);
0269         cc2   = coef1 * m_mean_motion *
0270                 (ao * (1.0 + 1.5 * etasq + eeta * (4.0 + etasq)) +
0271                  0.375 * J2 * tsi / psisq * con41 * (8.0 + 3.0 * etasq * (8.0 + etasq)));
0272         cc1 = m_bstar * cc2;
0273         cc3 = 0.0;
0274         if (m_eccentricity > 1.0e-4)
0275             cc3 = -2.0 * coef * tsi * J3OJ2 * m_mean_motion * sinio / m_eccentricity;
0276         x1mth2 = 1.0 - cosio2;
0277         cc4    = 2.0 * m_mean_motion * coef1 * ao * omeosq *
0278                  (eta * (2.0 + 0.5 * etasq) + m_eccentricity * (0.5 + 2.0 * etasq) -
0279                   J2 * tsi / (ao * psisq) *
0280                   (-3.0 * con41 * (1.0 - 2.0 * eeta + etasq * (1.5 - 0.5 * eeta)) +
0281                    0.75 * x1mth2 * (2.0 * etasq - eeta * (1.0 + etasq)) * cos(2.0 * m_arg_perigee)));
0282         cc5 = 2.0 * coef1 * ao * omeosq * (1.0 + 2.75 * (etasq + eeta) + eeta * etasq);
0283 
0284         cosio4 = cosio2 * cosio2;
0285         temp1  = 1.5 * J2 * pinvsq * m_mean_motion;
0286         temp2  = 0.5 * temp1 * J2 * pinvsq;
0287         temp3  = -0.46875 * J4 * pinvsq * pinvsq * m_mean_motion;
0288         mdot   = m_mean_motion + 0.5 * temp1 * rteosq * con41 +
0289                  0.0625 * temp2 * rteosq * (13.0 - 78.0 * cosio2 + 137.0 * cosio4);
0290         argpdot = -0.5 * temp1 * con42 + 0.0625 * temp2 * (7.0 - 114.0 * cosio2 + 395.0 * cosio4) +
0291                   temp3 * (3.0 - 36.0 * cosio2 + 49.0 * cosio4);
0292         xhdot1  = -temp1 * cosio;
0293         nodedot = xhdot1 + (0.5 * temp2 * (4.0 - 19.0 * cosio2) + 2.0 * temp3 * (3.0 - 7.0 * cosio2)) * cosio;
0294         xpidot  = argpdot + nodedot;
0295         omgcof  = m_bstar * cc3 * cos(m_arg_perigee);
0296         xmcof   = 0.0;
0297         if (m_eccentricity > 1.0e-4)
0298             xmcof = -X2O3 * coef * m_bstar / eeta;
0299         nodecf = 3.5 * omeosq * xhdot1 * cc1;
0300         t2cof  = 1.5 * cc1;
0301         // Do not divide by zero
0302         if (fabs(1.0 + cosio) > 1.5e-12)
0303             xlcof = -0.25 * J3OJ2 * sinio * (3.0 + 5.0 * cosio) / (1.0 + cosio);
0304         else
0305             xlcof = -0.25 * J3OJ2 * sinio * (3.0 + 5.0 * cosio) / temp4;
0306         aycof  = -0.5 * J3OJ2 * sinio;
0307         delmo  = pow((1.0 + eta * cos(m_mean_anomaly)), 3);
0308         sinmao = sin(m_mean_anomaly);
0309         x7thm1 = 7.0 * cosio2 - 1.0;
0310 
0311         // Deep space initialization
0312         if ((TWOPI / m_mean_motion) >= 225.0)
0313         {
0314             method = 'd';
0315             isimp  = true;
0316             tc     = 0.0;
0317             inclm  = m_inclination;
0318 
0319             // Init deep space common variables
0320             // Define some constants
0321             const double zes    = 0.01675;
0322             const double zel    = 0.05490;
0323             const double c1ss   = 2.9864797e-6;
0324             const double c1l    = 4.7968065e-7;
0325             const double zsinis = 0.39785416;
0326             const double zcosis = 0.91744867;
0327             const double zcosgs = 0.1945905;
0328             const double zsings = -0.98088458;
0329 
0330             int lsflg;
0331             double a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, betasq, cc, ctem, stem, x1, x2, x3, x4, x5, x6, x7, x8,
0332                    xnodce, xnoi, zcosg, zcosgl, zcosh, zcoshl, zcosi, zcosil, zsing, zsingl, zsinh, zsinhl, zsini, zsinil,
0333                    zx, zy;
0334 
0335             nm     = m_mean_motion;
0336             em     = m_eccentricity;
0337             snodm  = sin(m_ra);
0338             cnodm  = cos(m_ra);
0339             sinomm = sin(m_arg_perigee);
0340             cosomm = cos(m_arg_perigee);
0341             sinim  = sin(m_inclination);
0342             cosim  = cos(m_inclination);
0343             emsq   = em * em;
0344             betasq = 1.0 - emsq;
0345             rtemsq = sqrt(betasq);
0346 
0347             // Initialize lunar solar terms
0348             peo    = 0.0;
0349             pinco  = 0.0;
0350             plo    = 0.0;
0351             pgho   = 0.0;
0352             pho    = 0.0;
0353             day    = m_tle_jd - 2433281.5 + 18261.5 + tc / 1440.0;
0354             xnodce = fmod(4.5236020 - 9.2422029e-4 * day, TWOPI);
0355             stem   = sin(xnodce);
0356             ctem   = cos(xnodce);
0357             zcosil = 0.91375164 - 0.03568096 * ctem;
0358             zsinil = sqrt(1.0 - zcosil * zcosil);
0359             zsinhl = 0.089683511 * stem / zsinil;
0360             zcoshl = sqrt(1.0 - zsinhl * zsinhl);
0361             gam    = 5.8351514 + 0.0019443680 * day;
0362             zx     = 0.39785416 * stem / zsinil;
0363             zy     = zcoshl * ctem + 0.91744867 * zsinhl * stem;
0364             zx     = atan2(zx, zy);
0365             zx     = gam + zx - xnodce;
0366             zcosgl = cos(zx);
0367             zsingl = sin(zx);
0368 
0369             // Solar terms
0370             zcosg = zcosgs;
0371             zsing = zsings;
0372             zcosi = zcosis;
0373             zsini = zsinis;
0374             zcosh = cnodm;
0375             zsinh = snodm;
0376             cc    = c1ss;
0377             xnoi  = 1.0 / nm;
0378 
0379             for (lsflg = 1; lsflg <= 2; ++lsflg)
0380             {
0381                 a1  = zcosg * zcosh + zsing * zcosi * zsinh;
0382                 a3  = -zsing * zcosh + zcosg * zcosi * zsinh;
0383                 a7  = -zcosg * zsinh + zsing * zcosi * zcosh;
0384                 a8  = zsing * zsini;
0385                 a9  = zsing * zsinh + zcosg * zcosi * zcosh;
0386                 a10 = zcosg * zsini;
0387                 a2  = cosim * a7 + sinim * a8;
0388                 a4  = cosim * a9 + sinim * a10;
0389                 a5  = -sinim * a7 + cosim * a8;
0390                 a6  = -sinim * a9 + cosim * a10;
0391 
0392                 x1 = a1 * cosomm + a2 * sinomm;
0393                 x2 = a3 * cosomm + a4 * sinomm;
0394                 x3 = -a1 * sinomm + a2 * cosomm;
0395                 x4 = -a3 * sinomm + a4 * cosomm;
0396                 x5 = a5 * sinomm;
0397                 x6 = a6 * sinomm;
0398                 x7 = a5 * cosomm;
0399                 x8 = a6 * cosomm;
0400 
0401                 z31 = 12.0 * x1 * x1 - 3.0 * x3 * x3;
0402                 z32 = 24.0 * x1 * x2 - 6.0 * x3 * x4;
0403                 z33 = 12.0 * x2 * x2 - 3.0 * x4 * x4;
0404                 z1  = 3.0 * (a1 * a1 + a2 * a2) + z31 * emsq;
0405                 z2  = 6.0 * (a1 * a3 + a2 * a4) + z32 * emsq;
0406                 z3  = 3.0 * (a3 * a3 + a4 * a4) + z33 * emsq;
0407                 z11 = -6.0 * a1 * a5 + emsq * (-24.0 * x1 * x7 - 6.0 * x3 * x5);
0408                 z12 = -6.0 * (a1 * a6 + a3 * a5) + emsq * (-24.0 * (x2 * x7 + x1 * x8) - 6.0 * (x3 * x6 + x4 * x5));
0409                 z13 = -6.0 * a3 * a6 + emsq * (-24.0 * x2 * x8 - 6.0 * x4 * x6);
0410                 z21 = 6.0 * a2 * a5 + emsq * (24.0 * x1 * x5 - 6.0 * x3 * x7);
0411                 z22 = 6.0 * (a4 * a5 + a2 * a6) + emsq * (24.0 * (x2 * x5 + x1 * x6) - 6.0 * (x4 * x7 + x3 * x8));
0412                 z23 = 6.0 * a4 * a6 + emsq * (24.0 * x2 * x6 - 6.0 * x4 * x8);
0413                 z1  = z1 + z1 + betasq * z31;
0414                 z2  = z2 + z2 + betasq * z32;
0415                 z3  = z3 + z3 + betasq * z33;
0416                 s3  = cc * xnoi;
0417                 s2  = -0.5 * s3 / rtemsq;
0418                 s4  = s3 * rtemsq;
0419                 s1  = -15.0 * em * s4;
0420                 s5  = x1 * x3 + x2 * x4;
0421                 s6  = x2 * x3 + x1 * x4;
0422                 s7  = x2 * x4 - x1 * x3;
0423 
0424                 // Lunar terms
0425                 if (lsflg == 1)
0426                 {
0427                     ss1   = s1;
0428                     ss2   = s2;
0429                     ss3   = s3;
0430                     ss4   = s4;
0431                     ss5   = s5;
0432                     ss6   = s6;
0433                     ss7   = s7;
0434                     sz1   = z1;
0435                     sz2   = z2;
0436                     sz3   = z3;
0437                     sz11  = z11;
0438                     sz12  = z12;
0439                     sz13  = z13;
0440                     sz21  = z21;
0441                     sz22  = z22;
0442                     sz23  = z23;
0443                     sz31  = z31;
0444                     sz32  = z32;
0445                     sz33  = z33;
0446                     zcosg = zcosgl;
0447                     zsing = zsingl;
0448                     zcosi = zcosil;
0449                     zsini = zsinil;
0450                     zcosh = zcoshl * cnodm + zsinhl * snodm;
0451                     zsinh = snodm * zcoshl - cnodm * zsinhl;
0452                     cc    = c1l;
0453                 }
0454             }
0455 
0456             zmol = fmod(4.7199672 + 0.22997150 * day - gam, TWOPI);
0457             zmos = fmod(6.2565837 + 0.017201977 * day, TWOPI);
0458 
0459             //  Solar terms
0460             se2  = 2.0 * ss1 * ss6;
0461             se3  = 2.0 * ss1 * ss7;
0462             si2  = 2.0 * ss2 * sz12;
0463             si3  = 2.0 * ss2 * (sz13 - sz11);
0464             sl2  = -2.0 * ss3 * sz2;
0465             sl3  = -2.0 * ss3 * (sz3 - sz1);
0466             sl4  = -2.0 * ss3 * (-21.0 - 9.0 * emsq) * zes;
0467             sgh2 = 2.0 * ss4 * sz32;
0468             sgh3 = 2.0 * ss4 * (sz33 - sz31);
0469             sgh4 = -18.0 * ss4 * zes;
0470             sh2  = -2.0 * ss2 * sz22;
0471             sh3  = -2.0 * ss2 * (sz23 - sz21);
0472 
0473             // Lunar terms
0474             ee2  = 2.0 * s1 * s6;
0475             e3   = 2.0 * s1 * s7;
0476             xi2  = 2.0 * s2 * z12;
0477             xi3  = 2.0 * s2 * (z13 - z11);
0478             xl2  = -2.0 * s3 * z2;
0479             xl3  = -2.0 * s3 * (z3 - z1);
0480             xl4  = -2.0 * s3 * (-21.0 - 9.0 * emsq) * zel;
0481             xgh2 = 2.0 * s4 * z32;
0482             xgh3 = 2.0 * s4 * (z33 - z31);
0483             xgh4 = -18.0 * s4 * zel;
0484             xh2  = -2.0 * s2 * z22;
0485             xh3  = -2.0 * s2 * (z23 - z21);
0486 
0487             // Apply deep space long period periodic contributions to the mean elements
0488             //            double f2, f3, sinzf,  zf, zm;
0489             double ses, sghl, sghs, shll, shs, sis, sls;
0490 
0491             // Define some constants
0492             const double zns = 1.19459e-5;
0493             const double znl = 1.5835218e-4;
0494 
0495             // Calculate time varying periodics
0496             // These results are never used, should we remove them?
0497             //            zm    = zmos;
0498             //            zf    = zm + 2.0 * zes * sin(zm);
0499             //            sinzf = sin(zf);
0500             //            f2    = 0.5 * sinzf * sinzf - 0.25;
0501             //            f3    = -0.5 * sinzf * cos(zf);
0502             //            ses   = se2 * f2 + se3 * f3;
0503             //            sis   = si2 * f2 + si3 * f3;
0504             //            sls   = sl2 * f2 + sl3 * f3 + sl4 * sinzf;
0505             //            sghs  = sgh2 * f2 + sgh3 * f3 + sgh4 * sinzf;
0506             //            shs   = sh2 * f2 + sh3 * f3;
0507             //            zm    = zmol;
0508 
0509             //            zf    = zm + 2.0 * zel * sin(zm);
0510             //            sinzf = sin(zf);
0511             //            f2    = 0.5 * sinzf * sinzf - 0.25;
0512             //            f3    = -0.5 * sinzf * cos(zf);
0513             //            sghl  = xgh2 * f2 + xgh3 * f3 + xgh4 * sinzf;
0514             //            shll  = xh2 * f2 + xh3 * f3;
0515 
0516             // Deep space contributions to mean motion dot due to geopotential resonance with half day and one day orbits
0517             double ainv2, aonv = 0.0, cosisq, eoc, f220, f221, f311, f321, f322, f330, f441, f442, f522, f523, f542,
0518                           f543, g200, g201, g211, g300, g310, g322, g410, g422, g520, g521, g532, g533, sgs, sini2,
0519                           temp, temp1, theta, xno2, emsqo;
0520             //            double emo;
0521 
0522             // Define some constant
0523             const double q22    = 1.7891679e-6;
0524             const double q31    = 2.1460748e-6;
0525             const double q33    = 2.2123015e-7;
0526             const double root22 = 1.7891679e-6;
0527             const double root44 = 7.3636953e-9;
0528             const double root54 = 2.1765803e-9;
0529             const double rptim  = 4.37526908801129966e-3; // this equates to 7.29211514668855e-5 rad/sec
0530             const double root32 = 3.7393792e-7;
0531             const double root52 = 1.1428639e-7;
0532 
0533             // Deep space initialization
0534             irez = 0;
0535             if ((nm < 0.0052359877) && (nm > 0.0034906585))
0536                 irez = 1;
0537             if ((nm >= 8.26e-3) && (nm <= 9.24e-3) && (em >= 0.5))
0538                 irez = 2;
0539 
0540             // Solar terms
0541             ses  = ss1 * zns * ss5;
0542             sis  = ss2 * zns * (sz11 + sz13);
0543             sls  = -zns * ss3 * (sz1 + sz3 - 14.0 - 6.0 * emsq);
0544             sghs = ss4 * zns * (sz31 + sz33 - 6.0);
0545             shs  = -zns * ss2 * (sz21 + sz23);
0546             if ((inclm < 5.2359877e-2) || (inclm > M_PI - 5.2359877e-2))
0547                 shs = 0.0;
0548             if (sinim != 0.0)
0549                 shs = shs / sinim;
0550             sgs = sghs - cosim * shs;
0551 
0552             // Lunar terms
0553             dedt = ses + s1 * znl * s5;
0554             didt = sis + s2 * znl * (z11 + z13);
0555             dmdt = sls - znl * s3 * (z1 + z3 - 14.0 - 6.0 * emsq);
0556             sghl = s4 * znl * (z31 + z33 - 6.0);
0557             shll = -znl * s2 * (z21 + z23);
0558             if ((inclm < 5.2359877e-2) || (inclm > M_PI - 5.2359877e-2))
0559                 shll = 0.0;
0560             domdt = sgs + sghl;
0561             dnodt = shs;
0562             if (sinim != 0.0)
0563             {
0564                 domdt = domdt - cosim / sinim * shll;
0565                 dnodt = dnodt + shll / sinim;
0566             }
0567 
0568             // Calculate deep space resonance effects
0569             // Value never used
0570             //            dndt  = 0.0;
0571             theta = fmod(gsto + tc * rptim, TWOPI);
0572 
0573             // Initialize the resonance terms
0574             if (irez != 0)
0575             {
0576                 aonv = pow(nm / XKE, X2O3);
0577 
0578                 // Geopotential resonance for 12 hour orbits
0579                 if (irez == 2)
0580                 {
0581                     cosisq = cosim * cosim;
0582                     // Value never used
0583                     //                    emo    = em;
0584                     em     = m_eccentricity;
0585                     emsqo  = emsq;
0586                     emsq   = eccsq;
0587                     eoc    = em * emsq;
0588                     g201   = -0.306 - (em - 0.64) * 0.440;
0589 
0590                     if (em <= 0.65)
0591                     {
0592                         g211 = 3.616 - 13.2470 * em + 16.2900 * emsq;
0593                         g310 = -19.302 + 117.3900 * em - 228.4190 * emsq + 156.5910 * eoc;
0594                         g322 = -18.9068 + 109.7927 * em - 214.6334 * emsq + 146.5816 * eoc;
0595                         g410 = -41.122 + 242.6940 * em - 471.0940 * emsq + 313.9530 * eoc;
0596                         g422 = -146.407 + 841.8800 * em - 1629.014 * emsq + 1083.4350 * eoc;
0597                         g520 = -532.114 + 3017.977 * em - 5740.032 * emsq + 3708.2760 * eoc;
0598                     }
0599                     else
0600                     {
0601                         g211 = -72.099 + 331.819 * em - 508.738 * emsq + 266.724 * eoc;
0602                         g310 = -346.844 + 1582.851 * em - 2415.925 * emsq + 1246.113 * eoc;
0603                         g322 = -342.585 + 1554.908 * em - 2366.899 * emsq + 1215.972 * eoc;
0604                         g410 = -1052.797 + 4758.686 * em - 7193.992 * emsq + 3651.957 * eoc;
0605                         g422 = -3581.690 + 16178.110 * em - 24462.770 * emsq + 12422.520 * eoc;
0606                         if (em > 0.715)
0607                             g520 = -5149.66 + 29936.92 * em - 54087.36 * emsq + 31324.56 * eoc;
0608                         else
0609                             g520 = 1464.74 - 4664.75 * em + 3763.64 * emsq;
0610                     }
0611                     if (em < 0.7)
0612                     {
0613                         g533 = -919.22770 + 4988.6100 * em - 9064.7700 * emsq + 5542.21 * eoc;
0614                         g521 = -822.71072 + 4568.6173 * em - 8491.4146 * emsq + 5337.524 * eoc;
0615                         g532 = -853.66600 + 4690.2500 * em - 8624.7700 * emsq + 5341.4 * eoc;
0616                     }
0617                     else
0618                     {
0619                         g533 = -37995.780 + 161616.52 * em - 229838.20 * emsq + 109377.94 * eoc;
0620                         g521 = -51752.104 + 218913.95 * em - 309468.16 * emsq + 146349.42 * eoc;
0621                         g532 = -40023.880 + 170470.89 * em - 242699.48 * emsq + 115605.82 * eoc;
0622                     }
0623 
0624                     sini2 = sinim * sinim;
0625                     f220  = 0.75 * (1.0 + 2.0 * cosim + cosisq);
0626                     f221  = 1.5 * sini2;
0627                     f321  = 1.875 * sinim * (1.0 - 2.0 * cosim - 3.0 * cosisq);
0628                     f322  = -1.875 * sinim * (1.0 + 2.0 * cosim - 3.0 * cosisq);
0629                     f441  = 35.0 * sini2 * f220;
0630                     f442  = 39.3750 * sini2 * sini2;
0631                     f522 =
0632                         9.84375 * sinim *
0633                         (sini2 * (1.0 - 2.0 * cosim - 5.0 * cosisq) + 0.33333333 * (-2.0 + 4.0 * cosim + 6.0 * cosisq));
0634                     f523  = sinim * (4.92187512 * sini2 * (-2.0 - 4.0 * cosim + 10.0 * cosisq) +
0635                                      6.56250012 * (1.0 + 2.0 * cosim - 3.0 * cosisq));
0636                     f542  = 29.53125 * sinim * (2.0 - 8.0 * cosim + cosisq * (-12.0 + 8.0 * cosim + 10.0 * cosisq));
0637                     f543  = 29.53125 * sinim * (-2.0 - 8.0 * cosim + cosisq * (12.0 + 8.0 * cosim - 10.0 * cosisq));
0638                     xno2  = nm * nm;
0639                     ainv2 = aonv * aonv;
0640                     temp1 = 3.0 * xno2 * ainv2;
0641                     temp  = temp1 * root22;
0642                     d2201 = temp * f220 * g201;
0643                     d2211 = temp * f221 * g211;
0644                     temp1 = temp1 * aonv;
0645                     temp  = temp1 * root32;
0646                     d3210 = temp * f321 * g310;
0647                     d3222 = temp * f322 * g322;
0648                     temp1 = temp1 * aonv;
0649                     temp  = 2.0 * temp1 * root44;
0650                     d4410 = temp * f441 * g410;
0651                     d4422 = temp * f442 * g422;
0652                     temp1 = temp1 * aonv;
0653                     temp  = temp1 * root52;
0654                     d5220 = temp * f522 * g520;
0655                     d5232 = temp * f523 * g532;
0656                     temp  = 2.0 * temp1 * root54;
0657                     d5421 = temp * f542 * g521;
0658                     d5433 = temp * f543 * g533;
0659                     xlamo = fmod(m_mean_anomaly + m_ra + m_ra - theta - theta, TWOPI);
0660                     xfact = mdot + dmdt + 2.0 * (nodedot + dnodt - rptim) - m_mean_motion;
0661                     // Value never used
0662                     //                    em    = emo;
0663                     emsq  = emsqo;
0664                 }
0665 
0666                 if (irez == 1)
0667                 {
0668                     g200  = 1.0 + emsq * (-2.5 + 0.8125 * emsq);
0669                     g310  = 1.0 + 2.0 * emsq;
0670                     g300  = 1.0 + emsq * (-6.0 + 6.60937 * emsq);
0671                     f220  = 0.75 * (1.0 + cosim) * (1.0 + cosim);
0672                     f311  = 0.9375 * sinim * sinim * (1.0 + 3.0 * cosim) - 0.75 * (1.0 + cosim);
0673                     f330  = 1.0 + cosim;
0674                     f330  = 1.875 * f330 * f330 * f330;
0675                     del1  = 3.0 * nm * nm * aonv * aonv;
0676                     del2  = 2.0 * del1 * f220 * g200 * q22;
0677                     del3  = 3.0 * del1 * f330 * g300 * q33 * aonv;
0678                     del1  = del1 * f311 * g310 * q31 * aonv;
0679                     xlamo = fmod(m_mean_anomaly + m_ra + m_arg_perigee - theta, TWOPI);
0680                     xfact = mdot + xpidot - rptim + dmdt + domdt + dnodt - m_mean_motion;
0681                 }
0682 
0683                 xli   = xlamo;
0684                 xni   = m_mean_motion;
0685                 atime = 0.0;
0686                 // Value never used
0687                 //                nm    = m_mean_motion + dndt;
0688             }
0689         }
0690 
0691         // Set variables if not deep space
0692         if (!isimp)
0693         {
0694             cc1sq = cc1 * cc1;
0695             d2    = 4.0 * ao * tsi * cc1sq;
0696             temp  = d2 * tsi * cc1 / 3.0;
0697             d3    = (17.0 * ao + sfour) * temp;
0698             d4    = 0.5 * temp * ao * tsi * (221.0 * ao + 31.0 * sfour) * cc1;
0699             t3cof = d2 + 2.0 * cc1sq;
0700             t4cof = 0.25 * (3.0 * d3 + cc1 * (12.0 * d2 + 10.0 * cc1sq));
0701             t5cof = 0.2 * (3.0 * d4 + 12.0 * cc1 * d3 + 6.0 * d2 * d2 + 15.0 * cc1sq * (2.0 * d2 + cc1sq));
0702         }
0703     }
0704 }
0705 
0706 int Satellite::updatePos()
0707 {
0708     KStarsData *data = KStarsData::Instance();
0709     return sgp4((data->clock()->utc().djd() - m_tle_jd) * MINPD);
0710 }
0711 
0712 int Satellite::sgp4(double tsince)
0713 {
0714     KStarsData *data = KStarsData::Instance();
0715 
0716     int ktr;
0717     double am, axnl, aynl, betal, cosim, cnod, cos2u, coseo1 = 0, cosi, cosip, cosisq, cossu, cosu, delm, delomg, em,
0718                                                       ecose, el2, eo1, ep, esine, argpm, argpp, argpdf, pl,
0719                                                       mrt = 0.0, mvt, rdotl, rl, rvdot, rvdotl, sinim, dndt, sin2u, sineo1 = 0, sini, sinip, sinsu, sinu, snod, su, t2,
0720                                                       t3, t4, tem5, temp, temp1, temp2, tempa, tempe, templ, u, ux, uy, uz, vx, vy, vz, inclm, mm, nm, nodem, xinc,
0721                                                       xincp, xl, xlm, mp, xmdf, xmx, xmy, nodedf, xnode, nodep, tc, sat_posx, sat_posy, sat_posz, sat_posw, sat_velx,
0722                                                       sat_vely, sat_velz, sinlat, obs_posx, obs_posy, obs_posz, obs_posw, /*obs_velx, obs_vely, obs_velz,*/
0723                                                       coslat, thetageo, sintheta, costheta, c, sq, achcp, vkmpersec;
0724     //    double emsq;
0725 
0726     const double temp4 = 1.5e-12;
0727 
0728     double jul_utc = data->clock()->utc().djd();
0729 
0730     vkmpersec = RADIUSEARTHKM * XKE / 60.0;
0731 
0732     // Update for secular gravity and atmospheric drag
0733     xmdf   = m_mean_anomaly + mdot * tsince;
0734     argpdf = m_arg_perigee + argpdot * tsince;
0735     nodedf = m_ra + nodedot * tsince;
0736     argpm  = argpdf;
0737     mm     = xmdf;
0738     t2     = tsince * tsince;
0739     nodem  = nodedf + nodecf * t2;
0740     tempa  = 1.0 - cc1 * tsince;
0741     tempe  = m_bstar * cc4 * tsince;
0742     templ  = t2cof * t2;
0743 
0744     if (!isimp)
0745     {
0746         delomg = omgcof * tsince;
0747         delm   = xmcof * (pow((1.0 + eta * cos(xmdf)), 3) - delmo);
0748         temp   = delomg + delm;
0749         mm     = xmdf + temp;
0750         argpm  = argpdf - temp;
0751         t3     = t2 * tsince;
0752         t4     = t3 * tsince;
0753         tempa  = tempa - d2 * t2 - d3 * t3 - d4 * t4;
0754         tempe  = tempe + m_bstar * cc5 * (sin(mm) - sinmao);
0755         templ  = templ + t3cof * t3 + t4 * (t4cof + tsince * t5cof);
0756     }
0757 
0758     nm    = m_mean_motion;
0759     em    = m_eccentricity;
0760     inclm = m_inclination;
0761 
0762     if (method == 'd')
0763     {
0764         tc = tsince;
0765         // Deep space contributions to mean elements for perturbing third body
0766         int iretn;
0767         double delt, ft, theta, x2li, x2omi, xl, xldot, xnddt, xndt, xomi;
0768 
0769         // Define some constants
0770         const double fasx2 = 0.13130908;
0771         const double fasx4 = 2.8843198;
0772         const double fasx6 = 0.37448087;
0773         const double g22   = 5.7686396;
0774         const double g32   = 0.95240898;
0775         const double g44   = 1.8014998;
0776         const double g52   = 1.0508330;
0777         const double g54   = 4.4108898;
0778         const double rptim = 4.37526908801129966e-3; // this equates to 7.29211514668855e-5 rad/sec
0779         const double step  = 720.0;
0780         const double step2 = step * step / 2;
0781 
0782         // Calculate deep space resonance effects
0783         // Value never used
0784         //        dndt  = 0.0;
0785         theta = fmod(gsto + tc * rptim, TWOPI);
0786         em    = em + dedt * tsince;
0787 
0788         inclm = inclm + didt * tsince;
0789         argpm = argpm + domdt * tsince;
0790         nodem = nodem + dnodt * tsince;
0791         mm    = mm + dmdt * tsince;
0792 
0793         // Update resonances : numerical (euler-maclaurin) integration
0794         ft = 0.0;
0795         if (irez != 0)
0796         {
0797             if ((atime == 0.0) || (tsince * atime <= 0.0) || (fabs(tsince) < fabs(atime)))
0798             {
0799                 atime = 0.0;
0800                 xni   = m_mean_motion;
0801                 xli   = xlamo;
0802             }
0803 
0804             if (tsince > 0.0)
0805                 delt = step;
0806             else
0807                 delt = -step;
0808 
0809             iretn = 381; // added for do loop
0810 
0811             while (iretn == 381)
0812             {
0813                 // Near - synchronous resonance terms
0814                 if (irez != 2)
0815                 {
0816                     xndt  = del1 * sin(xli - fasx2) + del2 * sin(2.0 * (xli - fasx4)) + del3 * sin(3.0 * (xli - fasx6));
0817                     xldot = xni + xfact;
0818                     xnddt = del1 * cos(xli - fasx2) + 2.0 * del2 * cos(2.0 * (xli - fasx4)) +
0819                             3.0 * del3 * cos(3.0 * (xli - fasx6));
0820                     xnddt = xnddt * xldot;
0821                 }
0822                 else
0823                 {
0824                     // Near - half-day resonance terms
0825                     xomi  = m_arg_perigee + argpdot * atime;
0826                     x2omi = xomi + xomi;
0827                     x2li  = xli + xli;
0828                     xndt  = d2201 * sin(x2omi + xli - g22) + d2211 * sin(xli - g22) + d3210 * sin(xomi + xli - g32) +
0829                             d3222 * sin(-xomi + xli - g32) + d4410 * sin(x2omi + x2li - g44) + d4422 * sin(x2li - g44) +
0830                             d5220 * sin(xomi + xli - g52) + d5232 * sin(-xomi + xli - g52) +
0831                             d5421 * sin(xomi + x2li - g54) + d5433 * sin(-xomi + x2li - g54);
0832                     xldot = xni + xfact;
0833                     xnddt = d2201 * cos(x2omi + xli - g22) + d2211 * cos(xli - g22) + d3210 * cos(xomi + xli - g32) +
0834                             d3222 * cos(-xomi + xli - g32) + d5220 * cos(xomi + xli - g52) +
0835                             d5232 * cos(-xomi + xli - g52) +
0836                             2.0 * (d4410 * cos(x2omi + x2li - g44) + d4422 * cos(x2li - g44) +
0837                                    d5421 * cos(xomi + x2li - g54) + d5433 * cos(-xomi + x2li - g54));
0838                     xnddt = xnddt * xldot;
0839                 }
0840 
0841                 if (fabs(tsince - atime) >= step)
0842                 {
0843                     iretn = 381;
0844                 }
0845                 else
0846                 {
0847                     ft    = tsince - atime;
0848                     iretn = 0;
0849                 }
0850 
0851                 if (iretn == 381)
0852                 {
0853                     xli   = xli + xldot * delt + xndt * step2;
0854                     xni   = xni + xndt * delt + xnddt * step2;
0855                     atime = atime + delt;
0856                 }
0857             }
0858 
0859             nm = xni + xndt * ft + xnddt * ft * ft * 0.5;
0860             xl = xli + xldot * ft + xndt * ft * ft * 0.5;
0861 
0862             if (irez != 1)
0863             {
0864                 mm   = xl - 2.0 * nodem + 2.0 * theta;
0865                 dndt = nm - m_mean_motion;
0866             }
0867             else
0868             {
0869                 mm   = xl - nodem - argpm + theta;
0870                 dndt = nm - m_mean_motion;
0871             }
0872 
0873             nm = m_mean_motion + dndt;
0874         }
0875     }
0876 
0877     if (nm <= 0.0)
0878     {
0879         qDebug() << Q_FUNC_INFO << "Mean motion less than 0.0";
0880         return (2);
0881     }
0882 
0883     am = pow((XKE / nm), X2O3) * tempa * tempa;
0884     nm = XKE / pow(am, 1.5);
0885     em = em - tempe;
0886 
0887     if ((em >= 1.0) || (em < -0.001))
0888     {
0889         qDebug() << Q_FUNC_INFO << "Eccentricity >= 1.0 or < -0.001";
0890         return (1);
0891     }
0892 
0893     if (em < 1.0e-6)
0894         em = 1.0e-6;
0895 
0896     mm   = mm + m_mean_motion * templ;
0897     xlm  = mm + argpm + nodem;
0898     // Value never used
0899     //    emsq = em * em;
0900     // Value never used
0901     //    temp = 1.0 - emsq;
0902 
0903     nodem = fmod(nodem, TWOPI);
0904     argpm = fmod(argpm, TWOPI);
0905     xlm   = fmod(xlm, TWOPI);
0906     mm    = fmod(xlm - argpm - nodem, TWOPI);
0907 
0908     // Compute extra mean quantities
0909     sinim = sin(inclm);
0910     cosim = cos(inclm);
0911 
0912     // Add lunar-solar periodics
0913     ep    = em;
0914     xincp = inclm;
0915     argpp = argpm;
0916     nodep = nodem;
0917     mp    = mm;
0918     sinip = sinim;
0919     cosip = cosim;
0920     if (method == 'd')
0921     {
0922         double alfdp, betdp, cosip, cosop, dalf, dbet, dls, f2, f3, pe, pgh, ph, pinc, pl, sel, ses, sghl, sghs, shll,
0923                shs, sil, sinip, sinop, sinzf, sis, sll, sls, xls, xnoh, zf, zm;
0924 
0925         // Define some constants
0926         const double zns = 1.19459e-5;
0927         const double zes = 0.01675;
0928         const double znl = 1.5835218e-4;
0929         const double zel = 0.05490;
0930 
0931         // Calculate time varying periodics
0932         zm    = zmos + zns * tsince;
0933         zf    = zm + 2.0 * zes * sin(zm);
0934         sinzf = sin(zf);
0935         f2    = 0.5 * sinzf * sinzf - 0.25;
0936         f3    = -0.5 * sinzf * cos(zf);
0937         ses   = se2 * f2 + se3 * f3;
0938         sis   = si2 * f2 + si3 * f3;
0939         sls   = sl2 * f2 + sl3 * f3 + sl4 * sinzf;
0940         sghs  = sgh2 * f2 + sgh3 * f3 + sgh4 * sinzf;
0941         shs   = sh2 * f2 + sh3 * f3;
0942         zm    = zmol + znl * tsince;
0943 
0944         zf    = zm + 2.0 * zel * sin(zm);
0945         sinzf = sin(zf);
0946         f2    = 0.5 * sinzf * sinzf - 0.25;
0947         f3    = -0.5 * sinzf * cos(zf);
0948         sel   = ee2 * f2 + e3 * f3;
0949         sil   = xi2 * f2 + xi3 * f3;
0950         sll   = xl2 * f2 + xl3 * f3 + xl4 * sinzf;
0951         sghl  = xgh2 * f2 + xgh3 * f3 + xgh4 * sinzf;
0952         shll  = xh2 * f2 + xh3 * f3;
0953         pe    = ses + sel;
0954         pinc  = sis + sil;
0955         pl    = sls + sll;
0956         pgh   = sghs + sghl;
0957         ph    = shs + shll;
0958 
0959         pe    = pe - peo;
0960         pinc  = pinc - pinco;
0961         pl    = pl - plo;
0962         pgh   = pgh - pgho;
0963         ph    = ph - pho;
0964         xincp = xincp + pinc;
0965         ep    = ep + pe;
0966         sinip = sin(xincp);
0967         cosip = cos(xincp);
0968 
0969         // Apply periodics directly
0970         if (xincp >= 0.2)
0971         {
0972             ph    = ph / sinip;
0973             pgh   = pgh - cosip * ph;
0974             argpp = argpp + pgh;
0975             nodep = nodep + ph;
0976             mp    = mp + pl;
0977         }
0978         else
0979         {
0980             // Apply periodics with lyddane modification
0981             sinop = sin(nodep);
0982             cosop = cos(nodep);
0983             alfdp = sinip * sinop;
0984             betdp = sinip * cosop;
0985             dalf  = ph * cosop + pinc * cosip * sinop;
0986             dbet  = -ph * sinop + pinc * cosip * cosop;
0987             alfdp = alfdp + dalf;
0988             betdp = betdp + dbet;
0989             nodep = fmod(nodep, TWOPI);
0990             if (nodep < 0.0)
0991                 nodep += TWOPI;
0992             xls   = mp + argpp + cosip * nodep;
0993             dls   = pl + pgh - pinc * nodep * sinip;
0994             xls   = xls + dls;
0995             xnoh  = nodep;
0996             nodep = atan2(alfdp, betdp);
0997             if ((nodep < 0.0))
0998                 nodep += TWOPI;
0999             if (fabs(xnoh - nodep) > M_PI)
1000             {
1001                 if (nodep < xnoh)
1002                     nodep += TWOPI;
1003                 else
1004                     nodep -= TWOPI;
1005             }
1006             mp    = mp + pl;
1007             argpp = xls - mp - cosip * nodep;
1008         }
1009 
1010         if (xincp < 0.0)
1011         {
1012             xincp = -xincp;
1013             nodep = nodep + M_PI;
1014             argpp = argpp - M_PI;
1015         }
1016 
1017         if ((ep < 0.0) || (ep > 1.0))
1018         {
1019             qDebug() << Q_FUNC_INFO << "Eccentricity < 0.0  or > 1.0";
1020             return (3);
1021         }
1022     }
1023 
1024     // Long period periodics
1025     if (method == 'd')
1026     {
1027         sinip = sin(xincp);
1028         cosip = cos(xincp);
1029         aycof = -0.5 * J3OJ2 * sinip;
1030         if (fabs(cosip + 1.0) > 1.5e-12)
1031             xlcof = -0.25 * J3OJ2 * sinip * (3.0 + 5.0 * cosip) / (1.0 + cosip);
1032         else
1033             xlcof = -0.25 * J3OJ2 * sinip * (3.0 + 5.0 * cosip) / temp4;
1034     }
1035     axnl = ep * cos(argpp);
1036     temp = 1.0 / (am * (1.0 - ep * ep));
1037     aynl = ep * sin(argpp) + temp * aycof;
1038     xl   = mp + argpp + nodep + temp * xlcof * axnl;
1039 
1040     // Solve kepler's equation
1041     u    = fmod(xl - nodep, TWOPI);
1042     eo1  = u;
1043     tem5 = 9999.9;
1044     ktr  = 1;
1045     while ((fabs(tem5) >= 1.0e-12) && (ktr <= 10))
1046     {
1047         sineo1 = sin(eo1);
1048         coseo1 = cos(eo1);
1049         tem5   = 1.0 - coseo1 * axnl - sineo1 * aynl;
1050         tem5   = (u - aynl * coseo1 + axnl * sineo1 - eo1) / tem5;
1051         if (fabs(tem5) >= 0.95)
1052             tem5 = tem5 > 0.0 ? 0.95 : -0.95;
1053         eo1 = eo1 + tem5;
1054         ktr = ktr + 1;
1055     }
1056 
1057     // Short period preliminary quantities
1058     ecose = axnl * coseo1 + aynl * sineo1;
1059     esine = axnl * sineo1 - aynl * coseo1;
1060     el2   = axnl * axnl + aynl * aynl;
1061     pl    = am * (1.0 - el2);
1062 
1063     if (pl < 0.0)
1064     {
1065         qDebug() << Q_FUNC_INFO << "Semi-latus rectum < 0.0";
1066         return (4);
1067     }
1068 
1069     rl     = am * (1.0 - ecose);
1070     rdotl  = sqrt(am) * esine / rl;
1071     rvdotl = sqrt(pl) / rl;
1072     betal  = sqrt(1.0 - el2);
1073     temp   = esine / (1.0 + betal);
1074     sinu   = am / rl * (sineo1 - aynl - axnl * temp);
1075     cosu   = am / rl * (coseo1 - axnl + aynl * temp);
1076     su     = atan2(sinu, cosu);
1077     sin2u  = (cosu + cosu) * sinu;
1078     cos2u  = 1.0 - 2.0 * sinu * sinu;
1079     temp   = 1.0 / pl;
1080     temp1  = 0.5 * J2 * temp;
1081     temp2  = temp1 * temp;
1082 
1083     // Update for short period periodics
1084     if (method == 'd')
1085     {
1086         cosisq = cosip * cosip;
1087         con41  = 3.0 * cosisq - 1.0;
1088         x1mth2 = 1.0 - cosisq;
1089         x7thm1 = 7.0 * cosisq - 1.0;
1090     }
1091     mrt   = rl * (1.0 - 1.5 * temp2 * betal * con41) + 0.5 * temp1 * x1mth2 * cos2u;
1092     su    = su - 0.25 * temp2 * x7thm1 * sin2u;
1093     xnode = nodep + 1.5 * temp2 * cosip * sin2u;
1094     xinc  = xincp + 1.5 * temp2 * cosip * sinip * cos2u;
1095     mvt   = rdotl - nm * temp1 * x1mth2 * sin2u / XKE;
1096     rvdot = rvdotl + nm * temp1 * (x1mth2 * cos2u + 1.5 * con41) / XKE;
1097 
1098     // Orientation vectors
1099     sinsu = sin(su);
1100     cossu = cos(su);
1101     snod  = sin(xnode);
1102     cnod  = cos(xnode);
1103     sini  = sin(xinc);
1104     cosi  = cos(xinc);
1105     xmx   = -snod * cosi;
1106     xmy   = cnod * cosi;
1107     ux    = xmx * sinsu + cnod * cossu;
1108     uy    = xmy * sinsu + snod * cossu;
1109     uz    = sini * sinsu;
1110     vx    = xmx * cossu - cnod * sinsu;
1111     vy    = xmy * cossu - snod * sinsu;
1112     vz    = sini * cossu;
1113 
1114     // Position and velocity (in km and km/sec)
1115     sat_posx   = (mrt * ux) * RADIUSEARTHKM;
1116     sat_posy   = (mrt * uy) * RADIUSEARTHKM;
1117     sat_posz   = (mrt * uz) * RADIUSEARTHKM;
1118     sat_posw   = sqrt(sat_posx * sat_posx + sat_posy * sat_posy + sat_posz * sat_posz);
1119     sat_velx   = (mvt * ux + rvdot * vx) * vkmpersec;
1120     sat_vely   = (mvt * uy + rvdot * vy) * vkmpersec;
1121     sat_velz   = (mvt * uz + rvdot * vz) * vkmpersec;
1122     m_velocity = sqrt(sat_velx * sat_velx + sat_vely * sat_vely + sat_velz * sat_velz);
1123 
1124     //     printf("tsince=%.15f\n", tsince);
1125     //     printf("sat_posx=%.15f\n", sat_posx);
1126     //     printf("sat_posy=%.15f\n", sat_posy);
1127     //     printf("sat_posz=%.15f\n", sat_posz);
1128     //     printf("sat_velx=%.15f\n", sat_velx);
1129     //     printf("sat_vely=%.15f\n", sat_vely);
1130     //     printf("sat_velz=%.15f\n", sat_velz);
1131 
1132     if (mrt < 1.0)
1133     {
1134         qDebug() << Q_FUNC_INFO << "Satellite has decayed";
1135         return (6);
1136     }
1137 
1138     // Observer ECI position and velocity
1139     sinlat   = sin(data->geo()->lat()->radians());
1140     coslat   = cos(data->geo()->lat()->radians());
1141     thetageo = data->geo()->LMST(jul_utc);
1142     sintheta = sin(thetageo);
1143     costheta = cos(thetageo);
1144     c        = 1.0 / sqrt(1.0 + F * (F - 2.0) * sinlat * sinlat);
1145     sq       = (1.0 - F) * (1.0 - F) * c;
1146     achcp    = (RADIUSEARTHKM * c + MEANALT) * coslat;
1147     obs_posx = achcp * costheta;
1148     obs_posy = achcp * sintheta;
1149     obs_posz = (RADIUSEARTHKM * sq + MEANALT) * sinlat;
1150     obs_posw = sqrt(obs_posx * obs_posx + obs_posy * sat_posy + obs_posz * obs_posz);
1151     /*obs_velx = -MFACTOR * obs_posy;
1152     obs_vely = MFACTOR * obs_posx;
1153     obs_velz = 0.;*/
1154 
1155     m_altitude = sat_posw - obs_posw + MEANALT;
1156 
1157     // Az and Dec
1158     double range_posx = sat_posx - obs_posx;
1159     double range_posy = sat_posy - obs_posy;
1160     double range_posz = sat_posz - obs_posz;
1161     m_range           = sqrt(range_posx * range_posx + range_posy * range_posy + range_posz * range_posz);
1162     //     double range_velx = sat_velx - obs_velx;
1163     //     double range_vely = sat_velx - obs_vely;
1164     //     double range_velz = sat_velx - obs_velz;
1165 
1166     double top_s = sinlat * costheta * range_posx + sinlat * sintheta * range_posy - coslat * range_posz;
1167     double top_e = -sintheta * range_posx + costheta * range_posy;
1168     double top_z = coslat * costheta * range_posx + coslat * sintheta * range_posy + sinlat * range_posz;
1169 
1170     double azimuth = atan(-top_e / top_s);
1171     if (top_s > 0.)
1172         azimuth += M_PI;
1173     if (azimuth < 0.)
1174         azimuth += TWOPI;
1175     double elevation = arcSin(top_z / m_range);
1176 
1177     //     printf("azimuth=%.15f\n\r", azimuth / DEG2RAD);
1178     //     printf("elevation=%.15f\n\r", elevation / DEG2RAD);
1179 
1180     setAz(azimuth / DEG2RAD);
1181     setAlt(elevation / DEG2RAD);
1182     HorizontalToEquatorial(data->lst(), data->geo()->lat());
1183 
1184     // is the satellite visible ?
1185     // Find ECI coordinates of the sun
1186     double mjd, year, T, M, L, e, C, O, Lsa, nu, R, eps;
1187 
1188     mjd  = jul_utc - 2415020.0;
1189     year = 1900.0 + mjd / 365.25;
1190     T    = (mjd + deltaET(year) / (MINPD * 60.0)) / 36525.0;
1191     M    = DEG2RAD * (Modulus(358.47583 + Modulus(35999.04975 * T, 360.0) - (0.000150 + 0.0000033 * T) * T * T, 360.0));
1192     L    = DEG2RAD * (Modulus(279.69668 + Modulus(36000.76892 * T, 360.0) + 0.0003025 * T * T, 360.0));
1193     e    = 0.01675104 - (0.0000418 + 0.000000126 * T) * T;
1194     C    = DEG2RAD * ((1.919460 - (0.004789 + 0.000014 * T) * T) * sin(M) + (0.020094 - 0.000100 * T) * sin(2 * M) +
1195                       0.000293 * sin(3 * M));
1196     O    = DEG2RAD * (Modulus(259.18 - 1934.142 * T, 360.0));
1197     Lsa  = Modulus(L + C - DEG2RAD * (0.00569 - 0.00479 * sin(O)), TWOPI);
1198     nu   = Modulus(M + C, TWOPI);
1199     R    = 1.0000002 * (1.0 - e * e) / (1.0 + e * cos(nu));
1200     eps  = DEG2RAD * (23.452294 - (0.0130125 + (0.00000164 - 0.000000503 * T) * T) * T + 0.00256 * cos(O));
1201     R    = AU * R;
1202 
1203     double sun_posx = R * cos(Lsa);
1204     double sun_posy = R * sin(Lsa) * cos(eps);
1205     double sun_posz = R * sin(Lsa) * sin(eps);
1206     double sun_posw = R;
1207 
1208     // Calculates satellite's eclipse status and depth
1209     double sd_sun, sd_earth, delta, depth;
1210 
1211     // Determine partial eclipse
1212     sd_earth       = arcSin(RADIUSEARTHKM / sat_posw);
1213     double rho_x   = sun_posx - sat_posx;
1214     double rho_y   = sun_posy - sat_posy;
1215     double rho_z   = sun_posz - sat_posz;
1216     double rho_w   = sqrt(rho_x * rho_x + rho_y * rho_y + rho_z * rho_z);
1217     sd_sun         = arcSin(SR / rho_w);
1218     double earth_x = -1.0 * sat_posx;
1219     double earth_y = -1.0 * sat_posy;
1220     double earth_z = -1.0 * sat_posz;
1221     double earth_w = sat_posw;
1222     delta      = PIO2 - arcSin((sun_posx * earth_x + sun_posy * earth_y + sun_posz * earth_z) / (sun_posw * earth_w));
1223     depth      = sd_earth - sd_sun - delta;
1224     KSSun *sun = dynamic_cast<KSSun *>(data->skyComposite()->findByName(i18n("Sun")));
1225 
1226     m_is_eclipsed = sd_earth >= sd_sun && depth >= 0;
1227     m_is_visible  = !m_is_eclipsed && sun->alt().Degrees() <= -12.0 && elevation >= 0.0;
1228 
1229     return (0);
1230 }
1231 
1232 QString Satellite::sgp4ErrorString(int code)
1233 {
1234     switch (code)
1235     {
1236         case 0:
1237             return i18n("Success");
1238 
1239         case 1:
1240         case 3:
1241             return i18n("Eccentricity >= 1.0 or < -0.001");
1242 
1243         case 2:
1244             return i18n("Mean motion less than 0.0");
1245 
1246         case 4:
1247             return i18n("Semi-latus rectum < 0.0");
1248 
1249         case 6:
1250             return i18n("Satellite has decayed");
1251 
1252         default:
1253             return i18n("Unknown error");
1254     }
1255 }
1256 
1257 double Satellite::arcSin(double arg)
1258 {
1259     if (fabs(arg) >= 1.)
1260         if (arg > 0.)
1261             return PIO2;
1262         else if (arg < 0.)
1263             return -PIO2;
1264         else
1265             return 0.;
1266     else
1267         return (atan(arg / sqrt(1. - arg * arg)));
1268 }
1269 
1270 double Satellite::deltaET(double year)
1271 {
1272     double delta_et;
1273 
1274     delta_et = 26.465 + 0.747622 * (year - 1950) + 1.886913 * sin(TWOPI * (year - 1975) / 33);
1275 
1276     return delta_et;
1277 }
1278 
1279 double Satellite::Modulus(double arg1, double arg2)
1280 {
1281     int i;
1282     double ret_val;
1283 
1284     ret_val = arg1;
1285     i       = ret_val / arg2;
1286     ret_val -= i * arg2;
1287 
1288     if (ret_val < 0.0)
1289         ret_val += arg2;
1290 
1291     return ret_val;
1292 }
1293 
1294 bool Satellite::isVisible()
1295 {
1296     return m_is_visible;
1297 }
1298 
1299 bool Satellite::selected()
1300 {
1301     return m_is_selected;
1302 }
1303 
1304 void Satellite::setSelected(bool selected)
1305 {
1306     m_is_selected = selected;
1307 }
1308 
1309 void Satellite::initPopupMenu(KSPopupMenu *pmenu)
1310 {
1311 #ifndef KSTARS_LITE
1312     pmenu->createSatelliteMenu(this);
1313 #else
1314     Q_UNUSED(pmenu);
1315 #endif
1316 }
1317 
1318 double Satellite::velocity() const
1319 {
1320     return m_velocity;
1321 }
1322 
1323 double Satellite::altitude() const
1324 {
1325     return m_altitude;
1326 }
1327 
1328 double Satellite::range() const
1329 {
1330     return m_range;
1331 }
1332 
1333 QString Satellite::id() const
1334 {
1335     return m_id;
1336 }
1337 
1338 QString Satellite::tle() const
1339 {
1340     return m_tle;
1341 }