From 4580b530a8372cc24410d505c900fa678df143d9 Mon Sep 17 00:00:00 2001 From: Boris Chiou Date: Thu, 24 Aug 2017 13:41:09 +0800 Subject: [PATCH] Use DirectionVector as an alias of euclid::Vector3D. Therefore, we can reuse the methods of Vector3D, instead of implementing similar ones. --- .../helpers/animated_properties.mako.rs | 20 ++--- components/style/values/computed/transform.rs | 73 ++++++------------- 2 files changed, 32 insertions(+), 61 deletions(-) diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index ba94a96009e..f8437e3b605 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -1107,7 +1107,7 @@ impl ToAnimatedZero for TransformOperation { Ok(TransformOperation::Scale(1.0, 1.0, 1.0)) }, TransformOperation::Rotate(x, y, z, a) => { - let (x, y, z, _) = DirectionVector::get_normalized_vector_and_angle(x, y, z, a); + let (x, y, z, _) = TransformList::get_normalized_vector_and_angle(x, y, z, a); Ok(TransformOperation::Rotate(x, y, z, Angle::zero())) }, TransformOperation::Perspective(..) | @@ -1185,9 +1185,9 @@ impl Animate for TransformOperation { &TransformOperation::Rotate(tx, ty, tz, ta), ) => { let (fx, fy, fz, fa) = - DirectionVector::get_normalized_vector_and_angle(fx, fy, fz, fa); + TransformList::get_normalized_vector_and_angle(fx, fy, fz, fa); let (tx, ty, tz, ta) = - DirectionVector::get_normalized_vector_and_angle(tx, ty, tz, ta); + TransformList::get_normalized_vector_and_angle(tx, ty, tz, ta); if (fx, fy, fz) == (tx, ty, tz) { let ia = fa.animate(&ta, procedure)?; Ok(TransformOperation::Rotate(fx, fy, fz, ia)) @@ -1604,8 +1604,8 @@ impl Quaternion { /// Return a quaternion from a unit direction vector and angle (unit: radian). #[inline] fn from_direction_and_angle(vector: &DirectionVector, angle: f64) -> Self { - debug_assert!((vector.length() - 1.).abs() < 0.0001f64, - "Only accept an unit direction vector to create a quaternion"); + debug_assert!((vector.length() - 1.).abs() < 0.0001, + "Only accept an unit direction vector to create a quaternion"); // Reference: // https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation // @@ -1615,9 +1615,9 @@ impl Quaternion { // q = cos(theta/2) + (xi + yj + zk)(sin(theta/2)) // = cos(theta/2) + // x*sin(theta/2)i + y*sin(theta/2)j + z*sin(theta/2)k - Quaternion(vector.0.x * (angle / 2.).sin(), - vector.0.y * (angle / 2.).sin(), - vector.0.z * (angle / 2.).sin(), + Quaternion(vector.x as f64 * (angle / 2.).sin(), + vector.y as f64 * (angle / 2.).sin(), + vector.z as f64 * (angle / 2.).sin(), (angle / 2.).cos()) } @@ -2304,9 +2304,9 @@ impl ComputeSquaredDistance for TransformOperation { &TransformOperation::Rotate(tx, ty, tz, ta), ) => { let (fx, fy, fz, angle1) = - DirectionVector::get_normalized_vector_and_angle(fx, fy, fz, fa); + TransformList::get_normalized_vector_and_angle(fx, fy, fz, fa); let (tx, ty, tz, angle2) = - DirectionVector::get_normalized_vector_and_angle(tx, ty, tz, ta); + TransformList::get_normalized_vector_and_angle(tx, ty, tz, ta); if (fx, fy, fz) == (tx, ty, tz) { angle1.compute_squared_distance(&angle2) } else { diff --git a/components/style/values/computed/transform.rs b/components/style/values/computed/transform.rs index 6b6a94d19ca..02de6298444 100644 --- a/components/style/values/computed/transform.rs +++ b/components/style/values/computed/transform.rs @@ -5,7 +5,7 @@ //! Computed types for CSS values that are related to transformations. use app_units::Au; -use euclid::{Point3D, Rect, Transform3D}; +use euclid::{Rect, Transform3D, Vector3D}; use properties::longhands::transform::computed_value::{ComputedOperation, ComputedMatrix}; use properties::longhands::transform::computed_value::T as TransformList; use std::f32; @@ -20,6 +20,9 @@ pub type TransformOrigin = GenericTransformOrigin; +/// A vector to represent the direction vector (rotate axis) for Rotate3D. +pub type DirectionVector = Vector3D; + impl TransformOrigin { /// Returns the initial computed value for `transform-origin`. #[inline] @@ -32,52 +35,6 @@ impl TransformOrigin { } } -/// A wrapper of Point3D to represent the direction vector (rotate axis) for Rotate3D. -#[derive(Clone, Copy, Debug, PartialEq)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub struct DirectionVector(pub Point3D); - -impl DirectionVector { - /// Create a DirectionVector. - #[inline] - pub fn new(x: f32, y: f32, z: f32) -> Self { - DirectionVector(Point3D::new(x as f64, y as f64, z as f64)) - } - - /// Return the normalized direction vector. - #[inline] - pub fn normalize(&mut self) -> bool { - let len = self.length(); - if len > 0. { - self.0.x = self.0.x / len; - self.0.y = self.0.y / len; - self.0.z = self.0.z / len; - true - } else { - false - } - } - - /// Get the length of this vector. - #[inline] - pub fn length(&self) -> f64 { - self.0.to_array().iter().fold(0f64, |sum, v| sum + v * v).sqrt() - } - - /// Return the normalized direction vector and its angle. - /// A direction vector that cannot be normalized, such as [0,0,0], will cause the - /// rotation to not be applied. i.e. Use an identity matrix or rotate3d(0, 0, 1, 0). - pub fn get_normalized_vector_and_angle(x: f32, y: f32, z: f32, angle: Angle) - -> (f32, f32, f32, Angle) { - let mut vector = DirectionVector::new(x, y, z); - if vector.normalize() { - (vector.0.x as f32, vector.0.y as f32, vector.0.z as f32, angle) - } else { - (0., 0., 1., Angle::zero()) - } - } -} - impl From for Transform3D { #[inline] fn from(m: ComputedMatrix) -> Self { @@ -124,12 +81,9 @@ impl TransformList { for operation in list { let matrix = match *operation { ComputedOperation::Rotate(ax, ay, az, theta) => { - // https://www.w3.org/TR/css-transforms-1/#funcdef-rotate3d - // A direction vector that cannot be normalized, such as [0, 0, 0], will cause - // the rotation to not be applied, so we use identity matrix in this case. let theta = Angle::from_radians(2.0f32 * f32::consts::PI - theta.radians()); let (ax, ay, az, theta) = - DirectionVector::get_normalized_vector_and_angle(ax, ay, az, theta); + Self::get_normalized_vector_and_angle(ax, ay, az, theta); Transform3D::create_rotation(ax, ay, az, theta.into()) } ComputedOperation::Perspective(d) => { @@ -198,4 +152,21 @@ impl TransformList { Transform3D::create_perspective(d) } } + + /// Return the normalized direction vector and its angle for Rotate3D. + pub fn get_normalized_vector_and_angle(x: f32, y: f32, z: f32, angle: Angle) + -> (f32, f32, f32, Angle) { + use euclid::approxeq::ApproxEq; + use euclid::num::Zero; + let vector = DirectionVector::new(x, y, z); + if vector.square_length().approx_eq(&f32::zero()) { + // https://www.w3.org/TR/css-transforms-1/#funcdef-rotate3d + // A direction vector that cannot be normalized, such as [0, 0, 0], will cause the + // rotation to not be applied, so we use identity matrix (i.e. rotate3d(0, 0, 1, 0)). + (0., 0., 1., Angle::zero()) + } else { + let vector = vector.normalize(); + (vector.x, vector.y, vector.z, angle) + } + } }