Skip to content

Commit 115af74

Browse files
jacobrkerstetterpre-commit-ci[bot]pyansys-ci-botRobPasMue
authored
feat: add Named Selections query to geometric entities (#2356)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: pyansys-ci-bot <[email protected]> Co-authored-by: Roberto Pastor Muela <[email protected]>
1 parent c0513b1 commit 115af74

File tree

15 files changed

+398
-16
lines changed

15 files changed

+398
-16
lines changed

doc/changelog.d/2356.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add Named Selections query to geometric entities

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,14 @@ def serialize_beam(beam):
429429
"cross_section": serialize_beam_cross_section(beam.cross_section),
430430
}
431431

432+
def serialize_design_point(design_point):
433+
return {
434+
"id": design_point.id,
435+
"name": design_point.owner_name,
436+
"point": from_grpc_point_to_point3d(design_point.points[0]),
437+
"parent_id": design_point.parent_id.id,
438+
}
439+
432440
parts = getattr(response, "parts", [])
433441
transformed_parts = getattr(response, "transformed_parts", [])
434442
bodies = getattr(response, "bodies", [])
@@ -438,6 +446,7 @@ def serialize_beam(beam):
438446
component_coordinate_systems = getattr(response, "component_coord_systems", [])
439447
component_shared_topologies = getattr(response, "component_shared_topologies", [])
440448
beams = getattr(response, "beams", [])
449+
design_points = getattr(response, "design_points", [])
441450
return {
442451
"parts": [serialize_part(part) for part in parts] if len(parts) > 0 else [],
443452
"transformed_parts": [serialize_transformed_part(tp) for tp in transformed_parts],
@@ -452,6 +461,7 @@ def serialize_beam(beam):
452461
component_shared_topologies
453462
),
454463
"beams": [serialize_beam(beam) for beam in beams],
464+
"design_points": [serialize_design_point(dp) for dp in design_points],
455465
}
456466

457467
@protect_grpc

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from ansys.geometry.core.errors import protect_grpc
2727

2828
from ..base.named_selection import GRPCNamedSelectionService
29-
from .conversions import build_grpc_id, from_grpc_point_to_point3d
29+
from .conversions import build_grpc_id
3030

3131

3232
class GRPCNamedSelectionServiceV0(GRPCNamedSelectionService):
@@ -64,9 +64,7 @@ def get_named_selection(self, **kwargs): # noqa: D102
6464
"faces": [face.id for face in response.faces],
6565
"edges": [edge.id for edge in response.edges],
6666
"beams": [beam.id.id for beam in response.beams],
67-
"design_points": [
68-
(dp.id, from_grpc_point_to_point3d(dp.points[0])) for dp in response.design_points
69-
],
67+
"design_points": [dp.id for dp in response.design_points],
7068
"components": [comp.id for comp in response.components],
7169
"vertices": [vertex.id.id for vertex in response.vertices],
7270
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@
3030
from ansys.geometry.core.math.frame import Frame
3131
from ansys.geometry.core.math.point import Point3D
3232
from ansys.geometry.core.math.vector import UnitVector3D
33+
from ansys.geometry.core.misc.auxiliary import get_design_from_component
3334
from ansys.geometry.core.misc.checks import check_type
3435
from ansys.geometry.core.misc.measurements import Distance
3536
from ansys.geometry.core.shapes.curves.trimmed_curve import TrimmedCurve
3637
from ansys.geometry.core.shapes.parameterization import ParamUV
3738

3839
if TYPE_CHECKING: # pragma: no cover
3940
from ansys.geometry.core.designer.component import Component
41+
from ansys.geometry.core.designer.selection import NamedSelection
4042

4143

4244
class BeamType(Enum):
@@ -422,6 +424,21 @@ def is_alive(self) -> bool:
422424
"""Flag indicating whether the beam is still alive on the server."""
423425
return self._is_alive
424426

427+
def get_named_selections(self) -> list["NamedSelection"]:
428+
"""Get the named selections that include this beam.
429+
430+
Returns
431+
-------
432+
list[NamedSelection]
433+
List of named selections that include this beam.
434+
"""
435+
included_ns = []
436+
for ns in get_design_from_component(self.parent_component).named_selections:
437+
if any(beam.id == self.id for beam in ns.beams):
438+
included_ns.append(ns)
439+
440+
return included_ns
441+
425442
def __repr__(self) -> str:
426443
"""Represent the beam as a string."""
427444
lines = [f"ansys.geometry.core.designer.Beam {hex(id(self))}"]

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
from pyvista import MultiBlock, PolyData
6868

6969
from ansys.geometry.core.designer.component import Component
70+
from ansys.geometry.core.designer.selection import NamedSelection
7071

