Overload `*` between transforms and points

This commit is contained in:
Patrick Walton 2019-07-12 11:55:01 -07:00
parent 2c984de1ea
commit 437eda96da
8 changed files with 61 additions and 65 deletions

View File

@ -533,14 +533,14 @@ impl Contour {
}
for (point_index, point) in self.points.iter_mut().enumerate() {
*point = transform.transform_point(*point);
*point = *transform * *point;
union_rect(&mut self.bounds, *point, point_index == 0);
}
}
pub fn apply_perspective(&mut self, perspective: &Perspective) {
for (point_index, point) in self.points.iter_mut().enumerate() {
*point = perspective.transform_point_2d(*point);
*point = *perspective * *point;
union_rect(&mut self.bounds, *point, point_index == 0);
}
}

View File

@ -34,12 +34,12 @@ where
// TODO(pcwalton): Can we go faster by transforming an entire line segment with SIMD?
let mut segment = self.iter.next()?;
if !segment.is_none() {
segment.baseline.set_from(self.transform.transform_point(segment.baseline.from()));
segment.baseline.set_to(self.transform.transform_point(segment.baseline.to()));
segment.baseline.set_from(self.transform * segment.baseline.from());
segment.baseline.set_to(self.transform * segment.baseline.to());
if !segment.is_line() {
segment.ctrl.set_from(self.transform.transform_point(segment.ctrl.from()));
segment.ctrl.set_from(self.transform * segment.ctrl.from());
if !segment.is_quadratic() {
segment.ctrl.set_to(self.transform.transform_point(segment.ctrl.to()));
segment.ctrl.set_to(self.transform * segment.ctrl.to());
}
}
}
@ -79,14 +79,12 @@ where
fn next(&mut self) -> Option<Segment> {
let mut segment = self.iter.next()?;
if !segment.is_none() {
segment.baseline.set_from(
self.perspective.transform_point_2d(segment.baseline.from()),
);
segment.baseline.set_to(self.perspective.transform_point_2d(segment.baseline.to()));
segment.baseline.set_from(self.perspective * segment.baseline.from());
segment.baseline.set_to(self.perspective * segment.baseline.to());
if !segment.is_line() {
segment.ctrl.set_from(self.perspective.transform_point_2d(segment.ctrl.from()));
segment.ctrl.set_from(self.perspective * segment.ctrl.from());
if !segment.is_quadratic() {
segment.ctrl.set_to(self.perspective.transform_point_2d(segment.ctrl.to()));
segment.ctrl.set_to(self.perspective * segment.ctrl.to());
}
}
}

View File

@ -147,7 +147,7 @@ impl CameraTransform3D {
let update = !vector.is_zero();
if update {
let rotation = Transform4F::from_rotation(-self.yaw, -self.pitch, 0.0);
self.position = self.position + rotation.transform_point(vector);
self.position = self.position + rotation * vector;
}
update
}

View File

@ -232,7 +232,7 @@ impl LineSegment2F {
if f32::abs(matrix.det()) < EPSILON {
return None;
}
return Some(matrix.inverse().transform_point(self.from() - other.from()).y());
return Some((matrix.inverse() * (self.from() - other.from())).y());
const EPSILON: f32 = 0.0001;
}

View File

@ -60,12 +60,6 @@ impl Matrix2x2F {
Matrix2x2F(self.0.wyzx() * F32x4::new(1.0, -1.0, -1.0, 1.0))
}
#[inline]
pub fn transform_point(&self, point: Vector2F) -> Vector2F {
let halves = self.0 * point.0.to_f32x4().xxyy();
Vector2F(halves.xy() + halves.zw())
}
#[inline]
pub fn det(&self) -> f32 {
self.0[0] * self.0[3] - self.0[2] * self.0[1]
@ -110,6 +104,15 @@ impl Mul<Matrix2x2F> for Matrix2x2F {
}
}
impl Mul<Vector2F> for Matrix2x2F {
type Output = Vector2F;
#[inline]
fn mul(self, vector: Vector2F) -> Vector2F {
let halves = self.0 * vector.0.to_f32x4().xxyy();
Vector2F(halves.xy() + halves.zw())
}
}
/// An affine transform, optimized with SIMD.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform2F {
@ -179,23 +182,15 @@ impl Transform2F {
}
}
#[inline]
pub fn transform_point(&self, point: Vector2F) -> Vector2F {
self.matrix.transform_point(point) + self.vector
}
#[inline]
pub fn transform_line_segment(&self, line_segment: LineSegment2F) -> LineSegment2F {
LineSegment2F::new(self.transform_point(line_segment.from()),
self.transform_point(line_segment.to()))
LineSegment2F::new(*self * line_segment.from(), *self * line_segment.to())
}
#[inline]
pub fn transform_rect(&self, rect: &RectF) -> RectF {
let upper_left = self.transform_point(rect.origin());
let upper_right = self.transform_point(rect.upper_right());
let lower_left = self.transform_point(rect.lower_left());
let lower_right = self.transform_point(rect.lower_right());
let (upper_left, upper_right) = (*self * rect.origin(), *self * rect.upper_right());
let (lower_left, lower_right) = (*self * rect.lower_left(), *self * rect.lower_right());
let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right);
let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
RectF::from_points(min_point, max_point)
@ -297,11 +292,19 @@ impl Mul<Transform2F> for Transform2F {
fn mul(self, other: Transform2F) -> Transform2F {
Transform2F {
matrix: self.matrix * other.matrix,
vector: self.transform_point(other.vector),
vector: self * other.vector,
}
}
}
impl Mul<Vector2F> for Transform2F {
type Output = Vector2F;
#[inline]
fn mul(self, vector: Vector2F) -> Vector2F {
self.matrix * vector + self.vector
}
}
impl MulAssign for Transform2F {
#[inline]
fn mul_assign(&mut self, other: Transform2F) {

View File

@ -240,15 +240,6 @@ impl Transform4F {
Transform4F::from_translation(translation) * *self
}
#[inline]
pub fn transform_point(&self, point: Vector4F) -> Vector4F {
let term0 = self.c0 * F32x4::splat(point.x());
let term1 = self.c1 * F32x4::splat(point.y());
let term2 = self.c2 * F32x4::splat(point.z());
let term3 = self.c3 * F32x4::splat(point.w());
Vector4F(term0 + term1 + term2 + term3)
}
#[inline]
pub fn upper_left(&self) -> Matrix2x2F {
Matrix2x2F(self.c0.concat_xy_xy(self.c1))
@ -330,6 +321,19 @@ impl Mul<Transform4F> for Transform4F {
}
}
impl Mul<Vector4F> for Transform4F {
type Output = Vector4F;
#[inline]
fn mul(self, vector: Vector4F) -> Vector4F {
let term0 = self.c0 * F32x4::splat(vector.x());
let term1 = self.c1 * F32x4::splat(vector.y());
let term2 = self.c2 * F32x4::splat(vector.z());
let term3 = self.c3 * F32x4::splat(vector.w());
Vector4F(term0 + term1 + term2 + term3)
}
}
impl MulAssign<Transform4F> for Transform4F {
fn mul_assign(&mut self, other: Transform4F) {
*self = *self * other
@ -367,24 +371,10 @@ impl Perspective {
}
}
#[inline]
pub fn transform_point_2d(&self, point: Vector2F) -> Vector2F {
let point = self
.transform
.transform_point(point.to_3d())
.perspective_divide()
.to_2d()
* Vector2F::new(1.0, -1.0);
(point + Vector2F::splat(1.0)) * self.window_size.to_f32().scale(0.5)
}
// TODO(pcwalton): SIMD?
#[inline]
pub fn transform_rect(&self, rect: RectF) -> RectF {
let upper_left = self.transform_point_2d(rect.origin());
let upper_right = self.transform_point_2d(rect.upper_right());
let lower_left = self.transform_point_2d(rect.lower_left());
let lower_right = self.transform_point_2d(rect.lower_right());
let (upper_left, upper_right) = (*self * rect.origin(), *self * rect.upper_right());
let (lower_left, lower_right) = (*self * rect.lower_left(), *self * rect.lower_right());
let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right);
let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
RectF::from_points(min_point, max_point)
@ -402,6 +392,16 @@ impl Mul<Transform4F> for Perspective {
}
}
impl Mul<Vector2F> for Perspective {
type Output = Vector2F;
#[inline]
fn mul(self, vector: Vector2F) -> Vector2F {
let point = (self.transform * vector.to_3d()).perspective_divide().to_2d() *
Vector2F::new(1.0, -1.0);
(point + Vector2F::splat(1.0)) * self.window_size.to_f32().scale(0.5)
}
}
#[cfg(test)]
mod test {
use crate::vector::Vector4F;

View File

@ -83,7 +83,7 @@ impl RenderTransform {
debug!("-----");
debug!("bounds={:?} ORIGINAL quad={:?}", bounds, points);
for point in &mut points {
*point = perspective.transform.transform_point(*point);
*point = perspective.transform * *point;
}
debug!("... PERSPECTIVE quad={:?}", points);
@ -105,12 +105,7 @@ impl RenderTransform {
let inverse_transform = perspective.transform.inverse();
let clip_polygon = points
.into_iter()
.map(|point| {
inverse_transform
.transform_point(point)
.perspective_divide()
.to_2d()
})
.map(|point| (inverse_transform * point).perspective_divide().to_2d())
.collect();
return PreparedRenderTransform::Perspective {
perspective,

View File

@ -147,7 +147,7 @@ impl OutlinePathBuilder {
}
fn convert_point(&self, point: Point2D<f32>) -> Vector2F {
self.transform.transform_point(Vector2F::new(point.x, point.y))
self.transform * Vector2F::new(point.x, point.y)
}
}