From 8d16dc35371cb23c01a55c6eca28136349593ffa Mon Sep 17 00:00:00 2001 From: jacobrkerstetter Date: Fri, 21 Nov 2025 12:03:08 -0500 Subject: [PATCH 01/10] implement faces v1 - needs testing --- .../core/_grpc/_services/v0/conversions.py | 18 + .../geometry/core/_grpc/_services/v0/faces.py | 7 +- .../core/_grpc/_services/v1/conversions.py | 281 ++++++++- .../geometry/core/_grpc/_services/v1/faces.py | 545 +++++++++++++++++- 4 files changed, 819 insertions(+), 32 deletions(-) diff --git a/src/ansys/geometry/core/_grpc/_services/v0/conversions.py b/src/ansys/geometry/core/_grpc/_services/v0/conversions.py index 601f564696..f9177d5886 100644 --- a/src/ansys/geometry/core/_grpc/_services/v0/conversions.py +++ b/src/ansys/geometry/core/_grpc/_services/v0/conversions.py @@ -184,6 +184,24 @@ def from_unit_vector_to_grpc_direction(unit_vector: "UnitVector3D") -> GRPCDirec return GRPCDirection(x=unit_vector.x, y=unit_vector.y, z=unit_vector.z) +def from_grpc_direction_to_unit_vector(direction: GRPCDirection) -> "UnitVector3D": + """Convert a gRPC direction message to a ``UnitVector3D`` class. + + Parameters + ---------- + direction : GRPCDirection + Source direction data. + + Returns + ------- + UnitVector3D + Converted unit vector. + """ + from ansys.geometry.core.math.vector import UnitVector3D + + return UnitVector3D([direction.x, direction.y, direction.z]) + + def from_line_to_grpc_line(line: "Line") -> GRPCLine: """Convert a ``Line`` to a line gRPC message. diff --git a/src/ansys/geometry/core/_grpc/_services/v0/faces.py b/src/ansys/geometry/core/_grpc/_services/v0/faces.py index aaab06f122..f51ea42635 100644 --- a/src/ansys/geometry/core/_grpc/_services/v0/faces.py +++ b/src/ansys/geometry/core/_grpc/_services/v0/faces.py @@ -35,6 +35,7 @@ from .conversions import ( build_grpc_id, from_grpc_curve_to_curve, + from_grpc_direction_to_unit_vector, from_grpc_point_to_point3d, from_grpc_surface_to_surface, from_line_to_grpc_line, @@ -212,8 +213,6 @@ def set_color(self, **kwargs) -> dict: # noqa: D102 def get_normal(self, **kwargs) -> dict: # noqa: D102 from ansys.api.geometry.v0.faces_pb2 import GetNormalRequest - from ansys.geometry.core.math.vector import UnitVector3D - # Create the request - assumes all inputs are valid and of the proper type request = GetNormalRequest( id=kwargs["id"], @@ -226,9 +225,7 @@ def get_normal(self, **kwargs) -> dict: # noqa: D102 # Return the response - formatted as a dictionary return { - "normal": UnitVector3D( - [response.direction.x, response.direction.y, response.direction.z] - ), + "normal": from_grpc_direction_to_unit_vector(response.direction), } @protect_grpc diff --git a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py index d169eb7a62..6ccbcc8703 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py @@ -24,10 +24,26 @@ from typing import TYPE_CHECKING from ansys.api.discovery.v1.commonenums_pb2 import BackendType as GRPCBackendType -from ansys.api.discovery.v1.commonmessages_pb2 import EntityIdentifier +from ansys.api.discovery.v1.commonmessages_pb2 import ( + Direction as GRPCDirection, + EntityIdentifier, + Line as GRPCLine, + Point as GRPCPoint, +) +from ansys.api.discovery.v1.design.designmessages_pb2 import ( + CurveGeometry as GRPCCurveGeometry, + Surface as GRPCSurface, + TrackedCommandResponse as GRPCTrackedCommandResponse, +) if TYPE_CHECKING: from ansys.geometry.core.connection.backend import BackendType + from ansys.geometry.core.designer.face import SurfaceType + from ansys.geometry.core.math.point import Point3D + from ansys.geometry.core.math.vector import UnitVector3D + from ansys.geometry.core.shapes.curves.curve import Curve + from ansys.geometry.core.shapes.curves.line import Line + from ansys.geometry.core.shapes.surfaces.surface import Surface def from_grpc_backend_type_to_backend_type( @@ -84,3 +100,266 @@ def build_grpc_id(id: str) -> EntityIdentifier: Geometry service gRPC entity identifier message. """ return EntityIdentifier(id=id) + + +def from_grpc_surface_to_surface(surface: GRPCSurface, surface_type: "SurfaceType") -> "Surface": + """Convert a gRPC v1 surface message to a ``Surface`` class. + + Parameters + ---------- + surface : GRPCSurface + Geometry service gRPC surface message. + + Returns + ------- + Surface + Resulting converted surface. + """ + from ansys.geometry.core.designer.face import SurfaceType + from ansys.geometry.core.math.vector import UnitVector3D + from ansys.geometry.core.shapes.surfaces.cone import Cone + from ansys.geometry.core.shapes.surfaces.cylinder import Cylinder + from ansys.geometry.core.shapes.surfaces.plane import PlaneSurface + from ansys.geometry.core.shapes.surfaces.sphere import Sphere + from ansys.geometry.core.shapes.surfaces.torus import Torus + + origin = from_grpc_point_to_point3d(surface.origin) + axis = UnitVector3D([surface.axis.x, surface.axis.y, surface.axis.z]) + reference = UnitVector3D([surface.reference.x, surface.reference.y, surface.reference.z]) + + if surface_type == SurfaceType.SURFACETYPE_CONE: + result = Cone(origin, surface.radius, surface.half_angle, reference, axis) + elif surface_type == SurfaceType.SURFACETYPE_CYLINDER: + result = Cylinder(origin, surface.radius, reference, axis) + elif surface_type == SurfaceType.SURFACETYPE_SPHERE: + result = Sphere(origin, surface.radius, reference, axis) + elif surface_type == SurfaceType.SURFACETYPE_TORUS: + result = Torus(origin, surface.major_radius, surface.minor_radius, reference, axis) + elif surface_type == SurfaceType.SURFACETYPE_PLANE: + result = PlaneSurface(origin, reference, axis) + else: + result = None + return result + + +def from_grpc_point_to_point3d(point: GRPCPoint) -> "Point3D": + """Convert a gRPC v1 point message class to a ``Point3D`` class. + + Parameters + ---------- + point : GRPCPoint + Source point data. + + Returns + ------- + Point3D + Converted point. + """ + from ansys.geometry.core.math.point import Point3D + from ansys.geometry.core.misc.measurements import DEFAULT_UNITS + + return Point3D( + [point.x, point.y, point.z], + DEFAULT_UNITS.SERVER_LENGTH, + ) + + +def from_grpc_curve_to_curve(curve: GRPCCurveGeometry) -> "Curve": + """Convert a gRPC v1 curve message to a ``Curve`` class. + + Parameters + ---------- + curve : GRPCCurveGeometry + Geometry service gRPC curve message. + + Returns + ------- + Curve + Resulting converted curve. + """ + from ansys.geometry.core.math.point import Point3D + from ansys.geometry.core.math.vector import UnitVector3D + from ansys.geometry.core.shapes.curves.circle import Circle + from ansys.geometry.core.shapes.curves.ellipse import Ellipse + from ansys.geometry.core.shapes.curves.line import Line + + origin = Point3D([curve.origin.x, curve.origin.y, curve.origin.z]) + try: + reference = UnitVector3D([curve.reference.x, curve.reference.y, curve.reference.z]) + axis = UnitVector3D([curve.axis.x, curve.axis.y, curve.axis.z]) + except ValueError: + # curve will be a line + pass + + result = None + if curve.radius != 0: + result = Circle(origin, curve.radius, reference, axis) + elif curve.major_radius != 0 and curve.minor_radius != 0: + result = Ellipse(origin, curve.major_radius, curve.minor_radius, reference, axis) + elif curve.direction is not None and ( + curve.direction.x != 0 or curve.direction.y != 0 or curve.direction.z != 0 + ): + result = Line( + origin, + UnitVector3D( + [ + curve.direction.x, + curve.direction.y, + curve.direction.z, + ] + ), + ) + # Note: NURBS curves not yet supported in v1 conversions + + return result + + +def from_unit_vector_to_grpc_direction(unit_vector: "UnitVector3D") -> GRPCDirection: + """Convert a ``UnitVector3D`` class to a gRPC v1 unit vector message. + + Parameters + ---------- + unit_vector : UnitVector3D + Source vector data. + + Returns + ------- + GRPCDirection + Geometry service gRPC direction message. + """ + return GRPCDirection(x=unit_vector.x, y=unit_vector.y, z=unit_vector.z) + + +def from_grpc_direction_to_unit_vector(direction: GRPCDirection) -> "UnitVector3D": + """Convert a gRPC v1 direction message to a ``UnitVector3D`` class. + + Parameters + ---------- + direction : GRPCDirection + Source direction data. + + Returns + ------- + UnitVector3D + Converted unit vector. + """ + from ansys.geometry.core.math.vector import UnitVector3D + + return UnitVector3D([direction.x, direction.y, direction.z]) + + +def from_point3d_to_grpc_point(point: "Point3D") -> GRPCPoint: + """Convert a ``Point3D`` class to a gRPC v1 point message. + + Parameters + ---------- + point : Point3D + Source point data. + + Returns + ------- + GRPCPoint + Geometry service gRPC point message. The unit is meters. + """ + from ansys.geometry.core.misc.measurements import DEFAULT_UNITS + + return GRPCPoint( + x=point.x.m_as(DEFAULT_UNITS.SERVER_LENGTH), + y=point.y.m_as(DEFAULT_UNITS.SERVER_LENGTH), + z=point.z.m_as(DEFAULT_UNITS.SERVER_LENGTH), + ) + + +def from_line_to_grpc_line(line: "Line") -> GRPCLine: + """Convert a ``Line`` to a gRPC v1 line message. + + Parameters + ---------- + line : Line + Line to convert. + + Returns + ------- + GRPCLine + Geometry service gRPC ``Line`` message. + """ + start = line.origin + end = line.origin + line.direction + return GRPCLine(start=from_point3d_to_grpc_point(start), end=from_point3d_to_grpc_point(end)) + + +def serialize_tracked_command_response(response: GRPCTrackedCommandResponse) -> dict: + """Serialize a GRPC v1 TrackedCommandResponse object into a dictionary. + + Parameters + ---------- + response : TrackedCommandResponse + The gRPC TrackedCommandResponse object to serialize. + + Returns + ------- + dict + A dictionary representation of the TrackedCommandResponse 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, + } + + + tracked_changes = response.tracked_changes + return { + "success": response.command_response.success, + "created_bodies": [ + serialize_body(body) for body in getattr(tracked_changes, "created_bodies", []) + ], + "modified_bodies": [ + serialize_body(body) for body in getattr(tracked_changes, "modified_bodies", []) + ], + "deleted_bodies": [ + serialize_entity_identifier(entity) + for entity in getattr(tracked_changes, "deleted_bodies", []) + ], + "created_faces": [ + serialize_entity_identifier(face_id) + for face_id in getattr(tracked_changes, "created_face_ids", []) + ], + "modified_faces": [ + serialize_entity_identifier(face_id) + for face_id in getattr(tracked_changes, "modified_face_ids", []) + ], + "deleted_faces": [ + serialize_entity_identifier(face_id) + for face_id in getattr(tracked_changes, "deleted_face_ids", []) + ], + "created_edges": [ + serialize_entity_identifier(edge_id) + for edge_id in getattr(tracked_changes, "created_edge_ids", []) + ], + "modified_edges": [ + serialize_entity_identifier(edge_id) + for edge_id in getattr(tracked_changes, "modified_edge_ids", []) + ], + "deleted_edges": [ + serialize_entity_identifier(edge_id) + for edge_id in getattr(tracked_changes, "deleted_edge_ids", []) + ], + } \ No newline at end of file diff --git a/src/ansys/geometry/core/_grpc/_services/v1/faces.py b/src/ansys/geometry/core/_grpc/_services/v1/faces.py index 611381aa6e..9b06ce451d 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/faces.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/faces.py @@ -21,11 +21,28 @@ # SOFTWARE. """Module containing the faces service implementation for v1.""" +from ansys.api.discovery.v1.commonmessages_pb2 import MultipleEntitiesRequest import grpc from ansys.geometry.core.errors import protect_grpc +from ..base.conversions import ( + from_measurement_to_server_angle, + from_measurement_to_server_length, + to_area, +) from ..base.faces import GRPCFacesService +from .conversions import ( + build_grpc_id, + from_grpc_curve_to_curve, + from_grpc_direction_to_unit_vector, + from_grpc_point_to_point3d, + from_grpc_surface_to_surface, + from_line_to_grpc_line, + from_point3d_to_grpc_point, + from_unit_vector_to_grpc_direction, + serialize_tracked_command_response, +) class GRPCFacesServiceV1(GRPCFacesService): # pragma: no cover @@ -43,102 +60,578 @@ class GRPCFacesServiceV1(GRPCFacesService): # pragma: no cover @protect_grpc def __init__(self, channel: grpc.Channel): # noqa: D102 - from ansys.api.geometry.v1.faces_pb2_grpc import FacesStub + from ansys.api.discovery.v1.design.geometry.face_pb2_grpc import FaceStub + from ansys.api.discovery.v1.operations.edit_pb2_grpc import EditStub - self.stub = FacesStub(channel) + self.stub = FaceStub(channel) + self.EditStub = EditStub(channel) @protect_grpc def get_surface(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetSurface(request=request) + + # Return the response - formatted as a dictionary + return { + "surface": from_grpc_surface_to_surface(response, kwargs["surface_type"]), + } @protect_grpc def get_box_uv(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetBoxUV(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "uv_box": { + "u": (response.start_u, response.end_u), + "v": (response.start_v, response.end_v), + } + } @protect_grpc def get_area(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetArea(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return {"area": to_area(response.area)} @protect_grpc def get_edges(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetEdges(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "edges": [ + { + "id": edge.id.id, + "curve_type": edge.curve_type, + "is_reversed": edge.is_reversed, + } + for edge in response.edges + ] + } @protect_grpc def get_vertices(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetVertices(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "vertices": [ + { + "id": vertex.id.id, + "position": from_grpc_point_to_point3d(vertex.position), + } + for vertex in response.vertices + ] + } @protect_grpc def get_loops(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ..base.conversions import to_distance + + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetLoops(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "loops": [ + { + "type": int(loop.type), + "length": to_distance(loop.length).value, + "min_corner": from_grpc_point_to_point3d(loop.bounding_box.min), + "max_corner": from_grpc_point_to_point3d(loop.bounding_box.max), + "edges": [edge for edge in loop.edges], + } + for loop in response.loops + ] + } @protect_grpc def get_color(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetColor(request=request) + + # Return the response - formatted as a dictionary + color = response.colors.get(kwargs["id"], "") + return {"color": color} @protect_grpc def get_bounding_box(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetBoundingBox(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "min_corner": from_grpc_point_to_point3d(response.box.min), + "max_corner": from_grpc_point_to_point3d(response.box.max), + "center": from_grpc_point_to_point3d(response.box.center), + } @protect_grpc def set_color(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.design.designmessages_pb2 import ( + SetColorRequest, + SetColorRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = SetColorRequest( + request_data=[ + SetColorRequestData( + id=build_grpc_id(kwargs["id"]), + color=kwargs["color"], + ) + ] + ) + # Call the gRPC service + response = self.stub.SetColor(request=request) + + # Return the response - formatted as a dictionary + return {"success": len(response.successfully_set_ids) == 1} @protect_grpc def get_normal(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.design.geometry.face_pb2 import ( + GetNormalRequest, + GetNormalRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = GetNormalRequest( + request_data=[ + GetNormalRequestData( + id=build_grpc_id(kwargs["id"]), + u=kwargs["u"], + v=kwargs["v"], + ) + ] + ) + + # Call the gRPC service + response = self.stub.GetNormal(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "normal": from_grpc_direction_to_unit_vector(response.direction), + } @protect_grpc def evaluate(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.design.geometry.face_pb2 import ( + EvaluateRequest, + EvaluateRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = EvaluateRequest( + request_data=[ + EvaluateRequestData( + id=build_grpc_id(kwargs["id"]), + u=kwargs["u"], + v=kwargs["v"], + ) + ] + ) + + # Call the gRPC service + response = self.stub.Evaluate(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "point": from_grpc_point_to_point3d(response.point), + } @protect_grpc def create_iso_parametric_curve(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.design.geometry.face_pb2 import ( + CreateIsoParamCurvesRequest, + CreateIsoParamCurvesRequestData, + ) + + from ansys.geometry.core.shapes.parameterization import Interval + + from ..base.conversions import to_distance + + # Create the request - assumes all inputs are valid and of the proper type + request = CreateIsoParamCurvesRequest( + request_data=[ + CreateIsoParamCurvesRequestData( + id=build_grpc_id(kwargs["id"]), + u_dir_curve=kwargs["use_u_param"], + proportion=kwargs["parameter"], + ) + ] + ) + + # Call the gRPC service + response = self.stub.CreateIsoParamCurves(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "curves": [ + { + "geometry": from_grpc_curve_to_curve(curve.curve), + "start": from_grpc_point_to_point3d(curve.start), + "end": from_grpc_point_to_point3d(curve.end), + "interval": Interval(curve.interval_start, curve.interval_end), + "length": to_distance(curve.length).value, + } + for curve in response.curves + ] + } @protect_grpc def extrude_faces(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.operations.edit_pb2 import ( + ExtrudeFacesRequest, + ExtrudeFacesRequestData, + ) + + # Assign direction + direction = ( + None + if kwargs["direction"] is None + else from_unit_vector_to_grpc_direction(kwargs["direction"]) + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = ExtrudeFacesRequest( + request_data=ExtrudeFacesRequestData( + faces=[build_grpc_id(id) for id in kwargs["face_ids"]], + distance=from_measurement_to_server_length(kwargs["distance"]), + direction=direction, + extrude_type=kwargs["extrude_type"].value, + pull_symmetric=kwargs["pull_symmetric"], + offset_mode=kwargs["offset_mode"].value, + copy=kwargs["copy"], + force_do_as_extrude=kwargs["force_do_as_extrude"], + ) + ) + + # Call the gRPC service and serialize the response + response = self.EditStub.ExtrudeFaces(request=request) + tracked_response = serialize_tracked_command_response(response) + + # Return the response - formatted as a dictionary + return { + "success": tracked_response.get("success"), + "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], + } @protect_grpc def extrude_faces_up_to(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.operations.edit_pb2 import ( + ExtrudeFacesUpToRequest, + ExtrudeFacesUpToRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = ExtrudeFacesUpToRequest( + request_data=ExtrudeFacesUpToRequestData( + faces=[build_grpc_id(id) for id in kwargs["face_ids"]], + up_to_selection=build_grpc_id(kwargs["up_to_selection_id"]), + seed_point=from_point3d_to_grpc_point(kwargs["seed_point"]), + direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), + extrude_type=kwargs["extrude_type"].value, + pull_symmetric=kwargs["pull_symmetric"], + offset_mode=kwargs["offset_mode"].value, + copy=kwargs["copy"], + force_do_as_extrude=kwargs["force_do_as_extrude"], + ) + ) + + # Call the gRPC service and serialize the response + response = self.EditStub.ExtrudeFacesUpTo(request=request) + tracked_response = serialize_tracked_command_response(response) + + # Return the response - formatted as a dictionary + return { + "success": tracked_response.get("success"), + "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], + } @protect_grpc def offset_faces_set_radius(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.operations.edit_pb2 import ( + OffsetFacesSetRadiusRequest, + OffsetFacesSetRadiusRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = OffsetFacesSetRadiusRequest( + request_data=OffsetFacesSetRadiusRequestData( + faces=[build_grpc_id(id) for id in kwargs["face_ids"]], + radius=from_measurement_to_server_length(kwargs["radius"]), + offset_mode=kwargs["offset_mode"].value, + copy=kwargs["copy"], + extrude_type=kwargs["extrude_type"].value, + ) + ) + + # Call the gRPC service + response = self.EditStub.OffsetFacesSetRadius(request=request) + + # Return the response - formatted as a dictionary + return { + "success": response.tracked_command_response.command_response.success, + } @protect_grpc def revolve_faces(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.operations.edit_pb2 import ( + RevolveFacesRequest, + RevolveFacesRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = RevolveFacesRequest( + request_data=[ + RevolveFacesRequestData( + selection_id=[build_grpc_id(id) for id in kwargs["selection_ids"]], + axis=from_line_to_grpc_line(kwargs["axis"]), + angle=from_measurement_to_server_angle(kwargs["angle"]), + extrude_type=kwargs["extrude_type"].value, + ) + ] + ) + + # Call the gRPC service and serialize the response + response = self.EditStub.RevolveFaces(request=request) + tracked_response = serialize_tracked_command_response(response) + + # Return the response - formatted as a dictionary + return { + "success": tracked_response.get("success"), + "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], + } @protect_grpc def revolve_faces_up_to(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.operations.edit_pb2 import ( + RevolveFacesUpToRequest, + RevolveFacesUpToRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = RevolveFacesUpToRequest( + request_data=[ + RevolveFacesUpToRequestData( + selection_ids=[build_grpc_id(id) for id in kwargs["selection_ids"]], + up_to_selection_id=build_grpc_id(kwargs["up_to_selection_id"]), + direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), + axis=from_line_to_grpc_line(kwargs["axis"]), + extrude_type=kwargs["extrude_type"].value, + ) + ] + ) + + # Call the gRPC service and serialize the response + response = self.EditStub.RevolveFacesUpTo(request=request) + tracked_response = serialize_tracked_command_response(response) + + # Return the response - formatted as a dictionary + return { + "success": tracked_response.get("success"), + "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], + } @protect_grpc def revolve_faces_by_helix(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.operations.edit_pb2 import ( + RevolveFacesByHelixRequest, + RevolveFacesByHelixRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = RevolveFacesByHelixRequest( + request_data=[ + RevolveFacesByHelixRequestData( + selection_ids=[build_grpc_id(id) for id in kwargs["selection_ids"]], + direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), + axis=from_line_to_grpc_line(kwargs["axis"]), + height=from_measurement_to_server_length(kwargs["height"]), + pitch=from_measurement_to_server_length(kwargs["pitch"]), + taper_angle=from_measurement_to_server_angle(kwargs["taper_angle"]), + right_handed=kwargs["right_handed"], + both_sides=kwargs["both_sides"], + extrude_type=kwargs["extrude_type"].value, + ) + ] + ) + + # Call the gRPC service and serialize the response + response = self.EditStub.RevolveFacesByHelix(request=request) + tracked_response = serialize_tracked_command_response(response) + + # Return the response - formatted as a dictionary + return { + "success": tracked_response.get("success"), + "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], + } @protect_grpc def replace_faces(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.design.geometry.face_pb2 import ReplaceFaceRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = ReplaceFaceRequest( + target_selection_ids=[build_grpc_id(id) for id in kwargs["target_ids"]], + replacement_selection_ids=[build_grpc_id(id) for id in kwargs["replacement_ids"]], + ) + + # Call the gRPC service + response = self.stub.Replace(request=request) + + # Return the response - formatted as a dictionary + return { + "success": response.tracked_command_response.command_response.success, + } @protect_grpc def thicken_faces(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.operations.edit_pb2 import ( + ThickenFacesRequest, + ThickenFacesRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = ThickenFacesRequest( + request_data=ThickenFacesRequestData( + faces=[build_grpc_id(id) for id in kwargs["face_ids"]], + direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), + value=from_measurement_to_server_length(kwargs["thickness"]), + extrude_type=kwargs["extrude_type"].value, + pull_symmetric=kwargs["pull_symmetric"], + select_direction=kwargs["select_direction"], + ) + ) + + # Call the gRPC service + response = self.EditStub.ThickenFaces(request=request) + + # Return the response - formatted as a dictionary + return { + "success": response.tracked_command_response.command_response.success, + } @protect_grpc def draft_faces(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.operations.edit_pb2 import ( + DraftFacesRequest, + DraftFacesRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = DraftFacesRequest( + request_data=DraftFacesRequestData( + faces=[build_grpc_id(id) for id in kwargs["face_ids"]], + reference_faces=[build_grpc_id(id) for id in kwargs["reference_face_ids"]], + draft_side=kwargs["draft_side"].value, + draft_angle=from_measurement_to_server_angle(kwargs["angle"]), + extrude_type=kwargs["extrude_type"].value, + ) + ) + + # Call the gRPC server + response = self.EditStub.DraftFaces(request=request) + + # Return the drafted faces + return { + "created_faces": [face.id for face in response.created_faces], + } @protect_grpc def get_round_info(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["face_id"])]) + + # Call the gRPC service + response = self.stub.GetRoundInfo(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "along_u": response.along_u, + "radius": response.radius, + } @protect_grpc def offset_faces(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.operations.edit_pb2 import ( + OffsetFacesRequest, + OffsetFacesRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = OffsetFacesRequest( + request_data=[ + OffsetFacesRequestData( + faces=[build_grpc_id(id) for id in kwargs["face_ids"]], + offset=from_measurement_to_server_length(kwargs["distance"]), + direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), + extrude_type=kwargs["extrude_type"].value, + ) + ] + ) + + # Call the gRPC service and serialize the response + response = self.EditStub.OffsetFaces(request=request) + tracked_response = serialize_tracked_command_response(response) + + # Return the response - formatted as a dictionary + return { + "results": [face.get("id") for face in tracked_response.get("created_faces")], + } @protect_grpc def setup_offset_relationship(self, **kwargs) -> dict: # noqa: D102 - raise NotImplementedError + from ansys.api.discovery.v1.operations.edit_pb2 import ( + FaceOffsetRequest, + FaceOffsetRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = FaceOffsetRequest( + request_data=FaceOffsetRequestData( + face1=build_grpc_id(kwargs["face1_id"]), + face2=build_grpc_id(kwargs["face2_id"]), + set_baselines=kwargs["set_baselines"], + process_adjacent_faces=kwargs["process_adjacent_faces"], + ) + ) + + # Call the gRPC service + response = self.EditStub.FaceOffset(request=request) + + # Return the response - formatted as a dictionary + return { + "success": response.tracked_command_response.command_response.success, + } From 2a3fe73973f225f8dea4d8f1ecb9a8bfa335597a Mon Sep 17 00:00:00 2001 From: Jacob Kerstetter Date: Mon, 24 Nov 2025 11:07:41 -0500 Subject: [PATCH 02/10] added quantity conversion and fixed a few faces bugs --- .../core/_grpc/_services/v1/conversions.py | 73 ++++++++- .../geometry/core/_grpc/_services/v1/faces.py | 145 ++++++++++-------- 2 files changed, 148 insertions(+), 70 deletions(-) diff --git a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py index fa81a6c545..41089e4b42 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py @@ -35,6 +35,7 @@ Plane as GRPCPlane, Point as GRPCPoint, Polygon as GRPCPolygon, + Quantity as GRPCQuantity, ) from ansys.api.discovery.v1.design.designmessages_pb2 import ( CurveGeometry as GRPCCurveGeometry, @@ -50,6 +51,7 @@ Surface as GRPCSurface, Tessellation as GRPCTessellation, TessellationOptions as GRPCTessellationOptions, + TrackedCommandResponse as GRPCTrackedCommandResponse, TrimmedCurve as GRPCTrimmedCurve, TrimmedSurface as GRPCTrimmedSurface, ) @@ -66,6 +68,7 @@ from ansys.geometry.core.errors import GeometryRuntimeError from ansys.geometry.core.misc.checks import graphics_required +from ansys.geometry.core.misc.measurements import DEFAULT_UNITS from ansys.geometry.core.shapes.surfaces.nurbs import NURBSSurface if TYPE_CHECKING: @@ -81,6 +84,7 @@ from ansys.geometry.core.math.plane import Plane from ansys.geometry.core.math.point import Point2D, Point3D from ansys.geometry.core.math.vector import UnitVector3D + from ansys.geometry.core.misc.measurements import Measurement from ansys.geometry.core.misc.options import TessellationOptions from ansys.geometry.core.parameters.parameter import ( Parameter, @@ -198,7 +202,11 @@ def from_grpc_point_to_point3d(point: GRPCPoint) -> "Point3D": from ansys.geometry.core.misc.measurements import DEFAULT_UNITS return Point3D( - [point.x, point.y, point.z], + [ + point.x.value_in_geometry_units, + point.y.value_in_geometry_units, + point.z.value_in_geometry_units, + ], DEFAULT_UNITS.SERVER_LENGTH, ) @@ -1284,6 +1292,56 @@ def from_grpc_matrix_to_matrix(matrix: GRPCMatrix) -> "Matrix44": ) +def from_grpc_direction_to_unit_vector(direction: GRPCDirection) -> "UnitVector3D": + """Convert a gRPC direction to a unit vector. + + Parameters + ---------- + direction : GRPCDirection + Source gRPC direction data. + + Returns + ------- + UnitVector3D + Converted unit vector. + """ + from ansys.geometry.core.math.vector import UnitVector3D + + return UnitVector3D([direction.x, direction.y, direction.z]) + + +def from_length_to_grpc_quantity(input: "Measurement") -> GRPCQuantity: + """Convert a ``Measurement`` containing a length to a gRPC quantity. + + Parameters + ---------- + input : Measurement + Source measurement data. + + Returns + ------- + GRPCQuantity + Converted gRPC quantity. + """ + return GRPCQuantity(value_in_geometry_units=input.value.m_as(DEFAULT_UNITS.SERVER_LENGTH)) + + +def from_angle_to_grpc_quantity(input: "Measurement") -> GRPCQuantity: + """Convert a ``Measurement`` containing an angle to a gRPC quantity. + + Parameters + ---------- + input : Measurement + Source measurement data. + + Returns + ------- + GRPCQuantity + Converted gRPC quantity. + """ + return GRPCQuantity(value_in_geometry_units=input.value.m_as(DEFAULT_UNITS.SERVER_ANGLE)) + + def _nurbs_curves_compatibility(backend_version: "semver.Version", grpc_geometries: GRPCGeometries): """Check if the backend version is compatible with NURBS curves in sketches. @@ -1351,18 +1409,18 @@ def from_enclosure_options_to_grpc_enclosure_options( ) -def serialize_tracker_command_response(**kwargs) -> dict: - """Serialize a TrackerCommandResponse object into a dictionary. +def serialize_tracked_command_response(response: GRPCTrackedCommandResponse) -> dict: + """Serialize a TrackedCommandResponse object into a dictionary. Parameters ---------- - response : TrackerCommandResponse - The gRPC TrackerCommandResponse object to serialize. + response : GRPCTrackedCommandResponse + The gRPC TrackedCommandResponse object to serialize. Returns ------- dict - A dictionary representation of the TrackerCommandResponse object. + A dictionary representation of the TrackedCommandResponse object. """ def serialize_body(body): @@ -1387,9 +1445,8 @@ def serialize_entity_identifier(entity): "id": entity.id, } - response = kwargs["response"] return { - "success": response.success, + "success": getattr(response, "success", False), "created_bodies": [ serialize_body(body) for body in getattr(response, "created_bodies", []) ], diff --git a/src/ansys/geometry/core/_grpc/_services/v1/faces.py b/src/ansys/geometry/core/_grpc/_services/v1/faces.py index 9b06ce451d..e2fb294ec9 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/faces.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/faces.py @@ -34,10 +34,12 @@ from ..base.faces import GRPCFacesService from .conversions import ( build_grpc_id, + from_angle_to_grpc_quantity, from_grpc_curve_to_curve, from_grpc_direction_to_unit_vector, from_grpc_point_to_point3d, from_grpc_surface_to_surface, + from_length_to_grpc_quantity, from_line_to_grpc_line, from_point3d_to_grpc_point, from_unit_vector_to_grpc_direction, @@ -72,11 +74,11 @@ def get_surface(self, **kwargs) -> dict: # noqa: D102 request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) # Call the gRPC service - response = self.stub.GetSurface(request=request) + response = self.stub.GetSurface(request=request).response_data[0] # Return the response - formatted as a dictionary return { - "surface": from_grpc_surface_to_surface(response, kwargs["surface_type"]), + "surface": from_grpc_surface_to_surface(response.surface, kwargs["surface_type"]), } @protect_grpc @@ -90,8 +92,14 @@ def get_box_uv(self, **kwargs) -> dict: # noqa: D102 # Return the response - formatted as a dictionary return { "uv_box": { - "u": (response.start_u, response.end_u), - "v": (response.start_v, response.end_v), + "u": ( + response.start_u.value_in_geometry_units, + response.end_u.value_in_geometry_units, + ), + "v": ( + response.start_v.value_in_geometry_units, + response.end_v.value_in_geometry_units, + ), } } @@ -104,7 +112,7 @@ def get_area(self, **kwargs) -> dict: # noqa: D102 response = self.stub.GetArea(request=request).response_data[0] # Return the response - formatted as a dictionary - return {"area": to_area(response.area)} + return {"area": to_area(response.area.value_in_geometry_units)} @protect_grpc def get_edges(self, **kwargs) -> dict: # noqa: D102 @@ -159,8 +167,8 @@ def get_loops(self, **kwargs) -> dict: # noqa: D102 return { "loops": [ { - "type": int(loop.type), - "length": to_distance(loop.length).value, + "type": loop.type, + "length": to_distance(loop.length.value_in_geometry_units).value, "min_corner": from_grpc_point_to_point3d(loop.bounding_box.min), "max_corner": from_grpc_point_to_point3d(loop.bounding_box.max), "edges": [edge for edge in loop.edges], @@ -325,21 +333,23 @@ def extrude_faces(self, **kwargs) -> dict: # noqa: D102 # Create the request - assumes all inputs are valid and of the proper type request = ExtrudeFacesRequest( - request_data=ExtrudeFacesRequestData( - faces=[build_grpc_id(id) for id in kwargs["face_ids"]], - distance=from_measurement_to_server_length(kwargs["distance"]), - direction=direction, - extrude_type=kwargs["extrude_type"].value, - pull_symmetric=kwargs["pull_symmetric"], - offset_mode=kwargs["offset_mode"].value, - copy=kwargs["copy"], - force_do_as_extrude=kwargs["force_do_as_extrude"], - ) + request_data=[ + ExtrudeFacesRequestData( + ids=[build_grpc_id(id) for id in kwargs["face_ids"]], + distance=from_length_to_grpc_quantity(kwargs["distance"]), + direction=direction, + extrude_type=kwargs["extrude_type"].value, + pull_symmetric=kwargs["pull_symmetric"], + offset_mode=kwargs["offset_mode"].value, + copy=kwargs["copy"], + force_do_as_extrude=kwargs["force_do_as_extrude"], + ) + ] ) # Call the gRPC service and serialize the response response = self.EditStub.ExtrudeFaces(request=request) - tracked_response = serialize_tracked_command_response(response) + tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary return { @@ -356,22 +366,24 @@ def extrude_faces_up_to(self, **kwargs) -> dict: # noqa: D102 # Create the request - assumes all inputs are valid and of the proper type request = ExtrudeFacesUpToRequest( - request_data=ExtrudeFacesUpToRequestData( - faces=[build_grpc_id(id) for id in kwargs["face_ids"]], - up_to_selection=build_grpc_id(kwargs["up_to_selection_id"]), - seed_point=from_point3d_to_grpc_point(kwargs["seed_point"]), - direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), - extrude_type=kwargs["extrude_type"].value, - pull_symmetric=kwargs["pull_symmetric"], - offset_mode=kwargs["offset_mode"].value, - copy=kwargs["copy"], - force_do_as_extrude=kwargs["force_do_as_extrude"], - ) + request_data=[ + ExtrudeFacesUpToRequestData( + faces=[build_grpc_id(id) for id in kwargs["face_ids"]], + up_to_selection=build_grpc_id(kwargs["up_to_selection_id"]), + seed_point=from_point3d_to_grpc_point(kwargs["seed_point"]), + direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), + extrude_type=kwargs["extrude_type"].value, + pull_symmetric=kwargs["pull_symmetric"], + offset_mode=kwargs["offset_mode"].value, + copy=kwargs["copy"], + force_do_as_extrude=kwargs["force_do_as_extrude"], + ) + ] ) # Call the gRPC service and serialize the response response = self.EditStub.ExtrudeFacesUpTo(request=request) - tracked_response = serialize_tracked_command_response(response) + tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary return { @@ -387,14 +399,17 @@ def offset_faces_set_radius(self, **kwargs) -> dict: # noqa: D102 ) # Create the request - assumes all inputs are valid and of the proper type + # TODO: multiple faces? request = OffsetFacesSetRadiusRequest( - request_data=OffsetFacesSetRadiusRequestData( - faces=[build_grpc_id(id) for id in kwargs["face_ids"]], - radius=from_measurement_to_server_length(kwargs["radius"]), - offset_mode=kwargs["offset_mode"].value, - copy=kwargs["copy"], - extrude_type=kwargs["extrude_type"].value, - ) + request_data=[ + OffsetFacesSetRadiusRequestData( + id=[build_grpc_id(id) for id in kwargs["face_ids"]], + radius=from_measurement_to_server_length(kwargs["radius"]), + offset_mode=kwargs["offset_mode"].value, + copy=kwargs["copy"], + extrude_type=kwargs["extrude_type"].value, + ) + ] ) # Call the gRPC service @@ -426,7 +441,7 @@ def revolve_faces(self, **kwargs) -> dict: # noqa: D102 # Call the gRPC service and serialize the response response = self.EditStub.RevolveFaces(request=request) - tracked_response = serialize_tracked_command_response(response) + tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary return { @@ -456,7 +471,7 @@ def revolve_faces_up_to(self, **kwargs) -> dict: # noqa: D102 # Call the gRPC service and serialize the response response = self.EditStub.RevolveFacesUpTo(request=request) - tracked_response = serialize_tracked_command_response(response) + tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary return { @@ -490,7 +505,7 @@ def revolve_faces_by_helix(self, **kwargs) -> dict: # noqa: D102 # Call the gRPC service and serialize the response response = self.EditStub.RevolveFacesByHelix(request=request) - tracked_response = serialize_tracked_command_response(response) + tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary return { @@ -525,14 +540,16 @@ def thicken_faces(self, **kwargs) -> dict: # noqa: D102 # Create the request - assumes all inputs are valid and of the proper type request = ThickenFacesRequest( - request_data=ThickenFacesRequestData( - faces=[build_grpc_id(id) for id in kwargs["face_ids"]], - direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), - value=from_measurement_to_server_length(kwargs["thickness"]), - extrude_type=kwargs["extrude_type"].value, - pull_symmetric=kwargs["pull_symmetric"], - select_direction=kwargs["select_direction"], - ) + request_data=[ + ThickenFacesRequestData( + ids=[build_grpc_id(id) for id in kwargs["face_ids"]], + direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), + value=from_length_to_grpc_quantity(kwargs["thickness"]), + extrude_type=kwargs["extrude_type"].value, + pull_symmetric=kwargs["pull_symmetric"], + select_direction=kwargs["select_direction"], + ) + ] ) # Call the gRPC service @@ -552,13 +569,15 @@ def draft_faces(self, **kwargs) -> dict: # noqa: D102 # Create the request - assumes all inputs are valid and of the proper type request = DraftFacesRequest( - request_data=DraftFacesRequestData( - faces=[build_grpc_id(id) for id in kwargs["face_ids"]], - reference_faces=[build_grpc_id(id) for id in kwargs["reference_face_ids"]], - draft_side=kwargs["draft_side"].value, - draft_angle=from_measurement_to_server_angle(kwargs["angle"]), - extrude_type=kwargs["extrude_type"].value, - ) + request_data=[ + DraftFacesRequestData( + ids=[build_grpc_id(id) for id in kwargs["face_ids"]], + reference_ids=[build_grpc_id(id) for id in kwargs["reference_face_ids"]], + draft_side=kwargs["draft_side"].value, + draft_angle=from_angle_to_grpc_quantity(kwargs["angle"]), + extrude_type=kwargs["extrude_type"].value, + ) + ] ) # Call the gRPC server @@ -604,7 +623,7 @@ def offset_faces(self, **kwargs) -> dict: # noqa: D102 # Call the gRPC service and serialize the response response = self.EditStub.OffsetFaces(request=request) - tracked_response = serialize_tracked_command_response(response) + tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary return { @@ -620,12 +639,14 @@ def setup_offset_relationship(self, **kwargs) -> dict: # noqa: D102 # Create the request - assumes all inputs are valid and of the proper type request = FaceOffsetRequest( - request_data=FaceOffsetRequestData( - face1=build_grpc_id(kwargs["face1_id"]), - face2=build_grpc_id(kwargs["face2_id"]), - set_baselines=kwargs["set_baselines"], - process_adjacent_faces=kwargs["process_adjacent_faces"], - ) + request_data=[ + FaceOffsetRequestData( + face1=build_grpc_id(kwargs["face1_id"]), + face2=build_grpc_id(kwargs["face2_id"]), + set_baselines=kwargs["set_baselines"], + process_adjacent_faces=kwargs["process_adjacent_faces"], + ) + ] ) # Call the gRPC service From 6ee5a1d3d4bb3cfa34312fe4b3d751f0f6923234 Mon Sep 17 00:00:00 2001 From: Jacob Kerstetter Date: Mon, 24 Nov 2025 14:02:30 -0500 Subject: [PATCH 03/10] wip --- .../geometry/core/_grpc/_services/v1/edges.py | 155 ++++++++++++++++-- 1 file changed, 144 insertions(+), 11 deletions(-) diff --git a/src/ansys/geometry/core/_grpc/_services/v1/edges.py b/src/ansys/geometry/core/_grpc/_services/v1/edges.py index 507ac6c449..d29dd39c70 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/edges.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/edges.py @@ -21,11 +21,21 @@ # SOFTWARE. """Module containing the edges service implementation for v1.""" +from ansys.api.discovery.v1.commonmessages_pb2 import MultipleEntitiesRequest import grpc from ansys.geometry.core.errors import protect_grpc +from ..base.conversions import to_distance from ..base.edges import GRPCEdgesService +from .conversions import ( + build_grpc_id, + from_grpc_curve_to_curve, + from_grpc_point_to_point3d, + from_length_to_grpc_quantity, + from_point3d_to_grpc_point, + from_unit_vector_to_grpc_direction, +) class GRPCEdgesServiceV1(GRPCEdgesService): # pragma: no cover @@ -43,45 +53,168 @@ class GRPCEdgesServiceV1(GRPCEdgesService): # pragma: no cover @protect_grpc def __init__(self, channel: grpc.Channel): # noqa: D102 - from ansys.api.geometry.v1.edges_pb2_grpc import EdgesStub + from ansys.api.discovery.v1.design.geometry.edge_pb2_grpc import EdgeStub + from ansys.api.discovery.v1.operations.edit_pb2_grpc import EditStub - self.stub = EdgesStub(channel) + self.stub = EdgeStub(channel) + self.EditStub = EditStub(channel) @protect_grpc def get_edge(self, **kwargs) -> dict: # noqa: D102 - return NotImplementedError + from ansys.api.discovery.v1.commonmessages_pb2 import EntityRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = EntityRequest(id=build_grpc_id(kwargs["id"])) + + # Call the gRPC service + response = self.stub.Get(request=request) + + # Return the response - formatted as a dictionary + return { + "id": response.edge.id, + "curve_type": response.edge.curve_type, + "is_reversed": response.edge.is_reversed, + } @protect_grpc def get_curve(self, **kwargs) -> dict: # noqa: D102 - return NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetCurve(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "curve": from_grpc_curve_to_curve(response.curve), + } @protect_grpc def get_start_and_end_points(self, **kwargs) -> dict: # noqa: D102 - return NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetStartAndEndPoints(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "start": from_grpc_point_to_point3d(response.start), + "end": from_grpc_point_to_point3d(response.end), + } @protect_grpc def get_length(self, **kwargs) -> dict: # noqa: D102 - return NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetLength(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "length": to_distance(response.length.value_in_geometry_units), + } @protect_grpc def get_interval(self, **kwargs) -> dict: # noqa: D102 - return NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetInterval(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "start": response.start, + "end": response.end, + } @protect_grpc def get_faces(self, **kwargs) -> dict: # noqa: D102 - return NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetFaces(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "faces": [ + { + "id": face.id, + "surface_type": face.surface_type, + "is_reversed": face.is_reversed, + } + for face in response.faces + ], + } @protect_grpc def get_vertices(self, **kwargs) -> dict: # noqa: D102 - return NotImplementedError + # Create the request - assumes all inputs are valid and of proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetVertices(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "vertices": [ + { + "id": vertex.id.id, + "position": from_grpc_point_to_point3d(vertex.position), + } + for vertex in response.vertices + ], + } @protect_grpc def get_bounding_box(self, **kwargs) -> dict: # noqa: D102 - return NotImplementedError + # Create the request - assumes all inputs are valid and of the proper type + request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) + + # Call the gRPC service + response = self.stub.GetBoundingBox(request=request).response_data[0] + + # Return the response - formatted as a dictionary + return { + "min_corner": from_grpc_point_to_point3d(response.box.min), + "max_corner": from_grpc_point_to_point3d(response.box.max), + "center": from_grpc_point_to_point3d(response.box.center), + } @protect_grpc def extrude_edges(self, **kwargs) -> dict: # noqa: D102 - return NotImplementedError + from ansys.api.geometry.v0.commands_pb2 import ExtrudeEdgesRequest + + # Parse some optional arguments + point = from_point3d_to_grpc_point(kwargs["point"]) if kwargs["point"] else None + direction = ( + from_unit_vector_to_grpc_direction(kwargs["direction"]) if kwargs["direction"] else None + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = ExtrudeEdgesRequest( + edges=[build_grpc_id(edge_id) for edge_id in kwargs["edge_ids"]], + distance=from_length_to_grpc_quantity(kwargs["distance"]), + face=build_grpc_id(kwargs["face"]), + point=point, + direction=direction, + extrude_type=kwargs["extrude_type"].value, + pull_symmetric=kwargs["pull_symmetric"], + copy=kwargs["copy"], + natural_extension=kwargs["natural_extension"], + ) + + # Call the gRPC service + resp = self.EditStub.ExtrudeEdges(request) + + # Return the response - formatted as a dictionary + return { + "created_bodies": [body.id for body in resp.created_bodies], + "success": resp.success, + } @protect_grpc def extrude_edges_up_to(self, **kwargs) -> dict: # noqa: D102 From 2e1887dfb16b2253acf58dd924e0d56d16e10652 Mon Sep 17 00:00:00 2001 From: Jacob Kerstetter Date: Mon, 24 Nov 2025 15:56:10 -0500 Subject: [PATCH 04/10] faces/edges wip - failing some tests --- .../geometry/core/_grpc/_services/_service.py | 36 +++--- .../core/_grpc/_services/v1/conversions.py | 2 +- .../geometry/core/_grpc/_services/v1/edges.py | 112 +++++++++++++++--- .../geometry/core/_grpc/_services/v1/faces.py | 6 +- 4 files changed, 118 insertions(+), 38 deletions(-) diff --git a/src/ansys/geometry/core/_grpc/_services/_service.py b/src/ansys/geometry/core/_grpc/_services/_service.py index 73f237de29..caced54adb 100644 --- a/src/ansys/geometry/core/_grpc/_services/_service.py +++ b/src/ansys/geometry/core/_grpc/_services/_service.py @@ -410,15 +410,16 @@ def edges(self) -> GRPCEdgesService: # Import the appropriate edges service based on the version from .v0.edges import GRPCEdgesServiceV0 from .v1.edges import GRPCEdgesServiceV1 + self._edges = GRPCEdgesServiceV1(self.channel) - if self.version == GeometryApiProtos.V0: - self._edges = GRPCEdgesServiceV0(self.channel) - elif self.version == GeometryApiProtos.V1: # pragma: no cover - # V1 is not implemented yet - self._edges = GRPCEdgesServiceV1(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}") + # if self.version == GeometryApiProtos.V0: + # self._edges = GRPCEdgesServiceV0(self.channel) + # elif self.version == GeometryApiProtos.V1: # pragma: no cover + # # V1 is not implemented yet + # self._edges = GRPCEdgesServiceV1(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._edges @@ -436,15 +437,16 @@ def faces(self) -> GRPCFacesService: # Import the appropriate faces service based on the version from .v0.faces import GRPCFacesServiceV0 from .v1.faces import GRPCFacesServiceV1 - - if self.version == GeometryApiProtos.V0: - self._faces = GRPCFacesServiceV0(self.channel) - elif self.version == GeometryApiProtos.V1: # pragma: no cover - # V1 is not implemented yet - self._faces = GRPCFacesServiceV1(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}") + self._faces = GRPCFacesServiceV1(self.channel) + + # if self.version == GeometryApiProtos.V0: + # self._faces = GRPCFacesServiceV0(self.channel) + # elif self.version == GeometryApiProtos.V1: # pragma: no cover + # # V1 is not implemented yet + # self._faces = GRPCFacesServiceV1(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._faces diff --git a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py index 41089e4b42..e9bbecf735 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py @@ -993,7 +993,7 @@ def from_grpc_curve_to_curve(curve: GRPCCurveGeometry) -> "Curve": from ansys.geometry.core.shapes.curves.ellipse import Ellipse from ansys.geometry.core.shapes.curves.line import Line - origin = Point3D([curve.origin.x, curve.origin.y, curve.origin.z]) + origin = from_grpc_point_to_point3d(curve.origin) try: reference = UnitVector3D([curve.reference.x, curve.reference.y, curve.reference.z]) axis = UnitVector3D([curve.axis.x, curve.axis.y, curve.axis.z]) diff --git a/src/ansys/geometry/core/_grpc/_services/v1/edges.py b/src/ansys/geometry/core/_grpc/_services/v1/edges.py index d29dd39c70..c1de80e36d 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/edges.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/edges.py @@ -35,6 +35,7 @@ from_length_to_grpc_quantity, from_point3d_to_grpc_point, from_unit_vector_to_grpc_direction, + serialize_tracked_command_response, ) @@ -186,7 +187,10 @@ def get_bounding_box(self, **kwargs) -> dict: # noqa: D102 @protect_grpc def extrude_edges(self, **kwargs) -> dict: # noqa: D102 - from ansys.api.geometry.v0.commands_pb2 import ExtrudeEdgesRequest + from ansys.api.discovery.v1.operations.edit_pb2 import ( + ExtrudeEdgesRequest, + ExtrudeEdgesRequestData, + ) # Parse some optional arguments point = from_point3d_to_grpc_point(kwargs["point"]) if kwargs["point"] else None @@ -196,34 +200,108 @@ def extrude_edges(self, **kwargs) -> dict: # noqa: D102 # Create the request - assumes all inputs are valid and of the proper type request = ExtrudeEdgesRequest( - edges=[build_grpc_id(edge_id) for edge_id in kwargs["edge_ids"]], - distance=from_length_to_grpc_quantity(kwargs["distance"]), - face=build_grpc_id(kwargs["face"]), - point=point, - direction=direction, - extrude_type=kwargs["extrude_type"].value, - pull_symmetric=kwargs["pull_symmetric"], - copy=kwargs["copy"], - natural_extension=kwargs["natural_extension"], + request_data=[ + ExtrudeEdgesRequestData( + edge_ids=[build_grpc_id(edge_id) for edge_id in kwargs["edge_ids"]], + face_id=build_grpc_id(kwargs["face"]), + point=point, + direction=direction, + distance=from_length_to_grpc_quantity(kwargs["distance"]), + extrude_type=kwargs["extrude_type"].value, + pull_symmetric=kwargs["pull_symmetric"], + copy=kwargs["copy"], + natural_extension=kwargs["natural_extension"], + ) + ] ) - # Call the gRPC service - resp = self.EditStub.ExtrudeEdges(request) + # Call the gRPC service and serialize the response + response = self.EditStub.ExtrudeEdges(request) + tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary return { - "created_bodies": [body.id for body in resp.created_bodies], - "success": resp.success, + "success": tracked_response.get("success"), + "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], } @protect_grpc def extrude_edges_up_to(self, **kwargs) -> dict: # noqa: D102 - return NotImplementedError + from ansys.api.discovery.v1.operations.edit_pb2 import ( + ExtrudeEdgesUpToRequest, + ExtrudeEdgesUpToRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = ExtrudeEdgesUpToRequest( + request_data=[ + ExtrudeEdgesUpToRequestData( + edge_ids=[build_grpc_id(id) for id in kwargs["face_ids"]], + up_to_selection_id=build_grpc_id(kwargs["up_to_selection_id"]), + seed_point=from_point3d_to_grpc_point(kwargs["seed_point"]), + direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), + extrude_type=kwargs["extrude_type"].value, + ) + ] + ) + + # Call the gRPC service and serialize the response + response = self.EditStub.ExtrudeFacesUpTo(request=request) + tracked_response = serialize_tracked_command_response(response.tracked_command_response) + + # Return the response - formatted as a dictionary + return { + "success": tracked_response.get("success"), + "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], + } @protect_grpc def move_imprint_edges(self, **kwargs) -> dict: # noqa: D102 - return NotImplementedError + from ansys.api.discovery.v1.operations.edit_pb2 import ( + MoveImprintEdgesRequest, + MoveImprintEdgesRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = MoveImprintEdgesRequest( + request_data=[ + MoveImprintEdgesRequestData( + edge_ids=[build_grpc_id(edge_id) for edge_id in kwargs["edge_ids"]], + direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), + distance=from_length_to_grpc_quantity(kwargs["distance"]), + ) + ] + ) + + # Call the gRPC service + response = self.EditStub.MoveImprintEdges(request) + + # Return the response - formatted as a dictionary + return { + "success": response.tracked_command_response.command_response.success, + } @protect_grpc def offset_edges(self, **kwargs) -> dict: # noqa: D102 - return NotImplementedError + from ansys.api.discovery.v1.operations.edit_pb2 import ( + OffsetEdgesRequest, + OffsetEdgesRequestData, + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = OffsetEdgesRequest( + request_data=[ + OffsetEdgesRequestData( + edge_ids=[build_grpc_id(edge_id) for edge_id in kwargs["edge_ids"]], + value=from_length_to_grpc_quantity(kwargs["offset"]), + ) + ] + ) + + # Call the gRPC service + response = self.EditStub.OffsetEdges(request) + + # Return the response - formatted as a dictionary + return { + "success": response.tracked_command_response.command_response.success, + } diff --git a/src/ansys/geometry/core/_grpc/_services/v1/faces.py b/src/ansys/geometry/core/_grpc/_services/v1/faces.py index e2fb294ec9..6b5fe7d2ea 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/faces.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/faces.py @@ -368,15 +368,15 @@ def extrude_faces_up_to(self, **kwargs) -> dict: # noqa: D102 request = ExtrudeFacesUpToRequest( request_data=[ ExtrudeFacesUpToRequestData( - faces=[build_grpc_id(id) for id in kwargs["face_ids"]], - up_to_selection=build_grpc_id(kwargs["up_to_selection_id"]), - seed_point=from_point3d_to_grpc_point(kwargs["seed_point"]), + ids=[build_grpc_id(id) for id in kwargs["face_ids"]], + up_to_selection_id=build_grpc_id(kwargs["up_to_selection_id"]), direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), extrude_type=kwargs["extrude_type"].value, pull_symmetric=kwargs["pull_symmetric"], offset_mode=kwargs["offset_mode"].value, copy=kwargs["copy"], force_do_as_extrude=kwargs["force_do_as_extrude"], + seed_point=from_point3d_to_grpc_point(kwargs["seed_point"]), ) ] ) From c9b613a5fc7b5d6f4f438c2239a2bcef09d7bc23 Mon Sep 17 00:00:00 2001 From: Jacob Kerstetter Date: Tue, 25 Nov 2025 10:26:15 -0500 Subject: [PATCH 05/10] reverting v1 hardcode fixing some conversions and small bugs --- .../geometry/core/_grpc/_services/_service.py | 36 +++++++++---------- .../core/_grpc/_services/v1/conversions.py | 26 +++++++------- .../geometry/core/_grpc/_services/v1/faces.py | 14 ++++---- src/ansys/geometry/core/designer/face.py | 1 - 4 files changed, 39 insertions(+), 38 deletions(-) diff --git a/src/ansys/geometry/core/_grpc/_services/_service.py b/src/ansys/geometry/core/_grpc/_services/_service.py index caced54adb..73f237de29 100644 --- a/src/ansys/geometry/core/_grpc/_services/_service.py +++ b/src/ansys/geometry/core/_grpc/_services/_service.py @@ -410,16 +410,15 @@ def edges(self) -> GRPCEdgesService: # Import the appropriate edges service based on the version from .v0.edges import GRPCEdgesServiceV0 from .v1.edges import GRPCEdgesServiceV1 - self._edges = GRPCEdgesServiceV1(self.channel) - # if self.version == GeometryApiProtos.V0: - # self._edges = GRPCEdgesServiceV0(self.channel) - # elif self.version == GeometryApiProtos.V1: # pragma: no cover - # # V1 is not implemented yet - # self._edges = GRPCEdgesServiceV1(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}") + if self.version == GeometryApiProtos.V0: + self._edges = GRPCEdgesServiceV0(self.channel) + elif self.version == GeometryApiProtos.V1: # pragma: no cover + # V1 is not implemented yet + self._edges = GRPCEdgesServiceV1(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._edges @@ -437,16 +436,15 @@ def faces(self) -> GRPCFacesService: # Import the appropriate faces service based on the version from .v0.faces import GRPCFacesServiceV0 from .v1.faces import GRPCFacesServiceV1 - self._faces = GRPCFacesServiceV1(self.channel) - - # if self.version == GeometryApiProtos.V0: - # self._faces = GRPCFacesServiceV0(self.channel) - # elif self.version == GeometryApiProtos.V1: # pragma: no cover - # # V1 is not implemented yet - # self._faces = GRPCFacesServiceV1(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}") + + if self.version == GeometryApiProtos.V0: + self._faces = GRPCFacesServiceV0(self.channel) + elif self.version == GeometryApiProtos.V1: # pragma: no cover + # V1 is not implemented yet + self._faces = GRPCFacesServiceV1(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._faces diff --git a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py index e9bbecf735..dd4179b78b 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py @@ -179,9 +179,9 @@ def from_point3d_to_grpc_point(point: "Point3D") -> GRPCPoint: from ansys.geometry.core.misc.measurements import DEFAULT_UNITS return GRPCPoint( - x=point.x.m_as(DEFAULT_UNITS.SERVER_LENGTH), - y=point.y.m_as(DEFAULT_UNITS.SERVER_LENGTH), - z=point.z.m_as(DEFAULT_UNITS.SERVER_LENGTH), + x=GRPCQuantity(value_in_geometry_units=point.x.m_as(DEFAULT_UNITS.SERVER_LENGTH)), + y=GRPCQuantity(value_in_geometry_units=point.y.m_as(DEFAULT_UNITS.SERVER_LENGTH)), + z=GRPCQuantity(value_in_geometry_units=point.z.m_as(DEFAULT_UNITS.SERVER_LENGTH)), ) @@ -987,7 +987,6 @@ def from_grpc_curve_to_curve(curve: GRPCCurveGeometry) -> "Curve": Curve Resulting converted curve. """ - from ansys.geometry.core.math.point import Point3D from ansys.geometry.core.math.vector import UnitVector3D from ansys.geometry.core.shapes.curves.circle import Circle from ansys.geometry.core.shapes.curves.ellipse import Ellipse @@ -1000,10 +999,13 @@ def from_grpc_curve_to_curve(curve: GRPCCurveGeometry) -> "Curve": except ValueError: # curve will be a line pass - if curve.radius != 0: - result = Circle(origin, curve.radius, reference, axis) - elif curve.major_radius != 0 and curve.minor_radius != 0: - result = Ellipse(origin, curve.major_radius, curve.minor_radius, reference, axis) + + major_radius = curve.major_radius.value_in_geometry_units + minor_radius = curve.minor_radius.value_in_geometry_units + if curve.radius.value_in_geometry_units != 0: + result = Circle(origin, curve.radius.value_in_geometry_units, reference, axis) + elif major_radius != 0 and minor_radius != 0: + result = Ellipse(origin, major_radius, minor_radius, reference, axis) elif curve.nurbs_curve.nurbs_data.degree != 0: result = from_grpc_nurbs_curve_to_nurbs_curve(curve.nurbs_curve) elif curve.direction is not None: @@ -1446,15 +1448,15 @@ def serialize_entity_identifier(entity): } return { - "success": getattr(response, "success", False), + "success": getattr(response.command_response, "success", False), "created_bodies": [ - serialize_body(body) for body in getattr(response, "created_bodies", []) + serialize_body(body) for body in getattr(response.tracked_changes, "created_bodies", []) ], "modified_bodies": [ - serialize_body(body) for body in getattr(response, "modified_bodies", []) + serialize_body(body) for body in getattr(response.tracked_changes, "modified_bodies", []) ], "deleted_bodies": [ serialize_entity_identifier(entity) - for entity in getattr(response, "deleted_bodies", []) + for entity in getattr(response.tracked_changes, "deleted_bodies", []) ], } diff --git a/src/ansys/geometry/core/_grpc/_services/v1/faces.py b/src/ansys/geometry/core/_grpc/_services/v1/faces.py index 6b5fe7d2ea..18cb129e06 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/faces.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/faces.py @@ -433,7 +433,7 @@ def revolve_faces(self, **kwargs) -> dict: # noqa: D102 RevolveFacesRequestData( selection_id=[build_grpc_id(id) for id in kwargs["selection_ids"]], axis=from_line_to_grpc_line(kwargs["axis"]), - angle=from_measurement_to_server_angle(kwargs["angle"]), + angle=from_angle_to_grpc_quantity(kwargs["angle"]), extrude_type=kwargs["extrude_type"].value, ) ] @@ -493,9 +493,9 @@ def revolve_faces_by_helix(self, **kwargs) -> dict: # noqa: D102 selection_ids=[build_grpc_id(id) for id in kwargs["selection_ids"]], direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), axis=from_line_to_grpc_line(kwargs["axis"]), - height=from_measurement_to_server_length(kwargs["height"]), - pitch=from_measurement_to_server_length(kwargs["pitch"]), - taper_angle=from_measurement_to_server_angle(kwargs["taper_angle"]), + height=from_length_to_grpc_quantity(kwargs["height"]), + pitch=from_length_to_grpc_quantity(kwargs["pitch"]), + taper_angle=from_angle_to_grpc_quantity(kwargs["taper_angle"]), right_handed=kwargs["right_handed"], both_sides=kwargs["both_sides"], extrude_type=kwargs["extrude_type"].value, @@ -510,7 +510,9 @@ def revolve_faces_by_helix(self, **kwargs) -> dict: # noqa: D102 # Return the response - formatted as a dictionary return { "success": tracked_response.get("success"), - "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], + "created_bodies": [ + body.get("id").id for body in tracked_response.get("created_bodies") + ], } @protect_grpc @@ -613,7 +615,7 @@ def offset_faces(self, **kwargs) -> dict: # noqa: D102 request = OffsetFacesRequest( request_data=[ OffsetFacesRequestData( - faces=[build_grpc_id(id) for id in kwargs["face_ids"]], + face_ids=[build_grpc_id(id) for id in kwargs["face_ids"]], offset=from_measurement_to_server_length(kwargs["distance"]), direction=from_unit_vector_to_grpc_direction(kwargs["direction"]), extrude_type=kwargs["extrude_type"].value, diff --git a/src/ansys/geometry/core/designer/face.py b/src/ansys/geometry/core/designer/face.py index 3267b0fff4..fa07939fe4 100644 --- a/src/ansys/geometry/core/designer/face.py +++ b/src/ansys/geometry/core/designer/face.py @@ -543,7 +543,6 @@ def get_named_selections(self) -> list["NamedSelection"]: """ included_ns = [] for ns in get_design_from_body(self.body).named_selections: - print([face.id for face in ns.faces]) if any(face.id == self.id for face in ns.faces): included_ns.append(ns) From f3b747705cda55ffeaeee0bbf6e70abeceef0da2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 25 Nov 2025 15:27:57 +0000 Subject: [PATCH 06/10] chore: auto fixes from pre-commit hooks --- src/ansys/geometry/core/_grpc/_services/v1/conversions.py | 3 ++- src/ansys/geometry/core/_grpc/_services/v1/faces.py | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py index dd4179b78b..74b6f6428c 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py @@ -1453,7 +1453,8 @@ def serialize_entity_identifier(entity): serialize_body(body) for body in getattr(response.tracked_changes, "created_bodies", []) ], "modified_bodies": [ - serialize_body(body) for body in getattr(response.tracked_changes, "modified_bodies", []) + serialize_body(body) + for body in getattr(response.tracked_changes, "modified_bodies", []) ], "deleted_bodies": [ serialize_entity_identifier(entity) diff --git a/src/ansys/geometry/core/_grpc/_services/v1/faces.py b/src/ansys/geometry/core/_grpc/_services/v1/faces.py index 18cb129e06..5681f0943e 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/faces.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/faces.py @@ -27,7 +27,6 @@ from ansys.geometry.core.errors import protect_grpc from ..base.conversions import ( - from_measurement_to_server_angle, from_measurement_to_server_length, to_area, ) @@ -72,7 +71,7 @@ def __init__(self, channel: grpc.Channel): # noqa: D102 def get_surface(self, **kwargs) -> dict: # noqa: D102 # Create the request - assumes all inputs are valid and of the proper type request = MultipleEntitiesRequest(ids=[build_grpc_id(kwargs["id"])]) - + # Call the gRPC service response = self.stub.GetSurface(request=request).response_data[0] From 5e8b48c16bb5cd19a0e20fa33fe9da4208fccfc9 Mon Sep 17 00:00:00 2001 From: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Tue, 25 Nov 2025 15:29:05 +0000 Subject: [PATCH 07/10] chore: adding changelog file 2412.maintenance.md [dependabot-skip] --- doc/changelog.d/2412.maintenance.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/changelog.d/2412.maintenance.md diff --git a/doc/changelog.d/2412.maintenance.md b/doc/changelog.d/2412.maintenance.md new file mode 100644 index 0000000000..ad0828813d --- /dev/null +++ b/doc/changelog.d/2412.maintenance.md @@ -0,0 +1 @@ +V1 implementation of faces + edges stubs From c421ab3acf7e1ca66ac7eeceabe6cd428afb485a Mon Sep 17 00:00:00 2001 From: Jacob Kerstetter Date: Tue, 25 Nov 2025 10:33:17 -0500 Subject: [PATCH 08/10] extracting entity identifier id's --- .../geometry/core/_grpc/_services/v1/edges.py | 8 ++++++-- .../geometry/core/_grpc/_services/v1/faces.py | 18 +++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/ansys/geometry/core/_grpc/_services/v1/edges.py b/src/ansys/geometry/core/_grpc/_services/v1/edges.py index c1de80e36d..946e28e32a 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/edges.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/edges.py @@ -222,7 +222,9 @@ def extrude_edges(self, **kwargs) -> dict: # noqa: D102 # Return the response - formatted as a dictionary return { "success": tracked_response.get("success"), - "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], + "created_bodies": [ + body.get("id").id for body in tracked_response.get("created_bodies") + ], } @protect_grpc @@ -252,7 +254,9 @@ def extrude_edges_up_to(self, **kwargs) -> dict: # noqa: D102 # Return the response - formatted as a dictionary return { "success": tracked_response.get("success"), - "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], + "created_bodies": [ + body.get("id").id for body in tracked_response.get("created_bodies") + ], } @protect_grpc diff --git a/src/ansys/geometry/core/_grpc/_services/v1/faces.py b/src/ansys/geometry/core/_grpc/_services/v1/faces.py index 18cb129e06..95865d6b42 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/faces.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/faces.py @@ -354,7 +354,9 @@ def extrude_faces(self, **kwargs) -> dict: # noqa: D102 # Return the response - formatted as a dictionary return { "success": tracked_response.get("success"), - "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], + "created_bodies": [ + body.get("id").id for body in tracked_response.get("created_bodies") + ], } @protect_grpc @@ -388,7 +390,9 @@ def extrude_faces_up_to(self, **kwargs) -> dict: # noqa: D102 # Return the response - formatted as a dictionary return { "success": tracked_response.get("success"), - "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], + "created_bodies": [ + body.get("id").id for body in tracked_response.get("created_bodies") + ], } @protect_grpc @@ -446,7 +450,9 @@ def revolve_faces(self, **kwargs) -> dict: # noqa: D102 # Return the response - formatted as a dictionary return { "success": tracked_response.get("success"), - "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], + "created_bodies": [ + body.get("id").id for body in tracked_response.get("created_bodies") + ], } @protect_grpc @@ -476,7 +482,9 @@ def revolve_faces_up_to(self, **kwargs) -> dict: # noqa: D102 # Return the response - formatted as a dictionary return { "success": tracked_response.get("success"), - "created_bodies": [body.get("id") for body in tracked_response.get("created_bodies")], + "created_bodies": [ + body.get("id").id for body in tracked_response.get("created_bodies") + ], } @protect_grpc @@ -629,7 +637,7 @@ def offset_faces(self, **kwargs) -> dict: # noqa: D102 # Return the response - formatted as a dictionary return { - "results": [face.get("id") for face in tracked_response.get("created_faces")], + "results": [face.get("id").id for face in tracked_response.get("created_faces")], } @protect_grpc From 903bd462ac22a72ae965898f5e01845283db8db1 Mon Sep 17 00:00:00 2001 From: Jacob Kerstetter Date: Tue, 25 Nov 2025 10:52:27 -0500 Subject: [PATCH 09/10] fix offsetfaces todo --- src/ansys/geometry/core/_grpc/_services/v1/faces.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ansys/geometry/core/_grpc/_services/v1/faces.py b/src/ansys/geometry/core/_grpc/_services/v1/faces.py index a3e33889da..417784d860 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/faces.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/faces.py @@ -402,12 +402,11 @@ def offset_faces_set_radius(self, **kwargs) -> dict: # noqa: D102 ) # Create the request - assumes all inputs are valid and of the proper type - # TODO: multiple faces? request = OffsetFacesSetRadiusRequest( request_data=[ OffsetFacesSetRadiusRequestData( - id=[build_grpc_id(id) for id in kwargs["face_ids"]], - radius=from_measurement_to_server_length(kwargs["radius"]), + faces_ids=[build_grpc_id(id) for id in kwargs["face_ids"]], + radius=from_length_to_grpc_quantity(kwargs["radius"]), offset_mode=kwargs["offset_mode"].value, copy=kwargs["copy"], extrude_type=kwargs["extrude_type"].value, From 7ef54ea3a726b5d39dfed21780843e7921ff52ab Mon Sep 17 00:00:00 2001 From: Jacob Kerstetter Date: Tue, 25 Nov 2025 12:00:00 -0500 Subject: [PATCH 10/10] resolving comments --- .../core/_grpc/_services/v1/conversions.py | 5 +++-- .../geometry/core/_grpc/_services/v1/edges.py | 10 ++++----- .../geometry/core/_grpc/_services/v1/faces.py | 22 +++++++++---------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py index 74b6f6428c..61944d450e 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/conversions.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/conversions.py @@ -1000,10 +1000,11 @@ def from_grpc_curve_to_curve(curve: GRPCCurveGeometry) -> "Curve": # curve will be a line pass + radius = curve.radius.value_in_geometry_units major_radius = curve.major_radius.value_in_geometry_units minor_radius = curve.minor_radius.value_in_geometry_units - if curve.radius.value_in_geometry_units != 0: - result = Circle(origin, curve.radius.value_in_geometry_units, reference, axis) + if radius != 0: + result = Circle(origin, radius, reference, axis) elif major_radius != 0 and minor_radius != 0: result = Ellipse(origin, major_radius, minor_radius, reference, axis) elif curve.nurbs_curve.nurbs_data.degree != 0: diff --git a/src/ansys/geometry/core/_grpc/_services/v1/edges.py b/src/ansys/geometry/core/_grpc/_services/v1/edges.py index 946e28e32a..8ecb95d3b5 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/edges.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/edges.py @@ -58,7 +58,7 @@ def __init__(self, channel: grpc.Channel): # noqa: D102 from ansys.api.discovery.v1.operations.edit_pb2_grpc import EditStub self.stub = EdgeStub(channel) - self.EditStub = EditStub(channel) + self.edit_stub = EditStub(channel) @protect_grpc def get_edge(self, **kwargs) -> dict: # noqa: D102 @@ -216,7 +216,7 @@ def extrude_edges(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC service and serialize the response - response = self.EditStub.ExtrudeEdges(request) + response = self.edit_stub.ExtrudeEdges(request) tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary @@ -248,7 +248,7 @@ def extrude_edges_up_to(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC service and serialize the response - response = self.EditStub.ExtrudeFacesUpTo(request=request) + response = self.edit_stub.ExtrudeFacesUpTo(request=request) tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary @@ -278,7 +278,7 @@ def move_imprint_edges(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC service - response = self.EditStub.MoveImprintEdges(request) + response = self.edit_stub.MoveImprintEdges(request) # Return the response - formatted as a dictionary return { @@ -303,7 +303,7 @@ def offset_edges(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC service - response = self.EditStub.OffsetEdges(request) + response = self.edit_stub.OffsetEdges(request) # Return the response - formatted as a dictionary return { diff --git a/src/ansys/geometry/core/_grpc/_services/v1/faces.py b/src/ansys/geometry/core/_grpc/_services/v1/faces.py index 417784d860..6629004f87 100644 --- a/src/ansys/geometry/core/_grpc/_services/v1/faces.py +++ b/src/ansys/geometry/core/_grpc/_services/v1/faces.py @@ -65,7 +65,7 @@ def __init__(self, channel: grpc.Channel): # noqa: D102 from ansys.api.discovery.v1.operations.edit_pb2_grpc import EditStub self.stub = FaceStub(channel) - self.EditStub = EditStub(channel) + self.edit_stub = EditStub(channel) @protect_grpc def get_surface(self, **kwargs) -> dict: # noqa: D102 @@ -347,7 +347,7 @@ def extrude_faces(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC service and serialize the response - response = self.EditStub.ExtrudeFaces(request=request) + response = self.edit_stub.ExtrudeFaces(request=request) tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary @@ -383,7 +383,7 @@ def extrude_faces_up_to(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC service and serialize the response - response = self.EditStub.ExtrudeFacesUpTo(request=request) + response = self.edit_stub.ExtrudeFacesUpTo(request=request) tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary @@ -415,7 +415,7 @@ def offset_faces_set_radius(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC service - response = self.EditStub.OffsetFacesSetRadius(request=request) + response = self.edit_stub.OffsetFacesSetRadius(request=request) # Return the response - formatted as a dictionary return { @@ -442,7 +442,7 @@ def revolve_faces(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC service and serialize the response - response = self.EditStub.RevolveFaces(request=request) + response = self.edit_stub.RevolveFaces(request=request) tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary @@ -474,7 +474,7 @@ def revolve_faces_up_to(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC service and serialize the response - response = self.EditStub.RevolveFacesUpTo(request=request) + response = self.edit_stub.RevolveFacesUpTo(request=request) tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary @@ -510,7 +510,7 @@ def revolve_faces_by_helix(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC service and serialize the response - response = self.EditStub.RevolveFacesByHelix(request=request) + response = self.edit_stub.RevolveFacesByHelix(request=request) tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary @@ -561,7 +561,7 @@ def thicken_faces(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC service - response = self.EditStub.ThickenFaces(request=request) + response = self.edit_stub.ThickenFaces(request=request) # Return the response - formatted as a dictionary return { @@ -589,7 +589,7 @@ def draft_faces(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC server - response = self.EditStub.DraftFaces(request=request) + response = self.edit_stub.DraftFaces(request=request) # Return the drafted faces return { @@ -630,7 +630,7 @@ def offset_faces(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC service and serialize the response - response = self.EditStub.OffsetFaces(request=request) + response = self.edit_stub.OffsetFaces(request=request) tracked_response = serialize_tracked_command_response(response.tracked_command_response) # Return the response - formatted as a dictionary @@ -658,7 +658,7 @@ def setup_offset_relationship(self, **kwargs) -> dict: # noqa: D102 ) # Call the gRPC service - response = self.EditStub.FaceOffset(request=request) + response = self.edit_stub.FaceOffset(request=request) # Return the response - formatted as a dictionary return {