Skip to content

feat: Find and Fix Stitch Faces/Missing Faces Enhancements #1953

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions doc/changelog.d/1953.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Find and Fix Stitch Faces/Missing Faces Enhancements
95 changes: 91 additions & 4 deletions src/ansys/geometry/core/tools/repair_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
check_type_all_elements_in_iterable,
min_backend_version,
)
from ansys.geometry.core.misc.measurements import Angle, Distance
from ansys.geometry.core.tools.check_geometry import GeometryIssue, InspectResult
from ansys.geometry.core.tools.problem_areas import (
DuplicateFaceProblemAreas,
Expand Down Expand Up @@ -280,7 +281,12 @@ def find_duplicate_faces(self, bodies: list["Body"]) -> list[DuplicateFaceProble
]

@protect_grpc
def find_missing_faces(self, bodies: list["Body"]) -> list[MissingFaceProblemAreas]:
def find_missing_faces(
self,
bodies: list["Body"],
angle: Angle = None,
distance: Distance = None,
) -> list[MissingFaceProblemAreas]:
"""Find the missing faces.

This method find the missing face problem areas and returns a list of missing
Expand All @@ -300,7 +306,11 @@ def find_missing_faces(self, bodies: list["Body"]) -> list[MissingFaceProblemAre
return []
body_ids = [body.id for body in bodies]
problem_areas_response = self._repair_stub.FindMissingFaces(
FindMissingFacesRequest(faces=body_ids)
FindMissingFacesRequest(
faces=body_ids,
distance=DoubleValue(value=distance.value) if distance else None,
angle=DoubleValue(value=angle.value) if angle else None,
)
)
parent_design = get_design_from_body(bodies[0])

Expand Down Expand Up @@ -349,7 +359,11 @@ def find_small_faces(self, bodies: list["Body"]) -> list[SmallFaceProblemAreas]:
]

@protect_grpc
def find_stitch_faces(self, bodies: list["Body"]) -> list[StitchFaceProblemAreas]:
def find_stitch_faces(
self,
bodies: list["Body"],
max_distance: Distance = None,
) -> list[StitchFaceProblemAreas]:
"""Return the list of stitch face problem areas.

This method find the stitch face problem areas and returns a list of ids of stitch face
Expand All @@ -367,7 +381,10 @@ def find_stitch_faces(self, bodies: list["Body"]) -> list[StitchFaceProblemAreas
"""
body_ids = [body.id for body in bodies]
problem_areas_response = self._repair_stub.FindStitchFaces(
FindStitchFacesRequest(faces=body_ids)
FindStitchFacesRequest(
faces=body_ids,
maximum_distance=DoubleValue(value=max_distance) if max_distance else None,
)
)
parent_design = get_design_from_body(bodies[0])
return [
Expand Down Expand Up @@ -685,6 +702,76 @@ def find_and_fix_simplify(
)
return message

@protect_grpc
@min_backend_version(25, 2, 0)
def find_and_fix_stitch_faces(
self,
bodies: list["Body"],
max_distance: Distance = None,
allow_multiple_bodies: bool = False,
maintain_components: bool = True,
check_for_coincidence: bool = False,
comprehensive_result: bool = False,
) -> RepairToolMessage:
"""Find and fix the stitch face problem areas.

Parameters
----------
bodies : list[Body]
List of bodies that stitchable faces are investigated on.
max_distance : Real, optional
The maximum distance between faces to be stitched.
By default, 0.0001.
allow_multiple_bodies : bool, optional
Whether to allow multiple bodies in the result.
By default, False.
maintain_components : bool, optional
Whether to stitch bodies within the components.
By default, True.
check_for_coincidence : bool, optional
Whether coincidence surfaces are searched.
By default, False.
comprehensive_result : bool, optional
Whether to fix all problem areas individually.
By default, False.

Returns
-------
RepairToolMessage
Message containing number of problem areas found/fixed, created and/or modified bodies.

Notes
-----
This method finds the stitchable faces and fixes them.
"""
from ansys.geometry.core.designer.body import Body

check_type_all_elements_in_iterable(bodies, Body)

body_ids = [body.id for body in bodies]

response = self._repair_stub.FindAndFixStitchFaces(
FindStitchFacesRequest(
faces=body_ids,
maximum_distance=DoubleValue(value=max_distance) if max_distance else None,
allow_multiple_bodies=BoolValue(value=allow_multiple_bodies),
maintain_components=BoolValue(value=maintain_components),
check_for_coincidence=BoolValue(value=check_for_coincidence),
comprehensive=comprehensive_result,
)
)

parent_design = get_design_from_body(bodies[0])
parent_design._update_design_inplace()
message = RepairToolMessage(
response.success,
response.created_bodies_monikers,
response.modified_bodies_monikers,
response.found,
response.repaired,
)
return message

@protect_grpc
@min_backend_version(25, 2, 0)
def inspect_geometry(self, bodies: list["Body"] = None) -> list[InspectResult]:
Expand Down
Binary file added tests/integration/files/stitch_1200_bodies.dsco
Binary file not shown.
26 changes: 26 additions & 0 deletions tests/integration/test_repair_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,32 @@ def test_find_and_stitch_and_missing_faces(modeler: Modeler):
assert not design.bodies[0].is_surface


def test_find_and_fix_stitch_faces(modeler: Modeler):
"""Test to find and fix stitch faces and validate that we get a solid."""
design = modeler.open_file(FILES_DIR / "stitch_1200_bodies.dsco")
assert len(design.bodies) == 3600

stitch_faces = modeler.repair_tools.find_and_fix_stitch_faces(design.bodies)
assert stitch_faces.found == 1
assert stitch_faces.repaired == 1

assert len(design.bodies) == 1200


def test_find_and_fix_stitch_faces_comprehensive(modeler: Modeler):
"""Test to find and fix stitch faces and validate that we get a solid."""
design = modeler.open_file(FILES_DIR / "stitch_1200_bodies.dsco")
assert len(design.bodies) == 3600

stitch_faces = modeler.repair_tools.find_and_fix_stitch_faces(
design.bodies, comprehensive_result=True
)
assert stitch_faces.found == 1200
assert stitch_faces.repaired == 1200

assert len(design.bodies) == 1200


def test_find_simplify(modeler: Modeler):
"""Test to read geometry and find it's unsimplified face problem areas."""
design = modeler.open_file(FILES_DIR / "SOBracket2_HalfModel.scdocx")
Expand Down
Loading