Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions docs/source/_static/css/environment-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,24 @@
["Isaac-Lift-Cable-Franka-Camera", "rsl_rl", "newton_mjwarp_vbd_proxy", "isaacsim_rtx,newton_renderer,ovrtx", "ik,joint", "tasks/manipulation/franka_lift_cable.jpg", false, {"*": ["joint"]}],
["Isaac-Lift-Cloth-Franka", "rsl_rl", "isaacsim_physx,newton_mjwarp_vbd_proxy", "", "ik,joint", "tasks/manipulation/franka_lift_cloth.jpg", false, {"*": ["joint"]}],
["Isaac-Lift-Cloth-Franka-Camera", "rsl_rl", "isaacsim_physx,newton_mjwarp_vbd_proxy", "isaacsim_rtx,newton_renderer,ovrtx", "ik,joint", "tasks/manipulation/franka_lift_cloth.jpg", false, {"*": ["joint"]}],
["Isaac-Lift-Franka", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "cube,shapes", "", false, {"*": ["shapes"]}],
["Isaac-Lift-Franka", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions,cube,shapes", "", false, {"*": ["shapes"]}],
["Isaac-Lift-KukaAllegro", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "cube,shapes", "tasks/manipulation/kuka_allegro_lift.jpg", false, {"*": ["shapes"]}],
["Isaac-Lift-KukaAllegro-Camera", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo128,albedo256,albedo64,cube,depth128,depth256,depth64,duo_camera,raycaster_depth128,raycaster_depth256,raycaster_depth64,rgb128,rgb256,rgb64,semantic_segmentation128,semantic_segmentation256,semantic_segmentation64,shapes,simple_shading_constant_diffuse128,simple_shading_constant_diffuse256,simple_shading_constant_diffuse64,simple_shading_diffuse_mdl128,simple_shading_diffuse_mdl256,simple_shading_diffuse_mdl64,simple_shading_full_mdl128,simple_shading_full_mdl256,simple_shading_full_mdl64,single_camera", "tasks/manipulation/kuka_allegro_lift.jpg", false, {"*": ["rgb64", "shapes", "single_camera"]}],
["Isaac-Lift-Soft-Franka", "rsl_rl", "isaacsim_physx,newton_mjwarp_vbd_proxy", "", "ik,joint", "newton/franka-mjwarp-vbd-coupling.png", false, {"*": ["joint"]}, {}, "tetrahedralization"],
["Isaac-Lift-Soft-Franka-Camera", "rsl_rl", "isaacsim_physx,newton_mjwarp_vbd_proxy", "isaacsim_rtx,newton_renderer,ovrtx", "ik,joint", "newton/franka-mjwarp-vbd-coupling.png", false, {"*": ["joint"]}, {}, "tetrahedralization"],
["Isaac-Open-Drawer-Franka-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/franka_open_drawer.jpg"],
["Isaac-Open-Drawer-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/franka_open_drawer.jpg"],
["Isaac-Open-Drawer-Franka-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions", "tasks/manipulation/franka_open_drawer.jpg"],
["Isaac-Open-Drawer-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions", "tasks/manipulation/franka_open_drawer.jpg"],
["Isaac-Pendulum-MARL-Direct", "rl_games,skrl", "isaacsim_physx,newton_kamino,newton_mjwarp,ovphysx", "", "", "tasks/classic/cart_double_pendulum.jpg", false, {}, {"skrl": "MAPPO"}],
["Isaac-Reach-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik,diffik_abs,joint_pos,newton_ik", "tasks/manipulation/franka_reach.jpg", true, {"*": ["joint_pos"]}],
["Isaac-Reach-Franka-OSC", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik_abs", "tasks/manipulation/franka_reach.jpg", false, {"*": ["diffik_abs"]}],
["Isaac-Reach-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions,diffik,diffik_abs,joint_pos,newton_ik", "tasks/manipulation/franka_reach.jpg", true, {"*": ["joint_pos"]}],
["Isaac-Reach-Franka-OSC", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions,diffik_abs", "tasks/manipulation/franka_reach.jpg", false, {"*": ["diffik_abs"]}],
["Isaac-Reach-UR10", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/ur10_reach.jpg", true],
["Isaac-RenderBenchmark-Franka-Cabinet", "", "isaacsim_physx,newton_mjwarp", "isaacsim_rtx,newton_renderer,ovrtx", "albedo,depth,rgb,simple_shading_constant_diffuse,simple_shading_diffuse_mdl,simple_shading_full_mdl", "", false, {"*": ["rgb"]}],
["Isaac-RenderBenchmark-Franka-Cabinet", "", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo,depth,rgb,simple_shading_constant_diffuse,simple_shading_diffuse_mdl,simple_shading_full_mdl", "", false, {"*": ["rgb"]}],
["Isaac-Reorient-Cube-Allegro-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/allegro_cube.jpg", true],
["Isaac-Reorient-Cube-Allegro", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "randomized,reset_only", "tasks/manipulation/allegro_cube.jpg", false, {"*": ["reset_only"]}],
["Isaac-Reorient-Cube-Shadow-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/shadow_cube.jpg"],
["Isaac-Reorient-Cube-Shadow", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "asymmetric,randomized"],
["Isaac-Reorient-Cube-Shadow-Camera-Direct", "rl_games,rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo,depth,full,rgb,semantic_segmentation,simple_shading_constant_diffuse,simple_shading_diffuse_mdl,simple_shading_full_mdl", "tasks/manipulation/shadow_cube.jpg", false, {"*": ["full"]}],
["Isaac-Reorient-Cube-Shadow-Camera", "rl_games,rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo,depth,full,randomized,rgb,semantic_segmentation,simple_shading_constant_diffuse,simple_shading_diffuse_mdl,simple_shading_full_mdl", "", false, {"*": ["full"]}],
["Isaac-Reorient-Franka", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "cube,shapes", "", false, {"*": ["shapes"]}],
["Isaac-Reorient-KukaAllegro", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "cube,shapes", "tasks/manipulation/kuka_allegro_reorient.jpg", false, {"*": ["shapes"]}],
["Isaac-Reorient-KukaAllegro-Camera", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo128,albedo256,albedo64,cube,depth128,depth256,depth64,duo_camera,raycaster_depth128,raycaster_depth256,raycaster_depth64,rgb128,rgb256,rgb64,semantic_segmentation128,semantic_segmentation256,semantic_segmentation64,shapes,simple_shading_constant_diffuse128,simple_shading_constant_diffuse256,simple_shading_constant_diffuse64,simple_shading_diffuse_mdl128,simple_shading_diffuse_mdl256,simple_shading_diffuse_mdl64,simple_shading_full_mdl128,simple_shading_full_mdl256,simple_shading_full_mdl64,single_camera", "tasks/manipulation/kuka_allegro_reorient.jpg", false, {"*": ["rgb64", "shapes", "single_camera"]}],
["Isaac-Shadow-Handover-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/shadow_hand_over.jpg", false, {}, {"skrl": "MAPPO"}],
Expand Down Expand Up @@ -92,14 +91,14 @@
["IsaacContrib-Lift-Cube-Franka-IK-Abs", "", "", "", "", "tasks/manipulation/franka_lift.jpg"],
["IsaacContrib-Lift-Cube-Franka-IK-Rel", "", "", "", "", "tasks/manipulation/franka_lift.jpg"],
["IsaacContrib-Lift-Cube-OpenArm", "rl_games,rsl_rl", "", "", "", "tasks/manipulation/openarm_uni_lift.jpg"],
["IsaacContrib-Multitask-Manipulation", "rsl_rl", "", "", "", "tasks/manipulation/multitask_manipulation.jpg"],
["IsaacContrib-Multitask-Manipulation", "rsl_rl", "", "", "arm_collisions", "tasks/manipulation/multitask_manipulation.jpg"],
["IsaacContrib-Navigation-3DObstacles-ARL-Robot-1", "rl_games,rsl_rl,skrl", "", "", "", "tasks/drone_arl/arl_robot_1_navigation.jpg"],
["IsaacContrib-Navigation-Flat-AnymalC", "rsl_rl,skrl", "", "", "", "tasks/navigation/anymal_c_nav.jpg"],
["IsaacContrib-NutPour-GR1T2-Pink-IK-Abs", "", "", "", ""],
["IsaacContrib-Open-Drawer-Franka-IK-Abs", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", ""],
["IsaacContrib-Open-Drawer-Franka-IK-Rel", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", ""],
["IsaacContrib-Open-Drawer-Franka-IK-Abs", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions"],
["IsaacContrib-Open-Drawer-Franka-IK-Rel", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "arm_collisions"],
["IsaacContrib-Open-Drawer-OpenArm", "rl_games,rsl_rl", "", "", "", "tasks/manipulation/openarm_uni_open_drawer.jpg"],
["IsaacContrib-PickPlace-FixedBaseUpperBodyIK-G1-Abs", "", "", "", "", "tasks/manipulation/g1_pick_place_fixed_base.jpg"],
["IsaacContrib-PickPlace-FixedBaseUpperBodyIK-G1-Abs", "", "", "isaacsim_rtx,newton_renderer,ovrtx", "", "tasks/manipulation/g1_pick_place_fixed_base.jpg"],
["IsaacContrib-PickPlace-G1-InspireFTP-Abs", "", "", "", "", "tasks/manipulation/g1_pick_place.jpg"],
["IsaacContrib-PickPlace-GR1T2-Abs", "", "", "isaacsim_rtx,newton_renderer,ovrtx", "", "tasks/manipulation/gr-1_pick_place.jpg"],
["IsaacContrib-PickPlace-GR1T2-WaistEnabled-Abs", "", "", "", "", "tasks/manipulation/gr-1_pick_place_waist.jpg"],
Expand Down Expand Up @@ -336,7 +335,6 @@
[/Reach-UR10/, "tasks/manipulation/ur10_reach.jpg"],
[/Reorient-Cube-Allegro/, "tasks/manipulation/allegro_cube.jpg"],
[/Reorient-Cube-Shadow/, "tasks/manipulation/shadow_cube.jpg"],
[/Reorient-Franka/, "tasks/manipulation/franka_lift.jpg"],
[/Reorient-KukaAllegro/, "tasks/manipulation/kuka_allegro_reorient.jpg"],
[/Shadow-Handover/, "tasks/manipulation/shadow_hand_over.jpg"],
[/AnymalB/, "tasks/locomotion/anymal_b_flat.jpg"],
Expand Down
9 changes: 5 additions & 4 deletions examples/haply_teleoperation.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from isaaclab.utils import configclass, instantiate, replace
from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR

from isaaclab_assets import FRANKA_PANDA_HIGH_PD_CFG
from isaaclab_assets import FRANKA_PANDA_FLAT_HIGH_PD_CFG

if TYPE_CHECKING:
from isaaclab.assets import Articulation, RigidObject
Expand Down Expand Up @@ -127,10 +127,11 @@ class FrankaHaplySceneCfg(InteractiveSceneCfg):
init_state=AssetBaseCfg.InitialStateCfg(pos=(0.50, 0.0, 1.05), rot=(0.707, 0, 0, 0.707)),
)

robot_cfg: ArticulationCfg = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot")
robot_cfg: ArticulationCfg = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot")
Comment thread
maxkra15 marked this conversation as resolved.
robot = instantiate(robot_cfg)
robot.init_state.pos = (-0.02, 0.0, 1.05)
robot.spawn.activate_contact_sensors = True
robot.spawn.variants["Physics"] = "mujoco" if args_cli.physics == "newton_mjwarp" else "physx"

cube = RigidObjectCfg(
prim_path="{ENV_REGEX_NS}/Cube",
Expand All @@ -146,15 +147,15 @@ class FrankaHaplySceneCfg(InteractiveSceneCfg):
)

left_finger_contact_sensor = ContactSensorCfg(
prim_path="{ENV_REGEX_NS}/Robot/panda_leftfinger",
prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_leftfinger",
update_period=0.0,
history_length=3,
debug_vis=True,
track_pose=True,
)

right_finger_contact_sensor = ContactSensorCfg(
prim_path="{ENV_REGEX_NS}/Robot/panda_rightfinger",
prim_path="{ENV_REGEX_NS}/Robot/(Geometry/.*/)?panda_rightfinger",
update_period=0.0,
history_length=3,
debug_vis=True,
Expand Down
1 change: 0 additions & 1 deletion examples/heterogeneous_scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@
"IsaacContrib-Navigation-Flat-AnymalC",
# arm and hand manipulation
"Isaac-Lift-Franka",
"Isaac-Reorient-Franka",
"Isaac-Lift-KukaAllegro",
"Isaac-Reorient-KukaAllegro",
"Isaac-Open-Drawer-Franka",
Expand Down
4 changes: 2 additions & 2 deletions scripts/tutorials/05_controllers/run_diff_ik.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
##
# Pre-defined configs
##
from isaaclab_assets import FRANKA_PANDA_HIGH_PD_CFG, UR10_CFG # isort:skip
from isaaclab_assets import FRANKA_PANDA_FLAT_HIGH_PD_CFG, UR10_CFG # isort:skip


@configclass
Expand Down Expand Up @@ -82,7 +82,7 @@ class TableTopSceneCfg(InteractiveSceneCfg):

# articulation
if args_cli.robot == "franka_panda":
robot = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot")
robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot")
elif args_cli.robot == "ur10":
robot = replace(UR10_CFG, prim_path="{ENV_REGEX_NS}/Robot")
else:
Expand Down
10 changes: 4 additions & 6 deletions scripts/tutorials/05_controllers/run_osc.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
##
# Pre-defined configs
##
from isaaclab_assets import FRANKA_PANDA_HIGH_PD_CFG # isort:skip
from isaaclab_assets import FRANKA_PANDA_FLAT_HIGH_PD_CFG # isort:skip


@configclass
Expand Down Expand Up @@ -97,11 +97,9 @@ class SceneCfg(InteractiveSceneCfg):
debug_vis=False,
)

robot = replace(FRANKA_PANDA_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot")
robot.actuators["panda_shoulder"].stiffness = 0.0
robot.actuators["panda_shoulder"].damping = 0.0
robot.actuators["panda_forearm"].stiffness = 0.0
robot.actuators["panda_forearm"].damping = 0.0
robot = replace(FRANKA_PANDA_FLAT_HIGH_PD_CFG, prim_path="{ENV_REGEX_NS}/Robot")
robot.actuators["panda_arm"].stiffness = 0.0
robot.actuators["panda_arm"].damping = 0.0
robot.spawn.rigid_props.disable_gravity = True


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Added
^^^^^

* Added an ``offset`` to ``DifferentialInverseKinematicsActionCfg`` so normalized policies can use
an affine task-space action transform. The default is zero and preserves existing configurations.
2 changes: 2 additions & 0 deletions source/isaaclab/isaaclab/envs/mdp/actions/actions_cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,8 @@ class OffsetCfg:
"""Offset of target frame w.r.t. to the body frame. Defaults to None, in which case no offset is applied."""
scale: float | tuple[float, ...] = 1.0
"""Scale factor for the action. Defaults to 1.0."""
offset: float | tuple[float, ...] = 0.0
"""Offset applied to the scaled action in controller-specific units. Defaults to 0.0."""
controller: DifferentialIKControllerCfg = MISSING
"""The configuration for the differential IK controller."""

Expand Down
22 changes: 14 additions & 8 deletions source/isaaclab/isaaclab/envs/mdp/actions/task_space_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,25 @@
class DifferentialInverseKinematicsAction(ActionTerm):
r"""Inverse Kinematics action term.

This action term performs pre-processing of the raw actions using scaling transformation.
This action term pre-processes raw actions using an affine transformation.

.. math::
\text{action} = \text{scaling} \times \text{input action}
\text{action} = \text{offset} + \text{scaling} \times \text{input action}
\text{joint position} = J^{-} \times \text{action}

where :math:`\text{scaling}` is the scaling applied to the input action, and :math:`\text{input action}`
is the input action from the user, :math:`J` is the Jacobian over the articulation's actuated joints,
and \text{joint position} is the desired joint position command for the articulation's joints.
where :math:`\text{offset}` and :math:`\text{scaling}` define the affine transformation,
:math:`\text{input action}` is the input action from the user, :math:`J` is the Jacobian over the
articulation's actuated joints, and \text{joint position} is the desired joint position command.
"""

cfg: actions_cfg.DifferentialInverseKinematicsActionCfg
"""The configuration of the action term."""
_asset: Articulation
"""The articulation asset on which the action term is applied."""
_scale: torch.Tensor
"""The scaling factor applied to the input action. Shape is (1, action_dim)."""
"""The scaling factor applied to the input action. Shape is (num_envs, action_dim)."""
_offset: torch.Tensor
"""The offset applied to the scaled action. Shape is (num_envs, action_dim)."""
_clip: torch.Tensor
"""The clip applied to the input action."""

Expand Down Expand Up @@ -100,9 +102,11 @@ def __init__(self, cfg: actions_cfg.DifferentialInverseKinematicsActionCfg, env:
# owned buffer; _compute_frame_jacobian mutates this, not the data-layer view.
self._jacobian_b = torch.zeros(self.num_envs, 6, len(self._jacobi_joint_ids), device=self.device)

# save the scale as tensors
# save the affine transform as tensors
self._scale = torch.zeros((self.num_envs, self.action_dim), device=self.device)
self._scale[:] = torch.tensor(self.cfg.scale, device=self.device)
self._offset = torch.zeros((self.num_envs, self.action_dim), device=self.device)
self._offset[:] = torch.tensor(self.cfg.offset, device=self.device)

# convert the fixed offsets to torch tensors of batched shape
if self.cfg.body_offset is not None:
Expand Down Expand Up @@ -160,6 +164,7 @@ def IO_descriptor(self) -> GenericActionIODescriptor:
- body_name: The name of the body.
- joint_names: The names of the joints.
- scale: The scale of the action term.
- offset: The offset of the action term.
- clip: The clip of the action term.
- controller_cfg: The configuration of the controller.
- body_offset: The offset of the body.
Expand All @@ -174,6 +179,7 @@ def IO_descriptor(self) -> GenericActionIODescriptor:
self._IO_descriptor.body_name = self._body_name
self._IO_descriptor.joint_names = self._joint_names
self._IO_descriptor.scale = self._scale
self._IO_descriptor.offset = self._offset
if self.cfg.clip is not None:
self._IO_descriptor.clip = self.cfg.clip
else:
Expand All @@ -189,7 +195,7 @@ def IO_descriptor(self) -> GenericActionIODescriptor:
def process_actions(self, actions: torch.Tensor):
# store the raw actions
self._raw_actions[:] = actions
self._processed_actions[:] = self.raw_actions * self._scale
self._processed_actions[:] = self.raw_actions * self._scale + self._offset
if self.cfg.clip is not None:
self._processed_actions = torch.clamp(
self._processed_actions, min=self._clip[:, :, 0], max=self._clip[:, :, 1]
Expand Down
8 changes: 8 additions & 0 deletions source/isaaclab/isaaclab/sim/utils/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ def resolve_matching_prims_from_source(
env_regex_ns: str = "/World/envs/env_[^/]+",
raise_if_no_matches: bool = True,
traverse_instance_prims: bool = True,
prefer_direct_matches: bool = False,
) -> list[tuple[Usd.Prim, str]]:
"""Resolve matching prims from a single(source) instance when multiple instances are present.

Expand All @@ -402,6 +403,8 @@ def resolve_matching_prims_from_source(
env_regex_ns: Namespace pattern that marks one instance root when no clone plan applies.
raise_if_no_matches: Whether to raise if no prim matches ``path_expr``. Defaults to True.
traverse_instance_prims: Whether to traverse instance prims when applying ``predicate``.
prefer_direct_matches: Prefer matching prims named by ``path_expr`` over their matching descendants.
Descendants remain a fallback when no direct prim satisfies ``predicate``.

Returns:
A list of ``(source_prim, destination_expr)`` pairs. Empty only when
Expand Down Expand Up @@ -481,6 +484,11 @@ def resolve_matching_prims_from_source(
unique_matches.setdefault(child_path, (child, dest + child_path[len(source_path) :]))
results = list(unique_matches.values())

if prefer_direct_matches:
direct_matches = [pair for pair in results if re.fullmatch(path_expr, pair[0].GetPath().pathString)]
if direct_matches:
results = direct_matches

if expected_num_matches is not None and len(results) != expected_num_matches:
raise RuntimeError(f"Expected {expected_num_matches} prims at '{path_expr}', found {len(results)}.")
if raise_if_no_matches and not results:
Expand Down
Loading
Loading