Skip to content
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
87 changes: 86 additions & 1 deletion cadquery/occ_impl/shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
List,
Sequence,
Iterator,
Dict,
Any,
overload,
TypeVar,
Expand Down Expand Up @@ -136,7 +137,11 @@
BRepOffsetAPI_MakeOffset,
)

from OCP.BRepFilletAPI import BRepFilletAPI_MakeChamfer, BRepFilletAPI_MakeFillet
from OCP.BRepFilletAPI import (
BRepFilletAPI_MakeChamfer,
BRepFilletAPI_MakeFillet,
BRepFilletAPI_MakeFillet2d,
)

from OCP.TopTools import TopTools_IndexedDataMapOfShapeListOfShape, TopTools_ListOfShape

Expand Down Expand Up @@ -680,6 +685,28 @@ def _entities(self, topo_type: Shapes) -> List[TopoDS_Shape]:

return list(out.values())

def _entitiesFrom(
self, child_type: Shapes, parent_type: Shapes
) -> Dict["Shape", List["Shape"]]:

res = TopTools_IndexedDataMapOfShapeListOfShape()

TopTools_IndexedDataMapOfShapeListOfShape()
TopExp.MapShapesAndAncestors_s(
self.wrapped,
inverse_shape_LUT[child_type],
inverse_shape_LUT[parent_type],
res,
)

out: Dict[Shape, List[Shape]] = {}
for i in range(1, res.Extent() + 1):
out[Shape.cast(res.FindKey(i))] = [
Shape.cast(el) for el in res.FindFromIndex(i)
]

return out

def Vertices(self) -> List["Vertex"]:
"""
:returns: All the vertices in this Shape
Expand Down Expand Up @@ -904,6 +931,9 @@ def moved(self, loc: Location) -> "Shape":
def __hash__(self) -> int:
return self.hashCode()

def __eq__(self, other) -> bool:
return self.isSame(other)

def _bool_op(
self,
args: Iterable["Shape"],
Expand Down Expand Up @@ -1778,6 +1808,24 @@ def offset2D(

return rv

def fillet2D(self, radius: float, vertices: Iterable[Vertex]) -> "Wire":
"""
Apply 2D fillet to a wire
"""

f = Face.makeFromWires(self)

return f.fillet2D(radius, vertices).outerWire()

def chamfer2D(self, d: float, vertices: Iterable[Vertex]) -> "Wire":
"""
Apply 2D chamfer to a wire
"""

f = Face.makeFromWires(self)

return f.chamfer2D(d, vertices).outerWire()


class Face(Shape):
"""
Expand Down Expand Up @@ -1974,6 +2022,43 @@ def makeFromWires(

return cls(face).fix()

def fillet2D(self, radius: float, vertices: Iterable[Vertex]) -> "Face":
"""
Apply 2D fillet to a face
"""

fillet_builder = BRepFilletAPI_MakeFillet2d(self.wrapped)

for v in vertices:
fillet_builder.AddFillet(v.wrapped, radius)

fillet_builder.Build()

return self.__class__(fillet_builder.Shape())

def chamfer2D(self, d: float, vertices: Iterable[Vertex]) -> "Face":
"""
Apply 2D chamfer to a face
"""

chamfer_builder = BRepFilletAPI_MakeFillet2d(self.wrapped)
edge_map = self._entitiesFrom("Vertex", "Edge")

for v in vertices:
edges = edge_map[v]
if len(edges) < 2:
raise ValueError("Cannot chamfer at this location")

e1, e2 = edges

chamfer_builder.AddChamfer(
TopoDS.Edge_s(e1.wrapped), TopoDS.Edge_s(e2.wrapped), d, d
)

chamfer_builder.Build()

return self.__class__(chamfer_builder.Shape()).fix()


class Shell(Shape):
"""
Expand Down
39 changes: 39 additions & 0 deletions tests/test_cadquery.py
Original file line number Diff line number Diff line change
Expand Up @@ -4269,3 +4269,42 @@ def testCompSolid(self):

self.assertEqual(len(result.CompSolids()), 1)
self.assertEqual(len(result.Solids()), 4)

def test2Dfillet(self):

r = Workplane().rect(1, 2).wires().val()
f = Face.makeFromWires(r)
verts = r.Vertices()

self.assertEqual(len(f.fillet2D(0.5, verts).Vertices()), 6)
self.assertEqual(len(r.fillet2D(0.5, verts).Vertices()), 6)
self.assertEqual(len(r.fillet2D(0.25, verts).Vertices()), 8)

# Test fillet2D with open wire and single vertex
w0 = Workplane().hLine(1).vLine(1).wire()
w0_verts = w0.vertices(">X and <Y").vals()
unfilleted_wire0 = w0.val()
filleted_wire0 = unfilleted_wire0.fillet2D(0.5, w0_verts)

self.assertEqual(len(filleted_wire0.Vertices()), 4)

# the filleted wire is shorter than the original
self.assertGreater(unfilleted_wire0.Length() - filleted_wire0.Length(), 0.1)

def test2Dchamfer(self):

r = Workplane().rect(1, 2).wires().val()
f = Face.makeFromWires(r)
verts = r.Vertices()

self.assertEqual(len(f.chamfer2D(0.5, verts).Vertices()), 6)
self.assertEqual(len(r.chamfer2D(0.5, verts).Vertices()), 6)
self.assertEqual(len(r.chamfer2D(0.25, verts).Vertices()), 8)

r = Workplane().hLine(1).vLine(1).wire().val()
vs = r.Vertices()

self.assertEqual(len(r.chamfer2D(0.25, [vs[1]]).Vertices()), 4)

with raises(ValueError):
r.chamfer2D(0.25, [vs[0]])