Bound complete member displacement across large origins
This commit is contained in:
@@ -70,10 +70,12 @@ fn center(
|
||||
Ok(center)
|
||||
}
|
||||
|
||||
fn translate(value: f32, delta: f32) -> Result<f32, ModelError> {
|
||||
let next = value + delta;
|
||||
if !next.is_finite() || ((f64::from(next) - f64::from(value)) - f64::from(delta)).abs() > 0.001
|
||||
{
|
||||
fn translate(value: f32, old_origin: f32, new_origin: f32) -> Result<f32, ModelError> {
|
||||
// Bound the complete displacement, including origin subtraction. A rounded
|
||||
// f32 delta can hide lost relative precision even when its addition is exact.
|
||||
let intended = f64::from(value) + (f64::from(new_origin) - f64::from(old_origin));
|
||||
let next = intended as f32;
|
||||
if !next.is_finite() || (f64::from(next) - intended).abs() > 0.001 {
|
||||
return Err(error("boundary member translation precision exceeded"));
|
||||
}
|
||||
Ok(next)
|
||||
@@ -355,18 +357,17 @@ pub(super) fn reorder(
|
||||
for (&c, y) in after.iter().zip(ys) {
|
||||
charge(work, groups[g].blocks[c].members.len() + 1)?;
|
||||
let old = groups[g].blocks[c].position.y;
|
||||
let delta = y - old;
|
||||
if !y.is_finite() || !delta.is_finite() {
|
||||
if !y.is_finite() {
|
||||
return Err(error("boundary packing overflow"));
|
||||
}
|
||||
if delta != 0.0 {
|
||||
if y != old {
|
||||
changed.push(c);
|
||||
}
|
||||
for id in &groups[g].blocks[c].members {
|
||||
let p = offsets
|
||||
.get_mut(id)
|
||||
.ok_or_else(|| error("boundary lost member offset"))?;
|
||||
p.y = translate(p.y, delta)?;
|
||||
p.y = translate(p.y, old, y)?;
|
||||
}
|
||||
groups[g].blocks[c].position.y = y;
|
||||
}
|
||||
@@ -666,7 +667,20 @@ mod tests {
|
||||
center(id(3), &parents, &offsets, &sizes, &mut 0).unwrap(),
|
||||
45.1015625
|
||||
);
|
||||
assert_eq!(translate(10.125, 0.375).unwrap(), 10.5);
|
||||
assert!(translate(32768.0, 0.002).is_err());
|
||||
assert_eq!(translate(10.125, 0.0, 0.375).unwrap(), 10.5);
|
||||
assert!(translate(32768.0, 0.0, 0.002).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn member_offset_survives_large_origin_subtraction() {
|
||||
let blocks = vec![
|
||||
block(1, 0.0, 65404.0),
|
||||
block(2, 65436.0, 68.0),
|
||||
block(3, 65536.0, 100.0),
|
||||
block(4, 65668.0, 68.002),
|
||||
];
|
||||
let ys = packing(&blocks, &[0, 1, 2, 3], &[3, 2, 1, 0], 32.0).unwrap();
|
||||
let member = translate(65568.0, 65536.0, ys[1]).unwrap();
|
||||
assert!((f64::from(member) - f64::from(ys[1]) - 32.0).abs() <= 0.001);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user