dimforge / ncollide

2 and 3-dimensional collision detection library in Rust.
https://ncollide.org
Apache License 2.0
921 stars 107 forks source link

Convex hull computation results skewed when using f32 #352

Closed bellwether-softworks closed 3 years ago

bellwether-softworks commented 3 years ago

When using the transformation::convex_hull function to process a series of points, results diverge between f64 and f32 types. Consider the following trivial example:

use nalgebra::Point3;

type T = f64;

fn main() {
    let points: Vec<Point3<T>> = vec![
        Point3::new(-0.75, -1.75, -44.583675),
        Point3::new(-0.75, 1.75, -44.583675),
        Point3::new(-0.75, -1.75, 44.583675),
        Point3::new(0.75, -1.75, 44.583675),
        Point3::new(0.75, 1.75, 44.583675),
        Point3::new(-0.75, 1.75, 44.583675),
        Point3::new(0.75, -1.75, -43.37378),
        Point3::new(0.75, 1.75, -43.37378),
    ];

    let hull = ncollide3d::transformation::convex_hull(&points[..]);

    hull.coords.iter()
        .for_each(|pt| println!("{:?}", pt));
}

The resulting output is, as expected, roughly identical to the input points:

Point { coords: Matrix { data: [-0.7499999999738924, -1.7500000000001088, -44.58367499848073] } }
Point { coords: Matrix { data: [-0.7499999999738924, 1.750000000000089, -44.583674998480234] } }
Point { coords: Matrix { data: [-0.7500000000260676, -1.750000000000089, 44.583675001540286] } }
Point { coords: Matrix { data: [0.7499999999738924, -1.750000000000089, 44.583674998480234] } }
Point { coords: Matrix { data: [0.7499999999738924, 1.7500000000001088, 44.58367499848073] } }
Point { coords: Matrix { data: [-0.7500000000260675, 1.7500000000001088, 44.583675001540776] } }
Point { coords: Matrix { data: [0.7500000000253595, -1.7500000000001086, -43.373780001540496] } }
Point { coords: Matrix { data: [0.7500000000253596, 1.750000000000089, -43.37378000154] } }

However, when changing the type T to f32, the results are:

Point { coords: Matrix { data: [-0.73202866, -1.7499257, -43.57128] } }
Point { coords: Matrix { data: [-0.73202866, 1.749931, -43.571415] } }
Point { coords: Matrix { data: [-0.76763266, -1.749931, 45.66003] } }
Point { coords: Matrix { data: [0.73202866, -1.749931, 43.571415] } }
Point { coords: Matrix { data: [0.73202866, 1.7499257, 43.57128] } }
Point { coords: Matrix { data: [-0.76763266, 1.7499257, 45.659897] } }
Point { coords: Matrix { data: [0.7671495, -1.7499257, -44.449135] } }
Point { coords: Matrix { data: [0.7671495, 1.749931, -44.449265] } }

If rendering, it becomes clear that the f32-based shape (which was originally derived from a cuboid's corner points) is skewed: image

bellwether-softworks commented 3 years ago

After experimentation, it was found that the use of the improved_fixed_point_support feature results in correct output in both f32 and f64 scenarios.