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, PointBased, Xformable};
use crate::schemas::common::get_typed;
pub trait Curves: PointBased {
fn curve_vertex_counts_attr(&self) -> Attribute {
self.prim().attribute(tok::A_CURVE_VERTEX_COUNTS)
}
fn create_curve_vertex_counts_attr(&self) -> Result<Attribute> {
Ok(self
.prim()
.create_attribute(tok::A_CURVE_VERTEX_COUNTS, "int[]")?
.set_custom(false)?)
}
fn widths_attr(&self) -> Attribute {
self.prim().attribute(tok::A_WIDTHS)
}
fn create_widths_attr(&self) -> Result<Attribute> {
Ok(self
.prim()
.create_attribute(tok::A_WIDTHS, "float[]")?
.set_custom(false)?)
}
}
#[derive(Clone, derive_more::Deref)]
pub struct BasisCurves(Prim);
impl BasisCurves {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.define_prim(path)?.set_type_name(tok::T_BASIS_CURVES)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_BASIS_CURVES).map(|o| o.map(Self))
}
pub fn type_attr(&self) -> Attribute {
self.attribute(tok::A_TYPE)
}
pub fn create_type_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_TYPE, "token")?
.set_custom(false)?
.set_variability(sdf::Variability::Uniform)?)
}
pub fn basis_attr(&self) -> Attribute {
self.attribute(tok::A_BASIS)
}
pub fn create_basis_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_BASIS, "token")?
.set_custom(false)?
.set_variability(sdf::Variability::Uniform)?)
}
pub fn wrap_attr(&self) -> Attribute {
self.attribute(tok::A_WRAP)
}
pub fn create_wrap_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_WRAP, "token")?
.set_custom(false)?
.set_variability(sdf::Variability::Uniform)?)
}
}
impl_geom_schema!(curves BasisCurves);
#[derive(Clone, derive_more::Deref)]
pub struct NurbsCurves(Prim);
impl NurbsCurves {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.define_prim(path)?.set_type_name(tok::T_NURBS_CURVES)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_NURBS_CURVES).map(|o| o.map(Self))
}
pub fn order_attr(&self) -> Attribute {
self.attribute(tok::A_ORDER)
}
pub fn create_order_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_ORDER, "int[]")?.set_custom(false)?)
}
pub fn knots_attr(&self) -> Attribute {
self.attribute(tok::A_KNOTS)
}
pub fn create_knots_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_KNOTS, "double[]")?.set_custom(false)?)
}
pub fn ranges_attr(&self) -> Attribute {
self.attribute(tok::A_RANGES)
}
pub fn create_ranges_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_RANGES, "double2[]")?.set_custom(false)?)
}
pub fn point_weights_attr(&self) -> Attribute {
self.attribute(tok::A_POINT_WEIGHTS)
}
pub fn create_point_weights_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_POINT_WEIGHTS, "double[]")?
.set_custom(false)?)
}
}
impl_geom_schema!(curves NurbsCurves);
#[derive(Clone, derive_more::Deref)]
pub struct HermiteCurves(Prim);
impl HermiteCurves {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.define_prim(path)?.set_type_name(tok::T_HERMITE_CURVES)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_HERMITE_CURVES).map(|o| o.map(Self))
}
pub fn tangents_attr(&self) -> Attribute {
self.attribute(tok::A_TANGENTS)
}
pub fn create_tangents_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_TANGENTS, "vector3f[]")?
.set_custom(false)?)
}
}
impl_geom_schema!(curves HermiteCurves);
#[derive(Clone, derive_more::Deref)]
pub struct NurbsPatch(Prim);
impl NurbsPatch {
pub fn define(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Self> {
Ok(Self(stage.define_prim(path)?.set_type_name(tok::T_NURBS_PATCH)?))
}
pub fn get(stage: &Stage, path: impl Into<sdf::Path>) -> Result<Option<Self>> {
get_typed(stage, path, tok::T_NURBS_PATCH).map(|o| o.map(Self))
}
pub fn u_vertex_count_attr(&self) -> Attribute {
self.attribute(tok::A_U_VERTEX_COUNT)
}
pub fn create_u_vertex_count_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_U_VERTEX_COUNT, "int")?.set_custom(false)?)
}
pub fn v_vertex_count_attr(&self) -> Attribute {
self.attribute(tok::A_V_VERTEX_COUNT)
}
pub fn create_v_vertex_count_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_V_VERTEX_COUNT, "int")?.set_custom(false)?)
}
pub fn u_order_attr(&self) -> Attribute {
self.attribute(tok::A_U_ORDER)
}
pub fn create_u_order_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_U_ORDER, "int")?.set_custom(false)?)
}
pub fn v_order_attr(&self) -> Attribute {
self.attribute(tok::A_V_ORDER)
}
pub fn create_v_order_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_V_ORDER, "int")?.set_custom(false)?)
}
pub fn u_knots_attr(&self) -> Attribute {
self.attribute(tok::A_U_KNOTS)
}
pub fn create_u_knots_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_U_KNOTS, "double[]")?.set_custom(false)?)
}
pub fn v_knots_attr(&self) -> Attribute {
self.attribute(tok::A_V_KNOTS)
}
pub fn create_v_knots_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_V_KNOTS, "double[]")?.set_custom(false)?)
}
pub fn u_form_attr(&self) -> Attribute {
self.attribute(tok::A_U_FORM)
}
pub fn create_u_form_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_U_FORM, "token")?
.set_custom(false)?
.set_variability(sdf::Variability::Uniform)?)
}
pub fn v_form_attr(&self) -> Attribute {
self.attribute(tok::A_V_FORM)
}
pub fn create_v_form_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_V_FORM, "token")?
.set_custom(false)?
.set_variability(sdf::Variability::Uniform)?)
}
pub fn u_range_attr(&self) -> Attribute {
self.attribute(tok::A_U_RANGE)
}
pub fn create_u_range_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_U_RANGE, "double2")?.set_custom(false)?)
}
pub fn v_range_attr(&self) -> Attribute {
self.attribute(tok::A_V_RANGE)
}
pub fn create_v_range_attr(&self) -> Result<Attribute> {
Ok(self.create_attribute(tok::A_V_RANGE, "double2")?.set_custom(false)?)
}
pub fn point_weights_attr(&self) -> Attribute {
self.attribute(tok::A_POINT_WEIGHTS)
}
pub fn create_point_weights_attr(&self) -> Result<Attribute> {
Ok(self
.create_attribute(tok::A_POINT_WEIGHTS, "double[]")?
.set_custom(false)?)
}
}
impl_geom_schema!(pointbased NurbsPatch);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basis_curves_roundtrip() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
let c = BasisCurves::define(&stage, "/C")?;
c.create_points_attr()?.set(sdf::Value::Vec3fVec(vec![
[0.0_f32, 0.0, 0.0].into(),
[1.0, 0.0, 0.0].into(),
]))?;
c.create_curve_vertex_counts_attr()?.set(sdf::Value::IntVec(vec![2]))?;
c.create_type_attr()?.set(sdf::Value::Token("linear".into()))?;
c.create_widths_attr()?
.set_metadata(tok::META_INTERPOLATION, sdf::Value::Token("vertex".into()))?
.set(sdf::Value::FloatVec(vec![0.1, 0.1]))?;
let c = BasisCurves::get(&stage, "/C")?.expect("BasisCurves");
assert_eq!(c.curve_vertex_counts_attr().get()?, Some(sdf::Value::IntVec(vec![2])));
assert_eq!(c.type_attr().get()?, Some(sdf::Value::Token("linear".into())));
assert_eq!(
c.widths_attr().get_metadata(tok::META_INTERPOLATION)?,
Some(sdf::Value::Token("vertex".into()))
);
assert!(BasisCurves::get(&stage, "/Missing")?.is_none());
Ok(())
}
#[test]
fn nurbs_curves_attrs() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
let c = NurbsCurves::define(&stage, "/N")?;
c.create_order_attr()?.set(vec![4])?;
c.create_knots_attr()?
.set(sdf::Value::DoubleVec(vec![0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0]))?;
c.create_point_weights_attr()?.set(vec![1.0_f64, 1.0, 1.0, 1.0])?;
let c = NurbsCurves::get(&stage, "/N")?.expect("NurbsCurves");
assert_eq!(c.order_attr().get()?, Some(sdf::Value::IntVec(vec![4])));
assert_eq!(
c.point_weights_attr()
.get::<sdf::Value>()?
.and_then(|v| v.try_as_double_vec())
.map(|v| v.len()),
Some(4)
);
Ok(())
}
#[test]
fn hermite_curves_tangents() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
let c = HermiteCurves::define(&stage, "/H")?;
c.create_points_attr()?.set(sdf::Value::Vec3fVec(vec![
[0.0_f32, 0.0, 0.0].into(),
[1.0, 0.0, 0.0].into(),
]))?;
c.create_curve_vertex_counts_attr()?.set(sdf::Value::IntVec(vec![2]))?;
c.create_tangents_attr()?.set(sdf::Value::Vec3fVec(vec![
[1.0_f32, 0.0, 0.0].into(),
[1.0, 0.0, 0.0].into(),
]))?;
let c = HermiteCurves::get(&stage, "/H")?.expect("HermiteCurves");
assert_eq!(
c.tangents_attr()
.get::<sdf::Value>()?
.and_then(|v| v.try_as_vec_3f_vec())
.map(|v| v.len()),
Some(2)
);
Ok(())
}
#[test]
fn nurbs_patch_grid() -> Result<()> {
let stage = Stage::builder().in_memory("anon.usda")?;
let p = NurbsPatch::define(&stage, "/P")?;
p.create_u_vertex_count_attr()?.set(4_i32)?;
p.create_v_vertex_count_attr()?.set(4_i32)?;
p.create_u_form_attr()?.set(sdf::Value::Token("periodic".into()))?;
let p = NurbsPatch::get(&stage, "/P")?.expect("NurbsPatch");
assert_eq!(p.u_vertex_count_attr().get()?, Some(sdf::Value::Int(4)));
assert_eq!(p.u_form_attr().get()?, Some(sdf::Value::Token("periodic".into())));
Ok(())
}
}