Snap an (already range-clamped) value to a discrete dimension's
min + k·step grid, keeping the result inside [min, max]. Anchoring at the
declared minimum makes offset exports such as 1/6/11 reachable with step 5.
The range comparisons carry the SAME step-relative epsilon as
SceneDimsManager.defaultPosition, and for the same reason: an
exactly on-grid end can round an ulp past itself (Math.round(0.7/0.1)*0.1
= 0.7000000000000001, Math.round(0.9/0.3)*0.3 = 0.8999999999999999), and
a strict comparison would then step a whole cell inward — making the
first/last frame of a fractional-step dimension unreachable. A sub-epsilon
excursion keeps its exact grid value rather than being clamped, so the
position stays byte-identical to the one defaultPosition computes for the
same target (viewStatesEqual / S-cache keys compare exact floats).
Exported so the animation prefetcher (DimensionAnimationManager.
peekNextValue) can predict EXACTLY the value setDimensionValue will land
on — the t+1 prefetch and the playhead must agree even when a loop wrap
targets an off-grid range end.
Snap an (already range-clamped) value to a discrete dimension's
min + k·stepgrid, keeping the result inside [min, max]. Anchoring at the declared minimum makes offset exports such as 1/6/11 reachable with step 5.The range comparisons carry the SAME step-relative epsilon as SceneDimsManager.defaultPosition, and for the same reason: an exactly on-grid end can round an ulp past itself (
Math.round(0.7/0.1)*0.1= 0.7000000000000001,Math.round(0.9/0.3)*0.3= 0.8999999999999999), and a strict comparison would then step a whole cell inward — making the first/last frame of a fractional-step dimension unreachable. A sub-epsilon excursion keeps its exact grid value rather than being clamped, so the position stays byte-identical to the one defaultPosition computes for the same target (viewStatesEqual / S-cache keys compare exact floats).Exported so the animation prefetcher (DimensionAnimationManager. peekNextValue) can predict EXACTLY the value setDimensionValue will land on — the t+1 prefetch and the playhead must agree even when a loop wrap targets an off-grid range end.