Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / basegfx / source / matrix / b3dhommatrix.cxx
blob2e5e798fb001626e60bbe10e801b0427851dc27a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
23 #include <memory>
25 namespace basegfx
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()] );
73 sal_Int16 nParity;
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);
89 return *this;
92 B3DHomMatrix& B3DHomMatrix::operator-=(const B3DHomMatrix& rMat)
94 mpImpl->doSubMatrix(*rMat.mpImpl);
95 return *this;
98 B3DHomMatrix& B3DHomMatrix::operator*=(double fValue)
100 const double fOne(1.0);
102 if(!fTools::equal(fOne, fValue))
103 mpImpl->doMulMatrix(fValue);
105 return *this;
108 B3DHomMatrix& B3DHomMatrix::operator/=(double fValue)
110 const double fOne(1.0);
112 if(!fTools::equal(fOne, fValue))
113 mpImpl->doMulMatrix(1.0 / fValue);
115 return *this;
118 B3DHomMatrix& B3DHomMatrix::operator*=(const B3DHomMatrix& rMat)
120 if(!rMat.isIdentity())
121 mpImpl->doMulMatrix(*rMat.mpImpl);
123 return *this;
126 bool B3DHomMatrix::operator==(const B3DHomMatrix& rMat) const
128 if(mpImpl.same_object(rMat.mpImpl))
129 return true;
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))
266 fNear = 0.001;
269 if(!fTools::more(fFar, fZero))
271 fFar = fOne;
274 if(fTools::equal(fNear, fFar))
276 fFar = fNear + fOne;
279 if(fTools::equal(fLeft, fRight))
281 fLeft -= fOne;
282 fRight += fOne;
285 if(fTools::equal(fTop, fBottom))
287 fBottom -= fOne;
288 fTop += fOne;
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))
309 fFar = fNear + 1.0;
312 if(fTools::equal(fLeft, fRight))
314 fLeft -= 1.0;
315 fRight += 1.0;
318 if(fTools::equal(fTop, fBottom))
320 fBottom -= 1.0;
321 fTop += 1.0;
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;
340 // translate -VRP
341 aOrientationMat.set(0, 3, -rVRP.getX());
342 aOrientationMat.set(1, 3, -rVRP.getY());
343 aOrientationMat.set(2, 3, -rVRP.getZ());
345 // build rotation
346 aVUV.normalize();
347 aVPN.normalize();
349 // build x-axis as perpendicular from aVUV and aVPN
350 B3DVector aRx(aVUV.getPerpendicular(aVPN));
351 aRx.normalize();
353 // y-axis perpendicular to that
354 B3DVector aRy(aVPN.getPerpendicular(aRx));
355 aRy.normalize();
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())
376 return;
378 // If determinant is zero, decomposition is not possible
379 if(determinant() == 0.0)
380 return;
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));
394 B3DVector aTemp;
396 // get ScaleX
397 rScale.setX(aCol0.getLength());
398 aCol0.normalize();
400 // get ShearXY
401 rShear.setX(aCol0.scalar(aCol1));
403 if(fTools::equalZero(rShear.getX()))
405 rShear.setX(0.0);
407 else
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());
412 aCol1 = aTemp;
415 // get ScaleY
416 rScale.setY(aCol1.getLength());
417 aCol1.normalize();
419 const double fShearX(rShear.getX());
421 if(!fTools::equalZero(fShearX))
423 rShear.setX(rShear.getX() / rScale.getY());
426 // get ShearXZ
427 rShear.setY(aCol0.scalar(aCol2));
429 if(fTools::equalZero(rShear.getY()))
431 rShear.setY(0.0);
433 else
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());
438 aCol2 = aTemp;
441 // get ShearYZ
442 rShear.setZ(aCol1.scalar(aCol2));
444 if(fTools::equalZero(rShear.getZ()))
446 rShear.setZ(0.0);
448 else
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());
453 aCol2 = aTemp;
456 // get ScaleZ
457 rScale.setZ(aCol2.getLength());
458 aCol2.normalize();
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)))
482 rScale = -rScale;
483 aCol0 = -aCol0;
484 aCol1 = -aCol1;
485 aCol2 = -aCol2;
488 // correct scale values
489 rScale.correctValues(1.0);
491 // Get rotations
493 double fy=0;
494 double cy=0;
496 if( ::basegfx::fTools::equal( aCol0.getZ(), 1.0 )
497 || aCol0.getZ() > 1.0 )
499 fy = -F_PI/2.0;
500 cy = 0.0;
502 else if( ::basegfx::fTools::equal( aCol0.getZ(), -1.0 )
503 || aCol0.getZ() < -1.0 )
505 fy = F_PI/2.0;
506 cy = 0.0;
508 else
510 fy = asin( -aCol0.getZ() );
511 cy = cos(fy);
514 rRotate.setY(fy);
515 if( ::basegfx::fTools::equalZero( cy ) )
517 if( aCol0.getZ() > 0.0 )
518 rRotate.setX(atan2(-1.0*aCol1.getX(), aCol1.getY()));
519 else
520 rRotate.setX(atan2(aCol1.getX(), aCol1.getY()));
521 rRotate.setZ(0.0);
523 else
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: */