Navigation Menu

Skip to content

Commit

Permalink
Fix divided by zero problem on non-normalizable direction vector.
Browse files Browse the repository at this point in the history
While normalizing the direction vector, we have to make sure we don't
divide the components by zero length to avoid any assertion of "NaN".
  • Loading branch information
BorisChiou committed Aug 19, 2017
1 parent c1b196b commit 03cf0a8
Showing 1 changed file with 25 additions and 24 deletions.
49 changes: 25 additions & 24 deletions components/style/properties/helpers/animated_properties.mako.rs
Expand Up @@ -1425,11 +1425,9 @@ fn add_weighted_transform_lists(from_list: &[TransformOperation],
}
(&TransformOperation::Rotate(fx, fy, fz, fa),
&TransformOperation::Rotate(tx, ty, tz, ta)) => {
let norm_f = ((fx * fx) + (fy * fy) + (fz * fz)).sqrt();
let norm_t = ((tx * tx) + (ty * ty) + (tz * tz)).sqrt();
let (fx, fy, fz) = (fx / norm_f, fy / norm_f, fz / norm_f);
let (tx, ty, tz) = (tx / norm_t, ty / norm_t, tz / norm_t);
if fx == tx && fy == ty && fz == tz {
let (fx, fy, fz, fa) = get_normalized_vector_and_angle(fx, fy, fz, fa);
let (tx, ty, tz, ta) = get_normalized_vector_and_angle(tx, ty, tz, ta);
if (fx, fy, fz) == (tx, ty, tz) {
let ia = fa.add_weighted(&ta, self_portion, other_portion).unwrap();
result.push(TransformOperation::Rotate(fx, fy, fz, ia));
} else {
Expand Down Expand Up @@ -1882,8 +1880,8 @@ impl ComputeSquaredDistance for Quaternion {
impl DirectionVector {
/// Create a DirectionVector.
#[inline]
fn new(x: f64, y: f64, z: f64) -> Self {
DirectionVector(Point3D::new(x, y, z))
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.
Expand All @@ -1907,6 +1905,19 @@ impl DirectionVector {
}
}

/// 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).
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())
}
}

/// Decompose a 3D matrix.
/// https://drafts.csswg.org/css-transforms/#decomposing-a-3d-matrix
fn decompose_3d_matrix(mut matrix: ComputedMatrix) -> Result<MatrixDecomposed3D, ()> {
Expand Down Expand Up @@ -2539,25 +2550,15 @@ fn compute_transform_lists_squared_distance(from_list: &[TransformOperation],
}
(&TransformOperation::Rotate(fx, fy, fz, fa),
&TransformOperation::Rotate(tx, ty, tz, ta)) => {
// 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).
let get_normalized_vector_and_angle = |x: f32, y: f32, z: f32, angle: Angle|
-> (DirectionVector, Angle) {
let mut vector = DirectionVector::new(x as f64, y as f64, z as f64);
if vector.normalize() {
(vector, angle)
} else {
(DirectionVector::new(0., 0., 1.), Angle::zero())
}
};

let (vector1, angle1) = get_normalized_vector_and_angle(fx, fy, fz, fa);
let (vector2, angle2) = get_normalized_vector_and_angle(tx, ty, tz, ta);
if vector1 == vector2 {
let (fx, fy, fz, angle1) = get_normalized_vector_and_angle(fx, fy, fz, fa);
let (tx, ty, tz, angle2) = get_normalized_vector_and_angle(tx, ty, tz, ta);
if (fx, fy, fz) == (tx, ty, tz) {
angle1.compute_squared_distance(&angle2).unwrap_or(zero_distance)
} else {
let q1 = Quaternion::from_direction_and_angle(&vector1, angle1.radians64());
let q2 = Quaternion::from_direction_and_angle(&vector2, angle2.radians64());
let v1 = DirectionVector::new(fx, fy, fz);
let v2 = DirectionVector::new(tx, ty, tz);
let q1 = Quaternion::from_direction_and_angle(&v1, angle1.radians64());
let q2 = Quaternion::from_direction_and_angle(&v2, angle2.radians64());
q1.compute_squared_distance(&q2).unwrap_or(zero_distance)
}
}
Expand Down

0 comments on commit 03cf0a8

Please sign in to comment.