Skip to content

fix: tessellation options were not extended to component/face methods #1850

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

Merged
merged 5 commits into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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/1850.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tessellation options were not extended to component/face methods
22 changes: 17 additions & 5 deletions src/ansys/geometry/core/designer/body.py
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ def copy(self, parent: "Component", name: str = None) -> "Body":

@abstractmethod
def tessellate(
self, merge: bool = False, tessellation_options: TessellationOptions = None
self, merge: bool = False, tess_options: TessellationOptions | None = None
) -> Union["PolyData", "MultiBlock"]:
"""Tessellate the body and return the geometry as triangles.

Expand All @@ -578,7 +578,7 @@ def tessellate(
Whether to merge the body into a single mesh. When ``False`` (default), the
number of triangles are preserved and only the topology is merged.
When ``True``, the individual faces of the tessellation are merged.
tessellation_options : TessellationOptions, default: None
tess_options : TessellationOptions | None, default: None
A set of options to determine the tessellation quality.

Returns
Expand Down Expand Up @@ -1276,14 +1276,22 @@ def tessellate( # noqa: D102
self,
merge: bool = False,
transform: Matrix44 = IDENTITY_MATRIX44,
tess_options: TessellationOptions = None,
tess_options: TessellationOptions | None = None,
) -> Union["PolyData", "MultiBlock"]:
# lazy import here to improve initial module load time
import pyvista as pv

if not self.is_alive:
return pv.PolyData() if merge else pv.MultiBlock()

# If the server does not support tessellation options, ignore them
if tess_options is not None and self._grpc_client.backend_version < (25, 2, 0):
self._grpc_client.log.warning(
"Tessellation options are not supported by server"
f" version {self._grpc_client.backend_version}. Ignoring options."
)
tess_options = None

self._grpc_client.log.debug(f"Requesting tessellation for body {self.id}.")

# cache tessellation
Expand Down Expand Up @@ -1319,7 +1327,11 @@ def tessellate( # noqa: D102
str(face_id): tess_to_pd(face_tess)
for face_id, face_tess in resp.face_tessellation.items()
}
except Exception:
except Exception as err:
# Streaming is not supported in older versions...
if self._grpc_client.backend_version < (25, 2, 0):
raise err

tessellation_map = {}
request = GetTessellationRequest(self._grpc_id)
for response in self._bodies_stub.GetTessellationStream(request):
Expand Down Expand Up @@ -1854,7 +1866,7 @@ def copy(self, parent: "Component", name: str = None) -> "Body": # noqa: D102

@ensure_design_is_active
def tessellate( # noqa: D102
self, merge: bool = False, tess_options: TessellationOptions = None
self, merge: bool = False, tess_options: TessellationOptions | None = None
) -> Union["PolyData", "MultiBlock"]:
return self._template.tessellate(
merge, self.parent_component.get_world_transform(), tess_options
Expand Down
13 changes: 10 additions & 3 deletions src/ansys/geometry/core/designer/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
min_backend_version,
)
from ansys.geometry.core.misc.measurements import DEFAULT_UNITS, Angle, Distance
from ansys.geometry.core.misc.options import TessellationOptions
from ansys.geometry.core.shapes.curves.circle import Circle
from ansys.geometry.core.shapes.curves.trimmed_curve import TrimmedCurve
from ansys.geometry.core.shapes.parameterization import Interval, ParamUV
Expand Down Expand Up @@ -1608,11 +1609,15 @@ def _kill_component_on_client(self) -> None:
self._is_alive = False

@graphics_required
def tessellate(self, _recursive_call: bool = False) -> Union["PolyData", list["MultiBlock"]]:
def tessellate(
self, tess_options: TessellationOptions | None = None, _recursive_call: bool = False
) -> Union["PolyData", list["MultiBlock"]]:
"""Tessellate the component.

