#![allow(dead_code)]
#[allow(clippy::needless_range_loop)]
pub fn scale_faces(positions: &mut [[f32; 3]], indices: &[u32], face_mask: &[bool], scale: f32) {
let face_count = indices.len() / 3;
let flen = face_mask.len().min(face_count);
for fi in 0..flen {
if !face_mask[fi] {
continue;
}
let i0 = indices[fi * 3] as usize;
let i1 = indices[fi * 3 + 1] as usize;
let i2 = indices[fi * 3 + 2] as usize;
let cx = (positions[i0][0] + positions[i1][0] + positions[i2][0]) / 3.0;
let cy = (positions[i0][1] + positions[i1][1] + positions[i2][1]) / 3.0;
let cz = (positions[i0][2] + positions[i1][2] + positions[i2][2]) / 3.0;
for vi in [i0, i1, i2] {
positions[vi][0] = cx + (positions[vi][0] - cx) * scale;
positions[vi][1] = cy + (positions[vi][1] - cy) * scale;
positions[vi][2] = cz + (positions[vi][2] - cz) * scale;
}
}
}
pub fn scale_edges(
positions: &mut [[f32; 3]],
edges: &[[usize; 2]],
edge_mask: &[bool],
scale: f32,
) {
let len = edges.len().min(edge_mask.len());
for i in 0..len {
if !edge_mask[i] {
continue;
}
let [a, b] = edges[i];
let mx = (positions[a][0] + positions[b][0]) * 0.5;
let my = (positions[a][1] + positions[b][1]) * 0.5;
let mz = (positions[a][2] + positions[b][2]) * 0.5;
positions[a][0] = mx + (positions[a][0] - mx) * scale;
positions[a][1] = my + (positions[a][1] - my) * scale;
positions[a][2] = mz + (positions[a][2] - mz) * scale;
positions[b][0] = mx + (positions[b][0] - mx) * scale;
positions[b][1] = my + (positions[b][1] - my) * scale;
positions[b][2] = mz + (positions[b][2] - mz) * scale;
}
}
pub fn face_centroid(positions: &[[f32; 3]], indices: &[u32], face_index: usize) -> [f32; 3] {
let i0 = indices[face_index * 3] as usize;
let i1 = indices[face_index * 3 + 1] as usize;
let i2 = indices[face_index * 3 + 2] as usize;
[
(positions[i0][0] + positions[i1][0] + positions[i2][0]) / 3.0,
(positions[i0][1] + positions[i1][1] + positions[i2][1]) / 3.0,
(positions[i0][2] + positions[i1][2] + positions[i2][2]) / 3.0,
]
}
pub fn selected_face_count(face_mask: &[bool]) -> usize {
face_mask.iter().filter(|&&v| v).count()
}
#[cfg(test)]
mod tests {
use super::*;
fn square_mesh() -> (Vec<[f32; 3]>, Vec<u32>) {
let pos = vec![
[0.0_f32, 0.0, 0.0],
[1.0, 0.0, 0.0],
[1.0, 1.0, 0.0],
[0.0, 1.0, 0.0],
];
let idx = vec![0u32, 1, 2, 0, 2, 3];
(pos, idx)
}
#[test]
fn test_scale_faces_identity() {
let (mut pos, idx) = square_mesh();
let original = pos.clone();
scale_faces(&mut pos, &idx, &[true, false], 1.0);
for (p, o) in pos.iter().zip(original.iter()) {
assert!((p[0] - o[0]).abs() < 1e-6);
}
}
#[test]
fn test_scale_faces_shrinks() {
let (mut pos, idx) = square_mesh();
scale_faces(&mut pos, &idx, &[true, false], 0.0);
let cx = (0.0 + 1.0 + 1.0) / 3.0;
assert!((pos[0][0] - cx).abs() < 1e-5);
}
#[test]
fn test_selected_face_count() {
assert_eq!(selected_face_count(&[true, false, true]), 2);
}
#[test]
fn test_face_centroid() {
let (pos, idx) = square_mesh();
let c = face_centroid(&pos, &idx, 0);
assert!((c[0] - 2.0 / 3.0).abs() < 1e-5);
}
#[test]
fn test_scale_edges_shrinks() {
let mut pos = vec![[0.0_f32, 0.0, 0.0], [2.0, 0.0, 0.0]];
scale_edges(&mut pos, &[[0, 1]], &[true], 0.0);
assert!((pos[0][0] - 1.0).abs() < 1e-5);
assert!((pos[1][0] - 1.0).abs() < 1e-5);
}
#[test]
fn test_scale_edges_identity() {
let mut pos = vec![[0.0_f32, 0.0, 0.0], [2.0, 0.0, 0.0]];
let orig = pos.clone();
scale_edges(&mut pos, &[[0, 1]], &[true], 1.0);
assert!((pos[0][0] - orig[0][0]).abs() < 1e-6);
}
#[test]
fn test_scale_unselected_face_unchanged() {
let (mut pos, idx) = square_mesh();
let p3_before = pos[3];
scale_faces(&mut pos, &idx, &[false, false], 0.0);
assert!((pos[3][0] - p3_before[0]).abs() < 1e-6);
}
}