diff --git a/lib/rust/mmscenegraph/tests/common/mod.rs b/lib/rust/mmscenegraph/tests/common/mod.rs index bf6ffbf2..14321f86 100644 --- a/lib/rust/mmscenegraph/tests/common/mod.rs +++ b/lib/rust/mmscenegraph/tests/common/mod.rs @@ -135,6 +135,17 @@ pub fn chan_data_filter_only_y(data: &[(FrameTime, Real)]) -> Vec { data.iter().map(|x| x.1 as Real).collect() } +pub fn chan_data_combine_xy( + x_values: &[FrameTime], + y_values: &[Real], +) -> Vec<(FrameTime, Real)> { + x_values + .iter() + .zip(y_values.iter()) + .map(|x| (*x.0, *x.1)) + .collect() +} + fn calculate_data_min_max_values( data: &[(FrameTime, Real)], out_x_min: &mut FrameTime, @@ -146,16 +157,24 @@ fn calculate_data_min_max_values( let x = *x as FrameTime; let y = *y as Real; - if x < *out_x_min { - *out_x_min = x; - } else if x > *out_x_max { - *out_x_max = x; + if x.is_finite() { + if x < *out_x_min { + *out_x_min = x; + } + + if x > *out_x_max { + *out_x_max = x; + } } - if y < *out_y_min { - *out_y_min = y; - } else if y > *out_y_max { - *out_y_max = y; + if y.is_finite() { + if y < *out_y_min { + *out_y_min = y; + } + + if y > *out_y_max { + *out_y_max = y; + } } } } @@ -171,16 +190,24 @@ fn calculate_control_point_min_max_values( let x = control_point.x(); let y = control_point.y(); - if x < *out_x_min { - *out_x_min = x; - } else if x > *out_x_max { - *out_x_max = x; + if x.is_finite() { + if x < *out_x_min { + *out_x_min = x; + } + + if x > *out_x_max { + *out_x_max = x; + } } - if y < *out_y_min { - *out_y_min = y; - } else if y > *out_y_max { - *out_y_max = y; + if y.is_finite() { + if y < *out_y_min { + *out_y_min = y; + } + + if y > *out_y_max { + *out_y_max = y; + } } } } @@ -730,3 +757,70 @@ pub fn save_chart_linear_n_points_regression_pop( Ok(()) } + +#[allow(dead_code)] +pub fn save_chart_curves( + data_values: &[(FrameTime, Real)], + data_velocity: &[(FrameTime, Real)], + data_acceleration: &[(FrameTime, Real)], + data_jerk: &[(FrameTime, Real)], + chart_title: &str, + chart_file_path: &OsStr, + chart_resolution: (u32, u32), +) -> Result<()> { + let root_area = BitMapBackend::new( + chart_file_path, + (chart_resolution.0, chart_resolution.1), + ) + .into_drawing_area(); + + root_area.fill(&WHITE)?; + let root_area = root_area.titled(chart_title, ("sans-serif", 60))?; + + let chart_captions = &["Values", "Velocity", "Acceleration", "Jerk"]; + let line_colors = &[BLACK, RED, GREEN, BLUE]; + let data_list = &[data_values, data_velocity, data_acceleration, data_jerk]; + + let drawing_areas = root_area.split_evenly((4, 1)); + for (i, drawing_area) in drawing_areas.iter().enumerate() { + let data = data_list[i]; + let data_count = data.len(); + + let bounds = calculate_bounds(&[data], None); + + let x_pad = 0.1; + let y_pad = (bounds.y_max - bounds.y_min) * 0.05; + let chart_min_value_x = bounds.x_min - x_pad; + let chart_max_value_x = bounds.x_max + x_pad; + let chart_min_value_y = bounds.y_min - y_pad; + let chart_max_value_y = bounds.y_max + y_pad; + + let chart_caption = chart_captions[i]; + let mut cc = ChartBuilder::on(drawing_area) + .margin(5) + .set_all_label_area_size(50) + .caption(&chart_caption, ("sans-serif", 20)) + .build_cartesian_2d( + chart_min_value_x..chart_max_value_x, + chart_min_value_y..chart_max_value_y, + )?; + + cc.configure_mesh() + .x_labels(20) + .y_labels(5) + .disable_mesh() + .x_label_formatter(&|v| format!("{:.0}", v)) + .y_label_formatter(&|v| format!("{:.3}", v)) + .draw()?; + + let line_color = line_colors[i]; + draw_line_series(&mut cc, data, &line_color, 1)?; + } + + // To avoid the IO failure being ignored silently, we manually + // call the present function + root_area.present()?; + debug!("Chart saved to: {:?}", chart_file_path); + + Ok(()) +} diff --git a/lib/rust/mmscenegraph/tests/curve_derivatives.rs b/lib/rust/mmscenegraph/tests/curve_derivatives.rs index e8dc25f2..a2c895a2 100644 --- a/lib/rust/mmscenegraph/tests/curve_derivatives.rs +++ b/lib/rust/mmscenegraph/tests/curve_derivatives.rs @@ -27,6 +27,18 @@ mod common; use anyhow::Result; use approx::assert_relative_eq; +use crate::common::chan_data_combine_xy; +use crate::common::chan_data_filter_only_x; +use crate::common::chan_data_filter_only_y; +use crate::common::construct_input_file_path; +use crate::common::construct_output_file_path; +use crate::common::find_data_dir; +use crate::common::print_chan_data; +use crate::common::read_chan_file; +use crate::common::save_chart_curves; +use crate::common::save_chart_linear_regression; +use crate::common::CHART_RESOLUTION; + use mmscenegraph_rust::curve::derivatives::allocate_derivatives_order_3; use mmscenegraph_rust::curve::derivatives::calculate_derivatives_order_3; @@ -52,18 +64,22 @@ fn print_arrays(velocity: &[f64], acceleration: &[f64], jerk: &[f64]) { #[test] fn calculate_derivatives1() -> Result<()> { - // Constant speed, upwards. - let times = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0]; - let heights = vec![1.0, 1.1, 1.2, 1.3, 1.4, 1.5]; + let chart_title = "calculate_derivatives1"; + let chart_resolution = CHART_RESOLUTION; + + let data_dir = find_data_dir()?; + let out_file_path = + construct_output_file_path(&data_dir, "calculate_derivatives1.png")?; - // let (velocity, acceleration, jerk) = - // calculate_derivatives(×, &heights)?; + // Constant speed, upwards. + let x_values = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0]; + let y_values = vec![1.0, 1.1, 1.2, 1.3, 1.4, 1.5]; let (mut velocity, mut acceleration, mut jerk) = - allocate_derivatives_order_3(times.len())?; + allocate_derivatives_order_3(x_values.len())?; calculate_derivatives_order_3( - ×, - &heights, + &x_values, + &y_values, &mut velocity, &mut acceleration, &mut jerk, @@ -71,6 +87,21 @@ fn calculate_derivatives1() -> Result<()> { print_arrays(&velocity, &acceleration, &jerk); + let data = chan_data_combine_xy(&x_values, &y_values); + let data_velocity = chan_data_combine_xy(&x_values, &velocity); + let data_acceleration = chan_data_combine_xy(&x_values, &acceleration); + let data_jerk = chan_data_combine_xy(&x_values, &jerk); + + save_chart_curves( + &data, + &data_velocity, + &data_acceleration, + &data_jerk, + chart_title, + &out_file_path.as_os_str(), + chart_resolution, + )?; + assert_eq!(velocity.len(), 6); assert_eq!(acceleration.len(), 6); assert_eq!(jerk.len(), 6); @@ -101,18 +132,22 @@ fn calculate_derivatives1() -> Result<()> { #[test] fn calculate_derivatives2() -> Result<()> { - // Constant velocity, downwards. - let times = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0]; - let heights = vec![-1.0, -1.1, -1.2, -1.3, -1.4, -1.5]; + let chart_title = "calculate_derivatives2"; + let chart_resolution = CHART_RESOLUTION; + + let data_dir = find_data_dir()?; + let out_file_path = + construct_output_file_path(&data_dir, "calculate_derivatives2.png")?; - // let (velocity, acceleration, jerk) = - // calculate_derivatives(×, &heights)?; + // Constant velocity, downwards. + let x_values = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0]; + let y_values = vec![-1.0, -1.1, -1.2, -1.3, -1.4, -1.5]; let (mut velocity, mut acceleration, mut jerk) = - allocate_derivatives_order_3(times.len())?; + allocate_derivatives_order_3(x_values.len())?; calculate_derivatives_order_3( - ×, - &heights, + &x_values, + &y_values, &mut velocity, &mut acceleration, &mut jerk, @@ -120,6 +155,21 @@ fn calculate_derivatives2() -> Result<()> { print_arrays(&velocity, &acceleration, &jerk); + let data = chan_data_combine_xy(&x_values, &y_values); + let data_velocity = chan_data_combine_xy(&x_values, &velocity); + let data_acceleration = chan_data_combine_xy(&x_values, &acceleration); + let data_jerk = chan_data_combine_xy(&x_values, &jerk); + + save_chart_curves( + &data, + &data_velocity, + &data_acceleration, + &data_jerk, + chart_title, + &out_file_path.as_os_str(), + chart_resolution, + )?; + assert_eq!(velocity.len(), 6); assert_eq!(acceleration.len(), 6); assert_eq!(jerk.len(), 6); @@ -150,15 +200,22 @@ fn calculate_derivatives2() -> Result<()> { #[test] fn calculate_derivatives3() -> Result<()> { + let chart_title = "calculate_derivatives3"; + let chart_resolution = CHART_RESOLUTION; + + let data_dir = find_data_dir()?; + let out_file_path = + construct_output_file_path(&data_dir, "calculate_derivatives3.png")?; + // Variable velocity. - let times = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0]; - let heights = vec![1.0, 1.1, 1.25, 1.5, 2.0, 4.0]; + let x_values = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0]; + let y_values = vec![1.0, 1.1, 1.25, 1.5, 2.0, 4.0]; let (mut velocity, mut acceleration, mut jerk) = - allocate_derivatives_order_3(times.len())?; + allocate_derivatives_order_3(x_values.len())?; calculate_derivatives_order_3( - ×, - &heights, + &x_values, + &y_values, &mut velocity, &mut acceleration, &mut jerk, @@ -166,6 +223,21 @@ fn calculate_derivatives3() -> Result<()> { print_arrays(&velocity, &acceleration, &jerk); + let data = chan_data_combine_xy(&x_values, &y_values); + let data_velocity = chan_data_combine_xy(&x_values, &velocity); + let data_acceleration = chan_data_combine_xy(&x_values, &acceleration); + let data_jerk = chan_data_combine_xy(&x_values, &jerk); + + save_chart_curves( + &data, + &data_velocity, + &data_acceleration, + &data_jerk, + chart_title, + &out_file_path.as_os_str(), + chart_resolution, + )?; + assert_eq!(velocity.len(), 6); assert_eq!(acceleration.len(), 6); assert_eq!(jerk.len(), 6); @@ -182,14 +254,21 @@ fn calculate_derivatives3() -> Result<()> { #[test] fn calculate_derivatives4() -> Result<()> { - let times = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; - let heights = vec![0.0, 1.0, 4.0, 9.0, 16.0, 25.0, 36.0]; // f(x) = x^2 + let chart_title = "calculate_derivatives4"; + let chart_resolution = CHART_RESOLUTION; + + let data_dir = find_data_dir()?; + let out_file_path = + construct_output_file_path(&data_dir, "calculate_derivatives4.png")?; + + let x_values = vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; + let y_values = vec![0.0, 1.0, 4.0, 9.0, 16.0, 25.0, 36.0]; // f(x) = x^2 let (mut velocity, mut acceleration, mut jerk) = - allocate_derivatives_order_3(times.len())?; + allocate_derivatives_order_3(x_values.len())?; calculate_derivatives_order_3( - ×, - &heights, + &x_values, + &y_values, &mut velocity, &mut acceleration, &mut jerk, @@ -197,6 +276,21 @@ fn calculate_derivatives4() -> Result<()> { print_arrays(&velocity, &acceleration, &jerk); + let data = chan_data_combine_xy(&x_values, &y_values); + let data_velocity = chan_data_combine_xy(&x_values, &velocity); + let data_acceleration = chan_data_combine_xy(&x_values, &acceleration); + let data_jerk = chan_data_combine_xy(&x_values, &jerk); + + save_chart_curves( + &data, + &data_velocity, + &data_acceleration, + &data_jerk, + chart_title, + &out_file_path.as_os_str(), + chart_resolution, + )?; + assert_eq!(velocity.len(), 7); assert_eq!(acceleration.len(), 7); assert_eq!(jerk.len(), 7); @@ -228,3 +322,426 @@ fn calculate_derivatives4() -> Result<()> { Ok(()) } + +#[test] +fn calculate_derivatives_identity_pop1() -> Result<()> { + let chart_title = "derivatives_identity_pop1"; + let chart_resolution = CHART_RESOLUTION; + + let data_dir = find_data_dir()?; + let in_file_path = + construct_input_file_path(&data_dir, "identity_pop1.chan")?; + let out_file_path = + construct_output_file_path(&data_dir, "derivatives_identity_pop1.png")?; + + let data = read_chan_file(&in_file_path.as_os_str())?; + // print_chan_data(&data); + let x_values = chan_data_filter_only_x(&data); + let y_values = chan_data_filter_only_y(&data); + + let (mut velocity, mut acceleration, mut jerk) = + allocate_derivatives_order_3(x_values.len())?; + calculate_derivatives_order_3( + &x_values, + &y_values, + &mut velocity, + &mut acceleration, + &mut jerk, + )?; + + print_arrays(&velocity, &acceleration, &jerk); + + let data_velocity = chan_data_combine_xy(&x_values, &velocity); + let data_acceleration = chan_data_combine_xy(&x_values, &acceleration); + let data_jerk = chan_data_combine_xy(&x_values, &jerk); + + save_chart_curves( + &data, + &data_velocity, + &data_acceleration, + &data_jerk, + chart_title, + &out_file_path.as_os_str(), + chart_resolution, + )?; + + Ok(()) +} + +#[test] +fn calculate_derivatives_identity_pop2() -> Result<()> { + let chart_title = "derivatives_identity_pop2"; + let chart_resolution = CHART_RESOLUTION; + + let data_dir = find_data_dir()?; + let in_file_path = + construct_input_file_path(&data_dir, "identity_pop2.chan")?; + let out_file_path = + construct_output_file_path(&data_dir, "derivatives_identity_pop2.png")?; + + let data = read_chan_file(&in_file_path.as_os_str())?; + // print_chan_data(&data); + let x_values = chan_data_filter_only_x(&data); + let y_values = chan_data_filter_only_y(&data); + + let (mut velocity, mut acceleration, mut jerk) = + allocate_derivatives_order_3(x_values.len())?; + calculate_derivatives_order_3( + &x_values, + &y_values, + &mut velocity, + &mut acceleration, + &mut jerk, + )?; + + print_arrays(&velocity, &acceleration, &jerk); + + let data_velocity = chan_data_combine_xy(&x_values, &velocity); + let data_acceleration = chan_data_combine_xy(&x_values, &acceleration); + let data_jerk = chan_data_combine_xy(&x_values, &jerk); + + save_chart_curves( + &data, + &data_velocity, + &data_acceleration, + &data_jerk, + chart_title, + &out_file_path.as_os_str(), + chart_resolution, + )?; + + Ok(()) +} + +#[test] +fn calculate_derivatives_identity_pop3() -> Result<()> { + let chart_title = "derivatives_identity_pop3"; + let chart_resolution = CHART_RESOLUTION; + + let data_dir = find_data_dir()?; + let in_file_path = + construct_input_file_path(&data_dir, "identity_pop3.chan")?; + let out_file_path = + construct_output_file_path(&data_dir, "derivatives_identity_pop3.png")?; + + let data = read_chan_file(&in_file_path.as_os_str())?; + // print_chan_data(&data); + let x_values = chan_data_filter_only_x(&data); + let y_values = chan_data_filter_only_y(&data); + + let (mut velocity, mut acceleration, mut jerk) = + allocate_derivatives_order_3(x_values.len())?; + calculate_derivatives_order_3( + &x_values, + &y_values, + &mut velocity, + &mut acceleration, + &mut jerk, + )?; + + print_arrays(&velocity, &acceleration, &jerk); + + let data_velocity = chan_data_combine_xy(&x_values, &velocity); + let data_acceleration = chan_data_combine_xy(&x_values, &acceleration); + let data_jerk = chan_data_combine_xy(&x_values, &jerk); + + save_chart_curves( + &data, + &data_velocity, + &data_acceleration, + &data_jerk, + chart_title, + &out_file_path.as_os_str(), + chart_resolution, + )?; + + Ok(()) +} + +#[test] +fn calculate_derivatives_identity_pop4() -> Result<()> { + let chart_title = "derivatives_identity_pop4"; + let chart_resolution = CHART_RESOLUTION; + + let data_dir = find_data_dir()?; + let in_file_path = + construct_input_file_path(&data_dir, "identity_pop4.chan")?; + let out_file_path = + construct_output_file_path(&data_dir, "derivatives_identity_pop4.png")?; + + let data = read_chan_file(&in_file_path.as_os_str())?; + // print_chan_data(&data); + let x_values = chan_data_filter_only_x(&data); + let y_values = chan_data_filter_only_y(&data); + + let (mut velocity, mut acceleration, mut jerk) = + allocate_derivatives_order_3(x_values.len())?; + calculate_derivatives_order_3( + &x_values, + &y_values, + &mut velocity, + &mut acceleration, + &mut jerk, + )?; + + print_arrays(&velocity, &acceleration, &jerk); + + let data_velocity = chan_data_combine_xy(&x_values, &velocity); + let data_acceleration = chan_data_combine_xy(&x_values, &acceleration); + let data_jerk = chan_data_combine_xy(&x_values, &jerk); + + save_chart_curves( + &data, + &data_velocity, + &data_acceleration, + &data_jerk, + chart_title, + &out_file_path.as_os_str(), + chart_resolution, + )?; + + Ok(()) +} + +#[test] +fn calculate_derivatives_bounce_5_up_down_raw() -> Result<()> { + let chart_title = "derivatives_bounce_5_up_down_raw"; + let chart_resolution = CHART_RESOLUTION; + + let data_dir = find_data_dir()?; + let in_file_path = + construct_input_file_path(&data_dir, "bounce_5_up_down_raw.chan")?; + let out_file_path = construct_output_file_path( + &data_dir, + "derivatives_bounce_5_up_down_raw.png", + )?; + + let data = read_chan_file(&in_file_path.as_os_str())?; + // print_chan_data(&data); + let x_values = chan_data_filter_only_x(&data); + let y_values = chan_data_filter_only_y(&data); + + let (mut velocity, mut acceleration, mut jerk) = + allocate_derivatives_order_3(x_values.len())?; + calculate_derivatives_order_3( + &x_values, + &y_values, + &mut velocity, + &mut acceleration, + &mut jerk, + )?; + + print_arrays(&velocity, &acceleration, &jerk); + + let data_velocity = chan_data_combine_xy(&x_values, &velocity); + let data_acceleration = chan_data_combine_xy(&x_values, &acceleration); + let data_jerk = chan_data_combine_xy(&x_values, &jerk); + + save_chart_curves( + &data, + &data_velocity, + &data_acceleration, + &data_jerk, + chart_title, + &out_file_path.as_os_str(), + chart_resolution, + )?; + + Ok(()) +} + +#[test] +fn calculate_derivatives_bounce_5_up_down_variance1() -> Result<()> { + let chart_title = "derivatives_bounce_5_up_down_variance1"; + let chart_resolution = CHART_RESOLUTION; + + let data_dir = find_data_dir()?; + let in_file_path = construct_input_file_path( + &data_dir, + "bounce_5_up_down_variance1.chan", + )?; + let out_file_path = construct_output_file_path( + &data_dir, + "derivatives_bounce_5_up_down_variance1.png", + )?; + + let data = read_chan_file(&in_file_path.as_os_str())?; + // print_chan_data(&data); + let x_values = chan_data_filter_only_x(&data); + let y_values = chan_data_filter_only_y(&data); + + let (mut velocity, mut acceleration, mut jerk) = + allocate_derivatives_order_3(x_values.len())?; + calculate_derivatives_order_3( + &x_values, + &y_values, + &mut velocity, + &mut acceleration, + &mut jerk, + )?; + + print_arrays(&velocity, &acceleration, &jerk); + + let data_velocity = chan_data_combine_xy(&x_values, &velocity); + let data_acceleration = chan_data_combine_xy(&x_values, &acceleration); + let data_jerk = chan_data_combine_xy(&x_values, &jerk); + + save_chart_curves( + &data, + &data_velocity, + &data_acceleration, + &data_jerk, + chart_title, + &out_file_path.as_os_str(), + chart_resolution, + )?; + + Ok(()) +} + +#[test] +fn calculate_derivatives_bounce_5_up_down_variance2() -> Result<()> { + let chart_title = "derivatives_bounce_5_up_down_variance2"; + let chart_resolution = CHART_RESOLUTION; + + let data_dir = find_data_dir()?; + let in_file_path = construct_input_file_path( + &data_dir, + "bounce_5_up_down_variance2.chan", + )?; + let out_file_path = construct_output_file_path( + &data_dir, + "derivatives_bounce_5_up_down_variance2.png", + )?; + + let data = read_chan_file(&in_file_path.as_os_str())?; + // print_chan_data(&data); + let x_values = chan_data_filter_only_x(&data); + let y_values = chan_data_filter_only_y(&data); + + let (mut velocity, mut acceleration, mut jerk) = + allocate_derivatives_order_3(x_values.len())?; + calculate_derivatives_order_3( + &x_values, + &y_values, + &mut velocity, + &mut acceleration, + &mut jerk, + )?; + + print_arrays(&velocity, &acceleration, &jerk); + + let data_velocity = chan_data_combine_xy(&x_values, &velocity); + let data_acceleration = chan_data_combine_xy(&x_values, &acceleration); + let data_jerk = chan_data_combine_xy(&x_values, &jerk); + + save_chart_curves( + &data, + &data_velocity, + &data_acceleration, + &data_jerk, + chart_title, + &out_file_path.as_os_str(), + chart_resolution, + )?; + + Ok(()) +} + +#[test] +fn calculate_derivatives_bounce_5_up_down_variance3() -> Result<()> { + let chart_title = "derivatives_bounce_5_up_down_variance3"; + let chart_resolution = CHART_RESOLUTION; + + let data_dir = find_data_dir()?; + let in_file_path = construct_input_file_path( + &data_dir, + "bounce_5_up_down_variance3.chan", + )?; + let out_file_path = construct_output_file_path( + &data_dir, + "derivatives_bounce_5_up_down_variance3.png", + )?; + + let data = read_chan_file(&in_file_path.as_os_str())?; + // print_chan_data(&data); + let x_values = chan_data_filter_only_x(&data); + let y_values = chan_data_filter_only_y(&data); + + let (mut velocity, mut acceleration, mut jerk) = + allocate_derivatives_order_3(x_values.len())?; + calculate_derivatives_order_3( + &x_values, + &y_values, + &mut velocity, + &mut acceleration, + &mut jerk, + )?; + + print_arrays(&velocity, &acceleration, &jerk); + + let data_velocity = chan_data_combine_xy(&x_values, &velocity); + let data_acceleration = chan_data_combine_xy(&x_values, &acceleration); + let data_jerk = chan_data_combine_xy(&x_values, &jerk); + + save_chart_curves( + &data, + &data_velocity, + &data_acceleration, + &data_jerk, + chart_title, + &out_file_path.as_os_str(), + chart_resolution, + )?; + + Ok(()) +} + +#[test] +fn calculate_derivatives_bounce_5_up_down_variance4() -> Result<()> { + let chart_title = "derivatives_bounce_5_up_down_variance4"; + let chart_resolution = CHART_RESOLUTION; + + let data_dir = find_data_dir()?; + let in_file_path = construct_input_file_path( + &data_dir, + "bounce_5_up_down_variance4.chan", + )?; + let out_file_path = construct_output_file_path( + &data_dir, + "derivatives_bounce_5_up_down_variance4.png", + )?; + + let data = read_chan_file(&in_file_path.as_os_str())?; + // print_chan_data(&data); + let x_values = chan_data_filter_only_x(&data); + let y_values = chan_data_filter_only_y(&data); + + let (mut velocity, mut acceleration, mut jerk) = + allocate_derivatives_order_3(x_values.len())?; + calculate_derivatives_order_3( + &x_values, + &y_values, + &mut velocity, + &mut acceleration, + &mut jerk, + )?; + + print_arrays(&velocity, &acceleration, &jerk); + + let data_velocity = chan_data_combine_xy(&x_values, &velocity); + let data_acceleration = chan_data_combine_xy(&x_values, &acceleration); + let data_jerk = chan_data_combine_xy(&x_values, &jerk); + + save_chart_curves( + &data, + &data_velocity, + &data_acceleration, + &data_jerk, + chart_title, + &out_file_path.as_os_str(), + chart_resolution, + )?; + + Ok(()) +} diff --git a/lib/rust/mmscenegraph/tests/data/calculate_derivatives1.png b/lib/rust/mmscenegraph/tests/data/calculate_derivatives1.png new file mode 100644 index 00000000..bbeaf21b Binary files /dev/null and b/lib/rust/mmscenegraph/tests/data/calculate_derivatives1.png differ diff --git a/lib/rust/mmscenegraph/tests/data/calculate_derivatives2.png b/lib/rust/mmscenegraph/tests/data/calculate_derivatives2.png new file mode 100644 index 00000000..dd87cc6b Binary files /dev/null and b/lib/rust/mmscenegraph/tests/data/calculate_derivatives2.png differ diff --git a/lib/rust/mmscenegraph/tests/data/calculate_derivatives3.png b/lib/rust/mmscenegraph/tests/data/calculate_derivatives3.png new file mode 100644 index 00000000..7cabb025 Binary files /dev/null and b/lib/rust/mmscenegraph/tests/data/calculate_derivatives3.png differ diff --git a/lib/rust/mmscenegraph/tests/data/calculate_derivatives4.png b/lib/rust/mmscenegraph/tests/data/calculate_derivatives4.png new file mode 100644 index 00000000..63450c30 Binary files /dev/null and b/lib/rust/mmscenegraph/tests/data/calculate_derivatives4.png differ diff --git a/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_raw.png b/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_raw.png new file mode 100644 index 00000000..8a0ee2a1 Binary files /dev/null and b/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_raw.png differ diff --git a/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_variance1.png b/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_variance1.png new file mode 100644 index 00000000..31c4f597 Binary files /dev/null and b/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_variance1.png differ diff --git a/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_variance2.png b/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_variance2.png new file mode 100644 index 00000000..cd7fafd3 Binary files /dev/null and b/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_variance2.png differ diff --git a/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_variance3.png b/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_variance3.png new file mode 100644 index 00000000..7606b5c2 Binary files /dev/null and b/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_variance3.png differ diff --git a/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_variance4.png b/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_variance4.png new file mode 100644 index 00000000..bafbb1db Binary files /dev/null and b/lib/rust/mmscenegraph/tests/data/derivatives_bounce_5_up_down_variance4.png differ diff --git a/lib/rust/mmscenegraph/tests/data/derivatives_identity_pop1.png b/lib/rust/mmscenegraph/tests/data/derivatives_identity_pop1.png new file mode 100644 index 00000000..7ea77f72 Binary files /dev/null and b/lib/rust/mmscenegraph/tests/data/derivatives_identity_pop1.png differ diff --git a/lib/rust/mmscenegraph/tests/data/derivatives_identity_pop2.png b/lib/rust/mmscenegraph/tests/data/derivatives_identity_pop2.png new file mode 100644 index 00000000..1075783f Binary files /dev/null and b/lib/rust/mmscenegraph/tests/data/derivatives_identity_pop2.png differ diff --git a/lib/rust/mmscenegraph/tests/data/derivatives_identity_pop3.png b/lib/rust/mmscenegraph/tests/data/derivatives_identity_pop3.png new file mode 100644 index 00000000..3193925c Binary files /dev/null and b/lib/rust/mmscenegraph/tests/data/derivatives_identity_pop3.png differ diff --git a/lib/rust/mmscenegraph/tests/data/derivatives_identity_pop4.png b/lib/rust/mmscenegraph/tests/data/derivatives_identity_pop4.png new file mode 100644 index 00000000..db2a76c1 Binary files /dev/null and b/lib/rust/mmscenegraph/tests/data/derivatives_identity_pop4.png differ