use crate::bcar::BCar;
use crate::geometry::Point;
use crate::geometry::Pose;
use crate::geometry::PoseRange;
use crate::geometry;
use crate::properties::Motion;
use crate::properties::Size;
use crate::pslot::PSlot;
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct EntryPlanner {
car_size: Size,
slot: PSlot,
}
impl EntryPlanner {
pub fn new(slot: PSlot, car_size: Size) -> EntryPlanner {
EntryPlanner {slot, car_size}
}
pub fn parked(&self, car: BCar) -> bool {
return self.slot.inside(car.lf())
&& self.slot.inside(car.lr())
&& self.slot.inside(car.rr())
&& self.slot.inside(car.rf())
}
pub fn unparked(&self, car: BCar) -> bool {
return !self.slot.inside(car.lf())
&& !self.slot.inside(car.rf())
}
pub fn collide(&self, c: BCar) -> Option<Point> {
let b0 = self.slot.border[0];
let b1 = self.slot.border[1];
let b2 = self.slot.border[2];
let b3 = self.slot.border[3];
let c0 = c.lf();
let c1 = c.lr();
let c2 = c.rr();
let c3 = c.rf();
match geometry::intersect_line_line(b0, b1, c0, c1) {
Some(i) => return Some(i),
None => {},
}
match geometry::intersect_line_line(b0, b1, c1, c2) {
Some(i) => return Some(i),
None => {},
}
match geometry::intersect_line_line(b0, b1, c2, c3) {
Some(i) => return Some(i),
None => {},
}
match geometry::intersect_line_line(b0, b1, c3, c0) {
Some(i) => return Some(i),
None => {},
}
match geometry::intersect_line_line(b1, b2, c0, c1) {
Some(i) => return Some(i),
None => {},
}
match geometry::intersect_line_line(b1, b2, c1, c2) {
Some(i) => return Some(i),
None => {},
}
match geometry::intersect_line_line(b1, b2, c2, c3) {
Some(i) => return Some(i),
None => {},
}
match geometry::intersect_line_line(b1, b2, c3, c0) {
Some(i) => return Some(i),
None => {},
}
match geometry::intersect_line_line(b2, b3, c0, c1) {
Some(i) => return Some(i),
None => {},
}
match geometry::intersect_line_line(b2, b3, c1, c2) {
Some(i) => return Some(i),
None => {},
}
match geometry::intersect_line_line(b2, b3, c2, c3) {
Some(i) => return Some(i),
None => {},
}
match geometry::intersect_line_line(b2, b3, c3, c0) {
Some(i) => return Some(i),
None => {},
}
None
}
pub fn drive_out_of_slot(&self, c: &mut BCar) -> (u8, Vec<BCar>) {
assert!(self.car_size.length < self.slot.length());
assert!(self.slot.right());
assert!(self.slot.parallel());
assert!(self.car_size.width < self.car_size.length);
assert!(self.car_size.width < self.slot.width());
let mut out: Vec<BCar> = Vec::new();
out.push(*c);
let mut cusp = 0;
loop {
if self.unparked(*c) {
return (cusp, out);
}
c.next();
if let Some(_i) = self.collide(*c) {
c.motion.speed *= -1.0;
c.next();
c.motion.steer *= -1.0;
cusp += 1;
if cusp > 10 {
return (cusp, out);
}
}
out.push(*c);
}
}
pub fn drive_in_the_slot(&self, c: &mut BCar) -> (u8, Vec<BCar>) {
assert!(self.car_size.length < self.slot.length());
assert!(self.slot.right());
assert!(self.slot.parallel());
assert!(self.car_size.width < self.car_size.length);
assert!(self.car_size.width < self.slot.width());
let mut out: Vec<BCar> = Vec::new();
out.push(*c);
let mut cusp = 0;
loop {
if self.parked(*c) {
return (cusp, out);
}
c.next();
if let Some(_i) = self.collide(*c) {
c.motion.speed *= -1.0;
c.next();
c.motion.steer *= -1.0;
cusp += 1;
if cusp > 10 {
return (cusp, out);
}
}
out.push(*c);
}
}
pub fn guess_goal_by_reversed(&self) -> BCar {
assert!(self.car_size.length < self.slot.length());
assert!(self.slot.right());
assert!(self.slot.parallel());
assert!(self.car_size.width < self.car_size.length);
assert!(self.car_size.width < self.slot.width());
let pi = std::f64::consts::PI;
let cdist = 1e-3 + self.car_size.length
- self.car_size.distance_to_front;
let cw2 = 1e-3 + self.car_size.width/2.0;
BCar::new(
Pose::new(
self.slot.border[0].x
+ cdist * self.slot.heading().cos()
- cw2 * (self.slot.heading() + pi/2.0).cos()
,
self.slot.border[0].y
+ cdist * self.slot.heading().sin()
- cw2 * (self.slot.heading() + pi/2.0).sin()
,
self.slot.heading()
,
),
self.car_size,
Motion::new(1e-3, self.car_size.max_steer()),
)
}
pub fn find_goals_by_bfs(&self) -> Vec<BCar> {
assert!(self.car_size.length < self.slot.length());
assert!(self.slot.right());
assert!(self.slot.parallel());
assert!(self.car_size.width < self.car_size.length);
assert!(self.car_size.width < self.slot.width());
let mut queue: Vec<BCar> = Vec::new();
let pi = std::f64::consts::PI;
let cdist = -1e-3 + self.slot.length()
- self.car_size.distance_to_front;
let cw2 = 1e-3 + self.car_size.width/2.0;
let mut c = BCar::new(
Pose::new(
self.slot.border[0].x
+ cdist * self.slot.heading().cos()
+ cw2 * (self.slot.heading() + pi/2.0).cos()
,
self.slot.border[0].y
+ cdist * self.slot.heading().sin()
+ cw2 * (self.slot.heading() + pi/2.0).sin()
,
self.slot.heading()
,
),
self.car_size,
Motion::new(-1e-3, self.car_size.max_steer()),
);
let max_to_slot = match geometry::intersect_circle_line(
self.slot.border[3], c.size.length,
self.slot.border[1], self.slot.border[2],
) {
Some((i1, i2)) => {
geometry::angle_between_closer(
c.rr(), self.slot.border[3], i1, i2
)
},
None => panic!("there must be intersection"),
};
let mut a_to_slot = 0.0;
let d_to_slot = 1e-4;
while a_to_slot < max_to_slot {
a_to_slot += d_to_slot;
c.pose.rotate(self.slot.border[3], d_to_slot);
let ccl_rr = geometry::edist(c.ccl(), c.rr());
let ccl_p1 = geometry::edist(c.ccl(), self.slot.border[0]);
if ccl_rr < ccl_p1 { continue; } queue.push(c);
}
let mut goals: Vec<(u8, Vec<BCar>)> = Vec::new();
while let Some(mut c) = queue.pop() {
goals.push(self.drive_in_the_slot(&mut c));
}
let mut min = goals[0].0;
for g in &goals {
if g.0 < min { min = g.0; }
}
let mut min_goals: Vec<(u8, Vec<BCar>)> = Vec::new();
for g in goals {
if g.0 == min { min_goals.push(g); }
}
let mut outs: Vec<(u8, Vec<BCar>)> = Vec::new();
for g in &min_goals {
let mut c = g.1[g.1.len() - 1];
c.motion.speed *= -1.0;
outs.push(self.drive_out_of_slot(&mut c));
}
let mut min = outs[0].0;
for o in &outs {
if o.0 < min { min = o.0; }
}
let mut min_outs: Vec<(u8, Vec<BCar>)> = Vec::new();
for o in outs {
if o.0 == min { min_outs.push(o); }
}
let mut goals: Vec<BCar> = Vec::new();
for o in &min_outs {
goals.push(o.1[0]);
}
goals
}
pub fn find_entries_by_bfs(&self) -> PoseRange {
let goals = self.find_goals_by_bfs();
let mut entries: Vec<BCar> = Vec::new();
for g in goals {
let mut c = g;
let out = self.drive_out_of_slot(&mut c);
entries.push(out.1[out.1.len() - 1]);
}
PoseRange::from_poses(entries[0].pose, entries[entries.len() - 1].pose)
}
}