Skip to content

feat: update with delta #1922

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 75 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
b827101
ci: simplify blitz ci
RobPasMue Mar 10, 2025
7039876
fix: translating sketch issues when using a custom default unit (#1808)
RobPasMue Mar 10, 2025
f26f02c
feat: matrix helper methods (#1806)
umutsoysalansys Mar 11, 2025
472f787
new method
umutsoysalansys Mar 11, 2025
6e26772
surface body
umutsoysalansys Mar 13, 2025
ed2c9a5
update with latest tracker for bodies
umutsoysalansys Mar 19, 2025
e224a2f
Merge branch 'main' into feat/update-with-delta
umutsoysalansys Apr 2, 2025
3c376bb
update in tracker
umutsoysalansys Apr 7, 2025
99f00f3
tracker updated
umutsoysalansys Apr 7, 2025
32be1b1
duplicate and inexact faces
umutsoysalansys Apr 8, 2025
3a5d83d
Merge branch 'main' into feat/update-with-delta
umutsoysalansys Apr 17, 2025
b70665c
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Apr 18, 2025
cc05617
chore: adding changelog file 1922.added.md [dependabot-skip]
pyansys-ci-bot Apr 18, 2025
e2a9046
replacing update design inplace
umutsoysalansys Apr 18, 2025
8b94ad8
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Apr 18, 2025
b52d54f
Update problem_areas.py
umutsoysalansys Apr 18, 2025
cc59f6a
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Apr 18, 2025
39f4d38
Merge branch 'main' into feat/update-with-delta
umutsoysalansys Apr 21, 2025
be524f6
fixing function arguments ordre
umutsoysalansys Apr 21, 2025
75f2be0
Update repair_tools.py
umutsoysalansys Apr 21, 2025
4495fdf
fixing function arguments order more
umutsoysalansys Apr 21, 2025
63e7e8c
Merge branch 'main' into feat/update-with-delta
umutsoysalansys Apr 21, 2025
32a042c
remove result
umutsoysalansys Apr 21, 2025
26fa520
Merge branch 'feat/update-with-delta' of https://github.com/ansys/pya…
umutsoysalansys Apr 21, 2025
065921a
test update
umutsoysalansys Apr 21, 2025
1161257
Merge branch 'main' into feat/update-with-delta
umutsoysalansys May 7, 2025
2d3ec4a
closing design after tests
umutsoysalansys May 7, 2025
4b0b124
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] May 7, 2025
9974c3e
Update design.py
umutsoysalansys May 7, 2025
e7fbeb9
Merge branch 'main' into feat/update-with-delta
umutsoysalansys May 8, 2025
91d77f3
Merge branch 'main' into feat/update-with-delta
umutsoysalansys May 13, 2025
35ab917
adding missing mapping for new response fields.
umutsoysalansys May 13, 2025
3782407
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] May 13, 2025
5a109da
object to dict
umutsoysalansys May 19, 2025
9677b6e
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] May 19, 2025
61b5b76
updates
umutsoysalansys May 19, 2025
34ebecf
Merge branch 'feat/update-with-delta' of https://github.com/ansys/pya…
umutsoysalansys May 19, 2025
9a8cbe8
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] May 19, 2025
5f34c57
more serialization
umutsoysalansys May 19, 2025
e486df6
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] May 19, 2025
90ae770
fix constructor order mismatch
umutsoysalansys Jun 3, 2025
61dda5c
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Jun 3, 2025
49f184f
revert test changes
umutsoysalansys Jun 3, 2025
3442dc4
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Jun 3, 2025
244c25e
chore: adding changelog file 1922.added.md [dependabot-skip]
pyansys-ci-bot Jun 3, 2025
44562ce
Update test_repair_tools.py
umutsoysalansys Jun 3, 2025
b71a87b
clean up
umutsoysalansys Jun 3, 2025
b03bc70
Merge branch 'main' into feat/update-with-delta
umutsoysalansys Jun 3, 2025
0626ed0
Merge branch 'main' into feat/update-with-delta
umutsoysalansys Jun 4, 2025
275d382
feature flag
umutsoysalansys Jun 6, 2025
b8cbc56
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Jun 6, 2025
61dc9c6
Update test_repair_tools.py
umutsoysalansys Jun 9, 2025
5cd756a
Update test_repair_tools.py
umutsoysalansys Jun 9, 2025
21f8df2
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Jun 9, 2025
13428c5
clean up
umutsoysalansys Jun 9, 2025
aca836e
Merge branch 'feat/update-with-delta' of https://github.com/ansys/pya…
umutsoysalansys Jun 9, 2025
580e7b7
delete redundant call
umutsoysalansys Jun 9, 2025
17a3056
reverting is alive and the turning the flag on.
umutsoysalansys Jun 9, 2025
d00943e
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Jun 9, 2025
b2945e2
Update problem_areas.py
umutsoysalansys Jun 9, 2025
f1ab0e1
Merge branch 'feat/update-with-delta' of https://github.com/ansys/pya…
umutsoysalansys Jun 9, 2025
a58c412
removing print statements.
umutsoysalansys Jun 9, 2025
3c20f7a
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Jun 9, 2025
9a20caa
serializers are converted to protected methods.
umutsoysalansys Jun 9, 2025
50d2b37
Merge branch 'feat/update-with-delta' of https://github.com/ansys/pya…
umutsoysalansys Jun 9, 2025
ecd7ed3
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Jun 9, 2025
f4ee4cf
Merge branch 'main' into feat/update-with-delta
umutsoysalansys Jun 9, 2025
73fa504
name correction
umutsoysalansys Jun 9, 2025
85a58a7
Merge branch 'feat/update-with-delta' of https://github.com/ansys/pya…
umutsoysalansys Jun 9, 2025
3670858
clean up
umutsoysalansys Jun 9, 2025
1933ec0
logging
umutsoysalansys Jun 10, 2025
b15adb5
chore: auto fixes from pre-commit hooks
pre-commit-ci[bot] Jun 10, 2025
7698a6c
revert the flag to false
umutsoysalansys Jun 10, 2025
4b0f0f1
Merge branch 'main' into feat/update-with-delta
umutsoysalansys Jun 10, 2025
7298adf
Merge branch 'main' into feat/update-with-delta
umutsoysalansys Jun 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/changelog.d/1922.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update with delta
3 changes: 3 additions & 0 deletions src/ansys/geometry/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,6 @@

