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-17 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       64824 :     class Impl2DHomMatrix : public ::basegfx::internal::ImplHomMatrixTemplate< 3 >
      33             :     {
      34             :     };
      35             : 
      36             :     namespace { struct IdentityMatrix : public rtl::Static< B2DHomMatrix::ImplType,
      37             :                                                             IdentityMatrix > {}; }
      38             : 
      39       44174 :     B2DHomMatrix::B2DHomMatrix() :
      40       44174 :         mpImpl( IdentityMatrix::get() ) // use common identity matrix
      41             :     {
      42       44174 :     }
      43             : 
      44       38455 :     B2DHomMatrix::B2DHomMatrix(const B2DHomMatrix& rMat) :
      45       38455 :         mpImpl(rMat.mpImpl)
      46             :     {
      47       38455 :     }
      48             : 
      49       82301 :     B2DHomMatrix::~B2DHomMatrix()
      50             :     {
      51       82301 :     }
      52             : 
      53        3474 :     B2DHomMatrix::B2DHomMatrix(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2)
      54        3474 :     :   mpImpl( IdentityMatrix::get() ) // use common identity matrix, will be made unique with 1st set-call
      55             :     {
      56        3474 :         mpImpl->set(0, 0, f_0x0);
      57        3474 :         mpImpl->set(0, 1, f_0x1);
      58        3474 :         mpImpl->set(0, 2, f_0x2);
      59        3474 :         mpImpl->set(1, 0, f_1x0);
      60        3474 :         mpImpl->set(1, 1, f_1x1);
      61        3474 :         mpImpl->set(1, 2, f_1x2);
      62        3474 :     }
      63             : 
      64       13282 :     B2DHomMatrix& B2DHomMatrix::operator=(const B2DHomMatrix& rMat)
      65             :     {
      66       13282 :         mpImpl = rMat.mpImpl;
      67       13282 :         return *this;
      68             :     }
      69             : 
      70      460184 :     double B2DHomMatrix::get(sal_uInt16 nRow, sal_uInt16 nColumn) const
      71             :     {
      72      460184 :         return mpImpl->get(nRow, nColumn);
      73             :     }
      74             : 
      75       48092 :     void B2DHomMatrix::set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
      76             :     {
      77       48092 :         mpImpl->set(nRow, nColumn, fValue);
      78       48092 :     }
      79             : 
      80           8 :     void B2DHomMatrix::set3x2(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2)
      81             :     {
      82           8 :         mpImpl->set(0, 0, f_0x0);
      83           8 :         mpImpl->set(0, 1, f_0x1);
      84           8 :         mpImpl->set(0, 2, f_0x2);
      85           8 :         mpImpl->set(1, 0, f_1x0);
      86           8 :         mpImpl->set(1, 1, f_1x1);
      87           8 :         mpImpl->set(1, 2, f_1x2);
      88           8 :     }
      89             : 
      90       53484 :     bool B2DHomMatrix::isLastLineDefault() const
      91             :     {
      92       53484 :         return mpImpl->isLastLineDefault();
      93             :     }
      94             : 
      95       39934 :     bool B2DHomMatrix::isIdentity() const
      96             :     {
      97       39934 :         if(mpImpl.same_object(IdentityMatrix::get()))
      98        9384 :             return true;
      99             : 
     100       30550 :         return mpImpl->isIdentity();
     101             :     }
     102             : 
     103         390 :     void B2DHomMatrix::identity()
     104             :     {
     105         390 :         mpImpl = IdentityMatrix::get();
     106         390 :     }
     107             : 
     108           0 :     bool B2DHomMatrix::isInvertible() const
     109             :     {
     110           0 :         return mpImpl->isInvertible();
     111             :     }
     112             : 
     113        1594 :     bool B2DHomMatrix::invert()
     114             :     {
     115        1594 :         Impl2DHomMatrix aWork(*mpImpl);
     116        1594 :         sal_uInt16* pIndex = new sal_uInt16[mpImpl->getEdgeLength()];
     117             :         sal_Int16 nParity;
     118             : 
     119        1594 :         if(aWork.ludcmp(pIndex, nParity))
     120             :         {
     121        1594 :             mpImpl->doInvert(aWork, pIndex);
     122        1594 :             delete[] pIndex;
     123             : 
     124        1594 :             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        7382 :     B2DHomMatrix& B2DHomMatrix::operator*=(const B2DHomMatrix& rMat)
     164             :     {
     165        7382 :         if(!rMat.isIdentity())
     166        6832 :             mpImpl->doMulMatrix(*rMat.mpImpl);
     167             : 
     168        7382 :         return *this;
     169             :     }
     170             : 
     171        2116 :     bool B2DHomMatrix::operator==(const B2DHomMatrix& rMat) const
     172             :     {
     173        2116 :         if(mpImpl.same_object(rMat.mpImpl))
     174        1584 :             return true;
     175             : 
     176         532 :         return mpImpl->isEqual(*rMat.mpImpl);
     177             :     }
     178             : 
     179         540 :     bool B2DHomMatrix::operator!=(const B2DHomMatrix& rMat) const
     180             :     {
     181         540 :         return !(*this == rMat);
     182             :     }
     183             : 
     184        4478 :     void B2DHomMatrix::rotate(double fRadiant)
     185             :     {
     186        4478 :         if(!fTools::equalZero(fRadiant))
     187             :         {
     188        1972 :             double fSin(0.0);
     189        1972 :             double fCos(1.0);
     190             : 
     191        1972 :             tools::createSinCosOrthogonal(fSin, fCos, fRadiant);
     192        1972 :             Impl2DHomMatrix aRotMat;
     193             : 
     194        1972 :             aRotMat.set(0, 0, fCos);
     195        1972 :             aRotMat.set(1, 1, fCos);
     196        1972 :             aRotMat.set(1, 0, fSin);
     197        1972 :             aRotMat.set(0, 1, -fSin);
     198             : 
     199        1972 :             mpImpl->doMulMatrix(aRotMat);
     200             :         }
     201        4478 :     }
     202             : 
     203        3446 :     void B2DHomMatrix::translate(double fX, double fY)
     204             :     {
     205        3446 :         if(!fTools::equalZero(fX) || !fTools::equalZero(fY))
     206             :         {
     207        3402 :             Impl2DHomMatrix aTransMat;
     208             : 
     209        3402 :             aTransMat.set(0, 2, fX);
     210        3402 :             aTransMat.set(1, 2, fY);
     211             : 
     212        3402 :             mpImpl->doMulMatrix(aTransMat);
     213             :         }
     214        3446 :     }
     215             : 
     216        1232 :     void B2DHomMatrix::scale(double fX, double fY)
     217             :     {
     218        1232 :         const double fOne(1.0);
     219             : 
     220        1232 :         if(!fTools::equal(fOne, fX) || !fTools::equal(fOne, fY))
     221             :         {
     222        1062 :             Impl2DHomMatrix aScaleMat;
     223             : 
     224        1062 :             aScaleMat.set(0, 0, fX);
     225        1062 :             aScaleMat.set(1, 1, fY);
     226             : 
     227        1062 :             mpImpl->doMulMatrix(aScaleMat);
     228             :         }
     229        1232 :     }
     230             : 
     231         166 :     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         166 :         if(!fTools::equalZero(fSx))
     235             :         {
     236          98 :             Impl2DHomMatrix aShearXMat;
     237             : 
     238          98 :             aShearXMat.set(0, 1, fSx);
     239             : 
     240          98 :             mpImpl->doMulMatrix(aShearXMat);
     241             :         }
     242         166 :     }
     243             : 
     244           2 :     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           2 :         if(!fTools::equalZero(fSy))
     248             :         {
     249           2 :             Impl2DHomMatrix aShearYMat;
     250             : 
     251           2 :             aShearYMat.set(1, 0, fSy);
     252             : 
     253           2 :             mpImpl->doMulMatrix(aShearYMat);
     254             :         }
     255           2 :     }
     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        9822 :     bool B2DHomMatrix::decompose(B2DTuple& rScale, B2DTuple& rTranslate, double& rRotate, double& rShearX) const
     265             :     {
     266             :         // when perspective is used, decompose is not made here
     267        9822 :         if(!mpImpl->isLastLineDefault())
     268             :         {
     269           0 :             return false;
     270             :         }
     271             : 
     272             :         // reset rotate and shear and copy translation values in every case
     273        9822 :         rRotate = rShearX = 0.0;
     274        9822 :         rTranslate.setX(get(0, 2));
     275        9822 :         rTranslate.setY(get(1, 2));
     276             : 
     277             :         // test for rotation and shear
     278        9822 :         if(fTools::equalZero(get(0, 1)) && fTools::equalZero(get(1, 0)))
     279             :         {
     280             :             // no rotation and shear, copy scale values
     281        9740 :             rScale.setX(get(0, 0));
     282        9740 :             rScale.setY(get(1, 1));
     283             : 
     284             :             // or is there?
     285        9740 :             if( rScale.getX() < 0 && rScale.getY() < 0 )
     286             :             {
     287             :                 // there is - 180 degree rotated
     288           4 :                 rScale *= -1;
     289           4 :                 rRotate = 180*F_PI180;
     290             :             }
     291             :         }
     292             :         else
     293             :         {
     294             :             // get the unit vectors of the transformation -> the perpendicular vectors
     295          82 :             B2DVector aUnitVecX(get(0, 0), get(1, 0));
     296          82 :             B2DVector aUnitVecY(get(0, 1), get(1, 1));
     297          82 :             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          82 :             if(fTools::equalZero(fScalarXY))
     303             :             {
     304             :                 // calculate unsigned scale values
     305          34 :                 rScale.setX(aUnitVecX.getLength());
     306          34 :                 rScale.setY(aUnitVecY.getLength());
     307             : 
     308             :                 // check unit vectors for zero lengths
     309          34 :                 const bool bXIsZero(fTools::equalZero(rScale.getX()));
     310          34 :                 const bool bYIsZero(fTools::equalZero(rScale.getY()));
     311             : 
     312          34 :                 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          34 :                     rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX());
     336             : 
     337             :                     // use orientation to evtl. correct sign of Y-Scale
     338          34 :                     const double fCrossXY(aUnitVecX.cross(aUnitVecY));
     339             : 
     340          34 :                     if(fCrossXY < 0.0)
     341             :                     {
     342           8 :                         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          48 :                 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          48 :                 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          48 :                 rScale.setX(aUnitVecX.getLength());
     360             : 
     361          48 :                 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          48 :                     rShearX = fScalarXY / fCrossXY;
     378             : 
     379          48 :                     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          40 :                         aUnitVecX.setX(rScale.getX());
     384          40 :                         aUnitVecX.setY(0.0);
     385             : 
     386             :                         // for Y correction we rotate the UnitVecY back about -rRotate
     387          40 :                         const double fNegRotate(-rRotate);
     388          40 :                         const double fSin(sin(fNegRotate));
     389          40 :                         const double fCos(cos(fNegRotate));
     390             : 
     391          40 :                         const double fNewX(aUnitVecY.getX() * fCos - aUnitVecY.getY() * fSin);
     392          40 :                         const double fNewY(aUnitVecY.getX() * fSin + aUnitVecY.getY() * fCos);
     393             : 
     394          40 :                         aUnitVecY.setX(fNewX);
     395          40 :                         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          48 :                     aUnitVecY.setX(aUnitVecY.getX() - (aUnitVecY.getY() * rShearX));
     401          48 :                     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          48 :                     rScale.setY(aUnitVecY.getLength());
     406             : 
     407             :                     // use orientation to set sign of Y-Scale
     408          48 :                     if(fCrossXY < 0.0)
     409             :                     {
     410          24 :                         rScale.setY(-rScale.getY());
     411             :                     }
     412             :                 }
     413          82 :             }
     414             :         }
     415             : 
     416        9822 :         return true;
     417             :     }
     418             : } // end of namespace basegfx
     419             : 
     420             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10