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 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 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 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 dist = dist.min(max);
149
150 (dist, Ok(None))
151 }
152}