DOCUMENTATION_BUILD: bool = os.environ.get("PYANSYS_GEOMETRY_DOC_BUILD", "false").lower() == "true"
"""Global flag for the documentation to use the proper PyVista Jupyter backend."""

USE_TRACKER_TO_UPDATE_DESIGN: bool = False
"""Global constant for checking whether to use the tracker to update designs."""
76 changes: 73 additions & 3 deletions src/ansys/geometry/core/_grpc/_services/v0/repair_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,13 +251,19 @@ def find_and_fix_simplify(self, **kwargs) -> dict: # noqa: D102
)
# Call the gRPC service
response = self.stub.FindAndSimplify(request)

serialized_tracker_response = self._serialize_tracker_command_response(
response.complete_command_response
)

# Return the response - formatted as a dictionary
return {
"success": response.success,
"found": response.found,
"repaired": response.repaired,
"created_bodies_monikers": [],
"modified_bodies_monikers": [],
"complete_command_response": serialized_tracker_response,
}

@protect_grpc
Expand All @@ -271,7 +277,7 @@ def inspect_geometry(self, **kwargs) -> dict: # noqa: D102
inspect_result_response = self.stub.InspectGeometry(request)

# Serialize and return the response
return self.serialize_inspect_result_response(inspect_result_response)
return self._serialize_inspect_result_response(inspect_result_response)

@protect_grpc
def repair_geometry(self, **kwargs) -> dict: # noqa: D102
Expand Down Expand Up @@ -326,13 +332,18 @@ def find_and_fix_short_edges(self, **kwargs): # noqa: D102
# Call the gRPC service
response = self.stub.FindAndFixShortEdges(request)

serialized_tracker_response = self._serialize_tracker_command_response(
response.complete_command_response
)

# Return the response - formatted as a dictionary
return {
"success": response.success,
"found": response.found,
"repaired": response.repaired,
"created_bodies_monikers": [],
"modified_bodies_monikers": [],
"complete_command_response": serialized_tracker_response,
}

@protect_grpc
Expand All @@ -346,13 +357,18 @@ def find_and_fix_extra_edges(self, **kwargs) -> dict: # noqa: D102
# Call the gRPC service
response = self.stub.FindAndFixExtraEdges(request)

serialized_tracker_response = self._serialize_tracker_command_response(
response.complete_command_response
)

# Return the response - formatted as a dictionary
return {
"success": response.success,
"found": response.found,
"repaired": response.repaired,
"created_bodies_monikers": response.created_bodies_monikers,
"modified_bodies_monikers": response.modified_bodies_monikers,
"complete_command_response": serialized_tracker_response,
}

