Skip to content

feat: add tracker v0 #1881

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions doc/changelog.d/1881.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add tracker v0
11 changes: 9 additions & 2 deletions src/ansys/geometry/core/tools/problem_areas.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
)
from ansys.geometry.core.misc.checks import check_type_all_elements_in_iterable
from ansys.geometry.core.tools.repair_tool_message import RepairToolMessage
from ansys.geometry.core.tools.tracker_response_message import TrackerResponseMessage

if TYPE_CHECKING: # pragma: no cover
from ansys.geometry.core.designer.body import Body
Expand Down Expand Up @@ -135,6 +136,7 @@ def fix(self) -> RepairToolMessage:
response.result.success,
response.result.created_bodies_monikers,
response.result.modified_bodies_monikers,
tracked_changes=TrackerResponseMessage(response.result.complete_command_response),
)

return message
Expand Down Expand Up @@ -190,6 +192,7 @@ def fix(self) -> RepairToolMessage:
response.result.success,
response.result.created_bodies_monikers,
response.result.modified_bodies_monikers,
tracked_changes=TrackerResponseMessage(response.result.complete_command_response),
)
return message

Expand Down Expand Up @@ -244,6 +247,7 @@ def fix(self) -> RepairToolMessage:
response.result.success,
response.result.created_bodies_monikers,
response.result.modified_bodies_monikers,
tracked_changes=TrackerResponseMessage(response.result.complete_command_response),
)
return message

Expand Down Expand Up @@ -297,6 +301,7 @@ def fix(self) -> RepairToolMessage:
response.result.success,
response.result.created_bodies_monikers,
response.result.modified_bodies_monikers,
tracked_changes=TrackerResponseMessage(response.result.complete_command_response),
)

return message
Expand Down Expand Up @@ -398,15 +403,16 @@ def fix(self) -> RepairToolMessage:
if not self.faces:
return RepairToolMessage(False, [], [])

parent_design = get_design_from_face(self.faces[0])
# parent_design = get_design_from_face(self.faces[0])
response = self._repair_stub.FixSmallFaces(
FixSmallFacesRequest(small_face_problem_area_id=self._grpc_id)
)
parent_design._update_design_inplace()
# parent_design._update_design_inplace()
message = RepairToolMessage(
response.result.success,
response.result.created_bodies_monikers,
response.result.modified_bodies_monikers,
tracked_changes=TrackerResponseMessage(response.result.complete_command_response),
)
return message

Expand Down Expand Up @@ -461,6 +467,7 @@ def fix(self) -> RepairToolMessage:
response.result.success,
response.result.created_bodies_monikers,
response.result.modified_bodies_monikers,
tracked_changes=TrackerResponseMessage(response.result.complete_command_response),
)
return message

Expand Down
12 changes: 11 additions & 1 deletion src/ansys/geometry/core/tools/repair_tool_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
# SOFTWARE.
"""Module for repair tool message."""

from ansys.geometry.core.tools.tracker_response_message import TrackerResponseMessage


class RepairToolMessage:
"""Provides return message for the repair tool methods."""
Expand All @@ -32,6 +34,7 @@ def __init__(
modified_bodies: list[str],
found: int = -1,
repaired: int = -1,
tracked_changes: TrackerResponseMessage = None,
):
"""Initialize a new instance of the extra edge problem area class.

Expand All @@ -49,14 +52,16 @@ def __init__(
repaired: int, default: -1
Number of problem areas repaired during the repair operation.
If default, the operation does not provide the number of fixed problem areas.

tracked_changes: TrackerResponseChanges, default: None
The tracked changes from the repair operation.

"""
self._success = success
self._created_bodies = created_bodies
self._modified_bodies = modified_bodies
self._found = found
self._repaired = repaired
self._tracked_changes = tracked_changes

@property
def success(self) -> bool:
Expand All @@ -82,3 +87,8 @@ def found(self) -> int:
def repaired(self) -> int:
"""Number of problem areas repaired during the repair operation."""
return self._repaired

@property
def tracked_changes(self) -> TrackerResponseMessage:
"""The tracked changes from the repair operation."""
return self._tracked_changes
142 changes: 142 additions & 0 deletions src/ansys/geometry/core/tools/tracker_response_message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# 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 for tracker response message."""

# from typing import TYPE_CHECKING

# if TYPE_CHECKING: # pragma: no cover
# from ansys.geometry.core.designer.body import Body

from ansys.api.geometry.v0.models_pb2 import TrackerCommandResponse


class TrackerResponseMessage:
"""Provides response for tracked functionality."""

# def __init__(
# self,
# success: bool,
# created_bodies: list[str],
# modified_bodies: list[str],
# deleted_bodies: list[str],
# created_components: list[str],
# modified_components: list[str],
# deleted_components: list[str],
# ):
# """Initialize the TrackerResponseMessage instance.

# Parameters
# ----------
# success: bool
# True if the tracking was successful, false if it is not.
# created_bodies: list[str]
# List of bodies created during tracked operation.
# modified_bodies: list[str]
# List of bodies modified during tracked operation.
# deleted_bodies: list[str]
# List of bodies deleted during tracked operation.
# created_components: list[str]
# List of components created during tracked operation.
# modified_components: list[str]
# List of components modified during tracked operation.
# deleted_components: list[str]
# List of components deleted during tracked operation.

# """
# self._success = success
# self._created_bodies = created_bodies
# self._modified_bodies = modified_bodies
# self._deleted_bodies = deleted_bodies
# self._created_components = created_components
# self._modified_components = modified_components
# self._deleted_components = deleted_components

def __init__(
self,
message: TrackerCommandResponse,
):
"""Initialize the TrackerResponseMessage instance from another message."""
self._success = message.success
created_body_list = []
for body in message.created_bodies:
created_body_list.append(body.id)
self._created_bodies = created_body_list

modified_body_list = []
for body in message.modified_bodies:
modified_body_list.append(body.id)
self._modified_bodies = modified_body_list

deleted_body_list = []
for body in message.deleted_bodies:
deleted_body_list.append(body.id)
self._deleted_bodies = deleted_body_list

created_component_list = []
for component in message.created_components:
created_component_list.append(component.id)
self._created_components = created_component_list

modified_component_list = []
for component in message.modified_components:
modified_component_list.append(component.id)
self._modified_components = modified_component_list

deleted_component_list = []
for component in message.deleted_components:
deleted_component_list.append(component.id)
self._deleted_components = deleted_component_list

@property
def success(self) -> bool:
"""Return success status."""
return self._success

@property
def created_bodies(self) -> list[str]:
"""Return list of created bodies."""
return self._created_bodies

@property
def modified_bodies(self) -> list[str]:
"""Return list of modified bodies."""
return self._modified_bodies

@property
def deleted_bodies(self) -> list[str]:
"""Return list of deleted bodies."""
return self._deleted_bodies

@property
def created_components(self) -> list[str]:
"""Return list of created components."""
return self._created_components

@property
def modified_components(self) -> list[str]:
"""Return list of modified components."""
return self._modified_components

@property
def deleted_components(self) -> list[str]:
"""Return list of deleted components."""
return self._deleted_components
47 changes: 40 additions & 7 deletions tests/integration/test_repair_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ def test_fix_split_edge(modeler: Modeler):
"""Test to find and fix split edge problem areas."""
design = modeler.open_file(FILES_DIR / "SplitEdgeDesignTest.scdocx")
problem_areas = modeler.repair_tools.find_split_edges(design.bodies, 25, 150)
assert problem_areas[0].fix().success is True
message = problem_areas[0].fix()
assert message.success is True
assert len(message.tracked_changes.modified_components) == 1


def test_find_extra_edges(modeler: Modeler):
Expand Down Expand Up @@ -82,7 +84,9 @@ def test_fix_extra_edge(modeler: Modeler):
"""Test to find and fix extra edge problem areas."""
design = modeler.open_file(FILES_DIR / "ExtraEdgesDesignBefore.scdocx")
problem_areas = modeler.repair_tools.find_extra_edges(design.bodies)
assert problem_areas[0].fix().success is True
message = problem_areas[0].fix()
assert message.success is True
assert len(message.tracked_changes.modified_components) == 1


