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