| /* | |
| * Copyright 2006 The Android Open Source Project | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| * | |
| * Initial import from skia:src/core/SkMatrix.cpp | |
| * | |
| * Copyright 2022 Rive | |
| */ | |
| #include "rive/math/mat2d.hpp" | |
| #include "rive/math/math_types.hpp" | |
| #include <cmath> | |
| static inline float sdot(float a, float b, float c, float d) { return a * b + c * d; } | |
| namespace rive | |
| { | |
| float Mat2D::findMaxScale() const | |
| { | |
| if (xy() == 0 && yx() == 0) | |
| { | |
| return std::max(fabsf(xx()), fabsf(yy())); | |
| } | |
| // ignore the translation part of the matrix, just look at 2x2 portion. | |
| // compute singular values, take largest or smallest abs value. | |
| // [a b; b c] = A^T*A | |
| float a = sdot(xx(), xx(), xy(), xy()); | |
| float b = sdot(xx(), yx(), yy(), xy()); | |
| float c = sdot(yx(), yx(), yy(), yy()); | |
| // eigenvalues of A^T*A are the squared singular values of A. | |
| // characteristic equation is det((A^T*A) - l*I) = 0 | |
| // l^2 - (a + c)l + (ac-b^2) | |
| // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff | |
| // and roots are guaranteed to be pos and real). | |
| float bSqd = b * b; | |
| // if upper left 2x2 is orthogonal save some math | |
| float result; | |
| if (bSqd <= math::EPSILON * math::EPSILON) | |
| { | |
| result = std::max(a, c); | |
| } | |
| else | |
| { | |
| float aminusc = a - c; | |
| float apluscdiv2 = (a + c) * .5f; | |
| float x = sqrtf(aminusc * aminusc + 4 * bSqd) * .5f; | |
| result = apluscdiv2 + x; | |
| } | |
| if (!std::isfinite(result)) | |
| { | |
| result = 0; | |
| } | |
| // Due to the floating point inaccuracy, there might be an error in a, b, c | |
| // calculated by sdot, further deepened by subsequent arithmetic operations | |
| // on them. Therefore, we allow and cap the nearly-zero negative values. | |
| result = std::max(result, 0.f); | |
| result = sqrtf(result); | |
| return result; | |
| } | |
| } // namespace rive |