diff --git a/crates/opencascade-sys/src/lib.rs b/crates/opencascade-sys/src/lib.rs index fdb36a51..62814356 100644 --- a/crates/opencascade-sys/src/lib.rs +++ b/crates/opencascade-sys/src/lib.rs @@ -940,6 +940,9 @@ pub mod ffi { pub fn BRepIntCurveSurface_Inter_point( intersector: &BRepIntCurveSurface_Inter, ) -> UniquePtr; + pub fn U(self: &BRepIntCurveSurface_Inter) -> f64; + pub fn V(self: &BRepIntCurveSurface_Inter) -> f64; + pub fn W(self: &BRepIntCurveSurface_Inter) -> f64; // BRepFeat type BRepFeat_MakeCylindricalHole; diff --git a/crates/opencascade/src/primitives/shape.rs b/crates/opencascade/src/primitives/shape.rs index c0a67c24..0cb135fb 100644 --- a/crates/opencascade/src/primitives/shape.rs +++ b/crates/opencascade/src/primitives/shape.rs @@ -542,12 +542,12 @@ impl Shape { } // TODO(bschwind) - Convert the return type to an iterator. - pub fn faces_along_ray(&self, ray_start: DVec3, ray_dir: DVec3) -> Vec<(Face, DVec3)> { + pub fn faces_along_line(&self, line_origin: DVec3, line_dir: DVec3) -> Vec { let mut intersector = ffi::BRepIntCurveSurface_Inter_ctor(); let tolerance = 0.0001; intersector.pin_mut().Init( &self.inner, - &ffi::gp_Lin_ctor(&make_point(ray_start), &make_dir(ray_dir)), + &ffi::gp_Lin_ctor(&make_point(line_origin), &make_dir(line_dir)), tolerance, ); @@ -558,7 +558,13 @@ impl Shape { let face = Face::from_face(&face); let point = ffi::BRepIntCurveSurface_Inter_point(&intersector); - results.push((face, dvec3(point.X(), point.Y(), point.Z()))); + results.push(LineFaceHitPoint { + face, + t: intersector.W(), + u: intersector.U(), + v: intersector.V(), + point: dvec3(point.X(), point.Y(), point.Z()), + }); intersector.pin_mut().Next(); } @@ -605,3 +611,17 @@ impl Shape { Self::from_shape(make_hole.pin_mut().Shape()) } } + +/// Information about a point where a line hits (i.e. intersects) a face +pub struct LineFaceHitPoint { + /// The face that is hit + pub face: Face, + /// The T parameter along the line + pub t: f64, + /// The U parameter on the face + pub u: f64, + /// The V parameter on the face + pub v: f64, + /// The intersection point + pub point: DVec3, +} diff --git a/examples/src/keycap.rs b/examples/src/keycap.rs index 435b2bf3..da666931 100644 --- a/examples/src/keycap.rs +++ b/examples/src/keycap.rs @@ -210,16 +210,12 @@ pub fn shape() -> Shape { // TODO(bschwind) - Abstract all this into a "extrude_to_next_face" function. let origin = workplane.to_world_pos(dvec3(*x, *y, 0.0)); - let mut faces = keycap.faces_along_ray(origin, workplane.normal()); - faces.sort_by(|(_, a_point), (_, b_point)| { - let a_dist = (*a_point - origin).length(); - let b_dist = (*b_point - origin).length(); - - a_dist.total_cmp(&b_dist) - }); - - let (face_target, _) = faces.get(0).expect("We should have a face to extrude to"); - let post = circle.extrude_to_face(&keycap, face_target); + let faces = keycap.faces_along_line(origin, workplane.normal()); + let nearest_hit = faces + .iter() + .min_by(|hit_a, hit_b| hit_a.t.partial_cmp(&hit_b.t).unwrap()) + .expect("We should have a face to extrude to"); + let post = circle.extrude_to_face(&keycap, &nearest_hit.face); keycap = keycap.union(&post).into(); }