Parameters
----------
tess_options : TessellationOptions | None, default: None
A set of options to determine the tessellation quality.
_recursive_call: bool, default: False
Internal flag to indicate if this method is being called recursively.
Not to be used by the user.
Expand All @@ -1627,14 +1632,16 @@ def tessellate(self, _recursive_call: bool = False) -> Union["PolyData", list["M
import pyvista as pv

# Tessellate the bodies in this component
datasets: list["MultiBlock"] = [body.tessellate(merge=False) for body in self.bodies]
datasets: list["MultiBlock"] = [
body.tessellate(merge=False, tess_options=tess_options) for body in self.bodies
]

# Now, go recursively inside its subcomponents (with no arguments) and
# merge the PolyData obtained into our blocks
for comp in self._components:
if not comp.is_alive:
continue
datasets.extend(comp.tessellate(_recursive_call=True))
datasets.extend(comp.tessellate(tess_options=tess_options, _recursive_call=True))

# Convert to polydata as it's slightly faster than extract surface
# plus this method is only for visualizing the component as a whole (no
Expand Down
15 changes: 13 additions & 2 deletions src/ansys/geometry/core/designer/face.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
min_backend_version,
)
from ansys.geometry.core.misc.measurements import DEFAULT_UNITS
from ansys.geometry.core.misc.options import TessellationOptions
from ansys.geometry.core.shapes.box_uv import BoxUV
from ansys.geometry.core.shapes.curves.trimmed_curve import TrimmedCurve
from ansys.geometry.core.shapes.parameterization import Interval
Expand Down Expand Up @@ -598,17 +599,27 @@ def setup_offset_relationship(
return result.success

@graphics_required
def tessellate(self) -> "pv.PolyData":
def tessellate(self, tess_options: TessellationOptions | None = None) -> "pv.PolyData":
"""Tessellate the face and return the geometry as triangles.

Parameters
----------
tess_options : TessellationOptions | None, default: None
A set of options to determine the tessellation quality.

Notes
-----
The tessellation options are ONLY used if the face has not been tessellated before.
If the face has been tessellated before, the stored tessellation is returned.

Returns
-------
~pyvista.PolyData
:class:`pyvista.PolyData` object holding the face.
"""
# If tessellation has not been called before... call it
if self._body._template._tessellation is None:
self._body.tessellate()
self._body.tessellate(tess_options=tess_options)

# Search the tessellation of the face - if it exists
# ---> We need to used the last element of the ID since we are looking inside
Expand Down
2 changes: 1 addition & 1 deletion src/ansys/geometry/core/misc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,5 @@
run_if_graphics_required,
)
from ansys.geometry.core.misc.measurements import DEFAULT_UNITS, Angle, Distance
from ansys.geometry.core.misc.options import ImportOptions
from ansys.geometry.core.misc.options import ImportOptions, TessellationOptions
from ansys.geometry.core.misc.units import UNITS, PhysicalQuantity
14 changes: 12 additions & 2 deletions src/ansys/geometry/core/modeler.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,12 +438,22 @@ def open_file(
if full_path != fp_path:
if full_path.stat().st_size < pygeom_defaults.MAX_MESSAGE_LENGTH:
self._upload_file(full_path)
else:
elif self.client.backend_version >= (25, 2, 0):
self._upload_file_stream(full_path)
else: # pragma: no cover
raise RuntimeError(
"File is too large to upload."
" Service versions above 25R2 support streaming."
)

if file_size_kb < pygeom_defaults.MAX_MESSAGE_LENGTH:
self._upload_file(file_path, True, import_options)
else:
elif self.client.backend_version >= (25, 2, 0):
self._upload_file_stream(file_path, True, import_options)
else: # pragma: no cover
raise RuntimeError(
"File is too large to upload. Service versions above 25R2 support streaming."
)
else:
DesignsStub(self.client.channel).Open(
OpenRequest(filepath=file_path, import_options=import_options.to_dict())
Expand Down
Loading