use crate::geom::graph::node;
use crate::geom::{self, Vector2, Vector3};
use crate::math::BaseFloat;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Properties<S = geom::scalar::Default> {
pub x: Option<Dimension<S>>,
pub y: Option<Dimension<S>>,
pub z: Option<Dimension<S>>,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Dimension<S = geom::scalar::Default> {
Absolute(S),
Relative(node::Index, Relative<S>),
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Relative<S = geom::scalar::Default> {
Matching,
Padded(S),
Scaled(S),
}
pub trait SetDimensions<S>: Sized {
fn properties(&mut self) -> &mut Properties<S>;
fn x_dimension(mut self, x: Dimension<S>) -> Self {
self.properties().x = Some(x);
self
}
fn y_dimension(mut self, y: Dimension<S>) -> Self {
self.properties().y = Some(y);
self
}
fn z_dimension(mut self, z: Dimension<S>) -> Self {
self.properties().z = Some(z);
self
}
fn width(self, w: S) -> Self {
self.x_dimension(Dimension::Absolute(w))
}
fn height(self, h: S) -> Self {
self.y_dimension(Dimension::Absolute(h))
}
fn depth(self, d: S) -> Self {
self.z_dimension(Dimension::Absolute(d))
}
fn w(self, w: S) -> Self {
self.width(w)
}
fn h(self, h: S) -> Self {
self.height(h)
}
fn d(self, d: S) -> Self {
self.depth(d)
}
fn wh(self, v: Vector2<S>) -> Self {
self.w(v.x).h(v.y)
}
fn whd(self, v: Vector3<S>) -> Self {
self.w(v.x).h(v.y).d(v.z)
}
fn w_h(self, x: S, y: S) -> Self {
self.wh(Vector2 { x, y })
}
fn w_h_d(self, x: S, y: S, z: S) -> Self {
self.whd(Vector3 { x, y, z })
}
fn x_dimension_relative(self, other: node::Index, x: Relative<S>) -> Self {
self.x_dimension(Dimension::Relative(other, x))
}
fn y_dimension_relative(self, other: node::Index, y: Relative<S>) -> Self {
self.y_dimension(Dimension::Relative(other, y))
}
fn z_dimension_relative(self, other: node::Index, z: Relative<S>) -> Self {
self.z_dimension(Dimension::Relative(other, z))
}
fn w_of(self, other: node::Index) -> Self {
self.x_dimension_relative(other, Relative::Matching)
}
fn h_of(self, other: node::Index) -> Self {
self.y_dimension_relative(other, Relative::Matching)
}
fn d_of(self, other: node::Index) -> Self {
self.z_dimension_relative(other, Relative::Matching)
}
fn wh_of(self, other: node::Index) -> Self {
self.w_of(other).h_of(other)
}
fn whd_of(self, other: node::Index) -> Self {
self.w_of(other).h_of(other).d_of(other)
}
fn padded_w_of(self, other: node::Index, pad: S) -> Self {
self.x_dimension_relative(other, Relative::Padded(pad))
}
fn padded_h_of(self, other: node::Index, pad: S) -> Self {
self.y_dimension_relative(other, Relative::Padded(pad))
}
fn padded_d_of(self, other: node::Index, pad: S) -> Self {
self.z_dimension_relative(other, Relative::Padded(pad))
}
fn padded_wh_of(self, other: node::Index, pad: S) -> Self
where
S: Clone,
{
self.padded_w_of(other, pad.clone()).padded_h_of(other, pad)
}
fn padded_whd_of(self, other: node::Index, pad: S) -> Self
where
S: Clone,
{
self.padded_w_of(other, pad.clone())
.padded_h_of(other, pad.clone())
.padded_d_of(other, pad)
}
fn scaled_w_of(self, other: node::Index, scale: S) -> Self {
self.x_dimension_relative(other, Relative::Scaled(scale))
}
fn scaled_h_of(self, other: node::Index, scale: S) -> Self {
self.y_dimension_relative(other, Relative::Scaled(scale))
}
fn scaled_d_of(self, other: node::Index, scale: S) -> Self {
self.z_dimension_relative(other, Relative::Scaled(scale))
}
fn scaled_wh_of(self, other: node::Index, scale: S) -> Self
where
S: Clone,
{
self.scaled_w_of(other, scale.clone())
.scaled_h_of(other, scale)
}
fn scaled_whd_of(self, other: node::Index, scale: S) -> Self
where
S: Clone,
{
self.scaled_w_of(other, scale.clone())
.scaled_h_of(other, scale.clone())
.scaled_d_of(other, scale)
}
}
impl<S> SetDimensions<S> for Properties<S> {
fn properties(&mut self) -> &mut Properties<S> {
self
}
}
impl<S> Default for Properties<S> {
fn default() -> Self {
let x = None;
let y = None;
let z = None;
Properties { x, y, z }
}
}
impl<S> Dimension<S>
where
S: BaseFloat,
{
pub fn to_scalar<F>(&self, dimension_of: F) -> S
where
F: FnOnce(&node::Index) -> S,
{
match *self {
Dimension::Absolute(s) => s,
Dimension::Relative(ref n, relative) => match relative {
Relative::Matching => dimension_of(n),
Relative::Padded(pad) => dimension_of(n) - pad * (S::one() + S::one()),
Relative::Scaled(scale) => dimension_of(n) * scale,
},
}
}
}