use embassy_ssd1306_graphics::Graphics;
use embedded_hal_async::i2c::I2c;
use crate::draw_utils::segment;
#[derive(Clone, Copy, Debug)]
pub struct SpringMass {
pub anchor_x: i32,
pub anchor_y: i32,
pub rest_len: i32,
pub block_w: i32,
pub coils: i32,
pub amplitude: i32,
}
impl SpringMass {
#[inline]
pub fn new(anchor_x: i32, anchor_y: i32, rest_len: i32, block_w: i32) -> Self {
Self { anchor_x, anchor_y, rest_len, block_w, coils: 6, amplitude: 4 }
}
#[inline]
pub fn with_coils(mut self, coils: i32, amplitude: i32) -> Self {
self.coils = coils;
self.amplitude = amplitude;
self
}
pub fn draw<I: I2c>(
&self,
gfx: &mut Graphics<'_, I>,
extension: i32,
on: bool,
) {
let total_len = (self.rest_len + extension).max(self.coils + 4);
for dx in -(self.block_w / 2)..=(self.block_w / 2) {
gfx.pixel(self.anchor_x + dx, self.anchor_y, on);
}
let spring_top = self.anchor_y + 2;
segment(gfx, self.anchor_x, self.anchor_y, self.anchor_x, spring_top, on);
let spring_bot = self.anchor_y + total_len - 2;
if spring_bot > spring_top {
let h = spring_bot - spring_top;
let mut prev_x = self.anchor_x;
let mut prev_y = spring_top;
for i in 1..=self.coils {
let ny = spring_top + h * i / self.coils;
let nx = if i % 2 == 1 {
self.anchor_x + self.amplitude
} else {
self.anchor_x - self.amplitude
};
segment(gfx, prev_x, prev_y, nx, ny, on);
prev_x = nx;
prev_y = ny;
}
segment(gfx, prev_x, prev_y, self.anchor_x, spring_bot, on);
}
let mass_top = self.anchor_y + total_len;
segment(gfx, self.anchor_x, spring_bot, self.anchor_x, mass_top, on);
let block_h = 6i32;
let half_w = self.block_w / 2;
for dy in 0..block_h {
for dx in -half_w..=half_w {
gfx.pixel(self.anchor_x + dx, mass_top + dy, on);
}
}
}
#[inline]
pub fn erase<I: I2c>(
&self,
gfx: &mut Graphics<'_, I>,
extension: i32,
) {
self.draw(gfx, extension, false);
}
}