xref: /AOO41X/main/drawinglayer/source/primitive3d/sdrextrudeprimitive3d.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_drawinglayer.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include <drawinglayer/primitive3d/sdrextrudeprimitive3d.hxx>
32*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx>
33*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
34*cdf0e10cSrcweir #include <basegfx/polygon/b3dpolypolygontools.hxx>
35*cdf0e10cSrcweir #include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx>
36*cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx>
37*cdf0e10cSrcweir #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
38*cdf0e10cSrcweir #include <drawinglayer/geometry/viewinformation3d.hxx>
39*cdf0e10cSrcweir #include <drawinglayer/attribute/sdrfillattribute.hxx>
40*cdf0e10cSrcweir #include <drawinglayer/attribute/sdrlineattribute.hxx>
41*cdf0e10cSrcweir #include <drawinglayer/attribute/sdrshadowattribute.hxx>
42*cdf0e10cSrcweir 
43*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
44*cdf0e10cSrcweir 
45*cdf0e10cSrcweir using namespace com::sun::star;
46*cdf0e10cSrcweir 
47*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
48*cdf0e10cSrcweir 
49*cdf0e10cSrcweir namespace drawinglayer
50*cdf0e10cSrcweir {
51*cdf0e10cSrcweir 	namespace primitive3d
52*cdf0e10cSrcweir 	{
53*cdf0e10cSrcweir 		Primitive3DSequence SdrExtrudePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const
54*cdf0e10cSrcweir 		{
55*cdf0e10cSrcweir 			Primitive3DSequence aRetval;
56*cdf0e10cSrcweir 
57*cdf0e10cSrcweir 			// get slices
58*cdf0e10cSrcweir 			const Slice3DVector& rSliceVector = getSlices();
59*cdf0e10cSrcweir 
60*cdf0e10cSrcweir 			if(rSliceVector.size())
61*cdf0e10cSrcweir 			{
62*cdf0e10cSrcweir 				sal_uInt32 a;
63*cdf0e10cSrcweir 
64*cdf0e10cSrcweir 				// decide what to create
65*cdf0e10cSrcweir 				const ::com::sun::star::drawing::NormalsKind eNormalsKind(getSdr3DObjectAttribute().getNormalsKind());
66*cdf0e10cSrcweir 				const bool bCreateNormals(::com::sun::star::drawing::NormalsKind_SPECIFIC == eNormalsKind);
67*cdf0e10cSrcweir 				const bool bCreateTextureCoordiantesX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX());
68*cdf0e10cSrcweir 				const bool bCreateTextureCoordiantesY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY());
69*cdf0e10cSrcweir 				double fRelativeTextureWidth(1.0);
70*cdf0e10cSrcweir 				basegfx::B2DHomMatrix aTexTransform;
71*cdf0e10cSrcweir 
72*cdf0e10cSrcweir 				if(!getSdrLFSAttribute().getFill().isDefault() && (bCreateTextureCoordiantesX || bCreateTextureCoordiantesY))
73*cdf0e10cSrcweir 				{
74*cdf0e10cSrcweir 					const basegfx::B2DPolygon aFirstPolygon(maCorrectedPolyPolygon.getB2DPolygon(0L));
75*cdf0e10cSrcweir 					const double fFrontLength(basegfx::tools::getLength(aFirstPolygon));
76*cdf0e10cSrcweir 					const double fFrontArea(basegfx::tools::getArea(aFirstPolygon));
77*cdf0e10cSrcweir 					const double fSqrtFrontArea(sqrt(fFrontArea));
78*cdf0e10cSrcweir 					fRelativeTextureWidth = basegfx::fTools::equalZero(fSqrtFrontArea) ? 1.0 : fFrontLength / fSqrtFrontArea;
79*cdf0e10cSrcweir 					fRelativeTextureWidth = (double)((sal_uInt32)(fRelativeTextureWidth - 0.5));
80*cdf0e10cSrcweir 
81*cdf0e10cSrcweir 					if(fRelativeTextureWidth < 1.0)
82*cdf0e10cSrcweir 					{
83*cdf0e10cSrcweir 						fRelativeTextureWidth = 1.0;
84*cdf0e10cSrcweir 					}
85*cdf0e10cSrcweir 
86*cdf0e10cSrcweir 					aTexTransform.translate(-0.5, -0.5);
87*cdf0e10cSrcweir 					aTexTransform.scale(-1.0, -1.0);
88*cdf0e10cSrcweir 					aTexTransform.translate(0.5, 0.5);
89*cdf0e10cSrcweir 					aTexTransform.scale(fRelativeTextureWidth, 1.0);
90*cdf0e10cSrcweir 				}
91*cdf0e10cSrcweir 
92*cdf0e10cSrcweir 				// create geometry
93*cdf0e10cSrcweir 				::std::vector< basegfx::B3DPolyPolygon > aFill;
94*cdf0e10cSrcweir 				extractPlanesFromSlice(aFill, rSliceVector,
95*cdf0e10cSrcweir 					bCreateNormals, getSmoothHorizontalNormals(), getSmoothNormals(), getSmoothLids(), false,
96*cdf0e10cSrcweir 					0.5, 0.6, bCreateTextureCoordiantesX || bCreateTextureCoordiantesY, aTexTransform);
97*cdf0e10cSrcweir 
98*cdf0e10cSrcweir 				// get full range
99*cdf0e10cSrcweir 				const basegfx::B3DRange aRange(getRangeFrom3DGeometry(aFill));
100*cdf0e10cSrcweir 
101*cdf0e10cSrcweir 				// normal creation
102*cdf0e10cSrcweir 				if(!getSdrLFSAttribute().getFill().isDefault())
103*cdf0e10cSrcweir 				{
104*cdf0e10cSrcweir 					if(::com::sun::star::drawing::NormalsKind_SPHERE == eNormalsKind)
105*cdf0e10cSrcweir 					{
106*cdf0e10cSrcweir 						applyNormalsKindSphereTo3DGeometry(aFill, aRange);
107*cdf0e10cSrcweir 					}
108*cdf0e10cSrcweir 					else if(::com::sun::star::drawing::NormalsKind_FLAT == eNormalsKind)
109*cdf0e10cSrcweir 					{
110*cdf0e10cSrcweir 						applyNormalsKindFlatTo3DGeometry(aFill);
111*cdf0e10cSrcweir 					}
112*cdf0e10cSrcweir 
113*cdf0e10cSrcweir 					if(getSdr3DObjectAttribute().getNormalsInvert())
114*cdf0e10cSrcweir 					{
115*cdf0e10cSrcweir 						applyNormalsInvertTo3DGeometry(aFill);
116*cdf0e10cSrcweir 					}
117*cdf0e10cSrcweir 				}
118*cdf0e10cSrcweir 
119*cdf0e10cSrcweir 				// texture coordinates
120*cdf0e10cSrcweir 				if(!getSdrLFSAttribute().getFill().isDefault())
121*cdf0e10cSrcweir 				{
122*cdf0e10cSrcweir 					applyTextureTo3DGeometry(
123*cdf0e10cSrcweir 						getSdr3DObjectAttribute().getTextureProjectionX(),
124*cdf0e10cSrcweir 						getSdr3DObjectAttribute().getTextureProjectionY(),
125*cdf0e10cSrcweir 						aFill,
126*cdf0e10cSrcweir 						aRange,
127*cdf0e10cSrcweir 						getTextureSize());
128*cdf0e10cSrcweir 				}
129*cdf0e10cSrcweir 
130*cdf0e10cSrcweir 				if(!getSdrLFSAttribute().getFill().isDefault())
131*cdf0e10cSrcweir 				{
132*cdf0e10cSrcweir 					// add fill
133*cdf0e10cSrcweir 					aRetval = create3DPolyPolygonFillPrimitives(
134*cdf0e10cSrcweir 						aFill,
135*cdf0e10cSrcweir 						getTransform(),
136*cdf0e10cSrcweir 						getTextureSize(),
137*cdf0e10cSrcweir 						getSdr3DObjectAttribute(),
138*cdf0e10cSrcweir 						getSdrLFSAttribute().getFill(),
139*cdf0e10cSrcweir 						getSdrLFSAttribute().getFillFloatTransGradient());
140*cdf0e10cSrcweir 				}
141*cdf0e10cSrcweir 				else
142*cdf0e10cSrcweir 				{
143*cdf0e10cSrcweir 					// create simplified 3d hit test geometry
144*cdf0e10cSrcweir                     aRetval = createHiddenGeometryPrimitives3D(
145*cdf0e10cSrcweir 				        aFill,
146*cdf0e10cSrcweir 				        getTransform(),
147*cdf0e10cSrcweir 				        getTextureSize(),
148*cdf0e10cSrcweir 				        getSdr3DObjectAttribute());
149*cdf0e10cSrcweir 				}
150*cdf0e10cSrcweir 
151*cdf0e10cSrcweir 				// add line
152*cdf0e10cSrcweir 				if(!getSdrLFSAttribute().getLine().isDefault())
153*cdf0e10cSrcweir 				{
154*cdf0e10cSrcweir 					if(getSdr3DObjectAttribute().getReducedLineGeometry())
155*cdf0e10cSrcweir                     {
156*cdf0e10cSrcweir 						// create geometric outlines with reduced line geometry for chart.
157*cdf0e10cSrcweir 						const basegfx::B3DPolyPolygon aVerLine(extractVerticalLinesFromSlice(rSliceVector));
158*cdf0e10cSrcweir 						const sal_uInt32 nCount(aVerLine.count());
159*cdf0e10cSrcweir 						basegfx::B3DPolyPolygon aReducedLoops;
160*cdf0e10cSrcweir 						basegfx::B3DPolyPolygon aNewLineGeometry;
161*cdf0e10cSrcweir 
162*cdf0e10cSrcweir 						// sort out doubles (front and back planes when no edge rounding is done). Since
163*cdf0e10cSrcweir 						// this is a line geometry merged from PolyPolygons, loop over all Polygons
164*cdf0e10cSrcweir 						for(a = 0; a < nCount; a++)
165*cdf0e10cSrcweir 						{
166*cdf0e10cSrcweir 							const sal_uInt32 nReducedCount(aReducedLoops.count());
167*cdf0e10cSrcweir 							const basegfx::B3DPolygon aCandidate(aVerLine.getB3DPolygon(a));
168*cdf0e10cSrcweir 							bool bAdd(true);
169*cdf0e10cSrcweir 
170*cdf0e10cSrcweir 							if(nReducedCount)
171*cdf0e10cSrcweir 							{
172*cdf0e10cSrcweir 								for(sal_uInt32 b(0); bAdd && b < nReducedCount; b++)
173*cdf0e10cSrcweir 								{
174*cdf0e10cSrcweir 									if(aCandidate == aReducedLoops.getB3DPolygon(b))
175*cdf0e10cSrcweir 									{
176*cdf0e10cSrcweir 										bAdd = false;
177*cdf0e10cSrcweir 									}
178*cdf0e10cSrcweir 								}
179*cdf0e10cSrcweir 							}
180*cdf0e10cSrcweir 
181*cdf0e10cSrcweir 							if(bAdd)
182*cdf0e10cSrcweir 							{
183*cdf0e10cSrcweir 								aReducedLoops.append(aCandidate);
184*cdf0e10cSrcweir 							}
185*cdf0e10cSrcweir 						}
186*cdf0e10cSrcweir 
187*cdf0e10cSrcweir 						// from here work with reduced loops and reduced count without changing them
188*cdf0e10cSrcweir 						const sal_uInt32 nReducedCount(aReducedLoops.count());
189*cdf0e10cSrcweir 
190*cdf0e10cSrcweir 						if(nReducedCount > 1)
191*cdf0e10cSrcweir 						{
192*cdf0e10cSrcweir 							for(sal_uInt32 b(1); b < nReducedCount; b++)
193*cdf0e10cSrcweir 							{
194*cdf0e10cSrcweir 								// get loop pair
195*cdf0e10cSrcweir 								const basegfx::B3DPolygon aCandA(aReducedLoops.getB3DPolygon(b - 1));
196*cdf0e10cSrcweir 								const basegfx::B3DPolygon aCandB(aReducedLoops.getB3DPolygon(b));
197*cdf0e10cSrcweir 
198*cdf0e10cSrcweir 								// for each loop pair create the connection edges
199*cdf0e10cSrcweir 								createReducedOutlines(
200*cdf0e10cSrcweir 									rViewInformation,
201*cdf0e10cSrcweir 									getTransform(),
202*cdf0e10cSrcweir 									aCandA,
203*cdf0e10cSrcweir 									aCandB,
204*cdf0e10cSrcweir 									aNewLineGeometry);
205*cdf0e10cSrcweir 							}
206*cdf0e10cSrcweir 						}
207*cdf0e10cSrcweir 
208*cdf0e10cSrcweir 						// add reduced loops themselves
209*cdf0e10cSrcweir 						aNewLineGeometry.append(aReducedLoops);
210*cdf0e10cSrcweir 
211*cdf0e10cSrcweir 						// to create vertical edges at non-C1/C2 steady loops, use maCorrectedPolyPolygon
212*cdf0e10cSrcweir 						// directly since the 3D Polygons do not suport this.
213*cdf0e10cSrcweir 						//
214*cdf0e10cSrcweir 						// Unfortunately there is no bezier polygon provided by the chart module; one reason is
215*cdf0e10cSrcweir 						// that the API for extrude wants a 3D polygon geometry (for historical reasons, i guess)
216*cdf0e10cSrcweir 						// and those have no beziers. Another reason is that he chart module uses self-created
217*cdf0e10cSrcweir 						// stuff to create the 2D geometry (in ShapeFactory::createPieSegment), but this geometry
218*cdf0e10cSrcweir 						// does not contain bezier infos, either. The only way which is possible for now is to 'detect'
219*cdf0e10cSrcweir 						// candidates for vertical edges of pie segments by looking for the angles in the polygon.
220*cdf0e10cSrcweir 						//
221*cdf0e10cSrcweir 						// This is all not very well designed ATM. Ideally, the ReducedLineGeometry is responsible
222*cdf0e10cSrcweir 						// for creating the outer geometry edges (createReducedOutlines), but for special edges
223*cdf0e10cSrcweir 						// like the vertical ones for pie center and both start/end, the incarnation with the
224*cdf0e10cSrcweir 						// knowledge about that it needs to create those and IS a pie segment -> in this case,
225*cdf0e10cSrcweir 						// the chart itself.
226*cdf0e10cSrcweir 						const sal_uInt32 nPolyCount(maCorrectedPolyPolygon.count());
227*cdf0e10cSrcweir 
228*cdf0e10cSrcweir 						for(sal_uInt32 c(0); c < nPolyCount; c++)
229*cdf0e10cSrcweir 						{
230*cdf0e10cSrcweir 							const basegfx::B2DPolygon aCandidate(maCorrectedPolyPolygon.getB2DPolygon(c));
231*cdf0e10cSrcweir 							const sal_uInt32 nPointCount(aCandidate.count());
232*cdf0e10cSrcweir 
233*cdf0e10cSrcweir 							if(nPointCount > 2)
234*cdf0e10cSrcweir 							{
235*cdf0e10cSrcweir 								sal_uInt32 nIndexA(nPointCount);
236*cdf0e10cSrcweir 								sal_uInt32 nIndexB(nPointCount);
237*cdf0e10cSrcweir 								sal_uInt32 nIndexC(nPointCount);
238*cdf0e10cSrcweir 
239*cdf0e10cSrcweir 								for(sal_uInt32 d(0); d < nPointCount; d++)
240*cdf0e10cSrcweir 								{
241*cdf0e10cSrcweir 									const sal_uInt32 nPrevInd((d + nPointCount - 1) % nPointCount);
242*cdf0e10cSrcweir 									const sal_uInt32 nNextInd((d + 1) % nPointCount);
243*cdf0e10cSrcweir 									const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(d));
244*cdf0e10cSrcweir 									const basegfx::B2DVector aPrev(aCandidate.getB2DPoint(nPrevInd) - aPoint);
245*cdf0e10cSrcweir 									const basegfx::B2DVector aNext(aCandidate.getB2DPoint(nNextInd) - aPoint);
246*cdf0e10cSrcweir 									const double fAngle(aPrev.angle(aNext));
247*cdf0e10cSrcweir 
248*cdf0e10cSrcweir 									// take each angle which deviates more than 10% from going straight as
249*cdf0e10cSrcweir 									// special edge. This will detect the two outer edges of pie segments,
250*cdf0e10cSrcweir 									// but not always the center one (think about a near 180 degree pie)
251*cdf0e10cSrcweir 									if(F_PI - fabs(fAngle) > F_PI * 0.1)
252*cdf0e10cSrcweir 									{
253*cdf0e10cSrcweir 										if(nPointCount == nIndexA)
254*cdf0e10cSrcweir 										{
255*cdf0e10cSrcweir 											nIndexA = d;
256*cdf0e10cSrcweir 										}
257*cdf0e10cSrcweir 										else if(nPointCount == nIndexB)
258*cdf0e10cSrcweir 										{
259*cdf0e10cSrcweir 											nIndexB = d;
260*cdf0e10cSrcweir 										}
261*cdf0e10cSrcweir 										else if(nPointCount == nIndexC)
262*cdf0e10cSrcweir 										{
263*cdf0e10cSrcweir 											nIndexC = d;
264*cdf0e10cSrcweir 											d = nPointCount;
265*cdf0e10cSrcweir 										}
266*cdf0e10cSrcweir 									}
267*cdf0e10cSrcweir 								}
268*cdf0e10cSrcweir 
269*cdf0e10cSrcweir 								const bool bIndexAUsed(nIndexA != nPointCount);
270*cdf0e10cSrcweir 								const bool bIndexBUsed(nIndexB != nPointCount);
271*cdf0e10cSrcweir 								bool bIndexCUsed(nIndexC != nPointCount);
272*cdf0e10cSrcweir 
273*cdf0e10cSrcweir 								if(bIndexCUsed)
274*cdf0e10cSrcweir 								{
275*cdf0e10cSrcweir 									// already three special edges found, so the center one was already detected
276*cdf0e10cSrcweir 									// and does not need to be searched
277*cdf0e10cSrcweir 								}
278*cdf0e10cSrcweir 								else if(bIndexAUsed && bIndexBUsed)
279*cdf0e10cSrcweir 								{
280*cdf0e10cSrcweir 									// outer edges detected (they are approx. 90 degrees), but center one not.
281*cdf0e10cSrcweir 									// Look with the knowledge that it's in-between the two found ones
282*cdf0e10cSrcweir 									if(((nIndexA + 2) % nPointCount) == nIndexB)
283*cdf0e10cSrcweir 									{
284*cdf0e10cSrcweir 										nIndexC = (nIndexA + 1) % nPointCount;
285*cdf0e10cSrcweir 									}
286*cdf0e10cSrcweir 									else if(((nIndexA + nPointCount - 2) % nPointCount) == nIndexB)
287*cdf0e10cSrcweir 									{
288*cdf0e10cSrcweir 										nIndexC = (nIndexA + nPointCount - 1) % nPointCount;
289*cdf0e10cSrcweir 									}
290*cdf0e10cSrcweir 
291*cdf0e10cSrcweir 									bIndexCUsed = (nIndexC != nPointCount);
292*cdf0e10cSrcweir 								}
293*cdf0e10cSrcweir 
294*cdf0e10cSrcweir 								if(bIndexAUsed)
295*cdf0e10cSrcweir 								{
296*cdf0e10cSrcweir 									const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(nIndexA));
297*cdf0e10cSrcweir 									const basegfx::B3DPoint aStart(aPoint.getX(), aPoint.getY(), 0.0);
298*cdf0e10cSrcweir 									const basegfx::B3DPoint aEnd(aPoint.getX(), aPoint.getY(), getDepth());
299*cdf0e10cSrcweir 									basegfx::B3DPolygon aToBeAdded;
300*cdf0e10cSrcweir 
301*cdf0e10cSrcweir 									aToBeAdded.append(aStart);
302*cdf0e10cSrcweir 									aToBeAdded.append(aEnd);
303*cdf0e10cSrcweir 									aNewLineGeometry.append(aToBeAdded);
304*cdf0e10cSrcweir 								}
305*cdf0e10cSrcweir 
306*cdf0e10cSrcweir 								if(bIndexBUsed)
307*cdf0e10cSrcweir 								{
308*cdf0e10cSrcweir 									const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(nIndexB));
309*cdf0e10cSrcweir 									const basegfx::B3DPoint aStart(aPoint.getX(), aPoint.getY(), 0.0);
310*cdf0e10cSrcweir 									const basegfx::B3DPoint aEnd(aPoint.getX(), aPoint.getY(), getDepth());
311*cdf0e10cSrcweir 									basegfx::B3DPolygon aToBeAdded;
312*cdf0e10cSrcweir 
313*cdf0e10cSrcweir 									aToBeAdded.append(aStart);
314*cdf0e10cSrcweir 									aToBeAdded.append(aEnd);
315*cdf0e10cSrcweir 									aNewLineGeometry.append(aToBeAdded);
316*cdf0e10cSrcweir 								}
317*cdf0e10cSrcweir 
318*cdf0e10cSrcweir 								if(bIndexCUsed)
319*cdf0e10cSrcweir 								{
320*cdf0e10cSrcweir 									const basegfx::B2DPoint aPoint(aCandidate.getB2DPoint(nIndexC));
321*cdf0e10cSrcweir 									const basegfx::B3DPoint aStart(aPoint.getX(), aPoint.getY(), 0.0);
322*cdf0e10cSrcweir 									const basegfx::B3DPoint aEnd(aPoint.getX(), aPoint.getY(), getDepth());
323*cdf0e10cSrcweir 									basegfx::B3DPolygon aToBeAdded;
324*cdf0e10cSrcweir 
325*cdf0e10cSrcweir 									aToBeAdded.append(aStart);
326*cdf0e10cSrcweir 									aToBeAdded.append(aEnd);
327*cdf0e10cSrcweir 									aNewLineGeometry.append(aToBeAdded);
328*cdf0e10cSrcweir 								}
329*cdf0e10cSrcweir 							}
330*cdf0e10cSrcweir 						}
331*cdf0e10cSrcweir 
332*cdf0e10cSrcweir 						// append loops themselves
333*cdf0e10cSrcweir 						aNewLineGeometry.append(aReducedLoops);
334*cdf0e10cSrcweir 
335*cdf0e10cSrcweir 						if(aNewLineGeometry.count())
336*cdf0e10cSrcweir 						{
337*cdf0e10cSrcweir 							const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives(
338*cdf0e10cSrcweir                                 aNewLineGeometry, getTransform(), getSdrLFSAttribute().getLine()));
339*cdf0e10cSrcweir 							appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines);
340*cdf0e10cSrcweir 						}
341*cdf0e10cSrcweir 					}
342*cdf0e10cSrcweir 					else
343*cdf0e10cSrcweir 					{
344*cdf0e10cSrcweir 						// extract line geometry from slices
345*cdf0e10cSrcweir 						const basegfx::B3DPolyPolygon aHorLine(extractHorizontalLinesFromSlice(rSliceVector, false));
346*cdf0e10cSrcweir 						const basegfx::B3DPolyPolygon aVerLine(extractVerticalLinesFromSlice(rSliceVector));
347*cdf0e10cSrcweir 
348*cdf0e10cSrcweir 						// add horizontal lines
349*cdf0e10cSrcweir 						const Primitive3DSequence aHorLines(create3DPolyPolygonLinePrimitives(
350*cdf0e10cSrcweir                             aHorLine, getTransform(), getSdrLFSAttribute().getLine()));
351*cdf0e10cSrcweir 						appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aHorLines);
352*cdf0e10cSrcweir 
353*cdf0e10cSrcweir 						// add vertical lines
354*cdf0e10cSrcweir 						const Primitive3DSequence aVerLines(create3DPolyPolygonLinePrimitives(
355*cdf0e10cSrcweir                             aVerLine, getTransform(), getSdrLFSAttribute().getLine()));
356*cdf0e10cSrcweir 						appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aVerLines);
357*cdf0e10cSrcweir 					}
358*cdf0e10cSrcweir 				}
359*cdf0e10cSrcweir 
360*cdf0e10cSrcweir 				// add shadow
361*cdf0e10cSrcweir 				if(!getSdrLFSAttribute().getShadow().isDefault() && aRetval.hasElements())
362*cdf0e10cSrcweir 				{
363*cdf0e10cSrcweir 					const Primitive3DSequence aShadow(createShadowPrimitive3D(
364*cdf0e10cSrcweir                         aRetval, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D()));
365*cdf0e10cSrcweir 					appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow);
366*cdf0e10cSrcweir 				}
367*cdf0e10cSrcweir 			}
368*cdf0e10cSrcweir 
369*cdf0e10cSrcweir 			return aRetval;
370*cdf0e10cSrcweir 		}
371*cdf0e10cSrcweir 
372*cdf0e10cSrcweir 		void SdrExtrudePrimitive3D::impCreateSlices()
373*cdf0e10cSrcweir 		{
374*cdf0e10cSrcweir 			// prepare the polygon. No double points, correct orientations and a correct
375*cdf0e10cSrcweir 			// outmost polygon are needed
376*cdf0e10cSrcweir 			maCorrectedPolyPolygon = getPolyPolygon();
377*cdf0e10cSrcweir 			maCorrectedPolyPolygon.removeDoublePoints();
378*cdf0e10cSrcweir 			maCorrectedPolyPolygon = basegfx::tools::correctOrientations(maCorrectedPolyPolygon);
379*cdf0e10cSrcweir 			maCorrectedPolyPolygon = basegfx::tools::correctOutmostPolygon(maCorrectedPolyPolygon);
380*cdf0e10cSrcweir 
381*cdf0e10cSrcweir 			// prepare slices as geometry
382*cdf0e10cSrcweir 			createExtrudeSlices(maSlices, maCorrectedPolyPolygon, getBackScale(), getDiagonal(), getDepth(), getCharacterMode(), getCloseFront(), getCloseBack());
383*cdf0e10cSrcweir 		}
384*cdf0e10cSrcweir 
385*cdf0e10cSrcweir 		const Slice3DVector& SdrExtrudePrimitive3D::getSlices() const
386*cdf0e10cSrcweir 		{
387*cdf0e10cSrcweir 			// This can be made dependent of  getSdrLFSAttribute().getFill() and getSdrLFSAttribute().getLine()
388*cdf0e10cSrcweir 			// again when no longer geometry is needed for non-visible 3D objects as it is now for chart
389*cdf0e10cSrcweir 			if(getPolyPolygon().count() && !maSlices.size())
390*cdf0e10cSrcweir 			{
391*cdf0e10cSrcweir 			    ::osl::Mutex m_mutex;
392*cdf0e10cSrcweir 				const_cast< SdrExtrudePrimitive3D& >(*this).impCreateSlices();
393*cdf0e10cSrcweir 			}
394*cdf0e10cSrcweir 
395*cdf0e10cSrcweir 			return maSlices;
396*cdf0e10cSrcweir 		}
397*cdf0e10cSrcweir 
398*cdf0e10cSrcweir 		SdrExtrudePrimitive3D::SdrExtrudePrimitive3D(
399*cdf0e10cSrcweir 			const basegfx::B3DHomMatrix& rTransform,
400*cdf0e10cSrcweir 			const basegfx::B2DVector& rTextureSize,
401*cdf0e10cSrcweir 			const attribute::SdrLineFillShadowAttribute3D& rSdrLFSAttribute,
402*cdf0e10cSrcweir 			const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute,
403*cdf0e10cSrcweir 			const basegfx::B2DPolyPolygon& rPolyPolygon,
404*cdf0e10cSrcweir 			double fDepth,
405*cdf0e10cSrcweir 			double fDiagonal,
406*cdf0e10cSrcweir 			double fBackScale,
407*cdf0e10cSrcweir 			bool bSmoothNormals,
408*cdf0e10cSrcweir 			bool bSmoothHorizontalNormals,
409*cdf0e10cSrcweir 			bool bSmoothLids,
410*cdf0e10cSrcweir 			bool bCharacterMode,
411*cdf0e10cSrcweir 			bool bCloseFront,
412*cdf0e10cSrcweir 			bool bCloseBack)
413*cdf0e10cSrcweir 		:	SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute),
414*cdf0e10cSrcweir             maCorrectedPolyPolygon(),
415*cdf0e10cSrcweir             maSlices(),
416*cdf0e10cSrcweir 			maPolyPolygon(rPolyPolygon),
417*cdf0e10cSrcweir 			mfDepth(fDepth),
418*cdf0e10cSrcweir 			mfDiagonal(fDiagonal),
419*cdf0e10cSrcweir 			mfBackScale(fBackScale),
420*cdf0e10cSrcweir             mpLastRLGViewInformation(0),
421*cdf0e10cSrcweir 			mbSmoothNormals(bSmoothNormals),
422*cdf0e10cSrcweir 			mbSmoothHorizontalNormals(bSmoothHorizontalNormals),
423*cdf0e10cSrcweir 			mbSmoothLids(bSmoothLids),
424*cdf0e10cSrcweir 			mbCharacterMode(bCharacterMode),
425*cdf0e10cSrcweir 			mbCloseFront(bCloseFront),
426*cdf0e10cSrcweir 			mbCloseBack(bCloseBack)
427*cdf0e10cSrcweir 		{
428*cdf0e10cSrcweir 			// make sure depth is positive
429*cdf0e10cSrcweir 			if(basegfx::fTools::lessOrEqual(getDepth(), 0.0))
430*cdf0e10cSrcweir 			{
431*cdf0e10cSrcweir 				mfDepth = 0.0;
432*cdf0e10cSrcweir 			}
433*cdf0e10cSrcweir 
434*cdf0e10cSrcweir 			// make sure the percentage value getDiagonal() is between 0.0 and 1.0
435*cdf0e10cSrcweir 			if(basegfx::fTools::lessOrEqual(getDiagonal(), 0.0))
436*cdf0e10cSrcweir 			{
437*cdf0e10cSrcweir 				mfDiagonal = 0.0;
438*cdf0e10cSrcweir 			}
439*cdf0e10cSrcweir 			else if(basegfx::fTools::moreOrEqual(getDiagonal(), 1.0))
440*cdf0e10cSrcweir 			{
441*cdf0e10cSrcweir 				mfDiagonal = 1.0;
442*cdf0e10cSrcweir 			}
443*cdf0e10cSrcweir 
444*cdf0e10cSrcweir 			// no close front/back when polygon is not closed
445*cdf0e10cSrcweir 			if(getPolyPolygon().count() && !getPolyPolygon().getB2DPolygon(0L).isClosed())
446*cdf0e10cSrcweir 			{
447*cdf0e10cSrcweir 				mbCloseFront = mbCloseBack = false;
448*cdf0e10cSrcweir 			}
449*cdf0e10cSrcweir 
450*cdf0e10cSrcweir 			// no edge rounding when not closing
451*cdf0e10cSrcweir 			if(!getCloseFront() && !getCloseBack())
452*cdf0e10cSrcweir 			{
453*cdf0e10cSrcweir 				mfDiagonal = 0.0;
454*cdf0e10cSrcweir 			}
455*cdf0e10cSrcweir 		}
456*cdf0e10cSrcweir 
457*cdf0e10cSrcweir         SdrExtrudePrimitive3D::~SdrExtrudePrimitive3D()
458*cdf0e10cSrcweir         {
459*cdf0e10cSrcweir             if(mpLastRLGViewInformation)
460*cdf0e10cSrcweir             {
461*cdf0e10cSrcweir                 delete mpLastRLGViewInformation;
462*cdf0e10cSrcweir             }
463*cdf0e10cSrcweir         }
464*cdf0e10cSrcweir 
465*cdf0e10cSrcweir         bool SdrExtrudePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const
466*cdf0e10cSrcweir 		{
467*cdf0e10cSrcweir 			if(SdrPrimitive3D::operator==(rPrimitive))
468*cdf0e10cSrcweir 			{
469*cdf0e10cSrcweir 				const SdrExtrudePrimitive3D& rCompare = static_cast< const SdrExtrudePrimitive3D& >(rPrimitive);
470*cdf0e10cSrcweir 
471*cdf0e10cSrcweir 				return (getPolyPolygon() == rCompare.getPolyPolygon()
472*cdf0e10cSrcweir 					&& getDepth() == rCompare.getDepth()
473*cdf0e10cSrcweir 					&& getDiagonal() == rCompare.getDiagonal()
474*cdf0e10cSrcweir 					&& getBackScale() == rCompare.getBackScale()
475*cdf0e10cSrcweir 					&& getSmoothNormals() == rCompare.getSmoothNormals()
476*cdf0e10cSrcweir 					&& getSmoothHorizontalNormals() == rCompare.getSmoothHorizontalNormals()
477*cdf0e10cSrcweir 					&& getSmoothLids() == rCompare.getSmoothLids()
478*cdf0e10cSrcweir 					&& getCharacterMode() == rCompare.getCharacterMode()
479*cdf0e10cSrcweir 					&& getCloseFront() == rCompare.getCloseFront()
480*cdf0e10cSrcweir 					&& getCloseBack() == rCompare.getCloseBack());
481*cdf0e10cSrcweir 			}
482*cdf0e10cSrcweir 
483*cdf0e10cSrcweir 			return false;
484*cdf0e10cSrcweir 		}
485*cdf0e10cSrcweir 
486*cdf0e10cSrcweir 		basegfx::B3DRange SdrExtrudePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const
487*cdf0e10cSrcweir 		{
488*cdf0e10cSrcweir 			// use defaut from sdrPrimitive3D which uses transformation expanded by line width/2
489*cdf0e10cSrcweir 			// The parent implementation which uses the ranges of the decomposition would be more
490*cdf0e10cSrcweir 			// corrcet, but for historical reasons it is necessary to do the old method: To get
491*cdf0e10cSrcweir 			// the range of the non-transformed geometry and transform it then. This leads to different
492*cdf0e10cSrcweir 			// ranges where the new method is more correct, but the need to keep the old behaviour
493*cdf0e10cSrcweir 			// has priority here.
494*cdf0e10cSrcweir 			return get3DRangeFromSlices(getSlices());
495*cdf0e10cSrcweir 		}
496*cdf0e10cSrcweir 
497*cdf0e10cSrcweir         Primitive3DSequence SdrExtrudePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const
498*cdf0e10cSrcweir         {
499*cdf0e10cSrcweir             if(getSdr3DObjectAttribute().getReducedLineGeometry())
500*cdf0e10cSrcweir             {
501*cdf0e10cSrcweir                 if(!mpLastRLGViewInformation ||
502*cdf0e10cSrcweir                     (getBuffered3DDecomposition().hasElements()
503*cdf0e10cSrcweir                         && *mpLastRLGViewInformation != rViewInformation))
504*cdf0e10cSrcweir                 {
505*cdf0e10cSrcweir 					// conditions of last local decomposition with reduced lines have changed. Remember
506*cdf0e10cSrcweir                     // new one and clear current decompositiopn
507*cdf0e10cSrcweir     			    ::osl::Mutex m_mutex;
508*cdf0e10cSrcweir 					SdrExtrudePrimitive3D* pThat = const_cast< SdrExtrudePrimitive3D* >(this);
509*cdf0e10cSrcweir                     pThat->setBuffered3DDecomposition(Primitive3DSequence());
510*cdf0e10cSrcweir     				delete pThat->mpLastRLGViewInformation;
511*cdf0e10cSrcweir                     pThat->mpLastRLGViewInformation = new geometry::ViewInformation3D(rViewInformation);
512*cdf0e10cSrcweir                 }
513*cdf0e10cSrcweir             }
514*cdf0e10cSrcweir 
515*cdf0e10cSrcweir             // no test for buffering needed, call parent
516*cdf0e10cSrcweir             return SdrPrimitive3D::get3DDecomposition(rViewInformation);
517*cdf0e10cSrcweir         }
518*cdf0e10cSrcweir 
519*cdf0e10cSrcweir 		// provide unique ID
520*cdf0e10cSrcweir 		ImplPrimitrive3DIDBlock(SdrExtrudePrimitive3D, PRIMITIVE3D_ID_SDREXTRUDEPRIMITIVE3D)
521*cdf0e10cSrcweir 
522*cdf0e10cSrcweir 	} // end of namespace primitive3d
523*cdf0e10cSrcweir } // end of namespace drawinglayer
524*cdf0e10cSrcweir 
525*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
526*cdf0e10cSrcweir // eof
527