1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: sdrextrudelathetools3d.cxx,v $
9 * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $
11 * The Contents of this file are made available subject to
12 * the terms of GNU Lesser General Public License Version 2.1.
15 * GNU Lesser General Public License Version 2.1
16 * =============================================
17 * Copyright 2005 by Sun Microsystems, Inc.
18 * 901 San Antonio Road, Palo Alto, CA 94303, USA
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License version 2.1, as published by the Free Software Foundation.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
34 ************************************************************************/
36 // MARKER(update_precomp.py): autogen include statement, do not remove
37 #include "precompiled_drawinglayer.hxx"
39 #include <drawinglayer/primitive3d/sdrextrudelathetools3d.hxx>
40 #include <basegfx/polygon/b2dpolypolygon.hxx>
41 #include <basegfx/range/b2drange.hxx>
42 #include <basegfx/polygon/b2dpolypolygontools.hxx>
43 #include <basegfx/matrix/b2dhommatrix.hxx>
44 #include <basegfx/point/b3dpoint.hxx>
45 #include <basegfx/polygon/b3dpolygon.hxx>
46 #include <basegfx/polygon/b3dpolygontools.hxx>
47 #include <basegfx/polygon/b3dpolypolygontools.hxx>
48 #include <basegfx/range/b3drange.hxx>
49 #include <basegfx/matrix/b3dhommatrix.hxx>
50 #include <basegfx/polygon/b2dpolygontools.hxx>
51 #include <drawinglayer/geometry/viewinformation3d.hxx>
54 //////////////////////////////////////////////////////////////////////////////
55 // decompositon helpers for extrude/lathe (rotation) objects
59 //////////////////////////////////////////////////////////////////////////////
62 basegfx::B2DPolyPolygon
impScalePolyPolygonOnCenter(
63 const basegfx::B2DPolyPolygon
& rSource
,
66 basegfx::B2DPolyPolygon
aRetval(rSource
);
68 if(!basegfx::fTools::equalZero(fScale
))
70 const basegfx::B2DRange
aRange(basegfx::tools::getRange(rSource
));
71 const basegfx::B2DPoint
aCenter(aRange
.getCenter());
72 basegfx::B2DHomMatrix aTrans
;
74 aTrans
.translate(-aCenter
.getX(), -aCenter
.getY());
75 aTrans
.scale(fScale
, fScale
);
76 aTrans
.translate(aCenter
.getX(), aCenter
.getY());
77 aRetval
.transform(aTrans
);
83 void impGetOuterPolyPolygon(
84 basegfx::B2DPolyPolygon
& rPolygon
,
85 basegfx::B2DPolyPolygon
& rOuterPolyPolygon
,
89 rOuterPolyPolygon
= rPolygon
;
91 if(basegfx::fTools::more(fOffset
, 0.0))
95 // grow the outside polygon and scale all polygons to original size. This is done
96 // to avoid a shrink which potentially would lead to self-intersections, but changes
97 // the original polygon -> not a precision step, so e.g. not usable for charts
98 const basegfx::B2DRange
aRange(basegfx::tools::getRange(rPolygon
));
99 rPolygon
= basegfx::tools::growInNormalDirection(rPolygon
, fOffset
);
100 const basegfx::B2DRange
aGrownRange(basegfx::tools::getRange(rPolygon
));
101 const double fScaleX(basegfx::fTools::equalZero(aGrownRange
.getWidth()) ? 1.0 : aRange
.getWidth() / aGrownRange
.getWidth());
102 const double fScaleY(basegfx::fTools::equalZero(aGrownRange
.getHeight())? 1.0 : aRange
.getHeight() / aGrownRange
.getHeight());
103 basegfx::B2DHomMatrix aScaleTrans
;
105 aScaleTrans
.translate(-aGrownRange
.getMinX(), -aGrownRange
.getMinY());
106 aScaleTrans
.scale(fScaleX
, fScaleY
);
107 aScaleTrans
.translate(aRange
.getMinX(), aRange
.getMinY());
108 rPolygon
.transform(aScaleTrans
);
109 rOuterPolyPolygon
.transform(aScaleTrans
);
113 // use more precision, shrink the outer polygons. Since this may lead to self-intersections,
114 // some kind of correction should be applied here after that step
115 rOuterPolyPolygon
= basegfx::tools::growInNormalDirection(rPolygon
, -fOffset
);
116 basegfx::tools::correctGrowShrinkPolygonPair(rPolygon
, rOuterPolyPolygon
);
121 void impAddInBetweenFill(
122 basegfx::B3DPolyPolygon
& rTarget
,
123 const basegfx::B3DPolyPolygon
& rPolA
,
124 const basegfx::B3DPolyPolygon
& rPolB
,
128 bool bCreateTextureCoordinates
)
130 OSL_ENSURE(rPolA
.count() == rPolB
.count(), "impAddInBetweenFill: unequally sized polygons (!)");
131 const sal_uInt32
nPolygonCount(rPolA
.count());
133 for(sal_uInt32
a(0L); a
< nPolygonCount
; a
++)
135 const basegfx::B3DPolygon
aSubA(rPolA
.getB3DPolygon(a
));
136 const basegfx::B3DPolygon
aSubB(rPolB
.getB3DPolygon(a
));
137 OSL_ENSURE(aSubA
.count() == aSubB
.count(), "impAddInBetweenFill: unequally sized polygons (!)");
138 const sal_uInt32
nPointCount(aSubA
.count());
142 const sal_uInt32
nEdgeCount(aSubA
.isClosed() ? nPointCount
: nPointCount
- 1L);
143 double fTexHorMultiplicatorA(0.0), fTexHorMultiplicatorB(0.0);
144 double fPolygonPosA(0.0), fPolygonPosB(0.0);
146 if(bCreateTextureCoordinates
)
148 const double fPolygonLengthA(basegfx::tools::getLength(aSubA
));
149 fTexHorMultiplicatorA
= basegfx::fTools::equalZero(fPolygonLengthA
) ? 1.0 : 1.0 / fPolygonLengthA
;
151 const double fPolygonLengthB(basegfx::tools::getLength(aSubB
));
152 fTexHorMultiplicatorB
= basegfx::fTools::equalZero(fPolygonLengthB
) ? 1.0 : 1.0 / fPolygonLengthB
;
155 for(sal_uInt32
b(0L); b
< nEdgeCount
; b
++)
157 const sal_uInt32
nIndexA(b
);
158 const sal_uInt32
nIndexB((b
+ 1L) % nPointCount
);
160 const basegfx::B3DPoint
aStartA(aSubA
.getB3DPoint(nIndexA
));
161 const basegfx::B3DPoint
aEndA(aSubA
.getB3DPoint(nIndexB
));
162 const basegfx::B3DPoint
aStartB(aSubB
.getB3DPoint(nIndexA
));
163 const basegfx::B3DPoint
aEndB(aSubB
.getB3DPoint(nIndexB
));
165 basegfx::B3DPolygon aNew
;
166 aNew
.setClosed(true);
168 aNew
.append(aStartA
);
169 aNew
.append(aStartB
);
175 aNew
.setNormal(0L, aSubA
.getNormal(nIndexA
));
176 aNew
.setNormal(1L, aSubB
.getNormal(nIndexA
));
177 aNew
.setNormal(2L, aSubB
.getNormal(nIndexB
));
178 aNew
.setNormal(3L, aSubA
.getNormal(nIndexB
));
181 if(bCreateTextureCoordinates
)
183 const double fRelTexAL(fPolygonPosA
* fTexHorMultiplicatorA
);
184 const double fEdgeLengthA(basegfx::B3DVector(aEndA
- aStartA
).getLength());
185 fPolygonPosA
+= fEdgeLengthA
;
186 const double fRelTexAR(fPolygonPosA
* fTexHorMultiplicatorA
);
188 const double fRelTexBL(fPolygonPosB
* fTexHorMultiplicatorB
);
189 const double fEdgeLengthB(basegfx::B3DVector(aEndB
- aStartB
).getLength());
190 fPolygonPosB
+= fEdgeLengthB
;
191 const double fRelTexBR(fPolygonPosB
* fTexHorMultiplicatorB
);
193 aNew
.setTextureCoordinate(0L, basegfx::B2DPoint(fRelTexAL
, fTexVerStart
));
194 aNew
.setTextureCoordinate(1L, basegfx::B2DPoint(fRelTexBL
, fTexVerStop
));
195 aNew
.setTextureCoordinate(2L, basegfx::B2DPoint(fRelTexBR
, fTexVerStop
));
196 aNew
.setTextureCoordinate(3L, basegfx::B2DPoint(fRelTexAR
, fTexVerStart
));
199 rTarget
.append(aNew
);
206 basegfx::B3DPolyPolygon
& rCandidate
,
207 const basegfx::B3DVector
& rNormal
)
209 for(sal_uInt32
a(0L); a
< rCandidate
.count(); a
++)
211 basegfx::B3DPolygon
aSub(rCandidate
.getB3DPolygon(a
));
213 for(sal_uInt32
b(0L); b
< aSub
.count(); b
++)
215 aSub
.setNormal(b
, rNormal
);
218 rCandidate
.setB3DPolygon(a
, aSub
);
222 void impCreateInBetweenNormals(
223 basegfx::B3DPolyPolygon
& rPolA
,
224 basegfx::B3DPolyPolygon
& rPolB
,
225 bool bSmoothHorizontalNormals
)
227 OSL_ENSURE(rPolA
.count() == rPolB
.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
229 for(sal_uInt32
a(0L); a
< rPolA
.count(); a
++)
231 basegfx::B3DPolygon
aSubA(rPolA
.getB3DPolygon(a
));
232 basegfx::B3DPolygon
aSubB(rPolB
.getB3DPolygon(a
));
233 OSL_ENSURE(aSubA
.count() == aSubB
.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
234 const sal_uInt32
nPointCount(aSubA
.count());
238 basegfx::B3DPoint
aPrevA(aSubA
.getB3DPoint(nPointCount
- 1L));
239 basegfx::B3DPoint
aCurrA(aSubA
.getB3DPoint(0L));
240 const bool bClosed(aSubA
.isClosed());
242 for(sal_uInt32
b(0L); b
< nPointCount
; b
++)
244 const sal_uInt32
nIndNext((b
+ 1L) % nPointCount
);
245 const basegfx::B3DPoint
aNextA(aSubA
.getB3DPoint(nIndNext
));
246 const basegfx::B3DPoint
aCurrB(aSubB
.getB3DPoint(b
));
249 basegfx::B3DVector
aDepth(aCurrB
- aCurrA
);
252 if(aDepth
.equalZero())
254 // no difference, try to get depth from next point
255 const basegfx::B3DPoint
aNextB(aSubB
.getB3DPoint(nIndNext
));
256 aDepth
= aNextB
- aNextA
;
260 // vector to left (correct for non-closed lines)
261 const bool bFirstAndNotClosed(!bClosed
&& 0L == b
);
262 basegfx::B3DVector
aLeft(bFirstAndNotClosed
? aCurrA
- aNextA
: aPrevA
- aCurrA
);
265 // create left normal
266 const basegfx::B3DVector
aNormalLeft(aDepth
.getPerpendicular(aLeft
));
268 if(bSmoothHorizontalNormals
)
270 // vector to right (correct for non-closed lines)
271 const bool bLastAndNotClosed(!bClosed
&& b
+ 1L == nPointCount
);
272 basegfx::B3DVector
aRight(bLastAndNotClosed
? aCurrA
- aPrevA
: aNextA
- aCurrA
);
275 // create right normal
276 const basegfx::B3DVector
aNormalRight(aRight
.getPerpendicular(aDepth
));
278 // create smoothed in-between normal
279 basegfx::B3DVector
aNewNormal(aNormalLeft
+ aNormalRight
);
280 aNewNormal
.normalize();
282 // set as new normal at polygons
283 aSubA
.setNormal(b
, aNewNormal
);
284 aSubB
.setNormal(b
, aNewNormal
);
288 // set aNormalLeft as new normal at polygons
289 aSubA
.setNormal(b
, aNormalLeft
);
290 aSubB
.setNormal(b
, aNormalLeft
);
298 rPolA
.setB3DPolygon(a
, aSubA
);
299 rPolB
.setB3DPolygon(a
, aSubB
);
305 basegfx::B3DPolyPolygon
& rPolA
,
306 const basegfx::B3DPolyPolygon
& rPolB
,
309 const double fWeightB(1.0 - fWeightA
);
310 OSL_ENSURE(rPolA
.count() == rPolB
.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
312 for(sal_uInt32
a(0L); a
< rPolA
.count(); a
++)
314 basegfx::B3DPolygon
aSubA(rPolA
.getB3DPolygon(a
));
315 const basegfx::B3DPolygon
aSubB(rPolB
.getB3DPolygon(a
));
316 OSL_ENSURE(aSubA
.count() == aSubB
.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
317 const sal_uInt32
nPointCount(aSubA
.count());
319 for(sal_uInt32
b(0L); b
< nPointCount
; b
++)
321 const basegfx::B3DVector
aVA(aSubA
.getNormal(b
) * fWeightA
);
322 const basegfx::B3DVector
aVB(aSubB
.getNormal(b
) * fWeightB
);
323 basegfx::B3DVector
aVNew(aVA
+ aVB
);
325 aSubA
.setNormal(b
, aVNew
);
328 rPolA
.setB3DPolygon(a
, aSubA
);
332 bool impHasCutWith(const basegfx::B2DPolygon
& rPoly
, const basegfx::B2DPoint
& rStart
, const basegfx::B2DPoint
& rEnd
)
334 // polygon is closed, one of the points is a member
335 const sal_uInt32
nPointCount(rPoly
.count());
339 basegfx::B2DPoint
aCurrent(rPoly
.getB2DPoint(0));
340 const basegfx::B2DVector
aVector(rEnd
- rStart
);
342 for(sal_uInt32
a(0); a
< nPointCount
; a
++)
344 const sal_uInt32
nNextIndex((a
+ 1) % nPointCount
);
345 const basegfx::B2DPoint
aNext(rPoly
.getB2DPoint(nNextIndex
));
346 const basegfx::B2DVector
aEdgeVector(aNext
- aCurrent
);
348 if(basegfx::tools::findCut(
350 aCurrent
, aEdgeVector
))
361 } // end of anonymous namespace
363 //////////////////////////////////////////////////////////////////////////////
365 namespace drawinglayer
367 namespace primitive3d
369 void createLatheSlices(
370 Slice3DVector
& rSliceVector
,
371 const basegfx::B2DPolyPolygon
& rSource
,
380 if(basegfx::fTools::equalZero(fRotation
) || 0L == nSteps
)
382 // no rotation or no steps, just one plane
383 rSliceVector
.push_back(Slice3D(rSource
, basegfx::B3DHomMatrix()));
387 const bool bBackScale(!basegfx::fTools::equal(fBackScale
, 1.0));
388 const bool bClosedRotation(!bBackScale
&& basegfx::fTools::equal(fRotation
, F_2PI
));
389 basegfx::B2DPolyPolygon
aFront(rSource
);
390 basegfx::B2DPolyPolygon
aBack(rSource
);
391 basegfx::B3DHomMatrix aTransformBack
;
392 basegfx::B2DPolyPolygon aOuterBack
;
396 bCloseFront
= bCloseBack
= false;
402 if(basegfx::fTools::equalZero(fBackScale
))
404 fBackScale
= 0.000001;
407 // back is scaled compared to front, create scaled version
408 aBack
= impScalePolyPolygonOnCenter(aBack
, fBackScale
);
411 if(bCloseFront
|| bCloseBack
)
413 const basegfx::B2DRange
aBaseRange(basegfx::tools::getRange(aFront
));
414 const double fOuterLength(aBaseRange
.getMaxX() * fRotation
);
415 const double fInnerLength(aBaseRange
.getMinX() * fRotation
);
416 const double fAverageLength((fOuterLength
+ fInnerLength
) * 0.5);
420 const double fOffsetLen((fAverageLength
/ 12.0) * fDiagonal
);
421 basegfx::B2DPolyPolygon aOuterFront
;
422 impGetOuterPolyPolygon(aFront
, aOuterFront
, fOffsetLen
, bCharacterMode
);
423 basegfx::B3DHomMatrix aTransform
;
424 aTransform
.translate(0.0, 0.0, fOffsetLen
);
425 rSliceVector
.push_back(Slice3D(aOuterFront
, aTransform
, SLICETYPE3D_FRONTCAP
));
430 const double fOffsetLen((fAverageLength
/ 12.0) * fDiagonal
);
431 impGetOuterPolyPolygon(aBack
, aOuterBack
, fOffsetLen
, bCharacterMode
);
432 aTransformBack
.translate(0.0, 0.0, -fOffsetLen
);
433 aTransformBack
.rotate(0.0, fRotation
, 0.0);
437 // add start polygon (a = 0L)
440 rSliceVector
.push_back(Slice3D(aFront
, basegfx::B3DHomMatrix()));
443 // create segments (a + 1 .. nSteps)
444 const double fStepSize(1.0 / (double)nSteps
);
446 for(sal_uInt32
a(0L); a
< nSteps
; a
++)
448 const double fStep((double)(a
+ 1L) * fStepSize
);
449 basegfx::B2DPolyPolygon
aNewPoly(bBackScale
? basegfx::tools::interpolate(aFront
, aBack
, fStep
) : aFront
);
450 basegfx::B3DHomMatrix aNewMat
;
451 aNewMat
.rotate(0.0, fRotation
* fStep
, 0.0);
452 rSliceVector
.push_back(Slice3D(aNewPoly
, aNewMat
));
457 rSliceVector
.push_back(Slice3D(aOuterBack
, aTransformBack
, SLICETYPE3D_BACKCAP
));
462 void createExtrudeSlices(
463 Slice3DVector
& rSliceVector
,
464 const basegfx::B2DPolyPolygon
& rSource
,
472 if(basegfx::fTools::equalZero(fDepth
))
474 // no depth, just one plane
475 rSliceVector
.push_back(Slice3D(rSource
, basegfx::B3DHomMatrix()));
479 // there is depth, create Polygons for front,back and their default depth positions
480 basegfx::B2DPolyPolygon
aFront(rSource
);
481 basegfx::B2DPolyPolygon
aBack(rSource
);
482 const bool bBackScale(!basegfx::fTools::equal(fBackScale
, 1.0));
483 double fZFront(fDepth
); // default depth for aFront
484 double fZBack(0.0); // default depth for aBack
485 basegfx::B2DPolyPolygon aOuterBack
;
490 if(basegfx::fTools::equalZero(fBackScale
))
492 fBackScale
= 0.000001;
495 // aFront is scaled compared to aBack, create scaled version
496 aFront
= impScalePolyPolygonOnCenter(aFront
, fBackScale
);
501 const double fOffset(fDepth
* fDiagonal
* 0.5);
502 fZFront
= fDepth
- fOffset
;
503 basegfx::B2DPolyPolygon aOuterFront
;
504 impGetOuterPolyPolygon(aFront
, aOuterFront
, fOffset
, bCharacterMode
);
505 basegfx::B3DHomMatrix aTransformFront
;
506 aTransformFront
.translate(0.0, 0.0, fDepth
);
507 rSliceVector
.push_back(Slice3D(aOuterFront
, aTransformFront
, SLICETYPE3D_FRONTCAP
));
512 const double fOffset(fDepth
* fDiagonal
* 0.5);
514 impGetOuterPolyPolygon(aBack
, aOuterBack
, fOffset
, bCharacterMode
);
517 // add front and back polygons at evtl. changed depths
519 basegfx::B3DHomMatrix aTransformA
, aTransformB
;
521 aTransformA
.translate(0.0, 0.0, fZFront
);
522 rSliceVector
.push_back(Slice3D(aFront
, aTransformA
));
524 aTransformB
.translate(0.0, 0.0, fZBack
);
525 rSliceVector
.push_back(Slice3D(aBack
, aTransformB
));
530 rSliceVector
.push_back(Slice3D(aOuterBack
, basegfx::B3DHomMatrix(), SLICETYPE3D_BACKCAP
));
535 basegfx::B3DPolyPolygon
extractHorizontalLinesFromSlice(const Slice3DVector
& rSliceVector
, bool bCloseHorLines
)
537 basegfx::B3DPolyPolygon aRetval
;
538 const sal_uInt32
nNumSlices(rSliceVector
.size());
542 const sal_uInt32
nSlideSubPolygonCount(rSliceVector
[0].getB3DPolyPolygon().count());
544 for(sal_uInt32
b(0); b
< nSlideSubPolygonCount
; b
++)
546 const sal_uInt32
nSubPolygonPointCount(rSliceVector
[0].getB3DPolyPolygon().getB3DPolygon(b
).count());
548 for(sal_uInt32
c(0); c
< nSubPolygonPointCount
; c
++)
550 basegfx::B3DPolygon aNew
;
552 for(sal_uInt32
d(0); d
< nNumSlices
; d
++)
554 OSL_ENSURE(nSlideSubPolygonCount
== rSliceVector
[d
].getB3DPolyPolygon().count(),
555 "Slice PolyPolygon with different Polygon count (!)");
556 OSL_ENSURE(nSubPolygonPointCount
== rSliceVector
[d
].getB3DPolyPolygon().getB3DPolygon(b
).count(),
557 "Slice Polygon with different point count (!)");
558 aNew
.append(rSliceVector
[d
].getB3DPolyPolygon().getB3DPolygon(b
).getB3DPoint(c
));
561 aNew
.setClosed(bCloseHorLines
);
562 aRetval
.append(aNew
);
570 basegfx::B3DPolyPolygon
extractVerticalLinesFromSlice(const Slice3DVector
& rSliceVector
)
572 basegfx::B3DPolyPolygon aRetval
;
573 const sal_uInt32
nNumSlices(rSliceVector
.size());
575 for(sal_uInt32
a(0L); a
< nNumSlices
; a
++)
577 aRetval
.append(rSliceVector
[a
].getB3DPolyPolygon());
583 void extractPlanesFromSlice(
584 ::std::vector
< basegfx::B3DPolyPolygon
>& rFill
,
585 const Slice3DVector
& rSliceVector
,
587 bool bSmoothHorizontalNormals
,
591 double fSmoothNormalsMix
,
592 double fSmoothLidsMix
,
593 bool bCreateTextureCoordinates
,
594 const basegfx::B2DHomMatrix
& rTexTransform
)
596 const sal_uInt32
nNumSlices(rSliceVector
.size());
601 const sal_uInt32
nLoopCount(bClosed
? nNumSlices
: nNumSlices
- 1L);
602 basegfx::B3DPolyPolygon aEdgeRounding
;
605 // tetxture parameters
606 double fInvTexHeight(1.0);
607 double fTexHeightPos(0.0);
608 double fTexStart(0.0);
609 double fTexStop(1.0);
610 ::std::vector
<double> aTexHeightArray
;
611 basegfx::B3DRange aTexRangeFront
;
612 basegfx::B3DRange aTexRangeBack
;
614 if(bCreateTextureCoordinates
)
616 aTexRangeFront
= basegfx::tools::getRange(rSliceVector
[0L].getB3DPolyPolygon());
617 aTexRangeBack
= basegfx::tools::getRange(rSliceVector
[nNumSlices
- 1L].getB3DPolyPolygon());
619 if(aTexRangeBack
.getDepth() > aTexRangeBack
.getWidth())
621 // last polygon is rotated so that depth is bigger than width, exchange X and Z
622 // for making applyDefaultTextureCoordinatesParallel use Z instead of X for
623 // horizontal texture coordinate
624 aTexRangeBack
= basegfx::B3DRange(
625 aTexRangeBack
.getMinZ(), aTexRangeBack
.getMinY(), aTexRangeBack
.getMinX(),
626 aTexRangeBack
.getMaxZ(), aTexRangeBack
.getMaxY(), aTexRangeBack
.getMaxX());
629 basegfx::B3DPoint
aCenter(basegfx::tools::getRange(rSliceVector
[0L].getB3DPolyPolygon()).getCenter());
631 for(a
= 0L; a
< nLoopCount
; a
++)
633 const basegfx::B3DPoint
aNextCenter(basegfx::tools::getRange(rSliceVector
[(a
+ 1L) % nNumSlices
].getB3DPolyPolygon()).getCenter());
634 const double fLength(basegfx::B3DVector(aNextCenter
- aCenter
).getLength());
635 aTexHeightArray
.push_back(fLength
);
636 aCenter
= aNextCenter
;
639 const double fTexHeight(::std::accumulate(aTexHeightArray
.begin(), aTexHeightArray
.end(), 0.0));
641 if(!basegfx::fTools::equalZero(fTexHeight
))
643 fInvTexHeight
= 1.0 / fTexHeight
;
649 for(a
= 0L; a
< nLoopCount
; a
++)
651 const Slice3D
& rSliceA(rSliceVector
[a
]);
652 const Slice3D
& rSliceB(rSliceVector
[(a
+ 1L) % nNumSlices
]);
653 const bool bAcceptPair(SLICETYPE3D_REGULAR
== rSliceA
.getSliceType() && SLICETYPE3D_REGULAR
== rSliceB
.getSliceType());
654 basegfx::B3DPolyPolygon
aPolA(rSliceA
.getB3DPolyPolygon());
655 basegfx::B3DPolyPolygon
aPolB(rSliceB
.getB3DPolyPolygon());
661 impCreateInBetweenNormals(aPolB
, aPolA
, bSmoothHorizontalNormals
);
665 const sal_uInt32
nIndPrev((a
+ nNumSlices
- 1L) % nNumSlices
);
666 const Slice3D
& rSlicePrev(rSliceVector
[nIndPrev
]);
667 basegfx::B3DPolyPolygon
aPrev(rSlicePrev
.getB3DPolyPolygon());
668 basegfx::B3DPolyPolygon
aPolAA(rSliceA
.getB3DPolyPolygon());
670 if(SLICETYPE3D_FRONTCAP
== rSlicePrev
.getSliceType())
672 basegfx::B3DPolyPolygon
aFront(rSlicePrev
.getB3DPolyPolygon());
673 const bool bHasSlant(aPolAA
!= aPrev
);
675 if(bCreateTextureCoordinates
)
677 aFront
= basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront
, aTexRangeFront
);
682 basegfx::B3DVector
aNormal(0.0, 0.0, -1.0);
686 aNormal
= -aFront
.getB3DPolygon(0L).getNormal();
689 impSetNormal(aFront
, aNormal
);
693 impCreateInBetweenNormals(aPolAA
, aPrev
, bSmoothHorizontalNormals
);
698 impMixNormals(aPolA
, aPolAA
, fSmoothNormalsMix
);
703 // take over from surface
710 impMixNormals(aFront
, aPrev
, fSmoothLidsMix
);
715 // take over from front
724 impMixNormals(aPolA
, aFront
, fSmoothNormalsMix
);
730 impMixNormals(aFront
, aPolA
, fSmoothLidsMix
);
738 if(bCreateTextureCoordinates
)
740 fTexStart
= fTexHeightPos
* fInvTexHeight
;
741 fTexStop
= (fTexHeightPos
- aTexHeightArray
[(a
+ nLoopCount
- 1L) % nLoopCount
]) * fInvTexHeight
;
744 impAddInBetweenFill(aEdgeRounding
, aPolAA
, aPrev
, fTexStart
, fTexStop
, bCreateNormals
, bCreateTextureCoordinates
);
748 rFill
.push_back(aFront
);
752 if(bCreateNormals
&& bSmoothNormals
&& (nIndPrev
!= a
+ 1L))
754 impCreateInBetweenNormals(aPolAA
, aPrev
, bSmoothHorizontalNormals
);
755 impMixNormals(aPolA
, aPolAA
, 0.5);
761 const sal_uInt32
nIndNext((a
+ 2L) % nNumSlices
);
762 const Slice3D
& rSliceNext(rSliceVector
[nIndNext
]);
763 basegfx::B3DPolyPolygon
aNext(rSliceNext
.getB3DPolyPolygon());
764 basegfx::B3DPolyPolygon
aPolBB(rSliceB
.getB3DPolyPolygon());
766 if(SLICETYPE3D_BACKCAP
== rSliceNext
.getSliceType())
768 basegfx::B3DPolyPolygon
aBack(rSliceNext
.getB3DPolyPolygon());
769 const bool bHasSlant(aPolBB
!= aNext
);
771 if(bCreateTextureCoordinates
)
773 aBack
= basegfx::tools::applyDefaultTextureCoordinatesParallel(aBack
, aTexRangeBack
);
778 const basegfx::B3DVector
aNormal(aBack
.count() ? aBack
.getB3DPolygon(0L).getNormal() : basegfx::B3DVector(0.0, 0.0, 1.0));
779 impSetNormal(aBack
, aNormal
);
783 impCreateInBetweenNormals(aNext
, aPolBB
, bSmoothHorizontalNormals
);
788 impMixNormals(aPolB
, aPolBB
, fSmoothNormalsMix
);
793 // take over from surface
800 impMixNormals(aBack
, aNext
, fSmoothLidsMix
);
805 // take over from back
814 impMixNormals(aPolB
, aBack
, fSmoothNormalsMix
);
820 impMixNormals(aBack
, aPolB
, fSmoothLidsMix
);
828 if(bCreateTextureCoordinates
)
830 fTexStart
= (fTexHeightPos
+ aTexHeightArray
[a
] + aTexHeightArray
[(a
+ 1L) % nLoopCount
]) * fInvTexHeight
;
831 fTexStop
= (fTexHeightPos
+ aTexHeightArray
[a
]) * fInvTexHeight
;
834 impAddInBetweenFill(aEdgeRounding
, aNext
, aPolBB
, fTexStart
, fTexStop
, bCreateNormals
, bCreateTextureCoordinates
);
837 rFill
.push_back(aBack
);
841 if(bCreateNormals
&& bSmoothNormals
&& (nIndNext
!= a
))
843 impCreateInBetweenNormals(aNext
, aPolBB
, bSmoothHorizontalNormals
);
844 impMixNormals(aPolB
, aPolBB
, 0.5);
849 if(bCreateTextureCoordinates
)
851 fTexStart
= (fTexHeightPos
+ aTexHeightArray
[a
]) * fInvTexHeight
;
852 fTexStop
= fTexHeightPos
* fInvTexHeight
;
855 impAddInBetweenFill(aEdgeRounding
, aPolB
, aPolA
, fTexStart
, fTexStop
, bCreateNormals
, bCreateTextureCoordinates
);
858 if(bCreateTextureCoordinates
)
860 fTexHeightPos
+= aTexHeightArray
[a
];
866 // no loop, but a single slice (1 == nNumSlices), create a filling from the single
868 const Slice3D
& rSlice(rSliceVector
[0]);
869 basegfx::B3DPolyPolygon
aFront(rSlice
.getB3DPolyPolygon());
871 if(bCreateTextureCoordinates
)
873 aFront
= basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront
, aTexRangeFront
);
878 basegfx::B3DVector
aNormal(0.0, 0.0, -1.0);
882 aNormal
= -aFront
.getB3DPolygon(0L).getNormal();
885 impSetNormal(aFront
, aNormal
);
889 rFill
.push_back(aFront
);
892 if(bCreateTextureCoordinates
)
894 aEdgeRounding
.transformTextureCoordiantes(rTexTransform
);
897 for(a
= 0L; a
< aEdgeRounding
.count(); a
++)
899 rFill
.push_back(basegfx::B3DPolyPolygon(aEdgeRounding
.getB3DPolygon(a
)));
904 void createReducedOutlines(
905 const geometry::ViewInformation3D
& rViewInformation
,
906 const basegfx::B3DHomMatrix
& rObjectTransform
,
907 const basegfx::B3DPolygon
& rLoopA
,
908 const basegfx::B3DPolygon
& rLoopB
,
909 basegfx::B3DPolyPolygon
& rTarget
)
911 const sal_uInt32
nPointCount(rLoopA
.count());
913 // with idetic polygons there are no outlines
916 if(nPointCount
&& nPointCount
== rLoopB
.count())
918 const basegfx::B3DHomMatrix
aObjectTransform(rViewInformation
.getObjectToView() * rObjectTransform
);
919 const basegfx::B2DPolygon
a2DLoopA(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopA
, aObjectTransform
));
920 const basegfx::B2DPolygon
a2DLoopB(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopB
, aObjectTransform
));
921 const basegfx::B2DPoint
a2DCenterA(a2DLoopA
.getB2DRange().getCenter());
922 const basegfx::B2DPoint
a2DCenterB(a2DLoopB
.getB2DRange().getCenter());
924 // without detectable Y-Axis there are no outlines
925 if(!a2DCenterA
.equal(a2DCenterB
))
927 // search for outmost left and right inter-loop-edges which do not cut the loops
928 const basegfx::B2DPoint
aCommonCenter(basegfx::average(a2DCenterA
, a2DCenterB
));
929 const basegfx::B2DVector
aAxisVector(a2DCenterA
- a2DCenterB
);
930 double fMaxLeft(0.0);
931 double fMaxRight(0.0);
932 sal_uInt32
nIndexLeft(0);
933 sal_uInt32
nIndexRight(0);
935 for(sal_uInt32
a(0); a
< nPointCount
; a
++)
937 const basegfx::B2DPoint
aStart(a2DLoopA
.getB2DPoint(a
));
938 const basegfx::B2DPoint
aEnd(a2DLoopB
.getB2DPoint(a
));
939 const basegfx::B2DPoint
aMiddle(basegfx::average(aStart
, aEnd
));
941 if(!basegfx::tools::isInside(a2DLoopA
, aMiddle
))
943 if(!basegfx::tools::isInside(a2DLoopB
, aMiddle
))
945 if(!impHasCutWith(a2DLoopA
, aStart
, aEnd
))
947 if(!impHasCutWith(a2DLoopB
, aStart
, aEnd
))
949 const basegfx::B2DVector
aCandidateVector(aMiddle
- aCommonCenter
);
950 const double fCross(aCandidateVector
.cross(aAxisVector
));
951 const double fDistance(aCandidateVector
.getLength());
955 if(fDistance
> fMaxLeft
)
957 fMaxLeft
= fDistance
;
961 else if(fCross
< 0.0)
963 if(fDistance
> fMaxRight
)
965 fMaxRight
= fDistance
;
977 basegfx::B3DPolygon aToBeAdded
;
978 aToBeAdded
.append(rLoopA
.getB3DPoint(nIndexLeft
));
979 aToBeAdded
.append(rLoopB
.getB3DPoint(nIndexLeft
));
980 rTarget
.append(aToBeAdded
);
985 basegfx::B3DPolygon aToBeAdded
;
986 aToBeAdded
.append(rLoopA
.getB3DPoint(nIndexRight
));
987 aToBeAdded
.append(rLoopB
.getB3DPoint(nIndexRight
));
988 rTarget
.append(aToBeAdded
);
995 } // end of namespace primitive3d
996 } // end of namespace drawinglayer
998 //////////////////////////////////////////////////////////////////////////////