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 <basegfx/matrix/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 void B3DHomMatrix::rotate(double fAngleX
,double fAngleY
,double fAngleZ
)
147 if(fTools::equalZero(fAngleX
) && fTools::equalZero(fAngleY
) && fTools::equalZero(fAngleZ
))
150 if(!fTools::equalZero(fAngleX
))
152 Impl3DHomMatrix aRotMatX
;
153 double fSin(sin(fAngleX
));
154 double fCos(cos(fAngleX
));
156 aRotMatX
.set(1, 1, fCos
);
157 aRotMatX
.set(2, 2, fCos
);
158 aRotMatX
.set(2, 1, fSin
);
159 aRotMatX
.set(1, 2, -fSin
);
161 mpImpl
->doMulMatrix(aRotMatX
);
164 if(!fTools::equalZero(fAngleY
))
166 Impl3DHomMatrix aRotMatY
;
167 double fSin(sin(fAngleY
));
168 double fCos(cos(fAngleY
));
170 aRotMatY
.set(0, 0, fCos
);
171 aRotMatY
.set(2, 2, fCos
);
172 aRotMatY
.set(0, 2, fSin
);
173 aRotMatY
.set(2, 0, -fSin
);
175 mpImpl
->doMulMatrix(aRotMatY
);
178 if(fTools::equalZero(fAngleZ
))
181 Impl3DHomMatrix aRotMatZ
;
182 double fSin(sin(fAngleZ
));
183 double fCos(cos(fAngleZ
));
185 aRotMatZ
.set(0, 0, fCos
);
186 aRotMatZ
.set(1, 1, fCos
);
187 aRotMatZ
.set(1, 0, fSin
);
188 aRotMatZ
.set(0, 1, -fSin
);
190 mpImpl
->doMulMatrix(aRotMatZ
);
193 void B3DHomMatrix::rotate(const B3DTuple
& rRotation
)
195 rotate(rRotation
.getX(), rRotation
.getY(), rRotation
.getZ());
198 void B3DHomMatrix::translate(double fX
, double fY
, double fZ
)
200 if(!fTools::equalZero(fX
) || !fTools::equalZero(fY
) || !fTools::equalZero(fZ
))
202 Impl3DHomMatrix aTransMat
;
204 aTransMat
.set(0, 3, fX
);
205 aTransMat
.set(1, 3, fY
);
206 aTransMat
.set(2, 3, fZ
);
208 mpImpl
->doMulMatrix(aTransMat
);
212 void B3DHomMatrix::translate(const B3DTuple
& rRotation
)
214 translate(rRotation
.getX(), rRotation
.getY(), rRotation
.getZ());
217 void B3DHomMatrix::scale(double fX
, double fY
, double fZ
)
219 const double fOne(1.0);
221 if(!fTools::equal(fOne
, fX
) || !fTools::equal(fOne
, fY
) ||!fTools::equal(fOne
, fZ
))
223 Impl3DHomMatrix aScaleMat
;
225 aScaleMat
.set(0, 0, fX
);
226 aScaleMat
.set(1, 1, fY
);
227 aScaleMat
.set(2, 2, fZ
);
229 mpImpl
->doMulMatrix(aScaleMat
);
233 void B3DHomMatrix::scale(const B3DTuple
& rRotation
)
235 scale(rRotation
.getX(), rRotation
.getY(), rRotation
.getZ());
238 void B3DHomMatrix::shearXY(double fSx
, double fSy
)
240 // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
241 if(!fTools::equalZero(fSx
) || !fTools::equalZero(fSy
))
243 Impl3DHomMatrix aShearXYMat
;
245 aShearXYMat
.set(0, 2, fSx
);
246 aShearXYMat
.set(1, 2, fSy
);
248 mpImpl
->doMulMatrix(aShearXYMat
);
252 void B3DHomMatrix::shearXZ(double fSx
, double fSz
)
254 // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
255 if(!fTools::equalZero(fSx
) || !fTools::equalZero(fSz
))
257 Impl3DHomMatrix aShearXZMat
;
259 aShearXZMat
.set(0, 1, fSx
);
260 aShearXZMat
.set(2, 1, fSz
);
262 mpImpl
->doMulMatrix(aShearXZMat
);
265 void B3DHomMatrix::frustum(double fLeft
, double fRight
, double fBottom
, double fTop
, double fNear
, double fFar
)
267 const double fZero(0.0);
268 const double fOne(1.0);
270 if(!fTools::more(fNear
, fZero
))
275 if(!fTools::more(fFar
, fZero
))
280 if(fTools::equal(fNear
, fFar
))
285 if(fTools::equal(fLeft
, fRight
))
291 if(fTools::equal(fTop
, fBottom
))
297 Impl3DHomMatrix aFrustumMat
;
299 aFrustumMat
.set(0, 0, 2.0 * fNear
/ (fRight
- fLeft
));
300 aFrustumMat
.set(1, 1, 2.0 * fNear
/ (fTop
- fBottom
));
301 aFrustumMat
.set(0, 2, (fRight
+ fLeft
) / (fRight
- fLeft
));
302 aFrustumMat
.set(1, 2, (fTop
+ fBottom
) / (fTop
- fBottom
));
303 aFrustumMat
.set(2, 2, -fOne
* ((fFar
+ fNear
) / (fFar
- fNear
)));
304 aFrustumMat
.set(3, 2, -fOne
);
305 aFrustumMat
.set(2, 3, -fOne
* ((2.0 * fFar
* fNear
) / (fFar
- fNear
)));
306 aFrustumMat
.set(3, 3, fZero
);
308 mpImpl
->doMulMatrix(aFrustumMat
);
311 void B3DHomMatrix::ortho(double fLeft
, double fRight
, double fBottom
, double fTop
, double fNear
, double fFar
)
313 if(fTools::equal(fNear
, fFar
))
318 if(fTools::equal(fLeft
, fRight
))
324 if(fTools::equal(fTop
, fBottom
))
330 Impl3DHomMatrix aOrthoMat
;
332 aOrthoMat
.set(0, 0, 2.0 / (fRight
- fLeft
));
333 aOrthoMat
.set(1, 1, 2.0 / (fTop
- fBottom
));
334 aOrthoMat
.set(2, 2, -1.0 * (2.0 / (fFar
- fNear
)));
335 aOrthoMat
.set(0, 3, -1.0 * ((fRight
+ fLeft
) / (fRight
- fLeft
)));
336 aOrthoMat
.set(1, 3, -1.0 * ((fTop
+ fBottom
) / (fTop
- fBottom
)));
337 aOrthoMat
.set(2, 3, -1.0 * ((fFar
+ fNear
) / (fFar
- fNear
)));
339 mpImpl
->doMulMatrix(aOrthoMat
);
342 void B3DHomMatrix::orientation(const B3DPoint
& rVRP
, B3DVector aVPN
, B3DVector aVUV
)
344 Impl3DHomMatrix aOrientationMat
;
347 aOrientationMat
.set(0, 3, -rVRP
.getX());
348 aOrientationMat
.set(1, 3, -rVRP
.getY());
349 aOrientationMat
.set(2, 3, -rVRP
.getZ());
355 // build x-axis as perpendicular from aVUV and aVPN
356 B3DVector
aRx(aVUV
.getPerpendicular(aVPN
));
359 // y-axis perpendicular to that
360 B3DVector
aRy(aVPN
.getPerpendicular(aRx
));
363 // the calculated normals are the line vectors of the rotation matrix,
364 // set them to create rotation
365 aOrientationMat
.set(0, 0, aRx
.getX());
366 aOrientationMat
.set(0, 1, aRx
.getY());
367 aOrientationMat
.set(0, 2, aRx
.getZ());
368 aOrientationMat
.set(1, 0, aRy
.getX());
369 aOrientationMat
.set(1, 1, aRy
.getY());
370 aOrientationMat
.set(1, 2, aRy
.getZ());
371 aOrientationMat
.set(2, 0, aVPN
.getX());
372 aOrientationMat
.set(2, 1, aVPN
.getY());
373 aOrientationMat
.set(2, 2, aVPN
.getZ());
375 mpImpl
->doMulMatrix(aOrientationMat
);
378 void B3DHomMatrix::decompose(B3DTuple
& rScale
, B3DTuple
& rTranslate
, B3DTuple
& rRotate
, B3DTuple
& rShear
) const
380 // when perspective is used, decompose is not made here
381 if(!mpImpl
->isLastLineDefault())
384 // If determinant is zero, decomposition is not possible
385 if(determinant() == 0.0)
388 // isolate translation
389 rTranslate
.setX(mpImpl
->get(0, 3));
390 rTranslate
.setY(mpImpl
->get(1, 3));
391 rTranslate
.setZ(mpImpl
->get(2, 3));
393 // correct translate values
394 rTranslate
.correctValues();
396 // get scale and shear
397 B3DVector
aCol0(mpImpl
->get(0, 0), mpImpl
->get(1, 0), mpImpl
->get(2, 0));
398 B3DVector
aCol1(mpImpl
->get(0, 1), mpImpl
->get(1, 1), mpImpl
->get(2, 1));
399 B3DVector
aCol2(mpImpl
->get(0, 2), mpImpl
->get(1, 2), mpImpl
->get(2, 2));
403 rScale
.setX(aCol0
.getLength());
407 rShear
.setX(aCol0
.scalar(aCol1
));
409 if(fTools::equalZero(rShear
.getX()))
415 aTemp
.setX(aCol1
.getX() - rShear
.getX() * aCol0
.getX());
416 aTemp
.setY(aCol1
.getY() - rShear
.getX() * aCol0
.getY());
417 aTemp
.setZ(aCol1
.getZ() - rShear
.getX() * aCol0
.getZ());
422 rScale
.setY(aCol1
.getLength());
425 const double fShearX(rShear
.getX());
427 if(!fTools::equalZero(fShearX
))
429 rShear
.setX(rShear
.getX() / rScale
.getY());
433 rShear
.setY(aCol0
.scalar(aCol2
));
435 if(fTools::equalZero(rShear
.getY()))
441 aTemp
.setX(aCol2
.getX() - rShear
.getY() * aCol0
.getX());
442 aTemp
.setY(aCol2
.getY() - rShear
.getY() * aCol0
.getY());
443 aTemp
.setZ(aCol2
.getZ() - rShear
.getY() * aCol0
.getZ());
448 rShear
.setZ(aCol1
.scalar(aCol2
));
450 if(fTools::equalZero(rShear
.getZ()))
456 aTemp
.setX(aCol2
.getX() - rShear
.getZ() * aCol1
.getX());
457 aTemp
.setY(aCol2
.getY() - rShear
.getZ() * aCol1
.getY());
458 aTemp
.setZ(aCol2
.getZ() - rShear
.getZ() * aCol1
.getZ());
463 rScale
.setZ(aCol2
.getLength());
466 const double fShearY(rShear
.getY());
468 if(!fTools::equalZero(fShearY
))
470 // coverity[copy_paste_error : FALSE] - this is correct getZ, not getY
471 rShear
.setY(rShear
.getY() / rScale
.getZ());
474 const double fShearZ(rShear
.getZ());
476 if(!fTools::equalZero(fShearZ
))
478 // coverity[original] - this is not an original copy-and-paste source for ^^^
479 rShear
.setZ(rShear
.getZ() / rScale
.getZ());
482 // correct shear values
483 rShear
.correctValues();
485 // Coordinate system flip?
486 if(0.0 > aCol0
.scalar(aCol1
.getPerpendicular(aCol2
)))
494 // correct scale values
495 rScale
.correctValues(1.0);
502 if( ::basegfx::fTools::equal( aCol0
.getZ(), 1.0 )
503 || aCol0
.getZ() > 1.0 )
508 else if( ::basegfx::fTools::equal( aCol0
.getZ(), -1.0 )
509 || aCol0
.getZ() < -1.0 )
516 fy
= asin( -aCol0
.getZ() );
521 if( ::basegfx::fTools::equalZero( cy
) )
523 if( aCol0
.getZ() > 0.0 )
524 rRotate
.setX(atan2(-1.0*aCol1
.getX(), aCol1
.getY()));
526 rRotate
.setX(atan2(aCol1
.getX(), aCol1
.getY()));
531 rRotate
.setX(atan2(aCol1
.getZ(), aCol2
.getZ()));
532 rRotate
.setZ(atan2(aCol0
.getY(), aCol0
.getX()));
535 // correct rotate values
536 rRotate
.correctValues();
539 } // end of namespace basegfx
541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */