1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: b3dhommatrix.cxx,v $
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>
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
) :
58 B3DHomMatrix::~B3DHomMatrix()
62 B3DHomMatrix
& B3DHomMatrix::operator=(const B3DHomMatrix
& rMat
)
68 void B3DHomMatrix::makeUnique()
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()))
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()];
112 if(aWork
.ludcmp(pIndex
, nParity
))
114 mpImpl
->doInvert(aWork
, pIndex
);
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
);
156 B3DHomMatrix
& B3DHomMatrix::operator-=(const B3DHomMatrix
& rMat
)
158 mpImpl
->doSubMatrix(*rMat
.mpImpl
);
162 B3DHomMatrix
& B3DHomMatrix::operator*=(double fValue
)
164 const double fOne(1.0);
166 if(!fTools::equal(fOne
, fValue
))
167 mpImpl
->doMulMatrix(fValue
);
172 B3DHomMatrix
& B3DHomMatrix::operator/=(double fValue
)
174 const double fOne(1.0);
176 if(!fTools::equal(fOne
, fValue
))
177 mpImpl
->doMulMatrix(1.0 / fValue
);
182 B3DHomMatrix
& B3DHomMatrix::operator*=(const B3DHomMatrix
& rMat
)
184 if(!rMat
.isIdentity())
185 mpImpl
->doMulMatrix(*rMat
.mpImpl
);
190 bool B3DHomMatrix::operator==(const B3DHomMatrix
& rMat
) const
192 if(mpImpl
.same_object(rMat
.mpImpl
))
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
))
333 if(!fTools::more(fFar
, fZero
))
338 if(fTools::equal(fNear
, fFar
))
343 if(fTools::equal(fLeft
, fRight
))
349 if(fTools::equal(fTop
, fBottom
))
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
))
376 if(fTools::equal(fLeft
, fRight
))
382 if(fTools::equal(fTop
, fBottom
))
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
;
405 aOrientationMat
.set(0, 3, -aVRP
.getX());
406 aOrientationMat
.set(1, 3, -aVRP
.getY());
407 aOrientationMat
.set(2, 3, -aVRP
.getZ());
413 // build x-axis as peroendicular fron aVUV and aVPN
414 B3DVector
aRx(aVUV
.getPerpendicular(aVPN
));
417 // y-axis perpendicular to that
418 B3DVector
aRy(aVPN
.getPerpendicular(aRx
));
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())
442 // If determinant is zero, decomposition is not possible
443 if(0.0 == determinant())
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));
461 rScale
.setX(aCol0
.getLength());
465 rShear
.setX(aCol0
.scalar(aCol1
));
467 if(fTools::equalZero(rShear
.getX()))
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());
480 rScale
.setY(aCol1
.getLength());
483 const double fShearX(rShear
.getX());
485 if(!fTools::equalZero(fShearX
))
487 rShear
.setX(rShear
.getX() / rScale
.getY());
491 rShear
.setY(aCol0
.scalar(aCol2
));
493 if(fTools::equalZero(rShear
.getY()))
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());
506 rShear
.setZ(aCol1
.scalar(aCol2
));
508 if(fTools::equalZero(rShear
.getZ()))
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());
521 rScale
.setZ(aCol2
.getLength());
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
)))
550 // correct scale values
551 rScale
.correctValues(1.0);
558 if( ::basegfx::fTools::equal( aCol0
.getZ(), 1.0 )
559 || aCol0
.getZ() > 1.0 )
564 else if( ::basegfx::fTools::equal( aCol0
.getZ(), -1.0 )
565 || aCol0
.getZ() < -1.0 )
572 fy
= asin( -aCol0
.getZ() );
577 if( ::basegfx::fTools::equalZero( cy
) )
579 if( aCol0
.getZ() > 0.0 )
580 rRotate
.setX(atan2(-1.0*aCol1
.getX(), aCol1
.getY()));
582 rRotate
.setX(atan2(aCol1
.getX(), aCol1
.getY()));
587 rRotate
.setX(atan2(aCol1
.getZ(), aCol2
.getZ()));
588 rRotate
.setZ(atan2(aCol0
.getY(), aCol0
.getX()));
591 // corrcet rotate values
592 rRotate
.correctValues();
597 } // end of namespace basegfx