Skip to content

Commit

Permalink
Added cylinder 3D primitive.
Browse files Browse the repository at this point in the history
  • Loading branch information
martinbudden committed Aug 25, 2021
1 parent 247f0e6 commit 4110dd0
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 0 deletions.
58 changes: 58 additions & 0 deletions cadquery/cq.py
Original file line number Diff line number Diff line change
Expand Up @@ -3800,6 +3800,64 @@ def sphere(
else:
return self.union(spheres, clean=clean)

def cylinder(
self: T,
radius: float,
height: float,
centered: Union[bool, Tuple[bool, bool, bool]] = True,
combine: bool = True,
clean: bool = True,
) -> T:

"""
Returns a cylinder with the specified radius and height for each point on the stack
:param radius: The radius of the cylinder
:type radius: float > 0
:param height: The height of the cylinder
:type height: float > 0
:param centered: If True, the cylinder will be centered around the reference point. If False,
the corner of a bounding box around the cylinder will be on the reference point and it
will extend in the positive x, y and z directions. Can also use a 3-tuple to specify
centering along each axis.
: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 cylinder object for each point on the stack
One cylinder is created for each item on the current stack. If no items are on the stack, one
box using the current workplane center is created.
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 cylinders produced fused onto it otherwise,
the result is the combination of all the produced cylinders.
If combine is false, the result will be a list of the cylinders produced.
"""

if isinstance(centered, bool):
centered = (centered, centered, centered)

offset = Vector()
if not centered[0]:
offset += Vector(radius, 0, 0)
if not centered[1]:
offset += Vector(0, radius, 0)
if centered[2]:
offset += Vector(0, 0, -height/2)

c = self.circle(radius)._extrude(height).move(Location(offset))

# We want a cylinder for each point on the workplane
cylinders = self.eachpoint(lambda loc: c.moved(loc), True)

# If we don't need to combine everything, just return the created cylinders
if not combine:
return cylinders
else:
return self.union(cylinders, clean=clean)

def wedge(
self: T,
dx: float,
Expand Down
1 change: 1 addition & 0 deletions doc/apireference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ Some 3-d operations also require an active 2-d workplane, but some do not.
Workplane.cutThruAll
Workplane.box
Workplane.sphere
Workplane.cylinder
Workplane.union
Workplane.combine
Workplane.intersect
Expand Down
30 changes: 30 additions & 0 deletions tests/test_cadquery.py
Original file line number Diff line number Diff line change
Expand Up @@ -2443,6 +2443,36 @@ def testSphereCombine(self):
self.assertEqual(1, s.solids().size())
self.assertEqual(4, s.faces().size())

def testCylinderDefaults(self):
s = Workplane("XY").cylinder(10, 20)
self.saveModel(s)
self.assertEqual(1, s.size())
self.assertEqual(1, s.solids().size())
self.assertEqual(3, s.faces().size())
self.assertEqual(2, s.vertices().size())
self.assertTupleAlmostEquals(s.val().Center().toTuple(), (0, 0, 0), 3)

def testCylinderCentering(self):
radius = 10
height = 40
b = (True, False)
expected_x = (0, radius)
expected_y = (0, radius)
expected_z = (0, height/2)
for (xopt, xval), (yopt, yval), (zopt, zval) in product(
zip(b, expected_x), zip(b, expected_y), zip(b, expected_z)
):
s = Workplane("XY").cylinder(radius, height, centered=(xopt, yopt, zopt))
self.assertEqual(1, s.size())
self.assertTupleAlmostEquals(s.val().Center().toTuple(), (xval, yval, zval), 3)
# check centered=True produces the same result as centered=(True, True, True)
for val in b:
s0 = Workplane("XY").cylinder(radius, height, centered=val)
self.assertEqual(s0.size(), 1)
s1 = Workplane("XY").cylinder(radius, height, centered=(val, val, val))
self.assertEqual(s1.size(), 1)
self.assertTupleAlmostEquals(s0.val().Center().toTuple(), s1.val().Center().toTuple(), 3)

def testWedgeDefaults(self):
s = Workplane("XY").wedge(10, 10, 10, 5, 5, 5, 5)
self.saveModel(s)
Expand Down

0 comments on commit 4110dd0

Please sign in to comment.