documentation, comments, and cleanup

This commit is contained in:
Simon Gardling
2022-03-10 13:38:28 -05:00
parent a8597374c2
commit 9935285c98
4 changed files with 98 additions and 39 deletions

View File

@@ -2,22 +2,24 @@ use std::ops::Range;
use eframe::egui::plot::Value;
// Handles logging based on if the target is wasm (or not) and if `debug_assertions` is enabled or not
cfg_if::cfg_if! {
if #[cfg(target_arch = "wasm32")] {
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
// Use `js_namespace` here to bind `console.log(..)` instead of just
// `log(..)`
// `console.log(...)`
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
/// Used for logging normal messages
#[allow(dead_code)]
pub fn log_helper(s: &str) {
log(s);
}
/// Used for debug messages, only does anything if `debug_assertions` is enabled
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn debug_log(s: &str) {
@@ -25,11 +27,13 @@ cfg_if::cfg_if! {
log(s);
}
} else {
/// Used for logging normal messages
#[allow(dead_code)]
pub fn log_helper(s: &str) {
println!("{}", s);
}
/// Used for debug messages, only does anything if `debug_assertions` is enabled
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn debug_log(s: &str) {
@@ -39,28 +43,43 @@ cfg_if::cfg_if! {
}
}
/// `SteppedVector` is used in order to efficiently sort through an ordered `Vec<f64>`
/// Used in order to speedup the processing of cached data when moving horizontally without zoom in `FunctionEntry`. Before this struct, the index was calculated with `.iter().position(....` which was horribly inefficient
pub struct SteppedVector {
// Actual data being referenced. HAS to be sorted from maximum value to minumum
data: Vec<f64>,
// Minimum value
min: f64,
// Maximum value
max: f64,
// Since all entries in `data` are evenly spaced, this field stores the step between 2 adjacent elements
step: f64,
}
impl SteppedVector {
/// Returns `Option<usize>` with index of element with value `x`. and `None` if `x` does not exist in `data`
pub fn get_index(&self, x: f64) -> Option<usize> {
// if `x` is outside range, just go ahead and return `None` as it *shouldn't* be in `data`
if (x > self.max) | (self.min > x) {
return None;
}
// Should work....
// Do some math in order to calculate the expected index value
let possible_i = ((x + self.min) / self.step) as usize;
// Make sure that the index is valid by checking the data returned vs the actual data (just in case)
if self.data[possible_i] == x {
// It is valid!
Some(possible_i)
} else {
// (For some reason) it wasn't!
None
}
// Not really needed as the above code should handle everything
// Old (inefficent) code
/*
for (i, ele) in self.data.iter().enumerate() {
if ele > &x {
@@ -74,12 +93,16 @@ impl SteppedVector {
}
}
// Convert `Vec<f64>` into `SteppedVector`
impl From<Vec<f64>> for SteppedVector {
// Note: input `data` is assumed to be sorted from min to max
/// Note: input `data` is assumed to be sorted properly
/// `data` is a Vector of 64 bit floating point numbers ordered from max -> min
fn from(data: Vec<f64>) -> SteppedVector {
let max = data[0];
let min = data[data.len() - 1];
let step = (max - min).abs() / ((data.len() - 1) as f64);
let max = data[0]; // The max value should be the first element
let min = data[data.len() - 1]; // The minimum value should be the last element
let step = (max - min).abs() / ((data.len() - 1) as f64); // Calculate the step between elements
// Create and return the struct
SteppedVector {
data,
min,
@@ -89,10 +112,10 @@ impl From<Vec<f64>> for SteppedVector {
}
}
// Rounds f64 to specific number of digits
pub fn digits_precision(x: f64, digits: usize) -> f64 {
let large_number: f64 = 10.0_f64.powf(digits as f64);
(x * large_number).round() / large_number
// Rounds f64 to specific number of decimal places
pub fn decimal_round(x: f64, n: usize) -> f64 {
let large_number: f64 = 10.0_f64.powf(n as f64); // 10^n
(x * large_number).round() / large_number // round and devide in order to cut off after the `n`th decimal place
}
/// Implements newton's method of finding roots.
@@ -100,8 +123,8 @@ pub fn digits_precision(x: f64, digits: usize) -> f64 {
/// `range` is the range of valid x values (used to stop calculation when the point won't display anyways)
/// `data` is the data to iterate over (a Vector of egui's `Value` struct)
/// `f` is f(x)
/// `f_` is f'(x)
/// The function returns a list of `x` values where roots occur
/// `f_1` is f'(x)
/// The function returns a Vector of `x` values where roots occur
pub fn newtons_method(
threshold: f64, range: Range<f64>, data: Vec<Value>, f: &dyn Fn(f64) -> f64,
f_1: &dyn Fn(f64) -> f64,