use std::{f32::consts::PI, time::Duration};
use crate::cursor::{Position, Velocity};
#[derive(Debug, Clone, Default)]
pub struct Blob {
pub(crate) session_id: i32,
pub(crate) position: Position,
pub(crate) velocity: Velocity,
pub(crate) acceleration: f32,
pub(crate) angle: f32,
pub(crate) rotation_speed: f32,
pub(crate) rotation_acceleration: f32,
pub(crate) width: f32,
pub(crate) height: f32,
pub(crate) area: f32,
}
impl Blob {
pub fn new(
session_id: i32,
position: Position,
angle: f32,
width: f32,
height: f32,
area: f32,
) -> Self {
Self {
session_id,
position,
velocity: Velocity::default(),
acceleration: 0f32,
angle,
rotation_speed: 0f32,
rotation_acceleration: 0f32,
width,
height,
area,
}
}
pub fn with_motion(
mut self,
velocity: Velocity,
rotation_speed: f32,
acceleration: f32,
rotation_acceleration: f32,
) -> Self {
self.velocity = velocity;
self.rotation_speed = rotation_speed;
self.acceleration = acceleration;
self.rotation_acceleration = rotation_acceleration;
self
}
pub fn update(
&mut self,
delta_time: Duration,
position: Position,
angle: f32,
width: f32,
height: f32,
area: f32,
) {
let delta_time = delta_time.as_secs_f32();
let distance = position.distance_from(&self.position);
let delta_x = position.x - self.position.x;
let delta_y = position.y - self.position.y;
let last_speed = self.velocity.get_speed();
let speed = distance / delta_time;
self.velocity = Velocity {
x: delta_x / delta_time,
y: delta_y / delta_time,
};
self.acceleration = (speed - last_speed) / delta_time;
self.position = position;
let delta_turn = (angle - self.angle) / (2. * PI);
let rotation_speed = delta_turn / delta_time;
self.rotation_acceleration = (rotation_speed - self.rotation_speed) / delta_time;
self.rotation_speed = rotation_speed;
self.width = width;
self.height = height;
self.area = area;
}
pub fn get_session_id(&self) -> i32 {
self.session_id
}
pub fn get_position(&self) -> &Position {
&self.position
}
pub fn get_x_position(&self) -> f32 {
self.position.x
}
pub fn get_y_position(&self) -> f32 {
self.position.y
}
pub fn get_velocity(&self) -> &Velocity {
&self.velocity
}
pub fn get_x_velocity(&self) -> f32 {
self.velocity.x
}
pub fn get_y_velocity(&self) -> f32 {
self.velocity.y
}
pub fn get_acceleration(&self) -> f32 {
self.acceleration
}
pub fn get_angle(&self) -> f32 {
self.angle
}
pub fn get_rotation_speed(&self) -> f32 {
self.rotation_speed
}
pub fn get_rotation_acceleration(&self) -> f32 {
self.rotation_acceleration
}
pub fn get_width(&self) -> f32 {
self.width
}
pub fn get_height(&self) -> f32 {
self.height
}
pub fn get_pixel_width(&self, screen_width: u16) -> u16 {
(self.width * screen_width as f32) as u16
}
pub fn get_pixel_height(&self, screen_height: u16) -> u16 {
(self.width * screen_height as f32) as u16
}
pub fn get_area(&self) -> f32 {
self.area
}
}
impl PartialEq for Blob {
fn eq(&self, other: &Self) -> bool {
self.session_id == other.session_id
&& self.get_x_position() == other.get_x_position()
&& self.get_x_position() == other.get_y_position()
&& self.angle == other.angle
&& self.velocity == other.velocity
&& self.rotation_speed == other.rotation_speed
&& self.acceleration == other.acceleration
&& self.rotation_acceleration == other.rotation_acceleration
&& self.width == other.width
&& self.height == other.height
&& self.area == other.area
}
}
#[cfg(test)]
mod tests {
use std::{f32::consts::SQRT_2, time::Duration};
use crate::{blob::Blob, cursor::Position};
#[test]
fn blob_update() {
let mut blob = Blob::new(0, Position { x: 0., y: 0. }, 0., 0., 0., 0.);
blob.update(
Duration::from_secs(1),
Position { x: 1., y: 1. },
90f32.to_radians(),
0.5,
0.5,
0.25,
);
assert_eq!(blob.get_x_position(), 1.);
assert_eq!(blob.get_y_position(), 1.);
assert_eq!(blob.get_x_velocity(), 1.);
assert_eq!(blob.get_y_velocity(), 1.);
assert_eq!(blob.get_acceleration(), SQRT_2);
assert_eq!(blob.get_rotation_speed(), 0.25);
assert_eq!(blob.get_rotation_acceleration(), 0.25);
assert_eq!(blob.get_width(), 0.5);
assert_eq!(blob.get_height(), 0.5);
assert_eq!(blob.get_area(), 0.25);
}
}