use crate::geometry::Point;
use crate::geometry::Pose;
use crate::properties::Motion;
use crate::properties::Size;
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct BCar {
pub pose: Pose,
pub size: Size,
pub motion: Motion,
}
impl BCar {
pub fn new(pose: Pose, size: Size, motion: Motion) -> BCar {
BCar {pose, size, motion}
}
pub fn new_xyh(x: f64, y: f64, h: f64) -> BCar {
BCar {
pose: Pose::new(x, y, h),
size: Size::default(),
motion: Motion::default(),
}
}
pub fn default() -> BCar {
BCar {
pose: Pose::default(),
size: Size::default(),
motion: Motion::default(),
}
}
pub fn size(&self) -> Size {
self.size
}
pub fn set_size(&mut self, s: Size) {
self.size = s;
}
pub fn pose(&self) -> Pose {
self.pose
}
pub fn set_pose(&mut self, p: Pose) {
self.pose = p
}
pub fn motion(&self) -> Motion {
self.motion
}
pub fn set_motion(&mut self, m: Motion) {
self.motion = m
}
pub fn drivable(&self, pose: Pose) -> bool {
let pi = std::f64::consts::PI;
let pi2 = pi / 2.0;
let mut a_1 = (pose.y - self.pose.y).atan2(pose.x - self.pose.x);
a_1 -= self.pose.h;
while a_1 < -pi { a_1 += 2.0 * pi; }
while a_1 > pi { a_1 -= 2.0 * pi; }
let mut h_d = pose.h - self.pose.h;
while h_d < -pi { h_d += 2.0 * pi; }
while h_d > pi { h_d -= 2.0 * pi; }
let mut a_2 = 0.0;
let mut zb = self.pose;
if h_d == 0.0 && (a_1 == 0.0 || a_2 == pi || a_2 == -pi) {
return true;
} else if 0.0 < a_1 && a_1 <= pi2 { zb.rotate(self.ccl(), h_d);
if pose.y == zb.y && pose.x == zb.x { return true;
}
a_2 = (pose.y - zb.y).atan2(pose.x - zb.x);
while a_2 < -pi { a_2 += 2.0 * pi; }
while a_2 > pi { a_2 -= 2.0 * pi; }
if zb.h >= a_2 && a_2 >= self.pose.h {
return true;
}
} else if pi2 < a_1 && a_1 <= pi { zb.rotate(self.ccl(), h_d);
if pose.y == zb.y && pose.x == zb.x { return true;
}
a_2 = (pose.y - zb.y).atan2(pose.x - zb.x);
a_2 -= pi;
while a_2 < -pi { a_2 += 2.0 * pi; }
while a_2 > pi { a_2 -= 2.0 * pi; }
if self.pose.h >= a_2 && a_2 >= zb.h {
return true;
}
} else if 0.0 > a_1 && a_1 >= -pi2 { zb.rotate(self.ccr(), h_d);
if pose.y == zb.y && pose.x == zb.x { return true;
}
a_2 = (pose.y - zb.y).atan2(pose.x - zb.x);
while a_2 < -pi { a_2 += 2.0 * pi; }
while a_2 > pi { a_2 -= 2.0 * pi; }
if self.pose.h >= a_2 && a_2 >= zb.h {
return true;
}
} else if -pi2 > a_1 && a_1 >= -pi { zb.rotate(self.ccr(), h_d);
if pose.y == zb.y && pose.x == zb.x { return true;
}
a_2 = (pose.y - zb.y).atan2(pose.x - zb.x);
a_2 -= pi;
while a_2 < -pi { a_2 += 2.0 * pi; }
while a_2 > pi { a_2 -= 2.0 * pi; }
if zb.h >= a_2 && a_2 >= self.pose.h {
return true;
}
}
false
}
pub fn mtr(&self) -> f64 {
(
(self.size.curb_to_curb / 2.0).powi(2)
- self.size.wheelbase.powi(2)
).sqrt()
- self.size.width / 2.0
}
pub fn ccl(&self) -> Point {
let x = self.pose.x;
let y = self.pose.y;
let h = self.pose.h;
Point::new(
x + self.mtr() * (h + std::f64::consts::PI / 2.0).cos(),
y + self.mtr() * (h + std::f64::consts::PI / 2.0).sin(),
)
}
pub fn ccr(&self) -> Point {
let x = self.pose.x;
let y = self.pose.y;
let h = self.pose.h;
Point::new(
x + self.mtr() * (h - std::f64::consts::PI / 2.0).cos(),
y + self.mtr() * (h - std::f64::consts::PI / 2.0).sin(),
)
}
pub fn cf(&self) -> Point {
let mut x = self.pose.x;
x += self.size.distance_to_front * self.pose.h.cos();
let mut y = self.pose.y;
y += self.size.distance_to_front * self.pose.h.sin();
Point {x, y}
}
pub fn lf(&self) -> Point {
let pi = std::f64::consts::PI;
let mut x = self.pose.x;
x += self.size.width/2.0 * (self.pose.h + pi/2.0).cos();
x += self.size.distance_to_front * self.pose.h.cos();
let mut y = self.pose.y;
y += self.size.width/2.0 * (self.pose.h + pi/2.0).sin();
y += self.size.distance_to_front * self.pose.h.sin();
Point {x, y}
}
pub fn la(&self) -> Point {
let pi = std::f64::consts::PI;
let mut x = self.pose.x;
x += self.size.width/2.0 * (self.pose.h + pi/2.0).cos();
let mut y = self.pose.y;
y += self.size.width/2.0 * (self.pose.h + pi/2.0).sin();
Point {x, y}
}
pub fn lr(&self) -> Point {
let pi = std::f64::consts::PI;
let distance_to_rear = self.size.length - self.size.distance_to_front;
let mut x = self.pose.x;
x += self.size.width/2.0 * (self.pose.h + pi/2.0).cos();
x += -distance_to_rear * self.pose.h.cos();
let mut y = self.pose.y;
y += self.size.width/2.0 * (self.pose.h + pi/2.0).sin();
y += -distance_to_rear * self.pose.h.sin();
Point {x, y}
}
pub fn rr(&self) -> Point {
let pi = std::f64::consts::PI;
let distance_to_rear = self.size.length - self.size.distance_to_front;
let mut x = self.pose.x;
x += self.size.width/2.0 * (self.pose.h - pi/2.0).cos();
x += -distance_to_rear * self.pose.h.cos();
let mut y = self.pose.y;
y += self.size.width/2.0 * (self.pose.h - pi/2.0).sin();
y += -distance_to_rear * self.pose.h.sin();
Point {x, y}
}
pub fn ra(&self) -> Point {
let pi = std::f64::consts::PI;
let mut x = self.pose.x;
x += self.size.width/2.0 * (self.pose.h - pi/2.0).cos();
let mut y = self.pose.y;
y += self.size.width/2.0 * (self.pose.h - pi/2.0).sin();
Point {x, y}
}
pub fn rf(&self) -> Point {
let pi = std::f64::consts::PI;
let mut x = self.pose.x;
x += self.size.width/2.0 * (self.pose.h - pi/2.0).cos();
x += self.size.distance_to_front * self.pose.h.cos();
let mut y = self.pose.y;
y += self.size.width/2.0 * (self.pose.h - pi/2.0).sin();
y += self.size.distance_to_front * self.pose.h.sin();
Point {x, y}
}
}
impl Iterator for BCar {
type Item = BCar;
fn next(&mut self) -> Option<Self::Item> {
self.pose.x += self.motion.speed * self.pose.h.cos();
self.pose.y += self.motion.speed * self.pose.h.sin();
self.pose.h += self.motion.speed
/ self.size.wheelbase
* self.motion.steer.tan();
Some(*self)
}
}