Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / drawinglayer / source / primitive3d / sdrextrudelathetools3d.cxx
bloba54a0d07b8b67921b1ae5f462a94e22d9db83361
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <drawinglayer/primitive3d/sdrextrudelathetools3d.hxx>
22 #include <osl/diagnose.h>
23 #include <basegfx/polygon/b2dpolypolygon.hxx>
24 #include <basegfx/range/b2drange.hxx>
25 #include <basegfx/polygon/b2dpolypolygontools.hxx>
26 #include <basegfx/matrix/b2dhommatrix.hxx>
27 #include <basegfx/point/b3dpoint.hxx>
28 #include <basegfx/polygon/b3dpolygon.hxx>
29 #include <basegfx/polygon/b3dpolygontools.hxx>
30 #include <basegfx/polygon/b3dpolypolygontools.hxx>
31 #include <basegfx/range/b3drange.hxx>
32 #include <basegfx/matrix/b3dhommatrix.hxx>
33 #include <basegfx/polygon/b2dpolygontools.hxx>
34 #include <drawinglayer/geometry/viewinformation3d.hxx>
35 #include <numeric>
38 // decomposition helpers for extrude/lathe (rotation) objects
40 namespace
43 // common helpers
45 basegfx::B2DPolyPolygon impScalePolyPolygonOnCenter(
46 const basegfx::B2DPolyPolygon& rSource,
47 double fScale)
49 basegfx::B2DPolyPolygon aRetval(rSource);
51 if(!basegfx::fTools::equalZero(fScale))
53 const basegfx::B2DRange aRange(basegfx::utils::getRange(rSource));
54 const basegfx::B2DPoint aCenter(aRange.getCenter());
55 basegfx::B2DHomMatrix aTrans;
57 aTrans.translate(-aCenter.getX(), -aCenter.getY());
58 aTrans.scale(fScale, fScale);
59 aTrans.translate(aCenter.getX(), aCenter.getY());
60 aRetval.transform(aTrans);
63 return aRetval;
66 void impGetOuterPolyPolygon(
67 basegfx::B2DPolyPolygon& rPolygon,
68 basegfx::B2DPolyPolygon& rOuterPolyPolygon,
69 double fOffset,
70 bool bCharacterMode)
72 rOuterPolyPolygon = rPolygon;
74 if(basegfx::fTools::more(fOffset, 0.0))
76 if(bCharacterMode)
78 // grow the outside polygon and scale all polygons to original size. This is done
79 // to avoid a shrink which potentially would lead to self-intersections, but changes
80 // the original polygon -> not a precision step, so e.g. not usable for charts
81 const basegfx::B2DRange aRange(basegfx::utils::getRange(rPolygon));
82 rPolygon = basegfx::utils::growInNormalDirection(rPolygon, fOffset);
83 const basegfx::B2DRange aGrownRange(basegfx::utils::getRange(rPolygon));
84 const double fScaleX(basegfx::fTools::equalZero(aGrownRange.getWidth()) ? 1.0 : aRange.getWidth() / aGrownRange.getWidth());
85 const double fScaleY(basegfx::fTools::equalZero(aGrownRange.getHeight())? 1.0 : aRange.getHeight() / aGrownRange.getHeight());
86 basegfx::B2DHomMatrix aScaleTrans;
88 aScaleTrans.translate(-aGrownRange.getMinX(), -aGrownRange.getMinY());
89 aScaleTrans.scale(fScaleX, fScaleY);
90 aScaleTrans.translate(aRange.getMinX(), aRange.getMinY());
91 rPolygon.transform(aScaleTrans);
92 rOuterPolyPolygon.transform(aScaleTrans);
94 else
96 // use more precision, shrink the outer polygons. Since this may lead to self-intersections,
97 // some kind of correction should be applied here after that step
98 rOuterPolyPolygon = basegfx::utils::growInNormalDirection(rPolygon, -fOffset);
99 // basegfx::utils::correctGrowShrinkPolygonPair(rPolygon, rOuterPolyPolygon);
104 void impAddInBetweenFill(
105 basegfx::B3DPolyPolygon& rTarget,
106 const basegfx::B3DPolyPolygon& rPolA,
107 const basegfx::B3DPolyPolygon& rPolB,
108 double fTexVerStart,
109 double fTexVerStop,
110 bool bCreateNormals,
111 bool bCreateTextureCoordinates)
113 OSL_ENSURE(rPolA.count() == rPolB.count(), "impAddInBetweenFill: unequally sized polygons (!)");
114 const sal_uInt32 nPolygonCount(std::min(rPolA.count(), rPolB.count()));
116 for(sal_uInt32 a(0); a < nPolygonCount; a++)
118 const basegfx::B3DPolygon& aSubA(rPolA.getB3DPolygon(a));
119 const basegfx::B3DPolygon& aSubB(rPolB.getB3DPolygon(a));
120 OSL_ENSURE(aSubA.count() == aSubB.count(), "impAddInBetweenFill: unequally sized polygons (!)");
121 const sal_uInt32 nPointCount(std::min(aSubA.count(), aSubB.count()));
123 if(nPointCount)
125 const sal_uInt32 nEdgeCount(aSubA.isClosed() ? nPointCount : nPointCount - 1);
126 double fTexHorMultiplicatorA(0.0), fTexHorMultiplicatorB(0.0);
127 double fPolygonPosA(0.0), fPolygonPosB(0.0);
129 if(bCreateTextureCoordinates)
131 const double fPolygonLengthA(basegfx::utils::getLength(aSubA));
132 fTexHorMultiplicatorA = basegfx::fTools::equalZero(fPolygonLengthA) ? 1.0 : 1.0 / fPolygonLengthA;
134 const double fPolygonLengthB(basegfx::utils::getLength(aSubB));
135 fTexHorMultiplicatorB = basegfx::fTools::equalZero(fPolygonLengthB) ? 1.0 : 1.0 / fPolygonLengthB;
138 for(sal_uInt32 b(0); b < nEdgeCount; b++)
140 const sal_uInt32 nIndexA(b);
141 const sal_uInt32 nIndexB((b + 1) % nPointCount);
143 const basegfx::B3DPoint aStartA(aSubA.getB3DPoint(nIndexA));
144 const basegfx::B3DPoint aEndA(aSubA.getB3DPoint(nIndexB));
145 const basegfx::B3DPoint aStartB(aSubB.getB3DPoint(nIndexA));
146 const basegfx::B3DPoint aEndB(aSubB.getB3DPoint(nIndexB));
148 basegfx::B3DPolygon aNew;
149 aNew.setClosed(true);
151 aNew.append(aStartA);
152 aNew.append(aStartB);
153 aNew.append(aEndB);
154 aNew.append(aEndA);
156 if(bCreateNormals)
158 aNew.setNormal(0, aSubA.getNormal(nIndexA));
159 aNew.setNormal(1, aSubB.getNormal(nIndexA));
160 aNew.setNormal(2, aSubB.getNormal(nIndexB));
161 aNew.setNormal(3, aSubA.getNormal(nIndexB));
164 if(bCreateTextureCoordinates)
166 const double fRelTexAL(fPolygonPosA * fTexHorMultiplicatorA);
167 const double fEdgeLengthA(basegfx::B3DVector(aEndA - aStartA).getLength());
168 fPolygonPosA += fEdgeLengthA;
169 const double fRelTexAR(fPolygonPosA * fTexHorMultiplicatorA);
171 const double fRelTexBL(fPolygonPosB * fTexHorMultiplicatorB);
172 const double fEdgeLengthB(basegfx::B3DVector(aEndB - aStartB).getLength());
173 fPolygonPosB += fEdgeLengthB;
174 const double fRelTexBR(fPolygonPosB * fTexHorMultiplicatorB);
176 aNew.setTextureCoordinate(0, basegfx::B2DPoint(fRelTexAL, fTexVerStart));
177 aNew.setTextureCoordinate(1, basegfx::B2DPoint(fRelTexBL, fTexVerStop));
178 aNew.setTextureCoordinate(2, basegfx::B2DPoint(fRelTexBR, fTexVerStop));
179 aNew.setTextureCoordinate(3, basegfx::B2DPoint(fRelTexAR, fTexVerStart));
182 rTarget.append(aNew);
188 void impSetNormal(
189 basegfx::B3DPolyPolygon& rCandidate,
190 const basegfx::B3DVector& rNormal)
192 for(sal_uInt32 a(0); a < rCandidate.count(); a++)
194 basegfx::B3DPolygon aSub(rCandidate.getB3DPolygon(a));
196 for(sal_uInt32 b(0); b < aSub.count(); b++)
198 aSub.setNormal(b, rNormal);
201 rCandidate.setB3DPolygon(a, aSub);
205 void impCreateInBetweenNormals(
206 basegfx::B3DPolyPolygon& rPolA,
207 basegfx::B3DPolyPolygon& rPolB)
209 OSL_ENSURE(rPolA.count() == rPolB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
210 const sal_uInt32 nPolygonCount(std::min(rPolA.count(), rPolB.count()));
212 for(sal_uInt32 a(0); a < nPolygonCount; a++)
214 basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a));
215 basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a));
216 OSL_ENSURE(aSubA.count() == aSubB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
217 const sal_uInt32 nPointCount(std::min(aSubA.count(), aSubB.count()));
219 if(nPointCount)
221 basegfx::B3DPoint aPrevA(aSubA.getB3DPoint(nPointCount - 1));
222 basegfx::B3DPoint aCurrA(aSubA.getB3DPoint(0));
223 const bool bClosed(aSubA.isClosed());
225 for(sal_uInt32 b(0); b < nPointCount; b++)
227 const sal_uInt32 nIndNext((b + 1) % nPointCount);
228 const basegfx::B3DPoint aNextA(aSubA.getB3DPoint(nIndNext));
229 const basegfx::B3DPoint aCurrB(aSubB.getB3DPoint(b));
231 // vector to back
232 basegfx::B3DVector aDepth(aCurrB - aCurrA);
233 aDepth.normalize();
235 if(aDepth.equalZero())
237 // no difference, try to get depth from next point
238 const basegfx::B3DPoint aNextB(aSubB.getB3DPoint(nIndNext));
239 aDepth = aNextB - aNextA;
240 aDepth.normalize();
243 // vector to left (correct for non-closed lines)
244 const bool bFirstAndNotClosed(!bClosed && 0 == b);
245 basegfx::B3DVector aLeft(bFirstAndNotClosed ? aCurrA - aNextA : aPrevA - aCurrA);
246 aLeft.normalize();
248 // create left normal
249 const basegfx::B3DVector aNormalLeft(aDepth.getPerpendicular(aLeft));
251 // smooth horizontal normals
253 // vector to right (correct for non-closed lines)
254 const bool bLastAndNotClosed(!bClosed && b + 1 == nPointCount);
255 basegfx::B3DVector aRight(bLastAndNotClosed ? aCurrA - aPrevA : aNextA - aCurrA);
256 aRight.normalize();
258 // create right normal
259 const basegfx::B3DVector aNormalRight(aRight.getPerpendicular(aDepth));
261 // create smoothed in-between normal
262 basegfx::B3DVector aNewNormal(aNormalLeft + aNormalRight);
263 aNewNormal.normalize();
265 // set as new normal at polygons
266 aSubA.setNormal(b, aNewNormal);
267 aSubB.setNormal(b, aNewNormal);
270 // prepare next step
271 aPrevA = aCurrA;
272 aCurrA = aNextA;
275 rPolA.setB3DPolygon(a, aSubA);
276 rPolB.setB3DPolygon(a, aSubB);
281 void impMixNormals(
282 basegfx::B3DPolyPolygon& rPolA,
283 const basegfx::B3DPolyPolygon& rPolB,
284 double fWeightA)
286 const double fWeightB(1.0 - fWeightA);
287 OSL_ENSURE(rPolA.count() == rPolB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
288 const sal_uInt32 nPolygonCount(std::min(rPolA.count(), rPolB.count()));
290 for(sal_uInt32 a(0); a < nPolygonCount; a++)
292 basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a));
293 const basegfx::B3DPolygon& aSubB(rPolB.getB3DPolygon(a));
294 OSL_ENSURE(aSubA.count() == aSubB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
295 const sal_uInt32 nPointCount(std::min(aSubA.count(), aSubB.count()));
297 for(sal_uInt32 b(0); b < nPointCount; b++)
299 const basegfx::B3DVector aVA(aSubA.getNormal(b) * fWeightA);
300 const basegfx::B3DVector aVB(aSubB.getNormal(b) * fWeightB);
301 basegfx::B3DVector aVNew(aVA + aVB);
302 aVNew.normalize();
303 aSubA.setNormal(b, aVNew);
306 rPolA.setB3DPolygon(a, aSubA);
310 bool impHasCutWith(const basegfx::B2DPolygon& rPoly, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd)
312 // polygon is closed, one of the points is a member
313 const sal_uInt32 nPointCount(rPoly.count());
315 if(nPointCount)
317 basegfx::B2DPoint aCurrent(rPoly.getB2DPoint(0));
318 const basegfx::B2DVector aVector(rEnd - rStart);
320 for(sal_uInt32 a(0); a < nPointCount; a++)
322 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
323 const basegfx::B2DPoint aNext(rPoly.getB2DPoint(nNextIndex));
324 const basegfx::B2DVector aEdgeVector(aNext - aCurrent);
326 if(basegfx::utils::findCut(
327 rStart, aVector,
328 aCurrent, aEdgeVector) != CutFlagValue::NONE)
330 return true;
333 aCurrent = aNext;
337 return false;
339 } // end of anonymous namespace
342 namespace drawinglayer
344 namespace primitive3d
346 void createLatheSlices(
347 Slice3DVector& rSliceVector,
348 const basegfx::B2DPolyPolygon& rSource,
349 double fBackScale,
350 double fDiagonal,
351 double fRotation,
352 sal_uInt32 nSteps,
353 bool bCharacterMode,
354 bool bCloseFront,
355 bool bCloseBack)
357 if(basegfx::fTools::equalZero(fRotation) || 0 == nSteps)
359 // no rotation or no steps, just one plane
360 rSliceVector.emplace_back(rSource, basegfx::B3DHomMatrix());
362 else
364 const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0));
365 const bool bClosedRotation(!bBackScale && basegfx::fTools::equal(fRotation, F_2PI));
366 basegfx::B2DPolyPolygon aFront(rSource);
367 basegfx::B2DPolyPolygon aBack(rSource);
368 basegfx::B3DHomMatrix aTransformBack;
369 basegfx::B2DPolyPolygon aOuterBack;
371 if(bClosedRotation)
373 bCloseFront = bCloseBack = false;
376 if(bBackScale)
378 // avoid null zoom
379 if(basegfx::fTools::equalZero(fBackScale))
381 fBackScale = 0.000001;
384 // back is scaled compared to front, create scaled version
385 aBack = impScalePolyPolygonOnCenter(aBack, fBackScale);
388 if(bCloseFront || bCloseBack)
390 const basegfx::B2DRange aBaseRange(basegfx::utils::getRange(aFront));
391 const double fOuterLength(aBaseRange.getMaxX() * fRotation);
392 const double fInnerLength(aBaseRange.getMinX() * fRotation);
393 const double fAverageLength((fOuterLength + fInnerLength) * 0.5);
395 if(bCloseFront)
397 const double fOffsetLen((fAverageLength / 12.0) * fDiagonal);
398 basegfx::B2DPolyPolygon aOuterFront;
399 impGetOuterPolyPolygon(aFront, aOuterFront, fOffsetLen, bCharacterMode);
400 basegfx::B3DHomMatrix aTransform;
401 aTransform.translate(0.0, 0.0, fOffsetLen);
402 rSliceVector.emplace_back(aOuterFront, aTransform, SLICETYPE3D_FRONTCAP);
405 if(bCloseBack)
407 const double fOffsetLen((fAverageLength / 12.0) * fDiagonal);
408 impGetOuterPolyPolygon(aBack, aOuterBack, fOffsetLen, bCharacterMode);
409 aTransformBack.translate(0.0, 0.0, -fOffsetLen);
410 aTransformBack.rotate(0.0, fRotation, 0.0);
414 // add start polygon (a = 0)
415 if(!bClosedRotation)
417 rSliceVector.emplace_back(aFront, basegfx::B3DHomMatrix());
420 // create segments (a + 1 .. nSteps)
421 const double fStepSize(1.0 / static_cast<double>(nSteps));
423 for(sal_uInt32 a(0); a < nSteps; a++)
425 const double fStep(static_cast<double>(a + 1) * fStepSize);
426 basegfx::B2DPolyPolygon aNewPoly(bBackScale ? basegfx::utils::interpolate(aFront, aBack, fStep) : aFront);
427 basegfx::B3DHomMatrix aNewMat;
428 aNewMat.rotate(0.0, fRotation * fStep, 0.0);
429 rSliceVector.emplace_back(aNewPoly, aNewMat);
432 if(bCloseBack)
434 rSliceVector.emplace_back(aOuterBack, aTransformBack, SLICETYPE3D_BACKCAP);
439 void createExtrudeSlices(
440 Slice3DVector& rSliceVector,
441 const basegfx::B2DPolyPolygon& rSource,
442 double fBackScale,
443 double fDiagonal,
444 double fDepth,
445 bool bCharacterMode,
446 bool bCloseFront,
447 bool bCloseBack)
449 if(basegfx::fTools::equalZero(fDepth))
451 // no depth, just one plane
452 rSliceVector.emplace_back(rSource, basegfx::B3DHomMatrix());
454 else
456 // there is depth, create Polygons for front,back and their default depth positions
457 basegfx::B2DPolyPolygon aFront(rSource);
458 basegfx::B2DPolyPolygon aBack(rSource);
459 const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0));
460 double fZFront(fDepth); // default depth for aFront
461 double fZBack(0.0); // default depth for aBack
462 basegfx::B2DPolyPolygon aOuterBack;
464 if(bBackScale)
466 // avoid null zoom
467 if(basegfx::fTools::equalZero(fBackScale))
469 fBackScale = 0.000001;
472 // aFront is scaled compared to aBack, create scaled version
473 aFront = impScalePolyPolygonOnCenter(aFront, fBackScale);
476 if(bCloseFront)
478 const double fOffset(fDepth * fDiagonal * 0.5);
479 fZFront = fDepth - fOffset;
480 basegfx::B2DPolyPolygon aOuterFront;
481 impGetOuterPolyPolygon(aFront, aOuterFront, fOffset, bCharacterMode);
482 basegfx::B3DHomMatrix aTransformFront;
483 aTransformFront.translate(0.0, 0.0, fDepth);
484 rSliceVector.emplace_back(aOuterFront, aTransformFront, SLICETYPE3D_FRONTCAP);
487 if(bCloseBack)
489 const double fOffset(fDepth * fDiagonal * 0.5);
490 fZBack = fOffset;
491 impGetOuterPolyPolygon(aBack, aOuterBack, fOffset, bCharacterMode);
494 // add front and back polygons at evtl. changed depths
496 basegfx::B3DHomMatrix aTransformA, aTransformB;
498 aTransformA.translate(0.0, 0.0, fZFront);
499 rSliceVector.emplace_back(aFront, aTransformA);
501 aTransformB.translate(0.0, 0.0, fZBack);
502 rSliceVector.emplace_back(aBack, aTransformB);
505 if(bCloseBack)
507 rSliceVector.emplace_back(aOuterBack, basegfx::B3DHomMatrix(), SLICETYPE3D_BACKCAP);
512 basegfx::B3DPolyPolygon extractHorizontalLinesFromSlice(const Slice3DVector& rSliceVector, bool bCloseHorLines)
514 basegfx::B3DPolyPolygon aRetval;
515 const sal_uInt32 nNumSlices(rSliceVector.size());
517 if(nNumSlices)
519 const sal_uInt32 nSlideSubPolygonCount(rSliceVector[0].getB3DPolyPolygon().count());
521 for(sal_uInt32 b(0); b < nSlideSubPolygonCount; b++)
523 const sal_uInt32 nSubPolygonPointCount(rSliceVector[0].getB3DPolyPolygon().getB3DPolygon(b).count());
525 for(sal_uInt32 c(0); c < nSubPolygonPointCount; c++)
527 basegfx::B3DPolygon aNew;
529 for(sal_uInt32 d(0); d < nNumSlices; d++)
531 const bool bSamePolygonCount(nSlideSubPolygonCount == rSliceVector[d].getB3DPolyPolygon().count());
532 const bool bSamePointCount(nSubPolygonPointCount == rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).count());
534 if(bSamePolygonCount && bSamePointCount)
536 aNew.append(rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).getB3DPoint(c));
538 else
540 OSL_ENSURE(bSamePolygonCount, "Slice tools::PolyPolygon with different Polygon count (!)");
541 OSL_ENSURE(bSamePointCount, "Slice Polygon with different point count (!)");
545 aNew.setClosed(bCloseHorLines);
546 aRetval.append(aNew);
551 return aRetval;
554 basegfx::B3DPolyPolygon extractVerticalLinesFromSlice(const Slice3DVector& rSliceVector)
556 basegfx::B3DPolyPolygon aRetval;
557 const sal_uInt32 nNumSlices(rSliceVector.size());
559 for(sal_uInt32 a(0); a < nNumSlices; a++)
561 aRetval.append(rSliceVector[a].getB3DPolyPolygon());
564 return aRetval;
567 void extractPlanesFromSlice(
568 std::vector< basegfx::B3DPolyPolygon >& rFill,
569 const Slice3DVector& rSliceVector,
570 bool bCreateNormals,
571 bool bSmoothNormals,
572 bool bSmoothLids,
573 bool bClosed,
574 double fSmoothNormalsMix,
575 double fSmoothLidsMix,
576 bool bCreateTextureCoordinates,
577 const basegfx::B2DHomMatrix& rTexTransform)
579 const sal_uInt32 nNumSlices(rSliceVector.size());
581 if(nNumSlices)
583 // common parameters
584 const sal_uInt32 nLoopCount(bClosed ? nNumSlices : nNumSlices - 1);
585 basegfx::B3DPolyPolygon aEdgeRounding;
586 sal_uInt32 a;
588 // texture parameters
589 double fInvTexHeight(1.0);
590 std::vector<double> aTexHeightArray;
591 basegfx::B3DRange aTexRangeFront;
592 basegfx::B3DRange aTexRangeBack;
594 if(bCreateTextureCoordinates)
596 aTexRangeFront = basegfx::utils::getRange(rSliceVector[0].getB3DPolyPolygon());
597 aTexRangeBack = basegfx::utils::getRange(rSliceVector[nNumSlices - 1].getB3DPolyPolygon());
599 if(aTexRangeBack.getDepth() > aTexRangeBack.getWidth())
601 // last polygon is rotated so that depth is bigger than width, exchange X and Z
602 // for making applyDefaultTextureCoordinatesParallel use Z instead of X for
603 // horizontal texture coordinate
604 aTexRangeBack = basegfx::B3DRange(
605 aTexRangeBack.getMinZ(), aTexRangeBack.getMinY(), aTexRangeBack.getMinX(),
606 aTexRangeBack.getMaxZ(), aTexRangeBack.getMaxY(), aTexRangeBack.getMaxX());
609 basegfx::B3DPoint aCenter(basegfx::utils::getRange(rSliceVector[0].getB3DPolyPolygon()).getCenter());
611 for(a = 0; a < nLoopCount; a++)
613 const basegfx::B3DPoint aNextCenter(basegfx::utils::getRange(rSliceVector[(a + 1) % nNumSlices].getB3DPolyPolygon()).getCenter());
614 const double fLength(basegfx::B3DVector(aNextCenter - aCenter).getLength());
615 aTexHeightArray.push_back(fLength);
616 aCenter = aNextCenter;
619 const double fTexHeight(std::accumulate(aTexHeightArray.begin(), aTexHeightArray.end(), 0.0));
621 if(!basegfx::fTools::equalZero(fTexHeight))
623 fInvTexHeight = 1.0 / fTexHeight;
627 if(nLoopCount)
629 double fTexHeightPos(0.0);
630 for(a = 0; a < nLoopCount; a++)
632 const Slice3D& rSliceA(rSliceVector[a]);
633 const Slice3D& rSliceB(rSliceVector[(a + 1) % nNumSlices]);
634 const bool bAcceptPair(SLICETYPE3D_REGULAR == rSliceA.getSliceType() && SLICETYPE3D_REGULAR == rSliceB.getSliceType());
635 basegfx::B3DPolyPolygon aPolA(rSliceA.getB3DPolyPolygon());
636 basegfx::B3DPolyPolygon aPolB(rSliceB.getB3DPolyPolygon());
638 if(bAcceptPair)
640 if(bCreateNormals)
642 impCreateInBetweenNormals(aPolB, aPolA);
646 const sal_uInt32 nIndPrev((a + nNumSlices - 1) % nNumSlices);
647 const Slice3D& rSlicePrev(rSliceVector[nIndPrev]);
648 basegfx::B3DPolyPolygon aPrev(rSlicePrev.getB3DPolyPolygon());
649 basegfx::B3DPolyPolygon aPolAA(rSliceA.getB3DPolyPolygon());
651 if(SLICETYPE3D_FRONTCAP == rSlicePrev.getSliceType())
653 basegfx::B3DPolyPolygon aFront(rSlicePrev.getB3DPolyPolygon());
654 const bool bHasSlant(aPolAA != aPrev);
656 if(bCreateTextureCoordinates)
658 aFront = basegfx::utils::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront);
661 if(bCreateNormals)
663 basegfx::B3DVector aNormal(0.0, 0.0, -1.0);
665 if(aFront.count())
667 aNormal = -aFront.getB3DPolygon(0).getNormal();
670 impSetNormal(aFront, aNormal);
672 if(bHasSlant)
674 impCreateInBetweenNormals(aPolAA, aPrev);
676 if(bSmoothNormals)
678 // smooth and copy
679 impMixNormals(aPolA, aPolAA, fSmoothNormalsMix);
680 aPolAA = aPolA;
682 else
684 // take over from surface
685 aPolAA = aPolA;
688 if(bSmoothLids)
690 // smooth and copy
691 impMixNormals(aFront, aPrev, fSmoothLidsMix);
692 aPrev = aFront;
694 else
696 // take over from front
697 aPrev = aFront;
700 else
702 if(bSmoothNormals)
704 // smooth
705 impMixNormals(aPolA, aFront, fSmoothNormalsMix);
708 if(bSmoothLids)
710 // smooth and copy
711 impMixNormals(aFront, aPolA, fSmoothLidsMix);
712 aPolA = aFront;
717 if(bHasSlant)
719 double fTexStart{};
720 double fTexStop{};
721 if(bCreateTextureCoordinates)
723 fTexStart = fTexHeightPos * fInvTexHeight;
724 fTexStop = (fTexHeightPos - aTexHeightArray[(a + nLoopCount - 1) % nLoopCount]) * fInvTexHeight;
727 impAddInBetweenFill(aEdgeRounding, aPolAA, aPrev, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates);
730 aFront.flip();
731 rFill.push_back(aFront);
733 else
735 if(bCreateNormals && bSmoothNormals && (nIndPrev != a + 1))
737 impCreateInBetweenNormals(aPolAA, aPrev);
738 impMixNormals(aPolA, aPolAA, 0.5);
744 const sal_uInt32 nIndNext((a + 2) % nNumSlices);
745 const Slice3D& rSliceNext(rSliceVector[nIndNext]);
746 basegfx::B3DPolyPolygon aNext(rSliceNext.getB3DPolyPolygon());
747 basegfx::B3DPolyPolygon aPolBB(rSliceB.getB3DPolyPolygon());
749 if(SLICETYPE3D_BACKCAP == rSliceNext.getSliceType())
751 basegfx::B3DPolyPolygon aBack(rSliceNext.getB3DPolyPolygon());
752 const bool bHasSlant(aPolBB != aNext);
754 if(bCreateTextureCoordinates)
756 aBack = basegfx::utils::applyDefaultTextureCoordinatesParallel(aBack, aTexRangeBack);
759 if(bCreateNormals)
761 const basegfx::B3DVector aNormal(aBack.count() ? aBack.getB3DPolygon(0).getNormal() : basegfx::B3DVector(0.0, 0.0, 1.0));
762 impSetNormal(aBack, aNormal);
764 if(bHasSlant)
766 impCreateInBetweenNormals(aNext, aPolBB);
768 if(bSmoothNormals)
770 // smooth and copy
771 impMixNormals(aPolB, aPolBB, fSmoothNormalsMix);
772 aPolBB = aPolB;
774 else
776 // take over from surface
777 aPolBB = aPolB;
780 if(bSmoothLids)
782 // smooth and copy
783 impMixNormals(aBack, aNext, fSmoothLidsMix);
784 aNext = aBack;
786 else
788 // take over from back
789 aNext = aBack;
792 else
794 if(bSmoothNormals)
796 // smooth
797 impMixNormals(aPolB, aBack, fSmoothNormalsMix);
800 if(bSmoothLids)
802 // smooth and copy
803 impMixNormals(aBack, aPolB, fSmoothLidsMix);
804 aPolB = aBack;
809 if(bHasSlant)
811 double fTexStart{};
812 double fTexStop{};
813 if(bCreateTextureCoordinates)
815 fTexStart = (fTexHeightPos + aTexHeightArray[a] + aTexHeightArray[(a + 1) % nLoopCount]) * fInvTexHeight;
816 fTexStop = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight;
819 impAddInBetweenFill(aEdgeRounding, aNext, aPolBB, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates);
822 rFill.push_back(aBack);
824 else
826 if(bCreateNormals && bSmoothNormals && (nIndNext != a))
828 impCreateInBetweenNormals(aNext, aPolBB);
829 impMixNormals(aPolB, aPolBB, 0.5);
834 double fTexStart{};
835 double fTexStop{};
836 if(bCreateTextureCoordinates)
838 fTexStart = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight;
839 fTexStop = fTexHeightPos * fInvTexHeight;
842 impAddInBetweenFill(aEdgeRounding, aPolB, aPolA, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates);
845 if(bCreateTextureCoordinates)
847 fTexHeightPos += aTexHeightArray[a];
851 else
853 // no loop, but a single slice (1 == nNumSlices), create a filling from the single
854 // front plane
855 const Slice3D& rSlice(rSliceVector[0]);
856 basegfx::B3DPolyPolygon aFront(rSlice.getB3DPolyPolygon());
858 if(bCreateTextureCoordinates)
860 aFront = basegfx::utils::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront);
863 if(bCreateNormals)
865 basegfx::B3DVector aNormal(0.0, 0.0, -1.0);
867 if(aFront.count())
869 aNormal = -aFront.getB3DPolygon(0).getNormal();
872 impSetNormal(aFront, aNormal);
875 aFront.flip();
876 rFill.push_back(aFront);
879 if(bCreateTextureCoordinates)
881 aEdgeRounding.transformTextureCoordinates(rTexTransform);
884 for(a = 0; a < aEdgeRounding.count(); a++)
886 rFill.emplace_back(aEdgeRounding.getB3DPolygon(a));
891 void createReducedOutlines(
892 const geometry::ViewInformation3D& rViewInformation,
893 const basegfx::B3DHomMatrix& rObjectTransform,
894 const basegfx::B3DPolygon& rLoopA,
895 const basegfx::B3DPolygon& rLoopB,
896 basegfx::B3DPolyPolygon& rTarget)
898 const sal_uInt32 nPointCount(rLoopA.count());
900 // with identical polygons there are no outlines
901 if(rLoopA != rLoopB)
903 if(nPointCount && nPointCount == rLoopB.count())
905 const basegfx::B3DHomMatrix aObjectTransform(rViewInformation.getObjectToView() * rObjectTransform);
906 const basegfx::B2DPolygon a2DLoopA(basegfx::utils::createB2DPolygonFromB3DPolygon(rLoopA, aObjectTransform));
907 const basegfx::B2DPolygon a2DLoopB(basegfx::utils::createB2DPolygonFromB3DPolygon(rLoopB, aObjectTransform));
908 const basegfx::B2DPoint a2DCenterA(a2DLoopA.getB2DRange().getCenter());
909 const basegfx::B2DPoint a2DCenterB(a2DLoopB.getB2DRange().getCenter());
911 // without detectable Y-Axis there are no outlines
912 if(!a2DCenterA.equal(a2DCenterB))
914 // search for outmost left and right inter-loop-edges which do not cut the loops
915 const basegfx::B2DPoint aCommonCenter(basegfx::average(a2DCenterA, a2DCenterB));
916 const basegfx::B2DVector aAxisVector(a2DCenterA - a2DCenterB);
917 double fMaxLeft(0.0);
918 double fMaxRight(0.0);
919 sal_uInt32 nIndexLeft(0);
920 sal_uInt32 nIndexRight(0);
922 for(sal_uInt32 a(0); a < nPointCount; a++)
924 const basegfx::B2DPoint aStart(a2DLoopA.getB2DPoint(a));
925 const basegfx::B2DPoint aEnd(a2DLoopB.getB2DPoint(a));
926 const basegfx::B2DPoint aMiddle(basegfx::average(aStart, aEnd));
928 if(!basegfx::utils::isInside(a2DLoopA, aMiddle))
930 if(!basegfx::utils::isInside(a2DLoopB, aMiddle))
932 if(!impHasCutWith(a2DLoopA, aStart, aEnd))
934 if(!impHasCutWith(a2DLoopB, aStart, aEnd))
936 const basegfx::B2DVector aCandidateVector(aMiddle - aCommonCenter);
937 const double fCross(aCandidateVector.cross(aAxisVector));
938 const double fDistance(aCandidateVector.getLength());
940 if(fCross > 0.0)
942 if(fDistance > fMaxLeft)
944 fMaxLeft = fDistance;
945 nIndexLeft = a;
948 else if(fCross < 0.0)
950 if(fDistance > fMaxRight)
952 fMaxRight = fDistance;
953 nIndexRight = a;
962 if(fMaxLeft != 0.0)
964 basegfx::B3DPolygon aToBeAdded;
965 aToBeAdded.append(rLoopA.getB3DPoint(nIndexLeft));
966 aToBeAdded.append(rLoopB.getB3DPoint(nIndexLeft));
967 rTarget.append(aToBeAdded);
970 if(fMaxRight != 0.0)
972 basegfx::B3DPolygon aToBeAdded;
973 aToBeAdded.append(rLoopA.getB3DPoint(nIndexRight));
974 aToBeAdded.append(rLoopB.getB3DPoint(nIndexRight));
975 rTarget.append(aToBeAdded);
982 } // end of namespace primitive3d
983 } // end of namespace drawinglayer
985 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */