LCOV - code coverage report
Current view: top level - basegfx/source/matrix - b2dhommatrix.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 145 173 83.8 %
Date: 2015-06-13 12:38:46 Functions: 24 29 82.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <osl/diagnose.h>
      21             : #include <rtl/instance.hxx>
      22             : #include <basegfx/matrix/b2dhommatrix.hxx>
      23             : #include <hommatrixtemplate.hxx>
      24             : #include <basegfx/tuple/b2dtuple.hxx>
      25             : #include <basegfx/vector/b2dvector.hxx>
      26             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      27             : 
      28             : namespace basegfx
      29             : {
      30             :     typedef ::basegfx::internal::ImplHomMatrixTemplate< 3 > Impl2DHomMatrix_Base;
      31     4066387 :     class Impl2DHomMatrix : public Impl2DHomMatrix_Base
      32             :     {
      33             :     };
      34             : 
      35             :     namespace { struct IdentityMatrix : public rtl::Static< B2DHomMatrix::ImplType,
      36             :                                                             IdentityMatrix > {}; }
      37             : 
      38     1047827 :     B2DHomMatrix::B2DHomMatrix() :
      39     1047827 :         mpImpl( IdentityMatrix::get() ) // use common identity matrix
      40             :     {
      41     1047827 :     }
      42             : 
      43     2274576 :     B2DHomMatrix::B2DHomMatrix(const B2DHomMatrix& rMat) :
      44     2274576 :         mpImpl(rMat.mpImpl)
      45             :     {
      46     2274576 :     }
      47             : 
      48     3459844 :     B2DHomMatrix::~B2DHomMatrix()
      49             :     {
      50     3459844 :     }
      51             : 
      52      138698 :     B2DHomMatrix::B2DHomMatrix(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2)
      53      138698 :     :   mpImpl( IdentityMatrix::get() ) // use common identity matrix, will be made unique with 1st set-call
      54             :     {
      55      138698 :         mpImpl->set(0, 0, f_0x0);
      56      138698 :         mpImpl->set(0, 1, f_0x1);
      57      138698 :         mpImpl->set(0, 2, f_0x2);
      58      138698 :         mpImpl->set(1, 0, f_1x0);
      59      138698 :         mpImpl->set(1, 1, f_1x1);
      60      138698 :         mpImpl->set(1, 2, f_1x2);
      61      138698 :     }
      62             : 
      63      533160 :     B2DHomMatrix& B2DHomMatrix::operator=(const B2DHomMatrix& rMat)
      64             :     {
      65      533160 :         mpImpl = rMat.mpImpl;
      66      533160 :         return *this;
      67             :     }
      68             : 
      69    63162488 :     double B2DHomMatrix::get(sal_uInt16 nRow, sal_uInt16 nColumn) const
      70             :     {
      71    63162488 :         return mpImpl->get(nRow, nColumn);
      72             :     }
      73             : 
      74     1034916 :     void B2DHomMatrix::set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
      75             :     {
      76     1034916 :         mpImpl->set(nRow, nColumn, fValue);
      77     1034916 :     }
      78             : 
      79         644 :     void B2DHomMatrix::set3x2(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2)
      80             :     {
      81         644 :         mpImpl->set(0, 0, f_0x0);
      82         644 :         mpImpl->set(0, 1, f_0x1);
      83         644 :         mpImpl->set(0, 2, f_0x2);
      84         644 :         mpImpl->set(1, 0, f_1x0);
      85         644 :         mpImpl->set(1, 1, f_1x1);
      86         644 :         mpImpl->set(1, 2, f_1x2);
      87         644 :     }
      88             : 
      89     9672352 :     bool B2DHomMatrix::isLastLineDefault() const
      90             :     {
      91     9672352 :         return mpImpl->isLastLineDefault();
      92             :     }
      93             : 
      94     3501896 :     bool B2DHomMatrix::isIdentity() const
      95             :     {
      96     3501896 :         if(mpImpl.same_object(IdentityMatrix::get()))
      97      304092 :             return true;
      98             : 
      99     3197804 :         return mpImpl->isIdentity();
     100             :     }
     101             : 
     102       24619 :     void B2DHomMatrix::identity()
     103             :     {
     104       24619 :         mpImpl = IdentityMatrix::get();
     105       24619 :     }
     106             : 
     107           0 :     bool B2DHomMatrix::isInvertible() const
     108             :     {
     109           0 :         return mpImpl->isInvertible();
     110             :     }
     111             : 
     112       62503 :     bool B2DHomMatrix::invert()
     113             :     {
     114       62503 :         Impl2DHomMatrix aWork(*mpImpl);
     115       62503 :         sal_uInt16* pIndex = new sal_uInt16[Impl2DHomMatrix_Base::getEdgeLength()];
     116             :         sal_Int16 nParity;
     117             : 
     118       62503 :         if(aWork.ludcmp(pIndex, nParity))
     119             :         {
     120       62503 :             mpImpl->doInvert(aWork, pIndex);
     121       62503 :             delete[] pIndex;
     122             : 
     123       62503 :             return true;
     124             :         }
     125             : 
     126           0 :         delete[] pIndex;
     127           0 :         return false;
     128             :     }
     129             : 
     130           0 :     B2DHomMatrix& B2DHomMatrix::operator+=(const B2DHomMatrix& rMat)
     131             :     {
     132           0 :         mpImpl->doAddMatrix(*rMat.mpImpl);
     133           0 :         return *this;
     134             :     }
     135             : 
     136           0 :     B2DHomMatrix& B2DHomMatrix::operator-=(const B2DHomMatrix& rMat)
     137             :     {
     138           0 :         mpImpl->doSubMatrix(*rMat.mpImpl);
     139           0 :         return *this;
     140             :     }
     141             : 
     142           0 :     B2DHomMatrix& B2DHomMatrix::operator*=(double fValue)
     143             :     {
     144           0 :         const double fOne(1.0);
     145             : 
     146           0 :         if(!fTools::equal(fOne, fValue))
     147           0 :             mpImpl->doMulMatrix(fValue);
     148             : 
     149           0 :         return *this;
     150             :     }
     151             : 
     152           0 :     B2DHomMatrix& B2DHomMatrix::operator/=(double fValue)
     153             :     {
     154           0 :         const double fOne(1.0);
     155             : 
     156           0 :         if(!fTools::equal(fOne, fValue))
     157           0 :             mpImpl->doMulMatrix(1.0 / fValue);
     158             : 
     159           0 :         return *this;
     160             :     }
     161             : 
     162      503774 :     B2DHomMatrix& B2DHomMatrix::operator*=(const B2DHomMatrix& rMat)
     163             :     {
     164      503774 :         if(!rMat.isIdentity())
     165      479664 :             mpImpl->doMulMatrix(*rMat.mpImpl);
     166             : 
     167      503774 :         return *this;
     168             :     }
     169             : 
     170       78789 :     bool B2DHomMatrix::operator==(const B2DHomMatrix& rMat) const
     171             :     {
     172       78789 :         if(mpImpl.same_object(rMat.mpImpl))
     173       21744 :             return true;
     174             : 
     175       57045 :         return mpImpl->isEqual(*rMat.mpImpl);
     176             :     }
     177             : 
     178       20193 :     bool B2DHomMatrix::operator!=(const B2DHomMatrix& rMat) const
     179             :     {
     180       20193 :         return !(*this == rMat);
     181             :     }
     182             : 
     183      108634 :     void B2DHomMatrix::rotate(double fRadiant)
     184             :     {
     185      108634 :         if(!fTools::equalZero(fRadiant))
     186             :         {
     187       58291 :             double fSin(0.0);
     188       58291 :             double fCos(1.0);
     189             : 
     190       58291 :             tools::createSinCosOrthogonal(fSin, fCos, fRadiant);
     191       58291 :             Impl2DHomMatrix aRotMat;
     192             : 
     193       58291 :             aRotMat.set(0, 0, fCos);
     194       58291 :             aRotMat.set(1, 1, fCos);
     195       58291 :             aRotMat.set(1, 0, fSin);
     196       58291 :             aRotMat.set(0, 1, -fSin);
     197             : 
     198       58291 :             mpImpl->doMulMatrix(aRotMat);
     199             :         }
     200      108634 :     }
     201             : 
     202      365812 :     void B2DHomMatrix::translate(double fX, double fY)
     203             :     {
     204      365812 :         if(!fTools::equalZero(fX) || !fTools::equalZero(fY))
     205             :         {
     206      315017 :             Impl2DHomMatrix aTransMat;
     207             : 
     208      315017 :             aTransMat.set(0, 2, fX);
     209      315017 :             aTransMat.set(1, 2, fY);
     210             : 
     211      315017 :             mpImpl->doMulMatrix(aTransMat);
     212             :         }
     213      365812 :     }
     214             : 
     215      377517 :     void B2DHomMatrix::scale(double fX, double fY)
     216             :     {
     217      377517 :         const double fOne(1.0);
     218             : 
     219      377517 :         if(!fTools::equal(fOne, fX) || !fTools::equal(fOne, fY))
     220             :         {
     221      311470 :             Impl2DHomMatrix aScaleMat;
     222             : 
     223      311470 :             aScaleMat.set(0, 0, fX);
     224      311470 :             aScaleMat.set(1, 1, fY);
     225             : 
     226      311470 :             mpImpl->doMulMatrix(aScaleMat);
     227             :         }
     228      377517 :     }
     229             : 
     230         322 :     void B2DHomMatrix::shearX(double fSx)
     231             :     {
     232             :         // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
     233         322 :         if(!fTools::equalZero(fSx))
     234             :         {
     235          51 :             Impl2DHomMatrix aShearXMat;
     236             : 
     237          51 :             aShearXMat.set(0, 1, fSx);
     238             : 
     239          51 :             mpImpl->doMulMatrix(aShearXMat);
     240             :         }
     241         322 :     }
     242             : 
     243           1 :     void B2DHomMatrix::shearY(double fSy)
     244             :     {
     245             :         // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
     246           1 :         if(!fTools::equalZero(fSy))
     247             :         {
     248           1 :             Impl2DHomMatrix aShearYMat;
     249             : 
     250           1 :             aShearYMat.set(1, 0, fSy);
     251             : 
     252           1 :             mpImpl->doMulMatrix(aShearYMat);
     253             :         }
     254           1 :     }
     255             : 
     256             :     /** Decomposition
     257             : 
     258             :        New, optimized version with local shearX detection. Old version (keeping
     259             :        below, is working well, too) used the 3D matrix decomposition when
     260             :        shear was used. Keeping old version as comment below since it may get
     261             :        necessary to add the determinant() test from there here, too.
     262             :     */
     263      154453 :     bool B2DHomMatrix::decompose(B2DTuple& rScale, B2DTuple& rTranslate, double& rRotate, double& rShearX) const
     264             :     {
     265             :         // when perspective is used, decompose is not made here
     266      154453 :         if(!mpImpl->isLastLineDefault())
     267             :         {
     268           0 :             return false;
     269             :         }
     270             : 
     271             :         // reset rotate and shear and copy translation values in every case
     272      154453 :         rRotate = rShearX = 0.0;
     273      154453 :         rTranslate.setX(get(0, 2));
     274      154453 :         rTranslate.setY(get(1, 2));
     275             : 
     276             :         // test for rotation and shear
     277      154453 :         if(fTools::equalZero(get(0, 1)) && fTools::equalZero(get(1, 0)))
     278             :         {
     279             :             // no rotation and shear, copy scale values
     280      144598 :             rScale.setX(get(0, 0));
     281      144598 :             rScale.setY(get(1, 1));
     282             : 
     283             :             // or is there?
     284      144598 :             if( rScale.getX() < 0 && rScale.getY() < 0 )
     285             :             {
     286             :                 // there is - 180 degree rotated
     287         198 :                 rScale *= -1;
     288         198 :                 rRotate = 180*F_PI180;
     289             :             }
     290             :         }
     291             :         else
     292             :         {
     293             :             // get the unit vectors of the transformation -> the perpendicular vectors
     294        9855 :             B2DVector aUnitVecX(get(0, 0), get(1, 0));
     295       19710 :             B2DVector aUnitVecY(get(0, 1), get(1, 1));
     296        9855 :             const double fScalarXY(aUnitVecX.scalar(aUnitVecY));
     297             : 
     298             :             // Test if shear is zero. That's the case if the unit vectors in the matrix
     299             :             // are perpendicular -> scalar is zero. This is also the case when one of
     300             :             // the unit vectors is zero.
     301        9855 :             if(fTools::equalZero(fScalarXY))
     302             :             {
     303             :                 // calculate unsigned scale values
     304        7082 :                 rScale.setX(aUnitVecX.getLength());
     305        7082 :                 rScale.setY(aUnitVecY.getLength());
     306             : 
     307             :                 // check unit vectors for zero lengths
     308        7082 :                 const bool bXIsZero(fTools::equalZero(rScale.getX()));
     309        7082 :                 const bool bYIsZero(fTools::equalZero(rScale.getY()));
     310             : 
     311        7082 :                 if(bXIsZero || bYIsZero)
     312             :                 {
     313             :                     // still extract as much as possible. Scalings are already set
     314           0 :                     if(!bXIsZero)
     315             :                     {
     316             :                         // get rotation of X-Axis
     317           0 :                         rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX());
     318             :                     }
     319           0 :                     else if(!bYIsZero)
     320             :                     {
     321             :                         // get rotation of X-Axis. When assuming X and Y perpendicular
     322             :                         // and correct rotation, it's the Y-Axis rotation minus 90 degrees
     323           0 :                         rRotate = atan2(aUnitVecY.getY(), aUnitVecY.getX()) - M_PI_2;
     324             :                     }
     325             : 
     326             :                     // one or both unit vectors do not extist, determinant is zero, no decomposition possible.
     327             :                     // Eventually used rotations or shears are lost
     328           0 :                     return false;
     329             :                 }
     330             :                 else
     331             :                 {
     332             :                     // no shear
     333             :                     // calculate rotation of X unit vector relative to (1, 0)
     334        7082 :                     rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX());
     335             : 
     336             :                     // use orientation to evtl. correct sign of Y-Scale
     337        7082 :                     const double fCrossXY(aUnitVecX.cross(aUnitVecY));
     338             : 
     339        7082 :                     if(fCrossXY < 0.0)
     340             :                     {
     341           4 :                         rScale.setY(-rScale.getY());
     342             :                     }
     343             :                 }
     344             :             }
     345             :             else
     346             :             {
     347             :                 // fScalarXY is not zero, thus both unit vectors exist. No need to handle that here
     348             :                 // shear, extract it
     349        2773 :                 double fCrossXY(aUnitVecX.cross(aUnitVecY));
     350             : 
     351             :                 // get rotation by calculating angle of X unit vector relative to (1, 0).
     352             :                 // This is before the parallell test following the motto to extract
     353             :                 // as much as possible
     354        2773 :                 rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX());
     355             : 
     356             :                 // get unsigned scale value for X. It will not change and is useful
     357             :                 // for further corrections
     358        2773 :                 rScale.setX(aUnitVecX.getLength());
     359             : 
     360        2773 :                 if(fTools::equalZero(fCrossXY))
     361             :                 {
     362             :                     // extract as much as possible
     363           0 :                     rScale.setY(aUnitVecY.getLength());
     364             : 
     365             :                     // unit vectors are parallel, thus not linear independent. No
     366             :                     // useful decomposition possible. This should not happen since
     367             :                     // the only way to get the unit vectors nearly parallell is
     368             :                     // a very big shearing. Anyways, be prepared for hand-filled
     369             :                     // matrices
     370             :                     // Eventually used rotations or shears are lost
     371           0 :                     return false;
     372             :                 }
     373             :                 else
     374             :                 {
     375             :                     // calculate the contained shear
     376        2773 :                     rShearX = fScalarXY / fCrossXY;
     377             : 
     378        2773 :                     if(!fTools::equalZero(rRotate))
     379             :                     {
     380             :                         // To be able to correct the shear for aUnitVecY, rotation needs to be
     381             :                         // removed first. Correction of aUnitVecX is easy, it will be rotated back to (1, 0).
     382        2769 :                         aUnitVecX.setX(rScale.getX());
     383        2769 :                         aUnitVecX.setY(0.0);
     384             : 
     385             :                         // for Y correction we rotate the UnitVecY back about -rRotate
     386        2769 :                         const double fNegRotate(-rRotate);
     387        2769 :                         const double fSin(sin(fNegRotate));
     388        2769 :                         const double fCos(cos(fNegRotate));
     389             : 
     390        2769 :                         const double fNewX(aUnitVecY.getX() * fCos - aUnitVecY.getY() * fSin);
     391        2769 :                         const double fNewY(aUnitVecY.getX() * fSin + aUnitVecY.getY() * fCos);
     392             : 
     393        2769 :                         aUnitVecY.setX(fNewX);
     394        2769 :                         aUnitVecY.setY(fNewY);
     395             :                     }
     396             : 
     397             :                     // Correct aUnitVecY and fCrossXY to fShear=0. Rotation is already removed.
     398             :                     // Shear correction can only work with removed rotation
     399        2773 :                     aUnitVecY.setX(aUnitVecY.getX() - (aUnitVecY.getY() * rShearX));
     400        2773 :                     fCrossXY = aUnitVecX.cross(aUnitVecY);
     401             : 
     402             :                     // calculate unsigned scale value for Y, after the corrections since
     403             :                     // the shear correction WILL change the length of aUnitVecY
     404        2773 :                     rScale.setY(aUnitVecY.getLength());
     405             : 
     406             :                     // use orientation to set sign of Y-Scale
     407        2773 :                     if(fCrossXY < 0.0)
     408             :                     {
     409          12 :                         rScale.setY(-rScale.getY());
     410             :                     }
     411             :                 }
     412        9855 :             }
     413             :         }
     414             : 
     415      154453 :         return true;
     416             :     }
     417             : } // end of namespace basegfx
     418             : 
     419             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11