1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_basegfx.hxx" 26 27 #include <rtl/instance.hxx> 28 #include <basegfx/matrix/b3dhommatrix.hxx> 29 #include <hommatrixtemplate.hxx> 30 #include <basegfx/vector/b3dvector.hxx> 31 32 namespace basegfx 33 { 34 class Impl3DHomMatrix : public ::basegfx::internal::ImplHomMatrixTemplate< 4 > 35 { 36 }; 37 38 namespace { struct IdentityMatrix : public rtl::Static< B3DHomMatrix::ImplType, 39 IdentityMatrix > {}; } 40 B3DHomMatrix()41 B3DHomMatrix::B3DHomMatrix() : 42 mpImpl( IdentityMatrix::get() ) // use common identity matrix 43 { 44 } 45 B3DHomMatrix(const B3DHomMatrix & rMat)46 B3DHomMatrix::B3DHomMatrix(const B3DHomMatrix& rMat) : 47 mpImpl(rMat.mpImpl) 48 { 49 } 50 ~B3DHomMatrix()51 B3DHomMatrix::~B3DHomMatrix() 52 { 53 } 54 operator =(const B3DHomMatrix & rMat)55 B3DHomMatrix& B3DHomMatrix::operator=(const B3DHomMatrix& rMat) 56 { 57 mpImpl = rMat.mpImpl; 58 return *this; 59 } 60 makeUnique()61 void B3DHomMatrix::makeUnique() 62 { 63 mpImpl.make_unique(); 64 } 65 get(sal_uInt16 nRow,sal_uInt16 nColumn) const66 double B3DHomMatrix::get(sal_uInt16 nRow, sal_uInt16 nColumn) const 67 { 68 return mpImpl->get(nRow, nColumn); 69 } 70 set(sal_uInt16 nRow,sal_uInt16 nColumn,double fValue)71 void B3DHomMatrix::set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue) 72 { 73 mpImpl->set(nRow, nColumn, fValue); 74 } 75 isLastLineDefault() const76 bool B3DHomMatrix::isLastLineDefault() const 77 { 78 return mpImpl->isLastLineDefault(); 79 } 80 isIdentity() const81 bool B3DHomMatrix::isIdentity() const 82 { 83 if(mpImpl.same_object(IdentityMatrix::get())) 84 return true; 85 86 return mpImpl->isIdentity(); 87 } 88 identity()89 void B3DHomMatrix::identity() 90 { 91 mpImpl = IdentityMatrix::get(); 92 } 93 isInvertible() const94 bool B3DHomMatrix::isInvertible() const 95 { 96 return mpImpl->isInvertible(); 97 } 98 invert()99 bool B3DHomMatrix::invert() 100 { 101 Impl3DHomMatrix aWork(*mpImpl); 102 sal_uInt16* pIndex = new sal_uInt16[mpImpl->getEdgeLength()]; 103 sal_Int16 nParity; 104 105 if(aWork.ludcmp(pIndex, nParity)) 106 { 107 mpImpl->doInvert(aWork, pIndex); 108 delete[] pIndex; 109 110 return true; 111 } 112 113 delete[] pIndex; 114 return false; 115 } 116 isNormalized() const117 bool B3DHomMatrix::isNormalized() const 118 { 119 return mpImpl->isNormalized(); 120 } 121 normalize()122 void B3DHomMatrix::normalize() 123 { 124 if(!const_cast<const B3DHomMatrix*>(this)->mpImpl->isNormalized()) 125 mpImpl->doNormalize(); 126 } 127 determinant() const128 double B3DHomMatrix::determinant() const 129 { 130 return mpImpl->doDeterminant(); 131 } 132 trace() const133 double B3DHomMatrix::trace() const 134 { 135 return mpImpl->doTrace(); 136 } 137 transpose()138 void B3DHomMatrix::transpose() 139 { 140 mpImpl->doTranspose(); 141 } 142 operator +=(const B3DHomMatrix & rMat)143 B3DHomMatrix& B3DHomMatrix::operator+=(const B3DHomMatrix& rMat) 144 { 145 mpImpl->doAddMatrix(*rMat.mpImpl); 146 return *this; 147 } 148 operator -=(const B3DHomMatrix & rMat)149 B3DHomMatrix& B3DHomMatrix::operator-=(const B3DHomMatrix& rMat) 150 { 151 mpImpl->doSubMatrix(*rMat.mpImpl); 152 return *this; 153 } 154 operator *=(double fValue)155 B3DHomMatrix& B3DHomMatrix::operator*=(double fValue) 156 { 157 const double fOne(1.0); 158 159 if(!fTools::equal(fOne, fValue)) 160 mpImpl->doMulMatrix(fValue); 161 162 return *this; 163 } 164 operator /=(double fValue)165 B3DHomMatrix& B3DHomMatrix::operator/=(double fValue) 166 { 167 const double fOne(1.0); 168 169 if(!fTools::equal(fOne, fValue)) 170 mpImpl->doMulMatrix(1.0 / fValue); 171 172 return *this; 173 } 174 operator *=(const B3DHomMatrix & rMat)175 B3DHomMatrix& B3DHomMatrix::operator*=(const B3DHomMatrix& rMat) 176 { 177 if(!rMat.isIdentity()) 178 mpImpl->doMulMatrix(*rMat.mpImpl); 179 180 return *this; 181 } 182 operator ==(const B3DHomMatrix & rMat) const183 bool B3DHomMatrix::operator==(const B3DHomMatrix& rMat) const 184 { 185 if(mpImpl.same_object(rMat.mpImpl)) 186 return true; 187 188 return mpImpl->isEqual(*rMat.mpImpl); 189 } 190 operator !=(const B3DHomMatrix & rMat) const191 bool B3DHomMatrix::operator!=(const B3DHomMatrix& rMat) const 192 { 193 return !(*this == rMat); 194 } 195 rotate(double fAngleX,double fAngleY,double fAngleZ)196 void B3DHomMatrix::rotate(double fAngleX,double fAngleY,double fAngleZ) 197 { 198 if(!fTools::equalZero(fAngleX) || !fTools::equalZero(fAngleY) || !fTools::equalZero(fAngleZ)) 199 { 200 if(!fTools::equalZero(fAngleX)) 201 { 202 Impl3DHomMatrix aRotMatX; 203 double fSin(sin(fAngleX)); 204 double fCos(cos(fAngleX)); 205 206 aRotMatX.set(1, 1, fCos); 207 aRotMatX.set(2, 2, fCos); 208 aRotMatX.set(2, 1, fSin); 209 aRotMatX.set(1, 2, -fSin); 210 211 mpImpl->doMulMatrix(aRotMatX); 212 } 213 214 if(!fTools::equalZero(fAngleY)) 215 { 216 Impl3DHomMatrix aRotMatY; 217 double fSin(sin(fAngleY)); 218 double fCos(cos(fAngleY)); 219 220 aRotMatY.set(0, 0, fCos); 221 aRotMatY.set(2, 2, fCos); 222 aRotMatY.set(0, 2, fSin); 223 aRotMatY.set(2, 0, -fSin); 224 225 mpImpl->doMulMatrix(aRotMatY); 226 } 227 228 if(!fTools::equalZero(fAngleZ)) 229 { 230 Impl3DHomMatrix aRotMatZ; 231 double fSin(sin(fAngleZ)); 232 double fCos(cos(fAngleZ)); 233 234 aRotMatZ.set(0, 0, fCos); 235 aRotMatZ.set(1, 1, fCos); 236 aRotMatZ.set(1, 0, fSin); 237 aRotMatZ.set(0, 1, -fSin); 238 239 mpImpl->doMulMatrix(aRotMatZ); 240 } 241 } 242 } 243 translate(double fX,double fY,double fZ)244 void B3DHomMatrix::translate(double fX, double fY, double fZ) 245 { 246 if(!fTools::equalZero(fX) || !fTools::equalZero(fY) || !fTools::equalZero(fZ)) 247 { 248 Impl3DHomMatrix aTransMat; 249 250 aTransMat.set(0, 3, fX); 251 aTransMat.set(1, 3, fY); 252 aTransMat.set(2, 3, fZ); 253 254 mpImpl->doMulMatrix(aTransMat); 255 } 256 } 257 scale(double fX,double fY,double fZ)258 void B3DHomMatrix::scale(double fX, double fY, double fZ) 259 { 260 const double fOne(1.0); 261 262 if(!fTools::equal(fOne, fX) || !fTools::equal(fOne, fY) ||!fTools::equal(fOne, fZ)) 263 { 264 Impl3DHomMatrix aScaleMat; 265 266 aScaleMat.set(0, 0, fX); 267 aScaleMat.set(1, 1, fY); 268 aScaleMat.set(2, 2, fZ); 269 270 mpImpl->doMulMatrix(aScaleMat); 271 } 272 } 273 shearXY(double fSx,double fSy)274 void B3DHomMatrix::shearXY(double fSx, double fSy) 275 { 276 // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!) 277 if(!fTools::equalZero(fSx) || !fTools::equalZero(fSy)) 278 { 279 Impl3DHomMatrix aShearXYMat; 280 281 aShearXYMat.set(0, 2, fSx); 282 aShearXYMat.set(1, 2, fSy); 283 284 mpImpl->doMulMatrix(aShearXYMat); 285 } 286 } 287 shearYZ(double fSy,double fSz)288 void B3DHomMatrix::shearYZ(double fSy, double fSz) 289 { 290 // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!) 291 if(!fTools::equalZero(fSy) || !fTools::equalZero(fSz)) 292 { 293 Impl3DHomMatrix aShearYZMat; 294 295 aShearYZMat.set(1, 0, fSy); 296 aShearYZMat.set(2, 0, fSz); 297 298 mpImpl->doMulMatrix(aShearYZMat); 299 } 300 } 301 shearXZ(double fSx,double fSz)302 void B3DHomMatrix::shearXZ(double fSx, double fSz) 303 { 304 // #i76239# do not test againt 1.0, but against 0.0. We are talking about a value not on the diagonal (!) 305 if(!fTools::equalZero(fSx) || !fTools::equalZero(fSz)) 306 { 307 Impl3DHomMatrix aShearXZMat; 308 309 aShearXZMat.set(0, 1, fSx); 310 aShearXZMat.set(2, 1, fSz); 311 312 mpImpl->doMulMatrix(aShearXZMat); 313 } 314 } 315 frustum(double fLeft,double fRight,double fBottom,double fTop,double fNear,double fFar)316 void B3DHomMatrix::frustum(double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar) 317 { 318 const double fZero(0.0); 319 const double fOne(1.0); 320 321 if(!fTools::more(fNear, fZero)) 322 { 323 fNear = 0.001; 324 } 325 326 if(!fTools::more(fFar, fZero)) 327 { 328 fFar = fOne; 329 } 330 331 if(fTools::equal(fNear, fFar)) 332 { 333 fFar = fNear + fOne; 334 } 335 336 if(fTools::equal(fLeft, fRight)) 337 { 338 fLeft -= fOne; 339 fRight += fOne; 340 } 341 342 if(fTools::equal(fTop, fBottom)) 343 { 344 fBottom -= fOne; 345 fTop += fOne; 346 } 347 348 Impl3DHomMatrix aFrustumMat; 349 350 aFrustumMat.set(0, 0, 2.0 * fNear / (fRight - fLeft)); 351 aFrustumMat.set(1, 1, 2.0 * fNear / (fTop - fBottom)); 352 aFrustumMat.set(0, 2, (fRight + fLeft) / (fRight - fLeft)); 353 aFrustumMat.set(1, 2, (fTop + fBottom) / (fTop - fBottom)); 354 aFrustumMat.set(2, 2, -fOne * ((fFar + fNear) / (fFar - fNear))); 355 aFrustumMat.set(3, 2, -fOne); 356 aFrustumMat.set(2, 3, -fOne * ((2.0 * fFar * fNear) / (fFar - fNear))); 357 aFrustumMat.set(3, 3, fZero); 358 359 mpImpl->doMulMatrix(aFrustumMat); 360 } 361 ortho(double fLeft,double fRight,double fBottom,double fTop,double fNear,double fFar)362 void B3DHomMatrix::ortho(double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar) 363 { 364 if(fTools::equal(fNear, fFar)) 365 { 366 fFar = fNear + 1.0; 367 } 368 369 if(fTools::equal(fLeft, fRight)) 370 { 371 fLeft -= 1.0; 372 fRight += 1.0; 373 } 374 375 if(fTools::equal(fTop, fBottom)) 376 { 377 fBottom -= 1.0; 378 fTop += 1.0; 379 } 380 381 Impl3DHomMatrix aOrthoMat; 382 383 aOrthoMat.set(0, 0, 2.0 / (fRight - fLeft)); 384 aOrthoMat.set(1, 1, 2.0 / (fTop - fBottom)); 385 aOrthoMat.set(2, 2, -1.0 * (2.0 / (fFar - fNear))); 386 aOrthoMat.set(0, 3, -1.0 * ((fRight + fLeft) / (fRight - fLeft))); 387 aOrthoMat.set(1, 3, -1.0 * ((fTop + fBottom) / (fTop - fBottom))); 388 aOrthoMat.set(2, 3, -1.0 * ((fFar + fNear) / (fFar - fNear))); 389 390 mpImpl->doMulMatrix(aOrthoMat); 391 } 392 orientation(B3DPoint aVRP,B3DVector aVPN,B3DVector aVUV)393 void B3DHomMatrix::orientation(B3DPoint aVRP, B3DVector aVPN, B3DVector aVUV) 394 { 395 Impl3DHomMatrix aOrientationMat; 396 397 // translate -VRP 398 aOrientationMat.set(0, 3, -aVRP.getX()); 399 aOrientationMat.set(1, 3, -aVRP.getY()); 400 aOrientationMat.set(2, 3, -aVRP.getZ()); 401 402 // build rotation 403 aVUV.normalize(); 404 aVPN.normalize(); 405 406 // build x-axis as peroendicular fron aVUV and aVPN 407 B3DVector aRx(aVUV.getPerpendicular(aVPN)); 408 aRx.normalize(); 409 410 // y-axis perpendicular to that 411 B3DVector aRy(aVPN.getPerpendicular(aRx)); 412 aRy.normalize(); 413 414 // the calculated normals are the line vectors of the rotation matrix, 415 // set them to create rotation 416 aOrientationMat.set(0, 0, aRx.getX()); 417 aOrientationMat.set(0, 1, aRx.getY()); 418 aOrientationMat.set(0, 2, aRx.getZ()); 419 aOrientationMat.set(1, 0, aRy.getX()); 420 aOrientationMat.set(1, 1, aRy.getY()); 421 aOrientationMat.set(1, 2, aRy.getZ()); 422 aOrientationMat.set(2, 0, aVPN.getX()); 423 aOrientationMat.set(2, 1, aVPN.getY()); 424 aOrientationMat.set(2, 2, aVPN.getZ()); 425 426 mpImpl->doMulMatrix(aOrientationMat); 427 } 428 decompose(B3DTuple & rScale,B3DTuple & rTranslate,B3DTuple & rRotate,B3DTuple & rShear) const429 bool B3DHomMatrix::decompose(B3DTuple& rScale, B3DTuple& rTranslate, B3DTuple& rRotate, B3DTuple& rShear) const 430 { 431 // when perspective is used, decompose is not made here 432 if(!mpImpl->isLastLineDefault()) 433 return false; 434 435 // If determinant is zero, decomposition is not possible 436 if(0.0 == determinant()) 437 return false; 438 439 // isolate translation 440 rTranslate.setX(mpImpl->get(0, 3)); 441 rTranslate.setY(mpImpl->get(1, 3)); 442 rTranslate.setZ(mpImpl->get(2, 3)); 443 444 // correct translate values 445 rTranslate.correctValues(); 446 447 // get scale and shear 448 B3DVector aCol0(mpImpl->get(0, 0), mpImpl->get(1, 0), mpImpl->get(2, 0)); 449 B3DVector aCol1(mpImpl->get(0, 1), mpImpl->get(1, 1), mpImpl->get(2, 1)); 450 B3DVector aCol2(mpImpl->get(0, 2), mpImpl->get(1, 2), mpImpl->get(2, 2)); 451 B3DVector aTemp; 452 453 // get ScaleX 454 rScale.setX(aCol0.getLength()); 455 aCol0.normalize(); 456 457 // get ShearXY 458 rShear.setX(aCol0.scalar(aCol1)); 459 460 if(fTools::equalZero(rShear.getX())) 461 { 462 rShear.setX(0.0); 463 } 464 else 465 { 466 aTemp.setX(aCol1.getX() - rShear.getX() * aCol0.getX()); 467 aTemp.setY(aCol1.getY() - rShear.getX() * aCol0.getY()); 468 aTemp.setZ(aCol1.getZ() - rShear.getX() * aCol0.getZ()); 469 aCol1 = aTemp; 470 } 471 472 // get ScaleY 473 rScale.setY(aCol1.getLength()); 474 aCol1.normalize(); 475 476 const double fShearX(rShear.getX()); 477 478 if(!fTools::equalZero(fShearX)) 479 { 480 rShear.setX(rShear.getX() / rScale.getY()); 481 } 482 483 // get ShearXZ 484 rShear.setY(aCol0.scalar(aCol2)); 485 486 if(fTools::equalZero(rShear.getY())) 487 { 488 rShear.setY(0.0); 489 } 490 else 491 { 492 aTemp.setX(aCol2.getX() - rShear.getY() * aCol0.getX()); 493 aTemp.setY(aCol2.getY() - rShear.getY() * aCol0.getY()); 494 aTemp.setZ(aCol2.getZ() - rShear.getY() * aCol0.getZ()); 495 aCol2 = aTemp; 496 } 497 498 // get ShearYZ 499 rShear.setZ(aCol1.scalar(aCol2)); 500 501 if(fTools::equalZero(rShear.getZ())) 502 { 503 rShear.setZ(0.0); 504 } 505 else 506 { 507 aTemp.setX(aCol2.getX() - rShear.getZ() * aCol1.getX()); 508 aTemp.setY(aCol2.getY() - rShear.getZ() * aCol1.getY()); 509 aTemp.setZ(aCol2.getZ() - rShear.getZ() * aCol1.getZ()); 510 aCol2 = aTemp; 511 } 512 513 // get ScaleZ 514 rScale.setZ(aCol2.getLength()); 515 aCol2.normalize(); 516 517 const double fShearY(rShear.getY()); 518 519 if(!fTools::equalZero(fShearY)) 520 { 521 rShear.setY(rShear.getY() / rScale.getZ()); 522 } 523 524 const double fShearZ(rShear.getZ()); 525 526 if(!fTools::equalZero(fShearZ)) 527 { 528 rShear.setZ(rShear.getZ() / rScale.getZ()); 529 } 530 531 // correct shear values 532 rShear.correctValues(); 533 534 // Coordinate system flip? 535 if(0.0 > aCol0.scalar(aCol1.getPerpendicular(aCol2))) 536 { 537 rScale = -rScale; 538 aCol0 = -aCol0; 539 aCol1 = -aCol1; 540 aCol2 = -aCol2; 541 } 542 543 // correct scale values 544 rScale.correctValues(1.0); 545 546 // Get rotations 547 { 548 double fy=0; 549 double cy=0; 550 551 if( ::basegfx::fTools::equal( aCol0.getZ(), 1.0 ) 552 || aCol0.getZ() > 1.0 ) 553 { 554 fy = -F_PI/2.0; 555 cy = 0.0; 556 } 557 else if( ::basegfx::fTools::equal( aCol0.getZ(), -1.0 ) 558 || aCol0.getZ() < -1.0 ) 559 { 560 fy = F_PI/2.0; 561 cy = 0.0; 562 } 563 else 564 { 565 fy = asin( -aCol0.getZ() ); 566 cy = cos(fy); 567 } 568 569 rRotate.setY(fy); 570 if( ::basegfx::fTools::equalZero( cy ) ) 571 { 572 if( aCol0.getZ() > 0.0 ) 573 rRotate.setX(atan2(-1.0*aCol1.getX(), aCol1.getY())); 574 else 575 rRotate.setX(atan2(aCol1.getX(), aCol1.getY())); 576 rRotate.setZ(0.0); 577 } 578 else 579 { 580 rRotate.setX(atan2(aCol1.getZ(), aCol2.getZ())); 581 rRotate.setZ(atan2(aCol0.getY(), aCol0.getX())); 582 } 583 584 // corrcet rotate values 585 rRotate.correctValues(); 586 } 587 588 return true; 589 } 590 } // end of namespace basegfx 591 592 // eof 593