Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assembly toCompound #726

Merged
merged 4 commits into from
Apr 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)