use crate::sgp_common::{actan, fmod2p, SatData, Vector3};
pub fn sgp4(tsince: f64, satdata: &SatData) -> (Vector3, Vector3) {
let ae: f64 = 1.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 s: f64 = ae + 78.0 / xkmper;
let qo: f64 = ae + 120.0 / xkmper;
let xke: f64 = ((3600.0_f64 * ge) / (xkmper.powi(3))).sqrt();
let qoms2t: f64 = (qo - s).powi(4);
let temp2: f64 = xke / (satdata.xno);
let a1: f64 = temp2.powf(tothrd);
let cosio: f64 = (satdata.xincl).cos();
let theta2: f64 = cosio * cosio;
let x3thm1 = 3.0 * theta2 - 1.0;
let eosq: f64 = satdata.eo * satdata.eo;
let betao2: f64 = 1.0 - eosq;
let betao: f64 = betao2.sqrt();
let del1: f64 = 1.5 * ck2 * x3thm1 / ((a1 * a1) * betao * betao2);
let ao: f64 = a1 * (1.0 - del1 * ((1.0 / 3.0) + del1 * (1.0 + (134.0 / 81.0) * del1)));
let delo: f64 = 1.5 * ck2 * x3thm1 / ((ao * ao) * betao * betao2);
let xnodp: f64 = (satdata.xno) / (1.0 + delo);
let aodp: f64 = ao / (1.0 - delo);
let mut isimp = 0;
if aodp * (1.0 - satdata.eo) / ae < 220.0 / xkmper + ae {
isimp = 1;
}
let mut s4: f64 = s;
let mut qoms24: f64 = qoms2t;
let perige = (aodp * (1.0 - satdata.eo) - ae) * xkmper;
if perige < 156.0 {
s4 = perige - 78.0;
if perige <= 98.0 {
s4 = 20.0;
}
qoms24 = ((120.0 - s4) * ae / xkmper).powi(4);
s4 = s4 / xkmper + ae;
}
let pinvsq: f64 = 1.0 / ((aodp * aodp) * (betao2 * betao2));
let tsi: f64 = 1.0 / (aodp - s4);
let eta: f64 = aodp * (satdata.eo) * tsi;
let etasq: f64 = eta * eta;
let eeta: f64 = (satdata.eo) * eta;
let psisq: f64 = (1.0 - etasq).abs();
let coef: f64 = qoms24 * tsi.powi(4);
let coef1: f64 = coef / psisq.powf(3.5);
let c2: f64 = coef1 * xnodp * (aodp * (1.0 + 1.5 * etasq + eeta * (4.0 + etasq))
+ 0.75 * ck2 * tsi / psisq * x3thm1 * (8.0 + 3.0 * etasq * (8.0 + etasq)));
let c1: f64 = (satdata.bstar) * c2;
let sinio: f64 = (satdata.xincl).sin();
let a3ovk2: f64 = -xj3 / ck2 * (ae.powi(3));
let c3: f64 = coef * tsi * a3ovk2 * xnodp * ae * sinio / (satdata.eo.max(1e-12));
let x1mth2: f64 = 1.0 - theta2;
let c4: f64 = 2.0 * xnodp * coef1 * aodp * betao2 * (eta * (2.0 + 0.5 * etasq)
+ (satdata.eo) * (0.5 + 2.0 * etasq) - 2.0 * ck2 * tsi / (aodp * psisq)
* (-3.0 * x3thm1 * (1.0 - 2.0 * eeta + etasq * (1.5 - 0.5 * eeta))
+ 0.75 * x1mth2 * (2.0 * etasq - eeta * (1.0 + etasq)) * (satdata.omegao * 2.0).cos()));
let c5: f64 = 2.0 * coef1 * aodp * betao2 * (1.0 + 2.75 * (etasq + eeta) + eeta * etasq);
let theta4: f64 = theta2 * theta2;
let temp1: f64 = 3.0 * ck2 * pinvsq * xnodp;
let temp2b: f64 = temp1 * ck2 * pinvsq;
let temp3: f64 = 1.25 * ck4 * pinvsq * pinvsq * xnodp;
let xmdot: f64 = xnodp + 0.5 * temp1 * betao * x3thm1 + 0.0625 * temp2b * betao * (13.0 - 78.0 * theta2 + 137.0 * theta4);
let x1m5th: f64 = 1.0 - 5.0 * theta2;
let omgdot = -0.5 * temp1 * x1m5th + 0.0625 * temp2b * (7.0 - 114.0 * theta2 + 395.0 * theta4) + temp3 * (3.0 - 36.0 * theta2 + 49.0 * theta4);
let xhdot1 = -temp1 * cosio;
let xnodot = xhdot1 + (0.5 * temp2b * (4.0 - 19.0 * theta2) + 2.0 * temp3 * (3.0 - 7.0 * theta2)) * cosio;
let omgcof = (satdata.bstar) * c3 * (satdata.omegao).cos();
let xmcof = -(2.0 / 3.0) * coef * (satdata.bstar) * ae / (eeta.max(1e-12));
let xnodcf = 3.5 * betao2 * xhdot1 * c1;
let t2cof = 1.5 * c1;
let xlcof = 0.125 * a3ovk2 * sinio * (3.0 + 5.0 * cosio) / (1.0 + cosio);
let aycof = 0.25 * a3ovk2 * sinio;
let delmo = (1.0 + eta * (satdata.xmo).cos()).powi(3);
let sinmo = (satdata.xmo).sin();
let x7thm1 = 7.0 * theta2 - 1.0;
let (_c1sq, d2, _tempd, d3, d4, t3cof, t4cof, t5cof) = if isimp == 0 {
let c1sq = c1 * c1;
let d2 = 4.0 * aodp * tsi * c1sq;
let tempd = d2 * tsi * c1 / 3.0;
let d3 = (17.0 * aodp + s4) * tempd;
let d4 = 0.5 * tempd * aodp * tsi * (221.0 * aodp + 31.0 * s4) * c1;
let t3cof = d2 + 2.0 * c1sq;
let t4cof = 0.25 * (3.0 * d3 + c1 * (12.0 * d2 + 10.0 * c1sq));
let t5cof = 0.2 * (3.0 * d4 + 12.0 * c1 * d3 + 6.0 * d2 * d2 + 15.0 * c1sq * (2.0 * d2 + c1sq));
(c1sq, d2, tempd, d3, d4, t3cof, t4cof, t5cof)
} else {
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
};
let xmdf = satdata.xmo + xmdot * tsince;
let omgadf = satdata.omegao + omgdot * tsince;
let xnoddf = satdata.xnodeo + xnodot * tsince;
let mut omega = omgadf;
let mut xmp = xmdf;
let tsq = tsince * tsince;
let xnode = xnoddf + xnodcf * tsq;
let mut tempa = 1.0 - c1 * tsince;
let mut tempe = (satdata.bstar) * c4 * tsince;
let mut templ = t2cof * tsq;
if isimp == 0 {
let delomg = omgcof * tsince;
let delm = xmcof * (((1.0 + eta * xmdf.cos()).powf(3.0)) - delmo);
let temp = delomg + delm;
xmp = xmdf + temp;
omega = omgadf - temp;
let tcube = tsq * tsince;
let tfour = tsince * tcube;
tempa = tempa - d2 * tsq - d3 * tcube - d4 * tfour;
tempe += (satdata.bstar) * c5 * ((xmp).sin() - sinmo);
templ = templ + t3cof * tcube + tfour * (t4cof + tsince * t5cof);
}
let a = aodp * (tempa * tempa);
let e = (satdata.eo) - tempe;
let xl = xmp + omega + xnode + xnodp * templ;
let beta = (1.0_f64 - (e * e)).sqrt();
let xn = xke / a.powf(tothrd);
let axn = e * omega.cos();
let temp = 1.0 / (a * (beta * beta));
let xll = temp * xlcof * axn;
let aynl = temp * aycof;
let xlt = xl + xll;
let ayn = e * omega.sin() + aynl;
let capu = fmod2p(xlt - xnode);
let temp2w = capu;
let mut epw = temp2w;
for _i in 0..10 {
let sinepw = epw.sin();
let cosepw = epw.cos();
let temp3 = axn * sinepw;
let temp4 = ayn * cosepw;
let temp5 = axn * cosepw;
let temp6 = ayn * sinepw;
let new_epw = (capu - temp4 + temp3 - epw) / (1.0 - temp5 - temp6) + epw;
let delta = new_epw - epw;
epw = new_epw;
if delta.abs() <= e6a {
break;
}
}
let ecose = axn * epw.cos() + ayn * epw.sin();
let esine = axn * epw.sin() - ayn * epw.cos();
let elsq = (axn * axn) + (ayn * ayn);
let temp = 1.0 - elsq;
let pl = a * temp;
let r = a * (1.0 - ecose);
let temp1 = 1.0 / r;
let rdot = xke * a.sqrt() * esine * temp1;
let rfdot = xke * pl.sqrt() * temp1;
let temp2c = a * temp1;
let betal = temp.sqrt();
let temp3c = 1.0 / (1.0 + betal);
let cosu = temp2c * (epw.cos() - axn + ayn * esine * temp3c);
let sinu = temp2c * (epw.sin() - ayn - axn * esine * temp3c);
let u = actan(sinu, cosu);
let sin2u = 2.0 * sinu * cosu;
let cos2u = 2.0 * (cosu * cosu) - 1.0;
let temp4c = 1.0 / pl;
let temp1c = ck2 * temp4c;
let temp2d = temp1c * temp4c;
let rk = r * (1.0 - 1.5 * temp2d * betal * x3thm1) + 0.5 * temp1c * x1mth2 * cos2u;
let uk = u - 0.25 * temp2d * x7thm1 * sin2u;
let xnodek = xnode + 1.5 * temp2d * cosio * sin2u;
let xinck = satdata.xincl + 1.5 * temp2d * cosio * sinio * cos2u;
let rdotk = rdot - xn * temp1c * x1mth2 * sin2u;
let rfdotk = rfdot + xn * temp1c * (x1mth2 * cos2u + 1.5 * x3thm1);
let mv1 = -xnodek.sin() * xinck.cos();
let mv2 = xnodek.cos() * xinck.cos();
let mv3 = xinck.sin();
let nv1 = xnodek.cos();
let nv2 = xnodek.sin();
let nv3 = 0.0;
let uv1 = mv1 * uk.sin() + nv1 * uk.cos();
let uv2 = mv2 * uk.sin() + nv2 * uk.cos();
let uv3 = mv3 * uk.sin() + nv3 * uk.cos();
let vv1 = mv1 * uk.cos() - nv1 * uk.sin();
let vv2 = mv2 * uk.cos() - nv2 * uk.sin();
let vv3 = mv3 * uk.cos() - nv3 * uk.sin();
let pos_x = rk * uv1;
let pos_y = rk * uv2;
let pos_z = rk * uv3;
let vel_x = rdotk * uv1 + rfdotk * vv1;
let vel_y = rdotk * uv2 + rfdotk * vv2;
let vel_z = rdotk * uv3 + rfdotk * 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)
}