1 /* 2 * Copyright (C) 1999 Antti Koivisto (koivisto (at) kde.org) 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 * 20 */ 21 22 #include "config.h" 23 #include "platform/transforms/RotateTransformOperation.h" 24 25 #include "platform/animation/AnimationUtilities.h" 26 #include "platform/geometry/FloatPoint3D.h" 27 #include "wtf/MathExtras.h" 28 #include <algorithm> 29 30 namespace blink { 31 32 static const double angleEpsilon = 1e-4; 33 34 FloatPoint3D RotateTransformOperation::axis() const 35 { 36 return FloatPoint3D(x(), y(), z()); 37 } 38 39 bool RotateTransformOperation::shareSameAxis(const RotateTransformOperation* from, const RotateTransformOperation* to, FloatPoint3D* axis, double* fromAngle, double* toAngle) 40 { 41 *axis = FloatPoint3D(0, 0, 1); 42 *fromAngle = 0; 43 *toAngle = 0; 44 45 if (!from && !to) 46 return true; 47 48 bool fromZero = !from || from->axis().isZero(); 49 bool toZero = !to || to->axis().isZero(); 50 51 if (fromZero && toZero) 52 return true; 53 54 if (fromZero) { 55 *axis = to->axis(); 56 *toAngle = to->angle(); 57 return true; 58 } 59 60 if (toZero) { 61 *axis = from->axis(); 62 *fromAngle = from->angle(); 63 return true; 64 } 65 66 FloatPoint3D fromAxis = from->axis(); 67 FloatPoint3D toAxis = to->axis(); 68 69 double fromSquared = fromAxis.lengthSquared(); 70 double toSquared = toAxis.lengthSquared(); 71 72 double dot = fromAxis.dot(toAxis); 73 double error = std::abs(1 - (dot * dot) / (fromSquared * toSquared)); 74 75 if (error > angleEpsilon) 76 return false; 77 *axis = from->axis(); 78 *fromAngle = from->angle(); 79 *toAngle = to->angle(); 80 return true; 81 } 82 83 PassRefPtr<TransformOperation> RotateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) 84 { 85 if (from && !from->isSameType(*this)) 86 return this; 87 88 if (blendToIdentity) 89 return RotateTransformOperation::create(m_x, m_y, m_z, m_angle - m_angle * progress, m_type); 90 91 const RotateTransformOperation* fromOp = static_cast<const RotateTransformOperation*>(from); 92 93 // Optimize for single axis rotation 94 if (!fromOp || (fromOp->m_x == 0 && fromOp->m_y == 0 && fromOp->m_z == 1) || 95 (fromOp->m_x == 0 && fromOp->m_y == 1 && fromOp->m_z == 0) || 96 (fromOp->m_x == 1 && fromOp->m_y == 0 && fromOp->m_z == 0)) { 97 double fromAngle = fromOp ? fromOp->m_angle : 0; 98 return RotateTransformOperation::create(fromOp ? fromOp->m_x : m_x, 99 fromOp ? fromOp->m_y : m_y, 100 fromOp ? fromOp->m_z : m_z, 101 blink::blend(fromAngle, m_angle, progress), m_type); 102 } 103 double fromAngle; 104 double toAngle; 105 FloatPoint3D axis; 106 107 if (shareSameAxis(fromOp, this, &axis, &fromAngle, &toAngle)) 108 return RotateTransformOperation::create(axis.x(), axis.y(), axis.z(), blink::blend(fromAngle, toAngle, progress), m_type); 109 110 const RotateTransformOperation* toOp = this; 111 112 // Create the 2 rotation matrices 113 TransformationMatrix fromT; 114 TransformationMatrix toT; 115 fromT.rotate3d((fromOp ? fromOp->m_x : 0), 116 (fromOp ? fromOp->m_y : 0), 117 (fromOp ? fromOp->m_z : 1), 118 (fromOp ? fromOp->m_angle : 0)); 119 120 toT.rotate3d((toOp ? toOp->m_x : 0), 121 (toOp ? toOp->m_y : 0), 122 (toOp ? toOp->m_z : 1), 123 (toOp ? toOp->m_angle : 0)); 124 125 // Blend them 126 toT.blend(fromT, progress); 127 128 // Extract the result as a quaternion 129 TransformationMatrix::DecomposedType decomp; 130 toT.decompose(decomp); 131 132 // Convert that to Axis/Angle form 133 double x = -decomp.quaternionX; 134 double y = -decomp.quaternionY; 135 double z = -decomp.quaternionZ; 136 double length = std::sqrt(x * x + y * y + z * z); 137 double angle = 0; 138 139 if (length > 0.00001) { 140 x /= length; 141 y /= length; 142 z /= length; 143 angle = rad2deg(std::acos(decomp.quaternionW) * 2); 144 } else { 145 x = 0; 146 y = 0; 147 z = 1; 148 } 149 return RotateTransformOperation::create(x, y, z, angle, Rotate3D); 150 } 151 152 bool RotateTransformOperation::canBlendWith(const TransformOperation& other) const 153 { 154 return other.isSameType(*this); 155 } 156 157 } // namespace blink 158