diff --git a/doc/changelog.d/1912.added.md b/doc/changelog.d/1912.added.md new file mode 100644 index 0000000000..0696e6dc10 --- /dev/null +++ b/doc/changelog.d/1912.added.md @@ -0,0 +1 @@ +repair tools refactoring \ No newline at end of file diff --git a/src/ansys/geometry/core/_grpc/_services/_service.py b/src/ansys/geometry/core/_grpc/_services/_service.py index 9d331d4279..f72432144e 100644 --- a/src/ansys/geometry/core/_grpc/_services/_service.py +++ b/src/ansys/geometry/core/_grpc/_services/_service.py @@ -31,6 +31,7 @@ from .base.measurement_tools import GRPCMeasurementToolsService from .base.named_selection import GRPCNamedSelectionService from .base.prepare_tools import GRPCPrepareToolsService +from .base.repair_tools import GRPCRepairToolsService class _GRPCServices: @@ -76,6 +77,7 @@ def __init__(self, channel: grpc.Channel, version: GeometryApiProtos | str | Non self._dbu_application = None self._named_selection = None self._measurement_tools = None + self._repair_tools = None self._prepare_tools = None self._driving_dimensions = None self._coordinate_systems = None @@ -210,6 +212,30 @@ def measurement_tools(self) -> GRPCMeasurementToolsService: return self._measurement_tools + @property + def repair_tools(self) -> GRPCRepairToolsService: + """ + Get the repair tools service for the specified version. + + Returns + ------- + RepairToolsServiceBase + The repair tools service for the specified version. + """ + if not self._repair_tools: + from .v0.repair_tools import GRPCRepairToolsServiceV0 + from .v1.repair_tools import GRPCRepairToolsServiceV1 + + if self.version == GeometryApiProtos.V0: + self._repair_tools = GRPCRepairToolsServiceV0(self.channel) + elif self.version == GeometryApiProtos.V1: # pragma: no cover + # V1 is not implemented yet + self._repair_tools = GRPCRepairToolsServiceV1(self.channel) + else: # pragma: no cover + # This should never happen as the version is set in the constructor + raise ValueError(f"Unsupported version: {self.version}") + return self._repair_tools + @property def prepare_tools(self) -> GRPCPrepareToolsService: """ diff --git a/src/ansys/geometry/core/_grpc/_services/base/repair_tools.py b/src/ansys/geometry/core/_grpc/_services/base/repair_tools.py new file mode 100644 index 0000000000..f9fbd791cd --- /dev/null +++ b/src/ansys/geometry/core/_grpc/_services/base/repair_tools.py @@ -0,0 +1,124 @@ +# Copyright (C) 2023 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +"""Module containing the repair tools service implementation (abstraction layer). + +This module defines an abstract base class for a gRPC-based repair tools service. +The class provides a set of abstract methods for identifying and repairing various +geometry issues, such as split edges, extra edges, duplicate faces, and more. +""" + +from abc import ABC, abstractmethod + +import grpc + + +class GRPCRepairToolsService(ABC): + """Abstract base class for gRPC-based repair tools service. + + Parameters + ---------- + channel: grpc.Channel + The gRPC channel used to communicate with the service. + """ + + def __init__(self, channel: grpc.Channel): + """Initialize the gRPC repair tools service.""" + + @abstractmethod + def find_split_edges(self, **kwargs) -> dict: + """Identify split edges in the geometry.""" + pass # pragma: no cover + + @abstractmethod + def find_extra_edges(self, **kwargs) -> dict: + """Identify extra edges in the geometry.""" + pass # pragma: no cover + + @abstractmethod + def find_inexact_edges(self, **kwargs) -> dict: + """Identify inexact edges in the geometry.""" + pass # pragma: no cover + + @abstractmethod + def find_short_edges(self, **kwargs) -> dict: + """Identify short edges in the geometry.""" + pass # pragma: no cover + + @abstractmethod + def find_duplicate_faces(self, **kwargs) -> dict: + """Identify duplicate faces in the geometry.""" + pass # pragma: no cover + + @abstractmethod + def find_missing_faces(self, **kwargs) -> dict: + """Identify missing faces in the geometry.""" + pass # pragma: no cover + + @abstractmethod + def find_small_faces(self, **kwargs) -> dict: + """Identify small faces in the geometry.""" + pass # pragma: no cover + + @abstractmethod + def find_stitch_faces(self, **kwargs) -> dict: + """Identify faces that can be stitched together in the geometry.""" + pass # pragma: no cover + + @abstractmethod + def find_simplify(self, **kwargs) -> dict: + """Identify areas in the geometry that can be simplified.""" + pass # pragma: no cover + + @abstractmethod + def find_interferences(self, **kwargs) -> dict: + """Identify interferences in the geometry.""" + pass # pragma: no cover + + @abstractmethod + def find_and_fix_short_edges(self, **kwargs) -> dict: + """Identify and fix short edges in the geometry.""" + pass # pragma: no cover + + @abstractmethod + def find_and_fix_extra_edges(self, **kwargs) -> dict: + """Identify and fix extra edges in the geometry.""" + pass # pragma: no cover + + @abstractmethod + def find_and_fix_split_edges(self, **kwargs) -> dict: + """Identify and fix split edges in the geometry.""" + pass # pragma: no cover + + @abstractmethod + def find_and_fix_simplify(self, **kwargs) -> dict: + """Identify and simplify areas in the geometry.""" + pass # pragma: no cover + + @abstractmethod + def inspect_geometry(self, **kwargs) -> dict: + """Inspect the geometry for issues.""" + pass # pragma: no cover + + @abstractmethod + def repair_geometry(self, **kwargs) -> dict: + """Repair the geometry by addressing identified issues.""" + pass # pragma: no cover diff --git a/src/ansys/geometry/core/_grpc/_services/v0/repair_tools.py b/src/ansys/geometry/core/_grpc/_services/v0/repair_tools.py new file mode 100644 index 0000000000..5b7000e990 --- /dev/null +++ b/src/ansys/geometry/core/_grpc/_services/v0/repair_tools.py @@ -0,0 +1,436 @@ +# Copyright (C) 2023 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +"""Module containing the repair tools service implementation for v0. + +This module defines an abstract base class for a gRPC-based repair tools service. +The class provides a set of abstract methods for identifying and repairing various +geometry issues, such as split edges, extra edges, duplicate faces etc. +""" + +import grpc + +from ansys.geometry.core.errors import protect_grpc + +from ..base.repair_tools import GRPCRepairToolsService + + +class GRPCRepairToolsServiceV0(GRPCRepairToolsService): # noqa: D102 + """Repair tools service for gRPC communication with the Geometry server. + + This class provides methods to interact with the Geometry server's + Repair Tools service. It is specifically designed for the v0 version + of the Geometry API. + + Parameters + ---------- + channel : grpc.Channel + The gRPC channel to the server. + """ + + @protect_grpc + def __init__(self, channel: grpc.Channel): + from ansys.api.geometry.v0.repairtools_pb2_grpc import RepairToolsStub + + self.stub = RepairToolsStub(channel) + + @protect_grpc + def find_split_edges(self, **kwargs) -> dict: # noqa: D102 + from google.protobuf.wrappers_pb2 import DoubleValue + + from ansys.api.geometry.v0.repairtools_pb2 import FindSplitEdgesRequest + + # Create the gRPC request + request = FindSplitEdgesRequest( + bodies_or_faces=kwargs["bodies_or_faces"], + angle=DoubleValue(value=float(kwargs["angle"])), + distance=DoubleValue(value=float(kwargs["distance"])), + ) + + # Call the gRPC service + response = self.stub.FindSplitEdges(request) + + # Format and return the response as a dictionary + return { + "problems": [ + { + "id": res.id, + "edges": res.edge_monikers, + } + for res in response.result + ] + } + + @protect_grpc + def find_extra_edges(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FindExtraEdgesRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = FindExtraEdgesRequest(selection=kwargs["selection"]) + + # Return the response - formatted as a dictionary + response = self.stub.FindExtraEdges(request) + + # Return the response - formatted as a dictionary + return { + "problems": [ + { + "id": res.id, + "edges": res.edge_monikers, + } + for res in response.result + ] + } + + @protect_grpc + def find_inexact_edges(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FindInexactEdgesRequest + + request = FindInexactEdgesRequest(selection=kwargs["selection"]) + + # Call the gRPC service + response = self.stub.FindInexactEdges(request) + + # Return the response - formatted as a dictionary + return { + "problems": [ + { + "id": res.id, + "edges": res.edge_monikers, + } + for res in response.result + ] + } + + @protect_grpc + def find_short_edges(self, **kwargs) -> dict: # noqa: D102 + from google.protobuf.wrappers_pb2 import DoubleValue + + from ansys.api.geometry.v0.repairtools_pb2 import FindShortEdgesRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = FindShortEdgesRequest( + selection=kwargs["selection"], + max_edge_length=DoubleValue(value=kwargs["length"]), + ) + + # Call the gRPC service + response = self.stub.FindShortEdges(request) + + # Return the response - formatted as a dictionary + return { + "problems": [ + { + "id": res.id, + "edges": res.edge_monikers, + } + for res in response.result + ] + } + + @protect_grpc + def find_duplicate_faces(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FindDuplicateFacesRequest + + request = FindDuplicateFacesRequest(faces=kwargs["faces"]) + + # Call the gRPC service + response = self.stub.FindDuplicateFaces(request) + + # Return the response - formatted as a dictionary + return { + "problems": [ + { + "id": res.id, + "faces": res.face_monikers, + } + for res in response.result + ] + } + + @protect_grpc + def find_missing_faces(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FindMissingFacesRequest + + request = FindMissingFacesRequest(faces=kwargs["faces"]) + # Call the gRPC service + response = self.stub.FindMissingFaces(request) + + # Return the response - formatted as a dictionary + return { + "problems": [ + { + "id": res.id, + "edges": res.edge_monikers, + } + for res in response.result + ] + } + + @protect_grpc + def find_small_faces(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FindSmallFacesRequest + + request = FindSmallFacesRequest(selection=kwargs["selection"]) + # Call the gRPC service + response = self.stub.FindSmallFaces(request) + + # Return the response - formatted as a dictionary + return { + "problems": [ + { + "id": res.id, + "faces": res.face_monikers, + } + for res in response.result + ] + } + + @protect_grpc + def find_stitch_faces(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FindStitchFacesRequest + + request = FindStitchFacesRequest(faces=kwargs["faces"]) + # Call the gRPC service + response = self.stub.FindStitchFaces(request) + # Return the response - formatted as a dictionary + return { + "problems": [ + { + "id": res.id, + "bodies": res.body_monikers, + } + for res in response.result + ] + } + + @protect_grpc + def find_simplify(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FindAdjustSimplifyRequest + + request = FindAdjustSimplifyRequest(selection=kwargs["selection"]) + + # Call the gRPC service + response = self.stub.FindAdjustSimplify(request) + # Return the response - formatted as a dictionary + return { + "problems": [ + { + "id": res.id, + "bodies": res.body_monikers, + } + for res in response.result + ] + } + + @protect_grpc + def find_and_fix_simplify(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FindAdjustSimplifyRequest + + request = FindAdjustSimplifyRequest( + selection=kwargs["selection"], + comprehensive=kwargs["comprehensive_result"], + ) + # Call the gRPC service + response = self.stub.FindAndSimplify(request) + # Return the response - formatted as a dictionary + return { + "success": response.success, + "found": response.found, + "repaired": response.repaired, + "created_bodies_monikers": [], + "modified_bodies_monikers": [], + } + + @protect_grpc + def inspect_geometry(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import InspectGeometryRequest + + # Create the gRPC request + request = InspectGeometryRequest(bodies=kwargs.get("bodies", [])) + + # Call the gRPC service + inspect_result_response = self.stub.InspectGeometry(request) + + # Serialize and return the response + return self.serialize_inspect_result_response(inspect_result_response) + + @protect_grpc + def repair_geometry(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import RepairGeometryRequest + + request = RepairGeometryRequest(bodies=kwargs.get("bodies", [])) + + # Call the gRPC service + response = self.stub.RepairGeometry(request) + + # Return the response - formatted as a dictionary + return { + "success": response.result.success, + } + + @protect_grpc + def find_interferences(self, **kwargs) -> dict: # noqa: D102 + from google.protobuf.wrappers_pb2 import BoolValue + + from ansys.api.geometry.v0.repairtools_pb2 import FindInterferenceRequest + + request = FindInterferenceRequest( + bodies=kwargs["bodies"], + cut_smaller_body=BoolValue(value=kwargs["cut_smaller_body"]), + ) + + # Call the gRPC service + response = self.stub.FindInterference(request) + + # Return the response - formatted as a dictionary + return { + "problems": [ + { + "id": res.id, + "bodies": res.body_monikers, + } + for res in response.result + ] + } + + @protect_grpc + def find_and_fix_short_edges(self, **kwargs): # noqa: D102 + from google.protobuf.wrappers_pb2 import DoubleValue + + from ansys.api.geometry.v0.repairtools_pb2 import FindShortEdgesRequest + + request = FindShortEdgesRequest( + selection=kwargs["selection"], + max_edge_length=DoubleValue(value=kwargs["length"]), + comprehensive=kwargs["comprehensive_result"], + ) + # Call the gRPC service + response = self.stub.FindAndFixShortEdges(request) + + # Return the response - formatted as a dictionary + return { + "success": response.success, + "found": response.found, + "repaired": response.repaired, + "created_bodies_monikers": [], + "modified_bodies_monikers": [], + } + + @protect_grpc + def find_and_fix_extra_edges(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FindExtraEdgesRequest + + request = FindExtraEdgesRequest( + selection=kwargs["selection"], + comprehensive=kwargs["comprehensive_result"], + ) + # Call the gRPC service + response = self.stub.FindAndFixExtraEdges(request) + + # Return the response - formatted as a dictionary + return { + "success": response.success, + "found": response.found, + "repaired": response.repaired, + "created_bodies_monikers": response.created_bodies_monikers, + "modified_bodies_monikers": response.modified_bodies_monikers, + } + + @protect_grpc + def find_and_fix_split_edges(self, **kwargs) -> dict: # noqa: D102 + from google.protobuf.wrappers_pb2 import DoubleValue + + from ansys.api.geometry.v0.repairtools_pb2 import FindSplitEdgesRequest + + request = FindSplitEdgesRequest( + bodies_or_faces=kwargs["bodies_or_faces"], + angle=DoubleValue(value=float(kwargs["angle"])), + distance=DoubleValue(value=float(kwargs["length"])), + comprehensive=kwargs["comprehensive_result"], + ) + + # Call the gRPC service + response = self.stub.FindAndFixSplitEdges(request) + + # Return the response - formatted as a dictionary + return { + "success": response.success, + "found": response.found, + "repaired": response.repaired, + "created_bodies_monikers": [], + "modified_bodies_monikers": [], + } + + @staticmethod + def serialize_inspect_result_response(response) -> dict: # noqa: D102 + def serialize_body(body): + return { + "id": body.id, + "name": body.name, + "can_suppress": body.can_suppress, + "transform_to_master": { + "m00": body.transform_to_master.m00, + "m11": body.transform_to_master.m11, + "m22": body.transform_to_master.m22, + "m33": body.transform_to_master.m33, + }, + "master_id": body.master_id, + "parent_id": body.parent_id, + } + + def serialize_face(face): + return { + "id": face.id, + "surface_type": face.surface_type, + "export_id": face.export_id, + "is_reversed": getattr(face, "is_reversed", False), + "parent_id": face.parent_id.id, + } + + def serialize_edge(edge): + return { + "id": edge.id, + "curve_type": edge.curve_type, + "export_id": edge.export_id, + "length": edge.length, + "owner_id": edge.owner_id, + "parent": serialize_body(edge.parent) if hasattr(edge, "parent") else None, + } + + def serialize_issue(issue): + return { + "message_type": issue.message_type, + "message_id": issue.message_id, + "message": issue.message, + "faces": [serialize_face(f) for f in issue.faces], + "edges": [serialize_edge(e) for e in issue.edges], + } + + return { + "issues_by_body": [ + { + "body": serialize_body(body_issues.body), + "issues": [serialize_issue(i) for i in body_issues.issues], + } + for body_issues in response.issues_by_body + ] + } diff --git a/src/ansys/geometry/core/_grpc/_services/v1/repair_tools.py b/src/ansys/geometry/core/_grpc/_services/v1/repair_tools.py new file mode 100644 index 0000000000..75c23aa7f1 --- /dev/null +++ b/src/ansys/geometry/core/_grpc/_services/v1/repair_tools.py @@ -0,0 +1,87 @@ +# Copyright (C) 2023 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +"""Module containing the repair tools service implementation.""" + +from abc import ABC + +import grpc + + +class GRPCRepairToolsServiceV1(ABC): + """Repair tools service for gRPC communication with the Geometry server. + + Parameters + ---------- + channel : grpc.Channel + The gRPC channel to the server. + """ + + def __init__(self, channel: grpc.Channel): + """Initialize the MeasurementToolsService class.""" + + def find_split_edges(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def find_extra_edges(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def find_inexact_edges(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def find_short_edges(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def find_duplicate_faces(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def find_missing_faces(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def find_small_faces(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def find_stitch_faces(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def find_simplify(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def find_interferences(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def find_and_fix_short_edges(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def find_and_fix_extra_edges(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def find_and_fix_split_edges(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def find_and_fix_simplify(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def inspect_geometry(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + def repair_geometry(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError diff --git a/src/ansys/geometry/core/tools/repair_tools.py b/src/ansys/geometry/core/tools/repair_tools.py index f874581c06..a0d468a70b 100644 --- a/src/ansys/geometry/core/tools/repair_tools.py +++ b/src/ansys/geometry/core/tools/repair_tools.py @@ -23,29 +23,6 @@ from typing import TYPE_CHECKING -from google.protobuf.wrappers_pb2 import BoolValue, DoubleValue - -from ansys.api.geometry.v0.models_pb2 import ( - InspectGeometryMessageId, - InspectGeometryMessageType, - InspectGeometryResult, - InspectGeometryResultIssue, -) -from ansys.api.geometry.v0.repairtools_pb2 import ( - FindAdjustSimplifyRequest, - FindDuplicateFacesRequest, - FindExtraEdgesRequest, - FindInexactEdgesRequest, - FindInterferenceRequest, - FindMissingFacesRequest, - FindShortEdgesRequest, - FindSmallFacesRequest, - FindSplitEdgesRequest, - FindStitchFacesRequest, - InspectGeometryRequest, - RepairGeometryRequest, -) -from ansys.api.geometry.v0.repairtools_pb2_grpc import RepairToolsStub from ansys.geometry.core.connection import GrpcClient from ansys.geometry.core.errors import protect_grpc from ansys.geometry.core.misc.auxiliary import ( @@ -85,9 +62,8 @@ class RepairTools: def __init__(self, grpc_client: GrpcClient, modeler: "Modeler"): """Initialize a new instance of the ``RepairTools`` class.""" - self._grpc_client = grpc_client - self._repair_stub = RepairToolsStub(self._grpc_client.channel) self._modeler = modeler + self._grpc_client = grpc_client @protect_grpc def find_split_edges( @@ -115,23 +91,20 @@ def find_split_edges( if not bodies: return [] - angle_value = DoubleValue(value=float(angle)) - length_value = DoubleValue(value=float(length)) body_ids = [body.id for body in bodies] - problem_areas_response = self._repair_stub.FindSplitEdges( - FindSplitEdgesRequest( - bodies_or_faces=body_ids, angle=angle_value, distance=length_value - ) + problem_areas_response = self._grpc_client.services.repair_tools.find_split_edges( + bodies_or_faces=body_ids, angle=angle, distance=length ) + parent_design = get_design_from_body(bodies[0]) return [ SplitEdgeProblemAreas( - f"{res.id}", + f"{res['id']}", self._grpc_client, - get_edges_from_ids(parent_design, res.edge_monikers), + get_edges_from_ids(parent_design, res["edges"]), ) - for res in problem_areas_response.result + for res in problem_areas_response["problems"] ] @protect_grpc @@ -155,18 +128,18 @@ def find_extra_edges(self, bodies: list["Body"]) -> list[ExtraEdgeProblemAreas]: return [] body_ids = [body.id for body in bodies] - problem_areas_response = self._repair_stub.FindExtraEdges( - FindExtraEdgesRequest(selection=body_ids) + problem_areas_response = self._grpc_client.services.repair_tools.find_extra_edges( + selection=body_ids ) parent_design = get_design_from_body(bodies[0]) return [ ExtraEdgeProblemAreas( - f"{res.id}", + f"{res['id']}", self._grpc_client, - get_edges_from_ids(parent_design, res.edge_monikers), + get_edges_from_ids(parent_design, res["edges"]), ) - for res in problem_areas_response.result + for res in problem_areas_response["problems"] ] @protect_grpc @@ -190,19 +163,19 @@ def find_inexact_edges(self, bodies: list["Body"]) -> list[InexactEdgeProblemAre return [] body_ids = [body.id for body in bodies] - problem_areas_response = self._repair_stub.FindInexactEdges( - FindInexactEdgesRequest(selection=body_ids) + problem_areas_response = self._grpc_client.services.repair_tools.find_inexact_edges( + selection=body_ids ) parent_design = get_design_from_body(bodies[0]) return [ InexactEdgeProblemAreas( - f"{res.id}", + f"{res['id']}", self._grpc_client, - get_edges_from_ids(parent_design, res.edge_monikers), + get_edges_from_ids(parent_design, res["edges"]), ) - for res in problem_areas_response.result + for res in problem_areas_response["problems"] ] @protect_grpc @@ -227,21 +200,20 @@ def find_short_edges( if not bodies: return [] - problem_areas_response = self._repair_stub.FindShortEdges( - FindShortEdgesRequest( - selection=[body.id for body in bodies], - max_edge_length=DoubleValue(value=length), - ) + body_ids = [body.id for body in bodies] + + problem_areas_response = self._grpc_client.services.repair_tools.find_short_edges( + selection=body_ids, length=length ) parent_design = get_design_from_body(bodies[0]) return [ ShortEdgeProblemAreas( - f"{res.id}", + f"{res['id']}", self._grpc_client, - get_edges_from_ids(parent_design, res.edge_monikers), + get_edges_from_ids(parent_design, res["edges"]), ) - for res in problem_areas_response.result + for res in problem_areas_response["problems"] ] @protect_grpc @@ -265,18 +237,18 @@ def find_duplicate_faces(self, bodies: list["Body"]) -> list[DuplicateFaceProble return [] body_ids = [body.id for body in bodies] - problem_areas_response = self._repair_stub.FindDuplicateFaces( - FindDuplicateFacesRequest(faces=body_ids) + problem_areas_response = self._grpc_client.services.repair_tools.find_duplicate_faces( + faces=body_ids ) parent_design = get_design_from_body(bodies[0]) return [ DuplicateFaceProblemAreas( - f"{res.id}", + f"{res['id']}", self._grpc_client, - get_faces_from_ids(parent_design, res.face_monikers), + get_faces_from_ids(parent_design, res["faces"]), ) - for res in problem_areas_response.result + for res in problem_areas_response["problems"] ] @protect_grpc @@ -299,18 +271,18 @@ def find_missing_faces(self, bodies: list["Body"]) -> list[MissingFaceProblemAre if not bodies: return [] body_ids = [body.id for body in bodies] - problem_areas_response = self._repair_stub.FindMissingFaces( - FindMissingFacesRequest(faces=body_ids) + problem_areas_response = self._grpc_client.services.repair_tools.find_missing_faces( + faces=body_ids ) parent_design = get_design_from_body(bodies[0]) return [ MissingFaceProblemAreas( - f"{res.id}", + f"{res['id']}", self._grpc_client, - get_edges_from_ids(parent_design, res.edge_monikers), + get_edges_from_ids(parent_design, res["edges"]), ) - for res in problem_areas_response.result + for res in problem_areas_response["problems"] ] @protect_grpc @@ -334,18 +306,18 @@ def find_small_faces(self, bodies: list["Body"]) -> list[SmallFaceProblemAreas]: return [] body_ids = [body.id for body in bodies] - problem_areas_response = self._repair_stub.FindSmallFaces( - FindSmallFacesRequest(selection=body_ids) + problem_areas_response = self._grpc_client.services.repair_tools.find_small_faces( + selection=body_ids ) parent_design = get_design_from_body(bodies[0]) return [ SmallFaceProblemAreas( - f"{res.id}", + f"{res['id']}", self._grpc_client, - get_faces_from_ids(parent_design, res.face_monikers), + get_faces_from_ids(parent_design, res["faces"]), ) - for res in problem_areas_response.result + for res in problem_areas_response["problems"] ] @protect_grpc @@ -366,17 +338,17 @@ def find_stitch_faces(self, bodies: list["Body"]) -> list[StitchFaceProblemAreas List of objects representing stitch face problem areas. """ body_ids = [body.id for body in bodies] - problem_areas_response = self._repair_stub.FindStitchFaces( - FindStitchFacesRequest(faces=body_ids) + problem_areas_response = self._grpc_client.services.repair_tools.find_stitch_faces( + faces=body_ids ) parent_design = get_design_from_body(bodies[0]) return [ StitchFaceProblemAreas( - f"{res.id}", + f"{res['id']}", self._grpc_client, - get_bodies_from_ids(parent_design, res.body_monikers), + get_bodies_from_ids(parent_design, res["bodies"]), ) - for res in problem_areas_response.result + for res in problem_areas_response["problems"] ] @protect_grpc @@ -400,19 +372,17 @@ def find_simplify(self, bodies: list["Body"]) -> list[UnsimplifiedFaceProblemAre body_ids = [body.id for body in bodies] parent_design = get_design_from_body(bodies[0]) - problem_areas_response = self._repair_stub.FindAdjustSimplify( - FindAdjustSimplifyRequest( - selection=body_ids, - ) + problem_areas_response = self._grpc_client.services.repair_tools.find_simplify( + selection=body_ids ) return [ UnsimplifiedFaceProblemAreas( - f"{res.id}", + f"{res['id']}", self._grpc_client, - get_faces_from_ids(parent_design, res.body_monikers), + get_faces_from_ids(parent_design, res["bodies"]), ) - for res in problem_areas_response.result + for res in problem_areas_response["problems"] ] @protect_grpc @@ -451,18 +421,18 @@ def find_interferences( parent_design = get_design_from_body(bodies[0]) body_ids = [body.id for body in bodies] - cut_smaller_body_bool = BoolValue(value=cut_smaller_body) - problem_areas_response = self._repair_stub.FindInterference( - FindInterferenceRequest(bodies=body_ids, cut_smaller_body=cut_smaller_body_bool) + # cut_smaller_body_bool = BoolValue(value=cut_smaller_body) + problem_areas_response = self._grpc_client.services.repair_tools.find_interferences( + bodies=body_ids, cut_smaller_body=cut_smaller_body ) return [ InterferenceProblemAreas( - f"{res.id}", + f"{res['id']}", self._grpc_client, - get_bodies_from_ids(parent_design, res.body_monikers), + get_bodies_from_ids(parent_design, res["bodies"]), ) - for res in problem_areas_response.result + for res in problem_areas_response["problems"] ] @protect_grpc @@ -500,22 +470,22 @@ def find_and_fix_short_edges( if not bodies: return RepairToolMessage(False, [], [], 0, 0) - response = self._repair_stub.FindAndFixShortEdges( - FindShortEdgesRequest( - selection=[body.id for body in bodies], - max_edge_length=DoubleValue(value=length), - comprehensive=comprehensive_result, - ) + body_ids = [body.id for body in bodies] + + response = self._grpc_client.services.repair_tools.find_and_fix_short_edges( + selection=body_ids, + length=length, + comprehensive_result=comprehensive_result, ) parent_design = get_design_from_body(bodies[0]) parent_design._update_design_inplace() message = RepairToolMessage( - response.success, - response.created_bodies_monikers, - response.modified_bodies_monikers, - response.found, - response.repaired, + success=response["success"], + found=response["found"], + repaired=response["repaired"], + created_bodies=[], + modified_bodies=[], ) return message @@ -553,20 +523,20 @@ def find_and_fix_extra_edges( if not bodies: return RepairToolMessage(False, [], [], 0, 0) - response = self._repair_stub.FindAndFixExtraEdges( - FindExtraEdgesRequest( - selection=[body.id for body in bodies], comprehensive=comprehensive_result - ) + body_ids = [body.id for body in bodies] + response = self._grpc_client.services.repair_tools.find_and_fix_extra_edges( + selection=body_ids, + comprehensive_result=comprehensive_result, ) parent_design = get_design_from_body(bodies[0]) parent_design._update_design_inplace() message = RepairToolMessage( - response.success, - response.created_bodies_monikers, - response.modified_bodies_monikers, - response.found, - response.repaired, + response["success"], + response["created_bodies_monikers"], + response["modified_bodies_monikers"], + response["found"], + response["repaired"], ) return message @@ -612,27 +582,23 @@ def find_and_fix_split_edges( if not bodies: return RepairToolMessage(False, [], [], 0, 0) - angle_value = DoubleValue(value=float(angle)) - length_value = DoubleValue(value=float(length)) body_ids = [body.id for body in bodies] - response = self._repair_stub.FindAndFixSplitEdges( - FindSplitEdgesRequest( - bodies_or_faces=body_ids, - angle=angle_value, - distance=length_value, - comprehensive=comprehensive_result, - ) + response = self._grpc_client.services.repair_tools.find_and_fix_split_edges( + bodies_or_faces=body_ids, + angle=angle, + length=length, + comprehensive_result=comprehensive_result, ) parent_design = get_design_from_body(bodies[0]) parent_design._update_design_inplace() message = RepairToolMessage( - response.success, - response.created_bodies_monikers, - response.modified_bodies_monikers, - response.found, - response.repaired, + response["success"], + response["created_bodies_monikers"], + response["modified_bodies_monikers"], + response["found"], + response["repaired"], ) return message @@ -670,23 +636,22 @@ def find_and_fix_simplify( body_ids = [body.id for body in bodies] - response = self._repair_stub.FindAndSimplify( - FindAdjustSimplifyRequest(selection=body_ids, comprehensive=comprehensive_result) + response = self._grpc_client.services.repair_tools.find_and_fix_simplify( + selection=body_ids, + comprehensive_result=comprehensive_result, ) parent_design = get_design_from_body(bodies[0]) parent_design._update_design_inplace() message = RepairToolMessage( - response.success, - response.created_bodies_monikers, - response.modified_bodies_monikers, - response.found, - response.repaired, + response["success"], + response["created_bodies_monikers"], + response["modified_bodies_monikers"], + response["found"], + response["repaired"], ) return message - @protect_grpc - @min_backend_version(25, 2, 0) def inspect_geometry(self, bodies: list["Body"] = None) -> list[InspectResult]: """Return a list of geometry issues organized by body. @@ -706,20 +671,20 @@ def inspect_geometry(self, bodies: list["Body"] = None) -> list[InspectResult]: """ parent_design = self._modeler.get_active_design() body_ids = [] if bodies is None else [body._grpc_id for body in bodies] - inspect_result_response = self._repair_stub.InspectGeometry( - InspectGeometryRequest(bodies=body_ids) + inspect_result_response_dict = self._grpc_client.services.repair_tools.inspect_geometry( + parent_design=parent_design, bodies=body_ids ) return self.__create_inspect_result_from_response( - parent_design, inspect_result_response.issues_by_body + parent_design, inspect_result_response_dict["issues_by_body"] ) def __create_inspect_result_from_response( - self, design, inspect_geometry_results: list[InspectGeometryResult] + self, design, inspect_geometry_results: list[dict] ) -> list[InspectResult]: inspect_results = [] for inspect_geometry_result in inspect_geometry_results: - body = get_bodies_from_ids(design, [inspect_geometry_result.body.id]) - issues = self.__create_issues_from_response(inspect_geometry_result.issues) + body = get_bodies_from_ids(design, [inspect_geometry_result["body"]["id"]]) + issues = self.__create_issues_from_response(inspect_geometry_result["issues"]) inspect_result = InspectResult( grpc_client=self._grpc_client, body=body[0], issues=issues ) @@ -729,22 +694,25 @@ def __create_inspect_result_from_response( def __create_issues_from_response( self, - inspect_geometry_result_issues: list[InspectGeometryResultIssue], + inspect_geometry_result_issues: list[dict], ) -> list[GeometryIssue]: issues = [] - for inspect_result_issue in inspect_geometry_result_issues: - message_type = InspectGeometryMessageType.Name(inspect_result_issue.message_type) - message_id = InspectGeometryMessageId.Name(inspect_result_issue.message_id) - message = inspect_result_issue.message + for issue in inspect_geometry_result_issues: + message_type = issue["message_type"] + message_id = issue["message_id"] + message = issue["message"] + + faces = [face["id"] for face in issue.get("faces", [])] + edges = [edge["id"] for edge in issue.get("edges", [])] - issue = GeometryIssue( + geometry_issue = GeometryIssue( message_type=message_type, message_id=message_id, message=message, - faces=[face.id for face in inspect_result_issue.faces], - edges=[edge.id for edge in inspect_result_issue.edges], + faces=faces, + edges=edges, ) - issues.append(issue) + issues.append(geometry_issue) return issues @protect_grpc @@ -766,9 +734,9 @@ def repair_geometry(self, bodies: list["Body"] = None) -> RepairToolMessage: Message containing success of the operation. """ body_ids = [] if bodies is None else [body._grpc_id for body in bodies] - repair_result_response = self._repair_stub.RepairGeometry( - RepairGeometryRequest(bodies=body_ids) + repair_result_response = self._grpc_client.services.repair_tools.repair_geometry( + bodies=body_ids ) - message = RepairToolMessage(repair_result_response.result.success, [], []) + message = RepairToolMessage(repair_result_response["success"], [], []) return message