diff --git a/doc/changelog.d/702.miscellaneous.md b/doc/changelog.d/702.miscellaneous.md new file mode 100644 index 000000000..94467fc44 --- /dev/null +++ b/doc/changelog.d/702.miscellaneous.md @@ -0,0 +1 @@ +cleanup \ No newline at end of file diff --git a/src/ansys/mechanical/core/embedding/viz/pyvista_plotter.py b/src/ansys/mechanical/core/embedding/viz/pyvista_plotter.py index 50445368c..666c2f33c 100644 --- a/src/ansys/mechanical/core/embedding/viz/pyvista_plotter.py +++ b/src/ansys/mechanical/core/embedding/viz/pyvista_plotter.py @@ -32,10 +32,11 @@ import numpy as np import pyvista as pv -from .utils import bgr_to_rgb_tuple +from .utils import bgr_to_rgb_tuple, get_nodes_and_coords -def _transform_to_pyvista(transform): +def _transform_to_pyvista(transform: "Ansys.ACT.Math.Matrix4D"): + """Convert the Transformation matrix to a numpy array.""" np_transform = np.array([transform[i] for i in range(16)]).reshape(4, 4) # There's a bug in mechanical, the scenegraph wrappers use theMatrix4D # type, which puts the transformations in the transposed location relative @@ -47,21 +48,13 @@ def _transform_to_pyvista(transform): return np_transform -def _reshape_3cols(arr: np.array, name: str): - err = f"{name} must be of the form (x0,y0,z0,x1,y1,z1,...,xn,yn,zn).\ - Given {name} are not divisible by 3!" - assert arr.size % 3 == 0, err - numrows = int(arr.size / 3) - numcols = 3 - arr = np.reshape(arr, (numrows, numcols)) - return arr +def _get_nodes_and_coords(tri_tessellation: "Ansys.Mechanical.Scenegraph.TriTessellationNode"): + """Get the nodes and indices of the TriTessellationNode. - -def _get_nodes_and_coords(tri_tessellation): - np_coordinates = _reshape_3cols( - np.array(tri_tessellation.Coordinates, dtype=np.double), "coordinates" - ) - np_indices = _reshape_3cols(np.array(tri_tessellation.Indices, dtype=np.int32), "indices") + pyvista format expects a number of vertices per facet which is always 3 + from this kind of node. + """ + np_coordinates, np_indices = get_nodes_and_coords(tri_tessellation) np_indices = np.insert(np_indices, 0, 3, axis=1) return np_coordinates, np_indices diff --git a/src/ansys/mechanical/core/embedding/viz/usd_converter.py b/src/ansys/mechanical/core/embedding/viz/usd_converter.py index 1d7f41097..811c652a7 100644 --- a/src/ansys/mechanical/core/embedding/viz/usd_converter.py +++ b/src/ansys/mechanical/core/embedding/viz/usd_converter.py @@ -25,7 +25,6 @@ import typing import clr -import numpy as np from pxr import Gf, Usd, UsdGeom clr.AddReference("Ansys.Mechanical.DataModel") @@ -33,10 +32,11 @@ import Ansys # isort: skip -from .utils import bgr_to_rgb_tuple +from .utils import bgr_to_rgb_tuple, get_nodes_and_coords -def _transform_to_rotation_quat(transform) -> Gf.Quatf: +def _transform_to_rotation_quat(transform: "Ansys.ACT.Math.Matrix4D") -> Gf.Quatf: + """Convert the Transformation matrix to a single-precision quaternion.""" transforms = [transform[i] for i in range(16)] m = Gf.Matrix4d() m.SetRow(0, transforms[0:4]) @@ -54,32 +54,15 @@ def _transform_to_rotation_quat(transform) -> Gf.Quatf: return quatf -def _reshape_3cols(arr: np.array, name: str): - err = f"{name} must be of the form (x0,y0,z0,x1,y1,z1,...,xn,yn,zn).\ - Given {name} are not divisible by 3!" - assert arr.size % 3 == 0, err - numrows = int(arr.size / 3) - numcols = 3 - arr = np.reshape(arr, (numrows, numcols)) - return arr - - -def _get_nodes_and_coords(tri_tessellation): - np_coordinates = _reshape_3cols( - np.array(tri_tessellation.Coordinates, dtype=np.double), "coordinates" - ) - np_indices = _reshape_3cols(np.array(tri_tessellation.Indices, dtype=np.int32), "indices") - return np_coordinates, np_indices - - def _convert_tri_tessellation_node( node: "Ansys.Mechanical.Scenegraph.TriTessellationNode", stage: Usd.Stage, path: str, rgb: typing.Tuple[int, int, int], ) -> Usd.Prim: + """Convert a mechanical TriTessellationNode node into a Usd Mesh prim.""" mesh_prim = UsdGeom.Mesh.Define(stage, path) - np_coordinates, np_indices = _get_nodes_and_coords(node) + np_coordinates, np_indices = get_nodes_and_coords(node) mesh_prim.CreatePointsAttr(np_coordinates) mesh_prim.CreateFaceVertexCountsAttr([3] * len(np_indices)) mesh_prim.CreateFaceVertexIndicesAttr(np_indices) @@ -94,6 +77,7 @@ def _convert_transform_node( path: str, rgb: typing.Tuple[int, int, int], ) -> Usd.Prim: + """Convert a mechanical transform node into a Usd Xform prim.""" prim = UsdGeom.Xform.Define(stage, path) prim.AddOrientOp().Set(_transform_to_rotation_quat(node.Transform)) child_node = node.Child @@ -108,16 +92,14 @@ def to_usd_stage(app: "ansys.mechanical.core.embedding.App", name: str) -> None: """Convert mechanical scene to usd stage.""" stage = Usd.Stage.CreateNew(name) - root_prim = UsdGeom.Xform.Define(stage, "/root") # "/hello" - # stage.SetDefaultPrim(root_prim) + root_prim = UsdGeom.Xform.Define(stage, "/root") category = Ansys.Mechanical.DataModel.Enums.DataModelObjectCategory.Body bodies = app.DataModel.GetObjectsByType(category) for body in bodies: scenegraph_node = Ansys.ACT.Mechanical.Tools.ScenegraphHelpers.GetScenegraph(body) - _convert_transform_node( - scenegraph_node, stage, f"/root/body{body.ObjectId}", bgr_to_rgb_tuple(body.Color) - ) + body_path = root_prim.GetPath().AppendPath(f"body{body.ObjectId}") + _convert_transform_node(scenegraph_node, stage, body_path, bgr_to_rgb_tuple(body.Color)) return stage diff --git a/src/ansys/mechanical/core/embedding/viz/utils.py b/src/ansys/mechanical/core/embedding/viz/utils.py index ffaf5e2df..0621878ab 100644 --- a/src/ansys/mechanical/core/embedding/viz/utils.py +++ b/src/ansys/mechanical/core/embedding/viz/utils.py @@ -23,6 +23,8 @@ """Common plotting utilities.""" import typing +import numpy as np + def bgr_to_rgb_tuple(bgr_int: int) -> typing.Tuple[int, int, int]: """Convert bgr integer to rgb tuple.""" @@ -30,3 +32,30 @@ def bgr_to_rgb_tuple(bgr_int: int) -> typing.Tuple[int, int, int]: g = (bgr_int >> 8) & 255 b = (bgr_int >> 16) & 255 return r, g, b + + +def _reshape_3cols(arr: np.array, name: str = "array"): + """Reshapes the given array into 3 columns. + + Precondition - the array's length must be divisible by 3. + """ + err = f"{name} must be of the form (x0,y0,z0,x1,y1,z1,...,xn,yn,zn).\ + Given {name} are not divisible by 3!" + assert arr.size % 3 == 0, err + numrows = int(arr.size / 3) + numcols = 3 + arr = np.reshape(arr, (numrows, numcols)) + return arr + + +def get_nodes_and_coords(tri_tessellation: "Ansys.Mechanical.Scenegraph.TriTessellationNode"): + """Extract the nodes and coordinates from the TriTessellationNode. + + The TriTessellationNode contains "Coordinates" and "Indices" + that are flat arrays. This function converts them to numpy arrays + """ + np_coordinates = _reshape_3cols( + np.array(tri_tessellation.Coordinates, dtype=np.double), "coordinates" + ) + np_indices = _reshape_3cols(np.array(tri_tessellation.Indices, dtype=np.int32), "indices") + return np_coordinates, np_indices