Skip to content

Commit

Permalink
Assembly toCompound (#726)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
3 people authored Apr 19, 2021
1 parent cf820d5 commit 0f249df
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 3 deletions.
13 changes: 12 additions & 1 deletion cadquery/assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from uuid import uuid1 as uuid

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

return rv

def toCompound(self) -> Compound:
"""
Returns a Compound made from this Assembly (including all children) with the
current Locations applied. Usually this method would only be used after solving.
"""

shapes = self.shapes
shapes.extend((child.toCompound() for child in self.children))

return Compound.makeCompound(shapes).locate(self.loc)
4 changes: 2 additions & 2 deletions cadquery/occ_impl/shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,7 @@ def location(self) -> Location:

return Location(self.wrapped.Location())

def locate(self, loc: Location) -> "Shape":
def locate(self: T, loc: Location) -> T:
"""
Apply a location in absolute sense to self
"""
Expand All @@ -918,7 +918,7 @@ def located(self, loc: Location) -> "Shape":

return r

def move(self, loc: Location) -> "Shape":
def move(self: T, loc: Location) -> T:
"""
Apply a location in relative sense (i.e. update current location) to self
"""
Expand Down
39 changes: 39 additions & 0 deletions tests/test_assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,3 +391,42 @@ def resulting_plane(shape0):

# solid should fail
fail_this(cq.Solid.makeBox(1, 1, 1))


def test_toCompound(simple_assy, nested_assy):

c0 = simple_assy.toCompound()
assert isinstance(c0, cq.Compound)
assert len(c0.Solids()) == 4

c1 = nested_assy.toCompound()
assert isinstance(c1, cq.Compound)
assert len(c1.Solids()) == 4

# check nested assy location appears in compound
# create four boxes, stack them on top of each other, check highest face is in final compound
box0 = cq.Workplane().box(1, 1, 3, centered=(True, True, False))
box1 = cq.Workplane().box(1, 1, 4)
box2 = cq.Workplane().box(1, 1, 5)
box3 = cq.Workplane().box(1, 1, 6)
# top level assy
assy0 = cq.Assembly(box0, name="box0")
assy0.add(box1, name="box1")
assy0.constrain("box0@faces@>Z", "box1@faces@<Z", "Plane")
# subassy
assy1 = cq.Assembly()
assy1.add(box2, name="box2")
assy1.add(box3, name="box3")
assy1.constrain("box2@faces@>Z", "box3@faces@<Z", "Plane")
assy1.solve()
assy0.add(assy1, name="assy1")
assy0.constrain("box1@faces@>Z", "assy1/box2@faces@<Z", "Plane")
# before solving there should be no face with Center = (0, 0, 18)
c2 = assy0.toCompound()
assert not cq.Vector(0, 0, 18) in [x.Center() for x in c2.Faces()]
# after solving there should be a face with Center = (0, 0, 18)
assy0.solve()
c3 = assy0.toCompound()
assert cq.Vector(0, 0, 18) in [x.Center() for x in c3.Faces()]
# also check with bounding box
assert c3.BoundingBox().zlen == pytest.approx(18)

0 comments on commit 0f249df

Please sign in to comment.