xref: /trunk/main/basegfx/source/matrix/b2dhommatrix.cxx (revision 30acf5e801d38c3701bf451b42e514ce81855b4c)
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 
2209dbbe93SAndrew 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 
45cdf0e10cSrcweir     B2DHomMatrix::B2DHomMatrix() :
46cdf0e10cSrcweir         mpImpl( IdentityMatrix::get() ) // use common identity matrix
47cdf0e10cSrcweir     {
48cdf0e10cSrcweir     }
49cdf0e10cSrcweir 
50cdf0e10cSrcweir     B2DHomMatrix::B2DHomMatrix(const B2DHomMatrix& rMat) :
51cdf0e10cSrcweir         mpImpl(rMat.mpImpl)
52cdf0e10cSrcweir     {
53cdf0e10cSrcweir     }
54cdf0e10cSrcweir 
55cdf0e10cSrcweir     B2DHomMatrix::~B2DHomMatrix()
56cdf0e10cSrcweir     {
57cdf0e10cSrcweir     }
58cdf0e10cSrcweir 
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 
70cdf0e10cSrcweir     B2DHomMatrix& B2DHomMatrix::operator=(const B2DHomMatrix& rMat)
71cdf0e10cSrcweir     {
72cdf0e10cSrcweir         mpImpl = rMat.mpImpl;
73cdf0e10cSrcweir         return *this;
74cdf0e10cSrcweir     }
75cdf0e10cSrcweir 
76cdf0e10cSrcweir     void B2DHomMatrix::makeUnique()
77cdf0e10cSrcweir     {
78cdf0e10cSrcweir         mpImpl.make_unique();
79cdf0e10cSrcweir     }
80cdf0e10cSrcweir 
81cdf0e10cSrcweir     double B2DHomMatrix::get(sal_uInt16 nRow, sal_uInt16 nColumn) const
82cdf0e10cSrcweir     {
83cdf0e10cSrcweir         return mpImpl->get(nRow, nColumn);
84cdf0e10cSrcweir     }
85cdf0e10cSrcweir 
86cdf0e10cSrcweir     void B2DHomMatrix::set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
87cdf0e10cSrcweir     {
88cdf0e10cSrcweir         mpImpl->set(nRow, nColumn, fValue);
89cdf0e10cSrcweir     }
90cdf0e10cSrcweir 
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 
101cdf0e10cSrcweir     bool B2DHomMatrix::isLastLineDefault() const
102cdf0e10cSrcweir     {
103cdf0e10cSrcweir         return mpImpl->isLastLineDefault();
104cdf0e10cSrcweir     }
105cdf0e10cSrcweir 
106cdf0e10cSrcweir     bool B2DHomMatrix::isIdentity() const
107cdf0e10cSrcweir     {
108cdf0e10cSrcweir         if(mpImpl.same_object(IdentityMatrix::get()))
109cdf0e10cSrcweir             return true;
110cdf0e10cSrcweir 
111cdf0e10cSrcweir         return mpImpl->isIdentity();
112cdf0e10cSrcweir     }
113cdf0e10cSrcweir 
114cdf0e10cSrcweir     void B2DHomMatrix::identity()
115cdf0e10cSrcweir     {
116cdf0e10cSrcweir         mpImpl = IdentityMatrix::get();
117cdf0e10cSrcweir     }
118cdf0e10cSrcweir 
119cdf0e10cSrcweir     bool B2DHomMatrix::isInvertible() const
120cdf0e10cSrcweir     {
121cdf0e10cSrcweir         return mpImpl->isInvertible();
122cdf0e10cSrcweir     }
123cdf0e10cSrcweir 
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 
142cdf0e10cSrcweir     bool B2DHomMatrix::isNormalized() const
143cdf0e10cSrcweir     {
144cdf0e10cSrcweir         return mpImpl->isNormalized();
145cdf0e10cSrcweir     }
146cdf0e10cSrcweir 
147cdf0e10cSrcweir     void B2DHomMatrix::normalize()
148cdf0e10cSrcweir     {
149cdf0e10cSrcweir         if(!const_cast<const B2DHomMatrix*>(this)->mpImpl->isNormalized())
150cdf0e10cSrcweir             mpImpl->doNormalize();
151cdf0e10cSrcweir     }
152cdf0e10cSrcweir 
153cdf0e10cSrcweir     double B2DHomMatrix::determinant() const
154cdf0e10cSrcweir     {
155cdf0e10cSrcweir         return mpImpl->doDeterminant();
156cdf0e10cSrcweir     }
157cdf0e10cSrcweir 
158cdf0e10cSrcweir     double B2DHomMatrix::trace() const
159cdf0e10cSrcweir     {
160cdf0e10cSrcweir         return mpImpl->doTrace();
161cdf0e10cSrcweir     }
162cdf0e10cSrcweir 
163cdf0e10cSrcweir     void B2DHomMatrix::transpose()
164cdf0e10cSrcweir     {
165cdf0e10cSrcweir         mpImpl->doTranspose();
166cdf0e10cSrcweir     }
167cdf0e10cSrcweir 
168cdf0e10cSrcweir     B2DHomMatrix& B2DHomMatrix::operator+=(const B2DHomMatrix& rMat)
169cdf0e10cSrcweir     {
170cdf0e10cSrcweir         mpImpl->doAddMatrix(*rMat.mpImpl);
171cdf0e10cSrcweir         return *this;
172cdf0e10cSrcweir     }
173cdf0e10cSrcweir 
174cdf0e10cSrcweir     B2DHomMatrix& B2DHomMatrix::operator-=(const B2DHomMatrix& rMat)
175cdf0e10cSrcweir     {
176cdf0e10cSrcweir         mpImpl->doSubMatrix(*rMat.mpImpl);
177cdf0e10cSrcweir         return *this;
178cdf0e10cSrcweir     }
179cdf0e10cSrcweir 
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 
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 
200cdf0e10cSrcweir     B2DHomMatrix& B2DHomMatrix::operator*=(const B2DHomMatrix& rMat)
201cdf0e10cSrcweir     {
202cdf0e10cSrcweir         if(!rMat.isIdentity())
203cdf0e10cSrcweir             mpImpl->doMulMatrix(*rMat.mpImpl);
204cdf0e10cSrcweir 
205cdf0e10cSrcweir         return *this;
206cdf0e10cSrcweir     }
207cdf0e10cSrcweir 
208cdf0e10cSrcweir     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 
216cdf0e10cSrcweir     bool B2DHomMatrix::operator!=(const B2DHomMatrix& rMat) const
217cdf0e10cSrcweir     {
218cdf0e10cSrcweir         return !(*this == rMat);
219cdf0e10cSrcweir     }
220cdf0e10cSrcweir 
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 
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 
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 
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 
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     */
301cdf0e10cSrcweir     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).
382*30acf5e8Spfg                 // This is before the parallel 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
397*30acf5e8Spfg                     // the only way to get the unit vectors nearly parallel 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