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

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

Issue 298473002: Add function to get both min and max scale factors from matrix (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Address comments Created 6 years, 7 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 | « include/core/SkMatrix.h ('k') | tests/MatrixTest.cpp » ('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 "SkFloatBits.h" 9 #include "SkFloatBits.h"
10 #include "SkOnce.h" 10 #include "SkOnce.h"
(...skipping 1433 matching lines...) Expand 10 before | Expand all | Expand 10 after
1444 } 1444 }
1445 if (!proc(dst, &tempMap, scale)) { 1445 if (!proc(dst, &tempMap, scale)) {
1446 return false; 1446 return false;
1447 } 1447 }
1448 this->setConcat(tempMap, result); 1448 this->setConcat(tempMap, result);
1449 return true; 1449 return true;
1450 } 1450 }
1451 1451
1452 /////////////////////////////////////////////////////////////////////////////// 1452 ///////////////////////////////////////////////////////////////////////////////
1453 1453
1454 enum MinOrMax { 1454 enum MinMaxOrBoth {
1455 kMin_MinOrMax, 1455 kMin_MinMaxOrBoth,
1456 kMax_MinOrMax 1456 kMax_MinMaxOrBoth,
1457 kBoth_MinMaxOrBoth
1457 }; 1458 };
1458 1459
1459 template <MinOrMax MIN_OR_MAX> SkScalar get_scale_factor(SkMatrix::TypeMask type Mask, 1460 template <MinMaxOrBoth MIN_MAX_OR_BOTH> bool get_scale_factor(SkMatrix::TypeMask typeMask,
1460 const SkScalar m[9]) { 1461 const SkScalar m[9 ],
1462 SkScalar results[/ *1 or 2*/]) {
1461 if (typeMask & SkMatrix::kPerspective_Mask) { 1463 if (typeMask & SkMatrix::kPerspective_Mask) {
1462 return -1; 1464 return false;
1463 } 1465 }
1464 if (SkMatrix::kIdentity_Mask == typeMask) { 1466 if (SkMatrix::kIdentity_Mask == typeMask) {
1465 return 1; 1467 results[0] = SK_Scalar1;
1468 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1469 results[1] = SK_Scalar1;
1470 }
1471 return true;
1466 } 1472 }
1467 if (!(typeMask & SkMatrix::kAffine_Mask)) { 1473 if (!(typeMask & SkMatrix::kAffine_Mask)) {
1468 if (kMin_MinOrMax == MIN_OR_MAX) { 1474 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1469 return SkMinScalar(SkScalarAbs(m[SkMatrix::kMScaleX]), 1475 results[0] = SkMinScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
1470 SkScalarAbs(m[SkMatrix::kMScaleY])); 1476 SkScalarAbs(m[SkMatrix::kMScaleY]));
1477 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1478 results[0] = SkMaxScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
1479 SkScalarAbs(m[SkMatrix::kMScaleY]));
1471 } else { 1480 } else {
1472 return SkMaxScalar(SkScalarAbs(m[SkMatrix::kMScaleX]), 1481 results[0] = SkScalarAbs(m[SkMatrix::kMScaleX]);
1473 SkScalarAbs(m[SkMatrix::kMScaleY])); 1482 results[1] = SkScalarAbs(m[SkMatrix::kMScaleY]);
1483 if (results[0] > results[1]) {
1484 SkTSwap(results[0], results[1]);
1485 }
1474 } 1486 }
1487 return true;
1475 } 1488 }
1476 // ignore the translation part of the matrix, just look at 2x2 portion. 1489 // ignore the translation part of the matrix, just look at 2x2 portion.
1477 // compute singular values, take largest or smallest abs value. 1490 // compute singular values, take largest or smallest abs value.
1478 // [a b; b c] = A^T*A 1491 // [a b; b c] = A^T*A
1479 SkScalar a = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX], 1492 SkScalar a = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX],
1480 m[SkMatrix::kMSkewY], m[SkMatrix::kMSkewY]); 1493 m[SkMatrix::kMSkewY], m[SkMatrix::kMSkewY]);
1481 SkScalar b = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX], 1494 SkScalar b = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX],
1482 m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]); 1495 m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]);
1483 SkScalar c = sdot(m[SkMatrix::kMSkewX], m[SkMatrix::kMSkewX], 1496 SkScalar c = sdot(m[SkMatrix::kMSkewX], m[SkMatrix::kMSkewX],
1484 m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]); 1497 m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]);
1485 // eigenvalues of A^T*A are the squared singular values of A. 1498 // eigenvalues of A^T*A are the squared singular values of A.
1486 // characteristic equation is det((A^T*A) - l*I) = 0 1499 // characteristic equation is det((A^T*A) - l*I) = 0
1487 // l^2 - (a + c)l + (ac-b^2) 1500 // l^2 - (a + c)l + (ac-b^2)
1488 // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff 1501 // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
1489 // and roots are guaranteed to be pos and real). 1502 // and roots are guaranteed to be pos and real).
1490 SkScalar chosenRoot;
1491 SkScalar bSqd = b * b; 1503 SkScalar bSqd = b * b;
1492 // if upper left 2x2 is orthogonal save some math 1504 // if upper left 2x2 is orthogonal save some math
1493 if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) { 1505 if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
1494 if (kMin_MinOrMax == MIN_OR_MAX) { 1506 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1495 chosenRoot = SkMinScalar(a, c); 1507 results[0] = SkMinScalar(a, c);
1508 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1509 results[0] = SkMaxScalar(a, c);
1496 } else { 1510 } else {
1497 chosenRoot = SkMaxScalar(a, c); 1511 results[0] = a;
1512 results[1] = c;
1513 if (results[0] > results[1]) {
1514 SkTSwap(results[0], results[1]);
1515 }
1498 } 1516 }
1499 } else { 1517 } else {
1500 SkScalar aminusc = a - c; 1518 SkScalar aminusc = a - c;
1501 SkScalar apluscdiv2 = SkScalarHalf(a + c); 1519 SkScalar apluscdiv2 = SkScalarHalf(a + c);
1502 SkScalar x = SkScalarHalf(SkScalarSqrt(aminusc * aminusc + 4 * bSqd)); 1520 SkScalar x = SkScalarHalf(SkScalarSqrt(aminusc * aminusc + 4 * bSqd));
1503 if (kMin_MinOrMax == MIN_OR_MAX) { 1521 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1504 chosenRoot = apluscdiv2 - x; 1522 results[0] = apluscdiv2 - x;
1523 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1524 results[0] = apluscdiv2 + x;
1505 } else { 1525 } else {
1506 chosenRoot = apluscdiv2 + x; 1526 results[0] = apluscdiv2 - x;
1527 results[1] = apluscdiv2 + x;
1507 } 1528 }
1508 } 1529 }
1509 SkASSERT(chosenRoot >= 0); 1530 SkASSERT(results[0] >= 0);
1510 return SkScalarSqrt(chosenRoot); 1531 results[0] = SkScalarSqrt(results[0]);
1532 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1533 SkASSERT(results[1] >= 0);
1534 results[1] = SkScalarSqrt(results[1]);
1535 }
1536 return true;
1511 } 1537 }
1512 1538
1513 SkScalar SkMatrix::getMinScale() const { 1539 SkScalar SkMatrix::getMinScale() const {
1514 return get_scale_factor<kMin_MinOrMax>(this->getType(), fMat); 1540 SkScalar factor;
1541 if (get_scale_factor<kMin_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1542 return factor;
1543 } else {
1544 return -1;
1545 }
1515 } 1546 }
1516 1547
1517 SkScalar SkMatrix::getMaxScale() const { 1548 SkScalar SkMatrix::getMaxScale() const {
1518 return get_scale_factor<kMax_MinOrMax>(this->getType(), fMat); 1549 SkScalar factor;
1550 if (get_scale_factor<kMax_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1551 return factor;
1552 } else {
1553 return -1;
1554 }
1555 }
1556
1557 bool SkMatrix::getMinMaxScales(SkScalar scaleFactors[2]) const {
1558 return get_scale_factor<kBoth_MinMaxOrBoth>(this->getType(), fMat, scaleFact ors);
1519 } 1559 }
1520 1560
1521 static void reset_identity_matrix(SkMatrix* identity) { 1561 static void reset_identity_matrix(SkMatrix* identity) {
1522 identity->reset(); 1562 identity->reset();
1523 } 1563 }
1524 1564
1525 const SkMatrix& SkMatrix::I() { 1565 const SkMatrix& SkMatrix::I() {
1526 // If you can use C++11 now, you might consider replacing this with a conste xpr constructor. 1566 // If you can use C++11 now, you might consider replacing this with a conste xpr constructor.
1527 static SkMatrix gIdentity; 1567 static SkMatrix gIdentity;
1528 SK_DECLARE_STATIC_ONCE(once); 1568 SK_DECLARE_STATIC_ONCE(once);
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
1728 rotation1->fX = cos1; 1768 rotation1->fX = cos1;
1729 rotation1->fY = sin1; 1769 rotation1->fY = sin1;
1730 } 1770 }
1731 if (NULL != rotation2) { 1771 if (NULL != rotation2) {
1732 rotation2->fX = cos2; 1772 rotation2->fX = cos2;
1733 rotation2->fY = sin2; 1773 rotation2->fY = sin2;
1734 } 1774 }
1735 1775
1736 return true; 1776 return true;
1737 } 1777 }
OLDNEW
« no previous file with comments | « include/core/SkMatrix.h ('k') | tests/MatrixTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698