OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/math_util.h" | 5 #include "cc/math_util.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <limits> | 8 #include <limits> |
9 | 9 |
10 #include "ui/gfx/quad_f.h" | 10 #include "ui/gfx/quad_f.h" |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 numVerticesInClippedQuad++; | 100 numVerticesInClippedQuad++; |
101 } | 101 } |
102 | 102 |
103 gfx::Rect MathUtil::mapClippedRect(const gfx::Transform& transform, const gfx::R
ect& srcRect) | 103 gfx::Rect MathUtil::mapClippedRect(const gfx::Transform& transform, const gfx::R
ect& srcRect) |
104 { | 104 { |
105 return gfx::ToEnclosingRect(mapClippedRect(transform, gfx::RectF(srcRect))); | 105 return gfx::ToEnclosingRect(mapClippedRect(transform, gfx::RectF(srcRect))); |
106 } | 106 } |
107 | 107 |
108 gfx::RectF MathUtil::mapClippedRect(const gfx::Transform& transform, const gfx::
RectF& srcRect) | 108 gfx::RectF MathUtil::mapClippedRect(const gfx::Transform& transform, const gfx::
RectF& srcRect) |
109 { | 109 { |
110 if (MathUtil::isIdentityOrTranslation(transform)) | 110 if (transform.IsIdentityOrTranslation()) |
111 return srcRect + gfx::Vector2dF(static_cast<float>(transform.matrix().ge
tDouble(0, 3)), static_cast<float>(transform.matrix().getDouble(1, 3))); | 111 return srcRect + gfx::Vector2dF(static_cast<float>(transform.matrix().ge
tDouble(0, 3)), static_cast<float>(transform.matrix().getDouble(1, 3))); |
112 | 112 |
113 // Apply the transform, but retain the result in homogeneous coordinates. | 113 // Apply the transform, but retain the result in homogeneous coordinates. |
114 gfx::QuadF q = gfx::QuadF(srcRect); | 114 gfx::QuadF q = gfx::QuadF(srcRect); |
115 HomogeneousCoordinate h1 = mapHomogeneousPoint(transform, gfx::Point3F(q.p1(
))); | 115 HomogeneousCoordinate h1 = mapHomogeneousPoint(transform, gfx::Point3F(q.p1(
))); |
116 HomogeneousCoordinate h2 = mapHomogeneousPoint(transform, gfx::Point3F(q.p2(
))); | 116 HomogeneousCoordinate h2 = mapHomogeneousPoint(transform, gfx::Point3F(q.p2(
))); |
117 HomogeneousCoordinate h3 = mapHomogeneousPoint(transform, gfx::Point3F(q.p3(
))); | 117 HomogeneousCoordinate h3 = mapHomogeneousPoint(transform, gfx::Point3F(q.p3(
))); |
118 HomogeneousCoordinate h4 = mapHomogeneousPoint(transform, gfx::Point3F(q.p4(
))); | 118 HomogeneousCoordinate h4 = mapHomogeneousPoint(transform, gfx::Point3F(q.p4(
))); |
119 | 119 |
120 return computeEnclosingClippedRect(h1, h2, h3, h4); | 120 return computeEnclosingClippedRect(h1, h2, h3, h4); |
121 } | 121 } |
122 | 122 |
123 gfx::RectF MathUtil::projectClippedRect(const gfx::Transform& transform, const g
fx::RectF& srcRect) | 123 gfx::RectF MathUtil::projectClippedRect(const gfx::Transform& transform, const g
fx::RectF& srcRect) |
124 { | 124 { |
125 if (MathUtil::isIdentityOrTranslation(transform)) | 125 if (transform.IsIdentityOrTranslation()) |
126 return srcRect + gfx::Vector2dF(static_cast<float>(transform.matrix().ge
tDouble(0, 3)), static_cast<float>(transform.matrix().getDouble(1, 3))); | 126 return srcRect + gfx::Vector2dF(static_cast<float>(transform.matrix().ge
tDouble(0, 3)), static_cast<float>(transform.matrix().getDouble(1, 3))); |
127 | 127 |
128 // Perform the projection, but retain the result in homogeneous coordinates. | 128 // Perform the projection, but retain the result in homogeneous coordinates. |
129 gfx::QuadF q = gfx::QuadF(srcRect); | 129 gfx::QuadF q = gfx::QuadF(srcRect); |
130 HomogeneousCoordinate h1 = projectHomogeneousPoint(transform, q.p1()); | 130 HomogeneousCoordinate h1 = projectHomogeneousPoint(transform, q.p1()); |
131 HomogeneousCoordinate h2 = projectHomogeneousPoint(transform, q.p2()); | 131 HomogeneousCoordinate h2 = projectHomogeneousPoint(transform, q.p2()); |
132 HomogeneousCoordinate h3 = projectHomogeneousPoint(transform, q.p3()); | 132 HomogeneousCoordinate h3 = projectHomogeneousPoint(transform, q.p3()); |
133 HomogeneousCoordinate h4 = projectHomogeneousPoint(transform, q.p4()); | 133 HomogeneousCoordinate h4 = projectHomogeneousPoint(transform, q.p4()); |
134 | 134 |
135 return computeEnclosingClippedRect(h1, h2, h3, h4); | 135 return computeEnclosingClippedRect(h1, h2, h3, h4); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, h4.cartesianPoint2d()
); | 234 expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, h4.cartesianPoint2d()
); |
235 | 235 |
236 if (h4.shouldBeClipped() ^ h1.shouldBeClipped()) | 236 if (h4.shouldBeClipped() ^ h1.shouldBeClipped()) |
237 expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, computeClippedPointFo
rEdge(h4, h1).cartesianPoint2d()); | 237 expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, computeClippedPointFo
rEdge(h4, h1).cartesianPoint2d()); |
238 | 238 |
239 return gfx::RectF(gfx::PointF(xmin, ymin), gfx::SizeF(xmax - xmin, ymax - ym
in)); | 239 return gfx::RectF(gfx::PointF(xmin, ymin), gfx::SizeF(xmax - xmin, ymax - ym
in)); |
240 } | 240 } |
241 | 241 |
242 gfx::QuadF MathUtil::mapQuad(const gfx::Transform& transform, const gfx::QuadF&
q, bool& clipped) | 242 gfx::QuadF MathUtil::mapQuad(const gfx::Transform& transform, const gfx::QuadF&
q, bool& clipped) |
243 { | 243 { |
244 if (MathUtil::isIdentityOrTranslation(transform)) { | 244 if (transform.IsIdentityOrTranslation()) { |
245 gfx::QuadF mappedQuad(q); | 245 gfx::QuadF mappedQuad(q); |
246 mappedQuad += gfx::Vector2dF(static_cast<float>(transform.matrix().getDo
uble(0, 3)), static_cast<float>(transform.matrix().getDouble(1, 3))); | 246 mappedQuad += gfx::Vector2dF(static_cast<float>(transform.matrix().getDo
uble(0, 3)), static_cast<float>(transform.matrix().getDouble(1, 3))); |
247 clipped = false; | 247 clipped = false; |
248 return mappedQuad; | 248 return mappedQuad; |
249 } | 249 } |
250 | 250 |
251 HomogeneousCoordinate h1 = mapHomogeneousPoint(transform, gfx::Point3F(q.p1(
))); | 251 HomogeneousCoordinate h1 = mapHomogeneousPoint(transform, gfx::Point3F(q.p1(
))); |
252 HomogeneousCoordinate h2 = mapHomogeneousPoint(transform, gfx::Point3F(q.p2(
))); | 252 HomogeneousCoordinate h2 = mapHomogeneousPoint(transform, gfx::Point3F(q.p2(
))); |
253 HomogeneousCoordinate h3 = mapHomogeneousPoint(transform, gfx::Point3F(q.p3(
))); | 253 HomogeneousCoordinate h3 = mapHomogeneousPoint(transform, gfx::Point3F(q.p3(
))); |
254 HomogeneousCoordinate h4 = mapHomogeneousPoint(transform, gfx::Point3F(q.p4(
))); | 254 HomogeneousCoordinate h4 = mapHomogeneousPoint(transform, gfx::Point3F(q.p4(
))); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 transform.matrix().setDouble(2, 3, 0); | 366 transform.matrix().setDouble(2, 3, 0); |
367 } | 367 } |
368 | 368 |
369 static inline float scaleOnAxis(double a, double b, double c) | 369 static inline float scaleOnAxis(double a, double b, double c) |
370 { | 370 { |
371 return std::sqrt(a * a + b * b + c * c); | 371 return std::sqrt(a * a + b * b + c * c); |
372 } | 372 } |
373 | 373 |
374 gfx::Vector2dF MathUtil::computeTransform2dScaleComponents(const gfx::Transform&
transform) | 374 gfx::Vector2dF MathUtil::computeTransform2dScaleComponents(const gfx::Transform&
transform) |
375 { | 375 { |
376 if (hasPerspective(transform)) | 376 if (transform.HasPerspective()) |
377 return gfx::Vector2dF(1, 1); | 377 return gfx::Vector2dF(1, 1); |
378 float xScale = scaleOnAxis(transform.matrix().getDouble(0, 0), transform.mat
rix().getDouble(1, 0), transform.matrix().getDouble(2, 0)); | 378 float xScale = scaleOnAxis(transform.matrix().getDouble(0, 0), transform.mat
rix().getDouble(1, 0), transform.matrix().getDouble(2, 0)); |
379 float yScale = scaleOnAxis(transform.matrix().getDouble(0, 1), transform.mat
rix().getDouble(1, 1), transform.matrix().getDouble(2, 1)); | 379 float yScale = scaleOnAxis(transform.matrix().getDouble(0, 1), transform.mat
rix().getDouble(1, 1), transform.matrix().getDouble(2, 1)); |
380 return gfx::Vector2dF(xScale, yScale); | 380 return gfx::Vector2dF(xScale, yScale); |
381 } | 381 } |
382 | 382 |
383 float MathUtil::smallestAngleBetweenVectors(gfx::Vector2dF v1, gfx::Vector2dF v2
) | 383 float MathUtil::smallestAngleBetweenVectors(gfx::Vector2dF v1, gfx::Vector2dF v2
) |
384 { | 384 { |
385 double dotProduct = gfx::DotProduct(v1, v2) / v1.Length() / v2.Length(); | 385 double dotProduct = gfx::DotProduct(v1, v2) / v1.Length() / v2.Length(); |
386 // Clamp to compensate for rounding errors. | 386 // Clamp to compensate for rounding errors. |
387 dotProduct = std::max(-1.0, std::min(1.0, dotProduct)); | 387 dotProduct = std::max(-1.0, std::min(1.0, dotProduct)); |
388 return static_cast<float>(Rad2Deg(std::acos(dotProduct))); | 388 return static_cast<float>(Rad2Deg(std::acos(dotProduct))); |
389 } | 389 } |
390 | 390 |
391 gfx::Vector2dF MathUtil::projectVector(gfx::Vector2dF source, gfx::Vector2dF des
tination) | 391 gfx::Vector2dF MathUtil::projectVector(gfx::Vector2dF source, gfx::Vector2dF des
tination) |
392 { | 392 { |
393 float projectedLength = gfx::DotProduct(source, destination) / destination.L
engthSquared(); | 393 float projectedLength = gfx::DotProduct(source, destination) / destination.L
engthSquared(); |
394 return gfx::Vector2dF(projectedLength * destination.x(), projectedLength * d
estination.y()); | 394 return gfx::Vector2dF(projectedLength * destination.x(), projectedLength * d
estination.y()); |
395 } | 395 } |
396 | 396 |
397 bool MathUtil::isBackFaceVisible(const gfx::Transform& transform) | |
398 { | |
399 // Compute whether a layer with a forward-facing normal of (0, 0, 1) would | |
400 // have its back face visible after applying the transform. | |
401 // | |
402 // This is done by transforming the normal and seeing if the resulting z | |
403 // value is positive or negative. However, note that transforming a normal | |
404 // actually requires using the inverse-transpose of the original transform. | |
405 | |
406 // TODO (shawnsingh) make this perform more efficiently - we do not | |
407 // actually need to instantiate/invert/transpose any matrices, exploiting th
e | |
408 // fact that we only need to transform (0, 0, 1, 0). | |
409 gfx::Transform inverseTransform = MathUtil::inverse(transform); | |
410 const SkMatrix44& mInv = inverseTransform.matrix(); | |
411 | |
412 return mInv.getDouble(2, 2) < 0; | |
413 } | |
414 | |
415 bool MathUtil::isIdentityOrTranslation(const gfx::Transform& transform) | |
416 { | |
417 const SkMatrix44& matrix = transform.matrix(); | |
418 | |
419 bool hasNoPerspective = !matrix.getDouble(3, 0) && !matrix.getDouble(3, 1) &
& !matrix.getDouble(3, 2) && (matrix.getDouble(3, 3) == 1); | |
420 bool hasNoRotationOrSkew = !matrix.getDouble(0, 1) && !matrix.getDouble(0, 2
) && !matrix.getDouble(1, 0) && | |
421 !matrix.getDouble(1, 2) && !matrix.getDouble(2, 0) && !matrix.getDouble(
2, 1); | |
422 bool hasNoScale = matrix.getDouble(0, 0) == 1 && matrix.getDouble(1, 1) == 1
&& matrix.getDouble(2, 2) == 1; | |
423 | |
424 return hasNoPerspective && hasNoRotationOrSkew && hasNoScale; | |
425 } | |
426 | |
427 bool MathUtil::hasPerspective(const gfx::Transform& transform) | |
428 { | |
429 // Mathematically it is a bit too strict to expect the 4th element to be | |
430 // equal to 1. However, the only non-perspective case where this element | |
431 // becomes non-1 is when it was explicitly initialized. In that case it | |
432 // still causes us to have a nontrivial divide-by-w, so we count it as | |
433 // being perspective here. | |
434 const SkMatrix44& matrix = transform.matrix(); | |
435 return matrix.getDouble(3, 0) || matrix.getDouble(3, 1) || matrix.getDouble(
3, 2) || (matrix.getDouble(3, 3) != 1); | |
436 } | |
437 | |
438 void MathUtil::rotateEulerAngles(gfx::Transform* transform, double eulerX, doubl
e eulerY, double eulerZ) | 397 void MathUtil::rotateEulerAngles(gfx::Transform* transform, double eulerX, doubl
e eulerY, double eulerZ) |
439 { | 398 { |
440 // TODO (shawnsingh): make this implementation faster and more accurate by | 399 // TODO (shawnsingh): make this implementation faster and more accurate by |
441 // hard-coding each matrix instead of calling rotateAxisAngle(). | 400 // hard-coding each matrix instead of calling RotateAbout(). |
442 gfx::Transform rotationAboutX; | 401 gfx::Transform rotationAboutX; |
443 gfx::Transform rotationAboutY; | 402 gfx::Transform rotationAboutY; |
444 gfx::Transform rotationAboutZ; | 403 gfx::Transform rotationAboutZ; |
445 | 404 |
446 MathUtil::rotateAxisAngle(&rotationAboutX, 1, 0, 0, eulerX); | 405 rotationAboutX.RotateAboutXAxis(eulerX); |
447 MathUtil::rotateAxisAngle(&rotationAboutY, 0, 1, 0, eulerY); | 406 rotationAboutY.RotateAboutYAxis(eulerY); |
448 MathUtil::rotateAxisAngle(&rotationAboutZ, 0, 0, 1, eulerZ); | 407 rotationAboutZ.RotateAboutZAxis(eulerZ); |
449 | 408 |
450 gfx::Transform composite = rotationAboutZ * rotationAboutY * rotationAboutX; | 409 gfx::Transform composite = rotationAboutZ * rotationAboutY * rotationAboutX; |
451 transform->PreconcatTransform(composite); | 410 transform->PreconcatTransform(composite); |
452 } | 411 } |
453 | 412 |
454 void MathUtil::rotateAxisAngle(gfx::Transform* transform, double i, double j, do
uble k, double degrees) | |
455 { | |
456 gfx::Vector3dF axis(i, j, k); | |
457 transform->RotateAbout(axis, degrees); | |
458 } | |
459 | |
460 gfx::Transform MathUtil::inverse(const gfx::Transform& transform) | 413 gfx::Transform MathUtil::inverse(const gfx::Transform& transform) |
461 { | 414 { |
462 gfx::Transform result; | 415 gfx::Transform result; |
463 bool invertedSuccessfully = transform.GetInverse(&result); | 416 bool invertedSuccessfully = transform.GetInverse(&result); |
464 | 417 |
465 if (invertedSuccessfully) | 418 if (invertedSuccessfully) |
466 return result; | 419 return result; |
467 | 420 |
468 // If transform was un-invertible, then just return identity. | 421 // If transform was un-invertible, then just return identity. |
469 return gfx::Transform(); | 422 return gfx::Transform(); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
529 matrix.setDouble(1, 0, b); | 482 matrix.setDouble(1, 0, b); |
530 matrix.setDouble(0, 1, c); | 483 matrix.setDouble(0, 1, c); |
531 matrix.setDouble(1, 1, d); | 484 matrix.setDouble(1, 1, d); |
532 matrix.setDouble(0, 3, e); | 485 matrix.setDouble(0, 3, e); |
533 matrix.setDouble(1, 3, f); | 486 matrix.setDouble(1, 3, f); |
534 | 487 |
535 return result; | 488 return result; |
536 } | 489 } |
537 | 490 |
538 } // namespace cc | 491 } // namespace cc |
OLD | NEW |