aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/function_cache.rs32
-rw-r--r--src/main.rs75
-rw-r--r--src/math/complex.rs16
-rw-r--r--src/math/expression.rs3
-rw-r--r--src/math/function.rs2
-rw-r--r--src/math/operation.rs2
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