diff --git a/src/egui_app.rs b/src/egui_app.rs index 91c6d78..a818b6f 100644 --- a/src/egui_app.rs +++ b/src/egui_app.rs @@ -1,5 +1,5 @@ use crate::function::{FunctionEntry, RiemannSum, EMPTY_FUNCTION_ENTRY}; -use crate::misc::{debug_log, digits_precision, log_helper}; +use crate::misc::{debug_log, log_helper}; use crate::parsing::{process_func_str, test_func}; use const_format::formatc; @@ -602,9 +602,6 @@ impl epi::App for MathApp { } let available_width: usize = ui.available_width() as usize; - let step = (self.settings.integral_min_x - self.settings.integral_max_x).abs() - / (self.settings.integral_num as f64); - Plot::new("plot") .set_margin_fraction(Vec2::ZERO) .data_aspect(1.0) @@ -624,33 +621,7 @@ impl epi::App for MathApp { } function.update_bounds(minx_bounds, maxx_bounds, available_width); - - let (back_values, integral, derivative) = function.run(); - let func_str = function.get_func_str(); - plot_ui.line(back_values.color(Color32::RED).name(func_str)); - - if let Some(derivative_data) = derivative { - plot_ui.line( - derivative_data - .color(Color32::GREEN) - .name(function.get_derivative_str()), - ); - } - - if let Some(integral_data) = integral { - let integral_name = format!("Integral of {}", func_str); - plot_ui.bar_chart( - integral_data - .0 - .color(Color32::BLUE) - .width(step) - .name(integral_name), - ); - - digits_precision(integral_data.1, 8) - } else { - f64::NAN - } + function.display(plot_ui) }) .collect(); self.last_info = (area_list, start.elapsed()); diff --git a/src/function.rs b/src/function.rs index 3d876e6..46ee7d8 100644 --- a/src/function.rs +++ b/src/function.rs @@ -1,15 +1,14 @@ #![allow(clippy::too_many_arguments)] // Clippy, shut +use crate::function_output::FunctionOutput; #[allow(unused_imports)] use crate::misc::{debug_log, SteppedVector}; use crate::egui_app::{DEFAULT_FUNCION, DEFAULT_RIEMANN}; use crate::parsing::BackingFunction; -use eframe::egui::{ - plot::{BarChart, Line, Value, Values}, - widgets::plot::Bar, -}; +use eframe::egui::plot::PlotUi; +use eframe::egui::{plot::Value, widgets::plot::Bar}; use std::fmt::{self, Debug}; #[derive(PartialEq, Debug, Copy, Clone)] @@ -35,9 +34,7 @@ pub struct FunctionEntry { max_x: f64, pixel_width: usize, - back_cache: Option>, - integral_cache: Option<(Vec, f64)>, - derivative_cache: Option>, + output: FunctionOutput, pub(crate) integral: bool, pub(crate) derivative: bool, @@ -56,9 +53,7 @@ impl FunctionEntry { min_x: -1.0, max_x: 1.0, pixel_width: 100, - back_cache: None, - integral_cache: None, - derivative_cache: None, + output: FunctionOutput::new_empty(), integral: false, derivative: false, integral_min_x: f64::NAN, @@ -76,9 +71,7 @@ impl FunctionEntry { if func_str != self.func_str { self.func_str = func_str.clone(); self.function = BackingFunction::new(&func_str); - self.back_cache = None; - self.integral_cache = None; - self.derivative_cache = None; + self.output.invalidate_whole(); } self.derivative = derivative; @@ -91,7 +84,7 @@ impl FunctionEntry { | (integral_num != Some(self.integral_num)) | (sum != Some(self.sum)) { - self.integral_cache = None; + self.output.invalidate_integral(); self.integral_min_x = integral_min_x.expect("integral_min_x is None"); self.integral_max_x = integral_max_x.expect("integral_max_x is None"); self.integral_num = integral_num.expect("integral_num is None"); @@ -101,14 +94,14 @@ impl FunctionEntry { pub fn update_bounds(&mut self, min_x: f64, max_x: f64, pixel_width: usize) { if pixel_width != self.pixel_width { - self.back_cache = None; - self.derivative_cache = None; + self.output.invalidate_back(); + self.output.invalidate_derivative(); self.min_x = min_x; self.max_x = max_x; self.pixel_width = pixel_width; - } else if ((min_x != self.min_x) | (max_x != self.max_x)) && self.back_cache.is_some() { + } else if ((min_x != self.min_x) | (max_x != self.max_x)) && self.output.back.is_some() { let resolution: f64 = self.pixel_width as f64 / (max_x.abs() + min_x.abs()); - let back_cache = self.back_cache.as_ref().unwrap(); + let back_cache = self.output.back.as_ref().unwrap(); let x_data: SteppedVector = back_cache .iter() @@ -116,7 +109,7 @@ impl FunctionEntry { .collect::>() .into(); - self.back_cache = Some( + self.output.back = Some( (0..self.pixel_width) .map(|x| (x as f64 / resolution as f64) + min_x) .map(|x| { @@ -128,13 +121,13 @@ impl FunctionEntry { }) .collect(), ); - // assert_eq!(self.back_cache.as_ref().unwrap().len(), self.pixel_width); + // assert_eq!(self.output.back.as_ref().unwrap().len(), self.pixel_width); - if self.derivative_cache.is_some() { + if self.output.derivative.is_some() { if self.derivative { - let derivative_cache = self.derivative_cache.as_ref().unwrap(); + let derivative_cache = self.output.derivative.as_ref().unwrap(); - self.derivative_cache = Some( + self.output.derivative = Some( (0..self.pixel_width) .map(|x| (x as f64 / resolution as f64) + min_x) .map(|x| { @@ -146,14 +139,14 @@ impl FunctionEntry { }) .collect(), ); - // assert_eq!(self.derivative_cache.as_ref().unwrap().len(), self.pixel_width); + // assert_eq!(self.output.derivative.as_ref().unwrap().len(), self.pixel_width); } else { - self.derivative_cache = None; + self.output.invalidate_derivative(); } } } else { - self.back_cache = None; - self.derivative_cache = None; + self.output.invalidate_back(); + self.output.invalidate_derivative(); self.min_x = min_x; self.max_x = max_x; self.pixel_width = pixel_width; @@ -163,8 +156,8 @@ impl FunctionEntry { pub fn run_back(&mut self) -> (Vec, Option<(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() { - self.back_cache = Some( + if self.output.back.is_none() { + self.output.back = Some( (0..self.pixel_width) .map(|x| (x as f64 / resolution as f64) + self.min_x) .map(|x| Value::new(x, self.function.get(x))) @@ -172,32 +165,32 @@ impl FunctionEntry { ); } - self.back_cache.as_ref().unwrap().clone() + self.output.back.as_ref().unwrap().clone() }; let derivative_values: Option> = match self.derivative { true => { - if self.derivative_cache.is_none() { - self.derivative_cache = Some( + if self.output.derivative.is_none() { + self.output.derivative = Some( (0..self.pixel_width) .map(|x| (x as f64 / resolution as f64) + self.min_x) .map(|x| Value::new(x, self.function.derivative(x))) .collect(), ); } - Some(self.derivative_cache.as_ref().unwrap().clone()) + Some(self.output.derivative.as_ref().unwrap().clone()) } false => None, }; let integral_data = match self.integral { true => { - if self.integral_cache.is_none() { + if self.output.integral.is_none() { let (data, area) = self.integral_rectangles(); - self.integral_cache = + self.output.integral = Some((data.iter().map(|(x, y)| Bar::new(*x, *y)).collect(), area)); } - let cache = self.integral_cache.as_ref().unwrap(); + let cache = self.output.integral.as_ref().unwrap(); Some((cache.0.clone(), cache.1)) } false => None, @@ -206,21 +199,6 @@ impl FunctionEntry { (back_values, integral_data, derivative_values) } - pub fn run(&mut self) -> (Line, Option<(BarChart, f64)>, Option) { - let (back_values, integral_data_option, derivative_option) = self.run_back(); - - ( - Line::new(Values::from_values(back_values)), - if let Some(integral_data) = integral_data_option { - Some((BarChart::new(integral_data.0), integral_data.1)) - } else { - None - }, - derivative_option - .map(|derivative_data| Line::new(Values::from_values(derivative_data))), - ) - } - // Creates and does the math for creating all the rectangles under the graph fn integral_rectangles(&self) -> (Vec<(f64, f64)>, f64) { if self.integral_min_x.is_nan() { @@ -275,7 +253,7 @@ impl FunctionEntry { pub fn update_riemann(mut self, riemann: RiemannSum) -> Self { if self.sum != riemann { self.sum = riemann; - self.integral_cache = None; + self.output.invalidate_integral(); } self } @@ -309,7 +287,19 @@ impl FunctionEntry { self } - pub fn get_derivative_str(&self) -> String { self.function.get_derivative_str() } + pub fn display(&mut self, plot_ui: &mut PlotUi) -> f64 { + let (back_values, integral, derivative) = self.run_back(); + self.output.back = Some(back_values); + self.output.integral = integral; + self.output.derivative = derivative; + + self.output.display( + plot_ui, + self.get_func_str(), + &self.function.get_derivative_str(), + (self.integral_min_x - self.integral_max_x).abs() / (self.integral_num as f64), + ) + } } #[cfg(test)] diff --git a/src/function_output.rs b/src/function_output.rs new file mode 100644 index 0000000..b11780c --- /dev/null +++ b/src/function_output.rs @@ -0,0 +1,77 @@ +use eframe::{ + egui::{ + plot::{BarChart, Line, PlotUi, Value, Values}, + widgets::plot::Bar, + }, + epaint::Color32, +}; + +use crate::misc::digits_precision; + +#[derive(Clone)] +pub struct FunctionOutput { + pub(crate) back: Option>, + pub(crate) integral: Option<(Vec, f64)>, + pub(crate) derivative: Option>, +} + +impl FunctionOutput { + pub fn new( + back: Option>, integral: Option<(Vec, f64)>, derivative: Option>, + ) -> Self { + Self { + back, + integral, + derivative, + } + } + + pub fn new_empty() -> Self { + Self { + back: None, + integral: None, + derivative: None, + } + } + + pub fn invalidate_whole(&mut self) { + self.back = None; + self.integral = None; + self.derivative = None; + } + + pub fn invalidate_back(&mut self) { self.back = None; } + + pub fn invalidate_integral(&mut self) { self.integral = None; } + + pub fn invalidate_derivative(&mut self) { self.derivative = None; } + + pub fn display( + &self, plot_ui: &mut PlotUi, func_str: &str, derivative_str: &str, step: f64, + ) -> f64 { + plot_ui.line( + Line::new(Values::from_values(self.back.clone().unwrap())) + .color(Color32::RED) + .name(func_str), + ); + if let Some(derivative_data) = self.derivative.clone() { + plot_ui.line( + Line::new(Values::from_values(derivative_data)) + .color(Color32::GREEN) + .name(derivative_str), + ); + } + + if let Some(integral_data) = self.integral.clone() { + plot_ui.bar_chart( + BarChart::new(integral_data.0) + .color(Color32::BLUE) + .width(step), + ); + + digits_precision(integral_data.1, 8) + } else { + f64::NAN + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 225b30b..2314eb0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ mod egui_app; mod function; +mod function_output; mod misc; mod parsing; diff --git a/src/main.rs b/src/main.rs index 0523209..2e1bf6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ mod egui_app; mod function; +mod function_output; mod misc; mod parsing;