diff --git a/geometry/src/transform.rs b/geometry/src/transform.rs index e3c75f3e..7f802f04 100644 --- a/geometry/src/transform.rs +++ b/geometry/src/transform.rs @@ -10,9 +10,66 @@ //! Applies a transform to paths. +use crate::point::Point2DF32; +use crate::simd::F32x4; use euclid::Transform2D; use lyon_path::PathEvent; +/// An affine transform, optimized with SIMD. +#[derive(Clone, Copy)] +pub struct Transform2DF32 { + // Row-major order. + matrix: F32x4, + vector: Point2DF32, +} + +impl Default for Transform2DF32 { + #[inline] + fn default() -> Transform2DF32 { + Self::from_scale(&Point2DF32::splat(1.0)) + } +} + +impl Transform2DF32 { + #[inline] + pub fn from_scale(scale: &Point2DF32) -> Transform2DF32 { + Transform2DF32 { + matrix: F32x4::new(scale.x(), 0.0, 0.0, scale.y()), + vector: Point2DF32::default(), + } + } + + #[inline] + pub fn row_major(m11: f32, m12: f32, m21: f32, m22: f32, m31: f32, m32: f32) + -> Transform2DF32 { + Transform2DF32 { + matrix: F32x4::new(m11, m12, m21, m22), + vector: Point2DF32::new(m31, m32), + } + } + + #[inline] + pub fn transform_point(&self, point: &Point2DF32) -> Point2DF32 { + let x11x12y21y22 = point.0.xxyy() * self.matrix; + Point2DF32(x11x12y21y22 + x11x12y21y22.zwzw() + self.vector.0) + } + + #[inline] + pub fn post_mul(&self, other: &Transform2DF32) -> Transform2DF32 { + let lhs = self.matrix.xzxz() * other.matrix.xxyy(); + let rhs = self.matrix.ywyw() * other.matrix.zzww(); + let matrix = lhs + rhs; + let vector = other.transform_point(&self.vector) + other.vector; + Transform2DF32 { matrix, vector } + } + + #[inline] + pub fn pre_mul(&self, other: &Transform2DF32) -> Transform2DF32 { + other.post_mul(self) + } +} + +/// Transforms a path with a Euclid 2D transform. pub struct Transform2DPathIter where I: Iterator { inner: I, transform: Transform2D, diff --git a/utils/tile-svg/src/main.rs b/utils/tile-svg/src/main.rs index 1b1db8ef..a9fe46b2 100644 --- a/utils/tile-svg/src/main.rs +++ b/utils/tile-svg/src/main.rs @@ -30,6 +30,7 @@ use pathfinder_geometry::point::Point2DF32; use pathfinder_geometry::segment::{Segment, SegmentFlags, SegmentKind}; use pathfinder_geometry::simd::{F32x4, I32x4}; use pathfinder_geometry::stroke::{StrokeStyle, StrokeToFillIter}; +use pathfinder_geometry::transform::Transform2DF32; use pathfinder_geometry::util; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use rayon::ThreadPoolBuilder; @@ -1815,56 +1816,6 @@ impl PartialOrd for ActiveEdge { } } -// Geometry - -// Affine transforms - -#[derive(Clone, Copy)] -struct Transform2DF32 { - // Row-major order. - matrix: F32x4, - vector: Point2DF32, -} - -impl Default for Transform2DF32 { - fn default() -> Transform2DF32 { - Self::from_scale(&Point2DF32::splat(1.0)) - } -} - -impl Transform2DF32 { - fn from_scale(scale: &Point2DF32) -> Transform2DF32 { - Transform2DF32 { - matrix: F32x4::new(scale.x(), 0.0, 0.0, scale.y()), - vector: Point2DF32::default(), - } - } - - fn row_major(m11: f32, m12: f32, m21: f32, m22: f32, m31: f32, m32: f32) -> Transform2DF32 { - Transform2DF32 { - matrix: F32x4::new(m11, m12, m21, m22), - vector: Point2DF32::new(m31, m32), - } - } - - fn transform_point(&self, point: &Point2DF32) -> Point2DF32 { - let x11x12y21y22 = point.0.xxyy() * self.matrix; - Point2DF32(x11x12y21y22 + x11x12y21y22.zwzw() + self.vector.0) - } - - fn post_mul(&self, other: &Transform2DF32) -> Transform2DF32 { - let lhs = self.matrix.xzxz() * other.matrix.xxyy(); - let rhs = self.matrix.ywyw() * other.matrix.zzww(); - let matrix = lhs + rhs; - let vector = other.transform_point(&self.vector) + other.vector; - Transform2DF32 { matrix, vector } - } - - fn pre_mul(&self, other: &Transform2DF32) -> Transform2DF32 { - other.post_mul(self) - } -} - // Testing #[cfg(test)]