109dbbe93SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 309dbbe93SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 409dbbe93SAndrew Rist * or more contributor license agreements. See the NOTICE file 509dbbe93SAndrew Rist * distributed with this work for additional information 609dbbe93SAndrew Rist * regarding copyright ownership. The ASF licenses this file 709dbbe93SAndrew Rist * to you under the Apache License, Version 2.0 (the 809dbbe93SAndrew Rist * "License"); you may not use this file except in compliance 909dbbe93SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 1109dbbe93SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 1309dbbe93SAndrew Rist * Unless required by applicable law or agreed to in writing, 1409dbbe93SAndrew Rist * software distributed under the License is distributed on an 1509dbbe93SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 1609dbbe93SAndrew Rist * KIND, either express or implied. See the License for the 1709dbbe93SAndrew Rist * specific language governing permissions and limitations 1809dbbe93SAndrew Rist * under the License. 19cdf0e10cSrcweir * 2009dbbe93SAndrew Rist *************************************************************/ 2109dbbe93SAndrew Rist 22cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 23cdf0e10cSrcweir #include "precompiled_basegfx.hxx" 24cdf0e10cSrcweir #include <osl/diagnose.h> 25cdf0e10cSrcweir #include <rtl/instance.hxx> 26cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx> 27cdf0e10cSrcweir #include <hommatrixtemplate.hxx> 28cdf0e10cSrcweir #include <basegfx/tuple/b2dtuple.hxx> 29cdf0e10cSrcweir #include <basegfx/vector/b2dvector.hxx> 30cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrixtools.hxx> 31cdf0e10cSrcweir 32cdf0e10cSrcweir namespace basegfx 33cdf0e10cSrcweir { 34cdf0e10cSrcweir class Impl2DHomMatrix : public ::basegfx::internal::ImplHomMatrixTemplate< 3 > 35cdf0e10cSrcweir { 36cdf0e10cSrcweir }; 37cdf0e10cSrcweir 38cdf0e10cSrcweir namespace { struct IdentityMatrix : public rtl::Static< B2DHomMatrix::ImplType, 39cdf0e10cSrcweir IdentityMatrix > {}; } 40cdf0e10cSrcweir B2DHomMatrix()41cdf0e10cSrcweir B2DHomMatrix::B2DHomMatrix() : 42cdf0e10cSrcweir mpImpl( IdentityMatrix::get() ) // use common identity matrix 43cdf0e10cSrcweir { 44cdf0e10cSrcweir } 45cdf0e10cSrcweir B2DHomMatrix(const B2DHomMatrix & rMat)46cdf0e10cSrcweir B2DHomMatrix::B2DHomMatrix(const B2DHomMatrix& rMat) : 47cdf0e10cSrcweir mpImpl(rMat.mpImpl) 48cdf0e10cSrcweir { 49cdf0e10cSrcweir } 50cdf0e10cSrcweir ~B2DHomMatrix()51cdf0e10cSrcweir B2DHomMatrix::~B2DHomMatrix() 52cdf0e10cSrcweir { 53cdf0e10cSrcweir } 54cdf0e10cSrcweir B2DHomMatrix(double f_0x0,double f_0x1,double f_0x2,double f_1x0,double f_1x1,double f_1x2)55cdf0e10cSrcweir B2DHomMatrix::B2DHomMatrix(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2) 56cdf0e10cSrcweir : mpImpl( IdentityMatrix::get() ) // use common identity matrix, will be made unique with 1st set-call 57cdf0e10cSrcweir { 58cdf0e10cSrcweir mpImpl->set(0, 0, f_0x0); 59cdf0e10cSrcweir mpImpl->set(0, 1, f_0x1); 60cdf0e10cSrcweir mpImpl->set(0, 2, f_0x2); 61cdf0e10cSrcweir mpImpl->set(1, 0, f_1x0); 62cdf0e10cSrcweir mpImpl->set(1, 1, f_1x1); 63cdf0e10cSrcweir mpImpl->set(1, 2, f_1x2); 64cdf0e10cSrcweir } 65cdf0e10cSrcweir operator =(const B2DHomMatrix & rMat)66cdf0e10cSrcweir B2DHomMatrix& B2DHomMatrix::operator=(const B2DHomMatrix& rMat) 67cdf0e10cSrcweir { 68cdf0e10cSrcweir mpImpl = rMat.mpImpl; 69cdf0e10cSrcweir return *this; 70cdf0e10cSrcweir } 71cdf0e10cSrcweir makeUnique()72cdf0e10cSrcweir void B2DHomMatrix::makeUnique() 73cdf0e10cSrcweir { 74cdf0e10cSrcweir mpImpl.make_unique(); 75cdf0e10cSrcweir } 76cdf0e10cSrcweir get(sal_uInt16 nRow,sal_uInt16 nColumn) const77cdf0e10cSrcweir double B2DHomMatrix::get(sal_uInt16 nRow, sal_uInt16 nColumn) const 78cdf0e10cSrcweir { 79cdf0e10cSrcweir return mpImpl->get(nRow, nColumn); 80cdf0e10cSrcweir } 81cdf0e10cSrcweir set(sal_uInt16 nRow,sal_uInt16 nColumn,double fValue)82cdf0e10cSrcweir void B2DHomMatrix::set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue) 83cdf0e10cSrcweir { 84cdf0e10cSrcweir mpImpl->set(nRow, nColumn, fValue); 85cdf0e10cSrcweir } 86cdf0e10cSrcweir set3x2(double f_0x0,double f_0x1,double f_0x2,double f_1x0,double f_1x1,double f_1x2)87cdf0e10cSrcweir void B2DHomMatrix::set3x2(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2) 88cdf0e10cSrcweir { 89cdf0e10cSrcweir mpImpl->set(0, 0, f_0x0); 90cdf0e10cSrcweir mpImpl->set(0, 1, f_0x1); 91cdf0e10cSrcweir mpImpl->set(0, 2, f_0x2); 92cdf0e10cSrcweir mpImpl->set(1, 0, f_1x0); 93cdf0e10cSrcweir mpImpl->set(1, 1, f_1x1); 94cdf0e10cSrcweir mpImpl->set(1, 2, f_1x2); 95cdf0e10cSrcweir } 96cdf0e10cSrcweir isLastLineDefault() const97cdf0e10cSrcweir bool B2DHomMatrix::isLastLineDefault() const 98cdf0e10cSrcweir { 99cdf0e10cSrcweir return mpImpl->isLastLineDefault(); 100cdf0e10cSrcweir } 101cdf0e10cSrcweir isIdentity() const102cdf0e10cSrcweir bool B2DHomMatrix::isIdentity() const 103cdf0e10cSrcweir { 104cdf0e10cSrcweir if(mpImpl.same_object(IdentityMatrix::get())) 105cdf0e10cSrcweir return true; 106cdf0e10cSrcweir 107cdf0e10cSrcweir return mpImpl->isIdentity(); 108cdf0e10cSrcweir } 109cdf0e10cSrcweir identity()110cdf0e10cSrcweir void B2DHomMatrix::identity() 111cdf0e10cSrcweir { 112cdf0e10cSrcweir mpImpl = IdentityMatrix::get(); 113cdf0e10cSrcweir } 114cdf0e10cSrcweir isInvertible() const115cdf0e10cSrcweir bool B2DHomMatrix::isInvertible() const 116cdf0e10cSrcweir { 117cdf0e10cSrcweir return mpImpl->isInvertible(); 118cdf0e10cSrcweir } 119cdf0e10cSrcweir invert()120cdf0e10cSrcweir bool B2DHomMatrix::invert() 121cdf0e10cSrcweir { 122cdf0e10cSrcweir Impl2DHomMatrix aWork(*mpImpl); 123cdf0e10cSrcweir sal_uInt16* pIndex = new sal_uInt16[mpImpl->getEdgeLength()]; 124cdf0e10cSrcweir sal_Int16 nParity; 125cdf0e10cSrcweir 126cdf0e10cSrcweir if(aWork.ludcmp(pIndex, nParity)) 127cdf0e10cSrcweir { 128cdf0e10cSrcweir mpImpl->doInvert(aWork, pIndex); 129cdf0e10cSrcweir delete[] pIndex; 130cdf0e10cSrcweir 131cdf0e10cSrcweir return true; 132cdf0e10cSrcweir } 133cdf0e10cSrcweir 134cdf0e10cSrcweir delete[] pIndex; 135cdf0e10cSrcweir return false; 136cdf0e10cSrcweir } 137cdf0e10cSrcweir isNormalized() const138cdf0e10cSrcweir bool B2DHomMatrix::isNormalized() const 139cdf0e10cSrcweir { 140cdf0e10cSrcweir return mpImpl->isNormalized(); 141cdf0e10cSrcweir } 142cdf0e10cSrcweir normalize()143cdf0e10cSrcweir void B2DHomMatrix::normalize() 144cdf0e10cSrcweir { 145cdf0e10cSrcweir if(!const_cast<const B2DHomMatrix*>(this)->mpImpl->isNormalized()) 146cdf0e10cSrcweir mpImpl->doNormalize(); 147cdf0e10cSrcweir } 148cdf0e10cSrcweir determinant() const149cdf0e10cSrcweir double B2DHomMatrix::determinant() const 150cdf0e10cSrcweir { 151cdf0e10cSrcweir return mpImpl->doDeterminant(); 152cdf0e10cSrcweir } 153cdf0e10cSrcweir trace() const154cdf0e10cSrcweir double B2DHomMatrix::trace() const 155cdf0e10cSrcweir { 156cdf0e10cSrcweir return mpImpl->doTrace(); 157cdf0e10cSrcweir } 158cdf0e10cSrcweir transpose()159cdf0e10cSrcweir void B2DHomMatrix::transpose() 160cdf0e10cSrcweir { 161cdf0e10cSrcweir mpImpl->doTranspose(); 162cdf0e10cSrcweir } 163cdf0e10cSrcweir operator +=(const B2DHomMatrix & rMat)164cdf0e10cSrcweir B2DHomMatrix& B2DHomMatrix::operator+=(const B2DHomMatrix& rMat) 165cdf0e10cSrcweir { 166cdf0e10cSrcweir mpImpl->doAddMatrix(*rMat.mpImpl); 167cdf0e10cSrcweir return *this; 168cdf0e10cSrcweir } 169cdf0e10cSrcweir operator -=(const B2DHomMatrix & rMat)170cdf0e10cSrcweir B2DHomMatrix& B2DHomMatrix::operator-=(const B2DHomMatrix& rMat) 171cdf0e10cSrcweir { 172cdf0e10cSrcweir mpImpl->doSubMatrix(*rMat.mpImpl); 173cdf0e10cSrcweir return *this; 174cdf0e10cSrcweir } 175cdf0e10cSrcweir operator *=(double fValue)176cdf0e10cSrcweir B2DHomMatrix& B2DHomMatrix::operator*=(double fValue) 177cdf0e10cSrcweir { 178cdf0e10cSrcweir const double fOne(1.0); 179cdf0e10cSrcweir 180cdf0e10cSrcweir if(!fTools::equal(fOne, fValue)) 181cdf0e10cSrcweir mpImpl->doMulMatrix(fValue); 182cdf0e10cSrcweir 183cdf0e10cSrcweir return *this; 184cdf0e10cSrcweir } 185cdf0e10cSrcweir operator /=(double fValue)186cdf0e10cSrcweir B2DHomMatrix& B2DHomMatrix::operator/=(double fValue) 187cdf0e10cSrcweir { 188cdf0e10cSrcweir const double fOne(1.0); 189cdf0e10cSrcweir 190cdf0e10cSrcweir if(!fTools::equal(fOne, fValue)) 191cdf0e10cSrcweir mpImpl->doMulMatrix(1.0 / fValue); 192cdf0e10cSrcweir 193cdf0e10cSrcweir return *this; 194cdf0e10cSrcweir } 195cdf0e10cSrcweir operator *=(const B2DHomMatrix & rMat)196cdf0e10cSrcweir B2DHomMatrix& B2DHomMatrix::operator*=(const B2DHomMatrix& rMat) 197cdf0e10cSrcweir { 198cdf0e10cSrcweir if(!rMat.isIdentity()) 199cdf0e10cSrcweir mpImpl->doMulMatrix(*rMat.mpImpl); 200cdf0e10cSrcweir 201cdf0e10cSrcweir return *this; 202cdf0e10cSrcweir } 203cdf0e10cSrcweir operator ==(const B2DHomMatrix & rMat) const204cdf0e10cSrcweir bool B2DHomMatrix::operator==(const B2DHomMatrix& rMat) const 205cdf0e10cSrcweir { 206cdf0e10cSrcweir if(mpImpl.same_object(rMat.mpImpl)) 207cdf0e10cSrcweir return true; 208cdf0e10cSrcweir 209cdf0e10cSrcweir return mpImpl->isEqual(*rMat.mpImpl); 210cdf0e10cSrcweir } 211cdf0e10cSrcweir operator !=(const B2DHomMatrix & rMat) const212cdf0e10cSrcweir bool B2DHomMatrix::operator!=(const B2DHomMatrix& rMat) const 213cdf0e10cSrcweir { 214cdf0e10cSrcweir return !(*this == rMat); 215cdf0e10cSrcweir } 216cdf0e10cSrcweir rotate(double fRadiant)217cdf0e10cSrcweir void B2DHomMatrix::rotate(double fRadiant) 218cdf0e10cSrcweir { 219cdf0e10cSrcweir if(!fTools::equalZero(fRadiant)) 220cdf0e10cSrcweir { 221cdf0e10cSrcweir double fSin(0.0); 222cdf0e10cSrcweir double fCos(1.0); 223cdf0e10cSrcweir 224cdf0e10cSrcweir tools::createSinCosOrthogonal(fSin, fCos, fRadiant); 225cdf0e10cSrcweir Impl2DHomMatrix aRotMat; 226cdf0e10cSrcweir 227cdf0e10cSrcweir aRotMat.set(0, 0, fCos); 228cdf0e10cSrcweir aRotMat.set(1, 1, fCos); 229cdf0e10cSrcweir aRotMat.set(1, 0, fSin); 230cdf0e10cSrcweir aRotMat.set(0, 1, -fSin); 231cdf0e10cSrcweir 232cdf0e10cSrcweir mpImpl->doMulMatrix(aRotMat); 233cdf0e10cSrcweir } 234cdf0e10cSrcweir } 235cdf0e10cSrcweir translate(double fX,double fY)236cdf0e10cSrcweir void B2DHomMatrix::translate(double fX, double fY) 237cdf0e10cSrcweir { 238cdf0e10cSrcweir if(!fTools::equalZero(fX) || !fTools::equalZero(fY)) 239cdf0e10cSrcweir { 240cdf0e10cSrcweir Impl2DHomMatrix aTransMat; 241cdf0e10cSrcweir 242cdf0e10cSrcweir aTransMat.set(0, 2, fX); 243cdf0e10cSrcweir aTransMat.set(1, 2, fY); 244cdf0e10cSrcweir 245cdf0e10cSrcweir mpImpl->doMulMatrix(aTransMat); 246cdf0e10cSrcweir } 247cdf0e10cSrcweir } 248cdf0e10cSrcweir scale(double fX,double fY)249cdf0e10cSrcweir void B2DHomMatrix::scale(double fX, double fY) 250cdf0e10cSrcweir { 251cdf0e10cSrcweir const double fOne(1.0); 252cdf0e10cSrcweir 253cdf0e10cSrcweir if(!fTools::equal(fOne, fX) || !fTools::equal(fOne, fY)) 254cdf0e10cSrcweir { 255cdf0e10cSrcweir Impl2DHomMatrix aScaleMat; 256cdf0e10cSrcweir 257cdf0e10cSrcweir aScaleMat.set(0, 0, fX); 258cdf0e10cSrcweir aScaleMat.set(1, 1, fY); 259cdf0e10cSrcweir 260cdf0e10cSrcweir mpImpl->doMulMatrix(aScaleMat); 261cdf0e10cSrcweir } 262cdf0e10cSrcweir } 263cdf0e10cSrcweir shearX(double fSx)264cdf0e10cSrcweir void B2DHomMatrix::shearX(double fSx) 265cdf0e10cSrcweir { 266*45d1b581Smseidel // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!) 267cdf0e10cSrcweir if(!fTools::equalZero(fSx)) 268cdf0e10cSrcweir { 269cdf0e10cSrcweir Impl2DHomMatrix aShearXMat; 270cdf0e10cSrcweir 271cdf0e10cSrcweir aShearXMat.set(0, 1, fSx); 272cdf0e10cSrcweir 273cdf0e10cSrcweir mpImpl->doMulMatrix(aShearXMat); 274cdf0e10cSrcweir } 275cdf0e10cSrcweir } 276cdf0e10cSrcweir shearY(double fSy)277cdf0e10cSrcweir void B2DHomMatrix::shearY(double fSy) 278cdf0e10cSrcweir { 279*45d1b581Smseidel // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!) 280cdf0e10cSrcweir if(!fTools::equalZero(fSy)) 281cdf0e10cSrcweir { 282cdf0e10cSrcweir Impl2DHomMatrix aShearYMat; 283cdf0e10cSrcweir 284cdf0e10cSrcweir aShearYMat.set(1, 0, fSy); 285cdf0e10cSrcweir 286cdf0e10cSrcweir mpImpl->doMulMatrix(aShearYMat); 287cdf0e10cSrcweir } 288cdf0e10cSrcweir } 289cdf0e10cSrcweir 290cdf0e10cSrcweir /** Decomposition 291cdf0e10cSrcweir 292cdf0e10cSrcweir New, optimized version with local shearX detection. Old version (keeping 293cdf0e10cSrcweir below, is working well, too) used the 3D matrix decomposition when 294cdf0e10cSrcweir shear was used. Keeping old version as comment below since it may get 295cdf0e10cSrcweir necessary to add the determinant() test from there here, too. 296cdf0e10cSrcweir */ decompose(B2DTuple & rScale,B2DTuple & rTranslate,double & rRotate,double & rShearX) const297cdf0e10cSrcweir bool B2DHomMatrix::decompose(B2DTuple& rScale, B2DTuple& rTranslate, double& rRotate, double& rShearX) const 298cdf0e10cSrcweir { 299cdf0e10cSrcweir // when perspective is used, decompose is not made here 300cdf0e10cSrcweir if(!mpImpl->isLastLineDefault()) 301cdf0e10cSrcweir { 302cdf0e10cSrcweir return false; 303cdf0e10cSrcweir } 304cdf0e10cSrcweir 305cdf0e10cSrcweir // reset rotate and shear and copy translation values in every case 306cdf0e10cSrcweir rRotate = rShearX = 0.0; 307cdf0e10cSrcweir rTranslate.setX(get(0, 2)); 308cdf0e10cSrcweir rTranslate.setY(get(1, 2)); 309cdf0e10cSrcweir 310cdf0e10cSrcweir // test for rotation and shear 311cdf0e10cSrcweir if(fTools::equalZero(get(0, 1)) && fTools::equalZero(get(1, 0))) 312cdf0e10cSrcweir { 313cdf0e10cSrcweir // no rotation and shear, copy scale values 314cdf0e10cSrcweir rScale.setX(get(0, 0)); 315cdf0e10cSrcweir rScale.setY(get(1, 1)); 316cdf0e10cSrcweir } 317cdf0e10cSrcweir else 318cdf0e10cSrcweir { 319cdf0e10cSrcweir // get the unit vectors of the transformation -> the perpendicular vectors 320cdf0e10cSrcweir B2DVector aUnitVecX(get(0, 0), get(1, 0)); 321cdf0e10cSrcweir B2DVector aUnitVecY(get(0, 1), get(1, 1)); 322cdf0e10cSrcweir const double fScalarXY(aUnitVecX.scalar(aUnitVecY)); 323cdf0e10cSrcweir 324cdf0e10cSrcweir // Test if shear is zero. That's the case if the unit vectors in the matrix 325cdf0e10cSrcweir // are perpendicular -> scalar is zero. This is also the case when one of 326cdf0e10cSrcweir // the unit vectors is zero. 327cdf0e10cSrcweir if(fTools::equalZero(fScalarXY)) 328cdf0e10cSrcweir { 329cdf0e10cSrcweir // calculate unsigned scale values 330cdf0e10cSrcweir rScale.setX(aUnitVecX.getLength()); 331cdf0e10cSrcweir rScale.setY(aUnitVecY.getLength()); 332cdf0e10cSrcweir 333cdf0e10cSrcweir // check unit vectors for zero lengths 334cdf0e10cSrcweir const bool bXIsZero(fTools::equalZero(rScale.getX())); 335cdf0e10cSrcweir const bool bYIsZero(fTools::equalZero(rScale.getY())); 336cdf0e10cSrcweir 337cdf0e10cSrcweir if(bXIsZero || bYIsZero) 338cdf0e10cSrcweir { 339cdf0e10cSrcweir // still extract as much as possible. Scalings are already set 340cdf0e10cSrcweir if(!bXIsZero) 341cdf0e10cSrcweir { 342cdf0e10cSrcweir // get rotation of X-Axis 343cdf0e10cSrcweir rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX()); 344cdf0e10cSrcweir } 345cdf0e10cSrcweir else if(!bYIsZero) 346cdf0e10cSrcweir { 347cdf0e10cSrcweir // get rotation of X-Axis. When assuming X and Y perpendicular 348cdf0e10cSrcweir // and correct rotation, it's the Y-Axis rotation minus 90 degrees 349cdf0e10cSrcweir rRotate = atan2(aUnitVecY.getY(), aUnitVecY.getX()) - M_PI_2; 350cdf0e10cSrcweir } 351cdf0e10cSrcweir 352*45d1b581Smseidel // one or both unit vectors do not exist, determinant is zero, no decomposition possible. 353cdf0e10cSrcweir // Eventually used rotations or shears are lost 354cdf0e10cSrcweir return false; 355cdf0e10cSrcweir } 356cdf0e10cSrcweir else 357cdf0e10cSrcweir { 358cdf0e10cSrcweir // no shear 359cdf0e10cSrcweir // calculate rotation of X unit vector relative to (1, 0) 360cdf0e10cSrcweir rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX()); 361cdf0e10cSrcweir 362cdf0e10cSrcweir // use orientation to evtl. correct sign of Y-Scale 363cdf0e10cSrcweir const double fCrossXY(aUnitVecX.cross(aUnitVecY)); 364cdf0e10cSrcweir 365cdf0e10cSrcweir if(fCrossXY < 0.0) 366cdf0e10cSrcweir { 367cdf0e10cSrcweir rScale.setY(-rScale.getY()); 368cdf0e10cSrcweir } 369cdf0e10cSrcweir } 370cdf0e10cSrcweir } 371cdf0e10cSrcweir else 372cdf0e10cSrcweir { 373cdf0e10cSrcweir // fScalarXY is not zero, thus both unit vectors exist. No need to handle that here 374cdf0e10cSrcweir // shear, extract it 375cdf0e10cSrcweir double fCrossXY(aUnitVecX.cross(aUnitVecY)); 376cdf0e10cSrcweir 377cdf0e10cSrcweir // get rotation by calculating angle of X unit vector relative to (1, 0). 37830acf5e8Spfg // This is before the parallel test following the motto to extract 379cdf0e10cSrcweir // as much as possible 380cdf0e10cSrcweir rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX()); 381cdf0e10cSrcweir 382cdf0e10cSrcweir // get unsigned scale value for X. It will not change and is useful 383cdf0e10cSrcweir // for further corrections 384cdf0e10cSrcweir rScale.setX(aUnitVecX.getLength()); 385cdf0e10cSrcweir 386cdf0e10cSrcweir if(fTools::equalZero(fCrossXY)) 387cdf0e10cSrcweir { 388cdf0e10cSrcweir // extract as much as possible 389cdf0e10cSrcweir rScale.setY(aUnitVecY.getLength()); 390cdf0e10cSrcweir 391cdf0e10cSrcweir // unit vectors are parallel, thus not linear independent. No 392cdf0e10cSrcweir // useful decomposition possible. This should not happen since 39330acf5e8Spfg // the only way to get the unit vectors nearly parallel is 394cdf0e10cSrcweir // a very big shearing. Anyways, be prepared for hand-filled 395cdf0e10cSrcweir // matrices 396cdf0e10cSrcweir // Eventually used rotations or shears are lost 397cdf0e10cSrcweir return false; 398cdf0e10cSrcweir } 399cdf0e10cSrcweir else 400cdf0e10cSrcweir { 401cdf0e10cSrcweir // calculate the contained shear 402cdf0e10cSrcweir rShearX = fScalarXY / fCrossXY; 403cdf0e10cSrcweir 404cdf0e10cSrcweir if(!fTools::equalZero(rRotate)) 405cdf0e10cSrcweir { 406cdf0e10cSrcweir // To be able to correct the shear for aUnitVecY, rotation needs to be 407cdf0e10cSrcweir // removed first. Correction of aUnitVecX is easy, it will be rotated back to (1, 0). 408cdf0e10cSrcweir aUnitVecX.setX(rScale.getX()); 409cdf0e10cSrcweir aUnitVecX.setY(0.0); 410cdf0e10cSrcweir 411cdf0e10cSrcweir // for Y correction we rotate the UnitVecY back about -rRotate 412cdf0e10cSrcweir const double fNegRotate(-rRotate); 413cdf0e10cSrcweir const double fSin(sin(fNegRotate)); 414cdf0e10cSrcweir const double fCos(cos(fNegRotate)); 415cdf0e10cSrcweir 416cdf0e10cSrcweir const double fNewX(aUnitVecY.getX() * fCos - aUnitVecY.getY() * fSin); 417cdf0e10cSrcweir const double fNewY(aUnitVecY.getX() * fSin + aUnitVecY.getY() * fCos); 418cdf0e10cSrcweir 419cdf0e10cSrcweir aUnitVecY.setX(fNewX); 420cdf0e10cSrcweir aUnitVecY.setY(fNewY); 421cdf0e10cSrcweir } 422cdf0e10cSrcweir 423cdf0e10cSrcweir // Correct aUnitVecY and fCrossXY to fShear=0. Rotation is already removed. 424cdf0e10cSrcweir // Shear correction can only work with removed rotation 425cdf0e10cSrcweir aUnitVecY.setX(aUnitVecY.getX() - (aUnitVecY.getY() * rShearX)); 426cdf0e10cSrcweir fCrossXY = aUnitVecX.cross(aUnitVecY); 427cdf0e10cSrcweir 428cdf0e10cSrcweir // calculate unsigned scale value for Y, after the corrections since 429cdf0e10cSrcweir // the shear correction WILL change the length of aUnitVecY 430cdf0e10cSrcweir rScale.setY(aUnitVecY.getLength()); 431cdf0e10cSrcweir 432cdf0e10cSrcweir // use orientation to set sign of Y-Scale 433cdf0e10cSrcweir if(fCrossXY < 0.0) 434cdf0e10cSrcweir { 435cdf0e10cSrcweir rScale.setY(-rScale.getY()); 436cdf0e10cSrcweir } 437cdf0e10cSrcweir } 438cdf0e10cSrcweir } 439cdf0e10cSrcweir } 440cdf0e10cSrcweir 441cdf0e10cSrcweir return true; 442cdf0e10cSrcweir } 443cdf0e10cSrcweir } // end of namespace basegfx 444cdf0e10cSrcweir 445*45d1b581Smseidel /* vim: set noet sw=4 ts=4: */ 446