xref: /trunk/main/basegfx/source/polygon/b3dpolygonclipper.cxx (revision cf6516809c57e1bb0a940545cca99cdad54d4ce2)
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
10cdf0e10cSrcweir  *
11*09dbbe93SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
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.
19cdf0e10cSrcweir  *
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