Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
24 changes: 24 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,16 @@ 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.
"""
return


class MasterBody(IBody):
"""Represents solids and surfaces organized within the design assembly.
Expand Down Expand Up @@ -1360,6 +1370,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 +1924,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