1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <rtl/instance.hxx>
21 #include <basegfx/matrix/b3dhommatrix.hxx>
22 #include <hommatrixtemplate.hxx>
23 #include <basegfx/vector/b3dvector.hxx>
27 typedef ::basegfx::internal::ImplHomMatrixTemplate
< 4 >Impl3DHomMatrix_Base
;
28 class Impl3DHomMatrix
: public Impl3DHomMatrix_Base
32 namespace { struct IdentityMatrix
: public rtl::Static
< B3DHomMatrix::ImplType
,
33 IdentityMatrix
> {}; }
35 B3DHomMatrix::B3DHomMatrix() :
36 mpImpl( IdentityMatrix::get() ) // use common identity matrix
40 B3DHomMatrix::B3DHomMatrix(const B3DHomMatrix
& rMat
) :
45 B3DHomMatrix::~B3DHomMatrix()
49 B3DHomMatrix
& B3DHomMatrix::operator=(const B3DHomMatrix
& rMat
)
55 double B3DHomMatrix::get(sal_uInt16 nRow
, sal_uInt16 nColumn
) const
57 return mpImpl
->get(nRow
, nColumn
);
60 void B3DHomMatrix::set(sal_uInt16 nRow
, sal_uInt16 nColumn
, double fValue
)
62 mpImpl
->set(nRow
, nColumn
, fValue
);
65 bool B3DHomMatrix::isLastLineDefault() const
67 return mpImpl
->isLastLineDefault();
70 bool B3DHomMatrix::isIdentity() const
72 if(mpImpl
.same_object(IdentityMatrix::get()))
75 return mpImpl
->isIdentity();
78 void B3DHomMatrix::identity()
80 mpImpl
= IdentityMatrix::get();
83 bool B3DHomMatrix::invert()
85 Impl3DHomMatrix
aWork(*mpImpl
);
86 sal_uInt16
* pIndex
= new sal_uInt16
[Impl3DHomMatrix_Base::getEdgeLength()];
89 if(aWork
.ludcmp(pIndex
, nParity
))
91 mpImpl
->doInvert(aWork
, pIndex
);
101 double B3DHomMatrix::determinant() const
103 return mpImpl
->doDeterminant();
106 B3DHomMatrix
& B3DHomMatrix::operator+=(const B3DHomMatrix
& rMat
)
108 mpImpl
->doAddMatrix(*rMat
.mpImpl
);
112 B3DHomMatrix
& B3DHomMatrix::operator-=(const B3DHomMatrix
& rMat
)
114 mpImpl
->doSubMatrix(*rMat
.mpImpl
);
118 B3DHomMatrix
& B3DHomMatrix::operator*=(double fValue
)
120 const double fOne(1.0);
122 if(!fTools::equal(fOne
, fValue
))
123 mpImpl
->doMulMatrix(fValue
);
128 B3DHomMatrix
& B3DHomMatrix::operator/=(double fValue
)
130 const double fOne(1.0);
132 if(!fTools::equal(fOne
, fValue
))
133 mpImpl
->doMulMatrix(1.0 / fValue
);
138 B3DHomMatrix
& B3DHomMatrix::operator*=(const B3DHomMatrix
& rMat
)
140 if(!rMat
.isIdentity())
141 mpImpl
->doMulMatrix(*rMat
.mpImpl
);
146 bool B3DHomMatrix::operator==(const B3DHomMatrix
& rMat
) const
148 if(mpImpl
.same_object(rMat
.mpImpl
))
151 return mpImpl
->isEqual(*rMat
.mpImpl
);
154 bool B3DHomMatrix::operator!=(const B3DHomMatrix
& rMat
) const
156 return !(*this == rMat
);
159 void B3DHomMatrix::rotate(double fAngleX
,double fAngleY
,double fAngleZ
)
161 if(!fTools::equalZero(fAngleX
) || !fTools::equalZero(fAngleY
) || !fTools::equalZero(fAngleZ
))
163 if(!fTools::equalZero(fAngleX
))
165 Impl3DHomMatrix aRotMatX
;
166 double fSin(sin(fAngleX
));
167 double fCos(cos(fAngleX
));
169 aRotMatX
.set(1, 1, fCos
);
170 aRotMatX
.set(2, 2, fCos
);
171 aRotMatX
.set(2, 1, fSin
);
172 aRotMatX
.set(1, 2, -fSin
);
174 mpImpl
->doMulMatrix(aRotMatX
);
177 if(!fTools::equalZero(fAngleY
))
179 Impl3DHomMatrix aRotMatY
;
180 double fSin(sin(fAngleY
));
181 double fCos(cos(fAngleY
));
183 aRotMatY
.set(0, 0, fCos
);
184 aRotMatY
.set(2, 2, fCos
);
185 aRotMatY
.set(0, 2, fSin
);
186 aRotMatY
.set(2, 0, -fSin
);
188 mpImpl
->doMulMatrix(aRotMatY
);
191 if(!fTools::equalZero(fAngleZ
))
193 Impl3DHomMatrix aRotMatZ
;
194 double fSin(sin(fAngleZ
));
195 double fCos(cos(fAngleZ
));
197 aRotMatZ
.set(0, 0, fCos
);
198 aRotMatZ
.set(1, 1, fCos
);
199 aRotMatZ
.set(1, 0, fSin
);
200 aRotMatZ
.set(0, 1, -fSin
);
202 mpImpl
->doMulMatrix(aRotMatZ
);
207 void B3DHomMatrix::translate(double fX
, double fY
, double fZ
)
209 if(!fTools::equalZero(fX
) || !fTools::equalZero(fY
) || !fTools::equalZero(fZ
))
211 Impl3DHomMatrix aTransMat
;
213 aTransMat
.set(0, 3, fX
);
214 aTransMat
.set(1, 3, fY
);
215 aTransMat
.set(2, 3, fZ
);
217 mpImpl
->doMulMatrix(aTransMat
);
221 void B3DHomMatrix::scale(double fX
, double fY
, double fZ
)
223 const double fOne(1.0);
225 if(!fTools::equal(fOne
, fX
) || !fTools::equal(fOne
, fY
) ||!fTools::equal(fOne
, fZ
))
227 Impl3DHomMatrix aScaleMat
;
229 aScaleMat
.set(0, 0, fX
);
230 aScaleMat
.set(1, 1, fY
);
231 aScaleMat
.set(2, 2, fZ
);
233 mpImpl
->doMulMatrix(aScaleMat
);
237 void B3DHomMatrix::shearXY(double fSx
, double fSy
)
239 // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
240 if(!fTools::equalZero(fSx
) || !fTools::equalZero(fSy
))
242 Impl3DHomMatrix aShearXYMat
;
244 aShearXYMat
.set(0, 2, fSx
);
245 aShearXYMat
.set(1, 2, fSy
);
247 mpImpl
->doMulMatrix(aShearXYMat
);
251 void B3DHomMatrix::shearXZ(double fSx
, double fSz
)
253 // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
254 if(!fTools::equalZero(fSx
) || !fTools::equalZero(fSz
))
256 Impl3DHomMatrix aShearXZMat
;
258 aShearXZMat
.set(0, 1, fSx
);
259 aShearXZMat
.set(2, 1, fSz
);
261 mpImpl
->doMulMatrix(aShearXZMat
);
264 void B3DHomMatrix::frustum(double fLeft
, double fRight
, double fBottom
, double fTop
, double fNear
, double fFar
)
266 const double fZero(0.0);
267 const double fOne(1.0);
269 if(!fTools::more(fNear
, fZero
))
274 if(!fTools::more(fFar
, fZero
))
279 if(fTools::equal(fNear
, fFar
))
284 if(fTools::equal(fLeft
, fRight
))
290 if(fTools::equal(fTop
, fBottom
))
296 Impl3DHomMatrix aFrustumMat
;
298 aFrustumMat
.set(0, 0, 2.0 * fNear
/ (fRight
- fLeft
));
299 aFrustumMat
.set(1, 1, 2.0 * fNear
/ (fTop
- fBottom
));
300 aFrustumMat
.set(0, 2, (fRight
+ fLeft
) / (fRight
- fLeft
));
301 aFrustumMat
.set(1, 2, (fTop
+ fBottom
) / (fTop
- fBottom
));
302 aFrustumMat
.set(2, 2, -fOne
* ((fFar
+ fNear
) / (fFar
- fNear
)));
303 aFrustumMat
.set(3, 2, -fOne
);
304 aFrustumMat
.set(2, 3, -fOne
* ((2.0 * fFar
* fNear
) / (fFar
- fNear
)));
305 aFrustumMat
.set(3, 3, fZero
);
307 mpImpl
->doMulMatrix(aFrustumMat
);
310 void B3DHomMatrix::ortho(double fLeft
, double fRight
, double fBottom
, double fTop
, double fNear
, double fFar
)
312 if(fTools::equal(fNear
, fFar
))
317 if(fTools::equal(fLeft
, fRight
))
323 if(fTools::equal(fTop
, fBottom
))
329 Impl3DHomMatrix aOrthoMat
;
331 aOrthoMat
.set(0, 0, 2.0 / (fRight
- fLeft
));
332 aOrthoMat
.set(1, 1, 2.0 / (fTop
- fBottom
));
333 aOrthoMat
.set(2, 2, -1.0 * (2.0 / (fFar
- fNear
)));
334 aOrthoMat
.set(0, 3, -1.0 * ((fRight
+ fLeft
) / (fRight
- fLeft
)));
335 aOrthoMat
.set(1, 3, -1.0 * ((fTop
+ fBottom
) / (fTop
- fBottom
)));
336 aOrthoMat
.set(2, 3, -1.0 * ((fFar
+ fNear
) / (fFar
- fNear
)));
338 mpImpl
->doMulMatrix(aOrthoMat
);
341 void B3DHomMatrix::orientation(const B3DPoint
& rVRP
, B3DVector aVPN
, B3DVector aVUV
)
343 Impl3DHomMatrix aOrientationMat
;
346 aOrientationMat
.set(0, 3, -rVRP
.getX());
347 aOrientationMat
.set(1, 3, -rVRP
.getY());
348 aOrientationMat
.set(2, 3, -rVRP
.getZ());
354 // build x-axis as peroendicular fron aVUV and aVPN
355 B3DVector
aRx(aVUV
.getPerpendicular(aVPN
));
358 // y-axis perpendicular to that
359 B3DVector
aRy(aVPN
.getPerpendicular(aRx
));
362 // the calculated normals are the line vectors of the rotation matrix,
363 // set them to create rotation
364 aOrientationMat
.set(0, 0, aRx
.getX());
365 aOrientationMat
.set(0, 1, aRx
.getY());
366 aOrientationMat
.set(0, 2, aRx
.getZ());
367 aOrientationMat
.set(1, 0, aRy
.getX());
368 aOrientationMat
.set(1, 1, aRy
.getY());
369 aOrientationMat
.set(1, 2, aRy
.getZ());
370 aOrientationMat
.set(2, 0, aVPN
.getX());
371 aOrientationMat
.set(2, 1, aVPN
.getY());
372 aOrientationMat
.set(2, 2, aVPN
.getZ());
374 mpImpl
->doMulMatrix(aOrientationMat
);
377 bool B3DHomMatrix::decompose(B3DTuple
& rScale
, B3DTuple
& rTranslate
, B3DTuple
& rRotate
, B3DTuple
& rShear
) const
379 // when perspective is used, decompose is not made here
380 if(!mpImpl
->isLastLineDefault())
383 // If determinant is zero, decomposition is not possible
384 if(0.0 == determinant())
387 // isolate translation
388 rTranslate
.setX(mpImpl
->get(0, 3));
389 rTranslate
.setY(mpImpl
->get(1, 3));
390 rTranslate
.setZ(mpImpl
->get(2, 3));
392 // correct translate values
393 rTranslate
.correctValues();
395 // get scale and shear
396 B3DVector
aCol0(mpImpl
->get(0, 0), mpImpl
->get(1, 0), mpImpl
->get(2, 0));
397 B3DVector
aCol1(mpImpl
->get(0, 1), mpImpl
->get(1, 1), mpImpl
->get(2, 1));
398 B3DVector
aCol2(mpImpl
->get(0, 2), mpImpl
->get(1, 2), mpImpl
->get(2, 2));
402 rScale
.setX(aCol0
.getLength());
406 rShear
.setX(aCol0
.scalar(aCol1
));
408 if(fTools::equalZero(rShear
.getX()))
414 aTemp
.setX(aCol1
.getX() - rShear
.getX() * aCol0
.getX());
415 aTemp
.setY(aCol1
.getY() - rShear
.getX() * aCol0
.getY());
416 aTemp
.setZ(aCol1
.getZ() - rShear
.getX() * aCol0
.getZ());
421 rScale
.setY(aCol1
.getLength());
424 const double fShearX(rShear
.getX());
426 if(!fTools::equalZero(fShearX
))
428 rShear
.setX(rShear
.getX() / rScale
.getY());
432 rShear
.setY(aCol0
.scalar(aCol2
));
434 if(fTools::equalZero(rShear
.getY()))
440 aTemp
.setX(aCol2
.getX() - rShear
.getY() * aCol0
.getX());
441 aTemp
.setY(aCol2
.getY() - rShear
.getY() * aCol0
.getY());
442 aTemp
.setZ(aCol2
.getZ() - rShear
.getY() * aCol0
.getZ());
447 rShear
.setZ(aCol1
.scalar(aCol2
));
449 if(fTools::equalZero(rShear
.getZ()))
455 aTemp
.setX(aCol2
.getX() - rShear
.getZ() * aCol1
.getX());
456 aTemp
.setY(aCol2
.getY() - rShear
.getZ() * aCol1
.getY());
457 aTemp
.setZ(aCol2
.getZ() - rShear
.getZ() * aCol1
.getZ());
462 rScale
.setZ(aCol2
.getLength());
465 const double fShearY(rShear
.getY());
467 if(!fTools::equalZero(fShearY
))
469 // coverity[copy_paste_error] - this is correct getZ, not getY
470 rShear
.setY(rShear
.getY() / rScale
.getZ());
473 const double fShearZ(rShear
.getZ());
475 if(!fTools::equalZero(fShearZ
))
477 // coverity[original] - this is not an original copy-and-paste source for ^^^
478 rShear
.setZ(rShear
.getZ() / rScale
.getZ());
481 // correct shear values
482 rShear
.correctValues();
484 // Coordinate system flip?
485 if(0.0 > aCol0
.scalar(aCol1
.getPerpendicular(aCol2
)))
493 // correct scale values
494 rScale
.correctValues(1.0);
501 if( ::basegfx::fTools::equal( aCol0
.getZ(), 1.0 )
502 || aCol0
.getZ() > 1.0 )
507 else if( ::basegfx::fTools::equal( aCol0
.getZ(), -1.0 )
508 || aCol0
.getZ() < -1.0 )
515 fy
= asin( -aCol0
.getZ() );
520 if( ::basegfx::fTools::equalZero( cy
) )
522 if( aCol0
.getZ() > 0.0 )
523 rRotate
.setX(atan2(-1.0*aCol1
.getX(), aCol1
.getY()));
525 rRotate
.setX(atan2(aCol1
.getX(), aCol1
.getY()));
530 rRotate
.setX(atan2(aCol1
.getZ(), aCol2
.getZ()));
531 rRotate
.setZ(atan2(aCol0
.getY(), aCol0
.getX()));
534 // correct rotate values
535 rRotate
.correctValues();
540 } // end of namespace basegfx
542 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */