|
@@ -3,29 +3,48 @@
|
|
|
extern crate serde_derive;
|
|
|
extern crate serde;
|
|
|
extern crate serde_json;
|
|
|
-use std::io::BufWriter;
|
|
|
-use std::io::BufReader;
|
|
|
-use std::fs::File;
|
|
|
-use std::collections::HashMap;
|
|
|
+use mentat::MonotonicCubicSpline;
|
|
|
use splines::{Interpolation, Key, Spline};
|
|
|
+use std::collections::HashMap;
|
|
|
+use std::fs::File;
|
|
|
+use std::io::BufReader;
|
|
|
+use std::io::BufWriter;
|
|
|
+
|
|
|
+#[derive(Serialize, Deserialize, Debug)]
|
|
|
+pub enum Adjustment {
|
|
|
+ MOAQuarter = 4,
|
|
|
+ MOAHalf = 2,
|
|
|
+}
|
|
|
+
|
|
|
+impl Default for Adjustment {
|
|
|
+ fn default() -> Self {
|
|
|
+ Adjustment::MOAQuarter
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Serialize, Deserialize, Debug, Default)]
|
|
|
+pub struct Gun {
|
|
|
+ pub name: String,
|
|
|
+ pub adjustment: Adjustment,
|
|
|
+ pub caliber: f32,
|
|
|
+ #[serde(default)]
|
|
|
+ pub weight: f32,
|
|
|
+}
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Default)]
|
|
|
-struct BallisticsData {
|
|
|
- // velocity: HashMap<i32, f32>,
|
|
|
- // energy: HashMap<i32, f32>,
|
|
|
- // trajectory: HashMap<i32, f32>
|
|
|
- velocity: Vec<(i32, f32)>,
|
|
|
- energy: Vec<(i32, f32)>,
|
|
|
- trajectory: Vec<(i32, f32)>,
|
|
|
+pub struct BallisticsData {
|
|
|
+ pub velocity: Vec<(i32, f32)>,
|
|
|
+ pub energy: Vec<(i32, f32)>,
|
|
|
+ pub trajectory: Vec<(i32, f32)>,
|
|
|
+ #[serde(default)]
|
|
|
+ pub trajectory_filled: Vec<(i32, f32)>,
|
|
|
}
|
|
|
|
|
|
impl BallisticsData {
|
|
|
- fn attr_at(&self, d: i32, attribute: &Vec<(i32, f32)>) -> f32{
|
|
|
-
|
|
|
-
|
|
|
+ fn attr_at(&self, d: i32, attribute: &Vec<(i32, f32)>) -> f32 {
|
|
|
for i in 0..attribute.len() {
|
|
|
if attribute[i].0 >= d {
|
|
|
- let start = attribute.get(i-1).unwrap_or(&attribute[i]);
|
|
|
+ let start = attribute.get(i - 1).unwrap_or(&attribute[i]);
|
|
|
let end = attribute[i];
|
|
|
let mu = normalized_pos_in_range(start.0 as f32, end.0 as f32, d as f32);
|
|
|
return lerp(start.1 as f32, end.1 as f32, mu);
|
|
@@ -34,6 +53,32 @@ impl BallisticsData {
|
|
|
0.0
|
|
|
}
|
|
|
|
|
|
+ pub fn monospline(&self) -> Spline<f32, f32> {
|
|
|
+ // let x = vec![50.0, 100.0, 150.0, 200.0, 300.0];
|
|
|
+ // let y = vec![1.0, 4.0, -8.0, -10.5, -40.0];
|
|
|
+
|
|
|
+ let x: Vec<f64> = self.trajectory.iter().map(|x| x.0 as f64).collect();
|
|
|
+ let y: Vec<f64> = self.trajectory.iter().map(|x| x.1 as f64).collect();
|
|
|
+
|
|
|
+ // let smooth = MonotonicCubicSpline::partial(x.clone(), y.clone());
|
|
|
+
|
|
|
+ let mut smooth = MonotonicCubicSpline::new(&x, &y);
|
|
|
+
|
|
|
+ let mut a = vec![];
|
|
|
+
|
|
|
+ for i in self.trajectory[0].0..self.trajectory[self.trajectory.len() - 1].0 {
|
|
|
+ let p = i as f32;
|
|
|
+ a.push(Key::new(
|
|
|
+ p as f32,
|
|
|
+ smooth.interpolate(p as f64) as f32,
|
|
|
+ Interpolation::Linear,
|
|
|
+ ));
|
|
|
+ // a.push(Key::new(p as f32, spline.smooth(p as f64) as f32, Interpolation::Linear));
|
|
|
+ }
|
|
|
+
|
|
|
+ Spline::from_vec(a)
|
|
|
+ }
|
|
|
+
|
|
|
fn data_at(&self, d: i32) {
|
|
|
let vel = self.attr_at(d, &self.velocity);
|
|
|
let energy = self.attr_at(d, &self.energy);
|
|
@@ -41,31 +86,54 @@ impl BallisticsData {
|
|
|
println!("D{} V{} E{} T{}", d, vel, energy, trajectory);
|
|
|
}
|
|
|
|
|
|
+ pub fn spline(&self) -> Spline<f32, f32> {
|
|
|
+ // let mut a: Vec<Key<f32, f32>> = self.trajectory
|
|
|
+ // .iter()
|
|
|
+ // .map(|x| Key::new(x.0 as f32, x.1, Interpolation::CatmullRom))
|
|
|
+ // .collect();
|
|
|
+
|
|
|
+ let mut a = vec![];
|
|
|
+
|
|
|
+ let mut i = 0;
|
|
|
+ for pt in &self.trajectory {
|
|
|
+ // let mut interp : Interpolation<f32, f32> = Interpolation::Cosine;
|
|
|
+ let mut interp: Interpolation<f32, f32> = Interpolation::CatmullRom;
|
|
|
+ if i == 0 || i >= self.trajectory.len() - 2 {
|
|
|
+ interp = Interpolation::Linear;
|
|
|
+ }
|
|
|
+ a.push(Key::new(pt.0 as f32, pt.1, interp));
|
|
|
+ i += 1;
|
|
|
+ }
|
|
|
|
|
|
- fn spline(&self) -> Spline<f32, f32>{
|
|
|
+ // a[0] = Key::new(self.trajectory[0].0 as f32, self.trajectory[0].1, Interpolation::Linear);
|
|
|
+ // a[self.trajectory.len()-1] = Key::new(self.trajectory[self.trajectory.len()-1].0 as f32, self.trajectory[self.trajectory.len()-1].1, Interpolation::Linear);
|
|
|
|
|
|
- let a: Vec<Key<f32, f32>> = self.trajectory
|
|
|
- .iter()
|
|
|
- .map(|x| Key::new(x.0 as f32, x.1, Interpolation::Cosine))
|
|
|
- .collect();
|
|
|
Spline::from_vec(a)
|
|
|
}
|
|
|
|
|
|
-
|
|
|
fn drop(&self, dist: i32) -> f32 {
|
|
|
- self.spline()
|
|
|
+ self.monospline()
|
|
|
.clamped_sample(dist as f32)
|
|
|
.unwrap_or(-999999.0)
|
|
|
}
|
|
|
|
|
|
- fn drop_zeroed(&self, dist: i32, zero_dist: i32) -> f32 {
|
|
|
- let z_comp = self.spline().clamped_sample(zero_dist as f32).unwrap_or(0.0);
|
|
|
+ pub fn drop_zeroed(&self, dist: i32, zero_dist: i32) -> f32 {
|
|
|
+ let z_comp = self
|
|
|
+ .monospline()
|
|
|
+ .clamped_sample(zero_dist as f32)
|
|
|
+ .unwrap_or(0.0);
|
|
|
// println!("drop at {} {}", dist, z_comp);
|
|
|
- self.spline()
|
|
|
+ self.monospline()
|
|
|
.clamped_sample(dist as f32)
|
|
|
- .unwrap_or(-999999.0) - z_comp
|
|
|
+ .unwrap_or(-999999.0)
|
|
|
+ - z_comp
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
+fn drop_to_clicks (d: f32, moa_divisor: Adjustment) -> i32 {
|
|
|
+ let radius = d;
|
|
|
+ let diameter = 2.0 * radius * std::f32::consts::PI;
|
|
|
+ 1
|
|
|
}
|
|
|
|
|
|
fn normalized_pos_in_range(min: f32, max: f32, d: f32) -> f32 {
|
|
@@ -73,14 +141,12 @@ fn normalized_pos_in_range(min: f32, max: f32, d: f32) -> f32 {
|
|
|
}
|
|
|
|
|
|
fn lerp(y1: f32, y2: f32, mu: f32) -> f32 {
|
|
|
- y1*(1.0-mu)+y2*mu
|
|
|
+ y1 * (1.0 - mu) + y2 * mu
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
fn write_sample() {
|
|
|
let mut bd = BallisticsData::default();
|
|
|
- bd.velocity.push((0,720.0));
|
|
|
+ bd.velocity.push((0, 720.0));
|
|
|
let mut map = HashMap::new();
|
|
|
map.insert("Hammerhead", bd);
|
|
|
// write out the file
|
|
@@ -88,23 +154,17 @@ fn write_sample() {
|
|
|
serde_json::to_writer_pretty(writer, &map).unwrap();
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-fn load_cartridges() -> Result<HashMap<String, BallisticsData>, serde_json::Error> {
|
|
|
+pub fn load_cartridges() -> Result<HashMap<String, BallisticsData>, serde_json::Error> {
|
|
|
let reader = BufReader::new(File::open("loading_data.json").unwrap());
|
|
|
-
|
|
|
// let s: Result<HashMap<String, BallisticsData>, _> = serde_json::from_reader(reader);
|
|
|
serde_json::from_reader(reader)
|
|
|
// println!("{:?}", loaded_car);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
#[test]
|
|
|
fn w() {
|
|
|
//write_sample();
|
|
|
|
|
|
-
|
|
|
match load_cartridges() {
|
|
|
Ok(c) => {
|
|
|
for (name, cartridge) in c {
|
|
@@ -114,22 +174,15 @@ fn w() {
|
|
|
// dbg!(cartridge.drop_zeroed(300, 150));
|
|
|
// dbg!(cartridge.drop(250));
|
|
|
|
|
|
- let s = cartridge.spline();
|
|
|
+ let s = cartridge.monospline();
|
|
|
for d in (50..310).step_by(10) {
|
|
|
// cartridge.data_at(d);
|
|
|
let z = s.clamped_sample(100.0).unwrap_or(-999999.0);
|
|
|
let r = s.clamped_sample(d as f32).unwrap_or(-999999.0) - z;
|
|
|
println!("{} {:?}", d, r);
|
|
|
-
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
- },
|
|
|
- Err(e) => println!("{:?}",e)
|
|
|
+ }
|
|
|
+ Err(e) => println!("{:?}", e),
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
}
|