ACE3/extension/src/fcs.rs
BrettMayson 043b3907fe
Extensions - Rust (#9015)
Co-authored-by: Pepijn Holster <pgaholster@gmail.com>
Co-authored-by: PabstMirror <pabstmirror@gmail.com>
Co-authored-by: LorenLuke <LukeLLL@aol.com>
Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com>
Co-authored-by: johnb432 <58661205+johnb432@users.noreply.github.com>
2024-08-17 12:50:38 -03:00

80 lines
2.2 KiB
Rust

use crate::common::GRAVITY;
const SIMULATION_STEP: f64 = 0.05;
const MAX_ITERATIONS: u16 = 600;
const MAX_ELEVATION: f64 = 20.0;
const PRECISION: f64 = 0.1;
fn trace_bullet(
init_speed: f64,
air_friction: f64,
angle: f64,
angle_target: f64,
distance: f64,
) -> f64 {
let mut vel_x = angle.to_radians().cos() * init_speed;
let mut vel_y = angle.to_radians().sin() * init_speed;
let pos_target_x = angle_target.to_radians().cos() * distance;
let pos_target_y = angle_target.to_radians().sin() * distance;
let mut pos_x = 0.0;
let mut pos_y = 0.0;
let mut last_pos_x = 0.0;
let mut last_pos_y = 0.0;
for _ in 0..MAX_ITERATIONS {
last_pos_x = pos_x;
last_pos_y = pos_y;
let vel_mag = vel_x.hypot(vel_y);
pos_x += vel_x * SIMULATION_STEP * 0.5;
pos_y += vel_y * SIMULATION_STEP * 0.5;
vel_x += SIMULATION_STEP * (vel_x * vel_mag * air_friction);
vel_y += SIMULATION_STEP * (vel_y * vel_mag).mul_add(air_friction, -GRAVITY);
pos_x += vel_x * SIMULATION_STEP * 0.5;
pos_y += vel_y * SIMULATION_STEP * 0.5;
if pos_x >= pos_target_x {
break;
}
}
let coef = (pos_target_x - last_pos_x) / (pos_x - last_pos_x);
(pos_y - last_pos_y).mul_add(coef, last_pos_y) - pos_target_y
}
pub fn get_solution(init_speed: f64, air_friction: f64, angle_target: f64, distance: f64) -> f64 {
if trace_bullet(
init_speed,
air_friction,
MAX_ELEVATION,
angle_target,
distance,
) < 0.0
{
return MAX_ELEVATION - angle_target;
}
let mut a1 = angle_target;
let mut a2 = MAX_ELEVATION;
let mut f1 = trace_bullet(init_speed, air_friction, a1, angle_target, distance);
if f1.abs() <= PRECISION {
return 0.0;
}
while f1.abs() > PRECISION {
let f2 = trace_bullet(init_speed, air_friction, a2, angle_target, distance);
let tmp = a2 - f2 * (a2 - a1) / (f2 - f1);
a1 = a2;
a2 = tmp;
f1 = f2;
}
a2 - angle_target
}
#[cfg(test)]
mod tests {
use super::get_solution;
#[test]
fn test_get_solution() {
assert!((get_solution(400.0, 0.0, 28.0, 950.0) - -8.0).abs() < f64::EPSILON);
}
}