xref: /AOO41X/main/basegfx/source/matrix/b3dhommatrix.cxx (revision 09dbbe930366fe6f99ae3b8ae1cf8690b638dbda)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basegfx.hxx"
26 
27 #include <rtl/instance.hxx>
28 #include <basegfx/matrix/b3dhommatrix.hxx>
29 #include <hommatrixtemplate.hxx>
30 #include <basegfx/vector/b3dvector.hxx>
31 
32 namespace basegfx
33 {
34     class Impl3DHomMatrix : public ::basegfx::internal::ImplHomMatrixTemplate< 4 >
35     {
36     };
37 
38     namespace { struct IdentityMatrix : public rtl::Static< B3DHomMatrix::ImplType,
39                                                             IdentityMatrix > {}; }
40 
B3DHomMatrix()41     B3DHomMatrix::B3DHomMatrix() :
42         mpImpl( IdentityMatrix::get() ) // use common identity matrix
43     {
44     }
45 
B3DHomMatrix(const B3DHomMatrix & rMat)46     B3DHomMatrix::B3DHomMatrix(const B3DHomMatrix& rMat) :
47         mpImpl(rMat.mpImpl)
48     {
49     }
50 
~B3DHomMatrix()51     B3DHomMatrix::~B3DHomMatrix()
52     {
53     }
54 
operator =(const B3DHomMatrix & rMat)55     B3DHomMatrix& B3DHomMatrix::operator=(const B3DHomMatrix& rMat)
56     {
57         mpImpl = rMat.mpImpl;
58         return *this;
59     }
60 
makeUnique()61     void B3DHomMatrix::makeUnique()
62     {
63         mpImpl.make_unique();
64     }
65 
get(sal_uInt16 nRow,sal_uInt16 nColumn) const66     double B3DHomMatrix::get(sal_uInt16 nRow, sal_uInt16 nColumn) const
67     {
68         return mpImpl->get(nRow, nColumn);
69     }
70 
set(sal_uInt16 nRow,sal_uInt16 nColumn,double fValue)71     void B3DHomMatrix::set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
72     {
73         mpImpl->set(nRow, nColumn, fValue);
74     }
75 
isLastLineDefault() const76     bool B3DHomMatrix::isLastLineDefault() const
77     {
78         return mpImpl->isLastLineDefault();
79     }
80 
isIdentity() const81     bool B3DHomMatrix::isIdentity() const
82     {
83         if(mpImpl.same_object(IdentityMatrix::get()))
84             return true;
85 
86         return mpImpl->isIdentity();
87     }
88 
identity()89     void B3DHomMatrix::identity()
90     {
91         mpImpl = IdentityMatrix::get();
92     }
93 
isInvertible() const94     bool B3DHomMatrix::isInvertible() const
95     {
96         return mpImpl->isInvertible();
97     }
98 
invert()99     bool B3DHomMatrix::invert()
100     {
101         Impl3DHomMatrix aWork(*mpImpl);
102         sal_uInt16* pIndex = new sal_uInt16[mpImpl->getEdgeLength()];
103         sal_Int16 nParity;
104 
105         if(aWork.ludcmp(pIndex, nParity))
106         {
107             mpImpl->doInvert(aWork, pIndex);
108             delete[] pIndex;
109 
110             return true;
111         }
112 
113         delete[] pIndex;
114         return false;
115     }
116 
isNormalized() const117     bool B3DHomMatrix::isNormalized() const
118     {
119         return mpImpl->isNormalized();
120     }
121 
normalize()122     void B3DHomMatrix::normalize()
123     {
124         if(!const_cast<const B3DHomMatrix*>(this)->mpImpl->isNormalized())
125             mpImpl->doNormalize();
126     }
127 
determinant() const128     double B3DHomMatrix::determinant() const
129     {
130         return mpImpl->doDeterminant();
131     }
132 
trace() const133     double B3DHomMatrix::trace() const
134     {
135         return mpImpl->doTrace();
136     }
137 
transpose()138     void B3DHomMatrix::transpose()
139     {
140         mpImpl->doTranspose();
141     }
142 
operator +=(const B3DHomMatrix & rMat)143     B3DHomMatrix& B3DHomMatrix::operator+=(const B3DHomMatrix& rMat)
144     {
145         mpImpl->doAddMatrix(*rMat.mpImpl);
146         return *this;
147     }
148 
operator -=(const B3DHomMatrix & rMat)149     B3DHomMatrix& B3DHomMatrix::operator-=(const B3DHomMatrix& rMat)
150     {
151         mpImpl->doSubMatrix(*rMat.mpImpl);
152         return *this;
153     }
154 
operator *=(double fValue)155     B3DHomMatrix& B3DHomMatrix::operator*=(double fValue)
156     {
157         const double fOne(1.0);
158 
159         if(!fTools::equal(fOne, fValue))
160             mpImpl->doMulMatrix(fValue);
161 
162         return *this;
163     }
164 
operator /=(double fValue)165     B3DHomMatrix& B3DHomMatrix::operator/=(double fValue)
166     {
167         const double fOne(1.0);
168 
169         if(!fTools::equal(fOne, fValue))
170             mpImpl->doMulMatrix(1.0 / fValue);
171 
172         return *this;
173     }
174 
operator *=(const B3DHomMatrix & rMat)175     B3DHomMatrix& B3DHomMatrix::operator*=(const B3DHomMatrix& rMat)
176     {
177         if(!rMat.isIdentity())
178             mpImpl->doMulMatrix(*rMat.mpImpl);
179 
180         return *this;
181     }
182 
operator ==(const B3DHomMatrix & rMat) const183     bool B3DHomMatrix::operator==(const B3DHomMatrix& rMat) const
184     {
185         if(mpImpl.same_object(rMat.mpImpl))
186             return true;
187 
188         return mpImpl->isEqual(*rMat.mpImpl);
189     }
190 
operator !=(const B3DHomMatrix & rMat) const191     bool B3DHomMatrix::operator!=(const B3DHomMatrix& rMat) const
192     {
193         return !(*this == rMat);
194     }
195 
rotate(double fAngleX,double fAngleY,double fAngleZ)196     void B3DHomMatrix::rotate(double fAngleX,double fAngleY,double fAngleZ)
197     {
198         if(!fTools::equalZero(fAngleX) || !fTools::equalZero(fAngleY) || !fTools::equalZero(fAngleZ))
199         {
200             if(!fTools::equalZero(fAngleX))
201             {
202                 Impl3DHomMatrix aRotMatX;
203                 double fSin(sin(fAngleX));
204                 double fCos(cos(fAngleX));
205 
206                 aRotMatX.set(1, 1, fCos);
207                 aRotMatX.set(2, 2, fCos);
208                 aRotMatX.set(2, 1, fSin);
209                 aRotMatX.set(1, 2, -fSin);
210 
211                 mpImpl->doMulMatrix(aRotMatX);
212             }
213 
214             if(!fTools::equalZero(fAngleY))
215             {
216                 Impl3DHomMatrix aRotMatY;
217                 double fSin(sin(fAngleY));
218                 double fCos(cos(fAngleY));
219 
220                 aRotMatY.set(0, 0, fCos);
221                 aRotMatY.set(2, 2, fCos);
222                 aRotMatY.set(0, 2, fSin);
223                 aRotMatY.set(2, 0, -fSin);
224 
225                 mpImpl->doMulMatrix(aRotMatY);
226             }
227 
228             if(!fTools::equalZero(fAngleZ))
229             {
230                 Impl3DHomMatrix aRotMatZ;
231                 double fSin(sin(fAngleZ));
232                 double fCos(cos(fAngleZ));
233 
234                 aRotMatZ.set(0, 0, fCos);
235                 aRotMatZ.set(1, 1, fCos);
236                 aRotMatZ.set(1, 0, fSin);
237                 aRotMatZ.set(0, 1, -fSin);
238 
239                 mpImpl->doMulMatrix(aRotMatZ);
240             }
241         }
242     }
243 
translate(double fX,double fY,double fZ)244     void B3DHomMatrix::translate(double fX, double fY, double fZ)
245     {
246         if(!fTools::equalZero(fX) || !fTools::equalZero(fY) || !fTools::equalZero(fZ))
247         {
248             Impl3DHomMatrix aTransMat;
249 
250             aTransMat.set(0, 3, fX);
251             aTransMat.set(1, 3, fY);
252             aTransMat.set(2, 3, fZ);
253 
254             mpImpl->doMulMatrix(aTransMat);
255         }
256     }
257 
scale(double fX,double fY,double fZ)258     void B3DHomMatrix::scale(double fX, double fY, double fZ)
259     {
260         const double fOne(1.0);
261 
262         if(!fTools::equal(fOne, fX) || !fTools::equal(fOne, fY) ||!fTools::equal(fOne, fZ))
263         {
264             Impl3DHomMatrix aScaleMat;
265 
266             aScaleMat.set(0, 0, fX);
267             aScaleMat.set(1, 1, fY);
268             aScaleMat.set(2, 2, fZ);
269 
270             mpImpl->doMulMatrix(aScaleMat);
271         }
272     }
273 
shearXY(double fSx,double fSy)274     void B3DHomMatrix::shearXY(double fSx, double fSy)
275     {
276         // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
277         if(!fTools::equalZero(fSx) || !fTools::equalZero(fSy))
278         {
279             Impl3DHomMatrix aShearXYMat;
280 
281             aShearXYMat.set(0, 2, fSx);
282             aShearXYMat.set(1, 2, fSy);
283 
284             mpImpl->doMulMatrix(aShearXYMat);
285         }
286     }
287 
shearYZ(double fSy,double fSz)288     void B3DHomMatrix::shearYZ(double fSy, double fSz)
289     {
290         // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
291         if(!fTools::equalZero(fSy) || !fTools::equalZero(fSz))
292         {
293             Impl3DHomMatrix aShearYZMat;
294 
295             aShearYZMat.set(1, 0, fSy);
296             aShearYZMat.set(2, 0, fSz);
297 
298             mpImpl->doMulMatrix(aShearYZMat);
299         }
300     }
301 
shearXZ(double fSx,double fSz)302     void B3DHomMatrix::shearXZ(double fSx, double fSz)
303     {
304         // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
305         if(!fTools::equalZero(fSx) || !fTools::equalZero(fSz))
306         {
307             Impl3DHomMatrix aShearXZMat;
308 
309             aShearXZMat.set(0, 1, fSx);
310             aShearXZMat.set(2, 1, fSz);
311 
312             mpImpl->doMulMatrix(aShearXZMat);
313         }
314     }
315 
frustum(double fLeft,double fRight,double fBottom,double fTop,double fNear,double fFar)316     void B3DHomMatrix::frustum(double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar)
317     {
318         const double fZero(0.0);
319         const double fOne(1.0);
320 
321         if(!fTools::more(fNear, fZero))
322         {
323             fNear = 0.001;
324         }
325 
326         if(!fTools::more(fFar, fZero))
327         {
328             fFar = fOne;
329         }
330 
331         if(fTools::equal(fNear, fFar))
332         {
333             fFar = fNear + fOne;
334         }
335 
336         if(fTools::equal(fLeft, fRight))
337         {
338             fLeft -= fOne;
339             fRight += fOne;
340         }
341 
342         if(fTools::equal(fTop, fBottom))
343         {
344             fBottom -= fOne;
345             fTop += fOne;
346         }
347 
348         Impl3DHomMatrix aFrustumMat;
349 
350         aFrustumMat.set(0, 0, 2.0 * fNear / (fRight - fLeft));
351         aFrustumMat.set(1, 1, 2.0 * fNear / (fTop - fBottom));
352         aFrustumMat.set(0, 2, (fRight + fLeft) / (fRight - fLeft));
353         aFrustumMat.set(1, 2, (fTop + fBottom) / (fTop - fBottom));
354         aFrustumMat.set(2, 2, -fOne * ((fFar + fNear) / (fFar - fNear)));
355         aFrustumMat.set(3, 2, -fOne);
356         aFrustumMat.set(2, 3, -fOne * ((2.0 * fFar * fNear) / (fFar - fNear)));
357         aFrustumMat.set(3, 3, fZero);
358 
359         mpImpl->doMulMatrix(aFrustumMat);
360     }
361 
ortho(double fLeft,double fRight,double fBottom,double fTop,double fNear,double fFar)362     void B3DHomMatrix::ortho(double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar)
363     {
364         if(fTools::equal(fNear, fFar))
365         {
366             fFar = fNear + 1.0;
367         }
368 
369         if(fTools::equal(fLeft, fRight))
370         {
371             fLeft -= 1.0;
372             fRight += 1.0;
373         }
374 
375         if(fTools::equal(fTop, fBottom))
376         {
377             fBottom -= 1.0;
378             fTop += 1.0;
379         }
380 
381         Impl3DHomMatrix aOrthoMat;
382 
383         aOrthoMat.set(0, 0, 2.0 / (fRight - fLeft));
384         aOrthoMat.set(1, 1, 2.0 / (fTop - fBottom));
385         aOrthoMat.set(2, 2, -1.0 * (2.0 / (fFar - fNear)));
386         aOrthoMat.set(0, 3, -1.0 * ((fRight + fLeft) / (fRight - fLeft)));
387         aOrthoMat.set(1, 3, -1.0 * ((fTop + fBottom) / (fTop - fBottom)));
388         aOrthoMat.set(2, 3, -1.0 * ((fFar + fNear) / (fFar - fNear)));
389 
390         mpImpl->doMulMatrix(aOrthoMat);
391     }
392 
orientation(B3DPoint aVRP,B3DVector aVPN,B3DVector aVUV)393     void B3DHomMatrix::orientation(B3DPoint aVRP, B3DVector aVPN, B3DVector aVUV)
394     {
395         Impl3DHomMatrix aOrientationMat;
396 
397         // translate -VRP
398         aOrientationMat.set(0, 3, -aVRP.getX());
399         aOrientationMat.set(1, 3, -aVRP.getY());
400         aOrientationMat.set(2, 3, -aVRP.getZ());
401 
402         // build rotation
403         aVUV.normalize();
404         aVPN.normalize();
405 
406         // build x-axis as peroendicular fron aVUV and aVPN
407         B3DVector aRx(aVUV.getPerpendicular(aVPN));
408         aRx.normalize();
409 
410         // y-axis perpendicular to that
411         B3DVector aRy(aVPN.getPerpendicular(aRx));
412         aRy.normalize();
413 
414         // the calculated normals are the line vectors of the rotation matrix,
415         // set them to create rotation
416         aOrientationMat.set(0, 0, aRx.getX());
417         aOrientationMat.set(0, 1, aRx.getY());
418         aOrientationMat.set(0, 2, aRx.getZ());
419         aOrientationMat.set(1, 0, aRy.getX());
420         aOrientationMat.set(1, 1, aRy.getY());
421         aOrientationMat.set(1, 2, aRy.getZ());
422         aOrientationMat.set(2, 0, aVPN.getX());
423         aOrientationMat.set(2, 1, aVPN.getY());
424         aOrientationMat.set(2, 2, aVPN.getZ());
425 
426         mpImpl->doMulMatrix(aOrientationMat);
427     }
428 
decompose(B3DTuple & rScale,B3DTuple & rTranslate,B3DTuple & rRotate,B3DTuple & rShear) const429     bool B3DHomMatrix::decompose(B3DTuple& rScale, B3DTuple& rTranslate, B3DTuple& rRotate, B3DTuple& rShear) const
430     {
431         // when perspective is used, decompose is not made here
432         if(!mpImpl->isLastLineDefault())
433             return false;
434 
435         // If determinant is zero, decomposition is not possible
436         if(0.0 == determinant())
437             return false;
438 
439         // isolate translation
440         rTranslate.setX(mpImpl->get(0, 3));
441         rTranslate.setY(mpImpl->get(1, 3));
442         rTranslate.setZ(mpImpl->get(2, 3));
443 
444         // correct translate values
445         rTranslate.correctValues();
446 
447         // get scale and shear
448         B3DVector aCol0(mpImpl->get(0, 0), mpImpl->get(1, 0), mpImpl->get(2, 0));
449         B3DVector aCol1(mpImpl->get(0, 1), mpImpl->get(1, 1), mpImpl->get(2, 1));
450         B3DVector aCol2(mpImpl->get(0, 2), mpImpl->get(1, 2), mpImpl->get(2, 2));
451         B3DVector aTemp;
452 
453         // get ScaleX
454         rScale.setX(aCol0.getLength());
455         aCol0.normalize();
456 
457         // get ShearXY
458         rShear.setX(aCol0.scalar(aCol1));
459 
460         if(fTools::equalZero(rShear.getX()))
461         {
462             rShear.setX(0.0);
463         }
464         else
465         {
466             aTemp.setX(aCol1.getX() - rShear.getX() * aCol0.getX());
467             aTemp.setY(aCol1.getY() - rShear.getX() * aCol0.getY());
468             aTemp.setZ(aCol1.getZ() - rShear.getX() * aCol0.getZ());
469             aCol1 = aTemp;
470         }
471 
472         // get ScaleY
473         rScale.setY(aCol1.getLength());
474         aCol1.normalize();
475 
476         const double fShearX(rShear.getX());
477 
478         if(!fTools::equalZero(fShearX))
479         {
480             rShear.setX(rShear.getX() / rScale.getY());
481         }
482 
483         // get ShearXZ
484         rShear.setY(aCol0.scalar(aCol2));
485 
486         if(fTools::equalZero(rShear.getY()))
487         {
488             rShear.setY(0.0);
489         }
490         else
491         {
492             aTemp.setX(aCol2.getX() - rShear.getY() * aCol0.getX());
493             aTemp.setY(aCol2.getY() - rShear.getY() * aCol0.getY());
494             aTemp.setZ(aCol2.getZ() - rShear.getY() * aCol0.getZ());
495             aCol2 = aTemp;
496         }
497 
498         // get ShearYZ
499         rShear.setZ(aCol1.scalar(aCol2));
500 
501         if(fTools::equalZero(rShear.getZ()))
502         {
503             rShear.setZ(0.0);
504         }
505         else
506         {
507             aTemp.setX(aCol2.getX() - rShear.getZ() * aCol1.getX());
508             aTemp.setY(aCol2.getY() - rShear.getZ() * aCol1.getY());
509             aTemp.setZ(aCol2.getZ() - rShear.getZ() * aCol1.getZ());
510             aCol2 = aTemp;
511         }
512 
513         // get ScaleZ
514         rScale.setZ(aCol2.getLength());
515         aCol2.normalize();
516 
517         const double fShearY(rShear.getY());
518 
519         if(!fTools::equalZero(fShearY))
520         {
521             rShear.setY(rShear.getY() / rScale.getZ());
522         }
523 
524         const double fShearZ(rShear.getZ());
525 
526         if(!fTools::equalZero(fShearZ))
527         {
528             rShear.setZ(rShear.getZ() / rScale.getZ());
529         }
530 
531         // correct shear values
532         rShear.correctValues();
533 
534         // Coordinate system flip?
535         if(0.0 > aCol0.scalar(aCol1.getPerpendicular(aCol2)))
536         {
537             rScale = -rScale;
538             aCol0 = -aCol0;
539             aCol1 = -aCol1;
540             aCol2 = -aCol2;
541         }
542 
543         // correct scale values
544         rScale.correctValues(1.0);
545 
546         // Get rotations
547         {
548             double fy=0;
549             double cy=0;
550 
551             if( ::basegfx::fTools::equal( aCol0.getZ(), 1.0 )
552                 || aCol0.getZ() > 1.0 )
553             {
554                 fy = -F_PI/2.0;
555                 cy = 0.0;
556             }
557             else if( ::basegfx::fTools::equal( aCol0.getZ(), -1.0 )
558                 || aCol0.getZ() < -1.0 )
559             {
560                 fy = F_PI/2.0;
561                 cy = 0.0;
562             }
563             else
564             {
565                 fy = asin( -aCol0.getZ() );
566                 cy = cos(fy);
567             }
568 
569             rRotate.setY(fy);
570             if( ::basegfx::fTools::equalZero( cy ) )
571             {
572                 if( aCol0.getZ() > 0.0 )
573                     rRotate.setX(atan2(-1.0*aCol1.getX(), aCol1.getY()));
574                 else
575                     rRotate.setX(atan2(aCol1.getX(), aCol1.getY()));
576                 rRotate.setZ(0.0);
577             }
578             else
579             {
580                 rRotate.setX(atan2(aCol1.getZ(), aCol2.getZ()));
581                 rRotate.setZ(atan2(aCol0.getY(), aCol0.getX()));
582             }
583 
584             // corrcet rotate values
585             rRotate.correctValues();
586         }
587 
588         return true;
589     }
590 } // end of namespace basegfx
591 
592 // eof
593