Skip to content

Commit 23b4797

Browse files
fix bug: extrude both direction and cut #1090 (#1234)
* fix bug: extrude both direction and cut #1090 * Use glue in the _extrude both case * Check for redundant faces * Add type annotation for mypy * Restructure to fix mypy failure * Typo fix * We expect 6+4 faces... * added a docstring on param both in cutBlind --------- Co-authored-by: AU <[email protected]> Co-authored-by: Yihui (Ray) Ren <[email protected]>
1 parent 0aa889c commit 23b4797

File tree

2 files changed

+63
-13
lines changed

2 files changed

+63
-13
lines changed

cadquery/cq.py

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3015,7 +3015,7 @@ def extrude(
30153015

30163016
# If subtractive mode is requested, use cutBlind
30173017
if combine in ("cut", "s"):
3018-
return self.cutBlind(until, clean, taper)
3018+
return self.cutBlind(until, clean, both, taper)
30193019

30203020
# Handle `until` multiple values
30213021
elif until in ("next", "last") and combine in (True, "a"):
@@ -3143,7 +3143,7 @@ def sweep(
31433143
from warnings import warn
31443144

31453145
warn(
3146-
"sweepAlongWires keyword argument is is deprecated and will "
3146+
"sweepAlongWires keyword argument is deprecated and will "
31473147
"be removed in the next version; use multisection instead",
31483148
DeprecationWarning,
31493149
)
@@ -3426,6 +3426,7 @@ def cutBlind(
34263426
self: T,
34273427
until: Union[float, Literal["next", "last"], Face],
34283428
clean: bool = True,
3429+
both: bool = False,
34293430
taper: Optional[float] = None,
34303431
) -> T:
34313432
"""
@@ -3442,6 +3443,7 @@ def cutBlind(
34423443
normal. "last" cuts to the last face. If an object of type Face is passed, then the cut
34433444
will extend until this face.
34443445
:param clean: call :meth:`clean` afterwards to have a clean shape
3446+
:param both: cut in both directions symmetrically
34453447
:param taper: angle for optional tapered extrusion
34463448
:raises ValueError: if there is no solid to subtract from in the chain
34473449
:return: a CQ object with the resulting object selected
@@ -3450,19 +3452,43 @@ def cutBlind(
34503452
"""
34513453
# Handling of `until` passed values
34523454
s: Union[Compound, Solid, Shape]
3455+
if isinstance(both, float) and taper == None:
3456+
# Because inserting a new paramater "both" in front of "taper",
3457+
# existing code calling this function with position arguments will
3458+
# pass the taper argument (float) to the "both" argument. This
3459+
# warning is to catch that.
3460+
from warnings import warn
3461+
3462+
warn(
3463+
"cutBlind added a new keyword argument `both=True`. "
3464+
"The signature is changed from "
3465+
"(until, clean, taper) -> (until, clean, both, taper)",
3466+
DeprecationWarning,
3467+
)
3468+
3469+
# assign 3rd argument value to taper
3470+
taper = both
3471+
both = False
3472+
34533473
if isinstance(until, str) and until in ("next", "last"):
34543474
if until == "next":
34553475
faceIndex = 0
34563476
elif until == "last":
34573477
faceIndex = -1
34583478

3459-
s = self._extrude(None, taper=taper, upToFace=faceIndex, additive=False)
3479+
s = self._extrude(
3480+
None, both=both, taper=taper, upToFace=faceIndex, additive=False
3481+
)
34603482

34613483
elif isinstance(until, Face):
3462-
s = self._extrude(None, taper=taper, upToFace=until, additive=False)
3484+
s = self._extrude(
3485+
None, both=both, taper=taper, upToFace=until, additive=False
3486+
)
34633487

34643488
elif isinstance(until, (int, float)):
3465-
toCut = self._extrude(until, taper=taper, upToFace=None, additive=False)
3489+
toCut = self._extrude(
3490+
until, both=both, taper=taper, upToFace=None, additive=False
3491+
)
34663492
solidRef = self.findSolid()
34673493
s = solidRef.cut(toCut)
34683494
else:
@@ -3610,8 +3636,6 @@ def getFacesList(face, eDir, direction, both=False):
36103636
direction = "AlongAxis" if additive else "Opposite"
36113637
taper = 0.0 if taper is None else taper
36123638

3613-
toFuse = []
3614-
36153639
if upToFace is not None:
36163640
res = self.findSolid()
36173641
for face in faces:
@@ -3644,17 +3668,20 @@ def getFacesList(face, eDir, direction, both=False):
36443668
upToFace=limitFace2,
36453669
additive=additive,
36463670
)
3647-
36483671
else:
3672+
toFuse = []
36493673
for face in faces:
3650-
res = Solid.extrudeLinear(face, eDir, taper=taper)
3651-
toFuse.append(res)
3674+
s1 = Solid.extrudeLinear(face, eDir, taper=taper)
36523675

36533676
if both:
3654-
res = Solid.extrudeLinear(face, eDir.multiply(-1.0), taper=taper)
3655-
toFuse.append(res)
3677+
s2 = Solid.extrudeLinear(face, eDir.multiply(-1.0), taper=taper)
3678+
toFuse.append(s1.fuse(s2, glue=True))
3679+
else:
3680+
toFuse.append(s1)
3681+
3682+
res = Compound.makeCompound(toFuse)
36563683

3657-
return res if upToFace is not None else Compound.makeCompound(toFuse)
3684+
return res
36583685

36593686
def _revolve(
36603687
self, angleDegrees: float, axisStart: VectorLike, axisEnd: VectorLike

tests/test_cadquery.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3620,6 +3620,18 @@ def testExtrude(self):
36203620
r = box.faces(">Z").workplane(invert=True).circle(0.5).extrude(4, combine="cut")
36213621
self.assertGreater(box.val().Volume(), r.val().Volume())
36223622

3623+
# Test extrude with both=True and combine="cut"
3624+
wp_ref = Workplane("XY").rect(40, 40).extrude(20, both=True)
3625+
3626+
wp_ref_regular_cut = (
3627+
wp_ref.workplane(offset=-20).rect(20, 20).extrude(40, combine="s")
3628+
)
3629+
3630+
wp = wp_ref.workplane().rect(20, 20).extrude(20, both=True, combine="s")
3631+
3632+
assert wp.faces().size() == 6 + 4
3633+
self.assertAlmostEqual(wp_ref_regular_cut.val().Volume(), wp.val().Volume())
3634+
36233635
def testTaperedExtrudeCutBlind(self):
36243636

36253637
h = 1.0
@@ -3663,6 +3675,17 @@ def testTaperedExtrudeCutBlind(self):
36633675

36643676
self.assertTrue(middle_face.val().Area() < 1)
36653677

3678+
with self.assertWarns(DeprecationWarning):
3679+
s = (
3680+
Workplane("XY")
3681+
.rect(2 * r, 2 * r)
3682+
.extrude(2 * h)
3683+
.faces(">Z")
3684+
.workplane()
3685+
.rect(r, r)
3686+
.cutBlind(-h, True, float(t))
3687+
)
3688+
36663689
def testClose(self):
36673690
# Close without endPoint and startPoint coincide.
36683691
# Create a half-circle

0 commit comments

Comments
 (0)