diff options
Diffstat (limited to 'src/geom')
| -rw-r--r-- | src/geom/gen.rs | 15 | ||||
| -rw-r--r-- | src/geom/linear.rs | 2 | ||||
| -rw-r--r-- | src/geom/mod.rs | 2 | ||||
| -rw-r--r-- | src/geom/path.rs | 10 | ||||
| -rw-r--r-- | src/geom/scalar.rs | 2 | ||||
| -rw-r--r-- | src/geom/sides.rs | 20 | ||||
| -rw-r--r-- | src/geom/size.rs | 131 | ||||
| -rw-r--r-- | src/geom/spec.rs | 219 |
8 files changed, 199 insertions, 202 deletions
diff --git a/src/geom/gen.rs b/src/geom/gen.rs index 5232139b..fc4c56e7 100644 --- a/src/geom/gen.rs +++ b/src/geom/gen.rs @@ -53,21 +53,6 @@ impl Gen<Length> { pub fn to_point(self, main: SpecAxis) -> Point { self.to_spec(main).to_point() } - - /// Convert to a size. - pub fn to_size(self, main: SpecAxis) -> Size { - self.to_spec(main).to_size() - } -} - -impl<T> Gen<Option<T>> { - /// Unwrap the individual fields. - pub fn unwrap_or(self, other: Gen<T>) -> Gen<T> { - Gen { - cross: self.cross.unwrap_or(other.cross), - main: self.main.unwrap_or(other.main), - } - } } impl<T> Get<GenAxis> for Gen<T> { diff --git a/src/geom/linear.rs b/src/geom/linear.rs index 4a0def2f..77923c43 100644 --- a/src/geom/linear.rs +++ b/src/geom/linear.rs @@ -42,7 +42,7 @@ impl Linear { } /// Whether there is a linear component. - pub fn is_relative(&self) -> bool { + pub fn is_relative(self) -> bool { !self.rel.is_zero() } } diff --git a/src/geom/mod.rs b/src/geom/mod.rs index b0c75d25..2f722f16 100644 --- a/src/geom/mod.rs +++ b/src/geom/mod.rs @@ -16,7 +16,6 @@ mod point; mod relative; mod scalar; mod sides; -mod size; mod spec; mod transform; @@ -34,7 +33,6 @@ pub use point::*; pub use relative::*; pub use scalar::*; pub use sides::*; -pub use size::*; pub use spec::*; pub use transform::*; diff --git a/src/geom/path.rs b/src/geom/path.rs index 20519cb3..87e20dd1 100644 --- a/src/geom/path.rs +++ b/src/geom/path.rs @@ -26,9 +26,9 @@ impl Path { let point = Point::new; let mut path = Self::new(); path.move_to(point(z, z)); - path.line_to(point(size.w, z)); - path.line_to(point(size.w, size.h)); - path.line_to(point(z, size.h)); + path.line_to(point(size.x, z)); + path.line_to(point(size.x, size.y)); + path.line_to(point(z, size.y)); path.close_path(); path } @@ -37,8 +37,8 @@ impl Path { pub fn ellipse(size: Size) -> Self { // https://stackoverflow.com/a/2007782 let z = Length::zero(); - let rx = size.w / 2.0; - let ry = size.h / 2.0; + let rx = size.x / 2.0; + let ry = size.y / 2.0; let m = 0.551784; let mx = m * rx; let my = m * ry; diff --git a/src/geom/scalar.rs b/src/geom/scalar.rs index 6536e23a..066246a9 100644 --- a/src/geom/scalar.rs +++ b/src/geom/scalar.rs @@ -2,7 +2,7 @@ use super::*; /// A 64-bit float that implements `Eq`, `Ord` and `Hash`. /// -/// Panics if its `NaN` during any of those operations. +/// Panics if it's `NaN` during any of those operations. #[derive(Default, Copy, Clone, Serialize, Deserialize)] #[serde(transparent)] pub struct Scalar(pub f64); diff --git a/src/geom/sides.rs b/src/geom/sides.rs index 83407ad6..c0929fc7 100644 --- a/src/geom/sides.rs +++ b/src/geom/sides.rs @@ -33,11 +33,13 @@ impl<T> Sides<T> { } } -impl Sides<Length> { - /// A size with `left` and `right` summed into `width`, and `top` and - /// `bottom` summed into `height`. - pub fn size(self) -> Size { - Size::new(self.left + self.right, self.top + self.bottom) +impl<T> Sides<T> +where + T: Add, +{ + /// Sums up `left` and `right` into `x`, and `top` and `bottom` into `y`. + pub fn sum_by_axis(self) -> Spec<T::Output> { + Spec::new(self.left + self.right, self.top + self.bottom) } } @@ -45,10 +47,10 @@ impl Sides<Linear> { /// Resolve the linear sides relative to the given `size`. pub fn resolve(self, size: Size) -> Sides<Length> { Sides { - left: self.left.resolve(size.w), - top: self.top.resolve(size.h), - right: self.right.resolve(size.w), - bottom: self.bottom.resolve(size.h), + left: self.left.resolve(size.x), + top: self.top.resolve(size.y), + right: self.right.resolve(size.x), + bottom: self.bottom.resolve(size.y), } } } diff --git a/src/geom/size.rs b/src/geom/size.rs deleted file mode 100644 index 1c049425..00000000 --- a/src/geom/size.rs +++ /dev/null @@ -1,131 +0,0 @@ -use super::*; - -/// A size in 2D. -#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] -pub struct Size { - /// The width. - pub w: Length, - /// The height. - pub h: Length, -} - -impl Size { - /// The zero size. - pub const fn zero() -> Self { - Self { w: Length::zero(), h: Length::zero() } - } - - /// Create a new size from width and height. - pub const fn new(w: Length, h: Length) -> Self { - Self { w, h } - } - - /// Create an instance with two equal components. - pub const fn splat(v: Length) -> Self { - Self { w: v, h: v } - } - - /// Whether the other size fits into this one (smaller width and height). - pub fn fits(self, other: Self) -> bool { - self.w.fits(other.w) && self.h.fits(other.h) - } - - /// Whether both components are finite. - pub fn is_finite(self) -> bool { - self.w.is_finite() && self.h.is_finite() - } - - /// Whether any of the two components is infinite. - pub fn is_infinite(self) -> bool { - self.w.is_infinite() || self.h.is_infinite() - } - - /// Convert to a point. - pub const fn to_point(self) -> Point { - Point::new(self.w, self.h) - } - - /// Convert to a Spec. - pub const fn to_spec(self) -> Spec<Length> { - Spec::new(self.w, self.h) - } - - /// Convert to the generic representation. - pub const fn to_gen(self, main: SpecAxis) -> Gen<Length> { - match main { - SpecAxis::Horizontal => Gen::new(self.h, self.w), - SpecAxis::Vertical => Gen::new(self.w, self.h), - } - } -} - -impl Get<SpecAxis> for Size { - type Component = Length; - - fn get(self, axis: SpecAxis) -> Length { - match axis { - SpecAxis::Horizontal => self.w, - SpecAxis::Vertical => self.h, - } - } - - fn get_mut(&mut self, axis: SpecAxis) -> &mut Length { - match axis { - SpecAxis::Horizontal => &mut self.w, - SpecAxis::Vertical => &mut self.h, - } - } -} - -impl Debug for Size { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "Size({:?}, {:?})", self.w, self.h) - } -} - -impl Neg for Size { - type Output = Self; - - fn neg(self) -> Self { - Self { w: -self.w, h: -self.h } - } -} - -impl Add for Size { - type Output = Self; - - fn add(self, other: Self) -> Self { - Self { w: self.w + other.w, h: self.h + other.h } - } -} - -sub_impl!(Size - Size -> Size); - -impl Mul<f64> for Size { - type Output = Self; - - fn mul(self, other: f64) -> Self { - Self { w: self.w * other, h: self.h * other } - } -} - -impl Mul<Size> for f64 { - type Output = Size; - - fn mul(self, other: Size) -> Size { - other * self - } -} - -impl Div<f64> for Size { - type Output = Self; - - fn div(self, other: f64) -> Self { - Self { w: self.w / other, h: self.h / other } - } -} - -assign_impl!(Size -= Size); -assign_impl!(Size += Size); -assign_impl!(Size *= f64); -assign_impl!(Size /= f64); diff --git a/src/geom/spec.rs b/src/geom/spec.rs index 608643d8..640d6231 100644 --- a/src/geom/spec.rs +++ b/src/geom/spec.rs @@ -1,7 +1,10 @@ +use std::any::Any; +use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not}; + use super::*; /// A container with a horizontal and vertical component. -#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct Spec<T> { /// The horizontal component. pub x: T, @@ -31,9 +34,18 @@ impl<T> Spec<T> { Spec { x: f(self.x), y: f(self.y) } } + /// Convert from `&Spec<T>` to `Spec<&T>`. + pub fn as_ref(&self) -> Spec<&T> { + Spec { x: &self.x, y: &self.y } + } + + /// Convert from `&mut Spec<T>` to `Spec<&mut T>`. + pub fn as_mut(&mut self) -> Spec<&mut T> { + Spec { x: &mut self.x, y: &mut self.y } + } + /// Zip two instances into an instance over a tuple. - pub fn zip<U>(self, other: impl Into<Spec<U>>) -> Spec<(T, U)> { - let other = other.into(); + pub fn zip<U>(self, other: Spec<U>) -> Spec<(T, U)> { Spec { x: (self.x, other.x), y: (self.y, other.y), @@ -56,6 +68,14 @@ impl<T> Spec<T> { f(&self.x) && f(&self.y) } + /// Filter the individual fields with a mask. + pub fn filter(self, mask: Spec<bool>) -> Spec<Option<T>> { + Spec { + x: if mask.x { Some(self.x) } else { None }, + y: if mask.y { Some(self.y) } else { None }, + } + } + /// Convert to the generic representation. pub fn to_gen(self, main: SpecAxis) -> Gen<T> { match main { @@ -65,39 +85,6 @@ impl<T> Spec<T> { } } -impl From<Size> for Spec<Length> { - fn from(size: Size) -> Self { - size.to_spec() - } -} - -impl Spec<Length> { - /// The zero value. - pub fn zero() -> Self { - Self { x: Length::zero(), y: Length::zero() } - } - - /// Convert to a point. - pub fn to_point(self) -> Point { - Point::new(self.x, self.y) - } - - /// Convert to a size. - pub fn to_size(self) -> Size { - Size::new(self.x, self.y) - } -} - -impl<T> Spec<Option<T>> { - /// Unwrap the individual fields. - pub fn unwrap_or(self, other: Spec<T>) -> Spec<T> { - Spec { - x: self.x.unwrap_or(other.x), - y: self.y.unwrap_or(other.y), - } - } -} - impl<T> Get<SpecAxis> for Spec<T> { type Component = T; @@ -116,9 +103,20 @@ impl<T> Get<SpecAxis> for Spec<T> { } } -impl<T: Debug> Debug for Spec<T> { +impl<T> Debug for Spec<T> +where + T: Debug + 'static, +{ fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "Spec({:?}, {:?})", self.x, self.y) + if let Spec { x: Some(x), y: Some(y) } = + self.as_ref().map(|v| (v as &dyn Any).downcast_ref::<Align>()) + { + write!(f, "{:?}-{:?}", x, y) + } else if (&self.x as &dyn Any).is::<Length>() { + write!(f, "Size({:?}, {:?})", self.x, self.y) + } else { + write!(f, "Spec({:?}, {:?})", self.x, self.y) + } } } @@ -159,3 +157,148 @@ impl Debug for SpecAxis { }) } } + +/// A size in 2D. +pub type Size = Spec<Length>; + +impl Size { + /// The zero value. + pub fn zero() -> Self { + Self { x: Length::zero(), y: Length::zero() } + } + + /// Whether the other size fits into this one (smaller width and height). + pub fn fits(self, other: Self) -> bool { + self.x.fits(other.x) && self.y.fits(other.y) + } + + /// Whether both components are finite. + pub fn is_finite(self) -> bool { + self.x.is_finite() && self.y.is_finite() + } + + /// Whether any of the two components is infinite. + pub fn is_infinite(self) -> bool { + self.x.is_infinite() || self.y.is_infinite() + } + + /// Convert to a point. + pub fn to_point(self) -> Point { + Point::new(self.x, self.y) + } +} + +impl Neg for Size { + type Output = Self; + + fn neg(self) -> Self { + Self { x: -self.x, y: -self.y } + } +} + +impl Add for Size { + type Output = Self; + + fn add(self, other: Self) -> Self { + Self { x: self.x + other.x, y: self.y + other.y } + } +} + +sub_impl!(Size - Size -> Size); + +impl Mul<f64> for Size { + type Output = Self; + + fn mul(self, other: f64) -> Self { + Self { x: self.x * other, y: self.y * other } + } +} + +impl Mul<Size> for f64 { + type Output = Size; + + fn mul(self, other: Size) -> Size { + other * self + } +} + +impl Div<f64> for Size { + type Output = Self; + + fn div(self, other: f64) -> Self { + Self { x: self.x / other, y: self.y / other } + } +} + +assign_impl!(Size -= Size); +assign_impl!(Size += Size); +assign_impl!(Size *= f64); +assign_impl!(Size /= f64); + +impl<T> Spec<Option<T>> { + /// Whether the individual fields are some. + pub fn map_is_some(&self) -> Spec<bool> { + self.as_ref().map(Option::is_some) + } + + /// Whether the individual fields are none. + pub fn map_is_none(&self) -> Spec<bool> { + self.as_ref().map(Option::is_none) + } + + /// Unwrap the individual fields. + pub fn unwrap_or(self, other: Spec<T>) -> Spec<T> { + Spec { + x: self.x.unwrap_or(other.x), + y: self.y.unwrap_or(other.y), + } + } +} + +impl Spec<bool> { + /// Select `t.x` if `self.x` is true and `f.x` otherwise and same for `y`. + pub fn select<T>(self, t: Spec<T>, f: Spec<T>) -> Spec<T> { + Spec { + x: if self.x { t.x } else { f.x }, + y: if self.y { t.y } else { f.y }, + } + } +} + +impl Not for Spec<bool> { + type Output = Self; + + fn not(self) -> Self::Output { + Self { x: !self.x, y: !self.y } + } +} + +impl BitOr for Spec<bool> { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self { x: self.x | rhs.x, y: self.y | rhs.y } + } +} + +impl BitAnd for Spec<bool> { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self::Output { + Self { x: self.x & rhs.x, y: self.y & rhs.y } + } +} + +impl BitOrAssign for Spec<bool> { + fn bitor_assign(&mut self, rhs: Self) { + self.x |= rhs.x; + self.y |= rhs.y; + } +} + +impl BitAndAssign for Spec<bool> { + fn bitand_assign(&mut self, rhs: Self) { + self.x &= rhs.x; + self.y &= rhs.y; + } +} |
