From 46f6001a4a687f7fa4774362b83c60608961efdb Mon Sep 17 00:00:00 2001 From: hyOzd Date: Sun, 21 Jun 2015 23:49:31 +0300 Subject: [PATCH 1/4] added chamfer api --- cadquery/CQ.py | 38 +++++++++++++++++++++++++++++++++ cadquery/freecad_impl/shapes.py | 14 ++++++++++++ 2 files changed, 52 insertions(+) diff --git a/cadquery/CQ.py b/cadquery/CQ.py index d666659..862435f 100644 --- a/cadquery/CQ.py +++ b/cadquery/CQ.py @@ -795,6 +795,44 @@ class CQ(object): solid.wrapped = s.wrapped return self.newObject([s]) + def chamfer(self, length, length2 = None): + """ + Chamfers a solid on the selected edges. + + The edges on the stack are chamfered. The solid to which the + edges belong must be in the parent chain of the selected + edges. + + Optional parameter `length2` can be supplied with a different + value than `length` for a chamfer that is shorter on one side + longer on the other side. + + :param length: the length of the fillet, must be greater than zero + :param length2: optional parameter for asymmetrical chamfer + :type length: positive float + :type length2: positive float + :raises: ValueError if at least one edge is not selected + :raises: ValueError if the solid containing the edge is not in the chain + :returns: cq object with the resulting solid selected. + + This example will create a unit cube, with the top edges chamfered:: + + s = Workplane("XY").box(1,1,1).faces("+Z").edges().chamfer(0.1) + + This example will create chamfers longer on the sides:: + + s = Workplane("XY").box(1,1,1).faces("+Z").edges().chamfer(0.2, 0.1) + """ + solid = self.findSolid() + + edgeList = self.edges().vals() + if len(edgeList) < 1: + raise ValueError("Chamfer requires that edges be selected") + + s = solid.chamfer(length, length2, edgeList) + + solid.wrapped = s.wrapped + return self.newObject([s]) class Workplane(CQ): """ diff --git a/cadquery/freecad_impl/shapes.py b/cadquery/freecad_impl/shapes.py index 03e34b5..2255c14 100644 --- a/cadquery/freecad_impl/shapes.py +++ b/cadquery/freecad_impl/shapes.py @@ -812,6 +812,20 @@ class Solid(Shape): nativeEdges = [e.wrapped for e in edgeList] return Shape.cast(self.wrapped.makeFillet(radius, nativeEdges)) + def chamfer(self, radius, radius2, edgeList): + """ + Chamfers the specified edges of this solid. + :param radius: radius > 0, the radius (length) of the chamfer + :param radius2: radius2 > 0, optional parameter for asymmetrical chamfer. Should be `None` if not required. + :param edgeList: a list of Edge objects, which must belong to this solid + :return: Chamfered solid + """ + nativeEdges = [e.wrapped for e in edgeList] + if radius2: + return Shape.cast(self.wrapped.makeChamfer(radius, radius2, nativeEdges)) + else: + return Shape.cast(self.wrapped.makeChamfer(radius, nativeEdges)) + def shell(self, faceList, thickness, tolerance=0.0001): """ make a shelled solid of given by removing the list of faces From dc2f74cfd7fc940b6344c9c74f9acbc41ebc4baa Mon Sep 17 00:00:00 2001 From: hyOzd Date: Mon, 22 Jun 2015 00:03:47 +0300 Subject: [PATCH 2/4] chamfer example; there is no need to call edges(), faces() selector works fine --- cadquery/CQ.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cadquery/CQ.py b/cadquery/CQ.py index 862435f..44bd0e9 100644 --- a/cadquery/CQ.py +++ b/cadquery/CQ.py @@ -817,11 +817,11 @@ class CQ(object): This example will create a unit cube, with the top edges chamfered:: - s = Workplane("XY").box(1,1,1).faces("+Z").edges().chamfer(0.1) + s = Workplane("XY").box(1,1,1).faces("+Z").chamfer(0.1) This example will create chamfers longer on the sides:: - s = Workplane("XY").box(1,1,1).faces("+Z").edges().chamfer(0.2, 0.1) + s = Workplane("XY").box(1,1,1).faces("+Z").chamfer(0.2, 0.1) """ solid = self.findSolid() From 807aa5d604bee38510c6c1ac91f3eeaebf630fd0 Mon Sep 17 00:00:00 2001 From: hyOzd Date: Mon, 22 Jun 2015 21:09:56 +0300 Subject: [PATCH 3/4] use 'length' for chamfer instead of 'radius' --- cadquery/freecad_impl/shapes.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cadquery/freecad_impl/shapes.py b/cadquery/freecad_impl/shapes.py index 2255c14..e0f2ecf 100644 --- a/cadquery/freecad_impl/shapes.py +++ b/cadquery/freecad_impl/shapes.py @@ -812,19 +812,20 @@ class Solid(Shape): nativeEdges = [e.wrapped for e in edgeList] return Shape.cast(self.wrapped.makeFillet(radius, nativeEdges)) - def chamfer(self, radius, radius2, edgeList): + def chamfer(self, length, length2, edgeList): """ Chamfers the specified edges of this solid. - :param radius: radius > 0, the radius (length) of the chamfer - :param radius2: radius2 > 0, optional parameter for asymmetrical chamfer. Should be `None` if not required. + :param length: length > 0, the length (length) of the chamfer + :param length2: length2 > 0, optional parameter for asymmetrical chamfer. Should be `None` if not required. :param edgeList: a list of Edge objects, which must belong to this solid :return: Chamfered solid """ nativeEdges = [e.wrapped for e in edgeList] - if radius2: - return Shape.cast(self.wrapped.makeChamfer(radius, radius2, nativeEdges)) + # note: we prefer 'length' word to 'radius' as opposed to FreeCAD's API + if length2: + return Shape.cast(self.wrapped.makeChamfer(length, length2, nativeEdges)) else: - return Shape.cast(self.wrapped.makeChamfer(radius, nativeEdges)) + return Shape.cast(self.wrapped.makeChamfer(length, nativeEdges)) def shell(self, faceList, thickness, tolerance=0.0001): """ From fd4010704158948db2ffe427fffcb07c8527e7b6 Mon Sep 17 00:00:00 2001 From: hyOzd Date: Mon, 22 Jun 2015 22:02:20 +0300 Subject: [PATCH 4/4] added tests for chamfer api --- tests/TestCadQuery.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/TestCadQuery.py b/tests/TestCadQuery.py index 6a1f586..b8e6f83 100644 --- a/tests/TestCadQuery.py +++ b/tests/TestCadQuery.py @@ -804,6 +804,36 @@ class TestCadQuery(BaseTest): self.saveModel(c) self.assertEqual(12,c.faces().size() ) + def testChamfer(self): + """ + Test chamfer API with a box shape + """ + cube = CQ(makeUnitCube()).faces(">Z").chamfer(0.1) + self.saveModel(cube) + self.assertEqual(10, cube.faces().size()) + + def testChamferAsymmetrical(self): + """ + Test chamfer API with a box shape for asymmetrical lengths + """ + cube = CQ(makeUnitCube()).faces(">Z").chamfer(0.1, 0.2) + self.saveModel(cube) + self.assertEqual(10, cube.faces().size()) + + # test if edge lengths are different + edge = cube.edges(">Z").vals()[0] + self.assertAlmostEqual(0.6, edge.Length(), 3) + edge = cube.edges("|Z").vals()[0] + self.assertAlmostEqual(0.9, edge.Length(), 3) + + def testChamferCylinder(self): + """ + Test chamfer API with a cylinder shape + """ + cylinder = Workplane("XY").circle(1).extrude(1).faces(">Z").chamfer(0.1) + self.saveModel(cylinder) + self.assertEqual(4, cylinder.faces().size()) + def testCounterBores(self): """ Tests making a set of counterbored holes in a face