xref: /trunk/main/basegfx/source/matrix/b2dhommatrix.cxx (revision 45d1b581a3afed2711c07fe77472516d35fbd7b3)
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