# ----------------------------------------------------------------------------
# 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.
# ----------------------------------------------------------------------------
"""Backend-specific physical-property helpers for rigid objects."""
from __future__ import annotations
from typing import Any
from embodichain.utils import logger
__all__ = [
"apply_legacy_physical_attr",
"get_legacy_damping",
"get_legacy_friction",
"get_legacy_inertia",
"get_legacy_mass",
"can_use_newton_entity_dynamics_fallback",
"get_newton_physical_attr",
"get_newton_physical_attr_or_none",
"mirror_newton_physical_attr",
"newton_lifecycle_state",
"set_legacy_collision_filter",
"set_legacy_damping",
"set_legacy_friction",
"set_legacy_inertia",
"set_legacy_mass",
]
_UINT64_MAX = (1 << 64) - 1
def _newton_metadata_attr(scene: object, entity: object) -> Any:
"""Return the legacy Newton metadata attribute for one entity."""
entity_handle = int(entity.get_native_handle())
if entity_handle < 0:
entity_handle &= _UINT64_MAX
manager = getattr(scene, "manager", None)
if manager is None:
return None
return getattr(manager, "dexsim_meta", {}).get(entity_handle, {}).get("attr")
[docs]
def get_newton_physical_attr(
scene: object,
entity: object,
env_idx: int,
object_uid: str,
) -> Any:
"""Return required Newton metadata physical attributes for an entity."""
attr = _newton_metadata_attr(scene, entity)
if attr is None:
logger.log_error(
f"Newton physical attributes for rigid object {object_uid!r} "
f"env {env_idx} are unavailable."
)
return attr
[docs]
def get_newton_physical_attr_or_none(scene: object, entity: object) -> Any:
"""Return Newton metadata physical attributes when available."""
return _newton_metadata_attr(scene, entity)
[docs]
def mirror_newton_physical_attr(
scene: object,
entity: object,
env_idx: int,
object_uid: str,
physical_attr: Any,
) -> None:
"""Copy public physical attributes onto the Newton rebuild metadata."""
attr = get_newton_physical_attr(scene, entity, env_idx, object_uid)
for name in (
"mass",
"density",
"dynamic_friction",
"static_friction",
"restitution",
"contact_offset",
"rest_offset",
"linear_damping",
"angular_damping",
"sleep_threshold",
"enable_ccd",
"max_depenetration_velocity",
"min_position_iters",
"min_velocity_iters",
"max_linear_velocity",
"max_angular_velocity",
):
setattr(attr, name, getattr(physical_attr, name))
[docs]
def apply_legacy_physical_attr(entity: object, physical_attr: Any) -> None:
"""Apply a DexSim ``PhysicalAttr`` through the legacy entity API."""
entity.set_physical_attr(physical_attr)
[docs]
def set_legacy_collision_filter(entity: object, filter_data: Any) -> None:
"""Set collision filters through the legacy physical-body API."""
entity.get_physical_body().set_collision_filter_data(filter_data)
[docs]
def set_legacy_mass(entity: object, value: float) -> None:
"""Set mass through the legacy physical-body API."""
entity.get_physical_body().set_mass(value)
[docs]
def get_legacy_mass(entity: object) -> Any:
"""Read mass through the legacy physical-body API."""
return entity.get_physical_body().get_mass()
[docs]
def set_legacy_friction(entity: object, value: float) -> None:
"""Set both legacy static and dynamic friction coefficients."""
body = entity.get_physical_body()
body.set_dynamic_friction(value)
body.set_static_friction(value)
[docs]
def get_legacy_friction(entity: object) -> Any:
"""Read dynamic friction through the legacy physical-body API."""
return entity.get_physical_body().get_dynamic_friction()
[docs]
def set_legacy_damping(entity: object, linear: float, angular: float) -> None:
"""Set legacy linear and angular damping."""
body = entity.get_physical_body()
body.set_linear_damping(linear)
body.set_angular_damping(angular)
[docs]
def get_legacy_damping(entity: object) -> tuple[Any, Any]:
"""Read legacy linear and angular damping."""
body = entity.get_physical_body()
return body.get_linear_damping(), body.get_angular_damping()
[docs]
def set_legacy_inertia(entity: object, value: Any) -> None:
"""Set legacy mass-space inertia diagonal."""
entity.get_physical_body().set_mass_space_inertia_tensor(value)
[docs]
def get_legacy_inertia(entity: object) -> Any:
"""Read legacy mass-space inertia diagonal."""
return entity.get_physical_body().get_mass_space_inertia_tensor()
[docs]
def newton_lifecycle_state(scene: object) -> str:
"""Return the current Newton lifecycle state name."""
manager = getattr(scene, "manager", None)
return getattr(getattr(manager, "lifecycle_state", None), "name", "")
[docs]
def can_use_newton_entity_dynamics_fallback(scene: object) -> bool:
"""Whether legacy Newton entity dynamics helpers are safe to call."""
return newton_lifecycle_state(scene) == "BUILDER"