Skip to content

feat: component operations - make_independent() and import_named_selections() #2129

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

Merged
merged 9 commits into from
Jul 24, 2025
1 change: 1 addition & 0 deletions doc/changelog.d/2129.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Component operations - make_independent() and import_named_selections()
43 changes: 43 additions & 0 deletions src/ansys/geometry/core/designer/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
from ansys.api.geometry.v0.commands_pb2_grpc import CommandsStub
from ansys.api.geometry.v0.components_pb2 import (
CreateRequest,
ImportGroupsRequest,
MakeIndependentRequest,
SetPlacementRequest,
SetSharedTopologyRequest,
)
Expand Down Expand Up @@ -70,6 +72,7 @@
from ansys.geometry.core.math.matrix import Matrix44
from ansys.geometry.core.math.point import Point3D
from ansys.geometry.core.math.vector import UnitVector3D, Vector3D
from ansys.geometry.core.misc.auxiliary import get_design_from_component
from ansys.geometry.core.misc.checks import (
ensure_design_is_active,
graphics_required,
Expand Down Expand Up @@ -1876,3 +1879,43 @@ def build_parent_tree(comp: Component, parent_tree: str = "") -> str:
lines.extend([f"|{'-' * (indent - 1)}(comp) {comp.name}" for comp in comps])

return lines if return_list else print("\n".join(lines))

@protect_grpc
@min_backend_version(26, 1, 0)
def import_named_selections(self) -> None:
"""Import named selections of a component.

When a design is inserted, it becomes a component. From 26R1 onwards, the named selections
of that component will be imported by default. If a file is opened that contains a
component that did not have its named selections imported, this method can be used to
import them.

Warnings
--------
This method is only available starting on Ansys release 26R1.
"""
self._component_stub.ImportGroups(ImportGroupsRequest(id=self._grpc_id))

design = get_design_from_component(self)
design._update_design_inplace()

@protect_grpc
@min_backend_version(26, 1, 0)
def make_independent(self, others: list["Component"] = None) -> None:
"""Make a component independent if it is an instance.

If a component is an instance of another component, modifying one component modifies both.
When a component is made independent, it is no longer associated with other instances and
can be modified separately.

Parameters
----------
others : list[Component], default: None
Optionally include multiple components to make them all independent.

Warnings
--------
This method is only available starting on Ansys release 26R1.
"""
ids = [self._grpc_id, *[o._grpc_id for o in others or []]]
self._component_stub.MakeIndependent(MakeIndependentRequest(ids=ids))
Binary file added tests/integration/files/cars.scdocx
Binary file not shown.
Binary file not shown.
30 changes: 30 additions & 0 deletions tests/integration/test_design.py
Original file line number Diff line number Diff line change
Expand Up @@ -3548,3 +3548,33 @@ def test_extrude_edges_missing_parameters(modeler: Modeler):
from_point=None,
direction=None,
)


def test_import_component_named_selections(modeler: Modeler):
"""Test importing named selections from an inserted design component."""
# This file had a component inserted into it that has named selections that we need to import
design = modeler.open_file(Path(FILES_DIR, "import_component_groups.scdocx"))
component = design.components[0]

assert len(design.named_selections) == 0
component.import_named_selections()
assert len(design.named_selections) == 3


def test_component_make_independent(modeler: Modeler):
"""Test making components independent."""

design = modeler.open_file(Path(FILES_DIR, "cars.scdocx"))
face = next((ns for ns in design.named_selections if ns.name == "to_pull"), None).faces[0]
comp = next(
(ns for ns in design.named_selections if ns.name == "make_independent"), None
).components[0]

comp.make_independent()

assert Accuracy.length_is_equal(comp.bodies[0].volume.m, face.body.volume.m)

modeler.geometry_commands.extrude_faces(face, 1)
comp = design.components[0].components[-1].components[-1] # stale from update-design-in-place

assert not Accuracy.length_is_equal(comp.bodies[0].volume.m, face.body.volume.m)