Skip to content

Commit 4110dd0

Browse files
committed
Added cylinder 3D primitive.
1 parent 247f0e6 commit 4110dd0

File tree

3 files changed

+89
-0
lines changed

3 files changed

+89
-0
lines changed

cadquery/cq.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3800,6 +3800,64 @@ def sphere(
38003800
else:
38013801
return self.union(spheres, clean=clean)
38023802

3803+
def cylinder(
3804+
self: T,
3805+
radius: float,
3806+
height: float,
3807+
centered: Union[bool, Tuple[bool, bool, bool]] = True,
3808+
combine: bool = True,
3809+
clean: bool = True,
3810+
) -> T:
3811+
3812+
"""
3813+
Returns a cylinder with the specified radius and height for each point on the stack
3814+
3815+
:param radius: The radius of the cylinder
3816+
:type radius: float > 0
3817+
:param height: The height of the cylinder
3818+
:type height: float > 0
3819+
:param centered: If True, the cylinder will be centered around the reference point. If False,
3820+
the corner of a bounding box around the cylinder will be on the reference point and it
3821+
will extend in the positive x, y and z directions. Can also use a 3-tuple to specify
3822+
centering along each axis.
3823+
:param combine: Whether the results should be combined with other solids on the stack
3824+
(and each other)
3825+
:type combine: true to combine shapes, false otherwise
3826+
:param clean: call :py:meth:`clean` afterwards to have a clean shape
3827+
:return: A cylinder object for each point on the stack
3828+
3829+
One cylinder is created for each item on the current stack. If no items are on the stack, one
3830+
box using the current workplane center is created.
3831+
3832+
If combine is true, the result will be a single object on the stack. If a solid was found
3833+
in the chain, the result is that solid with all cylinders produced fused onto it otherwise,
3834+
the result is the combination of all the produced cylinders.
3835+
3836+
If combine is false, the result will be a list of the cylinders produced.
3837+
"""
3838+
3839+
if isinstance(centered, bool):
3840+
centered = (centered, centered, centered)
3841+
3842+
offset = Vector()
3843+
if not centered[0]:
3844+
offset += Vector(radius, 0, 0)
3845+
if not centered[1]:
3846+
offset += Vector(0, radius, 0)
3847+
if centered[2]:
3848+
offset += Vector(0, 0, -height/2)
3849+
3850+
c = self.circle(radius)._extrude(height).move(Location(offset))
3851+
3852+
# We want a cylinder for each point on the workplane
3853+
cylinders = self.eachpoint(lambda loc: c.moved(loc), True)
3854+
3855+
# If we don't need to combine everything, just return the created cylinders
3856+
if not combine:
3857+
return cylinders
3858+
else:
3859+
return self.union(cylinders, clean=clean)
3860+
38033861
def wedge(
38043862
self: T,
38053863
dx: float,

doc/apireference.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ Some 3-d operations also require an active 2-d workplane, but some do not.
9090
Workplane.cutThruAll
9191
Workplane.box
9292
Workplane.sphere
93+
Workplane.cylinder
9394
Workplane.union
9495
Workplane.combine
9596
Workplane.intersect

tests/test_cadquery.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2443,6 +2443,36 @@ def testSphereCombine(self):
24432443
self.assertEqual(1, s.solids().size())
24442444
self.assertEqual(4, s.faces().size())
24452445

2446+
def testCylinderDefaults(self):
2447+
s = Workplane("XY").cylinder(10, 20)
2448+
self.saveModel(s)
2449+
self.assertEqual(1, s.size())
2450+
self.assertEqual(1, s.solids().size())
2451+
self.assertEqual(3, s.faces().size())
2452+
self.assertEqual(2, s.vertices().size())
2453+
self.assertTupleAlmostEquals(s.val().Center().toTuple(), (0, 0, 0), 3)
2454+
2455+
def testCylinderCentering(self):
2456+
radius = 10
2457+
height = 40
2458+
b = (True, False)
2459+
expected_x = (0, radius)
2460+
expected_y = (0, radius)
2461+
expected_z = (0, height/2)
2462+
for (xopt, xval), (yopt, yval), (zopt, zval) in product(
2463+
zip(b, expected_x), zip(b, expected_y), zip(b, expected_z)
2464+
):
2465+
s = Workplane("XY").cylinder(radius, height, centered=(xopt, yopt, zopt))
2466+
self.assertEqual(1, s.size())
2467+
self.assertTupleAlmostEquals(s.val().Center().toTuple(), (xval, yval, zval), 3)
2468+
# check centered=True produces the same result as centered=(True, True, True)
2469+
for val in b:
2470+
s0 = Workplane("XY").cylinder(radius, height, centered=val)
2471+
self.assertEqual(s0.size(), 1)
2472+
s1 = Workplane("XY").cylinder(radius, height, centered=(val, val, val))
2473+
self.assertEqual(s1.size(), 1)
2474+
self.assertTupleAlmostEquals(s0.val().Center().toTuple(), s1.val().Center().toTuple(), 3)
2475+
24462476
def testWedgeDefaults(self):
24472477
s = Workplane("XY").wedge(10, 10, 10, 5, 5, 5, 5)
24482478
self.saveModel(s)

0 commit comments

Comments
 (0)