use crate::data::{AnyDataArray, DataArray, PolyData};
#[derive(Debug, Clone)]
pub struct MeshDiff {
pub max_position_diff: f64,
pub avg_position_diff: f64,
pub points_a: usize,
pub points_b: usize,
pub cells_a: usize,
pub cells_b: usize,
pub same_topology: bool,
pub identical: bool,
}
impl std::fmt::Display for MeshDiff {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.identical {
write!(f, "Identical")
} else {
write!(f, "Different: max_pos_diff={:.6}, points={}vs{}, cells={}vs{}, same_topo={}",
self.max_position_diff, self.points_a, self.points_b,
self.cells_a, self.cells_b, self.same_topology)
}
}
}
pub fn diff(a: &PolyData, b: &PolyData) -> MeshDiff {
let points_a = a.points.len();
let points_b = b.points.len();
let cells_a = a.polys.num_cells();
let cells_b = b.polys.num_cells();
let same_count = points_a == points_b && cells_a == cells_b;
let same_topology = same_count && {
a.polys.iter().zip(b.polys.iter()).all(|(ca, cb)| ca == cb)
};
let (max_diff, avg_diff) = if points_a == points_b && points_a > 0 {
let mut max_d = 0.0f64;
let mut sum_d = 0.0f64;
for i in 0..points_a {
let pa = a.points.get(i);
let pb = b.points.get(i);
let d = ((pa[0]-pb[0]).powi(2) + (pa[1]-pb[1]).powi(2) + (pa[2]-pb[2]).powi(2)).sqrt();
max_d = max_d.max(d);
sum_d += d;
}
(max_d, sum_d / points_a as f64)
} else {
(f64::INFINITY, f64::INFINITY)
};
let identical = same_topology && max_diff < 1e-10;
MeshDiff {
max_position_diff: max_diff,
avg_position_diff: avg_diff,
points_a, points_b, cells_a, cells_b,
same_topology, identical,
}
}
pub fn displacement_field(a: &PolyData, b: &PolyData) -> Option<PolyData> {
if a.points.len() != b.points.len() { return None; }
let mut result = a.clone();
let n = a.points.len();
let mut disp = Vec::with_capacity(n * 3);
for i in 0..n {
let pa = a.points.get(i);
let pb = b.points.get(i);
disp.push(pb[0] - pa[0]);
disp.push(pb[1] - pa[1]);
disp.push(pb[2] - pa[2]);
}
let arr = DataArray::from_vec("Displacement", disp, 3);
result.point_data_mut().add_array(AnyDataArray::F64(arr));
result.point_data_mut().set_active_vectors("Displacement");
Some(result)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn identical_meshes() {
let a = PolyData::from_triangles(
vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
vec![[0, 1, 2]],
);
let d = diff(&a, &a);
assert!(d.identical);
assert!(d.same_topology);
assert!(d.max_position_diff < 1e-10);
}
#[test]
fn different_positions() {
let a = PolyData::from_triangles(
vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
vec![[0, 1, 2]],
);
let b = PolyData::from_triangles(
vec![[0.0, 0.0, 0.0], [2.0, 0.0, 0.0], [0.0, 2.0, 0.0]],
vec![[0, 1, 2]],
);
let d = diff(&a, &b);
assert!(!d.identical);
assert!(d.same_topology);
assert!(d.max_position_diff > 0.5);
}
#[test]
fn different_topology() {
let a = PolyData::from_triangles(
vec![[0.0; 3], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
vec![[0, 1, 2]],
);
let b = PolyData::from_triangles(
vec![[0.0; 3], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0]],
vec![[0, 1, 2], [1, 3, 2]],
);
let d = diff(&a, &b);
assert!(!d.identical);
assert!(!d.same_topology);
}
#[test]
fn displacement() {
let a = PolyData::from_triangles(
vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
vec![[0, 1, 2]],
);
let b = PolyData::from_triangles(
vec![[0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 1.0, 1.0]],
vec![[0, 1, 2]],
);
let result = displacement_field(&a, &b).unwrap();
assert!(result.point_data().vectors().is_some());
}
#[test]
fn display() {
let a = PolyData::from_triangles(
vec![[0.0; 3], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
vec![[0, 1, 2]],
);
let d = diff(&a, &a);
assert_eq!(format!("{d}"), "Identical");
}
}