diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/function_cache.rs | 32 | ||||
| -rw-r--r-- | src/main.rs | 75 | ||||
| -rw-r--r-- | src/math/complex.rs | 16 | ||||
| -rw-r--r-- | src/math/expression.rs | 3 | ||||
| -rw-r--r-- | src/math/function.rs | 2 | ||||
| -rw-r--r-- | src/math/operation.rs | 2 |
6 files changed, 91 insertions, 39 deletions
diff --git a/src/function_cache.rs b/src/function_cache.rs new file mode 100644 index 0000000..d4beb16 --- /dev/null +++ b/src/function_cache.rs @@ -0,0 +1,32 @@ +use std::collections::HashMap; + +use crate::math::{ + complex::Complex, context::Context, expression_function::ExpressionFunction, + function::{FunctionArgument, Function}, +}; + +#[derive(Default)] +pub struct FunctionCache { + func: ExpressionFunction, + cache: HashMap<Complex, Complex>, +} + +impl FunctionCache { + pub fn new(func: ExpressionFunction) -> Self { + Self { + func, + cache: HashMap::new(), + } + } + + pub fn eval(&mut self, x: Complex, ctx: &Context) -> Complex { + if self.cache.contains_key(&x) { + *self.cache.get(&x).unwrap() + } else { + let fargs = FunctionArgument::from_values(vec![x]); + let v = self.func.eval(&fargs, ctx).unwrap(); + self.cache.insert(x, v); + v + } + } +} diff --git a/src/main.rs b/src/main.rs index bbd54b8..7521440 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ +pub mod function_cache; pub mod math; +use function_cache::FunctionCache; use iced::event; use iced::executor; use iced::mouse; @@ -14,10 +16,9 @@ use iced::{ }; use math::context::Context; use math::expression_function::ExpressionFunction; -use math::function::Function; +use std::sync::Mutex; use crate::math::complex::Complex; -use crate::math::function::FunctionArgument; pub fn main() -> iced::Result { Graph::run(Settings { @@ -29,7 +30,7 @@ pub fn main() -> iced::Result { #[derive(Default)] struct Graph { graph: Cache, - func: ExpressionFunction, + func: Mutex<FunctionCache>, ctx: Context, input_state: String, } @@ -37,6 +38,7 @@ struct Graph { #[derive(Debug, Clone)] enum Message { InputChanged(String), + UpdateFunction, UpdateScreen, } @@ -48,10 +50,11 @@ impl Application for Graph { fn new(_flags: ()) -> (Self, Command<Message>) { let ctx = Context::commonsense(); + let func = ExpressionFunction::from_string("f(x) = x^2".to_string(), ctx.operations()); ( Graph { input_state: "f(x) = x^2".to_string(), - func: ExpressionFunction::from_string("f(x) = x^2".to_string(), ctx.operations()), + func: Mutex::new(FunctionCache::new(func)), ctx, ..Default::default() }, @@ -68,8 +71,15 @@ impl Application for Graph { Message::InputChanged(s) => { self.input_state = s; } + Message::UpdateFunction => { + let func = ExpressionFunction::from_string( + self.input_state.clone(), + self.ctx.operations(), + ); + self.func = Mutex::new(FunctionCache::new(func)); + self.graph.clear(); + } Message::UpdateScreen => { - self.func = ExpressionFunction::from_string(self.input_state.clone(), self.ctx.operations()); self.graph.clear(); } } @@ -79,7 +89,7 @@ impl Application for Graph { fn view(&self) -> Element<Message> { let input = text_input("x", &self.input_state) .on_input(Message::InputChanged) - .on_submit(Message::UpdateScreen) + .on_submit(Message::UpdateFunction) .padding(15) .size(30); let canvas = canvas(self as &Self) @@ -118,7 +128,7 @@ impl Default for MouseState { interaction: Interaction::default(), center: Point::default(), last_position: None, - scale: 50.0 + scale: 50.0, } } } @@ -169,12 +179,12 @@ impl canvas::Program<Message, Renderer> for Graph { frame.with_save(|frame| { let start_y = ((state.center.y - frame.height() / 2.0) / state.scale) as i64 * state.scale as i64; - let start_x = - ((state.center.x - frame.width() / 2.0) / state.scale) as i64 * state.scale as i64; + let start_x = ((state.center.x - frame.width() / 2.0) / state.scale) as i64 + * state.scale as i64; let end_y = ((state.center.y + frame.height() / 2.0) / state.scale) as i64 * state.scale as i64; - let end_x = - ((state.center.x + frame.width() / 2.0) / state.scale) as i64 * state.scale as i64; + let end_x = ((state.center.x + frame.width() / 2.0) / state.scale) as i64 + * state.scale as i64; for y in (start_y..end_y + state.scale as i64).step_by(1) { let line = Path::line( @@ -230,12 +240,10 @@ impl canvas::Program<Message, Renderer> for Graph { frame.stroke(&line, zeroline.clone()); let mut y1 = self .func - .eval( - &FunctionArgument::from_values(vec![Complex::new(start_x as f64, 0.0)]), - &self.ctx, - ) + .lock() .unwrap() - .real as f32; + .eval(Complex::new(start_x as f64, 0.0), &self.ctx) + .real as f32; for x in start_x..end_x { for d in 0..10 { let d = d as f32 / 10.0; @@ -243,14 +251,13 @@ impl canvas::Program<Message, Renderer> for Graph { let x2 = x as f32 + d + 0.1; let y2 = self .func - .eval( - &FunctionArgument::from_values(vec![Complex::new(x2 as f64, 0.0)]), - &self.ctx, - ) + .lock() .unwrap() + .eval(Complex::new(x2 as f64, 0.0), &self.ctx) .real as f32; if y1.is_finite() && !y1.is_nan() && y2.is_finite() && !y2.is_nan() { - let line = Path::line(state.map_coords(x1, y1), state.map_coords(x2, y2)); + let line = + Path::line(state.map_coords(x1, y1), state.map_coords(x2, y2)); frame.stroke(&line, graphline.clone()) } y1 = y2; @@ -263,12 +270,12 @@ impl canvas::Program<Message, Renderer> for Graph { } fn update( - &self, - state: &mut Self::State, - event: canvas::Event, - _bounds: Rectangle, - cursor: iced::advanced::mouse::Cursor, - ) -> (canvas::event::Status, Option<Message>) { + &self, + state: &mut Self::State, + event: canvas::Event, + _bounds: Rectangle, + cursor: iced::advanced::mouse::Cursor, + ) -> (canvas::event::Status, Option<Message>) { if let canvas::Event::Mouse(mouse::Event::ButtonPressed(_)) = event { state.interaction = Interaction::Grabbing; state.last_position = cursor.position(); @@ -299,11 +306,9 @@ impl canvas::Program<Message, Renderer> for Graph { state.scale *= 1.1; } state.scale = state.scale.max(0.000001); - println!("SCALE: {}", state.scale); - return (event::Status::Captured, Some(Message::UpdateScreen)) - }, - _ => { + return (event::Status::Captured, Some(Message::UpdateScreen)); } + _ => {} } } (event::Status::Ignored, None) @@ -316,12 +321,8 @@ impl canvas::Program<Message, Renderer> for Graph { _cursor: mouse::Cursor, ) -> mouse::Interaction { match state.interaction { - Interaction::Grabbing => { - mouse::Interaction::Grabbing - }, - _ => { - mouse::Interaction::Grab - } + Interaction::Grabbing => mouse::Interaction::Grabbing, + _ => mouse::Interaction::Grab, } } } diff --git a/src/math/complex.rs b/src/math/complex.rs index 5b95df4..4d85155 100644 --- a/src/math/complex.rs +++ b/src/math/complex.rs @@ -1,4 +1,5 @@ use std::f64::consts::E; +use std::hash::Hash; use std::num::ParseFloatError; use std::str::FromStr; @@ -75,6 +76,21 @@ impl std::fmt::Display for Complex { } } +impl PartialEq for Complex { + fn eq(&self, other: &Self) -> bool { + self.real == other.real && self.imag == other.imag + } +} + +impl Hash for Complex { + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + format!("{}#{}", self.real, self.imag).hash(state); + state.finish(); + } +} + +impl Eq for Complex {} + #[derive(Debug)] pub struct ComplexParseError; diff --git a/src/math/expression.rs b/src/math/expression.rs index 049886d..14a3eb8 100644 --- a/src/math/expression.rs +++ b/src/math/expression.rs @@ -4,6 +4,7 @@ use super::function::FunctionArgument; use super::string::{ContainsAndSkipBrackets, SplitMatchingBracket}; use super::operation::Operation; +#[derive(PartialEq, Eq, Hash, Clone)] enum ExpressionType { Value(Complex), Variable(String), @@ -17,7 +18,7 @@ impl Default for ExpressionType { } } -#[derive(Default)] +#[derive(Default, PartialEq, Eq, Hash, Clone)] pub struct Expression { expr_type: ExpressionType, repr: String, diff --git a/src/math/function.rs b/src/math/function.rs index 93d288c..700bee1 100644 --- a/src/math/function.rs +++ b/src/math/function.rs @@ -1,11 +1,13 @@ use super::expression::Expression; use super::{complex::Complex, context::Context}; +#[derive(PartialEq, Eq, Hash, Clone)] enum FunctionArgumentType { ExpressionArgument(Vec<Expression>), ValueArgument(Vec<Complex>), } +#[derive(PartialEq, Eq, Hash, Clone)] pub struct FunctionArgument { args: FunctionArgumentType, len: usize, diff --git a/src/math/operation.rs b/src/math/operation.rs index bcf6510..e54a2d1 100644 --- a/src/math/operation.rs +++ b/src/math/operation.rs @@ -2,7 +2,7 @@ use crate::math::complex::Complex; pub type Operator = fn(Complex, Complex) -> Complex; -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct Operation { sign: char, func: Operator |