Skip to content
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
1 change: 1 addition & 0 deletions doc/changelog.d/2282.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Combine and merge bodies
5 changes: 5 additions & 0 deletions src/ansys/geometry/core/_grpc/_services/base/bodies.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,8 @@ def split_body(self, **kwargs) -> dict:
def create_body_from_loft_profiles_with_guides(self, **kwargs) -> dict:
"""Create a body from loft profiles with guides."""
pass

@abstractmethod
def combine_merge(self, **kwargs) -> dict:
"""Combine and merge bodies."""
pass
15 changes: 15 additions & 0 deletions src/ansys/geometry/core/_grpc/_services/v0/bodies.py
Original file line number Diff line number Diff line change
Expand Up @@ -890,3 +890,18 @@ def create_body_from_loft_profiles_with_guides(self, **kwargs) -> dict: # noqa:
"master_id": new_body.master_id,
"is_surface": new_body.is_surface,
}

@protect_grpc
def combine_merge(self, **kwargs) -> dict: # noqa: D102
from ansys.api.geometry.v0.commands_pb2 import CombineMergeBodiesRequest

# Create the request - assumes all inputs are valid and of the proper type
request = CombineMergeBodiesRequest(
target_selection=[build_grpc_id(id) for id in kwargs["body_ids"]],
)

# Call the gRPC service
_ = self.command_stub.CombineMergeBodies(request=request)

# Return the response - formatted as a dictionary
return {}
4 changes: 4 additions & 0 deletions src/ansys/geometry/core/_grpc/_services/v1/bodies.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,3 +203,7 @@ def split_body(self, **kwargs) -> dict: # noqa: D102
@protect_grpc
def create_body_from_loft_profiles_with_guides(self, **kwargs) -> dict: # noqa: D102
raise NotImplementedError

@protect_grpc
def combine_merge(self, **kwargs) -> dict: # noqa: D102
raise NotImplementedError
28 changes: 28 additions & 0 deletions src/ansys/geometry/core/designer/body.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,20 @@ def unite(self, other: Union["Body", Iterable["Body"]], keep_other: bool = False
"""
return

def combine_merge(self, other: Union["Body", list["Body"]]) -> None:
"""Combine this body with another body or bodies, merging them into a single body.

Parameters
----------
other : Union[Body, list[Body]]
The body or list of bodies to combine with this body.

Notes
-----
The ``self`` parameter is directly modified, and the ``other`` bodies are consumed.
"""
return


class MasterBody(IBody):
"""Represents solids and surfaces organized within the design assembly.
Expand Down Expand Up @@ -1360,6 +1374,17 @@ def remove_faces(self, selection: Face | Iterable[Face], offset: Real) -> bool:

return result.success

@min_backend_version(25, 2, 0)
@check_input_types
def combine_merge(self, other: Union["Body", list["Body"]]) -> None: # noqa: D102
other = other if isinstance(other, list) else [other]
check_type_all_elements_in_iterable(other, Body)

self._grpc_client.log.debug(f"Combining and merging to body {self.id}.")
self._grpc_client.services.bodies.combine_merge(
body_ids=[self.id] + [body.id for body in other]
)

def plot( # noqa: D102
self,
merge: bool = True,
Expand Down Expand Up @@ -1903,6 +1928,9 @@ def unite(self, other: Union["Body", Iterable["Body"]], keep_other: bool = False
else:
self.__generic_boolean_command(other, False, "unite", "union operation failed")

def combine_merge(self, other: Union["Body", list["Body"]]) -> None: # noqa: D102
self._template.combine_merge(other)

@reset_tessellation_cache
@ensure_design_is_active
@check_input_types
Expand Down
24 changes: 24 additions & 0 deletions tests/integration/test_design.py
Original file line number Diff line number Diff line change
Expand Up @@ -3909,3 +3909,27 @@ def test_write_body_facets_on_save(

missing = expected_files - namelist
assert not missing


def test_combine_merge(modeler: Modeler):
design = modeler.create_design("combine_merge")
box1 = design.extrude_sketch("box1", Sketch().box(Point2D([0, 0]), 1, 1), 1)
box2 = design.extrude_sketch("box2", Sketch().box(Point2D([0.5, 0.5]), 1, 1), 1)
assert len(design.bodies) == 2

# combine the two boxes and check body count and volume
box1.combine_merge([box2])
design._update_design_inplace()
assert len(design.bodies) == 1
assert box1.volume.m == pytest.approx(Quantity(1.75, UNITS.m**3).m, rel=1e-6, abs=1e-8)

# create a third box
box1 = design.bodies[0]
box3 = design.extrude_sketch("box3", Sketch().box(Point2D([-0.5, -0.5]), 1, 1), 1)
assert len(design.bodies) == 2

# combine the two boxes and check body count and volume
box1.combine_merge([box3])
design._update_design_inplace()
assert len(design.bodies) == 1
assert box1.volume.m == pytest.approx(Quantity(2.5, UNITS.m**3).m, rel=1e-6, abs=1e-8)
Loading