use pyo3::prelude::*;
use std::f64::consts::{TAU, FRAC_PI_2};
use crate::{Star, Vec3};
use crate::errors::RocheError;
use crate::{fblink, set_earth_iangle, x_l1};
#[pyfunction]
#[pyo3(signature = (q, iangle, r1, r2=-1.0, ntheta=200))]
pub fn wdphases(q: f64, iangle: f64, r1: f64, r2: f64, ntheta: i32) -> Result<(f64, f64), RocheError> {
let ffac: f64;
if r2 <= 0.0{
ffac = 1.0;
} else {
ffac = r2/(1.0-x_l1(q)?);
}
let mut phi4lo: f64 = 0.0;
let mut phi4hi: f64 = 0.25;
let mut phi4: f64 = 0.0;
if !eclipsed_4(q, iangle, phi4lo, r1, ffac, ntheta)? {
let message = format!(
"no eclipse at all for q={}, i={}, r1={}", q, iangle, r1
);
return Err(RocheError::WdphasesError(message))
}
while phi4hi - phi4lo > r1/(ntheta as f64)/10.0 {
phi4 = (phi4lo + phi4hi)/2.0;
if eclipsed_4(q, iangle, phi4, r1, ffac, ntheta)? {
phi4lo = phi4;
} else {
phi4hi = phi4;
}
}
let mut phi3lo: f64 = 0.0;
let mut phi3hi: f64 = 0.25;
let mut phi3: f64 = 0.0;
if uneclipsed_3(q, iangle, phi3lo, r1, ffac, ntheta)? {
return Ok((-1.0, phi4));
}
while phi3hi - phi3lo > r1/(ntheta as f64)/10.0 {
phi3 = (phi3lo + phi3hi)/2.0;
if uneclipsed_3(q, iangle, phi3, r1, ffac, ntheta)? {
phi3hi = phi3;
} else {
phi3lo = phi3;
}
}
Ok((phi3, phi4))
}
fn xyv(iangle: f64, r1: f64, phase: f64) -> (Vec3, Vec3) {
let (sinp, cosp) = (TAU * phase).sin_cos();
let x = Vec3::new(-r1*sinp, r1*cosp, 0.0);
let iangle_radians = iangle.to_radians();
let (sini, cosi) = iangle_radians.sin_cos();
let y = Vec3::new(-r1*cosi*cosp, -r1*cosi*sinp, r1*sini);
(x, y)
}
fn uneclipsed_3(q: f64, iangle: f64, phase: f64, r1: f64, ffac: f64, ntheta: i32) -> Result<bool, RocheError> {
let (x, y) = xyv(iangle, r1, phase);
let mut theta: f64;
let mut v: Vec3;
let mut sint: f64;
let mut cost: f64;
for i in 0..ntheta {
theta = FRAC_PI_2 * (i as f64 /(ntheta as f64 - 1.0));
(sint, cost) = theta.sin_cos();
v = -x*cost + y*sint;
if !fblink(q, Star::Secondary, 1.0, ffac, 1.0e-5, &set_earth_iangle(iangle, phase), &v)? {
return Ok(true);
}
}
Ok(false)
}
fn eclipsed_4(q: f64, iangle: f64, phase: f64, r1: f64, ffac: f64, ntheta: i32) -> Result<bool, RocheError> {
let (x, y) = xyv(iangle, r1, phase);
let mut theta: f64;
let mut v: Vec3;
let mut sint: f64;
let mut cost: f64;
for i in 0..ntheta {
theta = FRAC_PI_2 * (i as f64 /(ntheta as f64 - 1.0));
(sint, cost) = theta.sin_cos();
v = x*cost - y*sint;
if fblink(q, Star::Secondary, 1.0, ffac, 1.0e-5, &set_earth_iangle(iangle, phase), &v)? {
return Ok(true);
}
}
Ok(false)
}