#![allow(dead_code)]
pub struct TaperParams {
pub factor: f32,
pub axis: u8,
pub limit_min: f32,
pub limit_max: f32,
}
pub fn new_taper_params(factor: f32, axis: u8) -> TaperParams {
TaperParams {
factor,
axis,
limit_min: -1.0,
limit_max: 1.0,
}
}
pub fn taper_vertex(p: [f32; 3], params: &TaperParams) -> [f32; 3] {
let range = params.limit_max - params.limit_min;
match params.axis {
0 => {
let t = if range.abs() < 1e-10 {
0.5
} else {
((p[0] - params.limit_min) / range).clamp(0.0, 1.0)
};
let scale = taper_scale_at(params, t);
[p[0], p[1] * scale, p[2] * scale]
}
1 => {
let t = if range.abs() < 1e-10 {
0.5
} else {
((p[1] - params.limit_min) / range).clamp(0.0, 1.0)
};
let scale = taper_scale_at(params, t);
[p[0] * scale, p[1], p[2] * scale]
}
_ => {
let t = if range.abs() < 1e-10 {
0.5
} else {
((p[2] - params.limit_min) / range).clamp(0.0, 1.0)
};
let scale = taper_scale_at(params, t);
[p[0] * scale, p[1] * scale, p[2]]
}
}
}
pub fn taper_scale_at(params: &TaperParams, t: f32) -> f32 {
1.0 + params.factor * t
}
pub fn taper_volume_ratio(params: &TaperParams) -> f32 {
let f = params.factor;
1.0 + f + f * f / 3.0
}
pub fn taper_is_uniform(params: &TaperParams) -> bool {
params.factor.abs() < 1e-10
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_taper_params() {
let p = new_taper_params(0.5, 2);
assert!((p.factor - 0.5).abs() < 1e-6);
assert_eq!(p.axis, 2);
}
#[test]
fn test_taper_vertex_at_base() {
let params = new_taper_params(2.0, 2);
let v = [1.0f32, 1.0, -1.0];
let out = taper_vertex(v, ¶ms);
assert!((out[0] - 1.0).abs() < 1e-5);
}
#[test]
fn test_taper_scale_at_zero() {
let params = new_taper_params(3.0, 2);
assert!((taper_scale_at(¶ms, 0.0) - 1.0).abs() < 1e-6);
}
#[test]
fn test_taper_scale_at_one() {
let params = new_taper_params(0.5, 2);
assert!((taper_scale_at(¶ms, 1.0) - 1.5).abs() < 1e-6);
}
#[test]
fn test_taper_is_uniform_true() {
let params = new_taper_params(0.0, 2);
assert!(taper_is_uniform(¶ms));
}
#[test]
fn test_taper_volume_ratio_no_factor() {
let params = new_taper_params(0.0, 2);
assert!((taper_volume_ratio(¶ms) - 1.0).abs() < 1e-6);
}
#[test]
fn test_taper_axis0_scales_yz() {
let params = TaperParams {
factor: 1.0,
axis: 0,
limit_min: 0.0,
limit_max: 1.0,
};
let v = [1.0f32, 1.0, 1.0];
let out = taper_vertex(v, ¶ms);
assert!((out[0] - 1.0).abs() < 1e-5, "x must be unchanged");
assert!((out[1] - 2.0).abs() < 1e-5, "y should be scaled by factor");
assert!((out[2] - 2.0).abs() < 1e-5, "z should be scaled by factor");
}
#[test]
fn test_taper_axis1_scales_xz() {
let params = TaperParams {
factor: 1.0,
axis: 1,
limit_min: 0.0,
limit_max: 1.0,
};
let v = [1.0f32, 1.0, 1.0];
let out = taper_vertex(v, ¶ms);
assert!((out[1] - 1.0).abs() < 1e-5, "y must be unchanged");
assert!((out[0] - 2.0).abs() < 1e-5, "x should be scaled by factor");
assert!((out[2] - 2.0).abs() < 1e-5, "z should be scaled by factor");
}
#[test]
fn test_taper_axis0_differs_from_axis2() {
let p0 = TaperParams { factor: 0.5, axis: 0, limit_min: 0.0, limit_max: 2.0 };
let p2 = TaperParams { factor: 0.5, axis: 2, limit_min: 0.0, limit_max: 2.0 };
let v = [1.0f32, 1.0, 1.0];
assert!(
taper_vertex(v, &p0) != taper_vertex(v, &p2),
"axis=0 and axis=2 must produce different results"
);
}
}