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

Imprinting and matching #1353

Merged
merged 12 commits into from
Jul 4, 2023
52 changes: 50 additions & 2 deletions cadquery/occ_impl/assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from OCP.Quantity import Quantity_ColorRGBA
from OCP.BRepAlgoAPI import BRepAlgoAPI_Fuse
from OCP.TopTools import TopTools_ListOfShape
from OCP.BOPAlgo import BOPAlgo_GlueEnum
from OCP.BOPAlgo import BOPAlgo_GlueEnum, BOPAlgo_MakeConnected
from OCP.TopoDS import TopoDS_Shape

from vtkmodules.vtkRenderingCore import (
Expand All @@ -22,7 +22,7 @@
)

from .geom import Location
from .shapes import Shape, Compound
from .shapes import Shape, Solid, Compound
from .exporters.vtk import toString
from ..cq import Workplane

Expand Down Expand Up @@ -411,3 +411,51 @@ def extract_shapes(assy, parent_loc=None, parent_color=None):
color_tool.SetColor(cur_lbl, color.wrapped, XCAFDoc_ColorGen)

return top_level_lbl, doc


def imprint(assy: AssemblyProtocol) -> Tuple[Shape, Dict[Shape, Tuple[str, ...]]]:

# assy iterator
def iterate(a, loc=None, name=None):

name = f"{name}/{a.name}" if name else a.name
loc = loc * a.loc if loc else a.loc

if a.obj:
yield a.obj, name, loc

for ch in a.children:
yield from iterate(ch, loc, name)

# make the id map
id_map = {}

for obj, name, loc in iterate(assy):
if isinstance(obj, Shape):
tmp = obj.moved(loc)
else:
tmp = Compound.makeCompound(obj.vals()).moved(loc)

for s in tmp.Solids():
id_map[s] = name

# connect topologically
bldr = BOPAlgo_MakeConnected()
bldr.SetRunParallel(True)
bldr.SetUseOBB(True)

for obj in id_map:
bldr.AddArgument(obj.wrapped)

bldr.Perform()
res = Shape(bldr.Shape())

# make the conneted solid -> id map
adam-urbanczyk marked this conversation as resolved.
Show resolved Hide resolved
origins: Dict[Shape, Tuple[str, ...]] = {}

for s in res.Solids():
ids = tuple(id_map[Solid(el)] for el in bldr.GetOrigins(s.wrapped))
# if GetOrigins yiels nothing, solid was not modified
adam-urbanczyk marked this conversation as resolved.
Show resolved Hide resolved
origins[s] = ids if ids else (id_map[s],)

return res, origins
4 changes: 3 additions & 1 deletion environment.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
name: cadquery
channels:
- conda-forge
- cadquery/dev
- cadquery
dependencies:
- python>=3.8
- ipython
- ocp=7.7.*
- ocp=7.7.1.*
- python-gmsh
adam-urbanczyk marked this conversation as resolved.
Show resolved Hide resolved
- pyparsing>=2.1.9
- sphinx=5.0.1
- sphinx_rtd_theme
Expand Down
39 changes: 39 additions & 0 deletions tests/test_assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -1475,3 +1475,42 @@ def test_point_constraint(simple_assy2):
t2 = assy.children[1].loc.wrapped.Transformation().TranslationPart()

assert t2.Modulus() == pytest.approx(1)


@pytest.fixture
def touching_assy():

b1 = cq.Workplane().box(1, 1, 1)
b2 = cq.Workplane(origin=(1, 0, 0)).box(1, 1, 1)

return cq.Assembly().add(b1).add(b2)


@pytest.fixture
def disjoint_assy():

b1 = cq.Workplane().box(1, 1, 1)
b2 = cq.Workplane(origin=(2, 0, 0)).box(1, 1, 1)

return cq.Assembly().add(b1).add(b2)


def test_imprinting(touching_assy, disjoint_assy):

# normal usecase
r, o = cq.occ_impl.assembly.imprint(touching_assy)

assert len(r.Solids()) == 2
assert len(r.Faces()) == 11

for s in r.Solids():
assert s in o

# edge usecase
r, o = cq.occ_impl.assembly.imprint(disjoint_assy)

assert len(r.Solids()) == 2
assert len(r.Faces()) == 12

for s in r.Solids():
assert s in o