#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct VertexSlideResult {
pub positions: Vec<[f32; 3]>,
pub moved: bool,
}
pub fn slide_vertex(
positions: &[[f32; 3]],
vertex: usize,
target_neighbor: usize,
factor: f32,
) -> VertexSlideResult {
let factor = factor.clamp(0.0, 1.0);
let mut new_pos = positions.to_vec();
let a = positions[vertex];
let b = positions[target_neighbor];
new_pos[vertex] = [
a[0] + (b[0] - a[0]) * factor,
a[1] + (b[1] - a[1]) * factor,
a[2] + (b[2] - a[2]) * factor,
];
VertexSlideResult {
positions: new_pos,
moved: factor > 0.0,
}
}
pub fn slide_vertices(positions: &[[f32; 3]], slides: &[(usize, usize, f32)]) -> VertexSlideResult {
let mut new_pos = positions.to_vec();
let mut moved = false;
for &(vertex, target, factor) in slides {
let factor = factor.clamp(0.0, 1.0);
let a = new_pos[vertex];
let b = positions[target];
new_pos[vertex] = [
a[0] + (b[0] - a[0]) * factor,
a[1] + (b[1] - a[1]) * factor,
a[2] + (b[2] - a[2]) * factor,
];
if factor > 0.0 {
moved = true;
}
}
VertexSlideResult {
positions: new_pos,
moved,
}
}
pub fn vertex_distance(positions: &[[f32; 3]], a: usize, b: usize) -> f32 {
let dx = positions[a][0] - positions[b][0];
let dy = positions[a][1] - positions[b][1];
let dz = positions[a][2] - positions[b][2];
(dx * dx + dy * dy + dz * dz).sqrt()
}
pub fn nearest_neighbor(
positions: &[[f32; 3]],
vertex: usize,
candidates: &[usize],
) -> Option<usize> {
candidates.iter().copied().min_by(|&a, &b| {
let da = vertex_distance(positions, vertex, a);
let db = vertex_distance(positions, vertex, b);
da.partial_cmp(&db).unwrap_or(std::cmp::Ordering::Equal)
})
}
pub fn slide_to_json(result: &VertexSlideResult) -> String {
format!(
"{{\"vertices\":{},\"moved\":{}}}",
result.positions.len(),
result.moved
)
}
pub fn vertex_slide_position(
positions: &[[f32; 3]],
v: usize,
target: usize,
factor: f32,
) -> [f32; 3] {
let factor = factor.clamp(0.0, 1.0);
let a = positions[v];
let b = positions[target];
[
a[0] + (b[0] - a[0]) * factor,
a[1] + (b[1] - a[1]) * factor,
a[2] + (b[2] - a[2]) * factor,
]
}
pub fn vertex_slide_toward_nearest(
positions: &[[f32; 3]],
v: usize,
candidates: &[usize],
factor: f32,
) -> [f32; 3] {
match nearest_neighbor(positions, v, candidates) {
Some(n) => vertex_slide_position(positions, v, n, factor),
None => positions[v],
}
}
pub fn vertex_slide_clamp(factor: f32) -> f32 {
factor.clamp(0.0, 1.0)
}
pub fn vertex_edge_direction(positions: &[[f32; 3]], v: usize, target: usize) -> [f32; 3] {
let a = positions[v];
let b = positions[target];
let dx = b[0] - a[0];
let dy = b[1] - a[1];
let dz = b[2] - a[2];
let len = (dx * dx + dy * dy + dz * dz).sqrt();
if len < f32::EPSILON {
return [0.0; 3];
}
[dx / len, dy / len, dz / len]
}
pub fn vertex_slide_offset(
positions: &[[f32; 3]],
v: usize,
target: usize,
distance: f32,
) -> [f32; 3] {
let dir = vertex_edge_direction(positions, v, target);
let p = positions[v];
[
p[0] + dir[0] * distance,
p[1] + dir[1] * distance,
p[2] + dir[2] * distance,
]
}
#[cfg(test)]
mod tests {
use super::*;
fn line_verts() -> Vec<[f32; 3]> {
vec![[0.0, 0.0, 0.0], [2.0, 0.0, 0.0], [4.0, 0.0, 0.0]]
}
#[test]
fn test_slide_half() {
let pos = line_verts();
let r = slide_vertex(&pos, 0, 1, 0.5);
assert!((r.positions[0][0] - 1.0).abs() < 1e-5);
}
#[test]
fn test_slide_full() {
let pos = line_verts();
let r = slide_vertex(&pos, 0, 1, 1.0);
assert!((r.positions[0][0] - 2.0).abs() < 1e-5);
}
#[test]
fn test_slide_zero_not_moved() {
let pos = line_verts();
let r = slide_vertex(&pos, 0, 1, 0.0);
assert!(!r.moved);
}
#[test]
fn test_vertex_slide_position() {
let pos = line_verts();
let p = vertex_slide_position(&pos, 0, 1, 0.5);
assert!((p[0] - 1.0).abs() < 1e-5);
}
#[test]
fn test_vertex_edge_direction() {
let pos = line_verts();
let d = vertex_edge_direction(&pos, 0, 1);
assert!((d[0] - 1.0).abs() < 1e-5);
}
#[test]
fn test_vertex_slide_offset() {
let pos = line_verts();
let p = vertex_slide_offset(&pos, 0, 1, 1.0);
assert!((p[0] - 1.0).abs() < 1e-5);
}
#[test]
fn test_vertex_slide_toward_nearest() {
let pos = line_verts();
let p = vertex_slide_toward_nearest(&pos, 0, &[1, 2], 1.0);
assert!((p[0] - 2.0).abs() < 1e-5);
}
}