Skip to content

Commit 782aa66

Browse files
jacobrkerstetterpre-commit-ci[bot]pyansys-ci-botRobPasMue
authored
feat: combine and merge bodies (#2282)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: pyansys-ci-bot <[email protected]> Co-authored-by: Roberto Pastor Muela <[email protected]>
1 parent 99370ab commit 782aa66

File tree

6 files changed

+77
-0
lines changed

6 files changed

+77
-0
lines changed

doc/changelog.d/2282.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Combine and merge bodies

src/ansys/geometry/core/_grpc/_services/base/bodies.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,8 @@ def split_body(self, **kwargs) -> dict:
231231
def create_body_from_loft_profiles_with_guides(self, **kwargs) -> dict:
232232
"""Create a body from loft profiles with guides."""
233233
pass
234+
235+
@abstractmethod
236+
def combine_merge(self, **kwargs) -> dict:
237+
"""Combine and merge bodies."""
238+
pass

src/ansys/geometry/core/_grpc/_services/v0/bodies.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,3 +890,18 @@ def create_body_from_loft_profiles_with_guides(self, **kwargs) -> dict: # noqa:
890890
"master_id": new_body.master_id,
891891
"is_surface": new_body.is_surface,
892892
}
893+
894+
@protect_grpc
895+
def combine_merge(self, **kwargs) -> dict: # noqa: D102
896+
from ansys.api.geometry.v0.commands_pb2 import CombineMergeBodiesRequest
897+
898+
# Create the request - assumes all inputs are valid and of the proper type
899+
request = CombineMergeBodiesRequest(
900+
target_selection=[build_grpc_id(id) for id in kwargs["body_ids"]],
901+
)
902+
903+
# Call the gRPC service
904+
_ = self.command_stub.CombineMergeBodies(request=request)
905+
906+
# Return the response - formatted as a dictionary
907+
return {}

src/ansys/geometry/core/_grpc/_services/v1/bodies.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,7 @@ def split_body(self, **kwargs) -> dict: # noqa: D102
203203
@protect_grpc
204204
def create_body_from_loft_profiles_with_guides(self, **kwargs) -> dict: # noqa: D102
205205
raise NotImplementedError
206+
207+
@protect_grpc
208+
def combine_merge(self, **kwargs) -> dict: # noqa: D102
209+
raise NotImplementedError

src/ansys/geometry/core/designer/body.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,20 @@ def unite(self, other: Union["Body", Iterable["Body"]], keep_other: bool = False
819819
"""
820820
return
821821

822+
def combine_merge(self, other: Union["Body", list["Body"]]) -> None:
823+
"""Combine this body with another body or bodies, merging them into a single body.
824+
825+
Parameters
826+
----------
827+
other : Union[Body, list[Body]]
828+
The body or list of bodies to combine with this body.
829+
830+
Notes
831+
-----
832+
The ``self`` parameter is directly modified, and the ``other`` bodies are consumed.
833+
"""
834+
return
835+
822836

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

13611375
return result.success
13621376

1377+
@min_backend_version(25, 2, 0)
1378+
@check_input_types
1379+
def combine_merge(self, other: Union["Body", list["Body"]]) -> None: # noqa: D102
1380+
other = other if isinstance(other, list) else [other]
1381+
check_type_all_elements_in_iterable(other, Body)
1382+
1383+
self._grpc_client.log.debug(f"Combining and merging to body {self.id}.")
1384+
self._grpc_client.services.bodies.combine_merge(
1385+
body_ids=[self.id] + [body.id for body in other]
1386+
)
1387+
13631388
def plot( # noqa: D102
13641389
self,
13651390
merge: bool = True,
@@ -1903,6 +1928,9 @@ def unite(self, other: Union["Body", Iterable["Body"]], keep_other: bool = False
19031928
else:
19041929
self.__generic_boolean_command(other, False, "unite", "union operation failed")
19051930

1931+
def combine_merge(self, other: Union["Body", list["Body"]]) -> None: # noqa: D102
1932+
self._template.combine_merge(other)
1933+
19061934
@reset_tessellation_cache
19071935
@ensure_design_is_active
19081936
@check_input_types

tests/integration/test_design.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3909,3 +3909,27 @@ def test_write_body_facets_on_save(
39093909

39103910
missing = expected_files - namelist
39113911
assert not missing
3912+
3913+
3914+
def test_combine_merge(modeler: Modeler):
3915+
design = modeler.create_design("combine_merge")
3916+
box1 = design.extrude_sketch("box1", Sketch().box(Point2D([0, 0]), 1, 1), 1)
3917+
box2 = design.extrude_sketch("box2", Sketch().box(Point2D([0.5, 0.5]), 1, 1), 1)
3918+
assert len(design.bodies) == 2
3919+
3920+
# combine the two boxes and check body count and volume
3921+
box1.combine_merge([box2])
3922+
design._update_design_inplace()
3923+
assert len(design.bodies) == 1
3924+
assert box1.volume.m == pytest.approx(Quantity(1.75, UNITS.m**3).m, rel=1e-6, abs=1e-8)
3925+
3926+
# create a third box
3927+
box1 = design.bodies[0]
3928+
box3 = design.extrude_sketch("box3", Sketch().box(Point2D([-0.5, -0.5]), 1, 1), 1)
3929+
assert len(design.bodies) == 2
3930+
3931+
# combine the two boxes and check body count and volume
3932+
box1.combine_merge([box3])
3933+
design._update_design_inplace()
3934+
assert len(design.bodies) == 1
3935+
assert box1.volume.m == pytest.approx(Quantity(2.5, UNITS.m**3).m, rel=1e-6, abs=1e-8)

0 commit comments

Comments
 (0)