Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: src/core/SkMatrix.cpp

Issue 23596006: Revise SVD code to remove arctangents. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Fix matrix_decompose bench to actually check random matrices. Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « bench/MatrixBench.cpp ('k') | src/core/SkMatrixUtils.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2006 The Android Open Source Project 2 * Copyright 2006 The Android Open Source Project
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkMatrix.h" 8 #include "SkMatrix.h"
9 #include "Sk64.h" 9 #include "Sk64.h"
10 #include "SkFloatBits.h" 10 #include "SkFloatBits.h"
(...skipping 1989 matching lines...) Expand 10 before | Expand all | Expand 10 after
2000 dst.fTop *= scale; 2000 dst.fTop *= scale;
2001 dst.fRight *= scale; 2001 dst.fRight *= scale;
2002 dst.fBottom *= scale; 2002 dst.fBottom *= scale;
2003 } 2003 }
2004 2004
2005 SkIRect idst; 2005 SkIRect idst;
2006 dst.round(&idst); 2006 dst.round(&idst);
2007 return isrc == idst; 2007 return isrc == idst;
2008 } 2008 }
2009 2009
2010 // A square matrix M can be decomposed (via polar decomposition) into two matric es --
2011 // an orthogonal matrix Q and a symmetric matrix S. In turn we can decompose S i nto U*W*U^T,
2012 // where U is another orthogonal matrix and W is a scale matrix. These can be re combined
2013 // to give M = (Q*U)*W*U^T, i.e., the product of two orthogonal matrices and a s cale matrix.
2014 //
2015 // The one wrinkle is that traditionally Q may contain a reflection -- the
2016 // calculation has been rejiggered to put that reflection into W.
2010 bool SkDecomposeUpper2x2(const SkMatrix& matrix, 2017 bool SkDecomposeUpper2x2(const SkMatrix& matrix,
2011 SkScalar* rotation0, 2018 SkPoint* rotation1,
2012 SkScalar* xScale, SkScalar* yScale, 2019 SkPoint* scale,
2013 SkScalar* rotation1) { 2020 SkPoint* rotation2) {
2014 2021
2015 // borrowed from Jim Blinn's article "Consider the Lowly 2x2 Matrix"
2016 // Note: he uses row vectors, so we have to do some swapping of terms
2017 SkScalar A = matrix[SkMatrix::kMScaleX]; 2022 SkScalar A = matrix[SkMatrix::kMScaleX];
2018 SkScalar B = matrix[SkMatrix::kMSkewX]; 2023 SkScalar B = matrix[SkMatrix::kMSkewX];
2019 SkScalar C = matrix[SkMatrix::kMSkewY]; 2024 SkScalar C = matrix[SkMatrix::kMSkewY];
2020 SkScalar D = matrix[SkMatrix::kMScaleY]; 2025 SkScalar D = matrix[SkMatrix::kMScaleY];
2021 2026
2022 if (is_degenerate_2x2(A, B, C, D)) { 2027 if (is_degenerate_2x2(A, B, C, D)) {
2023 return false; 2028 return false;
2024 } 2029 }
2025 2030
2026 SkScalar E = SK_ScalarHalf*(A + D); 2031 double w1, w2;
2027 SkScalar F = SK_ScalarHalf*(A - D); 2032 SkScalar cos1, sin1;
2028 SkScalar G = SK_ScalarHalf*(C + B); 2033 SkScalar cos2, sin2;
2029 SkScalar H = SK_ScalarHalf*(C - B);
2030 2034
2031 SkScalar sqrt0 = SkScalarSqrt(E*E + H*H); 2035 // do polar decomposition (M = Q*S)
2032 SkScalar sqrt1 = SkScalarSqrt(F*F + G*G); 2036 SkScalar cosQ, sinQ;
2037 double Sa, Sb, Sd;
2038 // if M is already symmetric (i.e., M = I*S)
2039 if (SkScalarNearlyEqual(B, C)) {
2040 cosQ = SK_Scalar1;
2041 sinQ = 0;
2033 2042
2034 SkScalar xs, ys, r0, r1; 2043 Sa = A;
2044 Sb = B;
2045 Sd = D;
2046 } else {
2047 cosQ = A + D;
2048 sinQ = C - B;
2049 SkScalar reciplen = SK_Scalar1/SkScalarSqrt(cosQ*cosQ + sinQ*sinQ);
2050 cosQ *= reciplen;
2051 sinQ *= reciplen;
2035 2052
2036 xs = sqrt0 + sqrt1; 2053 // S = Q^-1*M
2037 ys = sqrt0 - sqrt1; 2054 // we don't calc Sc since it's symmetric
2038 // can't have zero yScale, must be degenerate 2055 Sa = A*cosQ + C*sinQ;
2039 SkASSERT(!SkScalarNearlyZero(ys)); 2056 Sb = B*cosQ + D*sinQ;
2040 2057 Sd = -B*sinQ + D*cosQ;
2041 // uniformly scaled rotation
2042 if (SkScalarNearlyZero(F) && SkScalarNearlyZero(G)) {
2043 SkASSERT(!SkScalarNearlyZero(E) || !SkScalarNearlyZero(H));
2044 r0 = SkScalarATan2(H, E);
2045 r1 = 0;
2046 // uniformly scaled reflection
2047 } else if (SkScalarNearlyZero(E) && SkScalarNearlyZero(H)) {
2048 SkASSERT(!SkScalarNearlyZero(F) || !SkScalarNearlyZero(G));
2049 r0 = -SkScalarATan2(G, F);
2050 r1 = 0;
2051 } else {
2052 SkASSERT(!SkScalarNearlyZero(E) || !SkScalarNearlyZero(H));
2053 SkASSERT(!SkScalarNearlyZero(F) || !SkScalarNearlyZero(G));
2054
2055 SkScalar arctan0 = SkScalarATan2(H, E);
2056 SkScalar arctan1 = SkScalarATan2(G, F);
2057 r0 = SK_ScalarHalf*(arctan0 - arctan1);
2058 r1 = SK_ScalarHalf*(arctan0 + arctan1);
2059
2060 // simplify the results
2061 const SkScalar kHalfPI = SK_ScalarHalf*SK_ScalarPI;
2062 if (SkScalarNearlyEqual(SkScalarAbs(r0), kHalfPI)) {
2063 SkScalar tmp = xs;
2064 xs = ys;
2065 ys = tmp;
2066
2067 r1 += r0;
2068 r0 = 0;
2069 } else if (SkScalarNearlyEqual(SkScalarAbs(r1), kHalfPI)) {
2070 SkScalar tmp = xs;
2071 xs = ys;
2072 ys = tmp;
2073
2074 r0 += r1;
2075 r1 = 0;
2076 }
2077 } 2058 }
2078 2059
2079 if (NULL != xScale) { 2060 // Now we need to compute eigenvalues of S (our scale factors)
2080 *xScale = xs; 2061 // and eigenvectors (bases for our rotation)
2062 // From this, should be able to reconstruct S as U*W*U^T
2063 if (SkScalarNearlyZero(Sb)) {
2064 // already diagonalized
2065 cos1 = SK_Scalar1;
2066 sin1 = 0;
2067 w1 = Sa;
2068 w2 = Sd;
2069 cos2 = cosQ;
2070 sin2 = sinQ;
2071 } else {
2072 double diff = Sa - Sd;
2073 double discriminant = sqrt(diff*diff + 4.0*Sb*Sb);
2074 double trace = Sa + Sd;
2075 if (diff > 0) {
2076 w1 = 0.5*(trace + discriminant);
2077 w2 = 0.5*(trace - discriminant);
2078 } else {
2079 w1 = 0.5*(trace - discriminant);
2080 w2 = 0.5*(trace + discriminant);
2081 }
2082
2083 cos1 = Sb; sin1 = w1 - Sa;
2084 SkScalar reciplen = SK_Scalar1/SkScalarSqrt(cos1*cos1 + sin1*sin1);
2085 cos1 *= reciplen;
2086 sin1 *= reciplen;
2087
2088 // rotation 2 is composition of Q and U
2089 cos2 = cos1*cosQ - sin1*sinQ;
2090 sin2 = sin1*cosQ + cos1*sinQ;
2091
2092 // rotation 1 is U^T
2093 sin1 = -sin1;
2081 } 2094 }
2082 if (NULL != yScale) { 2095
2083 *yScale = ys; 2096 if (NULL != scale) {
2084 } 2097 scale->fX = w1;
2085 if (NULL != rotation0) { 2098 scale->fY = w2;
2086 *rotation0 = r0;
2087 } 2099 }
2088 if (NULL != rotation1) { 2100 if (NULL != rotation1) {
2089 *rotation1 = r1; 2101 rotation1->fX = cos1;
2102 rotation1->fY = sin1;
2103 }
2104 if (NULL != rotation2) {
2105 rotation2->fX = cos2;
2106 rotation2->fY = sin2;
2090 } 2107 }
2091 2108
2092 return true; 2109 return true;
2093 } 2110 }
OLDNEW
« no previous file with comments | « bench/MatrixBench.cpp ('k') | src/core/SkMatrixUtils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698