#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct CopyScaleConstraint {
pub target_scale: [f32; 3],
pub copy_x: bool,
pub copy_y: bool,
pub copy_z: bool,
pub power: f32,
pub influence: f32,
pub label: String,
}
pub fn new_copy_scale(target_scale: [f32; 3], label: &str) -> CopyScaleConstraint {
CopyScaleConstraint {
target_scale,
copy_x: true,
copy_y: true,
copy_z: true,
power: 1.0,
influence: 1.0,
label: label.to_owned(),
}
}
pub fn apply_copy_scale(c: &CopyScaleConstraint, source: [f32; 3]) -> [f32; 3] {
let blend_s = |src: f32, tgt: f32| {
let powered = tgt.powf(c.power);
src + (powered - src) * c.influence
};
[
if c.copy_x {
blend_s(source[0], c.target_scale[0])
} else {
source[0]
},
if c.copy_y {
blend_s(source[1], c.target_scale[1])
} else {
source[1]
},
if c.copy_z {
blend_s(source[2], c.target_scale[2])
} else {
source[2]
},
]
}
pub fn active_scale_axis_count(c: &CopyScaleConstraint) -> usize {
[c.copy_x, c.copy_y, c.copy_z]
.iter()
.filter(|&&b| b)
.count()
}
pub fn is_uniform_target(c: &CopyScaleConstraint) -> bool {
let [x, y, z] = c.target_scale;
(x - y).abs() < 1e-6 && (y - z).abs() < 1e-6
}
pub fn copy_scale_to_json(c: &CopyScaleConstraint) -> String {
format!(
r#"{{"label":"{}", "influence":{:.4}, "power":{:.4}, "copy_x":{}, "copy_y":{}, "copy_z":{}}}"#,
c.label, c.influence, c.power, c.copy_x, c.copy_y, c.copy_z
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_all_axes_active() {
let c = new_copy_scale([1.0; 3], "sc");
assert_eq!(active_scale_axis_count(&c), 3);
}
#[test]
fn apply_full_influence_copies_target() {
let c = new_copy_scale([2.0, 3.0, 4.0], "sc");
let out = apply_copy_scale(&c, [1.0; 3]);
assert!((out[0] - 2.0).abs() < 1e-5);
assert!((out[1] - 3.0).abs() < 1e-5);
assert!((out[2] - 4.0).abs() < 1e-5);
}
#[test]
fn apply_zero_influence_leaves_source() {
let mut c = new_copy_scale([5.0; 3], "sc");
c.influence = 0.0;
let out = apply_copy_scale(&c, [2.0, 3.0, 4.0]);
assert!((out[0] - 2.0).abs() < 1e-5);
}
#[test]
fn disabled_z_leaves_z() {
let mut c = new_copy_scale([9.0; 3], "sc");
c.copy_z = false;
let out = apply_copy_scale(&c, [1.0, 1.0, 0.5]);
assert!((out[2] - 0.5).abs() < 1e-5);
}
#[test]
fn active_axis_count_one_disabled() {
let mut c = new_copy_scale([1.0; 3], "sc");
c.copy_y = false;
assert_eq!(active_scale_axis_count(&c), 2);
}
#[test]
fn is_uniform_target_for_uniform_scale() {
let c = new_copy_scale([2.0, 2.0, 2.0], "sc");
assert!(is_uniform_target(&c));
}
#[test]
fn is_uniform_target_false_for_non_uniform() {
let c = new_copy_scale([1.0, 2.0, 3.0], "sc");
assert!(!is_uniform_target(&c));
}
#[test]
fn json_contains_label() {
let c = new_copy_scale([1.0; 3], "myScale");
assert!(copy_scale_to_json(&c).contains("myScale"));
}
#[test]
fn default_influence_is_one() {
let c = new_copy_scale([1.0; 3], "sc");
assert!((c.influence - 1.0).abs() < 1e-6);
}
}