use libm as math;
use egui::widgets::plot::Value;
pub fn find_distance_angle(drag:f64, velocity:f64, mass:f64, gravity:f64, max_time: f64, precision:i8, vertical_distance:f64) -> (f64,f64) {
let delta_time = 0.001; let mut angle= 45.0; let mut delta_angle = -1.0; let mut iterations = 0; let mut distance = 0.0;
let mut has_been_above_target: bool;
if vertical_distance < 0.0 {
has_been_above_target = false;
} else {
has_been_above_target = true;
}
while iterations < precision {
let mut time = 0.0;
while time <= max_time {
let x = (mass/drag)*velocity*math::cos(0.0174532925*angle)*(1.0-math::exp(-(drag/mass)*time)); let y = (mass/drag)*(velocity*math::sin(0.0174532925*angle)+((mass*gravity)/drag))*(1.0-math::exp(-(drag/mass)*time))-((mass/drag)*gravity*time)-vertical_distance;
if !has_been_above_target && y >= vertical_distance {has_been_above_target = true;}
if y < vertical_distance && has_been_above_target {
if x > distance { distance = x; } else if x < distance { delta_angle = -0.1 * delta_angle; iterations += 1; } else { distance = x; iterations += 5; break; }
break; }
time += delta_time; }
angle += delta_angle; }
(distance, angle) }
pub fn find_trajectory_angle(drag:f64, velocity:f64, mass:f64, gravity:f64, max_time:f64, precision:i8, ballistic:bool, distance:f64, vertical_distance:f64) -> (Vec<Value>, f64) {
let (max_distance, max_dist_angle) = find_distance_angle(drag, velocity, mass, gravity, max_time, precision, vertical_distance);
if distance > max_distance {
panic!("Invalid Requested Range, decrease to {} or less!", max_distance);
}
let delta_time = 0.001; let mut angle= max_dist_angle; let mut delta_angle = -1.0; let mut iterations = 0;
let mut has_been_above_target: bool;
if vertical_distance < 0.0 {
has_been_above_target = false;
} else {
has_been_above_target = true;
}
if ballistic {
delta_angle *= -1.0;
}
let mut trajectory: Vec<Value> = Vec::new();
while iterations < precision {
trajectory.clear(); let mut time = 0.0;
while time <= max_time {
let x = (mass/drag)*velocity*math::cos(0.0174532925*angle)*(1.0-math::exp(-(drag/mass)*time)); let y = (mass/drag)*(velocity*math::sin(0.0174532925*angle)+((mass*gravity)/drag))*(1.0-math::exp(-(drag/mass)*time))-((mass/drag)*gravity*time)-vertical_distance;
trajectory.push(Value::new(x, y));
if !has_been_above_target && y >= vertical_distance {has_been_above_target = true;}
if y < vertical_distance && has_been_above_target {
if delta_angle > 0.0 && x > distance { delta_angle *= -0.1; iterations += 1; } else if delta_angle < 0.0 && x < distance { delta_angle *= -0.1; iterations += 1; }
break; }
time += delta_time; }
angle += delta_angle; }
(trajectory,angle) }
pub fn find_trajectory_distance_time(drag:f64, velocity:f64, mass:f64, angle:f64, gravity:f64, max_time:f64, vertical_distance:f64) -> (Vec<Value>,f64,f64) {
let delta_time = 0.001; let mut time = 0.0;
let mut x = 0.0;
let mut y = 0.0;
let mut has_been_above_target: bool;
if vertical_distance < 0.0 {
has_been_above_target = false;
} else {
has_been_above_target = true;
}
let mut trajectory: Vec<Value> = Vec::new();
while time <= max_time { x = (mass/drag)*velocity*math::cos(0.0174532925*angle)*(1.0-math::exp(-(drag/mass)*time)); y = (mass/drag)*(velocity*math::sin(0.0174532925*angle)+((mass*gravity)/drag))*(1.0-math::exp(-(drag/mass)*time))-((mass/drag)*gravity*time)-vertical_distance;
trajectory.push(Value::new(x, y));
if !has_been_above_target && y >= vertical_distance {has_been_above_target = true;}
if y < vertical_distance && has_been_above_target { break; }
time += delta_time; }
(trajectory, x, time) }