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 <basegfx/matrix/b3dhommatrix.hxx>
21 #include <hommatrixtemplate.hxx>
22 #include <basegfx/vector/b3dvector.hxx>
27 typedef ::basegfx::internal::ImplHomMatrixTemplate
< 4 >Impl3DHomMatrix_Base
;
28 class Impl3DHomMatrix
: public Impl3DHomMatrix_Base
32 B3DHomMatrix::B3DHomMatrix() = default;
34 B3DHomMatrix::B3DHomMatrix(const B3DHomMatrix
&) = default;
36 B3DHomMatrix::B3DHomMatrix(B3DHomMatrix
&&) = default;
38 B3DHomMatrix::~B3DHomMatrix() = default;
40 B3DHomMatrix
& B3DHomMatrix::operator=(const B3DHomMatrix
&) = default;
42 B3DHomMatrix
& B3DHomMatrix::operator=(B3DHomMatrix
&&) = default;
44 double B3DHomMatrix::get(sal_uInt16 nRow
, sal_uInt16 nColumn
) const
46 return mpImpl
->get(nRow
, nColumn
);
49 void B3DHomMatrix::set(sal_uInt16 nRow
, sal_uInt16 nColumn
, double fValue
)
51 mpImpl
->set(nRow
, nColumn
, fValue
);
54 bool B3DHomMatrix::isLastLineDefault() const
56 return mpImpl
->isLastLineDefault();
59 bool B3DHomMatrix::isIdentity() const
61 return mpImpl
->isIdentity();
64 void B3DHomMatrix::identity()
66 *mpImpl
= Impl3DHomMatrix();
69 void B3DHomMatrix::invert()
71 Impl3DHomMatrix
aWork(*mpImpl
);
72 std::unique_ptr
<sal_uInt16
[]> pIndex( new sal_uInt16
[Impl3DHomMatrix_Base::getEdgeLength()] );
75 if(aWork
.ludcmp(pIndex
.get(), nParity
))
77 mpImpl
->doInvert(aWork
, pIndex
.get());
81 double B3DHomMatrix::determinant() const
83 return mpImpl
->doDeterminant();
86 B3DHomMatrix
& B3DHomMatrix::operator+=(const B3DHomMatrix
& rMat
)
88 mpImpl
->doAddMatrix(*rMat
.mpImpl
);
92 B3DHomMatrix
& B3DHomMatrix::operator-=(const B3DHomMatrix
& rMat
)
94 mpImpl
->doSubMatrix(*rMat
.mpImpl
);
98 B3DHomMatrix
& B3DHomMatrix::operator*=(double fValue
)
100 const double fOne(1.0);
102 if(!fTools::equal(fOne
, fValue
))
103 mpImpl
->doMulMatrix(fValue
);
108 B3DHomMatrix
& B3DHomMatrix::operator/=(double fValue
)
110 const double fOne(1.0);
112 if(!fTools::equal(fOne
, fValue
))
113 mpImpl
->doMulMatrix(1.0 / fValue
);
118 B3DHomMatrix
& B3DHomMatrix::operator*=(const B3DHomMatrix
& rMat
)
120 if(rMat
.isIdentity())
122 // multiply with identity, no change -> nothing to do
124 else if(isIdentity())
126 // we are identity, result will be rMat -> assign
132 mpImpl
->doMulMatrix(*rMat
.mpImpl
);
137 bool B3DHomMatrix::operator==(const B3DHomMatrix
& rMat
) const
139 if(mpImpl
.same_object(rMat
.mpImpl
))
142 return mpImpl
->isEqual(*rMat
.mpImpl
);
145 bool B3DHomMatrix::operator!=(const B3DHomMatrix
& rMat
) const
147 return !(*this == rMat
);
150 void B3DHomMatrix::rotate(double fAngleX
,double fAngleY
,double fAngleZ
)
152 if(!fTools::equalZero(fAngleX
) || !fTools::equalZero(fAngleY
) || !fTools::equalZero(fAngleZ
))
154 if(!fTools::equalZero(fAngleX
))
156 Impl3DHomMatrix aRotMatX
;
157 double fSin(sin(fAngleX
));
158 double fCos(cos(fAngleX
));
160 aRotMatX
.set(1, 1, fCos
);
161 aRotMatX
.set(2, 2, fCos
);
162 aRotMatX
.set(2, 1, fSin
);
163 aRotMatX
.set(1, 2, -fSin
);
165 mpImpl
->doMulMatrix(aRotMatX
);
168 if(!fTools::equalZero(fAngleY
))
170 Impl3DHomMatrix aRotMatY
;
171 double fSin(sin(fAngleY
));
172 double fCos(cos(fAngleY
));
174 aRotMatY
.set(0, 0, fCos
);
175 aRotMatY
.set(2, 2, fCos
);
176 aRotMatY
.set(0, 2, fSin
);
177 aRotMatY
.set(2, 0, -fSin
);
179 mpImpl
->doMulMatrix(aRotMatY
);
182 if(!fTools::equalZero(fAngleZ
))
184 Impl3DHomMatrix aRotMatZ
;
185 double fSin(sin(fAngleZ
));
186 double fCos(cos(fAngleZ
));
188 aRotMatZ
.set(0, 0, fCos
);
189 aRotMatZ
.set(1, 1, fCos
);
190 aRotMatZ
.set(1, 0, fSin
);
191 aRotMatZ
.set(0, 1, -fSin
);
193 mpImpl
->doMulMatrix(aRotMatZ
);
198 void B3DHomMatrix::rotate(const B3DTuple
& rRotation
)
200 rotate(rRotation
.getX(), rRotation
.getY(), rRotation
.getZ());
203 void B3DHomMatrix::translate(double fX
, double fY
, double fZ
)
205 if(!fTools::equalZero(fX
) || !fTools::equalZero(fY
) || !fTools::equalZero(fZ
))
207 Impl3DHomMatrix aTransMat
;
209 aTransMat
.set(0, 3, fX
);
210 aTransMat
.set(1, 3, fY
);
211 aTransMat
.set(2, 3, fZ
);
213 mpImpl
->doMulMatrix(aTransMat
);
217 void B3DHomMatrix::translate(const B3DTuple
& rRotation
)
219 translate(rRotation
.getX(), rRotation
.getY(), rRotation
.getZ());
222 void B3DHomMatrix::scale(double fX
, double fY
, double fZ
)
224 const double fOne(1.0);
226 if(!fTools::equal(fOne
, fX
) || !fTools::equal(fOne
, fY
) ||!fTools::equal(fOne
, fZ
))
228 Impl3DHomMatrix aScaleMat
;
230 aScaleMat
.set(0, 0, fX
);
231 aScaleMat
.set(1, 1, fY
);
232 aScaleMat
.set(2, 2, fZ
);
234 mpImpl
->doMulMatrix(aScaleMat
);
238 void B3DHomMatrix::scale(const B3DTuple
& rRotation
)
240 scale(rRotation
.getX(), rRotation
.getY(), rRotation
.getZ());
243 void B3DHomMatrix::shearXY(double fSx
, double fSy
)
245 // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
246 if(!fTools::equalZero(fSx
) || !fTools::equalZero(fSy
))
248 Impl3DHomMatrix aShearXYMat
;
250 aShearXYMat
.set(0, 2, fSx
);
251 aShearXYMat
.set(1, 2, fSy
);
253 mpImpl
->doMulMatrix(aShearXYMat
);
257 void B3DHomMatrix::shearXZ(double fSx
, double fSz
)
259 // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
260 if(!fTools::equalZero(fSx
) || !fTools::equalZero(fSz
))
262 Impl3DHomMatrix aShearXZMat
;
264 aShearXZMat
.set(0, 1, fSx
);
265 aShearXZMat
.set(2, 1, fSz
);
267 mpImpl
->doMulMatrix(aShearXZMat
);
270 void B3DHomMatrix::frustum(double fLeft
, double fRight
, double fBottom
, double fTop
, double fNear
, double fFar
)
272 const double fZero(0.0);
273 const double fOne(1.0);
275 if(!fTools::more(fNear
, fZero
))
280 if(!fTools::more(fFar
, fZero
))
285 if(fTools::equal(fNear
, fFar
))
290 if(fTools::equal(fLeft
, fRight
))
296 if(fTools::equal(fTop
, fBottom
))
302 Impl3DHomMatrix aFrustumMat
;
304 aFrustumMat
.set(0, 0, 2.0 * fNear
/ (fRight
- fLeft
));
305 aFrustumMat
.set(1, 1, 2.0 * fNear
/ (fTop
- fBottom
));
306 aFrustumMat
.set(0, 2, (fRight
+ fLeft
) / (fRight
- fLeft
));
307 aFrustumMat
.set(1, 2, (fTop
+ fBottom
) / (fTop
- fBottom
));
308 aFrustumMat
.set(2, 2, -fOne
* ((fFar
+ fNear
) / (fFar
- fNear
)));
309 aFrustumMat
.set(3, 2, -fOne
);
310 aFrustumMat
.set(2, 3, -fOne
* ((2.0 * fFar
* fNear
) / (fFar
- fNear
)));
311 aFrustumMat
.set(3, 3, fZero
);
313 mpImpl
->doMulMatrix(aFrustumMat
);
316 void B3DHomMatrix::ortho(double fLeft
, double fRight
, double fBottom
, double fTop
, double fNear
, double fFar
)
318 if(fTools::equal(fNear
, fFar
))
323 if(fTools::equal(fLeft
, fRight
))
329 if(fTools::equal(fTop
, fBottom
))
335 Impl3DHomMatrix aOrthoMat
;
337 aOrthoMat
.set(0, 0, 2.0 / (fRight
- fLeft
));
338 aOrthoMat
.set(1, 1, 2.0 / (fTop
- fBottom
));
339 aOrthoMat
.set(2, 2, -1.0 * (2.0 / (fFar
- fNear
)));
340 aOrthoMat
.set(0, 3, -1.0 * ((fRight
+ fLeft
) / (fRight
- fLeft
)));
341 aOrthoMat
.set(1, 3, -1.0 * ((fTop
+ fBottom
) / (fTop
- fBottom
)));
342 aOrthoMat
.set(2, 3, -1.0 * ((fFar
+ fNear
) / (fFar
- fNear
)));
344 mpImpl
->doMulMatrix(aOrthoMat
);
347 void B3DHomMatrix::orientation(const B3DPoint
& rVRP
, B3DVector aVPN
, B3DVector aVUV
)
349 Impl3DHomMatrix aOrientationMat
;
352 aOrientationMat
.set(0, 3, -rVRP
.getX());
353 aOrientationMat
.set(1, 3, -rVRP
.getY());
354 aOrientationMat
.set(2, 3, -rVRP
.getZ());
360 // build x-axis as perpendicular from aVUV and aVPN
361 B3DVector
aRx(aVUV
.getPerpendicular(aVPN
));
364 // y-axis perpendicular to that
365 B3DVector
aRy(aVPN
.getPerpendicular(aRx
));
368 // the calculated normals are the line vectors of the rotation matrix,
369 // set them to create rotation
370 aOrientationMat
.set(0, 0, aRx
.getX());
371 aOrientationMat
.set(0, 1, aRx
.getY());
372 aOrientationMat
.set(0, 2, aRx
.getZ());
373 aOrientationMat
.set(1, 0, aRy
.getX());
374 aOrientationMat
.set(1, 1, aRy
.getY());
375 aOrientationMat
.set(1, 2, aRy
.getZ());
376 aOrientationMat
.set(2, 0, aVPN
.getX());
377 aOrientationMat
.set(2, 1, aVPN
.getY());
378 aOrientationMat
.set(2, 2, aVPN
.getZ());
380 mpImpl
->doMulMatrix(aOrientationMat
);
383 void B3DHomMatrix::decompose(B3DTuple
& rScale
, B3DTuple
& rTranslate
, B3DTuple
& rRotate
, B3DTuple
& rShear
) const
385 // when perspective is used, decompose is not made here
386 if(!mpImpl
->isLastLineDefault())
389 // If determinant is zero, decomposition is not possible
390 if(determinant() == 0.0)
393 // isolate translation
394 rTranslate
.setX(mpImpl
->get(0, 3));
395 rTranslate
.setY(mpImpl
->get(1, 3));
396 rTranslate
.setZ(mpImpl
->get(2, 3));
398 // correct translate values
399 rTranslate
.correctValues();
401 // get scale and shear
402 B3DVector
aCol0(mpImpl
->get(0, 0), mpImpl
->get(1, 0), mpImpl
->get(2, 0));
403 B3DVector
aCol1(mpImpl
->get(0, 1), mpImpl
->get(1, 1), mpImpl
->get(2, 1));
404 B3DVector
aCol2(mpImpl
->get(0, 2), mpImpl
->get(1, 2), mpImpl
->get(2, 2));
408 rScale
.setX(aCol0
.getLength());
412 rShear
.setX(aCol0
.scalar(aCol1
));
414 if(fTools::equalZero(rShear
.getX()))
420 aTemp
.setX(aCol1
.getX() - rShear
.getX() * aCol0
.getX());
421 aTemp
.setY(aCol1
.getY() - rShear
.getX() * aCol0
.getY());
422 aTemp
.setZ(aCol1
.getZ() - rShear
.getX() * aCol0
.getZ());
427 rScale
.setY(aCol1
.getLength());
430 const double fShearX(rShear
.getX());
432 if(!fTools::equalZero(fShearX
))
434 rShear
.setX(rShear
.getX() / rScale
.getY());
438 rShear
.setY(aCol0
.scalar(aCol2
));
440 if(fTools::equalZero(rShear
.getY()))
446 aTemp
.setX(aCol2
.getX() - rShear
.getY() * aCol0
.getX());
447 aTemp
.setY(aCol2
.getY() - rShear
.getY() * aCol0
.getY());
448 aTemp
.setZ(aCol2
.getZ() - rShear
.getY() * aCol0
.getZ());
453 rShear
.setZ(aCol1
.scalar(aCol2
));
455 if(fTools::equalZero(rShear
.getZ()))
461 aTemp
.setX(aCol2
.getX() - rShear
.getZ() * aCol1
.getX());
462 aTemp
.setY(aCol2
.getY() - rShear
.getZ() * aCol1
.getY());
463 aTemp
.setZ(aCol2
.getZ() - rShear
.getZ() * aCol1
.getZ());
468 rScale
.setZ(aCol2
.getLength());
471 const double fShearY(rShear
.getY());
473 if(!fTools::equalZero(fShearY
))
475 // coverity[copy_paste_error : FALSE] - this is correct getZ, not getY
476 rShear
.setY(rShear
.getY() / rScale
.getZ());
479 const double fShearZ(rShear
.getZ());
481 if(!fTools::equalZero(fShearZ
))
483 // coverity[original] - this is not an original copy-and-paste source for ^^^
484 rShear
.setZ(rShear
.getZ() / rScale
.getZ());
487 // correct shear values
488 rShear
.correctValues();
490 // Coordinate system flip?
491 if(0.0 > aCol0
.scalar(aCol1
.getPerpendicular(aCol2
)))
499 // correct scale values
500 rScale
.correctValues(1.0);
507 if( ::basegfx::fTools::equal( aCol0
.getZ(), 1.0 )
508 || aCol0
.getZ() > 1.0 )
513 else if( ::basegfx::fTools::equal( aCol0
.getZ(), -1.0 )
514 || aCol0
.getZ() < -1.0 )
521 fy
= asin( -aCol0
.getZ() );
526 if( ::basegfx::fTools::equalZero( cy
) )
528 if( aCol0
.getZ() > 0.0 )
529 rRotate
.setX(atan2(-1.0*aCol1
.getX(), aCol1
.getY()));
531 rRotate
.setX(atan2(aCol1
.getX(), aCol1
.getY()));
536 rRotate
.setX(atan2(aCol1
.getZ(), aCol2
.getZ()));
537 rRotate
.setZ(atan2(aCol0
.getY(), aCol0
.getX()));
540 // correct rotate values
541 rRotate
.correctValues();
544 } // end of namespace basegfx
546 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */