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