BREP_RANSAC 0.1.2

Topology-aware analytic surface recognition for CAD triangle meshes
Documentation
use brep_ransac::{
    constrain_cylinder_coaxial, constrain_plane_perpendicular_to_axis, reconstruct_surface,
    synthetic, AnalyticSurface, CylinderSurface, PlaneSurface, RecognitionOptions, SamplingMode,
    SurfaceHint, SurfaceType, Vec3,
};

fn options() -> RecognitionOptions {
    RecognitionOptions {
        distance_tolerance: 1.0e-6,
        normal_tolerance: 0.1,
        minimum_support: 4,
        sampling: SamplingMode::Vertices,
        ..RecognitionOptions::default()
    }
}

#[test]
fn cylinder_axis_can_be_constrained_to_an_existing_cylinder() {
    let reference = AnalyticSurface::Cylinder(CylinderSurface {
        axis_origin: Vec3::new(2.0, -1.0, 0.0),
        axis: Vec3::Z,
        radius: 8.0,
    });
    let truth = AnalyticSurface::Cylinder(CylinderSurface {
        axis_origin: Vec3::new(2.0, -1.0, 10.0),
        axis: Vec3::Z,
        radius: 3.0,
    });
    let mesh = synthetic::partial(truth, 20);
    let ids = (0..mesh.triangles.len()).collect::<Vec<_>>();
    let hint = constrain_cylinder_coaxial(
        CylinderSurface {
            axis_origin: Vec3::new(2.1, -0.9, 3.0),
            axis: Vec3::new(0.01, 0.0, 0.99995).normalized().unwrap(),
            radius: 2.9,
        },
        reference,
    )
    .unwrap();
    let fit = reconstruct_surface(&mesh, &ids, &hint, &options()).unwrap();
    let AnalyticSurface::Cylinder(result) = fit.surface else {
        unreachable!()
    };
    assert_eq!(result.axis, Vec3::Z);
    assert!((result.axis_origin.x - 2.0).abs() < 1.0e-12);
    assert!((result.axis_origin.y + 1.0).abs() < 1.0e-12);
    assert!((result.radius - 3.0).abs() < 1.0e-8);
}

#[test]
fn plane_can_be_constrained_perpendicular_to_a_known_axis() {
    let truth = AnalyticSurface::Plane(PlaneSurface {
        origin: Vec3::new(0.0, 0.0, 4.0),
        normal: Vec3::Z,
    });
    let mesh = synthetic::partial(truth, 16);
    let ids = (0..mesh.triangles.len()).collect::<Vec<_>>();
    let hint = constrain_plane_perpendicular_to_axis(
        PlaneSurface {
            origin: Vec3::new(0.0, 0.0, 3.9),
            normal: Vec3::new(0.01, -0.02, 0.99975).normalized().unwrap(),
        },
        Vec3::Z,
    )
    .unwrap();
    let SurfaceHint::Constrained { constraints, .. } = &hint else {
        unreachable!()
    };
    assert!(constraints.fixed.axis_or_normal);
    assert!(!constraints.fixed.origin_or_center);
    let fit = reconstruct_surface(&mesh, &ids, &hint, &options()).unwrap();
    assert_eq!(fit.surface.surface_type(), SurfaceType::Plane);
    let AnalyticSurface::Plane(result) = fit.surface else {
        unreachable!()
    };
    assert_eq!(result.normal, Vec3::Z);
    assert!((result.origin.z - 4.0).abs() < 1.0e-12);
}