Skip to content

Commit 140e8de

Browse files
umutsoysalansyspyansys-ci-botb-matteoRobPasMuePipKat
authored
feat: loft profiles (#1075)
Co-authored-by: pyansys-ci-bot <pyansys.github.bot@ansys.com> Co-authored-by: m-bini <matteo.bini@ansys.com> Co-authored-by: Roberto Pastor Muela <37798125+RobPasMue@users.noreply.github.com> Co-authored-by: Kathy Pippert <84872299+PipKat@users.noreply.github.com>
1 parent f7f8bfa commit 140e8de

File tree

3 files changed

+92
-1
lines changed

3 files changed

+92
-1
lines changed

doc/changelog.d/1075.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
feat: loft profiles

src/ansys/geometry/core/designer/component.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from ansys.api.geometry.v0.bodies_pb2 import (
2929
CreateBodyFromFaceRequest,
3030
CreateExtrudedBodyFromFaceProfileRequest,
31+
CreateExtrudedBodyFromLoftProfilesRequest,
3132
CreateExtrudedBodyRequest,
3233
CreatePlanarBodyRequest,
3334
CreateSphereBodyRequest,
@@ -44,7 +45,7 @@
4445
SetSharedTopologyRequest,
4546
)
4647
from ansys.api.geometry.v0.components_pb2_grpc import ComponentsStub
47-
from ansys.api.geometry.v0.models_pb2 import Direction, Line
48+
from ansys.api.geometry.v0.models_pb2 import Direction, Line, TrimmedCurveList
4849
from beartype import beartype as check_input_types
4950
from beartype.typing import TYPE_CHECKING, List, Optional, Tuple, Union
5051
from pint import Quantity
@@ -684,6 +685,73 @@ def create_sphere(self, name: str, center: Point3D, radius: Distance) -> Body:
684685
self._master_component.part.bodies.append(tb)
685686
return Body(response.id, response.name, self, tb)
686687

688+
@protect_grpc
689+
@check_input_types
690+
@ensure_design_is_active
691+
@min_backend_version(24, 2, 0)
692+
def create_body_from_loft_profile(
693+
self,
694+
name: str,
695+
profiles: List[List[TrimmedCurve]],
696+
periodic: bool = False,
697+
ruled: bool = False,
698+
) -> Body:
699+
"""
700+
Create a lofted body from a collection of trimmed curves.
701+
702+
Parameters
703+
----------
704+
name : str
705+
Name of the lofted body.
706+
profiles : List[List[TrimmedCurve]]
707+
Collection of lists of trimmed curves (profiles) defining the lofted body's shape.
708+
periodic : bool, default: False
709+
Whether the lofted body should have periodic continuity.
710+
ruled : bool
711+
Whether the lofted body should be ruled.
712+
713+
Returns
714+
-------
715+
Body
716+
Created lofted body object.
717+
718+
Notes
719+
-----
720+
Surfaces produced have a U parameter in the direction of the profile curves,
721+
and a V parameter in the direction of lofting.
722+
Profiles can have different numbers of segments. A minimum twist solution is
723+
produced.
724+
Profiles should be all closed or all open. Closed profiles cannot contain inner
725+
loops. If closed profiles are supplied, a closed (solid) body is produced, if
726+
possible. Otherwise, an open (sheet) body is produced.
727+
The periodic argument applies when the profiles are closed. It is ignored if
728+
the profiles are open.
729+
730+
If ``periodic=True``, at least three profiles must be supplied. The loft continues
731+
from the last profile back to the first profile to produce surfaces that are
732+
periodic in V.
733+
734+
If ``periodic=False``, at least two profiles must be supplied. If the first
735+
and last profiles are planar, end capping faces are created. Otherwise, an open
736+
(sheet) body is produced.
737+
If ``ruled=True``, separate ruled surfaces are produced between each pair of profiles.
738+
If ``periodic=True``, the loft continues from the last profile back to the first
739+
profile, but the surfaces are not periodic.
740+
"""
741+
profiles_grpc = [
742+
TrimmedCurveList(curves=[trimmed_curve_to_grpc_trimmed_curve(tc) for tc in profile])
743+
for profile in profiles
744+
]
745+
746+
request = CreateExtrudedBodyFromLoftProfilesRequest(
747+
name=name, parent=self.id, profiles=profiles_grpc, periodic=periodic, ruled=ruled
748+
)
749+
self._grpc_client.log.debug(f"Creating a loft profile body on {self.id} .")
750+
response = self._bodies_stub.CreateExtrudedBodyFromLoftProfiles(request)
751+
tb = MasterBody(response.master_id, name, self._grpc_client, is_surface=False)
752+
self._master_component.part.bodies.append(tb)
753+
return Body(response.id, response.name, self, tb)
754+
687755
@protect_grpc
688756
@check_input_types
689757
@ensure_design_is_active

tests/integration/test_design.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2265,3 +2265,25 @@ def test_sweep_chain(modeler: Modeler):
22652265
# check volume of body
22662266
# expected is 0 since it's not a closed surface
22672267
assert body.volume.m == 0
2268+
2269+
2270+
def test_create_body_from_loft_profile(modeler: Modeler):
2271+
"""Test the ``create_body_from_loft_profile()`` method to create a vase shape."""
2272+
skip_if_linux(modeler)
2273+
design_sketch = modeler.create_design("loftprofile")
2274+
2275+
profile1 = Circle(origin=[0, 0, 0], radius=8).trim(Interval(0, 2 * np.pi))
2276+
profile2 = Circle(origin=[0, 0, 10], radius=10).trim(Interval(0, 2 * np.pi))
2277+
profile3 = Circle(origin=[0, 0, 20], radius=5).trim(Interval(0, 2 * np.pi))
2278+
2279+
# Call the method
2280+
result = design_sketch.create_body_from_loft_profile(
2281+
"vase", [[profile1], [profile2], [profile3]], False, False
2282+
)
2283+
2284+
# Assert that the resulting body has only one face.
2285+
assert len(result.faces) == 1
2286+
2287+
# check volume of body
2288+
# expected is 0 since it's not a closed surface
2289+
assert result.volume.m == 0

0 commit comments

Comments
 (0)