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())
121 mpImpl
->doMulMatrix(*rMat
.mpImpl
);
126 bool B3DHomMatrix::operator==(const B3DHomMatrix
& rMat
) const
128 if(mpImpl
.same_object(rMat
.mpImpl
))
131 return mpImpl
->isEqual(*rMat
.mpImpl
);
134 bool B3DHomMatrix::operator!=(const B3DHomMatrix
& rMat
) const
136 return !(*this == rMat
);
139 void B3DHomMatrix::rotate(double fAngleX
,double fAngleY
,double fAngleZ
)
141 if(!fTools::equalZero(fAngleX
) || !fTools::equalZero(fAngleY
) || !fTools::equalZero(fAngleZ
))
143 if(!fTools::equalZero(fAngleX
))
145 Impl3DHomMatrix aRotMatX
;
146 double fSin(sin(fAngleX
));
147 double fCos(cos(fAngleX
));
149 aRotMatX
.set(1, 1, fCos
);
150 aRotMatX
.set(2, 2, fCos
);
151 aRotMatX
.set(2, 1, fSin
);
152 aRotMatX
.set(1, 2, -fSin
);
154 mpImpl
->doMulMatrix(aRotMatX
);
157 if(!fTools::equalZero(fAngleY
))
159 Impl3DHomMatrix aRotMatY
;
160 double fSin(sin(fAngleY
));
161 double fCos(cos(fAngleY
));
163 aRotMatY
.set(0, 0, fCos
);
164 aRotMatY
.set(2, 2, fCos
);
165 aRotMatY
.set(0, 2, fSin
);
166 aRotMatY
.set(2, 0, -fSin
);
168 mpImpl
->doMulMatrix(aRotMatY
);
171 if(!fTools::equalZero(fAngleZ
))
173 Impl3DHomMatrix aRotMatZ
;
174 double fSin(sin(fAngleZ
));
175 double fCos(cos(fAngleZ
));
177 aRotMatZ
.set(0, 0, fCos
);
178 aRotMatZ
.set(1, 1, fCos
);
179 aRotMatZ
.set(1, 0, fSin
);
180 aRotMatZ
.set(0, 1, -fSin
);
182 mpImpl
->doMulMatrix(aRotMatZ
);
187 void B3DHomMatrix::rotate(const B3DTuple
& rRotation
)
189 rotate(rRotation
.getX(), rRotation
.getY(), rRotation
.getZ());
192 void B3DHomMatrix::translate(double fX
, double fY
, double fZ
)
194 if(!fTools::equalZero(fX
) || !fTools::equalZero(fY
) || !fTools::equalZero(fZ
))
196 Impl3DHomMatrix aTransMat
;
198 aTransMat
.set(0, 3, fX
);
199 aTransMat
.set(1, 3, fY
);
200 aTransMat
.set(2, 3, fZ
);
202 mpImpl
->doMulMatrix(aTransMat
);
206 void B3DHomMatrix::translate(const B3DTuple
& rRotation
)
208 translate(rRotation
.getX(), rRotation
.getY(), rRotation
.getZ());
211 void B3DHomMatrix::scale(double fX
, double fY
, double fZ
)
213 const double fOne(1.0);
215 if(!fTools::equal(fOne
, fX
) || !fTools::equal(fOne
, fY
) ||!fTools::equal(fOne
, fZ
))
217 Impl3DHomMatrix aScaleMat
;
219 aScaleMat
.set(0, 0, fX
);
220 aScaleMat
.set(1, 1, fY
);
221 aScaleMat
.set(2, 2, fZ
);
223 mpImpl
->doMulMatrix(aScaleMat
);
227 void B3DHomMatrix::scale(const B3DTuple
& rRotation
)
229 scale(rRotation
.getX(), rRotation
.getY(), rRotation
.getZ());
232 void B3DHomMatrix::shearXY(double fSx
, double fSy
)
234 // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
235 if(!fTools::equalZero(fSx
) || !fTools::equalZero(fSy
))
237 Impl3DHomMatrix aShearXYMat
;
239 aShearXYMat
.set(0, 2, fSx
);
240 aShearXYMat
.set(1, 2, fSy
);
242 mpImpl
->doMulMatrix(aShearXYMat
);
246 void B3DHomMatrix::shearXZ(double fSx
, double fSz
)
248 // #i76239# do not test against 1.0, but against 0.0. We are talking about a value not on the diagonal (!)
249 if(!fTools::equalZero(fSx
) || !fTools::equalZero(fSz
))
251 Impl3DHomMatrix aShearXZMat
;
253 aShearXZMat
.set(0, 1, fSx
);
254 aShearXZMat
.set(2, 1, fSz
);
256 mpImpl
->doMulMatrix(aShearXZMat
);
259 void B3DHomMatrix::frustum(double fLeft
, double fRight
, double fBottom
, double fTop
, double fNear
, double fFar
)
261 const double fZero(0.0);
262 const double fOne(1.0);
264 if(!fTools::more(fNear
, fZero
))
269 if(!fTools::more(fFar
, fZero
))
274 if(fTools::equal(fNear
, fFar
))
279 if(fTools::equal(fLeft
, fRight
))
285 if(fTools::equal(fTop
, fBottom
))
291 Impl3DHomMatrix aFrustumMat
;
293 aFrustumMat
.set(0, 0, 2.0 * fNear
/ (fRight
- fLeft
));
294 aFrustumMat
.set(1, 1, 2.0 * fNear
/ (fTop
- fBottom
));
295 aFrustumMat
.set(0, 2, (fRight
+ fLeft
) / (fRight
- fLeft
));
296 aFrustumMat
.set(1, 2, (fTop
+ fBottom
) / (fTop
- fBottom
));
297 aFrustumMat
.set(2, 2, -fOne
* ((fFar
+ fNear
) / (fFar
- fNear
)));
298 aFrustumMat
.set(3, 2, -fOne
);
299 aFrustumMat
.set(2, 3, -fOne
* ((2.0 * fFar
* fNear
) / (fFar
- fNear
)));
300 aFrustumMat
.set(3, 3, fZero
);
302 mpImpl
->doMulMatrix(aFrustumMat
);
305 void B3DHomMatrix::ortho(double fLeft
, double fRight
, double fBottom
, double fTop
, double fNear
, double fFar
)
307 if(fTools::equal(fNear
, fFar
))
312 if(fTools::equal(fLeft
, fRight
))
318 if(fTools::equal(fTop
, fBottom
))
324 Impl3DHomMatrix aOrthoMat
;
326 aOrthoMat
.set(0, 0, 2.0 / (fRight
- fLeft
));
327 aOrthoMat
.set(1, 1, 2.0 / (fTop
- fBottom
));
328 aOrthoMat
.set(2, 2, -1.0 * (2.0 / (fFar
- fNear
)));
329 aOrthoMat
.set(0, 3, -1.0 * ((fRight
+ fLeft
) / (fRight
- fLeft
)));
330 aOrthoMat
.set(1, 3, -1.0 * ((fTop
+ fBottom
) / (fTop
- fBottom
)));
331 aOrthoMat
.set(2, 3, -1.0 * ((fFar
+ fNear
) / (fFar
- fNear
)));
333 mpImpl
->doMulMatrix(aOrthoMat
);
336 void B3DHomMatrix::orientation(const B3DPoint
& rVRP
, B3DVector aVPN
, B3DVector aVUV
)
338 Impl3DHomMatrix aOrientationMat
;
341 aOrientationMat
.set(0, 3, -rVRP
.getX());
342 aOrientationMat
.set(1, 3, -rVRP
.getY());
343 aOrientationMat
.set(2, 3, -rVRP
.getZ());
349 // build x-axis as perpendicular from aVUV and aVPN
350 B3DVector
aRx(aVUV
.getPerpendicular(aVPN
));
353 // y-axis perpendicular to that
354 B3DVector
aRy(aVPN
.getPerpendicular(aRx
));
357 // the calculated normals are the line vectors of the rotation matrix,
358 // set them to create rotation
359 aOrientationMat
.set(0, 0, aRx
.getX());
360 aOrientationMat
.set(0, 1, aRx
.getY());
361 aOrientationMat
.set(0, 2, aRx
.getZ());
362 aOrientationMat
.set(1, 0, aRy
.getX());
363 aOrientationMat
.set(1, 1, aRy
.getY());
364 aOrientationMat
.set(1, 2, aRy
.getZ());
365 aOrientationMat
.set(2, 0, aVPN
.getX());
366 aOrientationMat
.set(2, 1, aVPN
.getY());
367 aOrientationMat
.set(2, 2, aVPN
.getZ());
369 mpImpl
->doMulMatrix(aOrientationMat
);
372 void B3DHomMatrix::decompose(B3DTuple
& rScale
, B3DTuple
& rTranslate
, B3DTuple
& rRotate
, B3DTuple
& rShear
) const
374 // when perspective is used, decompose is not made here
375 if(!mpImpl
->isLastLineDefault())
378 // If determinant is zero, decomposition is not possible
379 if(determinant() == 0.0)
382 // isolate translation
383 rTranslate
.setX(mpImpl
->get(0, 3));
384 rTranslate
.setY(mpImpl
->get(1, 3));
385 rTranslate
.setZ(mpImpl
->get(2, 3));
387 // correct translate values
388 rTranslate
.correctValues();
390 // get scale and shear
391 B3DVector
aCol0(mpImpl
->get(0, 0), mpImpl
->get(1, 0), mpImpl
->get(2, 0));
392 B3DVector
aCol1(mpImpl
->get(0, 1), mpImpl
->get(1, 1), mpImpl
->get(2, 1));
393 B3DVector
aCol2(mpImpl
->get(0, 2), mpImpl
->get(1, 2), mpImpl
->get(2, 2));
397 rScale
.setX(aCol0
.getLength());
401 rShear
.setX(aCol0
.scalar(aCol1
));
403 if(fTools::equalZero(rShear
.getX()))
409 aTemp
.setX(aCol1
.getX() - rShear
.getX() * aCol0
.getX());
410 aTemp
.setY(aCol1
.getY() - rShear
.getX() * aCol0
.getY());
411 aTemp
.setZ(aCol1
.getZ() - rShear
.getX() * aCol0
.getZ());
416 rScale
.setY(aCol1
.getLength());
419 const double fShearX(rShear
.getX());
421 if(!fTools::equalZero(fShearX
))
423 rShear
.setX(rShear
.getX() / rScale
.getY());
427 rShear
.setY(aCol0
.scalar(aCol2
));
429 if(fTools::equalZero(rShear
.getY()))
435 aTemp
.setX(aCol2
.getX() - rShear
.getY() * aCol0
.getX());
436 aTemp
.setY(aCol2
.getY() - rShear
.getY() * aCol0
.getY());
437 aTemp
.setZ(aCol2
.getZ() - rShear
.getY() * aCol0
.getZ());
442 rShear
.setZ(aCol1
.scalar(aCol2
));
444 if(fTools::equalZero(rShear
.getZ()))
450 aTemp
.setX(aCol2
.getX() - rShear
.getZ() * aCol1
.getX());
451 aTemp
.setY(aCol2
.getY() - rShear
.getZ() * aCol1
.getY());
452 aTemp
.setZ(aCol2
.getZ() - rShear
.getZ() * aCol1
.getZ());
457 rScale
.setZ(aCol2
.getLength());
460 const double fShearY(rShear
.getY());
462 if(!fTools::equalZero(fShearY
))
464 // coverity[copy_paste_error] - this is correct getZ, not getY
465 rShear
.setY(rShear
.getY() / rScale
.getZ());
468 const double fShearZ(rShear
.getZ());
470 if(!fTools::equalZero(fShearZ
))
472 // coverity[original] - this is not an original copy-and-paste source for ^^^
473 rShear
.setZ(rShear
.getZ() / rScale
.getZ());
476 // correct shear values
477 rShear
.correctValues();
479 // Coordinate system flip?
480 if(0.0 > aCol0
.scalar(aCol1
.getPerpendicular(aCol2
)))
488 // correct scale values
489 rScale
.correctValues(1.0);
496 if( ::basegfx::fTools::equal( aCol0
.getZ(), 1.0 )
497 || aCol0
.getZ() > 1.0 )
502 else if( ::basegfx::fTools::equal( aCol0
.getZ(), -1.0 )
503 || aCol0
.getZ() < -1.0 )
510 fy
= asin( -aCol0
.getZ() );
515 if( ::basegfx::fTools::equalZero( cy
) )
517 if( aCol0
.getZ() > 0.0 )
518 rRotate
.setX(atan2(-1.0*aCol1
.getX(), aCol1
.getY()));
520 rRotate
.setX(atan2(aCol1
.getX(), aCol1
.getY()));
525 rRotate
.setX(atan2(aCol1
.getZ(), aCol2
.getZ()));
526 rRotate
.setZ(atan2(aCol0
.getY(), aCol0
.getX()));
529 // correct rotate values
530 rRotate
.correctValues();
533 } // end of namespace basegfx
535 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */