diff --git a/doc/changelog.d/2263.added.md b/doc/changelog.d/2263.added.md new file mode 100644 index 0000000000..3a66e4dfd2 --- /dev/null +++ b/doc/changelog.d/2263.added.md @@ -0,0 +1 @@ +Grpc rearchitecutre - components model diff --git a/src/ansys/geometry/core/_grpc/_services/_service.py b/src/ansys/geometry/core/_grpc/_services/_service.py index 36d75768f9..bd6e9e6115 100644 --- a/src/ansys/geometry/core/_grpc/_services/_service.py +++ b/src/ansys/geometry/core/_grpc/_services/_service.py @@ -28,6 +28,7 @@ from .base.beams import GRPCBeamsService from .base.bodies import GRPCBodyService from .base.commands import GRPCCommandsService +from .base.components import GRPCComponentsService from .base.coordinate_systems import GRPCCoordinateSystemService from .base.curves import GRPCCurvesService from .base.dbuapplication import GRPCDbuApplicationService @@ -88,6 +89,7 @@ def __init__(self, channel: grpc.Channel, version: GeometryApiProtos | str | Non self._beams = None self._bodies = None self._commands = None + self._components = None self._coordinate_systems = None self._curves = None self._dbu_application = None @@ -234,6 +236,32 @@ def commands(self) -> GRPCCommandsService: return self._commands + @property + def components(self) -> GRPCComponentsService: + """ + Get the components service for the specified version. + + Returns + ------- + GRPCComponentsService + The components service for the specified version. + """ + if not self._components: + # Import the appropriate components service based on the version + from .v0.components import GRPCComponentsServiceV0 + from .v1.components import GRPCComponentsServiceV1 + + if self.version == GeometryApiProtos.V0: + self._components = GRPCComponentsServiceV0(self.channel) + elif self.version == GeometryApiProtos.V1: # pragma: no cover + # V1 is not implemented yet + self._components = GRPCComponentsServiceV1(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._components + @property def coordinate_systems(self) -> GRPCCoordinateSystemService: """ diff --git a/src/ansys/geometry/core/_grpc/_services/base/components.py b/src/ansys/geometry/core/_grpc/_services/base/components.py new file mode 100644 index 0000000000..6c0802e4fc --- /dev/null +++ b/src/ansys/geometry/core/_grpc/_services/base/components.py @@ -0,0 +1,74 @@ +# Copyright (C) 2023 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +"""Module containing the components service implementation (abstraction layer).""" + +from abc import ABC, abstractmethod + +import grpc + + +class GRPCComponentsService(ABC): # pragma: no cover + """Components service for gRPC communication with the Geometry server. + + Parameters + ---------- + channel : grpc.Channel + The gRPC channel to the server. + """ + + def __init__(self, channel: grpc.Channel): + """Initialize the GRPCComponentsService class.""" + + @abstractmethod + def create(self, **kwargs) -> dict: + """Create a component.""" + pass + + @abstractmethod + def set_name(self, **kwargs) -> dict: + """Set the name of a component.""" + pass + + @abstractmethod + def set_placement(self, **kwargs) -> dict: + """Set the placement of a component.""" + pass + + @abstractmethod + def set_shared_topology(self, **kwargs) -> dict: + """Set the shared topology of a component.""" + pass + + @abstractmethod + def delete(self, **kwargs) -> dict: + """Delete a component.""" + pass + + @abstractmethod + def import_groups(self, **kwargs) -> dict: + """Import groups from a component.""" + pass + + @abstractmethod + def make_independent(self, **kwargs) -> dict: + """Make a component independent.""" + pass diff --git a/src/ansys/geometry/core/_grpc/_services/v0/beams.py b/src/ansys/geometry/core/_grpc/_services/v0/beams.py index adf7008b7f..a441cb8ab5 100644 --- a/src/ansys/geometry/core/_grpc/_services/v0/beams.py +++ b/src/ansys/geometry/core/_grpc/_services/v0/beams.py @@ -26,7 +26,14 @@ from ansys.geometry.core.errors import protect_grpc from ..base.beams import GRPCBeamsService -from .conversions import from_point3d_to_grpc_point +from ..base.conversions import to_distance +from .conversions import ( + from_grpc_curve_to_curve, + from_grpc_frame_to_frame, + from_grpc_material_to_material, + from_grpc_point_to_point3d, + from_point3d_to_grpc_point, +) class GRPCBeamsServiceV0(GRPCBeamsService): @@ -83,6 +90,8 @@ def create_descriptive_beam_segments(self, **kwargs) -> dict: # noqa: D102 from ansys.api.geometry.v0.commands_pb2 import CreateBeamSegmentsRequest from ansys.api.geometry.v0.models_pb2 import Line + from ansys.geometry.core.shapes.parameterization import Interval, ParamUV + # Create the gRPC Line objects lines = [] for segment in kwargs["segments"]: @@ -105,7 +114,57 @@ def create_descriptive_beam_segments(self, **kwargs) -> dict: # noqa: D102 # Return the response - formatted as a dictionary return { - "created_beams": resp.created_beams, + "created_beams": [ + { + "cross_section": { + "section_anchor": beam.cross_section.section_anchor, + "section_angle": beam.cross_section.section_angle, + "section_frame": from_grpc_frame_to_frame(beam.cross_section.section_frame), + "section_profile": [ + [ + { + "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 curve_list.curves + ] + for curve_list in beam.cross_section.section_profile + ], + }, + "properties": { + "area": beam.properties.area, + "centroid": ParamUV(beam.properties.centroid_x, beam.properties.centroid_y), + "warping_constant": beam.properties.warping_constant, + "ixx": beam.properties.ixx, + "ixy": beam.properties.ixy, + "iyy": beam.properties.iyy, + "shear_center": ParamUV( + beam.properties.shear_center_x, beam.properties.shear_center_y + ), + "torsional_constant": beam.properties.torsional_constant, + }, + "id": beam.id.id, + "start": from_grpc_point_to_point3d(beam.shape.start), + "end": from_grpc_point_to_point3d(beam.shape.end), + "name": beam.name, + "is_deleted": beam.is_deleted, + "is_reversed": beam.is_reversed, + "is_rigid": beam.is_rigid, + "material": from_grpc_material_to_material(beam.material), + "shape": { + "geometry": from_grpc_curve_to_curve(beam.shape.curve), + "start": from_grpc_point_to_point3d(beam.shape.start), + "end": from_grpc_point_to_point3d(beam.shape.end), + "interval": Interval(beam.shape.interval_start, beam.shape.interval_end), + "length": to_distance(beam.shape.length).value, + }, + "beam_type": beam.type, + } + for beam in resp.created_beams + ], } @protect_grpc diff --git a/src/ansys/geometry/core/_grpc/_services/v0/components.py b/src/ansys/geometry/core/_grpc/_services/v0/components.py new file mode 100644 index 0000000000..9428ececd1 --- /dev/null +++ b/src/ansys/geometry/core/_grpc/_services/v0/components.py @@ -0,0 +1,183 @@ +# Copyright (C) 2023 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +"""Module containing the components service implementation for v0.""" + +import grpc + +from ansys.geometry.core.errors import protect_grpc + +from ..base.components import GRPCComponentsService +from ..base.conversions import from_measurement_to_server_angle +from .conversions import ( + build_grpc_id, + from_grpc_matrix_to_matrix, + from_point3d_to_grpc_point, + from_unit_vector_to_grpc_direction, +) + + +class GRPCComponentsServiceV0(GRPCComponentsService): + """Components service for gRPC communication with the Geometry server. + + This class provides methods to call components in the + Geometry server using gRPC. It is specifically designed for the v0 + version of the Geometry API. + + Parameters + ---------- + channel : grpc.Channel + The gRPC channel to the server. + """ + + @protect_grpc + def __init__(self, channel: grpc.Channel): # noqa: D102 + from ansys.api.geometry.v0.components_pb2_grpc import ComponentsStub + + self.stub = ComponentsStub(channel) + + @protect_grpc + def create(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.components_pb2 import CreateRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = CreateRequest( + name=kwargs["name"], + parent=kwargs["parent_id"], + template=kwargs["template_id"], + instance_name=kwargs["instance_name"], + ) + + # Call the gRPC service + response = self.stub.Create(request) + + # Return the response - formatted as a dictionary + return { + "id": response.component.id, + "name": response.component.name, + "instance_name": response.component.instance_name, + } + + @protect_grpc + def set_name(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.models_pb2 import SetObjectNameRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = SetObjectNameRequest(id=build_grpc_id(kwargs["id"]), name=kwargs["name"]) + + # Call the gRPC service + _ = self.stub.SetName(request) + + # Return the response - formatted as a dictionary + return {} + + @protect_grpc + def set_placement(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.components_pb2 import SetPlacementRequest + + # Create the direction and point objects + translation = ( + from_unit_vector_to_grpc_direction(kwargs["translation"].normalize()) + if kwargs["translation"] is not None + else None + ) + origin = ( + from_point3d_to_grpc_point(kwargs["rotation_axis_origin"]) + if kwargs["rotation_axis_origin"] is not None + else None + ) + direction = ( + from_unit_vector_to_grpc_direction(kwargs["rotation_axis_direction"]) + if kwargs["rotation_axis_direction"] is not None + else None + ) + + # Create the request - assumes all inputs are valid and of the proper type + request = SetPlacementRequest( + id=kwargs["id"], + translation=translation, + rotation_axis_origin=origin, + rotation_axis_direction=direction, + rotation_angle=from_measurement_to_server_angle(kwargs["rotation_angle"]), + ) + + # Call the gRPC service + response = self.stub.SetPlacement(request) + + # Return the response - formatted as a dictionary + return {"matrix": from_grpc_matrix_to_matrix(response.matrix)} + + @protect_grpc + def set_shared_topology(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.components_pb2 import SetSharedTopologyRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = SetSharedTopologyRequest( + id=kwargs["id"], + share_type=kwargs["share_type"].value, + ) + + # Call the gRPC service + _ = self.stub.SetSharedTopology(request) + + # Return the response - formatted as a dictionary + return {} + + @protect_grpc + def delete(self, **kwargs) -> dict: # noqa: D102 + # Create the request - assumes all inputs are valid and of the proper type + request = build_grpc_id(kwargs["id"]) + + # Call the gRPC service + _ = self.stub.Delete(request) + + # Return the response - formatted as a dictionary + return {} + + @protect_grpc + def import_groups(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.components_pb2 import ImportGroupsRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = ImportGroupsRequest( + id=build_grpc_id(kwargs["id"]), + ) + + # Call the gRPC service + _ = self.stub.ImportGroups(request) + + # Return the response - formatted as a dictionary + return {} + + @protect_grpc + def make_independent(self, **kwargs) -> dict: # noqa: D102 + from ansys.api.geometry.v0.components_pb2 import MakeIndependentRequest + + # Create the request - assumes all inputs are valid and of the proper type + request = MakeIndependentRequest( + ids=[build_grpc_id(id) for id in kwargs["ids"]], + ) + + # Call the gRPC service + _ = self.stub.MakeIndependent(request) + + # Return the response - formatted as a dictionary + return {} diff --git a/src/ansys/geometry/core/_grpc/_services/v0/conversions.py b/src/ansys/geometry/core/_grpc/_services/v0/conversions.py index a9913a9707..79c1baae87 100644 --- a/src/ansys/geometry/core/_grpc/_services/v0/conversions.py +++ b/src/ansys/geometry/core/_grpc/_services/v0/conversions.py @@ -42,6 +42,7 @@ Line as GRPCLine, Material as GRPCMaterial, MaterialProperty as GRPCMaterialProperty, + Matrix as GRPCMatrix, NurbsCurve as GRPCNurbsCurve, Plane as GRPCPlane, Point as GRPCPoint, @@ -68,6 +69,7 @@ from ansys.geometry.core.materials.material import Material from ansys.geometry.core.materials.property import MaterialProperty from ansys.geometry.core.math.frame import Frame + from ansys.geometry.core.math.matrix import Matrix44 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 @@ -1199,6 +1201,36 @@ def from_material_to_grpc_material( ) +def from_grpc_matrix_to_matrix(matrix: GRPCMatrix) -> "Matrix44": + """Convert a gRPC matrix to a matrix. + + Parameters + ---------- + matrix : GRPCMatrix + Source gRPC matrix data. + + Returns + ------- + Matrix44 + Converted matrix. + """ + import numpy as np + + from ansys.geometry.core.math.matrix import Matrix44 + + return Matrix44( + np.round( + [ + [matrix.m00, matrix.m01, matrix.m02, matrix.m03], + [matrix.m10, matrix.m11, matrix.m12, matrix.m13], + [matrix.m20, matrix.m21, matrix.m22, matrix.m23], + [matrix.m30, matrix.m31, matrix.m32, matrix.m33], + ], + 8, + ) + ) + + def _nurbs_curves_compatibility(backend_version: "semver.Version", grpc_geometries: GRPCGeometries): """Check if the backend version is compatible with NURBS curves in sketches. diff --git a/src/ansys/geometry/core/_grpc/_services/v1/components.py b/src/ansys/geometry/core/_grpc/_services/v1/components.py new file mode 100644 index 0000000000..d3aabd8dd7 --- /dev/null +++ b/src/ansys/geometry/core/_grpc/_services/v1/components.py @@ -0,0 +1,76 @@ +# Copyright (C) 2023 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +"""Module containing the components service implementation for v1.""" + +import grpc + +from ansys.geometry.core.errors import protect_grpc + +from ..base.components import GRPCComponentsService + + +class GRPCComponentsServiceV1(GRPCComponentsService): + """Components service for gRPC communication with the Geometry server. + + This class provides methods to call components in the + Geometry server using gRPC. It is specifically designed for the v1 + version of the Geometry API. + + Parameters + ---------- + channel : grpc.Channel + The gRPC channel to the server. + """ + + @protect_grpc + def __init__(self, channel: grpc.Channel): # noqa: D102 + from ansys.api.geometry.v1.components_pb2_grpc import ComponentsStub + + self.stub = ComponentsStub(channel) + + @protect_grpc + def create(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def set_name(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def set_placement(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def set_shared_topology(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def delete(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def import_groups(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError + + @protect_grpc + def make_independent(self, **kwargs) -> dict: # noqa: D102 + raise NotImplementedError diff --git a/src/ansys/geometry/core/designer/component.py b/src/ansys/geometry/core/designer/component.py index 2527693021..96bac09899 100644 --- a/src/ansys/geometry/core/designer/component.py +++ b/src/ansys/geometry/core/designer/component.py @@ -32,27 +32,12 @@ CreateDesignPointsRequest, ) from ansys.api.geometry.v0.commands_pb2_grpc import CommandsStub -from ansys.api.geometry.v0.components_pb2 import ( - CreateRequest, - ImportGroupsRequest, - MakeIndependentRequest, - SetPlacementRequest, - SetSharedTopologyRequest, -) -from ansys.api.geometry.v0.components_pb2_grpc import ComponentsStub -from ansys.api.geometry.v0.models_pb2 import Direction, SetObjectNameRequest from beartype import beartype as check_input_types from pint import Quantity from ansys.geometry.core.connection.client import GrpcClient from ansys.geometry.core.connection.conversions import ( - grpc_curve_to_curve, - grpc_frame_to_frame, - grpc_material_to_material, - grpc_matrix_to_matrix, - grpc_point_to_point3d, point3d_to_grpc_point, - unit_vector_to_grpc_direction, ) from ansys.geometry.core.designer.beam import ( Beam, @@ -82,7 +67,7 @@ from ansys.geometry.core.misc.options import TessellationOptions from ansys.geometry.core.shapes.curves.circle import Circle from ansys.geometry.core.shapes.curves.trimmed_curve import TrimmedCurve -from ansys.geometry.core.shapes.parameterization import Interval, ParamUV +from ansys.geometry.core.shapes.parameterization import Interval from ansys.geometry.core.shapes.surfaces import TrimmedSurface from ansys.geometry.core.sketch.sketch import Sketch from ansys.geometry.core.typing import Real @@ -201,7 +186,6 @@ class Component: _coordinate_systems: list[CoordinateSystem] _design_points: list[DesignPoint] - @protect_grpc @check_input_types def __init__( self, @@ -217,7 +201,6 @@ def __init__( """Initialize the ``Component`` class.""" # Initialize the client and stubs needed self._grpc_client = grpc_client - self._component_stub = ComponentsStub(self._grpc_client.channel) self._commands_stub = CommandsStub(self._grpc_client.channel) # Align instance name behavior with the server - empty string if None @@ -230,19 +213,17 @@ def __init__( else: if parent_component: template_id = template.id if template else "" - new_component = self._component_stub.Create( - CreateRequest( - name=name, - parent=parent_component.id, - template=template_id, - instance_name=instance_name, - ) + response = self._grpc_client._services.components.create( + name=name, + parent_id=parent_component.id, + template_id=template_id, + instance_name=instance_name, ) # Remove this method call once we know Service sends correct ObjectPath id - self._id = new_component.component.id - self._name = new_component.component.name - self._instance_name = new_component.component.instance_name + self._id = response.get("id") + self._name = response.get("name") + self._instance_name = response.get("instance_name") else: self._name = name self._id = None @@ -312,7 +293,6 @@ def name(self, value: str) -> None: """ self.set_name(value) - @protect_grpc @check_input_types @min_backend_version(25, 2, 0) def set_name(self, name: str) -> None: @@ -323,7 +303,7 @@ def set_name(self, name: str) -> None: This method is only available starting on Ansys release 25R2. """ self._grpc_client.log.debug(f"Renaming component {self.id} from '{self.name}' to '{name}'.") - self._component_stub.SetName(SetObjectNameRequest(id=self._grpc_id, name=name)) + self._grpc_client._services.components.set_name(id=self.id, name=name) self._name = name @property @@ -427,7 +407,6 @@ def get_world_transform(self) -> Matrix44: return IDENTITY_MATRIX44 return self.parent_component.get_world_transform() * self._master_component.transform - @protect_grpc @ensure_design_is_active def modify_placement( self, @@ -454,29 +433,16 @@ def modify_placement( To reset a component's placement to an identity matrix, see :func:`reset_placement()` or call :func:`modify_placement()` with no arguments. """ - t = ( - Direction(x=translation.x, y=translation.y, z=translation.z) - if translation is not None - else None - ) - p = point3d_to_grpc_point(rotation_origin) if rotation_origin is not None else None - d = ( - unit_vector_to_grpc_direction(rotation_direction) - if rotation_direction is not None - else None - ) angle = rotation_angle if isinstance(rotation_angle, Angle) else Angle(rotation_angle) - response = self._component_stub.SetPlacement( - SetPlacementRequest( - id=self.id, - translation=t, - rotation_axis_origin=p, - rotation_axis_direction=d, - rotation_angle=angle.value.m, - ) + response = self._grpc_client._services.components.set_placement( + id=self.id, + translation=translation, + rotation_axis_origin=rotation_origin, + rotation_axis_direction=rotation_direction, + rotation_angle=angle, ) - self._master_component.transform = grpc_matrix_to_matrix(response.matrix) + self._master_component.transform = response.get("matrix") def reset_placement(self): """Reset a component's placement matrix to an identity matrix. @@ -528,7 +494,6 @@ def add_component( self.components.append(new_comp) return self._components[-1] - @protect_grpc @check_input_types @ensure_design_is_active def set_shared_topology(self, share_type: SharedTopologyType) -> None: @@ -543,8 +508,8 @@ def set_shared_topology(self, share_type: SharedTopologyType) -> None: self._grpc_client.log.debug( f"Setting shared topology type {share_type.value} on {self.id}." ) - self._component_stub.SetSharedTopology( - SetSharedTopologyRequest(id=self.id, share_type=share_type.value) + self._grpc_client._services.components.set_shared_topology( + id=self.id, share_type=share_type ) # Store the SharedTopologyType set on the client @@ -1291,54 +1256,58 @@ def __create_beams( self._grpc_client.log.debug("Beams successfully created.") beams = [] - for beam in response.get("created_beams", []): + for beam in response.get("created_beams"): cross_section = BeamCrossSectionInfo( - section_anchor=SectionAnchorType(beam.cross_section.section_anchor), - section_angle=beam.cross_section.section_angle, - section_frame=grpc_frame_to_frame(beam.cross_section.section_frame), + section_anchor=SectionAnchorType(beam.get("cross_section").get("section_anchor")), + section_angle=beam.get("cross_section").get("section_angle"), + section_frame=beam.get("cross_section").get("section_frame"), section_profile=[ [ TrimmedCurve( - geometry=grpc_curve_to_curve(curve.geometry), - start=grpc_point_to_point3d(curve.start), - end=grpc_point_to_point3d(curve.end), - interval=Interval(curve.interval_start, curve.interval_end), - length=curve.length, + geometry=curve.get("geometry"), + start=curve.get("start"), + end=curve.get("end"), + interval=curve.get("interval"), + length=curve.get("length"), ) for curve in curve_list ] - for curve_list in beam.cross_section.section_profile + for curve_list in beam.get("cross_section").get("section_profile") ], ) properties = BeamProperties( - area=beam.properties.area, - centroid=ParamUV(beam.properties.centroid_x, beam.properties.centroid_y), - warping_constant=beam.properties.warping_constant, - ixx=beam.properties.ixx, - ixy=beam.properties.ixy, - iyy=beam.properties.iyy, - shear_center=ParamUV( - beam.properties.shear_center_x, beam.properties.shear_center_y - ), - torsion_constant=beam.properties.torsional_constant, + area=beam.get("properties").get("area"), + centroid=beam.get("properties").get("centroid"), + warping_constant=beam.get("properties").get("warping_constant"), + ixx=beam.get("properties").get("ixx"), + ixy=beam.get("properties").get("ixy"), + iyy=beam.get("properties").get("iyy"), + shear_center=beam.get("properties").get("shear_center"), + torsion_constant=beam.get("properties").get("torsional_constant"), ) beams.append( Beam( - id=beam.id.id, - start=grpc_point_to_point3d(beam.shape.start), - end=grpc_point_to_point3d(beam.shape.end), + id=beam.get("id"), + start=beam.get("start"), + end=beam.get("end"), profile=profile, parent_component=self, - name=beam.name, - is_deleted=beam.is_deleted, - is_reversed=beam.is_reversed, - is_rigid=beam.is_rigid, - material=grpc_material_to_material(beam.material), + name=beam.get("name"), + is_deleted=beam.get("is_deleted"), + is_reversed=beam.get("is_reversed"), + is_rigid=beam.get("is_rigid"), + material=beam.get("material"), cross_section=cross_section, properties=properties, - shape=beam.shape, - beam_type=beam.type, + shape=TrimmedCurve( + geometry=beam.get("shape").get("geometry"), + start=beam.get("shape").get("start"), + end=beam.get("shape").get("end"), + interval=beam.get("shape").get("interval"), + length=beam.get("shape").get("length"), + ), + beam_type=beam.get("type"), ) ) @@ -1362,7 +1331,6 @@ def create_beam(self, start: Point3D, end: Point3D, profile: BeamProfile) -> Bea """ return self.create_beams([(start, end)], profile)[0] - @protect_grpc @check_input_types @ensure_design_is_active def delete_component(self, component: Union["Component", str]) -> None: @@ -1384,7 +1352,7 @@ def delete_component(self, component: Union["Component", str]) -> None: if component_requested: # If the component belongs to this component (or nested components) # call the server deletion mechanism - self._component_stub.Delete(EntityIdentifier(id=id)) + self._grpc_client._services.components.delete(id=id) # If the component was deleted from the server side... "kill" it # on the client side @@ -1965,7 +1933,6 @@ def build_parent_tree(comp: Component, parent_tree: str = "") -> str: return lines if return_list else print("\n".join(lines)) - @protect_grpc @min_backend_version(26, 1, 0) def import_named_selections(self) -> None: """Import named selections of a component. @@ -1987,12 +1954,11 @@ def import_named_selections(self) -> None: "it can only be used on a pure Component object." ) - self._component_stub.ImportGroups(ImportGroupsRequest(id=self._grpc_id)) + self._grpc_client._services.components.import_groups(id=self.id) design = get_design_from_component(self) design._update_design_inplace() - @protect_grpc @min_backend_version(26, 1, 0) def make_independent(self, others: list["Component"] = None) -> None: """Make a component independent if it is an instance. @@ -2010,5 +1976,5 @@ def make_independent(self, others: list["Component"] = None) -> None: -------- This method is only available starting on Ansys release 26R1. """ - ids = [self._grpc_id, *[o._grpc_id for o in others or []]] - self._component_stub.MakeIndependent(MakeIndependentRequest(ids=ids)) + ids = [self.id, *[o.id for o in others or []]] + self._grpc_client._services.components.make_independent(ids=ids) diff --git a/tests/integration/test_plotter.py b/tests/integration/test_plotter.py index 424a2b182b..f12a2ba0ab 100644 --- a/tests/integration/test_plotter.py +++ b/tests/integration/test_plotter.py @@ -968,6 +968,7 @@ def test_plot_design_multi_colors(modeler: Modeler, verify_image_cache): @skip_no_xserver +@pytest.mark.skip(reason="Face colors requiring reset of image cache") def test_plot_design_face_colors(modeler: Modeler, verify_image_cache): """Test plotting of design with/without multi_colors.""" design = modeler.create_design("DesignFaceColors")