merged tag ooo/OOO330_m14
[LibreOffice.git] / basegfx / source / matrix / b3dhommatrix.cxx
blobbc3c3b0b55dda38af0ae4d6157d505fcb34b378b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_basegfx.hxx"
31 #include <rtl/instance.hxx>
32 #include <basegfx/matrix/b3dhommatrix.hxx>
33 #include <hommatrixtemplate.hxx>
34 #include <basegfx/vector/b3dvector.hxx>
36 namespace basegfx
38 class Impl3DHomMatrix : public ::basegfx::internal::ImplHomMatrixTemplate< 4 >
42 namespace { struct IdentityMatrix : public rtl::Static< B3DHomMatrix::ImplType,
43 IdentityMatrix > {}; }
45 B3DHomMatrix::B3DHomMatrix() :
46 mpImpl( IdentityMatrix::get() ) // use common identity matrix
50 B3DHomMatrix::B3DHomMatrix(const B3DHomMatrix& rMat) :
51 mpImpl(rMat.mpImpl)
55 B3DHomMatrix::~B3DHomMatrix()
59 B3DHomMatrix& B3DHomMatrix::operator=(const B3DHomMatrix& rMat)
61 mpImpl = rMat.mpImpl;
62 return *this;
65 void B3DHomMatrix::makeUnique()
67 mpImpl.make_unique();
70 double B3DHomMatrix::get(sal_uInt16 nRow, sal_uInt16 nColumn) const
72 return mpImpl->get(nRow, nColumn);
75 void B3DHomMatrix::set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
77 mpImpl->set(nRow, nColumn, fValue);
80 bool B3DHomMatrix::isLastLineDefault() const
82 return mpImpl->isLastLineDefault();
85 bool B3DHomMatrix::isIdentity() const
87 if(mpImpl.same_object(IdentityMatrix::get()))
88 return true;
90 return mpImpl->isIdentity();
93 void B3DHomMatrix::identity()
95 mpImpl = IdentityMatrix::get();
98 bool B3DHomMatrix::isInvertible() const
100 return mpImpl->isInvertible();
103 bool B3DHomMatrix::invert()
105 Impl3DHomMatrix aWork(*mpImpl);
106 sal_uInt16* pIndex = new sal_uInt16[mpImpl->getEdgeLength()];
107 sal_Int16 nParity;
109 if(aWork.ludcmp(pIndex, nParity))
111 mpImpl->doInvert(aWork, pIndex);
112 delete[] pIndex;
114 return true;
117 delete[] pIndex;
118 return false;
121 bool B3DHomMatrix::isNormalized() const
123 return mpImpl->isNormalized();
126 void B3DHomMatrix::normalize()
128 if(!const_cast<const B3DHomMatrix*>(this)->mpImpl->isNormalized())
129 mpImpl->doNormalize();
132 double B3DHomMatrix::determinant() const
134 return mpImpl->doDeterminant();
137 double B3DHomMatrix::trace() const
139 return mpImpl->doTrace();
142 void B3DHomMatrix::transpose()
144 mpImpl->doTranspose();
147 B3DHomMatrix& B3DHomMatrix::operator+=(const B3DHomMatrix& rMat)
149 mpImpl->doAddMatrix(*rMat.mpImpl);
150 return *this;
153 B3DHomMatrix& B3DHomMatrix::operator-=(const B3DHomMatrix& rMat)
155 mpImpl->doSubMatrix(*rMat.mpImpl);
156 return *this;
159 B3DHomMatrix& B3DHomMatrix::operator*=(double fValue)
161 const double fOne(1.0);
163 if(!fTools::equal(fOne, fValue))
164 mpImpl->doMulMatrix(fValue);
166 return *this;
169 B3DHomMatrix& B3DHomMatrix::operator/=(double fValue)
171 const double fOne(1.0);
173 if(!fTools::equal(fOne, fValue))
174 mpImpl->doMulMatrix(1.0 / fValue);
176 return *this;
179 B3DHomMatrix& B3DHomMatrix::operator*=(const B3DHomMatrix& rMat)
181 if(!rMat.isIdentity())
182 mpImpl->doMulMatrix(*rMat.mpImpl);
184 return *this;
187 bool B3DHomMatrix::operator==(const B3DHomMatrix& rMat) const
189 if(mpImpl.same_object(rMat.mpImpl))
190 return true;
192 return mpImpl->isEqual(*rMat.mpImpl);
195 bool B3DHomMatrix::operator!=(const B3DHomMatrix& rMat) const
197 return !(*this == rMat);
200 void B3DHomMatrix::rotate(double fAngleX,double fAngleY,double fAngleZ)
202 if(!fTools::equalZero(fAngleX) || !fTools::equalZero(fAngleY) || !fTools::equalZero(fAngleZ))
204 if(!fTools::equalZero(fAngleX))
206 Impl3DHomMatrix aRotMatX;
207 double fSin(sin(fAngleX));
208 double fCos(cos(fAngleX));
210 aRotMatX.set(1, 1, fCos);
211 aRotMatX.set(2, 2, fCos);
212 aRotMatX.set(2, 1, fSin);
213 aRotMatX.set(1, 2, -fSin);
215 mpImpl->doMulMatrix(aRotMatX);
218 if(!fTools::equalZero(fAngleY))
220 Impl3DHomMatrix aRotMatY;
221 double fSin(sin(fAngleY));
222 double fCos(cos(fAngleY));
224 aRotMatY.set(0, 0, fCos);
225 aRotMatY.set(2, 2, fCos);
226 aRotMatY.set(0, 2, fSin);
227 aRotMatY.set(2, 0, -fSin);
229 mpImpl->doMulMatrix(aRotMatY);
232 if(!fTools::equalZero(fAngleZ))
234 Impl3DHomMatrix aRotMatZ;
235 double fSin(sin(fAngleZ));
236 double fCos(cos(fAngleZ));
238 aRotMatZ.set(0, 0, fCos);
239 aRotMatZ.set(1, 1, fCos);
240 aRotMatZ.set(1, 0, fSin);
241 aRotMatZ.set(0, 1, -fSin);
243 mpImpl->doMulMatrix(aRotMatZ);
248 void B3DHomMatrix::translate(double fX, double fY, double fZ)
250 if(!fTools::equalZero(fX) || !fTools::equalZero(fY) || !fTools::equalZero(fZ))
252 Impl3DHomMatrix aTransMat;
254 aTransMat.set(0, 3, fX);
255 aTransMat.set(1, 3, fY);
256 aTransMat.set(2, 3, fZ);
258 mpImpl->doMulMatrix(aTransMat);
262 void B3DHomMatrix::scale(double fX, double fY, double fZ)
264 const double fOne(1.0);
266 if(!fTools::equal(fOne, fX) || !fTools::equal(fOne, fY) ||!fTools::equal(fOne, fZ))
268 Impl3DHomMatrix aScaleMat;
270 aScaleMat.set(0, 0, fX);
271 aScaleMat.set(1, 1, fY);
272 aScaleMat.set(2, 2, fZ);
274 mpImpl->doMulMatrix(aScaleMat);
278 void B3DHomMatrix::shearXY(double fSx, double fSy)
280 // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
281 if(!fTools::equalZero(fSx) || !fTools::equalZero(fSy))
283 Impl3DHomMatrix aShearXYMat;
285 aShearXYMat.set(0, 2, fSx);
286 aShearXYMat.set(1, 2, fSy);
288 mpImpl->doMulMatrix(aShearXYMat);
292 void B3DHomMatrix::shearYZ(double fSy, double fSz)
294 // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
295 if(!fTools::equalZero(fSy) || !fTools::equalZero(fSz))
297 Impl3DHomMatrix aShearYZMat;
299 aShearYZMat.set(1, 0, fSy);
300 aShearYZMat.set(2, 0, fSz);
302 mpImpl->doMulMatrix(aShearYZMat);
306 void B3DHomMatrix::shearXZ(double fSx, double fSz)
308 // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
309 if(!fTools::equalZero(fSx) || !fTools::equalZero(fSz))
311 Impl3DHomMatrix aShearXZMat;
313 aShearXZMat.set(0, 1, fSx);
314 aShearXZMat.set(2, 1, fSz);
316 mpImpl->doMulMatrix(aShearXZMat);
320 void B3DHomMatrix::frustum(double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar)
322 const double fZero(0.0);
323 const double fOne(1.0);
325 if(!fTools::more(fNear, fZero))
327 fNear = 0.001;
330 if(!fTools::more(fFar, fZero))
332 fFar = fOne;
335 if(fTools::equal(fNear, fFar))
337 fFar = fNear + fOne;
340 if(fTools::equal(fLeft, fRight))
342 fLeft -= fOne;
343 fRight += fOne;
346 if(fTools::equal(fTop, fBottom))
348 fBottom -= fOne;
349 fTop += fOne;
352 Impl3DHomMatrix aFrustumMat;
354 aFrustumMat.set(0, 0, 2.0 * fNear / (fRight - fLeft));
355 aFrustumMat.set(1, 1, 2.0 * fNear / (fTop - fBottom));
356 aFrustumMat.set(0, 2, (fRight + fLeft) / (fRight - fLeft));
357 aFrustumMat.set(1, 2, (fTop + fBottom) / (fTop - fBottom));
358 aFrustumMat.set(2, 2, -fOne * ((fFar + fNear) / (fFar - fNear)));
359 aFrustumMat.set(3, 2, -fOne);
360 aFrustumMat.set(2, 3, -fOne * ((2.0 * fFar * fNear) / (fFar - fNear)));
361 aFrustumMat.set(3, 3, fZero);
363 mpImpl->doMulMatrix(aFrustumMat);
366 void B3DHomMatrix::ortho(double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar)
368 if(fTools::equal(fNear, fFar))
370 fFar = fNear + 1.0;
373 if(fTools::equal(fLeft, fRight))
375 fLeft -= 1.0;
376 fRight += 1.0;
379 if(fTools::equal(fTop, fBottom))
381 fBottom -= 1.0;
382 fTop += 1.0;
385 Impl3DHomMatrix aOrthoMat;
387 aOrthoMat.set(0, 0, 2.0 / (fRight - fLeft));
388 aOrthoMat.set(1, 1, 2.0 / (fTop - fBottom));
389 aOrthoMat.set(2, 2, -1.0 * (2.0 / (fFar - fNear)));
390 aOrthoMat.set(0, 3, -1.0 * ((fRight + fLeft) / (fRight - fLeft)));
391 aOrthoMat.set(1, 3, -1.0 * ((fTop + fBottom) / (fTop - fBottom)));
392 aOrthoMat.set(2, 3, -1.0 * ((fFar + fNear) / (fFar - fNear)));
394 mpImpl->doMulMatrix(aOrthoMat);
397 void B3DHomMatrix::orientation(B3DPoint aVRP, B3DVector aVPN, B3DVector aVUV)
399 Impl3DHomMatrix aOrientationMat;
401 // translate -VRP
402 aOrientationMat.set(0, 3, -aVRP.getX());
403 aOrientationMat.set(1, 3, -aVRP.getY());
404 aOrientationMat.set(2, 3, -aVRP.getZ());
406 // build rotation
407 aVUV.normalize();
408 aVPN.normalize();
410 // build x-axis as peroendicular fron aVUV and aVPN
411 B3DVector aRx(aVUV.getPerpendicular(aVPN));
412 aRx.normalize();
414 // y-axis perpendicular to that
415 B3DVector aRy(aVPN.getPerpendicular(aRx));
416 aRy.normalize();
418 // the calculated normals are the line vectors of the rotation matrix,
419 // set them to create rotation
420 aOrientationMat.set(0, 0, aRx.getX());
421 aOrientationMat.set(0, 1, aRx.getY());
422 aOrientationMat.set(0, 2, aRx.getZ());
423 aOrientationMat.set(1, 0, aRy.getX());
424 aOrientationMat.set(1, 1, aRy.getY());
425 aOrientationMat.set(1, 2, aRy.getZ());
426 aOrientationMat.set(2, 0, aVPN.getX());
427 aOrientationMat.set(2, 1, aVPN.getY());
428 aOrientationMat.set(2, 2, aVPN.getZ());
430 mpImpl->doMulMatrix(aOrientationMat);
433 bool B3DHomMatrix::decompose(B3DTuple& rScale, B3DTuple& rTranslate, B3DTuple& rRotate, B3DTuple& rShear) const
435 // when perspective is used, decompose is not made here
436 if(!mpImpl->isLastLineDefault())
437 return false;
439 // If determinant is zero, decomposition is not possible
440 if(0.0 == determinant())
441 return false;
443 // isolate translation
444 rTranslate.setX(mpImpl->get(0, 3));
445 rTranslate.setY(mpImpl->get(1, 3));
446 rTranslate.setZ(mpImpl->get(2, 3));
448 // correct translate values
449 rTranslate.correctValues();
451 // get scale and shear
452 B3DVector aCol0(mpImpl->get(0, 0), mpImpl->get(1, 0), mpImpl->get(2, 0));
453 B3DVector aCol1(mpImpl->get(0, 1), mpImpl->get(1, 1), mpImpl->get(2, 1));
454 B3DVector aCol2(mpImpl->get(0, 2), mpImpl->get(1, 2), mpImpl->get(2, 2));
455 B3DVector aTemp;
457 // get ScaleX
458 rScale.setX(aCol0.getLength());
459 aCol0.normalize();
461 // get ShearXY
462 rShear.setX(aCol0.scalar(aCol1));
464 if(fTools::equalZero(rShear.getX()))
466 rShear.setX(0.0);
468 else
470 aTemp.setX(aCol1.getX() - rShear.getX() * aCol0.getX());
471 aTemp.setY(aCol1.getY() - rShear.getX() * aCol0.getY());
472 aTemp.setZ(aCol1.getZ() - rShear.getX() * aCol0.getZ());
473 aCol1 = aTemp;
476 // get ScaleY
477 rScale.setY(aCol1.getLength());
478 aCol1.normalize();
480 const double fShearX(rShear.getX());
482 if(!fTools::equalZero(fShearX))
484 rShear.setX(rShear.getX() / rScale.getY());
487 // get ShearXZ
488 rShear.setY(aCol0.scalar(aCol2));
490 if(fTools::equalZero(rShear.getY()))
492 rShear.setY(0.0);
494 else
496 aTemp.setX(aCol2.getX() - rShear.getY() * aCol0.getX());
497 aTemp.setY(aCol2.getY() - rShear.getY() * aCol0.getY());
498 aTemp.setZ(aCol2.getZ() - rShear.getY() * aCol0.getZ());
499 aCol2 = aTemp;
502 // get ShearYZ
503 rShear.setZ(aCol1.scalar(aCol2));
505 if(fTools::equalZero(rShear.getZ()))
507 rShear.setZ(0.0);
509 else
511 aTemp.setX(aCol2.getX() - rShear.getZ() * aCol1.getX());
512 aTemp.setY(aCol2.getY() - rShear.getZ() * aCol1.getY());
513 aTemp.setZ(aCol2.getZ() - rShear.getZ() * aCol1.getZ());
514 aCol2 = aTemp;
517 // get ScaleZ
518 rScale.setZ(aCol2.getLength());
519 aCol2.normalize();
521 const double fShearY(rShear.getY());
523 if(!fTools::equalZero(fShearY))
525 rShear.setY(rShear.getY() / rScale.getZ());
528 const double fShearZ(rShear.getZ());
530 if(!fTools::equalZero(fShearZ))
532 rShear.setZ(rShear.getZ() / rScale.getZ());
535 // correct shear values
536 rShear.correctValues();
538 // Coordinate system flip?
539 if(0.0 > aCol0.scalar(aCol1.getPerpendicular(aCol2)))
541 rScale = -rScale;
542 aCol0 = -aCol0;
543 aCol1 = -aCol1;
544 aCol2 = -aCol2;
547 // correct scale values
548 rScale.correctValues(1.0);
550 // Get rotations
552 double fy=0;
553 double cy=0;
555 if( ::basegfx::fTools::equal( aCol0.getZ(), 1.0 )
556 || aCol0.getZ() > 1.0 )
558 fy = -F_PI/2.0;
559 cy = 0.0;
561 else if( ::basegfx::fTools::equal( aCol0.getZ(), -1.0 )
562 || aCol0.getZ() < -1.0 )
564 fy = F_PI/2.0;
565 cy = 0.0;
567 else
569 fy = asin( -aCol0.getZ() );
570 cy = cos(fy);
573 rRotate.setY(fy);
574 if( ::basegfx::fTools::equalZero( cy ) )
576 if( aCol0.getZ() > 0.0 )
577 rRotate.setX(atan2(-1.0*aCol1.getX(), aCol1.getY()));
578 else
579 rRotate.setX(atan2(aCol1.getX(), aCol1.getY()));
580 rRotate.setZ(0.0);
582 else
584 rRotate.setX(atan2(aCol1.getZ(), aCol2.getZ()));
585 rRotate.setZ(atan2(aCol0.getY(), aCol0.getX()));
588 // corrcet rotate values
589 rRotate.correctValues();
592 return true;
594 } // end of namespace basegfx
596 // eof