Skip to content

Commit d27b1d9

Browse files
jonahrbRobPasMue
andauthored
Implement Boolean Methods for Bodies (#474)
Co-authored-by: Roberto Pastor Muela <37798125+RobPasMue@users.noreply.github.com>
1 parent c40ddde commit d27b1d9

File tree

2 files changed

+366
-1
lines changed

2 files changed

+366
-1
lines changed

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

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from functools import wraps
55

66
from ansys.api.geometry.v0.bodies_pb2 import (
7+
BooleanRequest,
78
CopyRequest,
89
SetAssignedMaterialRequest,
910
TranslateRequest,
@@ -367,6 +368,55 @@ def plot(
367368
"""
368369
return
369370

371+
def intersect(self, other: "Body") -> None:
372+
"""
373+
Intersect two bodies. `self` will be directly modified with the result, and `other` will be
374+
consumed, so it is important to make copies if needed.
375+
376+
Parameters
377+
----------
378+
other : Body
379+
The body to intersect with.
380+
381+
Raises
382+
------
383+
ValueError
384+
If the bodies do not intersect.
385+
"""
386+
return
387+
388+
@protect_grpc
389+
def subtract(self, other: "Body") -> None:
390+
"""
391+
Subtract two bodies. `self` is the minuend, and `other` is the subtrahend
392+
(`self` - `other`). `self` will be directly modified with the result, and
393+
`other` will be consumed, so it is important to make copies if needed.
394+
395+
Parameters
396+
----------
397+
other : Body
398+
The body to subtract from self.
399+
400+
Raises
401+
------
402+
ValueError
403+
If the subtraction results in an empty (complete) subtraction.
404+
"""
405+
return
406+
407+
@protect_grpc
408+
def unite(self, other: "Body") -> None:
409+
"""
410+
Unite two bodies. `self` will be directly modified with the resulting union, and `other`
411+
will be consumed, so it is important to make copies if needed.
412+
413+
Parameters
414+
----------
415+
other : Body
416+
The body to unite with self.
417+
"""
418+
return
419+
370420

371421
class TemplateBody(IBody):
372422
"""
@@ -687,6 +737,21 @@ def plot(
687737
pl.add_body(self, merge=merge, **plotting_options)
688738
pl_helper.show_plotter(pl, screenshot=screenshot)
689739

740+
def intersect(self, other: "Body") -> None:
741+
raise NotImplementedError(
742+
"TemplateBody does not implement boolean methods. Call this method on a Body instead."
743+
)
744+
745+
def subtract(self, other: "Body") -> None:
746+
raise NotImplementedError(
747+
"TemplateBody does not implement boolean methods. Call this method on a Body instead."
748+
)
749+
750+
def unite(self, other: "Body") -> None:
751+
raise NotImplementedError(
752+
"TemplateBody does not implement boolean methods. Call this method on a Body instead."
753+
)
754+
690755
def __repr__(self) -> str:
691756
"""String representation of the body."""
692757
lines = [f"ansys.geometry.core.designer.TemplateBody {hex(id(self))}"]
@@ -725,6 +790,27 @@ def __init__(self, id, name, parent: "Component", template: TemplateBody) -> Non
725790
self._parent = parent
726791
self._template = template
727792

793+
def reset_tessellation_cache(func):
794+
"""Decorator for ``Body`` methods that require a tessellation cache update.
795+
796+
Parameters
797+
----------
798+
func : method
799+
The method being called.
800+
801+
Returns
802+
-------
803+
Any
804+
The output of the method, if any.
805+
"""
806+
807+
@wraps(func)
808+
def wrapper(self: "Body", *args, **kwargs):
809+
self._template._tessellation = None
810+
return func(self, *args, **kwargs)
811+
812+
return wrapper
813+
728814
@property
729815
def id(self) -> str:
730816
return self._id
@@ -845,6 +931,38 @@ def plot(
845931
) -> None:
846932
return self._template.plot(merge, screenshot, use_trame, **plotting_options)
847933

934+
@protect_grpc
935+
@reset_tessellation_cache
936+
def intersect(self, other: "Body") -> None:
937+
response = self._template._bodies_stub.Boolean(
938+
BooleanRequest(body1=self.id, body2=other.id, method="intersect")
939+
).empty_result
940+
941+
if response == 1:
942+
raise ValueError("Bodies do not intersect.")
943+
944+
other.parent.delete_body(other)
945+
946+
@protect_grpc
947+
@reset_tessellation_cache
948+
def subtract(self, other: "Body") -> None:
949+
response = self._template._bodies_stub.Boolean(
950+
BooleanRequest(body1=self.id, body2=other.id, method="subtract")
951+
).empty_result
952+
953+
if response == 1:
954+
raise ValueError("Subtraction of bodies results in an empty (complete) subtraction.")
955+
956+
other.parent.delete_body(other)
957+
958+
@protect_grpc
959+
@reset_tessellation_cache
960+
def unite(self, other: "Body") -> None:
961+
self._template._bodies_stub.Boolean(
962+
BooleanRequest(body1=self.id, body2=other.id, method="unite")
963+
)
964+
other.parent.delete_body(other)
965+
848966
def __repr__(self) -> str:
849967
"""String representation of the body."""
850968
lines = [f"ansys.geometry.core.designer.Body {hex(id(self))}"]

0 commit comments

Comments
 (0)