1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
//! Bridges between JavaScript and [mod@wasm_bindgen].
mod drawer;
use wasm_bindgen::prelude::*;
/// Wrapper of objects containing states
#[wasm_bindgen]
pub struct WasmWrapper {
/// Pendulum, nothing else.
p: pendulum::Pendulum,
/// History of the last mass point in Cartesian coordinate.
trajs: Vec<[f64; 2]>,
/// History of the kinetic and the potential energies.
enes: [Vec<f64>; 2],
/// Handles drawing, keeping HTML objects.
drawer: crate::drawer::Drawer,
}
/// Maximum length of the trajectory ([`WasmWrapper::trajs`])
const NTRAJS: usize = 150;
/// Maximum length of the energy history ([`WasmWrapper::enes`])
const NENES: usize = 500;
/// Serves as an opaque pointer to store all states.
#[wasm_bindgen]
impl WasmWrapper {
/// Initialiser.
pub fn new(nitems: usize) -> WasmWrapper {
// I need to initialise the size of the canvas first
let drawer = crate::drawer::Drawer::new();
drawer.update_canvas_size();
// prepare all buffers, pack them and return it
return WasmWrapper {
p: pendulum::simulator::init(nitems),
trajs: Vec::<[f64; 2]>::new(),
enes: [Vec::<f64>::new(), Vec::<f64>::new()],
drawer: drawer,
};
}
/// Integrator.
pub fn integrate(&mut self) -> () {
// loop until desired time is reached
const RATE: f64 = 5e-2;
let mut time: f64 = 0.;
loop {
let dt: f64 = pendulum::simulator::integrate(&mut self.p);
time += dt;
if RATE < time {
break;
}
}
// save history
fn update_history<T>(max: usize, old: &mut Vec<T>, new: T) -> () {
// NOTE: VecDeque would be superior, saying strictly
let nitems: usize = old.len();
if max <= nitems {
// long enough, discard the head and add the new to the tail
old.rotate_left(1);
old[max - 1] = new;
} else {
// short enough, just append the new to the tail
old.push(new);
}
}
// history of the last mass point
// compute Cartesian coordinate of the last mass point
let angles: &Vec<f64> = &self.p.get_positions();
let mut x: f64 = 0.;
let mut y: f64 = 0.;
for angle in angles {
x += angle.cos();
y += angle.sin();
}
update_history::<[f64; 2]>(NTRAJS, &mut self.trajs, [x, y]);
// history of the kinetic and the potential energies
let e: pendulum::Energy = pendulum::logger::check_energies(&self.p);
update_history::<f64>(NENES, &mut self.enes[0], e.t);
update_history::<f64>(NENES, &mut self.enes[1], e.u);
}
/// Is a wrapper of the drawing function.
pub fn draw(&self) -> () {
self.drawer.draw(
self.p.get_nitems(),
&self.p.get_positions(),
&self.trajs,
&self.enes,
);
}
/// Changes canvas size, invoked by the `resize` event.
pub fn update_canvas_size(&self) -> () {
self.drawer.update_canvas_size();
}
}
/// Is invoked when the wasm file is loaded in JS.
#[wasm_bindgen(start)]
pub fn init() -> () {}