1use crate::MapError;
8use rstar::{AABB, RTree, RTreeObject};
9
10pub const MAX_SAMPLES: usize = 50_000_000;
11pub const MAX_SIMPLICES: usize = 100_000_000;
12pub const RCOND_LIMIT: f64 = 1000.0 * f64::EPSILON;
14
15#[derive(Clone)]
16struct Triangle {
17 id: u32,
18 bounds: AABB<[f64; 2]>,
19 a: [f64; 2],
20 u: [f64; 2],
21 v: [f64; 2],
22 determinant: f64,
23 z: [f64; 3],
24}
25
26impl RTreeObject for Triangle {
27 type Envelope = AABB<[f64; 2]>;
28 fn envelope(&self) -> Self::Envelope {
29 self.bounds
30 }
31}
32
33impl Triangle {
34 #[inline]
36 fn at(&self, p: [f64; 2]) -> Option<f64> {
37 let x = p[0] - self.a[0];
38 let y = p[1] - self.a[1];
39 let b = (x * self.v[1] - y * self.v[0]) / self.determinant;
40 let c = (self.u[0] * y - self.u[1] * x) / self.determinant;
41 let a = 1.0 - b - c;
42 let eps = 100.0 * f64::EPSILON;
43 if a >= -eps && b >= -eps && c >= -eps {
44 Some(a * self.z[0] + b * self.z[1] + c * self.z[2])
45 } else {
46 None
47 }
48 }
49}
50
51fn rcond(u: [f64; 2], v: [f64; 2], det: f64) -> f64 {
53 let norm = (u[0].abs() + u[1].abs()).max(v[0].abs() + v[1].abs());
54 let inv = (v[1].abs() + u[1].abs()).max(v[0].abs() + u[0].abs()) / det.abs();
55 1.0 / (norm * inv)
56}
57
58pub struct PreparedInterpolator {
59 tree: RTree<Triangle>,
60 pub samples: usize,
61 pub simplices_supplied: usize,
62 pub triangles_valid: usize,
63 pub degenerate_skipped: usize,
64}
65
66impl PreparedInterpolator {
67 pub fn new(samples: &[[f64; 3]], simplices: &[[usize; 3]]) -> Result<Self, MapError> {
68 if samples.len() > MAX_SAMPLES || simplices.len() > MAX_SIMPLICES {
69 return Err(MapError::Budget(format!(
70 "samples {} / simplices {} exceed limits {MAX_SAMPLES} / {MAX_SIMPLICES}",
71 samples.len(),
72 simplices.len()
73 )));
74 }
75 if let Some(i) = samples
76 .iter()
77 .position(|s| !s.iter().all(|x| x.is_finite()))
78 {
79 return Err(MapError::Invalid(format!("sample {i} is not finite")));
80 }
81 let mut triangles = Vec::with_capacity(simplices.len());
82 let mut degenerate = 0usize;
83 for (id, t) in simplices.iter().enumerate() {
84 if let Some(bad) = t.iter().find(|i| **i >= samples.len()) {
85 return Err(MapError::Invalid(format!(
86 "simplex {id} index {bad} out of bounds for {} samples",
87 samples.len()
88 )));
89 }
90 let (a, b, c) = (samples[t[0]], samples[t[1]], samples[t[2]]);
91 let u = [b[0] - a[0], b[1] - a[1]];
92 let v = [c[0] - a[0], c[1] - a[1]];
93 if !u.iter().chain(v.iter()).all(|x| x.is_finite()) {
94 return Err(MapError::Invalid(format!(
95 "simplex {id} edge vector overflows"
96 )));
97 }
98 let determinant = u[0] * v[1] - u[1] * v[0];
99 if !determinant.is_finite() {
100 return Err(MapError::Invalid(format!(
101 "simplex {id} determinant overflows"
102 )));
103 }
104 if determinant == 0.0 || rcond(u, v, determinant) < RCOND_LIMIT {
105 degenerate += 1;
106 continue;
107 }
108 triangles.push(Triangle {
109 id: id as u32,
110 a: [a[0], a[1]],
111 u,
112 v,
113 determinant,
114 z: [a[2], b[2], c[2]],
115 bounds: AABB::from_corners(
116 [a[0].min(b[0]).min(c[0]), a[1].min(b[1]).min(c[1])],
117 [a[0].max(b[0]).max(c[0]), a[1].max(b[1]).max(c[1])],
118 ),
119 });
120 }
121 let valid = triangles.len();
122 Ok(Self {
123 tree: RTree::bulk_load(triangles),
124 samples: samples.len(),
125 simplices_supplied: simplices.len(),
126 triangles_valid: valid,
127 degenerate_skipped: degenerate,
128 })
129 }
130
131 #[inline]
133 pub fn locate(&self, p: [f64; 2]) -> Option<(u32, f64)> {
134 let mut best: Option<(u32, f64)> = None;
135 for t in self
136 .tree
137 .locate_in_envelope_intersecting(AABB::from_point(p))
138 {
139 if let Some(z) = t.at(p)
140 && best.is_none_or(|(id, _)| t.id < id)
141 {
142 best = Some((t.id, z));
143 }
144 }
145 best
146 }
147
148 pub fn approx_bytes(&self) -> u64 {
150 (self.triangles_valid as u64) * prepared_bytes_per_simplex()
151 }
152}
153
154pub fn triangle_bytes() -> u64 {
156 std::mem::size_of::<Triangle>() as u64
157}
158
159pub fn prepared_bytes_per_simplex() -> u64 {
161 triangle_bytes() + 48
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn plane_and_lowest_id_tie() {
170 let s = [[0., 0., 0.], [1., 0., 1.], [0., 1., 1.], [1., 1., 2.]];
171 let p = PreparedInterpolator::new(&s, &[[1, 2, 3], [0, 1, 2]]).unwrap();
173 let (id, z) = p.locate([0.5, 0.5]).unwrap();
174 assert_eq!(id, 0);
175 assert!((z - 1.0).abs() < 1e-15);
176 assert!(p.locate([2.0, 2.0]).is_none());
177 }
178
179 #[test]
180 fn degenerate_skipped_and_counted() {
181 let s = [[0., 0., 0.], [1., 0., 1.], [2., 0., 2.], [0., 1., 1.]];
182 let p = PreparedInterpolator::new(&s, &[[0, 1, 2], [0, 1, 3], [0, 0, 3]]).unwrap();
183 assert_eq!(p.degenerate_skipped, 2);
184 assert_eq!(p.triangles_valid, 1);
185 assert_eq!(p.locate([0.25, 0.25]).unwrap().0, 1);
187 }
188
189 #[test]
190 fn near_degenerate_sliver_skipped() {
191 let s = [[0., 0., 0.], [1., 0., 1.], [0.5, 1e-14, 1.]];
192 let p = PreparedInterpolator::new(&s, &[[0, 1, 2]]).unwrap();
193 assert_eq!(p.degenerate_skipped, 1);
194 }
195
196 #[test]
197 fn invalid_inputs_fail() {
198 let s = [[0., 0., 0.], [1., 0., 1.], [0., 1., f64::NAN]];
199 assert!(PreparedInterpolator::new(&s, &[[0, 1, 2]]).is_err());
200 let s = [[0., 0., 0.], [1., 0., 1.], [0., 1., 1.]];
201 assert!(PreparedInterpolator::new(&s, &[[0, 1, 3]]).is_err());
202 let s = [[-1e308, 0., 0.], [1e308, 0., 1.], [0., 1e308, 1.]];
203 assert!(PreparedInterpolator::new(&s, &[[0, 1, 2]]).is_err());
204 }
205}