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 #ifndef _HOMMATRIX_TEMPLATE_HXX 25 #define _HOMMATRIX_TEMPLATE_HXX 26 27 #include <sal/types.h> 28 #include <basegfx/numeric/ftools.hxx> 29 #include <math.h> 30 #include <string.h> 31 32 namespace basegfx 33 { 34 namespace internal 35 { 36 implGetDefaultValue(sal_uInt16 nRow,sal_uInt16 nColumn)37 inline double implGetDefaultValue(sal_uInt16 nRow, sal_uInt16 nColumn) 38 { 39 if(nRow == nColumn) 40 return 1.0; 41 return 0.0; 42 } 43 44 template < unsigned int _RowSize > class ImplMatLine 45 { 46 enum { RowSize = _RowSize }; 47 48 double mfValue[RowSize]; 49 50 public: ImplMatLine()51 ImplMatLine() 52 { 53 } 54 ImplMatLine(sal_uInt16 nRow,ImplMatLine<RowSize> * pToBeCopied=0L)55 ImplMatLine(sal_uInt16 nRow, ImplMatLine< RowSize >* pToBeCopied = 0L) 56 { 57 if(pToBeCopied) 58 { 59 memcpy(&mfValue, pToBeCopied, sizeof(double) * RowSize); 60 } 61 else 62 { 63 for(sal_uInt16 a(0); a < RowSize; a++) 64 { 65 mfValue[a] = implGetDefaultValue(nRow, a); 66 } 67 } 68 } 69 get(sal_uInt16 nColumn) const70 double get(sal_uInt16 nColumn) const 71 { 72 return mfValue[nColumn]; 73 } 74 set(sal_uInt16 nColumn,const double & rValue)75 void set(sal_uInt16 nColumn, const double& rValue) 76 { 77 mfValue[nColumn] = rValue; 78 } 79 }; 80 81 template < unsigned int _RowSize > class ImplHomMatrixTemplate 82 { 83 enum { RowSize = _RowSize }; 84 85 ImplMatLine< RowSize > maLine[RowSize - 1]; 86 ImplMatLine< RowSize >* mpLine; 87 88 public: 89 // Is last line used? isLastLineDefault() const90 bool isLastLineDefault() const 91 { 92 if(!mpLine) 93 return true; 94 95 for(sal_uInt16 a(0); a < RowSize; a++) 96 { 97 const double fDefault(implGetDefaultValue((RowSize - 1), a)); 98 const double fLineValue(mpLine->get(a)); 99 100 if(!::basegfx::fTools::equal(fDefault, fLineValue)) 101 { 102 return false; 103 } 104 } 105 106 // reset last line, it equals default 107 delete ((ImplHomMatrixTemplate< RowSize >*)this)->mpLine; 108 ((ImplHomMatrixTemplate< RowSize >*)this)->mpLine = 0L; 109 110 return true; 111 } 112 ImplHomMatrixTemplate()113 ImplHomMatrixTemplate() 114 : mpLine(0L) 115 { 116 // complete initialization with identity matrix, all lines 117 // were initialized with a trailing 1 followed by 0's. 118 for(sal_uInt16 a(0); a < RowSize-1; a++) 119 { 120 for(sal_uInt16 b(0); b < RowSize; b++) 121 maLine[a].set(b, implGetDefaultValue(a, b) ); 122 } 123 } 124 ImplHomMatrixTemplate(const ImplHomMatrixTemplate & rToBeCopied)125 ImplHomMatrixTemplate(const ImplHomMatrixTemplate& rToBeCopied) 126 : mpLine(0L) 127 { 128 // complete initialization using copy 129 for(sal_uInt16 a(0); a < (RowSize - 1); a++) 130 { 131 memcpy(&maLine[a], &rToBeCopied.maLine[a], sizeof(ImplMatLine< RowSize >)); 132 } 133 134 if(rToBeCopied.mpLine) 135 { 136 mpLine = new ImplMatLine< RowSize >((RowSize - 1), rToBeCopied.mpLine); 137 } 138 } 139 ~ImplHomMatrixTemplate()140 ~ImplHomMatrixTemplate() 141 { 142 if(mpLine) 143 { 144 delete mpLine; 145 } 146 } 147 getEdgeLength() const148 sal_uInt16 getEdgeLength() const { return RowSize; } 149 get(sal_uInt16 nRow,sal_uInt16 nColumn) const150 double get(sal_uInt16 nRow, sal_uInt16 nColumn) const 151 { 152 if(nRow < (RowSize - 1)) 153 { 154 return maLine[nRow].get(nColumn); 155 } 156 157 if(mpLine) 158 { 159 return mpLine->get(nColumn); 160 } 161 162 return implGetDefaultValue((RowSize - 1), nColumn); 163 } 164 set(sal_uInt16 nRow,sal_uInt16 nColumn,const double & rValue)165 void set(sal_uInt16 nRow, sal_uInt16 nColumn, const double& rValue) 166 { 167 if(nRow < (RowSize - 1)) 168 { 169 maLine[nRow].set(nColumn, rValue); 170 } 171 else if(mpLine) 172 { 173 mpLine->set(nColumn, rValue); 174 } 175 else 176 { 177 const double fDefault(implGetDefaultValue((RowSize - 1), nColumn)); 178 179 if(!::basegfx::fTools::equal(fDefault, rValue)) 180 { 181 mpLine = new ImplMatLine< RowSize >((RowSize - 1), 0L); 182 mpLine->set(nColumn, rValue); 183 } 184 } 185 } 186 testLastLine()187 void testLastLine() 188 { 189 if(mpLine) 190 { 191 bool bNecessary(false); 192 193 for(sal_uInt16 a(0);!bNecessary && a < RowSize; a++) 194 { 195 const double fDefault(implGetDefaultValue((RowSize - 1), a)); 196 const double fLineValue(mpLine->get(a)); 197 198 if(!::basegfx::fTools::equal(fDefault, fLineValue)) 199 { 200 bNecessary = true; 201 } 202 } 203 204 if(!bNecessary) 205 { 206 delete mpLine; 207 mpLine = 0L; 208 } 209 } 210 } 211 212 // Left-upper decompositon ludcmp(sal_uInt16 nIndex[],sal_Int16 & nParity)213 bool ludcmp(sal_uInt16 nIndex[], sal_Int16& nParity) 214 { 215 double fBig, fSum, fDum; 216 double fStorage[RowSize]; 217 sal_uInt16 a, b, c; 218 219 // #i30874# Initialize nAMax (compiler warns) 220 sal_uInt16 nAMax = 0; 221 222 nParity = 1; 223 224 // Calc the max of each line. If a line is empty, 225 // stop immediately since matrix is not invertible then. 226 for(a = 0; a < RowSize; a++) 227 { 228 fBig = 0.0; 229 230 for(b = 0; b < RowSize; b++) 231 { 232 double fTemp(fabs(get(a, b))); 233 234 if(::basegfx::fTools::more(fTemp, fBig)) 235 { 236 fBig = fTemp; 237 } 238 } 239 240 if(::basegfx::fTools::equalZero(fBig)) 241 { 242 return false; 243 } 244 245 fStorage[a] = 1.0 / fBig; 246 } 247 248 // start normalizing 249 for(b = 0; b < RowSize; b++) 250 { 251 for(a = 0; a < b; a++) 252 { 253 fSum = get(a, b); 254 255 for(c = 0; c < a; c++) 256 { 257 fSum -= get(a, c) * get(c, b); 258 } 259 260 set(a, b, fSum); 261 } 262 263 fBig = 0.0; 264 265 for(a = b; a < RowSize; a++) 266 { 267 fSum = get(a, b); 268 269 for(c = 0; c < b; c++) 270 { 271 fSum -= get(a, c) * get(c, b); 272 } 273 274 set(a, b, fSum); 275 fDum = fStorage[a] * fabs(fSum); 276 277 if(::basegfx::fTools::moreOrEqual(fDum, fBig)) 278 { 279 fBig = fDum; 280 nAMax = a; 281 } 282 } 283 284 if(b != nAMax) 285 { 286 for(c = 0; c < RowSize; c++) 287 { 288 fDum = get(nAMax, c); 289 set(nAMax, c, get(b, c)); 290 set(b, c, fDum); 291 } 292 293 nParity = -nParity; 294 fStorage[nAMax] = fStorage[b]; 295 } 296 297 nIndex[b] = nAMax; 298 299 // here the failure of precision occurs 300 const double fValBB(fabs(get(b, b))); 301 302 if(::basegfx::fTools::equalZero(fValBB)) 303 { 304 return false; 305 } 306 307 if(b != (RowSize - 1)) 308 { 309 fDum = 1.0 / get(b, b); 310 311 for(a = b + 1; a < RowSize; a++) 312 { 313 set(a, b, get(a, b) * fDum); 314 } 315 } 316 } 317 318 return true; 319 } 320 lubksb(const sal_uInt16 nIndex[],double fRow[]) const321 void lubksb(const sal_uInt16 nIndex[], double fRow[]) const 322 { 323 sal_uInt16 b, ip; 324 sal_Int16 a, a2 = -1; 325 double fSum; 326 327 for(a = 0; a < RowSize; a++) 328 { 329 ip = nIndex[a]; 330 fSum = fRow[ip]; 331 fRow[ip] = fRow[a]; 332 333 if(a2 >= 0) 334 { 335 for(b = a2; b < a; b++) 336 { 337 fSum -= get(a, b) * fRow[b]; 338 } 339 } 340 else if(!::basegfx::fTools::equalZero(fSum)) 341 { 342 a2 = a; 343 } 344 345 fRow[a] = fSum; 346 } 347 348 for(a = (RowSize - 1); a >= 0; a--) 349 { 350 fSum = fRow[a]; 351 352 for(b = a + 1; b < RowSize; b++) 353 { 354 fSum -= get(a, b) * fRow[b]; 355 } 356 357 const double fValueAA(get(a, a)); 358 359 if(!::basegfx::fTools::equalZero(fValueAA)) 360 { 361 fRow[a] = fSum / get(a, a); 362 } 363 } 364 } 365 isIdentity() const366 bool isIdentity() const 367 { 368 // last line needs no testing if not existing 369 const sal_uInt16 nMaxLine( 370 sal::static_int_cast<sal_uInt16>(mpLine ? RowSize : (RowSize - 1)) ); 371 372 for(sal_uInt16 a(0); a < nMaxLine; a++) 373 { 374 for(sal_uInt16 b(0); b < RowSize; b++) 375 { 376 const double fDefault(implGetDefaultValue(a, b)); 377 const double fValueAB(get(a, b)); 378 379 if(!::basegfx::fTools::equal(fDefault, fValueAB)) 380 { 381 return false; 382 } 383 } 384 } 385 386 return true; 387 } 388 isInvertible() const389 bool isInvertible() const 390 { 391 ImplHomMatrixTemplate aWork(*this); 392 sal_uInt16 nIndex[RowSize]; 393 sal_Int16 nParity; 394 395 return aWork.ludcmp(nIndex, nParity); 396 } 397 isNormalized() const398 bool isNormalized() const 399 { 400 if(!mpLine) 401 return true; 402 403 const double fHomValue(get((RowSize - 1), (RowSize - 1))); 404 405 if(::basegfx::fTools::equalZero(fHomValue)) 406 { 407 return true; 408 } 409 410 const double fOne(1.0); 411 412 if(::basegfx::fTools::equal(fOne, fHomValue)) 413 { 414 return true; 415 } 416 417 return false; 418 } 419 doInvert(const ImplHomMatrixTemplate & rWork,const sal_uInt16 nIndex[])420 void doInvert(const ImplHomMatrixTemplate& rWork, const sal_uInt16 nIndex[]) 421 { 422 double fArray[RowSize]; 423 424 for(sal_uInt16 a(0); a < RowSize; a++) 425 { 426 // prepare line 427 sal_uInt16 b; 428 for( b = 0; b < RowSize; b++) 429 { 430 fArray[b] = implGetDefaultValue(a, b); 431 } 432 433 // expand line 434 rWork.lubksb(nIndex, fArray); 435 436 // copy line transposed to this matrix 437 for( b = 0; b < RowSize; b++) 438 { 439 set(b, a, fArray[b]); 440 } 441 } 442 443 // evtl. get rid of last matrix line 444 testLastLine(); 445 } 446 doNormalize()447 void doNormalize() 448 { 449 if(mpLine) 450 { 451 const double fHomValue(get((RowSize - 1), (RowSize - 1))); 452 453 for(sal_uInt16 a(0); a < RowSize; a++) 454 { 455 for(sal_uInt16 b(0); b < RowSize; b++) 456 { 457 set(a, b, get(a, b) / fHomValue); 458 } 459 } 460 461 // evtl. get rid of last matrix line 462 testLastLine(); 463 } 464 } 465 doDeterminant() const466 double doDeterminant() const 467 { 468 ImplHomMatrixTemplate aWork(*this); 469 sal_uInt16 nIndex[RowSize]; 470 sal_Int16 nParity; 471 double fRetval(0.0); 472 473 if(aWork.ludcmp(nIndex, nParity)) 474 { 475 fRetval = (double)nParity; 476 477 // last line needs no multiply if not existing; default value would be 1. 478 const sal_uInt16 nMaxLine( 479 sal::static_int_cast<sal_uInt16>(aWork.mpLine ? RowSize : (RowSize - 1)) ); 480 481 for(sal_uInt16 a(0); a < nMaxLine; a++) 482 { 483 fRetval *= aWork.get(a, a); 484 } 485 } 486 487 return fRetval; 488 } 489 doTrace() const490 double doTrace() const 491 { 492 double fTrace = (mpLine) ? 0.0 : 1.0; 493 const sal_uInt16 nMaxLine( 494 sal::static_int_cast<sal_uInt16>(mpLine ? RowSize : (RowSize - 1)) ); 495 496 for(sal_uInt16 a(0); a < nMaxLine; a++) 497 { 498 fTrace += get(a, a); 499 } 500 501 return fTrace; 502 } 503 doTranspose()504 void doTranspose() 505 { 506 for(sal_uInt16 a(0); a < (RowSize - 1); a++) 507 { 508 for(sal_uInt16 b(a + 1); b < RowSize; b++) 509 { 510 const double fTemp(get(a, b)); 511 set(a, b, get(b, a)); 512 set(b, a, fTemp); 513 } 514 } 515 516 testLastLine(); 517 } 518 doAddMatrix(const ImplHomMatrixTemplate & rMat)519 void doAddMatrix(const ImplHomMatrixTemplate& rMat) 520 { 521 for(sal_uInt16 a(0); a < RowSize; a++) 522 { 523 for(sal_uInt16 b(0); b < RowSize; b++) 524 { 525 set(a, b, get(a, b) + rMat.get(a, b)); 526 } 527 } 528 529 testLastLine(); 530 } 531 doSubMatrix(const ImplHomMatrixTemplate & rMat)532 void doSubMatrix(const ImplHomMatrixTemplate& rMat) 533 { 534 for(sal_uInt16 a(0); a < RowSize; a++) 535 { 536 for(sal_uInt16 b(0); b < RowSize; b++) 537 { 538 set(a, b, get(a, b) - rMat.get(a, b)); 539 } 540 } 541 542 testLastLine(); 543 } 544 doMulMatrix(const double & rfValue)545 void doMulMatrix(const double& rfValue) 546 { 547 for(sal_uInt16 a(0); a < RowSize; a++) 548 { 549 for(sal_uInt16 b(0); b < RowSize; b++) 550 { 551 set(a, b, get(a, b) * rfValue); 552 } 553 } 554 555 testLastLine(); 556 } 557 doMulMatrix(const ImplHomMatrixTemplate & rMat)558 void doMulMatrix(const ImplHomMatrixTemplate& rMat) 559 { 560 // create a copy as source for the original values 561 const ImplHomMatrixTemplate aCopy(*this); 562 563 // TODO: maybe optimize cases where last line is [0 0 1]. 564 565 double fValue(0.0); 566 567 for(sal_uInt16 a(0); a < RowSize; ++a) 568 { 569 for(sal_uInt16 b(0); b < RowSize; ++b) 570 { 571 fValue = 0.0; 572 573 for(sal_uInt16 c(0); c < RowSize; ++c) 574 fValue += aCopy.get(c, b) * rMat.get(a, c); 575 576 set(a, b, fValue); 577 } 578 } 579 580 testLastLine(); 581 } 582 isEqual(const ImplHomMatrixTemplate & rMat) const583 bool isEqual(const ImplHomMatrixTemplate& rMat) const 584 { 585 const sal_uInt16 nMaxLine( 586 sal::static_int_cast<sal_uInt16>((mpLine || rMat.mpLine) ? RowSize : (RowSize - 1)) ); 587 588 for(sal_uInt16 a(0); a < nMaxLine; a++) 589 { 590 for(sal_uInt16 b(0); b < RowSize; b++) 591 { 592 const double fValueA(get(a, b)); 593 const double fValueB(rMat.get(a, b)); 594 595 if(!::basegfx::fTools::equal(fValueA, fValueB)) 596 { 597 return false; 598 } 599 } 600 } 601 602 return true; 603 } 604 }; 605 606 } // namespace internal 607 } // namespace basegfx 608 609 #endif /* _HOMMATRIX_TEMPLATE_HXX */ 610