refactor handling of {min,max}_x

This commit is contained in:
Simon Gardling
2022-05-16 10:23:08 -04:00
parent 54c0703946
commit cfd245f82c
3 changed files with 35 additions and 28 deletions

View File

@@ -41,10 +41,6 @@ pub struct FunctionEntry {
/// Stores a function string (that hasn't been processed via `process_func_str`) to display to the user /// Stores a function string (that hasn't been processed via `process_func_str`) to display to the user
raw_func_str: String, raw_func_str: String,
/// Minimum and Maximum values of what do display
min_x: f64,
max_x: f64,
/// If calculating/displayingintegrals are enabled /// If calculating/displayingintegrals are enabled
pub integral: bool, pub integral: bool,
@@ -127,8 +123,6 @@ impl FunctionEntry {
pub const EMPTY: FunctionEntry = FunctionEntry { pub const EMPTY: FunctionEntry = FunctionEntry {
function: BackingFunction::EMPTY, function: BackingFunction::EMPTY,
raw_func_str: String::new(), raw_func_str: String::new(),
min_x: -1.0,
max_x: 1.0,
integral: false, integral: false,
derivative: false, derivative: false,
nth_derviative: false, nth_derviative: false,
@@ -249,19 +243,20 @@ impl FunctionEntry {
} }
/// Helps with processing newton's method depending on level of derivative /// Helps with processing newton's method depending on level of derivative
fn newtons_method_helper(&self, threshold: &f64, derivative_level: usize) -> Vec<Value> { fn newtons_method_helper(
let range = self.min_x..self.max_x; &self, threshold: &f64, derivative_level: usize, range: &std::ops::Range<f64>,
) -> Vec<Value> {
let newtons_method_output: Vec<f64> = match derivative_level { let newtons_method_output: Vec<f64> = match derivative_level {
0 => newtons_method_helper( 0 => newtons_method_helper(
threshold, threshold,
&range, range,
self.back_data.as_slice(), self.back_data.as_slice(),
&|x: f64| self.function.get(x), &|x: f64| self.function.get(x),
&|x: f64| self.function.get_derivative_1(x), &|x: f64| self.function.get_derivative_1(x),
), ),
1 => newtons_method_helper( 1 => newtons_method_helper(
threshold, threshold,
&range, range,
self.derivative_data.as_slice(), self.derivative_data.as_slice(),
&|x: f64| self.function.get_derivative_1(x), &|x: f64| self.function.get_derivative_1(x),
&|x: f64| self.function.get_derivative_2(x), &|x: f64| self.function.get_derivative_2(x),
@@ -276,7 +271,8 @@ impl FunctionEntry {
/// Does the calculations and stores results in `self` /// Does the calculations and stores results in `self`
pub fn calculate( pub fn calculate(
&mut self, min_x: &f64, max_x: &f64, width_changed: bool, settings: &AppSettings, &mut self, min_x: &f64, max_x: &f64, width_changed: bool, min_max_changed: bool,
settings: &AppSettings,
) { ) {
if self.test_result.is_some() { if self.test_result.is_some() {
return; return;
@@ -293,12 +289,8 @@ impl FunctionEntry {
} }
let mut partial_regen = false; let mut partial_regen = false;
let min_max_changed = (min_x != &self.min_x) | (max_x != &self.max_x);
let derivative_required = settings.do_extrema | self.derivative; let derivative_required = settings.do_extrema | self.derivative;
self.min_x = *min_x;
self.max_x = *max_x;
if width_changed { if width_changed {
self.invalidate_back(); self.invalidate_back();
self.invalidate_derivative(); self.invalidate_derivative();
@@ -425,15 +417,16 @@ impl FunctionEntry {
} }
let threshold: f64 = resolution / 2.0; let threshold: f64 = resolution / 2.0;
let x_range = settings.min_x..settings.max_x;
// Calculates extrema // Calculates extrema
if settings.do_extrema && (min_max_changed | self.extrema_data.is_empty()) { if settings.do_extrema && (min_max_changed | self.extrema_data.is_empty()) {
self.extrema_data = self.newtons_method_helper(&threshold, 1); self.extrema_data = self.newtons_method_helper(&threshold, 1, &x_range);
} }
// Calculates roots // Calculates roots
if settings.do_roots && (min_max_changed | self.root_data.is_empty()) { if settings.do_roots && (min_max_changed | self.root_data.is_empty()) {
self.root_data = self.newtons_method_helper(&threshold, 0); self.root_data = self.newtons_method_helper(&threshold, 0, &x_range);
} }
} }
@@ -450,7 +443,7 @@ impl FunctionEntry {
let step = (settings.integral_min_x - settings.integral_max_x).abs() let step = (settings.integral_min_x - settings.integral_max_x).abs()
/ (settings.integral_num as f64); / (settings.integral_num as f64);
let resolution = (self.min_x - self.max_x).abs() / (settings.plot_width as f64); let resolution = (settings.min_x - settings.max_x).abs() / (settings.plot_width as f64);
// Plot back data // Plot back data
if !self.back_data.is_empty() { if !self.back_data.is_empty() {
@@ -566,7 +559,7 @@ impl FunctionEntry {
derivative_target: Vec<(f64, f64)>, area_target: f64, min_x: f64, max_x: f64, derivative_target: Vec<(f64, f64)>, area_target: f64, min_x: f64, max_x: f64,
) { ) {
{ {
self.calculate(&min_x, &max_x, true, &settings); self.calculate(&min_x, &max_x, true, true, &settings);
assert!(!self.back_data.is_empty()); assert!(!self.back_data.is_empty());
assert_eq!(self.back_data.len(), settings.plot_width + 1); assert_eq!(self.back_data.len(), settings.plot_width + 1);
let back_vec_tuple = self.back_data.to_tuple(); let back_vec_tuple = self.back_data.to_tuple();
@@ -586,7 +579,7 @@ impl FunctionEntry {
} }
{ {
self.calculate(&(min_x + 1.0), &(max_x + 1.0), true, &settings); self.calculate(&(min_x + 1.0), &(max_x + 1.0), true, true, &settings);
assert_eq!( assert_eq!(
self.derivative_data self.derivative_data
@@ -626,7 +619,7 @@ impl FunctionEntry {
} }
{ {
self.calculate(&(min_x - 1.0), &(max_x - 1.0), true, &settings); self.calculate(&(min_x - 1.0), &(max_x - 1.0), true, true, &settings);
assert_eq!( assert_eq!(
self.derivative_data self.derivative_data
@@ -682,7 +675,7 @@ impl FunctionEntry {
assert!(self.extrema_data.is_empty()); assert!(self.extrema_data.is_empty());
assert!(self.derivative_data.is_empty()); assert!(self.derivative_data.is_empty());
self.calculate(&min_x, &max_x, true, &settings); self.calculate(&min_x, &max_x, true, true, &settings);
assert!(!self.back_data.is_empty()); assert!(!self.back_data.is_empty());
assert!(self.integral_data.is_none()); assert!(self.integral_data.is_none());

View File

@@ -29,6 +29,10 @@ pub struct AppSettings {
/// Max value for calculating an /// Max value for calculating an
pub integral_max_x: f64, pub integral_max_x: f64,
pub min_x: f64,
pub max_x: f64,
/// Stores whether or not integral settings have changed /// Stores whether or not integral settings have changed
pub integral_changed: bool, pub integral_changed: bool,
@@ -52,6 +56,8 @@ impl const Default for AppSettings {
riemann_sum: DEFAULT_RIEMANN, riemann_sum: DEFAULT_RIEMANN,
integral_min_x: DEFAULT_MIN_X, integral_min_x: DEFAULT_MIN_X,
integral_max_x: DEFAULT_MAX_X, integral_max_x: DEFAULT_MAX_X,
min_x: 0.0,
max_x: 0.0,
integral_changed: true, integral_changed: true,
integral_num: DEFAULT_INTEGRAL_NUM, integral_num: DEFAULT_INTEGRAL_NUM,
do_extrema: true, do_extrema: true,
@@ -577,14 +583,19 @@ impl App for MathApp {
.legend(egui::plot::Legend::default()) .legend(egui::plot::Legend::default())
.show(ui, |plot_ui| { .show(ui, |plot_ui| {
let bounds = plot_ui.plot_bounds(); let bounds = plot_ui.plot_bounds();
let minx_bounds: f64 = bounds.min()[0]; let min_x: f64 = bounds.min()[0];
let maxx_bounds: f64 = bounds.max()[0]; let max_x: f64 = bounds.max()[0];
let min_max_changed =
(min_x != self.settings.min_x) | (max_x != self.settings.max_x);
self.settings.min_x = min_x;
self.settings.max_x = max_x;
dyn_mut_iter(self.functions.get_entries_mut()).for_each(|(_, function)| { dyn_mut_iter(self.functions.get_entries_mut()).for_each(|(_, function)| {
function.calculate( function.calculate(
&minx_bounds, &min_x,
&maxx_bounds, &max_x,
width_changed, width_changed,
min_max_changed,
&self.settings, &self.settings,
) )
}); });

View File

@@ -1,12 +1,15 @@
use ytbn_graphing_software::{AppSettings, FunctionEntry, Riemann}; use ytbn_graphing_software::{AppSettings, FunctionEntry, Riemann};
fn app_settings_constructor( fn app_settings_constructor(
sum: Riemann, integral_min_x: f64, integral_max_x: f64, pixel_width: usize, integral_num: usize, sum: Riemann, integral_min_x: f64, integral_max_x: f64, pixel_width: usize,
integral_num: usize, min_x: f64, max_x: f64,
) -> AppSettings { ) -> AppSettings {
AppSettings { AppSettings {
riemann_sum: sum, riemann_sum: sum,
integral_min_x, integral_min_x,
integral_max_x, integral_max_x,
min_x,
max_x,
integral_changed: true, integral_changed: true,
integral_num, integral_num,
do_extrema: false, do_extrema: false,
@@ -44,7 +47,7 @@ static DERIVATIVE_TARGET: [(f64, f64); 11] = [
]; ];
fn do_test(sum: Riemann, area_target: f64) { fn do_test(sum: Riemann, area_target: f64) {
let settings = app_settings_constructor(sum, -1.0, 1.0, 10, 10); let settings = app_settings_constructor(sum, -1.0, 1.0, 10, 10, -1.0, 1.0);
let mut function = FunctionEntry::EMPTY; let mut function = FunctionEntry::EMPTY;
function.update_string("x^2"); function.update_string("x^2");