Skip to content

Commit 7502957

Browse files
umutsoysalansysRobPasMuepyansys-ci-botpre-commit-ci[bot]
authored
feat: update with delta (#1922)
Co-authored-by: Roberto Pastor Muela <37798125+RobPasMue@users.noreply.github.com> Co-authored-by: pyansys-ci-bot <92810346+pyansys-ci-bot@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 9ba6307 commit 7502957

File tree

10 files changed

+452
-56
lines changed

10 files changed

+452
-56
lines changed

doc/changelog.d/1922.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Update with delta

src/ansys/geometry/core/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,6 @@
7070

7171
DOCUMENTATION_BUILD: bool = os.environ.get("PYANSYS_GEOMETRY_DOC_BUILD", "false").lower() == "true"
7272
"""Global flag for the documentation to use the proper PyVista Jupyter backend."""
73+
74+
USE_TRACKER_TO_UPDATE_DESIGN: bool = False
75+
"""Global constant for checking whether to use the tracker to update designs."""

src/ansys/geometry/core/_grpc/_services/v0/repair_tools.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,13 +344,18 @@ def find_and_fix_simplify(self, **kwargs) -> dict: # noqa: D102
344344
# Call the gRPC service
345345
response = self.stub.FindAndSimplify(request)
346346

347+
serialized_tracker_response = self._serialize_tracker_command_response(
348+
response.complete_command_response
349+
)
350+
347351
# Return the response - formatted as a dictionary
348352
return {
349353
"success": response.success,
350354
"found": response.found,
351355
"repaired": response.repaired,
352356
"created_bodies_monikers": [],
353357
"modified_bodies_monikers": [],
358+
"complete_command_response": serialized_tracker_response,
354359
}
355360

356361
@protect_grpc
@@ -378,13 +383,18 @@ def find_and_fix_stitch_faces(self, **kwargs) -> dict: # noqa: D102
378383
# Call the gRPC service
379384
response = self.stub.FindAndFixStitchFaces(request)
380385

386+
serialized_tracker_response = self._serialize_tracker_command_response(
387+
response.complete_command_response
388+
)
389+
381390
# Return the response - formatted as a dictionary
382391
return {
383392
"success": response.success,
384393
"created_bodies_monikers": response.created_bodies_monikers,
385394
"modified_bodies_monikers": response.modified_bodies_monikers,
386395
"found": response.found,
387396
"repaired": response.repaired,
397+
"complete_command_response": serialized_tracker_response,
388398
}
389399

390400
@protect_grpc
@@ -457,13 +467,18 @@ def find_and_fix_short_edges(self, **kwargs): # noqa: D102
457467
# Call the gRPC service
458468
response = self.stub.FindAndFixShortEdges(request)
459469

470+
serialized_tracker_response = self._serialize_tracker_command_response(
471+
response.complete_command_response
472+
)
473+
460474
# Return the response - formatted as a dictionary
461475
return {
462476
"success": response.success,
463477
"found": response.found,
464478
"repaired": response.repaired,
465479
"created_bodies_monikers": [],
466480
"modified_bodies_monikers": [],
481+
"complete_command_response": serialized_tracker_response,
467482
}
468483

469484
@protect_grpc
@@ -479,13 +494,18 @@ def find_and_fix_extra_edges(self, **kwargs) -> dict: # noqa: D102
479494
# Call the gRPC service
480495
response = self.stub.FindAndFixExtraEdges(request)
481496

497+
serialized_tracker_response = self._serialize_tracker_command_response(
498+
response.complete_command_response
499+
)
500+
482501
# Return the response - formatted as a dictionary
483502
return {
484503
"success": response.success,
485504
"found": response.found,
486505
"repaired": response.repaired,
487506
"created_bodies_monikers": response.created_bodies_monikers,
488507
"modified_bodies_monikers": response.modified_bodies_monikers,
508+
"complete_command_response": serialized_tracker_response,
489509
}
490510

491511
@protect_grpc
@@ -505,13 +525,18 @@ def find_and_fix_split_edges(self, **kwargs) -> dict: # noqa: D102
505525
# Call the gRPC service
506526
response = self.stub.FindAndFixSplitEdges(request)
507527

528+
serialized_tracker_response = self._serialize_tracker_command_response(
529+
response.complete_command_response
530+
)
531+
508532
# Return the response - formatted as a dictionary
509533
return {
510534
"success": response.success,
511535
"found": response.found,
512536
"repaired": response.repaired,
513537
"created_bodies_monikers": [],
514538
"modified_bodies_monikers": [],
539+
"complete_command_response": serialized_tracker_response,
515540
}
516541

517542
def __serialize_inspect_result_response(self, response) -> dict: # noqa: D102
@@ -567,3 +592,52 @@ def serialize_issue(issue):
567592
for body_issues in response.issues_by_body
568593
]
569594
}
595+
596+
def _serialize_tracker_command_response(self, response) -> dict:
597+
"""Serialize a TrackerCommandResponse object into a dictionary.
598+
599+
Parameters
600+
----------
601+
response : TrackerCommandResponse
602+
The gRPC TrackerCommandResponse object to serialize.
603+
604+
Returns
605+
-------
606+
dict
607+
A dictionary representation of the TrackerCommandResponse object.
608+
"""
609+
610+
def serialize_body(body):
611+
return {
612+
"id": body.id,
613+
"name": body.name,
614+
"can_suppress": body.can_suppress,
615+
"transform_to_master": {
616+
"m00": body.transform_to_master.m00,
617+
"m11": body.transform_to_master.m11,
618+
"m22": body.transform_to_master.m22,
619+
"m33": body.transform_to_master.m33,
620+
},
621+
"master_id": body.master_id,
622+
"parent_id": body.parent_id,
623+
}
624+
625+
def serialize_entity_identifier(entity):
626+
"""Serialize an EntityIdentifier object into a dictionary."""
627+
return {
628+
"id": entity.id,
629+
}
630+
631+
return {
632+
"success": response.success,
633+
"created_bodies": [
634+
serialize_body(body) for body in getattr(response, "created_bodies", [])
635+
],
636+
"modified_bodies": [
637+
serialize_body(body) for body in getattr(response, "modified_bodies", [])
638+
],
639+
"deleted_bodies": [
640+
serialize_entity_identifier(entity)
641+
for entity in getattr(response, "deleted_bodies", [])
642+
],
643+
}

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1940,7 +1940,16 @@ def __generic_boolean_command(
19401940
for b in other_bodies:
19411941
b.parent_component.delete_body(b)
19421942

1943-
parent_design._update_design_inplace()
1943+
from ansys.geometry.core import USE_TRACKER_TO_UPDATE_DESIGN
1944+
1945+
if not USE_TRACKER_TO_UPDATE_DESIGN:
1946+
parent_design._update_design_inplace()
1947+
else:
1948+
# If USE_TRACKER_TO_UPDATE_DESIGN is True, we serialize the response
1949+
# and update the parent design with the serialized response.
1950+
tracker_response = response.result.complete_command_response
1951+
serialized_response = self._serialize_tracker_command_response(tracker_response)
1952+
parent_design._update_from_tracker(serialized_response)
19441953

19451954
@reset_tessellation_cache
19461955
@ensure_design_is_active

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

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,3 +1254,141 @@ def _update_design_inplace(self) -> None:
12541254

12551255
# Read the existing design
12561256
self.__read_existing_design()
1257+
1258+
def _update_from_tracker(self, tracker_response: list[dict]):
1259+
"""Update the design with the changed bodies while preserving unchanged ones."""
1260+
self._grpc_client.log.debug(
1261+
f"Starting _update_from_tracker with response: {tracker_response}"
1262+
)
1263+
self._handle_modified_bodies(tracker_response.get("modified_bodies", []))
1264+
self._handle_deleted_bodies(tracker_response.get("deleted_bodies", []))
1265+
self._handle_created_bodies(tracker_response.get("created_bodies", []))
1266+
1267+
def _handle_modified_bodies(self, modified_bodies):
1268+
for body_info in modified_bodies:
1269+
body_id = body_info["id"]
1270+
body_name = body_info["name"]
1271+
self._grpc_client.log.debug(
1272+
f"Processing modified body: ID={body_id}, Name='{body_name}'"
1273+
)
1274+
updated = False
1275+
1276+
for body in self.bodies:
1277+
if body.id == body_id:
1278+
self._update_body(body, body_info)
1279+
updated = True
1280+
self._grpc_client.log.debug(
1281+
f"Modified body '{body_name}' (ID: {body_id}) updated at root level."
1282+
)
1283+
break
1284+
1285+
if not updated:
1286+
for component in self.components:
1287+
if self._find_and_update_body(body_info, component):
1288+
break
1289+
1290+
def _handle_deleted_bodies(self, deleted_bodies):
1291+
for body_info in deleted_bodies:
1292+
body_id = body_info["id"]
1293+
self._grpc_client.log.debug(f"Processing deleted body: ID={body_id}")
1294+
removed = False
1295+
1296+
for body in self.bodies:
1297+
if body.id == body_id:
1298+
body._is_alive = False
1299+
self.bodies.remove(body)
1300+
removed = True
1301+
self._grpc_client.log.info(
1302+
f"Deleted body (ID: {body_id}) removed from root level."
1303+
)
1304+
break
1305+
1306+
if not removed:
1307+
for component in self.components:
1308+
if self._find_and_remove_body(body_info, component):
1309+
break
1310+
1311+
def _handle_created_bodies(self, created_bodies):
1312+
for body_info in created_bodies:
1313+
body_id = body_info["id"]
1314+
body_name = body_info["name"]
1315+
is_surface = body_info.get("is_surface", False)
1316+
self._grpc_client.log.debug(
1317+
f"Processing created body: ID={body_id}, Name='{body_name}'"
1318+
)
1319+
1320+
if any(body.id == body_id for body in self.bodies):
1321+
self._grpc_client.log.debug(
1322+
f"Created body '{body_name}' (ID: {body_id}) already exists at root level."
1323+
)
1324+
continue
1325+
1326+
added = any(self._find_and_add_body(body_info, self.components))
1327+
if not added:
1328+
new_body = MasterBody(body_id, body_name, self._grpc_client, is_surface=is_surface)
1329+
self.bodies.append(new_body)
1330+
self._grpc_client.log.debug(
1331+
f"Added new body '{body_name}' (ID: {body_id}) to root level."
1332+
)
1333+
1334+
def _update_body(self, existing_body, body_info):
1335+
self._grpc_client.log.debug(
1336+
f"Updating body '{existing_body.name}' "
1337+
f"(ID: {existing_body.id}) with new info: {body_info}"
1338+
)
1339+
existing_body.name = body_info["name"]
1340+
existing_body._template._is_surface = body_info.get("is_surface", False)
1341+
1342+
def _find_and_add_body(self, body_info, components):
1343+
for component in components:
1344+
if component.id == body_info["parent_id"]:
1345+
new_body = MasterBody(
1346+
body_info["id"],
1347+
body_info["name"],
1348+
self._grpc_client,
1349+
is_surface=body_info.get("is_surface", False),
1350+
)
1351+
component.bodies.append(new_body)
1352+
self._grpc_client.log.debug(
1353+
f"Added new body '{new_body.name}' (ID: {new_body.id}) "
1354+
f"to component '{component.name}' (ID: {component.id})"
1355+
)
1356+
return True
1357+
1358+
if self._find_and_add_body(body_info, component.components):
1359+
return True
1360+
1361+
return False
1362+
1363+
def _find_and_update_body(self, body_info, component):
1364+
for body in component.bodies:
1365+
if body.id == body_info["id"]:
1366+
self._update_body(body, body_info)
1367+
self._grpc_client.log.debug(
1368+
f"Updated body '{body.name}' (ID: {body.id}) in component "
1369+
f"'{component.name}' (ID: {component.id})"
1370+
)
1371+
return True
1372+
1373+
for subcomponent in component.components:
1374+
if self._find_and_update_body(body_info, subcomponent):
1375+
return True
1376+
1377+
return False
1378+
1379+
def _find_and_remove_body(self, body_info, component):
1380+
for body in component.bodies:
1381+
if body.id == body_info["id"]:
1382+
body._is_alive = False
1383+
component.bodies.remove(body)
1384+
self._grpc_client.log.debug(
1385+
f"Removed body '{body_info['name']}' (ID: {body_info['id']}) from component "
1386+
f"'{component.name}' (ID: {component.id})"
1387+
)
1388+
return True
1389+
1390+
for subcomponent in component.components:
1391+
if self._find_and_remove_body(body_info, subcomponent):
1392+
return True
1393+
1394+
return False

src/ansys/geometry/core/tools/prepare_tools.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,9 @@ def enhanced_share_topology(
270270
from ansys.geometry.core.designer.body import Body
271271

272272
if not bodies:
273-
return RepairToolMessage(False, [], [], 0, 0)
273+
return RepairToolMessage(
274+
success=False, created_bodies=[], modified_bodies=[], found=0, repaired=0
275+
)
274276

275277
# Verify inputs
276278
check_type_all_elements_in_iterable(bodies, Body)
@@ -282,11 +284,11 @@ def enhanced_share_topology(
282284
)
283285

284286
message = RepairToolMessage(
285-
response.get("success"),
286-
response.get("created_bodies_monikers"),
287-
response.get("modified_bodies_monikers"),
288-
response.get("found"),
289-
response.get("repaired"),
287+
success=response.get("success"),
288+
created_bodies=response.get("created_bodies_monikers"),
289+
modified_bodies=response.get("modified_bodies_monikers"),
290+
found=response.get("found"),
291+
repaired=response.get("repaired"),
290292
)
291293
return message
292294

0 commit comments

Comments
 (0)