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