I believe that this was missing from CadQuery some time ago, and I've implemented a solution for myself. It's the ability to do a cut() on an assembly, e.g. to create a nice colored cutaway drawing of your assembly/design. Sorry, I don't have the time or internet resources to do a search to find where the appropriate place to post this is.
Code would look like the following. This is only a general strategy that works at least in some cases. An intersect() would be very similar; mathematically the intersect() strategy could be implemented by taking an infinitely large box, subtracting from it the intersection solid, and then doing a subtract() with the remaining object.
def subtract(whole_assy, subtrahend): if not isinstance(whole_assy, Assembly):
raise TypeError(
"subtract(): expected 'whole_assy' to be Assembly object type")
# Because we don't really want to apply the 'whole_assy.loc' transformation
# to all children of the Assembly object (and then we'd set that transform
# to identity), we instead choose to compute the inverse transformation and
# we pass 'subtrahend' through that inverse.
inverse = whole_assy.loc.inverse.wrapped.Transformation()
# We could also minimize the number of times 'subtrahend' is passed through
# a transformation by keeping a concatenated/cumulative inverse
# transformation and pass that around. We choose the more obvious course
# of action, which may be less optimal but requires less bookkeeping.
if isinstance(subtrahend, Shape):
subtrahend = subtrahend._apply_transform(inverse)
elif isinstance(subtrahend, Workplane):
subtrahend = subtrahend.newObject(
[
obj._apply_transform(inverse)
if isinstance(obj, Shape)
else obj
for obj in subtrahend.objects
]
)
else:
raise TypeError(
"subtract(): expected 'subtrahend' to be Shape or Workplane")
if whole_assy.obj is not None:
whole_assy.obj = whole_assy.obj.cut(subtrahend)
for child in whole_assy.children:
subtract(child, subtrahend)
return whole_assy