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 #include <basegfx/polygon/b3dpolypolygontools.hxx> 31 #include <basegfx/range/b3drange.hxx> 32 #include <basegfx/polygon/b3dpolypolygon.hxx> 33 #include <basegfx/polygon/b3dpolygon.hxx> 34 #include <basegfx/polygon/b3dpolygontools.hxx> 35 #include <numeric> 36 #include <basegfx/matrix/b3dhommatrix.hxx> 37 #include <basegfx/numeric/ftools.hxx> 38 #include <osl/mutex.hxx> 39 40 ////////////////////////////////////////////////////////////////////////////// 41 42 namespace basegfx 43 { 44 namespace tools 45 { 46 // B3DPolyPolygon tools 47 B3DRange getRange(const B3DPolyPolygon& rCandidate) 48 { 49 B3DRange aRetval; 50 const sal_uInt32 nPolygonCount(rCandidate.count()); 51 52 for(sal_uInt32 a(0L); a < nPolygonCount; a++) 53 { 54 B3DPolygon aCandidate = rCandidate.getB3DPolygon(a); 55 aRetval.expand(getRange(aCandidate)); 56 } 57 58 return aRetval; 59 } 60 61 void applyLineDashing(const B3DPolyPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B3DPolyPolygon* pLineTarget, B3DPolyPolygon* pGapTarget, double fFullDashDotLen) 62 { 63 if(0.0 == fFullDashDotLen && rDotDashArray.size()) 64 { 65 // calculate fFullDashDotLen from rDotDashArray 66 fFullDashDotLen = ::std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0); 67 } 68 69 if(rCandidate.count() && fFullDashDotLen > 0.0) 70 { 71 B3DPolyPolygon aLineTarget, aGapTarget; 72 73 for(sal_uInt32 a(0L); a < rCandidate.count(); a++) 74 { 75 const B3DPolygon aCandidate(rCandidate.getB3DPolygon(a)); 76 77 applyLineDashing( 78 aCandidate, 79 rDotDashArray, 80 pLineTarget ? &aLineTarget : 0, 81 pGapTarget ? &aGapTarget : 0, 82 fFullDashDotLen); 83 84 if(pLineTarget) 85 { 86 pLineTarget->append(aLineTarget); 87 } 88 89 if(pGapTarget) 90 { 91 pGapTarget->append(aGapTarget); 92 } 93 } 94 } 95 } 96 97 B3DPolyPolygon createUnitCubePolyPolygon() 98 { 99 static B3DPolyPolygon aRetval; 100 ::osl::Mutex m_mutex; 101 102 if(!aRetval.count()) 103 { 104 B3DPolygon aTemp; 105 aTemp.append(B3DPoint(0.0, 0.0, 1.0)); 106 aTemp.append(B3DPoint(0.0, 1.0, 1.0)); 107 aTemp.append(B3DPoint(1.0, 1.0, 1.0)); 108 aTemp.append(B3DPoint(1.0, 0.0, 1.0)); 109 aTemp.setClosed(true); 110 aRetval.append(aTemp); 111 112 aTemp.clear(); 113 aTemp.append(B3DPoint(0.0, 0.0, 0.0)); 114 aTemp.append(B3DPoint(0.0, 1.0, 0.0)); 115 aTemp.append(B3DPoint(1.0, 1.0, 0.0)); 116 aTemp.append(B3DPoint(1.0, 0.0, 0.0)); 117 aTemp.setClosed(true); 118 aRetval.append(aTemp); 119 120 aTemp.clear(); 121 aTemp.append(B3DPoint(0.0, 0.0, 0.0)); 122 aTemp.append(B3DPoint(0.0, 0.0, 1.0)); 123 aRetval.append(aTemp); 124 125 aTemp.clear(); 126 aTemp.append(B3DPoint(0.0, 1.0, 0.0)); 127 aTemp.append(B3DPoint(0.0, 1.0, 1.0)); 128 aRetval.append(aTemp); 129 130 aTemp.clear(); 131 aTemp.append(B3DPoint(1.0, 1.0, 0.0)); 132 aTemp.append(B3DPoint(1.0, 1.0, 1.0)); 133 aRetval.append(aTemp); 134 135 aTemp.clear(); 136 aTemp.append(B3DPoint(1.0, 0.0, 0.0)); 137 aTemp.append(B3DPoint(1.0, 0.0, 1.0)); 138 aRetval.append(aTemp); 139 } 140 141 return aRetval; 142 } 143 144 B3DPolyPolygon createUnitCubeFillPolyPolygon() 145 { 146 static B3DPolyPolygon aRetval; 147 ::osl::Mutex m_mutex; 148 149 if(!aRetval.count()) 150 { 151 B3DPolygon aTemp; 152 153 // all points 154 const B3DPoint A(0.0, 0.0, 0.0); 155 const B3DPoint B(0.0, 1.0, 0.0); 156 const B3DPoint C(1.0, 1.0, 0.0); 157 const B3DPoint D(1.0, 0.0, 0.0); 158 const B3DPoint E(0.0, 0.0, 1.0); 159 const B3DPoint F(0.0, 1.0, 1.0); 160 const B3DPoint G(1.0, 1.0, 1.0); 161 const B3DPoint H(1.0, 0.0, 1.0); 162 163 // create bottom 164 aTemp.append(D); 165 aTemp.append(A); 166 aTemp.append(E); 167 aTemp.append(H); 168 aTemp.setClosed(true); 169 aRetval.append(aTemp); 170 171 // create front 172 aTemp.clear(); 173 aTemp.append(B); 174 aTemp.append(A); 175 aTemp.append(D); 176 aTemp.append(C); 177 aTemp.setClosed(true); 178 aRetval.append(aTemp); 179 180 // create left 181 aTemp.clear(); 182 aTemp.append(E); 183 aTemp.append(A); 184 aTemp.append(B); 185 aTemp.append(F); 186 aTemp.setClosed(true); 187 aRetval.append(aTemp); 188 189 // create top 190 aTemp.clear(); 191 aTemp.append(C); 192 aTemp.append(G); 193 aTemp.append(F); 194 aTemp.append(B); 195 aTemp.setClosed(true); 196 aRetval.append(aTemp); 197 198 // create right 199 aTemp.clear(); 200 aTemp.append(H); 201 aTemp.append(G); 202 aTemp.append(C); 203 aTemp.append(D); 204 aTemp.setClosed(true); 205 aRetval.append(aTemp); 206 207 // create back 208 aTemp.clear(); 209 aTemp.append(F); 210 aTemp.append(G); 211 aTemp.append(H); 212 aTemp.append(E); 213 aTemp.setClosed(true); 214 aRetval.append(aTemp); 215 } 216 217 return aRetval; 218 } 219 220 B3DPolyPolygon createCubePolyPolygonFromB3DRange( const B3DRange& rRange) 221 { 222 B3DPolyPolygon aRetval; 223 224 if(!rRange.isEmpty()) 225 { 226 aRetval = createUnitCubePolyPolygon(); 227 B3DHomMatrix aTrans; 228 aTrans.scale(rRange.getWidth(), rRange.getHeight(), rRange.getDepth()); 229 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ()); 230 aRetval.transform(aTrans); 231 aRetval.removeDoublePoints(); 232 } 233 234 return aRetval; 235 } 236 237 B3DPolyPolygon createCubeFillPolyPolygonFromB3DRange( const B3DRange& rRange) 238 { 239 B3DPolyPolygon aRetval; 240 241 if(!rRange.isEmpty()) 242 { 243 aRetval = createUnitCubeFillPolyPolygon(); 244 B3DHomMatrix aTrans; 245 aTrans.scale(rRange.getWidth(), rRange.getHeight(), rRange.getDepth()); 246 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ()); 247 aRetval.transform(aTrans); 248 aRetval.removeDoublePoints(); 249 } 250 251 return aRetval; 252 } 253 254 // helper for getting the 3D Point from given cartesian coordiantes. fVer is defined from 255 // [F_PI2 .. -F_PI2], fHor from [0.0 .. F_2PI] 256 inline B3DPoint getPointFromCartesian(double fVer, double fHor) 257 { 258 const double fCosHor(cos(fHor)); 259 return B3DPoint(fCosHor * cos(fVer), sin(fHor), fCosHor * -sin(fVer)); 260 } 261 262 B3DPolyPolygon createUnitSpherePolyPolygon( 263 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg, 264 double fVerStart, double fVerStop, 265 double fHorStart, double fHorStop) 266 { 267 B3DPolyPolygon aRetval; 268 sal_uInt32 a, b; 269 270 if(!nHorSeg) 271 { 272 nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0)); 273 } 274 275 if(!nHorSeg) 276 { 277 nHorSeg = 1L; 278 } 279 280 if(!nVerSeg) 281 { 282 nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0)); 283 } 284 285 if(!nVerSeg) 286 { 287 nVerSeg = 1L; 288 } 289 290 // create constants 291 const double fVerDiffPerStep((fVerStop - fVerStart) / (double)nVerSeg); 292 const double fHorDiffPerStep((fHorStop - fHorStart) / (double)nHorSeg); 293 bool bHorClosed(fTools::equal(fHorStop - fHorStart, F_2PI)); 294 bool bVerFromTop(fTools::equal(fVerStart, F_PI2)); 295 bool bVerToBottom(fTools::equal(fVerStop, -F_PI2)); 296 297 // create horizontal rings 298 const sal_uInt32 nLoopVerInit(bVerFromTop ? 1L : 0L); 299 const sal_uInt32 nLoopVerLimit(bVerToBottom ? nVerSeg : nVerSeg + 1L); 300 const sal_uInt32 nLoopHorLimit(bHorClosed ? nHorSeg : nHorSeg + 1L); 301 302 for(a = nLoopVerInit; a < nLoopVerLimit; a++) 303 { 304 const double fVer(fVerStart + ((double)(a) * fVerDiffPerStep)); 305 B3DPolygon aNew; 306 307 for(b = 0L; b < nLoopHorLimit; b++) 308 { 309 const double fHor(fHorStart + ((double)(b) * fHorDiffPerStep)); 310 aNew.append(getPointFromCartesian(fHor, fVer)); 311 } 312 313 aNew.setClosed(bHorClosed); 314 aRetval.append(aNew); 315 } 316 317 // create vertical half-rings 318 for(a = 0L; a < nLoopHorLimit; a++) 319 { 320 const double fHor(fHorStart + ((double)(a) * fHorDiffPerStep)); 321 B3DPolygon aNew; 322 323 if(bVerFromTop) 324 { 325 aNew.append(B3DPoint(0.0, 1.0, 0.0)); 326 } 327 328 for(b = nLoopVerInit; b < nLoopVerLimit; b++) 329 { 330 const double fVer(fVerStart + ((double)(b) * fVerDiffPerStep)); 331 aNew.append(getPointFromCartesian(fHor, fVer)); 332 } 333 334 if(bVerToBottom) 335 { 336 aNew.append(B3DPoint(0.0, -1.0, 0.0)); 337 } 338 339 aRetval.append(aNew); 340 } 341 342 return aRetval; 343 } 344 345 B3DPolyPolygon createSpherePolyPolygonFromB3DRange( const B3DRange& rRange, 346 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg, 347 double fVerStart, double fVerStop, 348 double fHorStart, double fHorStop) 349 { 350 B3DPolyPolygon aRetval(createUnitSpherePolyPolygon(nHorSeg, nVerSeg, fVerStart, fVerStop, fHorStart, fHorStop)); 351 352 if(aRetval.count()) 353 { 354 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions 355 B3DHomMatrix aTrans; 356 aTrans.translate(1.0, 1.0, 1.0); 357 aTrans.scale(rRange.getWidth() / 2.0, rRange.getHeight() / 2.0, rRange.getDepth() / 2.0); 358 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ()); 359 aRetval.transform(aTrans); 360 } 361 362 return aRetval; 363 } 364 365 B3DPolyPolygon createUnitSphereFillPolyPolygon( 366 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg, 367 bool bNormals, 368 double fVerStart, double fVerStop, 369 double fHorStart, double fHorStop) 370 { 371 B3DPolyPolygon aRetval; 372 373 if(!nHorSeg) 374 { 375 nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0)); 376 } 377 378 if(!nHorSeg) 379 { 380 nHorSeg = 1L; 381 } 382 383 if(!nVerSeg) 384 { 385 nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0)); 386 } 387 388 if(!nVerSeg) 389 { 390 nVerSeg = 1L; 391 } 392 393 // vertical loop 394 for(sal_uInt32 a(0L); a < nVerSeg; a++) 395 { 396 const double fVer(fVerStart + (((fVerStop - fVerStart) * a) / nVerSeg)); 397 const double fVer2(fVerStart + (((fVerStop - fVerStart) * (a + 1)) / nVerSeg)); 398 399 // horizontal loop 400 for(sal_uInt32 b(0L); b < nHorSeg; b++) 401 { 402 const double fHor(fHorStart + (((fHorStop - fHorStart) * b) / nHorSeg)); 403 const double fHor2(fHorStart + (((fHorStop - fHorStart) * (b + 1)) / nHorSeg)); 404 B3DPolygon aNew; 405 406 aNew.append(getPointFromCartesian(fHor, fVer)); 407 aNew.append(getPointFromCartesian(fHor2, fVer)); 408 aNew.append(getPointFromCartesian(fHor2, fVer2)); 409 aNew.append(getPointFromCartesian(fHor, fVer2)); 410 411 if(bNormals) 412 { 413 for(sal_uInt32 c(0L); c < aNew.count(); c++) 414 { 415 aNew.setNormal(c, ::basegfx::B3DVector(aNew.getB3DPoint(c))); 416 } 417 } 418 419 aNew.setClosed(true); 420 aRetval.append(aNew); 421 } 422 } 423 424 return aRetval; 425 } 426 427 B3DPolyPolygon createSphereFillPolyPolygonFromB3DRange( const B3DRange& rRange, 428 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg, 429 bool bNormals, 430 double fVerStart, double fVerStop, 431 double fHorStart, double fHorStop) 432 { 433 B3DPolyPolygon aRetval(createUnitSphereFillPolyPolygon(nHorSeg, nVerSeg, bNormals, fVerStart, fVerStop, fHorStart, fHorStop)); 434 435 if(aRetval.count()) 436 { 437 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions 438 B3DHomMatrix aTrans; 439 aTrans.translate(1.0, 1.0, 1.0); 440 aTrans.scale(rRange.getWidth() / 2.0, rRange.getHeight() / 2.0, rRange.getDepth() / 2.0); 441 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ()); 442 aRetval.transform(aTrans); 443 } 444 445 return aRetval; 446 } 447 448 B3DPolyPolygon applyDefaultNormalsSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter) 449 { 450 B3DPolyPolygon aRetval; 451 452 for(sal_uInt32 a(0L); a < rCandidate.count(); a++) 453 { 454 aRetval.append(applyDefaultNormalsSphere(rCandidate.getB3DPolygon(a), rCenter)); 455 } 456 457 return aRetval; 458 } 459 460 B3DPolyPolygon invertNormals( const B3DPolyPolygon& rCandidate) 461 { 462 B3DPolyPolygon aRetval; 463 464 for(sal_uInt32 a(0L); a < rCandidate.count(); a++) 465 { 466 aRetval.append(invertNormals(rCandidate.getB3DPolygon(a))); 467 } 468 469 return aRetval; 470 } 471 472 B3DPolyPolygon applyDefaultTextureCoordinatesParallel( const B3DPolyPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY) 473 { 474 B3DPolyPolygon aRetval; 475 476 for(sal_uInt32 a(0L); a < rCandidate.count(); a++) 477 { 478 aRetval.append(applyDefaultTextureCoordinatesParallel(rCandidate.getB3DPolygon(a), rRange, bChangeX, bChangeY)); 479 } 480 481 return aRetval; 482 } 483 484 B3DPolyPolygon applyDefaultTextureCoordinatesSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY) 485 { 486 B3DPolyPolygon aRetval; 487 488 for(sal_uInt32 a(0L); a < rCandidate.count(); a++) 489 { 490 aRetval.append(applyDefaultTextureCoordinatesSphere(rCandidate.getB3DPolygon(a), rCenter, bChangeX, bChangeY)); 491 } 492 493 return aRetval; 494 } 495 496 bool isInside(const B3DPolyPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder) 497 { 498 const sal_uInt32 nPolygonCount(rCandidate.count()); 499 500 if(1L == nPolygonCount) 501 { 502 return isInside(rCandidate.getB3DPolygon(0), rPoint, bWithBorder); 503 } 504 else 505 { 506 sal_Int32 nInsideCount(0); 507 508 for(sal_uInt32 a(0); a < nPolygonCount; a++) 509 { 510 const B3DPolygon aPolygon(rCandidate.getB3DPolygon(a)); 511 const bool bInside(isInside(aPolygon, rPoint, bWithBorder)); 512 513 if(bInside) 514 { 515 nInsideCount++; 516 } 517 } 518 519 return (nInsideCount % 2L); 520 } 521 } 522 523 ////////////////////////////////////////////////////////////////////// 524 // comparators with tolerance for 3D PolyPolygons 525 526 bool equal(const B3DPolyPolygon& rCandidateA, const B3DPolyPolygon& rCandidateB, const double& rfSmallValue) 527 { 528 const sal_uInt32 nPolygonCount(rCandidateA.count()); 529 530 if(nPolygonCount != rCandidateB.count()) 531 return false; 532 533 for(sal_uInt32 a(0); a < nPolygonCount; a++) 534 { 535 const B3DPolygon aCandidate(rCandidateA.getB3DPolygon(a)); 536 537 if(!equal(aCandidate, rCandidateB.getB3DPolygon(a), rfSmallValue)) 538 return false; 539 } 540 541 return true; 542 } 543 544 bool equal(const B3DPolyPolygon& rCandidateA, const B3DPolyPolygon& rCandidateB) 545 { 546 const double fSmallValue(fTools::getSmallValue()); 547 548 return equal(rCandidateA, rCandidateB, fSmallValue); 549 } 550 551 } // end of namespace tools 552 } // end of namespace basegfx 553 554 ////////////////////////////////////////////////////////////////////////////// 555 556 // eof 557