move some logic to FunctionOutput
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
use crate::function::{FunctionEntry, RiemannSum, EMPTY_FUNCTION_ENTRY};
|
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 crate::parsing::{process_func_str, test_func};
|
||||||
|
|
||||||
use const_format::formatc;
|
use const_format::formatc;
|
||||||
@@ -602,9 +602,6 @@ impl epi::App for MathApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let available_width: usize = ui.available_width() as usize;
|
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")
|
Plot::new("plot")
|
||||||
.set_margin_fraction(Vec2::ZERO)
|
.set_margin_fraction(Vec2::ZERO)
|
||||||
.data_aspect(1.0)
|
.data_aspect(1.0)
|
||||||
@@ -624,33 +621,7 @@ impl epi::App for MathApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function.update_bounds(minx_bounds, maxx_bounds, available_width);
|
function.update_bounds(minx_bounds, maxx_bounds, available_width);
|
||||||
|
function.display(plot_ui)
|
||||||
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
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
self.last_info = (area_list, start.elapsed());
|
self.last_info = (area_list, start.elapsed());
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
#![allow(clippy::too_many_arguments)] // Clippy, shut
|
#![allow(clippy::too_many_arguments)] // Clippy, shut
|
||||||
|
|
||||||
|
use crate::function_output::FunctionOutput;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::misc::{debug_log, SteppedVector};
|
use crate::misc::{debug_log, SteppedVector};
|
||||||
|
|
||||||
use crate::egui_app::{DEFAULT_FUNCION, DEFAULT_RIEMANN};
|
use crate::egui_app::{DEFAULT_FUNCION, DEFAULT_RIEMANN};
|
||||||
use crate::parsing::BackingFunction;
|
use crate::parsing::BackingFunction;
|
||||||
|
|
||||||
use eframe::egui::{
|
use eframe::egui::plot::PlotUi;
|
||||||
plot::{BarChart, Line, Value, Values},
|
use eframe::egui::{plot::Value, widgets::plot::Bar};
|
||||||
widgets::plot::Bar,
|
|
||||||
};
|
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||||
@@ -35,9 +34,7 @@ pub struct FunctionEntry {
|
|||||||
max_x: f64,
|
max_x: f64,
|
||||||
pixel_width: usize,
|
pixel_width: usize,
|
||||||
|
|
||||||
back_cache: Option<Vec<Value>>,
|
output: FunctionOutput,
|
||||||
integral_cache: Option<(Vec<Bar>, f64)>,
|
|
||||||
derivative_cache: Option<Vec<Value>>,
|
|
||||||
|
|
||||||
pub(crate) integral: bool,
|
pub(crate) integral: bool,
|
||||||
pub(crate) derivative: bool,
|
pub(crate) derivative: bool,
|
||||||
@@ -56,9 +53,7 @@ impl FunctionEntry {
|
|||||||
min_x: -1.0,
|
min_x: -1.0,
|
||||||
max_x: 1.0,
|
max_x: 1.0,
|
||||||
pixel_width: 100,
|
pixel_width: 100,
|
||||||
back_cache: None,
|
output: FunctionOutput::new_empty(),
|
||||||
integral_cache: None,
|
|
||||||
derivative_cache: None,
|
|
||||||
integral: false,
|
integral: false,
|
||||||
derivative: false,
|
derivative: false,
|
||||||
integral_min_x: f64::NAN,
|
integral_min_x: f64::NAN,
|
||||||
@@ -76,9 +71,7 @@ impl FunctionEntry {
|
|||||||
if func_str != self.func_str {
|
if func_str != self.func_str {
|
||||||
self.func_str = func_str.clone();
|
self.func_str = func_str.clone();
|
||||||
self.function = BackingFunction::new(&func_str);
|
self.function = BackingFunction::new(&func_str);
|
||||||
self.back_cache = None;
|
self.output.invalidate_whole();
|
||||||
self.integral_cache = None;
|
|
||||||
self.derivative_cache = None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.derivative = derivative;
|
self.derivative = derivative;
|
||||||
@@ -91,7 +84,7 @@ impl FunctionEntry {
|
|||||||
| (integral_num != Some(self.integral_num))
|
| (integral_num != Some(self.integral_num))
|
||||||
| (sum != Some(self.sum))
|
| (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_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_max_x = integral_max_x.expect("integral_max_x is None");
|
||||||
self.integral_num = integral_num.expect("integral_num 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) {
|
pub fn update_bounds(&mut self, min_x: f64, max_x: f64, pixel_width: usize) {
|
||||||
if pixel_width != self.pixel_width {
|
if pixel_width != self.pixel_width {
|
||||||
self.back_cache = None;
|
self.output.invalidate_back();
|
||||||
self.derivative_cache = None;
|
self.output.invalidate_derivative();
|
||||||
self.min_x = min_x;
|
self.min_x = min_x;
|
||||||
self.max_x = max_x;
|
self.max_x = max_x;
|
||||||
self.pixel_width = pixel_width;
|
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 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
|
let x_data: SteppedVector = back_cache
|
||||||
.iter()
|
.iter()
|
||||||
@@ -116,7 +109,7 @@ impl FunctionEntry {
|
|||||||
.collect::<Vec<f64>>()
|
.collect::<Vec<f64>>()
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
self.back_cache = Some(
|
self.output.back = Some(
|
||||||
(0..self.pixel_width)
|
(0..self.pixel_width)
|
||||||
.map(|x| (x as f64 / resolution as f64) + min_x)
|
.map(|x| (x as f64 / resolution as f64) + min_x)
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
@@ -128,13 +121,13 @@ impl FunctionEntry {
|
|||||||
})
|
})
|
||||||
.collect(),
|
.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 {
|
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)
|
(0..self.pixel_width)
|
||||||
.map(|x| (x as f64 / resolution as f64) + min_x)
|
.map(|x| (x as f64 / resolution as f64) + min_x)
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
@@ -146,14 +139,14 @@ impl FunctionEntry {
|
|||||||
})
|
})
|
||||||
.collect(),
|
.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 {
|
} else {
|
||||||
self.derivative_cache = None;
|
self.output.invalidate_derivative();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.back_cache = None;
|
self.output.invalidate_back();
|
||||||
self.derivative_cache = None;
|
self.output.invalidate_derivative();
|
||||||
self.min_x = min_x;
|
self.min_x = min_x;
|
||||||
self.max_x = max_x;
|
self.max_x = max_x;
|
||||||
self.pixel_width = pixel_width;
|
self.pixel_width = pixel_width;
|
||||||
@@ -163,8 +156,8 @@ impl FunctionEntry {
|
|||||||
pub fn run_back(&mut self) -> (Vec<Value>, Option<(Vec<Bar>, f64)>, Option<Vec<Value>>) {
|
pub fn run_back(&mut self) -> (Vec<Value>, Option<(Vec<Bar>, f64)>, Option<Vec<Value>>) {
|
||||||
let resolution: f64 = (self.pixel_width as f64 / (self.max_x - self.min_x).abs()) as f64;
|
let resolution: f64 = (self.pixel_width as f64 / (self.max_x - self.min_x).abs()) as f64;
|
||||||
let back_values: Vec<Value> = {
|
let back_values: Vec<Value> = {
|
||||||
if self.back_cache.is_none() {
|
if self.output.back.is_none() {
|
||||||
self.back_cache = Some(
|
self.output.back = Some(
|
||||||
(0..self.pixel_width)
|
(0..self.pixel_width)
|
||||||
.map(|x| (x as f64 / resolution as f64) + self.min_x)
|
.map(|x| (x as f64 / resolution as f64) + self.min_x)
|
||||||
.map(|x| Value::new(x, self.function.get(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<Vec<Value>> = match self.derivative {
|
let derivative_values: Option<Vec<Value>> = match self.derivative {
|
||||||
true => {
|
true => {
|
||||||
if self.derivative_cache.is_none() {
|
if self.output.derivative.is_none() {
|
||||||
self.derivative_cache = Some(
|
self.output.derivative = Some(
|
||||||
(0..self.pixel_width)
|
(0..self.pixel_width)
|
||||||
.map(|x| (x as f64 / resolution as f64) + self.min_x)
|
.map(|x| (x as f64 / resolution as f64) + self.min_x)
|
||||||
.map(|x| Value::new(x, self.function.derivative(x)))
|
.map(|x| Value::new(x, self.function.derivative(x)))
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Some(self.derivative_cache.as_ref().unwrap().clone())
|
Some(self.output.derivative.as_ref().unwrap().clone())
|
||||||
}
|
}
|
||||||
false => None,
|
false => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let integral_data = match self.integral {
|
let integral_data = match self.integral {
|
||||||
true => {
|
true => {
|
||||||
if self.integral_cache.is_none() {
|
if self.output.integral.is_none() {
|
||||||
let (data, area) = self.integral_rectangles();
|
let (data, area) = self.integral_rectangles();
|
||||||
self.integral_cache =
|
self.output.integral =
|
||||||
Some((data.iter().map(|(x, y)| Bar::new(*x, *y)).collect(), area));
|
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))
|
Some((cache.0.clone(), cache.1))
|
||||||
}
|
}
|
||||||
false => None,
|
false => None,
|
||||||
@@ -206,21 +199,6 @@ impl FunctionEntry {
|
|||||||
(back_values, integral_data, derivative_values)
|
(back_values, integral_data, derivative_values)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) -> (Line, Option<(BarChart, f64)>, Option<Line>) {
|
|
||||||
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
|
// Creates and does the math for creating all the rectangles under the graph
|
||||||
fn integral_rectangles(&self) -> (Vec<(f64, f64)>, f64) {
|
fn integral_rectangles(&self) -> (Vec<(f64, f64)>, f64) {
|
||||||
if self.integral_min_x.is_nan() {
|
if self.integral_min_x.is_nan() {
|
||||||
@@ -275,7 +253,7 @@ impl FunctionEntry {
|
|||||||
pub fn update_riemann(mut self, riemann: RiemannSum) -> Self {
|
pub fn update_riemann(mut self, riemann: RiemannSum) -> Self {
|
||||||
if self.sum != riemann {
|
if self.sum != riemann {
|
||||||
self.sum = riemann;
|
self.sum = riemann;
|
||||||
self.integral_cache = None;
|
self.output.invalidate_integral();
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -309,7 +287,19 @@ impl FunctionEntry {
|
|||||||
self
|
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)]
|
#[cfg(test)]
|
||||||
|
|||||||
77
src/function_output.rs
Normal file
77
src/function_output.rs
Normal file
@@ -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<Vec<Value>>,
|
||||||
|
pub(crate) integral: Option<(Vec<Bar>, f64)>,
|
||||||
|
pub(crate) derivative: Option<Vec<Value>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionOutput {
|
||||||
|
pub fn new(
|
||||||
|
back: Option<Vec<Value>>, integral: Option<(Vec<Bar>, f64)>, derivative: Option<Vec<Value>>,
|
||||||
|
) -> 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
mod egui_app;
|
mod egui_app;
|
||||||
mod function;
|
mod function;
|
||||||
|
mod function_output;
|
||||||
mod misc;
|
mod misc;
|
||||||
mod parsing;
|
mod parsing;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
mod egui_app;
|
mod egui_app;
|
||||||
mod function;
|
mod function;
|
||||||
|
mod function_output;
|
||||||
mod misc;
|
mod misc;
|
||||||
mod parsing;
|
mod parsing;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user