Skip to main content

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