summaryrefslogtreecommitdiff
path: root/src/geom
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-11-23 22:04:08 +0100
committerLaurenz <laurmaedje@gmail.com>2021-11-23 22:04:08 +0100
commit8a88f71cb11565c1a78bd57f02a8df17cb2bf7a0 (patch)
tree8802c1ff48e2be118e3872d25bd2f2c1f7a21b4a /src/geom
parentc77c5a0f0ae6560a03a85e847006c29de9c7ae62 (diff)
Transformations
Diffstat (limited to 'src/geom')
-rw-r--r--src/geom/mod.rs2
-rw-r--r--src/geom/point.rs18
-rw-r--r--src/geom/relative.rs10
-rw-r--r--src/geom/transform.rs73
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()
+ }
+}