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 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 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 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 dist = dist.min(max);
138
139 (dist, Ok(None))
140 }
141}