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 
27cdf0e10cSrcweir #include <basegfx/polygon/b3dpolygonclipper.hxx>
28cdf0e10cSrcweir #include <osl/diagnose.h>
29cdf0e10cSrcweir #include <basegfx/polygon/b3dpolygontools.hxx>
30cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx>
31cdf0e10cSrcweir #include <basegfx/matrix/b3dhommatrix.hxx>
32cdf0e10cSrcweir #include <basegfx/polygon/b3dpolygontools.hxx>
33cdf0e10cSrcweir #include <basegfx/range/b3drange.hxx>
34cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx>
35cdf0e10cSrcweir #include <basegfx/range/b2drange.hxx>
36cdf0e10cSrcweir #include <basegfx/color/bcolor.hxx>
37cdf0e10cSrcweir 
38cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
39cdf0e10cSrcweir 
40cdf0e10cSrcweir namespace basegfx
41cdf0e10cSrcweir {
42cdf0e10cSrcweir 	namespace
43cdf0e10cSrcweir 	{
impIsInside(const B3DPoint & rCandidate,double fPlaneOffset,tools::B3DOrientation ePlaneOrthogonal)44cdf0e10cSrcweir 		inline bool impIsInside(const B3DPoint& rCandidate, double fPlaneOffset, tools::B3DOrientation ePlaneOrthogonal)
45cdf0e10cSrcweir 		{
46cdf0e10cSrcweir 			if(tools::B3DORIENTATION_X == ePlaneOrthogonal)
47cdf0e10cSrcweir 			{
48cdf0e10cSrcweir 				return fTools::moreOrEqual(rCandidate.getX(), fPlaneOffset);
49cdf0e10cSrcweir 			}
50cdf0e10cSrcweir 			else if(tools::B3DORIENTATION_Y == ePlaneOrthogonal)
51cdf0e10cSrcweir 			{
52cdf0e10cSrcweir 				return fTools::moreOrEqual(rCandidate.getY(), fPlaneOffset);
53cdf0e10cSrcweir 			}
54cdf0e10cSrcweir 			else
55cdf0e10cSrcweir 			{
56cdf0e10cSrcweir 				return fTools::moreOrEqual(rCandidate.getZ(), fPlaneOffset);
57cdf0e10cSrcweir 			}
58cdf0e10cSrcweir 		}
59cdf0e10cSrcweir 
impGetCut(const B3DPoint & rCurrent,const B3DPoint & rNext,double fPlaneOffset,tools::B3DOrientation ePlaneOrthogonal)60cdf0e10cSrcweir 		inline double impGetCut(const B3DPoint& rCurrent, const B3DPoint& rNext, double fPlaneOffset, tools::B3DOrientation ePlaneOrthogonal)
61cdf0e10cSrcweir 		{
62cdf0e10cSrcweir 			if(tools::B3DORIENTATION_X == ePlaneOrthogonal)
63cdf0e10cSrcweir 			{
64cdf0e10cSrcweir 				return ((fPlaneOffset - rCurrent.getX())/(rNext.getX() - rCurrent.getX()));
65cdf0e10cSrcweir 			}
66cdf0e10cSrcweir 			else if(tools::B3DORIENTATION_Y == ePlaneOrthogonal)
67cdf0e10cSrcweir 			{
68cdf0e10cSrcweir 				return ((fPlaneOffset - rCurrent.getY())/(rNext.getY() - rCurrent.getY()));
69cdf0e10cSrcweir 			}
70cdf0e10cSrcweir 			else
71cdf0e10cSrcweir 			{
72cdf0e10cSrcweir 				return ((fPlaneOffset - rCurrent.getZ())/(rNext.getZ() - rCurrent.getZ()));
73cdf0e10cSrcweir 			}
74cdf0e10cSrcweir 		}
75cdf0e10cSrcweir 
impAppendCopy(B3DPolygon & rDest,const B3DPolygon & rSource,sal_uInt32 nIndex)76cdf0e10cSrcweir 		void impAppendCopy(B3DPolygon& rDest, const B3DPolygon& rSource, sal_uInt32 nIndex)
77cdf0e10cSrcweir 		{
78cdf0e10cSrcweir 			rDest.append(rSource.getB3DPoint(nIndex));
79cdf0e10cSrcweir 
80cdf0e10cSrcweir 			if(rSource.areBColorsUsed())
81cdf0e10cSrcweir 			{
82cdf0e10cSrcweir 				rDest.setBColor(rDest.count() - 1L, rSource.getBColor(nIndex));
83cdf0e10cSrcweir 			}
84cdf0e10cSrcweir 
85cdf0e10cSrcweir 			if(rSource.areNormalsUsed())
86cdf0e10cSrcweir 			{
87cdf0e10cSrcweir 				rDest.setNormal(rDest.count() - 1L, rSource.getNormal(nIndex));
88cdf0e10cSrcweir 			}
89cdf0e10cSrcweir 
90cdf0e10cSrcweir 			if(rSource.areTextureCoordinatesUsed())
91cdf0e10cSrcweir 			{
92cdf0e10cSrcweir 				rDest.setTextureCoordinate(rDest.count() - 1L, rSource.getTextureCoordinate(nIndex));
93cdf0e10cSrcweir 			}
94cdf0e10cSrcweir 		}
95cdf0e10cSrcweir 
impAppendInterpolate(B3DPolygon & rDest,const B3DPolygon & rSource,sal_uInt32 nIndA,sal_uInt32 nIndB,double fCut)96cdf0e10cSrcweir 		void impAppendInterpolate(B3DPolygon& rDest, const B3DPolygon& rSource, sal_uInt32 nIndA, sal_uInt32 nIndB, double fCut)
97cdf0e10cSrcweir 		{
98cdf0e10cSrcweir 			const B3DPoint aCurrPoint(rSource.getB3DPoint(nIndA));
99cdf0e10cSrcweir 			const B3DPoint aNextPoint(rSource.getB3DPoint(nIndB));
100cdf0e10cSrcweir 			rDest.append(interpolate(aCurrPoint, aNextPoint, fCut));
101cdf0e10cSrcweir 
102cdf0e10cSrcweir 			if(rSource.areBColorsUsed())
103cdf0e10cSrcweir 			{
104cdf0e10cSrcweir 				const BColor aCurrBColor(rSource.getBColor(nIndA));
105cdf0e10cSrcweir 				const BColor aNextBColor(rSource.getBColor(nIndB));
106cdf0e10cSrcweir 				rDest.setBColor(rDest.count() - 1L, interpolate(aCurrBColor, aNextBColor, fCut));
107cdf0e10cSrcweir 			}
108cdf0e10cSrcweir 
109cdf0e10cSrcweir 			if(rSource.areNormalsUsed())
110cdf0e10cSrcweir 			{
111cdf0e10cSrcweir 				const B3DVector aCurrVector(rSource.getNormal(nIndA));
112cdf0e10cSrcweir 				const B3DVector aNextVector(rSource.getNormal(nIndB));
113cdf0e10cSrcweir 				rDest.setNormal(rDest.count() - 1L, interpolate(aCurrVector, aNextVector, fCut));
114cdf0e10cSrcweir 			}
115cdf0e10cSrcweir 
116cdf0e10cSrcweir 			if(rSource.areTextureCoordinatesUsed())
117cdf0e10cSrcweir 			{
118cdf0e10cSrcweir 				const B2DPoint aCurrTxCo(rSource.getTextureCoordinate(nIndA));
119cdf0e10cSrcweir 				const B2DPoint aNextTxCo(rSource.getTextureCoordinate(nIndB));
120cdf0e10cSrcweir 				rDest.setTextureCoordinate(rDest.count() - 1L, interpolate(aCurrTxCo, aNextTxCo, fCut));
121cdf0e10cSrcweir 			}
122cdf0e10cSrcweir 		}
123cdf0e10cSrcweir 	}
124cdf0e10cSrcweir } // end of namespace basegfx
125cdf0e10cSrcweir 
126cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
127cdf0e10cSrcweir 
128cdf0e10cSrcweir namespace basegfx
129cdf0e10cSrcweir {
130cdf0e10cSrcweir 	namespace tools
131cdf0e10cSrcweir 	{
clipPolygonOnOrthogonalPlane(const B3DPolygon & rCandidate,B3DOrientation ePlaneOrthogonal,bool bClipPositive,double fPlaneOffset,bool bStroke)132cdf0e10cSrcweir 		B3DPolyPolygon clipPolygonOnOrthogonalPlane(const B3DPolygon& rCandidate, B3DOrientation ePlaneOrthogonal, bool bClipPositive, double fPlaneOffset, bool bStroke)
133cdf0e10cSrcweir 		{
134cdf0e10cSrcweir 			B3DPolyPolygon aRetval;
135cdf0e10cSrcweir 
136cdf0e10cSrcweir 			if(rCandidate.count())
137cdf0e10cSrcweir 			{
138cdf0e10cSrcweir 				const B3DRange aCandidateRange(getRange(rCandidate));
139cdf0e10cSrcweir 
140cdf0e10cSrcweir 				if(B3DORIENTATION_X == ePlaneOrthogonal && fTools::moreOrEqual(aCandidateRange.getMinX(), fPlaneOffset))
141cdf0e10cSrcweir 				{
142cdf0e10cSrcweir 					// completely above and on the clip plane.
143cdf0e10cSrcweir 					if(bClipPositive)
144cdf0e10cSrcweir 					{
145cdf0e10cSrcweir 						// add completely
146cdf0e10cSrcweir 						aRetval.append(rCandidate);
147cdf0e10cSrcweir 					}
148cdf0e10cSrcweir 				}
149cdf0e10cSrcweir 				else if(B3DORIENTATION_X == ePlaneOrthogonal && fTools::lessOrEqual(aCandidateRange.getMaxX(), fPlaneOffset))
150cdf0e10cSrcweir 				{
151cdf0e10cSrcweir 					// completely below and on the clip plane.
152cdf0e10cSrcweir 					if(!bClipPositive)
153cdf0e10cSrcweir 					{
154cdf0e10cSrcweir 						// add completely
155cdf0e10cSrcweir 						aRetval.append(rCandidate);
156cdf0e10cSrcweir 					}
157cdf0e10cSrcweir 				}
158cdf0e10cSrcweir 				else if(B3DORIENTATION_Y == ePlaneOrthogonal && fTools::moreOrEqual(aCandidateRange.getMinY(), fPlaneOffset))
159cdf0e10cSrcweir 				{
160cdf0e10cSrcweir 					// completely above and on the clip plane.
161cdf0e10cSrcweir 					if(bClipPositive)
162cdf0e10cSrcweir 					{
163cdf0e10cSrcweir 						// add completely
164cdf0e10cSrcweir 						aRetval.append(rCandidate);
165cdf0e10cSrcweir 					}
166cdf0e10cSrcweir 				}
167cdf0e10cSrcweir 				else if(B3DORIENTATION_Y == ePlaneOrthogonal && fTools::lessOrEqual(aCandidateRange.getMaxY(), fPlaneOffset))
168cdf0e10cSrcweir 				{
169cdf0e10cSrcweir 					// completely below and on the clip plane.
170cdf0e10cSrcweir 					if(!bClipPositive)
171cdf0e10cSrcweir 					{
172cdf0e10cSrcweir 						// add completely
173cdf0e10cSrcweir 						aRetval.append(rCandidate);
174cdf0e10cSrcweir 					}
175cdf0e10cSrcweir 				}
176cdf0e10cSrcweir 				else if(B3DORIENTATION_Z == ePlaneOrthogonal && fTools::moreOrEqual(aCandidateRange.getMinZ(), fPlaneOffset))
177cdf0e10cSrcweir 				{
178cdf0e10cSrcweir 					// completely above and on the clip plane.
179cdf0e10cSrcweir 					if(bClipPositive)
180cdf0e10cSrcweir 					{
181cdf0e10cSrcweir 						// add completely
182cdf0e10cSrcweir 						aRetval.append(rCandidate);
183cdf0e10cSrcweir 					}
184cdf0e10cSrcweir 				}
185cdf0e10cSrcweir 				else if(B3DORIENTATION_Z == ePlaneOrthogonal && fTools::lessOrEqual(aCandidateRange.getMaxZ(), fPlaneOffset))
186cdf0e10cSrcweir 				{
187cdf0e10cSrcweir 					// completely below and on the clip plane.
188cdf0e10cSrcweir 					if(!bClipPositive)
189cdf0e10cSrcweir 					{
190cdf0e10cSrcweir 						// add completely
191cdf0e10cSrcweir 						aRetval.append(rCandidate);
192cdf0e10cSrcweir 					}
193cdf0e10cSrcweir 				}
194cdf0e10cSrcweir 				else
195cdf0e10cSrcweir 				{
196cdf0e10cSrcweir 					// prepare loop(s)
197cdf0e10cSrcweir 					B3DPolygon aNewPolygon;
198cdf0e10cSrcweir 					B3DPoint aCurrent(rCandidate.getB3DPoint(0L));
199cdf0e10cSrcweir 					const sal_uInt32 nPointCount(rCandidate.count());
200cdf0e10cSrcweir 					const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
201cdf0e10cSrcweir 					bool bCurrentInside(impIsInside(aCurrent, fPlaneOffset, ePlaneOrthogonal) == bClipPositive);
202cdf0e10cSrcweir 
203cdf0e10cSrcweir 					if(bCurrentInside)
204cdf0e10cSrcweir 					{
205cdf0e10cSrcweir 						impAppendCopy(aNewPolygon, rCandidate, 0L);
206cdf0e10cSrcweir 					}
207cdf0e10cSrcweir 
208cdf0e10cSrcweir 					if(bStroke)
209cdf0e10cSrcweir 					{
210cdf0e10cSrcweir 						// open polygon, create clipped line snippets.
211cdf0e10cSrcweir 						for(sal_uInt32 a(0L); a < nEdgeCount; a++)
212cdf0e10cSrcweir 						{
213cdf0e10cSrcweir 							// get next point data
214cdf0e10cSrcweir 							const sal_uInt32 nNextIndex((a + 1L == nPointCount) ? 0L : a + 1L);
215cdf0e10cSrcweir 							const B3DPoint aNext(rCandidate.getB3DPoint(nNextIndex));
216cdf0e10cSrcweir 							const bool bNextInside(impIsInside(aNext, fPlaneOffset, ePlaneOrthogonal) == bClipPositive);
217cdf0e10cSrcweir 
218cdf0e10cSrcweir 							if(bCurrentInside != bNextInside)
219cdf0e10cSrcweir 							{
220cdf0e10cSrcweir 								// change inside/outside
221cdf0e10cSrcweir 								if(bNextInside)
222cdf0e10cSrcweir 								{
223cdf0e10cSrcweir 									// entering, finish existing and start new line polygon
224cdf0e10cSrcweir 									if(aNewPolygon.count() > 1L)
225cdf0e10cSrcweir 									{
226cdf0e10cSrcweir 										aRetval.append(aNewPolygon);
227cdf0e10cSrcweir 									}
228cdf0e10cSrcweir 
229cdf0e10cSrcweir 									aNewPolygon.clear();
230cdf0e10cSrcweir 								}
231cdf0e10cSrcweir 
232cdf0e10cSrcweir 								// calculate and add cut point
233cdf0e10cSrcweir 								const double fCut(impGetCut(aCurrent, aNext, fPlaneOffset, ePlaneOrthogonal));
234cdf0e10cSrcweir 								impAppendInterpolate(aNewPolygon, rCandidate, a, nNextIndex, fCut);
235cdf0e10cSrcweir 
236cdf0e10cSrcweir 								// pepare next step
237cdf0e10cSrcweir 								bCurrentInside = bNextInside;
238cdf0e10cSrcweir 							}
239cdf0e10cSrcweir 
240cdf0e10cSrcweir 							if(bNextInside)
241cdf0e10cSrcweir 							{
242cdf0e10cSrcweir 								impAppendCopy(aNewPolygon, rCandidate, nNextIndex);
243cdf0e10cSrcweir 							}
244cdf0e10cSrcweir 
245cdf0e10cSrcweir 							// pepare next step
246cdf0e10cSrcweir 							aCurrent = aNext;
247cdf0e10cSrcweir 						}
248cdf0e10cSrcweir 
249cdf0e10cSrcweir 						if(aNewPolygon.count() > 1L)
250cdf0e10cSrcweir 						{
251cdf0e10cSrcweir 							aRetval.append(aNewPolygon);
252cdf0e10cSrcweir 						}
253cdf0e10cSrcweir 					}
254cdf0e10cSrcweir 					else
255cdf0e10cSrcweir 					{
256cdf0e10cSrcweir 						// closed polygon, create single clipped closed polygon
257cdf0e10cSrcweir 						for(sal_uInt32 a(0L); a < nEdgeCount; a++)
258cdf0e10cSrcweir 						{
259cdf0e10cSrcweir 							// get next point data, use offset
260cdf0e10cSrcweir 							const sal_uInt32 nNextIndex((a + 1L == nPointCount) ? 0L : a + 1L);
261cdf0e10cSrcweir 							const B3DPoint aNext(rCandidate.getB3DPoint(nNextIndex));
262cdf0e10cSrcweir 							const bool bNextInside(impIsInside(aNext, fPlaneOffset, ePlaneOrthogonal) == bClipPositive);
263cdf0e10cSrcweir 
264cdf0e10cSrcweir 							if(bCurrentInside != bNextInside)
265cdf0e10cSrcweir 							{
266cdf0e10cSrcweir 								// calculate and add cut point
267cdf0e10cSrcweir 								const double fCut(impGetCut(aCurrent, aNext, fPlaneOffset, ePlaneOrthogonal));
268cdf0e10cSrcweir 								impAppendInterpolate(aNewPolygon, rCandidate, a, nNextIndex, fCut);
269cdf0e10cSrcweir 
270cdf0e10cSrcweir 								// pepare next step
271cdf0e10cSrcweir 								bCurrentInside = bNextInside;
272cdf0e10cSrcweir 							}
273cdf0e10cSrcweir 
274cdf0e10cSrcweir 							if(bNextInside && nNextIndex)
275cdf0e10cSrcweir 							{
276cdf0e10cSrcweir 								impAppendCopy(aNewPolygon, rCandidate, nNextIndex);
277cdf0e10cSrcweir 							}
278cdf0e10cSrcweir 
279cdf0e10cSrcweir 							// pepare next step
280cdf0e10cSrcweir 							aCurrent = aNext;
281cdf0e10cSrcweir 						}
282cdf0e10cSrcweir 
283cdf0e10cSrcweir 						if(aNewPolygon.count() > 2L)
284cdf0e10cSrcweir 						{
285cdf0e10cSrcweir 							aNewPolygon.setClosed(true);
286cdf0e10cSrcweir 							aRetval.append(aNewPolygon);
287cdf0e10cSrcweir 						}
288cdf0e10cSrcweir 					}
289cdf0e10cSrcweir 				}
290cdf0e10cSrcweir 			}
291cdf0e10cSrcweir 
292cdf0e10cSrcweir 			return aRetval;
293cdf0e10cSrcweir 		}
294cdf0e10cSrcweir 
clipPolyPolygonOnOrthogonalPlane(const B3DPolyPolygon & rCandidate,B3DOrientation ePlaneOrthogonal,bool bClipPositive,double fPlaneOffset,bool bStroke)295cdf0e10cSrcweir 		B3DPolyPolygon clipPolyPolygonOnOrthogonalPlane(const B3DPolyPolygon& rCandidate, B3DOrientation ePlaneOrthogonal, bool bClipPositive, double fPlaneOffset, bool bStroke)
296cdf0e10cSrcweir 		{
297cdf0e10cSrcweir 			B3DPolyPolygon aRetval;
298cdf0e10cSrcweir 
299cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
300cdf0e10cSrcweir 			{
301cdf0e10cSrcweir 				aRetval.append(clipPolygonOnOrthogonalPlane(rCandidate.getB3DPolygon(a), ePlaneOrthogonal, bClipPositive, fPlaneOffset, bStroke));
302cdf0e10cSrcweir 			}
303cdf0e10cSrcweir 
304cdf0e10cSrcweir 			return aRetval;
305cdf0e10cSrcweir 		}
306cdf0e10cSrcweir 
clipPolyPolygonOnRange(const B3DPolyPolygon & rCandidate,const B2DRange & rRange,bool bInside,bool bStroke)307cdf0e10cSrcweir 		B3DPolyPolygon clipPolyPolygonOnRange(const B3DPolyPolygon& rCandidate, const B2DRange& rRange, bool bInside, bool bStroke)
308cdf0e10cSrcweir 		{
309cdf0e10cSrcweir 			B3DPolyPolygon aRetval;
310cdf0e10cSrcweir 
311cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
312cdf0e10cSrcweir 			{
313cdf0e10cSrcweir 				aRetval.append(clipPolygonOnRange(rCandidate.getB3DPolygon(a), rRange, bInside, bStroke));
314cdf0e10cSrcweir 			}
315cdf0e10cSrcweir 
316cdf0e10cSrcweir 			return aRetval;
317cdf0e10cSrcweir 		}
318cdf0e10cSrcweir 
clipPolygonOnRange(const B3DPolygon & rCandidate,const B2DRange & rRange,bool bInside,bool bStroke)319cdf0e10cSrcweir 		B3DPolyPolygon clipPolygonOnRange(const B3DPolygon& rCandidate, const B2DRange& rRange, bool bInside, bool bStroke)
320cdf0e10cSrcweir 		{
321cdf0e10cSrcweir 			B3DPolyPolygon aRetval;
322cdf0e10cSrcweir 
323cdf0e10cSrcweir 			if(rRange.isEmpty())
324cdf0e10cSrcweir 			{
325cdf0e10cSrcweir 				// clipping against an empty range. Nothing is inside an empty range, so the polygon
326cdf0e10cSrcweir 				// is outside the range. So only return if not inside is wanted
327cdf0e10cSrcweir 				if(!bInside && rCandidate.count())
328cdf0e10cSrcweir 				{
329cdf0e10cSrcweir 					aRetval.append(rCandidate);
330cdf0e10cSrcweir 				}
331cdf0e10cSrcweir 			}
332cdf0e10cSrcweir 			else if(rCandidate.count())
333cdf0e10cSrcweir 			{
334cdf0e10cSrcweir 				const B3DRange aCandidateRange3D(getRange(rCandidate));
335cdf0e10cSrcweir 				const B2DRange aCandidateRange(
336cdf0e10cSrcweir 					aCandidateRange3D.getMinX(), aCandidateRange3D.getMinY(),
337cdf0e10cSrcweir 					aCandidateRange3D.getMaxX(), aCandidateRange3D.getMaxY());
338cdf0e10cSrcweir 
339cdf0e10cSrcweir 				if(rRange.isInside(aCandidateRange))
340cdf0e10cSrcweir 				{
341cdf0e10cSrcweir 					// candidate is completely inside given range, nothing to do. Is also true with curves.
342cdf0e10cSrcweir 					if(bInside)
343cdf0e10cSrcweir 					{
344cdf0e10cSrcweir 						aRetval.append(rCandidate);
345cdf0e10cSrcweir 					}
346cdf0e10cSrcweir 				}
347cdf0e10cSrcweir 				else if(!rRange.overlaps(aCandidateRange))
348cdf0e10cSrcweir 				{
349cdf0e10cSrcweir 					// candidate is completely outside given range, nothing to do. Is also true with curves.
350cdf0e10cSrcweir 					if(!bInside)
351cdf0e10cSrcweir 					{
352cdf0e10cSrcweir 						aRetval.append(rCandidate);
353cdf0e10cSrcweir 					}
354cdf0e10cSrcweir 				}
355cdf0e10cSrcweir 				else
356cdf0e10cSrcweir 				{
357cdf0e10cSrcweir 					// clip against the six planes of the range
358cdf0e10cSrcweir 					// against lower X
359cdf0e10cSrcweir 					aRetval = clipPolygonOnOrthogonalPlane(rCandidate, tools::B3DORIENTATION_X, bInside, rRange.getMinX(), bStroke);
360cdf0e10cSrcweir 
361cdf0e10cSrcweir 					if(aRetval.count())
362cdf0e10cSrcweir 					{
363cdf0e10cSrcweir 						// against lower Y
364cdf0e10cSrcweir 						if(1L == aRetval.count())
365cdf0e10cSrcweir 						{
366cdf0e10cSrcweir 							aRetval = clipPolygonOnOrthogonalPlane(aRetval.getB3DPolygon(0L), tools::B3DORIENTATION_Y, bInside, rRange.getMinY(), bStroke);
367cdf0e10cSrcweir 						}
368cdf0e10cSrcweir 						else
369cdf0e10cSrcweir 						{
370cdf0e10cSrcweir 							aRetval = clipPolyPolygonOnOrthogonalPlane(aRetval, tools::B3DORIENTATION_Y, bInside, rRange.getMinY(), bStroke);
371cdf0e10cSrcweir 						}
372cdf0e10cSrcweir 
373cdf0e10cSrcweir 						if(aRetval.count())
374cdf0e10cSrcweir 						{
375cdf0e10cSrcweir 							// against higher X
376cdf0e10cSrcweir 							if(1L == aRetval.count())
377cdf0e10cSrcweir 							{
378cdf0e10cSrcweir 								aRetval = clipPolygonOnOrthogonalPlane(aRetval.getB3DPolygon(0L), tools::B3DORIENTATION_X, !bInside, rRange.getMaxX(), bStroke);
379cdf0e10cSrcweir 							}
380cdf0e10cSrcweir 							else
381cdf0e10cSrcweir 							{
382cdf0e10cSrcweir 								aRetval = clipPolyPolygonOnOrthogonalPlane(aRetval, tools::B3DORIENTATION_X, !bInside, rRange.getMaxX(), bStroke);
383cdf0e10cSrcweir 							}
384cdf0e10cSrcweir 
385cdf0e10cSrcweir 							if(aRetval.count())
386cdf0e10cSrcweir 							{
387cdf0e10cSrcweir 								// against higher Y
388cdf0e10cSrcweir 								if(1L == aRetval.count())
389cdf0e10cSrcweir 								{
390cdf0e10cSrcweir 									aRetval = clipPolygonOnOrthogonalPlane(aRetval.getB3DPolygon(0L), tools::B3DORIENTATION_Y, !bInside, rRange.getMaxY(), bStroke);
391cdf0e10cSrcweir 								}
392cdf0e10cSrcweir 								else
393cdf0e10cSrcweir 								{
394cdf0e10cSrcweir 									aRetval = clipPolyPolygonOnOrthogonalPlane(aRetval, tools::B3DORIENTATION_Y, !bInside, rRange.getMaxY(), bStroke);
395cdf0e10cSrcweir 								}
396cdf0e10cSrcweir 							}
397cdf0e10cSrcweir 						}
398cdf0e10cSrcweir 					}
399cdf0e10cSrcweir 				}
400cdf0e10cSrcweir 			}
401cdf0e10cSrcweir 
402cdf0e10cSrcweir 			return aRetval;
403cdf0e10cSrcweir 		}
404cdf0e10cSrcweir 
clipPolyPolygonOnRange(const B3DPolyPolygon & rCandidate,const B3DRange & rRange,bool bInside,bool bStroke)405cdf0e10cSrcweir 		B3DPolyPolygon clipPolyPolygonOnRange(const B3DPolyPolygon& rCandidate, const B3DRange& rRange, bool bInside, bool bStroke)
406cdf0e10cSrcweir 		{
407cdf0e10cSrcweir 			B3DPolyPolygon aRetval;
408cdf0e10cSrcweir 
409cdf0e10cSrcweir 			for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
410cdf0e10cSrcweir 			{
411cdf0e10cSrcweir 				aRetval.append(clipPolygonOnRange(rCandidate.getB3DPolygon(a), rRange, bInside, bStroke));
412cdf0e10cSrcweir 			}
413cdf0e10cSrcweir 
414cdf0e10cSrcweir 			return aRetval;
415cdf0e10cSrcweir 		}
416cdf0e10cSrcweir 
clipPolygonOnRange(const B3DPolygon & rCandidate,const B3DRange & rRange,bool bInside,bool bStroke)417cdf0e10cSrcweir 		B3DPolyPolygon clipPolygonOnRange(const B3DPolygon& rCandidate, const B3DRange& rRange, bool bInside, bool bStroke)
418cdf0e10cSrcweir 		{
419cdf0e10cSrcweir 			B3DPolyPolygon aRetval;
420cdf0e10cSrcweir 
421cdf0e10cSrcweir 			if(rRange.isEmpty())
422cdf0e10cSrcweir 			{
423cdf0e10cSrcweir 				// clipping against an empty range. Nothing is inside an empty range, so the polygon
424cdf0e10cSrcweir 				// is outside the range. So only return if not inside is wanted
425cdf0e10cSrcweir 				if(!bInside && rCandidate.count())
426cdf0e10cSrcweir 				{
427cdf0e10cSrcweir 					aRetval.append(rCandidate);
428cdf0e10cSrcweir 				}
429cdf0e10cSrcweir 			}
430cdf0e10cSrcweir 			else if(rCandidate.count())
431cdf0e10cSrcweir 			{
432cdf0e10cSrcweir 				const B3DRange aCandidateRange(getRange(rCandidate));
433cdf0e10cSrcweir 
434cdf0e10cSrcweir 				if(rRange.isInside(aCandidateRange))
435cdf0e10cSrcweir 				{
436cdf0e10cSrcweir 					// candidate is completely inside given range, nothing to do. Is also true with curves.
437cdf0e10cSrcweir 					if(bInside)
438cdf0e10cSrcweir 					{
439cdf0e10cSrcweir 						aRetval.append(rCandidate);
440cdf0e10cSrcweir 					}
441cdf0e10cSrcweir 				}
442cdf0e10cSrcweir 				else if(!rRange.overlaps(aCandidateRange))
443cdf0e10cSrcweir 				{
444cdf0e10cSrcweir 					// candidate is completely outside given range, nothing to do. Is also true with curves.
445cdf0e10cSrcweir 					if(!bInside)
446cdf0e10cSrcweir 					{
447cdf0e10cSrcweir 						aRetval.append(rCandidate);
448cdf0e10cSrcweir 					}
449cdf0e10cSrcweir 				}
450cdf0e10cSrcweir 				else
451cdf0e10cSrcweir 				{
452cdf0e10cSrcweir 					// clip against X,Y first and see if there's something left
453cdf0e10cSrcweir 					const B2DRange aCandidateRange2D(rRange.getMinX(), rRange.getMinY(), rRange.getMaxX(), rRange.getMaxY());
454cdf0e10cSrcweir 					aRetval = clipPolygonOnRange(rCandidate, aCandidateRange2D, bInside, bStroke);
455cdf0e10cSrcweir 
456cdf0e10cSrcweir 					if(aRetval.count())
457cdf0e10cSrcweir 					{
458cdf0e10cSrcweir 						// against lower Z
459cdf0e10cSrcweir 						if(1L == aRetval.count())
460cdf0e10cSrcweir 						{
461cdf0e10cSrcweir 							aRetval = clipPolygonOnOrthogonalPlane(aRetval.getB3DPolygon(0L), tools::B3DORIENTATION_Z, bInside, rRange.getMinZ(), bStroke);
462cdf0e10cSrcweir 						}
463cdf0e10cSrcweir 						else
464cdf0e10cSrcweir 						{
465cdf0e10cSrcweir 							aRetval = clipPolyPolygonOnOrthogonalPlane(aRetval, tools::B3DORIENTATION_Z, bInside, rRange.getMinZ(), bStroke);
466cdf0e10cSrcweir 						}
467cdf0e10cSrcweir 
468cdf0e10cSrcweir 						if(aRetval.count())
469cdf0e10cSrcweir 						{
470cdf0e10cSrcweir 							// against higher Z
471cdf0e10cSrcweir 							if(1L == aRetval.count())
472cdf0e10cSrcweir 							{
473cdf0e10cSrcweir 								aRetval = clipPolygonOnOrthogonalPlane(aRetval.getB3DPolygon(0L), tools::B3DORIENTATION_Z, !bInside, rRange.getMaxZ(), bStroke);
474cdf0e10cSrcweir 							}
475cdf0e10cSrcweir 							else
476cdf0e10cSrcweir 							{
477cdf0e10cSrcweir 								aRetval = clipPolyPolygonOnOrthogonalPlane(aRetval, tools::B3DORIENTATION_Z, !bInside, rRange.getMaxZ(), bStroke);
478cdf0e10cSrcweir 							}
479cdf0e10cSrcweir 						}
480cdf0e10cSrcweir 					}
481cdf0e10cSrcweir 				}
482cdf0e10cSrcweir 			}
483cdf0e10cSrcweir 
484cdf0e10cSrcweir 			return aRetval;
485cdf0e10cSrcweir 		}
486cdf0e10cSrcweir 
clipPolygonOnPlane(const B3DPolygon & rCandidate,const B3DPoint & rPointOnPlane,const B3DVector & rPlaneNormal,bool bClipPositive,bool bStroke)487cdf0e10cSrcweir 		B3DPolyPolygon clipPolygonOnPlane(const B3DPolygon& rCandidate, const B3DPoint& rPointOnPlane, const B3DVector& rPlaneNormal, bool bClipPositive, bool bStroke)
488cdf0e10cSrcweir 		{
489cdf0e10cSrcweir 			B3DPolyPolygon aRetval;
490cdf0e10cSrcweir 
491cdf0e10cSrcweir 			if(rPlaneNormal.equalZero())
492cdf0e10cSrcweir 			{
493cdf0e10cSrcweir 				// not really a plane definition, return polygon
494cdf0e10cSrcweir 				aRetval.append(rCandidate);
495cdf0e10cSrcweir 			}
496cdf0e10cSrcweir 			else if(rCandidate.count())
497cdf0e10cSrcweir 			{
498cdf0e10cSrcweir 				// build transform to project planeNormal on X-Axis and pointOnPlane to null point
499cdf0e10cSrcweir 				B3DHomMatrix aMatrixTransform;
500cdf0e10cSrcweir 				aMatrixTransform.translate(-rPointOnPlane.getX(), -rPointOnPlane.getY(), -rPointOnPlane.getZ());
501cdf0e10cSrcweir 				const double fRotInXY(atan2(rPlaneNormal.getY(), rPlaneNormal.getX()));
502cdf0e10cSrcweir 				const double fRotInXZ(atan2(-rPlaneNormal.getZ(), rPlaneNormal.getXYLength()));
503cdf0e10cSrcweir 				if(!fTools::equalZero(fRotInXY) || !fTools::equalZero(fRotInXZ))
504cdf0e10cSrcweir 				{
505cdf0e10cSrcweir 					aMatrixTransform.rotate(0.0, fRotInXZ, fRotInXY);
506cdf0e10cSrcweir 				}
507cdf0e10cSrcweir 
508cdf0e10cSrcweir 				// transform polygon to clip scenario
509cdf0e10cSrcweir 				B3DPolygon aCandidate(rCandidate);
510cdf0e10cSrcweir 				aCandidate.transform(aMatrixTransform);
511cdf0e10cSrcweir 
512cdf0e10cSrcweir 				// clip on YZ plane
513cdf0e10cSrcweir 				aRetval = clipPolygonOnOrthogonalPlane(aCandidate, tools::B3DORIENTATION_X, bClipPositive, 0.0, bStroke);
514cdf0e10cSrcweir 
515cdf0e10cSrcweir 				if(aRetval.count())
516cdf0e10cSrcweir 				{
517cdf0e10cSrcweir 					// if there is a result, it needs to be transformed back
518cdf0e10cSrcweir 					aMatrixTransform.invert();
519cdf0e10cSrcweir 					aRetval.transform(aMatrixTransform);
520cdf0e10cSrcweir 				}
521cdf0e10cSrcweir 			}
522cdf0e10cSrcweir 
523cdf0e10cSrcweir 			return aRetval;
524cdf0e10cSrcweir 		}
525cdf0e10cSrcweir 
clipPolyPolygonOnPlane(const B3DPolyPolygon & rCandidate,const B3DPoint & rPointOnPlane,const B3DVector & rPlaneNormal,bool bClipPositive,bool bStroke)526cdf0e10cSrcweir 		B3DPolyPolygon clipPolyPolygonOnPlane(const B3DPolyPolygon& rCandidate, const B3DPoint& rPointOnPlane, const B3DVector& rPlaneNormal, bool bClipPositive, bool bStroke)
527cdf0e10cSrcweir 		{
528cdf0e10cSrcweir 			B3DPolyPolygon aRetval;
529cdf0e10cSrcweir 
530cdf0e10cSrcweir 			if(rPlaneNormal.equalZero())
531cdf0e10cSrcweir 			{
532cdf0e10cSrcweir 				// not really a plane definition, return polygon
533cdf0e10cSrcweir 				aRetval = rCandidate;
534cdf0e10cSrcweir 			}
535cdf0e10cSrcweir 			else if(rCandidate.count())
536cdf0e10cSrcweir 			{
537cdf0e10cSrcweir 				// build transform to project planeNormal on X-Axis and pointOnPlane to null point
538cdf0e10cSrcweir 				B3DHomMatrix aMatrixTransform;
539cdf0e10cSrcweir 				aMatrixTransform.translate(-rPointOnPlane.getX(), -rPointOnPlane.getY(), -rPointOnPlane.getZ());
540cdf0e10cSrcweir 				const double fRotInXY(atan2(rPlaneNormal.getY(), rPlaneNormal.getX()));
541cdf0e10cSrcweir 				const double fRotInXZ(atan2(-rPlaneNormal.getZ(), rPlaneNormal.getXYLength()));
542cdf0e10cSrcweir 				if(!fTools::equalZero(fRotInXY) || !fTools::equalZero(fRotInXZ))
543cdf0e10cSrcweir 				{
544cdf0e10cSrcweir 					aMatrixTransform.rotate(0.0, fRotInXZ, fRotInXY);
545cdf0e10cSrcweir 				}
546cdf0e10cSrcweir 
547cdf0e10cSrcweir 				// transform polygon to clip scenario
548cdf0e10cSrcweir 				aRetval = rCandidate;
549cdf0e10cSrcweir 				aRetval.transform(aMatrixTransform);
550cdf0e10cSrcweir 
551cdf0e10cSrcweir 				// clip on YZ plane
552cdf0e10cSrcweir 				aRetval = clipPolyPolygonOnOrthogonalPlane(aRetval, tools::B3DORIENTATION_X, bClipPositive, 0.0, bStroke);
553cdf0e10cSrcweir 
554cdf0e10cSrcweir 				if(aRetval.count())
555cdf0e10cSrcweir 				{
556cdf0e10cSrcweir 					// if there is a result, it needs to be transformed back
557cdf0e10cSrcweir 					aMatrixTransform.invert();
558cdf0e10cSrcweir 					aRetval.transform(aMatrixTransform);
559cdf0e10cSrcweir 				}
560cdf0e10cSrcweir 			}
561cdf0e10cSrcweir 
562cdf0e10cSrcweir 			return aRetval;
563cdf0e10cSrcweir 		}
564cdf0e10cSrcweir 
565cdf0e10cSrcweir 	} // end of namespace tools
566cdf0e10cSrcweir } // end of namespace basegfx
567cdf0e10cSrcweir 
568cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
569cdf0e10cSrcweir 
570cdf0e10cSrcweir // eof
571