@protect_grpc
Expand All @@ -371,17 +387,21 @@ def find_and_fix_split_edges(self, **kwargs) -> dict: # noqa: D102
# Call the gRPC service
response = self.stub.FindAndFixSplitEdges(request)

serialized_tracker_response = self._serialize_tracker_command_response(
response.complete_command_response
)

# Return the response - formatted as a dictionary
return {
"success": response.success,
"found": response.found,
"repaired": response.repaired,
"created_bodies_monikers": [],
"modified_bodies_monikers": [],
"complete_command_response": serialized_tracker_response,
}

@staticmethod
def serialize_inspect_result_response(response) -> dict: # noqa: D102
def _serialize_inspect_result_response(self, response) -> dict: # noqa: D102
def serialize_body(body):
return {
"id": body.id,
Expand Down Expand Up @@ -434,3 +454,53 @@ def serialize_issue(issue):
for body_issues in response.issues_by_body
]
}

def _serialize_tracker_command_response(self, response) -> dict:
"""Serialize a TrackerCommandResponse object into a dictionary.

Parameters
----------
response : TrackerCommandResponse
The gRPC TrackerCommandResponse object to serialize.

Returns
-------
dict
A dictionary representation of the TrackerCommandResponse object.
"""

def serialize_body(body):
return {
"id": body.id,
"name": body.name,
"can_suppress": body.can_suppress,
"transform_to_master": {
"m00": body.transform_to_master.m00,
"m11": body.transform_to_master.m11,
"m22": body.transform_to_master.m22,
"m33": body.transform_to_master.m33,
},
"master_id": body.master_id,
"parent_id": body.parent_id,
}

def serialize_entity_identifier(entity):
"""Serialize an EntityIdentifier object into a dictionary."""
return {
"id": entity.id,
"type": entity.type,
}

