xref: /AOO41X/main/basegfx/source/polygon/b3dpolygontools.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_basegfx.hxx"
30*cdf0e10cSrcweir #include <osl/diagnose.h>
31*cdf0e10cSrcweir #include <basegfx/polygon/b3dpolygontools.hxx>
32*cdf0e10cSrcweir #include <basegfx/polygon/b3dpolygon.hxx>
33*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx>
34*cdf0e10cSrcweir #include <basegfx/range/b3drange.hxx>
35*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx>
36*cdf0e10cSrcweir #include <basegfx/matrix/b3dhommatrix.hxx>
37*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx>
38*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
39*cdf0e10cSrcweir #include <basegfx/tuple/b3ituple.hxx>
40*cdf0e10cSrcweir #include <numeric>
41*cdf0e10cSrcweir 
42*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
43*cdf0e10cSrcweir 
44*cdf0e10cSrcweir namespace basegfx
45*cdf0e10cSrcweir {
46*cdf0e10cSrcweir 	namespace tools
47*cdf0e10cSrcweir 	{
48*cdf0e10cSrcweir 		// B3DPolygon tools
49*cdf0e10cSrcweir 		void checkClosed(B3DPolygon& rCandidate)
50*cdf0e10cSrcweir 		{
51*cdf0e10cSrcweir 			while(rCandidate.count() > 1L
52*cdf0e10cSrcweir 				&& rCandidate.getB3DPoint(0L).equal(rCandidate.getB3DPoint(rCandidate.count() - 1L)))
53*cdf0e10cSrcweir 			{
54*cdf0e10cSrcweir 				rCandidate.setClosed(true);
55*cdf0e10cSrcweir 				rCandidate.remove(rCandidate.count() - 1L);
56*cdf0e10cSrcweir 			}
57*cdf0e10cSrcweir 		}
58*cdf0e10cSrcweir 
59*cdf0e10cSrcweir 		// Get successor and predecessor indices. Returning the same index means there
60*cdf0e10cSrcweir 		// is none. Same for successor.
61*cdf0e10cSrcweir 		sal_uInt32 getIndexOfPredecessor(sal_uInt32 nIndex, const B3DPolygon& rCandidate)
62*cdf0e10cSrcweir 		{
63*cdf0e10cSrcweir 			OSL_ENSURE(nIndex < rCandidate.count(), "getIndexOfPredecessor: Access to polygon out of range (!)");
64*cdf0e10cSrcweir 
65*cdf0e10cSrcweir 			if(nIndex)
66*cdf0e10cSrcweir 			{
67*cdf0e10cSrcweir 				return nIndex - 1L;
68*cdf0e10cSrcweir 			}
69*cdf0e10cSrcweir 			else if(rCandidate.count())
70*cdf0e10cSrcweir 			{
71*cdf0e10cSrcweir 				return rCandidate.count() - 1L;
72*cdf0e10cSrcweir 			}
73*cdf0e10cSrcweir 			else
74*cdf0e10cSrcweir 			{
75*cdf0e10cSrcweir 				return nIndex;
76*cdf0e10cSrcweir 			}
77*cdf0e10cSrcweir 		}
78*cdf0e10cSrcweir 
79*cdf0e10cSrcweir 		sal_uInt32 getIndexOfSuccessor(sal_uInt32 nIndex, const B3DPolygon& rCandidate)
80*cdf0e10cSrcweir 		{
81*cdf0e10cSrcweir 			OSL_ENSURE(nIndex < rCandidate.count(), "getIndexOfPredecessor: Access to polygon out of range (!)");
82*cdf0e10cSrcweir 
83*cdf0e10cSrcweir 			if(nIndex + 1L < rCandidate.count())
84*cdf0e10cSrcweir 			{
85*cdf0e10cSrcweir 				return nIndex + 1L;
86*cdf0e10cSrcweir 			}
87*cdf0e10cSrcweir 			else
88*cdf0e10cSrcweir 			{
89*cdf0e10cSrcweir 				return 0L;
90*cdf0e10cSrcweir 			}
91*cdf0e10cSrcweir 		}
92*cdf0e10cSrcweir 
93*cdf0e10cSrcweir 		B3DRange getRange(const B3DPolygon& rCandidate)
94*cdf0e10cSrcweir 		{
95*cdf0e10cSrcweir 			B3DRange aRetval;
96*cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
97*cdf0e10cSrcweir 
98*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nPointCount; a++)
99*cdf0e10cSrcweir 			{
100*cdf0e10cSrcweir 				const B3DPoint aTestPoint(rCandidate.getB3DPoint(a));
101*cdf0e10cSrcweir 				aRetval.expand(aTestPoint);
102*cdf0e10cSrcweir 			}
103*cdf0e10cSrcweir 
104*cdf0e10cSrcweir 			return aRetval;
105*cdf0e10cSrcweir 		}
106*cdf0e10cSrcweir 
107*cdf0e10cSrcweir 		B3DVector getNormal(const B3DPolygon& rCandidate)
108*cdf0e10cSrcweir 		{
109*cdf0e10cSrcweir 			return rCandidate.getNormal();
110*cdf0e10cSrcweir 		}
111*cdf0e10cSrcweir 
112*cdf0e10cSrcweir 		B3DVector getPositiveOrientedNormal(const B3DPolygon& rCandidate)
113*cdf0e10cSrcweir 		{
114*cdf0e10cSrcweir 			B3DVector aRetval(rCandidate.getNormal());
115*cdf0e10cSrcweir 
116*cdf0e10cSrcweir 			if(ORIENTATION_NEGATIVE == getOrientation(rCandidate))
117*cdf0e10cSrcweir 			{
118*cdf0e10cSrcweir 				aRetval = -aRetval;
119*cdf0e10cSrcweir 			}
120*cdf0e10cSrcweir 
121*cdf0e10cSrcweir 			return aRetval;
122*cdf0e10cSrcweir 		}
123*cdf0e10cSrcweir 
124*cdf0e10cSrcweir 		B2VectorOrientation getOrientation(const B3DPolygon& rCandidate)
125*cdf0e10cSrcweir 		{
126*cdf0e10cSrcweir 			B2VectorOrientation eRetval(ORIENTATION_NEUTRAL);
127*cdf0e10cSrcweir 
128*cdf0e10cSrcweir 			if(rCandidate.count() > 2L)
129*cdf0e10cSrcweir 			{
130*cdf0e10cSrcweir 				const double fSignedArea(getSignedArea(rCandidate));
131*cdf0e10cSrcweir 
132*cdf0e10cSrcweir 				if(fSignedArea > 0.0)
133*cdf0e10cSrcweir 				{
134*cdf0e10cSrcweir 					eRetval = ORIENTATION_POSITIVE;
135*cdf0e10cSrcweir 				}
136*cdf0e10cSrcweir 				else if(fSignedArea < 0.0)
137*cdf0e10cSrcweir 				{
138*cdf0e10cSrcweir 					eRetval = ORIENTATION_NEGATIVE;
139*cdf0e10cSrcweir 				}
140*cdf0e10cSrcweir 			}
141*cdf0e10cSrcweir 
142*cdf0e10cSrcweir 			return eRetval;
143*cdf0e10cSrcweir 		}
144*cdf0e10cSrcweir 
145*cdf0e10cSrcweir 		double getSignedArea(const B3DPolygon& rCandidate)
146*cdf0e10cSrcweir 		{
147*cdf0e10cSrcweir 			double fRetval(0.0);
148*cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
149*cdf0e10cSrcweir 
150*cdf0e10cSrcweir 			if(nPointCount > 2)
151*cdf0e10cSrcweir 			{
152*cdf0e10cSrcweir 				const B3DVector aAbsNormal(absolute(getNormal(rCandidate)));
153*cdf0e10cSrcweir 				sal_uInt16 nCase(3); // default: ignore z
154*cdf0e10cSrcweir 
155*cdf0e10cSrcweir 				if(aAbsNormal.getX() > aAbsNormal.getY())
156*cdf0e10cSrcweir 				{
157*cdf0e10cSrcweir 					if(aAbsNormal.getX() > aAbsNormal.getZ())
158*cdf0e10cSrcweir 					{
159*cdf0e10cSrcweir 						nCase = 1; // ignore x
160*cdf0e10cSrcweir 					}
161*cdf0e10cSrcweir 				}
162*cdf0e10cSrcweir 				else if(aAbsNormal.getY() > aAbsNormal.getZ())
163*cdf0e10cSrcweir 				{
164*cdf0e10cSrcweir 					nCase = 2; // ignore y
165*cdf0e10cSrcweir 				}
166*cdf0e10cSrcweir 
167*cdf0e10cSrcweir 				B3DPoint aPreviousPoint(rCandidate.getB3DPoint(nPointCount - 1L));
168*cdf0e10cSrcweir 
169*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nPointCount; a++)
170*cdf0e10cSrcweir 				{
171*cdf0e10cSrcweir 					const B3DPoint aCurrentPoint(rCandidate.getB3DPoint(a));
172*cdf0e10cSrcweir 
173*cdf0e10cSrcweir 					switch(nCase)
174*cdf0e10cSrcweir 					{
175*cdf0e10cSrcweir 						case 1: // ignore x
176*cdf0e10cSrcweir 							fRetval += aPreviousPoint.getZ() * aCurrentPoint.getY();
177*cdf0e10cSrcweir 							fRetval -= aPreviousPoint.getY() * aCurrentPoint.getZ();
178*cdf0e10cSrcweir 							break;
179*cdf0e10cSrcweir 						case 2: // ignore y
180*cdf0e10cSrcweir 							fRetval += aPreviousPoint.getX() * aCurrentPoint.getZ();
181*cdf0e10cSrcweir 							fRetval -= aPreviousPoint.getZ() * aCurrentPoint.getX();
182*cdf0e10cSrcweir 							break;
183*cdf0e10cSrcweir 						case 3: // ignore z
184*cdf0e10cSrcweir 							fRetval += aPreviousPoint.getX() * aCurrentPoint.getY();
185*cdf0e10cSrcweir 							fRetval -= aPreviousPoint.getY() * aCurrentPoint.getX();
186*cdf0e10cSrcweir 							break;
187*cdf0e10cSrcweir 					}
188*cdf0e10cSrcweir 
189*cdf0e10cSrcweir 					// prepare next step
190*cdf0e10cSrcweir 					aPreviousPoint = aCurrentPoint;
191*cdf0e10cSrcweir 				}
192*cdf0e10cSrcweir 
193*cdf0e10cSrcweir 				switch(nCase)
194*cdf0e10cSrcweir 				{
195*cdf0e10cSrcweir 					case 1: // ignore x
196*cdf0e10cSrcweir 						fRetval /= 2.0 * aAbsNormal.getX();
197*cdf0e10cSrcweir 						break;
198*cdf0e10cSrcweir 					case 2: // ignore y
199*cdf0e10cSrcweir 						fRetval /= 2.0 * aAbsNormal.getY();
200*cdf0e10cSrcweir 						break;
201*cdf0e10cSrcweir 					case 3: // ignore z
202*cdf0e10cSrcweir 						fRetval /= 2.0 * aAbsNormal.getZ();
203*cdf0e10cSrcweir 						break;
204*cdf0e10cSrcweir 				}
205*cdf0e10cSrcweir 			}
206*cdf0e10cSrcweir 
207*cdf0e10cSrcweir 			return fRetval;
208*cdf0e10cSrcweir 		}
209*cdf0e10cSrcweir 
210*cdf0e10cSrcweir 		double getArea(const B3DPolygon& rCandidate)
211*cdf0e10cSrcweir 		{
212*cdf0e10cSrcweir 			double fRetval(0.0);
213*cdf0e10cSrcweir 
214*cdf0e10cSrcweir 			if(rCandidate.count() > 2)
215*cdf0e10cSrcweir 			{
216*cdf0e10cSrcweir 				fRetval = getSignedArea(rCandidate);
217*cdf0e10cSrcweir 				const double fZero(0.0);
218*cdf0e10cSrcweir 
219*cdf0e10cSrcweir 				if(fTools::less(fRetval, fZero))
220*cdf0e10cSrcweir 				{
221*cdf0e10cSrcweir 					fRetval = -fRetval;
222*cdf0e10cSrcweir 				}
223*cdf0e10cSrcweir 			}
224*cdf0e10cSrcweir 
225*cdf0e10cSrcweir 			return fRetval;
226*cdf0e10cSrcweir 		}
227*cdf0e10cSrcweir 
228*cdf0e10cSrcweir 		double getEdgeLength(const B3DPolygon& rCandidate, sal_uInt32 nIndex)
229*cdf0e10cSrcweir 		{
230*cdf0e10cSrcweir 			OSL_ENSURE(nIndex < rCandidate.count(), "getEdgeLength: Access to polygon out of range (!)");
231*cdf0e10cSrcweir 			double fRetval(0.0);
232*cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
233*cdf0e10cSrcweir 
234*cdf0e10cSrcweir 			if(nIndex < nPointCount)
235*cdf0e10cSrcweir 			{
236*cdf0e10cSrcweir 				if(rCandidate.isClosed() || ((nIndex + 1L) != nPointCount))
237*cdf0e10cSrcweir 				{
238*cdf0e10cSrcweir 					const sal_uInt32 nNextIndex(getIndexOfSuccessor(nIndex, rCandidate));
239*cdf0e10cSrcweir 					const B3DPoint aCurrentPoint(rCandidate.getB3DPoint(nIndex));
240*cdf0e10cSrcweir 					const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
241*cdf0e10cSrcweir 					const B3DVector aVector(aNextPoint - aCurrentPoint);
242*cdf0e10cSrcweir 					fRetval = aVector.getLength();
243*cdf0e10cSrcweir 				}
244*cdf0e10cSrcweir 			}
245*cdf0e10cSrcweir 
246*cdf0e10cSrcweir 			return fRetval;
247*cdf0e10cSrcweir 		}
248*cdf0e10cSrcweir 
249*cdf0e10cSrcweir 		double getLength(const B3DPolygon& rCandidate)
250*cdf0e10cSrcweir 		{
251*cdf0e10cSrcweir 			double fRetval(0.0);
252*cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
253*cdf0e10cSrcweir 
254*cdf0e10cSrcweir 			if(nPointCount > 1L)
255*cdf0e10cSrcweir 			{
256*cdf0e10cSrcweir 				const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
257*cdf0e10cSrcweir 
258*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < nLoopCount; a++)
259*cdf0e10cSrcweir 				{
260*cdf0e10cSrcweir 					const sal_uInt32 nNextIndex(getIndexOfSuccessor(a, rCandidate));
261*cdf0e10cSrcweir 					const B3DPoint aCurrentPoint(rCandidate.getB3DPoint(a));
262*cdf0e10cSrcweir 					const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
263*cdf0e10cSrcweir 					const B3DVector aVector(aNextPoint - aCurrentPoint);
264*cdf0e10cSrcweir 					fRetval += aVector.getLength();
265*cdf0e10cSrcweir 				}
266*cdf0e10cSrcweir 			}
267*cdf0e10cSrcweir 
268*cdf0e10cSrcweir 			return fRetval;
269*cdf0e10cSrcweir 		}
270*cdf0e10cSrcweir 
271*cdf0e10cSrcweir 		B3DPoint getPositionAbsolute(const B3DPolygon& rCandidate, double fDistance, double fLength)
272*cdf0e10cSrcweir 		{
273*cdf0e10cSrcweir 			B3DPoint aRetval;
274*cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
275*cdf0e10cSrcweir 
276*cdf0e10cSrcweir 			if(nPointCount > 1L)
277*cdf0e10cSrcweir 			{
278*cdf0e10cSrcweir 				sal_uInt32 nIndex(0L);
279*cdf0e10cSrcweir 				bool bIndexDone(false);
280*cdf0e10cSrcweir 				const double fZero(0.0);
281*cdf0e10cSrcweir 				double fEdgeLength(fZero);
282*cdf0e10cSrcweir 
283*cdf0e10cSrcweir 				// get length if not given
284*cdf0e10cSrcweir 				if(fTools::equalZero(fLength))
285*cdf0e10cSrcweir 				{
286*cdf0e10cSrcweir 					fLength = getLength(rCandidate);
287*cdf0e10cSrcweir 				}
288*cdf0e10cSrcweir 
289*cdf0e10cSrcweir 				// handle fDistance < 0.0
290*cdf0e10cSrcweir 				if(fTools::less(fDistance, fZero))
291*cdf0e10cSrcweir 				{
292*cdf0e10cSrcweir 					if(rCandidate.isClosed())
293*cdf0e10cSrcweir 					{
294*cdf0e10cSrcweir 						// if fDistance < 0.0 increment with multiple of fLength
295*cdf0e10cSrcweir 						sal_uInt32 nCount(sal_uInt32(-fDistance / fLength));
296*cdf0e10cSrcweir 						fDistance += double(nCount + 1L) * fLength;
297*cdf0e10cSrcweir 					}
298*cdf0e10cSrcweir 					else
299*cdf0e10cSrcweir 					{
300*cdf0e10cSrcweir 						// crop to polygon start
301*cdf0e10cSrcweir 						fDistance = fZero;
302*cdf0e10cSrcweir 						bIndexDone = true;
303*cdf0e10cSrcweir 					}
304*cdf0e10cSrcweir 				}
305*cdf0e10cSrcweir 
306*cdf0e10cSrcweir 				// handle fDistance >= fLength
307*cdf0e10cSrcweir 				if(fTools::moreOrEqual(fDistance, fLength))
308*cdf0e10cSrcweir 				{
309*cdf0e10cSrcweir 					if(rCandidate.isClosed())
310*cdf0e10cSrcweir 					{
311*cdf0e10cSrcweir 						// if fDistance >= fLength decrement with multiple of fLength
312*cdf0e10cSrcweir 						sal_uInt32 nCount(sal_uInt32(fDistance / fLength));
313*cdf0e10cSrcweir 						fDistance -= (double)(nCount) * fLength;
314*cdf0e10cSrcweir 					}
315*cdf0e10cSrcweir 					else
316*cdf0e10cSrcweir 					{
317*cdf0e10cSrcweir 						// crop to polygon end
318*cdf0e10cSrcweir 						fDistance = fZero;
319*cdf0e10cSrcweir 						nIndex = nPointCount - 1L;
320*cdf0e10cSrcweir 						bIndexDone = true;
321*cdf0e10cSrcweir 					}
322*cdf0e10cSrcweir 				}
323*cdf0e10cSrcweir 
324*cdf0e10cSrcweir 				// look for correct index. fDistance is now [0.0 .. fLength[
325*cdf0e10cSrcweir 				if(!bIndexDone)
326*cdf0e10cSrcweir 				{
327*cdf0e10cSrcweir 					do
328*cdf0e10cSrcweir 					{
329*cdf0e10cSrcweir 						// get length of next edge
330*cdf0e10cSrcweir 						fEdgeLength = getEdgeLength(rCandidate, nIndex);
331*cdf0e10cSrcweir 
332*cdf0e10cSrcweir 						if(fTools::moreOrEqual(fDistance, fEdgeLength))
333*cdf0e10cSrcweir 						{
334*cdf0e10cSrcweir 							// go to next edge
335*cdf0e10cSrcweir 							fDistance -= fEdgeLength;
336*cdf0e10cSrcweir 							nIndex++;
337*cdf0e10cSrcweir 						}
338*cdf0e10cSrcweir 						else
339*cdf0e10cSrcweir 						{
340*cdf0e10cSrcweir 							// it's on this edge, stop
341*cdf0e10cSrcweir 							bIndexDone = true;
342*cdf0e10cSrcweir 						}
343*cdf0e10cSrcweir 					} while (!bIndexDone);
344*cdf0e10cSrcweir 				}
345*cdf0e10cSrcweir 
346*cdf0e10cSrcweir 				// get the point using nIndex
347*cdf0e10cSrcweir 				aRetval = rCandidate.getB3DPoint(nIndex);
348*cdf0e10cSrcweir 
349*cdf0e10cSrcweir 				// if fDistance != 0.0, move that length on the edge. The edge
350*cdf0e10cSrcweir 				// length is in fEdgeLength.
351*cdf0e10cSrcweir 				if(!fTools::equalZero(fDistance))
352*cdf0e10cSrcweir 				{
353*cdf0e10cSrcweir 					sal_uInt32 nNextIndex(getIndexOfSuccessor(nIndex, rCandidate));
354*cdf0e10cSrcweir 					const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
355*cdf0e10cSrcweir 					double fRelative(fZero);
356*cdf0e10cSrcweir 
357*cdf0e10cSrcweir 					if(!fTools::equalZero(fEdgeLength))
358*cdf0e10cSrcweir 					{
359*cdf0e10cSrcweir 						fRelative = fDistance / fEdgeLength;
360*cdf0e10cSrcweir 					}
361*cdf0e10cSrcweir 
362*cdf0e10cSrcweir 					// add calculated average value to the return value
363*cdf0e10cSrcweir 					aRetval += interpolate(aRetval, aNextPoint, fRelative);
364*cdf0e10cSrcweir 				}
365*cdf0e10cSrcweir 			}
366*cdf0e10cSrcweir 
367*cdf0e10cSrcweir 			return aRetval;
368*cdf0e10cSrcweir 		}
369*cdf0e10cSrcweir 
370*cdf0e10cSrcweir 		B3DPoint getPositionRelative(const B3DPolygon& rCandidate, double fDistance, double fLength)
371*cdf0e10cSrcweir 		{
372*cdf0e10cSrcweir 			// get length if not given
373*cdf0e10cSrcweir 			if(fTools::equalZero(fLength))
374*cdf0e10cSrcweir 			{
375*cdf0e10cSrcweir 				fLength = getLength(rCandidate);
376*cdf0e10cSrcweir 			}
377*cdf0e10cSrcweir 
378*cdf0e10cSrcweir 			// multiply fDistance with real length to get absolute position and
379*cdf0e10cSrcweir 			// use getPositionAbsolute
380*cdf0e10cSrcweir 			return getPositionAbsolute(rCandidate, fDistance * fLength, fLength);
381*cdf0e10cSrcweir 		}
382*cdf0e10cSrcweir 
383*cdf0e10cSrcweir 		void applyLineDashing(const B3DPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B3DPolyPolygon* pLineTarget, B3DPolyPolygon* pGapTarget, double fDotDashLength)
384*cdf0e10cSrcweir         {
385*cdf0e10cSrcweir             const sal_uInt32 nPointCount(rCandidate.count());
386*cdf0e10cSrcweir             const sal_uInt32 nDotDashCount(rDotDashArray.size());
387*cdf0e10cSrcweir 
388*cdf0e10cSrcweir 			if(fTools::lessOrEqual(fDotDashLength, 0.0))
389*cdf0e10cSrcweir             {
390*cdf0e10cSrcweir                 fDotDashLength = ::std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
391*cdf0e10cSrcweir             }
392*cdf0e10cSrcweir 
393*cdf0e10cSrcweir 			if(fTools::more(fDotDashLength, 0.0) && (pLineTarget || pGapTarget) && nPointCount)
394*cdf0e10cSrcweir             {
395*cdf0e10cSrcweir 				// clear targets
396*cdf0e10cSrcweir 				if(pLineTarget)
397*cdf0e10cSrcweir 				{
398*cdf0e10cSrcweir 					pLineTarget->clear();
399*cdf0e10cSrcweir 				}
400*cdf0e10cSrcweir 
401*cdf0e10cSrcweir 				if(pGapTarget)
402*cdf0e10cSrcweir 				{
403*cdf0e10cSrcweir 					pGapTarget->clear();
404*cdf0e10cSrcweir 				}
405*cdf0e10cSrcweir 
406*cdf0e10cSrcweir                 // prepare current edge's start
407*cdf0e10cSrcweir 				B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0));
408*cdf0e10cSrcweir                 const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
409*cdf0e10cSrcweir 
410*cdf0e10cSrcweir                 // prepare DotDashArray iteration and the line/gap switching bool
411*cdf0e10cSrcweir                 sal_uInt32 nDotDashIndex(0);
412*cdf0e10cSrcweir                 bool bIsLine(true);
413*cdf0e10cSrcweir                 double fDotDashMovingLength(rDotDashArray[0]);
414*cdf0e10cSrcweir 				B3DPolygon aSnippet;
415*cdf0e10cSrcweir 
416*cdf0e10cSrcweir 				// iterate over all edges
417*cdf0e10cSrcweir                 for(sal_uInt32 a(0); a < nEdgeCount; a++)
418*cdf0e10cSrcweir                 {
419*cdf0e10cSrcweir                     // update current edge
420*cdf0e10cSrcweir 					double fLastDotDashMovingLength(0.0);
421*cdf0e10cSrcweir                     const sal_uInt32 nNextIndex((a + 1) % nPointCount);
422*cdf0e10cSrcweir 					const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
423*cdf0e10cSrcweir 					const double fEdgeLength(B3DVector(aNextPoint - aCurrentPoint).getLength());
424*cdf0e10cSrcweir 
425*cdf0e10cSrcweir 					while(fTools::less(fDotDashMovingLength, fEdgeLength))
426*cdf0e10cSrcweir 					{
427*cdf0e10cSrcweir 						// new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
428*cdf0e10cSrcweir 						const bool bHandleLine(bIsLine && pLineTarget);
429*cdf0e10cSrcweir 						const bool bHandleGap(!bIsLine && pGapTarget);
430*cdf0e10cSrcweir 
431*cdf0e10cSrcweir                         if(bHandleLine || bHandleGap)
432*cdf0e10cSrcweir                         {
433*cdf0e10cSrcweir 							if(!aSnippet.count())
434*cdf0e10cSrcweir 							{
435*cdf0e10cSrcweir 								aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
436*cdf0e10cSrcweir 							}
437*cdf0e10cSrcweir 
438*cdf0e10cSrcweir 							aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength));
439*cdf0e10cSrcweir 
440*cdf0e10cSrcweir 							if(bHandleLine)
441*cdf0e10cSrcweir 							{
442*cdf0e10cSrcweir 								pLineTarget->append(aSnippet);
443*cdf0e10cSrcweir 							}
444*cdf0e10cSrcweir 							else
445*cdf0e10cSrcweir 							{
446*cdf0e10cSrcweir 								pGapTarget->append(aSnippet);
447*cdf0e10cSrcweir 							}
448*cdf0e10cSrcweir 
449*cdf0e10cSrcweir 							aSnippet.clear();
450*cdf0e10cSrcweir 						}
451*cdf0e10cSrcweir 
452*cdf0e10cSrcweir 						// prepare next DotDashArray step and flip line/gap flag
453*cdf0e10cSrcweir 						fLastDotDashMovingLength = fDotDashMovingLength;
454*cdf0e10cSrcweir                         fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
455*cdf0e10cSrcweir                         bIsLine = !bIsLine;
456*cdf0e10cSrcweir 					}
457*cdf0e10cSrcweir 
458*cdf0e10cSrcweir 					// append snippet [fLastDotDashMovingLength, fEdgeLength]
459*cdf0e10cSrcweir 					const bool bHandleLine(bIsLine && pLineTarget);
460*cdf0e10cSrcweir 					const bool bHandleGap(!bIsLine && pGapTarget);
461*cdf0e10cSrcweir 
462*cdf0e10cSrcweir 					if(bHandleLine || bHandleGap)
463*cdf0e10cSrcweir                     {
464*cdf0e10cSrcweir 						if(!aSnippet.count())
465*cdf0e10cSrcweir 						{
466*cdf0e10cSrcweir 							aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
467*cdf0e10cSrcweir 						}
468*cdf0e10cSrcweir 
469*cdf0e10cSrcweir 						aSnippet.append(aNextPoint);
470*cdf0e10cSrcweir 					}
471*cdf0e10cSrcweir 
472*cdf0e10cSrcweir 					// prepare move to next edge
473*cdf0e10cSrcweir 					fDotDashMovingLength -= fEdgeLength;
474*cdf0e10cSrcweir 
475*cdf0e10cSrcweir 					// prepare next edge step (end point gets new start point)
476*cdf0e10cSrcweir                     aCurrentPoint = aNextPoint;
477*cdf0e10cSrcweir                 }
478*cdf0e10cSrcweir 
479*cdf0e10cSrcweir                 // append last intermediate results (if exists)
480*cdf0e10cSrcweir                 if(aSnippet.count())
481*cdf0e10cSrcweir                 {
482*cdf0e10cSrcweir                     if(bIsLine && pLineTarget)
483*cdf0e10cSrcweir                     {
484*cdf0e10cSrcweir                         pLineTarget->append(aSnippet);
485*cdf0e10cSrcweir                     }
486*cdf0e10cSrcweir                     else if(!bIsLine && pGapTarget)
487*cdf0e10cSrcweir                     {
488*cdf0e10cSrcweir                         pGapTarget->append(aSnippet);
489*cdf0e10cSrcweir                     }
490*cdf0e10cSrcweir                 }
491*cdf0e10cSrcweir 
492*cdf0e10cSrcweir 				// check if start and end polygon may be merged
493*cdf0e10cSrcweir 				if(pLineTarget)
494*cdf0e10cSrcweir 				{
495*cdf0e10cSrcweir 					const sal_uInt32 nCount(pLineTarget->count());
496*cdf0e10cSrcweir 
497*cdf0e10cSrcweir 					if(nCount > 1)
498*cdf0e10cSrcweir 					{
499*cdf0e10cSrcweir 						// these polygons were created above, there exists none with less than two points,
500*cdf0e10cSrcweir 						// thus dircet point access below is allowed
501*cdf0e10cSrcweir 						const B3DPolygon aFirst(pLineTarget->getB3DPolygon(0));
502*cdf0e10cSrcweir 						B3DPolygon aLast(pLineTarget->getB3DPolygon(nCount - 1));
503*cdf0e10cSrcweir 
504*cdf0e10cSrcweir 						if(aFirst.getB3DPoint(0).equal(aLast.getB3DPoint(aLast.count() - 1)))
505*cdf0e10cSrcweir 						{
506*cdf0e10cSrcweir 							// start of first and end of last are the same -> merge them
507*cdf0e10cSrcweir 							aLast.append(aFirst);
508*cdf0e10cSrcweir 							aLast.removeDoublePoints();
509*cdf0e10cSrcweir 							pLineTarget->setB3DPolygon(0, aLast);
510*cdf0e10cSrcweir 							pLineTarget->remove(nCount - 1);
511*cdf0e10cSrcweir 						}
512*cdf0e10cSrcweir 					}
513*cdf0e10cSrcweir 				}
514*cdf0e10cSrcweir 
515*cdf0e10cSrcweir 				if(pGapTarget)
516*cdf0e10cSrcweir 				{
517*cdf0e10cSrcweir 					const sal_uInt32 nCount(pGapTarget->count());
518*cdf0e10cSrcweir 
519*cdf0e10cSrcweir 					if(nCount > 1)
520*cdf0e10cSrcweir 					{
521*cdf0e10cSrcweir 						// these polygons were created above, there exists none with less than two points,
522*cdf0e10cSrcweir 						// thus dircet point access below is allowed
523*cdf0e10cSrcweir 						const B3DPolygon aFirst(pGapTarget->getB3DPolygon(0));
524*cdf0e10cSrcweir 						B3DPolygon aLast(pGapTarget->getB3DPolygon(nCount - 1));
525*cdf0e10cSrcweir 
526*cdf0e10cSrcweir 						if(aFirst.getB3DPoint(0).equal(aLast.getB3DPoint(aLast.count() - 1)))
527*cdf0e10cSrcweir 						{
528*cdf0e10cSrcweir 							// start of first and end of last are the same -> merge them
529*cdf0e10cSrcweir 							aLast.append(aFirst);
530*cdf0e10cSrcweir 							aLast.removeDoublePoints();
531*cdf0e10cSrcweir 							pGapTarget->setB3DPolygon(0, aLast);
532*cdf0e10cSrcweir 							pGapTarget->remove(nCount - 1);
533*cdf0e10cSrcweir 						}
534*cdf0e10cSrcweir 					}
535*cdf0e10cSrcweir 				}
536*cdf0e10cSrcweir             }
537*cdf0e10cSrcweir             else
538*cdf0e10cSrcweir             {
539*cdf0e10cSrcweir 				// parameters make no sense, just add source to targets
540*cdf0e10cSrcweir                 if(pLineTarget)
541*cdf0e10cSrcweir                 {
542*cdf0e10cSrcweir                     pLineTarget->append(rCandidate);
543*cdf0e10cSrcweir                 }
544*cdf0e10cSrcweir 
545*cdf0e10cSrcweir 				if(pGapTarget)
546*cdf0e10cSrcweir 				{
547*cdf0e10cSrcweir                     pGapTarget->append(rCandidate);
548*cdf0e10cSrcweir 				}
549*cdf0e10cSrcweir             }
550*cdf0e10cSrcweir 		}
551*cdf0e10cSrcweir 
552*cdf0e10cSrcweir 		B3DPolygon applyDefaultNormalsSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter)
553*cdf0e10cSrcweir 		{
554*cdf0e10cSrcweir 			B3DPolygon aRetval(rCandidate);
555*cdf0e10cSrcweir 
556*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < aRetval.count(); a++)
557*cdf0e10cSrcweir 			{
558*cdf0e10cSrcweir 				B3DVector aVector(aRetval.getB3DPoint(a) - rCenter);
559*cdf0e10cSrcweir 				aVector.normalize();
560*cdf0e10cSrcweir 				aRetval.setNormal(a, aVector);
561*cdf0e10cSrcweir 			}
562*cdf0e10cSrcweir 
563*cdf0e10cSrcweir 			return aRetval;
564*cdf0e10cSrcweir 		}
565*cdf0e10cSrcweir 
566*cdf0e10cSrcweir 		B3DPolygon invertNormals( const B3DPolygon& rCandidate)
567*cdf0e10cSrcweir 		{
568*cdf0e10cSrcweir 			B3DPolygon aRetval(rCandidate);
569*cdf0e10cSrcweir 
570*cdf0e10cSrcweir 			if(aRetval.areNormalsUsed())
571*cdf0e10cSrcweir 			{
572*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < aRetval.count(); a++)
573*cdf0e10cSrcweir 				{
574*cdf0e10cSrcweir 					aRetval.setNormal(a, -aRetval.getNormal(a));
575*cdf0e10cSrcweir 				}
576*cdf0e10cSrcweir 			}
577*cdf0e10cSrcweir 
578*cdf0e10cSrcweir 			return aRetval;
579*cdf0e10cSrcweir 		}
580*cdf0e10cSrcweir 
581*cdf0e10cSrcweir 		B3DPolygon applyDefaultTextureCoordinatesParallel( const B3DPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY)
582*cdf0e10cSrcweir 		{
583*cdf0e10cSrcweir 			B3DPolygon aRetval(rCandidate);
584*cdf0e10cSrcweir 
585*cdf0e10cSrcweir 			if(bChangeX || bChangeY)
586*cdf0e10cSrcweir 			{
587*cdf0e10cSrcweir 				// create projection of standard texture coordinates in (X, Y) onto
588*cdf0e10cSrcweir 				// the 3d coordinates straight
589*cdf0e10cSrcweir 				const double fWidth(rRange.getWidth());
590*cdf0e10cSrcweir 				const double fHeight(rRange.getHeight());
591*cdf0e10cSrcweir 				const bool bWidthSet(!fTools::equalZero(fWidth));
592*cdf0e10cSrcweir 				const bool bHeightSet(!fTools::equalZero(fHeight));
593*cdf0e10cSrcweir 				const double fOne(1.0);
594*cdf0e10cSrcweir 
595*cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < aRetval.count(); a++)
596*cdf0e10cSrcweir 				{
597*cdf0e10cSrcweir 					const B3DPoint aPoint(aRetval.getB3DPoint(a));
598*cdf0e10cSrcweir 					B2DPoint aTextureCoordinate(aRetval.getTextureCoordinate(a));
599*cdf0e10cSrcweir 
600*cdf0e10cSrcweir 					if(bChangeX)
601*cdf0e10cSrcweir 					{
602*cdf0e10cSrcweir 						if(bWidthSet)
603*cdf0e10cSrcweir 						{
604*cdf0e10cSrcweir 							aTextureCoordinate.setX((aPoint.getX() - rRange.getMinX()) / fWidth);
605*cdf0e10cSrcweir 						}
606*cdf0e10cSrcweir 						else
607*cdf0e10cSrcweir 						{
608*cdf0e10cSrcweir 							aTextureCoordinate.setX(0.0);
609*cdf0e10cSrcweir 						}
610*cdf0e10cSrcweir 					}
611*cdf0e10cSrcweir 
612*cdf0e10cSrcweir 					if(bChangeY)
613*cdf0e10cSrcweir 					{
614*cdf0e10cSrcweir 						if(bHeightSet)
615*cdf0e10cSrcweir 						{
616*cdf0e10cSrcweir 							aTextureCoordinate.setY(fOne - ((aPoint.getY() - rRange.getMinY()) / fHeight));
617*cdf0e10cSrcweir 						}
618*cdf0e10cSrcweir 						else
619*cdf0e10cSrcweir 						{
620*cdf0e10cSrcweir 							aTextureCoordinate.setY(fOne);
621*cdf0e10cSrcweir 						}
622*cdf0e10cSrcweir 					}
623*cdf0e10cSrcweir 
624*cdf0e10cSrcweir 					aRetval.setTextureCoordinate(a, aTextureCoordinate);
625*cdf0e10cSrcweir 				}
626*cdf0e10cSrcweir 			}
627*cdf0e10cSrcweir 
628*cdf0e10cSrcweir 			return aRetval;
629*cdf0e10cSrcweir 		}
630*cdf0e10cSrcweir 
631*cdf0e10cSrcweir 		B3DPolygon applyDefaultTextureCoordinatesSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY)
632*cdf0e10cSrcweir 		{
633*cdf0e10cSrcweir 			B3DPolygon aRetval(rCandidate);
634*cdf0e10cSrcweir 
635*cdf0e10cSrcweir 			if(bChangeX || bChangeY)
636*cdf0e10cSrcweir 			{
637*cdf0e10cSrcweir 				// create texture coordinates using sphere projection to cartesian coordinates,
638*cdf0e10cSrcweir 				// use object's center as base
639*cdf0e10cSrcweir 				const double fOne(1.0);
640*cdf0e10cSrcweir 				const sal_uInt32 nPointCount(aRetval.count());
641*cdf0e10cSrcweir 				bool bPolarPoints(false);
642*cdf0e10cSrcweir 				sal_uInt32 a;
643*cdf0e10cSrcweir 
644*cdf0e10cSrcweir 				// create center cartesian coordinates to have a possibility to decide if on boundary
645*cdf0e10cSrcweir 				// transitions which value to choose
646*cdf0e10cSrcweir 				const B3DRange aPlaneRange(getRange(rCandidate));
647*cdf0e10cSrcweir 				const B3DPoint aPlaneCenter(aPlaneRange.getCenter() - rCenter);
648*cdf0e10cSrcweir 				const double fXCenter(fOne - ((atan2(aPlaneCenter.getZ(), aPlaneCenter.getX()) + F_PI) / F_2PI));
649*cdf0e10cSrcweir 
650*cdf0e10cSrcweir 				for(a = 0L; a < nPointCount; a++)
651*cdf0e10cSrcweir 				{
652*cdf0e10cSrcweir 					const B3DVector aVector(aRetval.getB3DPoint(a) - rCenter);
653*cdf0e10cSrcweir 					const double fY(fOne - ((atan2(aVector.getY(), aVector.getXZLength()) + F_PI2) / F_PI));
654*cdf0e10cSrcweir 					B2DPoint aTexCoor(aRetval.getTextureCoordinate(a));
655*cdf0e10cSrcweir 
656*cdf0e10cSrcweir 					if(fTools::equalZero(fY))
657*cdf0e10cSrcweir 					{
658*cdf0e10cSrcweir 						// point is a north polar point, no useful X-coordinate can be created.
659*cdf0e10cSrcweir 						if(bChangeY)
660*cdf0e10cSrcweir 						{
661*cdf0e10cSrcweir 							aTexCoor.setY(0.0);
662*cdf0e10cSrcweir 
663*cdf0e10cSrcweir 							if(bChangeX)
664*cdf0e10cSrcweir 							{
665*cdf0e10cSrcweir 								bPolarPoints = true;
666*cdf0e10cSrcweir 							}
667*cdf0e10cSrcweir 						}
668*cdf0e10cSrcweir 					}
669*cdf0e10cSrcweir 					else if(fTools::equal(fY, fOne))
670*cdf0e10cSrcweir 					{
671*cdf0e10cSrcweir 						// point is a south polar point, no useful X-coordinate can be created. Set
672*cdf0e10cSrcweir 						// Y-coordinte, though
673*cdf0e10cSrcweir 						if(bChangeY)
674*cdf0e10cSrcweir 						{
675*cdf0e10cSrcweir 							aTexCoor.setY(fOne);
676*cdf0e10cSrcweir 
677*cdf0e10cSrcweir 							if(bChangeX)
678*cdf0e10cSrcweir 							{
679*cdf0e10cSrcweir 								bPolarPoints = true;
680*cdf0e10cSrcweir 							}
681*cdf0e10cSrcweir 						}
682*cdf0e10cSrcweir 					}
683*cdf0e10cSrcweir 					else
684*cdf0e10cSrcweir 					{
685*cdf0e10cSrcweir 						double fX(fOne - ((atan2(aVector.getZ(), aVector.getX()) + F_PI) / F_2PI));
686*cdf0e10cSrcweir 
687*cdf0e10cSrcweir 						// correct cartesinan point coordiante dependent from center value
688*cdf0e10cSrcweir 						if(fX > fXCenter + 0.5)
689*cdf0e10cSrcweir 						{
690*cdf0e10cSrcweir 							fX -= fOne;
691*cdf0e10cSrcweir 						}
692*cdf0e10cSrcweir 						else if(fX < fXCenter - 0.5)
693*cdf0e10cSrcweir 						{
694*cdf0e10cSrcweir 							fX += fOne;
695*cdf0e10cSrcweir 						}
696*cdf0e10cSrcweir 
697*cdf0e10cSrcweir 						if(bChangeX)
698*cdf0e10cSrcweir 						{
699*cdf0e10cSrcweir 							aTexCoor.setX(fX);
700*cdf0e10cSrcweir 						}
701*cdf0e10cSrcweir 
702*cdf0e10cSrcweir 						if(bChangeY)
703*cdf0e10cSrcweir 						{
704*cdf0e10cSrcweir 							aTexCoor.setY(fY);
705*cdf0e10cSrcweir 						}
706*cdf0e10cSrcweir 					}
707*cdf0e10cSrcweir 
708*cdf0e10cSrcweir 					aRetval.setTextureCoordinate(a, aTexCoor);
709*cdf0e10cSrcweir 				}
710*cdf0e10cSrcweir 
711*cdf0e10cSrcweir 				if(bPolarPoints)
712*cdf0e10cSrcweir 				{
713*cdf0e10cSrcweir 					// correct X-texture coordinates if polar points are contained. Those
714*cdf0e10cSrcweir 					// coordinates cannot be correct, so use prev or next X-coordinate
715*cdf0e10cSrcweir 					for(a = 0L; a < nPointCount; a++)
716*cdf0e10cSrcweir 					{
717*cdf0e10cSrcweir 						B2DPoint aTexCoor(aRetval.getTextureCoordinate(a));
718*cdf0e10cSrcweir 
719*cdf0e10cSrcweir 						if(fTools::equalZero(aTexCoor.getY()) || fTools::equal(aTexCoor.getY(), fOne))
720*cdf0e10cSrcweir 						{
721*cdf0e10cSrcweir 							// get prev, next TexCoor and test for pole
722*cdf0e10cSrcweir 							const B2DPoint aPrevTexCoor(aRetval.getTextureCoordinate(a ? a - 1L : nPointCount - 1L));
723*cdf0e10cSrcweir 							const B2DPoint aNextTexCoor(aRetval.getTextureCoordinate((a + 1L) % nPointCount));
724*cdf0e10cSrcweir 							const bool bPrevPole(fTools::equalZero(aPrevTexCoor.getY()) || fTools::equal(aPrevTexCoor.getY(), fOne));
725*cdf0e10cSrcweir 							const bool bNextPole(fTools::equalZero(aNextTexCoor.getY()) || fTools::equal(aNextTexCoor.getY(), fOne));
726*cdf0e10cSrcweir 
727*cdf0e10cSrcweir 							if(!bPrevPole && !bNextPole)
728*cdf0e10cSrcweir 							{
729*cdf0e10cSrcweir 								// both no poles, mix them
730*cdf0e10cSrcweir 								aTexCoor.setX((aPrevTexCoor.getX() + aNextTexCoor.getX()) / 2.0);
731*cdf0e10cSrcweir 							}
732*cdf0e10cSrcweir 							else if(!bNextPole)
733*cdf0e10cSrcweir 							{
734*cdf0e10cSrcweir 								// copy next
735*cdf0e10cSrcweir 								aTexCoor.setX(aNextTexCoor.getX());
736*cdf0e10cSrcweir 							}
737*cdf0e10cSrcweir 							else
738*cdf0e10cSrcweir 							{
739*cdf0e10cSrcweir 								// copy prev, even if it's a pole, hopefully it is already corrected
740*cdf0e10cSrcweir 								aTexCoor.setX(aPrevTexCoor.getX());
741*cdf0e10cSrcweir 							}
742*cdf0e10cSrcweir 
743*cdf0e10cSrcweir 							aRetval.setTextureCoordinate(a, aTexCoor);
744*cdf0e10cSrcweir 						}
745*cdf0e10cSrcweir 					}
746*cdf0e10cSrcweir 				}
747*cdf0e10cSrcweir 			}
748*cdf0e10cSrcweir 
749*cdf0e10cSrcweir 			return aRetval;
750*cdf0e10cSrcweir 		}
751*cdf0e10cSrcweir 
752*cdf0e10cSrcweir 		bool isInEpsilonRange(const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, const B3DPoint& rTestPosition, double fDistance)
753*cdf0e10cSrcweir 		{
754*cdf0e10cSrcweir 			// build edge vector
755*cdf0e10cSrcweir 			const B3DVector aEdge(rEdgeEnd - rEdgeStart);
756*cdf0e10cSrcweir 			bool bDoDistanceTestStart(false);
757*cdf0e10cSrcweir 			bool bDoDistanceTestEnd(false);
758*cdf0e10cSrcweir 
759*cdf0e10cSrcweir 			if(aEdge.equalZero())
760*cdf0e10cSrcweir 			{
761*cdf0e10cSrcweir 				// no edge, just a point. Do one of the distance tests.
762*cdf0e10cSrcweir 				bDoDistanceTestStart = true;
763*cdf0e10cSrcweir 			}
764*cdf0e10cSrcweir 			else
765*cdf0e10cSrcweir 			{
766*cdf0e10cSrcweir                 // calculate fCut in aEdge
767*cdf0e10cSrcweir     			const B3DVector aTestEdge(rTestPosition - rEdgeStart);
768*cdf0e10cSrcweir                 const double fScalarTestEdge(aEdge.scalar(aTestEdge));
769*cdf0e10cSrcweir                 const double fScalarStartEdge(aEdge.scalar(rEdgeStart));
770*cdf0e10cSrcweir                 const double fScalarEdge(aEdge.scalar(aEdge));
771*cdf0e10cSrcweir                 const double fCut((fScalarTestEdge - fScalarStartEdge) / fScalarEdge);
772*cdf0e10cSrcweir 				const double fZero(0.0);
773*cdf0e10cSrcweir 				const double fOne(1.0);
774*cdf0e10cSrcweir 
775*cdf0e10cSrcweir 				if(fTools::less(fCut, fZero))
776*cdf0e10cSrcweir 				{
777*cdf0e10cSrcweir 					// left of rEdgeStart
778*cdf0e10cSrcweir 					bDoDistanceTestStart = true;
779*cdf0e10cSrcweir 				}
780*cdf0e10cSrcweir 				else if(fTools::more(fCut, fOne))
781*cdf0e10cSrcweir 				{
782*cdf0e10cSrcweir 					// right of rEdgeEnd
783*cdf0e10cSrcweir 					bDoDistanceTestEnd = true;
784*cdf0e10cSrcweir 				}
785*cdf0e10cSrcweir 				else
786*cdf0e10cSrcweir 				{
787*cdf0e10cSrcweir 					// inside line [0.0 .. 1.0]
788*cdf0e10cSrcweir 					const B3DPoint aCutPoint(interpolate(rEdgeStart, rEdgeEnd, fCut));
789*cdf0e10cSrcweir     			    const B3DVector aDelta(rTestPosition - aCutPoint);
790*cdf0e10cSrcweir 				    const double fDistanceSquare(aDelta.scalar(aDelta));
791*cdf0e10cSrcweir 
792*cdf0e10cSrcweir 				    if(fDistanceSquare <= fDistance * fDistance * fDistance)
793*cdf0e10cSrcweir 				    {
794*cdf0e10cSrcweir 						return true;
795*cdf0e10cSrcweir 					}
796*cdf0e10cSrcweir 					else
797*cdf0e10cSrcweir 					{
798*cdf0e10cSrcweir 						return false;
799*cdf0e10cSrcweir 					}
800*cdf0e10cSrcweir 				}
801*cdf0e10cSrcweir 			}
802*cdf0e10cSrcweir 
803*cdf0e10cSrcweir 			if(bDoDistanceTestStart)
804*cdf0e10cSrcweir 			{
805*cdf0e10cSrcweir     			const B3DVector aDelta(rTestPosition - rEdgeStart);
806*cdf0e10cSrcweir 				const double fDistanceSquare(aDelta.scalar(aDelta));
807*cdf0e10cSrcweir 
808*cdf0e10cSrcweir 				if(fDistanceSquare <= fDistance * fDistance * fDistance)
809*cdf0e10cSrcweir 				{
810*cdf0e10cSrcweir 					return true;
811*cdf0e10cSrcweir 				}
812*cdf0e10cSrcweir 			}
813*cdf0e10cSrcweir 			else if(bDoDistanceTestEnd)
814*cdf0e10cSrcweir 			{
815*cdf0e10cSrcweir     			const B3DVector aDelta(rTestPosition - rEdgeEnd);
816*cdf0e10cSrcweir 				const double fDistanceSquare(aDelta.scalar(aDelta));
817*cdf0e10cSrcweir 
818*cdf0e10cSrcweir 				if(fDistanceSquare <= fDistance * fDistance * fDistance)
819*cdf0e10cSrcweir 				{
820*cdf0e10cSrcweir 					return true;
821*cdf0e10cSrcweir 				}
822*cdf0e10cSrcweir 			}
823*cdf0e10cSrcweir 
824*cdf0e10cSrcweir 			return false;
825*cdf0e10cSrcweir 		}
826*cdf0e10cSrcweir 
827*cdf0e10cSrcweir 		bool isInEpsilonRange(const B3DPolygon& rCandidate, const B3DPoint& rTestPosition, double fDistance)
828*cdf0e10cSrcweir 		{
829*cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
830*cdf0e10cSrcweir 
831*cdf0e10cSrcweir 			if(nPointCount)
832*cdf0e10cSrcweir 			{
833*cdf0e10cSrcweir                 const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
834*cdf0e10cSrcweir 				B3DPoint aCurrent(rCandidate.getB3DPoint(0));
835*cdf0e10cSrcweir 
836*cdf0e10cSrcweir 				if(nEdgeCount)
837*cdf0e10cSrcweir 				{
838*cdf0e10cSrcweir 					// edges
839*cdf0e10cSrcweir 					for(sal_uInt32 a(0); a < nEdgeCount; a++)
840*cdf0e10cSrcweir 					{
841*cdf0e10cSrcweir 						const sal_uInt32 nNextIndex((a + 1) % nPointCount);
842*cdf0e10cSrcweir 						const B3DPoint aNext(rCandidate.getB3DPoint(nNextIndex));
843*cdf0e10cSrcweir 
844*cdf0e10cSrcweir 						if(isInEpsilonRange(aCurrent, aNext, rTestPosition, fDistance))
845*cdf0e10cSrcweir 						{
846*cdf0e10cSrcweir 							return true;
847*cdf0e10cSrcweir 						}
848*cdf0e10cSrcweir 
849*cdf0e10cSrcweir 						// prepare next step
850*cdf0e10cSrcweir 						aCurrent = aNext;
851*cdf0e10cSrcweir 					}
852*cdf0e10cSrcweir 				}
853*cdf0e10cSrcweir 				else
854*cdf0e10cSrcweir 				{
855*cdf0e10cSrcweir 					// no edges, but points -> not closed. Check single point. Just
856*cdf0e10cSrcweir 					// use isInEpsilonRange with twice the same point, it handles those well
857*cdf0e10cSrcweir 					if(isInEpsilonRange(aCurrent, aCurrent, rTestPosition, fDistance))
858*cdf0e10cSrcweir 					{
859*cdf0e10cSrcweir 						return true;
860*cdf0e10cSrcweir 					}
861*cdf0e10cSrcweir 				}
862*cdf0e10cSrcweir 			}
863*cdf0e10cSrcweir 
864*cdf0e10cSrcweir 			return false;
865*cdf0e10cSrcweir 		}
866*cdf0e10cSrcweir 
867*cdf0e10cSrcweir 		bool isInside(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder)
868*cdf0e10cSrcweir         {
869*cdf0e10cSrcweir 			if(bWithBorder && isPointOnPolygon(rCandidate, rPoint, true))
870*cdf0e10cSrcweir 			{
871*cdf0e10cSrcweir 				return true;
872*cdf0e10cSrcweir 			}
873*cdf0e10cSrcweir 			else
874*cdf0e10cSrcweir 			{
875*cdf0e10cSrcweir 				bool bRetval(false);
876*cdf0e10cSrcweir 				const B3DVector aPlaneNormal(rCandidate.getNormal());
877*cdf0e10cSrcweir 
878*cdf0e10cSrcweir 				if(!aPlaneNormal.equalZero())
879*cdf0e10cSrcweir 				{
880*cdf0e10cSrcweir 				    const sal_uInt32 nPointCount(rCandidate.count());
881*cdf0e10cSrcweir 
882*cdf0e10cSrcweir 				    if(nPointCount)
883*cdf0e10cSrcweir 				    {
884*cdf0e10cSrcweir 					    B3DPoint aCurrentPoint(rCandidate.getB3DPoint(nPointCount - 1));
885*cdf0e10cSrcweir 					    const double fAbsX(fabs(aPlaneNormal.getX()));
886*cdf0e10cSrcweir 					    const double fAbsY(fabs(aPlaneNormal.getY()));
887*cdf0e10cSrcweir 					    const double fAbsZ(fabs(aPlaneNormal.getZ()));
888*cdf0e10cSrcweir 
889*cdf0e10cSrcweir 					    if(fAbsX > fAbsY && fAbsX > fAbsZ)
890*cdf0e10cSrcweir 					    {
891*cdf0e10cSrcweir 						    // normal points mostly in X-Direction, use YZ-Polygon projection for check
892*cdf0e10cSrcweir                             // x -> y, y -> z
893*cdf0e10cSrcweir 					        for(sal_uInt32 a(0); a < nPointCount; a++)
894*cdf0e10cSrcweir 					        {
895*cdf0e10cSrcweir 						        const B3DPoint aPreviousPoint(aCurrentPoint);
896*cdf0e10cSrcweir 						        aCurrentPoint = rCandidate.getB3DPoint(a);
897*cdf0e10cSrcweir 
898*cdf0e10cSrcweir 						        // cross-over in Z?
899*cdf0e10cSrcweir 						        const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ()));
900*cdf0e10cSrcweir 						        const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ()));
901*cdf0e10cSrcweir 
902*cdf0e10cSrcweir 						        if(bCompZA != bCompZB)
903*cdf0e10cSrcweir 						        {
904*cdf0e10cSrcweir 							        // cross-over in Y?
905*cdf0e10cSrcweir 							        const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
906*cdf0e10cSrcweir 							        const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));
907*cdf0e10cSrcweir 
908*cdf0e10cSrcweir 							        if(bCompYA == bCompYB)
909*cdf0e10cSrcweir 							        {
910*cdf0e10cSrcweir 								        if(bCompYA)
911*cdf0e10cSrcweir 								        {
912*cdf0e10cSrcweir 									        bRetval = !bRetval;
913*cdf0e10cSrcweir 								        }
914*cdf0e10cSrcweir 							        }
915*cdf0e10cSrcweir 							        else
916*cdf0e10cSrcweir 							        {
917*cdf0e10cSrcweir 								        const double fCompare(
918*cdf0e10cSrcweir 									        aCurrentPoint.getY() - (aCurrentPoint.getZ() - rPoint.getZ()) *
919*cdf0e10cSrcweir 									        (aPreviousPoint.getY() - aCurrentPoint.getY()) /
920*cdf0e10cSrcweir 									        (aPreviousPoint.getZ() - aCurrentPoint.getZ()));
921*cdf0e10cSrcweir 
922*cdf0e10cSrcweir 								        if(fTools::more(fCompare, rPoint.getY()))
923*cdf0e10cSrcweir 								        {
924*cdf0e10cSrcweir 									        bRetval = !bRetval;
925*cdf0e10cSrcweir 								        }
926*cdf0e10cSrcweir 							        }
927*cdf0e10cSrcweir 						        }
928*cdf0e10cSrcweir 					        }
929*cdf0e10cSrcweir 					    }
930*cdf0e10cSrcweir 					    else if(fAbsY > fAbsX && fAbsY > fAbsZ)
931*cdf0e10cSrcweir 					    {
932*cdf0e10cSrcweir 						    // normal points mostly in Y-Direction, use XZ-Polygon projection for check
933*cdf0e10cSrcweir                             // x -> x, y -> z
934*cdf0e10cSrcweir 					        for(sal_uInt32 a(0); a < nPointCount; a++)
935*cdf0e10cSrcweir 					        {
936*cdf0e10cSrcweir 						        const B3DPoint aPreviousPoint(aCurrentPoint);
937*cdf0e10cSrcweir 						        aCurrentPoint = rCandidate.getB3DPoint(a);
938*cdf0e10cSrcweir 
939*cdf0e10cSrcweir 						        // cross-over in Z?
940*cdf0e10cSrcweir 						        const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ()));
941*cdf0e10cSrcweir 						        const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ()));
942*cdf0e10cSrcweir 
943*cdf0e10cSrcweir 						        if(bCompZA != bCompZB)
944*cdf0e10cSrcweir 						        {
945*cdf0e10cSrcweir 							        // cross-over in X?
946*cdf0e10cSrcweir 							        const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
947*cdf0e10cSrcweir 							        const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));
948*cdf0e10cSrcweir 
949*cdf0e10cSrcweir 							        if(bCompXA == bCompXB)
950*cdf0e10cSrcweir 							        {
951*cdf0e10cSrcweir 								        if(bCompXA)
952*cdf0e10cSrcweir 								        {
953*cdf0e10cSrcweir 									        bRetval = !bRetval;
954*cdf0e10cSrcweir 								        }
955*cdf0e10cSrcweir 							        }
956*cdf0e10cSrcweir 							        else
957*cdf0e10cSrcweir 							        {
958*cdf0e10cSrcweir 								        const double fCompare(
959*cdf0e10cSrcweir 									        aCurrentPoint.getX() - (aCurrentPoint.getZ() - rPoint.getZ()) *
960*cdf0e10cSrcweir 									        (aPreviousPoint.getX() - aCurrentPoint.getX()) /
961*cdf0e10cSrcweir 									        (aPreviousPoint.getZ() - aCurrentPoint.getZ()));
962*cdf0e10cSrcweir 
963*cdf0e10cSrcweir 								        if(fTools::more(fCompare, rPoint.getX()))
964*cdf0e10cSrcweir 								        {
965*cdf0e10cSrcweir 									        bRetval = !bRetval;
966*cdf0e10cSrcweir 								        }
967*cdf0e10cSrcweir 							        }
968*cdf0e10cSrcweir 						        }
969*cdf0e10cSrcweir 					        }
970*cdf0e10cSrcweir 					    }
971*cdf0e10cSrcweir 					    else
972*cdf0e10cSrcweir 					    {
973*cdf0e10cSrcweir 						    // normal points mostly in Z-Direction, use XY-Polygon projection for check
974*cdf0e10cSrcweir                             // x -> x, y -> y
975*cdf0e10cSrcweir 					        for(sal_uInt32 a(0); a < nPointCount; a++)
976*cdf0e10cSrcweir 					        {
977*cdf0e10cSrcweir 						        const B3DPoint aPreviousPoint(aCurrentPoint);
978*cdf0e10cSrcweir 						        aCurrentPoint = rCandidate.getB3DPoint(a);
979*cdf0e10cSrcweir 
980*cdf0e10cSrcweir 						        // cross-over in Y?
981*cdf0e10cSrcweir 						        const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
982*cdf0e10cSrcweir 						        const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));
983*cdf0e10cSrcweir 
984*cdf0e10cSrcweir 						        if(bCompYA != bCompYB)
985*cdf0e10cSrcweir 						        {
986*cdf0e10cSrcweir 							        // cross-over in X?
987*cdf0e10cSrcweir 							        const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
988*cdf0e10cSrcweir 							        const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));
989*cdf0e10cSrcweir 
990*cdf0e10cSrcweir 							        if(bCompXA == bCompXB)
991*cdf0e10cSrcweir 							        {
992*cdf0e10cSrcweir 								        if(bCompXA)
993*cdf0e10cSrcweir 								        {
994*cdf0e10cSrcweir 									        bRetval = !bRetval;
995*cdf0e10cSrcweir 								        }
996*cdf0e10cSrcweir 							        }
997*cdf0e10cSrcweir 							        else
998*cdf0e10cSrcweir 							        {
999*cdf0e10cSrcweir 								        const double fCompare(
1000*cdf0e10cSrcweir 									        aCurrentPoint.getX() - (aCurrentPoint.getY() - rPoint.getY()) *
1001*cdf0e10cSrcweir 									        (aPreviousPoint.getX() - aCurrentPoint.getX()) /
1002*cdf0e10cSrcweir 									        (aPreviousPoint.getY() - aCurrentPoint.getY()));
1003*cdf0e10cSrcweir 
1004*cdf0e10cSrcweir 								        if(fTools::more(fCompare, rPoint.getX()))
1005*cdf0e10cSrcweir 								        {
1006*cdf0e10cSrcweir 									        bRetval = !bRetval;
1007*cdf0e10cSrcweir 								        }
1008*cdf0e10cSrcweir 							        }
1009*cdf0e10cSrcweir 						        }
1010*cdf0e10cSrcweir 					        }
1011*cdf0e10cSrcweir 					    }
1012*cdf0e10cSrcweir                     }
1013*cdf0e10cSrcweir 				}
1014*cdf0e10cSrcweir 
1015*cdf0e10cSrcweir 				return bRetval;
1016*cdf0e10cSrcweir 			}
1017*cdf0e10cSrcweir         }
1018*cdf0e10cSrcweir 
1019*cdf0e10cSrcweir 		bool isInside(const B3DPolygon& rCandidate, const B3DPolygon& rPolygon, bool bWithBorder)
1020*cdf0e10cSrcweir         {
1021*cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rPolygon.count());
1022*cdf0e10cSrcweir 
1023*cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nPointCount; a++)
1024*cdf0e10cSrcweir 			{
1025*cdf0e10cSrcweir 				const B3DPoint aTestPoint(rPolygon.getB3DPoint(a));
1026*cdf0e10cSrcweir 
1027*cdf0e10cSrcweir 				if(!isInside(rCandidate, aTestPoint, bWithBorder))
1028*cdf0e10cSrcweir 				{
1029*cdf0e10cSrcweir 					return false;
1030*cdf0e10cSrcweir 				}
1031*cdf0e10cSrcweir 			}
1032*cdf0e10cSrcweir 
1033*cdf0e10cSrcweir 			return true;
1034*cdf0e10cSrcweir         }
1035*cdf0e10cSrcweir 
1036*cdf0e10cSrcweir 		bool isPointOnLine(const B3DPoint& rStart, const B3DPoint& rEnd, const B3DPoint& rCandidate, bool bWithPoints)
1037*cdf0e10cSrcweir         {
1038*cdf0e10cSrcweir 			if(rCandidate.equal(rStart) || rCandidate.equal(rEnd))
1039*cdf0e10cSrcweir 			{
1040*cdf0e10cSrcweir 				// candidate is in epsilon around start or end -> inside
1041*cdf0e10cSrcweir 				return bWithPoints;
1042*cdf0e10cSrcweir 			}
1043*cdf0e10cSrcweir 			else if(rStart.equal(rEnd))
1044*cdf0e10cSrcweir 			{
1045*cdf0e10cSrcweir 				// start and end are equal, but candidate is outside their epsilon -> outside
1046*cdf0e10cSrcweir 				return false;
1047*cdf0e10cSrcweir 			}
1048*cdf0e10cSrcweir 			else
1049*cdf0e10cSrcweir 			{
1050*cdf0e10cSrcweir 				const B3DVector aEdgeVector(rEnd - rStart);
1051*cdf0e10cSrcweir 				const B3DVector aTestVector(rCandidate - rStart);
1052*cdf0e10cSrcweir 
1053*cdf0e10cSrcweir 				if(areParallel(aEdgeVector, aTestVector))
1054*cdf0e10cSrcweir 				{
1055*cdf0e10cSrcweir 					const double fZero(0.0);
1056*cdf0e10cSrcweir 					const double fOne(1.0);
1057*cdf0e10cSrcweir                     double fParamTestOnCurr(0.0);
1058*cdf0e10cSrcweir 
1059*cdf0e10cSrcweir                     if(aEdgeVector.getX() > aEdgeVector.getY())
1060*cdf0e10cSrcweir                     {
1061*cdf0e10cSrcweir                         if(aEdgeVector.getX() > aEdgeVector.getZ())
1062*cdf0e10cSrcweir                         {
1063*cdf0e10cSrcweir                             // X is biggest
1064*cdf0e10cSrcweir                             fParamTestOnCurr = aTestVector.getX() / aEdgeVector.getX();
1065*cdf0e10cSrcweir                         }
1066*cdf0e10cSrcweir                         else
1067*cdf0e10cSrcweir                         {
1068*cdf0e10cSrcweir                             // Z is biggest
1069*cdf0e10cSrcweir                             fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ();
1070*cdf0e10cSrcweir                         }
1071*cdf0e10cSrcweir                     }
1072*cdf0e10cSrcweir                     else
1073*cdf0e10cSrcweir                     {
1074*cdf0e10cSrcweir                         if(aEdgeVector.getY() > aEdgeVector.getZ())
1075*cdf0e10cSrcweir                         {
1076*cdf0e10cSrcweir                             // Y is biggest
1077*cdf0e10cSrcweir                             fParamTestOnCurr = aTestVector.getY() / aEdgeVector.getY();
1078*cdf0e10cSrcweir                         }
1079*cdf0e10cSrcweir                         else
1080*cdf0e10cSrcweir                         {
1081*cdf0e10cSrcweir                             // Z is biggest
1082*cdf0e10cSrcweir                             fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ();
1083*cdf0e10cSrcweir                         }
1084*cdf0e10cSrcweir                     }
1085*cdf0e10cSrcweir 
1086*cdf0e10cSrcweir 					if(fTools::more(fParamTestOnCurr, fZero) && fTools::less(fParamTestOnCurr, fOne))
1087*cdf0e10cSrcweir 					{
1088*cdf0e10cSrcweir 						return true;
1089*cdf0e10cSrcweir 					}
1090*cdf0e10cSrcweir 				}
1091*cdf0e10cSrcweir 
1092*cdf0e10cSrcweir 				return false;
1093*cdf0e10cSrcweir 			}
1094*cdf0e10cSrcweir         }
1095*cdf0e10cSrcweir 
1096*cdf0e10cSrcweir 		bool isPointOnPolygon(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithPoints)
1097*cdf0e10cSrcweir         {
1098*cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
1099*cdf0e10cSrcweir 
1100*cdf0e10cSrcweir 			if(nPointCount > 1L)
1101*cdf0e10cSrcweir 			{
1102*cdf0e10cSrcweir 				const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
1103*cdf0e10cSrcweir 				B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0));
1104*cdf0e10cSrcweir 
1105*cdf0e10cSrcweir 				for(sal_uInt32 a(0); a < nLoopCount; a++)
1106*cdf0e10cSrcweir 				{
1107*cdf0e10cSrcweir 					const B3DPoint aNextPoint(rCandidate.getB3DPoint((a + 1) % nPointCount));
1108*cdf0e10cSrcweir 
1109*cdf0e10cSrcweir 					if(isPointOnLine(aCurrentPoint, aNextPoint, rPoint, bWithPoints))
1110*cdf0e10cSrcweir 					{
1111*cdf0e10cSrcweir 						return true;
1112*cdf0e10cSrcweir 					}
1113*cdf0e10cSrcweir 
1114*cdf0e10cSrcweir 					aCurrentPoint = aNextPoint;
1115*cdf0e10cSrcweir 				}
1116*cdf0e10cSrcweir 			}
1117*cdf0e10cSrcweir 			else if(nPointCount && bWithPoints)
1118*cdf0e10cSrcweir 			{
1119*cdf0e10cSrcweir 				return rPoint.equal(rCandidate.getB3DPoint(0));
1120*cdf0e10cSrcweir 			}
1121*cdf0e10cSrcweir 
1122*cdf0e10cSrcweir 			return false;
1123*cdf0e10cSrcweir         }
1124*cdf0e10cSrcweir 
1125*cdf0e10cSrcweir         bool getCutBetweenLineAndPlane(const B3DVector& rPlaneNormal, const B3DPoint& rPlanePoint, const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, double& fCut)
1126*cdf0e10cSrcweir         {
1127*cdf0e10cSrcweir             if(!rPlaneNormal.equalZero() && !rEdgeStart.equal(rEdgeEnd))
1128*cdf0e10cSrcweir             {
1129*cdf0e10cSrcweir 			    const B3DVector aTestEdge(rEdgeEnd - rEdgeStart);
1130*cdf0e10cSrcweir                 const double fScalarEdge(rPlaneNormal.scalar(aTestEdge));
1131*cdf0e10cSrcweir 
1132*cdf0e10cSrcweir 				if(!fTools::equalZero(fScalarEdge))
1133*cdf0e10cSrcweir 				{
1134*cdf0e10cSrcweir 					const B3DVector aCompareEdge(rPlanePoint - rEdgeStart);
1135*cdf0e10cSrcweir 					const double fScalarCompare(rPlaneNormal.scalar(aCompareEdge));
1136*cdf0e10cSrcweir 
1137*cdf0e10cSrcweir 					fCut = fScalarCompare / fScalarEdge;
1138*cdf0e10cSrcweir 					return true;
1139*cdf0e10cSrcweir 				}
1140*cdf0e10cSrcweir             }
1141*cdf0e10cSrcweir 
1142*cdf0e10cSrcweir             return false;
1143*cdf0e10cSrcweir         }
1144*cdf0e10cSrcweir 
1145*cdf0e10cSrcweir         bool getCutBetweenLineAndPolygon(const B3DPolygon& rCandidate, const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, double& fCut)
1146*cdf0e10cSrcweir         {
1147*cdf0e10cSrcweir             const sal_uInt32 nPointCount(rCandidate.count());
1148*cdf0e10cSrcweir 
1149*cdf0e10cSrcweir             if(nPointCount > 2 && !rEdgeStart.equal(rEdgeEnd))
1150*cdf0e10cSrcweir             {
1151*cdf0e10cSrcweir                 const B3DVector aPlaneNormal(rCandidate.getNormal());
1152*cdf0e10cSrcweir 
1153*cdf0e10cSrcweir                 if(!aPlaneNormal.equalZero())
1154*cdf0e10cSrcweir                 {
1155*cdf0e10cSrcweir                     const B3DPoint aPointOnPlane(rCandidate.getB3DPoint(0));
1156*cdf0e10cSrcweir 
1157*cdf0e10cSrcweir                     return getCutBetweenLineAndPlane(aPlaneNormal, aPointOnPlane, rEdgeStart, rEdgeEnd, fCut);
1158*cdf0e10cSrcweir                 }
1159*cdf0e10cSrcweir             }
1160*cdf0e10cSrcweir 
1161*cdf0e10cSrcweir             return false;
1162*cdf0e10cSrcweir         }
1163*cdf0e10cSrcweir 
1164*cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////
1165*cdf0e10cSrcweir 		// comparators with tolerance for 3D Polygons
1166*cdf0e10cSrcweir 
1167*cdf0e10cSrcweir 		bool equal(const B3DPolygon& rCandidateA, const B3DPolygon& rCandidateB, const double& rfSmallValue)
1168*cdf0e10cSrcweir 		{
1169*cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidateA.count());
1170*cdf0e10cSrcweir 
1171*cdf0e10cSrcweir 			if(nPointCount != rCandidateB.count())
1172*cdf0e10cSrcweir 				return false;
1173*cdf0e10cSrcweir 
1174*cdf0e10cSrcweir 			const bool bClosed(rCandidateA.isClosed());
1175*cdf0e10cSrcweir 
1176*cdf0e10cSrcweir 			if(bClosed != rCandidateB.isClosed())
1177*cdf0e10cSrcweir 				return false;
1178*cdf0e10cSrcweir 
1179*cdf0e10cSrcweir 			for(sal_uInt32 a(0); a < nPointCount; a++)
1180*cdf0e10cSrcweir 			{
1181*cdf0e10cSrcweir 				const B3DPoint aPoint(rCandidateA.getB3DPoint(a));
1182*cdf0e10cSrcweir 
1183*cdf0e10cSrcweir 				if(!aPoint.equal(rCandidateB.getB3DPoint(a), rfSmallValue))
1184*cdf0e10cSrcweir 					return false;
1185*cdf0e10cSrcweir 			}
1186*cdf0e10cSrcweir 
1187*cdf0e10cSrcweir 			return true;
1188*cdf0e10cSrcweir 		}
1189*cdf0e10cSrcweir 
1190*cdf0e10cSrcweir 		bool equal(const B3DPolygon& rCandidateA, const B3DPolygon& rCandidateB)
1191*cdf0e10cSrcweir 		{
1192*cdf0e10cSrcweir 			const double fSmallValue(fTools::getSmallValue());
1193*cdf0e10cSrcweir 
1194*cdf0e10cSrcweir 			return equal(rCandidateA, rCandidateB, fSmallValue);
1195*cdf0e10cSrcweir 		}
1196*cdf0e10cSrcweir 
1197*cdf0e10cSrcweir 		// snap points of horizontal or vertical edges to discrete values
1198*cdf0e10cSrcweir 		B3DPolygon snapPointsOfHorizontalOrVerticalEdges(const B3DPolygon& rCandidate)
1199*cdf0e10cSrcweir 		{
1200*cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
1201*cdf0e10cSrcweir 
1202*cdf0e10cSrcweir 			if(nPointCount > 1)
1203*cdf0e10cSrcweir 			{
1204*cdf0e10cSrcweir 				// Start by copying the source polygon to get a writeable copy. The closed state is
1205*cdf0e10cSrcweir 				// copied by aRetval's initialisation, too, so no need to copy it in this method
1206*cdf0e10cSrcweir 				B3DPolygon aRetval(rCandidate);
1207*cdf0e10cSrcweir 
1208*cdf0e10cSrcweir 				// prepare geometry data. Get rounded from original
1209*cdf0e10cSrcweir                 B3ITuple aPrevTuple(basegfx::fround(rCandidate.getB3DPoint(nPointCount - 1)));
1210*cdf0e10cSrcweir 				B3DPoint aCurrPoint(rCandidate.getB3DPoint(0));
1211*cdf0e10cSrcweir 				B3ITuple aCurrTuple(basegfx::fround(aCurrPoint));
1212*cdf0e10cSrcweir 
1213*cdf0e10cSrcweir 				// loop over all points. This will also snap the implicit closing edge
1214*cdf0e10cSrcweir 				// even when not closed, but that's no problem here
1215*cdf0e10cSrcweir 				for(sal_uInt32 a(0); a < nPointCount; a++)
1216*cdf0e10cSrcweir 				{
1217*cdf0e10cSrcweir 					// get next point. Get rounded from original
1218*cdf0e10cSrcweir                     const bool bLastRun(a + 1 == nPointCount);
1219*cdf0e10cSrcweir                     const sal_uInt32 nNextIndex(bLastRun ? 0 : a + 1);
1220*cdf0e10cSrcweir 					const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
1221*cdf0e10cSrcweir 					const B3ITuple aNextTuple(basegfx::fround(aNextPoint));
1222*cdf0e10cSrcweir 
1223*cdf0e10cSrcweir 					// get the states
1224*cdf0e10cSrcweir 					const bool bPrevVertical(aPrevTuple.getX() == aCurrTuple.getX());
1225*cdf0e10cSrcweir 					const bool bNextVertical(aNextTuple.getX() == aCurrTuple.getX());
1226*cdf0e10cSrcweir 					const bool bPrevHorizontal(aPrevTuple.getY() == aCurrTuple.getY());
1227*cdf0e10cSrcweir 					const bool bNextHorizontal(aNextTuple.getY() == aCurrTuple.getY());
1228*cdf0e10cSrcweir 					const bool bSnapX(bPrevVertical || bNextVertical);
1229*cdf0e10cSrcweir 					const bool bSnapY(bPrevHorizontal || bNextHorizontal);
1230*cdf0e10cSrcweir 
1231*cdf0e10cSrcweir 					if(bSnapX || bSnapY)
1232*cdf0e10cSrcweir 					{
1233*cdf0e10cSrcweir 						const B3DPoint aSnappedPoint(
1234*cdf0e10cSrcweir 							bSnapX ? aCurrTuple.getX() : aCurrPoint.getX(),
1235*cdf0e10cSrcweir 							bSnapY ? aCurrTuple.getY() : aCurrPoint.getY(),
1236*cdf0e10cSrcweir 							aCurrPoint.getZ());
1237*cdf0e10cSrcweir 
1238*cdf0e10cSrcweir 						aRetval.setB3DPoint(a, aSnappedPoint);
1239*cdf0e10cSrcweir 					}
1240*cdf0e10cSrcweir 
1241*cdf0e10cSrcweir 					// prepare next point
1242*cdf0e10cSrcweir                     if(!bLastRun)
1243*cdf0e10cSrcweir                     {
1244*cdf0e10cSrcweir     					aPrevTuple = aCurrTuple;
1245*cdf0e10cSrcweir 	    				aCurrPoint = aNextPoint;
1246*cdf0e10cSrcweir 		    			aCurrTuple = aNextTuple;
1247*cdf0e10cSrcweir                     }
1248*cdf0e10cSrcweir 				}
1249*cdf0e10cSrcweir 
1250*cdf0e10cSrcweir 				return aRetval;
1251*cdf0e10cSrcweir 			}
1252*cdf0e10cSrcweir 			else
1253*cdf0e10cSrcweir 			{
1254*cdf0e10cSrcweir 				return rCandidate;
1255*cdf0e10cSrcweir 			}
1256*cdf0e10cSrcweir 		}
1257*cdf0e10cSrcweir 
1258*cdf0e10cSrcweir 	} // end of namespace tools
1259*cdf0e10cSrcweir } // end of namespace basegfx
1260*cdf0e10cSrcweir 
1261*cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
1262*cdf0e10cSrcweir 
1263*cdf0e10cSrcweir // eof
1264