1*09dbbe93SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*09dbbe93SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*09dbbe93SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*09dbbe93SAndrew Rist  * distributed with this work for additional information
6*09dbbe93SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*09dbbe93SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*09dbbe93SAndrew Rist  * "License"); you may not use this file except in compliance
9*09dbbe93SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*09dbbe93SAndrew Rist  *
11*09dbbe93SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*09dbbe93SAndrew Rist  *
13*09dbbe93SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*09dbbe93SAndrew Rist  * software distributed under the License is distributed on an
15*09dbbe93SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*09dbbe93SAndrew Rist  * KIND, either express or implied.  See the License for the
17*09dbbe93SAndrew Rist  * specific language governing permissions and limitations
18*09dbbe93SAndrew Rist  * under the License.
19*09dbbe93SAndrew Rist  *
20*09dbbe93SAndrew Rist  *************************************************************/
21*09dbbe93SAndrew Rist 
22*09dbbe93SAndrew 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
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.
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 
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 
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 
103cdf0e10cSrcweir 		B3DVector getNormal(const B3DPolygon& rCandidate)
104cdf0e10cSrcweir 		{
105cdf0e10cSrcweir 			return rCandidate.getNormal();
106cdf0e10cSrcweir 		}
107cdf0e10cSrcweir 
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 
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 
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 
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 
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 
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 
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 
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 
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]);
410cdf0e10cSrcweir 				B3DPolygon aSnippet;
411cdf0e10cSrcweir 
412cdf0e10cSrcweir 				// iterate over all edges
413cdf0e10cSrcweir                 for(sal_uInt32 a(0); a < nEdgeCount; a++)
414cdf0e10cSrcweir                 {
415cdf0e10cSrcweir                     // update current edge
416cdf0e10cSrcweir 					double fLastDotDashMovingLength(0.0);
417cdf0e10cSrcweir                     const sal_uInt32 nNextIndex((a + 1) % nPointCount);
418cdf0e10cSrcweir 					const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
419cdf0e10cSrcweir 					const double fEdgeLength(B3DVector(aNextPoint - aCurrentPoint).getLength());
420cdf0e10cSrcweir 
421cdf0e10cSrcweir 					while(fTools::less(fDotDashMovingLength, fEdgeLength))
422cdf0e10cSrcweir 					{
423cdf0e10cSrcweir 						// new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
424cdf0e10cSrcweir 						const bool bHandleLine(bIsLine && pLineTarget);
425cdf0e10cSrcweir 						const bool bHandleGap(!bIsLine && pGapTarget);
426cdf0e10cSrcweir 
427cdf0e10cSrcweir                         if(bHandleLine || bHandleGap)
428cdf0e10cSrcweir                         {
429cdf0e10cSrcweir 							if(!aSnippet.count())
430cdf0e10cSrcweir 							{
431cdf0e10cSrcweir 								aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
432cdf0e10cSrcweir 							}
433cdf0e10cSrcweir 
434cdf0e10cSrcweir 							aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength));
435cdf0e10cSrcweir 
436cdf0e10cSrcweir 							if(bHandleLine)
437cdf0e10cSrcweir 							{
438cdf0e10cSrcweir 								pLineTarget->append(aSnippet);
439cdf0e10cSrcweir 							}
440cdf0e10cSrcweir 							else
441cdf0e10cSrcweir 							{
442cdf0e10cSrcweir 								pGapTarget->append(aSnippet);
443cdf0e10cSrcweir 							}
444cdf0e10cSrcweir 
445cdf0e10cSrcweir 							aSnippet.clear();
446cdf0e10cSrcweir 						}
447cdf0e10cSrcweir 
448cdf0e10cSrcweir 						// prepare next DotDashArray step and flip line/gap flag
449cdf0e10cSrcweir 						fLastDotDashMovingLength = fDotDashMovingLength;
450cdf0e10cSrcweir                         fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
451cdf0e10cSrcweir                         bIsLine = !bIsLine;
452cdf0e10cSrcweir 					}
453cdf0e10cSrcweir 
454cdf0e10cSrcweir 					// append snippet [fLastDotDashMovingLength, fEdgeLength]
455cdf0e10cSrcweir 					const bool bHandleLine(bIsLine && pLineTarget);
456cdf0e10cSrcweir 					const bool bHandleGap(!bIsLine && pGapTarget);
457cdf0e10cSrcweir 
458cdf0e10cSrcweir 					if(bHandleLine || bHandleGap)
459cdf0e10cSrcweir                     {
460cdf0e10cSrcweir 						if(!aSnippet.count())
461cdf0e10cSrcweir 						{
462cdf0e10cSrcweir 							aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
463cdf0e10cSrcweir 						}
464cdf0e10cSrcweir 
465cdf0e10cSrcweir 						aSnippet.append(aNextPoint);
466cdf0e10cSrcweir 					}
467cdf0e10cSrcweir 
468cdf0e10cSrcweir 					// prepare move to next edge
469cdf0e10cSrcweir 					fDotDashMovingLength -= fEdgeLength;
470cdf0e10cSrcweir 
471cdf0e10cSrcweir 					// prepare next edge step (end point gets new start point)
472cdf0e10cSrcweir                     aCurrentPoint = aNextPoint;
473cdf0e10cSrcweir                 }
474cdf0e10cSrcweir 
475cdf0e10cSrcweir                 // append last intermediate results (if exists)
476cdf0e10cSrcweir                 if(aSnippet.count())
477cdf0e10cSrcweir                 {
478cdf0e10cSrcweir                     if(bIsLine && pLineTarget)
479cdf0e10cSrcweir                     {
480cdf0e10cSrcweir                         pLineTarget->append(aSnippet);
481cdf0e10cSrcweir                     }
482cdf0e10cSrcweir                     else if(!bIsLine && pGapTarget)
483cdf0e10cSrcweir                     {
484cdf0e10cSrcweir                         pGapTarget->append(aSnippet);
485cdf0e10cSrcweir                     }
486cdf0e10cSrcweir                 }
487cdf0e10cSrcweir 
488cdf0e10cSrcweir 				// check if start and end polygon may be merged
489cdf0e10cSrcweir 				if(pLineTarget)
490cdf0e10cSrcweir 				{
491cdf0e10cSrcweir 					const sal_uInt32 nCount(pLineTarget->count());
492cdf0e10cSrcweir 
493cdf0e10cSrcweir 					if(nCount > 1)
494cdf0e10cSrcweir 					{
495cdf0e10cSrcweir 						// these polygons were created above, there exists none with less than two points,
496cdf0e10cSrcweir 						// thus dircet point access below is allowed
497cdf0e10cSrcweir 						const B3DPolygon aFirst(pLineTarget->getB3DPolygon(0));
498cdf0e10cSrcweir 						B3DPolygon aLast(pLineTarget->getB3DPolygon(nCount - 1));
499cdf0e10cSrcweir 
500cdf0e10cSrcweir 						if(aFirst.getB3DPoint(0).equal(aLast.getB3DPoint(aLast.count() - 1)))
501cdf0e10cSrcweir 						{
502cdf0e10cSrcweir 							// start of first and end of last are the same -> merge them
503cdf0e10cSrcweir 							aLast.append(aFirst);
504cdf0e10cSrcweir 							aLast.removeDoublePoints();
505cdf0e10cSrcweir 							pLineTarget->setB3DPolygon(0, aLast);
506cdf0e10cSrcweir 							pLineTarget->remove(nCount - 1);
507cdf0e10cSrcweir 						}
508cdf0e10cSrcweir 					}
509cdf0e10cSrcweir 				}
510cdf0e10cSrcweir 
511cdf0e10cSrcweir 				if(pGapTarget)
512cdf0e10cSrcweir 				{
513cdf0e10cSrcweir 					const sal_uInt32 nCount(pGapTarget->count());
514cdf0e10cSrcweir 
515cdf0e10cSrcweir 					if(nCount > 1)
516cdf0e10cSrcweir 					{
517cdf0e10cSrcweir 						// these polygons were created above, there exists none with less than two points,
518cdf0e10cSrcweir 						// thus dircet point access below is allowed
519cdf0e10cSrcweir 						const B3DPolygon aFirst(pGapTarget->getB3DPolygon(0));
520cdf0e10cSrcweir 						B3DPolygon aLast(pGapTarget->getB3DPolygon(nCount - 1));
521cdf0e10cSrcweir 
522cdf0e10cSrcweir 						if(aFirst.getB3DPoint(0).equal(aLast.getB3DPoint(aLast.count() - 1)))
523cdf0e10cSrcweir 						{
524cdf0e10cSrcweir 							// start of first and end of last are the same -> merge them
525cdf0e10cSrcweir 							aLast.append(aFirst);
526cdf0e10cSrcweir 							aLast.removeDoublePoints();
527cdf0e10cSrcweir 							pGapTarget->setB3DPolygon(0, aLast);
528cdf0e10cSrcweir 							pGapTarget->remove(nCount - 1);
529cdf0e10cSrcweir 						}
530cdf0e10cSrcweir 					}
531cdf0e10cSrcweir 				}
532cdf0e10cSrcweir             }
533cdf0e10cSrcweir             else
534cdf0e10cSrcweir             {
535cdf0e10cSrcweir 				// parameters make no sense, just add source to targets
536cdf0e10cSrcweir                 if(pLineTarget)
537cdf0e10cSrcweir                 {
538cdf0e10cSrcweir                     pLineTarget->append(rCandidate);
539cdf0e10cSrcweir                 }
540cdf0e10cSrcweir 
541cdf0e10cSrcweir 				if(pGapTarget)
542cdf0e10cSrcweir 				{
543cdf0e10cSrcweir                     pGapTarget->append(rCandidate);
544cdf0e10cSrcweir 				}
545cdf0e10cSrcweir             }
546cdf0e10cSrcweir 		}
547cdf0e10cSrcweir 
548cdf0e10cSrcweir 		B3DPolygon applyDefaultNormalsSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter)
549cdf0e10cSrcweir 		{
550cdf0e10cSrcweir 			B3DPolygon aRetval(rCandidate);
551cdf0e10cSrcweir 
552cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < aRetval.count(); a++)
553cdf0e10cSrcweir 			{
554cdf0e10cSrcweir 				B3DVector aVector(aRetval.getB3DPoint(a) - rCenter);
555cdf0e10cSrcweir 				aVector.normalize();
556cdf0e10cSrcweir 				aRetval.setNormal(a, aVector);
557cdf0e10cSrcweir 			}
558cdf0e10cSrcweir 
559cdf0e10cSrcweir 			return aRetval;
560cdf0e10cSrcweir 		}
561cdf0e10cSrcweir 
562cdf0e10cSrcweir 		B3DPolygon invertNormals( const B3DPolygon& rCandidate)
563cdf0e10cSrcweir 		{
564cdf0e10cSrcweir 			B3DPolygon aRetval(rCandidate);
565cdf0e10cSrcweir 
566cdf0e10cSrcweir 			if(aRetval.areNormalsUsed())
567cdf0e10cSrcweir 			{
568cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < aRetval.count(); a++)
569cdf0e10cSrcweir 				{
570cdf0e10cSrcweir 					aRetval.setNormal(a, -aRetval.getNormal(a));
571cdf0e10cSrcweir 				}
572cdf0e10cSrcweir 			}
573cdf0e10cSrcweir 
574cdf0e10cSrcweir 			return aRetval;
575cdf0e10cSrcweir 		}
576cdf0e10cSrcweir 
577cdf0e10cSrcweir 		B3DPolygon applyDefaultTextureCoordinatesParallel( const B3DPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY)
578cdf0e10cSrcweir 		{
579cdf0e10cSrcweir 			B3DPolygon aRetval(rCandidate);
580cdf0e10cSrcweir 
581cdf0e10cSrcweir 			if(bChangeX || bChangeY)
582cdf0e10cSrcweir 			{
583cdf0e10cSrcweir 				// create projection of standard texture coordinates in (X, Y) onto
584cdf0e10cSrcweir 				// the 3d coordinates straight
585cdf0e10cSrcweir 				const double fWidth(rRange.getWidth());
586cdf0e10cSrcweir 				const double fHeight(rRange.getHeight());
587cdf0e10cSrcweir 				const bool bWidthSet(!fTools::equalZero(fWidth));
588cdf0e10cSrcweir 				const bool bHeightSet(!fTools::equalZero(fHeight));
589cdf0e10cSrcweir 				const double fOne(1.0);
590cdf0e10cSrcweir 
591cdf0e10cSrcweir 				for(sal_uInt32 a(0L); a < aRetval.count(); a++)
592cdf0e10cSrcweir 				{
593cdf0e10cSrcweir 					const B3DPoint aPoint(aRetval.getB3DPoint(a));
594cdf0e10cSrcweir 					B2DPoint aTextureCoordinate(aRetval.getTextureCoordinate(a));
595cdf0e10cSrcweir 
596cdf0e10cSrcweir 					if(bChangeX)
597cdf0e10cSrcweir 					{
598cdf0e10cSrcweir 						if(bWidthSet)
599cdf0e10cSrcweir 						{
600cdf0e10cSrcweir 							aTextureCoordinate.setX((aPoint.getX() - rRange.getMinX()) / fWidth);
601cdf0e10cSrcweir 						}
602cdf0e10cSrcweir 						else
603cdf0e10cSrcweir 						{
604cdf0e10cSrcweir 							aTextureCoordinate.setX(0.0);
605cdf0e10cSrcweir 						}
606cdf0e10cSrcweir 					}
607cdf0e10cSrcweir 
608cdf0e10cSrcweir 					if(bChangeY)
609cdf0e10cSrcweir 					{
610cdf0e10cSrcweir 						if(bHeightSet)
611cdf0e10cSrcweir 						{
612cdf0e10cSrcweir 							aTextureCoordinate.setY(fOne - ((aPoint.getY() - rRange.getMinY()) / fHeight));
613cdf0e10cSrcweir 						}
614cdf0e10cSrcweir 						else
615cdf0e10cSrcweir 						{
616cdf0e10cSrcweir 							aTextureCoordinate.setY(fOne);
617cdf0e10cSrcweir 						}
618cdf0e10cSrcweir 					}
619cdf0e10cSrcweir 
620cdf0e10cSrcweir 					aRetval.setTextureCoordinate(a, aTextureCoordinate);
621cdf0e10cSrcweir 				}
622cdf0e10cSrcweir 			}
623cdf0e10cSrcweir 
624cdf0e10cSrcweir 			return aRetval;
625cdf0e10cSrcweir 		}
626cdf0e10cSrcweir 
627cdf0e10cSrcweir 		B3DPolygon applyDefaultTextureCoordinatesSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY)
628cdf0e10cSrcweir 		{
629cdf0e10cSrcweir 			B3DPolygon aRetval(rCandidate);
630cdf0e10cSrcweir 
631cdf0e10cSrcweir 			if(bChangeX || bChangeY)
632cdf0e10cSrcweir 			{
633cdf0e10cSrcweir 				// create texture coordinates using sphere projection to cartesian coordinates,
634cdf0e10cSrcweir 				// use object's center as base
635cdf0e10cSrcweir 				const double fOne(1.0);
636cdf0e10cSrcweir 				const sal_uInt32 nPointCount(aRetval.count());
637cdf0e10cSrcweir 				bool bPolarPoints(false);
638cdf0e10cSrcweir 				sal_uInt32 a;
639cdf0e10cSrcweir 
640cdf0e10cSrcweir 				// create center cartesian coordinates to have a possibility to decide if on boundary
641cdf0e10cSrcweir 				// transitions which value to choose
642cdf0e10cSrcweir 				const B3DRange aPlaneRange(getRange(rCandidate));
643cdf0e10cSrcweir 				const B3DPoint aPlaneCenter(aPlaneRange.getCenter() - rCenter);
644cdf0e10cSrcweir 				const double fXCenter(fOne - ((atan2(aPlaneCenter.getZ(), aPlaneCenter.getX()) + F_PI) / F_2PI));
645cdf0e10cSrcweir 
646cdf0e10cSrcweir 				for(a = 0L; a < nPointCount; a++)
647cdf0e10cSrcweir 				{
648cdf0e10cSrcweir 					const B3DVector aVector(aRetval.getB3DPoint(a) - rCenter);
649cdf0e10cSrcweir 					const double fY(fOne - ((atan2(aVector.getY(), aVector.getXZLength()) + F_PI2) / F_PI));
650cdf0e10cSrcweir 					B2DPoint aTexCoor(aRetval.getTextureCoordinate(a));
651cdf0e10cSrcweir 
652cdf0e10cSrcweir 					if(fTools::equalZero(fY))
653cdf0e10cSrcweir 					{
654cdf0e10cSrcweir 						// point is a north polar point, no useful X-coordinate can be created.
655cdf0e10cSrcweir 						if(bChangeY)
656cdf0e10cSrcweir 						{
657cdf0e10cSrcweir 							aTexCoor.setY(0.0);
658cdf0e10cSrcweir 
659cdf0e10cSrcweir 							if(bChangeX)
660cdf0e10cSrcweir 							{
661cdf0e10cSrcweir 								bPolarPoints = true;
662cdf0e10cSrcweir 							}
663cdf0e10cSrcweir 						}
664cdf0e10cSrcweir 					}
665cdf0e10cSrcweir 					else if(fTools::equal(fY, fOne))
666cdf0e10cSrcweir 					{
667cdf0e10cSrcweir 						// point is a south polar point, no useful X-coordinate can be created. Set
668cdf0e10cSrcweir 						// Y-coordinte, though
669cdf0e10cSrcweir 						if(bChangeY)
670cdf0e10cSrcweir 						{
671cdf0e10cSrcweir 							aTexCoor.setY(fOne);
672cdf0e10cSrcweir 
673cdf0e10cSrcweir 							if(bChangeX)
674cdf0e10cSrcweir 							{
675cdf0e10cSrcweir 								bPolarPoints = true;
676cdf0e10cSrcweir 							}
677cdf0e10cSrcweir 						}
678cdf0e10cSrcweir 					}
679cdf0e10cSrcweir 					else
680cdf0e10cSrcweir 					{
681cdf0e10cSrcweir 						double fX(fOne - ((atan2(aVector.getZ(), aVector.getX()) + F_PI) / F_2PI));
682cdf0e10cSrcweir 
683cdf0e10cSrcweir 						// correct cartesinan point coordiante dependent from center value
684cdf0e10cSrcweir 						if(fX > fXCenter + 0.5)
685cdf0e10cSrcweir 						{
686cdf0e10cSrcweir 							fX -= fOne;
687cdf0e10cSrcweir 						}
688cdf0e10cSrcweir 						else if(fX < fXCenter - 0.5)
689cdf0e10cSrcweir 						{
690cdf0e10cSrcweir 							fX += fOne;
691cdf0e10cSrcweir 						}
692cdf0e10cSrcweir 
693cdf0e10cSrcweir 						if(bChangeX)
694cdf0e10cSrcweir 						{
695cdf0e10cSrcweir 							aTexCoor.setX(fX);
696cdf0e10cSrcweir 						}
697cdf0e10cSrcweir 
698cdf0e10cSrcweir 						if(bChangeY)
699cdf0e10cSrcweir 						{
700cdf0e10cSrcweir 							aTexCoor.setY(fY);
701cdf0e10cSrcweir 						}
702cdf0e10cSrcweir 					}
703cdf0e10cSrcweir 
704cdf0e10cSrcweir 					aRetval.setTextureCoordinate(a, aTexCoor);
705cdf0e10cSrcweir 				}
706cdf0e10cSrcweir 
707cdf0e10cSrcweir 				if(bPolarPoints)
708cdf0e10cSrcweir 				{
709cdf0e10cSrcweir 					// correct X-texture coordinates if polar points are contained. Those
710cdf0e10cSrcweir 					// coordinates cannot be correct, so use prev or next X-coordinate
711cdf0e10cSrcweir 					for(a = 0L; a < nPointCount; a++)
712cdf0e10cSrcweir 					{
713cdf0e10cSrcweir 						B2DPoint aTexCoor(aRetval.getTextureCoordinate(a));
714cdf0e10cSrcweir 
715cdf0e10cSrcweir 						if(fTools::equalZero(aTexCoor.getY()) || fTools::equal(aTexCoor.getY(), fOne))
716cdf0e10cSrcweir 						{
717cdf0e10cSrcweir 							// get prev, next TexCoor and test for pole
718cdf0e10cSrcweir 							const B2DPoint aPrevTexCoor(aRetval.getTextureCoordinate(a ? a - 1L : nPointCount - 1L));
719cdf0e10cSrcweir 							const B2DPoint aNextTexCoor(aRetval.getTextureCoordinate((a + 1L) % nPointCount));
720cdf0e10cSrcweir 							const bool bPrevPole(fTools::equalZero(aPrevTexCoor.getY()) || fTools::equal(aPrevTexCoor.getY(), fOne));
721cdf0e10cSrcweir 							const bool bNextPole(fTools::equalZero(aNextTexCoor.getY()) || fTools::equal(aNextTexCoor.getY(), fOne));
722cdf0e10cSrcweir 
723cdf0e10cSrcweir 							if(!bPrevPole && !bNextPole)
724cdf0e10cSrcweir 							{
725cdf0e10cSrcweir 								// both no poles, mix them
726cdf0e10cSrcweir 								aTexCoor.setX((aPrevTexCoor.getX() + aNextTexCoor.getX()) / 2.0);
727cdf0e10cSrcweir 							}
728cdf0e10cSrcweir 							else if(!bNextPole)
729cdf0e10cSrcweir 							{
730cdf0e10cSrcweir 								// copy next
731cdf0e10cSrcweir 								aTexCoor.setX(aNextTexCoor.getX());
732cdf0e10cSrcweir 							}
733cdf0e10cSrcweir 							else
734cdf0e10cSrcweir 							{
735cdf0e10cSrcweir 								// copy prev, even if it's a pole, hopefully it is already corrected
736cdf0e10cSrcweir 								aTexCoor.setX(aPrevTexCoor.getX());
737cdf0e10cSrcweir 							}
738cdf0e10cSrcweir 
739cdf0e10cSrcweir 							aRetval.setTextureCoordinate(a, aTexCoor);
740cdf0e10cSrcweir 						}
741cdf0e10cSrcweir 					}
742cdf0e10cSrcweir 				}
743cdf0e10cSrcweir 			}
744cdf0e10cSrcweir 
745cdf0e10cSrcweir 			return aRetval;
746cdf0e10cSrcweir 		}
747cdf0e10cSrcweir 
748cdf0e10cSrcweir 		bool isInEpsilonRange(const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, const B3DPoint& rTestPosition, double fDistance)
749cdf0e10cSrcweir 		{
750cdf0e10cSrcweir 			// build edge vector
751cdf0e10cSrcweir 			const B3DVector aEdge(rEdgeEnd - rEdgeStart);
752cdf0e10cSrcweir 			bool bDoDistanceTestStart(false);
753cdf0e10cSrcweir 			bool bDoDistanceTestEnd(false);
754cdf0e10cSrcweir 
755cdf0e10cSrcweir 			if(aEdge.equalZero())
756cdf0e10cSrcweir 			{
757cdf0e10cSrcweir 				// no edge, just a point. Do one of the distance tests.
758cdf0e10cSrcweir 				bDoDistanceTestStart = true;
759cdf0e10cSrcweir 			}
760cdf0e10cSrcweir 			else
761cdf0e10cSrcweir 			{
762cdf0e10cSrcweir                 // calculate fCut in aEdge
763cdf0e10cSrcweir     			const B3DVector aTestEdge(rTestPosition - rEdgeStart);
764cdf0e10cSrcweir                 const double fScalarTestEdge(aEdge.scalar(aTestEdge));
765cdf0e10cSrcweir                 const double fScalarStartEdge(aEdge.scalar(rEdgeStart));
766cdf0e10cSrcweir                 const double fScalarEdge(aEdge.scalar(aEdge));
767cdf0e10cSrcweir                 const double fCut((fScalarTestEdge - fScalarStartEdge) / fScalarEdge);
768cdf0e10cSrcweir 				const double fZero(0.0);
769cdf0e10cSrcweir 				const double fOne(1.0);
770cdf0e10cSrcweir 
771cdf0e10cSrcweir 				if(fTools::less(fCut, fZero))
772cdf0e10cSrcweir 				{
773cdf0e10cSrcweir 					// left of rEdgeStart
774cdf0e10cSrcweir 					bDoDistanceTestStart = true;
775cdf0e10cSrcweir 				}
776cdf0e10cSrcweir 				else if(fTools::more(fCut, fOne))
777cdf0e10cSrcweir 				{
778cdf0e10cSrcweir 					// right of rEdgeEnd
779cdf0e10cSrcweir 					bDoDistanceTestEnd = true;
780cdf0e10cSrcweir 				}
781cdf0e10cSrcweir 				else
782cdf0e10cSrcweir 				{
783cdf0e10cSrcweir 					// inside line [0.0 .. 1.0]
784cdf0e10cSrcweir 					const B3DPoint aCutPoint(interpolate(rEdgeStart, rEdgeEnd, fCut));
785cdf0e10cSrcweir     			    const B3DVector aDelta(rTestPosition - aCutPoint);
786cdf0e10cSrcweir 				    const double fDistanceSquare(aDelta.scalar(aDelta));
787cdf0e10cSrcweir 
788cdf0e10cSrcweir 				    if(fDistanceSquare <= fDistance * fDistance * fDistance)
789cdf0e10cSrcweir 				    {
790cdf0e10cSrcweir 						return true;
791cdf0e10cSrcweir 					}
792cdf0e10cSrcweir 					else
793cdf0e10cSrcweir 					{
794cdf0e10cSrcweir 						return false;
795cdf0e10cSrcweir 					}
796cdf0e10cSrcweir 				}
797cdf0e10cSrcweir 			}
798cdf0e10cSrcweir 
799cdf0e10cSrcweir 			if(bDoDistanceTestStart)
800cdf0e10cSrcweir 			{
801cdf0e10cSrcweir     			const B3DVector aDelta(rTestPosition - rEdgeStart);
802cdf0e10cSrcweir 				const double fDistanceSquare(aDelta.scalar(aDelta));
803cdf0e10cSrcweir 
804cdf0e10cSrcweir 				if(fDistanceSquare <= fDistance * fDistance * fDistance)
805cdf0e10cSrcweir 				{
806cdf0e10cSrcweir 					return true;
807cdf0e10cSrcweir 				}
808cdf0e10cSrcweir 			}
809cdf0e10cSrcweir 			else if(bDoDistanceTestEnd)
810cdf0e10cSrcweir 			{
811cdf0e10cSrcweir     			const B3DVector aDelta(rTestPosition - rEdgeEnd);
812cdf0e10cSrcweir 				const double fDistanceSquare(aDelta.scalar(aDelta));
813cdf0e10cSrcweir 
814cdf0e10cSrcweir 				if(fDistanceSquare <= fDistance * fDistance * fDistance)
815cdf0e10cSrcweir 				{
816cdf0e10cSrcweir 					return true;
817cdf0e10cSrcweir 				}
818cdf0e10cSrcweir 			}
819cdf0e10cSrcweir 
820cdf0e10cSrcweir 			return false;
821cdf0e10cSrcweir 		}
822cdf0e10cSrcweir 
823cdf0e10cSrcweir 		bool isInEpsilonRange(const B3DPolygon& rCandidate, const B3DPoint& rTestPosition, double fDistance)
824cdf0e10cSrcweir 		{
825cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
826cdf0e10cSrcweir 
827cdf0e10cSrcweir 			if(nPointCount)
828cdf0e10cSrcweir 			{
829cdf0e10cSrcweir                 const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
830cdf0e10cSrcweir 				B3DPoint aCurrent(rCandidate.getB3DPoint(0));
831cdf0e10cSrcweir 
832cdf0e10cSrcweir 				if(nEdgeCount)
833cdf0e10cSrcweir 				{
834cdf0e10cSrcweir 					// edges
835cdf0e10cSrcweir 					for(sal_uInt32 a(0); a < nEdgeCount; a++)
836cdf0e10cSrcweir 					{
837cdf0e10cSrcweir 						const sal_uInt32 nNextIndex((a + 1) % nPointCount);
838cdf0e10cSrcweir 						const B3DPoint aNext(rCandidate.getB3DPoint(nNextIndex));
839cdf0e10cSrcweir 
840cdf0e10cSrcweir 						if(isInEpsilonRange(aCurrent, aNext, rTestPosition, fDistance))
841cdf0e10cSrcweir 						{
842cdf0e10cSrcweir 							return true;
843cdf0e10cSrcweir 						}
844cdf0e10cSrcweir 
845cdf0e10cSrcweir 						// prepare next step
846cdf0e10cSrcweir 						aCurrent = aNext;
847cdf0e10cSrcweir 					}
848cdf0e10cSrcweir 				}
849cdf0e10cSrcweir 				else
850cdf0e10cSrcweir 				{
851cdf0e10cSrcweir 					// no edges, but points -> not closed. Check single point. Just
852cdf0e10cSrcweir 					// use isInEpsilonRange with twice the same point, it handles those well
853cdf0e10cSrcweir 					if(isInEpsilonRange(aCurrent, aCurrent, rTestPosition, fDistance))
854cdf0e10cSrcweir 					{
855cdf0e10cSrcweir 						return true;
856cdf0e10cSrcweir 					}
857cdf0e10cSrcweir 				}
858cdf0e10cSrcweir 			}
859cdf0e10cSrcweir 
860cdf0e10cSrcweir 			return false;
861cdf0e10cSrcweir 		}
862cdf0e10cSrcweir 
863cdf0e10cSrcweir 		bool isInside(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder)
864cdf0e10cSrcweir         {
865cdf0e10cSrcweir 			if(bWithBorder && isPointOnPolygon(rCandidate, rPoint, true))
866cdf0e10cSrcweir 			{
867cdf0e10cSrcweir 				return true;
868cdf0e10cSrcweir 			}
869cdf0e10cSrcweir 			else
870cdf0e10cSrcweir 			{
871cdf0e10cSrcweir 				bool bRetval(false);
872cdf0e10cSrcweir 				const B3DVector aPlaneNormal(rCandidate.getNormal());
873cdf0e10cSrcweir 
874cdf0e10cSrcweir 				if(!aPlaneNormal.equalZero())
875cdf0e10cSrcweir 				{
876cdf0e10cSrcweir 				    const sal_uInt32 nPointCount(rCandidate.count());
877cdf0e10cSrcweir 
878cdf0e10cSrcweir 				    if(nPointCount)
879cdf0e10cSrcweir 				    {
880cdf0e10cSrcweir 					    B3DPoint aCurrentPoint(rCandidate.getB3DPoint(nPointCount - 1));
881cdf0e10cSrcweir 					    const double fAbsX(fabs(aPlaneNormal.getX()));
882cdf0e10cSrcweir 					    const double fAbsY(fabs(aPlaneNormal.getY()));
883cdf0e10cSrcweir 					    const double fAbsZ(fabs(aPlaneNormal.getZ()));
884cdf0e10cSrcweir 
885cdf0e10cSrcweir 					    if(fAbsX > fAbsY && fAbsX > fAbsZ)
886cdf0e10cSrcweir 					    {
887cdf0e10cSrcweir 						    // normal points mostly in X-Direction, use YZ-Polygon projection for check
888cdf0e10cSrcweir                             // x -> y, y -> z
889cdf0e10cSrcweir 					        for(sal_uInt32 a(0); a < nPointCount; a++)
890cdf0e10cSrcweir 					        {
891cdf0e10cSrcweir 						        const B3DPoint aPreviousPoint(aCurrentPoint);
892cdf0e10cSrcweir 						        aCurrentPoint = rCandidate.getB3DPoint(a);
893cdf0e10cSrcweir 
894cdf0e10cSrcweir 						        // cross-over in Z?
895cdf0e10cSrcweir 						        const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ()));
896cdf0e10cSrcweir 						        const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ()));
897cdf0e10cSrcweir 
898cdf0e10cSrcweir 						        if(bCompZA != bCompZB)
899cdf0e10cSrcweir 						        {
900cdf0e10cSrcweir 							        // cross-over in Y?
901cdf0e10cSrcweir 							        const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
902cdf0e10cSrcweir 							        const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));
903cdf0e10cSrcweir 
904cdf0e10cSrcweir 							        if(bCompYA == bCompYB)
905cdf0e10cSrcweir 							        {
906cdf0e10cSrcweir 								        if(bCompYA)
907cdf0e10cSrcweir 								        {
908cdf0e10cSrcweir 									        bRetval = !bRetval;
909cdf0e10cSrcweir 								        }
910cdf0e10cSrcweir 							        }
911cdf0e10cSrcweir 							        else
912cdf0e10cSrcweir 							        {
913cdf0e10cSrcweir 								        const double fCompare(
914cdf0e10cSrcweir 									        aCurrentPoint.getY() - (aCurrentPoint.getZ() - rPoint.getZ()) *
915cdf0e10cSrcweir 									        (aPreviousPoint.getY() - aCurrentPoint.getY()) /
916cdf0e10cSrcweir 									        (aPreviousPoint.getZ() - aCurrentPoint.getZ()));
917cdf0e10cSrcweir 
918cdf0e10cSrcweir 								        if(fTools::more(fCompare, rPoint.getY()))
919cdf0e10cSrcweir 								        {
920cdf0e10cSrcweir 									        bRetval = !bRetval;
921cdf0e10cSrcweir 								        }
922cdf0e10cSrcweir 							        }
923cdf0e10cSrcweir 						        }
924cdf0e10cSrcweir 					        }
925cdf0e10cSrcweir 					    }
926cdf0e10cSrcweir 					    else if(fAbsY > fAbsX && fAbsY > fAbsZ)
927cdf0e10cSrcweir 					    {
928cdf0e10cSrcweir 						    // normal points mostly in Y-Direction, use XZ-Polygon projection for check
929cdf0e10cSrcweir                             // x -> x, y -> z
930cdf0e10cSrcweir 					        for(sal_uInt32 a(0); a < nPointCount; a++)
931cdf0e10cSrcweir 					        {
932cdf0e10cSrcweir 						        const B3DPoint aPreviousPoint(aCurrentPoint);
933cdf0e10cSrcweir 						        aCurrentPoint = rCandidate.getB3DPoint(a);
934cdf0e10cSrcweir 
935cdf0e10cSrcweir 						        // cross-over in Z?
936cdf0e10cSrcweir 						        const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ()));
937cdf0e10cSrcweir 						        const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ()));
938cdf0e10cSrcweir 
939cdf0e10cSrcweir 						        if(bCompZA != bCompZB)
940cdf0e10cSrcweir 						        {
941cdf0e10cSrcweir 							        // cross-over in X?
942cdf0e10cSrcweir 							        const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
943cdf0e10cSrcweir 							        const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));
944cdf0e10cSrcweir 
945cdf0e10cSrcweir 							        if(bCompXA == bCompXB)
946cdf0e10cSrcweir 							        {
947cdf0e10cSrcweir 								        if(bCompXA)
948cdf0e10cSrcweir 								        {
949cdf0e10cSrcweir 									        bRetval = !bRetval;
950cdf0e10cSrcweir 								        }
951cdf0e10cSrcweir 							        }
952cdf0e10cSrcweir 							        else
953cdf0e10cSrcweir 							        {
954cdf0e10cSrcweir 								        const double fCompare(
955cdf0e10cSrcweir 									        aCurrentPoint.getX() - (aCurrentPoint.getZ() - rPoint.getZ()) *
956cdf0e10cSrcweir 									        (aPreviousPoint.getX() - aCurrentPoint.getX()) /
957cdf0e10cSrcweir 									        (aPreviousPoint.getZ() - aCurrentPoint.getZ()));
958cdf0e10cSrcweir 
959cdf0e10cSrcweir 								        if(fTools::more(fCompare, rPoint.getX()))
960cdf0e10cSrcweir 								        {
961cdf0e10cSrcweir 									        bRetval = !bRetval;
962cdf0e10cSrcweir 								        }
963cdf0e10cSrcweir 							        }
964cdf0e10cSrcweir 						        }
965cdf0e10cSrcweir 					        }
966cdf0e10cSrcweir 					    }
967cdf0e10cSrcweir 					    else
968cdf0e10cSrcweir 					    {
969cdf0e10cSrcweir 						    // normal points mostly in Z-Direction, use XY-Polygon projection for check
970cdf0e10cSrcweir                             // x -> x, y -> y
971cdf0e10cSrcweir 					        for(sal_uInt32 a(0); a < nPointCount; a++)
972cdf0e10cSrcweir 					        {
973cdf0e10cSrcweir 						        const B3DPoint aPreviousPoint(aCurrentPoint);
974cdf0e10cSrcweir 						        aCurrentPoint = rCandidate.getB3DPoint(a);
975cdf0e10cSrcweir 
976cdf0e10cSrcweir 						        // cross-over in Y?
977cdf0e10cSrcweir 						        const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
978cdf0e10cSrcweir 						        const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));
979cdf0e10cSrcweir 
980cdf0e10cSrcweir 						        if(bCompYA != bCompYB)
981cdf0e10cSrcweir 						        {
982cdf0e10cSrcweir 							        // cross-over in X?
983cdf0e10cSrcweir 							        const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
984cdf0e10cSrcweir 							        const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));
985cdf0e10cSrcweir 
986cdf0e10cSrcweir 							        if(bCompXA == bCompXB)
987cdf0e10cSrcweir 							        {
988cdf0e10cSrcweir 								        if(bCompXA)
989cdf0e10cSrcweir 								        {
990cdf0e10cSrcweir 									        bRetval = !bRetval;
991cdf0e10cSrcweir 								        }
992cdf0e10cSrcweir 							        }
993cdf0e10cSrcweir 							        else
994cdf0e10cSrcweir 							        {
995cdf0e10cSrcweir 								        const double fCompare(
996cdf0e10cSrcweir 									        aCurrentPoint.getX() - (aCurrentPoint.getY() - rPoint.getY()) *
997cdf0e10cSrcweir 									        (aPreviousPoint.getX() - aCurrentPoint.getX()) /
998cdf0e10cSrcweir 									        (aPreviousPoint.getY() - aCurrentPoint.getY()));
999cdf0e10cSrcweir 
1000cdf0e10cSrcweir 								        if(fTools::more(fCompare, rPoint.getX()))
1001cdf0e10cSrcweir 								        {
1002cdf0e10cSrcweir 									        bRetval = !bRetval;
1003cdf0e10cSrcweir 								        }
1004cdf0e10cSrcweir 							        }
1005cdf0e10cSrcweir 						        }
1006cdf0e10cSrcweir 					        }
1007cdf0e10cSrcweir 					    }
1008cdf0e10cSrcweir                     }
1009cdf0e10cSrcweir 				}
1010cdf0e10cSrcweir 
1011cdf0e10cSrcweir 				return bRetval;
1012cdf0e10cSrcweir 			}
1013cdf0e10cSrcweir         }
1014cdf0e10cSrcweir 
1015cdf0e10cSrcweir 		bool isInside(const B3DPolygon& rCandidate, const B3DPolygon& rPolygon, bool bWithBorder)
1016cdf0e10cSrcweir         {
1017cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rPolygon.count());
1018cdf0e10cSrcweir 
1019cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < nPointCount; a++)
1020cdf0e10cSrcweir 			{
1021cdf0e10cSrcweir 				const B3DPoint aTestPoint(rPolygon.getB3DPoint(a));
1022cdf0e10cSrcweir 
1023cdf0e10cSrcweir 				if(!isInside(rCandidate, aTestPoint, bWithBorder))
1024cdf0e10cSrcweir 				{
1025cdf0e10cSrcweir 					return false;
1026cdf0e10cSrcweir 				}
1027cdf0e10cSrcweir 			}
1028cdf0e10cSrcweir 
1029cdf0e10cSrcweir 			return true;
1030cdf0e10cSrcweir         }
1031cdf0e10cSrcweir 
1032cdf0e10cSrcweir 		bool isPointOnLine(const B3DPoint& rStart, const B3DPoint& rEnd, const B3DPoint& rCandidate, bool bWithPoints)
1033cdf0e10cSrcweir         {
1034cdf0e10cSrcweir 			if(rCandidate.equal(rStart) || rCandidate.equal(rEnd))
1035cdf0e10cSrcweir 			{
1036cdf0e10cSrcweir 				// candidate is in epsilon around start or end -> inside
1037cdf0e10cSrcweir 				return bWithPoints;
1038cdf0e10cSrcweir 			}
1039cdf0e10cSrcweir 			else if(rStart.equal(rEnd))
1040cdf0e10cSrcweir 			{
1041cdf0e10cSrcweir 				// start and end are equal, but candidate is outside their epsilon -> outside
1042cdf0e10cSrcweir 				return false;
1043cdf0e10cSrcweir 			}
1044cdf0e10cSrcweir 			else
1045cdf0e10cSrcweir 			{
1046cdf0e10cSrcweir 				const B3DVector aEdgeVector(rEnd - rStart);
1047cdf0e10cSrcweir 				const B3DVector aTestVector(rCandidate - rStart);
1048cdf0e10cSrcweir 
1049cdf0e10cSrcweir 				if(areParallel(aEdgeVector, aTestVector))
1050cdf0e10cSrcweir 				{
1051cdf0e10cSrcweir 					const double fZero(0.0);
1052cdf0e10cSrcweir 					const double fOne(1.0);
1053cdf0e10cSrcweir                     double fParamTestOnCurr(0.0);
1054cdf0e10cSrcweir 
1055cdf0e10cSrcweir                     if(aEdgeVector.getX() > aEdgeVector.getY())
1056cdf0e10cSrcweir                     {
1057cdf0e10cSrcweir                         if(aEdgeVector.getX() > aEdgeVector.getZ())
1058cdf0e10cSrcweir                         {
1059cdf0e10cSrcweir                             // X is biggest
1060cdf0e10cSrcweir                             fParamTestOnCurr = aTestVector.getX() / aEdgeVector.getX();
1061cdf0e10cSrcweir                         }
1062cdf0e10cSrcweir                         else
1063cdf0e10cSrcweir                         {
1064cdf0e10cSrcweir                             // Z is biggest
1065cdf0e10cSrcweir                             fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ();
1066cdf0e10cSrcweir                         }
1067cdf0e10cSrcweir                     }
1068cdf0e10cSrcweir                     else
1069cdf0e10cSrcweir                     {
1070cdf0e10cSrcweir                         if(aEdgeVector.getY() > aEdgeVector.getZ())
1071cdf0e10cSrcweir                         {
1072cdf0e10cSrcweir                             // Y is biggest
1073cdf0e10cSrcweir                             fParamTestOnCurr = aTestVector.getY() / aEdgeVector.getY();
1074cdf0e10cSrcweir                         }
1075cdf0e10cSrcweir                         else
1076cdf0e10cSrcweir                         {
1077cdf0e10cSrcweir                             // Z is biggest
1078cdf0e10cSrcweir                             fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ();
1079cdf0e10cSrcweir                         }
1080cdf0e10cSrcweir                     }
1081cdf0e10cSrcweir 
1082cdf0e10cSrcweir 					if(fTools::more(fParamTestOnCurr, fZero) && fTools::less(fParamTestOnCurr, fOne))
1083cdf0e10cSrcweir 					{
1084cdf0e10cSrcweir 						return true;
1085cdf0e10cSrcweir 					}
1086cdf0e10cSrcweir 				}
1087cdf0e10cSrcweir 
1088cdf0e10cSrcweir 				return false;
1089cdf0e10cSrcweir 			}
1090cdf0e10cSrcweir         }
1091cdf0e10cSrcweir 
1092cdf0e10cSrcweir 		bool isPointOnPolygon(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithPoints)
1093cdf0e10cSrcweir         {
1094cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
1095cdf0e10cSrcweir 
1096cdf0e10cSrcweir 			if(nPointCount > 1L)
1097cdf0e10cSrcweir 			{
1098cdf0e10cSrcweir 				const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
1099cdf0e10cSrcweir 				B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0));
1100cdf0e10cSrcweir 
1101cdf0e10cSrcweir 				for(sal_uInt32 a(0); a < nLoopCount; a++)
1102cdf0e10cSrcweir 				{
1103cdf0e10cSrcweir 					const B3DPoint aNextPoint(rCandidate.getB3DPoint((a + 1) % nPointCount));
1104cdf0e10cSrcweir 
1105cdf0e10cSrcweir 					if(isPointOnLine(aCurrentPoint, aNextPoint, rPoint, bWithPoints))
1106cdf0e10cSrcweir 					{
1107cdf0e10cSrcweir 						return true;
1108cdf0e10cSrcweir 					}
1109cdf0e10cSrcweir 
1110cdf0e10cSrcweir 					aCurrentPoint = aNextPoint;
1111cdf0e10cSrcweir 				}
1112cdf0e10cSrcweir 			}
1113cdf0e10cSrcweir 			else if(nPointCount && bWithPoints)
1114cdf0e10cSrcweir 			{
1115cdf0e10cSrcweir 				return rPoint.equal(rCandidate.getB3DPoint(0));
1116cdf0e10cSrcweir 			}
1117cdf0e10cSrcweir 
1118cdf0e10cSrcweir 			return false;
1119cdf0e10cSrcweir         }
1120cdf0e10cSrcweir 
1121cdf0e10cSrcweir         bool getCutBetweenLineAndPlane(const B3DVector& rPlaneNormal, const B3DPoint& rPlanePoint, const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, double& fCut)
1122cdf0e10cSrcweir         {
1123cdf0e10cSrcweir             if(!rPlaneNormal.equalZero() && !rEdgeStart.equal(rEdgeEnd))
1124cdf0e10cSrcweir             {
1125cdf0e10cSrcweir 			    const B3DVector aTestEdge(rEdgeEnd - rEdgeStart);
1126cdf0e10cSrcweir                 const double fScalarEdge(rPlaneNormal.scalar(aTestEdge));
1127cdf0e10cSrcweir 
1128cdf0e10cSrcweir 				if(!fTools::equalZero(fScalarEdge))
1129cdf0e10cSrcweir 				{
1130cdf0e10cSrcweir 					const B3DVector aCompareEdge(rPlanePoint - rEdgeStart);
1131cdf0e10cSrcweir 					const double fScalarCompare(rPlaneNormal.scalar(aCompareEdge));
1132cdf0e10cSrcweir 
1133cdf0e10cSrcweir 					fCut = fScalarCompare / fScalarEdge;
1134cdf0e10cSrcweir 					return true;
1135cdf0e10cSrcweir 				}
1136cdf0e10cSrcweir             }
1137cdf0e10cSrcweir 
1138cdf0e10cSrcweir             return false;
1139cdf0e10cSrcweir         }
1140cdf0e10cSrcweir 
1141cdf0e10cSrcweir         bool getCutBetweenLineAndPolygon(const B3DPolygon& rCandidate, const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, double& fCut)
1142cdf0e10cSrcweir         {
1143cdf0e10cSrcweir             const sal_uInt32 nPointCount(rCandidate.count());
1144cdf0e10cSrcweir 
1145cdf0e10cSrcweir             if(nPointCount > 2 && !rEdgeStart.equal(rEdgeEnd))
1146cdf0e10cSrcweir             {
1147cdf0e10cSrcweir                 const B3DVector aPlaneNormal(rCandidate.getNormal());
1148cdf0e10cSrcweir 
1149cdf0e10cSrcweir                 if(!aPlaneNormal.equalZero())
1150cdf0e10cSrcweir                 {
1151cdf0e10cSrcweir                     const B3DPoint aPointOnPlane(rCandidate.getB3DPoint(0));
1152cdf0e10cSrcweir 
1153cdf0e10cSrcweir                     return getCutBetweenLineAndPlane(aPlaneNormal, aPointOnPlane, rEdgeStart, rEdgeEnd, fCut);
1154cdf0e10cSrcweir                 }
1155cdf0e10cSrcweir             }
1156cdf0e10cSrcweir 
1157cdf0e10cSrcweir             return false;
1158cdf0e10cSrcweir         }
1159cdf0e10cSrcweir 
1160cdf0e10cSrcweir 		//////////////////////////////////////////////////////////////////////
1161cdf0e10cSrcweir 		// comparators with tolerance for 3D Polygons
1162cdf0e10cSrcweir 
1163cdf0e10cSrcweir 		bool equal(const B3DPolygon& rCandidateA, const B3DPolygon& rCandidateB, const double& rfSmallValue)
1164cdf0e10cSrcweir 		{
1165cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidateA.count());
1166cdf0e10cSrcweir 
1167cdf0e10cSrcweir 			if(nPointCount != rCandidateB.count())
1168cdf0e10cSrcweir 				return false;
1169cdf0e10cSrcweir 
1170cdf0e10cSrcweir 			const bool bClosed(rCandidateA.isClosed());
1171cdf0e10cSrcweir 
1172cdf0e10cSrcweir 			if(bClosed != rCandidateB.isClosed())
1173cdf0e10cSrcweir 				return false;
1174cdf0e10cSrcweir 
1175cdf0e10cSrcweir 			for(sal_uInt32 a(0); a < nPointCount; a++)
1176cdf0e10cSrcweir 			{
1177cdf0e10cSrcweir 				const B3DPoint aPoint(rCandidateA.getB3DPoint(a));
1178cdf0e10cSrcweir 
1179cdf0e10cSrcweir 				if(!aPoint.equal(rCandidateB.getB3DPoint(a), rfSmallValue))
1180cdf0e10cSrcweir 					return false;
1181cdf0e10cSrcweir 			}
1182cdf0e10cSrcweir 
1183cdf0e10cSrcweir 			return true;
1184cdf0e10cSrcweir 		}
1185cdf0e10cSrcweir 
1186cdf0e10cSrcweir 		bool equal(const B3DPolygon& rCandidateA, const B3DPolygon& rCandidateB)
1187cdf0e10cSrcweir 		{
1188cdf0e10cSrcweir 			const double fSmallValue(fTools::getSmallValue());
1189cdf0e10cSrcweir 
1190cdf0e10cSrcweir 			return equal(rCandidateA, rCandidateB, fSmallValue);
1191cdf0e10cSrcweir 		}
1192cdf0e10cSrcweir 
1193cdf0e10cSrcweir 		// snap points of horizontal or vertical edges to discrete values
1194cdf0e10cSrcweir 		B3DPolygon snapPointsOfHorizontalOrVerticalEdges(const B3DPolygon& rCandidate)
1195cdf0e10cSrcweir 		{
1196cdf0e10cSrcweir 			const sal_uInt32 nPointCount(rCandidate.count());
1197cdf0e10cSrcweir 
1198cdf0e10cSrcweir 			if(nPointCount > 1)
1199cdf0e10cSrcweir 			{
1200cdf0e10cSrcweir 				// Start by copying the source polygon to get a writeable copy. The closed state is
1201cdf0e10cSrcweir 				// copied by aRetval's initialisation, too, so no need to copy it in this method
1202cdf0e10cSrcweir 				B3DPolygon aRetval(rCandidate);
1203cdf0e10cSrcweir 
1204cdf0e10cSrcweir 				// prepare geometry data. Get rounded from original
1205cdf0e10cSrcweir                 B3ITuple aPrevTuple(basegfx::fround(rCandidate.getB3DPoint(nPointCount - 1)));
1206cdf0e10cSrcweir 				B3DPoint aCurrPoint(rCandidate.getB3DPoint(0));
1207cdf0e10cSrcweir 				B3ITuple aCurrTuple(basegfx::fround(aCurrPoint));
1208cdf0e10cSrcweir 
1209cdf0e10cSrcweir 				// loop over all points. This will also snap the implicit closing edge
1210cdf0e10cSrcweir 				// even when not closed, but that's no problem here
1211cdf0e10cSrcweir 				for(sal_uInt32 a(0); a < nPointCount; a++)
1212cdf0e10cSrcweir 				{
1213cdf0e10cSrcweir 					// get next point. Get rounded from original
1214cdf0e10cSrcweir                     const bool bLastRun(a + 1 == nPointCount);
1215cdf0e10cSrcweir                     const sal_uInt32 nNextIndex(bLastRun ? 0 : a + 1);
1216cdf0e10cSrcweir 					const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
1217cdf0e10cSrcweir 					const B3ITuple aNextTuple(basegfx::fround(aNextPoint));
1218cdf0e10cSrcweir 
1219cdf0e10cSrcweir 					// get the states
1220cdf0e10cSrcweir 					const bool bPrevVertical(aPrevTuple.getX() == aCurrTuple.getX());
1221cdf0e10cSrcweir 					const bool bNextVertical(aNextTuple.getX() == aCurrTuple.getX());
1222cdf0e10cSrcweir 					const bool bPrevHorizontal(aPrevTuple.getY() == aCurrTuple.getY());
1223cdf0e10cSrcweir 					const bool bNextHorizontal(aNextTuple.getY() == aCurrTuple.getY());
1224cdf0e10cSrcweir 					const bool bSnapX(bPrevVertical || bNextVertical);
1225cdf0e10cSrcweir 					const bool bSnapY(bPrevHorizontal || bNextHorizontal);
1226cdf0e10cSrcweir 
1227cdf0e10cSrcweir 					if(bSnapX || bSnapY)
1228cdf0e10cSrcweir 					{
1229cdf0e10cSrcweir 						const B3DPoint aSnappedPoint(
1230cdf0e10cSrcweir 							bSnapX ? aCurrTuple.getX() : aCurrPoint.getX(),
1231cdf0e10cSrcweir 							bSnapY ? aCurrTuple.getY() : aCurrPoint.getY(),
1232cdf0e10cSrcweir 							aCurrPoint.getZ());
1233cdf0e10cSrcweir 
1234cdf0e10cSrcweir 						aRetval.setB3DPoint(a, aSnappedPoint);
1235cdf0e10cSrcweir 					}
1236cdf0e10cSrcweir 
1237cdf0e10cSrcweir 					// prepare next point
1238cdf0e10cSrcweir                     if(!bLastRun)
1239cdf0e10cSrcweir                     {
1240cdf0e10cSrcweir     					aPrevTuple = aCurrTuple;
1241cdf0e10cSrcweir 	    				aCurrPoint = aNextPoint;
1242cdf0e10cSrcweir 		    			aCurrTuple = aNextTuple;
1243cdf0e10cSrcweir                     }
1244cdf0e10cSrcweir 				}
1245cdf0e10cSrcweir 
1246cdf0e10cSrcweir 				return aRetval;
1247cdf0e10cSrcweir 			}
1248cdf0e10cSrcweir 			else
1249cdf0e10cSrcweir 			{
1250cdf0e10cSrcweir 				return rCandidate;
1251cdf0e10cSrcweir 			}
1252cdf0e10cSrcweir 		}
1253cdf0e10cSrcweir 
1254cdf0e10cSrcweir 	} // end of namespace tools
1255cdf0e10cSrcweir } // end of namespace basegfx
1256cdf0e10cSrcweir 
1257cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
1258cdf0e10cSrcweir 
1259cdf0e10cSrcweir // eof
1260