Skip to content
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

cleanup #702

Merged
merged 4 commits into from
Apr 12, 2024
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/702.miscellaneous.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cleanup
25 changes: 9 additions & 16 deletions src/ansys/mechanical/core/embedding/viz/pyvista_plotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
36 changes: 9 additions & 27 deletions src/ansys/mechanical/core/embedding/viz/usd_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@
import typing

import clr
import numpy as np
from pxr import Gf, Usd, UsdGeom

clr.AddReference("Ansys.Mechanical.DataModel")
clr.AddReference("Ansys.ACT.Interfaces")

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])
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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

Expand Down
29 changes: 29 additions & 0 deletions src/ansys/mechanical/core/embedding/viz/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,39 @@
"""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."""
r = bgr_int & 255
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
Loading