From 79894c4cade5166809f123a14d281d81187ffc06 Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Fri, 4 Mar 2022 14:17:12 -0500 Subject: [PATCH] nth derivative support --- src/egui_app.rs | 33 +++++++++++++++++++++++++++++++-- src/function.rs | 21 +++++++++------------ 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/egui_app.rs b/src/egui_app.rs index ad8f229..08cfb86 100644 --- a/src/egui_app.rs +++ b/src/egui_app.rs @@ -77,8 +77,9 @@ const HELP_PANEL: &str = - The 'Info' button provides information on the build currently running."; // Used in the "Functions" section of the Help window -const HELP_FUNCTION: &str = "- The 'X' button before the ∫ symbol allows you to delete the function in question. Deleting a function is prevented if only 1 function exists. -- The ∫ button (between the 'd/dx' and 'X' buttons) indicates whether estimating an integral for that function is enabled or not. +const HELP_FUNCTION: &str = "- The 'X' button before the 'O' symbol allows you to delete the function in question. Deleting a function is prevented if only 1 function exists. +- The 'O' button after the 'X' button opens a window where you can configure some settings in relation to the function in question. +- The ∫ button (between the 'O' and 'd/dx' buttons) indicates whether estimating an integral for that function is enabled or not. - The 'd/dx' button next to the function input indicates whether or not calculating the derivative is enabled or not."; // Misc help info @@ -111,6 +112,9 @@ struct AppSettings { // Stores how integrals should be displayed pub integral_display_type: IntegralDisplay, + + // List of functions whose windows are open + pub opened_functions: Vec, } impl Default for AppSettings { @@ -124,6 +128,7 @@ impl Default for AppSettings { integral_max_x: DEFAULT_MAX_X, integral_num: DEFAULT_INTEGRAL_NUM, integral_display_type: IntegralDisplay::Rectangles, + opened_functions: Vec::new(), } } } @@ -235,6 +240,30 @@ impl MathApp { // Entry for a function ui.horizontal(|ui| { ui.label("Function:"); + if ui + .add(Button::new("O")) + .on_hover_text("Open Function Settings") + .clicked() + | self.settings.opened_functions.contains(&i) + { + self.settings.opened_functions.push(i); + Window::new(function.get_func_str()) + .default_pos([200.0, 200.0]) + .resizable(false) + .collapsible(false) + .show(ctx, |ui| { + if ui + .add( + Slider::new(&mut function.nth_derivative, 0..=2) // Derivatives go insane after the value 3, probably inaccuracies in the handling of floating point numbers. more investigation needed. + .text("Derivative"), + ) + .changed() + { + function.invalidate_derivative_cache(); + } + }); + } + if ui .add(Button::new("X")) .on_hover_text("Delete Function") diff --git a/src/function.rs b/src/function.rs index 90236c0..621d145 100644 --- a/src/function.rs +++ b/src/function.rs @@ -165,10 +165,9 @@ impl FunctionEntry { Option<(Vec, Vec, f64)>, Option>, ) { + let resolution: f64 = (self.pixel_width as f64 / (self.max_x - self.min_x).abs()) as f64; let back_values: Vec = { if self.back_cache.is_none() { - let resolution: f64 = - (self.pixel_width as f64 / (self.max_x - self.min_x).abs()) as f64; self.back_cache = Some( (0..self.pixel_width) .map(|x| (x as f64 / resolution as f64) + self.min_x) @@ -183,16 +182,11 @@ impl FunctionEntry { let derivative_values: Option> = match self.derivative { true => { if self.derivative_cache.is_none() { - let back_cache = self.back_cache.as_ref().unwrap().clone(); self.derivative_cache = Some( - back_cache - .iter() - .map(|ele| { - let x = ele.x; - let (x1, x2) = (x - EPSILON, x + EPSILON); - let (y1, y2) = (self.run_func(x1), self.run_func(x2)); - let slope = (y2 - y1) / (EPSILON * 2.0); - Value::new(x, slope) + (0..self.pixel_width) + .map(|x| (x as f64 / resolution as f64) + self.min_x) + .map(|x| { + Value::new(x, self.function.derivative(x, self.nth_derivative)) }) .collect(), ); @@ -282,6 +276,8 @@ impl FunctionEntry { // Set func_str to an empty string pub fn empty_func_str(&mut self) { self.func_str = String::new(); } + pub fn get_func_str(&self) -> String { self.func_str.clone() } + // Updates riemann value and invalidates front_cache if needed pub fn update_riemann(mut self, riemann: RiemannSum) -> Self { if self.sum != riemann { @@ -297,7 +293,6 @@ impl FunctionEntry { self } - // Toggles integral pub fn integral_num(mut self, integral_num: usize) -> Self { self.integral_num = integral_num; self @@ -317,6 +312,8 @@ impl FunctionEntry { self.integral_max_x = max_x; self } + + pub fn invalidate_derivative_cache(&mut self) { self.derivative_cache = None; } } #[test]