use crate::sgp_common::{actan, fmod2p, SatData, Vector3};
pub fn sgp8(tsince: f64, satdata: &SatData) -> (Vector3, Vector3) {
let ae: f64 = 1.0;
let xmnpda: f64 = 1440.0;
let tothrd: f64 = 2.0 / 3.0;
let xj3: f64 = -2.53881e-6;
let e6a: f64 = 1.0e-6;
let xkmper: f64 = 6378.135; let ge: f64 = 398600.8; let ck2: f64 = 1.0826158e-3 / 2.0;
let ck4: f64 = -3.0 * -1.65597e-6 / 8.0;
let rho = 2.461 * 0.00001 * xkmper;
let s = ae + 78.0 / xkmper;
let qo = ae + 120.0 / xkmper;
let xke = ((3600.0 * ge) / (xkmper.powi(3))).sqrt();
let qoms2t = (qo - s).powi(4);
let temp2 = xke / (satdata.xno);
let a1 = temp2.powf(tothrd);
let cosio = (satdata.xincl).cos();
let sinio = (satdata.xincl).sin();
let delta1 = 1.5 * ck2 * (3.0 * cosio * cosio - 1.0)
/ (a1.powi(2) * (1.0 - (satdata.eo * satdata.eo)).powf(1.5));
let a0 = a1
* (1.0
- (1.0 / 3.0) * delta1
- delta1 * delta1
- (134.0 / 81.0) * delta1 * delta1 * delta1);
let delta0 = 1.5 * ck2 * (3.0 * cosio * cosio - 1.0)
/ (a0.powi(2) * (1.0 - (satdata.eo * satdata.eo)).powf(1.5));
let noii = satdata.xno / (1.0 + delta0);
let aoii = a0 / (1.0 - delta0);
let b = 2.0 * (satdata.bstar) / rho;
let beta = (1.0 - (satdata.eo * satdata.eo)).sqrt();
let theta = cosio;
let temp = (noii * ck2) / (aoii.powi(2) * beta * beta * beta);
let m1dot = -1.5 * temp * (1.0 - 3.0 * (theta * theta));
let omega1dot = -1.5 * (temp / beta) * (1.0 - 5.0 * (theta * theta));
let xnode1dot = -3.0 * (temp / beta) * theta;
let m2dot = (3.0 / 16.0)
* (temp * ck2 / (aoii.powi(2) * beta.powi(4)))
* (13.0 - 78.0 * (theta * theta) + 137.0 * (theta.powi(4)));
let omega2dot = (3.0 / 16.0)
* (temp * ck2 / (aoii.powi(2) * beta.powi(5)))
* (7.0 - 114.0 * (theta * theta) + 395.0 * (theta.powi(4)))
+ 1.25 * (noii * ck4) / (aoii.powi(4) * beta.powi(8))
* (3.0 - 36.0 * (theta * theta) + 49.0 * (theta.powi(4)));
let xnode2dot =
1.5 * (temp * ck2 / (aoii.powi(2) * beta.powi(5))) * theta * (4.0 - 19.0 * (theta * theta))
+ 2.5 * (noii * ck4) / (aoii.powi(4) * beta.powi(8))
* theta
* (3.0 - 7.0 * (theta * theta));
let ldot = noii + m1dot + m2dot;
let omegadot = omega1dot + omega2dot;
let xnodedot = xnode1dot + xnode2dot;
let tsi = 1.0 / (aoii * (beta * beta) - s);
let eta = satdata.eo * s * tsi;
let phi = (1.0 - (eta * eta)).sqrt();
let alpha = (1.0 + (satdata.eo * satdata.eo)).sqrt();
let c0 = 0.5 * b * rho * qoms2t * noii * aoii * tsi.powf(4.0) / (alpha * phi.powf(7.0));
let c1 = 1.5 * noii * alpha.powf(4.0) * c0;
let d1 = tsi * (1.0 / (phi * phi)) / (aoii * (beta * beta));
let d2 = 12.0 + 36.0 * (eta * eta) + 4.5 * eta.powi(4);
let d3 = 15.0 * (eta * eta) + 2.5 * eta.powi(4);
let d4 = 5.0 * eta + (15.0 / 4.0) * eta.powi(3);
let d5 = tsi / (phi * phi);
let b1 = -ck2 * (1.0 - 3.0 * (theta * theta));
let b2 = -ck2 * (1.0 - (theta * theta));
let a30 = -xj3 * (ae.powi(3)) / ck2;
let b3 = a30 * sinio;
let c2 = d1 * d3 * b2;
let c3 = d4 * d5 * b3;
let n0dot = c1
* ((2.0
+ eta.powi(2) * (3.0 + 34.0 * (satdata.eo * satdata.eo))
+ 5.0 * satdata.eo * eta * (4.0 + eta.powi(2))
+ 8.5 * (satdata.eo * satdata.eo))
+ d1 * d2 * b1
+ c2 * (2.0 * (satdata.omegao).cos())
+ c3 * (satdata.omegao).sin());
let d6 = 30.0 * eta + 22.5 * eta.powi(3);
let d7 = 5.0 * eta + 12.5 * eta.powi(3);
let d8 = 1.0 + 6.75 * eta.powi(2) + eta.powi(4);
let c4 = d1 * d7 * b2;
let c5 = d5 * d8 * b3;
let e0dot = -c0
* (eta * (4.0 + eta.powi(2) + (satdata.eo * satdata.eo) * (15.5 + 7.0 * eta.powi(2)))
+ satdata.eo * (5.0 + 15.0 * eta.powi(2))
+ d1 * d6 * b1
+ c4 * (2.0 * (satdata.omegao).cos())
+ c5 * (satdata.omegao).sin());
let alphadottoalpha = satdata.eo * e0dot / (alpha * alpha);
let c6 = (1.0 / 3.0) * (n0dot / noii);
let tsidottotsi = 2.0 * aoii * tsi * (c6 * (beta * beta) + satdata.eo * e0dot);
let etadot = (e0dot + satdata.eo * tsidottotsi) * s * tsi;
let phidottophi = -eta * etadot / (phi * phi);
let c0dot_to_c0 = c6 + 4.0 * tsidottotsi - alphadottoalpha - 7.0 * phidottophi;
let c1dot_to_c1 = n0dot / noii + 4.0 * alphadottoalpha + c0dot_to_c0;
let d9 = 6.0 * eta
+ 20.0 * satdata.eo
+ 15.0 * satdata.eo * eta.powi(2)
+ 68.0 * (satdata.eo * satdata.eo) * eta;
let d10 = 20.0 * eta + 5.0 * eta.powi(3) + 17.0 * satdata.eo + 68.0 * satdata.eo * eta.powi(2);
let d11 = eta * (72.0 + 18.0 * eta.powi(2));
let d12 = eta * (30.0 + 10.0 * eta.powi(2));
let d13 = 5.0 + 11.25 * eta.powi(2);
let d14 = tsidottotsi - 2.0 * phidottophi;
let d15 = 2.0 * (c6 + satdata.eo * e0dot / (beta * beta));
let d1dot = d1 * (d14 + d15);
let d2dot = etadot * d11;
let d3dot = etadot * d12;
let d4dot = etadot * d13;
let d5dot = d5 * d14;
let c2dot = b2 * (d1dot * d3 + d1 * d3dot);
let c3dot = b3 * (d5dot * d4 + d5 * d4dot);
let d16 = d9 * etadot
+ d10 * e0dot
+ b1 * (d1dot * d2 + d1 * d2dot)
+ c2dot * (2.0 * (satdata.omegao).cos())
+ c3dot * (satdata.omegao).sin()
+ omega1dot * (c3 * (satdata.omegao).cos() - 2.0 * c2 * (2.0 * (satdata.omegao).sin()));
let n0ddot = n0dot * c1dot_to_c1 + c1 * d16;
let e0ddot = e0dot * c0dot_to_c0
- c0 * ((4.0
+ 3.0 * eta.powi(2)
+ 30.0 * satdata.eo * eta
+ 15.5 * (satdata.eo * satdata.eo)
+ 21.0 * eta.powi(2) * (satdata.eo * satdata.eo))
* etadot
+ (5.0
+ 15.0 * eta.powi(2)
+ 31.0 * satdata.eo * eta
+ 14.0 * satdata.eo * eta.powi(3))
* e0dot
+ b1 * (d1dot * d6 + d1 * etadot * (30.0 + 67.5 * eta.powi(2)))
+ b2 * (d1dot * d7 + d1 * etadot * (5.0 + 37.5 * eta.powi(2)))
* (2.0 * (satdata.omegao).cos())
+ b3 * (d5dot * d8 + d5 * eta * etadot * (13.5 + 4.0 * eta.powi(2)))
* (satdata.omegao).sin()
+ omega1dot
* (c5 * (satdata.omegao).cos() - 2.0 * c4 * (2.0 * (satdata.omegao).sin())));
let d17 = n0ddot / noii - (n0dot / noii).powi(2);
let tsiddottotsi = 2.0 * (tsidottotsi - c6) * tsidottotsi
+ 2.0
* aoii
* tsi
* ((1.0 / 3.0) * d17 * (beta * beta) - 2.0 * c6 * satdata.eo * e0dot
+ (e0dot * e0dot)
+ satdata.eo * e0ddot);
let etaddot = (e0ddot + 2.0 * e0dot * tsidottotsi) * s * tsi + eta * tsiddottotsi;
let d18 = tsiddottotsi - tsidottotsi.powi(2);
let d19 =
-(phidottophi * phidottophi) * (1.0 + 1.0 / (eta * eta)) - eta * etaddot / (phi * phi);
let d1ddot = d1dot * (d14 + d15)
+ d1 * (d18 - 2.0 * d19
+ (2.0 / 3.0) * d17
+ 2.0 * alpha.powi(2) * (e0dot * e0dot) / beta.powi(4)
+ 2.0 * satdata.eo * e0ddot / (beta * beta));
let n0tdot = n0dot
* (2.0 * (2.0 / 3.0) * d17
+ 3.0 * ((e0dot * e0dot) + satdata.eo * e0ddot) / (alpha * alpha)
- 6.0 * (satdata.eo * e0dot / (alpha * alpha)).powi(2)
+ 4.0 * d18
- 7.0 * d19)
+ c1dot_to_c1 * n0ddot;
let n0tdot = n0tdot
+ c1 * (c1dot_to_c1 * d16
+ d9 * etaddot
+ d10 * e0ddot
+ (etadot * etadot)
* (6.0 + 30.0 * satdata.eo * eta + 68.0 * (satdata.eo * satdata.eo))
+ etadot * e0dot * (40.0 + 30.0 * eta.powi(2) + 272.0 * satdata.eo * eta)
+ (e0dot * e0dot) * (17.0 + 68.0 * eta.powi(2))
+ b1 * (d1ddot * d2
+ 2.0 * d1dot * d2dot
+ d1 * (etaddot * d11 + (etadot * etadot) * (72.0 + 54.0 * eta.powi(2))))
+ b2 * (d1ddot * d3
+ 2.0 * d1dot * d3dot
+ d1 * (etaddot * d12 + (etadot * etadot) * (30.0 + 30.0 * eta.powi(2))))
* (2.0 * satdata.omegao.cos())
+ b3 * ((d5dot * d14 + d5 * (d18 - 2.0 * d19)) * d4
+ 2.0 * d4dot * d5dot
+ d5 * (etaddot * d13 + 22.5 * eta * (etadot * etadot)))
* satdata.omegao.sin()
+ omega1dot
* ((7.0 * (1.0 / 3.0) * (n0dot / noii)
+ 4.0 * satdata.eo * e0dot / (beta * beta))
* (c3 * satdata.omegao.cos() - 2.0 * c2 * (2.0 * satdata.omegao.sin()))
+ (2.0 * c3dot * satdata.omegao.cos()
- 4.0 * c2dot * (2.0 * satdata.omegao.sin())
- omega1dot
* (c3 * satdata.omegao.sin() + 4.0 * c2 * satdata.omegao.cos()))));
let smalln0ddot = n0ddot * 1.0e9;
let temp = (smalln0ddot * smalln0ddot) - n0dot * 1.0e18 * n0tdot;
let p = (temp + (smalln0ddot * smalln0ddot)) / temp;
let gamma = -n0tdot / (n0ddot * (p - 2.0));
let nd = n0dot / (p * gamma);
let q = 1.0 - e0ddot / (e0dot * gamma);
let ed = e0dot / (q * gamma);
let (n, _edot, e, z1) = if (n0dot / noii * xmnpda).abs() < 0.00216 {
let n = noii + n0dot * tsince;
let edot = -(2.0 / 3.0) * n0dot * (1.0 - satdata.eo) / noii;
let e = satdata.eo + edot * tsince;
let z1 = 0.5 * n0dot * tsince.powi(2);
(n, edot, e, z1)
} else {
let n = noii + nd * (1.0 - (1.0 - gamma * tsince).powf(p));
let edot = e0dot;
let e = satdata.eo + ed * (1.0 - (1.0 - gamma * tsince).powf(q));
let mut z1 = gamma * tsince;
z1 = 1.0 - z1;
z1 = z1.powf(p + 1.0);
z1 -= 1.0;
z1 /= gamma * (p + 1.0);
z1 += tsince;
z1 = z1 * n0dot / (p * gamma);
(n, edot, e, z1)
};
let omega = satdata.omegao + omegadot * tsince + (7.0 * z1) / (3.0 * noii) * omega1dot;
let xnode = satdata.xnodeo + xnodedot * tsince + xnode1dot * (7.0 * z1) / (3.0 * noii);
let mut m = satdata.xmo + tsince * ldot + z1 + m1dot * (7.0 * z1) / (3.0 * noii);
m = fmod2p(m);
let mut ew = m + satdata.eo * m.sin() * (1.0 + e * m.cos());
for _iter in 0..10 {
let delta = (m + e * ew.sin() - ew) / (1.0 - e * ew.cos());
ew += delta;
if delta.abs() <= e6a {
break;
}
}
let a = (xke / n).powf(tothrd);
let beta2 = (1.0 - e * e).sqrt();
let sinf = beta2 * ew.sin() / (1.0 - e * ew.cos());
let cosf = (ew.cos() - e) / (1.0 - e * ew.cos());
let f = actan(sinf, cosf);
let sinu = sinf * omega.cos() + cosf * omega.sin();
let cosu = cosf * omega.cos() - sinf * omega.sin();
let rii = a * (1.0 - e * e) / (1.0 + e * cosf);
let delta_r = (0.5 * ck2 * (1.0 / (a * (1.0 - e * e))))
* ((1.0 - (theta * theta)) * (2.0 * (cosu * cosu) - 1.0)
- 3.0 * (3.0 * (theta * theta) - 1.0))
- (0.25 * a30 * sinio) * sinu;
let temp2 = 3.0
* (0.5 * ck2 * (1.0 / (a * (1.0 - e * e))).powi(2))
* sinio
* (2.0 * (cosu * cosu) - 1.0)
- (0.25 * a30 * (1.0 / (a * (1.0 - e * e)))) * e * omega.sin();
let delta_i = temp2 * cosio;
let delta_u = (satdata.xincl / 2.0).sin()
* ((0.5 * ck2 * (1.0 / (a * (1.0 - e * e))).powi(2))
* (0.5 * (1.0 - 7.0 * (theta * theta)) * (2.0 * sinu * cosu)
- 3.0 * (1.0 - 5.0 * (theta * theta)) * (f - m + e * sinf))
- (0.25 * a30 * (1.0 / (a * (1.0 - e * e)))) * sinio * cosu * (2.0 + e * cosf))
- 0.5 * (0.25 * a30 * (1.0 / (a * (1.0 - e * e)))) * (theta * theta) * e * omega.cos()
/ (satdata.xincl / 2.0).cos();
let lambda = f
+ omega
+ xnode
+ (0.5 * ck2 * (1.0 / (a * (1.0 - e * e))).powi(2))
* (0.5 * (1.0 + 6.0 * cosio - 7.0 * (theta * theta)) * (2.0 * sinu * cosu)
- 3.0 * ((1.0 - 5.0 * (theta * theta)) + 2.0 * cosio) * (f - m + e * sinf))
+ (0.25 * a30 * (1.0 / (a * (1.0 - e * e))))
* sinio
* (cosio * e * omega.cos() / (1.0 + cosio) - (2.0 + e * cosf) * cosu);
let y4 = (satdata.xincl / 2.0).sin() * sinu
+ cosu * delta_u
+ 0.5 * sinu * (satdata.xincl / 2.0).cos() * delta_i;
let y5 = (satdata.xincl / 2.0).sin() * cosu - sinu * delta_u
+ 0.5 * cosu * (satdata.xincl / 2.0).cos() * delta_i;
let r = rii + delta_r;
let rdot = n * a * e * sinf / beta2
+ (-n * (a / rii).powi(2))
* (1.0
* ck2
* (1.0 / (a * (1.0 - e * e)))
* (1.0 - (theta * theta))
* (2.0 * sinu * cosu)
+ (0.25 * a30 * sinio) * cosu);
let rfdot = n * (a.powi(2)) * beta2 / rii
+ (-n * (a / rii).powi(2)) * delta_r
+ a * (n * (a / rii)) * sinio * temp2;
let cos_i2 = (1.0 - (y4 * y4) - (y5 * y5)).sqrt();
let uv1 = 2.0 * y4 * (y5 * lambda.sin() - y4 * lambda.cos()) + lambda.cos();
let uv2 = -2.0 * y4 * (y5 * lambda.cos() + y4 * lambda.sin()) + lambda.sin();
let uv3 = 2.0 * y4 * cos_i2;
let vv1 = 2.0 * y5 * (y5 * lambda.sin() - y4 * lambda.cos()) - lambda.sin();
let vv2 = -2.0 * y5 * (y5 * lambda.cos() + y4 * lambda.sin()) + lambda.cos();
let vv3 = 2.0 * y5 * cos_i2;
let pos_x = r * uv1;
let pos_y = r * uv2;
let pos_z = r * uv3;
let vel_x = rdot * uv1 + rfdot * vv1;
let vel_y = rdot * uv2 + rfdot * vv2;
let vel_z = rdot * uv3 + rfdot * vv3;
let pos = Vector3 {
x: pos_x * xkmper,
y: pos_y * xkmper,
z: pos_z * xkmper,
};
let vel = Vector3 {
x: vel_x * xkmper / 60.0,
y: vel_y * xkmper / 60.0,
z: vel_z * xkmper / 60.0,
};
(pos, vel)
}