diff --git a/source/isaaclab/isaaclab/assets/asset_base.py b/source/isaaclab/isaaclab/assets/asset_base.py index a618ddc0e13..ca70b99e8ff 100644 --- a/source/isaaclab/isaaclab/assets/asset_base.py +++ b/source/isaaclab/isaaclab/assets/asset_base.py @@ -14,13 +14,13 @@ from collections.abc import Sequence from typing import TYPE_CHECKING, Any -import isaacsim.core.utils.prims as prim_utils import omni.kit.app import omni.timeline from isaacsim.core.simulation_manager import IsaacEvents, SimulationManager from isaacsim.core.utils.stage import get_current_stage import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils if TYPE_CHECKING: from .asset_base_cfg import AssetBaseCfg diff --git a/source/isaaclab/isaaclab/controllers/rmp_flow.py b/source/isaaclab/isaaclab/controllers/rmp_flow.py index b9ce875c390..6420af46bf0 100644 --- a/source/isaaclab/isaaclab/controllers/rmp_flow.py +++ b/source/isaaclab/isaaclab/controllers/rmp_flow.py @@ -6,7 +6,6 @@ import torch from dataclasses import MISSING -import isaacsim.core.utils.prims as prim_utils from isaacsim.core.api.simulation_context import SimulationContext from isaacsim.core.prims import SingleArticulation @@ -19,6 +18,7 @@ from isaacsim.robot_motion.motion_generation import ArticulationMotionPolicy from isaacsim.robot_motion.motion_generation.lula.motion_policies import RmpFlow, RmpFlowSmoothed +import isaaclab.sim.utils as sim_utils from isaaclab.utils import configclass from isaaclab.utils.assets import retrieve_file_path @@ -81,7 +81,7 @@ def initialize(self, prim_paths_expr: str): # obtain the simulation time physics_dt = SimulationContext.instance().get_physics_dt() # find all prims - self._prim_paths = prim_utils.find_matching_prim_paths(prim_paths_expr) + self._prim_paths = sim_utils.find_matching_prim_paths(prim_paths_expr) self.num_robots = len(self._prim_paths) # resolve controller if self.cfg.name == "rmp_flow": diff --git a/source/isaaclab/isaaclab/markers/visualization_markers.py b/source/isaaclab/isaaclab/markers/visualization_markers.py index ce4611289bc..68a7e4f5cef 100644 --- a/source/isaaclab/isaaclab/markers/visualization_markers.py +++ b/source/isaaclab/isaaclab/markers/visualization_markers.py @@ -67,7 +67,7 @@ class VisualizationMarkers: The class parses the configuration to create different the marker prototypes into the stage. Each marker prototype prim is created as a child of the :class:`UsdGeom.PointInstancer` prim. The prim path for the marker prim is resolved using the key of the marker in the :attr:`VisualizationMarkersCfg.markers` - dictionary. The marker prototypes are created using the :meth:`isaacsim.core.utils.create_prim` + dictionary. The marker prototypes are created using the :meth:`isaaclab.sim.utils.prims.create_prim` function, and then instanced using :class:`UsdGeom.PointInstancer` prim to allow creating multiple instances of the marker prims. diff --git a/source/isaaclab/isaaclab/sim/spawners/from_files/from_files.py b/source/isaaclab/isaaclab/sim/spawners/from_files/from_files.py index a3c8a44015a..a977f08668e 100644 --- a/source/isaaclab/isaaclab/sim/spawners/from_files/from_files.py +++ b/source/isaaclab/isaaclab/sim/spawners/from_files/from_files.py @@ -7,11 +7,12 @@ from typing import TYPE_CHECKING -import isaacsim.core.utils.prims as prim_utils import omni.kit.commands import omni.log from pxr import Gf, Sdf, Usd +import isaaclab.sim.utils.prims as prim_utils + # from Isaac Sim 4.2 onwards, pxr.Semantics is deprecated try: import Semantics diff --git a/source/isaaclab/isaaclab/sim/spawners/lights/lights.py b/source/isaaclab/isaaclab/sim/spawners/lights/lights.py index dccd00f4bca..119cdcbd116 100644 --- a/source/isaaclab/isaaclab/sim/spawners/lights/lights.py +++ b/source/isaaclab/isaaclab/sim/spawners/lights/lights.py @@ -7,9 +7,9 @@ from typing import TYPE_CHECKING -import isaacsim.core.utils.prims as prim_utils from pxr import Usd, UsdLux +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim.utils import clone, safe_set_attribute_on_usd_prim if TYPE_CHECKING: diff --git a/source/isaaclab/isaaclab/sim/spawners/materials/__init__.py b/source/isaaclab/isaaclab/sim/spawners/materials/__init__.py index 966efec76b8..13f90cfb4b1 100644 --- a/source/isaaclab/isaaclab/sim/spawners/materials/__init__.py +++ b/source/isaaclab/isaaclab/sim/spawners/materials/__init__.py @@ -31,7 +31,7 @@ Usage: .. code-block:: python - import isaacsim.core.utils.prims as prim_utils + import isaaclab.sim.utils.prims as prim_utils import isaaclab.sim as sim_utils diff --git a/source/isaaclab/isaaclab/sim/spawners/materials/physics_materials.py b/source/isaaclab/isaaclab/sim/spawners/materials/physics_materials.py index e8977a14fd2..47fdd60892a 100644 --- a/source/isaaclab/isaaclab/sim/spawners/materials/physics_materials.py +++ b/source/isaaclab/isaaclab/sim/spawners/materials/physics_materials.py @@ -7,10 +7,10 @@ from typing import TYPE_CHECKING -import isaacsim.core.utils.prims as prim_utils from isaacsim.core.utils.stage import get_current_stage from pxr import PhysxSchema, Usd, UsdPhysics, UsdShade +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim.utils import clone, safe_set_attribute_on_usd_schema if TYPE_CHECKING: diff --git a/source/isaaclab/isaaclab/sim/spawners/materials/visual_materials.py b/source/isaaclab/isaaclab/sim/spawners/materials/visual_materials.py index 3c79f6f679e..c63b6696a2e 100644 --- a/source/isaaclab/isaaclab/sim/spawners/materials/visual_materials.py +++ b/source/isaaclab/isaaclab/sim/spawners/materials/visual_materials.py @@ -7,11 +7,11 @@ from typing import TYPE_CHECKING -import isaacsim.core.utils.prims as prim_utils import omni.kit.commands import omni.log from pxr import Usd +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim.utils import attach_stage_to_usd_context, clone, safe_set_attribute_on_usd_prim from isaaclab.utils.assets import NVIDIA_NUCLEUS_DIR diff --git a/source/isaaclab/isaaclab/sim/spawners/meshes/meshes.py b/source/isaaclab/isaaclab/sim/spawners/meshes/meshes.py index 17c23202ed6..a5b2a064e31 100644 --- a/source/isaaclab/isaaclab/sim/spawners/meshes/meshes.py +++ b/source/isaaclab/isaaclab/sim/spawners/meshes/meshes.py @@ -10,9 +10,9 @@ import trimesh.transformations from typing import TYPE_CHECKING -import isaacsim.core.utils.prims as prim_utils from pxr import Usd, UsdPhysics +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim import schemas from isaaclab.sim.utils import bind_physics_material, bind_visual_material, clone diff --git a/source/isaaclab/isaaclab/sim/spawners/sensors/sensors.py b/source/isaaclab/isaaclab/sim/spawners/sensors/sensors.py index 0a385902a55..e95c6e91e68 100644 --- a/source/isaaclab/isaaclab/sim/spawners/sensors/sensors.py +++ b/source/isaaclab/isaaclab/sim/spawners/sensors/sensors.py @@ -7,11 +7,11 @@ from typing import TYPE_CHECKING -import isaacsim.core.utils.prims as prim_utils import omni.kit.commands import omni.log from pxr import Sdf, Usd +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim.utils import attach_stage_to_usd_context, clone from isaaclab.utils import to_camel_case diff --git a/source/isaaclab/isaaclab/sim/spawners/shapes/shapes.py b/source/isaaclab/isaaclab/sim/spawners/shapes/shapes.py index f4fa156704a..0a045bf7534 100644 --- a/source/isaaclab/isaaclab/sim/spawners/shapes/shapes.py +++ b/source/isaaclab/isaaclab/sim/spawners/shapes/shapes.py @@ -7,9 +7,9 @@ from typing import TYPE_CHECKING -import isaacsim.core.utils.prims as prim_utils from pxr import Usd +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim import schemas from isaaclab.sim.utils import bind_physics_material, bind_visual_material, clone diff --git a/source/isaaclab/isaaclab/sim/spawners/wrappers/wrappers.py b/source/isaaclab/isaaclab/sim/spawners/wrappers/wrappers.py index 9f339aa70c7..74575639b6c 100644 --- a/source/isaaclab/isaaclab/sim/spawners/wrappers/wrappers.py +++ b/source/isaaclab/isaaclab/sim/spawners/wrappers/wrappers.py @@ -10,12 +10,12 @@ from typing import TYPE_CHECKING import carb -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils from isaacsim.core.utils.stage import get_current_stage from pxr import Sdf, Usd import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim.spawners.from_files import UsdFileCfg if TYPE_CHECKING: diff --git a/source/isaaclab/isaaclab/sim/utils/__init__.py b/source/isaaclab/isaaclab/sim/utils/__init__.py new file mode 100644 index 00000000000..9d1dcbd0e33 --- /dev/null +++ b/source/isaaclab/isaaclab/sim/utils/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) 2022-2025, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +from .utils import * # noqa: F401, F403 diff --git a/source/isaaclab/isaaclab/sim/utils/prims.py b/source/isaaclab/isaaclab/sim/utils/prims.py new file mode 100644 index 00000000000..2cfe7bd7fe1 --- /dev/null +++ b/source/isaaclab/isaaclab/sim/utils/prims.py @@ -0,0 +1,1018 @@ +# Copyright (c) 2022-2025, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +import numpy as np +import typing + +import omni.usd +import usdrt +from omni.usd.commands import DeletePrimsCommand, MovePrimCommand +from pxr import Sdf, Usd, UsdGeom, UsdPhysics + +import isaaclab.sim as sim_utils +from isaaclab.sim.utils.semantics import add_labels +from isaaclab.sim.utils.stage import add_reference_to_stage, get_current_stage + +SDF_type_to_Gf = { + "matrix3d": "Gf.Matrix3d", + "matrix3f": "Gf.Matrix3f", + "matrix4d": "Gf.Matrix4d", + "matrix4f": "Gf.Matrix4f", + "range1d": "Gf.Range1d", + "range1f": "Gf.Range1f", + "range2d": "Gf.Range2d", + "range2f": "Gf.Range2f", + "range3d": "Gf.Range3d", + "range3f": "Gf.Range3f", + "rect2i": "Gf.Rect2i", + "vec2d": "Gf.Vec2d", + "vec2f": "Gf.Vec2f", + "vec2h": "Gf.Vec2h", + "vec2i": "Gf.Vec2i", + "vec3d": "Gf.Vec3d", + "double3": "Gf.Vec3d", + "vec3f": "Gf.Vec3f", + "vec3h": "Gf.Vec3h", + "vec3i": "Gf.Vec3i", + "vec4d": "Gf.Vec4d", + "vec4f": "Gf.Vec4f", + "vec4h": "Gf.Vec4h", + "vec4i": "Gf.Vec4i", +} + + +def get_prim_at_path(prim_path: str, fabric: bool = False) -> Usd.Prim | usdrt.Usd._Usd.Prim: + """Get the USD or Fabric Prim at a given path string + + Args: + prim_path (str): path of the prim in the stage. + fabric (bool, optional): True for fabric stage and False for USD stage. Defaults to False. + + Returns: + typing.Union[Usd.Prim, usdrt.Usd._Usd.Prim]: USD or Fabric Prim object at the given path in the current stage. + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> prims_utils.get_prim_at_path("/World/Cube") + Usd.Prim() + """ + + current_stage = get_current_stage(fabric=fabric) + if current_stage: + return current_stage.GetPrimAtPath(prim_path) + else: + return None + + +def is_prim_path_valid(prim_path: str, fabric: bool = False) -> bool: + """Check if a path has a valid USD Prim at it + + Args: + prim_path (str): path of the prim in the stage + fabric (bool, optional): True for fabric stage and False for USD stage. Defaults to False. + + Returns: + bool: True if the path points to a valid prim + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # given the stage: /World/Cube + >>> prims_utils.is_prim_path_valid("/World/Cube") + True + >>> prims_utils.is_prim_path_valid("/World/Cube/") + False + >>> prims_utils.is_prim_path_valid("/World/Sphere") # it doesn't exist + False + """ + prim = get_prim_at_path(prim_path, fabric=fabric) + if prim: + return prim.IsValid() + else: + return False + + +def get_prim_attribute_names(prim_path: str, fabric: bool = False) -> list[str]: + """Get all the attribute names of a prim at the path + + Args: + prim_path (str): path of the prim in the stage + fabric (bool, optional): True for fabric stage and False for USD stage. Defaults to False. + + Raises: + Exception: If there is not a valid prim at the given path + + Returns: + typing.List[str]: List of the prim attribute names + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> prims_utils.get_prim_attribute_names("/World/Cube") + ['doubleSided', 'extent', 'orientation', 'primvars:displayColor', 'primvars:displayOpacity', + 'purpose', 'size', 'visibility', 'xformOp:orient', 'xformOp:scale', 'xformOp:translate', 'xformOpOrder'] + """ + return [attr.GetName() for attr in get_prim_at_path(prim_path=prim_path, fabric=fabric).GetAttributes()] + + +def get_prim_attribute_value(prim_path: str, attribute_name: str, fabric: bool = False) -> typing.Any: + """Get a prim attribute value + + Args: + prim_path (str): path of the prim in the stage + attribute_name (str): name of the attribute to get + fabric (bool, optional): True for fabric stage and False for USD stage. Defaults to False. + + Raises: + Exception: If there is not a valid prim at the given path + + Returns: + typing.Any: Prim attribute value + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> prims_utils.get_prim_attribute_value("/World/Cube", attribute_name="size") + 1.0 + """ + attr = get_prim_at_path(prim_path=prim_path, fabric=fabric).GetAttribute(attribute_name) + if fabric: + type_name = str(attr.GetTypeName().GetAsString()) + else: + type_name = str(attr.GetTypeName()) + if type_name in SDF_type_to_Gf: + return list(attr.Get()) + else: + return attr.Get() + + +def set_prim_attribute_value(prim_path: str, attribute_name: str, value: typing.Any, fabric: bool = False): + """Set a prim attribute value + + Args: + prim_path (str): path of the prim in the stage + attribute_name (str): name of the attribute to set + value (typing.Any): value to set the attribute to + fabric (bool, optional): True for fabric stage and False for USD stage. Defaults to False. + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # given the stage: /World/Cube. Set the Cube size to 5.0 + >>> prims_utils.set_prim_attribute_value("/World/Cube", attribute_name="size", value=5.0) + """ + attr = get_prim_at_path(prim_path=prim_path, fabric=fabric).GetAttribute(attribute_name) + if fabric: + type_name = str(attr.GetTypeName().GetAsString()) + else: + type_name = str(attr.GetTypeName()) + if isinstance(value, np.ndarray): + value = value.tolist() + if type_name in SDF_type_to_Gf: + value = np.array(value).flatten().tolist() + if fabric: + eval("attr.Set(usdrt." + SDF_type_to_Gf[type_name] + "(*value))") + else: + eval("attr.Set(" + SDF_type_to_Gf[type_name] + "(*value))") + else: + attr.Set(value) + + +def define_prim(prim_path: str, prim_type: str = "Xform", fabric: bool = False) -> Usd.Prim: + """Create a USD Prim at the given prim_path of type prim_type unless one already exists + + .. note:: + + This method will create a prim of the specified type in the specified path. + To apply a transformation (position, orientation, scale), set attributes or + load an USD file while creating the prim use the ``create_prim`` function. + + Args: + prim_path (str): path of the prim in the stage + prim_type (str, optional): The type of the prim to create. Defaults to "Xform". + fabric (bool, optional): True for fabric stage and False for USD stage. Defaults to False. + + Raises: + Exception: If there is already a prim at the prim_path + + Returns: + Usd.Prim: The created USD prim. + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> prims_utils.define_prim("/World/Shapes", prim_type="Xform") + Usd.Prim() + """ + if is_prim_path_valid(prim_path, fabric=fabric): + raise Exception(f"A prim already exists at prim path: {prim_path}") + return get_current_stage(fabric=fabric).DefinePrim(prim_path, prim_type) + + +def get_prim_type_name(prim_path: str, fabric: bool = False) -> str: + """Get the TypeName of the USD Prim at the path if it is valid + + Args: + prim_path (str): path of the prim in the stage + fabric (bool, optional): True for fabric stage and False for USD stage. Defaults to False. + + Raises: + Exception: If there is not a valid prim at the given path + + Returns: + str: The TypeName of the USD Prim at the path string + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> prims_utils.get_prim_type_name("/World/Cube") + Cube + """ + if not is_prim_path_valid(prim_path, fabric=fabric): + raise Exception(f"A prim does not exist at prim path: {prim_path}") + prim = get_prim_at_path(prim_path, fabric=fabric) + if fabric: + return prim.GetTypeName() + else: + return prim.GetPrimTypeInfo().GetTypeName() + + +def move_prim(path_from: str, path_to: str) -> None: + """Run the Move command to change a prims USD Path in the stage + + Args: + path_from (str): Path of the USD Prim you wish to move + path_to (str): Final destination of the prim + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # given the stage: /World/Cube. Move the prim Cube outside the prim World + >>> prims_utils.move_prim("/World/Cube", "/Cube") + """ + MovePrimCommand(path_from=path_from, path_to=path_to).do() + + +def get_first_matching_child_prim( + prim_path: str, predicate: typing.Callable[[str], bool], fabric: bool = False +) -> Usd.Prim: + """Recursively get the first USD Prim at the path string that passes the predicate function + + Args: + prim_path (str): path of the prim in the stage + predicate (typing.Callable[[str], bool]): Function to test the prims against + fabric (bool, optional): True for fabric stage and False for USD stage. Defaults to False. + + Returns: + Usd.Prim: The first prim or child of the prim, as defined by GetChildren, that passes the predicate + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # given the stage: /World/Cube, /World/Cube_01, /World/Cube_02. + >>> # Get the first child prim of type Cube + >>> predicate = lambda path: prims_utils.get_prim_type_name(path) == "Cube" + >>> prims_utils.get_first_matching_child_prim("/", predicate) + Usd.Prim() + """ + prim = get_current_stage(fabric=fabric).GetPrimAtPath(prim_path) + children_stack = [prim] + out = prim.GetChildren() + while len(children_stack) > 0: + prim = children_stack.pop(0) + if predicate(get_prim_path(prim)): + return prim + children = prim.GetChildren() + children_stack = children_stack + children + out = out + children + return None + + +def get_first_matching_parent_prim(prim_path: str, predicate: typing.Callable[[str], bool]) -> Usd.Prim: + """Recursively get the first USD Prim at the parent path string that passes the predicate function + + Args: + prim_path (str): path of the prim in the stage + predicate (typing.Callable[[str], bool]): Function to test the prims against + + Returns: + str: The first prim on the parent path, as defined by GetParent, that passes the predicate + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # given the stage: /World/Cube. Get the first parent of Cube prim of type Xform + >>> predicate = lambda path: prims_utils.get_prim_type_name(path) == "Xform" + >>> prims_utils.get_first_matching_parent_prim("/World/Cube", predicate) + Usd.Prim() + """ + current_prim_path = get_prim_path(get_prim_parent(get_prim_at_path(prim_path))) + while not is_prim_root_path(current_prim_path): + if predicate(current_prim_path): + return get_prim_at_path(current_prim_path) + current_prim_path = get_prim_path(get_prim_parent(get_prim_at_path(current_prim_path))) + return None + + +def get_all_matching_child_prims( + prim_path: str, predicate: typing.Callable[[str], bool] = lambda x: True, depth: int | None = None +) -> list[Usd.Prim]: + """Performs a breadth-first search starting from the root and returns all the prims matching the predicate. + + Args: + prim_path (str): root prim path to start traversal from. + predicate (typing.Callable[[str], bool]): predicate that checks the prim path of a prim and returns a boolean. + depth (typing.Optional[int]): maximum depth for traversal, should be bigger than zero if specified. + Defaults to None (i.e: traversal till the end of the tree). + + Returns: + typing.List[Usd.Prim]: A list containing the root and children prims matching specified predicate. + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # get all hidden prims + >>> predicate = lambda path: prims_utils.is_prim_hidden_in_stage(path) # True if the prim at path is hidden + >>> prims_utils.get_all_matching_child_prims("/", predicate) + [Usd.Prim(), + Usd.Prim(), + Usd.Prim(), + Usd.Prim(), + Usd.Prim()] + """ + prim = get_prim_at_path(prim_path) + traversal_queue = [(prim, 0)] + out = [] + while len(traversal_queue) > 0: + prim, current_depth = traversal_queue.pop(0) + if is_prim_path_valid(get_prim_path(prim)): + if predicate(get_prim_path(prim)): + out.append(prim) + if depth is None or current_depth < depth: + children = get_prim_children(prim) + traversal_queue = traversal_queue + [(child, current_depth + 1) for child in children] + return out + + +def get_prim_children(prim: Usd.Prim) -> list[Usd.Prim]: + """Return the call of the USD Prim's GetChildren member function + + Args: + prim (Usd.Prim): The parent USD Prim + + Returns: + typing.List[Usd.Prim]: A list of the prim's children. + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # given the stage: /World/Cube, /World/Cube_01, /World/Cube_02. + >>> # Get all prims under the prim World + >>> prim = prims_utils.get_prim_at_path("/World") + >>> prims_utils.get_prim_children(prim) + [Usd.Prim(), Usd.Prim(), Usd.Prim()] + """ + return prim.GetChildren() + + +def get_prim_parent(prim: Usd.Prim) -> Usd.Prim: + """Return the call of the USD Prim's GetChildren member function + + Args: + prim (Usd.Prim): The USD Prim to call GetParent on + + Returns: + Usd.Prim: The prim's parent returned from GetParent + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # given the stage: /World/Cube. Get the prim Cube's parent + >>> prim = prims_utils.get_prim_at_path("/World/Cube") + >>> prims_utils.get_prim_parent(prim) + Usd.Prim() + """ + return prim.GetParent() + + +def query_parent_path(prim_path: str, predicate: typing.Callable[[str], bool]) -> bool: + """Check if one of the ancestors of the prim at the prim_path can pass the predicate + + Args: + prim_path (str): path to the USD Prim for which to check the ancestors + predicate (typing.Callable[[str], bool]): The condition that must be True about the ancestors + + Returns: + bool: True if there is an ancestor that can pass the predicate, False otherwise + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # given the stage: /World/Cube. Check is the prim Cube has an ancestor of type Xform + >>> predicate = lambda path: prims_utils.get_prim_type_name(path) == "Xform" + >>> prims_utils.query_parent_path("/World/Cube", predicate) + True + """ + current_prim_path = get_prim_path(get_prim_parent(get_prim_at_path(prim_path))) + while not is_prim_root_path(current_prim_path): + if predicate(current_prim_path): + return True + current_prim_path = get_prim_path(get_prim_parent(get_prim_at_path(current_prim_path))) + return False + + +def is_prim_ancestral(prim_path: str) -> bool: + """Check if any of the prims ancestors were brought in as a reference + + Args: + prim_path (str): The path to the USD prim. + + Returns: + True if prim is part of a referenced prim, false otherwise. + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # /World/Cube is a prim created + >>> prims_utils.is_prim_ancestral("/World/Cube") + False + >>> # /World/panda is an USD file loaded (as reference) under that path + >>> prims_utils.is_prim_ancestral("/World/panda") + False + >>> prims_utils.is_prim_ancestral("/World/panda/panda_link0") + True + """ + return omni.usd.check_ancestral(get_prim_at_path(prim_path)) + + +def is_prim_root_path(prim_path: str) -> bool: + """Checks if the input prim path is root or not. + + Args: + prim_path (str): The path to the USD prim. + + Returns: + True if the prim path is "/", False otherwise + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # given the stage: /World/Cube + >>> prims_utils.is_prim_root_path("/") + True + >>> prims_utils.is_prim_root_path("/World") + False + >>> prims_utils.is_prim_root_path("/World/Cube") + False + """ + return prim_path == "/" + + +def is_prim_no_delete(prim_path: str) -> bool: + """Checks whether a prim can be deleted or not from USD stage. + + .. note :: + + This function checks for the ``no_delete`` prim metadata. A prim with this + metadata set to True cannot be deleted by using the edit menu, the context menu, + or by calling the ``delete_prim`` function, for example. + + Args: + prim_path (str): The path to the USD prim. + + Returns: + True if prim cannot be deleted, False if it can + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # prim without the 'no_delete' metadata + >>> prims_utils.is_prim_no_delete("/World/Cube") + None + >>> # prim with the 'no_delete' metadata set to True + >>> prims_utils.is_prim_no_delete("/World/Cube") + True + """ + return get_prim_at_path(prim_path).GetMetadata("no_delete") + + +def is_prim_hidden_in_stage(prim_path: str) -> bool: + """Checks if the prim is hidden in the USd stage or not. + + .. warning :: + + This function checks for the ``hide_in_stage_window`` prim metadata. + This metadata is not related to the visibility of the prim. + + Args: + prim_path (str): The path to the USD prim. + + Returns: + True if prim is hidden from stage window, False if not hidden. + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # prim without the 'hide_in_stage_window' metadata + >>> prims_utils.is_prim_hidden_in_stage("/World/Cube") + None + >>> # prim with the 'hide_in_stage_window' metadata set to True + >>> prims_utils.is_prim_hidden_in_stage("/World/Cube") + True + """ + return get_prim_at_path(prim_path).GetMetadata("hide_in_stage_window") + + +def get_prim_path(prim: Usd.Prim) -> str: + """Get the path of a given USD prim. + + Args: + prim (Usd.Prim): The input USD prim. + + Returns: + str: The path to the input prim. + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> prim = prims_utils.get_prim_at_path("/World/Cube") # Usd.Prim() + >>> prims_utils.get_prim_path(prim) + /World/Cube + """ + if prim: + if isinstance(prim, Usd.Prim): + return prim.GetPath().pathString + else: + return prim.GetPath() + else: + return None + + +def set_prim_visibility(prim: Usd.Prim, visible: bool) -> None: + """Sets the visibility of the prim in the opened stage. + + .. note:: + + The method does this through the USD API. + + Args: + prim (Usd.Prim): the USD prim + visible (bool): flag to set the visibility of the usd prim in stage. + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # given the stage: /World/Cube. Make the Cube not visible + >>> prim = prims_utils.get_prim_at_path("/World/Cube") + >>> prims_utils.set_prim_visibility(prim, False) + """ + imageable = UsdGeom.Imageable(prim) + if visible: + imageable.MakeVisible() + else: + imageable.MakeInvisible() + + +def create_prim( + prim_path: str, + prim_type: str = "Xform", + position: typing.Sequence[float] | None = None, + translation: typing.Sequence[float] | None = None, + orientation: typing.Sequence[float] | None = None, + scale: typing.Sequence[float] | None = None, + usd_path: str | None = None, + semantic_label: str | None = None, + semantic_type: str = "class", + attributes: dict | None = None, +) -> Usd.Prim: + """Create a prim into current USD stage. + + The method applies specified transforms, the semantic label and set specified attributes. + + Args: + prim_path (str): The path of the new prim. + prim_type (str): Prim type name + position (typing.Sequence[float], optional): prim position (applied last) + translation (typing.Sequence[float], optional): prim translation (applied last) + orientation (typing.Sequence[float], optional): prim rotation as quaternion + scale (np.ndarray (3), optional): scaling factor in x, y, z. + usd_path (str, optional): Path to the USD that this prim will reference. + semantic_label (str, optional): Semantic label. + semantic_type (str, optional): set to "class" unless otherwise specified. + attributes (dict, optional): Key-value pairs of prim attributes to set. + + Raises: + Exception: If there is already a prim at the prim_path + + Returns: + Usd.Prim: The created USD prim. + + Example: + + .. code-block:: python + + >>> import numpy as np + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # create a cube (/World/Cube) of size 2 centered at (1.0, 0.5, 0.0) + >>> prims_utils.create_prim( + ... prim_path="/World/Cube", + ... prim_type="Cube", + ... position=np.array([1.0, 0.5, 0.0]), + ... attributes={"size": 2.0} + ... ) + Usd.Prim() + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # load an USD file (franka.usd) to the stage under the path /World/panda + >>> prims_utils.create_prim( + ... prim_path="/World/panda", + ... prim_type="Xform", + ... usd_path="/home//Documents/Assets/Robots/FrankaRobotics/FrankaPanda/franka.usd" + ... ) + Usd.Prim() + """ + # Note: Imported here to prevent cyclic dependency in the module. + from isaacsim.core.prims import XFormPrim + + # create prim in stage + prim = define_prim(prim_path=prim_path, prim_type=prim_type) + if not prim: + return None + # apply attributes into prim + if attributes is not None: + for k, v in attributes.items(): + prim.GetAttribute(k).Set(v) + # add reference to USD file + if usd_path is not None: + add_reference_to_stage(usd_path=usd_path, prim_path=prim_path) + # add semantic label to prim + if semantic_label is not None: + add_labels(prim, labels=[semantic_label], instance_name=semantic_type) + # apply the transformations + from isaacsim.core.api.simulation_context.simulation_context import SimulationContext + + if SimulationContext.instance() is None: + # FIXME: remove this, we should never even use backend utils especially not numpy ones + import isaacsim.core.utils.numpy as backend_utils + + device = "cpu" + else: + backend_utils = SimulationContext.instance().backend_utils + device = SimulationContext.instance().device + if position is not None: + position = backend_utils.expand_dims(backend_utils.convert(position, device), 0) + if translation is not None: + translation = backend_utils.expand_dims(backend_utils.convert(translation, device), 0) + if orientation is not None: + orientation = backend_utils.expand_dims(backend_utils.convert(orientation, device), 0) + if scale is not None: + scale = backend_utils.expand_dims(backend_utils.convert(scale, device), 0) + XFormPrim(prim_path, positions=position, translations=translation, orientations=orientation, scales=scale) + + return prim + + +def delete_prim(prim_path: str) -> None: + """Remove the USD Prim and its descendants from the scene if able + + Args: + prim_path (str): path of the prim in the stage + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> prims_utils.delete_prim("/World/Cube") + """ + DeletePrimsCommand([prim_path]).do() + + +def get_prim_property(prim_path: str, property_name: str) -> typing.Any: + """Get the attribute of the USD Prim at the given path + + Args: + prim_path (str): path of the prim in the stage + property_name (str): name of the attribute to get + + Returns: + typing.Any: The attribute if it exists, None otherwise + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> prims_utils.get_prim_property("/World/Cube", property_name="size") + 1.0 + """ + prim = get_prim_at_path(prim_path=prim_path) + return prim.GetAttribute(property_name).Get() + + +def set_prim_property(prim_path: str, property_name: str, property_value: typing.Any) -> None: + """Set the attribute of the USD Prim at the path + + Args: + prim_path (str): path of the prim in the stage + property_name (str): name of the attribute to set + property_value (typing.Any): value to set the attribute to + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # given the stage: /World/Cube. Set the Cube size to 5.0 + >>> prims_utils.set_prim_property("/World/Cube", property_name="size", property_value=5.0) + """ + prim = get_prim_at_path(prim_path=prim_path) + prim.GetAttribute(property_name).Set(property_value) + + +def get_prim_object_type(prim_path: str) -> str | None: + """Get the dynamic control object type of the USD Prim at the given path. + + If the prim at the path is of Dynamic Control type e.g.: rigid_body, joint, dof, articulation, attractor, d6joint, + then the corresponding string returned. If is an Xformable prim, then "xform" is returned. Otherwise None + is returned. + + Args: + prim_path (str): path of the prim in the stage + + Raises: + Exception: If the USD Prim is not a supported type. + + Returns: + str: String corresponding to the object type. + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> prims_utils.get_prim_object_type("/World/Cube") + xform + """ + prim = get_prim_at_path(prim_path) + if prim.HasAPI(UsdPhysics.ArticulationRootAPI): + return "articulation" + elif prim.HasAPI(UsdPhysics.RigidBodyAPI): + return "rigid_body" + elif ( + prim.IsA(UsdPhysics.PrismaticJoint) or prim.IsA(UsdPhysics.RevoluteJoint) or prim.IsA(UsdPhysics.SphericalJoint) + ): + return "joint" + elif prim.IsA(UsdPhysics.Joint): + return "d6joint" + elif prim.IsA(UsdGeom.Xformable): + return "xform" + else: + return None + + +def is_prim_non_root_articulation_link(prim_path: str) -> bool: + """Used to query if the prim_path corresponds to a link in an articulation which is a non root link. + + Args: + prim_path (str): prim_path to query + + Returns: + bool: True if the prim path corresponds to a link in an articulation which is a non root link + and can't have a transformation applied to it. + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # /World/panda contains the prim tree for the Franka panda robot. + >>> # The prim on this path has the Physics Articulation Root property applied + >>> prims_utils.is_prim_non_root_articulation_link("/World/panda") + False + >>> prims_utils.is_prim_non_root_articulation_link("/World/panda/panda_link0") + True + """ + parent_articulation_root = get_first_matching_parent_prim( + prim_path=prim_path, predicate=lambda a: get_prim_at_path(a).HasAPI(UsdPhysics.ArticulationRootAPI) + ) + if parent_articulation_root is None: + return False + + has_physics_apis = get_prim_at_path(prim_path).HasAPI(UsdPhysics.RigidBodyAPI) + if not has_physics_apis: + return False + + # get all joints under ArticulationRoot + joint_prims = get_all_matching_child_prims( + prim_path=get_prim_path(parent_articulation_root), predicate=lambda a: "Joint" in get_prim_type_name(a) + ) + # this assumes if that the first link is a root articulation link + for joint_prim in joint_prims: + joint = UsdPhysics.Joint(joint_prim) + if joint.GetExcludeFromArticulationAttr().Get(): + continue + body_targets = joint.GetBody0Rel().GetTargets() + joint.GetBody1Rel().GetTargets() + for target in body_targets: + if prim_path == str(target): + return True + return False + + +def set_prim_hide_in_stage_window(prim: Usd.Prim, hide: bool): + """Set ``hide_in_stage_window`` metadata for a prim + + .. warning :: + + This metadata is unrelated to the visibility of the prim. + Use the ``set_prim_visibility`` function for the latter purpose + + Args: + prim (Usd.Prim): Prim to set + hide (bool): True to hide in stage window, false to show + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> prim = prims_utils.get_prim_at_path("/World/Cube") + >>> prims_utils.set_prim_hide_in_stage_window(prim, True) + """ + prim.SetMetadata("hide_in_stage_window", hide) + + +def set_prim_no_delete(prim: Usd.Prim, no_delete: bool): + """Set ``no_delete`` metadata for a prim + + .. note :: + + A prim with this metadata set to True cannot be deleted by using the edit menu, + the context menu, or by calling the ``delete_prim`` function, for example. + + Args: + prim (Usd.Prim): Prim to set + no_delete (bool):True to make prim undeletable in stage window, false to allow deletion + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> prim = prims_utils.get_prim_at_path("/World/Cube") + >>> prims_utils.set_prim_no_delete(prim, True) + """ + prim.SetMetadata("no_delete", no_delete) + + +def set_targets(prim: Usd.Prim, attribute: str, target_prim_paths: list): + """Set targets for a prim relationship attribute + + Args: + prim (Usd.Prim): Prim to create and set attribute on + attribute (str): Relationship attribute to create + target_prim_paths (list): list of targets to set + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # given the stage: /World/Cube, /World/Cube_01, /World/Cube_02. + >>> # Set each prim Cube to the relationship targetPrim of the prim World + >>> prim = prims_utils.get_prim_at_path("/World") + >>> targets = ["/World/Cube", "/World/Cube_01", "/World/Cube_02"] + >>> prims_utils.set_targets(prim, "targetPrim", targets) + """ + try: + input_rel = prim.CreateRelationship(attribute) + input_rel.SetTargets(target_prim_paths) + except Exception as e: + print(e, prim.GetPath()) + + +def get_articulation_root_api_prim_path(prim_path): + """Get the prim path that has the Articulation Root API + + .. note:: + + This function assumes that all prims defined by a regular expression correspond to the same articulation type + + Args: + prim_path (str): path or regex of the prim(s) on which to search for the prim containing the API + + Returns: + str: path or regex of the prim(s) that has the Articulation Root API. + If no prim has been found, the same input value is returned + + Example: + + .. code-block:: python + + >>> import isaaclab.utils.prims as prims_utils + >>> + >>> # given the stage: /World/env/Ant, /World/env_01/Ant, /World/env_02/Ant + >>> # search specifying the prim with the Articulation Root API + >>> prims_utils.get_articulation_root_api_prim_path("/World/env/Ant/torso") + /World/env/Ant/torso + >>> # search specifying some ancestor prim that does not have the Articulation Root API + >>> prims_utils.get_articulation_root_api_prim_path("/World/env/Ant") + /World/env/Ant/torso + >>> # regular expression search + >>> prims_utils.get_articulation_root_api_prim_path("/World/env.*/Ant") + /World/env.*/Ant/torso + """ + predicate = lambda path: get_prim_at_path(path).HasAPI(UsdPhysics.ArticulationRootAPI) # noqa: E731 + # single prim + if Sdf.Path.IsValidPathString(prim_path) and is_prim_path_valid(prim_path): + prim = get_first_matching_child_prim(prim_path, predicate) + if prim is not None: + return get_prim_path(prim) + # regular expression + else: + paths = sim_utils.find_matching_prim_paths(prim_path) + if len(paths): + prim = get_first_matching_child_prim(paths[0], predicate) + if prim is not None: + path = get_prim_path(prim) + remainder_path = "/".join(path.split("/")[prim_path.count("/") + 1 :]) + if remainder_path != "": + return prim_path + "/" + remainder_path + else: + return prim_path + return prim_path diff --git a/source/isaaclab/isaaclab/sim/utils/semantics.py b/source/isaaclab/isaaclab/sim/utils/semantics.py new file mode 100644 index 00000000000..48375e0a0eb --- /dev/null +++ b/source/isaaclab/isaaclab/sim/utils/semantics.py @@ -0,0 +1,275 @@ +# Copyright (c) 2022-2025, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause + +import carb +from isaacsim.core.utils.stage import get_current_stage +from pxr import Usd, UsdGeom, UsdSemantics + +# from Isaac Sim 4.2 onwards, pxr.Semantics is deprecated +try: + import Semantics +except ModuleNotFoundError: + from pxr import Semantics + + +def add_labels(prim: Usd.Prim, labels: list[str], instance_name: str = "class", overwrite: bool = True) -> None: + """Apply semantic labels to a prim using the UsdSemantics.LabelsAPI. + + Args: + prim (Usd.Prim): Usd Prim to add or update labels on. + labels (list): The list of labels to apply. + instance_name (str, optional): The name of the semantic instance. Defaults to "class". + overwrite (bool, optional): If True (default), existing labels for this instance are replaced. + If False, the new labels are appended to existing ones (if any). + """ + import omni.replicator.core.functional as F + + mode = "replace" if overwrite else "add" + F.modify.semantics(prim, {instance_name: labels}, mode=mode) + + +def get_labels(prim: Usd.Prim) -> dict[str, list[str]]: + """Returns semantic labels (UsdSemantics.LabelsAPI) applied to a prim. + + Args: + prim (Usd.Prim): Prim to return labels for. + + Returns: + dict[str, list[str]]: Dictionary mapping instance names to a list of labels. + Returns an empty dict if no LabelsAPI instances are found. + """ + result = {} + for schema_name in prim.GetAppliedSchemas(): + if schema_name.startswith("SemanticsLabelsAPI:"): + instance_name = schema_name.split(":", 1)[1] + sem_api = UsdSemantics.LabelsAPI(prim, instance_name) + labels_attr = sem_api.GetLabelsAttr() + if labels_attr: + labels = labels_attr.Get() + result[instance_name] = list(labels) if labels is not None else [] + else: + result[instance_name] = [] + return result + + +def remove_labels(prim: Usd.Prim, instance_name: str | None = None, include_descendants: bool = False) -> None: + """Removes semantic labels (UsdSemantics.LabelsAPI) from a prim. + + Args: + prim (Usd.Prim): Prim to remove labels from. + instance_name (str | None, optional): Specific instance name to remove. + If None (default), removes *all* LabelsAPI instances. + include_descendants (bool, optional): Also traverse children and remove labels recursively. Defaults to False. + """ + + def remove_single_prim_labels(target_prim: Usd.Prim): + schemas_to_remove = [] + for schema_name in target_prim.GetAppliedSchemas(): + if schema_name.startswith("SemanticsLabelsAPI:"): + current_instance = schema_name.split(":", 1)[1] + if instance_name is None or current_instance == instance_name: + schemas_to_remove.append(current_instance) + + for inst_to_remove in schemas_to_remove: + target_prim.RemoveAPI(UsdSemantics.LabelsAPI, inst_to_remove) + + if include_descendants: + for p in Usd.PrimRange(prim): + remove_single_prim_labels(p) + else: + remove_single_prim_labels(prim) + + +def check_missing_labels(prim_path: str | None = None) -> list[str]: + """Returns a list of prim paths of meshes with missing semantic labels (UsdSemantics.LabelsAPI). + + Args: + prim_path (str | None): This will check Prim path and its childrens' labels. If None, checks the whole stage. + + Returns: + list[str]: Prim paths of meshes with no LabelsAPI applied. + """ + prim_paths = [] + stage = get_current_stage() + if stage is None: + carb.log_warn("Invalid stage, skipping label check") + return prim_paths + + start_prim = stage.GetPrimAtPath(prim_path) if prim_path else stage.GetPseudoRoot() + if not start_prim: + # Allow None prim_path for whole stage check, warn if path specified but not found + if prim_path: + carb.log_warn(f"Prim path not found: {prim_path}") + return prim_paths + + prims_to_check = Usd.PrimRange(start_prim) + + for prim in prims_to_check: + if prim.IsA(UsdGeom.Mesh): + has_any_label = False + for schema_name in prim.GetAppliedSchemas(): + if schema_name.startswith("SemanticsLabelsAPI:"): + has_any_label = True + break + if not has_any_label: + prim_paths.append(prim.GetPath().pathString) + return prim_paths + + +def check_incorrect_labels(prim_path: str | None = None) -> list[list[str]]: + """Returns a list of [prim_path, label] for meshes where at least one semantic label (LabelsAPI) + is not found within the prim's path string (case-insensitive, ignoring '_' and '-'). + + Args: + prim_path (str | None): This will check Prim path and its childrens' labels. If None, checks the whole stage. + + Returns: + list[list[str]]: List containing pairs of [prim_path, first_incorrect_label]. + """ + incorrect_pairs = [] + stage = get_current_stage() + if stage is None: + carb.log_warn("Invalid stage, skipping label check") + return incorrect_pairs + + start_prim = stage.GetPrimAtPath(prim_path) if prim_path else stage.GetPseudoRoot() + if not start_prim: + if prim_path: + carb.log_warn(f"Prim path not found: {prim_path}") + return incorrect_pairs + + prims_to_check = Usd.PrimRange(start_prim) + + for prim in prims_to_check: + if prim.IsA(UsdGeom.Mesh): + labels_dict = get_labels(prim) + if labels_dict: + prim_path_str = prim.GetPath().pathString.lower() + all_labels = [ + label for sublist in labels_dict.values() for label in sublist if label + ] # Flatten and filter None/empty + for label in all_labels: + label_lower = label.lower() + # Check if label (or label without separators) is in path + if ( + label_lower not in prim_path_str + and label_lower.replace("_", "") not in prim_path_str + and label_lower.replace("-", "") not in prim_path_str + ): + incorrect_pair = [prim.GetPath().pathString, label] + incorrect_pairs.append(incorrect_pair) + break # Only report first incorrect label per prim + return incorrect_pairs + + +def count_labels_in_scene(prim_path: str | None = None) -> dict[str, int]: + """Returns a dictionary of semantic labels (UsdSemantics.LabelsAPI) and their corresponding count. + + Args: + prim_path (str | None): This will check Prim path and its childrens' labels. If None, checks the whole stage. + + Returns: + dict[str, int]: Dictionary mapping individual labels to their total count across all instances. + Includes a 'missing_labels' count for meshes with no LabelsAPI. + """ + labels_counter = {"missing_labels": 0} + stage = get_current_stage() + if stage is None: + carb.log_warn("Invalid stage, skipping label check") + return labels_counter + + start_prim = stage.GetPrimAtPath(prim_path) if prim_path else stage.GetPseudoRoot() + if not start_prim: + if prim_path: + carb.log_warn(f"Prim path not found: {prim_path}") + return labels_counter + + prims_to_check = Usd.PrimRange(start_prim) + + for prim in prims_to_check: + if prim.IsA(UsdGeom.Mesh): + labels_dict = get_labels(prim) + if not labels_dict: + labels_counter["missing_labels"] += 1 + else: + # Iterate through all labels from all instances on the prim + all_labels = [label for sublist in labels_dict.values() for label in sublist if label] + for label in all_labels: + labels_counter[label] = labels_counter.get(label, 0) + 1 + + return labels_counter + + +def upgrade_prim_semantics_to_labels(prim: Usd.Prim, include_descendants: bool = False) -> int: + """Upgrades a prim and optionally its descendants from the deprecated SemanticsAPI + to the new UsdSemantics.LabelsAPI. + + Converts each found SemanticsAPI instance on the processed prim(s) to a corresponding + LabelsAPI instance. The old 'semanticType' becomes the new LabelsAPI + 'instance_name', and the old 'semanticData' becomes the single label in the + new 'labels' list. The old SemanticsAPI is always removed after upgrading. + + Args: + prim (Usd.Prim): The starting prim to upgrade. + include_descendants (bool, optional): If True, upgrades the prim and all its descendants. + If False (default), upgrades only the specified prim. + + Returns: + int: The total number of SemanticsAPI instances successfully upgraded to LabelsAPI. + """ + total_upgraded = 0 + + prims_to_process = Usd.PrimRange(prim) if include_descendants else [prim] + + for current_prim in prims_to_process: + if not current_prim: + continue + + old_semantics = {} + for prop in current_prim.GetProperties(): + if Semantics.SemanticsAPI.IsSemanticsAPIPath(prop.GetPath()): + instance_name = prop.SplitName()[1] # Get instance name (e.g., 'Semantics', 'Semantics_a') + sem_api = Semantics.SemanticsAPI.Get(current_prim, instance_name) + if sem_api: + typeAttr = sem_api.GetSemanticTypeAttr() + dataAttr = sem_api.GetSemanticDataAttr() + if typeAttr and dataAttr and instance_name not in old_semantics: + old_semantics[instance_name] = (typeAttr.Get(), dataAttr.Get()) + + if not old_semantics: + continue + + for old_instance_name, (old_type, old_data) in old_semantics.items(): + + if not old_type or not old_data: + carb.log_warn( + f"[upgrade_prim] Skipping instance '{old_instance_name}' on {current_prim.GetPath()} due to missing" + " type or data." + ) + continue + + new_instance_name = old_type + new_labels = [old_data] + + try: + old_sem_api_to_remove = Semantics.SemanticsAPI.Get(current_prim, old_instance_name) + if old_sem_api_to_remove: + typeAttr = old_sem_api_to_remove.GetSemanticTypeAttr() + dataAttr = old_sem_api_to_remove.GetSemanticDataAttr() + # Ensure attributes are valid before trying to remove them by name + if typeAttr and typeAttr.IsDefined(): + current_prim.RemoveProperty(typeAttr.GetName()) + if dataAttr and dataAttr.IsDefined(): + current_prim.RemoveProperty(dataAttr.GetName()) + current_prim.RemoveAPI(Semantics.SemanticsAPI, old_instance_name) + + add_labels(current_prim, new_labels, instance_name=new_instance_name, overwrite=False) + + total_upgraded += 1 + + except Exception as e: + carb.log_warn(f"Failed to upgrade instance '{old_instance_name}' on {current_prim.GetPath()}: {e}") + continue + return total_upgraded diff --git a/source/isaaclab/isaaclab/sim/utils.py b/source/isaaclab/isaaclab/sim/utils/utils.py similarity index 100% rename from source/isaaclab/isaaclab/sim/utils.py rename to source/isaaclab/isaaclab/sim/utils/utils.py diff --git a/source/isaaclab/isaaclab/terrains/utils.py b/source/isaaclab/isaaclab/terrains/utils.py index 1c55a9325b2..92aa96975b9 100644 --- a/source/isaaclab/isaaclab/terrains/utils.py +++ b/source/isaaclab/isaaclab/terrains/utils.py @@ -80,10 +80,10 @@ def create_prim_from_mesh(prim_path: str, mesh: trimesh.Trimesh, **kwargs): physics_material: The physics material to apply. Defaults to None. """ # need to import these here to prevent isaacsim launching when importing this module - import isaacsim.core.utils.prims as prim_utils from pxr import UsdGeom import isaaclab.sim as sim_utils + import isaaclab.sim.utils.prims as prim_utils # create parent prim prim_utils.create_prim(prim_path, "Xform") diff --git a/source/isaaclab/isaaclab/ui/xr_widgets/instruction_widget.py b/source/isaaclab/isaaclab/ui/xr_widgets/instruction_widget.py index ec084098dcb..a8d82864db5 100644 --- a/source/isaaclab/isaaclab/ui/xr_widgets/instruction_widget.py +++ b/source/isaaclab/isaaclab/ui/xr_widgets/instruction_widget.py @@ -10,11 +10,12 @@ import omni.kit.commands import omni.ui as ui -from isaacsim.core.utils.prims import delete_prim, get_prim_at_path from omni.kit.xr.scene_view.utils import UiContainer, WidgetComponent from omni.kit.xr.scene_view.utils.spatial_source import SpatialSource from pxr import Gf +from isaaclab.sim.utils.prims import delete_prim, get_prim_at_path + Vec3Type: TypeAlias = Gf.Vec3f | Gf.Vec3d camera_facing_widget_container = {} diff --git a/source/isaaclab/isaaclab/utils/string.py b/source/isaaclab/isaaclab/utils/string.py index 43a2fa0b310..22e7f0e66be 100644 --- a/source/isaaclab/isaaclab/utils/string.py +++ b/source/isaaclab/isaaclab/utils/string.py @@ -370,3 +370,46 @@ def resolve_matching_names_values( ) # return return index_list, names_list, values_list + + +def find_unique_string_name(initial_name: str, is_unique_fn: Callable[[str], bool]) -> str: + """Find a unique string name based on the predicate function provided. + The string is appended with "_N", where N is a natural number till the resultant string + is unique. + Args: + initial_name (str): The initial string name. + is_unique_fn (Callable[[str], bool]): The predicate function to validate against. + Returns: + str: A unique string based on input function. + """ + if is_unique_fn(initial_name): + return initial_name + iterator = 1 + result = initial_name + "_" + str(iterator) + while not is_unique_fn(result): + result = initial_name + "_" + str(iterator) + iterator += 1 + return result + + +def find_root_prim_path_from_regex(prim_path_regex: str) -> tuple[str, int]: + """Find the first prim above the regex pattern prim and its position. + Args: + prim_path_regex (str): full prim path including the regex pattern prim. + Returns: + Tuple[str, int]: First position is the prim path to the parent of the regex prim. + Second position represents the level of the regex prim in the USD stage tree representation. + """ + prim_paths_list = str(prim_path_regex).split("/") + root_idx = None + for prim_path_idx in range(len(prim_paths_list)): + chars = set("[]*|^") + if any((c in chars) for c in prim_paths_list[prim_path_idx]): + root_idx = prim_path_idx + break + root_prim_path = None + tree_level = None + if root_idx is not None: + root_prim_path = "/".join(prim_paths_list[:root_idx]) + tree_level = root_idx + return root_prim_path, tree_level diff --git a/source/isaaclab/test/assets/check_fixed_base_assets.py b/source/isaaclab/test/assets/check_fixed_base_assets.py index 8a07be1c413..cafb4a561f6 100644 --- a/source/isaaclab/test/assets/check_fixed_base_assets.py +++ b/source/isaaclab/test/assets/check_fixed_base_assets.py @@ -35,9 +35,8 @@ import numpy as np import torch -import isaacsim.core.utils.prims as prim_utils - import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.assets import Articulation ## diff --git a/source/isaaclab/test/assets/test_articulation.py b/source/isaaclab/test/assets/test_articulation.py index dfacff5d2ec..b72744d3b14 100644 --- a/source/isaaclab/test/assets/test_articulation.py +++ b/source/isaaclab/test/assets/test_articulation.py @@ -20,11 +20,11 @@ import ctypes import torch -import isaacsim.core.utils.prims as prim_utils import pytest from isaacsim.core.version import get_version import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils import isaaclab.utils.math as math_utils import isaaclab.utils.string as string_utils from isaaclab.actuators import ActuatorBase, IdealPDActuatorCfg, ImplicitActuatorCfg diff --git a/source/isaaclab/test/assets/test_deformable_object.py b/source/isaaclab/test/assets/test_deformable_object.py index 2d589573e69..3044d973420 100644 --- a/source/isaaclab/test/assets/test_deformable_object.py +++ b/source/isaaclab/test/assets/test_deformable_object.py @@ -20,11 +20,11 @@ import torch import carb -import isaacsim.core.utils.prims as prim_utils import pytest from flaky import flaky import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils import isaaclab.utils.math as math_utils from isaaclab.assets import DeformableObject, DeformableObjectCfg from isaaclab.sim import build_simulation_context diff --git a/source/isaaclab/test/assets/test_rigid_object.py b/source/isaaclab/test/assets/test_rigid_object.py index 6a0dc77b861..e2eaef091d5 100644 --- a/source/isaaclab/test/assets/test_rigid_object.py +++ b/source/isaaclab/test/assets/test_rigid_object.py @@ -20,11 +20,11 @@ import torch from typing import Literal -import isaacsim.core.utils.prims as prim_utils import pytest from flaky import flaky import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.assets import RigidObject, RigidObjectCfg from isaaclab.sim import build_simulation_context from isaaclab.sim.spawners import materials diff --git a/source/isaaclab/test/assets/test_rigid_object_collection.py b/source/isaaclab/test/assets/test_rigid_object_collection.py index 876a2904bf1..b11d046ad81 100644 --- a/source/isaaclab/test/assets/test_rigid_object_collection.py +++ b/source/isaaclab/test/assets/test_rigid_object_collection.py @@ -19,10 +19,10 @@ import ctypes import torch -import isaacsim.core.utils.prims as prim_utils import pytest import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.assets import RigidObjectCfg, RigidObjectCollection, RigidObjectCollectionCfg from isaaclab.sim import build_simulation_context from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR diff --git a/source/isaaclab/test/assets/test_surface_gripper.py b/source/isaaclab/test/assets/test_surface_gripper.py index c2f81143f59..2dae2cf95da 100644 --- a/source/isaaclab/test/assets/test_surface_gripper.py +++ b/source/isaaclab/test/assets/test_surface_gripper.py @@ -18,11 +18,11 @@ import torch -import isaacsim.core.utils.prims as prim_utils import pytest from isaacsim.core.version import get_version import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.actuators import ImplicitActuatorCfg from isaaclab.assets import ( Articulation, diff --git a/source/isaaclab/test/controllers/test_differential_ik.py b/source/isaaclab/test/controllers/test_differential_ik.py index 0b84e09eff2..b7ac72aa323 100644 --- a/source/isaaclab/test/controllers/test_differential_ik.py +++ b/source/isaaclab/test/controllers/test_differential_ik.py @@ -14,12 +14,12 @@ import torch -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest from isaacsim.core.cloner import GridCloner import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.assets import Articulation from isaaclab.controllers import DifferentialIKController, DifferentialIKControllerCfg diff --git a/source/isaaclab/test/controllers/test_operational_space.py b/source/isaaclab/test/controllers/test_operational_space.py index b708b357218..8588df8a831 100644 --- a/source/isaaclab/test/controllers/test_operational_space.py +++ b/source/isaaclab/test/controllers/test_operational_space.py @@ -14,12 +14,12 @@ import torch -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest from isaacsim.core.cloner import GridCloner import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.assets import Articulation from isaaclab.controllers import OperationalSpaceController, OperationalSpaceControllerCfg from isaaclab.markers import VisualizationMarkers diff --git a/source/isaaclab/test/deps/isaacsim/check_camera.py b/source/isaaclab/test/deps/isaacsim/check_camera.py index c9e0374fc92..184bfc6858f 100644 --- a/source/isaaclab/test/deps/isaacsim/check_camera.py +++ b/source/isaaclab/test/deps/isaacsim/check_camera.py @@ -50,7 +50,6 @@ except ModuleNotFoundError: import isaacsim.core.utils.nucleus as nucleus_utils -import isaacsim.core.utils.prims as prim_utils import omni.replicator.core as rep from isaacsim.core.api.world import World from isaacsim.core.prims import Articulation, RigidPrim, SingleGeometryPrim, SingleRigidPrim @@ -59,6 +58,8 @@ from PIL import Image, ImageChops from pxr import Gf, UsdGeom +import isaaclab.sim.utils.prims as prim_utils + # check nucleus connection if nucleus_utils.get_assets_root_path() is None: msg = ( diff --git a/source/isaaclab/test/deps/isaacsim/check_floating_base_made_fixed.py b/source/isaaclab/test/deps/isaacsim/check_floating_base_made_fixed.py index dbe12e8265f..75abea11bef 100644 --- a/source/isaaclab/test/deps/isaacsim/check_floating_base_made_fixed.py +++ b/source/isaaclab/test/deps/isaacsim/check_floating_base_made_fixed.py @@ -33,7 +33,6 @@ import torch import isaacsim.core.utils.nucleus as nucleus_utils -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import omni.kit.commands import omni.log @@ -44,6 +43,8 @@ from isaacsim.core.utils.viewports import set_camera_view from pxr import PhysxSchema, UsdPhysics +import isaaclab.sim.utils.prims as prim_utils + # check nucleus connection if nucleus_utils.get_assets_root_path() is None: msg = ( diff --git a/source/isaaclab/test/deps/isaacsim/check_legged_robot_clone.py b/source/isaaclab/test/deps/isaacsim/check_legged_robot_clone.py index c26f627a220..aaa08f812e5 100644 --- a/source/isaaclab/test/deps/isaacsim/check_legged_robot_clone.py +++ b/source/isaaclab/test/deps/isaacsim/check_legged_robot_clone.py @@ -50,13 +50,14 @@ except ModuleNotFoundError: import isaacsim.core.utils.nucleus as nucleus_utils -import isaacsim.core.utils.prims as prim_utils from isaacsim.core.api.world import World from isaacsim.core.cloner import GridCloner from isaacsim.core.prims import Articulation from isaacsim.core.utils.carb import set_carb_setting from isaacsim.core.utils.viewports import set_camera_view +import isaaclab.sim.utils.prims as prim_utils + # check nucleus connection if nucleus_utils.get_assets_root_path() is None: msg = ( diff --git a/source/isaaclab/test/deps/isaacsim/check_ref_count.py b/source/isaaclab/test/deps/isaacsim/check_ref_count.py index 2683bd3e989..b5fbefa76d9 100644 --- a/source/isaaclab/test/deps/isaacsim/check_ref_count.py +++ b/source/isaaclab/test/deps/isaacsim/check_ref_count.py @@ -44,11 +44,12 @@ except ModuleNotFoundError: import isaacsim.core.utils.nucleus as nucleus_utils -import isaacsim.core.utils.prims as prim_utils from isaacsim.core.api.simulation_context import SimulationContext from isaacsim.core.prims import Articulation from isaacsim.core.utils.carb import set_carb_setting +import isaaclab.sim.utils.prims as prim_utils + # check nucleus connection if nucleus_utils.get_assets_root_path() is None: msg = ( diff --git a/source/isaaclab/test/deps/isaacsim/check_rep_texture_randomizer.py b/source/isaaclab/test/deps/isaacsim/check_rep_texture_randomizer.py index 5700b5c9044..fd0426f1202 100644 --- a/source/isaaclab/test/deps/isaacsim/check_rep_texture_randomizer.py +++ b/source/isaaclab/test/deps/isaacsim/check_rep_texture_randomizer.py @@ -45,7 +45,6 @@ import numpy as np import torch -import isaacsim.core.utils.prims as prim_utils import omni.replicator.core as rep from isaacsim.core.api.simulation_context import SimulationContext from isaacsim.core.cloner import GridCloner @@ -53,6 +52,8 @@ from isaacsim.core.prims import RigidPrim from isaacsim.core.utils.viewports import set_camera_view +import isaaclab.sim.utils.prims as prim_utils + def main(): """Spawn a bunch of balls and randomly change their textures.""" diff --git a/source/isaaclab/test/sensors/check_contact_sensor.py b/source/isaaclab/test/sensors/check_contact_sensor.py index 30d2c9be437..6d2a8ef4c23 100644 --- a/source/isaaclab/test/sensors/check_contact_sensor.py +++ b/source/isaaclab/test/sensors/check_contact_sensor.py @@ -36,13 +36,13 @@ import torch -import isaacsim.core.utils.prims as prim_utils from isaacsim.core.api.simulation_context import SimulationContext from isaacsim.core.cloner import GridCloner from isaacsim.core.utils.carb import set_carb_setting from isaacsim.core.utils.viewports import set_camera_view import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.assets import Articulation from isaaclab.sensors.contact_sensor import ContactSensor, ContactSensorCfg from isaaclab.utils.timer import Timer diff --git a/source/isaaclab/test/sensors/check_ray_caster.py b/source/isaaclab/test/sensors/check_ray_caster.py index e1d3473ecc4..0b481cc3166 100644 --- a/source/isaaclab/test/sensors/check_ray_caster.py +++ b/source/isaaclab/test/sensors/check_ray_caster.py @@ -41,13 +41,13 @@ import torch -import isaacsim.core.utils.prims as prim_utils from isaacsim.core.api.simulation_context import SimulationContext from isaacsim.core.cloner import GridCloner from isaacsim.core.prims import RigidPrim from isaacsim.core.utils.viewports import set_camera_view import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils import isaaclab.terrains as terrain_gen from isaaclab.sensors.ray_caster import RayCaster, RayCasterCfg, patterns from isaaclab.terrains.config.rough import ROUGH_TERRAINS_CFG diff --git a/source/isaaclab/test/sensors/test_camera.py b/source/isaaclab/test/sensors/test_camera.py index e660274b862..0844ebf41af 100644 --- a/source/isaaclab/test/sensors/test_camera.py +++ b/source/isaaclab/test/sensors/test_camera.py @@ -22,7 +22,6 @@ import scipy.spatial.transform as tf import torch -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import omni.replicator.core as rep import pytest @@ -30,6 +29,7 @@ from pxr import Gf, Usd, UsdGeom import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sensors.camera import Camera, CameraCfg from isaaclab.utils import convert_dict_to_backend from isaaclab.utils.math import convert_quat diff --git a/source/isaaclab/test/sensors/test_multi_tiled_camera.py b/source/isaaclab/test/sensors/test_multi_tiled_camera.py index 7408ae06b75..efa73b20e7c 100644 --- a/source/isaaclab/test/sensors/test_multi_tiled_camera.py +++ b/source/isaaclab/test/sensors/test_multi_tiled_camera.py @@ -20,7 +20,6 @@ import random import torch -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import omni.replicator.core as rep import pytest @@ -29,6 +28,7 @@ from pxr import Gf, UsdGeom import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sensors.camera import TiledCamera, TiledCameraCfg diff --git a/source/isaaclab/test/sensors/test_ray_caster_camera.py b/source/isaaclab/test/sensors/test_ray_caster_camera.py index dd693bbc3f1..66fcbf028aa 100644 --- a/source/isaaclab/test/sensors/test_ray_caster_camera.py +++ b/source/isaaclab/test/sensors/test_ray_caster_camera.py @@ -20,13 +20,13 @@ import os import torch -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import omni.replicator.core as rep import pytest from pxr import Gf import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sensors.camera import Camera, CameraCfg from isaaclab.sensors.ray_caster import RayCasterCamera, RayCasterCameraCfg, patterns from isaaclab.sim import PinholeCameraCfg diff --git a/source/isaaclab/test/sensors/test_sensor_base.py b/source/isaaclab/test/sensors/test_sensor_base.py index 9f82198214c..3fc55229ff2 100644 --- a/source/isaaclab/test/sensors/test_sensor_base.py +++ b/source/isaaclab/test/sensors/test_sensor_base.py @@ -18,11 +18,11 @@ from collections.abc import Sequence from dataclasses import dataclass -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sensors import SensorBase, SensorBaseCfg from isaaclab.utils import configclass diff --git a/source/isaaclab/test/sensors/test_tiled_camera.py b/source/isaaclab/test/sensors/test_tiled_camera.py index fdef7a3ae5c..7a6312cad26 100644 --- a/source/isaaclab/test/sensors/test_tiled_camera.py +++ b/source/isaaclab/test/sensors/test_tiled_camera.py @@ -20,13 +20,14 @@ import random import torch -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import omni.replicator.core as rep import pytest from isaacsim.core.prims import SingleGeometryPrim, SingleRigidPrim from pxr import Gf, UsdGeom +import isaaclab.sim.utils.prims as prim_utils + # from Isaac Sim 4.2 onwards, pxr.Semantics is deprecated try: import Semantics diff --git a/source/isaaclab/test/sim/check_meshes.py b/source/isaaclab/test/sim/check_meshes.py index 8595605b747..ecee0f07121 100644 --- a/source/isaaclab/test/sim/check_meshes.py +++ b/source/isaaclab/test/sim/check_meshes.py @@ -40,9 +40,8 @@ import torch import tqdm -import isaacsim.core.utils.prims as prim_utils - import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils def define_origins(num_origins: int, spacing: float) -> list[list[float]]: diff --git a/source/isaaclab/test/sim/test_build_simulation_context_headless.py b/source/isaaclab/test/sim/test_build_simulation_context_headless.py index af29346f9ee..c711cf49406 100644 --- a/source/isaaclab/test/sim/test_build_simulation_context_headless.py +++ b/source/isaaclab/test/sim/test_build_simulation_context_headless.py @@ -21,10 +21,10 @@ """Rest everything follows.""" import pytest -from isaacsim.core.utils.prims import is_prim_path_valid from isaaclab.sim.simulation_cfg import SimulationCfg from isaaclab.sim.simulation_context import build_simulation_context +from isaaclab.sim.utils.prims import is_prim_path_valid @pytest.mark.parametrize("gravity_enabled", [True, False]) diff --git a/source/isaaclab/test/sim/test_build_simulation_context_nonheadless.py b/source/isaaclab/test/sim/test_build_simulation_context_nonheadless.py index 1c1bf480da4..3a72f472c89 100644 --- a/source/isaaclab/test/sim/test_build_simulation_context_nonheadless.py +++ b/source/isaaclab/test/sim/test_build_simulation_context_nonheadless.py @@ -20,10 +20,10 @@ """Rest everything follows.""" import pytest -from isaacsim.core.utils.prims import is_prim_path_valid from isaaclab.sim.simulation_cfg import SimulationCfg from isaaclab.sim.simulation_context import build_simulation_context +from isaaclab.sim.utils.prims import is_prim_path_valid @pytest.mark.parametrize("gravity_enabled", [True, False]) diff --git a/source/isaaclab/test/sim/test_mesh_converter.py b/source/isaaclab/test/sim/test_mesh_converter.py index 90bfc557c78..9844b0e6bb8 100644 --- a/source/isaaclab/test/sim/test_mesh_converter.py +++ b/source/isaaclab/test/sim/test_mesh_converter.py @@ -17,13 +17,13 @@ import random import tempfile -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import omni import pytest from isaacsim.core.api.simulation_context import SimulationContext from pxr import UsdGeom, UsdPhysics +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim.converters import MeshConverter, MeshConverterCfg from isaaclab.sim.schemas import schemas_cfg from isaaclab.utils.assets import ISAACLAB_NUCLEUS_DIR, retrieve_file_path diff --git a/source/isaaclab/test/sim/test_mjcf_converter.py b/source/isaaclab/test/sim/test_mjcf_converter.py index 5921b12fc6c..366094f6bc6 100644 --- a/source/isaaclab/test/sim/test_mjcf_converter.py +++ b/source/isaaclab/test/sim/test_mjcf_converter.py @@ -14,12 +14,12 @@ import os -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest from isaacsim.core.api.simulation_context import SimulationContext from isaacsim.core.utils.extensions import enable_extension, get_extension_path_from_name +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim.converters import MjcfConverter, MjcfConverterCfg diff --git a/source/isaaclab/test/sim/test_schemas.py b/source/isaaclab/test/sim/test_schemas.py index 29b451f4214..3385282cd83 100644 --- a/source/isaaclab/test/sim/test_schemas.py +++ b/source/isaaclab/test/sim/test_schemas.py @@ -14,13 +14,13 @@ import math -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest from isaacsim.core.api.simulation_context import SimulationContext from pxr import UsdPhysics import isaaclab.sim.schemas as schemas +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim.utils import find_global_fixed_joint_prim from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR from isaaclab.utils.string import to_camel_case diff --git a/source/isaaclab/test/sim/test_simulation_context.py b/source/isaaclab/test/sim/test_simulation_context.py index f0f783463d2..658446a5b4c 100644 --- a/source/isaaclab/test/sim/test_simulation_context.py +++ b/source/isaaclab/test/sim/test_simulation_context.py @@ -14,10 +14,10 @@ import numpy as np -import isaacsim.core.utils.prims as prim_utils import pytest from isaacsim.core.api.simulation_context import SimulationContext as IsaacSimulationContext +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim import SimulationCfg, SimulationContext diff --git a/source/isaaclab/test/sim/test_spawn_from_files.py b/source/isaaclab/test/sim/test_spawn_from_files.py index 59b2741e4ee..c1f1b49e63c 100644 --- a/source/isaaclab/test/sim/test_spawn_from_files.py +++ b/source/isaaclab/test/sim/test_spawn_from_files.py @@ -12,13 +12,13 @@ """Rest everything follows.""" -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest from isaacsim.core.api.simulation_context import SimulationContext from isaacsim.core.utils.extensions import enable_extension, get_extension_path_from_name import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.utils.assets import ISAACLAB_NUCLEUS_DIR diff --git a/source/isaaclab/test/sim/test_spawn_lights.py b/source/isaaclab/test/sim/test_spawn_lights.py index ec178244e1b..890076745f1 100644 --- a/source/isaaclab/test/sim/test_spawn_lights.py +++ b/source/isaaclab/test/sim/test_spawn_lights.py @@ -12,13 +12,13 @@ """Rest everything follows.""" -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest from isaacsim.core.api.simulation_context import SimulationContext from pxr import UsdLux import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.utils.string import to_camel_case diff --git a/source/isaaclab/test/sim/test_spawn_materials.py b/source/isaaclab/test/sim/test_spawn_materials.py index e95ee6e3724..c5b00f68a9d 100644 --- a/source/isaaclab/test/sim/test_spawn_materials.py +++ b/source/isaaclab/test/sim/test_spawn_materials.py @@ -12,13 +12,13 @@ """Rest everything follows.""" -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest from isaacsim.core.api.simulation_context import SimulationContext from pxr import UsdPhysics, UsdShade import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.utils.assets import NVIDIA_NUCLEUS_DIR diff --git a/source/isaaclab/test/sim/test_spawn_meshes.py b/source/isaaclab/test/sim/test_spawn_meshes.py index b2297255d97..3a500a21352 100644 --- a/source/isaaclab/test/sim/test_spawn_meshes.py +++ b/source/isaaclab/test/sim/test_spawn_meshes.py @@ -12,12 +12,12 @@ """Rest everything follows.""" -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest from isaacsim.core.api.simulation_context import SimulationContext import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils @pytest.fixture diff --git a/source/isaaclab/test/sim/test_spawn_sensors.py b/source/isaaclab/test/sim/test_spawn_sensors.py index ac0cab828ad..093588ab53d 100644 --- a/source/isaaclab/test/sim/test_spawn_sensors.py +++ b/source/isaaclab/test/sim/test_spawn_sensors.py @@ -12,12 +12,12 @@ """Rest everything follows.""" -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest from isaacsim.core.api.simulation_context import SimulationContext import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim.spawners.sensors.sensors import CUSTOM_FISHEYE_CAMERA_ATTRIBUTES, CUSTOM_PINHOLE_CAMERA_ATTRIBUTES from isaaclab.utils.string import to_camel_case diff --git a/source/isaaclab/test/sim/test_spawn_shapes.py b/source/isaaclab/test/sim/test_spawn_shapes.py index c889a4ab818..1ef2c70f16e 100644 --- a/source/isaaclab/test/sim/test_spawn_shapes.py +++ b/source/isaaclab/test/sim/test_spawn_shapes.py @@ -12,12 +12,12 @@ """Rest everything follows.""" -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest from isaacsim.core.api.simulation_context import SimulationContext import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils @pytest.fixture @@ -259,7 +259,7 @@ def test_spawn_cone_clones(sim): assert prim.IsValid() assert prim_utils.get_prim_path(prim) == "/World/env_0/Cone" # find matching prims - prims = prim_utils.find_matching_prim_paths("/World/env_*/Cone") + prims = sim_utils.find_matching_prim_paths("/World/env_*/Cone") assert len(prims) == num_clones @@ -285,8 +285,8 @@ def test_spawn_cone_clone_with_all_props_global_material(sim): assert prim.IsValid() assert prim_utils.get_prim_path(prim) == "/World/env_0/Cone" # find matching prims - prims = prim_utils.find_matching_prim_paths("/World/env_*/Cone") + prims = sim_utils.find_matching_prim_paths("/World/env_*/Cone") assert len(prims) == num_clones # find matching material prims - prims = prim_utils.find_matching_prim_paths("/Looks/visualMaterial.*") + prims = sim_utils.find_matching_prim_paths("/Looks/visualMaterial.*") assert len(prims) == 1 diff --git a/source/isaaclab/test/sim/test_spawn_wrappers.py b/source/isaaclab/test/sim/test_spawn_wrappers.py index 5edae7a79d6..96e7d0c2c09 100644 --- a/source/isaaclab/test/sim/test_spawn_wrappers.py +++ b/source/isaaclab/test/sim/test_spawn_wrappers.py @@ -12,12 +12,12 @@ """Rest everything follows.""" -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest from isaacsim.core.api.simulation_context import SimulationContext import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.utils.assets import ISAACLAB_NUCLEUS_DIR @@ -69,7 +69,7 @@ def test_spawn_multiple_shapes_with_global_settings(sim): assert prim.IsValid() assert prim_utils.get_prim_path(prim) == "/World/env_0/Cone" - prim_paths = prim_utils.find_matching_prim_paths("/World/env_*/Cone") + prim_paths = sim_utils.find_matching_prim_paths("/World/env_*/Cone") assert len(prim_paths) == num_clones for prim_path in prim_paths: @@ -115,7 +115,7 @@ def test_spawn_multiple_shapes_with_individual_settings(sim): assert prim.IsValid() assert prim_utils.get_prim_path(prim) == "/World/env_0/Cone" - prim_paths = prim_utils.find_matching_prim_paths("/World/env_*/Cone") + prim_paths = sim_utils.find_matching_prim_paths("/World/env_*/Cone") assert len(prim_paths) == num_clones for prim_path in prim_paths: @@ -158,5 +158,5 @@ def test_spawn_multiple_files_with_global_settings(sim): assert prim.IsValid() assert prim_utils.get_prim_path(prim) == "/World/env_0/Robot" - prim_paths = prim_utils.find_matching_prim_paths("/World/env_*/Robot") + prim_paths = sim_utils.find_matching_prim_paths("/World/env_*/Robot") assert len(prim_paths) == num_clones diff --git a/source/isaaclab/test/sim/test_stage_in_memory.py b/source/isaaclab/test/sim/test_stage_in_memory.py index d114185862a..0a7e26f2b67 100644 --- a/source/isaaclab/test/sim/test_stage_in_memory.py +++ b/source/isaaclab/test/sim/test_stage_in_memory.py @@ -12,7 +12,6 @@ """Rest everything follows.""" -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import omni import omni.physx @@ -23,6 +22,7 @@ from isaacsim.core.version import get_version import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim.simulation_context import SimulationCfg, SimulationContext from isaaclab.utils.assets import ISAACLAB_NUCLEUS_DIR @@ -91,13 +91,13 @@ def test_stage_in_memory_with_shapes(sim): assert sim_utils.is_current_stage_in_memory() # verify prims exist in stage in memory - prims = prim_utils.find_matching_prim_paths(prim_path_regex) + prims = sim_utils.find_matching_prim_paths(prim_path_regex) assert len(prims) == num_clones # verify prims do not exist in context stage context_stage = omni.usd.get_context().get_stage() with sim_utils.use_stage(context_stage): - prims = prim_utils.find_matching_prim_paths(prim_path_regex) + prims = sim_utils.find_matching_prim_paths(prim_path_regex) assert len(prims) != num_clones # attach stage to context @@ -107,7 +107,7 @@ def test_stage_in_memory_with_shapes(sim): assert not sim_utils.is_current_stage_in_memory() # verify prims now exist in context stage - prims = prim_utils.find_matching_prim_paths(prim_path_regex) + prims = sim_utils.find_matching_prim_paths(prim_path_regex) assert len(prims) == num_clones @@ -157,13 +157,13 @@ def test_stage_in_memory_with_usds(sim): assert sim_utils.is_current_stage_in_memory() # verify prims exist in stage in memory - prims = prim_utils.find_matching_prim_paths(prim_path_regex) + prims = sim_utils.find_matching_prim_paths(prim_path_regex) assert len(prims) == num_clones # verify prims do not exist in context stage context_stage = omni.usd.get_context().get_stage() with sim_utils.use_stage(context_stage): - prims = prim_utils.find_matching_prim_paths(prim_path_regex) + prims = sim_utils.find_matching_prim_paths(prim_path_regex) assert len(prims) != num_clones # attach stage to context @@ -173,7 +173,7 @@ def test_stage_in_memory_with_usds(sim): assert not sim_utils.is_current_stage_in_memory() # verify prims now exist in context stage - prims = prim_utils.find_matching_prim_paths(prim_path_regex) + prims = sim_utils.find_matching_prim_paths(prim_path_regex) assert len(prims) == num_clones @@ -219,7 +219,7 @@ def test_stage_in_memory_with_clone_in_fabric(sim): # verify prims do not exist in context stage context_stage = omni.usd.get_context().get_stage() with sim_utils.use_stage(context_stage): - prims = prim_utils.find_matching_prim_paths(prim_path_regex) + prims = sim_utils.find_matching_prim_paths(prim_path_regex) assert len(prims) != num_clones # attach stage to context diff --git a/source/isaaclab/test/sim/test_urdf_converter.py b/source/isaaclab/test/sim/test_urdf_converter.py index f238fd02408..e11c437b57d 100644 --- a/source/isaaclab/test/sim/test_urdf_converter.py +++ b/source/isaaclab/test/sim/test_urdf_converter.py @@ -15,13 +15,13 @@ import numpy as np import os -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest from isaacsim.core.api.simulation_context import SimulationContext from isaacsim.core.prims import Articulation from isaacsim.core.utils.extensions import enable_extension, get_extension_path_from_name +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim.converters import UrdfConverter, UrdfConverterCfg diff --git a/source/isaaclab/test/sim/test_utils.py b/source/isaaclab/test/sim/test_utils.py index a18e0534294..c60be12b95b 100644 --- a/source/isaaclab/test/sim/test_utils.py +++ b/source/isaaclab/test/sim/test_utils.py @@ -15,12 +15,12 @@ import numpy as np import torch -import isaacsim.core.utils.prims as prim_utils import isaacsim.core.utils.stage as stage_utils import pytest from pxr import Sdf, Usd, UsdGeom, UsdPhysics import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils import isaaclab.utils.math as math_utils from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR, ISAACLAB_NUCLEUS_DIR @@ -104,36 +104,6 @@ def test_get_first_matching_child_prim(): assert isaaclab_result.GetPrimPath() == "/World/env_1/Franka/panda_link0/visuals/panda_link0" -def test_find_matching_prim_paths(): - """Test find_matching_prim_paths() function.""" - # create scene - for index in range(2048): - random_pos = np.random.uniform(-100, 100, size=3) - prim_utils.create_prim(f"/World/Floor_{index}", "Cube", position=random_pos, attributes={"size": 2.0}) - prim_utils.create_prim(f"/World/Floor_{index}/Sphere", "Sphere", attributes={"radius": 10}) - prim_utils.create_prim(f"/World/Floor_{index}/Sphere/childSphere", "Sphere", attributes={"radius": 1}) - prim_utils.create_prim(f"/World/Floor_{index}/Sphere/childSphere2", "Sphere", attributes={"radius": 1}) - - # test leaf paths - isaac_sim_result = prim_utils.find_matching_prim_paths("/World/Floor_.*/Sphere") - isaaclab_result = sim_utils.find_matching_prim_paths("/World/Floor_.*/Sphere") - assert isaac_sim_result == isaaclab_result - - # test non-leaf paths - isaac_sim_result = prim_utils.find_matching_prim_paths("/World/Floor_.*") - isaaclab_result = sim_utils.find_matching_prim_paths("/World/Floor_.*") - assert isaac_sim_result == isaaclab_result - - # test child-leaf paths - isaac_sim_result = prim_utils.find_matching_prim_paths("/World/Floor_.*/Sphere/childSphere.*") - isaaclab_result = sim_utils.find_matching_prim_paths("/World/Floor_.*/Sphere/childSphere.*") - assert isaac_sim_result == isaaclab_result - - # test valid path - with pytest.raises(ValueError): - sim_utils.get_all_matching_child_prims("World/Floor_.*") - - def test_find_global_fixed_joint_prim(): """Test find_global_fixed_joint_prim() function.""" # create scene diff --git a/source/isaaclab/test/terrains/check_terrain_importer.py b/source/isaaclab/test/terrains/check_terrain_importer.py index 2de8b457e32..bde3c9480b3 100644 --- a/source/isaaclab/test/terrains/check_terrain_importer.py +++ b/source/isaaclab/test/terrains/check_terrain_importer.py @@ -64,7 +64,6 @@ import numpy as np -import isaacsim.core.utils.prims as prim_utils import omni.kit import omni.kit.commands from isaacsim.core.api.materials import PhysicsMaterial @@ -77,6 +76,7 @@ from isaacsim.core.utils.viewports import set_camera_view import isaaclab.sim as sim_utils +import isaaclab.sim.utils.prims as prim_utils import isaaclab.terrains as terrain_gen from isaaclab.terrains.config.rough import ROUGH_TERRAINS_CFG from isaaclab.terrains.terrain_importer import TerrainImporter diff --git a/source/isaaclab/test/terrains/test_terrain_importer.py b/source/isaaclab/test/terrains/test_terrain_importer.py index 26bacac387c..9656834ceeb 100644 --- a/source/isaaclab/test/terrains/test_terrain_importer.py +++ b/source/isaaclab/test/terrains/test_terrain_importer.py @@ -17,7 +17,6 @@ import trimesh from typing import Literal -import isaacsim.core.utils.prims as prim_utils import omni.kit import omni.kit.commands import pytest @@ -28,6 +27,7 @@ from isaacsim.core.utils.extensions import enable_extension from pxr import UsdGeom +import isaaclab.sim.utils.prims as prim_utils import isaaclab.terrains as terrain_gen from isaaclab.sim import PreviewSurfaceCfg, SimulationContext, build_simulation_context, get_first_matching_child_prim from isaaclab.terrains import TerrainImporter, TerrainImporterCfg diff --git a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/dexsuite/mdp/utils.py b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/dexsuite/mdp/utils.py index f7b8e9db59b..0c9ed67b83b 100644 --- a/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/dexsuite/mdp/utils.py +++ b/source/isaaclab_tasks/isaaclab_tasks/manager_based/manipulation/dexsuite/mdp/utils.py @@ -10,9 +10,9 @@ import trimesh from trimesh.sample import sample_surface -import isaacsim.core.utils.prims as prim_utils from pxr import UsdGeom +import isaaclab.sim.utils.prims as prim_utils from isaaclab.sim.utils import get_all_matching_child_prims # ---- module-scope caches ----