# File: _asset_.py
# Author: Ryoichi Ando (ryoichi.ando@zozo.com)
# License: Apache v2.0
import numpy as np
[docs]
class AssetManager:
"""AssetManager class. Use this to register or remove data assets."""
def __init__(self):
"""Initialize the asset manager."""
self._mesh: dict[str, tuple] = {}
self._add = AssetUploader(self)
self._fetch = AssetFetcher(self)
[docs]
def list(self) -> list[str]:
"""List all the assets in the manager.
Returns:
list[str]: A list of asset names.
"""
return list(self._mesh.keys())
[docs]
def remove(self, name: str) -> bool:
"""Remove an asset from the manager.
Args:
name (str): The name of the asset to remove.
Returns:
bool: True if the asset was removed, False otherwise.
"""
if name in self._mesh.keys():
del self._mesh[name]
return True
else:
return False
[docs]
def clear(self):
"""Clear all the assets in the manager."""
self._mesh = {}
@property
def add(self) -> "AssetUploader":
"""Get the asset uploader."""
return self._add
@property
def fetch(self) -> "AssetFetcher":
"""Get the asset fetcher."""
return self._fetch
[docs]
class AssetUploader:
"""AssetUploader class. Use this to upload data assets to the manager."""
def __init__(self, manager: AssetManager):
"""Initialize the asset uploader."""
self._manager = manager
[docs]
def check_bounds(self, V: np.ndarray, E: np.ndarray):
"""Check if the indices in E are within the bounds of V."""
max_ind = np.max(E)
if max_ind >= V.shape[0]:
raise Exception(f"E contains index {max_ind} out of bounds ({V.shape[0]})")
[docs]
def tri(self, name: str, V: np.ndarray, F: np.ndarray):
"""Upload a triangle mesh to the asset manager.
Args:
name (str): The name of the asset.
V (np.ndarray): The vertices (#x3) of the mesh.
F (np.ndarray): The triangle elements (#x3) of the mesh.
"""
if V.shape[1] != 3:
raise Exception("V must have 3 columns")
elif F.shape[1] != 3:
raise Exception("F must have 3 columns")
if name in self._manager._mesh.keys():
raise Exception(f"name '{name}' already exists")
else:
self.check_bounds(V, F)
self._manager._mesh[name] = ("tri", V, F)
[docs]
def tet(self, name: str, V: np.ndarray, F: np.ndarray, T: np.ndarray):
"""Upload a tetrahedral mesh to the asset manager.
Args:
name (str): The name of the asset.
V (np.ndarray): The vertices (#x3) of the mesh.
F (np.ndarray): The surface triangle (#x3) elements of the mesh.
T (np.ndarray): The tetrahedral elements (#x4) of the mesh.
"""
if V.shape[1] != 3:
raise Exception("V must have 3 columns")
elif F.shape[1] != 3:
raise Exception("F must have 3 columns")
elif T.shape[1] != 4:
raise Exception("T must have 4 columns")
if name in self._manager._mesh.keys():
raise Exception(f"name '{name}' already exists")
else:
self.check_bounds(V, F)
self.check_bounds(V, T)
self._manager._mesh[name] = ("tet", V, F, T)
[docs]
def rod(self, name: str, V: np.ndarray, E: np.ndarray):
"""Upload a rod mesh to the asset manager.
Args:
name (str): The name of the asset.
V (np.ndarray): The vertices (#x3) of the rod.
E (np.ndarray): The edges of (#x2) the rod.
"""
if name in self._manager._mesh.keys():
raise Exception(f"name '{name}' already exists")
else:
self.check_bounds(V, E)
self._manager._mesh[name] = ("rod", V, E)
[docs]
def stitch(self, name: str, stitch: tuple[np.ndarray, np.ndarray]):
"""Upload a stitch mesh to the asset manager.
Args:
name (str): The name of the asset.
stitch (tuple[np.ndarray, np.ndarray]): Ind (index, #x3) and W (weight #x2) of the stitch mesh.
The weight encodes the liner interpolation between the last two vertices.
"""
Ind, W = stitch
if Ind.shape[1] != 3:
raise Exception("Ind must have 3 columns")
elif W.shape[1] != 2:
raise Exception("W must have 2 columns")
for w in W:
if abs(np.sum(w) - 1) > 1e-3:
raise Exception("each row in W must sum to 1")
if name in self._manager._mesh.keys():
raise Exception(f"name '{name}' already exists")
else:
self._manager._mesh[name] = ("stitch", Ind, W)
[docs]
class AssetFetcher:
"""AssetFetcher class. Use this to fetch data assets from the manager."""
def __init__(self, manager: AssetManager):
"""Initialize the asset fetcher."""
self._manager = manager
[docs]
def get(self, name: str) -> dict[str, np.ndarray]:
"""Get the asset data.
Args:
name (str): The name of the asset.
Returns:
dict[str, np.ndarray]: The asset data, containing the vertices and elements, such as V, F, T, E, Ind, W.
"""
result = {}
if name not in self._manager._mesh.keys():
raise Exception(f"Asset {name} does not exist")
else:
mesh = self._manager._mesh[name]
if mesh[0] == "tri":
result["V"] = mesh[1]
result["F"] = mesh[2]
elif mesh[0] == "tet":
result["V"] = mesh[1]
result["F"] = mesh[2]
result["T"] = mesh[3]
elif mesh[0] == "rod":
result["V"] = mesh[1]
result["E"] = mesh[2]
elif mesh[0] == "stitch":
result["Ind"] = mesh[1]
result["W"] = mesh[2]
return result
[docs]
def tri(self, name: str) -> tuple[np.ndarray, np.ndarray]:
"""Get the triangle mesh data.
Args:
name (str): The name of the asset.
Returns:
tuple[np.ndarray, np.ndarray]: The vertices (#x3) and elements (#x3) of the triangle mesh.
"""
if name not in self._manager._mesh.keys():
raise Exception(f"Tri {name} does not exist")
elif self._manager._mesh[name][0] != "tri":
raise Exception(f"Tri {name} is not a valid")
else:
mesh = self._manager._mesh[name]
assert mesh[0] == "tri"
return mesh[1], mesh[2]
[docs]
def tet(self, name: str) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
"""Get the tetrahedral mesh data.
Args:
name (str): The name of the asset.
Returns:
tuple[np.ndarray, np.ndarray, np.ndarray]: The vertices (#x3), surface
elements (#x3), and tetrahedral (#x4) elements of the mesh.
"""
if name not in self._manager._mesh.keys():
raise Exception(f"Tet {name} does not exist")
elif self._manager._mesh[name][0] != "tet":
raise Exception(f"Tet {name} is not a valid")
else:
mesh = self._manager._mesh[name]
assert mesh[0] == "tet"
return mesh[1], mesh[2], mesh[3]
[docs]
def rod(self, name: str) -> tuple[np.ndarray, np.ndarray]:
"""Get the rod mesh data.
Args:
name (str): The name of the asset.
Returns:
tuple[np.ndarray, np.ndarray]: The vertices and edges (#x2) of the rod mesh.
"""
if name not in self._manager._mesh.keys():
raise Exception(f"Rod {name} does not exist")
elif self._manager._mesh[name][0] != "rod":
raise Exception(f"Rod {name} is not a valid")
else:
mesh = self._manager._mesh[name]
assert mesh[0] == "rod"
return mesh[1], mesh[2]
[docs]
def stitch(self, name: str) -> tuple[np.ndarray, np.ndarray]:
"""Get the stitch mesh data.
Args:
name (str): The name of the asset.
Returns:
tuple[np.ndarray, np.ndarray]: Ind (index, #x3) and W (weight, #x2) of the stitch mesh.
The weight encodes the liner interpolation between the last two vertices.
"""
if name not in self._manager._mesh.keys():
raise Exception(f"Stitch {name} does not exist")
elif self._manager._mesh[name][0] != "stitch":
raise Exception(f"Stitch {name} is not a valid")
else:
mesh = self._manager._mesh[name]
assert mesh[0] == "stitch"
return mesh[1], mesh[2]