use anyhow::Result;
use crate::sdf;
use crate::usd::{Attribute, Prim, SchemaBase, SchemaKind, Stage};
use super::tokens as tok;
use super::{impl_geom_schema, Boundable, Gprim, Imageable, Xformable};
use crate::schemas::common::get_typed;
#[derive(Clone, derive_more::Deref)]
pub struct Cube(Prim);
impl Cube {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.define_prim(path)?.set_type_name(tok::T_CUBE)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_CUBE).map(|o| o.map(Self))
}
pub fn size_attr(&self) -> Attribute {
self.attribute(tok::A_SIZE)
}
pub fn create_size_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_SIZE, "double")?.set_custom(false)?)
}
}
impl_geom_schema!(gprim Cube);
#[derive(Clone, derive_more::Deref)]
pub struct Sphere(Prim);
impl Sphere {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.define_prim(path)?.set_type_name(tok::T_SPHERE)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_SPHERE).map(|o| o.map(Self))
}
pub fn radius_attr(&self) -> Attribute {
self.attribute(tok::A_RADIUS)
}
pub fn create_radius_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_RADIUS, "double")?.set_custom(false)?)
}
}
impl_geom_schema!(gprim Sphere);
#[derive(Clone, derive_more::Deref)]
pub struct Cone(Prim);
impl Cone {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.define_prim(path)?.set_type_name(tok::T_CONE)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_CONE).map(|o| o.map(Self))
}
pub fn radius_attr(&self) -> Attribute {
self.attribute(tok::A_RADIUS)
}
pub fn create_radius_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_RADIUS, "double")?.set_custom(false)?)
}
pub fn height_attr(&self) -> Attribute {
self.attribute(tok::A_HEIGHT)
}
pub fn create_height_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_HEIGHT, "double")?.set_custom(false)?)
}
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)?)
}
}
impl_geom_schema!(gprim Cone);
#[derive(Clone, derive_more::Deref)]
pub struct Cylinder(Prim);
impl Cylinder {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.define_prim(path)?.set_type_name(tok::T_CYLINDER)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_CYLINDER).map(|o| o.map(Self))
}
pub fn radius_attr(&self) -> Attribute {
self.attribute(tok::A_RADIUS)
}
pub fn create_radius_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_RADIUS, "double")?.set_custom(false)?)
}
pub fn height_attr(&self) -> Attribute {
self.attribute(tok::A_HEIGHT)
}
pub fn create_height_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_HEIGHT, "double")?.set_custom(false)?)
}
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)?)
}
}
impl_geom_schema!(gprim Cylinder);
#[derive(Clone, derive_more::Deref)]
pub struct Capsule(Prim);
impl Capsule {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.define_prim(path)?.set_type_name(tok::T_CAPSULE)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_CAPSULE).map(|o| o.map(Self))
}
pub fn radius_attr(&self) -> Attribute {
self.attribute(tok::A_RADIUS)
}
pub fn create_radius_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_RADIUS, "double")?.set_custom(false)?)
}
pub fn height_attr(&self) -> Attribute {
self.attribute(tok::A_HEIGHT)
}
pub fn create_height_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_HEIGHT, "double")?.set_custom(false)?)
}
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)?)
}
}
impl_geom_schema!(gprim Capsule);
#[derive(Clone, derive_more::Deref)]
pub struct Plane(Prim);
impl Plane {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.define_prim(path)?.set_type_name(tok::T_PLANE)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_PLANE).map(|o| o.map(Self))
}
pub fn width_attr(&self) -> Attribute {
self.attribute(tok::A_WIDTH)
}
pub fn create_width_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_WIDTH, "double")?.set_custom(false)?)
}
pub fn length_attr(&self) -> Attribute {
self.attribute(tok::A_LENGTH)
}
pub fn create_length_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_LENGTH, "double")?.set_custom(false)?)
}
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)?)
}
}
impl_geom_schema!(gprim Plane);
#[cfg(test)]
mod tests {
use super::*;
use crate::schemas::geom::Purpose;
#[test]
fn cube_roundtrip() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
Cube::define(&stage, "/Box")?.create_size_attr()?.set(0.5_f64)?;
let cube = Cube::get(&stage, "/Box")?.expect("Cube");
assert_eq!(cube.size_attr().get()?, Some(sdf::Value::Double(0.5)));
assert!(Cube::get(&stage, "/Missing")?.is_none());
Ok(())
}
#[test]
fn sphere_roundtrip_and_chain() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
let sphere = Sphere::define(&stage, "/Ball")?;
sphere.create_radius_attr()?.set(2.5_f64)?;
sphere.create_purpose_attr()?.set(sdf::Value::Token("render".into()))?;
sphere.create_double_sided_attr()?.set(true)?;
let sphere = Sphere::get(&stage, "/Ball")?.expect("Sphere");
assert_eq!(sphere.radius_attr().get()?, Some(sdf::Value::Double(2.5)));
assert_eq!(sphere.compute_purpose()?, Purpose::Render);
assert_eq!(sphere.double_sided_attr().get()?, Some(sdf::Value::Bool(true)));
assert_eq!(Sphere::KIND, SchemaKind::ConcreteTyped);
Ok(())
}
#[test]
fn axial_shapes_roundtrip() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
let cyl = Cylinder::define(&stage, "/Pipe")?;
cyl.create_radius_attr()?.set(0.3_f64)?;
cyl.create_height_attr()?.set(2.0_f64)?;
cyl.create_axis_attr()?.set(sdf::Value::Token("X".into()))?;
let cyl = Cylinder::get(&stage, "/Pipe")?.expect("Cylinder");
assert_eq!(cyl.radius_attr().get()?, Some(sdf::Value::Double(0.3)));
assert_eq!(cyl.axis_attr().get()?, Some(sdf::Value::Token("X".into())));
Cone::define(&stage, "/Pyramid")?.create_height_attr()?.set(2.0_f64)?;
assert!(Cone::get(&stage, "/Pyramid")?.is_some());
Capsule::define(&stage, "/Pill")?.create_radius_attr()?.set(0.5_f64)?;
assert!(Capsule::get(&stage, "/Pill")?.is_some());
Ok(())
}
#[test]
fn plane_roundtrip() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
let plane = Plane::define(&stage, "/Ground")?;
plane.create_width_attr()?.set(10.0_f64)?;
plane.create_length_attr()?.set(20.0_f64)?;
plane.create_axis_attr()?.set(sdf::Value::Token("Y".into()))?;
plane.create_double_sided_attr()?.set(false)?;
let plane = Plane::get(&stage, "/Ground")?.expect("Plane");
assert_eq!(plane.width_attr().get()?, Some(sdf::Value::Double(10.0)));
assert_eq!(plane.double_sided_attr().get()?, Some(sdf::Value::Bool(false)));
Ok(())
}
}