Skip to content
Merged
1 change: 1 addition & 0 deletions doc/changelog.d/1781.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
imprint curves without a sketch
54 changes: 43 additions & 11 deletions src/ansys/geometry/core/designer/body.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
point3d_to_grpc_point,
sketch_shapes_to_grpc_geometries,
tess_to_pd,
trimmed_curve_to_grpc_trimmed_curve,
unit_vector_to_grpc_direction,
)
from ansys.geometry.core.designer.edge import CurveType, Edge
Expand All @@ -93,6 +94,7 @@
min_backend_version,
)
from ansys.geometry.core.misc.measurements import DEFAULT_UNITS, Angle, Distance
from ansys.geometry.core.shapes.curves.trimmed_curve import TrimmedCurve
from ansys.geometry.core.sketch.sketch import Sketch
from ansys.geometry.core.typing import Real

Expand Down Expand Up @@ -1574,30 +1576,60 @@ def add_midsurface_offset( # noqa: D102
@protect_grpc
@ensure_design_is_active
def imprint_curves( # noqa: D102
self, faces: list[Face], sketch: Sketch
self, faces: list[Face], sketch: Sketch = None, trimmed_curves: list[TrimmedCurve] = None
) -> tuple[list[Edge], list[Face]]:
"""Imprint curves onto the specified faces using a sketch or edges.

Parameters
----------
faces : list[Face]
The list of faces to imprint the curves onto.
sketch : Sketch, optional
The sketch containing curves to imprint.
trimmed_curves : list[TrimmedCurve], optional
The list of curves to be imprinted. If sketch is provided, this parameter is ignored.

Returns
-------
tuple[list[Edge], list[Face]]
A tuple containing the list of new edges and faces created by the imprint operation.
"""
if sketch is None and self._template._grpc_client.backend_version < (25, 2, 0):
raise ValueError(
"A sketch must be provided for imprinting when using API versions below 25.2.0."
)

if sketch is None and trimmed_curves is None:
raise ValueError("Either a sketch or edges must be provided for imprinting.")

# Verify that each of the faces provided are part of this body
body_faces = self.faces
for provided_face in faces:
is_found = False
for body_face in body_faces:
if provided_face.id == body_face.id:
is_found = True
break
if not is_found:
if not any(provided_face.id == body_face.id for body_face in body_faces):
raise ValueError(f"Face with ID {provided_face.id} is not part of this body.")

self._template._grpc_client.log.debug(
f"Imprinting curves provided on {self.id} "
+ f"for faces {[face.id for face in faces]}."
f"Imprinting curves on {self.id} for faces {[face.id for face in faces]}."
)

curves = None
grpc_trimmed_curves = None

if sketch:
curves = sketch_shapes_to_grpc_geometries(sketch._plane, sketch.edges, sketch.faces)

if trimmed_curves:
grpc_trimmed_curves = [
trimmed_curve_to_grpc_trimmed_curve(curve) for curve in trimmed_curves
]

imprint_response = self._template._commands_stub.ImprintCurves(
ImprintCurvesRequest(
body=self._id,
curves=sketch_shapes_to_grpc_geometries(sketch._plane, sketch.edges, sketch.faces),
curves=curves,
faces=[face._id for face in faces],
plane=plane_to_grpc_plane(sketch.plane),
plane=plane_to_grpc_plane(sketch.plane) if sketch else None,
trimmed_curves=grpc_trimmed_curves,
)
)

Expand Down
51 changes: 51 additions & 0 deletions tests/integration/test_design.py
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,57 @@ def test_project_and_imprint_curves(modeler: Modeler):
assert len(body_copy.faces) == 8


def test_imprint_trimmed_curves(modeler: Modeler):
"""
Test the imprinting of trimmed curves onto a specified face of a body.
"""
unit = DEFAULT_UNITS.LENGTH

wx = 1
wy = 1
wz = 1
design = modeler.create_design("test imprint")

# create box
start_at = Point3D([wx / 2, wy / 2, 0.0], unit=unit)

plane = Plane(
start_at,
UNITVECTOR3D_X,
UNITVECTOR3D_Y,
)

box_plane = Sketch(plane)
box_plane.box(Point2D([0.0, 0.0], unit=unit), width=wx, height=wy)
box = design.extrude_sketch("box", box_plane, wz)

assert len(box.faces) == 6
assert len(box.edges) == 12

# create cylinder
point = Point3D([0.5, 0.5, 0.5])
ortho_1, ortho_2 = UNITVECTOR3D_X, UNITVECTOR3D_Y
plane = Plane(point, ortho_1, ortho_2)
sketch_cylinder = Sketch(plane)
sketch_cylinder.circle(Point2D([0.0, 0.0], unit=unit), radius=0.1)
cylinder = design.extrude_sketch("cylinder", sketch_cylinder, 0.5)

edges = cylinder.faces[1].edges
trimmed_curves = [edges[0].shape]
new_edges, new_faces = box.imprint_curves(faces=[box.faces[1]], trimmed_curves=trimmed_curves)

# the new edge is coming from the circular top edge of the cylinder.
assert new_edges[0].start == new_edges[0].end
# verify that there is one new edge coming from the circle.
assert len(new_faces) == 1
# verify that there is one new face coming from the circle.
assert len(new_edges) == 1
# verify that there are 7 faces in total.
assert len(box.faces) == 7
# verify that there are 14 edges in total.
assert len(box.edges) == 13


def test_copy_body(modeler: Modeler):
"""Test copying a body."""
# Create your design on the server side
Expand Down
Loading