OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 // Needed on Windows to get |M_PI| from <cmath> | 5 // Needed on Windows to get |M_PI| from <cmath> |
6 #ifdef _WIN32 | 6 #ifdef _WIN32 |
7 #define _USE_MATH_DEFINES | 7 #define _USE_MATH_DEFINES |
8 #endif | 8 #endif |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
11 #include <cmath> | 11 #include <cmath> |
12 #include <limits> | 12 #include <limits> |
13 | 13 |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "cc/animation/transform_operation.h" | 15 #include "cc/animation/transform_operation.h" |
16 #include "cc/animation/transform_operations.h" | |
16 #include "ui/gfx/box_f.h" | 17 #include "ui/gfx/box_f.h" |
18 #include "ui/gfx/transform_util.h" | |
17 #include "ui/gfx/vector3d_f.h" | 19 #include "ui/gfx/vector3d_f.h" |
18 | 20 |
19 namespace { | 21 namespace { |
20 const SkMScalar kAngleEpsilon = 1e-4f; | 22 const SkMScalar kAngleEpsilon = 1e-4f; |
21 } | 23 } |
22 | 24 |
23 namespace cc { | 25 namespace cc { |
24 | 26 |
25 bool TransformOperation::IsIdentity() const { | 27 bool TransformOperation::IsIdentity() const { |
26 return matrix.IsIdentity(); | 28 return matrix.IsIdentity(); |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
243 } | 245 } |
244 | 246 |
245 static float RadiansToDegrees(float radians) { | 247 static float RadiansToDegrees(float radians) { |
246 return (180.f * radians) / M_PI; | 248 return (180.f * radians) / M_PI; |
247 } | 249 } |
248 | 250 |
249 static float DegreesToRadians(float degrees) { | 251 static float DegreesToRadians(float degrees) { |
250 return (M_PI * degrees) / 180.f; | 252 return (M_PI * degrees) / 180.f; |
251 } | 253 } |
252 | 254 |
253 // Div by zero doesn't always result in Inf as you might hope, so we'll do this | |
254 // explicitly here. | |
255 static float SafeDivide(float numerator, float denominator) { | |
256 if (numerator == 0.f) | |
257 return 0.f; | |
258 | |
259 if (denominator == 0.f) { | |
260 return numerator > 0.f ? std::numeric_limits<float>::infinity() | |
261 : -std::numeric_limits<float>::infinity(); | |
262 } | |
263 | |
264 return numerator / denominator; | |
265 } | |
266 | |
267 static void BoundingBoxForArc(const gfx::Point3F& point, | 255 static void BoundingBoxForArc(const gfx::Point3F& point, |
268 const TransformOperation* from, | 256 const TransformOperation* from, |
269 const TransformOperation* to, | 257 const TransformOperation* to, |
270 SkMScalar min_progress, | 258 SkMScalar min_progress, |
271 SkMScalar max_progress, | 259 SkMScalar max_progress, |
272 gfx::BoxF* box) { | 260 gfx::BoxF* box) { |
273 const TransformOperation* exemplar = from ? from : to; | 261 const TransformOperation* exemplar = from ? from : to; |
274 gfx::Vector3dF axis(exemplar->rotate.axis.x, | 262 gfx::Vector3dF axis(exemplar->rotate.axis.x, |
275 exemplar->rotate.axis.y, | 263 exemplar->rotate.axis.y, |
276 exemplar->rotate.axis.z); | 264 exemplar->rotate.axis.z); |
277 | 265 |
278 const bool x_is_zero = axis.x() == 0.f; | 266 const bool x_is_zero = axis.x() == 0.f; |
279 const bool y_is_zero = axis.y() == 0.f; | 267 const bool y_is_zero = axis.y() == 0.f; |
280 const bool z_is_zero = axis.z() == 0.f; | 268 const bool z_is_zero = axis.z() == 0.f; |
281 | 269 |
282 // We will have at most 6 angles to test (excluding from->angle and | 270 // We will have at most 6 angles to test (excluding from->angle and |
283 // to->angle). | 271 // to->angle). |
284 static const int kMaxNumCandidates = 6; | 272 static const int kMaxNumCandidates = 6; |
285 double candidates[kMaxNumCandidates]; | 273 double candidates[kMaxNumCandidates]; |
286 int num_candidates = kMaxNumCandidates; | 274 int num_candidates = kMaxNumCandidates; |
287 | 275 |
288 if (x_is_zero && y_is_zero && z_is_zero) | 276 if (x_is_zero && y_is_zero && z_is_zero) |
289 return; | 277 return; |
290 | 278 |
291 SkMScalar from_angle = from ? from->rotate.angle : 0.f; | 279 SkMScalar from_angle = from ? from->rotate.angle : 0.f; |
292 SkMScalar to_angle = to ? to->rotate.angle : 0.f; | 280 SkMScalar to_angle = to ? to->rotate.angle : 0.f; |
293 | 281 |
282 // If the axes of rotation are pointing in opposite directions, we need to | |
283 // flip one of the angles. Note, if both |from| and |to| exist, then axis will | |
284 // correspond to |from|. | |
285 if (from && to) { | |
286 gfx::Vector3dF other_axis( | |
287 to->rotate.axis.x, to->rotate.axis.y, to->rotate.axis.z); | |
288 if (gfx::DotProduct(axis, other_axis) < 0.f) | |
289 to_angle *= -1.f; | |
290 } | |
ajuma
2013/11/01 21:02:08
One thing I find confusing is that we don't need t
Ian Vollick
2013/11/03 19:05:19
Whoops, nothing! I thought that we'd enforced that
| |
291 | |
294 float min_degrees = | 292 float min_degrees = |
295 SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, min_progress)); | 293 SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, min_progress)); |
296 float max_degrees = | 294 float max_degrees = |
297 SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, max_progress)); | 295 SkMScalarToFloat(BlendSkMScalars(from_angle, to_angle, max_progress)); |
298 if (max_degrees < min_degrees) | 296 if (max_degrees < min_degrees) |
299 std::swap(min_degrees, max_degrees); | 297 std::swap(min_degrees, max_degrees); |
300 | 298 |
301 gfx::Transform from_transform; | 299 gfx::Transform from_transform; |
302 from_transform.RotateAbout(axis, min_degrees); | 300 from_transform.RotateAbout(axis, min_degrees); |
303 gfx::Transform to_transform; | 301 gfx::Transform to_transform; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
353 | 351 |
354 gfx::Point3F pz(0.f, 0.f, 1.f); | 352 gfx::Point3F pz(0.f, 0.f, 1.f); |
355 gfx::Vector3dF to_pz = pz - center; | 353 gfx::Vector3dF to_pz = pz - center; |
356 gfx::Point3F pz_projected = | 354 gfx::Point3F pz_projected = |
357 pz - ScaleVector3d(normal, gfx::DotProduct(to_pz, normal)); | 355 pz - ScaleVector3d(normal, gfx::DotProduct(to_pz, normal)); |
358 gfx::Vector3dF vz = pz_projected - origin; | 356 gfx::Vector3dF vz = pz_projected - origin; |
359 | 357 |
360 double phi_x = atan2(gfx::DotProduct(v2, vx), gfx::DotProduct(v1, vx)); | 358 double phi_x = atan2(gfx::DotProduct(v2, vx), gfx::DotProduct(v1, vx)); |
361 double phi_z = atan2(gfx::DotProduct(v2, vz), gfx::DotProduct(v1, vz)); | 359 double phi_z = atan2(gfx::DotProduct(v2, vz), gfx::DotProduct(v1, vz)); |
362 | 360 |
363 // NB: it is fine if the denominators here are zero and these values go to | 361 candidates[0] = atan2(normal.y(), normal.x() * normal.z()) + phi_x; |
364 // infinity; atan can handle it. | |
365 double tan_theta1 = SafeDivide(normal.y(), (normal.x() * normal.z())); | |
366 double tan_theta2 = SafeDivide(-normal.z(), (normal.x() * normal.y())); | |
367 | |
368 candidates[0] = atan(tan_theta1) + phi_x; | |
369 candidates[1] = candidates[0] + M_PI; | 362 candidates[1] = candidates[0] + M_PI; |
370 candidates[2] = atan(tan_theta2) + phi_x; | 363 candidates[2] = atan2(-normal.z(), normal.x() * normal.y()) + phi_x; |
371 candidates[3] = candidates[2] + M_PI; | 364 candidates[3] = candidates[2] + M_PI; |
372 candidates[4] = atan(-tan_theta1) + phi_z; | 365 candidates[4] = atan2(normal.y(), -normal.x() * normal.z()) + phi_z; |
373 candidates[5] = candidates[4] + M_PI; | 366 candidates[5] = candidates[4] + M_PI; |
374 } | 367 } |
375 | 368 |
376 double min_radians = DegreesToRadians(min_degrees); | 369 double min_radians = DegreesToRadians(min_degrees); |
377 double max_radians = DegreesToRadians(max_degrees); | 370 double max_radians = DegreesToRadians(max_degrees); |
378 | 371 |
379 for (int i = 0; i < num_candidates; ++i) { | 372 for (int i = 0; i < num_candidates; ++i) { |
380 double radians = candidates[i]; | 373 double radians = candidates[i]; |
381 while (radians < min_radians) | 374 while (radians < min_radians) |
382 radians += 2.0 * M_PI; | 375 radians += 2.0 * M_PI; |
(...skipping 25 matching lines...) Expand all Loading... | |
408 } | 401 } |
409 | 402 |
410 TransformOperation::Type interpolation_type = | 403 TransformOperation::Type interpolation_type = |
411 TransformOperation::TransformOperationIdentity; | 404 TransformOperation::TransformOperationIdentity; |
412 if (is_identity_to) | 405 if (is_identity_to) |
413 interpolation_type = from->type; | 406 interpolation_type = from->type; |
414 else | 407 else |
415 interpolation_type = to->type; | 408 interpolation_type = to->type; |
416 | 409 |
417 switch (interpolation_type) { | 410 switch (interpolation_type) { |
418 case TransformOperation::TransformOperationTranslate: { | 411 case TransformOperation::TransformOperationIdentity: |
419 SkMScalar from_x, from_y, from_z; | |
420 if (is_identity_from) { | |
421 from_x = from_y = from_z = 0.0; | |
422 } else { | |
423 from_x = from->translate.x; | |
424 from_y = from->translate.y; | |
425 from_z = from->translate.z; | |
426 } | |
427 SkMScalar to_x, to_y, to_z; | |
428 if (is_identity_to) { | |
429 to_x = to_y = to_z = 0.0; | |
430 } else { | |
431 to_x = to->translate.x; | |
432 to_y = to->translate.y; | |
433 to_z = to->translate.z; | |
434 } | |
435 *bounds = box; | 412 *bounds = box; |
436 *bounds += gfx::Vector3dF(BlendSkMScalars(from_x, to_x, min_progress), | |
437 BlendSkMScalars(from_y, to_y, min_progress), | |
438 BlendSkMScalars(from_z, to_z, min_progress)); | |
439 gfx::BoxF bounds_max = box; | |
440 bounds_max += gfx::Vector3dF(BlendSkMScalars(from_x, to_x, max_progress), | |
441 BlendSkMScalars(from_y, to_y, max_progress), | |
442 BlendSkMScalars(from_z, to_z, max_progress)); | |
443 bounds->Union(bounds_max); | |
444 return true; | 413 return true; |
445 } | 414 case TransformOperation::TransformOperationTranslate: |
415 case TransformOperation::TransformOperationSkew: | |
416 case TransformOperation::TransformOperationPerspective: | |
446 case TransformOperation::TransformOperationScale: { | 417 case TransformOperation::TransformOperationScale: { |
447 SkMScalar from_x, from_y, from_z; | 418 gfx::Transform from_transform; |
448 if (is_identity_from) { | 419 gfx::Transform to_transform; |
449 from_x = from_y = from_z = 1.0; | 420 if (!BlendTransformOperations(from, to, min_progress, &from_transform) || |
450 } else { | 421 !BlendTransformOperations(from, to, max_progress, &to_transform)) |
451 from_x = from->scale.x; | 422 return false; |
452 from_y = from->scale.y; | 423 |
453 from_z = from->scale.z; | |
454 } | |
455 SkMScalar to_x, to_y, to_z; | |
456 if (is_identity_to) { | |
457 to_x = to_y = to_z = 1.0; | |
458 } else { | |
459 to_x = to->scale.x; | |
460 to_y = to->scale.y; | |
461 to_z = to->scale.z; | |
462 } | |
463 *bounds = box; | 424 *bounds = box; |
464 ApplyScaleToBox( | 425 from_transform.TransformBox(bounds); |
465 SkMScalarToFloat(BlendSkMScalars(from_x, to_x, min_progress)), | 426 |
466 SkMScalarToFloat(BlendSkMScalars(from_y, to_y, min_progress)), | 427 gfx::BoxF to_box = box; |
467 SkMScalarToFloat(BlendSkMScalars(from_z, to_z, min_progress)), | 428 to_transform.TransformBox(&to_box); |
468 bounds); | 429 bounds->ExpandTo(to_box); |
469 gfx::BoxF bounds_max = box; | |
470 ApplyScaleToBox( | |
471 SkMScalarToFloat(BlendSkMScalars(from_x, to_x, max_progress)), | |
472 SkMScalarToFloat(BlendSkMScalars(from_y, to_y, max_progress)), | |
473 SkMScalarToFloat(BlendSkMScalars(from_z, to_z, max_progress)), | |
474 &bounds_max); | |
475 if (!bounds->IsEmpty() && !bounds_max.IsEmpty()) { | |
476 bounds->Union(bounds_max); | |
477 } else if (!bounds->IsEmpty()) { | |
478 UnionBoxWithZeroScale(bounds); | |
479 } else if (!bounds_max.IsEmpty()) { | |
480 UnionBoxWithZeroScale(&bounds_max); | |
481 *bounds = bounds_max; | |
482 } | |
483 | 430 |
484 return true; | 431 return true; |
485 } | 432 } |
486 case TransformOperation::TransformOperationIdentity: | |
487 *bounds = box; | |
488 return true; | |
489 case TransformOperation::TransformOperationRotate: { | 433 case TransformOperation::TransformOperationRotate: { |
490 bool first_point = true; | 434 bool first_point = true; |
491 for (int i = 0; i < 8; ++i) { | 435 for (int i = 0; i < 8; ++i) { |
492 gfx::Point3F corner = box.origin(); | 436 gfx::Point3F corner = box.origin(); |
493 corner += gfx::Vector3dF(i & 1 ? box.width() : 0.f, | 437 corner += gfx::Vector3dF(i & 1 ? box.width() : 0.f, |
494 i & 2 ? box.height() : 0.f, | 438 i & 2 ? box.height() : 0.f, |
495 i & 4 ? box.depth() : 0.f); | 439 i & 4 ? box.depth() : 0.f); |
496 gfx::BoxF box_for_arc; | 440 gfx::BoxF box_for_arc; |
497 BoundingBoxForArc( | 441 BoundingBoxForArc( |
498 corner, from, to, min_progress, max_progress, &box_for_arc); | 442 corner, from, to, min_progress, max_progress, &box_for_arc); |
499 if (first_point) | 443 if (first_point) |
500 *bounds = box_for_arc; | 444 *bounds = box_for_arc; |
501 else | 445 else |
502 bounds->Union(box_for_arc); | 446 bounds->Union(box_for_arc); |
503 first_point = false; | 447 first_point = false; |
504 } | 448 } |
505 return true; | 449 return true; |
506 } | 450 } |
507 case TransformOperation::TransformOperationSkew: | |
508 case TransformOperation::TransformOperationPerspective: | |
509 case TransformOperation::TransformOperationMatrix: | 451 case TransformOperation::TransformOperationMatrix: |
510 return false; | 452 return false; |
511 } | 453 } |
512 NOTREACHED(); | 454 NOTREACHED(); |
513 return false; | 455 return false; |
514 } | 456 } |
515 | 457 |
516 } // namespace cc | 458 } // namespace cc |
OLD | NEW |