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