7172
# TODO: Temporary fix for boolean operations
7273
# This is a temporary fix for the boolean operations issue. The issue is that the
@@ -572,6 +573,17 @@ def copy(self, parent: "Component", name: str = None) -> "Body":
572573
"""
573574
return
574575

576+
@abstractmethod
577+
def get_named_selections(self) -> list["NamedSelection"]:
578+
"""Get the named selections associated with the body.
579+
580+
Returns
581+
-------
582+
list[NamedSelection]
583+
List of named selections associated with the body.
584+
"""
585+
return
586+
575587
@abstractmethod
576588
def get_raw_tessellation(
577589
self,
@@ -1052,6 +1064,7 @@ def _get_vertices_from_id(self, body: Union["Body", "MasterBody"]) -> list[Verte
10521064
Vertex(
10531065
vertex_resp.get("id"),
10541066
vertex_resp.get("position"),
1067+
body,
10551068
)
10561069
for vertex_resp in response.get("vertices")
10571070
]
@@ -1279,6 +1292,14 @@ def copy(self, parent: "Component", name: str = None) -> "Body": # noqa: D102
12791292
"Copy method is not implemented on the MasterBody. Call this method on a body instead."
12801293
)
12811294

1295+
def get_named_selections(self) -> list["NamedSelection"]: # noqa: D102
1296+
raise NotImplementedError(
1297+
"""
1298+
get_named_selections is not implemented at the MasterBody level.
1299+
Instead, call this method on a body.
1300+
"""
1301+
)
1302+
12821303
@min_backend_version(26, 1, 0)
12831304
def get_raw_tessellation( # noqa: D102
12841305
self,
@@ -1880,6 +1901,15 @@ def copy(self, parent: "Component", name: str = None) -> "Body": # noqa: D102
18801901
body_id = f"{parent.id}/{tb.id}" if parent.parent_component else tb.id
18811902
return Body(body_id, response.get("name"), parent, tb)
18821903

1904+
@ensure_design_is_active
1905+
def get_named_selections(self) -> list["NamedSelection"]: # noqa: D102
1906+
included_ns = []
1907+
for ns in get_design_from_body(self).named_selections:
1908+
if any(body.id == self.id for body in ns.bodies):
1909+
included_ns.append(ns)
1910+
1911+
return included_ns
1912+
18831913
@ensure_design_is_active
18841914
def get_raw_tessellation( # noqa: D102
18851915
self,

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
if TYPE_CHECKING: # pragma: no cover
6868
from pyvista import MultiBlock, PolyData
6969

70+
from ansys.geometry.core.designer.selection import NamedSelection
71+
7072

7173
@unique
7274
class SharedTopologyType(Enum):
@@ -1980,3 +1982,18 @@ def make_independent(self, others: list["Component"] = None) -> None:
19801982
"""
19811983
ids = [self.id, *[o.id for o in others or []]]
19821984
self._grpc_client._services.components.make_independent(ids=ids)
1985+
1986+
def get_named_selections(self) -> list["NamedSelection"]:
1987+
"""Get the named selections of the component.
1988+
1989+
Returns
1990+
-------
1991+
list[NamedSelection]
1992+
List of named selections belonging to the component.
1993+
"""
1994+
included_ns = []
1995+
for ns in get_design_from_component(self).named_selections:
1996+
if any(comp.id == self.id for comp in ns.components):
1997+
included_ns.append(ns)
1998+
1999+
return included_ns

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,6 +1308,18 @@ def __read_existing_design(self) -> None:
13081308
component.coordinate_systems.append(new_cs)
13091309
num_created_coord_systems += 1
13101310

1311+
# Create DesignPoints
1312+
for dp in response.get("design_points"):
1313+
created_dp = DesignPoint(
1314+
dp.get("id"),
1315+
dp.get("name"),
1316+
dp.get("point"),
1317+
created_components.get(dp.get("parent_id"), self),
1318+
)
1319+
1320+
# Append the design point to the component to which it belongs
1321+
created_dp.parent_component._design_points.append(created_dp)
1322+
13111323
end = time.time()
13121324

13131325
# Set SharedTopology

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

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@
2424
from typing import TYPE_CHECKING, Union
2525

2626
from ansys.geometry.core.math.point import Point3D
27+
from ansys.geometry.core.misc.auxiliary import get_design_from_component
2728
from ansys.geometry.core.misc.checks import graphics_required
2829
from ansys.geometry.core.misc.units import UNITS
2930

3031
if TYPE_CHECKING: # pragma: no cover
3132
import pyvista as pv
3233

3334
from ansys.geometry.core.designer.component import Component
35+
from ansys.geometry.core.designer.selection import NamedSelection
3436

3537

