merge the formfield patch from ooo-build
[ooovba.git] / basegfx / source / matrix / b3dhommatrix.cxx
blob90385c102bc3b533526af98b7daf693a9b7f97b7
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: b3dhommatrix.cxx,v $
10 * $Revision: 1.15 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_basegfx.hxx"
34 #include <rtl/instance.hxx>
35 #include <basegfx/matrix/b3dhommatrix.hxx>
36 #include <hommatrixtemplate.hxx>
37 #include <basegfx/vector/b3dvector.hxx>
39 namespace basegfx
41 class Impl3DHomMatrix : public ::basegfx::internal::ImplHomMatrixTemplate< 4 >
45 namespace { struct IdentityMatrix : public rtl::Static< B3DHomMatrix::ImplType,
46 IdentityMatrix > {}; }
48 B3DHomMatrix::B3DHomMatrix() :
49 mpImpl( IdentityMatrix::get() ) // use common identity matrix
53 B3DHomMatrix::B3DHomMatrix(const B3DHomMatrix& rMat) :
54 mpImpl(rMat.mpImpl)
58 B3DHomMatrix::~B3DHomMatrix()
62 B3DHomMatrix& B3DHomMatrix::operator=(const B3DHomMatrix& rMat)
64 mpImpl = rMat.mpImpl;
65 return *this;
68 void B3DHomMatrix::makeUnique()
70 mpImpl.make_unique();
73 double B3DHomMatrix::get(sal_uInt16 nRow, sal_uInt16 nColumn) const
75 return mpImpl->get(nRow, nColumn);
78 void B3DHomMatrix::set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
80 mpImpl->set(nRow, nColumn, fValue);
83 bool B3DHomMatrix::isLastLineDefault() const
85 return mpImpl->isLastLineDefault();
88 bool B3DHomMatrix::isIdentity() const
90 if(mpImpl.same_object(IdentityMatrix::get()))
91 return true;
93 return mpImpl->isIdentity();
96 void B3DHomMatrix::identity()
98 mpImpl = IdentityMatrix::get();
101 bool B3DHomMatrix::isInvertible() const
103 return mpImpl->isInvertible();
106 bool B3DHomMatrix::invert()
108 Impl3DHomMatrix aWork(*mpImpl);
109 sal_uInt16* pIndex = new sal_uInt16[mpImpl->getEdgeLength()];
110 sal_Int16 nParity;
112 if(aWork.ludcmp(pIndex, nParity))
114 mpImpl->doInvert(aWork, pIndex);
115 delete[] pIndex;
117 return true;
120 delete[] pIndex;
121 return false;
124 bool B3DHomMatrix::isNormalized() const
126 return mpImpl->isNormalized();
129 void B3DHomMatrix::normalize()
131 if(!const_cast<const B3DHomMatrix*>(this)->mpImpl->isNormalized())
132 mpImpl->doNormalize();
135 double B3DHomMatrix::determinant() const
137 return mpImpl->doDeterminant();
140 double B3DHomMatrix::trace() const
142 return mpImpl->doTrace();
145 void B3DHomMatrix::transpose()
147 mpImpl->doTranspose();
150 B3DHomMatrix& B3DHomMatrix::operator+=(const B3DHomMatrix& rMat)
152 mpImpl->doAddMatrix(*rMat.mpImpl);
153 return *this;
156 B3DHomMatrix& B3DHomMatrix::operator-=(const B3DHomMatrix& rMat)
158 mpImpl->doSubMatrix(*rMat.mpImpl);
159 return *this;
162 B3DHomMatrix& B3DHomMatrix::operator*=(double fValue)
164 const double fOne(1.0);
166 if(!fTools::equal(fOne, fValue))
167 mpImpl->doMulMatrix(fValue);
169 return *this;
172 B3DHomMatrix& B3DHomMatrix::operator/=(double fValue)
174 const double fOne(1.0);
176 if(!fTools::equal(fOne, fValue))
177 mpImpl->doMulMatrix(1.0 / fValue);
179 return *this;
182 B3DHomMatrix& B3DHomMatrix::operator*=(const B3DHomMatrix& rMat)
184 if(!rMat.isIdentity())
185 mpImpl->doMulMatrix(*rMat.mpImpl);
187 return *this;
190 bool B3DHomMatrix::operator==(const B3DHomMatrix& rMat) const
192 if(mpImpl.same_object(rMat.mpImpl))
193 return true;
195 return mpImpl->isEqual(*rMat.mpImpl);
198 bool B3DHomMatrix::operator!=(const B3DHomMatrix& rMat) const
200 return !(*this == rMat);
203 void B3DHomMatrix::rotate(double fAngleX,double fAngleY,double fAngleZ)
205 if(!fTools::equalZero(fAngleX) || !fTools::equalZero(fAngleY) || !fTools::equalZero(fAngleZ))
207 if(!fTools::equalZero(fAngleX))
209 Impl3DHomMatrix aRotMatX;
210 double fSin(sin(fAngleX));
211 double fCos(cos(fAngleX));
213 aRotMatX.set(1, 1, fCos);
214 aRotMatX.set(2, 2, fCos);
215 aRotMatX.set(2, 1, fSin);
216 aRotMatX.set(1, 2, -fSin);
218 mpImpl->doMulMatrix(aRotMatX);
221 if(!fTools::equalZero(fAngleY))
223 Impl3DHomMatrix aRotMatY;
224 double fSin(sin(fAngleY));
225 double fCos(cos(fAngleY));
227 aRotMatY.set(0, 0, fCos);
228 aRotMatY.set(2, 2, fCos);
229 aRotMatY.set(0, 2, fSin);
230 aRotMatY.set(2, 0, -fSin);
232 mpImpl->doMulMatrix(aRotMatY);
235 if(!fTools::equalZero(fAngleZ))
237 Impl3DHomMatrix aRotMatZ;
238 double fSin(sin(fAngleZ));
239 double fCos(cos(fAngleZ));
241 aRotMatZ.set(0, 0, fCos);
242 aRotMatZ.set(1, 1, fCos);
243 aRotMatZ.set(1, 0, fSin);
244 aRotMatZ.set(0, 1, -fSin);
246 mpImpl->doMulMatrix(aRotMatZ);
251 void B3DHomMatrix::translate(double fX, double fY, double fZ)
253 if(!fTools::equalZero(fX) || !fTools::equalZero(fY) || !fTools::equalZero(fZ))
255 Impl3DHomMatrix aTransMat;
257 aTransMat.set(0, 3, fX);
258 aTransMat.set(1, 3, fY);
259 aTransMat.set(2, 3, fZ);
261 mpImpl->doMulMatrix(aTransMat);
265 void B3DHomMatrix::scale(double fX, double fY, double fZ)
267 const double fOne(1.0);
269 if(!fTools::equal(fOne, fX) || !fTools::equal(fOne, fY) ||!fTools::equal(fOne, fZ))
271 Impl3DHomMatrix aScaleMat;
273 aScaleMat.set(0, 0, fX);
274 aScaleMat.set(1, 1, fY);
275 aScaleMat.set(2, 2, fZ);
277 mpImpl->doMulMatrix(aScaleMat);
281 void B3DHomMatrix::shearXY(double fSx, double fSy)
283 // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
284 if(!fTools::equalZero(fSx) || !fTools::equalZero(fSy))
286 Impl3DHomMatrix aShearXYMat;
288 aShearXYMat.set(0, 2, fSx);
289 aShearXYMat.set(1, 2, fSy);
291 mpImpl->doMulMatrix(aShearXYMat);
295 void B3DHomMatrix::shearYZ(double fSy, double fSz)
297 // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
298 if(!fTools::equalZero(fSy) || !fTools::equalZero(fSz))
300 Impl3DHomMatrix aShearYZMat;
302 aShearYZMat.set(1, 0, fSy);
303 aShearYZMat.set(2, 0, fSz);
305 mpImpl->doMulMatrix(aShearYZMat);
309 void B3DHomMatrix::shearXZ(double fSx, double fSz)
311 // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
312 if(!fTools::equalZero(fSx) || !fTools::equalZero(fSz))
314 Impl3DHomMatrix aShearXZMat;
316 aShearXZMat.set(0, 1, fSx);
317 aShearXZMat.set(2, 1, fSz);
319 mpImpl->doMulMatrix(aShearXZMat);
323 void B3DHomMatrix::frustum(double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar)
325 const double fZero(0.0);
326 const double fOne(1.0);
328 if(!fTools::more(fNear, fZero))
330 fNear = 0.001;
333 if(!fTools::more(fFar, fZero))
335 fFar = fOne;
338 if(fTools::equal(fNear, fFar))
340 fFar = fNear + fOne;
343 if(fTools::equal(fLeft, fRight))
345 fLeft -= fOne;
346 fRight += fOne;
349 if(fTools::equal(fTop, fBottom))
351 fBottom -= fOne;
352 fTop += fOne;
355 Impl3DHomMatrix aFrustumMat;
357 aFrustumMat.set(0, 0, 2.0 * fNear / (fRight - fLeft));
358 aFrustumMat.set(1, 1, 2.0 * fNear / (fTop - fBottom));
359 aFrustumMat.set(0, 2, (fRight + fLeft) / (fRight - fLeft));
360 aFrustumMat.set(1, 2, (fTop + fBottom) / (fTop - fBottom));
361 aFrustumMat.set(2, 2, -fOne * ((fFar + fNear) / (fFar - fNear)));
362 aFrustumMat.set(3, 2, -fOne);
363 aFrustumMat.set(2, 3, -fOne * ((2.0 * fFar * fNear) / (fFar - fNear)));
364 aFrustumMat.set(3, 3, fZero);
366 mpImpl->doMulMatrix(aFrustumMat);
369 void B3DHomMatrix::ortho(double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar)
371 if(fTools::equal(fNear, fFar))
373 fFar = fNear + 1.0;
376 if(fTools::equal(fLeft, fRight))
378 fLeft -= 1.0;
379 fRight += 1.0;
382 if(fTools::equal(fTop, fBottom))
384 fBottom -= 1.0;
385 fTop += 1.0;
388 Impl3DHomMatrix aOrthoMat;
390 aOrthoMat.set(0, 0, 2.0 / (fRight - fLeft));
391 aOrthoMat.set(1, 1, 2.0 / (fTop - fBottom));
392 aOrthoMat.set(2, 2, -1.0 * (2.0 / (fFar - fNear)));
393 aOrthoMat.set(0, 3, -1.0 * ((fRight + fLeft) / (fRight - fLeft)));
394 aOrthoMat.set(1, 3, -1.0 * ((fTop + fBottom) / (fTop - fBottom)));
395 aOrthoMat.set(2, 3, -1.0 * ((fFar + fNear) / (fFar - fNear)));
397 mpImpl->doMulMatrix(aOrthoMat);
400 void B3DHomMatrix::orientation(B3DPoint aVRP, B3DVector aVPN, B3DVector aVUV)
402 Impl3DHomMatrix aOrientationMat;
404 // translate -VRP
405 aOrientationMat.set(0, 3, -aVRP.getX());
406 aOrientationMat.set(1, 3, -aVRP.getY());
407 aOrientationMat.set(2, 3, -aVRP.getZ());
409 // build rotation
410 aVUV.normalize();
411 aVPN.normalize();
413 // build x-axis as peroendicular fron aVUV and aVPN
414 B3DVector aRx(aVUV.getPerpendicular(aVPN));
415 aRx.normalize();
417 // y-axis perpendicular to that
418 B3DVector aRy(aVPN.getPerpendicular(aRx));
419 aRy.normalize();
421 // the calculated normals are the line vectors of the rotation matrix,
422 // set them to create rotation
423 aOrientationMat.set(0, 0, aRx.getX());
424 aOrientationMat.set(0, 1, aRx.getY());
425 aOrientationMat.set(0, 2, aRx.getZ());
426 aOrientationMat.set(1, 0, aRy.getX());
427 aOrientationMat.set(1, 1, aRy.getY());
428 aOrientationMat.set(1, 2, aRy.getZ());
429 aOrientationMat.set(2, 0, aVPN.getX());
430 aOrientationMat.set(2, 1, aVPN.getY());
431 aOrientationMat.set(2, 2, aVPN.getZ());
433 mpImpl->doMulMatrix(aOrientationMat);
436 bool B3DHomMatrix::decompose(B3DTuple& rScale, B3DTuple& rTranslate, B3DTuple& rRotate, B3DTuple& rShear) const
438 // when perspective is used, decompose is not made here
439 if(!mpImpl->isLastLineDefault())
440 return false;
442 // If determinant is zero, decomposition is not possible
443 if(0.0 == determinant())
444 return false;
446 // isolate translation
447 rTranslate.setX(mpImpl->get(0, 3));
448 rTranslate.setY(mpImpl->get(1, 3));
449 rTranslate.setZ(mpImpl->get(2, 3));
451 // correct translate values
452 rTranslate.correctValues();
454 // get scale and shear
455 B3DVector aCol0(mpImpl->get(0, 0), mpImpl->get(1, 0), mpImpl->get(2, 0));
456 B3DVector aCol1(mpImpl->get(0, 1), mpImpl->get(1, 1), mpImpl->get(2, 1));
457 B3DVector aCol2(mpImpl->get(0, 2), mpImpl->get(1, 2), mpImpl->get(2, 2));
458 B3DVector aTemp;
460 // get ScaleX
461 rScale.setX(aCol0.getLength());
462 aCol0.normalize();
464 // get ShearXY
465 rShear.setX(aCol0.scalar(aCol1));
467 if(fTools::equalZero(rShear.getX()))
469 rShear.setX(0.0);
471 else
473 aTemp.setX(aCol1.getX() - rShear.getX() * aCol0.getX());
474 aTemp.setY(aCol1.getY() - rShear.getX() * aCol0.getY());
475 aTemp.setZ(aCol1.getZ() - rShear.getX() * aCol0.getZ());
476 aCol1 = aTemp;
479 // get ScaleY
480 rScale.setY(aCol1.getLength());
481 aCol1.normalize();
483 const double fShearX(rShear.getX());
485 if(!fTools::equalZero(fShearX))
487 rShear.setX(rShear.getX() / rScale.getY());
490 // get ShearXZ
491 rShear.setY(aCol0.scalar(aCol2));
493 if(fTools::equalZero(rShear.getY()))
495 rShear.setY(0.0);
497 else
499 aTemp.setX(aCol2.getX() - rShear.getY() * aCol0.getX());
500 aTemp.setY(aCol2.getY() - rShear.getY() * aCol0.getY());
501 aTemp.setZ(aCol2.getZ() - rShear.getY() * aCol0.getZ());
502 aCol2 = aTemp;
505 // get ShearYZ
506 rShear.setZ(aCol1.scalar(aCol2));
508 if(fTools::equalZero(rShear.getZ()))
510 rShear.setZ(0.0);
512 else
514 aTemp.setX(aCol2.getX() - rShear.getZ() * aCol1.getX());
515 aTemp.setY(aCol2.getY() - rShear.getZ() * aCol1.getY());
516 aTemp.setZ(aCol2.getZ() - rShear.getZ() * aCol1.getZ());
517 aCol2 = aTemp;
520 // get ScaleZ
521 rScale.setZ(aCol2.getLength());
522 aCol2.normalize();
524 const double fShearY(rShear.getY());
526 if(!fTools::equalZero(fShearY))
528 rShear.setY(rShear.getY() / rScale.getZ());
531 const double fShearZ(rShear.getZ());
533 if(!fTools::equalZero(fShearZ))
535 rShear.setZ(rShear.getZ() / rScale.getZ());
538 // correct shear values
539 rShear.correctValues();
541 // Coordinate system flip?
542 if(0.0 > aCol0.scalar(aCol1.getPerpendicular(aCol2)))
544 rScale = -rScale;
545 aCol0 = -aCol0;
546 aCol1 = -aCol1;
547 aCol2 = -aCol2;
550 // correct scale values
551 rScale.correctValues(1.0);
553 // Get rotations
555 double fy=0;
556 double cy=0;
558 if( ::basegfx::fTools::equal( aCol0.getZ(), 1.0 )
559 || aCol0.getZ() > 1.0 )
561 fy = -F_PI/2.0;
562 cy = 0.0;
564 else if( ::basegfx::fTools::equal( aCol0.getZ(), -1.0 )
565 || aCol0.getZ() < -1.0 )
567 fy = F_PI/2.0;
568 cy = 0.0;
570 else
572 fy = asin( -aCol0.getZ() );
573 cy = cos(fy);
576 rRotate.setY(fy);
577 if( ::basegfx::fTools::equalZero( cy ) )
579 if( aCol0.getZ() > 0.0 )
580 rRotate.setX(atan2(-1.0*aCol1.getX(), aCol1.getY()));
581 else
582 rRotate.setX(atan2(aCol1.getX(), aCol1.getY()));
583 rRotate.setZ(0.0);
585 else
587 rRotate.setX(atan2(aCol1.getZ(), aCol2.getZ()));
588 rRotate.setZ(atan2(aCol0.getY(), aCol0.getX()));
591 // corrcet rotate values
592 rRotate.correctValues();
595 return true;
597 } // end of namespace basegfx
599 // eof