use macroquad::prelude::*;
use parry2d::math::Vector;
use parry2d::shape::Cuboid;
use crate::behaviour::traits::{Attachable, Drawable};
use crate::parameter::{DT, RESOLUTION};
use crate::utils::{draw_rotated_rectangle, normalise};
#[derive(Debug, Clone)]
pub struct Trolley {
pub id: String,
pub pose: (f32, f32, f32),
pub mount_offset: f32,
pub shape: Cuboid,
}
impl Trolley {
pub fn new(id: String, footprint: &(f32, f32)) -> Trolley {
let shape = Cuboid::new(Vector::new(footprint.0 * 0.5, footprint.1 * 0.5));
let pose = (0.0, 0.0, 0.0);
let mount_offset = 0.0;
Trolley {
id,
pose,
shape,
mount_offset,
}
}
pub fn from_mount(
&mut self,
parent_pos: &(f32, f32, f32),
mount_offset: f32,
) -> Option<Trolley> {
self.mount(parent_pos, mount_offset);
return Some(self.clone());
}
}
impl Attachable for Trolley {
fn mount(&mut self, parent_pos: &(f32, f32, f32), mount_offset: f32) {
self.mount_offset = mount_offset;
let px = parent_pos.0;
let py = parent_pos.1;
let ptheta = parent_pos.2;
let length = self.shape.half_extents[0];
let width = self.shape.half_extents[1];
let x = px - (mount_offset + length) * ptheta.cos();
let y = py - (mount_offset + width) * ptheta.sin();
self.pose = (x, y, ptheta);
}
fn step(&mut self, _mount_pos: &(f32, f32, f32), mount_vel: &(f32, f32, f32)) {
let mount_v = mount_vel.0;
let mount_theta = _mount_pos.2;
let l = self.shape.half_extents[0] * 2.0;
let d = self.mount_offset + 3.0 * l / 4.0;
let v_axle = mount_v * (mount_theta - self.pose.2).cos();
let w_axle = mount_v * (mount_theta - self.pose.2).sin() / d;
let x_dot = v_axle * self.pose.2.cos();
let y_dot = v_axle * self.pose.2.sin();
let a = l / 4.0;
let xc_dot = x_dot - a * self.pose.2.sin() * w_axle;
let yc_dot = y_dot + a * self.pose.2.cos() * w_axle;
self.pose.2 = normalise(self.pose.2 + w_axle * DT);
self.pose.0 = self.pose.0 + xc_dot * DT;
self.pose.1 = self.pose.1 + yc_dot * DT;
}
}
impl Drawable for Trolley {
fn draw(&self, tf: fn((f32, f32)) -> (f32, f32)) {
let extents = self.shape.half_extents;
let w = extents[0];
let h = extents[1];
let rounded_radius = 0.25 * w;
let w_new = w - rounded_radius;
let h_new = h - rounded_radius;
draw_rotated_rectangle(
(self.pose.0, self.pose.1),
(w_new, h),
self.pose.2,
SKYBLUE,
tf,
);
draw_rotated_rectangle(
(self.pose.0, self.pose.1),
(w, h_new),
self.pose.2,
SKYBLUE,
tf,
);
let p1 = (w_new, h_new);
let p2 = (w_new, -h_new);
let p3 = (-w_new, -h_new);
let p4 = (-w_new, h_new);
let params = vec![p1, p2, p3, p4];
let c = self.pose.2.cos();
let s = self.pose.2.sin();
for param in params {
let (w, h) = param;
let cx = self.pose.0 + w * c - h * s;
let cy = self.pose.1 + w * s + h * c;
let tf_c = tf((cx, cy));
draw_circle(tf_c.0, tf_c.1, rounded_radius / RESOLUTION, SKYBLUE);
}
}
fn draw_bounds(&self, _tf: fn((f32, f32)) -> (f32, f32)) {}
}