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_drawinglayer.hxx" 26 27 #include <drawinglayer/primitive3d/sdrextrudelathetools3d.hxx> 28 #include <basegfx/polygon/b2dpolypolygon.hxx> 29 #include <basegfx/range/b2drange.hxx> 30 #include <basegfx/polygon/b2dpolypolygontools.hxx> 31 #include <basegfx/matrix/b2dhommatrix.hxx> 32 #include <basegfx/point/b3dpoint.hxx> 33 #include <basegfx/polygon/b3dpolygon.hxx> 34 #include <basegfx/polygon/b3dpolygontools.hxx> 35 #include <basegfx/polygon/b3dpolypolygontools.hxx> 36 #include <basegfx/range/b3drange.hxx> 37 #include <basegfx/matrix/b3dhommatrix.hxx> 38 #include <basegfx/polygon/b2dpolygontools.hxx> 39 #include <drawinglayer/geometry/viewinformation3d.hxx> 40 #include <numeric> 41 42 ////////////////////////////////////////////////////////////////////////////// 43 // decompositon helpers for extrude/lathe (rotation) objects 44 45 namespace 46 { 47 ////////////////////////////////////////////////////////////////////////////// 48 // common helpers 49 50 basegfx::B2DPolyPolygon impScalePolyPolygonOnCenter( 51 const basegfx::B2DPolyPolygon& rSource, 52 double fScale) 53 { 54 basegfx::B2DPolyPolygon aRetval(rSource); 55 56 if(!basegfx::fTools::equalZero(fScale)) 57 { 58 const basegfx::B2DRange aRange(basegfx::tools::getRange(rSource)); 59 const basegfx::B2DPoint aCenter(aRange.getCenter()); 60 basegfx::B2DHomMatrix aTrans; 61 62 aTrans.translate(-aCenter.getX(), -aCenter.getY()); 63 aTrans.scale(fScale, fScale); 64 aTrans.translate(aCenter.getX(), aCenter.getY()); 65 aRetval.transform(aTrans); 66 } 67 68 return aRetval; 69 } 70 71 void impGetOuterPolyPolygon( 72 basegfx::B2DPolyPolygon& rPolygon, 73 basegfx::B2DPolyPolygon& rOuterPolyPolygon, 74 double fOffset, 75 bool bCharacterMode) 76 { 77 rOuterPolyPolygon = rPolygon; 78 79 if(basegfx::fTools::more(fOffset, 0.0)) 80 { 81 if(bCharacterMode) 82 { 83 // grow the outside polygon and scale all polygons to original size. This is done 84 // to avoid a shrink which potentially would lead to self-intersections, but changes 85 // the original polygon -> not a precision step, so e.g. not usable for charts 86 const basegfx::B2DRange aRange(basegfx::tools::getRange(rPolygon)); 87 rPolygon = basegfx::tools::growInNormalDirection(rPolygon, fOffset); 88 const basegfx::B2DRange aGrownRange(basegfx::tools::getRange(rPolygon)); 89 const double fScaleX(basegfx::fTools::equalZero(aGrownRange.getWidth()) ? 1.0 : aRange.getWidth() / aGrownRange.getWidth()); 90 const double fScaleY(basegfx::fTools::equalZero(aGrownRange.getHeight())? 1.0 : aRange.getHeight() / aGrownRange.getHeight()); 91 basegfx::B2DHomMatrix aScaleTrans; 92 93 aScaleTrans.translate(-aGrownRange.getMinX(), -aGrownRange.getMinY()); 94 aScaleTrans.scale(fScaleX, fScaleY); 95 aScaleTrans.translate(aRange.getMinX(), aRange.getMinY()); 96 rPolygon.transform(aScaleTrans); 97 rOuterPolyPolygon.transform(aScaleTrans); 98 } 99 else 100 { 101 // use more precision, shrink the outer polygons. Since this may lead to self-intersections, 102 // some kind of correction should be applied here after that step 103 rOuterPolyPolygon = basegfx::tools::growInNormalDirection(rPolygon, -fOffset); 104 basegfx::tools::correctGrowShrinkPolygonPair(rPolygon, rOuterPolyPolygon); 105 } 106 } 107 } 108 109 void impAddInBetweenFill( 110 basegfx::B3DPolyPolygon& rTarget, 111 const basegfx::B3DPolyPolygon& rPolA, 112 const basegfx::B3DPolyPolygon& rPolB, 113 double fTexVerStart, 114 double fTexVerStop, 115 bool bCreateNormals, 116 bool bCreateTextureCoordinates) 117 { 118 OSL_ENSURE(rPolA.count() == rPolB.count(), "impAddInBetweenFill: unequally sized polygons (!)"); 119 const sal_uInt32 nPolygonCount(rPolA.count()); 120 121 for(sal_uInt32 a(0L); a < nPolygonCount; a++) 122 { 123 const basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a)); 124 const basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a)); 125 OSL_ENSURE(aSubA.count() == aSubB.count(), "impAddInBetweenFill: unequally sized polygons (!)"); 126 const sal_uInt32 nPointCount(aSubA.count()); 127 128 if(nPointCount) 129 { 130 const sal_uInt32 nEdgeCount(aSubA.isClosed() ? nPointCount : nPointCount - 1L); 131 double fTexHorMultiplicatorA(0.0), fTexHorMultiplicatorB(0.0); 132 double fPolygonPosA(0.0), fPolygonPosB(0.0); 133 134 if(bCreateTextureCoordinates) 135 { 136 const double fPolygonLengthA(basegfx::tools::getLength(aSubA)); 137 fTexHorMultiplicatorA = basegfx::fTools::equalZero(fPolygonLengthA) ? 1.0 : 1.0 / fPolygonLengthA; 138 139 const double fPolygonLengthB(basegfx::tools::getLength(aSubB)); 140 fTexHorMultiplicatorB = basegfx::fTools::equalZero(fPolygonLengthB) ? 1.0 : 1.0 / fPolygonLengthB; 141 } 142 143 for(sal_uInt32 b(0L); b < nEdgeCount; b++) 144 { 145 const sal_uInt32 nIndexA(b); 146 const sal_uInt32 nIndexB((b + 1L) % nPointCount); 147 148 const basegfx::B3DPoint aStartA(aSubA.getB3DPoint(nIndexA)); 149 const basegfx::B3DPoint aEndA(aSubA.getB3DPoint(nIndexB)); 150 const basegfx::B3DPoint aStartB(aSubB.getB3DPoint(nIndexA)); 151 const basegfx::B3DPoint aEndB(aSubB.getB3DPoint(nIndexB)); 152 153 basegfx::B3DPolygon aNew; 154 aNew.setClosed(true); 155 156 aNew.append(aStartA); 157 aNew.append(aStartB); 158 aNew.append(aEndB); 159 aNew.append(aEndA); 160 161 if(bCreateNormals) 162 { 163 aNew.setNormal(0L, aSubA.getNormal(nIndexA)); 164 aNew.setNormal(1L, aSubB.getNormal(nIndexA)); 165 aNew.setNormal(2L, aSubB.getNormal(nIndexB)); 166 aNew.setNormal(3L, aSubA.getNormal(nIndexB)); 167 } 168 169 if(bCreateTextureCoordinates) 170 { 171 const double fRelTexAL(fPolygonPosA * fTexHorMultiplicatorA); 172 const double fEdgeLengthA(basegfx::B3DVector(aEndA - aStartA).getLength()); 173 fPolygonPosA += fEdgeLengthA; 174 const double fRelTexAR(fPolygonPosA * fTexHorMultiplicatorA); 175 176 const double fRelTexBL(fPolygonPosB * fTexHorMultiplicatorB); 177 const double fEdgeLengthB(basegfx::B3DVector(aEndB - aStartB).getLength()); 178 fPolygonPosB += fEdgeLengthB; 179 const double fRelTexBR(fPolygonPosB * fTexHorMultiplicatorB); 180 181 aNew.setTextureCoordinate(0L, basegfx::B2DPoint(fRelTexAL, fTexVerStart)); 182 aNew.setTextureCoordinate(1L, basegfx::B2DPoint(fRelTexBL, fTexVerStop)); 183 aNew.setTextureCoordinate(2L, basegfx::B2DPoint(fRelTexBR, fTexVerStop)); 184 aNew.setTextureCoordinate(3L, basegfx::B2DPoint(fRelTexAR, fTexVerStart)); 185 } 186 187 rTarget.append(aNew); 188 } 189 } 190 } 191 } 192 193 void impSetNormal( 194 basegfx::B3DPolyPolygon& rCandidate, 195 const basegfx::B3DVector& rNormal) 196 { 197 for(sal_uInt32 a(0L); a < rCandidate.count(); a++) 198 { 199 basegfx::B3DPolygon aSub(rCandidate.getB3DPolygon(a)); 200 201 for(sal_uInt32 b(0L); b < aSub.count(); b++) 202 { 203 aSub.setNormal(b, rNormal); 204 } 205 206 rCandidate.setB3DPolygon(a, aSub); 207 } 208 } 209 210 void impCreateInBetweenNormals( 211 basegfx::B3DPolyPolygon& rPolA, 212 basegfx::B3DPolyPolygon& rPolB, 213 bool bSmoothHorizontalNormals) 214 { 215 OSL_ENSURE(rPolA.count() == rPolB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); 216 217 for(sal_uInt32 a(0L); a < rPolA.count(); a++) 218 { 219 basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a)); 220 basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a)); 221 OSL_ENSURE(aSubA.count() == aSubB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); 222 const sal_uInt32 nPointCount(aSubA.count()); 223 224 if(nPointCount) 225 { 226 basegfx::B3DPoint aPrevA(aSubA.getB3DPoint(nPointCount - 1L)); 227 basegfx::B3DPoint aCurrA(aSubA.getB3DPoint(0L)); 228 const bool bClosed(aSubA.isClosed()); 229 230 for(sal_uInt32 b(0L); b < nPointCount; b++) 231 { 232 const sal_uInt32 nIndNext((b + 1L) % nPointCount); 233 const basegfx::B3DPoint aNextA(aSubA.getB3DPoint(nIndNext)); 234 const basegfx::B3DPoint aCurrB(aSubB.getB3DPoint(b)); 235 236 // vector to back 237 basegfx::B3DVector aDepth(aCurrB - aCurrA); 238 aDepth.normalize(); 239 240 if(aDepth.equalZero()) 241 { 242 // no difference, try to get depth from next point 243 const basegfx::B3DPoint aNextB(aSubB.getB3DPoint(nIndNext)); 244 aDepth = aNextB - aNextA; 245 aDepth.normalize(); 246 } 247 248 // vector to left (correct for non-closed lines) 249 const bool bFirstAndNotClosed(!bClosed && 0L == b); 250 basegfx::B3DVector aLeft(bFirstAndNotClosed ? aCurrA - aNextA : aPrevA - aCurrA); 251 aLeft.normalize(); 252 253 // create left normal 254 const basegfx::B3DVector aNormalLeft(aDepth.getPerpendicular(aLeft)); 255 256 if(bSmoothHorizontalNormals) 257 { 258 // vector to right (correct for non-closed lines) 259 const bool bLastAndNotClosed(!bClosed && b + 1L == nPointCount); 260 basegfx::B3DVector aRight(bLastAndNotClosed ? aCurrA - aPrevA : aNextA - aCurrA); 261 aRight.normalize(); 262 263 // create right normal 264 const basegfx::B3DVector aNormalRight(aRight.getPerpendicular(aDepth)); 265 266 // create smoothed in-between normal 267 basegfx::B3DVector aNewNormal(aNormalLeft + aNormalRight); 268 aNewNormal.normalize(); 269 270 // set as new normal at polygons 271 aSubA.setNormal(b, aNewNormal); 272 aSubB.setNormal(b, aNewNormal); 273 } 274 else 275 { 276 // set aNormalLeft as new normal at polygons 277 aSubA.setNormal(b, aNormalLeft); 278 aSubB.setNormal(b, aNormalLeft); 279 } 280 281 // prepare next step 282 aPrevA = aCurrA; 283 aCurrA = aNextA; 284 } 285 286 rPolA.setB3DPolygon(a, aSubA); 287 rPolB.setB3DPolygon(a, aSubB); 288 } 289 } 290 } 291 292 void impMixNormals( 293 basegfx::B3DPolyPolygon& rPolA, 294 const basegfx::B3DPolyPolygon& rPolB, 295 double fWeightA) 296 { 297 const double fWeightB(1.0 - fWeightA); 298 OSL_ENSURE(rPolA.count() == rPolB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); 299 300 for(sal_uInt32 a(0L); a < rPolA.count(); a++) 301 { 302 basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a)); 303 const basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a)); 304 OSL_ENSURE(aSubA.count() == aSubB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); 305 const sal_uInt32 nPointCount(aSubA.count()); 306 307 for(sal_uInt32 b(0L); b < nPointCount; b++) 308 { 309 const basegfx::B3DVector aVA(aSubA.getNormal(b) * fWeightA); 310 const basegfx::B3DVector aVB(aSubB.getNormal(b) * fWeightB); 311 basegfx::B3DVector aVNew(aVA + aVB); 312 aVNew.normalize(); 313 aSubA.setNormal(b, aVNew); 314 } 315 316 rPolA.setB3DPolygon(a, aSubA); 317 } 318 } 319 320 bool impHasCutWith(const basegfx::B2DPolygon& rPoly, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd) 321 { 322 // polygon is closed, one of the points is a member 323 const sal_uInt32 nPointCount(rPoly.count()); 324 325 if(nPointCount) 326 { 327 basegfx::B2DPoint aCurrent(rPoly.getB2DPoint(0)); 328 const basegfx::B2DVector aVector(rEnd - rStart); 329 330 for(sal_uInt32 a(0); a < nPointCount; a++) 331 { 332 const sal_uInt32 nNextIndex((a + 1) % nPointCount); 333 const basegfx::B2DPoint aNext(rPoly.getB2DPoint(nNextIndex)); 334 const basegfx::B2DVector aEdgeVector(aNext - aCurrent); 335 336 if(basegfx::tools::findCut( 337 rStart, aVector, 338 aCurrent, aEdgeVector)) 339 { 340 return true; 341 } 342 343 aCurrent = aNext; 344 } 345 } 346 347 return false; 348 } 349 } // end of anonymous namespace 350 351 ////////////////////////////////////////////////////////////////////////////// 352 353 namespace drawinglayer 354 { 355 namespace primitive3d 356 { 357 void createLatheSlices( 358 Slice3DVector& rSliceVector, 359 const basegfx::B2DPolyPolygon& rSource, 360 double fBackScale, 361 double fDiagonal, 362 double fRotation, 363 sal_uInt32 nSteps, 364 bool bCharacterMode, 365 bool bCloseFront, 366 bool bCloseBack) 367 { 368 if(basegfx::fTools::equalZero(fRotation) || 0L == nSteps) 369 { 370 // no rotation or no steps, just one plane 371 rSliceVector.push_back(Slice3D(rSource, basegfx::B3DHomMatrix())); 372 } 373 else 374 { 375 const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0)); 376 const bool bClosedRotation(!bBackScale && basegfx::fTools::equal(fRotation, F_2PI)); 377 basegfx::B2DPolyPolygon aFront(rSource); 378 basegfx::B2DPolyPolygon aBack(rSource); 379 basegfx::B3DHomMatrix aTransformBack; 380 basegfx::B2DPolyPolygon aOuterBack; 381 382 if(bClosedRotation) 383 { 384 bCloseFront = bCloseBack = false; 385 } 386 387 if(bBackScale) 388 { 389 // avoid null zoom 390 if(basegfx::fTools::equalZero(fBackScale)) 391 { 392 fBackScale = 0.000001; 393 } 394 395 // back is scaled compared to front, create scaled version 396 aBack = impScalePolyPolygonOnCenter(aBack, fBackScale); 397 } 398 399 if(bCloseFront || bCloseBack) 400 { 401 const basegfx::B2DRange aBaseRange(basegfx::tools::getRange(aFront)); 402 const double fOuterLength(aBaseRange.getMaxX() * fRotation); 403 const double fInnerLength(aBaseRange.getMinX() * fRotation); 404 const double fAverageLength((fOuterLength + fInnerLength) * 0.5); 405 406 if(bCloseFront) 407 { 408 const double fOffsetLen((fAverageLength / 12.0) * fDiagonal); 409 basegfx::B2DPolyPolygon aOuterFront; 410 impGetOuterPolyPolygon(aFront, aOuterFront, fOffsetLen, bCharacterMode); 411 basegfx::B3DHomMatrix aTransform; 412 aTransform.translate(0.0, 0.0, fOffsetLen); 413 rSliceVector.push_back(Slice3D(aOuterFront, aTransform, SLICETYPE3D_FRONTCAP)); 414 } 415 416 if(bCloseBack) 417 { 418 const double fOffsetLen((fAverageLength / 12.0) * fDiagonal); 419 impGetOuterPolyPolygon(aBack, aOuterBack, fOffsetLen, bCharacterMode); 420 aTransformBack.translate(0.0, 0.0, -fOffsetLen); 421 aTransformBack.rotate(0.0, fRotation, 0.0); 422 } 423 } 424 425 // add start polygon (a = 0L) 426 if(!bClosedRotation) 427 { 428 rSliceVector.push_back(Slice3D(aFront, basegfx::B3DHomMatrix())); 429 } 430 431 // create segments (a + 1 .. nSteps) 432 const double fStepSize(1.0 / (double)nSteps); 433 434 for(sal_uInt32 a(0L); a < nSteps; a++) 435 { 436 const double fStep((double)(a + 1L) * fStepSize); 437 basegfx::B2DPolyPolygon aNewPoly(bBackScale ? basegfx::tools::interpolate(aFront, aBack, fStep) : aFront); 438 basegfx::B3DHomMatrix aNewMat; 439 aNewMat.rotate(0.0, fRotation * fStep, 0.0); 440 rSliceVector.push_back(Slice3D(aNewPoly, aNewMat)); 441 } 442 443 if(bCloseBack) 444 { 445 rSliceVector.push_back(Slice3D(aOuterBack, aTransformBack, SLICETYPE3D_BACKCAP)); 446 } 447 } 448 } 449 450 void createExtrudeSlices( 451 Slice3DVector& rSliceVector, 452 const basegfx::B2DPolyPolygon& rSource, 453 double fBackScale, 454 double fDiagonal, 455 double fDepth, 456 bool bCharacterMode, 457 bool bCloseFront, 458 bool bCloseBack) 459 { 460 if(basegfx::fTools::equalZero(fDepth)) 461 { 462 // no depth, just one plane 463 rSliceVector.push_back(Slice3D(rSource, basegfx::B3DHomMatrix())); 464 } 465 else 466 { 467 // there is depth, create Polygons for front,back and their default depth positions 468 basegfx::B2DPolyPolygon aFront(rSource); 469 basegfx::B2DPolyPolygon aBack(rSource); 470 const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0)); 471 double fZFront(fDepth); // default depth for aFront 472 double fZBack(0.0); // default depth for aBack 473 basegfx::B2DPolyPolygon aOuterBack; 474 475 if(bBackScale) 476 { 477 // avoid null zoom 478 if(basegfx::fTools::equalZero(fBackScale)) 479 { 480 fBackScale = 0.000001; 481 } 482 483 // aFront is scaled compared to aBack, create scaled version 484 aFront = impScalePolyPolygonOnCenter(aFront, fBackScale); 485 } 486 487 if(bCloseFront) 488 { 489 const double fOffset(fDepth * fDiagonal * 0.5); 490 fZFront = fDepth - fOffset; 491 basegfx::B2DPolyPolygon aOuterFront; 492 impGetOuterPolyPolygon(aFront, aOuterFront, fOffset, bCharacterMode); 493 basegfx::B3DHomMatrix aTransformFront; 494 aTransformFront.translate(0.0, 0.0, fDepth); 495 rSliceVector.push_back(Slice3D(aOuterFront, aTransformFront, SLICETYPE3D_FRONTCAP)); 496 } 497 498 if(bCloseBack) 499 { 500 const double fOffset(fDepth * fDiagonal * 0.5); 501 fZBack = fOffset; 502 impGetOuterPolyPolygon(aBack, aOuterBack, fOffset, bCharacterMode); 503 } 504 505 // add front and back polygons at evtl. changed depths 506 { 507 basegfx::B3DHomMatrix aTransformA, aTransformB; 508 509 aTransformA.translate(0.0, 0.0, fZFront); 510 rSliceVector.push_back(Slice3D(aFront, aTransformA)); 511 512 aTransformB.translate(0.0, 0.0, fZBack); 513 rSliceVector.push_back(Slice3D(aBack, aTransformB)); 514 } 515 516 if(bCloseBack) 517 { 518 rSliceVector.push_back(Slice3D(aOuterBack, basegfx::B3DHomMatrix(), SLICETYPE3D_BACKCAP)); 519 } 520 } 521 } 522 523 basegfx::B3DPolyPolygon extractHorizontalLinesFromSlice(const Slice3DVector& rSliceVector, bool bCloseHorLines) 524 { 525 basegfx::B3DPolyPolygon aRetval; 526 const sal_uInt32 nNumSlices(rSliceVector.size()); 527 528 if(nNumSlices) 529 { 530 const sal_uInt32 nSlideSubPolygonCount(rSliceVector[0].getB3DPolyPolygon().count()); 531 532 for(sal_uInt32 b(0); b < nSlideSubPolygonCount; b++) 533 { 534 const sal_uInt32 nSubPolygonPointCount(rSliceVector[0].getB3DPolyPolygon().getB3DPolygon(b).count()); 535 536 for(sal_uInt32 c(0); c < nSubPolygonPointCount; c++) 537 { 538 basegfx::B3DPolygon aNew; 539 540 for(sal_uInt32 d(0); d < nNumSlices; d++) 541 { 542 OSL_ENSURE(nSlideSubPolygonCount == rSliceVector[d].getB3DPolyPolygon().count(), 543 "Slice PolyPolygon with different Polygon count (!)"); 544 OSL_ENSURE(nSubPolygonPointCount == rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).count(), 545 "Slice Polygon with different point count (!)"); 546 aNew.append(rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).getB3DPoint(c)); 547 } 548 549 aNew.setClosed(bCloseHorLines); 550 aRetval.append(aNew); 551 } 552 } 553 } 554 555 return aRetval; 556 } 557 558 basegfx::B3DPolyPolygon extractVerticalLinesFromSlice(const Slice3DVector& rSliceVector) 559 { 560 basegfx::B3DPolyPolygon aRetval; 561 const sal_uInt32 nNumSlices(rSliceVector.size()); 562 563 for(sal_uInt32 a(0L); a < nNumSlices; a++) 564 { 565 aRetval.append(rSliceVector[a].getB3DPolyPolygon()); 566 } 567 568 return aRetval; 569 } 570 571 void extractPlanesFromSlice( 572 ::std::vector< basegfx::B3DPolyPolygon >& rFill, 573 const Slice3DVector& rSliceVector, 574 bool bCreateNormals, 575 bool bSmoothHorizontalNormals, 576 bool bSmoothNormals, 577 bool bSmoothLids, 578 bool bClosed, 579 double fSmoothNormalsMix, 580 double fSmoothLidsMix, 581 bool bCreateTextureCoordinates, 582 const basegfx::B2DHomMatrix& rTexTransform) 583 { 584 const sal_uInt32 nNumSlices(rSliceVector.size()); 585 586 if(nNumSlices) 587 { 588 // common parameters 589 const sal_uInt32 nLoopCount(bClosed ? nNumSlices : nNumSlices - 1L); 590 basegfx::B3DPolyPolygon aEdgeRounding; 591 sal_uInt32 a; 592 593 // tetxture parameters 594 double fInvTexHeight(1.0); 595 double fTexHeightPos(0.0); 596 double fTexStart(0.0); 597 double fTexStop(1.0); 598 ::std::vector<double> aTexHeightArray; 599 basegfx::B3DRange aTexRangeFront; 600 basegfx::B3DRange aTexRangeBack; 601 602 if(bCreateTextureCoordinates) 603 { 604 aTexRangeFront = basegfx::tools::getRange(rSliceVector[0L].getB3DPolyPolygon()); 605 aTexRangeBack = basegfx::tools::getRange(rSliceVector[nNumSlices - 1L].getB3DPolyPolygon()); 606 607 if(aTexRangeBack.getDepth() > aTexRangeBack.getWidth()) 608 { 609 // last polygon is rotated so that depth is bigger than width, exchange X and Z 610 // for making applyDefaultTextureCoordinatesParallel use Z instead of X for 611 // horizontal texture coordinate 612 aTexRangeBack = basegfx::B3DRange( 613 aTexRangeBack.getMinZ(), aTexRangeBack.getMinY(), aTexRangeBack.getMinX(), 614 aTexRangeBack.getMaxZ(), aTexRangeBack.getMaxY(), aTexRangeBack.getMaxX()); 615 } 616 617 basegfx::B3DPoint aCenter(basegfx::tools::getRange(rSliceVector[0L].getB3DPolyPolygon()).getCenter()); 618 619 for(a = 0L; a < nLoopCount; a++) 620 { 621 const basegfx::B3DPoint aNextCenter(basegfx::tools::getRange(rSliceVector[(a + 1L) % nNumSlices].getB3DPolyPolygon()).getCenter()); 622 const double fLength(basegfx::B3DVector(aNextCenter - aCenter).getLength()); 623 aTexHeightArray.push_back(fLength); 624 aCenter = aNextCenter; 625 } 626 627 const double fTexHeight(::std::accumulate(aTexHeightArray.begin(), aTexHeightArray.end(), 0.0)); 628 629 if(!basegfx::fTools::equalZero(fTexHeight)) 630 { 631 fInvTexHeight = 1.0 / fTexHeight; 632 } 633 } 634 635 if(nLoopCount) 636 { 637 for(a = 0L; a < nLoopCount; a++) 638 { 639 const Slice3D& rSliceA(rSliceVector[a]); 640 const Slice3D& rSliceB(rSliceVector[(a + 1L) % nNumSlices]); 641 const bool bAcceptPair(SLICETYPE3D_REGULAR == rSliceA.getSliceType() && SLICETYPE3D_REGULAR == rSliceB.getSliceType()); 642 basegfx::B3DPolyPolygon aPolA(rSliceA.getB3DPolyPolygon()); 643 basegfx::B3DPolyPolygon aPolB(rSliceB.getB3DPolyPolygon()); 644 645 if(bAcceptPair) 646 { 647 if(bCreateNormals) 648 { 649 impCreateInBetweenNormals(aPolB, aPolA, bSmoothHorizontalNormals); 650 } 651 652 { 653 const sal_uInt32 nIndPrev((a + nNumSlices - 1L) % nNumSlices); 654 const Slice3D& rSlicePrev(rSliceVector[nIndPrev]); 655 basegfx::B3DPolyPolygon aPrev(rSlicePrev.getB3DPolyPolygon()); 656 basegfx::B3DPolyPolygon aPolAA(rSliceA.getB3DPolyPolygon()); 657 658 if(SLICETYPE3D_FRONTCAP == rSlicePrev.getSliceType()) 659 { 660 basegfx::B3DPolyPolygon aFront(rSlicePrev.getB3DPolyPolygon()); 661 const bool bHasSlant(aPolAA != aPrev); 662 663 if(bCreateTextureCoordinates) 664 { 665 aFront = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront); 666 } 667 668 if(bCreateNormals) 669 { 670 basegfx::B3DVector aNormal(0.0, 0.0, -1.0); 671 672 if(aFront.count()) 673 { 674 aNormal = -aFront.getB3DPolygon(0L).getNormal(); 675 } 676 677 impSetNormal(aFront, aNormal); 678 679 if(bHasSlant) 680 { 681 impCreateInBetweenNormals(aPolAA, aPrev, bSmoothHorizontalNormals); 682 683 if(bSmoothNormals) 684 { 685 // smooth and copy 686 impMixNormals(aPolA, aPolAA, fSmoothNormalsMix); 687 aPolAA = aPolA; 688 } 689 else 690 { 691 // take over from surface 692 aPolAA = aPolA; 693 } 694 695 if(bSmoothLids) 696 { 697 // smooth and copy 698 impMixNormals(aFront, aPrev, fSmoothLidsMix); 699 aPrev = aFront; 700 } 701 else 702 { 703 // take over from front 704 aPrev = aFront; 705 } 706 } 707 else 708 { 709 if(bSmoothNormals) 710 { 711 // smooth 712 impMixNormals(aPolA, aFront, fSmoothNormalsMix); 713 } 714 715 if(bSmoothLids) 716 { 717 // smooth and copy 718 impMixNormals(aFront, aPolA, fSmoothLidsMix); 719 aPolA = aFront; 720 } 721 } 722 } 723 724 if(bHasSlant) 725 { 726 if(bCreateTextureCoordinates) 727 { 728 fTexStart = fTexHeightPos * fInvTexHeight; 729 fTexStop = (fTexHeightPos - aTexHeightArray[(a + nLoopCount - 1L) % nLoopCount]) * fInvTexHeight; 730 } 731 732 impAddInBetweenFill(aEdgeRounding, aPolAA, aPrev, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates); 733 } 734 735 aFront.flip(); 736 rFill.push_back(aFront); 737 } 738 else 739 { 740 if(bCreateNormals && bSmoothNormals && (nIndPrev != a + 1L)) 741 { 742 impCreateInBetweenNormals(aPolAA, aPrev, bSmoothHorizontalNormals); 743 impMixNormals(aPolA, aPolAA, 0.5); 744 } 745 } 746 } 747 748 { 749 const sal_uInt32 nIndNext((a + 2L) % nNumSlices); 750 const Slice3D& rSliceNext(rSliceVector[nIndNext]); 751 basegfx::B3DPolyPolygon aNext(rSliceNext.getB3DPolyPolygon()); 752 basegfx::B3DPolyPolygon aPolBB(rSliceB.getB3DPolyPolygon()); 753 754 if(SLICETYPE3D_BACKCAP == rSliceNext.getSliceType()) 755 { 756 basegfx::B3DPolyPolygon aBack(rSliceNext.getB3DPolyPolygon()); 757 const bool bHasSlant(aPolBB != aNext); 758 759 if(bCreateTextureCoordinates) 760 { 761 aBack = basegfx::tools::applyDefaultTextureCoordinatesParallel(aBack, aTexRangeBack); 762 } 763 764 if(bCreateNormals) 765 { 766 const basegfx::B3DVector aNormal(aBack.count() ? aBack.getB3DPolygon(0L).getNormal() : basegfx::B3DVector(0.0, 0.0, 1.0)); 767 impSetNormal(aBack, aNormal); 768 769 if(bHasSlant) 770 { 771 impCreateInBetweenNormals(aNext, aPolBB, bSmoothHorizontalNormals); 772 773 if(bSmoothNormals) 774 { 775 // smooth and copy 776 impMixNormals(aPolB, aPolBB, fSmoothNormalsMix); 777 aPolBB = aPolB; 778 } 779 else 780 { 781 // take over from surface 782 aPolBB = aPolB; 783 } 784 785 if(bSmoothLids) 786 { 787 // smooth and copy 788 impMixNormals(aBack, aNext, fSmoothLidsMix); 789 aNext = aBack; 790 } 791 else 792 { 793 // take over from back 794 aNext = aBack; 795 } 796 } 797 else 798 { 799 if(bSmoothNormals) 800 { 801 // smooth 802 impMixNormals(aPolB, aBack, fSmoothNormalsMix); 803 } 804 805 if(bSmoothLids) 806 { 807 // smooth and copy 808 impMixNormals(aBack, aPolB, fSmoothLidsMix); 809 aPolB = aBack; 810 } 811 } 812 } 813 814 if(bHasSlant) 815 { 816 if(bCreateTextureCoordinates) 817 { 818 fTexStart = (fTexHeightPos + aTexHeightArray[a] + aTexHeightArray[(a + 1L) % nLoopCount]) * fInvTexHeight; 819 fTexStop = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight; 820 } 821 822 impAddInBetweenFill(aEdgeRounding, aNext, aPolBB, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates); 823 } 824 825 rFill.push_back(aBack); 826 } 827 else 828 { 829 if(bCreateNormals && bSmoothNormals && (nIndNext != a)) 830 { 831 impCreateInBetweenNormals(aNext, aPolBB, bSmoothHorizontalNormals); 832 impMixNormals(aPolB, aPolBB, 0.5); 833 } 834 } 835 } 836 837 if(bCreateTextureCoordinates) 838 { 839 fTexStart = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight; 840 fTexStop = fTexHeightPos * fInvTexHeight; 841 } 842 843 impAddInBetweenFill(aEdgeRounding, aPolB, aPolA, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates); 844 } 845 846 if(bCreateTextureCoordinates) 847 { 848 fTexHeightPos += aTexHeightArray[a]; 849 } 850 } 851 } 852 else 853 { 854 // no loop, but a single slice (1 == nNumSlices), create a filling from the single 855 // front plane 856 const Slice3D& rSlice(rSliceVector[0]); 857 basegfx::B3DPolyPolygon aFront(rSlice.getB3DPolyPolygon()); 858 859 if(bCreateTextureCoordinates) 860 { 861 aFront = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront); 862 } 863 864 if(bCreateNormals) 865 { 866 basegfx::B3DVector aNormal(0.0, 0.0, -1.0); 867 868 if(aFront.count()) 869 { 870 aNormal = -aFront.getB3DPolygon(0L).getNormal(); 871 } 872 873 impSetNormal(aFront, aNormal); 874 } 875 876 aFront.flip(); 877 rFill.push_back(aFront); 878 } 879 880 if(bCreateTextureCoordinates) 881 { 882 aEdgeRounding.transformTextureCoordiantes(rTexTransform); 883 } 884 885 for(a = 0L; a < aEdgeRounding.count(); a++) 886 { 887 rFill.push_back(basegfx::B3DPolyPolygon(aEdgeRounding.getB3DPolygon(a))); 888 } 889 } 890 } 891 892 void createReducedOutlines( 893 const geometry::ViewInformation3D& rViewInformation, 894 const basegfx::B3DHomMatrix& rObjectTransform, 895 const basegfx::B3DPolygon& rLoopA, 896 const basegfx::B3DPolygon& rLoopB, 897 basegfx::B3DPolyPolygon& rTarget) 898 { 899 const sal_uInt32 nPointCount(rLoopA.count()); 900 901 // with idetic polygons there are no outlines 902 if(rLoopA != rLoopB) 903 { 904 if(nPointCount && nPointCount == rLoopB.count()) 905 { 906 const basegfx::B3DHomMatrix aObjectTransform(rViewInformation.getObjectToView() * rObjectTransform); 907 const basegfx::B2DPolygon a2DLoopA(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopA, aObjectTransform)); 908 const basegfx::B2DPolygon a2DLoopB(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopB, aObjectTransform)); 909 const basegfx::B2DPoint a2DCenterA(a2DLoopA.getB2DRange().getCenter()); 910 const basegfx::B2DPoint a2DCenterB(a2DLoopB.getB2DRange().getCenter()); 911 912 // without detectable Y-Axis there are no outlines 913 if(!a2DCenterA.equal(a2DCenterB)) 914 { 915 // search for outmost left and right inter-loop-edges which do not cut the loops 916 const basegfx::B2DPoint aCommonCenter(basegfx::average(a2DCenterA, a2DCenterB)); 917 const basegfx::B2DVector aAxisVector(a2DCenterA - a2DCenterB); 918 double fMaxLeft(0.0); 919 double fMaxRight(0.0); 920 sal_uInt32 nIndexLeft(0); 921 sal_uInt32 nIndexRight(0); 922 923 for(sal_uInt32 a(0); a < nPointCount; a++) 924 { 925 const basegfx::B2DPoint aStart(a2DLoopA.getB2DPoint(a)); 926 const basegfx::B2DPoint aEnd(a2DLoopB.getB2DPoint(a)); 927 const basegfx::B2DPoint aMiddle(basegfx::average(aStart, aEnd)); 928 929 if(!basegfx::tools::isInside(a2DLoopA, aMiddle)) 930 { 931 if(!basegfx::tools::isInside(a2DLoopB, aMiddle)) 932 { 933 if(!impHasCutWith(a2DLoopA, aStart, aEnd)) 934 { 935 if(!impHasCutWith(a2DLoopB, aStart, aEnd)) 936 { 937 const basegfx::B2DVector aCandidateVector(aMiddle - aCommonCenter); 938 const double fCross(aCandidateVector.cross(aAxisVector)); 939 const double fDistance(aCandidateVector.getLength()); 940 941 if(fCross > 0.0) 942 { 943 if(fDistance > fMaxLeft) 944 { 945 fMaxLeft = fDistance; 946 nIndexLeft = a; 947 } 948 } 949 else if(fCross < 0.0) 950 { 951 if(fDistance > fMaxRight) 952 { 953 fMaxRight = fDistance; 954 nIndexRight = a; 955 } 956 } 957 } 958 } 959 } 960 } 961 } 962 963 if(fMaxLeft != 0.0) 964 { 965 basegfx::B3DPolygon aToBeAdded; 966 aToBeAdded.append(rLoopA.getB3DPoint(nIndexLeft)); 967 aToBeAdded.append(rLoopB.getB3DPoint(nIndexLeft)); 968 rTarget.append(aToBeAdded); 969 } 970 971 if(fMaxRight != 0.0) 972 { 973 basegfx::B3DPolygon aToBeAdded; 974 aToBeAdded.append(rLoopA.getB3DPoint(nIndexRight)); 975 aToBeAdded.append(rLoopB.getB3DPoint(nIndexRight)); 976 rTarget.append(aToBeAdded); 977 } 978 } 979 } 980 } 981 } 982 983 } // end of namespace primitive3d 984 } // end of namespace drawinglayer 985 986 ////////////////////////////////////////////////////////////////////////////// 987 // eof 988