Source code for embodichain.lab.sim.cfg.source

# ----------------------------------------------------------------------------
# Copyright (c) 2021-2026 DexForce Technology Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ----------------------------------------------------------------------------

"""Source USD asset addressing, independent of runtime IDs and placement."""

from __future__ import annotations

from collections.abc import Mapping
from dataclasses import MISSING

from embodichain.utils import configclass

__all__ = ["UsdSourceCfg"]


[docs] @configclass class UsdSourceCfg: """Select a typed asset from a source USD stage. Supply this as ``source`` on a visual-object, rigid-object or articulation configuration. Runtime identity and placement belong to the containing configuration. This source does not bind an already imported scene entity. """ file_path: str = MISSING """Source USD, USDA, USDC or USDZ file.""" source_prim_path: str | None = None """Exact absolute prim path in the source stage. Omit only when the source contains a single candidate of the requested asset type. This is not a destination path, regex or parent/link binding. """
[docs] @classmethod def from_dict(cls, data: Mapping[str, object]) -> UsdSourceCfg: """Decode a source mapping, rejecting unknown source options. Args: data: Source file and optional exact source prim selector. Returns: Source configuration; call ``validate()`` after assembly. """ unknown = set(data) - {"file_path", "source_prim_path"} if unknown: raise ValueError(f"Unknown UsdSourceCfg fields: {sorted(unknown)}.") return cls(**data)
def _usd_source_from_value(value: object) -> UsdSourceCfg | None: if value is None or isinstance(value, UsdSourceCfg): return value if isinstance(value, Mapping): return UsdSourceCfg.from_dict(value) raise TypeError("source must be a UsdSourceCfg, a source mapping, or None.") def _raise_removed_source_fields(data: Mapping[str, object]) -> None: if "prim_path" in data or "source_prim_path" in data: raise ValueError( "Use source=UsdSourceCfg(file_path=..., source_prim_path=...) " "instead of a top-level prim selector." ) def _asset_file_path(cfg: object) -> str | None: """Resolve one file owner and validate an explicit USD source.""" source = getattr(cfg, "source", None) shape = getattr(cfg, "shape", None) legacy_path = ( getattr(shape, "fpath", None) if hasattr(cfg, "shape") else getattr(cfg, "fpath", None) ) if source is None: if hasattr(cfg, "shape") and shape is None: raise ValueError("Mesh objects require either shape or source.") return legacy_path if not isinstance(source, UsdSourceCfg): raise TypeError("source must be a UsdSourceCfg.") if shape is not None or legacy_path is not None: raise ValueError("source cannot be combined with shape or fpath.") source.validate() path = source.file_path if not isinstance(path, str) or not path.strip(): raise ValueError("UsdSourceCfg.file_path must be a non-empty string.") if not path.lower().endswith((".usd", ".usda", ".usdc", ".usdz")): raise ValueError("UsdSourceCfg.file_path requires a USD source file.") selector = source.source_prim_path if selector is not None: from pxr import Sdf if not isinstance(selector, str) or not Sdf.Path.IsValidPathString(selector): raise ValueError("source_prim_path must be an absolute USD prim path.") prim_path = Sdf.Path(selector) if ( not prim_path.IsAbsolutePath() or not prim_path.IsPrimPath() or prim_path.ContainsPrimVariantSelection() ): raise ValueError("source_prim_path must be an absolute USD prim path.") return path def _source_prim_path(cfg: object) -> str | None: source = getattr(cfg, "source", None) return None if source is None else source.source_prim_path