3638
class DesignPoint:
@@ -44,14 +46,11 @@ class DesignPoint:
4446
User-defined label for the design points.
4547
points : Point3D
4648
3D point constituting the design points.
47-
parent_component : Component | None
49+
parent_component : Component
4850
Parent component to place the new design point under within the design assembly.
49-
Its default value is None.
5051
"""
5152

52-
def __init__(
53-
self, id: str, name: str, point: Point3D, parent_component: Union["Component", None] = None
54-
):
53+
def __init__(self, id: str, name: str, point: Point3D, parent_component: Union["Component"]):
5554
"""Initialize the ``DesignPoints`` class."""
5655
self._id = id
5756
self._name = name
@@ -78,6 +77,21 @@ def parent_component(self) -> "Component":
7877
"""Component node that the design point is under."""
7978
return self._parent_component
8079

80+
def get_named_selections(self) -> list["NamedSelection"]:
81+
"""Get named selections that contain this design point.
82+
83+
Returns
84+
-------
85+
list[NamedSelection]
86+
List of named selections that contain this design point.
87+
"""
88+
included_ns = []
89+
for ns in get_design_from_component(self.parent_component).named_selections:
90+
if any(dp.id == self.id for dp in ns.design_points):
91+
included_ns.append(ns)
92+
93+
return included_ns
94+
8195
def __repr__(self) -> str:
8296
"""Represent the design points as a string."""
8397
lines = [f"ansys.geometry.core.designer.DesignPoints {hex(id(self))}"]

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@
3030
from ansys.geometry.core.errors import GeometryRuntimeError
3131
from ansys.geometry.core.math.bbox import BoundingBox
3232
from ansys.geometry.core.math.point import Point3D
33+
from ansys.geometry.core.misc.auxiliary import get_design_from_body
3334
from ansys.geometry.core.misc.checks import ensure_design_is_active, min_backend_version
3435
from ansys.geometry.core.shapes.curves.trimmed_curve import ReversedTrimmedCurve, TrimmedCurve
3536
from ansys.geometry.core.shapes.parameterization import Interval
3637

3738
if TYPE_CHECKING: # pragma: no cover
3839
from ansys.geometry.core.designer.body import Body
3940
from ansys.geometry.core.designer.face import Face
41+
from ansys.geometry.core.designer.selection import NamedSelection
4042
from ansys.geometry.core.designer.vertex import Vertex
4143

4244

@@ -185,6 +187,7 @@ def vertices(self) -> list["Vertex"]:
185187
Vertex(
186188
vertex_resp.get("id"),
187189
vertex_resp.get("position"),
190+
self.body,
188191
)
189192
for vertex_resp in response.get("vertices")
190193
]
@@ -229,3 +232,18 @@ def bounding_box(self) -> BoundingBox:
229232
return BoundingBox(
230233
response.get("min_corner"), response.get("max_corner"), response.get("center")
231234
)
235+
236+
def get_named_selections(self) -> list["NamedSelection"]:
237+
"""Get named selections associated with the edge.
238+
239+
Returns
240+
-------
241+
list[NamedSelection]
242+
List of named selections that include the edge.
243+
"""
244+
included_ns = []
245+
for ns in get_design_from_body(self.body).named_selections:
246+
if any(edge.id == self.id for edge in ns.edges):
247+
included_ns.append(ns)
248+
249+
return included_ns

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
DEFAULT_COLOR,
4040
convert_color_to_hex,
4141
convert_opacity_to_hex,
42+
get_design_from_body,
4243
)
4344
from ansys.geometry.core.misc.checks import (
4445
ensure_design_is_active,
@@ -58,6 +59,7 @@
5859
import pyvista as pv
5960

6061
from ansys.geometry.core.designer.body import Body
62+
from ansys.geometry.core.designer.selection import NamedSelection
6163

6264

6365
@unique
@@ -267,6 +269,7 @@ def vertices(self) -> list[Vertex]:
267269
Vertex(
268270
vertex_resp.get("id"),
269271
vertex_resp.get("position"),
272+
self.body,
270273
)
271274
for vertex_resp in response.get("vertices")
272275
]
@@ -530,6 +533,22 @@ def setup_offset_relationship(
530533

531534
return result.get("success")
532535

536+
def get_named_selections(self) -> list["NamedSelection"]:
537+
"""Get named selections associated with the edge.
538+
539+
Returns
540+
-------
541+
list[NamedSelection]
542+
List of named selections that include the edge.
543+
"""
544+
included_ns = []
545+
for ns in get_design_from_body(self.body).named_selections:
546+
print([face.id for face in ns.faces])
547+
if any(face.id == self.id for face in ns.faces):
548+
included_ns.append(ns)
549+
550+
return included_ns
551+
533552
@graphics_required
534553
def tessellate(self, tess_options: TessellationOptions | None = None) -> "pv.PolyData":
535554
"""Tessellate the face and return the geometry as triangles.

0 commit comments

Comments
 (0)