Skip to content
Open
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
33 changes: 22 additions & 11 deletions cadquery/occ_impl/assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
)
from OCP.BRepAlgoAPI import BRepAlgoAPI_Fuse
from OCP.TopTools import TopTools_ListOfShape
from OCP.BOPAlgo import BOPAlgo_GlueEnum, BOPAlgo_MakeConnected
from OCP.BOPAlgo import BOPAlgo_GlueEnum, BOPAlgo_Builder
from OCP.TopoDS import TopoDS_Shape
from OCP.gp import gp_EulerSequence

Expand All @@ -49,7 +49,7 @@
)

from .geom import Location
from .shapes import Shape, Solid, Compound
from .shapes import Shape, Solid, Compound, GlueLiteral, _set_glue, _set_builder_options
from .exporters.vtk import toString, extractEdgesFaces
from ..cq import Workplane
from ..utils import BiDict
Expand Down Expand Up @@ -855,9 +855,14 @@ def toFusedCAF(
return top_level_lbl, doc


def imprint(assy: AssemblyProtocol) -> Tuple[Shape, Dict[Shape, Tuple[str, ...]]]:
def imprint(
assy: AssemblyProtocol, tol: float = 0.0, glue: GlueLiteral = "partial",
) -> Tuple[Shape, Dict[Shape, Tuple[str, ...]]]:
"""
Imprint all the solids and construct a dictionary mapping imprinted solids to names from the input assy.

Depending on the use case, it might be required do use different `glue` option. Moreover, for large models
Comment thread
adam-urbanczyk marked this conversation as resolved.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Depending on the use case, it might be required do use different `glue` option. Moreover, for large models
Depending on the use case, it might be required to use a different `glue` option. Moreover, for large models

it might be needed to limit the number of threads using :meth:`cadquery.func.setThreads`
"""

# make the id map
Expand All @@ -868,22 +873,28 @@ def imprint(assy: AssemblyProtocol) -> Tuple[Shape, Dict[Shape, Tuple[str, ...]]
id_map[s] = name

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

_set_glue(builder, glue)
_set_builder_options(builder, tol)

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

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

# make the connected solid -> id map
ocp_origins = builder.Origins()
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 yields nothing, solid was not modified
if ocp_origins.IsBound(s.wrapped):
# if ocp_origins does not contain the solid, it was not modified
ids = tuple(id_map[Solid(el)] for el in ocp_origins.Find(s.wrapped))
else:
ids = ()

origins[s] = ids if ids else (id_map[s],)

return res, origins
2 changes: 1 addition & 1 deletion cadquery/occ_impl/nurbs.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ def isoline(self, param: float, dir: Literal["u", "v"] = "u") -> Curve:
@njiti
def _preprocess(
u: Array, order: int, knots: Array, periodic: bool
) -> Tuple[Array, Array, Optional[int], Optional[int], int]:
) -> Tuple[Array, Array, int, int, int]:
"""
Helper for handling periodicity. This function extends the knot vector,
wraps the parameters and calculates the delta span.
Expand Down
5 changes: 4 additions & 1 deletion cadquery/occ_impl/shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6956,12 +6956,15 @@ def enclose(
def imprint(
*shapes: Shape,
tol: float = 0.0,
glue: GlueLiteral = "full",
glue: GlueLiteral = "partial",
history: History | None = None,
name: str | None = None,
) -> Shape:
"""
Imprint arbitrary number of shapes.

Depending on the use case, it might be required do use different `glue` option. Moreover, for large models

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Depending on the use case, it might be required do use different `glue` option. Moreover, for large models
Depending on the use case, it might be required to use a different `glue` option. Moreover, for large models

it might be needed to limit the number of threads using :meth:`cadquery.func.setThreads`
"""

builder = BOPAlgo_Builder()
Expand Down
32 changes: 32 additions & 0 deletions tests/test_assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from pytest import approx

import cadquery as cq

from cadquery import Location
from cadquery.occ_impl.exporters.assembly import (
exportAssembly,
exportStepMeta,
Expand Down Expand Up @@ -2324,6 +2326,16 @@ def touching_assy():
return cq.Assembly().add(b1).add(b2)


@pytest.fixture
def complex_assy(touching_assy):

return (
cq.Assembly()
.add(touching_assy, name="sub1")
.add(touching_assy, loc=Location((5, 0, 0)), name="sub2")
)


@pytest.fixture
def disjoint_assy():

Expand Down Expand Up @@ -2354,6 +2366,26 @@ def test_imprinting(touching_assy, disjoint_assy):
assert s in o


def test_subassy_imprinting(complex_assy):

# imprint subassys separately
res1, origins1 = cq.occ_impl.assembly.imprint(complex_assy.sub1)
res2, origins2 = cq.occ_impl.assembly.imprint(complex_assy.sub2)

# reference one step imprint
ref, _ = cq.occ_impl.assembly.imprint(complex_assy)

# combine the results
res = res1 | res2
origins = origins1 | origins2

assert len(res.Solids()) == len(ref.Solids())
assert len(res.Faces()) == len(ref.Faces())

for s in res.Solids():
assert s in origins


def test_order_of_transform():

part = cq.Workplane().box(1, 1, 1).faces(">Z").vertices("<XY").tag("vtag")
Expand Down