1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "base/geometry/quaternion.h" 17 18namespace OHOS::Ace { 19namespace { 20 21constexpr double KEPSILON = 1e-5; 22 23} // namespace 24 25Quaternion Quaternion::Slerp(const Quaternion& to, double t) const 26{ 27 if (t < 0.0 || t > 1.0) { 28 // https://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/index.htm 29 // a scalar between 0.0 (at from) and 1.0 (at to) 30 return *this; 31 } 32 33 Quaternion from = *this; 34 35 double cosHalfAngle = from.x_ * to.x_ + from.y_ * to.y_ + from.z_ * to.z_ + from.w_ * to.w_; 36 if (cosHalfAngle < 0.0) { 37 // Since the half angle is > 90 degrees, the full rotation angle would 38 // exceed 180 degrees. The quaternions (x, y, z, w) and (-x, -y, -z, -w) 39 // represent the same rotation. Flipping the orientation of either 40 // quaternion ensures that the half angle is less than 90 and that we are 41 // taking the shortest path. 42 from = from.flip(); 43 cosHalfAngle = -cosHalfAngle; 44 } 45 46 // Ensure that acos is well behaved at the boundary. 47 if (cosHalfAngle > 1.0) { 48 cosHalfAngle = 1.0; 49 } 50 51 double sinHalfAngle = std::sqrt(1.0 - cosHalfAngle * cosHalfAngle); 52 if (sinHalfAngle < KEPSILON) { 53 // Quaternions share common axis and angle. 54 return *this; 55 } 56 57 double half_angle = std::acos(cosHalfAngle); 58 59 double scaleA = std::sin((1.0 - t) * half_angle) / sinHalfAngle; 60 double scaleB = std::sin(t * half_angle) / sinHalfAngle; 61 62 return (scaleA * from) + (scaleB * to); 63} 64 65} // namespace OHOS::Ace 66