Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offset for Face and Wire #145

Merged
merged 4 commits into from
Nov 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/opencascade-sys/include/wrapper.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <BRepLib.hxx>
#include <BRepLib_ToolTriangulatedShape.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include <BRepOffsetAPI_MakeOffset.hxx>
#include <BRepOffsetAPI_MakeThickSolid.hxx>
#include <BRepOffsetAPI_ThruSections.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
Expand All @@ -38,6 +39,7 @@
#include <Geom2d_TrimmedCurve.hxx>
#include <GeomAPI_ProjectPointOnSurf.hxx>
#include <GeomAbs_CurveType.hxx>
#include <GeomAbs_JoinType.hxx>
#include <Geom_BezierSurface.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <Geom_Plane.hxx>
Expand Down
31 changes: 31 additions & 0 deletions crates/opencascade-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -679,6 +687,29 @@ 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,
join: GeomAbs_JoinType,
) -> UniquePtr<BRepOffsetAPI_MakeOffset>;

#[cxx_name = "construct_unique"]
pub fn BRepOffsetAPI_MakeOffset_wire_ctor(
wire: &TopoDS_Wire,
join: GeomAbs_JoinType,
) -> UniquePtr<BRepOffsetAPI_MakeOffset>;

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 IsDone(self: &BRepOffsetAPI_MakeOffset) -> bool;

type GeomAbs_JoinType;

// Solids
type BRepOffsetAPI_MakeThickSolid;

Expand Down
29 changes: 29 additions & 0 deletions crates/opencascade/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,32 @@ pub fn approximate_function<F: FnMut(f64) -> f64>(
Some((t, val))
})
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum JoinType {
Arc,
// TODO(mkovaxx): Figure out how to make tangent joints work without segfaults
//Tangent,
Intersection,
}

impl From<ffi::GeomAbs_JoinType> 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<JoinType> 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,
}
}
}
18 changes: 17 additions & 1 deletion crates/opencascade/src/primitives/face.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -185,6 +187,20 @@ impl Face {
Self::from_face(result_face)
}

/// Offset the face by a given distance and join settings
#[must_use]
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();
let result_wire = ffi::TopoDS_cast_to_wire(offset_shape);
let wire = Wire::from_wire(result_wire);

wire.to_face()
}

pub fn edges(&self) -> EdgeIterator {
let explorer = ffi::TopExp_Explorer_ctor(
ffi::cast_face_to_shape(&self.inner),
Expand Down
15 changes: 14 additions & 1 deletion crates/opencascade/src/primitives/wire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -175,6 +175,19 @@ impl Wire {
Self { inner }
}

/// Offset the wire by a given distance and join settings
#[must_use]
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();
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())
Expand Down
2 changes: 2 additions & 0 deletions crates/viewer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ enum Example {
HighLevelBottle,
KeyboardCase,
Keycap,
Offset2d,
RoundedChamfer,
TurnersCube,
VariableFillet,
Expand All @@ -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(),
Expand Down
1 change: 1 addition & 0 deletions examples/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
32 changes: 32 additions & 0 deletions examples/src/offset_2d.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use glam::DVec3;
use opencascade::{
primitives::{IntoShape, JoinType, Shape},
workplane::Workplane,
};

// Demonstrates ofsetting a face or wire in 2D.

pub fn shape() -> Shape {
let mut shapes = vec![];

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))
.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);
}

shapes.into_iter().reduce(|acc, item| acc.union(&item).shape).unwrap()
}