Skip to content

Commit a903bfd

Browse files
jacobrkerstetterpyansys-ci-botpre-commit-ci[bot]RobPasMue
authored
feat: grpc prepare tools stub implementation (#1914)
Co-authored-by: Jacob Kerstetter <[email protected]> Co-authored-by: pyansys-ci-bot <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Roberto Pastor Muela <[email protected]>
1 parent 2a0292c commit a903bfd

File tree

7 files changed

+451
-84
lines changed

7 files changed

+451
-84
lines changed

doc/changelog.d/1914.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
grpc prepare tools stub implementation

src/ansys/geometry/core/_grpc/_services/_service.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from .base.dbuapplication import GRPCDbuApplicationService
2929
from .base.measurement_tools import GRPCMeasurementToolsService
3030
from .base.named_selection import GRPCNamedSelectionService
31+
from .base.prepare_tools import GRPCPrepareToolsService
3132

3233

3334
class _GRPCServices:
@@ -73,6 +74,7 @@ def __init__(self, channel: grpc.Channel, version: GeometryApiProtos | str | Non
7374
self._dbu_application = None
7475
self._named_selection = None
7576
self._measurement_tools = None
77+
self._prepare_tools = None
7678

7779
@property
7880
def bodies(self) -> GRPCBodyService:
@@ -203,3 +205,29 @@ def measurement_tools(self) -> GRPCMeasurementToolsService:
203205
raise ValueError(f"Unsupported version: {self.version}")
204206

205207
return self._measurement_tools
208+
209+
@property
210+
def prepare_tools(self) -> GRPCPrepareToolsService:
211+
"""
212+
Get the prepare tools service for the specified version.
213+
214+
Returns
215+
-------
216+
NamedSelectionServiceBase
217+
The prepare tools service for the specified version.
218+
"""
219+
if not self._prepare_tools:
220+
# Import the appropriate prepare tools service based on the version
221+
from .v0.prepare_tools import GRPCPrepareToolsServiceV0
222+
from .v1.prepare_tools import GRPCPrepareToolsServiceV1
223+
224+
if self.version == GeometryApiProtos.V0:
225+
self._prepare_tools = GRPCPrepareToolsServiceV0(self.channel)
226+
elif self.version == GeometryApiProtos.V1: # pragma: no cover
227+
# V1 is not implemented yet
228+
self._prepare_tools = GRPCPrepareToolsServiceV1(self.channel)
229+
else: # pragma: no cover
230+
# This should never happen as the version is set in the constructor
231+
raise ValueError(f"Unsupported version: {self.version}")
232+
233+
return self._prepare_tools
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright (C) 2023 - 2025 ANSYS, Inc. and/or its affiliates.
2+
# SPDX-License-Identifier: MIT
3+
#
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
"""Module containing the prepare tools service implementation (abstraction layer)."""
23+
24+
from abc import ABC, abstractmethod
25+
26+
import grpc
27+
28+
29+
class GRPCPrepareToolsService(ABC):
30+
"""Prepare tools service for gRPC communication with the Geometry server.
31+
32+
Parameters
33+
----------
34+
channel : grpc.Channel
35+
The gRPC channel to the server.
36+
"""
37+
38+
def __init__(self, channel: grpc.Channel):
39+
"""Initialize the PrepareToolsService class."""
40+
pass # pragma: no cover
41+
42+
@abstractmethod
43+
def extract_volume_from_faces(self, **kwargs) -> dict:
44+
"""Extract a volume from input faces."""
45+
pass # pragma: no cover
46+
47+
@abstractmethod
48+
def extract_volume_from_edge_loops(self, **kwargs) -> dict:
49+
"""Extract a volume from input edge loop."""
50+
pass # pragma: no cover
51+
52+
@abstractmethod
53+
def remove_rounds(self, **kwargs) -> dict:
54+
"""Remove rounds from geometry."""
55+
pass # pragma: no cover
56+
57+
@abstractmethod
58+
def share_topology(self, **kwargs) -> dict:
59+
"""Share topology between the given bodies."""
60+
pass # pragma: no cover
61+
62+
@abstractmethod
63+
def enhanced_share_topology(self, **kwargs) -> dict:
64+
"""Share topology between the given bodies."""
65+
pass # pragma: no cover
66+
67+
@abstractmethod
68+
def find_logos(self, **kwargs) -> dict:
69+
"""Detect logos in geometry."""
70+
pass # pragma: no cover
71+
72+
@abstractmethod
73+
def find_and_remove_logos(self, **kwargs) -> dict:
74+
"""Detect and remove logos in geometry."""
75+
pass # pragma: no cover
76+
77+
@abstractmethod
78+
def remove_logo(self, **kwargs) -> dict:
79+
"""Remove logos in geometry."""
80+
pass # pragma: no cover
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# Copyright (C) 2023 - 2025 ANSYS, Inc. and/or its affiliates.
2+
# SPDX-License-Identifier: MIT
3+
#
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
"""Module containing the Prepare Tools service implementation for v0."""
23+
24+
import grpc
25+
26+
from ansys.geometry.core.errors import protect_grpc
27+
28+
from ..base.prepare_tools import GRPCPrepareToolsService
29+
30+
31+
class GRPCPrepareToolsServiceV0(GRPCPrepareToolsService):
32+
"""Prepare tools service for gRPC communication with the Geometry server.
33+
34+
This class provides methods to interact with the Geometry server's
35+
Prepare Tools service. It is specifically designed for the v0 version
36+
of the Geometry API.
37+
38+
Parameters
39+
----------
40+
channel : grpc.Channel
41+
The gRPC channel to the server.
42+
"""
43+
44+
@protect_grpc
45+
def __init__(self, channel: grpc.Channel): # noqa: D102
46+
from ansys.api.geometry.v0.preparetools_pb2_grpc import PrepareToolsStub
47+
48+
self.stub = PrepareToolsStub(channel)
49+
50+
@protect_grpc
51+
def extract_volume_from_faces(self, **kwargs) -> dict: # noqa: D102
52+
from ansys.api.dbu.v0.dbumodels_pb2 import EntityIdentifier
53+
from ansys.api.geometry.v0.preparetools_pb2 import ExtractVolumeFromFacesRequest
54+
55+
# Create the request - assumes all inputs are valid and of the proper type
56+
request = ExtractVolumeFromFacesRequest(
57+
sealing_faces=[EntityIdentifier(id=face.id) for face in kwargs["sealing_faces"]],
58+
inside_faces=[EntityIdentifier(id=face.id) for face in kwargs["inside_faces"]],
59+
)
60+
61+
# Call the gRPC service
62+
response = self.stub.ExtractVolumeFromFaces(request)
63+
64+
# Return the response - formatted as a dictionary
65+
return {
66+
"success": response.success,
67+
"created_bodies": [body.id for body in response.created_bodies],
68+
}
69+
70+
@protect_grpc
71+
def extract_volume_from_edge_loops(self, **kwargs) -> dict: # noqa: D102
72+
from ansys.api.dbu.v0.dbumodels_pb2 import EntityIdentifier
73+
from ansys.api.geometry.v0.preparetools_pb2 import ExtractVolumeFromEdgeLoopsRequest
74+
75+
# Create the request - assumes all inputs are valid and of the proper type
76+
request = ExtractVolumeFromEdgeLoopsRequest(
77+
sealing_edges=[EntityIdentifier(id=face.id) for face in kwargs["sealing_edges"]],
78+
inside_faces=[EntityIdentifier(id=face.id) for face in kwargs["inside_faces"]],
79+
)
80+
81+
# Call the gRPC service
82+
response = self.stub.ExtractVolumeFromEdgeLoops(request)
83+
84+
# Return the response - formatted as a dictionary
85+
return {
86+
"success": response.success,
87+
"created_bodies": [body.id for body in response.created_bodies],
88+
}
89+
90+
@protect_grpc
91+
def remove_rounds(self, **kwargs) -> dict: # noqa: D102
92+
from google.protobuf.wrappers_pb2 import BoolValue
93+
94+
from ansys.api.geometry.v0.models_pb2 import Face
95+
from ansys.api.geometry.v0.preparetools_pb2 import RemoveRoundsRequest
96+
97+
# Create the request - assumes all inputs are valid and of the proper type
98+
request = RemoveRoundsRequest(
99+
selection=[Face(id=round.id) for round in kwargs["rounds"]],
100+
auto_shrink=BoolValue(value=kwargs["auto_shrink"]),
101+
)
102+
103+
# Call the gRPC service
104+
response = self.stub.RemoveRounds(request)
105+
106+
# Return the response - formatted as a dictionary
107+
return {
108+
"success": response.result,
109+
}
110+
111+
@protect_grpc
112+
def share_topology(self, **kwargs) -> dict: # noqa: D102
113+
from google.protobuf.wrappers_pb2 import BoolValue, DoubleValue
114+
115+
from ansys.api.geometry.v0.models_pb2 import Body
116+
from ansys.api.geometry.v0.preparetools_pb2 import ShareTopologyRequest
117+
118+
# Create the request - assumes all inputs are valid and of the proper type
119+
request = ShareTopologyRequest(
120+
selection=[Body(id=body.id) for body in kwargs["bodies"]],
121+
tolerance=DoubleValue(value=kwargs["tolerance"]),
122+
preserve_instances=BoolValue(value=kwargs["preserve_instances"]),
123+
)
124+
125+
# Call the gRPC service
126+
response = self.stub.ShareTopology(request)
127+
128+
# Return the response - formatted as a dictionary
129+
return {
130+
"success": response.result,
131+
}
132+
133+
@protect_grpc
134+
def enhanced_share_topology(self, **kwargs) -> dict: # noqa: D102
135+
from google.protobuf.wrappers_pb2 import BoolValue, DoubleValue
136+
137+
from ansys.api.geometry.v0.models_pb2 import Body
138+
from ansys.api.geometry.v0.preparetools_pb2 import ShareTopologyRequest
139+
140+
# Create the request - assumes all inputs are valid and of the proper type
141+
request = ShareTopologyRequest(
142+
selection=[Body(id=body.id) for body in kwargs["bodies"]],
143+
tolerance=DoubleValue(value=kwargs["tolerance"]),
144+
preserve_instances=BoolValue(value=kwargs["preserve_instances"]),
145+
)
146+
147+
# Call the gRPC service
148+
response = self.stub.EnhancedShareTopology(request)
149+
150+
# Return the response - formatted as a dictionary
151+
return {
152+
"success": response.success,
153+
"found": response.found,
154+
"repaired": response.repaired,
155+
"created_bodies_monikers": response.created_bodies_monikers,
156+
"modified_bodies_monikers": response.modified_bodies_monikers,
157+
"deleted_bodies_monikers": response.deleted_bodies_monikers,
158+
}
159+
160+
@protect_grpc
161+
def find_logos(self, **kwargs) -> dict: # noqa: D102
162+
from ansys.api.dbu.v0.dbumodels_pb2 import EntityIdentifier
163+
from ansys.api.geometry.v0.models_pb2 import FindLogoOptions
164+
from ansys.api.geometry.v0.preparetools_pb2 import FindLogosRequest
165+
166+
# Create the request - assumes all inputs are valid and of the proper type
167+
request = FindLogosRequest(
168+
bodies=[EntityIdentifier(id=body.id) for body in kwargs["bodies"]],
169+
options=FindLogoOptions(
170+
min_height=kwargs["min_height"],
171+
max_height=kwargs["max_height"],
172+
),
173+
)
174+
175+
# Call the gRPC service
176+
response = self.stub.FindLogos(request)
177+
178+
# Return the response - formatted as a dictionary
179+
return {
180+
"id": response.id,
181+
"face_ids": [face.id for face in response.logo_faces],
182+
}
183+
184+
@protect_grpc
185+
def find_and_remove_logos(self, **kwargs) -> dict: # noqa: D102
186+
from ansys.api.dbu.v0.dbumodels_pb2 import EntityIdentifier
187+
from ansys.api.geometry.v0.models_pb2 import FindLogoOptions
188+
from ansys.api.geometry.v0.preparetools_pb2 import FindLogosRequest
189+
190+
# Create the request - assumes all inputs are valid and of the proper type
191+
request = FindLogosRequest(
192+
bodies=[EntityIdentifier(id=body.id) for body in kwargs["bodies"]],
193+
options=FindLogoOptions(
194+
min_height=kwargs["min_height"],
195+
max_height=kwargs["max_height"],
196+
),
197+
)
198+
199+
# Call the gRPC service
200+
response = self.stub.FindAndRemoveLogos(request)
201+
202+
# Return the response - formatted as a dictionary
203+
return {"success": response.success}
204+
205+
@protect_grpc
206+
def remove_logo(self, **kwargs): # noqa: D102
207+
from ansys.api.dbu.v0.dbumodels_pb2 import EntityIdentifier
208+
from ansys.api.geometry.v0.preparetools_pb2 import RemoveLogoRequest
209+
210+
# Create the request - assumes all inputs are valid and of the proper type
211+
request = RemoveLogoRequest(
212+
face_ids=[EntityIdentifier(id=id) for id in kwargs["face_ids"]],
213+
)
214+
215+
# Call the gRPC service
216+
response = self.stub.RemoveLogo(request)
217+
218+
# Return the response - formatted as a dictionary
219+
return {"success": response.success}

0 commit comments

Comments
 (0)