LCOV - code coverage report
Current view: top level - libreoffice/basegfx/source/matrix - b2dhommatrix.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 145 173 83.8 %
Date: 2012-12-27 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             : ///////////////////////////////////////////////////////////////////////////////
      29             : 
      30             : namespace basegfx
      31             : {
      32       36761 :     class Impl2DHomMatrix : public ::basegfx::internal::ImplHomMatrixTemplate< 3 >
      33             :     {
      34             :     };
      35             : 
      36             :     namespace { struct IdentityMatrix : public rtl::Static< B2DHomMatrix::ImplType,
      37             :                                                             IdentityMatrix > {}; }
      38             : 
      39       22453 :     B2DHomMatrix::B2DHomMatrix() :
      40       22453 :         mpImpl( IdentityMatrix::get() ) // use common identity matrix
      41             :     {
      42       22453 :     }
      43             : 
      44       17309 :     B2DHomMatrix::B2DHomMatrix(const B2DHomMatrix& rMat) :
      45       17309 :         mpImpl(rMat.mpImpl)
      46             :     {
      47       17309 :     }
      48             : 
      49       40021 :     B2DHomMatrix::~B2DHomMatrix()
      50             :     {
      51       40021 :     }
      52             : 
      53        1754 :     B2DHomMatrix::B2DHomMatrix(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2)
      54        1754 :     :   mpImpl( IdentityMatrix::get() ) // use common identity matrix, will be made unique with 1st set-call
      55             :     {
      56        1754 :         mpImpl->set(0, 0, f_0x0);
      57        1754 :         mpImpl->set(0, 1, f_0x1);
      58        1754 :         mpImpl->set(0, 2, f_0x2);
      59        1754 :         mpImpl->set(1, 0, f_1x0);
      60        1754 :         mpImpl->set(1, 1, f_1x1);
      61        1754 :         mpImpl->set(1, 2, f_1x2);
      62        1754 :     }
      63             : 
      64        6729 :     B2DHomMatrix& B2DHomMatrix::operator=(const B2DHomMatrix& rMat)
      65             :     {
      66        6729 :         mpImpl = rMat.mpImpl;
      67        6729 :         return *this;
      68             :     }
      69             : 
      70      222555 :     double B2DHomMatrix::get(sal_uInt16 nRow, sal_uInt16 nColumn) const
      71             :     {
      72      222555 :         return mpImpl->get(nRow, nColumn);
      73             :     }
      74             : 
      75       23915 :     void B2DHomMatrix::set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
      76             :     {
      77       23915 :         mpImpl->set(nRow, nColumn, fValue);
      78       23915 :     }
      79             : 
      80           3 :     void B2DHomMatrix::set3x2(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2)
      81             :     {
      82           3 :         mpImpl->set(0, 0, f_0x0);
      83           3 :         mpImpl->set(0, 1, f_0x1);
      84           3 :         mpImpl->set(0, 2, f_0x2);
      85           3 :         mpImpl->set(1, 0, f_1x0);
      86           3 :         mpImpl->set(1, 1, f_1x1);
      87           3 :         mpImpl->set(1, 2, f_1x2);
      88           3 :     }
      89             : 
      90       21443 :     bool B2DHomMatrix::isLastLineDefault() const
      91             :     {
      92       21443 :         return mpImpl->isLastLineDefault();
      93             :     }
      94             : 
      95       21654 :     bool B2DHomMatrix::isIdentity() const
      96             :     {
      97       21654 :         if(mpImpl.same_object(IdentityMatrix::get()))
      98        4502 :             return true;
      99             : 
     100       17152 :         return mpImpl->isIdentity();
     101             :     }
     102             : 
     103         160 :     void B2DHomMatrix::identity()
     104             :     {
     105         160 :         mpImpl = IdentityMatrix::get();
     106         160 :     }
     107             : 
     108           0 :     bool B2DHomMatrix::isInvertible() const
     109             :     {
     110           0 :         return mpImpl->isInvertible();
     111             :     }
     112             : 
     113         642 :     bool B2DHomMatrix::invert()
     114             :     {
     115         642 :         Impl2DHomMatrix aWork(*mpImpl);
     116         642 :         sal_uInt16* pIndex = new sal_uInt16[mpImpl->getEdgeLength()];
     117             :         sal_Int16 nParity;
     118             : 
     119         642 :         if(aWork.ludcmp(pIndex, nParity))
     120             :         {
     121         642 :             mpImpl->doInvert(aWork, pIndex);
     122         642 :             delete[] pIndex;
     123             : 
     124         642 :             return true;
     125             :         }
     126             : 
     127           0 :         delete[] pIndex;
     128           0 :         return false;
     129             :     }
     130             : 
     131           0 :     B2DHomMatrix& B2DHomMatrix::operator+=(const B2DHomMatrix& rMat)
     132             :     {
     133           0 :         mpImpl->doAddMatrix(*rMat.mpImpl);
     134           0 :         return *this;
     135             :     }
     136             : 
     137           0 :     B2DHomMatrix& B2DHomMatrix::operator-=(const B2DHomMatrix& rMat)
     138             :     {
     139           0 :         mpImpl->doSubMatrix(*rMat.mpImpl);
     140           0 :         return *this;
     141             :     }
     142             : 
     143           0 :     B2DHomMatrix& B2DHomMatrix::operator*=(double fValue)
     144             :     {
     145           0 :         const double fOne(1.0);
     146             : 
     147           0 :         if(!fTools::equal(fOne, fValue))
     148           0 :             mpImpl->doMulMatrix(fValue);
     149             : 
     150           0 :         return *this;
     151             :     }
     152             : 
     153           0 :     B2DHomMatrix& B2DHomMatrix::operator/=(double fValue)
     154             :     {
     155           0 :         const double fOne(1.0);
     156             : 
     157           0 :         if(!fTools::equal(fOne, fValue))
     158           0 :             mpImpl->doMulMatrix(1.0 / fValue);
     159             : 
     160           0 :         return *this;
     161             :     }
     162             : 
     163        3694 :     B2DHomMatrix& B2DHomMatrix::operator*=(const B2DHomMatrix& rMat)
     164             :     {
     165        3694 :         if(!rMat.isIdentity())
     166        3397 :             mpImpl->doMulMatrix(*rMat.mpImpl);
     167             : 
     168        3694 :         return *this;
     169             :     }
     170             : 
     171         876 :     bool B2DHomMatrix::operator==(const B2DHomMatrix& rMat) const
     172             :     {
     173         876 :         if(mpImpl.same_object(rMat.mpImpl))
     174         649 :             return true;
     175             : 
     176         227 :         return mpImpl->isEqual(*rMat.mpImpl);
     177             :     }
     178             : 
     179          77 :     bool B2DHomMatrix::operator!=(const B2DHomMatrix& rMat) const
     180             :     {
     181          77 :         return !(*this == rMat);
     182             :     }
     183             : 
     184        3471 :     void B2DHomMatrix::rotate(double fRadiant)
     185             :     {
     186        3471 :         if(!fTools::equalZero(fRadiant))
     187             :         {
     188        2218 :             double fSin(0.0);
     189        2218 :             double fCos(1.0);
     190             : 
     191        2218 :             tools::createSinCosOrthogonal(fSin, fCos, fRadiant);
     192        2218 :             Impl2DHomMatrix aRotMat;
     193             : 
     194        2218 :             aRotMat.set(0, 0, fCos);
     195        2218 :             aRotMat.set(1, 1, fCos);
     196        2218 :             aRotMat.set(1, 0, fSin);
     197        2218 :             aRotMat.set(0, 1, -fSin);
     198             : 
     199        2218 :             mpImpl->doMulMatrix(aRotMat);
     200             :         }
     201        3471 :     }
     202             : 
     203        1743 :     void B2DHomMatrix::translate(double fX, double fY)
     204             :     {
     205        1743 :         if(!fTools::equalZero(fX) || !fTools::equalZero(fY))
     206             :         {
     207        1722 :             Impl2DHomMatrix aTransMat;
     208             : 
     209        1722 :             aTransMat.set(0, 2, fX);
     210        1722 :             aTransMat.set(1, 2, fY);
     211             : 
     212        1722 :             mpImpl->doMulMatrix(aTransMat);
     213             :         }
     214        1743 :     }
     215             : 
     216         640 :     void B2DHomMatrix::scale(double fX, double fY)
     217             :     {
     218         640 :         const double fOne(1.0);
     219             : 
     220         640 :         if(!fTools::equal(fOne, fX) || !fTools::equal(fOne, fY))
     221             :         {
     222         552 :             Impl2DHomMatrix aScaleMat;
     223             : 
     224         552 :             aScaleMat.set(0, 0, fX);
     225         552 :             aScaleMat.set(1, 1, fY);
     226             : 
     227         552 :             mpImpl->doMulMatrix(aScaleMat);
     228             :         }
     229         640 :     }
     230             : 
     231          83 :     void B2DHomMatrix::shearX(double fSx)
     232             :     {
     233             :         // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
     234          83 :         if(!fTools::equalZero(fSx))
     235             :         {
     236          49 :             Impl2DHomMatrix aShearXMat;
     237             : 
     238          49 :             aShearXMat.set(0, 1, fSx);
     239             : 
     240          49 :             mpImpl->doMulMatrix(aShearXMat);
     241             :         }
     242          83 :     }
     243             : 
     244           1 :     void B2DHomMatrix::shearY(double fSy)
     245             :     {
     246             :         // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
     247           1 :         if(!fTools::equalZero(fSy))
     248             :         {
     249           1 :             Impl2DHomMatrix aShearYMat;
     250             : 
     251           1 :             aShearYMat.set(1, 0, fSy);
     252             : 
     253           1 :             mpImpl->doMulMatrix(aShearYMat);
     254             :         }
     255           1 :     }
     256             : 
     257             :     /** Decomposition
     258             : 
     259             :        New, optimized version with local shearX detection. Old version (keeping
     260             :        below, is working well, too) used the 3D matrix decomposition when
     261             :        shear was used. Keeping old version as comment below since it may get
     262             :        necessary to add the determinant() test from there here, too.
     263             :     */
     264        8113 :     bool B2DHomMatrix::decompose(B2DTuple& rScale, B2DTuple& rTranslate, double& rRotate, double& rShearX) const
     265             :     {
     266             :         // when perspective is used, decompose is not made here
     267        8113 :         if(!mpImpl->isLastLineDefault())
     268             :         {
     269           0 :             return false;
     270             :         }
     271             : 
     272             :         // reset rotate and shear and copy translation values in every case
     273        8113 :         rRotate = rShearX = 0.0;
     274        8113 :         rTranslate.setX(get(0, 2));
     275        8113 :         rTranslate.setY(get(1, 2));
     276             : 
     277             :         // test for rotation and shear
     278        8113 :         if(fTools::equalZero(get(0, 1)) && fTools::equalZero(get(1, 0)))
     279             :         {
     280             :             // no rotation and shear, copy scale values
     281        8072 :             rScale.setX(get(0, 0));
     282        8072 :             rScale.setY(get(1, 1));
     283             : 
     284             :             // or is there?
     285        8072 :             if( rScale.getX() < 0 && rScale.getY() < 0 )
     286             :             {
     287             :                 // there is - 180 degree rotated
     288           2 :                 rScale *= -1;
     289           2 :                 rRotate = 180*F_PI180;
     290             :             }
     291             :         }
     292             :         else
     293             :         {
     294             :             // get the unit vectors of the transformation -> the perpendicular vectors
     295          41 :             B2DVector aUnitVecX(get(0, 0), get(1, 0));
     296          41 :             B2DVector aUnitVecY(get(0, 1), get(1, 1));
     297          41 :             const double fScalarXY(aUnitVecX.scalar(aUnitVecY));
     298             : 
     299             :             // Test if shear is zero. That's the case if the unit vectors in the matrix
     300             :             // are perpendicular -> scalar is zero. This is also the case when one of
     301             :             // the unit vectors is zero.
     302          41 :             if(fTools::equalZero(fScalarXY))
     303             :             {
     304             :                 // calculate unsigned scale values
     305          17 :                 rScale.setX(aUnitVecX.getLength());
     306          17 :                 rScale.setY(aUnitVecY.getLength());
     307             : 
     308             :                 // check unit vectors for zero lengths
     309          17 :                 const bool bXIsZero(fTools::equalZero(rScale.getX()));
     310          17 :                 const bool bYIsZero(fTools::equalZero(rScale.getY()));
     311             : 
     312          17 :                 if(bXIsZero || bYIsZero)
     313             :                 {
     314             :                     // still extract as much as possible. Scalings are already set
     315           0 :                     if(!bXIsZero)
     316             :                     {
     317             :                         // get rotation of X-Axis
     318           0 :                         rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX());
     319             :                     }
     320           0 :                     else if(!bYIsZero)
     321             :                     {
     322             :                         // get rotation of X-Axis. When assuming X and Y perpendicular
     323             :                         // and correct rotation, it's the Y-Axis rotation minus 90 degrees
     324           0 :                         rRotate = atan2(aUnitVecY.getY(), aUnitVecY.getX()) - M_PI_2;
     325             :                     }
     326             : 
     327             :                     // one or both unit vectors do not extist, determinant is zero, no decomposition possible.
     328             :                     // Eventually used rotations or shears are lost
     329           0 :                     return false;
     330             :                 }
     331             :                 else
     332             :                 {
     333             :                     // no shear
     334             :                     // calculate rotation of X unit vector relative to (1, 0)
     335          17 :                     rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX());
     336             : 
     337             :                     // use orientation to evtl. correct sign of Y-Scale
     338          17 :                     const double fCrossXY(aUnitVecX.cross(aUnitVecY));
     339             : 
     340          17 :                     if(fCrossXY < 0.0)
     341             :                     {
     342           4 :                         rScale.setY(-rScale.getY());
     343             :                     }
     344             :                 }
     345             :             }
     346             :             else
     347             :             {
     348             :                 // fScalarXY is not zero, thus both unit vectors exist. No need to handle that here
     349             :                 // shear, extract it
     350          24 :                 double fCrossXY(aUnitVecX.cross(aUnitVecY));
     351             : 
     352             :                 // get rotation by calculating angle of X unit vector relative to (1, 0).
     353             :                 // This is before the parallell test following the motto to extract
     354             :                 // as much as possible
     355          24 :                 rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX());
     356             : 
     357             :                 // get unsigned scale value for X. It will not change and is useful
     358             :                 // for further corrections
     359          24 :                 rScale.setX(aUnitVecX.getLength());
     360             : 
     361          24 :                 if(fTools::equalZero(fCrossXY))
     362             :                 {
     363             :                     // extract as much as possible
     364           0 :                     rScale.setY(aUnitVecY.getLength());
     365             : 
     366             :                     // unit vectors are parallel, thus not linear independent. No
     367             :                     // useful decomposition possible. This should not happen since
     368             :                     // the only way to get the unit vectors nearly parallell is
     369             :                     // a very big shearing. Anyways, be prepared for hand-filled
     370             :                     // matrices
     371             :                     // Eventually used rotations or shears are lost
     372           0 :                     return false;
     373             :                 }
     374             :                 else
     375             :                 {
     376             :                     // calculate the contained shear
     377          24 :                     rShearX = fScalarXY / fCrossXY;
     378             : 
     379          24 :                     if(!fTools::equalZero(rRotate))
     380             :                     {
     381             :                         // To be able to correct the shear for aUnitVecY, rotation needs to be
     382             :                         // removed first. Correction of aUnitVecX is easy, it will be rotated back to (1, 0).
     383          20 :                         aUnitVecX.setX(rScale.getX());
     384          20 :                         aUnitVecX.setY(0.0);
     385             : 
     386             :                         // for Y correction we rotate the UnitVecY back about -rRotate
     387          20 :                         const double fNegRotate(-rRotate);
     388          20 :                         const double fSin(sin(fNegRotate));
     389          20 :                         const double fCos(cos(fNegRotate));
     390             : 
     391          20 :                         const double fNewX(aUnitVecY.getX() * fCos - aUnitVecY.getY() * fSin);
     392          20 :                         const double fNewY(aUnitVecY.getX() * fSin + aUnitVecY.getY() * fCos);
     393             : 
     394          20 :                         aUnitVecY.setX(fNewX);
     395          20 :                         aUnitVecY.setY(fNewY);
     396             :                     }
     397             : 
     398             :                     // Correct aUnitVecY and fCrossXY to fShear=0. Rotation is already removed.
     399             :                     // Shear correction can only work with removed rotation
     400          24 :                     aUnitVecY.setX(aUnitVecY.getX() - (aUnitVecY.getY() * rShearX));
     401          24 :                     fCrossXY = aUnitVecX.cross(aUnitVecY);
     402             : 
     403             :                     // calculate unsigned scale value for Y, after the corrections since
     404             :                     // the shear correction WILL change the length of aUnitVecY
     405          24 :                     rScale.setY(aUnitVecY.getLength());
     406             : 
     407             :                     // use orientation to set sign of Y-Scale
     408          24 :                     if(fCrossXY < 0.0)
     409             :                     {
     410          12 :                         rScale.setY(-rScale.getY());
     411             :                     }
     412             :                 }
     413          41 :             }
     414             :         }
     415             : 
     416        8113 :         return true;
     417             :     }
     418             : } // end of namespace basegfx
     419             : 
     420             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10