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