veloren_common/
ray.rs

1use crate::vol::ReadVol;
2use vek::*;
3
4pub trait RayForEach<V> = FnMut(&V, Vec3<i32>);
5
6pub struct Ray<'a, V: ReadVol, F: FnMut(&V::Vox) -> bool, G: RayForEach<V::Vox>> {
7    vol: &'a V,
8    from: Vec3<f32>,
9    to: Vec3<f32>,
10    until: F,
11    is_while: bool,
12    for_each: Option<G>,
13    max_iter: usize,
14    ignore_error: bool,
15}
16
17impl<'a, V, F, G> Ray<'a, V, F, G>
18where
19    V: ReadVol,
20    F: FnMut(&V::Vox) -> bool,
21    G: RayForEach<V::Vox>,
22{
23    pub fn new(vol: &'a V, from: Vec3<f32>, to: Vec3<f32>, until: F) -> Self {
24        Self {
25            vol,
26            from,
27            to,
28            until,
29            is_while: false,
30            for_each: None,
31            max_iter: 100,
32            ignore_error: false,
33        }
34    }
35
36    pub fn until<H: FnMut(&V::Vox) -> bool>(self, f: H) -> Ray<'a, V, H, G> {
37        Ray {
38            vol: self.vol,
39            from: self.from,
40            to: self.to,
41            until: f,
42            is_while: false,
43            for_each: self.for_each,
44            max_iter: self.max_iter,
45            ignore_error: self.ignore_error,
46        }
47    }
48
49    pub fn while_<H: FnMut(&V::Vox) -> bool>(self, f: H) -> Ray<'a, V, H, G> {
50        Ray {
51            vol: self.vol,
52            from: self.from,
53            to: self.to,
54            until: f,
55            is_while: true,
56            for_each: self.for_each,
57            max_iter: self.max_iter,
58            ignore_error: self.ignore_error,
59        }
60    }
61
62    pub fn for_each<H: RayForEach<V::Vox>>(self, f: H) -> Ray<'a, V, F, H> {
63        Ray {
64            for_each: Some(f),
65            vol: self.vol,
66            from: self.from,
67            to: self.to,
68            is_while: self.is_while,
69            until: self.until,
70            max_iter: self.max_iter,
71            ignore_error: self.ignore_error,
72        }
73    }
74
75    #[must_use]
76    pub fn max_iter(mut self, max_iter: usize) -> Self {
77        self.max_iter = max_iter;
78        self
79    }
80
81    #[must_use]
82    pub fn ignore_error(mut self) -> Self {
83        self.ignore_error = true;
84        self
85    }
86
87    pub fn cast(mut self) -> (f32, Result<Option<&'a V::Vox>, V::Error>) {
88        // TODO: Fully test this!
89
90        const PLANCK: f32 = 0.001;
91
92        let mut dist = 0.0;
93        let dir = (self.to - self.from).normalized();
94        let max = (self.to - self.from).magnitude();
95
96        for _ in 0..self.max_iter {
97            // Allow one iteration above max.
98            if dist > max {
99                break;
100            }
101            let pos = self.from + dir * dist;
102            let ipos = pos.map(|e| e.floor() as i32);
103
104            let vox = self.vol.get(ipos);
105
106            if self.is_while {
107                let vox = match vox.map(|vox| (vox, (self.until)(vox))) {
108                    Ok((vox, true)) => return (dist, Ok(Some(vox))),
109                    Ok((vox, _)) => Some(vox),
110                    Err(err) if !self.ignore_error => return (dist, Err(err)),
111                    _ => None,
112                };
113
114                if let Some((vox, g)) = vox.zip(self.for_each.as_mut()) {
115                    g(vox, ipos);
116                }
117            } else {
118                // for_each
119                if let Some((vox, g)) = vox.as_ref().ok().zip(self.for_each.as_mut()) {
120                    g(vox, ipos);
121                }
122
123                match vox.map(|vox| (vox, (self.until)(vox))) {
124                    Ok((vox, true)) => return (dist, Ok(Some(vox))),
125                    Err(err) if !self.ignore_error => return (dist, Err(err)),
126                    _ => {},
127                }
128            }
129
130            let deltas =
131                (dir.map(|e| if e < 0.0 { 0.0 } else { 1.0 }) - pos.map(|e| e.abs().fract())) / dir;
132
133            dist += deltas.reduce(f32::min).max(PLANCK);
134        }
135
136        // The ray can go over the maximum magnitude in the last iteration
137        dist = dist.min(max);
138
139        (dist, Ok(None))
140    }
141}