parry icon indicating copy to clipboard operation
parry copied to clipboard

mesh_intersection between two meshes with co-planner triangles crashes the test

Open piaoger opened this issue 1 year ago • 2 comments

I found a couple of issues while playing with parry for mesh intersections. Even after upgrading to 0.17.3, I still find below test result for co-planner meshes is still crash with below message. Hope my test case is helpful.

thread 'test::test_mesh_intersection_2' panicked at /home/user/.cargo/registry/src/rsproxy.cn-0dccff568467c15b/spade-2.12.1/src/cdt.rs:550:53:
Constraint edges must not intersect.
stack backtrace:
   0: rust_begin_unwind
   1: core::panicking::panic_fmt
   2: spade::cdt::ConstrainedDelaunayTriangulation<V,DE,UE,F,L>::add_constraint
   3: spade::delaunay_core::bulk_load::bulk_load_stable
   4: parry3d_f64::transformation::mesh_intersection::mesh_intersection::merge_triangle_sets
   5: parry3d_f64::transformation::mesh_intersection::mesh_intersection::intersect_meshes_with_tolerances
   6: basalt_clash::test::test_mesh_intersection_2
   7: core::ops::function::FnOnce::call_once
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
test test::test_mesh_intersection_2 ... FAILED

two meshes with co-planner triangles

e4a99aa9001e792db8d0e9c2127d660

test code

#[cfg(test)]
mod test {
    use nalgebra::{Point3, Vector3};
    use obj::Obj;
    use obj::ObjData;
    use parry3d_f64::math::{Isometry, Real};
    use parry3d_f64::shape::{TriMesh, TriMeshFlags};
    use parry3d_f64::transformation::intersect_meshes_with_tolerances;
    use std::path::PathBuf;

    fn load_trimesh_from_obj(objfile: &str) -> TriMesh {
        let Obj {
            data: ObjData {
                position, objects, ..
            },
            ..
        } = Obj::load(objfile).unwrap();

        let mesh = TriMesh::with_flags(
            position
                .iter()
                .map(|v| Point3::new(v[0] as Real, v[1] as Real, v[2] as Real))
                .collect::<Vec<_>>(),
            objects[0].groups[0]
                .polys
                .iter()
                .map(|p| [p.0[0].0 as u32, p.0[1].0 as u32, p.0[2].0 as u32])
                .collect::<Vec<_>>(),
            TriMeshFlags::all(),
        );

        mesh
    }

    #[test]
    fn test_mesh_intersection_2() {
        let colliders = vec!["1.obj", "2.obj"];

        let mesh_a = load_trimesh_from_obj(&colliders[0]);
        let mesh_b = load_trimesh_from_obj(&colliders[1]);

        mesh_a.to_obj_file(&PathBuf::from(format!("intersection_test-2-a.obj")));
        mesh_b.to_obj_file(&PathBuf::from(format!("intersection_test-2-b.obj")));

        let mut tolerance = parry3d_f64::transformation::MeshIntersectionTolerances::default();
        tolerance.global_insertion_epsilon = 0.001;
        tolerance.angle_epsilon = (0.1_f64).to_radians();

        let mut result = intersect_meshes_with_tolerances(
            &Isometry::identity(),
            &mesh_a,
            false,
            &Isometry::translation(0.0, 0.0, 0.0),
            &mesh_b,
            false,
            tolerance,
        )
        .unwrap();

        if let Some(result) = result {
            let _ = result.to_obj_file(&PathBuf::from("intersection_test_result.obj"));
        }
    }
}

sample obj files

See attched objs.zip objs.zip

piaoger avatar Nov 24 '24 15:11 piaoger

  • Thanks for the report! I worked on https://github.com/Stoeoef/spade/pull/137 which will enable this scenario to at least not panic when integrated into parry. I'm not sure if this will result in a correct result though, but that's a first step 🤞

ThierryBerger avatar Jun 27 '25 11:06 ThierryBerger

The "no panic" strategy will be helpful. I had to make the intersection test out of process and just skip the empty result pairs.

piaoger avatar Jun 30 '25 10:06 piaoger