return {
"success": response.success,
"created_bodies": [
serialize_body(body) for body in getattr(response, "created_bodies", [])
],
"modified_bodies": [
serialize_body(body) for body in getattr(response, "modified_bodies", [])
],
"deleted_bodies": [
serialize_entity_identifier(entity)
for entity in getattr(response, "deleted_bodies", [])
],
}
11 changes: 10 additions & 1 deletion src/ansys/geometry/core/designer/body.py
Original file line number Diff line number Diff line change
Expand Up @@ -1849,7 +1849,16 @@ def __generic_boolean_command(
for b in other_bodies:
b.parent_component.delete_body(b)

parent_design._update_design_inplace()
from ansys.geometry.core import USE_TRACKER_TO_UPDATE_DESIGN

if not USE_TRACKER_TO_UPDATE_DESIGN:
parent_design._update_design_inplace()
else:
# If USE_TRACKER_TO_UPDATE_DESIGN is True, we serialize the response
# and update the parent design with the serialized response.
tracker_response = response.result.complete_command_response
serialized_response = self._serialize_tracker_command_response(tracker_response)
parent_design._update_from_tracker(serialized_response)

@reset_tessellation_cache
@ensure_design_is_active
Expand Down
174 changes: 174 additions & 0 deletions src/ansys/geometry/core/designer/design.py
Original file line number Diff line number Diff line change
Expand Up @@ -1220,3 +1220,177 @@ def _update_design_inplace(self) -> None:

# Read the existing design
self.__read_existing_design()

def _update_from_tracker(self, tracker_response):
"""
Update the design with the changed bodies while preserving unchanged ones.

Parameters
----------
tracker_response : list[dict]
A list of dictionaries representing tracker response information.
"""
self._grpc_client.log.debug(
f"Starting _update_from_tracker with response: {tracker_response}"
)

# Function to update a body if it exists
def update_body(existing_body, body_info):
self._grpc_client.log.debug(
f"Updating body '{existing_body.name}' (ID: {existing_body.id}) with new info: {body_info}"
)
existing_body.name = body_info["name"]
existing_body._template._is_surface = body_info.get("is_surface", False)

# Function to find and add bodies within components recursively
def find_and_add_body(body_info, component):
self._grpc_client.log.debug(
f"Searching for parent_id {body_info.get('parent_id')} to add body '{body_info['name']}' (ID: {body_info['id']}) within components list."
)
for component in component:
if component.id == body_info["parent_id"]:
new_body = MasterBody(
body_info["id"],
body_info["name"],
self._grpc_client,
is_surface=body_info.get("is_surface", False),
)
component.bodies.append(new_body)
self._grpc_client.log.debug(
f"Added new body '{new_body.name}' (ID: {new_body.id}) to component '{component.name}' (ID: {component.id})."
)

return True # Found and added

# Recursively search in subcomponents
if find_and_add_body(body_info, component.components):
return True

return False # Not found

# Function to find and update bodies within components recursively
def find_and_update_body(body_info, component):
self._grpc_client.log.debug(
f"Searching for body ID {body_info['id']} to update within components list."
)

if component == []:
return False
for body in component.bodies:
if body.id == body_info["id"]:
update_body(body, body_info)
self._grpc_client.log.debug(
f"Updated body '{body.name}' (ID: {body.id}) found in component '{component.name}' (ID: {component.id})."
)
return True # Found and updated

# Recursively search in subcomponents
if find_and_update_body(body_info, component.components):
return True

return False # Not found

# Function to find and remove bodies within components recursively

def find_and_remove_body(body_info, component):
self._grpc_client.log.debug(
f"Searching for body ID {body_info['id']} to remove within components list."
)
if component == []:
return False
for body in component.bodies:
if body.id == body_info["id"]:
# Remove the body from the component
body._is_alive = False # Mark as dead
component.bodies.remove(body)
self._grpc_client.log.debug(
f"Removed body '{body_info['name']}' (ID: {body_info['id']}) from component '{component.name}' (ID: {component.id})."
)

return True # Found and removed

# Recursively search in subcomponents
if find_and_remove_body(body_info, component.components):
return True

return False # Not found

# Loop through all changed bodies from the tracker
for body_info in tracker_response["modified_bodies"]:
self._grpc_client.log.debug(
f"Processing modified body: ID={body_id}, Name='{body_name}'"
)
body_id = body_info["id"]
body_name = body_info["name"]
is_surface = body_info.get(
"is_surface", False
) # Default to False if "is_surface" is missing
updated = False # Track if a body was updated

# First, check bodies at the root level
for body in self.bodies:
if body.id == body_id:
update_body(body, body_info)
updated = True
self._grpc_client.log.debug(
f"Modified body '{body_name}' (ID: {body_id}) found and updated at root level."
)
break

# If not found in root, search within components
if not updated:
for component in self.components:
updated = find_and_update_body(body_info, component)

# Loop through all deleted bodies from the tracker
for body_info in tracker_response["deleted_bodies"]:
self._grpc_client.log.debug(f"Processing deleted body: ID={body_id}")
body_id = body_info["id"]
removed = False # Track if a body was removed

# First, check bodies at the root level
for body in self.bodies:
if body.id == body_id:
body._is_alive = False # Mark as dead
self.bodies.remove(body)
removed = True
self._grpc_client.log.info(
f"Deleted body (ID: {body_id}) removed from root level."
)
break

# If not found in root, search within components
if not removed:
removed = find_and_remove_body(body_info, self.components)

# Loop through all added bodies from the tracker
for body_info in tracker_response["created_bodies"]:
self._grpc_client.log.debug(
f"Processing created body: ID={body_id}, Name='{body_name}'"
)
body_id = body_info["id"]
body_name = body_info["name"]
is_surface = body_info["is_surface"]

added = False # Track if a body was added

# First, check if the body already exists at the root level
for body in self.bodies:
if body.id == body_id:
added = True
self._grpc_client.log.debug(
f"Created body '{body_name}' (ID: {body_id}) already exists at root level (skipped adding)."
)
break

# If not found in root, search within components
if not added:
added = find_and_add_body(body_info, self.components)

# If still not found, add it as a new body at the root level
if not added:
new_body = MasterBody(body_id, body_name, self._grpc_client, is_surface=is_surface)
self.bodies.append(new_body)
self._grpc_client.log.debug(
f"Added new body '{new_body.name}' (ID: {new_body.id}) to root level as no parent was found."
)
10 changes: 5 additions & 5 deletions src/ansys/geometry/core/tools/prepare_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,11 +266,11 @@ def enhanced_share_topology(
)

message = RepairToolMessage(
response.get("success"),
response.get("created_bodies_monikers"),
response.get("modified_bodies_monikers"),
response.get("found"),
response.get("repaired"),
success=response.get("success"),
created_bodies=response.get("created_bodies_monikers"),
modified_bodies=response.get("modified_bodies_monikers"),
found=response.get("found"),
repaired=response.get("repaired"),
)
return message

Expand Down
Loading
Loading