diff options
| author | Laurenz <laurmaedje@gmail.com> | 2021-11-23 22:04:08 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2021-11-23 22:04:08 +0100 |
| commit | 8a88f71cb11565c1a78bd57f02a8df17cb2bf7a0 (patch) | |
| tree | 8802c1ff48e2be118e3872d25bd2f2c1f7a21b4a /src/geom | |
| parent | c77c5a0f0ae6560a03a85e847006c29de9c7ae62 (diff) | |
Transformations
Diffstat (limited to 'src/geom')
| -rw-r--r-- | src/geom/mod.rs | 2 | ||||
| -rw-r--r-- | src/geom/point.rs | 18 | ||||
| -rw-r--r-- | src/geom/relative.rs | 10 | ||||
| -rw-r--r-- | src/geom/transform.rs | 73 |
4 files changed, 103 insertions, 0 deletions
diff --git a/src/geom/mod.rs b/src/geom/mod.rs index c763e8fa..b0c75d25 100644 --- a/src/geom/mod.rs +++ b/src/geom/mod.rs @@ -18,6 +18,7 @@ mod scalar; mod sides; mod size; mod spec; +mod transform; pub use align::*; pub use angle::*; @@ -35,6 +36,7 @@ pub use scalar::*; pub use sides::*; pub use size::*; pub use spec::*; +pub use transform::*; use std::cmp::Ordering; use std::f64::consts::PI; diff --git a/src/geom/point.rs b/src/geom/point.rs index 7c11e81b..49e3018a 100644 --- a/src/geom/point.rs +++ b/src/geom/point.rs @@ -25,6 +25,16 @@ impl Point { Self { x: value, y: value } } + /// Create a new point with y set to zero. + pub const fn with_x(x: Length) -> Self { + Self { x, y: Length::zero() } + } + + /// Create a new point with x set to zero. + pub const fn with_y(y: Length) -> Self { + Self { x: Length::zero(), y } + } + /// Convert to the generic representation. pub const fn to_gen(self, block: SpecAxis) -> Gen<Length> { match block { @@ -32,6 +42,14 @@ impl Point { SpecAxis::Vertical => Gen::new(self.x, self.y), } } + + /// Transform the point with the given transformation. + pub fn transform(self, transform: Transform) -> Self { + Self::new( + transform.sx.resolve(self.x) + transform.kx.resolve(self.y) + transform.tx, + transform.ky.resolve(self.x) + transform.sy.resolve(self.y) + transform.ty, + ) + } } impl Get<SpecAxis> for Point { diff --git a/src/geom/relative.rs b/src/geom/relative.rs index 463c5d46..c894f4a5 100644 --- a/src/geom/relative.rs +++ b/src/geom/relative.rs @@ -5,6 +5,7 @@ use super::*; /// _Note_: `50%` is represented as `0.5` here, but stored as `50.0` in the /// corresponding [literal](crate::syntax::ast::LitKind::Percent). #[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Serialize, Deserialize)] pub struct Relative(Scalar); impl Relative { @@ -73,6 +74,14 @@ impl Add for Relative { sub_impl!(Relative - Relative -> Relative); +impl Mul for Relative { + type Output = Self; + + fn mul(self, other: Self) -> Self { + Self(self.0 * other.0) + } +} + impl Mul<f64> for Relative { type Output = Self; @@ -107,5 +116,6 @@ impl Div for Relative { assign_impl!(Relative += Relative); assign_impl!(Relative -= Relative); +assign_impl!(Relative *= Relative); assign_impl!(Relative *= f64); assign_impl!(Relative /= f64); diff --git a/src/geom/transform.rs b/src/geom/transform.rs new file mode 100644 index 00000000..ca44667b --- /dev/null +++ b/src/geom/transform.rs @@ -0,0 +1,73 @@ +use super::*; + +/// A scale-skew-translate transformation. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub struct Transform { + pub sx: Relative, + pub ky: Relative, + pub kx: Relative, + pub sy: Relative, + pub tx: Length, + pub ty: Length, +} + +impl Transform { + /// The identity transformation. + pub const fn identity() -> Self { + Self { + sx: Relative::one(), + ky: Relative::zero(), + kx: Relative::zero(), + sy: Relative::one(), + tx: Length::zero(), + ty: Length::zero(), + } + } + + /// A translation transform. + pub const fn translation(tx: Length, ty: Length) -> Self { + Self { tx, ty, ..Self::identity() } + } + + /// A scaling transform. + pub const fn scaling(sx: Relative, sy: Relative) -> Self { + Self { sx, sy, ..Self::identity() } + } + + /// A rotation transform. + pub fn rotation(angle: Angle) -> Self { + let v = angle.to_rad(); + let cos = Relative::new(v.cos()); + let sin = Relative::new(v.sin()); + Self { + sx: cos, + ky: sin, + kx: -sin, + sy: cos, + ..Self::default() + } + } + + /// Whether this is the identity transformation. + pub fn is_identity(&self) -> bool { + *self == Self::identity() + } + + /// Pre-concatenate another transformation. + pub fn pre_concat(&self, prev: Self) -> Self { + Transform { + sx: self.sx * prev.sx + self.kx * prev.ky, + ky: self.ky * prev.sx + self.sy * prev.ky, + kx: self.sx * prev.kx + self.kx * prev.sy, + sy: self.ky * prev.kx + self.sy * prev.sy, + tx: self.sx.resolve(prev.tx) + self.kx.resolve(prev.ty) + self.tx, + ty: self.ky.resolve(prev.tx) + self.sy.resolve(prev.ty) + self.ty, + } + } +} + +impl Default for Transform { + fn default() -> Self { + Self::identity() + } +} |
