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>
44 //////////////////////////////////////////////////////////////////////////////
45 // decompositon helpers for extrude/lathe (rotation) objects
49 //////////////////////////////////////////////////////////////////////////////
52 basegfx::B2DPolyPolygon
impScalePolyPolygonOnCenter(
53 const basegfx::B2DPolyPolygon
& rSource
,
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
);
73 void impGetOuterPolyPolygon(
74 basegfx::B2DPolyPolygon
& rPolygon
,
75 basegfx::B2DPolyPolygon
& rOuterPolyPolygon
,
79 rOuterPolyPolygon
= rPolygon
;
81 if(basegfx::fTools::more(fOffset
, 0.0))
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
);
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
,
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());
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
);
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
);
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());
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
));
239 basegfx::B3DVector
aDepth(aCurrB
- aCurrA
);
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
;
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
);
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
);
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
);
278 // set aNormalLeft as new normal at polygons
279 aSubA
.setNormal(b
, aNormalLeft
);
280 aSubB
.setNormal(b
, aNormalLeft
);
288 rPolA
.setB3DPolygon(a
, aSubA
);
289 rPolB
.setB3DPolygon(a
, aSubB
);
295 basegfx::B3DPolyPolygon
& rPolA
,
296 const basegfx::B3DPolyPolygon
& rPolB
,
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
);
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());
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(
340 aCurrent
, aEdgeVector
))
351 } // end of anonymous namespace
353 //////////////////////////////////////////////////////////////////////////////
355 namespace drawinglayer
357 namespace primitive3d
359 void createLatheSlices(
360 Slice3DVector
& rSliceVector
,
361 const basegfx::B2DPolyPolygon
& rSource
,
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()));
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
;
386 bCloseFront
= bCloseBack
= false;
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);
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
));
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)
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
));
447 rSliceVector
.push_back(Slice3D(aOuterBack
, aTransformBack
, SLICETYPE3D_BACKCAP
));
452 void createExtrudeSlices(
453 Slice3DVector
& rSliceVector
,
454 const basegfx::B2DPolyPolygon
& rSource
,
462 if(basegfx::fTools::equalZero(fDepth
))
464 // no depth, just one plane
465 rSliceVector
.push_back(Slice3D(rSource
, basegfx::B3DHomMatrix()));
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
;
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
);
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
));
502 const double fOffset(fDepth
* fDiagonal
* 0.5);
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
));
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());
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
);
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());
573 void extractPlanesFromSlice(
574 ::std::vector
< basegfx::B3DPolyPolygon
>& rFill
,
575 const Slice3DVector
& rSliceVector
,
577 bool bSmoothHorizontalNormals
,
581 double fSmoothNormalsMix
,
582 double fSmoothLidsMix
,
583 bool bCreateTextureCoordinates
,
584 const basegfx::B2DHomMatrix
& rTexTransform
)
586 const sal_uInt32
nNumSlices(rSliceVector
.size());
591 const sal_uInt32
nLoopCount(bClosed
? nNumSlices
: nNumSlices
- 1L);
592 basegfx::B3DPolyPolygon aEdgeRounding
;
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
;
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());
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
);
672 basegfx::B3DVector
aNormal(0.0, 0.0, -1.0);
676 aNormal
= -aFront
.getB3DPolygon(0L).getNormal();
679 impSetNormal(aFront
, aNormal
);
683 impCreateInBetweenNormals(aPolAA
, aPrev
, bSmoothHorizontalNormals
);
688 impMixNormals(aPolA
, aPolAA
, fSmoothNormalsMix
);
693 // take over from surface
700 impMixNormals(aFront
, aPrev
, fSmoothLidsMix
);
705 // take over from front
714 impMixNormals(aPolA
, aFront
, fSmoothNormalsMix
);
720 impMixNormals(aFront
, aPolA
, fSmoothLidsMix
);
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
);
738 rFill
.push_back(aFront
);
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
);
768 const basegfx::B3DVector
aNormal(aBack
.count() ? aBack
.getB3DPolygon(0L).getNormal() : basegfx::B3DVector(0.0, 0.0, 1.0));
769 impSetNormal(aBack
, aNormal
);
773 impCreateInBetweenNormals(aNext
, aPolBB
, bSmoothHorizontalNormals
);
778 impMixNormals(aPolB
, aPolBB
, fSmoothNormalsMix
);
783 // take over from surface
790 impMixNormals(aBack
, aNext
, fSmoothLidsMix
);
795 // take over from back
804 impMixNormals(aPolB
, aBack
, fSmoothNormalsMix
);
810 impMixNormals(aBack
, aPolB
, fSmoothLidsMix
);
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
);
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
];
856 // no loop, but a single slice (1 == nNumSlices), create a filling from the single
858 const Slice3D
& rSlice(rSliceVector
[0]);
859 basegfx::B3DPolyPolygon
aFront(rSlice
.getB3DPolyPolygon());
861 if(bCreateTextureCoordinates
)
863 aFront
= basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront
, aTexRangeFront
);
868 basegfx::B3DVector
aNormal(0.0, 0.0, -1.0);
872 aNormal
= -aFront
.getB3DPolygon(0L).getNormal();
875 impSetNormal(aFront
, aNormal
);
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
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());
945 if(fDistance
> fMaxLeft
)
947 fMaxLeft
= fDistance
;
951 else if(fCross
< 0.0)
953 if(fDistance
> fMaxRight
)
955 fMaxRight
= fDistance
;
967 basegfx::B3DPolygon aToBeAdded
;
968 aToBeAdded
.append(rLoopA
.getB3DPoint(nIndexLeft
));
969 aToBeAdded
.append(rLoopB
.getB3DPoint(nIndexLeft
));
970 rTarget
.append(aToBeAdded
);
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 //////////////////////////////////////////////////////////////////////////////
991 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */