nss: upgrade to release 3.73
[LibreOffice.git] / drawinglayer / source / primitive3d / sdrextrudelathetools3d.cxx
blobafe030ac77b976f187dcae9aab03afeb7739b62f
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))
75 return;
77 if(bCharacterMode)
79 // grow the outside polygon and scale all polygons to original size. This is done
80 // to avoid a shrink which potentially would lead to self-intersections, but changes
81 // the original polygon -> not a precision step, so e.g. not usable for charts
82 const basegfx::B2DRange aRange(basegfx::utils::getRange(rPolygon));
83 rPolygon = basegfx::utils::growInNormalDirection(rPolygon, fOffset);
84 const basegfx::B2DRange aGrownRange(basegfx::utils::getRange(rPolygon));
85 const double fScaleX(basegfx::fTools::equalZero(aGrownRange.getWidth()) ? 1.0 : aRange.getWidth() / aGrownRange.getWidth());
86 const double fScaleY(basegfx::fTools::equalZero(aGrownRange.getHeight())? 1.0 : aRange.getHeight() / aGrownRange.getHeight());
87 basegfx::B2DHomMatrix aScaleTrans;
89 aScaleTrans.translate(-aGrownRange.getMinX(), -aGrownRange.getMinY());
90 aScaleTrans.scale(fScaleX, fScaleY);
91 aScaleTrans.translate(aRange.getMinX(), aRange.getMinY());
92 rPolygon.transform(aScaleTrans);
93 rOuterPolyPolygon.transform(aScaleTrans);
95 else
97 // use more precision, shrink the outer polygons. Since this may lead to self-intersections,
98 // some kind of correction should be applied here after that step
99 rOuterPolyPolygon = basegfx::utils::growInNormalDirection(rPolygon, -fOffset);
100 // 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::primitive3d
344 void createLatheSlices(
345 Slice3DVector& rSliceVector,
346 const basegfx::B2DPolyPolygon& rSource,
347 double fBackScale,
348 double fDiagonal,
349 double fRotation,
350 sal_uInt32 nSteps,
351 bool bCharacterMode,
352 bool bCloseFront,
353 bool bCloseBack)
355 if(basegfx::fTools::equalZero(fRotation) || 0 == nSteps)
357 // no rotation or no steps, just one plane
358 rSliceVector.emplace_back(rSource, basegfx::B3DHomMatrix());
360 else
362 const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0));
363 const bool bClosedRotation(!bBackScale && basegfx::fTools::equal(fRotation, F_2PI));
364 basegfx::B2DPolyPolygon aFront(rSource);
365 basegfx::B2DPolyPolygon aBack(rSource);
366 basegfx::B3DHomMatrix aTransformBack;
367 basegfx::B2DPolyPolygon aOuterBack;
369 if(bClosedRotation)
371 bCloseFront = bCloseBack = false;
374 if(bBackScale)
376 // avoid null zoom
377 if(basegfx::fTools::equalZero(fBackScale))
379 fBackScale = 0.000001;
382 // back is scaled compared to front, create scaled version
383 aBack = impScalePolyPolygonOnCenter(aBack, fBackScale);
386 if(bCloseFront || bCloseBack)
388 const basegfx::B2DRange aBaseRange(basegfx::utils::getRange(aFront));
389 const double fOuterLength(aBaseRange.getMaxX() * fRotation);
390 const double fInnerLength(aBaseRange.getMinX() * fRotation);
391 const double fAverageLength((fOuterLength + fInnerLength) * 0.5);
393 if(bCloseFront)
395 const double fOffsetLen((fAverageLength / 12.0) * fDiagonal);
396 basegfx::B2DPolyPolygon aOuterFront;
397 impGetOuterPolyPolygon(aFront, aOuterFront, fOffsetLen, bCharacterMode);
398 basegfx::B3DHomMatrix aTransform;
399 aTransform.translate(0.0, 0.0, fOffsetLen);
400 rSliceVector.emplace_back(aOuterFront, aTransform, SLICETYPE3D_FRONTCAP);
403 if(bCloseBack)
405 const double fOffsetLen((fAverageLength / 12.0) * fDiagonal);
406 impGetOuterPolyPolygon(aBack, aOuterBack, fOffsetLen, bCharacterMode);
407 aTransformBack.translate(0.0, 0.0, -fOffsetLen);
408 aTransformBack.rotate(0.0, fRotation, 0.0);
412 // add start polygon (a = 0)
413 if(!bClosedRotation)
415 rSliceVector.emplace_back(aFront, basegfx::B3DHomMatrix());
418 // create segments (a + 1 .. nSteps)
419 const double fStepSize(1.0 / static_cast<double>(nSteps));
421 for(sal_uInt32 a(0); a < nSteps; a++)
423 const double fStep(static_cast<double>(a + 1) * fStepSize);
424 basegfx::B2DPolyPolygon aNewPoly(bBackScale ? basegfx::utils::interpolate(aFront, aBack, fStep) : aFront);
425 basegfx::B3DHomMatrix aNewMat;
426 aNewMat.rotate(0.0, fRotation * fStep, 0.0);
427 rSliceVector.emplace_back(aNewPoly, aNewMat);
430 if(bCloseBack)
432 rSliceVector.emplace_back(aOuterBack, aTransformBack, SLICETYPE3D_BACKCAP);
437 void createExtrudeSlices(
438 Slice3DVector& rSliceVector,
439 const basegfx::B2DPolyPolygon& rSource,
440 double fBackScale,
441 double fDiagonal,
442 double fDepth,
443 bool bCharacterMode,
444 bool bCloseFront,
445 bool bCloseBack)
447 if(basegfx::fTools::equalZero(fDepth))
449 // no depth, just one plane
450 rSliceVector.emplace_back(rSource, basegfx::B3DHomMatrix());
452 else
454 // there is depth, create Polygons for front,back and their default depth positions
455 basegfx::B2DPolyPolygon aFront(rSource);
456 basegfx::B2DPolyPolygon aBack(rSource);
457 const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0));
458 double fZFront(fDepth); // default depth for aFront
459 double fZBack(0.0); // default depth for aBack
460 basegfx::B2DPolyPolygon aOuterBack;
462 if(bBackScale)
464 // avoid null zoom
465 if(basegfx::fTools::equalZero(fBackScale))
467 fBackScale = 0.000001;
470 // aFront is scaled compared to aBack, create scaled version
471 aFront = impScalePolyPolygonOnCenter(aFront, fBackScale);
474 if(bCloseFront)
476 const double fOffset(fDepth * fDiagonal * 0.5);
477 fZFront = fDepth - fOffset;
478 basegfx::B2DPolyPolygon aOuterFront;
479 impGetOuterPolyPolygon(aFront, aOuterFront, fOffset, bCharacterMode);
480 basegfx::B3DHomMatrix aTransformFront;
481 aTransformFront.translate(0.0, 0.0, fDepth);
482 rSliceVector.emplace_back(aOuterFront, aTransformFront, SLICETYPE3D_FRONTCAP);
485 if(bCloseBack)
487 const double fOffset(fDepth * fDiagonal * 0.5);
488 fZBack = fOffset;
489 impGetOuterPolyPolygon(aBack, aOuterBack, fOffset, bCharacterMode);
492 // add front and back polygons at evtl. changed depths
494 basegfx::B3DHomMatrix aTransformA, aTransformB;
496 aTransformA.translate(0.0, 0.0, fZFront);
497 rSliceVector.emplace_back(aFront, aTransformA);
499 aTransformB.translate(0.0, 0.0, fZBack);
500 rSliceVector.emplace_back(aBack, aTransformB);
503 if(bCloseBack)
505 rSliceVector.emplace_back(aOuterBack, basegfx::B3DHomMatrix(), SLICETYPE3D_BACKCAP);
510 basegfx::B3DPolyPolygon extractHorizontalLinesFromSlice(const Slice3DVector& rSliceVector, bool bCloseHorLines)
512 basegfx::B3DPolyPolygon aRetval;
513 const sal_uInt32 nNumSlices(rSliceVector.size());
515 if(nNumSlices)
517 const sal_uInt32 nSlideSubPolygonCount(rSliceVector[0].getB3DPolyPolygon().count());
519 for(sal_uInt32 b(0); b < nSlideSubPolygonCount; b++)
521 const sal_uInt32 nSubPolygonPointCount(rSliceVector[0].getB3DPolyPolygon().getB3DPolygon(b).count());
523 for(sal_uInt32 c(0); c < nSubPolygonPointCount; c++)
525 basegfx::B3DPolygon aNew;
527 for(sal_uInt32 d(0); d < nNumSlices; d++)
529 const bool bSamePolygonCount(nSlideSubPolygonCount == rSliceVector[d].getB3DPolyPolygon().count());
530 const bool bSamePointCount(nSubPolygonPointCount == rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).count());
532 if(bSamePolygonCount && bSamePointCount)
534 aNew.append(rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).getB3DPoint(c));
536 else
538 OSL_ENSURE(bSamePolygonCount, "Slice tools::PolyPolygon with different Polygon count (!)");
539 OSL_ENSURE(bSamePointCount, "Slice Polygon with different point count (!)");
543 aNew.setClosed(bCloseHorLines);
544 aRetval.append(aNew);
549 return aRetval;
552 basegfx::B3DPolyPolygon extractVerticalLinesFromSlice(const Slice3DVector& rSliceVector)
554 basegfx::B3DPolyPolygon aRetval;
555 const sal_uInt32 nNumSlices(rSliceVector.size());
557 for(sal_uInt32 a(0); a < nNumSlices; a++)
559 aRetval.append(rSliceVector[a].getB3DPolyPolygon());
562 return aRetval;
565 void extractPlanesFromSlice(
566 std::vector< basegfx::B3DPolyPolygon >& rFill,
567 const Slice3DVector& rSliceVector,
568 bool bCreateNormals,
569 bool bSmoothNormals,
570 bool bSmoothLids,
571 bool bClosed,
572 double fSmoothNormalsMix,
573 double fSmoothLidsMix,
574 bool bCreateTextureCoordinates,
575 const basegfx::B2DHomMatrix& rTexTransform)
577 const sal_uInt32 nNumSlices(rSliceVector.size());
579 if(!nNumSlices)
580 return;
582 // common parameters
583 const sal_uInt32 nLoopCount(bClosed ? nNumSlices : nNumSlices - 1);
584 basegfx::B3DPolyPolygon aEdgeRounding;
585 sal_uInt32 a;
587 // texture parameters
588 double fInvTexHeight(1.0);
589 std::vector<double> aTexHeightArray;
590 basegfx::B3DRange aTexRangeFront;
591 basegfx::B3DRange aTexRangeBack;
593 if(bCreateTextureCoordinates)
595 aTexRangeFront = basegfx::utils::getRange(rSliceVector[0].getB3DPolyPolygon());
596 aTexRangeBack = basegfx::utils::getRange(rSliceVector[nNumSlices - 1].getB3DPolyPolygon());
598 if(aTexRangeBack.getDepth() > aTexRangeBack.getWidth())
600 // last polygon is rotated so that depth is bigger than width, exchange X and Z
601 // for making applyDefaultTextureCoordinatesParallel use Z instead of X for
602 // horizontal texture coordinate
603 aTexRangeBack = basegfx::B3DRange(
604 aTexRangeBack.getMinZ(), aTexRangeBack.getMinY(), aTexRangeBack.getMinX(),
605 aTexRangeBack.getMaxZ(), aTexRangeBack.getMaxY(), aTexRangeBack.getMaxX());
608 basegfx::B3DPoint aCenter(basegfx::utils::getRange(rSliceVector[0].getB3DPolyPolygon()).getCenter());
610 for(a = 0; a < nLoopCount; a++)
612 const basegfx::B3DPoint aNextCenter(basegfx::utils::getRange(rSliceVector[(a + 1) % nNumSlices].getB3DPolyPolygon()).getCenter());
613 const double fLength(basegfx::B3DVector(aNextCenter - aCenter).getLength());
614 aTexHeightArray.push_back(fLength);
615 aCenter = aNextCenter;
618 const double fTexHeight(std::accumulate(aTexHeightArray.begin(), aTexHeightArray.end(), 0.0));
620 if(!basegfx::fTools::equalZero(fTexHeight))
622 fInvTexHeight = 1.0 / fTexHeight;
626 if(nLoopCount)
628 double fTexHeightPos(0.0);
629 for(a = 0; a < nLoopCount; a++)
631 const Slice3D& rSliceA(rSliceVector[a]);
632 const Slice3D& rSliceB(rSliceVector[(a + 1) % nNumSlices]);
633 const bool bAcceptPair(SLICETYPE3D_REGULAR == rSliceA.getSliceType() && SLICETYPE3D_REGULAR == rSliceB.getSliceType());
634 basegfx::B3DPolyPolygon aPolA(rSliceA.getB3DPolyPolygon());
635 basegfx::B3DPolyPolygon aPolB(rSliceB.getB3DPolyPolygon());
637 if(bAcceptPair)
639 if(bCreateNormals)
641 impCreateInBetweenNormals(aPolB, aPolA);
645 const sal_uInt32 nIndPrev((a + nNumSlices - 1) % nNumSlices);
646 const Slice3D& rSlicePrev(rSliceVector[nIndPrev]);
647 basegfx::B3DPolyPolygon aPrev(rSlicePrev.getB3DPolyPolygon());
648 basegfx::B3DPolyPolygon aPolAA(rSliceA.getB3DPolyPolygon());
650 if(SLICETYPE3D_FRONTCAP == rSlicePrev.getSliceType())
652 basegfx::B3DPolyPolygon aFront(rSlicePrev.getB3DPolyPolygon());
653 const bool bHasSlant(aPolAA != aPrev);
655 if(bCreateTextureCoordinates)
657 aFront = basegfx::utils::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront);
660 if(bCreateNormals)
662 basegfx::B3DVector aNormal(0.0, 0.0, -1.0);
664 if(aFront.count())
666 aNormal = -aFront.getB3DPolygon(0).getNormal();
669 impSetNormal(aFront, aNormal);
671 if(bHasSlant)
673 impCreateInBetweenNormals(aPolAA, aPrev);
675 if(bSmoothNormals)
677 // smooth and copy
678 impMixNormals(aPolA, aPolAA, fSmoothNormalsMix);
679 aPolAA = aPolA;
681 else
683 // take over from surface
684 aPolAA = aPolA;
687 if(bSmoothLids)
689 // smooth and copy
690 impMixNormals(aFront, aPrev, fSmoothLidsMix);
691 aPrev = aFront;
693 else
695 // take over from front
696 aPrev = aFront;
699 else
701 if(bSmoothNormals)
703 // smooth
704 impMixNormals(aPolA, aFront, fSmoothNormalsMix);
707 if(bSmoothLids)
709 // smooth and copy
710 impMixNormals(aFront, aPolA, fSmoothLidsMix);
711 aPolA = aFront;
716 if(bHasSlant)
718 double fTexStart{};
719 double fTexStop{};
720 if(bCreateTextureCoordinates)
722 fTexStart = fTexHeightPos * fInvTexHeight;
723 fTexStop = (fTexHeightPos - aTexHeightArray[(a + nLoopCount - 1) % nLoopCount]) * fInvTexHeight;
726 impAddInBetweenFill(aEdgeRounding, aPolAA, aPrev, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates);
729 aFront.flip();
730 rFill.push_back(aFront);
732 else
734 if(bCreateNormals && bSmoothNormals && (nIndPrev != a + 1))
736 impCreateInBetweenNormals(aPolAA, aPrev);
737 impMixNormals(aPolA, aPolAA, 0.5);
743 const sal_uInt32 nIndNext((a + 2) % nNumSlices);
744 const Slice3D& rSliceNext(rSliceVector[nIndNext]);
745 basegfx::B3DPolyPolygon aNext(rSliceNext.getB3DPolyPolygon());
746 basegfx::B3DPolyPolygon aPolBB(rSliceB.getB3DPolyPolygon());
748 if(SLICETYPE3D_BACKCAP == rSliceNext.getSliceType())
750 basegfx::B3DPolyPolygon aBack(rSliceNext.getB3DPolyPolygon());
751 const bool bHasSlant(aPolBB != aNext);
753 if(bCreateTextureCoordinates)
755 aBack = basegfx::utils::applyDefaultTextureCoordinatesParallel(aBack, aTexRangeBack);
758 if(bCreateNormals)
760 const basegfx::B3DVector aNormal(aBack.count() ? aBack.getB3DPolygon(0).getNormal() : basegfx::B3DVector(0.0, 0.0, 1.0));
761 impSetNormal(aBack, aNormal);
763 if(bHasSlant)
765 impCreateInBetweenNormals(aNext, aPolBB);
767 if(bSmoothNormals)
769 // smooth and copy
770 impMixNormals(aPolB, aPolBB, fSmoothNormalsMix);
771 aPolBB = aPolB;
773 else
775 // take over from surface
776 aPolBB = aPolB;
779 if(bSmoothLids)
781 // smooth and copy
782 impMixNormals(aBack, aNext, fSmoothLidsMix);
783 aNext = aBack;
785 else
787 // take over from back
788 aNext = aBack;
791 else
793 if(bSmoothNormals)
795 // smooth
796 impMixNormals(aPolB, aBack, fSmoothNormalsMix);
799 if(bSmoothLids)
801 // smooth and copy
802 impMixNormals(aBack, aPolB, fSmoothLidsMix);
803 aPolB = aBack;
808 if(bHasSlant)
810 double fTexStart{};
811 double fTexStop{};
812 if(bCreateTextureCoordinates)
814 fTexStart = (fTexHeightPos + aTexHeightArray[a] + aTexHeightArray[(a + 1) % nLoopCount]) * fInvTexHeight;
815 fTexStop = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight;
818 impAddInBetweenFill(aEdgeRounding, aNext, aPolBB, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates);
821 rFill.push_back(aBack);
823 else
825 if(bCreateNormals && bSmoothNormals && (nIndNext != a))
827 impCreateInBetweenNormals(aNext, aPolBB);
828 impMixNormals(aPolB, aPolBB, 0.5);
833 double fTexStart{};
834 double fTexStop{};
835 if(bCreateTextureCoordinates)
837 fTexStart = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight;
838 fTexStop = fTexHeightPos * fInvTexHeight;
841 impAddInBetweenFill(aEdgeRounding, aPolB, aPolA, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates);
844 if(bCreateTextureCoordinates)
846 fTexHeightPos += aTexHeightArray[a];
850 else
852 // no loop, but a single slice (1 == nNumSlices), create a filling from the single
853 // front plane
854 const Slice3D& rSlice(rSliceVector[0]);
855 basegfx::B3DPolyPolygon aFront(rSlice.getB3DPolyPolygon());
857 if(bCreateTextureCoordinates)
859 aFront = basegfx::utils::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront);
862 if(bCreateNormals)
864 basegfx::B3DVector aNormal(0.0, 0.0, -1.0);
866 if(aFront.count())
868 aNormal = -aFront.getB3DPolygon(0).getNormal();
871 impSetNormal(aFront, aNormal);
874 aFront.flip();
875 rFill.push_back(aFront);
878 if(bCreateTextureCoordinates)
880 aEdgeRounding.transformTextureCoordinates(rTexTransform);
883 for(a = 0; a < aEdgeRounding.count(); a++)
885 rFill.emplace_back(aEdgeRounding.getB3DPolygon(a));
889 void createReducedOutlines(
890 const geometry::ViewInformation3D& rViewInformation,
891 const basegfx::B3DHomMatrix& rObjectTransform,
892 const basegfx::B3DPolygon& rLoopA,
893 const basegfx::B3DPolygon& rLoopB,
894 basegfx::B3DPolyPolygon& rTarget)
896 const sal_uInt32 nPointCount(rLoopA.count());
898 // with identical polygons there are no outlines
899 if(rLoopA == rLoopB)
900 return;
902 if(!(nPointCount && nPointCount == rLoopB.count()))
903 return;
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))
913 return;
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);
923 for(sal_uInt32 a(0); a < nPointCount; a++)
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));
929 if(!basegfx::utils::isInside(a2DLoopA, aMiddle))
931 if(!basegfx::utils::isInside(a2DLoopB, aMiddle))
933 if(!impHasCutWith(a2DLoopA, aStart, aEnd))
935 if(!impHasCutWith(a2DLoopB, aStart, aEnd))
937 const basegfx::B2DVector aCandidateVector(aMiddle - aCommonCenter);
938 const double fCross(aCandidateVector.cross(aAxisVector));
939 const double fDistance(aCandidateVector.getLength());
941 if(fCross > 0.0)
943 if(fDistance > fMaxLeft)
945 fMaxLeft = fDistance;
946 nIndexLeft = a;
949 else if(fCross < 0.0)
951 if(fDistance > fMaxRight)
953 fMaxRight = fDistance;
954 nIndexRight = a;
963 if(fMaxLeft != 0.0)
965 basegfx::B3DPolygon aToBeAdded;
966 aToBeAdded.append(rLoopA.getB3DPoint(nIndexLeft));
967 aToBeAdded.append(rLoopB.getB3DPoint(nIndexLeft));
968 rTarget.append(aToBeAdded);
971 if(fMaxRight != 0.0)
973 basegfx::B3DPolygon aToBeAdded;
974 aToBeAdded.append(rLoopA.getB3DPoint(nIndexRight));
975 aToBeAdded.append(rLoopB.getB3DPoint(nIndexRight));
976 rTarget.append(aToBeAdded);
980 } // end of namespace
982 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */