Bump for 3.6-28
[LibreOffice.git] / drawinglayer / source / primitive3d / sdrextrudelathetools3d.cxx
blobededddbe412bf6a4da68583138f7bf88f7e95f75
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include <drawinglayer/primitive3d/sdrextrudelathetools3d.hxx>
30 #include <basegfx/polygon/b2dpolypolygon.hxx>
31 #include <basegfx/range/b2drange.hxx>
32 #include <basegfx/polygon/b2dpolypolygontools.hxx>
33 #include <basegfx/matrix/b2dhommatrix.hxx>
34 #include <basegfx/point/b3dpoint.hxx>
35 #include <basegfx/polygon/b3dpolygon.hxx>
36 #include <basegfx/polygon/b3dpolygontools.hxx>
37 #include <basegfx/polygon/b3dpolypolygontools.hxx>
38 #include <basegfx/range/b3drange.hxx>
39 #include <basegfx/matrix/b3dhommatrix.hxx>
40 #include <basegfx/polygon/b2dpolygontools.hxx>
41 #include <drawinglayer/geometry/viewinformation3d.hxx>
42 #include <numeric>
44 //////////////////////////////////////////////////////////////////////////////
45 // decompositon helpers for extrude/lathe (rotation) objects
47 namespace
49 //////////////////////////////////////////////////////////////////////////////
50 // common helpers
52 basegfx::B2DPolyPolygon impScalePolyPolygonOnCenter(
53 const basegfx::B2DPolyPolygon& rSource,
54 double fScale)
56 basegfx::B2DPolyPolygon aRetval(rSource);
58 if(!basegfx::fTools::equalZero(fScale))
60 const basegfx::B2DRange aRange(basegfx::tools::getRange(rSource));
61 const basegfx::B2DPoint aCenter(aRange.getCenter());
62 basegfx::B2DHomMatrix aTrans;
64 aTrans.translate(-aCenter.getX(), -aCenter.getY());
65 aTrans.scale(fScale, fScale);
66 aTrans.translate(aCenter.getX(), aCenter.getY());
67 aRetval.transform(aTrans);
70 return aRetval;
73 void impGetOuterPolyPolygon(
74 basegfx::B2DPolyPolygon& rPolygon,
75 basegfx::B2DPolyPolygon& rOuterPolyPolygon,
76 double fOffset,
77 bool bCharacterMode)
79 rOuterPolyPolygon = rPolygon;
81 if(basegfx::fTools::more(fOffset, 0.0))
83 if(bCharacterMode)
85 // grow the outside polygon and scale all polygons to original size. This is done
86 // to avoid a shrink which potentially would lead to self-intersections, but changes
87 // the original polygon -> not a precision step, so e.g. not usable for charts
88 const basegfx::B2DRange aRange(basegfx::tools::getRange(rPolygon));
89 rPolygon = basegfx::tools::growInNormalDirection(rPolygon, fOffset);
90 const basegfx::B2DRange aGrownRange(basegfx::tools::getRange(rPolygon));
91 const double fScaleX(basegfx::fTools::equalZero(aGrownRange.getWidth()) ? 1.0 : aRange.getWidth() / aGrownRange.getWidth());
92 const double fScaleY(basegfx::fTools::equalZero(aGrownRange.getHeight())? 1.0 : aRange.getHeight() / aGrownRange.getHeight());
93 basegfx::B2DHomMatrix aScaleTrans;
95 aScaleTrans.translate(-aGrownRange.getMinX(), -aGrownRange.getMinY());
96 aScaleTrans.scale(fScaleX, fScaleY);
97 aScaleTrans.translate(aRange.getMinX(), aRange.getMinY());
98 rPolygon.transform(aScaleTrans);
99 rOuterPolyPolygon.transform(aScaleTrans);
101 else
103 // use more precision, shrink the outer polygons. Since this may lead to self-intersections,
104 // some kind of correction should be applied here after that step
105 rOuterPolyPolygon = basegfx::tools::growInNormalDirection(rPolygon, -fOffset);
106 basegfx::tools::correctGrowShrinkPolygonPair(rPolygon, rOuterPolyPolygon);
111 void impAddInBetweenFill(
112 basegfx::B3DPolyPolygon& rTarget,
113 const basegfx::B3DPolyPolygon& rPolA,
114 const basegfx::B3DPolyPolygon& rPolB,
115 double fTexVerStart,
116 double fTexVerStop,
117 bool bCreateNormals,
118 bool bCreateTextureCoordinates)
120 OSL_ENSURE(rPolA.count() == rPolB.count(), "impAddInBetweenFill: unequally sized polygons (!)");
121 const sal_uInt32 nPolygonCount(rPolA.count());
123 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
125 const basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a));
126 const basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a));
127 OSL_ENSURE(aSubA.count() == aSubB.count(), "impAddInBetweenFill: unequally sized polygons (!)");
128 const sal_uInt32 nPointCount(aSubA.count());
130 if(nPointCount)
132 const sal_uInt32 nEdgeCount(aSubA.isClosed() ? nPointCount : nPointCount - 1L);
133 double fTexHorMultiplicatorA(0.0), fTexHorMultiplicatorB(0.0);
134 double fPolygonPosA(0.0), fPolygonPosB(0.0);
136 if(bCreateTextureCoordinates)
138 const double fPolygonLengthA(basegfx::tools::getLength(aSubA));
139 fTexHorMultiplicatorA = basegfx::fTools::equalZero(fPolygonLengthA) ? 1.0 : 1.0 / fPolygonLengthA;
141 const double fPolygonLengthB(basegfx::tools::getLength(aSubB));
142 fTexHorMultiplicatorB = basegfx::fTools::equalZero(fPolygonLengthB) ? 1.0 : 1.0 / fPolygonLengthB;
145 for(sal_uInt32 b(0L); b < nEdgeCount; b++)
147 const sal_uInt32 nIndexA(b);
148 const sal_uInt32 nIndexB((b + 1L) % nPointCount);
150 const basegfx::B3DPoint aStartA(aSubA.getB3DPoint(nIndexA));
151 const basegfx::B3DPoint aEndA(aSubA.getB3DPoint(nIndexB));
152 const basegfx::B3DPoint aStartB(aSubB.getB3DPoint(nIndexA));
153 const basegfx::B3DPoint aEndB(aSubB.getB3DPoint(nIndexB));
155 basegfx::B3DPolygon aNew;
156 aNew.setClosed(true);
158 aNew.append(aStartA);
159 aNew.append(aStartB);
160 aNew.append(aEndB);
161 aNew.append(aEndA);
163 if(bCreateNormals)
165 aNew.setNormal(0L, aSubA.getNormal(nIndexA));
166 aNew.setNormal(1L, aSubB.getNormal(nIndexA));
167 aNew.setNormal(2L, aSubB.getNormal(nIndexB));
168 aNew.setNormal(3L, aSubA.getNormal(nIndexB));
171 if(bCreateTextureCoordinates)
173 const double fRelTexAL(fPolygonPosA * fTexHorMultiplicatorA);
174 const double fEdgeLengthA(basegfx::B3DVector(aEndA - aStartA).getLength());
175 fPolygonPosA += fEdgeLengthA;
176 const double fRelTexAR(fPolygonPosA * fTexHorMultiplicatorA);
178 const double fRelTexBL(fPolygonPosB * fTexHorMultiplicatorB);
179 const double fEdgeLengthB(basegfx::B3DVector(aEndB - aStartB).getLength());
180 fPolygonPosB += fEdgeLengthB;
181 const double fRelTexBR(fPolygonPosB * fTexHorMultiplicatorB);
183 aNew.setTextureCoordinate(0L, basegfx::B2DPoint(fRelTexAL, fTexVerStart));
184 aNew.setTextureCoordinate(1L, basegfx::B2DPoint(fRelTexBL, fTexVerStop));
185 aNew.setTextureCoordinate(2L, basegfx::B2DPoint(fRelTexBR, fTexVerStop));
186 aNew.setTextureCoordinate(3L, basegfx::B2DPoint(fRelTexAR, fTexVerStart));
189 rTarget.append(aNew);
195 void impSetNormal(
196 basegfx::B3DPolyPolygon& rCandidate,
197 const basegfx::B3DVector& rNormal)
199 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
201 basegfx::B3DPolygon aSub(rCandidate.getB3DPolygon(a));
203 for(sal_uInt32 b(0L); b < aSub.count(); b++)
205 aSub.setNormal(b, rNormal);
208 rCandidate.setB3DPolygon(a, aSub);
212 void impCreateInBetweenNormals(
213 basegfx::B3DPolyPolygon& rPolA,
214 basegfx::B3DPolyPolygon& rPolB,
215 bool bSmoothHorizontalNormals)
217 OSL_ENSURE(rPolA.count() == rPolB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
219 for(sal_uInt32 a(0L); a < rPolA.count(); a++)
221 basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a));
222 basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a));
223 OSL_ENSURE(aSubA.count() == aSubB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
224 const sal_uInt32 nPointCount(aSubA.count());
226 if(nPointCount)
228 basegfx::B3DPoint aPrevA(aSubA.getB3DPoint(nPointCount - 1L));
229 basegfx::B3DPoint aCurrA(aSubA.getB3DPoint(0L));
230 const bool bClosed(aSubA.isClosed());
232 for(sal_uInt32 b(0L); b < nPointCount; b++)
234 const sal_uInt32 nIndNext((b + 1L) % nPointCount);
235 const basegfx::B3DPoint aNextA(aSubA.getB3DPoint(nIndNext));
236 const basegfx::B3DPoint aCurrB(aSubB.getB3DPoint(b));
238 // vector to back
239 basegfx::B3DVector aDepth(aCurrB - aCurrA);
240 aDepth.normalize();
242 if(aDepth.equalZero())
244 // no difference, try to get depth from next point
245 const basegfx::B3DPoint aNextB(aSubB.getB3DPoint(nIndNext));
246 aDepth = aNextB - aNextA;
247 aDepth.normalize();
250 // vector to left (correct for non-closed lines)
251 const bool bFirstAndNotClosed(!bClosed && 0L == b);
252 basegfx::B3DVector aLeft(bFirstAndNotClosed ? aCurrA - aNextA : aPrevA - aCurrA);
253 aLeft.normalize();
255 // create left normal
256 const basegfx::B3DVector aNormalLeft(aDepth.getPerpendicular(aLeft));
258 if(bSmoothHorizontalNormals)
260 // vector to right (correct for non-closed lines)
261 const bool bLastAndNotClosed(!bClosed && b + 1L == nPointCount);
262 basegfx::B3DVector aRight(bLastAndNotClosed ? aCurrA - aPrevA : aNextA - aCurrA);
263 aRight.normalize();
265 // create right normal
266 const basegfx::B3DVector aNormalRight(aRight.getPerpendicular(aDepth));
268 // create smoothed in-between normal
269 basegfx::B3DVector aNewNormal(aNormalLeft + aNormalRight);
270 aNewNormal.normalize();
272 // set as new normal at polygons
273 aSubA.setNormal(b, aNewNormal);
274 aSubB.setNormal(b, aNewNormal);
276 else
278 // set aNormalLeft as new normal at polygons
279 aSubA.setNormal(b, aNormalLeft);
280 aSubB.setNormal(b, aNormalLeft);
283 // prepare next step
284 aPrevA = aCurrA;
285 aCurrA = aNextA;
288 rPolA.setB3DPolygon(a, aSubA);
289 rPolB.setB3DPolygon(a, aSubB);
294 void impMixNormals(
295 basegfx::B3DPolyPolygon& rPolA,
296 const basegfx::B3DPolyPolygon& rPolB,
297 double fWeightA)
299 const double fWeightB(1.0 - fWeightA);
300 OSL_ENSURE(rPolA.count() == rPolB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
302 for(sal_uInt32 a(0L); a < rPolA.count(); a++)
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(aSubA.count());
309 for(sal_uInt32 b(0L); b < nPointCount; b++)
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);
318 rPolA.setB3DPolygon(a, aSubA);
322 bool impHasCutWith(const basegfx::B2DPolygon& rPoly, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd)
324 // polygon is closed, one of the points is a member
325 const sal_uInt32 nPointCount(rPoly.count());
327 if(nPointCount)
329 basegfx::B2DPoint aCurrent(rPoly.getB2DPoint(0));
330 const basegfx::B2DVector aVector(rEnd - rStart);
332 for(sal_uInt32 a(0); a < nPointCount; a++)
334 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
335 const basegfx::B2DPoint aNext(rPoly.getB2DPoint(nNextIndex));
336 const basegfx::B2DVector aEdgeVector(aNext - aCurrent);
338 if(basegfx::tools::findCut(
339 rStart, aVector,
340 aCurrent, aEdgeVector))
342 return true;
345 aCurrent = aNext;
349 return false;
351 } // end of anonymous namespace
353 //////////////////////////////////////////////////////////////////////////////
355 namespace drawinglayer
357 namespace primitive3d
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)
370 if(basegfx::fTools::equalZero(fRotation) || 0L == nSteps)
372 // no rotation or no steps, just one plane
373 rSliceVector.push_back(Slice3D(rSource, basegfx::B3DHomMatrix()));
375 else
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;
384 if(bClosedRotation)
386 bCloseFront = bCloseBack = false;
389 if(bBackScale)
391 // avoid null zoom
392 if(basegfx::fTools::equalZero(fBackScale))
394 fBackScale = 0.000001;
397 // back is scaled compared to front, create scaled version
398 aBack = impScalePolyPolygonOnCenter(aBack, fBackScale);
401 if(bCloseFront || bCloseBack)
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);
408 if(bCloseFront)
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));
418 if(bCloseBack)
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);
427 // add start polygon (a = 0L)
428 if(!bClosedRotation)
430 rSliceVector.push_back(Slice3D(aFront, basegfx::B3DHomMatrix()));
433 // create segments (a + 1 .. nSteps)
434 const double fStepSize(1.0 / (double)nSteps);
436 for(sal_uInt32 a(0L); a < nSteps; a++)
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));
445 if(bCloseBack)
447 rSliceVector.push_back(Slice3D(aOuterBack, aTransformBack, SLICETYPE3D_BACKCAP));
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)
462 if(basegfx::fTools::equalZero(fDepth))
464 // no depth, just one plane
465 rSliceVector.push_back(Slice3D(rSource, basegfx::B3DHomMatrix()));
467 else
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;
477 if(bBackScale)
479 // avoid null zoom
480 if(basegfx::fTools::equalZero(fBackScale))
482 fBackScale = 0.000001;
485 // aFront is scaled compared to aBack, create scaled version
486 aFront = impScalePolyPolygonOnCenter(aFront, fBackScale);
489 if(bCloseFront)
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));
500 if(bCloseBack)
502 const double fOffset(fDepth * fDiagonal * 0.5);
503 fZBack = fOffset;
504 impGetOuterPolyPolygon(aBack, aOuterBack, fOffset, bCharacterMode);
507 // add front and back polygons at evtl. changed depths
509 basegfx::B3DHomMatrix aTransformA, aTransformB;
511 aTransformA.translate(0.0, 0.0, fZFront);
512 rSliceVector.push_back(Slice3D(aFront, aTransformA));
514 aTransformB.translate(0.0, 0.0, fZBack);
515 rSliceVector.push_back(Slice3D(aBack, aTransformB));
518 if(bCloseBack)
520 rSliceVector.push_back(Slice3D(aOuterBack, basegfx::B3DHomMatrix(), SLICETYPE3D_BACKCAP));
525 basegfx::B3DPolyPolygon extractHorizontalLinesFromSlice(const Slice3DVector& rSliceVector, bool bCloseHorLines)
527 basegfx::B3DPolyPolygon aRetval;
528 const sal_uInt32 nNumSlices(rSliceVector.size());
530 if(nNumSlices)
532 const sal_uInt32 nSlideSubPolygonCount(rSliceVector[0].getB3DPolyPolygon().count());
534 for(sal_uInt32 b(0); b < nSlideSubPolygonCount; b++)
536 const sal_uInt32 nSubPolygonPointCount(rSliceVector[0].getB3DPolyPolygon().getB3DPolygon(b).count());
538 for(sal_uInt32 c(0); c < nSubPolygonPointCount; c++)
540 basegfx::B3DPolygon aNew;
542 for(sal_uInt32 d(0); d < nNumSlices; d++)
544 OSL_ENSURE(nSlideSubPolygonCount == rSliceVector[d].getB3DPolyPolygon().count(),
545 "Slice PolyPolygon with different Polygon count (!)");
546 OSL_ENSURE(nSubPolygonPointCount == rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).count(),
547 "Slice Polygon with different point count (!)");
548 aNew.append(rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).getB3DPoint(c));
551 aNew.setClosed(bCloseHorLines);
552 aRetval.append(aNew);
557 return aRetval;
560 basegfx::B3DPolyPolygon extractVerticalLinesFromSlice(const Slice3DVector& rSliceVector)
562 basegfx::B3DPolyPolygon aRetval;
563 const sal_uInt32 nNumSlices(rSliceVector.size());
565 for(sal_uInt32 a(0L); a < nNumSlices; a++)
567 aRetval.append(rSliceVector[a].getB3DPolyPolygon());
570 return aRetval;
573 void extractPlanesFromSlice(
574 ::std::vector< basegfx::B3DPolyPolygon >& rFill,
575 const Slice3DVector& rSliceVector,
576 bool bCreateNormals,
577 bool bSmoothHorizontalNormals,
578 bool bSmoothNormals,
579 bool bSmoothLids,
580 bool bClosed,
581 double fSmoothNormalsMix,
582 double fSmoothLidsMix,
583 bool bCreateTextureCoordinates,
584 const basegfx::B2DHomMatrix& rTexTransform)
586 const sal_uInt32 nNumSlices(rSliceVector.size());
588 if(nNumSlices)
590 // common parameters
591 const sal_uInt32 nLoopCount(bClosed ? nNumSlices : nNumSlices - 1L);
592 basegfx::B3DPolyPolygon aEdgeRounding;
593 sal_uInt32 a;
595 // tetxture parameters
596 double fInvTexHeight(1.0);
597 double fTexHeightPos(0.0);
598 double fTexStart(0.0);
599 double fTexStop(1.0);
600 ::std::vector<double> aTexHeightArray;
601 basegfx::B3DRange aTexRangeFront;
602 basegfx::B3DRange aTexRangeBack;
604 if(bCreateTextureCoordinates)
606 aTexRangeFront = basegfx::tools::getRange(rSliceVector[0L].getB3DPolyPolygon());
607 aTexRangeBack = basegfx::tools::getRange(rSliceVector[nNumSlices - 1L].getB3DPolyPolygon());
609 if(aTexRangeBack.getDepth() > aTexRangeBack.getWidth())
611 // last polygon is rotated so that depth is bigger than width, exchange X and Z
612 // for making applyDefaultTextureCoordinatesParallel use Z instead of X for
613 // horizontal texture coordinate
614 aTexRangeBack = basegfx::B3DRange(
615 aTexRangeBack.getMinZ(), aTexRangeBack.getMinY(), aTexRangeBack.getMinX(),
616 aTexRangeBack.getMaxZ(), aTexRangeBack.getMaxY(), aTexRangeBack.getMaxX());
619 basegfx::B3DPoint aCenter(basegfx::tools::getRange(rSliceVector[0L].getB3DPolyPolygon()).getCenter());
621 for(a = 0L; a < nLoopCount; a++)
623 const basegfx::B3DPoint aNextCenter(basegfx::tools::getRange(rSliceVector[(a + 1L) % nNumSlices].getB3DPolyPolygon()).getCenter());
624 const double fLength(basegfx::B3DVector(aNextCenter - aCenter).getLength());
625 aTexHeightArray.push_back(fLength);
626 aCenter = aNextCenter;
629 const double fTexHeight(::std::accumulate(aTexHeightArray.begin(), aTexHeightArray.end(), 0.0));
631 if(!basegfx::fTools::equalZero(fTexHeight))
633 fInvTexHeight = 1.0 / fTexHeight;
637 if(nLoopCount)
639 for(a = 0L; a < nLoopCount; a++)
641 const Slice3D& rSliceA(rSliceVector[a]);
642 const Slice3D& rSliceB(rSliceVector[(a + 1L) % nNumSlices]);
643 const bool bAcceptPair(SLICETYPE3D_REGULAR == rSliceA.getSliceType() && SLICETYPE3D_REGULAR == rSliceB.getSliceType());
644 basegfx::B3DPolyPolygon aPolA(rSliceA.getB3DPolyPolygon());
645 basegfx::B3DPolyPolygon aPolB(rSliceB.getB3DPolyPolygon());
647 if(bAcceptPair)
649 if(bCreateNormals)
651 impCreateInBetweenNormals(aPolB, aPolA, bSmoothHorizontalNormals);
655 const sal_uInt32 nIndPrev((a + nNumSlices - 1L) % nNumSlices);
656 const Slice3D& rSlicePrev(rSliceVector[nIndPrev]);
657 basegfx::B3DPolyPolygon aPrev(rSlicePrev.getB3DPolyPolygon());
658 basegfx::B3DPolyPolygon aPolAA(rSliceA.getB3DPolyPolygon());
660 if(SLICETYPE3D_FRONTCAP == rSlicePrev.getSliceType())
662 basegfx::B3DPolyPolygon aFront(rSlicePrev.getB3DPolyPolygon());
663 const bool bHasSlant(aPolAA != aPrev);
665 if(bCreateTextureCoordinates)
667 aFront = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront);
670 if(bCreateNormals)
672 basegfx::B3DVector aNormal(0.0, 0.0, -1.0);
674 if(aFront.count())
676 aNormal = -aFront.getB3DPolygon(0L).getNormal();
679 impSetNormal(aFront, aNormal);
681 if(bHasSlant)
683 impCreateInBetweenNormals(aPolAA, aPrev, bSmoothHorizontalNormals);
685 if(bSmoothNormals)
687 // smooth and copy
688 impMixNormals(aPolA, aPolAA, fSmoothNormalsMix);
689 aPolAA = aPolA;
691 else
693 // take over from surface
694 aPolAA = aPolA;
697 if(bSmoothLids)
699 // smooth and copy
700 impMixNormals(aFront, aPrev, fSmoothLidsMix);
701 aPrev = aFront;
703 else
705 // take over from front
706 aPrev = aFront;
709 else
711 if(bSmoothNormals)
713 // smooth
714 impMixNormals(aPolA, aFront, fSmoothNormalsMix);
717 if(bSmoothLids)
719 // smooth and copy
720 impMixNormals(aFront, aPolA, fSmoothLidsMix);
721 aPolA = aFront;
726 if(bHasSlant)
728 if(bCreateTextureCoordinates)
730 fTexStart = fTexHeightPos * fInvTexHeight;
731 fTexStop = (fTexHeightPos - aTexHeightArray[(a + nLoopCount - 1L) % nLoopCount]) * fInvTexHeight;
734 impAddInBetweenFill(aEdgeRounding, aPolAA, aPrev, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates);
737 aFront.flip();
738 rFill.push_back(aFront);
740 else
742 if(bCreateNormals && bSmoothNormals && (nIndPrev != a + 1L))
744 impCreateInBetweenNormals(aPolAA, aPrev, bSmoothHorizontalNormals);
745 impMixNormals(aPolA, aPolAA, 0.5);
751 const sal_uInt32 nIndNext((a + 2L) % nNumSlices);
752 const Slice3D& rSliceNext(rSliceVector[nIndNext]);
753 basegfx::B3DPolyPolygon aNext(rSliceNext.getB3DPolyPolygon());
754 basegfx::B3DPolyPolygon aPolBB(rSliceB.getB3DPolyPolygon());
756 if(SLICETYPE3D_BACKCAP == rSliceNext.getSliceType())
758 basegfx::B3DPolyPolygon aBack(rSliceNext.getB3DPolyPolygon());
759 const bool bHasSlant(aPolBB != aNext);
761 if(bCreateTextureCoordinates)
763 aBack = basegfx::tools::applyDefaultTextureCoordinatesParallel(aBack, aTexRangeBack);
766 if(bCreateNormals)
768 const basegfx::B3DVector aNormal(aBack.count() ? aBack.getB3DPolygon(0L).getNormal() : basegfx::B3DVector(0.0, 0.0, 1.0));
769 impSetNormal(aBack, aNormal);
771 if(bHasSlant)
773 impCreateInBetweenNormals(aNext, aPolBB, bSmoothHorizontalNormals);
775 if(bSmoothNormals)
777 // smooth and copy
778 impMixNormals(aPolB, aPolBB, fSmoothNormalsMix);
779 aPolBB = aPolB;
781 else
783 // take over from surface
784 aPolBB = aPolB;
787 if(bSmoothLids)
789 // smooth and copy
790 impMixNormals(aBack, aNext, fSmoothLidsMix);
791 aNext = aBack;
793 else
795 // take over from back
796 aNext = aBack;
799 else
801 if(bSmoothNormals)
803 // smooth
804 impMixNormals(aPolB, aBack, fSmoothNormalsMix);
807 if(bSmoothLids)
809 // smooth and copy
810 impMixNormals(aBack, aPolB, fSmoothLidsMix);
811 aPolB = aBack;
816 if(bHasSlant)
818 if(bCreateTextureCoordinates)
820 fTexStart = (fTexHeightPos + aTexHeightArray[a] + aTexHeightArray[(a + 1L) % nLoopCount]) * fInvTexHeight;
821 fTexStop = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight;
824 impAddInBetweenFill(aEdgeRounding, aNext, aPolBB, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates);
827 rFill.push_back(aBack);
829 else
831 if(bCreateNormals && bSmoothNormals && (nIndNext != a))
833 impCreateInBetweenNormals(aNext, aPolBB, bSmoothHorizontalNormals);
834 impMixNormals(aPolB, aPolBB, 0.5);
839 if(bCreateTextureCoordinates)
841 fTexStart = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight;
842 fTexStop = fTexHeightPos * fInvTexHeight;
845 impAddInBetweenFill(aEdgeRounding, aPolB, aPolA, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates);
848 if(bCreateTextureCoordinates)
850 fTexHeightPos += aTexHeightArray[a];
854 else
856 // no loop, but a single slice (1 == nNumSlices), create a filling from the single
857 // front plane
858 const Slice3D& rSlice(rSliceVector[0]);
859 basegfx::B3DPolyPolygon aFront(rSlice.getB3DPolyPolygon());
861 if(bCreateTextureCoordinates)
863 aFront = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront);
866 if(bCreateNormals)
868 basegfx::B3DVector aNormal(0.0, 0.0, -1.0);
870 if(aFront.count())
872 aNormal = -aFront.getB3DPolygon(0L).getNormal();
875 impSetNormal(aFront, aNormal);
878 aFront.flip();
879 rFill.push_back(aFront);
882 if(bCreateTextureCoordinates)
884 aEdgeRounding.transformTextureCoordiantes(rTexTransform);
887 for(a = 0L; a < aEdgeRounding.count(); a++)
889 rFill.push_back(basegfx::B3DPolyPolygon(aEdgeRounding.getB3DPolygon(a)));
894 void createReducedOutlines(
895 const geometry::ViewInformation3D& rViewInformation,
896 const basegfx::B3DHomMatrix& rObjectTransform,
897 const basegfx::B3DPolygon& rLoopA,
898 const basegfx::B3DPolygon& rLoopB,
899 basegfx::B3DPolyPolygon& rTarget)
901 const sal_uInt32 nPointCount(rLoopA.count());
903 // with idetic polygons there are no outlines
904 if(rLoopA != rLoopB)
906 if(nPointCount && nPointCount == rLoopB.count())
908 const basegfx::B3DHomMatrix aObjectTransform(rViewInformation.getObjectToView() * rObjectTransform);
909 const basegfx::B2DPolygon a2DLoopA(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopA, aObjectTransform));
910 const basegfx::B2DPolygon a2DLoopB(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopB, aObjectTransform));
911 const basegfx::B2DPoint a2DCenterA(a2DLoopA.getB2DRange().getCenter());
912 const basegfx::B2DPoint a2DCenterB(a2DLoopB.getB2DRange().getCenter());
914 // without detectable Y-Axis there are no outlines
915 if(!a2DCenterA.equal(a2DCenterB))
917 // search for outmost left and right inter-loop-edges which do not cut the loops
918 const basegfx::B2DPoint aCommonCenter(basegfx::average(a2DCenterA, a2DCenterB));
919 const basegfx::B2DVector aAxisVector(a2DCenterA - a2DCenterB);
920 double fMaxLeft(0.0);
921 double fMaxRight(0.0);
922 sal_uInt32 nIndexLeft(0);
923 sal_uInt32 nIndexRight(0);
925 for(sal_uInt32 a(0); a < nPointCount; a++)
927 const basegfx::B2DPoint aStart(a2DLoopA.getB2DPoint(a));
928 const basegfx::B2DPoint aEnd(a2DLoopB.getB2DPoint(a));
929 const basegfx::B2DPoint aMiddle(basegfx::average(aStart, aEnd));
931 if(!basegfx::tools::isInside(a2DLoopA, aMiddle))
933 if(!basegfx::tools::isInside(a2DLoopB, aMiddle))
935 if(!impHasCutWith(a2DLoopA, aStart, aEnd))
937 if(!impHasCutWith(a2DLoopB, aStart, aEnd))
939 const basegfx::B2DVector aCandidateVector(aMiddle - aCommonCenter);
940 const double fCross(aCandidateVector.cross(aAxisVector));
941 const double fDistance(aCandidateVector.getLength());
943 if(fCross > 0.0)
945 if(fDistance > fMaxLeft)
947 fMaxLeft = fDistance;
948 nIndexLeft = a;
951 else if(fCross < 0.0)
953 if(fDistance > fMaxRight)
955 fMaxRight = fDistance;
956 nIndexRight = a;
965 if(fMaxLeft != 0.0)
967 basegfx::B3DPolygon aToBeAdded;
968 aToBeAdded.append(rLoopA.getB3DPoint(nIndexLeft));
969 aToBeAdded.append(rLoopB.getB3DPoint(nIndexLeft));
970 rTarget.append(aToBeAdded);
973 if(fMaxRight != 0.0)
975 basegfx::B3DPolygon aToBeAdded;
976 aToBeAdded.append(rLoopA.getB3DPoint(nIndexRight));
977 aToBeAdded.append(rLoopB.getB3DPoint(nIndexRight));
978 rTarget.append(aToBeAdded);
985 } // end of namespace primitive3d
986 } // end of namespace drawinglayer
988 //////////////////////////////////////////////////////////////////////////////
989 // eof
991 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */