use anyhow::Result;
use crate::sdf;
use crate::usd::{Attribute, Prim, Relationship, Stage};
use super::impl_physics_schema;
use super::tokens as tok;
use crate::schemas::common::{get_typed, get_with_api};
#[derive(Clone, derive_more::Deref)]
pub struct Scene(Prim);
impl Scene {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.define_prim(path)?.set_type_name(tok::T_PHYSICS_SCENE)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_PHYSICS_SCENE).map(|o| o.map(Self))
}
pub fn gravity_direction_attr(&self) -> Attribute {
self.attribute(tok::A_GRAVITY_DIRECTION)
}
pub fn create_gravity_direction_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_GRAVITY_DIRECTION, "vector3f")?
.set_custom(false)?)
}
pub fn gravity_magnitude_attr(&self) -> Attribute {
self.attribute(tok::A_GRAVITY_MAGNITUDE)
}
pub fn create_gravity_magnitude_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_GRAVITY_MAGNITUDE, "float")?
.set_custom(false)?)
}
}
impl_physics_schema!(typed Scene);
#[derive(Clone, derive_more::Deref)]
pub struct CollisionGroup(Prim);
impl CollisionGroup {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(
stage.define_prim(path)?.set_type_name(tok::T_PHYSICS_COLLISION_GROUP)?,
))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_PHYSICS_COLLISION_GROUP).map(|o| o.map(Self))
}
pub fn filtered_groups_rel(&self) -> Relationship {
self.relationship(tok::A_FILTERED_GROUPS)
}
pub fn create_filtered_groups_rel(&self) -> Result<Relationship> {
Ok(self.create_relationship(tok::A_FILTERED_GROUPS)?.set_custom(false)?)
}
pub fn merge_group_attr(&self) -> Attribute {
self.attribute(tok::A_MERGE_GROUP)
}
pub fn create_merge_group_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_MERGE_GROUP, "token")?
.set_custom(false)?
.set_variability(sdf::Variability::Uniform)?)
}
pub fn invert_filtered_groups_attr(&self) -> Attribute {
self.attribute(tok::A_INVERT_FILTERED_GROUPS)
}
pub fn create_invert_filtered_groups_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_INVERT_FILTERED_GROUPS, "bool")?
.set_custom(false)?
.set_variability(sdf::Variability::Uniform)?)
}
}
impl_physics_schema!(typed CollisionGroup);
#[derive(Clone, derive_more::Deref)]
pub struct Joint(Prim);
impl Joint {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.define_prim(path)?.set_type_name(tok::T_PHYSICS_JOINT)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_PHYSICS_JOINT).map(|o| o.map(Self))
}
}
impl_physics_schema!(joint Joint);
#[derive(Clone, derive_more::Deref)]
pub struct FixedJoint(Prim);
impl FixedJoint {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(
stage.define_prim(path)?.set_type_name(tok::T_PHYSICS_FIXED_JOINT)?,
))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_PHYSICS_FIXED_JOINT).map(|o| o.map(Self))
}
}
impl_physics_schema!(joint FixedJoint);
#[derive(Clone, derive_more::Deref)]
pub struct RevoluteJoint(Prim);
impl RevoluteJoint {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(
stage.define_prim(path)?.set_type_name(tok::T_PHYSICS_REVOLUTE_JOINT)?,
))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_PHYSICS_REVOLUTE_JOINT).map(|o| o.map(Self))
}
pub fn axis_attr(&self) -> Attribute {
self.attribute(tok::A_AXIS)
}
pub fn create_axis_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_AXIS, "token")?
.set_custom(false)?
.set_variability(sdf::Variability::Uniform)?)
}
pub fn lower_limit_attr(&self) -> Attribute {
self.attribute(tok::A_LOWER_LIMIT)
}
pub fn create_lower_limit_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_LOWER_LIMIT, "float")?.set_custom(false)?)
}
pub fn upper_limit_attr(&self) -> Attribute {
self.attribute(tok::A_UPPER_LIMIT)
}
pub fn create_upper_limit_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_UPPER_LIMIT, "float")?.set_custom(false)?)
}
}
impl_physics_schema!(joint RevoluteJoint);
#[derive(Clone, derive_more::Deref)]
pub struct PrismaticJoint(Prim);
impl PrismaticJoint {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(
stage.define_prim(path)?.set_type_name(tok::T_PHYSICS_PRISMATIC_JOINT)?,
))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_PHYSICS_PRISMATIC_JOINT).map(|o| o.map(Self))
}
pub fn axis_attr(&self) -> Attribute {
self.attribute(tok::A_AXIS)
}
pub fn create_axis_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_AXIS, "token")?
.set_custom(false)?
.set_variability(sdf::Variability::Uniform)?)
}
pub fn lower_limit_attr(&self) -> Attribute {
self.attribute(tok::A_LOWER_LIMIT)
}
pub fn create_lower_limit_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_LOWER_LIMIT, "float")?.set_custom(false)?)
}
pub fn upper_limit_attr(&self) -> Attribute {
self.attribute(tok::A_UPPER_LIMIT)
}
pub fn create_upper_limit_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_UPPER_LIMIT, "float")?.set_custom(false)?)
}
}
impl_physics_schema!(joint PrismaticJoint);
#[derive(Clone, derive_more::Deref)]
pub struct SphericalJoint(Prim);
impl SphericalJoint {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(
stage.define_prim(path)?.set_type_name(tok::T_PHYSICS_SPHERICAL_JOINT)?,
))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_PHYSICS_SPHERICAL_JOINT).map(|o| o.map(Self))
}
pub fn axis_attr(&self) -> Attribute {
self.attribute(tok::A_AXIS)
}
pub fn create_axis_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_AXIS, "token")?
.set_custom(false)?
.set_variability(sdf::Variability::Uniform)?)
}
pub fn cone_angle0_limit_attr(&self) -> Attribute {
self.attribute(tok::A_CONE_ANGLE_0_LIMIT)
}
pub fn create_cone_angle0_limit_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_CONE_ANGLE_0_LIMIT, "float")?
.set_custom(false)?)
}
pub fn cone_angle1_limit_attr(&self) -> Attribute {
self.attribute(tok::A_CONE_ANGLE_1_LIMIT)
}
pub fn create_cone_angle1_limit_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_CONE_ANGLE_1_LIMIT, "float")?
.set_custom(false)?)
}
}
impl_physics_schema!(joint SphericalJoint);
#[derive(Clone, derive_more::Deref)]
pub struct DistanceJoint(Prim);
impl DistanceJoint {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(
stage.define_prim(path)?.set_type_name(tok::T_PHYSICS_DISTANCE_JOINT)?,
))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_PHYSICS_DISTANCE_JOINT).map(|o| o.map(Self))
}
pub fn min_distance_attr(&self) -> Attribute {
self.attribute(tok::A_MIN_DISTANCE)
}
pub fn create_min_distance_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_MIN_DISTANCE, "float")?.set_custom(false)?)
}
pub fn max_distance_attr(&self) -> Attribute {
self.attribute(tok::A_MAX_DISTANCE)
}
pub fn create_max_distance_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_MAX_DISTANCE, "float")?.set_custom(false)?)
}
}
impl_physics_schema!(joint DistanceJoint);
#[derive(Clone, derive_more::Deref)]
pub struct RigidBodyAPI(Prim);
impl RigidBodyAPI {
pub fn apply(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(
stage.override_prim(path)?.add_applied_schema(tok::API_RIGID_BODY)?,
))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_with_api(stage, path, &[tok::API_RIGID_BODY]).map(|o| o.map(Self))
}
pub fn rigid_body_enabled_attr(&self) -> Attribute {
self.attribute(tok::A_RIGID_BODY_ENABLED)
}
pub fn create_rigid_body_enabled_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_RIGID_BODY_ENABLED, "bool")?
.set_custom(false)?)
}
pub fn kinematic_enabled_attr(&self) -> Attribute {
self.attribute(tok::A_KINEMATIC_ENABLED)
}
pub fn create_kinematic_enabled_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_KINEMATIC_ENABLED, "bool")?
.set_custom(false)?)
}
pub fn starts_asleep_attr(&self) -> Attribute {
self.attribute(tok::A_STARTS_ASLEEP)
}
pub fn create_starts_asleep_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_STARTS_ASLEEP, "bool")?
.set_custom(false)?
.set_variability(sdf::Variability::Uniform)?)
}
pub fn velocity_attr(&self) -> Attribute {
self.attribute(tok::A_VELOCITY)
}
pub fn create_velocity_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_VELOCITY, "vector3f")?.set_custom(false)?)
}
pub fn angular_velocity_attr(&self) -> Attribute {
self.attribute(tok::A_ANGULAR_VELOCITY)
}
pub fn create_angular_velocity_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_ANGULAR_VELOCITY, "vector3f")?
.set_custom(false)?)
}
pub fn simulation_owner_rel(&self) -> Relationship {
self.relationship(tok::A_SIMULATION_OWNER)
}
pub fn create_simulation_owner_rel(&self) -> Result<Relationship> {
Ok(self.create_relationship(tok::A_SIMULATION_OWNER)?.set_custom(false)?)
}
}
impl_physics_schema!(single_api RigidBodyAPI);
#[derive(Clone, derive_more::Deref)]
pub struct MassAPI(Prim);
impl MassAPI {
pub fn apply(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.override_prim(path)?.add_applied_schema(tok::API_MASS)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_with_api(stage, path, &[tok::API_MASS]).map(|o| o.map(Self))
}
pub fn mass_attr(&self) -> Attribute {
self.attribute(tok::A_MASS)
}
pub fn create_mass_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_MASS, "float")?.set_custom(false)?)
}
pub fn density_attr(&self) -> Attribute {
self.attribute(tok::A_DENSITY)
}
pub fn create_density_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_DENSITY, "float")?.set_custom(false)?)
}
pub fn center_of_mass_attr(&self) -> Attribute {
self.attribute(tok::A_CENTER_OF_MASS)
}
pub fn create_center_of_mass_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_CENTER_OF_MASS, "point3f")?
.set_custom(false)?)
}
pub fn diagonal_inertia_attr(&self) -> Attribute {
self.attribute(tok::A_DIAGONAL_INERTIA)
}
pub fn create_diagonal_inertia_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_DIAGONAL_INERTIA, "float3")?
.set_custom(false)?)
}
pub fn principal_axes_attr(&self) -> Attribute {
self.attribute(tok::A_PRINCIPAL_AXES)
}
pub fn create_principal_axes_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_PRINCIPAL_AXES, "quatf")?
.set_custom(false)?)
}
}
impl_physics_schema!(single_api MassAPI);
#[derive(Clone, derive_more::Deref)]
pub struct CollisionAPI(Prim);
impl CollisionAPI {
pub fn apply(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.override_prim(path)?.add_applied_schema(tok::API_COLLISION)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_with_api(stage, path, &[tok::API_COLLISION]).map(|o| o.map(Self))
}
pub fn collision_enabled_attr(&self) -> Attribute {
self.attribute(tok::A_COLLISION_ENABLED)
}
pub fn create_collision_enabled_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_COLLISION_ENABLED, "bool")?
.set_custom(false)?)
}
}
impl_physics_schema!(single_api CollisionAPI);
#[derive(Clone, derive_more::Deref)]
pub struct MeshCollisionAPI(Prim);
impl MeshCollisionAPI {
pub fn apply(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(
stage.override_prim(path)?.add_applied_schema(tok::API_MESH_COLLISION)?,
))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_with_api(stage, path, &[tok::API_MESH_COLLISION]).map(|o| o.map(Self))
}
pub fn approximation_attr(&self) -> Attribute {
self.attribute(tok::A_APPROXIMATION)
}
pub fn create_approximation_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_APPROXIMATION, "token")?
.set_custom(false)?
.set_variability(sdf::Variability::Uniform)?)
}
}
impl_physics_schema!(single_api MeshCollisionAPI);
#[derive(Clone, derive_more::Deref)]
pub struct MaterialAPI(Prim);
impl MaterialAPI {
pub fn apply(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(
stage
.override_prim(path)?
.add_applied_schema(tok::API_PHYSICS_MATERIAL)?,
))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_with_api(stage, path, &[tok::API_PHYSICS_MATERIAL]).map(|o| o.map(Self))
}
pub fn dynamic_friction_attr(&self) -> Attribute {
self.attribute(tok::A_DYNAMIC_FRICTION)
}
pub fn create_dynamic_friction_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_DYNAMIC_FRICTION, "float")?
.set_custom(false)?)
}
pub fn static_friction_attr(&self) -> Attribute {
self.attribute(tok::A_STATIC_FRICTION)
}
pub fn create_static_friction_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_STATIC_FRICTION, "float")?
.set_custom(false)?)
}
pub fn restitution_attr(&self) -> Attribute {
self.attribute(tok::A_RESTITUTION)
}
pub fn create_restitution_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_RESTITUTION, "float")?.set_custom(false)?)
}
pub fn density_attr(&self) -> Attribute {
self.attribute(tok::A_DENSITY)
}
pub fn create_density_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_DENSITY, "float")?.set_custom(false)?)
}
}
impl_physics_schema!(single_api MaterialAPI);
#[derive(Clone, derive_more::Deref)]
pub struct ArticulationRootAPI(Prim);
impl ArticulationRootAPI {
pub fn apply(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(
stage
.override_prim(path)?
.add_applied_schema(tok::API_ARTICULATION_ROOT)?,
))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_with_api(stage, path, &[tok::API_ARTICULATION_ROOT]).map(|o| o.map(Self))
}
}
impl_physics_schema!(single_api ArticulationRootAPI);
#[derive(Clone, derive_more::Deref)]
pub struct FilteredPairsAPI(Prim);
impl FilteredPairsAPI {
pub fn apply(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(
stage.override_prim(path)?.add_applied_schema(tok::API_FILTERED_PAIRS)?,
))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_with_api(stage, path, &[tok::API_FILTERED_PAIRS]).map(|o| o.map(Self))
}
pub fn filtered_pairs_rel(&self) -> Relationship {
self.relationship(tok::A_FILTERED_PAIRS)
}
pub fn create_filtered_pairs_rel(&self) -> Result<Relationship> {
Ok(self.create_relationship(tok::A_FILTERED_PAIRS)?.set_custom(false)?)
}
}
impl_physics_schema!(single_api FilteredPairsAPI);
#[derive(Clone, derive_more::Deref)]
pub struct DriveAPI {
#[deref]
prim: Prim,
name: String,
}
impl DriveAPI {
pub fn apply(stage: &Stage, path: impl Into<sdf::Path>, name: &str) -> Result<Self> {
let prim = stage
.override_prim(path)?
.add_applied_schema(format!("{}:{name}", tok::API_DRIVE))?;
Ok(Self {
prim,
name: name.to_string(),
})
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>, name: &str) -> Result<Option<Self>> {
let api = format!("{}:{name}", tok::API_DRIVE);
Ok(get_with_api(stage, path, &[api.as_str()])?.map(|prim| Self {
prim,
name: name.to_string(),
}))
}
pub fn get_all(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Vec<Self>> {
let prim = stage.prim_at(path);
let prefix = format!("{}:", tok::API_DRIVE);
Ok(prim
.api_schemas()?
.into_iter()
.filter_map(|s| s.strip_prefix(&prefix).map(str::to_string))
.map(|name| Self {
prim: prim.clone(),
name,
})
.collect())
}
pub fn name(&self) -> &str {
&self.name
}
fn prop(&self, sub: &str) -> String {
format!("drive:{}:physics:{sub}", self.name)
}
pub fn type_attr(&self) -> Attribute {
self.attribute(&self.prop(tok::DRIVE_SUB_TYPE))
}
pub fn create_type_attr(&self) -> Result<Attribute> {
Ok(self
.prim
.create_attribute(&self.prop(tok::DRIVE_SUB_TYPE), "token")?
.set_custom(false)?
.set_variability(sdf::Variability::Uniform)?)
}
pub fn target_position_attr(&self) -> Attribute {
self.attribute(&self.prop(tok::DRIVE_SUB_TARGET_POSITION))
}
pub fn create_target_position_attr(&self) -> Result<Attribute> {
Ok(self
.prim
.create_attribute(&self.prop(tok::DRIVE_SUB_TARGET_POSITION), "float")?
.set_custom(false)?)
}
pub fn target_velocity_attr(&self) -> Attribute {
self.attribute(&self.prop(tok::DRIVE_SUB_TARGET_VELOCITY))
}
pub fn create_target_velocity_attr(&self) -> Result<Attribute> {
Ok(self
.prim
.create_attribute(&self.prop(tok::DRIVE_SUB_TARGET_VELOCITY), "float")?
.set_custom(false)?)
}
pub fn damping_attr(&self) -> Attribute {
self.attribute(&self.prop(tok::DRIVE_SUB_DAMPING))
}
pub fn create_damping_attr(&self) -> Result<Attribute> {
Ok(self
.prim
.create_attribute(&self.prop(tok::DRIVE_SUB_DAMPING), "float")?
.set_custom(false)?)
}
pub fn stiffness_attr(&self) -> Attribute {
self.attribute(&self.prop(tok::DRIVE_SUB_STIFFNESS))
}
pub fn create_stiffness_attr(&self) -> Result<Attribute> {
Ok(self
.prim
.create_attribute(&self.prop(tok::DRIVE_SUB_STIFFNESS), "float")?
.set_custom(false)?)
}
pub fn max_force_attr(&self) -> Attribute {
self.attribute(&self.prop(tok::DRIVE_SUB_MAX_FORCE))
}
pub fn create_max_force_attr(&self) -> Result<Attribute> {
Ok(self
.prim
.create_attribute(&self.prop(tok::DRIVE_SUB_MAX_FORCE), "float")?
.set_custom(false)?)
}
}
impl_physics_schema!(multi_api DriveAPI);
#[derive(Clone, derive_more::Deref)]
pub struct LimitAPI {
#[deref]
prim: Prim,
name: String,
}
impl LimitAPI {
pub fn apply(stage: &Stage, path: impl Into<sdf::Path>, name: &str) -> Result<Self> {
let prim = stage
.override_prim(path)?
.add_applied_schema(format!("{}:{name}", tok::API_LIMIT))?;
Ok(Self {
prim,
name: name.to_string(),
})
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>, name: &str) -> Result<Option<Self>> {
let api = format!("{}:{name}", tok::API_LIMIT);
Ok(get_with_api(stage, path, &[api.as_str()])?.map(|prim| Self {
prim,
name: name.to_string(),
}))
}
pub fn get_all(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Vec<Self>> {
let prim = stage.prim_at(path);
let prefix = format!("{}:", tok::API_LIMIT);
Ok(prim
.api_schemas()?
.into_iter()
.filter_map(|s| s.strip_prefix(&prefix).map(str::to_string))
.map(|name| Self {
prim: prim.clone(),
name,
})
.collect())
}
pub fn name(&self) -> &str {
&self.name
}
fn prop(&self, sub: &str) -> String {
format!("limit:{}:physics:{sub}", self.name)
}
pub fn low_attr(&self) -> Attribute {
self.attribute(&self.prop(tok::LIMIT_SUB_LOW))
}
pub fn create_low_attr(&self) -> Result<Attribute> {
Ok(self
.prim
.create_attribute(&self.prop(tok::LIMIT_SUB_LOW), "float")?
.set_custom(false)?)
}
pub fn high_attr(&self) -> Attribute {
self.attribute(&self.prop(tok::LIMIT_SUB_HIGH))
}
pub fn create_high_attr(&self) -> Result<Attribute> {
Ok(self
.prim
.create_attribute(&self.prop(tok::LIMIT_SUB_HIGH), "float")?
.set_custom(false)?)
}
}
impl_physics_schema!(multi_api LimitAPI);
#[cfg(test)]
mod tests {
use super::*;
use crate::schemas::physics::{CollisionApprox, DriveType, JointAxis, JointBase};
#[test]
fn scene_and_joint_roundtrip() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
let scene = Scene::define(&stage, "/World/Scene")?;
scene.create_gravity_magnitude_attr()?.set(981.0_f32)?;
let hinge = RevoluteJoint::define(&stage, "/World/Hinge")?;
hinge.create_axis_attr()?.set(JointAxis::Z)?;
hinge.create_break_force_attr()?.set(500.0_f32)?;
let scene = Scene::get(&stage, "/World/Scene")?.expect("Scene");
assert_eq!(scene.gravity_magnitude_attr().get::<f32>()?, Some(981.0));
let hinge = RevoluteJoint::get(&stage, "/World/Hinge")?.expect("RevoluteJoint");
assert_eq!(hinge.axis_attr().get::<JointAxis>()?, Some(JointAxis::Z));
assert_eq!(hinge.break_force_attr().get::<f32>()?, Some(500.0));
assert!(Joint::get(&stage, "/World/Hinge")?.is_none());
Ok(())
}
#[test]
fn applied_apis_roundtrip() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
stage.define_prim("/World/Box")?.set_type_name("Cube")?;
let body = RigidBodyAPI::apply(&stage, "/World/Box")?;
body.create_rigid_body_enabled_attr()?.set(true)?;
MassAPI::apply(&stage, "/World/Box")?.create_mass_attr()?.set(2.5_f32)?;
MeshCollisionAPI::apply(&stage, "/World/Box")?
.create_approximation_attr()?
.set(CollisionApprox::ConvexHull)?;
let body = RigidBodyAPI::get(&stage, "/World/Box")?.expect("RigidBodyAPI");
assert_eq!(body.rigid_body_enabled_attr().get::<bool>()?, Some(true));
assert_eq!(
MassAPI::get(&stage, "/World/Box")?
.expect("MassAPI")
.mass_attr()
.get::<f32>()?,
Some(2.5)
);
assert_eq!(
MeshCollisionAPI::get(&stage, "/World/Box")?
.expect("MeshCollisionAPI")
.approximation_attr()
.get::<CollisionApprox>()?,
Some(CollisionApprox::ConvexHull)
);
assert!(CollisionAPI::get(&stage, "/World/Box")?.is_none());
Ok(())
}
#[test]
fn multi_apply_drive_and_limit() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
let joint = Joint::define(&stage, "/World/D6")?;
DriveAPI::apply(&stage, joint.path().clone(), "rotX")?
.create_type_attr()?
.set(DriveType::Acceleration)?;
DriveAPI::apply(&stage, "/World/D6", "rotY")?
.create_target_position_attr()?
.set(45.0_f32)?;
let limit = LimitAPI::apply(&stage, "/World/D6", "rotX")?;
limit.create_low_attr()?.set(-30.0_f32)?;
limit.create_high_attr()?.set(30.0_f32)?;
let drive = DriveAPI::get(&stage, "/World/D6", "rotX")?.expect("DriveAPI:rotX");
assert_eq!(drive.name(), "rotX");
assert_eq!(drive.type_attr().get::<DriveType>()?, Some(DriveType::Acceleration));
let limit = LimitAPI::get(&stage, "/World/D6", "rotX")?.expect("LimitAPI:rotX");
assert_eq!(limit.low_attr().get::<f32>()?, Some(-30.0));
assert_eq!(limit.high_attr().get::<f32>()?, Some(30.0));
let mut drives: Vec<String> = DriveAPI::get_all(&stage, "/World/D6")?
.iter()
.map(|d| d.name().to_string())
.collect();
drives.sort();
assert_eq!(drives, vec!["rotX".to_string(), "rotY".to_string()]);
assert_eq!(LimitAPI::get_all(&stage, "/World/D6")?.len(), 1);
assert!(DriveAPI::get(&stage, "/World/D6", "rotZ")?.is_none());
Ok(())
}
}