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() { 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); union_rect(&mut self.bounds, *point, point_index == 0);
} }
} }
pub fn apply_perspective(&mut self, perspective: &Perspective) { pub fn apply_perspective(&mut self, perspective: &Perspective) {
for (point_index, point) in self.points.iter_mut().enumerate() { 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); 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? // TODO(pcwalton): Can we go faster by transforming an entire line segment with SIMD?
let mut segment = self.iter.next()?; let mut segment = self.iter.next()?;
if !segment.is_none() { if !segment.is_none() {
segment.baseline.set_from(self.transform.transform_point(segment.baseline.from())); segment.baseline.set_from(self.transform * segment.baseline.from());
segment.baseline.set_to(self.transform.transform_point(segment.baseline.to())); segment.baseline.set_to(self.transform * segment.baseline.to());
if !segment.is_line() { 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() { 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> { fn next(&mut self) -> Option<Segment> {
let mut segment = self.iter.next()?; let mut segment = self.iter.next()?;
if !segment.is_none() { if !segment.is_none() {
segment.baseline.set_from( segment.baseline.set_from(self.perspective * segment.baseline.from());
self.perspective.transform_point_2d(segment.baseline.from()), segment.baseline.set_to(self.perspective * segment.baseline.to());
);
segment.baseline.set_to(self.perspective.transform_point_2d(segment.baseline.to()));
if !segment.is_line() { 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() { 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(); let update = !vector.is_zero();
if update { if update {
let rotation = Transform4F::from_rotation(-self.yaw, -self.pitch, 0.0); 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 update
} }

View File

@ -232,7 +232,7 @@ impl LineSegment2F {
if f32::abs(matrix.det()) < EPSILON { if f32::abs(matrix.det()) < EPSILON {
return None; 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; 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)) 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] #[inline]
pub fn det(&self) -> f32 { pub fn det(&self) -> f32 {
self.0[0] * self.0[3] - self.0[2] * self.0[1] 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. /// An affine transform, optimized with SIMD.
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform2F { 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] #[inline]
pub fn transform_line_segment(&self, line_segment: LineSegment2F) -> LineSegment2F { pub fn transform_line_segment(&self, line_segment: LineSegment2F) -> LineSegment2F {
LineSegment2F::new(self.transform_point(line_segment.from()), LineSegment2F::new(*self * line_segment.from(), *self * line_segment.to())
self.transform_point(line_segment.to()))
} }
#[inline] #[inline]
pub fn transform_rect(&self, rect: &RectF) -> RectF { pub fn transform_rect(&self, rect: &RectF) -> RectF {
let upper_left = self.transform_point(rect.origin()); let (upper_left, upper_right) = (*self * rect.origin(), *self * rect.upper_right());
let upper_right = self.transform_point(rect.upper_right()); let (lower_left, lower_right) = (*self * rect.lower_left(), *self * rect.lower_right());
let lower_left = self.transform_point(rect.lower_left());
let lower_right = self.transform_point(rect.lower_right());
let min_point = upper_left.min(upper_right).min(lower_left).min(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); let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
RectF::from_points(min_point, max_point) RectF::from_points(min_point, max_point)
@ -297,11 +292,19 @@ impl Mul<Transform2F> for Transform2F {
fn mul(self, other: Transform2F) -> Transform2F { fn mul(self, other: Transform2F) -> Transform2F {
Transform2F { Transform2F {
matrix: self.matrix * other.matrix, 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 { impl MulAssign for Transform2F {
#[inline] #[inline]
fn mul_assign(&mut self, other: Transform2F) { fn mul_assign(&mut self, other: Transform2F) {

View File

@ -240,15 +240,6 @@ impl Transform4F {
Transform4F::from_translation(translation) * *self 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] #[inline]
pub fn upper_left(&self) -> Matrix2x2F { pub fn upper_left(&self) -> Matrix2x2F {
Matrix2x2F(self.c0.concat_xy_xy(self.c1)) 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 { impl MulAssign<Transform4F> for Transform4F {
fn mul_assign(&mut self, other: Transform4F) { fn mul_assign(&mut self, other: Transform4F) {
*self = *self * other *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] #[inline]
pub fn transform_rect(&self, rect: RectF) -> RectF { pub fn transform_rect(&self, rect: RectF) -> RectF {
let upper_left = self.transform_point_2d(rect.origin()); let (upper_left, upper_right) = (*self * rect.origin(), *self * rect.upper_right());
let upper_right = self.transform_point_2d(rect.upper_right()); let (lower_left, lower_right) = (*self * rect.lower_left(), *self * rect.lower_right());
let lower_left = self.transform_point_2d(rect.lower_left());
let lower_right = self.transform_point_2d(rect.lower_right());
let min_point = upper_left.min(upper_right).min(lower_left).min(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); let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right);
RectF::from_points(min_point, max_point) 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)] #[cfg(test)]
mod test { mod test {
use crate::vector::Vector4F; use crate::vector::Vector4F;

View File

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

View File

@ -147,7 +147,7 @@ impl OutlinePathBuilder {
} }
fn convert_point(&self, point: Point2D<f32>) -> Vector2F { 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)
} }
} }