#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ScalarAttr {
pub name: String,
pub values: Vec<f32>,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct Vec3Attr {
pub name: String,
pub values: Vec<[f32; 3]>,
}
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TransferMethod {
NearestNeighbour,
Barycentric,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct TransferResult {
pub scalar_attrs: Vec<ScalarAttr>,
pub vec3_attrs: Vec<Vec3Attr>,
pub target_vertex_count: usize,
}
#[allow(dead_code)]
pub fn sq_dist(a: [f32; 3], b: [f32; 3]) -> f32 {
let d = [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
d[0] * d[0] + d[1] * d[1] + d[2] * d[2]
}
#[allow(dead_code)]
pub fn nearest_vertex(query: [f32; 3], source_pos: &[[f32; 3]]) -> usize {
source_pos
.iter()
.enumerate()
.map(|(i, &p)| (i, sq_dist(query, p)))
.min_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal))
.map(|(i, _)| i)
.unwrap_or(0)
}
#[allow(dead_code)]
pub fn transfer_scalar_nn(
src_pos: &[[f32; 3]],
src_attr: &ScalarAttr,
tgt_pos: &[[f32; 3]],
) -> ScalarAttr {
let values = tgt_pos
.iter()
.map(|&q| {
let ni = nearest_vertex(q, src_pos);
src_attr.values[ni]
})
.collect();
ScalarAttr {
name: src_attr.name.clone(),
values,
}
}
#[allow(dead_code)]
pub fn transfer_vec3_nn(
src_pos: &[[f32; 3]],
src_attr: &Vec3Attr,
tgt_pos: &[[f32; 3]],
) -> Vec3Attr {
let values = tgt_pos
.iter()
.map(|&q| {
let ni = nearest_vertex(q, src_pos);
src_attr.values[ni]
})
.collect();
Vec3Attr {
name: src_attr.name.clone(),
values,
}
}
#[allow(dead_code)]
pub fn barycentric(p: [f32; 3], a: [f32; 3], b: [f32; 3], c: [f32; 3]) -> Option<[f32; 3]> {
let v0 = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
let v1 = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
let v2 = [p[0] - a[0], p[1] - a[1], p[2] - a[2]];
let d00 = dot(v0, v0);
let d01 = dot(v0, v1);
let d11 = dot(v1, v1);
let d20 = dot(v2, v0);
let d21 = dot(v2, v1);
let denom = d00 * d11 - d01 * d01;
if denom.abs() < 1e-8 {
return None;
}
let v = (d11 * d20 - d01 * d21) / denom;
let w = (d00 * d21 - d01 * d20) / denom;
let u = 1.0 - v - w;
Some([u, v, w])
}
fn dot(a: [f32; 3], b: [f32; 3]) -> f32 {
a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
#[allow(dead_code)]
pub fn scale_scalar_attr(attr: &mut ScalarAttr, factor: f32) {
for v in &mut attr.values {
*v *= factor;
}
}
#[allow(dead_code)]
pub fn attrs_same_name(a: &ScalarAttr, b: &ScalarAttr) -> bool {
a.name == b.name
}
#[cfg(test)]
mod tests {
use super::*;
fn three_pts() -> Vec<[f32; 3]> {
vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]
}
fn attr_ones() -> ScalarAttr {
ScalarAttr {
name: "w".to_string(),
values: vec![1.0, 2.0, 3.0],
}
}
#[test]
fn test_sq_dist_zero() {
assert!((sq_dist([1.0, 2.0, 3.0], [1.0, 2.0, 3.0])).abs() < 1e-6);
}
#[test]
fn test_nearest_vertex() {
let src = three_pts();
let idx = nearest_vertex([0.9, 0.0, 0.0], &src);
assert_eq!(idx, 1);
}
#[test]
fn test_transfer_scalar_nn() {
let src = three_pts();
let attr = attr_ones();
let tgt = vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]];
let out = transfer_scalar_nn(&src, &attr, &tgt);
assert!((out.values[0] - 1.0).abs() < 1e-6);
assert!((out.values[1] - 2.0).abs() < 1e-6);
}
#[test]
fn test_transfer_vec3_nn() {
let src = three_pts();
let v3 = Vec3Attr {
name: "n".to_string(),
values: vec![[0.0, 0.0, 1.0]; 3],
};
let tgt = vec![[0.5, 0.0, 0.0]];
let out = transfer_vec3_nn(&src, &v3, &tgt);
assert!((out.values[0][2] - 1.0).abs() < 1e-6);
}
#[test]
fn test_barycentric_centroid() {
let a = [0.0_f32, 0.0, 0.0];
let b = [1.0, 0.0, 0.0];
let c = [0.0, 1.0, 0.0];
let p = [1.0 / 3.0, 1.0 / 3.0, 0.0];
let bary = barycentric(p, a, b, c).expect("should succeed");
assert!((bary[0] - 1.0 / 3.0).abs() < 1e-5);
assert!((bary[1] - 1.0 / 3.0).abs() < 1e-5);
assert!((bary[2] - 1.0 / 3.0).abs() < 1e-5);
}
#[test]
fn test_scale_scalar_attr() {
let mut a = attr_ones();
scale_scalar_attr(&mut a, 2.0);
assert!((a.values[0] - 2.0).abs() < 1e-6);
}
#[test]
fn test_attrs_same_name_true() {
let a = ScalarAttr {
name: "x".to_string(),
values: vec![],
};
let b = ScalarAttr {
name: "x".to_string(),
values: vec![],
};
assert!(attrs_same_name(&a, &b));
}
#[test]
fn test_attrs_same_name_false() {
let a = ScalarAttr {
name: "x".to_string(),
values: vec![],
};
let b = ScalarAttr {
name: "y".to_string(),
values: vec![],
};
assert!(!attrs_same_name(&a, &b));
}
#[test]
fn test_transfer_empty_target() {
let src = three_pts();
let attr = attr_ones();
let out = transfer_scalar_nn(&src, &attr, &[]);
assert!(out.values.is_empty());
}
#[test]
fn test_nearest_vertex_exact_match() {
let src = three_pts();
let idx = nearest_vertex([0.0, 1.0, 0.0], &src);
assert_eq!(idx, 2);
}
}