use std::ops::Deref;
use glam::Vec2;
use crate::{util::face_intersect, Face, NodeIndex};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Portal<'a> {
pub(crate) face: &'a Face,
pub(crate) portal_ref: PortalRef,
}
impl<'a> Portal<'a> {
pub fn portal_ref(&self) -> PortalRef {
self.portal_ref
}
pub fn dst(&self) -> NodeIndex {
self.portal_ref.dst
}
pub fn src(&self) -> NodeIndex {
self.portal_ref.src
}
pub fn normal(&self) -> Vec2 {
self.portal_ref.normal
}
pub fn face(&self) -> &Face {
self.face
}
pub(crate) fn try_clip(&self, start: Vec2, end: Vec2, margin: f32) -> Option<Vec2> {
let (l, r) = self.apply_margin(margin).into_tuple();
let p = face_intersect((l, r), start, (end - start).perp());
if p.distance > 0.0 && p.distance < 1.0 {
Some(p.point)
} else {
None
}
}
pub(crate) fn clip(&self, start: Vec2, end: Vec2, margin: f32) -> Vec2 {
let (l, r) = self.apply_margin(margin).into_tuple();
let p = face_intersect((l, r), start, (end - start).perp());
if p.distance < 0.0 {
l
} else if p.distance > 1.0 {
r
} else {
p.point
}
}
pub fn apply_margin(&self, margin: f32) -> Face {
let dir = self.face.dir();
let l = self.face.vertices[0] + margin * dir * self.adjacent[0] as i32 as f32;
let r = self.face.vertices[1] - margin * dir * self.adjacent[1] as i32 as f32;
Face::new([l, r])
}
}
impl<'a> Deref for Portal<'a> {
type Target = PortalRef;
fn deref(&self) -> &Self::Target {
&self.portal_ref
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub struct PortalRef {
pub(crate) src: NodeIndex,
pub(crate) dst: NodeIndex,
pub(crate) face: usize,
pub(crate) adjacent: [bool; 2],
pub(crate) normal: Vec2,
}
impl PortalRef {
pub fn normal(&self) -> Vec2 {
self.normal
}
pub fn src(&self) -> NodeIndex {
self.src
}
pub fn dst(&self) -> NodeIndex {
self.dst
}
pub fn normal_mut(&mut self) -> &mut Vec2 {
&mut self.normal
}
pub fn adjacent(&self) -> [bool; 2] {
self.adjacent
}
}