mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Use DirectionVector as an alias of euclid::Vector3D<f32>.
Therefore, we can reuse the methods of Vector3D, instead of implementing similar ones.
This commit is contained in:
parent
5c2d8507be
commit
4580b530a8
2 changed files with 32 additions and 61 deletions
|
@ -1107,7 +1107,7 @@ impl ToAnimatedZero for TransformOperation {
|
||||||
Ok(TransformOperation::Scale(1.0, 1.0, 1.0))
|
Ok(TransformOperation::Scale(1.0, 1.0, 1.0))
|
||||||
},
|
},
|
||||||
TransformOperation::Rotate(x, y, z, a) => {
|
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()))
|
Ok(TransformOperation::Rotate(x, y, z, Angle::zero()))
|
||||||
},
|
},
|
||||||
TransformOperation::Perspective(..) |
|
TransformOperation::Perspective(..) |
|
||||||
|
@ -1185,9 +1185,9 @@ impl Animate for TransformOperation {
|
||||||
&TransformOperation::Rotate(tx, ty, tz, ta),
|
&TransformOperation::Rotate(tx, ty, tz, ta),
|
||||||
) => {
|
) => {
|
||||||
let (fx, fy, fz, fa) =
|
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) =
|
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) {
|
if (fx, fy, fz) == (tx, ty, tz) {
|
||||||
let ia = fa.animate(&ta, procedure)?;
|
let ia = fa.animate(&ta, procedure)?;
|
||||||
Ok(TransformOperation::Rotate(fx, fy, fz, ia))
|
Ok(TransformOperation::Rotate(fx, fy, fz, ia))
|
||||||
|
@ -1604,7 +1604,7 @@ impl Quaternion {
|
||||||
/// Return a quaternion from a unit direction vector and angle (unit: radian).
|
/// Return a quaternion from a unit direction vector and angle (unit: radian).
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_direction_and_angle(vector: &DirectionVector, angle: f64) -> Self {
|
fn from_direction_and_angle(vector: &DirectionVector, angle: f64) -> Self {
|
||||||
debug_assert!((vector.length() - 1.).abs() < 0.0001f64,
|
debug_assert!((vector.length() - 1.).abs() < 0.0001,
|
||||||
"Only accept an unit direction vector to create a quaternion");
|
"Only accept an unit direction vector to create a quaternion");
|
||||||
// Reference:
|
// Reference:
|
||||||
// https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
|
// 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))
|
// q = cos(theta/2) + (xi + yj + zk)(sin(theta/2))
|
||||||
// = cos(theta/2) +
|
// = cos(theta/2) +
|
||||||
// x*sin(theta/2)i + y*sin(theta/2)j + z*sin(theta/2)k
|
// x*sin(theta/2)i + y*sin(theta/2)j + z*sin(theta/2)k
|
||||||
Quaternion(vector.0.x * (angle / 2.).sin(),
|
Quaternion(vector.x as f64 * (angle / 2.).sin(),
|
||||||
vector.0.y * (angle / 2.).sin(),
|
vector.y as f64 * (angle / 2.).sin(),
|
||||||
vector.0.z * (angle / 2.).sin(),
|
vector.z as f64 * (angle / 2.).sin(),
|
||||||
(angle / 2.).cos())
|
(angle / 2.).cos())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2304,9 +2304,9 @@ impl ComputeSquaredDistance for TransformOperation {
|
||||||
&TransformOperation::Rotate(tx, ty, tz, ta),
|
&TransformOperation::Rotate(tx, ty, tz, ta),
|
||||||
) => {
|
) => {
|
||||||
let (fx, fy, fz, angle1) =
|
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) =
|
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) {
|
if (fx, fy, fz) == (tx, ty, tz) {
|
||||||
angle1.compute_squared_distance(&angle2)
|
angle1.compute_squared_distance(&angle2)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! Computed types for CSS values that are related to transformations.
|
//! Computed types for CSS values that are related to transformations.
|
||||||
|
|
||||||
use app_units::Au;
|
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::{ComputedOperation, ComputedMatrix};
|
||||||
use properties::longhands::transform::computed_value::T as TransformList;
|
use properties::longhands::transform::computed_value::T as TransformList;
|
||||||
use std::f32;
|
use std::f32;
|
||||||
|
@ -20,6 +20,9 @@ pub type TransformOrigin = GenericTransformOrigin<LengthOrPercentage, LengthOrPe
|
||||||
/// A computed timing function.
|
/// A computed timing function.
|
||||||
pub type TimingFunction = GenericTimingFunction<u32, Number>;
|
pub type TimingFunction = GenericTimingFunction<u32, Number>;
|
||||||
|
|
||||||
|
/// A vector to represent the direction vector (rotate axis) for Rotate3D.
|
||||||
|
pub type DirectionVector = Vector3D<CSSFloat>;
|
||||||
|
|
||||||
impl TransformOrigin {
|
impl TransformOrigin {
|
||||||
/// Returns the initial computed value for `transform-origin`.
|
/// Returns the initial computed value for `transform-origin`.
|
||||||
#[inline]
|
#[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<f64>);
|
|
||||||
|
|
||||||
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<ComputedMatrix> for Transform3D<CSSFloat> {
|
impl From<ComputedMatrix> for Transform3D<CSSFloat> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(m: ComputedMatrix) -> Self {
|
fn from(m: ComputedMatrix) -> Self {
|
||||||
|
@ -124,12 +81,9 @@ impl TransformList {
|
||||||
for operation in list {
|
for operation in list {
|
||||||
let matrix = match *operation {
|
let matrix = match *operation {
|
||||||
ComputedOperation::Rotate(ax, ay, az, theta) => {
|
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 theta = Angle::from_radians(2.0f32 * f32::consts::PI - theta.radians());
|
||||||
let (ax, ay, az, theta) =
|
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())
|
Transform3D::create_rotation(ax, ay, az, theta.into())
|
||||||
}
|
}
|
||||||
ComputedOperation::Perspective(d) => {
|
ComputedOperation::Perspective(d) => {
|
||||||
|
@ -198,4 +152,21 @@ impl TransformList {
|
||||||
Transform3D::create_perspective(d)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue