improve caching
This commit is contained in:
parent
08623f411c
commit
c09c2d9beb
@ -1,4 +1,12 @@
|
|||||||
use crate::misc::{add_asterisks, Cache, Function};
|
use crate::misc::{add_asterisks, Function};
|
||||||
|
|
||||||
|
|
||||||
|
pub enum UpdateType {
|
||||||
|
FULL,
|
||||||
|
FRONT,
|
||||||
|
BACK,
|
||||||
|
NONE,
|
||||||
|
}
|
||||||
|
|
||||||
// Manages Chart generation and caching of values
|
// Manages Chart generation and caching of values
|
||||||
pub struct ChartManager {
|
pub struct ChartManager {
|
||||||
@ -7,8 +15,6 @@ pub struct ChartManager {
|
|||||||
max_x: f64,
|
max_x: f64,
|
||||||
num_interval: usize,
|
num_interval: usize,
|
||||||
resolution: usize,
|
resolution: usize,
|
||||||
back_cache: Cache<Vec<(f64, f64)>>,
|
|
||||||
front_cache: Cache<(Vec<(f64, f64)>, f64)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChartManager {
|
impl ChartManager {
|
||||||
@ -21,71 +27,37 @@ impl ChartManager {
|
|||||||
max_x,
|
max_x,
|
||||||
num_interval,
|
num_interval,
|
||||||
resolution,
|
resolution,
|
||||||
back_cache: Cache::new_empty(),
|
|
||||||
front_cache: Cache::new_empty(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn draw(&mut self) -> (Vec<(f64, f64)>, Vec<(f64, f64)>, f64) {
|
pub fn draw_back(&mut self) -> Vec<(f64, f64)> {
|
||||||
let absrange = (self.max_x - self.min_x).abs();
|
let absrange = (self.max_x - self.min_x).abs();
|
||||||
let data: Vec<(f64, f64)> = match self.back_cache.is_valid() {
|
let output: Vec<(f64, f64)> = (1..=self.resolution)
|
||||||
true => self.back_cache.get().clone(),
|
|
||||||
false => {
|
|
||||||
let output: Vec<(f64, f64)> = (1..=self.resolution)
|
|
||||||
.map(|x| ((x as f64 / self.resolution as f64) * absrange) + self.min_x)
|
.map(|x| ((x as f64 / self.resolution as f64) * absrange) + self.min_x)
|
||||||
.map(|x| (x, self.function.run(x)))
|
.map(|x| (x, self.function.run(x)))
|
||||||
.collect();
|
.collect();
|
||||||
self.back_cache.set(output.clone());
|
output
|
||||||
output
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let filtered_data: Vec<(f64, f64)> = data.iter().map(|(x, y)| (*x, *y)).collect();
|
|
||||||
|
|
||||||
let (rect_data, area): (Vec<(f64, f64)>, f64) = match self.front_cache.is_valid() {
|
|
||||||
true => self.front_cache.get().clone(),
|
|
||||||
false => {
|
|
||||||
let step = absrange / (self.num_interval as f64);
|
|
||||||
let output: (Vec<(f64, f64)>, f64) = self.integral_rectangles(step);
|
|
||||||
self.front_cache.set(output.clone());
|
|
||||||
output
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(filtered_data, rect_data, area)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn draw_front(&mut self) -> (Vec<(f64, f64)>, f64) {
|
||||||
|
self.integral_rectangles(self.get_step())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub fn get_step(&self) -> f64 { (self.max_x - self.min_x).abs() / (self.num_interval as f64) }
|
pub fn get_step(&self) -> f64 { (self.max_x - self.min_x).abs() / (self.num_interval as f64) }
|
||||||
|
|
||||||
pub fn do_update_front(&self, resolution: usize, num_interval: usize) -> bool {
|
|
||||||
(self.resolution != resolution) | (num_interval != self.num_interval)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_update_back(&self, func_str_new: String, min_x: f64, max_x: f64) -> bool {
|
|
||||||
let func_str: String = add_asterisks(func_str_new);
|
|
||||||
let update_func: bool = !self.function.str_compare(func_str);
|
|
||||||
|
|
||||||
update_func | (min_x != self.min_x) | (max_x != self.max_x)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn update(
|
pub fn update(
|
||||||
&mut self, func_str_new: String, min_x: f64, max_x: f64, num_interval: usize,
|
&mut self, func_str_new: String, min_x: f64, max_x: f64, num_interval: usize,
|
||||||
resolution: usize,
|
resolution: usize,
|
||||||
) -> (Vec<(f64, f64)>, Vec<(f64, f64)>, f64) {
|
) -> UpdateType {
|
||||||
let func_str: String = add_asterisks(func_str_new);
|
let func_str: String = add_asterisks(func_str_new);
|
||||||
let update_func: bool = !self.function.str_compare(func_str.clone());
|
let update_func: bool = !self.function.str_compare(func_str.clone());
|
||||||
|
|
||||||
let underlying_update = update_func | (min_x != self.min_x) | (max_x != self.max_x);
|
let update_back = update_func | (min_x != self.min_x) | (max_x != self.max_x);
|
||||||
|
let update_front = update_back | (self.resolution != resolution) | (num_interval != self.num_interval);
|
||||||
if underlying_update | (self.resolution != resolution) {
|
|
||||||
self.back_cache.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if underlying_update | (num_interval != self.num_interval) {
|
|
||||||
self.front_cache.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if update_func {
|
if update_func {
|
||||||
self.function = Function::from_string(func_str);
|
self.function = Function::from_string(func_str);
|
||||||
@ -96,7 +68,15 @@ impl ChartManager {
|
|||||||
self.num_interval = num_interval;
|
self.num_interval = num_interval;
|
||||||
self.resolution = resolution;
|
self.resolution = resolution;
|
||||||
|
|
||||||
self.draw()
|
if update_back && update_front {
|
||||||
|
UpdateType::FULL
|
||||||
|
} else if update_back {
|
||||||
|
UpdateType::BACK
|
||||||
|
} else if update_front {
|
||||||
|
UpdateType::FRONT
|
||||||
|
} else {
|
||||||
|
UpdateType::NONE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
104
src/egui_app.rs
104
src/egui_app.rs
@ -1,4 +1,4 @@
|
|||||||
use crate::chart_manager::ChartManager;
|
use crate::chart_manager::{ChartManager, UpdateType};
|
||||||
use crate::misc::{digits_precision, test_func, Cache};
|
use crate::misc::{digits_precision, test_func, Cache};
|
||||||
use eframe::{egui, epi};
|
use eframe::{egui, epi};
|
||||||
use egui::plot::{Line, Plot, Value, Values};
|
use egui::plot::{Line, Plot, Value, Values};
|
||||||
@ -12,7 +12,8 @@ pub struct MathApp {
|
|||||||
num_interval: usize,
|
num_interval: usize,
|
||||||
resolution: usize,
|
resolution: usize,
|
||||||
chart_manager: ChartManager,
|
chart_manager: ChartManager,
|
||||||
bar_cache: Cache<Vec<Bar>>,
|
back_cache: Cache<Vec<Value>>,
|
||||||
|
front_cache: Cache<(Vec<Bar>, f64)>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MathApp {
|
impl Default for MathApp {
|
||||||
@ -24,11 +25,50 @@ impl Default for MathApp {
|
|||||||
num_interval: 100,
|
num_interval: 100,
|
||||||
resolution: 10000,
|
resolution: 10000,
|
||||||
chart_manager: ChartManager::new("x^2".to_string(), -10.0, 10.0, 100, 10000),
|
chart_manager: ChartManager::new("x^2".to_string(), -10.0, 10.0, 100, 10000),
|
||||||
bar_cache: Cache::new_empty(),
|
back_cache: Cache::new_empty(),
|
||||||
|
front_cache: Cache::new_empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MathApp {
|
||||||
|
#[inline]
|
||||||
|
fn get_back(&mut self) -> Line {
|
||||||
|
let data = if self.back_cache.is_valid() {
|
||||||
|
self.back_cache.get().clone()
|
||||||
|
} else {
|
||||||
|
let data = self.chart_manager.draw_back();
|
||||||
|
let data_values: Vec<Value> = data.iter().map(|(x, y)| Value::new(*x, *y)).collect();
|
||||||
|
self.back_cache.set(data_values.clone());
|
||||||
|
data_values
|
||||||
|
};
|
||||||
|
Line::new(Values::from_values(data)).color(Color32::RED)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_front(&mut self) -> (Vec<Bar>, f64) {
|
||||||
|
if self.front_cache.is_valid() {
|
||||||
|
let cache = self.front_cache.get();
|
||||||
|
let vec_bars: Vec<Bar> = cache.0.to_vec();
|
||||||
|
(vec_bars, cache.1)
|
||||||
|
} else {
|
||||||
|
let (data, area) = self.chart_manager.draw_front();
|
||||||
|
let bars: Vec<Bar> = data.iter().map(|(x, y)| Bar::new(*x, *y)).collect();
|
||||||
|
|
||||||
|
let output = (bars, area);
|
||||||
|
self.front_cache.set(output.clone());
|
||||||
|
output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_data(&mut self) -> (Line, Vec<Bar>, f64) {
|
||||||
|
let (bars, area) = self.get_front();
|
||||||
|
(self.get_back(), bars, area)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl epi::App for MathApp {
|
impl epi::App for MathApp {
|
||||||
fn name(&self) -> &str { "Integral Demonstration" }
|
fn name(&self) -> &str { "Integral Demonstration" }
|
||||||
|
|
||||||
@ -48,7 +88,8 @@ impl epi::App for MathApp {
|
|||||||
num_interval,
|
num_interval,
|
||||||
resolution,
|
resolution,
|
||||||
chart_manager,
|
chart_manager,
|
||||||
bar_cache,
|
back_cache,
|
||||||
|
front_cache,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
// Note: This Instant implementation does not show microseconds when using wasm.
|
// Note: This Instant implementation does not show microseconds when using wasm.
|
||||||
@ -97,8 +138,23 @@ impl epi::App for MathApp {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// let update_back = chart_manager.do_update_back(func_str.clone(), *min_x, *max_x);
|
let do_update = chart_manager.update(
|
||||||
let update_front = chart_manager.do_update_front(*num_interval, *resolution);
|
func_str.clone(),
|
||||||
|
*min_x,
|
||||||
|
*max_x,
|
||||||
|
*num_interval,
|
||||||
|
*resolution,
|
||||||
|
);
|
||||||
|
|
||||||
|
match do_update {
|
||||||
|
UpdateType::FULL => {
|
||||||
|
back_cache.invalidate();
|
||||||
|
front_cache.invalidate();
|
||||||
|
},
|
||||||
|
UpdateType::BACK => back_cache.invalidate(),
|
||||||
|
UpdateType::FRONT => front_cache.invalidate(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
if !parse_error.is_empty() {
|
if !parse_error.is_empty() {
|
||||||
@ -106,43 +162,11 @@ impl epi::App for MathApp {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (filtered_data, rect_data, area) = chart_manager.update(
|
let (curve, bars, area) = self.get_data();
|
||||||
self.func_str.clone(),
|
|
||||||
*min_x,
|
|
||||||
*max_x,
|
|
||||||
*num_interval,
|
|
||||||
*resolution,
|
|
||||||
);
|
|
||||||
|
|
||||||
let filtered_data_values = filtered_data
|
|
||||||
.iter()
|
|
||||||
.map(|(x, y)| Value::new(*x, *y))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let curve = Line::new(Values::from_values(filtered_data_values)).color(Color32::RED);
|
|
||||||
|
|
||||||
let bars: Vec<Bar> = match update_front {
|
|
||||||
true => {
|
|
||||||
let bars: Vec<Bar> = rect_data.iter().map(|(x, y)| Bar::new(*x, *y)).collect();
|
|
||||||
|
|
||||||
bar_cache.set(bars.clone());
|
|
||||||
bars
|
|
||||||
}
|
|
||||||
false => {
|
|
||||||
if bar_cache.is_valid() {
|
|
||||||
bar_cache.get().clone()
|
|
||||||
} else {
|
|
||||||
let bars: Vec<Bar> =
|
|
||||||
rect_data.iter().map(|(x, y)| Bar::new(*x, *y)).collect();
|
|
||||||
|
|
||||||
bar_cache.set(bars.clone());
|
|
||||||
bars
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let bar_chart = BarChart::new(bars)
|
let bar_chart = BarChart::new(bars)
|
||||||
.color(Color32::BLUE)
|
.color(Color32::BLUE)
|
||||||
.width(chart_manager.get_step());
|
.width(self.chart_manager.get_step());
|
||||||
|
|
||||||
Plot::new("plot")
|
Plot::new("plot")
|
||||||
.view_aspect(1.0)
|
.view_aspect(1.0)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user