| 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 |