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 impScalePolyPolygonOnCenter(const basegfx::B2DPolyPolygon & rSource,double fScale)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 impGetOuterPolyPolygon(basegfx::B2DPolyPolygon & rPolygon,basegfx::B2DPolyPolygon & rOuterPolyPolygon,double fOffset,bool bCharacterMode)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 impAddInBetweenFill(basegfx::B3DPolyPolygon & rTarget,const basegfx::B3DPolyPolygon & rPolA,const basegfx::B3DPolyPolygon & rPolB,double fTexVerStart,double fTexVerStop,bool bCreateNormals,bool bCreateTextureCoordinates)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(::std::min(rPolA.count(), rPolB.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(::std::min(aSubA.count(), aSubB.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 impSetNormal(basegfx::B3DPolyPolygon & rCandidate,const basegfx::B3DVector & rNormal)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 impCreateInBetweenNormals(basegfx::B3DPolyPolygon & rPolA,basegfx::B3DPolyPolygon & rPolB,bool bSmoothHorizontalNormals)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 const sal_uInt32 nPolygonCount(::std::min(rPolA.count(), rPolB.count())); 217 218 for(sal_uInt32 a(0L); a < nPolygonCount; a++) 219 { 220 basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a)); 221 basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a)); 222 OSL_ENSURE(aSubA.count() == aSubB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); 223 const sal_uInt32 nPointCount(::std::min(aSubA.count(), aSubB.count())); 224 225 if(nPointCount) 226 { 227 basegfx::B3DPoint aPrevA(aSubA.getB3DPoint(nPointCount - 1L)); 228 basegfx::B3DPoint aCurrA(aSubA.getB3DPoint(0L)); 229 const bool bClosed(aSubA.isClosed()); 230 231 for(sal_uInt32 b(0L); b < nPointCount; b++) 232 { 233 const sal_uInt32 nIndNext((b + 1L) % nPointCount); 234 const basegfx::B3DPoint aNextA(aSubA.getB3DPoint(nIndNext)); 235 const basegfx::B3DPoint aCurrB(aSubB.getB3DPoint(b)); 236 237 // vector to back 238 basegfx::B3DVector aDepth(aCurrB - aCurrA); 239 aDepth.normalize(); 240 241 if(aDepth.equalZero()) 242 { 243 // no difference, try to get depth from next point 244 const basegfx::B3DPoint aNextB(aSubB.getB3DPoint(nIndNext)); 245 aDepth = aNextB - aNextA; 246 aDepth.normalize(); 247 } 248 249 // vector to left (correct for non-closed lines) 250 const bool bFirstAndNotClosed(!bClosed && 0L == b); 251 basegfx::B3DVector aLeft(bFirstAndNotClosed ? aCurrA - aNextA : aPrevA - aCurrA); 252 aLeft.normalize(); 253 254 // create left normal 255 const basegfx::B3DVector aNormalLeft(aDepth.getPerpendicular(aLeft)); 256 257 if(bSmoothHorizontalNormals) 258 { 259 // vector to right (correct for non-closed lines) 260 const bool bLastAndNotClosed(!bClosed && b + 1L == nPointCount); 261 basegfx::B3DVector aRight(bLastAndNotClosed ? aCurrA - aPrevA : aNextA - aCurrA); 262 aRight.normalize(); 263 264 // create right normal 265 const basegfx::B3DVector aNormalRight(aRight.getPerpendicular(aDepth)); 266 267 // create smoothed in-between normal 268 basegfx::B3DVector aNewNormal(aNormalLeft + aNormalRight); 269 aNewNormal.normalize(); 270 271 // set as new normal at polygons 272 aSubA.setNormal(b, aNewNormal); 273 aSubB.setNormal(b, aNewNormal); 274 } 275 else 276 { 277 // set aNormalLeft as new normal at polygons 278 aSubA.setNormal(b, aNormalLeft); 279 aSubB.setNormal(b, aNormalLeft); 280 } 281 282 // prepare next step 283 aPrevA = aCurrA; 284 aCurrA = aNextA; 285 } 286 287 rPolA.setB3DPolygon(a, aSubA); 288 rPolB.setB3DPolygon(a, aSubB); 289 } 290 } 291 } 292 impMixNormals(basegfx::B3DPolyPolygon & rPolA,const basegfx::B3DPolyPolygon & rPolB,double fWeightA)293 void impMixNormals( 294 basegfx::B3DPolyPolygon& rPolA, 295 const basegfx::B3DPolyPolygon& rPolB, 296 double fWeightA) 297 { 298 const double fWeightB(1.0 - fWeightA); 299 OSL_ENSURE(rPolA.count() == rPolB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); 300 const sal_uInt32 nPolygonCount(::std::min(rPolA.count(), rPolB.count())); 301 302 for(sal_uInt32 a(0L); a < nPolygonCount; a++) 303 { 304 basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a)); 305 const basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a)); 306 OSL_ENSURE(aSubA.count() == aSubB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)"); 307 const sal_uInt32 nPointCount(::std::min(aSubA.count(), aSubB.count())); 308 309 for(sal_uInt32 b(0L); b < nPointCount; b++) 310 { 311 const basegfx::B3DVector aVA(aSubA.getNormal(b) * fWeightA); 312 const basegfx::B3DVector aVB(aSubB.getNormal(b) * fWeightB); 313 basegfx::B3DVector aVNew(aVA + aVB); 314 aVNew.normalize(); 315 aSubA.setNormal(b, aVNew); 316 } 317 318 rPolA.setB3DPolygon(a, aSubA); 319 } 320 } 321 impHasCutWith(const basegfx::B2DPolygon & rPoly,const basegfx::B2DPoint & rStart,const basegfx::B2DPoint & rEnd)322 bool impHasCutWith(const basegfx::B2DPolygon& rPoly, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd) 323 { 324 // polygon is closed, one of the points is a member 325 const sal_uInt32 nPointCount(rPoly.count()); 326 327 if(nPointCount) 328 { 329 basegfx::B2DPoint aCurrent(rPoly.getB2DPoint(0)); 330 const basegfx::B2DVector aVector(rEnd - rStart); 331 332 for(sal_uInt32 a(0); a < nPointCount; a++) 333 { 334 const sal_uInt32 nNextIndex((a + 1) % nPointCount); 335 const basegfx::B2DPoint aNext(rPoly.getB2DPoint(nNextIndex)); 336 const basegfx::B2DVector aEdgeVector(aNext - aCurrent); 337 338 if(basegfx::tools::findCut( 339 rStart, aVector, 340 aCurrent, aEdgeVector)) 341 { 342 return true; 343 } 344 345 aCurrent = aNext; 346 } 347 } 348 349 return false; 350 } 351 } // end of anonymous namespace 352 353 ////////////////////////////////////////////////////////////////////////////// 354 355 namespace drawinglayer 356 { 357 namespace primitive3d 358 { createLatheSlices(Slice3DVector & rSliceVector,const basegfx::B2DPolyPolygon & rSource,double fBackScale,double fDiagonal,double fRotation,sal_uInt32 nSteps,bool bCharacterMode,bool bCloseFront,bool bCloseBack)359 void createLatheSlices( 360 Slice3DVector& rSliceVector, 361 const basegfx::B2DPolyPolygon& rSource, 362 double fBackScale, 363 double fDiagonal, 364 double fRotation, 365 sal_uInt32 nSteps, 366 bool bCharacterMode, 367 bool bCloseFront, 368 bool bCloseBack) 369 { 370 if(basegfx::fTools::equalZero(fRotation) || 0L == nSteps) 371 { 372 // no rotation or no steps, just one plane 373 rSliceVector.push_back(Slice3D(rSource, basegfx::B3DHomMatrix())); 374 } 375 else 376 { 377 const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0)); 378 const bool bClosedRotation(!bBackScale && basegfx::fTools::equal(fRotation, F_2PI)); 379 basegfx::B2DPolyPolygon aFront(rSource); 380 basegfx::B2DPolyPolygon aBack(rSource); 381 basegfx::B3DHomMatrix aTransformBack; 382 basegfx::B2DPolyPolygon aOuterBack; 383 384 if(bClosedRotation) 385 { 386 bCloseFront = bCloseBack = false; 387 } 388 389 if(bBackScale) 390 { 391 // avoid null zoom 392 if(basegfx::fTools::equalZero(fBackScale)) 393 { 394 fBackScale = 0.000001; 395 } 396 397 // back is scaled compared to front, create scaled version 398 aBack = impScalePolyPolygonOnCenter(aBack, fBackScale); 399 } 400 401 if(bCloseFront || bCloseBack) 402 { 403 const basegfx::B2DRange aBaseRange(basegfx::tools::getRange(aFront)); 404 const double fOuterLength(aBaseRange.getMaxX() * fRotation); 405 const double fInnerLength(aBaseRange.getMinX() * fRotation); 406 const double fAverageLength((fOuterLength + fInnerLength) * 0.5); 407 408 if(bCloseFront) 409 { 410 const double fOffsetLen((fAverageLength / 12.0) * fDiagonal); 411 basegfx::B2DPolyPolygon aOuterFront; 412 impGetOuterPolyPolygon(aFront, aOuterFront, fOffsetLen, bCharacterMode); 413 basegfx::B3DHomMatrix aTransform; 414 aTransform.translate(0.0, 0.0, fOffsetLen); 415 rSliceVector.push_back(Slice3D(aOuterFront, aTransform, SLICETYPE3D_FRONTCAP)); 416 } 417 418 if(bCloseBack) 419 { 420 const double fOffsetLen((fAverageLength / 12.0) * fDiagonal); 421 impGetOuterPolyPolygon(aBack, aOuterBack, fOffsetLen, bCharacterMode); 422 aTransformBack.translate(0.0, 0.0, -fOffsetLen); 423 aTransformBack.rotate(0.0, fRotation, 0.0); 424 } 425 } 426 427 // add start polygon (a = 0L) 428 if(!bClosedRotation) 429 { 430 rSliceVector.push_back(Slice3D(aFront, basegfx::B3DHomMatrix())); 431 } 432 433 // create segments (a + 1 .. nSteps) 434 const double fStepSize(1.0 / (double)nSteps); 435 436 for(sal_uInt32 a(0L); a < nSteps; a++) 437 { 438 const double fStep((double)(a + 1L) * fStepSize); 439 basegfx::B2DPolyPolygon aNewPoly(bBackScale ? basegfx::tools::interpolate(aFront, aBack, fStep) : aFront); 440 basegfx::B3DHomMatrix aNewMat; 441 aNewMat.rotate(0.0, fRotation * fStep, 0.0); 442 rSliceVector.push_back(Slice3D(aNewPoly, aNewMat)); 443 } 444 445 if(bCloseBack) 446 { 447 rSliceVector.push_back(Slice3D(aOuterBack, aTransformBack, SLICETYPE3D_BACKCAP)); 448 } 449 } 450 } 451 createExtrudeSlices(Slice3DVector & rSliceVector,const basegfx::B2DPolyPolygon & rSource,double fBackScale,double fDiagonal,double fDepth,bool bCharacterMode,bool bCloseFront,bool bCloseBack)452 void createExtrudeSlices( 453 Slice3DVector& rSliceVector, 454 const basegfx::B2DPolyPolygon& rSource, 455 double fBackScale, 456 double fDiagonal, 457 double fDepth, 458 bool bCharacterMode, 459 bool bCloseFront, 460 bool bCloseBack) 461 { 462 if(basegfx::fTools::equalZero(fDepth)) 463 { 464 // no depth, just one plane 465 rSliceVector.push_back(Slice3D(rSource, basegfx::B3DHomMatrix())); 466 } 467 else 468 { 469 // there is depth, create Polygons for front,back and their default depth positions 470 basegfx::B2DPolyPolygon aFront(rSource); 471 basegfx::B2DPolyPolygon aBack(rSource); 472 const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0)); 473 double fZFront(fDepth); // default depth for aFront 474 double fZBack(0.0); // default depth for aBack 475 basegfx::B2DPolyPolygon aOuterBack; 476 477 if(bBackScale) 478 { 479 // avoid null zoom 480 if(basegfx::fTools::equalZero(fBackScale)) 481 { 482 fBackScale = 0.000001; 483 } 484 485 // aFront is scaled compared to aBack, create scaled version 486 aFront = impScalePolyPolygonOnCenter(aFront, fBackScale); 487 } 488 489 if(bCloseFront) 490 { 491 const double fOffset(fDepth * fDiagonal * 0.5); 492 fZFront = fDepth - fOffset; 493 basegfx::B2DPolyPolygon aOuterFront; 494 impGetOuterPolyPolygon(aFront, aOuterFront, fOffset, bCharacterMode); 495 basegfx::B3DHomMatrix aTransformFront; 496 aTransformFront.translate(0.0, 0.0, fDepth); 497 rSliceVector.push_back(Slice3D(aOuterFront, aTransformFront, SLICETYPE3D_FRONTCAP)); 498 } 499 500 if(bCloseBack) 501 { 502 const double fOffset(fDepth * fDiagonal * 0.5); 503 fZBack = fOffset; 504 impGetOuterPolyPolygon(aBack, aOuterBack, fOffset, bCharacterMode); 505 } 506 507 // add front and back polygons at evtl. changed depths 508 { 509 basegfx::B3DHomMatrix aTransformA, aTransformB; 510 511 aTransformA.translate(0.0, 0.0, fZFront); 512 rSliceVector.push_back(Slice3D(aFront, aTransformA)); 513 514 aTransformB.translate(0.0, 0.0, fZBack); 515 rSliceVector.push_back(Slice3D(aBack, aTransformB)); 516 } 517 518 if(bCloseBack) 519 { 520 rSliceVector.push_back(Slice3D(aOuterBack, basegfx::B3DHomMatrix(), SLICETYPE3D_BACKCAP)); 521 } 522 } 523 } 524 extractHorizontalLinesFromSlice(const Slice3DVector & rSliceVector,bool bCloseHorLines)525 basegfx::B3DPolyPolygon extractHorizontalLinesFromSlice(const Slice3DVector& rSliceVector, bool bCloseHorLines) 526 { 527 basegfx::B3DPolyPolygon aRetval; 528 const sal_uInt32 nNumSlices(rSliceVector.size()); 529 530 if(nNumSlices) 531 { 532 const sal_uInt32 nSlideSubPolygonCount(rSliceVector[0].getB3DPolyPolygon().count()); 533 534 for(sal_uInt32 b(0); b < nSlideSubPolygonCount; b++) 535 { 536 const sal_uInt32 nSubPolygonPointCount(rSliceVector[0].getB3DPolyPolygon().getB3DPolygon(b).count()); 537 538 for(sal_uInt32 c(0); c < nSubPolygonPointCount; c++) 539 { 540 basegfx::B3DPolygon aNew; 541 542 for(sal_uInt32 d(0); d < nNumSlices; d++) 543 { 544 const bool bSamePolygonCount(nSlideSubPolygonCount == rSliceVector[d].getB3DPolyPolygon().count()); 545 const bool bSamePointCount(nSubPolygonPointCount == rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).count()); 546 547 if(bSamePolygonCount && bSamePointCount) 548 { 549 aNew.append(rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).getB3DPoint(c)); 550 } 551 else 552 { 553 OSL_ENSURE(bSamePolygonCount, "Slice PolyPolygon with different Polygon count (!)"); 554 OSL_ENSURE(bSamePointCount, "Slice Polygon with different point count (!)"); 555 } 556 } 557 558 aNew.setClosed(bCloseHorLines); 559 aRetval.append(aNew); 560 } 561 } 562 } 563 564 return aRetval; 565 } 566 extractVerticalLinesFromSlice(const Slice3DVector & rSliceVector)567 basegfx::B3DPolyPolygon extractVerticalLinesFromSlice(const Slice3DVector& rSliceVector) 568 { 569 basegfx::B3DPolyPolygon aRetval; 570 const sal_uInt32 nNumSlices(rSliceVector.size()); 571 572 for(sal_uInt32 a(0L); a < nNumSlices; a++) 573 { 574 aRetval.append(rSliceVector[a].getB3DPolyPolygon()); 575 } 576 577 return aRetval; 578 } 579 extractPlanesFromSlice(::std::vector<basegfx::B3DPolyPolygon> & rFill,const Slice3DVector & rSliceVector,bool bCreateNormals,bool bSmoothHorizontalNormals,bool bSmoothNormals,bool bSmoothLids,bool bClosed,double fSmoothNormalsMix,double fSmoothLidsMix,bool bCreateTextureCoordinates,const basegfx::B2DHomMatrix & rTexTransform)580 void extractPlanesFromSlice( 581 ::std::vector< basegfx::B3DPolyPolygon >& rFill, 582 const Slice3DVector& rSliceVector, 583 bool bCreateNormals, 584 bool bSmoothHorizontalNormals, 585 bool bSmoothNormals, 586 bool bSmoothLids, 587 bool bClosed, 588 double fSmoothNormalsMix, 589 double fSmoothLidsMix, 590 bool bCreateTextureCoordinates, 591 const basegfx::B2DHomMatrix& rTexTransform) 592 { 593 const sal_uInt32 nNumSlices(rSliceVector.size()); 594 595 if(nNumSlices) 596 { 597 // common parameters 598 const sal_uInt32 nLoopCount(bClosed ? nNumSlices : nNumSlices - 1L); 599 basegfx::B3DPolyPolygon aEdgeRounding; 600 sal_uInt32 a; 601 602 // tetxture parameters 603 double fInvTexHeight(1.0); 604 double fTexHeightPos(0.0); 605 double fTexStart(0.0); 606 double fTexStop(1.0); 607 ::std::vector<double> aTexHeightArray; 608 basegfx::B3DRange aTexRangeFront; 609 basegfx::B3DRange aTexRangeBack; 610 611 if(bCreateTextureCoordinates) 612 { 613 aTexRangeFront = basegfx::tools::getRange(rSliceVector[0L].getB3DPolyPolygon()); 614 aTexRangeBack = basegfx::tools::getRange(rSliceVector[nNumSlices - 1L].getB3DPolyPolygon()); 615 616 if(aTexRangeBack.getDepth() > aTexRangeBack.getWidth()) 617 { 618 // last polygon is rotated so that depth is bigger than width, exchange X and Z 619 // for making applyDefaultTextureCoordinatesParallel use Z instead of X for 620 // horizontal texture coordinate 621 aTexRangeBack = basegfx::B3DRange( 622 aTexRangeBack.getMinZ(), aTexRangeBack.getMinY(), aTexRangeBack.getMinX(), 623 aTexRangeBack.getMaxZ(), aTexRangeBack.getMaxY(), aTexRangeBack.getMaxX()); 624 } 625 626 basegfx::B3DPoint aCenter(basegfx::tools::getRange(rSliceVector[0L].getB3DPolyPolygon()).getCenter()); 627 628 for(a = 0L; a < nLoopCount; a++) 629 { 630 const basegfx::B3DPoint aNextCenter(basegfx::tools::getRange(rSliceVector[(a + 1L) % nNumSlices].getB3DPolyPolygon()).getCenter()); 631 const double fLength(basegfx::B3DVector(aNextCenter - aCenter).getLength()); 632 aTexHeightArray.push_back(fLength); 633 aCenter = aNextCenter; 634 } 635 636 const double fTexHeight(::std::accumulate(aTexHeightArray.begin(), aTexHeightArray.end(), 0.0)); 637 638 if(!basegfx::fTools::equalZero(fTexHeight)) 639 { 640 fInvTexHeight = 1.0 / fTexHeight; 641 } 642 } 643 644 if(nLoopCount) 645 { 646 for(a = 0L; a < nLoopCount; a++) 647 { 648 const Slice3D& rSliceA(rSliceVector[a]); 649 const Slice3D& rSliceB(rSliceVector[(a + 1L) % nNumSlices]); 650 const bool bAcceptPair(SLICETYPE3D_REGULAR == rSliceA.getSliceType() && SLICETYPE3D_REGULAR == rSliceB.getSliceType()); 651 basegfx::B3DPolyPolygon aPolA(rSliceA.getB3DPolyPolygon()); 652 basegfx::B3DPolyPolygon aPolB(rSliceB.getB3DPolyPolygon()); 653 654 if(bAcceptPair) 655 { 656 if(bCreateNormals) 657 { 658 impCreateInBetweenNormals(aPolB, aPolA, bSmoothHorizontalNormals); 659 } 660 661 { 662 const sal_uInt32 nIndPrev((a + nNumSlices - 1L) % nNumSlices); 663 const Slice3D& rSlicePrev(rSliceVector[nIndPrev]); 664 basegfx::B3DPolyPolygon aPrev(rSlicePrev.getB3DPolyPolygon()); 665 basegfx::B3DPolyPolygon aPolAA(rSliceA.getB3DPolyPolygon()); 666 667 if(SLICETYPE3D_FRONTCAP == rSlicePrev.getSliceType()) 668 { 669 basegfx::B3DPolyPolygon aFront(rSlicePrev.getB3DPolyPolygon()); 670 const bool bHasSlant(aPolAA != aPrev); 671 672 if(bCreateTextureCoordinates) 673 { 674 aFront = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront); 675 } 676 677 if(bCreateNormals) 678 { 679 basegfx::B3DVector aNormal(0.0, 0.0, -1.0); 680 681 if(aFront.count()) 682 { 683 aNormal = -aFront.getB3DPolygon(0L).getNormal(); 684 } 685 686 impSetNormal(aFront, aNormal); 687 688 if(bHasSlant) 689 { 690 impCreateInBetweenNormals(aPolAA, aPrev, bSmoothHorizontalNormals); 691 692 if(bSmoothNormals) 693 { 694 // smooth and copy 695 impMixNormals(aPolA, aPolAA, fSmoothNormalsMix); 696 aPolAA = aPolA; 697 } 698 else 699 { 700 // take over from surface 701 aPolAA = aPolA; 702 } 703 704 if(bSmoothLids) 705 { 706 // smooth and copy 707 impMixNormals(aFront, aPrev, fSmoothLidsMix); 708 aPrev = aFront; 709 } 710 else 711 { 712 // take over from front 713 aPrev = aFront; 714 } 715 } 716 else 717 { 718 if(bSmoothNormals) 719 { 720 // smooth 721 impMixNormals(aPolA, aFront, fSmoothNormalsMix); 722 } 723 724 if(bSmoothLids) 725 { 726 // smooth and copy 727 impMixNormals(aFront, aPolA, fSmoothLidsMix); 728 aPolA = aFront; 729 } 730 } 731 } 732 733 if(bHasSlant) 734 { 735 if(bCreateTextureCoordinates) 736 { 737 fTexStart = fTexHeightPos * fInvTexHeight; 738 fTexStop = (fTexHeightPos - aTexHeightArray[(a + nLoopCount - 1L) % nLoopCount]) * fInvTexHeight; 739 } 740 741 impAddInBetweenFill(aEdgeRounding, aPolAA, aPrev, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates); 742 } 743 744 aFront.flip(); 745 rFill.push_back(aFront); 746 } 747 else 748 { 749 if(bCreateNormals && bSmoothNormals && (nIndPrev != a + 1L)) 750 { 751 impCreateInBetweenNormals(aPolAA, aPrev, bSmoothHorizontalNormals); 752 impMixNormals(aPolA, aPolAA, 0.5); 753 } 754 } 755 } 756 757 { 758 const sal_uInt32 nIndNext((a + 2L) % nNumSlices); 759 const Slice3D& rSliceNext(rSliceVector[nIndNext]); 760 basegfx::B3DPolyPolygon aNext(rSliceNext.getB3DPolyPolygon()); 761 basegfx::B3DPolyPolygon aPolBB(rSliceB.getB3DPolyPolygon()); 762 763 if(SLICETYPE3D_BACKCAP == rSliceNext.getSliceType()) 764 { 765 basegfx::B3DPolyPolygon aBack(rSliceNext.getB3DPolyPolygon()); 766 const bool bHasSlant(aPolBB != aNext); 767 768 if(bCreateTextureCoordinates) 769 { 770 aBack = basegfx::tools::applyDefaultTextureCoordinatesParallel(aBack, aTexRangeBack); 771 } 772 773 if(bCreateNormals) 774 { 775 const basegfx::B3DVector aNormal(aBack.count() ? aBack.getB3DPolygon(0L).getNormal() : basegfx::B3DVector(0.0, 0.0, 1.0)); 776 impSetNormal(aBack, aNormal); 777 778 if(bHasSlant) 779 { 780 impCreateInBetweenNormals(aNext, aPolBB, bSmoothHorizontalNormals); 781 782 if(bSmoothNormals) 783 { 784 // smooth and copy 785 impMixNormals(aPolB, aPolBB, fSmoothNormalsMix); 786 aPolBB = aPolB; 787 } 788 else 789 { 790 // take over from surface 791 aPolBB = aPolB; 792 } 793 794 if(bSmoothLids) 795 { 796 // smooth and copy 797 impMixNormals(aBack, aNext, fSmoothLidsMix); 798 aNext = aBack; 799 } 800 else 801 { 802 // take over from back 803 aNext = aBack; 804 } 805 } 806 else 807 { 808 if(bSmoothNormals) 809 { 810 // smooth 811 impMixNormals(aPolB, aBack, fSmoothNormalsMix); 812 } 813 814 if(bSmoothLids) 815 { 816 // smooth and copy 817 impMixNormals(aBack, aPolB, fSmoothLidsMix); 818 aPolB = aBack; 819 } 820 } 821 } 822 823 if(bHasSlant) 824 { 825 if(bCreateTextureCoordinates) 826 { 827 fTexStart = (fTexHeightPos + aTexHeightArray[a] + aTexHeightArray[(a + 1L) % nLoopCount]) * fInvTexHeight; 828 fTexStop = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight; 829 } 830 831 impAddInBetweenFill(aEdgeRounding, aNext, aPolBB, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates); 832 } 833 834 rFill.push_back(aBack); 835 } 836 else 837 { 838 if(bCreateNormals && bSmoothNormals && (nIndNext != a)) 839 { 840 impCreateInBetweenNormals(aNext, aPolBB, bSmoothHorizontalNormals); 841 impMixNormals(aPolB, aPolBB, 0.5); 842 } 843 } 844 } 845 846 if(bCreateTextureCoordinates) 847 { 848 fTexStart = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight; 849 fTexStop = fTexHeightPos * fInvTexHeight; 850 } 851 852 impAddInBetweenFill(aEdgeRounding, aPolB, aPolA, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates); 853 } 854 855 if(bCreateTextureCoordinates) 856 { 857 fTexHeightPos += aTexHeightArray[a]; 858 } 859 } 860 } 861 else 862 { 863 // no loop, but a single slice (1 == nNumSlices), create a filling from the single 864 // front plane 865 const Slice3D& rSlice(rSliceVector[0]); 866 basegfx::B3DPolyPolygon aFront(rSlice.getB3DPolyPolygon()); 867 868 if(bCreateTextureCoordinates) 869 { 870 aFront = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront); 871 } 872 873 if(bCreateNormals) 874 { 875 basegfx::B3DVector aNormal(0.0, 0.0, -1.0); 876 877 if(aFront.count()) 878 { 879 aNormal = -aFront.getB3DPolygon(0L).getNormal(); 880 } 881 882 impSetNormal(aFront, aNormal); 883 } 884 885 aFront.flip(); 886 rFill.push_back(aFront); 887 } 888 889 if(bCreateTextureCoordinates) 890 { 891 aEdgeRounding.transformTextureCoordiantes(rTexTransform); 892 } 893 894 for(a = 0L; a < aEdgeRounding.count(); a++) 895 { 896 rFill.push_back(basegfx::B3DPolyPolygon(aEdgeRounding.getB3DPolygon(a))); 897 } 898 } 899 } 900 createReducedOutlines(const geometry::ViewInformation3D & rViewInformation,const basegfx::B3DHomMatrix & rObjectTransform,const basegfx::B3DPolygon & rLoopA,const basegfx::B3DPolygon & rLoopB,basegfx::B3DPolyPolygon & rTarget)901 void createReducedOutlines( 902 const geometry::ViewInformation3D& rViewInformation, 903 const basegfx::B3DHomMatrix& rObjectTransform, 904 const basegfx::B3DPolygon& rLoopA, 905 const basegfx::B3DPolygon& rLoopB, 906 basegfx::B3DPolyPolygon& rTarget) 907 { 908 const sal_uInt32 nPointCount(rLoopA.count()); 909 910 // with idetic polygons there are no outlines 911 if(rLoopA != rLoopB) 912 { 913 if(nPointCount && nPointCount == rLoopB.count()) 914 { 915 const basegfx::B3DHomMatrix aObjectTransform(rViewInformation.getObjectToView() * rObjectTransform); 916 const basegfx::B2DPolygon a2DLoopA(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopA, aObjectTransform)); 917 const basegfx::B2DPolygon a2DLoopB(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopB, aObjectTransform)); 918 const basegfx::B2DPoint a2DCenterA(a2DLoopA.getB2DRange().getCenter()); 919 const basegfx::B2DPoint a2DCenterB(a2DLoopB.getB2DRange().getCenter()); 920 921 // without detectable Y-Axis there are no outlines 922 if(!a2DCenterA.equal(a2DCenterB)) 923 { 924 // search for outmost left and right inter-loop-edges which do not cut the loops 925 const basegfx::B2DPoint aCommonCenter(basegfx::average(a2DCenterA, a2DCenterB)); 926 const basegfx::B2DVector aAxisVector(a2DCenterA - a2DCenterB); 927 double fMaxLeft(0.0); 928 double fMaxRight(0.0); 929 sal_uInt32 nIndexLeft(0); 930 sal_uInt32 nIndexRight(0); 931 932 for(sal_uInt32 a(0); a < nPointCount; a++) 933 { 934 const basegfx::B2DPoint aStart(a2DLoopA.getB2DPoint(a)); 935 const basegfx::B2DPoint aEnd(a2DLoopB.getB2DPoint(a)); 936 const basegfx::B2DPoint aMiddle(basegfx::average(aStart, aEnd)); 937 938 if(!basegfx::tools::isInside(a2DLoopA, aMiddle)) 939 { 940 if(!basegfx::tools::isInside(a2DLoopB, aMiddle)) 941 { 942 if(!impHasCutWith(a2DLoopA, aStart, aEnd)) 943 { 944 if(!impHasCutWith(a2DLoopB, aStart, aEnd)) 945 { 946 const basegfx::B2DVector aCandidateVector(aMiddle - aCommonCenter); 947 const double fCross(aCandidateVector.cross(aAxisVector)); 948 const double fDistance(aCandidateVector.getLength()); 949 950 if(fCross > 0.0) 951 { 952 if(fDistance > fMaxLeft) 953 { 954 fMaxLeft = fDistance; 955 nIndexLeft = a; 956 } 957 } 958 else if(fCross < 0.0) 959 { 960 if(fDistance > fMaxRight) 961 { 962 fMaxRight = fDistance; 963 nIndexRight = a; 964 } 965 } 966 } 967 } 968 } 969 } 970 } 971 972 if(fMaxLeft != 0.0) 973 { 974 basegfx::B3DPolygon aToBeAdded; 975 aToBeAdded.append(rLoopA.getB3DPoint(nIndexLeft)); 976 aToBeAdded.append(rLoopB.getB3DPoint(nIndexLeft)); 977 rTarget.append(aToBeAdded); 978 } 979 980 if(fMaxRight != 0.0) 981 { 982 basegfx::B3DPolygon aToBeAdded; 983 aToBeAdded.append(rLoopA.getB3DPoint(nIndexRight)); 984 aToBeAdded.append(rLoopB.getB3DPoint(nIndexRight)); 985 rTarget.append(aToBeAdded); 986 } 987 } 988 } 989 } 990 } 991 992 } // end of namespace primitive3d 993 } // end of namespace drawinglayer 994 995 ////////////////////////////////////////////////////////////////////////////// 996 // eof 997