diff --git a/docs/cheat_sheet.rst b/docs/cheat_sheet.rst index a71df1c..5645b75 100644 --- a/docs/cheat_sheet.rst +++ b/docs/cheat_sheet.rst @@ -153,7 +153,7 @@ Cheat Sheet +----------+---------------------+-----------------------------------------+---------------------------------------------+ | Operator | Operand | Method | Description | +==========+=====================+=========================================+=============================================+ - | == | Any | :meth:`~direct_api.Shape.is_equal` | Compare CAD objects not including meta data | + | == | Any | :meth:`~direct_api.Shape.is_same` | Compare CAD objects not including meta data | +----------+---------------------+-----------------------------------------+---------------------------------------------+ diff --git a/src/build123d/build_generic.py b/src/build123d/build_generic.py index ce71b2a..f369eaf 100644 --- a/src/build123d/build_generic.py +++ b/src/build123d/build_generic.py @@ -437,7 +437,7 @@ class Offset(Compound): else: openings_in_this_solid = [] new_solids.append( - solid.shell(openings_in_this_solid, amount, kind=kind).fix() + solid.offset_3d(openings_in_this_solid, amount, kind=kind).fix() ) new_objects = new_wires + new_faces + new_solids diff --git a/src/build123d/direct_api.py b/src/build123d/direct_api.py index 8150beb..b91f9f1 100644 --- a/src/build123d/direct_api.py +++ b/src/build123d/direct_api.py @@ -2066,6 +2066,64 @@ class Mixin3D: return return_value + def offset_3d( + self, + openings: Optional[Iterable[Face]], + thickness: float, + tolerance: float = 0.0001, + kind: Kind = Kind.ARC, + ) -> Solid: + """Shell + + Make an offset solid of self. + + Args: + openings (Optional[Iterable[Face]]): List of faces to be removed, + which must be part of the solid. Can be an empty list. + thickness (float): offset amount - positive offset outwards, negative inwards + tolerance (float, optional): modelling tolerance of the method. Defaults to 0.0001. + kind (Kind, optional): intersection type. Defaults to Kind.ARC. + + Raises: + ValueError: Kind.TANGENT not supported + + Returns: + Solid: A shelled solid. + """ + if kind == Kind.TANGENT: + raise ValueError("Kind.TANGENT not supported") + + kind_dict = { + Kind.ARC: GeomAbs_JoinType.GeomAbs_Arc, + Kind.INTERSECTION: GeomAbs_JoinType.GeomAbs_Intersection, + Kind.TANGENT: GeomAbs_JoinType.GeomAbs_Tangent, + } + + occ_faces_list = TopTools_ListOfShape() + for face in openings: + occ_faces_list.Append(face.wrapped) + + offset_builder = BRepOffsetAPI_MakeThickSolid() + offset_builder.MakeThickSolidByJoin( + self.wrapped, + occ_faces_list, + thickness, + tolerance, + Intersection=True, + RemoveIntEdges=True, + Join=kind_dict[kind], + ) + offset_builder.Build() + + offset_occt_solid = offset_builder.Shape() + offset_solid = self.__class__(offset_occt_solid) + + # The Solid can be inverted, if so reverse + if offset_solid.volume < 0: + offset_solid.wrapped.Reverse() + + return offset_solid + def is_inside(self, point: VectorLike, tolerance: float = 1.0e-6) -> bool: """Returns whether or not the point is inside a solid or compound object within the specified tolerance. @@ -2635,8 +2693,8 @@ class Shape(NodeMixin): return self.wrapped.IsEqual(other.wrapped) def __eq__(self, other) -> bool: - """Are shapes equal?""" - return self.is_equal(other) if isinstance(other, Shape) else False + """Are shapes same?""" + return self.is_same(other) if isinstance(other, Shape) else False def is_valid(self) -> bool: """Returns True if no defect is detected on the shape S or any of its diff --git a/tests/test_build_generic.py b/tests/test_build_generic.py index 39479c2..38c7606 100644 --- a/tests/test_build_generic.py +++ b/tests/test_build_generic.py @@ -163,12 +163,9 @@ class TestOffset(unittest.TestCase): def test_box_offset(self): with BuildPart() as test: - Box(1, 1, 1) - Offset( - amount=1, - kind=Kind.INTERSECTION, - ) - self.assertAlmostEqual(test.part.volume, 3**3 - 1**3, 5) + Box(10, 10, 10) + Offset(amount=-1, kind=Kind.INTERSECTION, mode=Mode.SUBTRACT) + self.assertAlmostEqual(test.part.volume, 10**3 - 8**3, 5) def test_box_offset_with_opening(self): with BuildPart() as test: