00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "precompiled_basegfx.hxx"
00030 #include <osl/diagnose.h>
00031 #include <rtl/instance.hxx>
00032 #include <basegfx/matrix/b2dhommatrix.hxx>
00033 #include <hommatrixtemplate.hxx>
00034 #include <basegfx/tuple/b2dtuple.hxx>
00035 #include <basegfx/vector/b2dvector.hxx>
00036
00037 namespace basegfx
00038 {
00039 class Impl2DHomMatrix : public ::basegfx::internal::ImplHomMatrixTemplate< 3 >
00040 {
00041 };
00042
00043 namespace { struct IdentityMatrix : public rtl::Static< B2DHomMatrix::ImplType,
00044 IdentityMatrix > {}; }
00045
00046 B2DHomMatrix::B2DHomMatrix() :
00047 mpImpl( IdentityMatrix::get() )
00048 {
00049 }
00050
00051 B2DHomMatrix::B2DHomMatrix(const B2DHomMatrix& rMat) :
00052 mpImpl(rMat.mpImpl)
00053 {
00054 }
00055
00056 B2DHomMatrix::~B2DHomMatrix()
00057 {
00058 }
00059
00060 B2DHomMatrix& B2DHomMatrix::operator=(const B2DHomMatrix& rMat)
00061 {
00062 mpImpl = rMat.mpImpl;
00063 return *this;
00064 }
00065
00066 void B2DHomMatrix::makeUnique()
00067 {
00068 mpImpl.make_unique();
00069 }
00070
00071 double B2DHomMatrix::get(sal_uInt16 nRow, sal_uInt16 nColumn) const
00072 {
00073 return mpImpl->get(nRow, nColumn);
00074 }
00075
00076 void B2DHomMatrix::set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
00077 {
00078 mpImpl->set(nRow, nColumn, fValue);
00079 }
00080
00081 bool B2DHomMatrix::isLastLineDefault() const
00082 {
00083 return mpImpl->isLastLineDefault();
00084 }
00085
00086 bool B2DHomMatrix::isIdentity() const
00087 {
00088 if(mpImpl.same_object(IdentityMatrix::get()))
00089 return true;
00090
00091 return mpImpl->isIdentity();
00092 }
00093
00094 void B2DHomMatrix::identity()
00095 {
00096 mpImpl = IdentityMatrix::get();
00097 }
00098
00099 bool B2DHomMatrix::isInvertible() const
00100 {
00101 return mpImpl->isInvertible();
00102 }
00103
00104 bool B2DHomMatrix::invert()
00105 {
00106 Impl2DHomMatrix aWork(*mpImpl);
00107 sal_uInt16* pIndex = new sal_uInt16[mpImpl->getEdgeLength()];
00108 sal_Int16 nParity;
00109
00110 if(aWork.ludcmp(pIndex, nParity))
00111 {
00112 mpImpl->doInvert(aWork, pIndex);
00113 delete[] pIndex;
00114
00115 return true;
00116 }
00117
00118 delete[] pIndex;
00119 return false;
00120 }
00121
00122 bool B2DHomMatrix::isNormalized() const
00123 {
00124 return mpImpl->isNormalized();
00125 }
00126
00127 void B2DHomMatrix::normalize()
00128 {
00129 if(!const_cast<const B2DHomMatrix*>(this)->mpImpl->isNormalized())
00130 mpImpl->doNormalize();
00131 }
00132
00133 double B2DHomMatrix::determinant() const
00134 {
00135 return mpImpl->doDeterminant();
00136 }
00137
00138 double B2DHomMatrix::trace() const
00139 {
00140 return mpImpl->doTrace();
00141 }
00142
00143 void B2DHomMatrix::transpose()
00144 {
00145 mpImpl->doTranspose();
00146 }
00147
00148 B2DHomMatrix& B2DHomMatrix::operator+=(const B2DHomMatrix& rMat)
00149 {
00150 mpImpl->doAddMatrix(*rMat.mpImpl);
00151 return *this;
00152 }
00153
00154 B2DHomMatrix& B2DHomMatrix::operator-=(const B2DHomMatrix& rMat)
00155 {
00156 mpImpl->doSubMatrix(*rMat.mpImpl);
00157 return *this;
00158 }
00159
00160 B2DHomMatrix& B2DHomMatrix::operator*=(double fValue)
00161 {
00162 const double fOne(1.0);
00163
00164 if(!fTools::equal(fOne, fValue))
00165 mpImpl->doMulMatrix(fValue);
00166
00167 return *this;
00168 }
00169
00170 B2DHomMatrix& B2DHomMatrix::operator/=(double fValue)
00171 {
00172 const double fOne(1.0);
00173
00174 if(!fTools::equal(fOne, fValue))
00175 mpImpl->doMulMatrix(1.0 / fValue);
00176
00177 return *this;
00178 }
00179
00180 B2DHomMatrix& B2DHomMatrix::operator*=(const B2DHomMatrix& rMat)
00181 {
00182 if(!rMat.isIdentity())
00183 mpImpl->doMulMatrix(*rMat.mpImpl);
00184
00185 return *this;
00186 }
00187
00188 bool B2DHomMatrix::operator==(const B2DHomMatrix& rMat) const
00189 {
00190 if(mpImpl.same_object(rMat.mpImpl))
00191 return true;
00192
00193 return mpImpl->isEqual(*rMat.mpImpl);
00194 }
00195
00196 bool B2DHomMatrix::operator!=(const B2DHomMatrix& rMat) const
00197 {
00198 return !(*this == rMat);
00199 }
00200
00201 void B2DHomMatrix::rotate(double fRadiant)
00202 {
00203 if(!fTools::equalZero(fRadiant))
00204 {
00205 double fSin(0.0);
00206 double fCos(0.0);
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216 if( fTools::equalZero( fmod( fRadiant, F_PI2 ) ) )
00217 {
00218
00219 const sal_Int32 nQuad(
00220 (4 + fround( 4/F_2PI*fmod( fRadiant, F_2PI ) )) % 4 );
00221 switch( nQuad )
00222 {
00223 case 0:
00224 fSin = 0.0;
00225 fCos = 1.0;
00226 break;
00227
00228 case 1:
00229 fSin = 1.0;
00230 fCos = 0.0;
00231 break;
00232
00233 case 2:
00234 fSin = 0.0;
00235 fCos = -1.0;
00236 break;
00237
00238 case 3:
00239 fSin = -1.0;
00240 fCos = 0.0;
00241 break;
00242
00243 default:
00244 OSL_ENSURE( false,
00245 "B2DHomMatrix::rotate(): Impossible case reached" );
00246 }
00247 }
00248 else
00249 {
00250
00251
00252 fSin = sin(fRadiant);
00253 fCos = cos(fRadiant);
00254 }
00255
00256 Impl2DHomMatrix aRotMat;
00257
00258 aRotMat.set(0, 0, fCos);
00259 aRotMat.set(1, 1, fCos);
00260 aRotMat.set(1, 0, fSin);
00261 aRotMat.set(0, 1, -fSin);
00262
00263 mpImpl->doMulMatrix(aRotMat);
00264 }
00265 }
00266
00267 void B2DHomMatrix::translate(double fX, double fY)
00268 {
00269 if(!fTools::equalZero(fX) || !fTools::equalZero(fY))
00270 {
00271 Impl2DHomMatrix aTransMat;
00272
00273 aTransMat.set(0, 2, fX);
00274 aTransMat.set(1, 2, fY);
00275
00276 mpImpl->doMulMatrix(aTransMat);
00277 }
00278 }
00279
00280 void B2DHomMatrix::scale(double fX, double fY)
00281 {
00282 const double fOne(1.0);
00283
00284 if(!fTools::equal(fOne, fX) || !fTools::equal(fOne, fY))
00285 {
00286 Impl2DHomMatrix aScaleMat;
00287
00288 aScaleMat.set(0, 0, fX);
00289 aScaleMat.set(1, 1, fY);
00290
00291 mpImpl->doMulMatrix(aScaleMat);
00292 }
00293 }
00294
00295 void B2DHomMatrix::shearX(double fSx)
00296 {
00297
00298 if(!fTools::equalZero(fSx))
00299 {
00300 Impl2DHomMatrix aShearXMat;
00301
00302 aShearXMat.set(0, 1, fSx);
00303
00304 mpImpl->doMulMatrix(aShearXMat);
00305 }
00306 }
00307
00308 void B2DHomMatrix::shearY(double fSy)
00309 {
00310
00311 if(!fTools::equalZero(fSy))
00312 {
00313 Impl2DHomMatrix aShearYMat;
00314
00315 aShearYMat.set(1, 0, fSy);
00316
00317 mpImpl->doMulMatrix(aShearYMat);
00318 }
00319 }
00320
00328 bool B2DHomMatrix::decompose(B2DTuple& rScale, B2DTuple& rTranslate, double& rRotate, double& rShearX) const
00329 {
00330
00331 if(!mpImpl->isLastLineDefault())
00332 {
00333 return false;
00334 }
00335
00336
00337 rRotate = rShearX = 0.0;
00338 rTranslate.setX(get(0, 2));
00339 rTranslate.setY(get(1, 2));
00340
00341
00342 if(fTools::equalZero(get(0, 1)) && fTools::equalZero(get(1, 0)))
00343 {
00344
00345 rScale.setX(get(0, 0));
00346 rScale.setY(get(1, 1));
00347 }
00348 else
00349 {
00350
00351 B2DVector aUnitVecX(get(0, 0), get(1, 0));
00352 B2DVector aUnitVecY(get(0, 1), get(1, 1));
00353 const double fScalarXY(aUnitVecX.scalar(aUnitVecY));
00354
00355
00356
00357
00358 if(fTools::equalZero(fScalarXY))
00359 {
00360
00361 rScale.setX(aUnitVecX.getLength());
00362 rScale.setY(aUnitVecY.getLength());
00363
00364
00365 const bool bXIsZero(fTools::equalZero(rScale.getX()));
00366 const bool bYIsZero(fTools::equalZero(rScale.getY()));
00367
00368 if(bXIsZero || bYIsZero)
00369 {
00370
00371 if(!bXIsZero)
00372 {
00373
00374 rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX());
00375 }
00376 else if(!bYIsZero)
00377 {
00378
00379
00380 rRotate = atan2(aUnitVecY.getY(), aUnitVecY.getX()) - M_PI_2;
00381 }
00382
00383
00384
00385 return false;
00386 }
00387 else
00388 {
00389
00390
00391 rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX());
00392
00393
00394 const double fCrossXY(aUnitVecX.cross(aUnitVecY));
00395
00396 if(fCrossXY < 0.0)
00397 {
00398 rScale.setY(-rScale.getY());
00399 }
00400 }
00401 }
00402 else
00403 {
00404
00405
00406 double fCrossXY(aUnitVecX.cross(aUnitVecY));
00407
00408
00409
00410
00411 rRotate = atan2(aUnitVecX.getY(), aUnitVecX.getX());
00412
00413
00414
00415 rScale.setX(aUnitVecX.getLength());
00416
00417 if(fTools::equalZero(fCrossXY))
00418 {
00419
00420 rScale.setY(aUnitVecY.getLength());
00421
00422
00423
00424
00425
00426
00427
00428 return false;
00429 }
00430 else
00431 {
00432
00433 rShearX = fScalarXY / fCrossXY;
00434
00435 if(!fTools::equalZero(rRotate))
00436 {
00437
00438
00439 aUnitVecX.setX(rScale.getX());
00440 aUnitVecX.setY(0.0);
00441
00442
00443 const double fNegRotate(-rRotate);
00444 const double fSin(sin(fNegRotate));
00445 const double fCos(cos(fNegRotate));
00446
00447 const double fNewX(aUnitVecY.getX() * fCos - aUnitVecY.getY() * fSin);
00448 const double fNewY(aUnitVecY.getX() * fSin + aUnitVecY.getY() * fCos);
00449
00450 aUnitVecY.setX(fNewX);
00451 aUnitVecY.setY(fNewY);
00452 }
00453
00454
00455
00456 aUnitVecY.setX(aUnitVecY.getX() - (aUnitVecY.getY() * rShearX));
00457 fCrossXY = aUnitVecX.cross(aUnitVecY);
00458
00459
00460
00461 rScale.setY(aUnitVecY.getLength());
00462
00463
00464 if(fCrossXY < 0.0)
00465 {
00466 rScale.setY(-rScale.getY());
00467 }
00468 }
00469 }
00470 }
00471
00472 return true;
00473 }
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572 }
00573
00574