#![allow(dead_code)]
use std::f32::consts::PI;
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct HipWidth {
pub width: f32,
pub depth: f32,
pub height: f32,
}
#[allow(dead_code)]
pub fn default_hip_width() -> HipWidth {
HipWidth {
width: 0.5,
depth: 0.5,
height: 0.5,
}
}
#[allow(dead_code)]
pub fn apply_hip_width(weights: &mut [f32], hw: &HipWidth) {
if !weights.is_empty() {
weights[0] = hw.width;
}
if weights.len() > 1 {
weights[1] = hw.depth;
}
if weights.len() > 2 {
weights[2] = hw.height;
}
}
#[allow(dead_code)]
pub fn hip_width_blend(a: &HipWidth, b: &HipWidth, t: f32) -> HipWidth {
let t = t.clamp(0.0, 1.0);
HipWidth {
width: a.width + (b.width - a.width) * t,
depth: a.depth + (b.depth - a.depth) * t,
height: a.height + (b.height - a.height) * t,
}
}
#[allow(dead_code)]
pub fn hip_ratio(hw: &HipWidth) -> f32 {
if hw.depth.abs() < f32::EPSILON {
return 1.0;
}
hw.width / hw.depth
}
#[allow(dead_code)]
pub fn hip_circumference_approx(hw: &HipWidth, scale_m: f32) -> f32 {
let a = hw.width * scale_m;
let b = hw.depth * scale_m;
let h = (a - b).powi(2) / ((a + b).powi(2) + f32::EPSILON);
PI * (a + b) * (1.0 + (3.0 * h) / (10.0 + (4.0 - 3.0 * h).sqrt()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_hip_width() {
let hw = default_hip_width();
assert!((hw.width - 0.5).abs() < 1e-6);
assert!((hw.depth - 0.5).abs() < 1e-6);
assert!((hw.height - 0.5).abs() < 1e-6);
}
#[test]
fn test_apply_hip_width_full() {
let hw = HipWidth {
width: 0.6,
depth: 0.4,
height: 0.7,
};
let mut w = [0.0f32; 3];
apply_hip_width(&mut w, &hw);
assert!((w[0] - 0.6).abs() < 1e-6);
assert!((w[1] - 0.4).abs() < 1e-6);
assert!((w[2] - 0.7).abs() < 1e-6);
}
#[test]
fn test_apply_hip_width_short_slice() {
let hw = default_hip_width();
let mut w = [0.0f32; 1];
apply_hip_width(&mut w, &hw);
assert!((w[0] - 0.5).abs() < 1e-6);
}
#[test]
fn test_apply_hip_width_empty() {
let hw = default_hip_width();
let mut w: [f32; 0] = [];
apply_hip_width(&mut w, &hw); }
#[test]
fn test_blend_at_zero() {
let a = default_hip_width();
let b = HipWidth {
width: 1.0,
depth: 1.0,
height: 1.0,
};
let r = hip_width_blend(&a, &b, 0.0);
assert!((r.width - 0.5).abs() < 1e-6);
}
#[test]
fn test_blend_at_one() {
let a = default_hip_width();
let b = HipWidth {
width: 1.0,
depth: 1.0,
height: 1.0,
};
let r = hip_width_blend(&a, &b, 1.0);
assert!((r.width - 1.0).abs() < 1e-6);
}
#[test]
fn test_blend_clamps_t() {
let a = default_hip_width();
let b = HipWidth {
width: 1.0,
depth: 0.8,
height: 0.9,
};
let r = hip_width_blend(&a, &b, -1.0);
assert!((r.width - a.width).abs() < 1e-6);
}
#[test]
fn test_hip_ratio_equal_axes() {
let hw = HipWidth {
width: 0.5,
depth: 0.5,
height: 0.5,
};
assert!((hip_ratio(&hw) - 1.0).abs() < 1e-6);
}
#[test]
fn test_hip_ratio_wide() {
let hw = HipWidth {
width: 1.0,
depth: 0.5,
height: 0.5,
};
assert!((hip_ratio(&hw) - 2.0).abs() < 1e-6);
}
#[test]
fn test_hip_circumference_positive() {
let hw = default_hip_width();
let c = hip_circumference_approx(&hw, 0.5);
assert!(c > 0.0);
}
}