From e88e5fb4de999985b13c5cdbc194a93f4def8176 Mon Sep 17 00:00:00 2001 From: Mate Kovacs Date: Thu, 19 Oct 2023 00:14:25 +0900 Subject: [PATCH 1/4] WIP things --- crates/opencascade-sys/include/wrapper.hxx | 1 + crates/opencascade-sys/src/lib.rs | 16 ++++++++++++++++ crates/opencascade/src/primitives/face.rs | 13 +++++++++++++ 3 files changed, 30 insertions(+) diff --git a/crates/opencascade-sys/include/wrapper.hxx b/crates/opencascade-sys/include/wrapper.hxx index f12c9bbd..2b310462 100644 --- a/crates/opencascade-sys/include/wrapper.hxx +++ b/crates/opencascade-sys/include/wrapper.hxx @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/crates/opencascade-sys/src/lib.rs b/crates/opencascade-sys/src/lib.rs index fbbd2579..e5d59adc 100644 --- a/crates/opencascade-sys/src/lib.rs +++ b/crates/opencascade-sys/src/lib.rs @@ -679,6 +679,22 @@ pub mod ffi { pub fn Build(self: Pin<&mut BRepFilletAPI_MakeChamfer>, progress: &Message_ProgressRange); pub fn IsDone(self: &BRepFilletAPI_MakeChamfer) -> bool; + // Offset + type BRepOffsetAPI_MakeOffset; + + #[cxx_name = "construct_unique"] + pub fn BRepOffsetAPI_MakeOffset_face_ctor(face: &TopoDS_Face) -> UniquePtr; + + #[cxx_name = "construct_unique"] + pub fn BRepOffsetAPI_MakeOffset_wire_ctor(wire: &TopoDS_Wire) -> UniquePtr; + + pub fn Shape(self: Pin<&mut BRepOffsetAPI_MakeOffset>) -> &TopoDS_Shape; + pub fn Build( + self: Pin<&mut BRepOffsetAPI_MakeOffset>, + progress: &Message_ProgressRange, + ); + pub fn IsDone(self: &BRepOffsetAPI_MakeOffset) -> bool; + // Solids type BRepOffsetAPI_MakeThickSolid; diff --git a/crates/opencascade/src/primitives/face.rs b/crates/opencascade/src/primitives/face.rs index b934c84d..2f13c40c 100644 --- a/crates/opencascade/src/primitives/face.rs +++ b/crates/opencascade/src/primitives/face.rs @@ -185,6 +185,19 @@ impl Face { Self::from_face(result_face) } + /// Offset the wires by a given distance and join settings + #[must_use] + pub fn offset(&self, distance: f64) -> Self { + let face_shape = ffi::cast_face_to_shape(&self.inner); + + let mut make_offset = ffi::BRepOffsetAPI_MakeOffset_ctor(&self.inner); + + let offset_shape = make_offset.pin_mut().Shape(); + let result_face = ffi::TopoDS_cast_to_face(offset_shape); + + Self::from_face(result_face) + } + pub fn edges(&self) -> EdgeIterator { let explorer = ffi::TopExp_Explorer_ctor( ffi::cast_face_to_shape(&self.inner), From 93b8f149dac6dcd55c474e25d3a981bb67dfe46a Mon Sep 17 00:00:00 2001 From: Mate Kovacs Date: Sun, 5 Nov 2023 17:05:23 +0900 Subject: [PATCH 2/4] finish changes and add example --- crates/opencascade-sys/src/lib.rs | 15 +++++++------ crates/opencascade/src/primitives/face.rs | 12 +++++------ crates/opencascade/src/primitives/wire.rs | 12 +++++++++++ crates/viewer/src/main.rs | 2 ++ examples/src/lib.rs | 1 + examples/src/offset_2d.rs | 26 +++++++++++++++++++++++ 6 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 examples/src/offset_2d.rs diff --git a/crates/opencascade-sys/src/lib.rs b/crates/opencascade-sys/src/lib.rs index e5d59adc..aeebe6f2 100644 --- a/crates/opencascade-sys/src/lib.rs +++ b/crates/opencascade-sys/src/lib.rs @@ -683,16 +683,19 @@ pub mod ffi { type BRepOffsetAPI_MakeOffset; #[cxx_name = "construct_unique"] - pub fn BRepOffsetAPI_MakeOffset_face_ctor(face: &TopoDS_Face) -> UniquePtr; + pub fn BRepOffsetAPI_MakeOffset_face_ctor( + face: &TopoDS_Face, + ) -> UniquePtr; #[cxx_name = "construct_unique"] - pub fn BRepOffsetAPI_MakeOffset_wire_ctor(wire: &TopoDS_Wire) -> UniquePtr; + pub fn BRepOffsetAPI_MakeOffset_wire_ctor( + wire: &TopoDS_Wire, + ) -> UniquePtr; + + pub fn Perform(self: Pin<&mut BRepOffsetAPI_MakeOffset>, offset: f64, alt: f64); pub fn Shape(self: Pin<&mut BRepOffsetAPI_MakeOffset>) -> &TopoDS_Shape; - pub fn Build( - self: Pin<&mut BRepOffsetAPI_MakeOffset>, - progress: &Message_ProgressRange, - ); + pub fn Build(self: Pin<&mut BRepOffsetAPI_MakeOffset>, progress: &Message_ProgressRange); pub fn IsDone(self: &BRepOffsetAPI_MakeOffset) -> bool; // Solids diff --git a/crates/opencascade/src/primitives/face.rs b/crates/opencascade/src/primitives/face.rs index 2f13c40c..ffbfee41 100644 --- a/crates/opencascade/src/primitives/face.rs +++ b/crates/opencascade/src/primitives/face.rs @@ -185,17 +185,17 @@ impl Face { Self::from_face(result_face) } - /// Offset the wires by a given distance and join settings + /// Offset the face by a given distance and join settings #[must_use] pub fn offset(&self, distance: f64) -> Self { - let face_shape = ffi::cast_face_to_shape(&self.inner); - - let mut make_offset = ffi::BRepOffsetAPI_MakeOffset_ctor(&self.inner); + let mut make_offset = ffi::BRepOffsetAPI_MakeOffset_face_ctor(&self.inner); + make_offset.pin_mut().Perform(distance, 0.0); let offset_shape = make_offset.pin_mut().Shape(); - let result_face = ffi::TopoDS_cast_to_face(offset_shape); + let result_wire = ffi::TopoDS_cast_to_wire(offset_shape); + let wire = Wire::from_wire(result_wire); - Self::from_face(result_face) + wire.to_face() } pub fn edges(&self) -> EdgeIterator { diff --git a/crates/opencascade/src/primitives/wire.rs b/crates/opencascade/src/primitives/wire.rs index fa9f8b5c..099d7dce 100644 --- a/crates/opencascade/src/primitives/wire.rs +++ b/crates/opencascade/src/primitives/wire.rs @@ -175,6 +175,18 @@ impl Wire { Self { inner } } + /// Offset the wire by a given distance and join settings + #[must_use] + pub fn offset(&self, distance: f64) -> Self { + let mut make_offset = ffi::BRepOffsetAPI_MakeOffset_wire_ctor(&self.inner); + make_offset.pin_mut().Perform(distance, 0.0); + + let offset_shape = make_offset.pin_mut().Shape(); + let result_wire = ffi::TopoDS_cast_to_wire(offset_shape); + + Self::from_wire(result_wire) + } + #[must_use] pub fn translate(&self, offset: DVec3) -> Self { self.transform(offset, dvec3(1.0, 0.0, 0.0), 0.degrees()) diff --git a/crates/viewer/src/main.rs b/crates/viewer/src/main.rs index 217bd7a2..d2b4a5bd 100644 --- a/crates/viewer/src/main.rs +++ b/crates/viewer/src/main.rs @@ -59,6 +59,7 @@ enum Example { HighLevelBottle, KeyboardCase, Keycap, + Offset2d, RoundedChamfer, TurnersCube, VariableFillet, @@ -74,6 +75,7 @@ impl Example { Example::HighLevelBottle => examples::high_level_bottle::shape(), Example::KeyboardCase => examples::keyboard_case::shape(), Example::Keycap => examples::keycap::shape(), + Example::Offset2d => examples::offset_2d::shape(), Example::RoundedChamfer => examples::rounded_chamfer::shape(), Example::TurnersCube => examples::turners_cube::shape(), Example::VariableFillet => examples::variable_fillet::shape(), diff --git a/examples/src/lib.rs b/examples/src/lib.rs index fab08478..82b0ee47 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -5,6 +5,7 @@ pub mod gizmo; pub mod high_level_bottle; pub mod keyboard_case; pub mod keycap; +pub mod offset_2d; pub mod rounded_chamfer; pub mod turners_cube; pub mod variable_fillet; diff --git a/examples/src/offset_2d.rs b/examples/src/offset_2d.rs new file mode 100644 index 00000000..f359e14f --- /dev/null +++ b/examples/src/offset_2d.rs @@ -0,0 +1,26 @@ +use glam::DVec3; +use opencascade::{ + primitives::{IntoShape, Shape}, + workplane::Workplane, +}; + +// Demonstrates ofsetting a face or wire in 2D. + +pub fn shape() -> Shape { + let solid = Workplane::xy() + .rect(16.0, 10.0) + .offset(4.0) // offset a wire + .to_face() + .extrude(DVec3::new(0.0, 0.0, 8.0)) + .into_shape(); + + let face = Workplane::xy() + .translated(DVec3::new(0.0, 20.0, 0.0)) + .rect(16.0, 10.0) + .to_face() + .offset(4.0) // offset a face + .extrude(DVec3::new(0.0, 0.0, 8.0)) + .into_shape(); + + solid.union(&face).into() +} From 8f380fffed6ddb1085d83039f01917016ae6f460 Mon Sep 17 00:00:00 2001 From: Mate Kovacs Date: Sun, 5 Nov 2023 18:08:19 +0900 Subject: [PATCH 3/4] expose JoinType for 2D offsets --- crates/opencascade-sys/include/wrapper.hxx | 1 + crates/opencascade-sys/src/lib.rs | 12 +++++++ crates/opencascade/src/primitives.rs | 28 +++++++++++++++ crates/opencascade/src/primitives/face.rs | 9 +++-- crates/opencascade/src/primitives/wire.rs | 7 ++-- examples/src/offset_2d.rs | 41 ++++++++++++++-------- 6 files changed, 77 insertions(+), 21 deletions(-) diff --git a/crates/opencascade-sys/include/wrapper.hxx b/crates/opencascade-sys/include/wrapper.hxx index 2b310462..4dffbef0 100644 --- a/crates/opencascade-sys/include/wrapper.hxx +++ b/crates/opencascade-sys/include/wrapper.hxx @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include diff --git a/crates/opencascade-sys/src/lib.rs b/crates/opencascade-sys/src/lib.rs index aeebe6f2..9ae62148 100644 --- a/crates/opencascade-sys/src/lib.rs +++ b/crates/opencascade-sys/src/lib.rs @@ -54,6 +54,14 @@ pub mod ffi { GeomAbs_OtherCurve, } + #[repr(u32)] + #[derive(Debug)] + pub enum GeomAbs_JoinType { + GeomAbs_Arc, + GeomAbs_Tangent, + GeomAbs_Intersection, + } + unsafe extern "C++" { // https://github.com/dtolnay/cxx/issues/280 @@ -685,11 +693,13 @@ pub mod ffi { #[cxx_name = "construct_unique"] pub fn BRepOffsetAPI_MakeOffset_face_ctor( face: &TopoDS_Face, + join: GeomAbs_JoinType, ) -> UniquePtr; #[cxx_name = "construct_unique"] pub fn BRepOffsetAPI_MakeOffset_wire_ctor( wire: &TopoDS_Wire, + join: GeomAbs_JoinType, ) -> UniquePtr; pub fn Perform(self: Pin<&mut BRepOffsetAPI_MakeOffset>, offset: f64, alt: f64); @@ -698,6 +708,8 @@ pub mod ffi { pub fn Build(self: Pin<&mut BRepOffsetAPI_MakeOffset>, progress: &Message_ProgressRange); pub fn IsDone(self: &BRepOffsetAPI_MakeOffset) -> bool; + type GeomAbs_JoinType; + // Solids type BRepOffsetAPI_MakeThickSolid; diff --git a/crates/opencascade/src/primitives.rs b/crates/opencascade/src/primitives.rs index 0fbce1ee..7354d232 100644 --- a/crates/opencascade/src/primitives.rs +++ b/crates/opencascade/src/primitives.rs @@ -218,3 +218,31 @@ pub fn approximate_function f64>( Some((t, val)) }) } + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum JoinType { + Arc, + Tangent, + Intersection, +} + +impl From for JoinType { + fn from(value: ffi::GeomAbs_JoinType) -> Self { + match value { + ffi::GeomAbs_JoinType::GeomAbs_Arc => Self::Arc, + ffi::GeomAbs_JoinType::GeomAbs_Tangent => Self::Tangent, + ffi::GeomAbs_JoinType::GeomAbs_Intersection => Self::Intersection, + ffi::GeomAbs_JoinType { repr } => panic!("Unexpected join type: {repr}"), + } + } +} + +impl From for ffi::GeomAbs_JoinType { + fn from(value: JoinType) -> Self { + match value { + JoinType::Arc => ffi::GeomAbs_JoinType::GeomAbs_Arc, + JoinType::Tangent => ffi::GeomAbs_JoinType::GeomAbs_Tangent, + JoinType::Intersection => ffi::GeomAbs_JoinType::GeomAbs_Intersection, + } + } +} diff --git a/crates/opencascade/src/primitives/face.rs b/crates/opencascade/src/primitives/face.rs index ffbfee41..808ddf70 100644 --- a/crates/opencascade/src/primitives/face.rs +++ b/crates/opencascade/src/primitives/face.rs @@ -1,6 +1,8 @@ use crate::{ angle::Angle, - primitives::{make_axis_1, make_point, make_vec, EdgeIterator, Shape, Solid, Surface, Wire}, + primitives::{ + make_axis_1, make_point, make_vec, EdgeIterator, JoinType, Shape, Solid, Surface, Wire, + }, workplane::Workplane, }; use cxx::UniquePtr; @@ -187,8 +189,9 @@ impl Face { /// Offset the face by a given distance and join settings #[must_use] - pub fn offset(&self, distance: f64) -> Self { - let mut make_offset = ffi::BRepOffsetAPI_MakeOffset_face_ctor(&self.inner); + pub fn offset(&self, distance: f64, join_type: JoinType) -> Self { + let mut make_offset = + ffi::BRepOffsetAPI_MakeOffset_face_ctor(&self.inner, join_type.into()); make_offset.pin_mut().Perform(distance, 0.0); let offset_shape = make_offset.pin_mut().Shape(); diff --git a/crates/opencascade/src/primitives/wire.rs b/crates/opencascade/src/primitives/wire.rs index 099d7dce..08f2a504 100644 --- a/crates/opencascade/src/primitives/wire.rs +++ b/crates/opencascade/src/primitives/wire.rs @@ -2,7 +2,7 @@ use std::iter::once; use crate::{ angle::{Angle, ToAngle}, - primitives::{make_dir, make_point, make_vec, Edge, Face, Shape}, + primitives::{make_dir, make_point, make_vec, Edge, Face, JoinType, Shape}, Error, }; use cxx::UniquePtr; @@ -177,8 +177,9 @@ impl Wire { /// Offset the wire by a given distance and join settings #[must_use] - pub fn offset(&self, distance: f64) -> Self { - let mut make_offset = ffi::BRepOffsetAPI_MakeOffset_wire_ctor(&self.inner); + pub fn offset(&self, distance: f64, join_type: JoinType) -> Self { + let mut make_offset = + ffi::BRepOffsetAPI_MakeOffset_wire_ctor(&self.inner, join_type.into()); make_offset.pin_mut().Perform(distance, 0.0); let offset_shape = make_offset.pin_mut().Shape(); diff --git a/examples/src/offset_2d.rs b/examples/src/offset_2d.rs index f359e14f..3fcc7d29 100644 --- a/examples/src/offset_2d.rs +++ b/examples/src/offset_2d.rs @@ -1,26 +1,37 @@ use glam::DVec3; use opencascade::{ - primitives::{IntoShape, Shape}, + primitives::{IntoShape, JoinType, Shape}, workplane::Workplane, }; // Demonstrates ofsetting a face or wire in 2D. pub fn shape() -> Shape { - let solid = Workplane::xy() - .rect(16.0, 10.0) - .offset(4.0) // offset a wire - .to_face() - .extrude(DVec3::new(0.0, 0.0, 8.0)) - .into_shape(); + let mut shapes = vec![]; - let face = Workplane::xy() - .translated(DVec3::new(0.0, 20.0, 0.0)) - .rect(16.0, 10.0) - .to_face() - .offset(4.0) // offset a face - .extrude(DVec3::new(0.0, 0.0, 8.0)) - .into_shape(); + for (i, join_type) in + [JoinType::Arc, JoinType::Tangent, JoinType::Intersection].into_iter().enumerate() + { + let solid_1 = Workplane::xy() + .translated(DVec3::new(32.0 * i as f64, 0.0, 0.0)) + .rect(16.0, 10.0) + .offset(4.0, join_type) // offset a wire + .to_face() + .extrude(DVec3::new(0.0, 0.0, 8.0)) + .into_shape(); - solid.union(&face).into() + shapes.push(solid_1); + + let solid_2 = Workplane::xy() + .translated(DVec3::new(32.0 * i as f64, 24.0, 0.0)) + .rect(16.0, 10.0) + .to_face() + .offset(4.0, join_type) // offset a face + .extrude(DVec3::new(0.0, 0.0, 8.0)) + .into_shape(); + + shapes.push(solid_2); + } + + shapes.into_iter().reduce(|acc, item| acc.union(&item).shape).unwrap() } From dd39fddc5cd3ead6b9eafe7339fa185a3c6c21da Mon Sep 17 00:00:00 2001 From: Mate Kovacs Date: Sat, 25 Nov 2023 11:46:29 +0900 Subject: [PATCH 4/4] put JointType::Tangent out of scope for now --- crates/opencascade/src/primitives.rs | 7 ++++--- examples/src/offset_2d.rs | 29 ++++++++++++---------------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/crates/opencascade/src/primitives.rs b/crates/opencascade/src/primitives.rs index 7354d232..0fda768a 100644 --- a/crates/opencascade/src/primitives.rs +++ b/crates/opencascade/src/primitives.rs @@ -222,7 +222,8 @@ pub fn approximate_function f64>( #[derive(Debug, Copy, Clone, PartialEq)] pub enum JoinType { Arc, - Tangent, + // TODO(mkovaxx): Figure out how to make tangent joints work without segfaults + //Tangent, Intersection, } @@ -230,7 +231,7 @@ impl From for JoinType { fn from(value: ffi::GeomAbs_JoinType) -> Self { match value { ffi::GeomAbs_JoinType::GeomAbs_Arc => Self::Arc, - ffi::GeomAbs_JoinType::GeomAbs_Tangent => Self::Tangent, + //ffi::GeomAbs_JoinType::GeomAbs_Tangent => Self::Tangent, ffi::GeomAbs_JoinType::GeomAbs_Intersection => Self::Intersection, ffi::GeomAbs_JoinType { repr } => panic!("Unexpected join type: {repr}"), } @@ -241,7 +242,7 @@ impl From for ffi::GeomAbs_JoinType { fn from(value: JoinType) -> Self { match value { JoinType::Arc => ffi::GeomAbs_JoinType::GeomAbs_Arc, - JoinType::Tangent => ffi::GeomAbs_JoinType::GeomAbs_Tangent, + //JoinType::Tangent => ffi::GeomAbs_JoinType::GeomAbs_Tangent, JoinType::Intersection => ffi::GeomAbs_JoinType::GeomAbs_Intersection, } } diff --git a/examples/src/offset_2d.rs b/examples/src/offset_2d.rs index 3fcc7d29..6087eaa8 100644 --- a/examples/src/offset_2d.rs +++ b/examples/src/offset_2d.rs @@ -9,28 +9,23 @@ use opencascade::{ pub fn shape() -> Shape { let mut shapes = vec![]; - for (i, join_type) in - [JoinType::Arc, JoinType::Tangent, JoinType::Intersection].into_iter().enumerate() - { - let solid_1 = Workplane::xy() + for (i, join_type) in [JoinType::Arc, JoinType::Intersection].into_iter().enumerate() { + let solid = Workplane::xy() .translated(DVec3::new(32.0 * i as f64, 0.0, 0.0)) - .rect(16.0, 10.0) - .offset(4.0, join_type) // offset a wire + .sketch() + .move_to(0.0, 10.0) + .line_to(5.0, 5.0) + .line_to(5.0, -5.0) + .line_to(0.0, 0.0) + .line_to(-5.0, -5.0) + .line_to(-5.0, 5.0) + .close() + .offset(1.0, join_type) // offset a wire .to_face() .extrude(DVec3::new(0.0, 0.0, 8.0)) .into_shape(); - shapes.push(solid_1); - - let solid_2 = Workplane::xy() - .translated(DVec3::new(32.0 * i as f64, 24.0, 0.0)) - .rect(16.0, 10.0) - .to_face() - .offset(4.0, join_type) // offset a face - .extrude(DVec3::new(0.0, 0.0, 8.0)) - .into_shape(); - - shapes.push(solid_2); + shapes.push(solid); } shapes.into_iter().reduce(|acc, item| acc.union(&item).shape).unwrap()