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