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