diff --git a/doc/changelog.d/2153.added.md b/doc/changelog.d/2153.added.md new file mode 100644 index 0000000000..f4ff49de0c --- /dev/null +++ b/doc/changelog.d/2153.added.md @@ -0,0 +1 @@ +Tracking boolean operations diff --git a/src/ansys/geometry/core/_grpc/_services/base/bodies.py b/src/ansys/geometry/core/_grpc/_services/base/bodies.py index d4adb13175..d0a4dda485 100644 --- a/src/ansys/geometry/core/_grpc/_services/base/bodies.py +++ b/src/ansys/geometry/core/_grpc/_services/base/bodies.py @@ -220,6 +220,9 @@ def boolean(self, **kwargs) -> dict: pass @abstractmethod + def combine(self, **kwargs) -> dict: + """Boolean operation through command.""" + def split_body(self, **kwargs) -> dict: """Split a body.""" pass diff --git a/src/ansys/geometry/core/_grpc/_services/base/repair_tools.py b/src/ansys/geometry/core/_grpc/_services/base/repair_tools.py index 4d2ac4cfde..620e69f72c 100644 --- a/src/ansys/geometry/core/_grpc/_services/base/repair_tools.py +++ b/src/ansys/geometry/core/_grpc/_services/base/repair_tools.py @@ -128,3 +128,53 @@ def inspect_geometry(self, **kwargs) -> dict: def repair_geometry(self, **kwargs) -> dict: """Repair the geometry by addressing identified issues.""" pass + + @abstractmethod + def fix_duplicate_faces(self, **kwargs) -> dict: # noqa: D102 + """Fix duplicate faces in the geometry.""" + pass + + @abstractmethod + def fix_missing_faces(self, **kwargs) -> dict: # noqa: D102 + """Fix missing faces in the geometry.""" + pass + + @abstractmethod + def fix_inexact_edges(self, **kwargs) -> dict: # noqa: D102 + """Fix inexact edges in the geometry.""" + pass + + @abstractmethod + def fix_extra_edges(self, **kwargs) -> dict: # noqa: D102 + """Fix extra edges in the geometry.""" + pass + + @abstractmethod + def fix_short_edges(self, **kwargs) -> dict: # noqa: D102 + """Fix short edges in the geometry.""" + pass + + @abstractmethod + def fix_small_faces(self, **kwargs) -> dict: # noqa: D102 + """Fix small faces in the geometry.""" + pass + + @abstractmethod + def fix_split_edges(self, **kwargs) -> dict: # noqa: D102 + """Fix split edges in the geometry.""" + pass + + @abstractmethod + def fix_stitch_faces(self, **kwargs) -> dict: # noqa: D102 + """Fix stitch faces in the geometry.""" + pass + + @abstractmethod + def fix_unsimplified_faces(self, **kwargs) -> dict: # noqa: D102 + """Fix areas to simplify in the geometry.""" + pass + + @abstractmethod + def fix_interference(self, **kwargs) -> dict: # noqa: D102 + """Fix interferences in the geometry.""" + pass diff --git a/src/ansys/geometry/core/_grpc/_services/v0/bodies.py b/src/ansys/geometry/core/_grpc/_services/v0/bodies.py index a8137d2dd8..fba4d3b297 100644 --- a/src/ansys/geometry/core/_grpc/_services/v0/bodies.py +++ b/src/ansys/geometry/core/_grpc/_services/v0/bodies.py @@ -24,6 +24,7 @@ import grpc import pint +import ansys.geometry.core as pyansys_geom from ansys.geometry.core.errors import protect_grpc from ansys.geometry.core.misc.measurements import DEFAULT_UNITS @@ -43,6 +44,7 @@ from_trimmed_curve_to_grpc_trimmed_curve, from_trimmed_surface_to_grpc_trimmed_surface, from_unit_vector_to_grpc_direction, + serialize_tracker_command_response, ) @@ -714,15 +716,22 @@ def boolean(self, **kwargs) -> dict: # noqa: D102 from ansys.api.geometry.v0.bodies_pb2 import BooleanRequest # Call the gRPC service and build the requests accordingly - resp = 0 + response_success = 0 + serialized_tracker_response = {} try: - resp = self.stub.Boolean( - request=BooleanRequest( - body1=kwargs["target"].id, - tool_bodies=[other.id for other in kwargs["other"]], - method=kwargs["method"], + request = BooleanRequest( + body1=kwargs["target"].id, + tool_bodies=[other.id for other in kwargs["other"]], + method=kwargs["method"], + ) + if pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: + request.keep_other = kwargs["keep_other"] + resp = self.stub.Boolean(request=request) + response_success = resp.empty_result + if pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: + serialized_tracker_response = serialize_tracker_command_response( + response=resp.response ) - ).empty_result except grpc.RpcError as err: # pragma: no cover # TODO: to be deleted - old versions did not have "tool_bodies" in the request # This is a temporary fix to support old versions of the server - should be deleted @@ -741,7 +750,7 @@ def boolean(self, **kwargs) -> dict: # noqa: D102 all_resp.append(tmp_resp) if all_resp.count(1) > 0: - resp = 1 + response_success = 1 elif len(kwargs["other"]) == 1: resp = self.stub.Boolean( request=BooleanRequest( @@ -749,18 +758,74 @@ def boolean(self, **kwargs) -> dict: # noqa: D102 body2=kwargs["other"][0].id, method=kwargs["method"], ) - ).empty_result + ) + response_success = resp.empty_result else: raise err - if resp == 1: + if response_success == 1: raise ValueError( f"Boolean operation of type '{kwargs['method']}' failed: {kwargs['err_msg']}.\n" f"Involving bodies:{kwargs['target']}, {kwargs['other']}" ) # Return the response - formatted as a dictionary - return {} + return {"complete_command_response": serialized_tracker_response} + + @protect_grpc + def combine(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.bodies_pb2 import ( + CombineIntersectBodiesRequest, + CombineMergeBodiesRequest, + ) + + other_bodies = kwargs["other"] + type_bool_op = kwargs["type_bool_op"] + keep_other = kwargs["keep_other"] + + if type_bool_op == "intersect": + body_ids = [body._grpc_id for body in other_bodies] + target_ids = [self._grpc_id] + request = CombineIntersectBodiesRequest( + target_selection=target_ids, + tool_selection=body_ids, + subtract_from_target=False, + keep_cutter=keep_other, + ) + response = self._template._commands_stub.CombineIntersectBodies(request) + elif type_bool_op == "subtract": + body_ids = [body._grpc_id for body in other_bodies] + target_ids = [self._grpc_id] + request = CombineIntersectBodiesRequest( + target_selection=target_ids, + tool_selection=body_ids, + subtract_from_target=True, + keep_cutter=keep_other, + ) + response = self._template._commands_stub.CombineIntersectBodies(request) + elif type_bool_op == "unite": + bodies = [self] + bodies.extend(other_bodies) + body_ids = [body._grpc_id for body in bodies] + request = CombineMergeBodiesRequest(target_selection=body_ids) + response = self._template._commands_stub.CombineMergeBodies(request) + else: + raise ValueError("Unknown operation requested") + if not response.success: + raise ValueError( + f"Operation of type '{type_bool_op}' failed: {kwargs['err_msg']}.\n" + f"Involving bodies:{self}, {other_bodies}" + ) + + if not keep_other: + for b in other_bodies: + b.parent_component.delete_body(b) + + tracker_response = response.result.complete_command_response + serialized_tracker_response = serialize_tracker_command_response(response=tracker_response) + + # Return the response - formatted as a dictionary + return {"complete_command_response": serialized_tracker_response} @protect_grpc def split_body(self, **kwargs) -> dict: # noqa: D102 diff --git a/src/ansys/geometry/core/_grpc/_services/v0/components.py b/src/ansys/geometry/core/_grpc/_services/v0/components.py index 9428ececd1..7d2f167ffa 100644 --- a/src/ansys/geometry/core/_grpc/_services/v0/components.py +++ b/src/ansys/geometry/core/_grpc/_services/v0/components.py @@ -74,6 +74,8 @@ def create(self, **kwargs) -> dict: # noqa: D102 "id": response.component.id, "name": response.component.name, "instance_name": response.component.instance_name, + "template": response.template, + "component": response.component, } @protect_grpc diff --git a/src/ansys/geometry/core/_grpc/_services/v0/conversions.py b/src/ansys/geometry/core/_grpc/_services/v0/conversions.py index 324033b800..05bf4f065f 100644 --- a/src/ansys/geometry/core/_grpc/_services/v0/conversions.py +++ b/src/ansys/geometry/core/_grpc/_services/v0/conversions.py @@ -1329,3 +1329,55 @@ def _check_write_body_facets_input(backend_version: "semver.Version", write_body + "26.1.0, but the current version used is " + f"{backend_version}." ) + + +def serialize_tracker_command_response(**kwargs) -> dict: + """Serialize a TrackerCommandResponse object into a dictionary. + + Parameters + ---------- + response : TrackerCommandResponse + The gRPC TrackerCommandResponse object to serialize. + + Returns + ------- + dict + A dictionary representation of the TrackerCommandResponse object. + """ + + 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, + "is_surface": body.is_surface, + } + + def serialize_entity_identifier(entity): + """Serialize an EntityIdentifier object into a dictionary.""" + return { + "id": entity.id, + } + + response = kwargs["response"] + return { + "success": response.success, + "created_bodies": [ + serialize_body(body) for body in getattr(response, "created_bodies", []) + ], + "modified_bodies": [ + serialize_body(body) for body in getattr(response, "modified_bodies", []) + ], + "deleted_bodies": [ + serialize_entity_identifier(entity) + for entity in getattr(response, "deleted_bodies", []) + ], + } diff --git a/src/ansys/geometry/core/_grpc/_services/v0/repair_tools.py b/src/ansys/geometry/core/_grpc/_services/v0/repair_tools.py index 60d4a074b3..ab574432fe 100644 --- a/src/ansys/geometry/core/_grpc/_services/v0/repair_tools.py +++ b/src/ansys/geometry/core/_grpc/_services/v0/repair_tools.py @@ -31,7 +31,9 @@ from ansys.geometry.core.errors import protect_grpc from ..base.repair_tools import GRPCRepairToolsService -from .conversions import build_grpc_id +from .conversions import ( + serialize_tracker_command_response, +) class GRPCRepairToolsServiceV0(GRPCRepairToolsService): # noqa: D102 @@ -370,8 +372,8 @@ def find_and_fix_short_edges(self, **kwargs): # noqa: D102 # Call the gRPC service response = self.stub.FindAndFixShortEdges(request) - serialized_tracker_response = self._serialize_tracker_command_response( - response.complete_command_response + serialized_tracker_response = serialize_tracker_command_response( + response=response.complete_command_response ) # Return the response - formatted as a dictionary @@ -397,8 +399,8 @@ def find_and_fix_extra_edges(self, **kwargs) -> dict: # noqa: D102 # Call the gRPC service response = self.stub.FindAndFixExtraEdges(request) - serialized_tracker_response = self._serialize_tracker_command_response( - response.complete_command_response + serialized_tracker_response = serialize_tracker_command_response( + response=response.complete_command_response ) # Return the response - formatted as a dictionary @@ -427,8 +429,8 @@ def find_and_fix_split_edges(self, **kwargs) -> dict: # noqa: D102 # Call the gRPC service response = self.stub.FindAndFixSplitEdges(request) - serialized_tracker_response = self._serialize_tracker_command_response( - response.complete_command_response + serialized_tracker_response = serialize_tracker_command_response( + response=response.complete_command_response ) # Return the response - formatted as a dictionary @@ -454,8 +456,8 @@ def find_and_fix_simplify(self, **kwargs) -> dict: # noqa: D102 # Call the gRPC service response = self.stub.FindAndSimplify(request) - serialized_tracker_response = self._serialize_tracker_command_response( - response.complete_command_response + serialized_tracker_response = serialize_tracker_command_response( + response=response.complete_command_response ) # Return the response - formatted as a dictionary @@ -492,8 +494,8 @@ def find_and_fix_stitch_faces(self, **kwargs) -> dict: # noqa: D102 # Call the gRPC service response = self.stub.FindAndFixStitchFaces(request) - serialized_tracker_response = self._serialize_tracker_command_response( - response.complete_command_response + serialized_tracker_response = serialize_tracker_command_response( + response=response.complete_command_response ) # Return the response - formatted as a dictionary @@ -511,20 +513,20 @@ def inspect_geometry(self, **kwargs) -> dict: # noqa: D102 from ansys.api.geometry.v0.repairtools_pb2 import InspectGeometryRequest # Create the request - assumes all inputs are valid and of the proper type - request = InspectGeometryRequest(bodies=[build_grpc_id(b) for b in kwargs["body_ids"]]) + request = InspectGeometryRequest(bodies=kwargs.get("bodies", [])) # Call the gRPC service - response = self.stub.InspectGeometry(request) + inspect_result_response = self.stub.InspectGeometry(request) # Serialize and return the response - return self.__serialize_inspect_result_response(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 # Create the request - assumes all inputs are valid and of the proper type - request = RepairGeometryRequest(bodies=[build_grpc_id(b) for b in kwargs["body_ids"]]) + request = RepairGeometryRequest(bodies=kwargs.get("bodies", [])) # Call the gRPC service response = self.stub.RepairGeometry(request) @@ -534,6 +536,226 @@ def repair_geometry(self, **kwargs) -> dict: # noqa: D102 "success": response.result.success, } + @protect_grpc + def fix_duplicate_faces(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FixDuplicateFacesRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = FixDuplicateFacesRequest( + duplicate_face_problem_area_id=kwargs["duplicate_face_problem_area_id"], + ) + + # Call the gRPC service + response = self.stub.FixDuplicateFaces(request) + + serialized_tracker_response = serialize_tracker_command_response( + response=response.result.complete_command_response + ) + + # Return the response - formatted as a dictionary + return { + "tracker_response": serialized_tracker_response, + "repair_tracker_response": self.__serialize_message_response(response), + } + + @protect_grpc + def fix_missing_faces(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FixMissingFacesRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = FixMissingFacesRequest( + missing_face_problem_area_id=kwargs["missing_face_problem_area_id"], + ) + + # Call the gRPC service + response = self.stub.FixMissingFaces(request) + + serialized_tracker_response = serialize_tracker_command_response( + response=response.result.complete_command_response + ) + + # Return the response - formatted as a dictionary + return { + "tracker_response": serialized_tracker_response, + "repair_tracker_response": self.__serialize_message_response(response), + } + + @protect_grpc + def fix_inexact_edges(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FixInexactEdgesRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = FixInexactEdgesRequest( + inexact_edge_problem_area_id=kwargs["inexact_edge_problem_area_id"], + ) + + # Call the gRPC service + response = self.stub.FixInexactEdges(request) + + serialized_tracker_response = serialize_tracker_command_response( + response=response.result.complete_command_response + ) + + # Return the response - formatted as a dictionary + return { + "tracker_response": serialized_tracker_response, + "repair_tracker_response": self.__serialize_message_response(response), + } + + @protect_grpc + def fix_extra_edges(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FixExtraEdgesRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = FixExtraEdgesRequest( + extra_edge_problem_area_id=kwargs["extra_edge_problem_area_id"], + ) + + # Call the gRPC service + response = self.stub.FixExtraEdges(request) + + serialized_tracker_response = serialize_tracker_command_response( + response=response.result.complete_command_response + ) + + # Return the response - formatted as a dictionary + return { + "tracker_response": serialized_tracker_response, + "repair_tracker_response": self.__serialize_message_response(response), + } + + @protect_grpc + def fix_short_edges(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FixShortEdgesRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = FixShortEdgesRequest( + short_edge_problem_area_id=kwargs["short_edge_problem_area_id"], + ) + + # Call the gRPC service + response = self.stub.FixShortEdges(request) + + serialized_tracker_response = serialize_tracker_command_response( + response=response.result.complete_command_response + ) + + # Return the response - formatted as a dictionary + return { + "tracker_response": serialized_tracker_response, + "repair_tracker_response": self.__serialize_message_response(response), + } + + @protect_grpc + def fix_small_faces(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FixSmallFacesRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = FixSmallFacesRequest( + small_face_problem_area_id=kwargs["small_face_problem_area_id"], + ) + + # Call the gRPC service + response = self.stub.FixSmallFaces(request) + + serialized_tracker_response = serialize_tracker_command_response( + response=response.result.complete_command_response + ) + + # Return the response - formatted as a dictionary + return { + "tracker_response": serialized_tracker_response, + "repair_tracker_response": self.__serialize_message_response(response), + } + + @protect_grpc + def fix_split_edges(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FixSplitEdgesRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = FixSplitEdgesRequest( + split_edge_problem_area_id=kwargs["split_edge_problem_area_id"], + ) + + # Call the gRPC service + response = self.stub.FixSplitEdges(request) + + serialized_tracker_response = serialize_tracker_command_response( + response=response.result.complete_command_response + ) + + # Return the response - formatted as a dictionary + return { + "tracker_response": serialized_tracker_response, + "repair_tracker_response": self.__serialize_message_response(response), + } + + @protect_grpc + def fix_stitch_faces(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FixStitchFacesRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = FixStitchFacesRequest( + stitch_face_problem_area_id=kwargs["stitch_face_problem_area_id"], + ) + + # Call the gRPC service + response = self.stub.FixStitchFaces(request) + + serialized_tracker_response = serialize_tracker_command_response( + response=response.result.complete_command_response + ) + + # Return the response - formatted as a dictionary + return { + "tracker_response": serialized_tracker_response, + "repair_tracker_response": self.__serialize_message_response(response), + } + + @protect_grpc + def fix_unsimplified_faces(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FixAdjustSimplifyRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = FixAdjustSimplifyRequest( + adjust_simplify_problem_area_id=kwargs["adjust_simplify_problem_area_id"], + ) + + # Call the gRPC service + response = self.stub.FixAdjustSimplify(request) + + serialized_tracker_response = serialize_tracker_command_response( + response=response.result.complete_command_response + ) + + # Return the response - formatted as a dictionary + return { + "tracker_response": serialized_tracker_response, + "repair_tracker_response": self.__serialize_message_response(response), + } + + @protect_grpc + def fix_interference(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.repairtools_pb2 import FixInterferenceRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = FixInterferenceRequest( + interference_problem_area_id=kwargs["interference_problem_area_id"], + ) + + # Call the gRPC service + response = self.stub.FixInterference(request) + + serialized_tracker_response = serialize_tracker_command_response( + response=response.result.complete_command_response + ) + + # Return the response - formatted as a dictionary + return { + "tracker_response": serialized_tracker_response, + "repair_tracker_response": self.__serialize_message_response(response), + } + def __serialize_inspect_result_response(self, response) -> dict: # noqa: D102 def serialize_body(body): return { @@ -588,52 +810,9 @@ def serialize_issue(issue): ] } - def _serialize_tracker_command_response(self, response) -> dict: - """Serialize a TrackerCommandResponse object into a dictionary. - - Parameters - ---------- - response : TrackerCommandResponse - The gRPC TrackerCommandResponse object to serialize. - - Returns - ------- - dict - A dictionary representation of the TrackerCommandResponse object. - """ - - 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, - "is_surface": body.is_surface, - } - - def serialize_entity_identifier(entity): - """Serialize an EntityIdentifier object into a dictionary.""" - return { - "id": entity.id, - } - + def __serialize_message_response(self, response): return { - "success": response.success, - "created_bodies": [ - serialize_body(body) for body in getattr(response, "created_bodies", []) - ], - "modified_bodies": [ - serialize_body(body) for body in getattr(response, "modified_bodies", []) - ], - "deleted_bodies": [ - serialize_entity_identifier(entity) - for entity in getattr(response, "deleted_bodies", []) - ], + "success": response.result.success, + "created_bodies_monikers": response.result.created_bodies_monikers, + "modified_bodies_monikers": response.result.modified_bodies_monikers, } diff --git a/src/ansys/geometry/core/_grpc/_services/v1/bodies.py b/src/ansys/geometry/core/_grpc/_services/v1/bodies.py index f8f6fc9751..c06afe63b3 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/bodies.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/bodies.py @@ -192,6 +192,10 @@ def get_tesellation_with_options(self, **kwargs) -> dict: # noqa: D102 def boolean(self, **kwargs) -> dict: # noqa: D102 raise NotImplementedError + @protect_grpc + def combine(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + @protect_grpc def split_body(self, **kwargs) -> dict: # noqa: D102 raise NotImplementedError diff --git a/src/ansys/geometry/core/_grpc/_services/v1/repair_tools.py b/src/ansys/geometry/core/_grpc/_services/v1/repair_tools.py index 3a53f3c2f5..4c95a9a041 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/repair_tools.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/repair_tools.py @@ -110,3 +110,43 @@ def inspect_geometry(self, **kwargs) -> dict: # noqa: D102 @protect_grpc def repair_geometry(self, **kwargs) -> dict: # noqa: D102 raise NotImplementedError + + @protect_grpc + def fix_duplicate_faces(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def fix_missing_faces(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def fix_inexact_edges(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def fix_extra_edges(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def fix_short_edges(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def fix_small_faces(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def fix_split_edges(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def fix_stitch_faces(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def fix_unsimplified_faces(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def fix_interference(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError diff --git a/src/ansys/geometry/core/designer/body.py b/src/ansys/geometry/core/designer/body.py index 2322b8e511..b1d948b977 100644 --- a/src/ansys/geometry/core/designer/body.py +++ b/src/ansys/geometry/core/designer/body.py @@ -31,8 +31,6 @@ from ansys.api.geometry.v0.commands_pb2 import ( AssignMidSurfaceOffsetTypeRequest, AssignMidSurfaceThicknessRequest, - CombineIntersectBodiesRequest, - CombineMergeBodiesRequest, ImprintCurvesRequest, ProjectCurvesRequest, RemoveFacesRequest, @@ -43,6 +41,7 @@ import matplotlib.colors as mcolors from pint import Quantity +import ansys.geometry.core as pyansys_geom from ansys.geometry.core.connection.client import GrpcClient from ansys.geometry.core.connection.conversions import ( plane_to_grpc_plane, @@ -1904,7 +1903,6 @@ def unite(self, other: Union["Body", Iterable["Body"]], keep_other: bool = False else: self.__generic_boolean_command(other, False, "unite", "union operation failed") - @protect_grpc @reset_tessellation_cache @ensure_design_is_active @check_input_types @@ -1912,59 +1910,20 @@ def __generic_boolean_command( self, other: Union["Body", Iterable["Body"]], keep_other: bool, - type_bool_op: str, - err_bool_op: str, + method: str, + err_msg: str, ) -> None: parent_design = get_design_from_body(self) - other_bodies = other if isinstance(other, Iterable) else [other] - if type_bool_op == "intersect": - body_ids = [body._grpc_id for body in other_bodies] - target_ids = [self._grpc_id] - request = CombineIntersectBodiesRequest( - target_selection=target_ids, - tool_selection=body_ids, - subtract_from_target=False, - keep_cutter=keep_other, - ) - response = self._template._commands_stub.CombineIntersectBodies(request) - elif type_bool_op == "subtract": - body_ids = [body._grpc_id for body in other_bodies] - target_ids = [self._grpc_id] - request = CombineIntersectBodiesRequest( - target_selection=target_ids, - tool_selection=body_ids, - subtract_from_target=True, - keep_cutter=keep_other, - ) - response = self._template._commands_stub.CombineIntersectBodies(request) - elif type_bool_op == "unite": - bodies = [self] - bodies.extend(other_bodies) - body_ids = [body._grpc_id for body in bodies] - request = CombineMergeBodiesRequest(target_selection=body_ids) - response = self._template._commands_stub.CombineMergeBodies(request) - else: - raise ValueError("Unknown operation requested") - if not response.success: - raise ValueError( - f"Operation of type '{type_bool_op}' failed: {err_bool_op}.\n" - f"Involving bodies:{self}, {other_bodies}" - ) + other = other if isinstance(other, Iterable) else [other] - if not keep_other: - for b in other_bodies: - b.parent_component.delete_body(b) - - from ansys.geometry.core import USE_TRACKER_TO_UPDATE_DESIGN + response = self._template._grpc_client.services.bodies.combine( + target=self, other=other, type_bool_op=method, err_msg=err_msg, keep_other=keep_other + ) - if not USE_TRACKER_TO_UPDATE_DESIGN: + if not pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: - # If USE_TRACKER_TO_UPDATE_DESIGN is True, we serialize the response - # and update the parent design with the serialized response. - tracker_response = response.result.complete_command_response - serialized_response = self._serialize_tracker_command_response(tracker_response) - parent_design._update_from_tracker(serialized_response) + parent_design._update_from_tracker(response["complete_command_response"]) @reset_tessellation_cache @ensure_design_is_active @@ -1977,20 +1936,26 @@ def __generic_boolean_op( err_msg: str, ) -> None: grpc_other = other if isinstance(other, Iterable) else [other] - if keep_other: - # Make a copy of the other body to keep it... - # stored temporarily in the parent component - since it will be deleted - grpc_other = [b.copy(self.parent_component, f"BoolOpCopy_{b.name}") for b in grpc_other] - - self._template._grpc_client.services.bodies.boolean( - target=self, - other=grpc_other, - method=method, - err_msg=err_msg, + if not pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: + if keep_other: + # Make a copy of the other body to keep it... + # stored temporarily in the parent component - since it will be deleted + grpc_other = [ + b.copy(self.parent_component, f"BoolOpCopy_{b.name}") for b in grpc_other + ] + + response = self._template._grpc_client.services.bodies.boolean( + target=self, other=grpc_other, method=method, err_msg=err_msg, keep_other=keep_other ) - for b in grpc_other: - b.parent_component.delete_body(b) + if not pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: + for b in grpc_other: + b.parent_component.delete_body(b) + else: + # If USE_TRACKER_TO_UPDATE_DESIGN is True, we serialize the response + # and update the parent design with the serialized response. + parent_design = get_design_from_body(self) + parent_design._update_from_tracker(response["complete_command_response"]) def __repr__(self) -> str: """Represent the ``Body`` as a string.""" diff --git a/src/ansys/geometry/core/designer/component.py b/src/ansys/geometry/core/designer/component.py index c792f73ec2..d0d1aade63 100644 --- a/src/ansys/geometry/core/designer/component.py +++ b/src/ansys/geometry/core/designer/component.py @@ -197,11 +197,14 @@ def __init__( # Align instance name behavior with the server - empty string if None instance_name = instance_name if instance_name else "" + response = None if preexisting_id: self._name = name self._id = preexisting_id self._instance_name = instance_name + self._template = None + self._component = None else: if parent_component: template_id = template.id if template else "" @@ -216,10 +219,14 @@ def __init__( self._id = response.get("id") self._name = response.get("name") self._instance_name = response.get("instance_name") + self._template = response.get("template") + self._component = response.get("component") else: self._name = name self._id = None self._instance_name = instance_name + self._template = None + self._component = None # Initialize needed instance variables self._components = [] @@ -249,8 +256,12 @@ def __init__( elif not read_existing_comp: # This is an independent Component - Create new Part and MasterComponent - p = Part(uuid.uuid4(), f"p_{name}", [], []) - master = MasterComponent(uuid.uuid4(), f"master_{name}", p) + p = Part(uuid.uuid4() if not self._template else self._template, f"p_{name}", [], []) + master = MasterComponent( + uuid.uuid4() if not self._template else self._component.master_id, + f"master_{name}", + p, + ) self._master_component = master self._master_component.occurrences.append(self) diff --git a/src/ansys/geometry/core/designer/design.py b/src/ansys/geometry/core/designer/design.py index 98565b7e22..de3d364387 100644 --- a/src/ansys/geometry/core/designer/design.py +++ b/src/ansys/geometry/core/designer/design.py @@ -1343,7 +1343,11 @@ def _handle_deleted_bodies(self, deleted_bodies): for body in self.bodies: if body.id == body_id: body._is_alive = False - self.bodies.remove(body) + for bd in self._master_component.part.bodies: + if bd.id == body_id: + self._master_component.part.bodies.remove(bd) + break + self._clear_cached_bodies() removed = True self._grpc_client.log.info( f"Deleted body (ID: {body_id}) removed from root level." @@ -1370,10 +1374,11 @@ def _handle_created_bodies(self, created_bodies): ) continue - added = any(self._find_and_add_body(body_info, self.components)) + added = self._find_and_add_body(body_info, self.components) if not added: new_body = MasterBody(body_id, body_name, self._grpc_client, is_surface=is_surface) - self.bodies.append(new_body) + self._master_component.part.bodies.append(new_body) + self._clear_cached_bodies() self._grpc_client.log.debug( f"Added new body '{body_name}' (ID: {body_id}) to root level." ) @@ -1388,14 +1393,17 @@ def _update_body(self, existing_body, body_info): def _find_and_add_body(self, body_info, components): for component in components: - if component.id == body_info["parent_id"]: + parent_id_for_body = component._master_component.part.id + if parent_id_for_body == body_info["parent_id"]: new_body = MasterBody( body_info["id"], body_info["name"], self._grpc_client, is_surface=body_info.get("is_surface", False), ) - component.bodies.append(new_body) + # component.bodies.append(new_body) + component._master_component.part.bodies.append(new_body) + component._clear_cached_bodies() self._grpc_client.log.debug( f"Added new body '{new_body.name}' (ID: {new_body.id}) " f"to component '{component.name}' (ID: {component.id})" @@ -1425,11 +1433,17 @@ def _find_and_update_body(self, body_info, component): def _find_and_remove_body(self, body_info, component): for body in component.bodies: - if body.id == body_info["id"]: + body_info_id = body_info["id"] + if body.id == f"{component.id}/{body_info_id}": body._is_alive = False - component.bodies.remove(body) + # component.bodies.remove(body) + for bd in component._master_component.part.bodies: + if bd.id == body_info_id: + component._master_component.part.bodies.remove(bd) + break + component._clear_cached_bodies() self._grpc_client.log.debug( - f"Removed body '{body_info['name']}' (ID: {body_info['id']}) from component " + f"Removed body (ID: {body_info['id']}) from component " f"'{component.name}' (ID: {component.id})" ) return True diff --git a/src/ansys/geometry/core/tools/problem_areas.py b/src/ansys/geometry/core/tools/problem_areas.py index b59b78986d..5223edfd0a 100644 --- a/src/ansys/geometry/core/tools/problem_areas.py +++ b/src/ansys/geometry/core/tools/problem_areas.py @@ -24,23 +24,11 @@ from abc import abstractmethod from typing import TYPE_CHECKING -from ansys.api.geometry.v0.repairtools_pb2 import ( - FixAdjustSimplifyRequest, - FixDuplicateFacesRequest, - FixExtraEdgesRequest, - FixInexactEdgesRequest, - FixInterferenceRequest, - FixMissingFacesRequest, - FixShortEdgesRequest, - FixSmallFacesRequest, - FixSplitEdgesRequest, - FixStitchFacesRequest, -) from ansys.api.geometry.v0.repairtools_pb2_grpc import RepairToolsStub from google.protobuf.wrappers_pb2 import Int32Value +import ansys.geometry.core as pyansys_geom from ansys.geometry.core.connection import GrpcClient -from ansys.geometry.core.errors import protect_grpc from ansys.geometry.core.misc.auxiliary import ( get_design_from_body, get_design_from_edge, @@ -83,57 +71,27 @@ def fix(self): """Fix problem area.""" raise NotImplementedError("Fix method is not implemented in the base class.") - def _serialize_tracker_command_response(self, response) -> dict: - """Serialize a TrackerCommandResponse object into a dictionary. + def build_repair_tool_message(self, response: dict) -> RepairToolMessage: + """Build a repair tool message from the service response. Parameters ---------- - response : TrackerCommandResponse - The gRPC TrackerCommandResponse object to serialize. + response : dict + The response from the service containing information about the repair operation. Returns ------- - dict - A dictionary representation of the TrackerCommandResponse object. + RepairToolMessage + A message containing the success status, created bodies, modified bodies, + number of found problem areas, and number of repaired problem areas. """ - - def serialize_body(body): - """Serialize a Body object into a dictionary.""" - 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, - "is_surface": body.is_surface, - } - - def serialize_entity_identifier(entity): - """Serialize an EntityIdentifier object into a dictionary.""" - return { - "id": entity.id, - } - - # Safely serialize each field, defaulting to an empty list if the field is missing - return { - "success": response.success, - "created_bodies": [ - serialize_body(body) for body in getattr(response, "created_bodies", []) - ], - "modified_bodies": [ - serialize_body(body) for body in getattr(response, "modified_bodies", []) - ], - "deleted_bodies": [ - serialize_entity_identifier(entity) - for entity in getattr(response, "deleted_bodies", []) - ], - } + return RepairToolMessage( + success=response.get("success"), + created_bodies=response.get("created_bodies_monikers", []), + modified_bodies=response.get("modified_bodies_monikers", []), + found=response.get("found", -1), + repaired=response.get("repaired", -1), + ) class DuplicateFaceProblemAreas(ProblemArea): @@ -167,7 +125,6 @@ def faces(self) -> list["Face"]: """The list of faces connected to this problem area.""" return self._faces - @protect_grpc def fix(self) -> RepairToolMessage: """Fix the problem area. @@ -180,24 +137,16 @@ def fix(self) -> RepairToolMessage: return RepairToolMessage(False, [], []) parent_design = get_design_from_face(self.faces[0]) - response = self._repair_stub.FixDuplicateFaces( - FixDuplicateFacesRequest(duplicate_face_problem_area_id=self._grpc_id) + response = self._grpc_client.services.repair_tools.fix_duplicate_faces( + duplicate_face_problem_area_id=self._grpc_id ) - from ansys.geometry.core import USE_TRACKER_TO_UPDATE_DESIGN - if not USE_TRACKER_TO_UPDATE_DESIGN: + if not pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: - tracker_response = response.result.complete_command_response - serialized_response = self._serialize_tracker_command_response(tracker_response) - parent_design._update_from_tracker(serialized_response) - - message = RepairToolMessage( - success=response.result.success, - created_bodies=response.result.created_bodies_monikers, - modified_bodies=response.result.modified_bodies_monikers, - ) + parent_design._update_from_tracker(response.get("tracker_response")) + message = self.build_repair_tool_message(response.get("repair_tracker_response")) return message @@ -230,7 +179,6 @@ def edges(self) -> list["Edge"]: """The list of edges connected to this problem area.""" return self._edges - @protect_grpc def fix(self) -> RepairToolMessage: """Fix the problem area. @@ -243,26 +191,16 @@ def fix(self) -> RepairToolMessage: return RepairToolMessage(False, [], []) parent_design = get_design_from_edge(self.edges[0]) - response = self._repair_stub.FixMissingFaces( - FixMissingFacesRequest(missing_face_problem_area_id=self._grpc_id) + response = self._grpc_client.services.repair_tools.fix_missing_faces( + missing_face_problem_area_id=self._grpc_id ) - serialized_response = self._serialize_tracker_command_response( - response.result.complete_command_response - ) - - from ansys.geometry.core import USE_TRACKER_TO_UPDATE_DESIGN - - if not USE_TRACKER_TO_UPDATE_DESIGN: + if not pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: - parent_design._update_from_tracker(serialized_response) + parent_design._update_from_tracker(response.get("tracker_response")) - message = RepairToolMessage( - success=response.result.success, - created_bodies=response.result.created_bodies_monikers, - modified_bodies=response.result.modified_bodies_monikers, - ) + message = self.build_repair_tool_message(response.get("repair_tracker_response")) return message @@ -295,7 +233,6 @@ def edges(self) -> list["Edge"]: """The list of edges connected to this problem area.""" return self._edges - @protect_grpc def fix(self) -> RepairToolMessage: """Fix the problem area. @@ -309,25 +246,16 @@ def fix(self) -> RepairToolMessage: parent_design = get_design_from_edge(self.edges[0]) - response = self._repair_stub.FixInexactEdges( - FixInexactEdgesRequest(inexact_edge_problem_area_id=self._grpc_id) + response = self._grpc_client.services.repair_tools.fix_inexact_edges( + inexact_edge_problem_area_id=self._grpc_id ) - from ansys.geometry.core import USE_TRACKER_TO_UPDATE_DESIGN - - if not USE_TRACKER_TO_UPDATE_DESIGN: + if not pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: - tracker_response = response.result.complete_command_response - serialized_response = self._serialize_tracker_command_response(tracker_response) - parent_design._update_from_tracker(serialized_response) - - message = RepairToolMessage( - success=response.result.success, - created_bodies=response.result.created_bodies_monikers, - modified_bodies=response.result.modified_bodies_monikers, - ) + parent_design._update_from_tracker(response.get("tracker_response")) + message = self.build_repair_tool_message(response.get("repair_tracker_response")) return message @@ -360,7 +288,6 @@ def edges(self) -> list["Edge"]: """The list of edges connected to this problem area.""" return self._edges - @protect_grpc def fix(self) -> RepairToolMessage: """Fix the problem area. @@ -373,23 +300,16 @@ def fix(self) -> RepairToolMessage: return RepairToolMessage(False, [], []) parent_design = get_design_from_edge(self.edges[0]) - request = FixExtraEdgesRequest(extra_edge_problem_area_id=self._grpc_id) - response = self._repair_stub.FixExtraEdges(request) - from ansys.geometry.core import USE_TRACKER_TO_UPDATE_DESIGN + response = self._grpc_client.services.repair_tools.fix_extra_edges( + extra_edge_problem_area_id=self._grpc_id + ) - if not USE_TRACKER_TO_UPDATE_DESIGN: + if not pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: - tracker_response = response.result.complete_command_response - serialized_response = self._serialize_tracker_command_response(tracker_response) - parent_design._update_from_tracker(serialized_response) - - message = RepairToolMessage( - success=response.result.success, - created_bodies=response.result.created_bodies_monikers, - modified_bodies=response.result.modified_bodies_monikers, - ) + parent_design._update_from_tracker(response.get("tracker_response")) + message = self.build_repair_tool_message(response.get("repair_tracker_response")) return message @@ -422,7 +342,6 @@ def edges(self) -> list["Edge"]: """The list of edges connected to this problem area.""" return self._edges - @protect_grpc def fix(self) -> RepairToolMessage: """Fix the problem area. @@ -435,24 +354,16 @@ def fix(self) -> RepairToolMessage: return RepairToolMessage(False, [], []) parent_design = get_design_from_edge(self.edges[0]) - response = self._repair_stub.FixShortEdges( - FixShortEdgesRequest(short_edge_problem_area_id=self._grpc_id) + response = self._grpc_client.services.repair_tools.fix_short_edges( + short_edge_problem_area_id=self._grpc_id ) - from ansys.geometry.core import USE_TRACKER_TO_UPDATE_DESIGN - if not USE_TRACKER_TO_UPDATE_DESIGN: + if not pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: - tracker_response = response.result.complete_command_response - serialized_response = self._serialize_tracker_command_response(tracker_response) - parent_design._update_from_tracker(serialized_response) - - message = RepairToolMessage( - success=response.result.success, - created_bodies=response.result.created_bodies_monikers, - modified_bodies=response.result.modified_bodies_monikers, - ) + parent_design._update_from_tracker(response.get("tracker_response")) + message = self.build_repair_tool_message(response.get("repair_tracker_response")) return message @@ -485,7 +396,6 @@ def faces(self) -> list["Face"]: """The list of faces connected to this problem area.""" return self._faces - @protect_grpc def fix(self) -> RepairToolMessage: """Fix the problem area. @@ -498,26 +408,16 @@ def fix(self) -> RepairToolMessage: return RepairToolMessage(False, [], []) parent_design = get_design_from_face(self.faces[0]) - response = self._repair_stub.FixSmallFaces( - FixSmallFacesRequest(small_face_problem_area_id=self._grpc_id) + response = self._grpc_client.services.repair_tools.fix_small_faces( + small_face_problem_area_id=self._grpc_id ) - from ansys.geometry.core import USE_TRACKER_TO_UPDATE_DESIGN - - if not USE_TRACKER_TO_UPDATE_DESIGN: + if not pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: - # If USE_TRACKER_TO_UPDATE_DESIGN is True, we serialize the response - # and update the parent design with the serialized response. - tracker_response = response.result.complete_command_response - serialized_response = self._serialize_tracker_command_response(tracker_response) - parent_design._update_from_tracker(serialized_response) - - message = RepairToolMessage( - success=response.result.success, - created_bodies=response.result.created_bodies_monikers, - modified_bodies=response.result.modified_bodies_monikers, - ) + parent_design._update_from_tracker(response.get("tracker_response")) + + message = self.build_repair_tool_message(response.get("repair_tracker_response")) return message @@ -550,7 +450,6 @@ def edges(self) -> list["Edge"]: """The list of edges connected to this problem area.""" return self._edges - @protect_grpc def fix(self) -> RepairToolMessage: """Fix the problem area. @@ -563,24 +462,16 @@ def fix(self) -> RepairToolMessage: return RepairToolMessage(False, [], []) parent_design = get_design_from_edge(self.edges[0]) - response = self._repair_stub.FixSplitEdges( - FixSplitEdgesRequest(split_edge_problem_area_id=self._grpc_id) + response = self._grpc_client.services.repair_tools.fix_split_edges( + split_edge_problem_area_id=self._grpc_id ) - from ansys.geometry.core import USE_TRACKER_TO_UPDATE_DESIGN - if not USE_TRACKER_TO_UPDATE_DESIGN: + if not pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: - tracker_respone = response.result.complete_command_response - serialized_response = self._serialize_tracker_command_response(tracker_respone) - parent_design._update_from_tracker(serialized_response) - - message = RepairToolMessage( - success=response.result.success, - created_bodies=response.result.created_bodies_monikers, - modified_bodies=response.result.modified_bodies_monikers, - ) + parent_design._update_from_tracker(response.get("tracker_response")) + message = self.build_repair_tool_message(response.get("repair_tracker_response")) return message @@ -613,7 +504,6 @@ def bodies(self) -> list["Body"]: """The list of bodies connected to this problem area.""" return self._bodies - @protect_grpc def fix(self) -> RepairToolMessage: """Fix the problem area. @@ -626,23 +516,16 @@ def fix(self) -> RepairToolMessage: return RepairToolMessage(False, [], []) parent_design = get_design_from_body(self.bodies[0]) - response = self._repair_stub.FixStitchFaces( - FixStitchFacesRequest(stitch_face_problem_area_id=self._grpc_id) + response = self._grpc_client.services.repair_tools.fix_stitch_faces( + stitch_face_problem_area_id=self._grpc_id ) - from ansys.geometry.core import USE_TRACKER_TO_UPDATE_DESIGN - if not USE_TRACKER_TO_UPDATE_DESIGN: + if not pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: - tracker_respone = response.result.complete_command_response - serialized_response = self._serialize_tracker_command_response(tracker_respone) - parent_design._update_from_tracker(serialized_response) - - message = RepairToolMessage( - success=response.result.success, - created_bodies=response.result.created_bodies_monikers, - modified_bodies=response.result.modified_bodies_monikers, - ) + parent_design._update_from_tracker(response.get("tracker_response")) + + message = self.build_repair_tool_message(response.get("repair_tracker_response")) return message @@ -670,7 +553,6 @@ def faces(self) -> list["Face"]: """The list of faces connected to this problem area.""" return self._faces - @protect_grpc def fix(self) -> RepairToolMessage: """Fix the problem area. @@ -683,23 +565,16 @@ def fix(self) -> RepairToolMessage: return RepairToolMessage(False, [], []) parent_design = get_design_from_face(self.faces[0]) - response = self._repair_stub.FixAdjustSimplify( - FixAdjustSimplifyRequest(adjust_simplify_problem_area_id=self._grpc_id) + response = self._grpc_client.services.repair_tools.fix_unsimplified_faces( + adjust_simplify_problem_area_id=self._grpc_id ) - from ansys.geometry.core import USE_TRACKER_TO_UPDATE_DESIGN - if not USE_TRACKER_TO_UPDATE_DESIGN: + if not pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: - tracker_respone = response.result.complete_command_response - serialized_response = self._serialize_tracker_command_response(tracker_respone) - parent_design._update_from_tracker(serialized_response) - - message = RepairToolMessage( - success=response.result.success, - created_bodies=response.result.created_bodies_monikers, - modified_bodies=response.result.modified_bodies_monikers, - ) + parent_design._update_from_tracker(response.get("tracker_response")) + + message = self.build_repair_tool_message(response.get("repair_tracker_response")) return message @@ -727,7 +602,6 @@ def bodies(self) -> list["Body"]: """The list of the bodies connected to this problem area.""" return self._bodies - @protect_grpc def fix(self) -> RepairToolMessage: """Fix the problem area. @@ -745,14 +619,18 @@ def fix(self) -> RepairToolMessage: return RepairToolMessage(False, [], []) parent_design = get_design_from_body(self.bodies[0]) - response = self._repair_stub.FixInterference( - FixInterferenceRequest(interference_problem_area_id=self._grpc_id) + response = self._grpc_client.services.repair_tools.fix_interference( + interference_problem_area_id=self._grpc_id ) - parent_design._update_design_inplace() + + if not pyansys_geom.USE_TRACKER_TO_UPDATE_DESIGN: + parent_design._update_design_inplace() + else: + parent_design._update_from_tracker(response.get("tracker_response")) + ## The tool does not return the created or modified objects. ## https://github.com/ansys/pyansys-geometry/issues/1319 - message = RepairToolMessage(response.result.success, [], []) - + message = RepairToolMessage(response.get("repair_tracker_response").get("success"), [], []) return message diff --git a/src/ansys/geometry/core/tools/repair_tool_message.py b/src/ansys/geometry/core/tools/repair_tool_message.py index 45ef82c33e..ea1725a2bb 100644 --- a/src/ansys/geometry/core/tools/repair_tool_message.py +++ b/src/ansys/geometry/core/tools/repair_tool_message.py @@ -59,6 +59,7 @@ def __init__( self._success = success self._created_bodies = created_bodies self._modified_bodies = modified_bodies + self._deleted_bodies = deleted_bodies self._found = found self._repaired = repaired @@ -77,6 +78,11 @@ def modified_bodies(self) -> list[str]: """The list of the modified bodies after the repair operation.""" return self._modified_bodies + @property + def deleted_bodies(self) -> list[str]: + """The list of the deleted bodies after the repair operation.""" + return self._deleted_bodies + @property def found(self) -> int: """Number of problem areas found for the repair operation.""" diff --git a/src/ansys/geometry/core/tools/repair_tools.py b/src/ansys/geometry/core/tools/repair_tools.py index 19afa90758..994cab0f2e 100644 --- a/src/ansys/geometry/core/tools/repair_tools.py +++ b/src/ansys/geometry/core/tools/repair_tools.py @@ -551,16 +551,16 @@ def find_and_fix_short_edges( ) body_ids = [body.id for body in bodies] + parent_design = get_design_from_body(bodies[0]) response = self._grpc_client.services.repair_tools.find_and_fix_short_edges( selection=body_ids, + parent_design=parent_design, length=length, comprehensive_result=comprehensive_result, ) # Update existing design - parent_design = get_design_from_body(bodies[0]) - if not pyansys_geometry.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: @@ -607,14 +607,14 @@ def find_and_fix_extra_edges( ) body_ids = [body.id for body in bodies] + parent_design = get_design_from_body(bodies[0]) response = self._grpc_client.services.repair_tools.find_and_fix_extra_edges( selection=body_ids, + parent_design=parent_design, comprehensive_result=comprehensive_result, ) # Update existing design - parent_design = get_design_from_body(bodies[0]) - if not pyansys_geometry.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: @@ -669,17 +669,17 @@ def find_and_fix_split_edges( ) body_ids = [body.id for body in bodies] + parent_design = get_design_from_body(bodies[0]) response = self._grpc_client.services.repair_tools.find_and_fix_split_edges( bodies_or_faces=body_ids, + parent_design=parent_design, angle=angle, length=length, comprehensive_result=comprehensive_result, ) # Update existing design - parent_design = get_design_from_body(bodies[0]) - if not pyansys_geometry.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: @@ -724,15 +724,15 @@ def find_and_fix_simplify( ) body_ids = [body.id for body in bodies] + parent_design = get_design_from_body(bodies[0]) response = self._grpc_client.services.repair_tools.find_and_fix_simplify( selection=body_ids, + parent_design=parent_design, comprehensive_result=comprehensive_result, ) # Update existing design - parent_design = get_design_from_body(bodies[0]) - if not pyansys_geometry.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: @@ -794,9 +794,11 @@ def find_and_fix_stitch_faces( ) body_ids = [body.id for body in bodies] + parent_design = get_design_from_body(bodies[0]) response = self._grpc_client.services.repair_tools.find_and_fix_stitch_faces( body_ids=body_ids, + parent_design=parent_design, max_distance=max_distance, allow_multiple_bodies=allow_multiple_bodies, maintain_components=maintain_components, @@ -805,8 +807,6 @@ def find_and_fix_stitch_faces( ) # Update existing design - parent_design = get_design_from_body(bodies[0]) - if not pyansys_geometry.USE_TRACKER_TO_UPDATE_DESIGN: parent_design._update_design_inplace() else: