summaryrefslogtreecommitdiff
path: root/src/geom
diff options
context:
space:
mode:
Diffstat (limited to 'src/geom')
-rw-r--r--src/geom/gen.rs15
-rw-r--r--src/geom/linear.rs2
-rw-r--r--src/geom/mod.rs2
-rw-r--r--src/geom/path.rs10
-rw-r--r--src/geom/scalar.rs2
-rw-r--r--src/geom/sides.rs20
-rw-r--r--src/geom/size.rs131
-rw-r--r--src/geom/spec.rs219
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;
+ }
+}