def test_find_inexact_edges(modeler: Modeler):
Expand Down Expand Up @@ -114,7 +118,9 @@ def test_fix_inexact_edge(modeler: Modeler):
"""
design = modeler.open_file(FILES_DIR / "InExactEdgesBefore.scdocx")
problem_areas = modeler.repair_tools.find_inexact_edges(design.bodies)
assert problem_areas[0].fix().success is True
message = problem_areas[0].fix()
assert message.success is True
assert len(message.tracked_changes.modified_components) == 1


def test_find_missing_faces(modeler: Modeler):
Expand Down Expand Up @@ -146,7 +152,10 @@ def test_fix_missing_face(modeler: Modeler):
"""
design = modeler.open_file(FILES_DIR / "MissingFacesDesignBefore.scdocx")
problem_areas = modeler.repair_tools.find_missing_faces(design.bodies)
assert problem_areas[0].fix().success is True
message = problem_areas[0].fix()
assert message.success is True
assert len(message.tracked_changes.modified_bodies) == 1
assert len(message.tracked_changes.modified_components) == 1


def test_find_duplicate_faces(modeler: Modeler):
Expand Down Expand Up @@ -178,7 +187,10 @@ def test_fix_duplicate_face(modeler: Modeler):
"""
design = modeler.open_file(FILES_DIR / "DuplicateFacesDesignBefore.scdocx")
problem_areas = modeler.repair_tools.find_duplicate_faces(design.bodies)
assert problem_areas[0].fix().success is True
message = problem_areas[0].fix()
assert message.success is True
assert len(message.tracked_changes.deleted_bodies) == 1
assert len(message.tracked_changes.modified_components) == 1


def test_find_small_faces(modeler: Modeler):
Expand Down Expand Up @@ -208,7 +220,10 @@ def test_find_small_face_faces(modeler: Modeler):
) # Skip test on CoreService
design = modeler.open_file(FILES_DIR / "SmallFacesBefore.scdocx")
problem_areas = modeler.repair_tools.find_small_faces(design.bodies)
assert len(problem_areas[0].faces) > 0
assert len(problem_areas[0].faces) == 1
assert len(problem_areas[1].faces) == 1
assert len(problem_areas[2].faces) == 1
assert len(problem_areas[3].faces) == 1


def test_fix_small_face(modeler: Modeler):
Expand All @@ -217,7 +232,25 @@ def test_fix_small_face(modeler: Modeler):
skip_if_core_service(modeler, test_fix_small_face.__name__, "repair_tools")
design = modeler.open_file(FILES_DIR / "SmallFacesBefore.scdocx")
problem_areas = modeler.repair_tools.find_small_faces(design.bodies)
assert problem_areas[0].fix().success is True
result = problem_areas[0].fix()
assert result.success is True
# There's a potential bug here. The test model can't remove it's small faces. Regardless,
# think we need to revisit some of the logic in this tool (and maybe the repair tools in
# general).
# assert len(result.tracked_changes.modified_bodies) == 1, "Modified bodies should be 1"
# assert len(result.tracked_changes.modified_components) == 1, "Modified components should be 1"
# result = problem_areas[1].fix()
# assert result.success is True
# assert len(result.tracked_changes.modified_bodies) == 1, "Modified bodies should be 1"
# assert len(result.tracked_changes.modified_components) == 1, "Modified components should be 1"
# result = problem_areas[2].fix()
# assert result.success is True
# assert len(result.tracked_changes.modified_bodies) == 1, "Modified bodies should be 1"
# assert len(result.tracked_changes.modified_components) == 1, "Modified components should be 1"
# result = problem_areas[3].fix()
# assert result.success is True
# assert len(result.tracked_changes.modified_bodies) == 1, "Modified bodies should be 1"
# assert len(result.tracked_changes.modified_components) == 1, "Modified components should be 1"


def test_find_stitch_faces(modeler: Modeler):
Expand Down
Loading