Skip to content

Commit 0f249df

Browse files
marcus7070jmwrightadam-urbanczyk
authored
Assembly toCompound (#726)
* Added Assembly.toCompound * spelling Co-authored-by: Jeremy Wright <[email protected]> * Add annotation + minor updates * Better annotations for locate and move Co-authored-by: Jeremy Wright <[email protected]> Co-authored-by: Adam Urbańczyk <[email protected]>
1 parent cf820d5 commit 0f249df

File tree

3 files changed

+53
-3
lines changed

3 files changed

+53
-3
lines changed

cadquery/assembly.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from uuid import uuid1 as uuid
55

66
from .cq import Workplane
7-
from .occ_impl.shapes import Shape, Face, Edge, Wire
7+
from .occ_impl.shapes import Shape, Compound, Face, Edge, Wire
88
from .occ_impl.geom import Location, Vector, Plane
99
from .occ_impl.assembly import Color
1010
from .occ_impl.solver import (
@@ -508,3 +508,14 @@ def _flatten(self, parents=[]):
508508
rv[PATH_DELIM.join(parents + [self.name])] = self
509509

510510
return rv
511+
512+
def toCompound(self) -> Compound:
513+
"""
514+
Returns a Compound made from this Assembly (including all children) with the
515+
current Locations applied. Usually this method would only be used after solving.
516+
"""
517+
518+
shapes = self.shapes
519+
shapes.extend((child.toCompound() for child in self.children))
520+
521+
return Compound.makeCompound(shapes).locate(self.loc)

cadquery/occ_impl/shapes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,7 @@ def location(self) -> Location:
899899

900900
return Location(self.wrapped.Location())
901901

902-
def locate(self, loc: Location) -> "Shape":
902+
def locate(self: T, loc: Location) -> T:
903903
"""
904904
Apply a location in absolute sense to self
905905
"""
@@ -918,7 +918,7 @@ def located(self, loc: Location) -> "Shape":
918918

919919
return r
920920

921-
def move(self, loc: Location) -> "Shape":
921+
def move(self: T, loc: Location) -> T:
922922
"""
923923
Apply a location in relative sense (i.e. update current location) to self
924924
"""

tests/test_assembly.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,42 @@ def resulting_plane(shape0):
391391

392392
# solid should fail
393393
fail_this(cq.Solid.makeBox(1, 1, 1))
394+
395+
396+
def test_toCompound(simple_assy, nested_assy):
397+
398+
c0 = simple_assy.toCompound()
399+
assert isinstance(c0, cq.Compound)
400+
assert len(c0.Solids()) == 4
401+
402+
c1 = nested_assy.toCompound()
403+
assert isinstance(c1, cq.Compound)
404+
assert len(c1.Solids()) == 4
405+
406+
# check nested assy location appears in compound
407+
# create four boxes, stack them on top of each other, check highest face is in final compound
408+
box0 = cq.Workplane().box(1, 1, 3, centered=(True, True, False))
409+
box1 = cq.Workplane().box(1, 1, 4)
410+
box2 = cq.Workplane().box(1, 1, 5)
411+
box3 = cq.Workplane().box(1, 1, 6)
412+
# top level assy
413+
assy0 = cq.Assembly(box0, name="box0")
414+
assy0.add(box1, name="box1")
415+
assy0.constrain("box0@faces@>Z", "box1@faces@<Z", "Plane")
416+
# subassy
417+
assy1 = cq.Assembly()
418+
assy1.add(box2, name="box2")
419+
assy1.add(box3, name="box3")
420+
assy1.constrain("box2@faces@>Z", "box3@faces@<Z", "Plane")
421+
assy1.solve()
422+
assy0.add(assy1, name="assy1")
423+
assy0.constrain("box1@faces@>Z", "assy1/box2@faces@<Z", "Plane")
424+
# before solving there should be no face with Center = (0, 0, 18)
425+
c2 = assy0.toCompound()
426+
assert not cq.Vector(0, 0, 18) in [x.Center() for x in c2.Faces()]
427+
# after solving there should be a face with Center = (0, 0, 18)
428+
assy0.solve()
429+
c3 = assy0.toCompound()
430+
assert cq.Vector(0, 0, 18) in [x.Center() for x in c3.Faces()]
431+
# also check with bounding box
432+
assert c3.BoundingBox().zlen == pytest.approx(18)

0 commit comments

Comments
 (0)