bsp_pathfinding/tree/
portal.rs

1use std::ops::Deref;
2
3use glam::Vec2;
4
5use crate::{util::face_intersect, Face, NodeIndex};
6
7#[derive(Debug, Clone, Copy, PartialEq)]
8/// Represents a surface connecting two nodes
9pub struct Portal<'a> {
10    pub(crate) face: &'a Face,
11
12    pub(crate) portal_ref: PortalRef,
13}
14
15impl<'a> Portal<'a> {
16    /// Get the portal's portal ref.
17    pub fn portal_ref(&self) -> PortalRef {
18        self.portal_ref
19    }
20
21    pub fn dst(&self) -> NodeIndex {
22        self.portal_ref.dst
23    }
24
25    /// Get the portal's src.
26    pub fn src(&self) -> NodeIndex {
27        self.portal_ref.src
28    }
29
30    /// Returns the normal which points into the portal
31    pub fn normal(&self) -> Vec2 {
32        self.portal_ref.normal
33    }
34
35    /// Get the portal's face.
36    pub fn face(&self) -> &Face {
37        self.face
38    }
39
40    // Returns true if the line is contained on the surface of the portal
41    pub(crate) fn try_clip(&self, start: Vec2, end: Vec2, margin: f32) -> Option<Vec2> {
42        let (l, r) = self.apply_margin(margin).into_tuple();
43        let p = face_intersect((l, r), start, (end - start).perp());
44
45        // let rel = (p - self.vertices[0]).dot(self.vertices[1] - self.vertices[0]);
46        if p.distance > 0.0 && p.distance < 1.0 {
47            Some(p.point)
48        } else {
49            None
50        }
51    }
52
53    pub(crate) fn clip(&self, start: Vec2, end: Vec2, margin: f32) -> Vec2 {
54        let (l, r) = self.apply_margin(margin).into_tuple();
55        let p = face_intersect((l, r), start, (end - start).perp());
56
57        // let rel = (p - self.vertices[0]).dot(self.vertices[1] - self.vertices[0]);
58        if p.distance < 0.0 {
59            l
60        } else if p.distance > 1.0 {
61            r
62        } else {
63            p.point
64        }
65    }
66
67    pub fn apply_margin(&self, margin: f32) -> Face {
68        let dir = self.face.dir();
69        let l = self.face.vertices[0] + margin * dir * self.adjacent[0] as i32 as f32;
70        let r = self.face.vertices[1] - margin * dir * self.adjacent[1] as i32 as f32;
71        Face::new([l, r])
72    }
73}
74
75impl<'a> Deref for Portal<'a> {
76    type Target = PortalRef;
77
78    fn deref(&self) -> &Self::Target {
79        &self.portal_ref
80    }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq)]
84/// References a portal
85#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
86pub struct PortalRef {
87    pub(crate) src: NodeIndex,
88    pub(crate) dst: NodeIndex,
89    pub(crate) face: usize,
90    pub(crate) adjacent: [bool; 2],
91    // Normal may be different than the face due to the normal pointing through
92    // the portal
93    pub(crate) normal: Vec2,
94}
95
96impl PortalRef {
97    /// Returns the normal which points into the portal
98    pub fn normal(&self) -> Vec2 {
99        self.normal
100    }
101
102    /// Get the portal ref's src.
103    pub fn src(&self) -> NodeIndex {
104        self.src
105    }
106
107    /// Get the portal ref's dst.
108    pub fn dst(&self) -> NodeIndex {
109        self.dst
110    }
111
112    /// Get a mutable reference to the portal ref's normal.
113    pub fn normal_mut(&mut self) -> &mut Vec2 {
114        &mut self.normal
115    }
116
117    /// Get the portal ref's adjacent.
118    pub fn adjacent(&self) -> [bool; 2] {
119        self.adjacent
120    }
121}