• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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/transform_util.h"
17 
18 namespace OHOS::Ace {
19 namespace {
20 
Length3(const float v[3])21 float Length3(const float v[3])
22 {
23     double vd[3] = { v[0], v[1], v[2] };
24     return static_cast<float>(std::sqrt(vd[0] * vd[0] + vd[1] * vd[1] + vd[2] * vd[2]));
25 }
26 
27 template<int n>
Dot(const float * a,const float * b)28 float Dot(const float* a, const float* b)
29 {
30     double total = 0.0;
31     for (int i = 0; i < n; ++i) {
32         total += a[i] * b[i];
33     }
34     return static_cast<float>(total);
35 }
36 
37 template<int n>
Combine(float * out,const float * a,const float * b,double scaleA,double scaleB)38 void Combine(float* out, const float* a, const float* b, double scaleA, double scaleB)
39 {
40     for (int i = 0; i < n; ++i) {
41         out[i] = static_cast<float>(a[i] * scaleA + b[i] * scaleB);
42     }
43 }
44 
Cross3(float out[3],const float a[3],const float b[3])45 void Cross3(float out[3], const float a[3], const float b[3])
46 {
47     float x = a[1] * b[2] - a[2] * b[1];
48     float y = a[2] * b[0] - a[0] * b[2];
49     float z = a[0] * b[1] - a[1] * b[0];
50     out[0] = x;
51     out[1] = y;
52     out[2] = z;
53 }
54 
55 // Returns false if the matrix cannot be normalized.
Normalize(Matrix4 & m)56 bool Normalize(Matrix4& m)
57 {
58     if (NearZero(m.Get(3, 3))) {
59         return false;
60     }
61     float scale = 1.0f / m.Get(3, 3);
62     for (int i = 0; i < 4; i++) {
63         for (int j = 0; j < 4; j++) {
64             auto value = m.Get(i, j) * scale;
65             m.Set(i, j, value);
66         }
67     }
68     return true;
69 }
70 
BuildPerspectiveMatrix(const DecomposedTransform & decomp)71 Matrix4 BuildPerspectiveMatrix(const DecomposedTransform& decomp)
72 {
73     Matrix4 matrix = Matrix4::CreateIdentity();
74 
75     for (int i = 0; i < 4; i++) {
76         matrix.Set(3, i, decomp.perspective[i]);
77     }
78     return matrix;
79 }
80 
BuildTranslationMatrix(const DecomposedTransform & decomp)81 Matrix4 BuildTranslationMatrix(const DecomposedTransform& decomp)
82 {
83     Matrix4 matrix = Matrix4::CreateIdentity();
84     float dx = decomp.translate[0];
85     float dy = decomp.translate[1];
86     float dz = decomp.translate[2];
87     if (NearZero(dx) && NearZero(dy) && NearZero(dz)) {
88         return matrix;
89     }
90 
91     matrix.Set(0, 3, dx);
92     matrix.Set(1, 3, dy);
93     matrix.Set(2, 3, dz);
94     return matrix;
95 }
96 
BuildRotationMatrix(const DecomposedTransform & decomp)97 Matrix4 BuildRotationMatrix(const DecomposedTransform& decomp)
98 {
99     Matrix4 matrix4;
100     double x = decomp.quaternion.GetX();
101     double y = decomp.quaternion.GetY();
102     double z = decomp.quaternion.GetZ();
103     double w = decomp.quaternion.GetW();
104 
105     matrix4.Set(0, 0, static_cast<float>(1.0 - 2.0 * (y * y + z * z)));
106     matrix4.Set(1, 0, static_cast<float>(2.0 * (x * y + z * w)));
107     matrix4.Set(2, 0, static_cast<float>(2.0 * (x * z - y * w)));
108     matrix4.Set(3, 0, 0);
109 
110     matrix4.Set(0, 1, static_cast<float>(2.0 * (x * y - z * w)));
111     matrix4.Set(1, 1, static_cast<float>(1.0 - 2.0 * (x * x + z * z)));
112     matrix4.Set(2, 1, static_cast<float>(2.0 * (y * z + x * w)));
113     matrix4.Set(3, 1, 0);
114 
115     matrix4.Set(0, 2, static_cast<float>(2.0 * (x * z + y * w)));
116     matrix4.Set(1, 2, static_cast<float>(2.0 * (y * z - x * w)));
117     matrix4.Set(2, 2, static_cast<float>(1.0 - 2.0 * (x * x + y * y)));
118     matrix4.Set(3, 2, 0);
119 
120     matrix4.Set(0, 3, 0);
121     matrix4.Set(1, 3, 0);
122     matrix4.Set(2, 3, 0);
123     matrix4.Set(3, 3, 1);
124 
125     return matrix4;
126 }
127 
BuildSkewMatrix(const DecomposedTransform & decomp)128 Matrix4 BuildSkewMatrix(const DecomposedTransform& decomp)
129 {
130     Matrix4 matrix = Matrix4::CreateIdentity();
131 
132     Matrix4 temp = Matrix4::CreateIdentity();
133     if (decomp.skew[2]) {
134         temp.Set(1, 2, decomp.skew[2]);
135         matrix = matrix * temp;
136     }
137 
138     if (decomp.skew[1]) {
139         temp.Set(1, 2, 0);
140         temp.Set(0, 2, decomp.skew[1]);
141         matrix = matrix * temp;
142     }
143 
144     if (decomp.skew[0]) {
145         temp.Set(0, 2, 0);
146         temp.Set(0, 1, decomp.skew[0]);
147         matrix = matrix * temp;
148     }
149     return matrix;
150 }
151 
BuildScaleMatrix(const DecomposedTransform & decomp)152 Matrix4 BuildScaleMatrix(const DecomposedTransform& decomp)
153 {
154     Matrix4 matrix = Matrix4::CreateIdentity();
155     matrix.SetScale(decomp.scale[0], decomp.scale[1], decomp.scale[2]);
156     return matrix;
157 }
158 
ComposeTransform(const Matrix4 & perspective,const Matrix4 & translation,const Matrix4 & rotation,const Matrix4 & skew,const Matrix4 & scale)159 Matrix4 ComposeTransform(const Matrix4& perspective, const Matrix4& translation, const Matrix4& rotation,
160     const Matrix4& skew, const Matrix4& scale)
161 {
162     Matrix4 matrix = Matrix4::CreateIdentity();
163     matrix = matrix * perspective;
164     matrix = matrix * translation;
165     matrix = matrix * rotation;
166     matrix = matrix * skew;
167     matrix = matrix * scale;
168     return matrix;
169 }
170 
171 } // namespace
172 
Blend(const TranslateOperation & to,const TranslateOperation & from,float progress)173 TranslateOperation TranslateOperation::Blend(
174     const TranslateOperation& to, const TranslateOperation& from, float progress)
175 {
176     TranslateOperation ret;
177     float scaleA = progress;
178     float scaleB = 1 - progress;
179     ret.dx = to.dx * scaleA + from.dx * scaleB;
180     ret.dy = to.dy * scaleA + from.dy * scaleB;
181     ret.dz = to.dz * scaleA + from.dz * scaleB;
182 
183     return ret;
184 }
185 
Blend(const ScaleOperation & to,const ScaleOperation & from,float progress)186 ScaleOperation ScaleOperation::Blend(const ScaleOperation& to, const ScaleOperation& from, float progress)
187 {
188     ScaleOperation ret;
189     float scaleA = progress;
190     float scaleB = 1 - progress;
191     ret.scaleX = to.scaleX * scaleA + from.scaleX * scaleB;
192     ret.scaleY = to.scaleY * scaleA + from.scaleY * scaleB;
193     ret.scaleZ = to.scaleZ * scaleA + from.scaleZ * scaleB;
194     return ret;
195 }
196 
Blend(const SkewOperation & to,const SkewOperation & from,float progress)197 SkewOperation SkewOperation::Blend(const SkewOperation& to, const SkewOperation& from, float progress)
198 {
199     SkewOperation ret;
200     float scaleA = progress;
201     float scaleB = 1 - progress;
202     ret.skewX = to.skewX * scaleA + from.skewX * scaleB;
203     ret.skewY = to.skewY * scaleA + from.skewY * scaleB;
204     return ret;
205 }
206 
Blend(const RotateOperation & to,const RotateOperation & from,float progress)207 RotateOperation RotateOperation::Blend(const RotateOperation& to, const RotateOperation& from, float progress)
208 {
209     RotateOperation ret;
210     float scaleA = progress;
211     float scaleB = 1 - progress;
212     ret.angle = to.angle * scaleA + from.angle * scaleB;
213     ret.dx = to.dx;
214     ret.dy = to.dy;
215     ret.dz = to.dz;
216     // rotate vector is (0,0,0) is error
217     if (NearZero(ret.dx) && NearZero(ret.dy) && NearZero(ret.dz)) {
218         ret.dx = from.dx;
219         ret.dy = from.dy;
220         ret.dz = from.dz;
221     }
222     return ret;
223 }
224 
Blend(const PerspectiveOperation & to,const PerspectiveOperation & from,float progress)225 PerspectiveOperation PerspectiveOperation::Blend(
226     const PerspectiveOperation& to, const PerspectiveOperation& from, float progress)
227 {
228     PerspectiveOperation ret;
229     ret.distance = from.distance + (to.distance - from.distance) * progress;
230     return ret;
231 }
232 
Blend(const TransformOperation & to,const TransformOperation & from,float progress)233 TransformOperation TransformOperation::Blend(
234     const TransformOperation& to, const TransformOperation& from, float progress)
235 {
236     TransformOperation ret;
237     if (to.type_ == from.type_ && to.type_ == TransformOperationType::UNDEFINED) {
238         return ret;
239     } else if (to.type_ == TransformOperationType::UNDEFINED) {
240         ret.type_ = from.type_;
241         BlendInner(Create(ret.type_), from, progress, ret);
242     } else if (from.type_ == TransformOperationType::UNDEFINED) {
243         ret.type_ = to.type_;
244         BlendInner(to, Create(ret.type_), progress, ret);
245     } else if (to.type_ == from.type_) {
246         ret.type_ = to.type_;
247         BlendInner(to, from, progress, ret);
248     }
249     return ret;
250 }
251 
Create(TransformOperationType type)252 TransformOperation TransformOperation::Create(TransformOperationType type)
253 {
254     TransformOperation ret;
255     ret.type_ = type;
256     switch (ret.type_) {
257         case TransformOperationType::TRANSLATE:
258             ret.translateOperation_ = TranslateOperation();
259             break;
260         case TransformOperationType::SCALE:
261             ret.scaleOperation_ = ScaleOperation();
262             break;
263         case TransformOperationType::SKEW:
264             ret.skewOperation_ = SkewOperation();
265             break;
266         case TransformOperationType::ROTATE:
267             ret.rotateOperation_ = RotateOperation();
268             break;
269         case TransformOperationType::MATRIX:
270             ret.matrix4_ = Matrix4::CreateIdentity();
271             break;
272         case TransformOperationType::PERSPECTIVE:
273             ret.perspectiveOperation_ = PerspectiveOperation();
274             break;
275         case TransformOperationType::UNDEFINED:
276             break;
277         default:
278             break;
279     }
280     return ret;
281 }
282 
BlendInner(const TransformOperation & to,const TransformOperation & from,float progress,TransformOperation & ret)283 void TransformOperation::BlendInner(
284     const TransformOperation& to, const TransformOperation& from, float progress, TransformOperation& ret)
285 {
286     switch (ret.type_) {
287         case TransformOperationType::TRANSLATE:
288             ret.translateOperation_ =
289                 TranslateOperation::Blend(to.translateOperation_, from.translateOperation_, progress);
290             break;
291         case TransformOperationType::SCALE:
292             ret.scaleOperation_ = ScaleOperation::Blend(to.scaleOperation_, from.scaleOperation_, progress);
293             break;
294         case TransformOperationType::SKEW:
295             ret.skewOperation_ = SkewOperation::Blend(to.skewOperation_, from.skewOperation_, progress);
296             break;
297         case TransformOperationType::ROTATE:
298             ret.rotateOperation_ = RotateOperation::Blend(to.rotateOperation_, from.rotateOperation_, progress);
299             break;
300         case TransformOperationType::MATRIX: {
301             DecomposedTransform toTransform;
302             DecomposedTransform fromTransform;
303             if (TransformUtil::DecomposeTransform(toTransform, to.matrix4_) &&
304                 TransformUtil::DecomposeTransform(fromTransform, from.matrix4_)) {
305                 auto result = TransformUtil::BlendDecomposedTransforms(toTransform, fromTransform, progress);
306                 ret.matrix4_ = TransformUtil::ComposeTransform(result);
307             } else {
308                 LOGE("DecomposeTransform failed");
309             }
310             break;
311         }
312         case TransformOperationType::PERSPECTIVE:
313             ret.perspectiveOperation_ =
314                 PerspectiveOperation::Blend(to.perspectiveOperation_, from.perspectiveOperation_, progress);
315             break;
316         case TransformOperationType::UNDEFINED:
317             break;
318         default:
319             break;
320     }
321 }
322 
ToString() const323 std::string DecomposedTransform::ToString() const
324 {
325     std::string out;
326     out.append("translate: ")
327         .append(std::to_string(translate[0]))
328         .append(" ")
329         .append(std::to_string(translate[1]))
330         .append(" ")
331         .append(std::to_string(translate[2]))
332         .append("\n")
333         .append("scale: ")
334         .append(std::to_string(scale[0]))
335         .append(" ")
336         .append(std::to_string(scale[1]))
337         .append(" ")
338         .append(std::to_string(scale[2]))
339         .append("\n")
340         .append("skew: ")
341         .append(std::to_string(skew[0]))
342         .append(" ")
343         .append(std::to_string(skew[1]))
344         .append(" ")
345         .append(std::to_string(skew[2]))
346         .append("\n")
347         .append("perspective: ")
348         .append(std::to_string(perspective[0]))
349         .append(" ")
350         .append(std::to_string(perspective[1]))
351         .append(" ")
352         .append(std::to_string(perspective[2]))
353         .append(" ")
354         .append(std::to_string(perspective[3]))
355         .append("\n")
356         .append("quaternion: ")
357         .append(std::to_string(quaternion.GetX()))
358         .append(" ")
359         .append(std::to_string(quaternion.GetY()))
360         .append(" ")
361         .append(std::to_string(quaternion.GetZ()))
362         .append(" ")
363         .append(std::to_string(quaternion.GetW()))
364         .append("\n");
365     return out;
366 }
367 
Blend(const TransformOperations & to,const TransformOperations & from,float progress)368 TransformOperations TransformOperations::Blend(
369     const TransformOperations& to, const TransformOperations& from, float progress)
370 {
371     TransformOperations result;
372     to.BlendInner(from, progress, result);
373     return result;
374 }
375 
MatchingLength(const TransformOperations & to,const TransformOperations & from) const376 std::size_t TransformOperations::MatchingLength(const TransformOperations& to, const TransformOperations& from) const
377 {
378     auto numOperations = std::min(to.operations_.size(), from.operations_.size());
379 
380     for (std::size_t i = 0; i < numOperations; i++) {
381         auto& first = to.operations_[i];
382         auto& second = from.operations_[i];
383 
384         if (first.type_ != TransformOperationType::UNDEFINED || second.type_ != TransformOperationType::UNDEFINED) {
385             if (first.type_ != second.type_) {
386                 return i;
387             }
388         }
389     }
390     return std::max(to.operations_.size(), from.operations_.size());
391 }
392 
ParseOperationsToMatrix(std::vector<TransformOperation> & operations)393 void TransformOperations::ParseOperationsToMatrix(std::vector<TransformOperation>& operations)
394 {
395     for (auto& operation : operations) {
396         ParseOperationToMatrix(operation);
397     }
398 }
399 
ParseOperationToMatrix(TransformOperation & operation)400 void TransformOperations::ParseOperationToMatrix(TransformOperation& operation)
401 {
402     switch (operation.type_) {
403         case TransformOperationType::TRANSLATE: {
404             auto& translate = operation.translateOperation_;
405             float dx = translate.dx.Value();
406             float dy = translate.dy.Value();
407             float dz = translate.dz.Value();
408             operation.matrix4_ = Matrix4::CreateTranslate(dx, dy, dz);
409             break;
410         }
411         case TransformOperationType::SCALE: {
412             auto& scale = operation.scaleOperation_;
413             operation.matrix4_ = Matrix4::CreateScale(scale.scaleX, scale.scaleY, scale.scaleZ);
414             break;
415         }
416         case TransformOperationType::SKEW: {
417             auto& skew = operation.skewOperation_;
418             operation.matrix4_ = Matrix4::CreateSkew(skew.skewX, skew.skewY);
419             break;
420         }
421         case TransformOperationType::ROTATE: {
422             auto& rotate = operation.rotateOperation_;
423             operation.matrix4_ = Matrix4::CreateRotate(rotate.angle, rotate.dx, rotate.dy, rotate.dz);
424             break;
425         }
426         case TransformOperationType::PERSPECTIVE: {
427             auto& perspective = operation.perspectiveOperation_;
428             double distance = perspective.distance.Value();
429             operation.matrix4_ = Matrix4::CreatePerspective(distance);
430             break;
431         }
432         case TransformOperationType::MATRIX:
433         case TransformOperationType::UNDEFINED:
434             break;
435         default:
436             break;
437     }
438 }
439 
BlendInner(const TransformOperations & from,float progress,TransformOperations & out) const440 void TransformOperations::BlendInner(const TransformOperations& from, float progress, TransformOperations& out) const
441 {
442     auto matchPrefix = MatchingLength(*this, from);
443     auto fromSize = from.operations_.size();
444     auto toSize = operations_.size();
445 
446     // find most match type transform
447     for (std::size_t i = 0; i < matchPrefix; i++) {
448         const auto& fromTransformOperation = i >= fromSize ? TransformOperation() : from.operations_[i];
449         const auto& toTransformOperation = i >= toSize ? TransformOperation() : operations_[i];
450         out.operations_.push_back(TransformOperation::Blend(toTransformOperation, fromTransformOperation, progress));
451     }
452     // type not match
453     if (matchPrefix < std::max(fromSize, toSize)) {
454         TransformOperation fromTransformOperation;
455         fromTransformOperation.type_ = TransformOperationType::MATRIX;
456         fromTransformOperation.matrix4_ = from.ComputerRemaining(matchPrefix);
457         TransformOperation toTransformOperation;
458         toTransformOperation.type_ = TransformOperationType::MATRIX;
459         toTransformOperation.matrix4_ = ComputerRemaining(matchPrefix);
460         out.operations_.push_back(TransformOperation::Blend(toTransformOperation, fromTransformOperation, progress));
461     }
462 }
463 
ComputerRemaining(std::size_t startOffset) const464 Matrix4 TransformOperations::ComputerRemaining(std::size_t startOffset) const
465 {
466     Matrix4 result = Matrix4::CreateIdentity();
467     for (auto i = startOffset; i < operations_.size(); i++) {
468         result = result * operations_[i].matrix4_;
469     }
470     return result;
471 }
472 
BlendDecomposedTransforms(const DecomposedTransform & to,const DecomposedTransform & from,double progress)473 DecomposedTransform TransformUtil::BlendDecomposedTransforms(
474     const DecomposedTransform& to, const DecomposedTransform& from, double progress)
475 {
476     DecomposedTransform ret;
477     Combine<3>(ret.translate, to.translate, from.translate, progress, 1.0 - progress);
478     Combine<3>(ret.scale, to.scale, from.scale, progress, 1.0 - progress);
479     Combine<3>(ret.skew, to.skew, from.skew, progress, 1.0 - progress);
480     Combine<4>(ret.perspective, to.perspective, from.perspective, progress, 1.0 - progress);
481     ret.quaternion = from.quaternion.Slerp(to.quaternion, progress);
482     return ret;
483 }
484 
DecomposeTransform(DecomposedTransform & out,const Matrix4 & transform)485 bool TransformUtil::DecomposeTransform(DecomposedTransform& out, const Matrix4& transform)
486 {
487     Matrix4 matrix = transform;
488 
489     if (!Normalize(matrix)) {
490         return false;
491     }
492 
493     Matrix4 perspectiveMatrix = matrix;
494     for (int i = 0; i < 3; i++) {
495         perspectiveMatrix.Set(3, i, 0.0);
496     }
497     perspectiveMatrix.Set(3, 3, 1.0);
498 
499     if (NearZero(std::abs(perspectiveMatrix.Determinant()))) {
500         return false;
501     }
502 
503     if (!NearZero(matrix.Get(3, 0)) || !NearZero(matrix.Get(3, 1)) || !NearZero(matrix.Get(3, 2))) {
504         double rhs[4] = { matrix.Get(3, 0), matrix.Get(3, 1), matrix.Get(3, 2), matrix.Get(3, 3) };
505 
506         Matrix4 inversePerspectiveMatrix = Matrix4::Invert(perspectiveMatrix);
507         Matrix4 transposedInversePerspectiveMatrix = inversePerspectiveMatrix;
508 
509         transposedInversePerspectiveMatrix.Transpose();
510         transposedInversePerspectiveMatrix.MapScalars(rhs, 4);
511 
512         for (int32_t i = 0; i < 4; i++) {
513             out.perspective[i] = rhs[i];
514         }
515     } else {
516         // No perspective.
517         for (int i = 0; i < 3; ++i)
518             out.perspective[i] = 0.0;
519         out.perspective[3] = 1.0;
520     }
521 
522     for (int32_t i = 0; i < 3; i++) {
523         out.translate[i] = matrix.Get(i, 3);
524     }
525 
526     // Copy of matrix is stored in column major order to facilitate column-level
527     // operations.
528     float column[3][3];
529     for (int32_t i = 0; i < 3; i++) {
530         for (int32_t j = 0; j < 3; j++) {
531             column[i][j] = matrix.Get(j, i);
532         }
533     }
534 
535     // Compute X scale factor and normalize first column.
536     out.scale[0] = Length3(column[0]);
537     if (out.scale[0] != 0.0) {
538         column[0][0] /= out.scale[0];
539         column[0][1] /= out.scale[0];
540         column[0][2] /= out.scale[0];
541     }
542 
543     // Compute XY shear factor and make 2nd column orthogonal to 1st.
544     out.skew[0] = Dot<3>(column[0], column[1]);
545     Combine<3>(column[1], column[1], column[0], 1.0, -out.skew[0]);
546 
547     // Now, compute Y scale and normalize 2nd column.
548     out.scale[1] = Length3(column[1]);
549     if (out.scale[1] != 0.0) {
550         column[1][0] /= out.scale[1];
551         column[1][1] /= out.scale[1];
552         column[1][2] /= out.scale[1];
553     }
554 
555     out.skew[0] /= out.scale[1];
556 
557     // Compute XZ and YZ shears, orthogonalize the 3rd column.
558     out.skew[1] = Dot<3>(column[0], column[2]);
559     Combine<3>(column[2], column[2], column[0], 1.0, -out.skew[1]);
560     out.skew[2] = Dot<3>(column[1], column[2]);
561     Combine<3>(column[2], column[2], column[1], 1.0, -out.skew[2]);
562 
563     // Next, get Z scale and normalize the 3rd column.
564     out.scale[2] = Length3(column[2]);
565     if (out.scale[2] != 0.0) {
566         column[2][0] /= out.scale[2];
567         column[2][1] /= out.scale[2];
568         column[2][2] /= out.scale[2];
569     }
570 
571     out.skew[1] /= out.scale[2];
572     out.skew[2] /= out.scale[2];
573 
574     // At this point, the matrix is orthonormal.
575     // Check for a coordinate system flip.  If the determinant
576     // is -1, then negate the matrix and the scaling factors.
577     // only 1 axis is flipped when the determinant is negative. Verify if it is
578     // correct to flip all of the scales and matrix elements, as this introduces
579     // rotation for the simple case of a single axis scale inversion.
580     float pdum3[3];
581     Cross3(pdum3, column[1], column[2]);
582     if (Dot<3>(column[0], pdum3) < 0) {
583         for (int i = 0; i < 3; i++) {
584             out.scale[i] *= -1.0;
585             for (int j = 0; j < 3; ++j)
586                 column[i][j] *= -1.0;
587         }
588     }
589 
590     // See https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion.
591     // Note: deviating from spec (http://www.w3.org/TR/css3-transforms/)
592     // which has a degenerate case of zero off-diagonal elements in the
593     // orthonormal matrix, which leads to errors in determining the sign
594     // of the quaternions.
595     double q_xx = column[0][0];
596     double q_xy = column[1][0];
597     double q_xz = column[2][0];
598     double q_yx = column[0][1];
599     double q_yy = column[1][1];
600     double q_yz = column[2][1];
601     double q_zx = column[0][2];
602     double q_zy = column[1][2];
603     double q_zz = column[2][2];
604 
605     double r, s, t, x, y, z, w;
606     t = q_xx + q_yy + q_zz;
607     if (t > 0) {
608         r = std::sqrt(1.0 + t);
609         s = 0.5 / r;
610         w = 0.5 * r;
611         x = (q_zy - q_yz) * s;
612         y = (q_xz - q_zx) * s;
613         z = (q_yx - q_xy) * s;
614     } else if (q_xx > q_yy && q_xx > q_zz) {
615         r = std::sqrt(1.0 + q_xx - q_yy - q_zz);
616         s = 0.5 / r;
617         x = 0.5 * r;
618         y = (q_xy + q_yx) * s;
619         z = (q_xz + q_zx) * s;
620         w = (q_zy - q_yz) * s;
621     } else if (q_yy > q_zz) {
622         r = std::sqrt(1.0 - q_xx + q_yy - q_zz);
623         s = 0.5 / r;
624         x = (q_xy + q_yx) * s;
625         y = 0.5 * r;
626         z = (q_yz + q_zy) * s;
627         w = (q_xz - q_zx) * s;
628     } else {
629         r = std::sqrt(1.0 - q_xx - q_yy + q_zz);
630         s = 0.5 / r;
631         x = (q_xz + q_zx) * s;
632         y = (q_yz + q_zy) * s;
633         z = 0.5 * r;
634         w = (q_yx - q_xy) * s;
635     }
636 
637     out.quaternion.SetX(static_cast<float>(x));
638     out.quaternion.SetY(static_cast<float>(y));
639     out.quaternion.SetZ(static_cast<float>(z));
640     out.quaternion.SetW(static_cast<float>(w));
641 
642     return true;
643 }
644 
ComposeTransform(const struct DecomposedTransform & decomp)645 Matrix4 TransformUtil::ComposeTransform(const struct DecomposedTransform& decomp)
646 {
647     Matrix4 perspective = BuildPerspectiveMatrix(decomp);
648     Matrix4 translation = BuildTranslationMatrix(decomp);
649     Matrix4 rotation = BuildRotationMatrix(decomp);
650     Matrix4 skew = BuildSkewMatrix(decomp);
651     Matrix4 scale = BuildScaleMatrix(decomp);
652 
653     return OHOS::Ace::ComposeTransform(perspective, translation, rotation, skew, scale);
654 }
655 
656 } // namespace OHOS::Ace