#![allow(dead_code)]
pub struct UvRotateAlignResult {
pub rotation_deg: f32,
pub vertex_count: usize,
}
pub fn edge_uv_angle_deg(uv0: [f32; 2], uv1: [f32; 2]) -> f32 {
let du = uv1[0] - uv0[0];
let dv = uv1[1] - uv0[1];
dv.atan2(du).to_degrees()
}
pub fn rotate_align_edge(
uvs: &mut [[f32; 2]],
edge_v0: usize,
edge_v1: usize,
) -> UvRotateAlignResult {
if edge_v0 >= uvs.len() || edge_v1 >= uvs.len() {
return UvRotateAlignResult {
rotation_deg: 0.0,
vertex_count: 0,
};
}
let angle = edge_uv_angle_deg(uvs[edge_v0], uvs[edge_v1]);
let rotation = -angle;
let rad = rotation.to_radians();
let cos_a = rad.cos();
let sin_a = rad.sin();
let pivot = uvs[edge_v0];
for uv in uvs.iter_mut() {
let du = uv[0] - pivot[0];
let dv = uv[1] - pivot[1];
uv[0] = pivot[0] + du * cos_a - dv * sin_a;
uv[1] = pivot[1] + du * sin_a + dv * cos_a;
}
UvRotateAlignResult {
rotation_deg: rotation,
vertex_count: uvs.len(),
}
}
pub fn rotate_island(uvs: &mut [[f32; 2]], angle_deg: f32) {
if uvs.is_empty() {
return;
}
let mut cu = 0.0f32;
let mut cv = 0.0f32;
for uv in uvs.iter() {
cu += uv[0];
cv += uv[1];
}
let n = uvs.len() as f32;
cu /= n;
cv /= n;
let rad = angle_deg.to_radians();
let cos_a = rad.cos();
let sin_a = rad.sin();
for uv in uvs.iter_mut() {
let du = uv[0] - cu;
let dv = uv[1] - cv;
uv[0] = cu + du * cos_a - dv * sin_a;
uv[1] = cv + du * sin_a + dv * cos_a;
}
}
pub fn edge_is_horizontal(uv0: [f32; 2], uv1: [f32; 2], tol: f32) -> bool {
(uv1[1] - uv0[1]).abs() < tol
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn edge_angle_horizontal_is_zero() {
let angle = edge_uv_angle_deg([0.0, 0.0], [1.0, 0.0]);
assert!(angle.abs() < 1e-5 );
}
#[test]
fn edge_angle_vertical_is_90() {
let angle = edge_uv_angle_deg([0.0, 0.0], [0.0, 1.0]);
assert!((angle - 90.0).abs() < 1e-4 );
}
#[test]
fn rotate_align_makes_edge_horizontal() {
let mut uvs = vec![[0.0f32, 0.0], [0.0, 1.0], [1.0, 0.5]];
rotate_align_edge(&mut uvs, 0, 1);
assert!(edge_is_horizontal(uvs[0], uvs[1], 1e-4) );
}
#[test]
fn rotate_align_out_of_bounds_returns_zero() {
let mut uvs = vec![[0.0f32, 0.0], [1.0, 0.0]];
let res = rotate_align_edge(&mut uvs, 0, 99);
assert_eq!(res.vertex_count, 0 );
}
#[test]
fn rotate_island_360_is_identity() {
let mut uvs = vec![[0.5f32, 0.2], [0.8, 0.6], [0.1, 0.9]];
let original = uvs.clone();
rotate_island(&mut uvs, 360.0);
for (a, b) in uvs.iter().zip(original.iter()) {
assert!((a[0] - b[0]).abs() < 1e-5 );
assert!((a[1] - b[1]).abs() < 1e-5 );
}
}
#[test]
fn rotate_island_empty_no_panic() {
let mut uvs: Vec<[f32; 2]> = vec![];
rotate_island(&mut uvs, 45.0);
assert_eq!(uvs.len(), 0 );
}
#[test]
fn edge_is_horizontal_true() {
assert!(edge_is_horizontal([0.0, 0.5], [1.0, 0.5], 1e-4) );
}
#[test]
fn edge_is_horizontal_false() {
assert!(!edge_is_horizontal([0.0, 0.0], [1.0, 1.0], 1e-4) );
}
#[test]
fn rotate_align_returns_count() {
let mut uvs = vec![[0.0f32, 0.0], [1.0, 0.0], [0.5, 1.0]];
let res = rotate_align_edge(&mut uvs, 0, 1);
assert_eq!(res.vertex_count, 3 );
}
}