diff --git a/doc/changelog.d/2367.fixed.md b/doc/changelog.d/2367.fixed.md new file mode 100644 index 0000000000..4174910cfa --- /dev/null +++ b/doc/changelog.d/2367.fixed.md @@ -0,0 +1 @@ +Add axis for circular pattern diff --git a/pyproject.toml b/pyproject.toml index ae6bc1b3fa..56e89230cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ classifiers = [ ] dependencies = [ - "ansys-api-discovery==1.0.3", + "ansys-api-discovery==1.0.5", "ansys-tools-path>=0.3,<1", "beartype>=0.11.0,<0.23", "geomdl>=5,<6", diff --git a/src/ansys/geometry/core/_grpc/_services/v0/patterns.py b/src/ansys/geometry/core/_grpc/_services/v0/patterns.py index b6adbab2e5..48136cb99d 100644 --- a/src/ansys/geometry/core/_grpc/_services/v0/patterns.py +++ b/src/ansys/geometry/core/_grpc/_services/v0/patterns.py @@ -30,7 +30,7 @@ from_measurement_to_server_length, ) from ..base.patterns import GRPCPatternsService -from .conversions import build_grpc_id, from_unit_vector_to_grpc_direction +from .conversions import build_grpc_id, from_line_to_grpc_line, from_unit_vector_to_grpc_direction class GRPCPatternsServiceV0(GRPCPatternsService): # pragma: no cover @@ -104,6 +104,8 @@ def modify_linear_pattern(self, **kwargs) -> dict: # noqa: D102 def create_circular_pattern(self, **kwargs) -> dict: # noqa: D102 from ansys.api.geometry.v0.commands_pb2 import CreateCircularPatternRequest + from ansys.geometry.core.shapes.curves.line import Line + # Create direction if not None radial_direction = ( from_unit_vector_to_grpc_direction(kwargs["radial_direction"]) @@ -118,16 +120,24 @@ def create_circular_pattern(self, **kwargs) -> dict: # noqa: D102 else None ) + # Create line if axis is a line object + circular_axis, axis = None, None + if isinstance(kwargs["circular_axis"], Line): + axis = from_line_to_grpc_line(kwargs["circular_axis"]) + else: + circular_axis = build_grpc_id(kwargs["circular_axis"]) + # Create the request - assumes all inputs are valid and of the proper type request = CreateCircularPatternRequest( selection=[build_grpc_id(id) for id in kwargs["selection_ids"]], - circular_axis=build_grpc_id(kwargs["circular_axis_id"]), circular_count=kwargs["circular_count"], + circular_axis=circular_axis, circular_angle=from_measurement_to_server_angle(kwargs["circular_angle"]), two_dimensional=kwargs["two_dimensional"], linear_count=kwargs["linear_count"], linear_pitch=linear_pitch, radial_direction=radial_direction, + axis=axis, ) # Call the gRPC service diff --git a/src/ansys/geometry/core/designer/geometry_commands.py b/src/ansys/geometry/core/designer/geometry_commands.py index 2c98a187a2..edbac245b4 100644 --- a/src/ansys/geometry/core/designer/geometry_commands.py +++ b/src/ansys/geometry/core/designer/geometry_commands.py @@ -716,7 +716,7 @@ def modify_linear_pattern( def create_circular_pattern( self, selection: Union["Face", list["Face"]], - circular_axis: "Edge", + circular_axis: Union["Edge", Line], circular_count: int, circular_angle: Angle | Quantity | Real, two_dimensional: bool = False, @@ -755,6 +755,7 @@ def create_circular_pattern( -------- This method is only available starting on Ansys release 25R2. """ + from ansys.geometry.core.designer.edge import Edge from ansys.geometry.core.designer.face import Face selection: list[Face] = selection if isinstance(selection, list) else [selection] @@ -778,16 +779,25 @@ def create_circular_pattern( "a two-dimensional pattern is desired." ) ) + if self._grpc_client.backend_version < (26, 1, 0) and isinstance(circular_axis, Line): + raise ValueError( + ( + "Using a Line as the circular axis is only supported " + "starting in Ansys release 26R1." + ) + ) # Convert angle and pitch to appropriate objects if not isinstance(circular_angle, Angle): circular_angle = Angle(circular_angle) if linear_pitch is not None and not isinstance(linear_pitch, Distance): linear_pitch = Distance(linear_pitch) + if isinstance(circular_axis, Edge): + circular_axis = circular_axis.id result = self._grpc_client.services.patterns.create_circular_pattern( selection_ids=[object.id for object in selection], - circular_axis_id=circular_axis.id, + circular_axis=circular_axis, circular_count=circular_count, circular_angle=circular_angle, two_dimensional=two_dimensional, diff --git a/tests/_incompatible_tests.yml b/tests/_incompatible_tests.yml index 514b913eb5..ae4c4a61c3 100644 --- a/tests/_incompatible_tests.yml +++ b/tests/_incompatible_tests.yml @@ -115,6 +115,7 @@ backends: - tests/integration/test_design_import.py::test_named_selections_after_file_insert - tests/integration/test_design_import.py::test_named_selections_after_file_open - tests/integration/test_design_import.py::test_file_insert_import_named_selections_post_import + - tests/integration/test_geometry_commands.py::test_circular_pattern_about_line # Export body facets added in 26.1 - tests/integration/test_design.py::test_write_body_facets_on_save[scdocx-None] - tests/integration/test_design.py::test_write_body_facets_on_save[dsco-DISCO] @@ -229,6 +230,7 @@ backends: - tests/integration/test_design_import.py::test_named_selections_after_file_insert - tests/integration/test_design_import.py::test_named_selections_after_file_open - tests/integration/test_design_import.py::test_file_insert_import_named_selections_post_import + - tests/integration/test_geometry_commands.py::test_circular_pattern_about_line # Export body facets add in 26.1 - tests/integration/test_design.py::test_write_body_facets_on_save[scdocx-None] - tests/integration/test_design.py::test_write_body_facets_on_save[dsco-DISCO] @@ -312,6 +314,7 @@ backends: - tests/integration/test_design_import.py::test_named_selections_after_file_insert - tests/integration/test_design_import.py::test_named_selections_after_file_open - tests/integration/test_design_import.py::test_file_insert_import_named_selections_post_import + - tests/integration/test_geometry_commands.py::test_circular_pattern_about_line # Export body facets add in 26.1 - tests/integration/test_design.py::test_write_body_facets_on_save[scdocx-None] - tests/integration/test_design.py::test_write_body_facets_on_save[dsco-DISCO] @@ -352,6 +355,7 @@ backends: - tests/integration/test_design_import.py::test_named_selections_after_file_insert - tests/integration/test_design_import.py::test_named_selections_after_file_open - tests/integration/test_design_import.py::test_file_insert_import_named_selections_post_import + - tests/integration/test_geometry_commands.py::test_circular_pattern_about_line # Export body facets add in 26.1 - tests/integration/test_design.py::test_write_body_facets_on_save[scdocx-None] - tests/integration/test_design.py::test_write_body_facets_on_save[dsco-DISCO] diff --git a/tests/integration/files/circular_pattern_about_line.png b/tests/integration/files/circular_pattern_about_line.png new file mode 100644 index 0000000000..e4be271832 Binary files /dev/null and b/tests/integration/files/circular_pattern_about_line.png differ diff --git a/tests/integration/test_geometry_commands.py b/tests/integration/test_geometry_commands.py index d61b85d6c6..bc077a10d3 100644 --- a/tests/integration/test_geometry_commands.py +++ b/tests/integration/test_geometry_commands.py @@ -450,6 +450,26 @@ def test_circular_pattern(modeler: Modeler): ) +def test_circular_pattern_about_line(modeler: Modeler): + """Test circular pattern about line.""" + design = modeler.create_design("d1") + base = design.extrude_sketch("box", Sketch().box(Point2D([0, 0]), 20, 20), 20) + + cutout = design.extrude_sketch("cylinder", Sketch().circle(Point2D([-5, -5]), 1), 20) + base.subtract(cutout) + + assert base.volume.m == pytest.approx(Quantity(7937.1681, UNITS.m**3).m, rel=1e-6, abs=1e-8) + assert len(base.faces) == 7 + + # full two-dimensional test - creates 3 rings around the center + axis = Line(Point3D([0, 0, 0]), UNITVECTOR3D_Z) + success = modeler.geometry_commands.create_circular_pattern(base.faces[-1], axis, 8, np.pi * 2) + + assert success + assert base.volume.m == pytest.approx(Quantity(7497.3452, UNITS.m**3).m, rel=1e-6, abs=1e-8) + assert len(base.faces) == 14 + + def test_fill_pattern(modeler: Modeler): """Test fill pattern.""" design = modeler.create_design("d1")