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>
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
) :
55 B3DHomMatrix::~B3DHomMatrix()
59 B3DHomMatrix
& B3DHomMatrix::operator=(const B3DHomMatrix
& rMat
)
65 void B3DHomMatrix::makeUnique()
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()))
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()];
109 if(aWork
.ludcmp(pIndex
, nParity
))
111 mpImpl
->doInvert(aWork
, pIndex
);
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
);
153 B3DHomMatrix
& B3DHomMatrix::operator-=(const B3DHomMatrix
& rMat
)
155 mpImpl
->doSubMatrix(*rMat
.mpImpl
);
159 B3DHomMatrix
& B3DHomMatrix::operator*=(double fValue
)
161 const double fOne(1.0);
163 if(!fTools::equal(fOne
, fValue
))
164 mpImpl
->doMulMatrix(fValue
);
169 B3DHomMatrix
& B3DHomMatrix::operator/=(double fValue
)
171 const double fOne(1.0);
173 if(!fTools::equal(fOne
, fValue
))
174 mpImpl
->doMulMatrix(1.0 / fValue
);
179 B3DHomMatrix
& B3DHomMatrix::operator*=(const B3DHomMatrix
& rMat
)
181 if(!rMat
.isIdentity())
182 mpImpl
->doMulMatrix(*rMat
.mpImpl
);
187 bool B3DHomMatrix::operator==(const B3DHomMatrix
& rMat
) const
189 if(mpImpl
.same_object(rMat
.mpImpl
))
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
))
330 if(!fTools::more(fFar
, fZero
))
335 if(fTools::equal(fNear
, fFar
))
340 if(fTools::equal(fLeft
, fRight
))
346 if(fTools::equal(fTop
, fBottom
))
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
))
373 if(fTools::equal(fLeft
, fRight
))
379 if(fTools::equal(fTop
, fBottom
))
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
;
402 aOrientationMat
.set(0, 3, -aVRP
.getX());
403 aOrientationMat
.set(1, 3, -aVRP
.getY());
404 aOrientationMat
.set(2, 3, -aVRP
.getZ());
410 // build x-axis as peroendicular fron aVUV and aVPN
411 B3DVector
aRx(aVUV
.getPerpendicular(aVPN
));
414 // y-axis perpendicular to that
415 B3DVector
aRy(aVPN
.getPerpendicular(aRx
));
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())
439 // If determinant is zero, decomposition is not possible
440 if(0.0 == determinant())
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));
458 rScale
.setX(aCol0
.getLength());
462 rShear
.setX(aCol0
.scalar(aCol1
));
464 if(fTools::equalZero(rShear
.getX()))
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());
477 rScale
.setY(aCol1
.getLength());
480 const double fShearX(rShear
.getX());
482 if(!fTools::equalZero(fShearX
))
484 rShear
.setX(rShear
.getX() / rScale
.getY());
488 rShear
.setY(aCol0
.scalar(aCol2
));
490 if(fTools::equalZero(rShear
.getY()))
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());
503 rShear
.setZ(aCol1
.scalar(aCol2
));
505 if(fTools::equalZero(rShear
.getZ()))
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());
518 rScale
.setZ(aCol2
.getLength());
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
)))
547 // correct scale values
548 rScale
.correctValues(1.0);
555 if( ::basegfx::fTools::equal( aCol0
.getZ(), 1.0 )
556 || aCol0
.getZ() > 1.0 )
561 else if( ::basegfx::fTools::equal( aCol0
.getZ(), -1.0 )
562 || aCol0
.getZ() < -1.0 )
569 fy
= asin( -aCol0
.getZ() );
574 if( ::basegfx::fTools::equalZero( cy
) )
576 if( aCol0
.getZ() > 0.0 )
577 rRotate
.setX(atan2(-1.0*aCol1
.getX(), aCol1
.getY()));
579 rRotate
.setX(atan2(aCol1
.getX(), aCol1
.getY()));
584 rRotate
.setX(atan2(aCol1
.getZ(), aCol2
.getZ()));
585 rRotate
.setZ(atan2(aCol0
.getY(), aCol0
.getX()));
588 // corrcet rotate values
589 rRotate
.correctValues();
594 } // end of namespace basegfx