From d6521b314777ff85296dcee3d60c57d477a1de2a Mon Sep 17 00:00:00 2001 From: Martin Budden Date: Wed, 25 Aug 2021 18:44:23 +0100 Subject: [PATCH 1/7] Added cone 3D primitive to Workplane. --- cadquery/cq.py | 53 ++++++++++++++++++++++++++++++++++++++++++ doc/apireference.rst | 1 + doc/roadmap.rst | 1 - tests/test_cadquery.py | 13 +++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/cadquery/cq.py b/cadquery/cq.py index 8b636917a..9e5daf082 100644 --- a/cadquery/cq.py +++ b/cadquery/cq.py @@ -3800,6 +3800,59 @@ def sphere( else: return self.union(spheres, clean=clean) + def cone( + self: T, + height: float, + radius: float = 0, + radius1: float = None, + radius2: float = None, + direct: Vector = Vector(0, 0, 1), + angle: float = 360, + combine: bool = True, + clean: bool = True, + ) -> T: + """ + Returns a cone with the specified radius and height for each point on the stack + A truncated cone can be created by specifying parameters radius1 and radius2 instead of radius. + :param height: The height of the cone + :type height: float > 0 + :param radius: The radius of the cone + :type radius: float > 0 + :param radius1: The radius of the bottom of the cone + :type radius1: float > 0 + :param radius2: The radius of the top of the cone + :type radius2: float > 0 + :param direct: The direction axis for the creation of the cone + :type direct: A three-tuple + :param angle: The angle to sweep the cone arc through + :type angle: float > 0 + :param combine: Whether the results should be combined with other solids on the stack + (and each other) + :type combine: true to combine shapes, false otherwise + :param clean: call :py:meth:`clean` afterwards to have a clean shape + :return: A cone object for each point on the stack + One cone is created for each item on the current stack. If no items are on the stack, one + cone is created using the current workplane center. + If combine is true, the result will be a single object on the stack. If a solid was found + in the chain, the result is that solid with all cones produced fused onto it otherwise, + the result is the combination of all the produced cones. + If combine is false, the result will be a list of the cones produced. + """ + + r1 = radius if radius1 is None or radius1 == 0 else radius1 + r2 = 0 if radius2 is None else radius2 + offset = Vector() + s = Solid.makeCone(r1, r2, height, offset, direct, angle) + + # We want a cone for each point on the workplane + cones = self.eachpoint(lambda loc: s.moved(loc), True) + + # If we don't need to combine everything, just return the created cones + if not combine: + return cones + else: + return self.union(cones, clean=clean) + def cylinder( self: T, height: float, diff --git a/doc/apireference.rst b/doc/apireference.rst index 8f61fdc63..1d49d36c9 100644 --- a/doc/apireference.rst +++ b/doc/apireference.rst @@ -91,6 +91,7 @@ Some 3D operations also require an active 2D workplane, but some do not. Workplane.box Workplane.sphere Workplane.cylinder + Workplane.cone Workplane.union Workplane.combine Workplane.intersect diff --git a/doc/roadmap.rst b/doc/roadmap.rst index a1bc6cc25..642e5f4eb 100644 --- a/doc/roadmap.rst +++ b/doc/roadmap.rst @@ -80,7 +80,6 @@ rotation/transform that return a copy primitive creation Need primitive creation for: - * cone * torus * wedge diff --git a/tests/test_cadquery.py b/tests/test_cadquery.py index f717ad7f8..3b3727c19 100644 --- a/tests/test_cadquery.py +++ b/tests/test_cadquery.py @@ -2475,6 +2475,19 @@ def testCylinderCentering(self): self.assertTupleAlmostEquals( s0.val().Center().toTuple(), s1.val().Center().toTuple(), 3 ) + def testConeDefaults(self): + s = Workplane("XY").cone(40, 10) + self.saveModel(s) + self.assertEqual(1, s.size()) + self.assertEqual(1, s.solids().size()) + self.assertEqual(2, s.faces().size()) + self.assertEqual(2, s.vertices().size()) + s1 = Workplane("XY").cone(40, radius1=10, radius2=5) + self.saveModel(s) + self.assertEqual(1, s1.size()) + self.assertEqual(1, s1.solids().size()) + self.assertEqual(3, s1.faces().size()) + self.assertEqual(2, s1.vertices().size()) def testWedgeDefaults(self): s = Workplane("XY").wedge(10, 10, 10, 5, 5, 5, 5) From 220ac89c01737baec87d9c3952fb2bbe5cec9922 Mon Sep 17 00:00:00 2001 From: Martin Budden Date: Tue, 31 Aug 2021 17:58:08 +0100 Subject: [PATCH 2/7] Improved cone docstring. Removed saveModel from cone test. --- cadquery/cq.py | 3 +++ tests/test_cadquery.py | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cadquery/cq.py b/cadquery/cq.py index 9e5daf082..57cc3c7c9 100644 --- a/cadquery/cq.py +++ b/cadquery/cq.py @@ -3831,11 +3831,14 @@ def cone( :type combine: true to combine shapes, false otherwise :param clean: call :py:meth:`clean` afterwards to have a clean shape :return: A cone object for each point on the stack + One cone is created for each item on the current stack. If no items are on the stack, one cone is created using the current workplane center. + If combine is true, the result will be a single object on the stack. If a solid was found in the chain, the result is that solid with all cones produced fused onto it otherwise, the result is the combination of all the produced cones. + If combine is false, the result will be a list of the cones produced. """ diff --git a/tests/test_cadquery.py b/tests/test_cadquery.py index 3b3727c19..cbf5e7bc0 100644 --- a/tests/test_cadquery.py +++ b/tests/test_cadquery.py @@ -2477,13 +2477,11 @@ def testCylinderCentering(self): ) def testConeDefaults(self): s = Workplane("XY").cone(40, 10) - self.saveModel(s) self.assertEqual(1, s.size()) self.assertEqual(1, s.solids().size()) self.assertEqual(2, s.faces().size()) self.assertEqual(2, s.vertices().size()) s1 = Workplane("XY").cone(40, radius1=10, radius2=5) - self.saveModel(s) self.assertEqual(1, s1.size()) self.assertEqual(1, s1.solids().size()) self.assertEqual(3, s1.faces().size()) From 8bac6b1f1f522034253e3e8a23fc596025877fb2 Mon Sep 17 00:00:00 2001 From: Martin Budden Date: Thu, 2 Sep 2021 10:49:44 +0100 Subject: [PATCH 3/7] Added newline. --- tests/test_cadquery.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_cadquery.py b/tests/test_cadquery.py index cbf5e7bc0..9b1a9d236 100644 --- a/tests/test_cadquery.py +++ b/tests/test_cadquery.py @@ -2475,6 +2475,7 @@ def testCylinderCentering(self): self.assertTupleAlmostEquals( s0.val().Center().toTuple(), s1.val().Center().toTuple(), 3 ) + def testConeDefaults(self): s = Workplane("XY").cone(40, 10) self.assertEqual(1, s.size()) From f9c36d074f6f1d6b3e3760027c872cf92052c114 Mon Sep 17 00:00:00 2001 From: Martin Budden Date: Thu, 2 Sep 2021 12:39:12 +0100 Subject: [PATCH 4/7] Added test. --- tests/test_cadquery.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_cadquery.py b/tests/test_cadquery.py index 9b1a9d236..940229350 100644 --- a/tests/test_cadquery.py +++ b/tests/test_cadquery.py @@ -2487,6 +2487,11 @@ def testConeDefaults(self): self.assertEqual(1, s1.solids().size()) self.assertEqual(3, s1.faces().size()) self.assertEqual(2, s1.vertices().size()) + s2 = Workplane("XY").cone(40, radius1=10, radius2=5, combine=True) + self.assertEqual(1, s2.size()) + self.assertEqual(1, s2.solids().size()) + self.assertEqual(3, s2.faces().size()) + self.assertEqual(2, s2.vertices().size()) def testWedgeDefaults(self): s = Workplane("XY").wedge(10, 10, 10, 5, 5, 5, 5) From 5dc7bba4093f9a80d96cc437e9920f62a3260181 Mon Sep 17 00:00:00 2001 From: Martin Budden Date: Thu, 2 Sep 2021 13:17:50 +0100 Subject: [PATCH 5/7] Changed test parameter. --- tests/test_cadquery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_cadquery.py b/tests/test_cadquery.py index 940229350..694a08bf4 100644 --- a/tests/test_cadquery.py +++ b/tests/test_cadquery.py @@ -2487,7 +2487,7 @@ def testConeDefaults(self): self.assertEqual(1, s1.solids().size()) self.assertEqual(3, s1.faces().size()) self.assertEqual(2, s1.vertices().size()) - s2 = Workplane("XY").cone(40, radius1=10, radius2=5, combine=True) + s2 = Workplane("XY").cone(40, radius1=10, radius2=5, combine=False) self.assertEqual(1, s2.size()) self.assertEqual(1, s2.solids().size()) self.assertEqual(3, s2.faces().size()) From e780ad937da8cd2c9bb94ebfa62a41c9ca8429d6 Mon Sep 17 00:00:00 2001 From: Martin Budden Date: Wed, 8 Sep 2021 15:05:29 +0100 Subject: [PATCH 6/7] Reordered cone parameters. --- cadquery/cq.py | 2 +- tests/test_cadquery.py | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cadquery/cq.py b/cadquery/cq.py index 57cc3c7c9..54e84da6a 100644 --- a/cadquery/cq.py +++ b/cadquery/cq.py @@ -3803,9 +3803,9 @@ def sphere( def cone( self: T, height: float, - radius: float = 0, radius1: float = None, radius2: float = None, + radius: float = 0, direct: Vector = Vector(0, 0, 1), angle: float = 360, combine: bool = True, diff --git a/tests/test_cadquery.py b/tests/test_cadquery.py index 694a08bf4..312f07e36 100644 --- a/tests/test_cadquery.py +++ b/tests/test_cadquery.py @@ -2482,16 +2482,21 @@ def testConeDefaults(self): self.assertEqual(1, s.solids().size()) self.assertEqual(2, s.faces().size()) self.assertEqual(2, s.vertices().size()) - s1 = Workplane("XY").cone(40, radius1=10, radius2=5) + s1 = Workplane("XY").cone(40, 10, 5) self.assertEqual(1, s1.size()) self.assertEqual(1, s1.solids().size()) self.assertEqual(3, s1.faces().size()) self.assertEqual(2, s1.vertices().size()) - s2 = Workplane("XY").cone(40, radius1=10, radius2=5, combine=False) + s2 = Workplane("XY").cone(40, radius1=10, radius2=5) self.assertEqual(1, s2.size()) self.assertEqual(1, s2.solids().size()) self.assertEqual(3, s2.faces().size()) self.assertEqual(2, s2.vertices().size()) + s3 = Workplane("XY").cone(40, radius1=10, radius2=5, combine=False) + self.assertEqual(1, s3.size()) + self.assertEqual(1, s3.solids().size()) + self.assertEqual(3, s3.faces().size()) + self.assertEqual(2, s3.vertices().size()) def testWedgeDefaults(self): s = Workplane("XY").wedge(10, 10, 10, 5, 5, 5, 5) From 57f080942bee2f2d68b486d316c48bc0b84d1d5a Mon Sep 17 00:00:00 2001 From: Martin Budden Date: Wed, 8 Sep 2021 15:07:12 +0100 Subject: [PATCH 7/7] Reordered cone docstring parameters. --- cadquery/cq.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cadquery/cq.py b/cadquery/cq.py index 54e84da6a..d1ff73f81 100644 --- a/cadquery/cq.py +++ b/cadquery/cq.py @@ -3816,12 +3816,12 @@ def cone( A truncated cone can be created by specifying parameters radius1 and radius2 instead of radius. :param height: The height of the cone :type height: float > 0 - :param radius: The radius of the cone - :type radius: float > 0 :param radius1: The radius of the bottom of the cone :type radius1: float > 0 :param radius2: The radius of the top of the cone :type radius2: float > 0 + :param radius: The radius of the cone + :type radius: float > 0 :param direct: The direction axis for the creation of the cone :type direct: A three-tuple :param angle: The angle to sweep the cone arc through