use super::tracks;
use crate::check::{Check, CheckCtx};
use crate::finding::{Finding, Severity};
use crate::model::TrackValues;
pub const VEC3_TOLERANCE: f32 = 1e-4;
pub const QUAT_TOLERANCE_RAD: f32 = 1e-3;
pub struct ConstantTrack;
impl Check for ConstantTrack {
fn id(&self) -> &'static str {
"constant-track"
}
fn run(&self, ctx: &CheckCtx, out: &mut Vec<Finding>) {
let doc = ctx.doc;
for (clip, bone, track) in tracks(doc) {
if track.key_count() < 2 {
continue; }
let constant = match &track.values {
TrackValues::Vec3s(_) => {
let Some(first) = track.key_vec3(0) else {
continue;
};
(1..track.key_count()).all(|k| {
track
.key_vec3(k)
.is_some_and(|v| (v - first).abs().max_element() <= VEC3_TOLERANCE)
})
}
TrackValues::Quats(_) => {
let Some(first) = track.key_quat(0) else {
continue;
};
if !first.is_finite() || first.length_squared() == 0.0 {
continue; }
(1..track.key_count()).all(|k| {
track.key_quat(k).is_some_and(|q| {
q.is_finite()
&& first.normalize().angle_between(q.normalize())
<= QUAT_TOLERANCE_RAD
})
})
}
};
if constant {
out.push(
Finding::new(
self.id(),
Severity::Note,
format!(
"{} track has {} keys but never moves — export bloat",
track.property.as_str(),
track.key_count()
),
)
.clip(clip)
.bone(bone),
);
}
}
}
}