xref: /aoo41x/main/vcl/source/gdi/region.cxx (revision d8ed516e)
19f62ea84SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
39f62ea84SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
49f62ea84SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
59f62ea84SAndrew Rist  * distributed with this work for additional information
69f62ea84SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
79f62ea84SAndrew Rist  * to you under the Apache License, Version 2.0 (the
89f62ea84SAndrew Rist  * "License"); you may not use this file except in compliance
99f62ea84SAndrew Rist  * with the License.  You may obtain a copy of the License at
109f62ea84SAndrew Rist  *
119f62ea84SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
129f62ea84SAndrew Rist  *
139f62ea84SAndrew Rist  * Unless required by applicable law or agreed to in writing,
149f62ea84SAndrew Rist  * software distributed under the License is distributed on an
159f62ea84SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
169f62ea84SAndrew Rist  * KIND, either express or implied.  See the License for the
179f62ea84SAndrew Rist  * specific language governing permissions and limitations
189f62ea84SAndrew Rist  * under the License.
199f62ea84SAndrew Rist  *
209f62ea84SAndrew Rist  *************************************************************/
219f62ea84SAndrew Rist 
22cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
23cdf0e10cSrcweir #include "precompiled_vcl.hxx"
24cdf0e10cSrcweir 
25cdf0e10cSrcweir #include <limits.h>
26cdf0e10cSrcweir #include <tools/vcompat.hxx>
27cdf0e10cSrcweir #include <tools/stream.hxx>
28cdf0e10cSrcweir #include <vcl/region.hxx>
29e6f63103SArmin Le Grand #include <regionband.hxx>
30cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx>
31cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx>
32cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
33cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygonclipper.hxx>
34cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
35cdf0e10cSrcweir #include <basegfx/range/b2drange.hxx>
36cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrixtools.hxx>
37cdf0e10cSrcweir 
38e6f63103SArmin Le Grand //////////////////////////////////////////////////////////////////////////////
39cdf0e10cSrcweir 
40cdf0e10cSrcweir DBG_NAME( Region )
41cdf0e10cSrcweir DBG_NAMEEX( Polygon )
42cdf0e10cSrcweir DBG_NAMEEX( PolyPolygon )
43cdf0e10cSrcweir 
44e6f63103SArmin Le Grand //////////////////////////////////////////////////////////////////////////////
45cdf0e10cSrcweir 
46e6f63103SArmin Le Grand namespace
47cdf0e10cSrcweir {
48e6f63103SArmin Le Grand     /** Return <TRUE/> when the given polygon is rectiliner and oriented so that
49e6f63103SArmin Le Grand         all sides are either horizontal or vertical.
50e6f63103SArmin Le Grand     */
ImplIsPolygonRectilinear(const PolyPolygon & rPolyPoly)51e6f63103SArmin Le Grand     bool ImplIsPolygonRectilinear (const PolyPolygon& rPolyPoly)
52cdf0e10cSrcweir     {
53e6f63103SArmin Le Grand         // Iterate over all polygons.
54e6f63103SArmin Le Grand         const sal_uInt16 nPolyCount = rPolyPoly.Count();
55e6f63103SArmin Le Grand         for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly)
56e6f63103SArmin Le Grand         {
57e6f63103SArmin Le Grand             const Polygon&	aPoly = rPolyPoly.GetObject(nPoly);
58cdf0e10cSrcweir 
59e6f63103SArmin Le Grand             // Iterate over all edges of the current polygon.
60e6f63103SArmin Le Grand             const sal_uInt16 nSize = aPoly.GetSize();
61cdf0e10cSrcweir 
62e6f63103SArmin Le Grand             if (nSize < 2)
63e6f63103SArmin Le Grand                 continue;
64e6f63103SArmin Le Grand             Point aPoint (aPoly.GetPoint(0));
65e6f63103SArmin Le Grand             const Point aLastPoint (aPoint);
66e6f63103SArmin Le Grand             for (sal_uInt16 nPoint = 1; nPoint < nSize; ++nPoint)
67e6f63103SArmin Le Grand             {
68e6f63103SArmin Le Grand                 const Point aNextPoint (aPoly.GetPoint(nPoint));
69e6f63103SArmin Le Grand                 // When there is at least one edge that is neither vertical nor
70e6f63103SArmin Le Grand                 // horizontal then the entire polygon is not rectilinear (and
71e6f63103SArmin Le Grand                 // oriented along primary axes.)
72e6f63103SArmin Le Grand                 if (aPoint.X() != aNextPoint.X() && aPoint.Y() != aNextPoint.Y())
73e6f63103SArmin Le Grand                     return false;
74e6f63103SArmin Le Grand 
75e6f63103SArmin Le Grand                 aPoint = aNextPoint;
76e6f63103SArmin Le Grand             }
77e6f63103SArmin Le Grand             // Compare closing edge.
78e6f63103SArmin Le Grand             if (aLastPoint.X() != aPoint.X() && aLastPoint.Y() != aPoint.Y())
79cdf0e10cSrcweir                 return false;
80cdf0e10cSrcweir         }
81e6f63103SArmin Le Grand         return true;
82cdf0e10cSrcweir     }
83cdf0e10cSrcweir 
84e6f63103SArmin Le Grand     /** Convert a rectilinear polygon (that is oriented along the primary axes)
85e6f63103SArmin Le Grand         to a list of bands.  For this special form of polygon we can use an
86e6f63103SArmin Le Grand         optimization that prevents the creation of one band per y value.
87e6f63103SArmin Le Grand         However, it still is possible that some temporary bands are created that
88e6f63103SArmin Le Grand         later can be optimized away.
89e6f63103SArmin Le Grand         @param rPolyPolygon
90e6f63103SArmin Le Grand             A set of zero, one, or more polygons, nested or not, that are
91e6f63103SArmin Le Grand             converted into a list of bands.
92e6f63103SArmin Le Grand         @return
93e6f63103SArmin Le Grand             A new RegionBand object is returned that contains the bands that
94e6f63103SArmin Le Grand             represent the given poly-polygon.
95e6f63103SArmin Le Grand     */
ImplRectilinearPolygonToBands(const PolyPolygon & rPolyPoly)96e6f63103SArmin Le Grand     RegionBand* ImplRectilinearPolygonToBands(const PolyPolygon& rPolyPoly)
97e6f63103SArmin Le Grand     {
98e6f63103SArmin Le Grand         OSL_ASSERT(ImplIsPolygonRectilinear (rPolyPoly));
99cdf0e10cSrcweir 
100e6f63103SArmin Le Grand         // Create a new RegionBand object as container of the bands.
101e6f63103SArmin Le Grand         RegionBand* pRegionBand = new RegionBand();
102e6f63103SArmin Le Grand         long nLineId = 0L;
103cdf0e10cSrcweir 
104e6f63103SArmin Le Grand         // Iterate over all polygons.
105e6f63103SArmin Le Grand 	    const sal_uInt16 nPolyCount = rPolyPoly.Count();
106e6f63103SArmin Le Grand         for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly)
107cdf0e10cSrcweir         {
108e6f63103SArmin Le Grand             const Polygon&	aPoly = rPolyPoly.GetObject(nPoly);
109cdf0e10cSrcweir 
110e6f63103SArmin Le Grand             // Iterate over all edges of the current polygon.
111e6f63103SArmin Le Grand             const sal_uInt16 nSize = aPoly.GetSize();
112e6f63103SArmin Le Grand             if (nSize < 2)
113e6f63103SArmin Le Grand                 continue;
114e6f63103SArmin Le Grand             // Avoid fetching every point twice (each point is the start point
115e6f63103SArmin Le Grand             // of one and the end point of another edge.)
116e6f63103SArmin Le Grand             Point aStart (aPoly.GetPoint(0));
117e6f63103SArmin Le Grand             Point aEnd;
118e6f63103SArmin Le Grand             for (sal_uInt16 nPoint = 1; nPoint <= nSize; ++nPoint, aStart=aEnd)
119e6f63103SArmin Le Grand             {
120e6f63103SArmin Le Grand                 // We take the implicit closing edge into account by mapping
121e6f63103SArmin Le Grand                 // index nSize to 0.
122e6f63103SArmin Le Grand                 aEnd = aPoly.GetPoint(nPoint%nSize);
123e6f63103SArmin Le Grand                 if (aStart.Y() == aEnd.Y())
124e6f63103SArmin Le Grand                 {
125e6f63103SArmin Le Grand                     // Horizontal lines are ignored.
126e6f63103SArmin Le Grand                     continue;
127e6f63103SArmin Le Grand                 }
128cdf0e10cSrcweir 
129e6f63103SArmin Le Grand                 // At this point the line has to be vertical.
130e6f63103SArmin Le Grand                 OSL_ASSERT(aStart.X() == aEnd.X());
131cdf0e10cSrcweir 
132e6f63103SArmin Le Grand                 // Sort y-coordinates to simplify the algorithm and store the
133e6f63103SArmin Le Grand                 // direction seperately.  The direction is calculated as it is
134e6f63103SArmin Le Grand                 // in other places (but seems to be the wrong way.)
135e6f63103SArmin Le Grand                 const long nTop (::std::min(aStart.Y(), aEnd.Y()));
136e6f63103SArmin Le Grand                 const long nBottom (::std::max(aStart.Y(), aEnd.Y()));
137e6f63103SArmin Le Grand                 const LineType eLineType (aStart.Y() > aEnd.Y() ? LINE_DESCENDING : LINE_ASCENDING);
138e6f63103SArmin Le Grand 
139e6f63103SArmin Le Grand                 // Make sure that the current line is covered by bands.
140e6f63103SArmin Le Grand                 pRegionBand->ImplAddMissingBands(nTop,nBottom);
141e6f63103SArmin Le Grand 
142e6f63103SArmin Le Grand                 // Find top-most band that may contain nTop.
143e6f63103SArmin Le Grand                 ImplRegionBand* pBand = pRegionBand->ImplGetFirstRegionBand();
144e6f63103SArmin Le Grand                 while (pBand!=NULL && pBand->mnYBottom < nTop)
145e6f63103SArmin Le Grand                     pBand = pBand->mpNextBand;
146e6f63103SArmin Le Grand                 ImplRegionBand* pTopBand = pBand;
147e6f63103SArmin Le Grand                 // If necessary split the band at nTop so that nTop is contained
148e6f63103SArmin Le Grand                 // in the lower band.
149e6f63103SArmin Le Grand                 if (pBand!=NULL
150e6f63103SArmin Le Grand                        // Prevent the current band from becoming 0 pixel high
151e6f63103SArmin Le Grand                     && pBand->mnYTop<nTop
152e6f63103SArmin Le Grand                        // this allows the lowest pixel of the band to be split off
153e6f63103SArmin Le Grand                     && pBand->mnYBottom>=nTop
154e6f63103SArmin Le Grand                        // do not split a band that is just one pixel high
155e6f63103SArmin Le Grand                     && pBand->mnYTop<pBand->mnYBottom)
156e6f63103SArmin Le Grand                 {
157e6f63103SArmin Le Grand                     // Split the top band.
158e6f63103SArmin Le Grand                     pTopBand = pBand->SplitBand(nTop);
159e6f63103SArmin Le Grand                 }
160cdf0e10cSrcweir 
161e6f63103SArmin Le Grand                 // Advance to band that may contain nBottom.
162e6f63103SArmin Le Grand                 while (pBand!=NULL && pBand->mnYBottom < nBottom)
163e6f63103SArmin Le Grand                     pBand = pBand->mpNextBand;
164e6f63103SArmin Le Grand                 // The lowest band may have to be split at nBottom so that
165e6f63103SArmin Le Grand                 // nBottom itself remains in the upper band.
166e6f63103SArmin Le Grand                 if (pBand!=NULL
167e6f63103SArmin Le Grand                        // allow the current band becoming 1 pixel high
168e6f63103SArmin Le Grand                     && pBand->mnYTop<=nBottom
169e6f63103SArmin Le Grand                        // prevent splitting off a band that is 0 pixel high
170e6f63103SArmin Le Grand                     && pBand->mnYBottom>nBottom
171e6f63103SArmin Le Grand                        // do not split a band that is just one pixel high
172e6f63103SArmin Le Grand                     && pBand->mnYTop<pBand->mnYBottom)
173e6f63103SArmin Le Grand                 {
174e6f63103SArmin Le Grand                     // Split the bottom band.
175e6f63103SArmin Le Grand                     pBand->SplitBand(nBottom+1);
176e6f63103SArmin Le Grand                 }
177cdf0e10cSrcweir 
178e6f63103SArmin Le Grand                 // Note that we remember the top band (in pTopBand) but not the
179e6f63103SArmin Le Grand                 // bottom band.  The later can be determined by comparing y
180e6f63103SArmin Le Grand                 // coordinates.
181cdf0e10cSrcweir 
182e6f63103SArmin Le Grand                 // Add the x-value as point to all bands in the nTop->nBottom range.
183e6f63103SArmin Le Grand                 for (pBand=pTopBand; pBand!=NULL&&pBand->mnYTop<=nBottom; pBand=pBand->mpNextBand)
184e6f63103SArmin Le Grand                     pBand->InsertPoint(aStart.X(), nLineId++, true, eLineType);
185e6f63103SArmin Le Grand             }
186e6f63103SArmin Le Grand         }
187cdf0e10cSrcweir 
188e6f63103SArmin Le Grand         return pRegionBand;
189e6f63103SArmin Le Grand     }
190cdf0e10cSrcweir 
191e6f63103SArmin Le Grand     /** Convert a general polygon (one for which ImplIsPolygonRectilinear()
192e6f63103SArmin Le Grand         returns <FALSE/>) to bands.
193e6f63103SArmin Le Grand     */
ImplGeneralPolygonToBands(const PolyPolygon & rPolyPoly,const Rectangle & rPolygonBoundingBox)194e6f63103SArmin Le Grand     RegionBand* ImplGeneralPolygonToBands(const PolyPolygon& rPolyPoly, const Rectangle& rPolygonBoundingBox)
195e6f63103SArmin Le Grand     {
196e6f63103SArmin Le Grand         long nLineID = 0L;
197e6f63103SArmin Le Grand 
198e6f63103SArmin Le Grand         // initialisation and creation of Bands
199e6f63103SArmin Le Grand         RegionBand* pRegionBand = new RegionBand();
200e6f63103SArmin Le Grand         pRegionBand->CreateBandRange(rPolygonBoundingBox.Top(), rPolygonBoundingBox.Bottom());
201e6f63103SArmin Le Grand 
202e6f63103SArmin Le Grand         // insert polygons
203e6f63103SArmin Le Grand 	    const sal_uInt16 nPolyCount = rPolyPoly.Count();
204e6f63103SArmin Le Grand 
205e6f63103SArmin Le Grand         for ( sal_uInt16 nPoly = 0; nPoly < nPolyCount; nPoly++ )
206cdf0e10cSrcweir         {
207e6f63103SArmin Le Grand             // get reference to current polygon
208e6f63103SArmin Le Grand             const Polygon&	aPoly = rPolyPoly.GetObject( nPoly );
209e6f63103SArmin Le Grand             const sal_uInt16	nSize = aPoly.GetSize();
210cdf0e10cSrcweir 
211e6f63103SArmin Le Grand             // not enough points ( <= 2 )? -> nothing to do!
212e6f63103SArmin Le Grand             if ( nSize <= 2 )
213e6f63103SArmin Le Grand                 continue;
214cdf0e10cSrcweir 
215e6f63103SArmin Le Grand             // band the polygon
216e6f63103SArmin Le Grand             for ( sal_uInt16 nPoint = 1; nPoint < nSize; nPoint++ )
217cdf0e10cSrcweir             {
218e6f63103SArmin Le Grand                 pRegionBand->InsertLine( aPoly.GetPoint(nPoint-1), aPoly.GetPoint(nPoint), nLineID++ );
219cdf0e10cSrcweir             }
220cdf0e10cSrcweir 
221e6f63103SArmin Le Grand             // close polygon with line from first point to last point, if neccesary
222e6f63103SArmin Le Grand             const Point rLastPoint = aPoly.GetPoint(nSize-1);
223e6f63103SArmin Le Grand             const Point rFirstPoint = aPoly.GetPoint(0);
224e6f63103SArmin Le Grand 
225e6f63103SArmin Le Grand             if ( rLastPoint != rFirstPoint )
226cdf0e10cSrcweir             {
227e6f63103SArmin Le Grand                 pRegionBand->InsertLine( rLastPoint, rFirstPoint, nLineID++ );
228cdf0e10cSrcweir             }
229cdf0e10cSrcweir         }
230cdf0e10cSrcweir 
231e6f63103SArmin Le Grand         return pRegionBand;
232e6f63103SArmin Le Grand     }
233e6f63103SArmin Le Grand } // end of anonymous namespace
234cdf0e10cSrcweir 
235e6f63103SArmin Le Grand //////////////////////////////////////////////////////////////////////////////
236cdf0e10cSrcweir 
IsEmpty() const237e6f63103SArmin Le Grand bool Region::IsEmpty() const
238e6f63103SArmin Le Grand {
239e6f63103SArmin Le Grand     return !mbIsNull && !mpB2DPolyPolygon.get() && !mpPolyPolygon.get() && !mpRegionBand.get();
240e6f63103SArmin Le Grand }
241cdf0e10cSrcweir 
IsNull() const242e6f63103SArmin Le Grand bool Region::IsNull() const
243e6f63103SArmin Le Grand {
244e6f63103SArmin Le Grand     return mbIsNull;
245e6f63103SArmin Le Grand }
246cdf0e10cSrcweir 
ImplCreateRegionBandFromPolyPolygon(const PolyPolygon & rPolyPolygon)247e6f63103SArmin Le Grand RegionBand* ImplCreateRegionBandFromPolyPolygon(const PolyPolygon& rPolyPolygon)
248cdf0e10cSrcweir {
249e6f63103SArmin Le Grand     RegionBand* pRetval = 0;
250cdf0e10cSrcweir 
251e6f63103SArmin Le Grand     if(rPolyPolygon.Count())
252cdf0e10cSrcweir     {
253e6f63103SArmin Le Grand         // ensure to subdivide when bezier segemnts are used, it's going to
254e6f63103SArmin Le Grand         // be expanded to rectangles
255e6f63103SArmin Le Grand         PolyPolygon aPolyPolygon;
256cdf0e10cSrcweir 
257e6f63103SArmin Le Grand         rPolyPolygon.AdaptiveSubdivide(aPolyPolygon);
258e6f63103SArmin Le Grand 
259e6f63103SArmin Le Grand         if(aPolyPolygon.Count())
260e6f63103SArmin Le Grand         {
261e6f63103SArmin Le Grand             const Rectangle aRect(aPolyPolygon.GetBoundRect());
262cdf0e10cSrcweir 
263e6f63103SArmin Le Grand             if(!aRect.IsEmpty())
264e6f63103SArmin Le Grand             {
265e6f63103SArmin Le Grand                 if(ImplIsPolygonRectilinear(aPolyPolygon))
266e6f63103SArmin Le Grand                 {
267e6f63103SArmin Le Grand                     // For rectilinear polygons there is an optimized band conversion.
268e6f63103SArmin Le Grand                     pRetval = ImplRectilinearPolygonToBands(aPolyPolygon);
269e6f63103SArmin Le Grand                 }
270e6f63103SArmin Le Grand                 else
271e6f63103SArmin Le Grand                 {
272e6f63103SArmin Le Grand                     pRetval = ImplGeneralPolygonToBands(aPolyPolygon, aRect);
273e6f63103SArmin Le Grand                 }
274cdf0e10cSrcweir 
275e6f63103SArmin Le Grand                 // Convert points into seps.
276e6f63103SArmin Le Grand                 if(pRetval)
277e6f63103SArmin Le Grand                 {
278e6f63103SArmin Le Grand                     pRetval->processPoints();
279e6f63103SArmin Le Grand 
280e6f63103SArmin Le Grand                     // Optimize list of bands.  Adjacent bands with identical lists
281e6f63103SArmin Le Grand                     // of seps are joined.
282e6f63103SArmin Le Grand                     if(!pRetval->OptimizeBandList())
283e6f63103SArmin Le Grand                     {
284e6f63103SArmin Le Grand                         delete pRetval;
285e6f63103SArmin Le Grand                         pRetval = 0;
286e6f63103SArmin Le Grand                     }
287e6f63103SArmin Le Grand                 }
288e6f63103SArmin Le Grand             }
289e6f63103SArmin Le Grand         }
290cdf0e10cSrcweir     }
291cdf0e10cSrcweir 
292e6f63103SArmin Le Grand     return pRetval;
293cdf0e10cSrcweir }
294cdf0e10cSrcweir 
ImplCreatePolyPolygonFromRegionBand() const295e6f63103SArmin Le Grand PolyPolygon Region::ImplCreatePolyPolygonFromRegionBand() const
296cdf0e10cSrcweir {
297e6f63103SArmin Le Grand     PolyPolygon aRetval;
298cdf0e10cSrcweir 
299e6f63103SArmin Le Grand     if(getRegionBand())
300cdf0e10cSrcweir     {
301e6f63103SArmin Le Grand         RectangleVector aRectangles;
302e6f63103SArmin Le Grand         GetRegionRectangles(aRectangles);
303cdf0e10cSrcweir 
304e6f63103SArmin Le Grand         for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++)
305cdf0e10cSrcweir         {
306e6f63103SArmin Le Grand             aRetval.Insert(Polygon(*aRectIter));
307cdf0e10cSrcweir         }
308cdf0e10cSrcweir     }
309e6f63103SArmin Le Grand     else
310e6f63103SArmin Le Grand     {
311e6f63103SArmin Le Grand         OSL_ENSURE(false, "Called with no local RegionBand (!)");
312e6f63103SArmin Le Grand     }
313cdf0e10cSrcweir 
314e6f63103SArmin Le Grand     return aRetval;
315cdf0e10cSrcweir }
316cdf0e10cSrcweir 
ImplCreateB2DPolyPolygonFromRegionBand() const317e6f63103SArmin Le Grand basegfx::B2DPolyPolygon Region::ImplCreateB2DPolyPolygonFromRegionBand() const
318e6f63103SArmin Le Grand {
319e6f63103SArmin Le Grand     PolyPolygon aPoly(ImplCreatePolyPolygonFromRegionBand());
320cdf0e10cSrcweir 
321e6f63103SArmin Le Grand     return aPoly.getB2DPolyPolygon();
322e6f63103SArmin Le Grand }
323cdf0e10cSrcweir 
Region(bool bIsNull)324e6f63103SArmin Le Grand Region::Region(bool bIsNull)
325e6f63103SArmin Le Grand :   mpB2DPolyPolygon(),
326e6f63103SArmin Le Grand     mpPolyPolygon(),
327e6f63103SArmin Le Grand     mpRegionBand(),
328e6f63103SArmin Le Grand     mbIsNull(bIsNull)
329cdf0e10cSrcweir {
330cdf0e10cSrcweir }
331cdf0e10cSrcweir 
Region(const Rectangle & rRect)332e6f63103SArmin Le Grand Region::Region(const Rectangle& rRect)
333e6f63103SArmin Le Grand :   mpB2DPolyPolygon(),
334e6f63103SArmin Le Grand     mpPolyPolygon(),
335e6f63103SArmin Le Grand     mpRegionBand(),
336e6f63103SArmin Le Grand     mbIsNull(false)
337cdf0e10cSrcweir {
338e6f63103SArmin Le Grand     mpRegionBand.reset(rRect.IsEmpty() ? 0 : new RegionBand(rRect));
339cdf0e10cSrcweir }
340cdf0e10cSrcweir 
Region(const Polygon & rPolygon)341e6f63103SArmin Le Grand Region::Region(const Polygon& rPolygon)
342e6f63103SArmin Le Grand :   mpB2DPolyPolygon(),
343e6f63103SArmin Le Grand     mpPolyPolygon(),
344e6f63103SArmin Le Grand     mpRegionBand(),
345e6f63103SArmin Le Grand     mbIsNull(false)
346cdf0e10cSrcweir {
347e6f63103SArmin Le Grand 	DBG_CHKOBJ( &rPolygon, Polygon, NULL );
348cdf0e10cSrcweir 
349e6f63103SArmin Le Grand     if(rPolygon.GetSize())
350e6f63103SArmin Le Grand     {
351e6f63103SArmin Le Grand     	ImplCreatePolyPolyRegion(rPolygon);
352e6f63103SArmin Le Grand     }
353e6f63103SArmin Le Grand }
354cdf0e10cSrcweir 
Region(const PolyPolygon & rPolyPoly)355e6f63103SArmin Le Grand Region::Region(const PolyPolygon& rPolyPoly)
356e6f63103SArmin Le Grand :   mpB2DPolyPolygon(),
357e6f63103SArmin Le Grand     mpPolyPolygon(),
358e6f63103SArmin Le Grand     mpRegionBand(),
359e6f63103SArmin Le Grand     mbIsNull(false)
360cdf0e10cSrcweir {
361e6f63103SArmin Le Grand 	DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
362cdf0e10cSrcweir 
363e6f63103SArmin Le Grand     if(rPolyPoly.Count())
364e6f63103SArmin Le Grand     {
365e6f63103SArmin Le Grand     	ImplCreatePolyPolyRegion(rPolyPoly);
366e6f63103SArmin Le Grand     }
367cdf0e10cSrcweir }
368cdf0e10cSrcweir 
Region(const basegfx::B2DPolyPolygon & rPolyPoly)369e6f63103SArmin Le Grand Region::Region(const basegfx::B2DPolyPolygon& rPolyPoly)
370e6f63103SArmin Le Grand :   mpB2DPolyPolygon(),
371e6f63103SArmin Le Grand     mpPolyPolygon(),
372e6f63103SArmin Le Grand     mpRegionBand(),
373e6f63103SArmin Le Grand     mbIsNull(false)
374cdf0e10cSrcweir {
375e6f63103SArmin Le Grand 	DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
376cdf0e10cSrcweir 
377e6f63103SArmin Le Grand     if(rPolyPoly.count())
378e6f63103SArmin Le Grand     {
379e6f63103SArmin Le Grand     	ImplCreatePolyPolyRegion(rPolyPoly);
380e6f63103SArmin Le Grand     }
381cdf0e10cSrcweir }
382cdf0e10cSrcweir 
Region(const Region & rRegion)383e6f63103SArmin Le Grand Region::Region(const Region& rRegion)
384e6f63103SArmin Le Grand :   mpB2DPolyPolygon(rRegion.mpB2DPolyPolygon),
385e6f63103SArmin Le Grand     mpPolyPolygon(rRegion.mpPolyPolygon),
386e6f63103SArmin Le Grand     mpRegionBand(rRegion.mpRegionBand),
387e6f63103SArmin Le Grand     mbIsNull(rRegion.mbIsNull)
388cdf0e10cSrcweir {
389cdf0e10cSrcweir }
390cdf0e10cSrcweir 
~Region()391e6f63103SArmin Le Grand Region::~Region()
392cdf0e10cSrcweir {
393e6f63103SArmin Le Grand }
394cdf0e10cSrcweir 
ImplCreatePolyPolyRegion(const PolyPolygon & rPolyPoly)395e6f63103SArmin Le Grand void Region::ImplCreatePolyPolyRegion( const PolyPolygon& rPolyPoly )
396e6f63103SArmin Le Grand {
397e6f63103SArmin Le Grand 	const sal_uInt16 nPolyCount = rPolyPoly.Count();
398cdf0e10cSrcweir 
399e6f63103SArmin Le Grand     if(nPolyCount)
400cdf0e10cSrcweir 	{
401e6f63103SArmin Le Grand 		// polypolygon empty? -> empty region
402e6f63103SArmin Le Grand 		const Rectangle aRect(rPolyPoly.GetBoundRect());
403e6f63103SArmin Le Grand 
404e6f63103SArmin Le Grand 		if(!aRect.IsEmpty())
405e6f63103SArmin Le Grand 		{
406e6f63103SArmin Le Grand 			// width OR height == 1 ? => Rectangular region
407e6f63103SArmin Le Grand 			if((1 == aRect.GetWidth()) || (1 == aRect.GetHeight()) || rPolyPoly.IsRect())
408e6f63103SArmin Le Grand             {
409e6f63103SArmin Le Grand                 mpRegionBand.reset(new RegionBand(aRect));
410e6f63103SArmin Le Grand             }
411e6f63103SArmin Le Grand 			else
412e6f63103SArmin Le Grand             {
413e6f63103SArmin Le Grand                 mpPolyPolygon.reset(new PolyPolygon(rPolyPoly));
414e6f63103SArmin Le Grand             }
415cdf0e10cSrcweir 
416e6f63103SArmin Le Grand             mbIsNull = false;
417e6f63103SArmin Le Grand 		}
418cdf0e10cSrcweir 	}
419cdf0e10cSrcweir }
420cdf0e10cSrcweir 
ImplCreatePolyPolyRegion(const basegfx::B2DPolyPolygon & rPolyPoly)421e6f63103SArmin Le Grand void Region::ImplCreatePolyPolyRegion( const basegfx::B2DPolyPolygon& rPolyPoly )
422cdf0e10cSrcweir {
423e6f63103SArmin Le Grand     if(rPolyPoly.count() && !rPolyPoly.getB2DRange().isEmpty())
424e6f63103SArmin Le Grand     {
425e6f63103SArmin Le Grand         mpB2DPolyPolygon.reset(new basegfx::B2DPolyPolygon(rPolyPoly));
426e6f63103SArmin Le Grand         mbIsNull = false;
427e6f63103SArmin Le Grand     }
428e6f63103SArmin Le Grand }
429cdf0e10cSrcweir 
Move(long nHorzMove,long nVertMove)430e6f63103SArmin Le Grand void Region::Move( long nHorzMove, long nVertMove )
431e6f63103SArmin Le Grand {
432e6f63103SArmin Le Grand 	if(IsNull() || IsEmpty())
433e6f63103SArmin Le Grand     {
434e6f63103SArmin Le Grand         // empty or null need no move
435e6f63103SArmin Le Grand 		return;
436e6f63103SArmin Le Grand     }
437cdf0e10cSrcweir 
438e6f63103SArmin Le Grand     if(!nHorzMove && !nVertMove)
439e6f63103SArmin Le Grand     {
440e6f63103SArmin Le Grand         // no move defined
441e6f63103SArmin Le Grand         return;
442e6f63103SArmin Le Grand     }
443cdf0e10cSrcweir 
444e6f63103SArmin Le Grand     if(getB2DPolyPolygon())
445e6f63103SArmin Le Grand     {
446e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aPoly(*getB2DPolyPolygon());
447cdf0e10cSrcweir 
448e6f63103SArmin Le Grand         aPoly.transform(basegfx::tools::createTranslateB2DHomMatrix(nHorzMove, nVertMove));
449e6f63103SArmin Le Grand         mpB2DPolyPolygon.reset(aPoly.count() ? new basegfx::B2DPolyPolygon(aPoly) : 0);
450e6f63103SArmin Le Grand         mpPolyPolygon.reset();
451e6f63103SArmin Le Grand         mpRegionBand.reset();
452e6f63103SArmin Le Grand     }
453e6f63103SArmin Le Grand     else if(getPolyPolygon())
454e6f63103SArmin Le Grand     {
455e6f63103SArmin Le Grand         PolyPolygon aPoly(*getPolyPolygon());
456cdf0e10cSrcweir 
457e6f63103SArmin Le Grand     	aPoly.Move(nHorzMove, nVertMove);
458e6f63103SArmin Le Grand         mpB2DPolyPolygon.reset();
459e6f63103SArmin Le Grand         mpPolyPolygon.reset(aPoly.Count() ? new PolyPolygon(aPoly) : 0);
460e6f63103SArmin Le Grand         mpRegionBand.reset();
461e6f63103SArmin Le Grand     }
462e6f63103SArmin Le Grand     else if(getRegionBand())
463e6f63103SArmin Le Grand     {
464e6f63103SArmin Le Grand         RegionBand* pNew = new RegionBand(*getRegionBand());
465cdf0e10cSrcweir 
466e6f63103SArmin Le Grand         pNew->Move(nHorzMove, nVertMove);
467e6f63103SArmin Le Grand         mpB2DPolyPolygon.reset();
468e6f63103SArmin Le Grand         mpPolyPolygon.reset();
469e6f63103SArmin Le Grand         mpRegionBand.reset(pNew);
470e6f63103SArmin Le Grand     }
471e6f63103SArmin Le Grand     else
472e6f63103SArmin Le Grand     {
473e6f63103SArmin Le Grand         OSL_ENSURE(false, "Region::Move error: impossible combination (!)");
474e6f63103SArmin Le Grand     }
475cdf0e10cSrcweir }
476cdf0e10cSrcweir 
Scale(double fScaleX,double fScaleY)477e6f63103SArmin Le Grand void Region::Scale( double fScaleX, double fScaleY )
478cdf0e10cSrcweir {
479e6f63103SArmin Le Grand 	if(IsNull() || IsEmpty())
480e6f63103SArmin Le Grand     {
481e6f63103SArmin Le Grand         // empty or null need no scale
482e6f63103SArmin Le Grand 		return;
483e6f63103SArmin Le Grand     }
484cdf0e10cSrcweir 
485e6f63103SArmin Le Grand     if(basegfx::fTools::equalZero(fScaleX) && basegfx::fTools::equalZero(fScaleY))
486e6f63103SArmin Le Grand     {
487e6f63103SArmin Le Grand         // no scale defined
488e6f63103SArmin Le Grand         return;
489e6f63103SArmin Le Grand     }
490cdf0e10cSrcweir 
491e6f63103SArmin Le Grand     if(getB2DPolyPolygon())
492e6f63103SArmin Le Grand     {
493e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aPoly(*getB2DPolyPolygon());
494cdf0e10cSrcweir 
495e6f63103SArmin Le Grand         aPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fScaleX, fScaleY));
496e6f63103SArmin Le Grand         mpB2DPolyPolygon.reset(aPoly.count() ? new basegfx::B2DPolyPolygon(aPoly) : 0);
497e6f63103SArmin Le Grand         mpPolyPolygon.reset();
498e6f63103SArmin Le Grand         mpRegionBand.reset();
499e6f63103SArmin Le Grand     }
500e6f63103SArmin Le Grand     else if(getPolyPolygon())
501e6f63103SArmin Le Grand     {
502e6f63103SArmin Le Grand         PolyPolygon aPoly(*getPolyPolygon());
503cdf0e10cSrcweir 
504e6f63103SArmin Le Grand         aPoly.Scale(fScaleX, fScaleY);
505e6f63103SArmin Le Grand         mpB2DPolyPolygon.reset();
506e6f63103SArmin Le Grand         mpPolyPolygon.reset(aPoly.Count() ? new PolyPolygon(aPoly) : 0);
507e6f63103SArmin Le Grand         mpRegionBand.reset();
508e6f63103SArmin Le Grand     }
509e6f63103SArmin Le Grand     else if(getRegionBand())
510e6f63103SArmin Le Grand     {
511e6f63103SArmin Le Grand         RegionBand* pNew = new RegionBand(*getRegionBand());
512cdf0e10cSrcweir 
513e6f63103SArmin Le Grand         pNew->Scale(fScaleX, fScaleY);
514e6f63103SArmin Le Grand         mpB2DPolyPolygon.reset();
515e6f63103SArmin Le Grand         mpPolyPolygon.reset();
516e6f63103SArmin Le Grand         mpRegionBand.reset(pNew);
517e6f63103SArmin Le Grand     }
518e6f63103SArmin Le Grand     else
519e6f63103SArmin Le Grand     {
520e6f63103SArmin Le Grand         OSL_ENSURE(false, "Region::Scale error: impossible combination (!)");
521e6f63103SArmin Le Grand     }
522cdf0e10cSrcweir }
523cdf0e10cSrcweir 
Union(const Rectangle & rRect)524e6f63103SArmin Le Grand bool Region::Union( const Rectangle& rRect )
525cdf0e10cSrcweir {
526e6f63103SArmin Le Grand     if(rRect.IsEmpty())
527e6f63103SArmin Le Grand     {
528e6f63103SArmin Le Grand         // empty rectangle will not expand the existing union, nothing to do
529e6f63103SArmin Le Grand         return true;
530e6f63103SArmin Le Grand     }
531cdf0e10cSrcweir 
532e6f63103SArmin Le Grand     if(IsEmpty())
533e6f63103SArmin Le Grand     {
534e6f63103SArmin Le Grand         // no local data, the union will be equal to source. Create using rectangle
535e6f63103SArmin Le Grand         *this = rRect;
536e6f63103SArmin Le Grand         return true;
537e6f63103SArmin Le Grand     }
538cdf0e10cSrcweir 
539e6f63103SArmin Le Grand     if(HasPolyPolygonOrB2DPolyPolygon())
540e6f63103SArmin Le Grand     {
541e6f63103SArmin Le Grand         // get this B2DPolyPolygon, solve on polygon base
542e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
543e6f63103SArmin Le Grand 
544e6f63103SArmin Le Grand         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation(aThisPolyPoly);
545e6f63103SArmin Le Grand 
546e6f63103SArmin Le Grand         if(!aThisPolyPoly.count())
547e6f63103SArmin Le Grand         {
548e6f63103SArmin Le Grand             // no local polygon, use the rectangle as new region
549e6f63103SArmin Le Grand             *this = rRect;
550e6f63103SArmin Le Grand         }
551e6f63103SArmin Le Grand         else
552e6f63103SArmin Le Grand         {
553e6f63103SArmin Le Grand             // get the other B2DPolyPolygon and use logical Or-Operation
554e6f63103SArmin Le Grand             const basegfx::B2DPolygon aRectPoly(
555e6f63103SArmin Le Grand                 basegfx::tools::createPolygonFromRect(
556e6f63103SArmin Le Grand                     basegfx::B2DRectangle(
557e6f63103SArmin Le Grand                         rRect.Left(),
558e6f63103SArmin Le Grand                         rRect.Top(),
559e6f63103SArmin Le Grand                         rRect.Right(),
560e6f63103SArmin Le Grand                         rRect.Bottom())));
561e6f63103SArmin Le Grand             const basegfx::B2DPolyPolygon aClip(
562e6f63103SArmin Le Grand                 basegfx::tools::solvePolygonOperationOr(
563e6f63103SArmin Le Grand                     aThisPolyPoly,
564e6f63103SArmin Le Grand                     basegfx::B2DPolyPolygon(aRectPoly)));
565e6f63103SArmin Le Grand             *this = Region(aClip);
566e6f63103SArmin Le Grand         }
567cdf0e10cSrcweir 
568e6f63103SArmin Le Grand         return true;
569e6f63103SArmin Le Grand     }
570cdf0e10cSrcweir 
571e6f63103SArmin Le Grand     // only region band mode possibility left here or null/empty
572e6f63103SArmin Le Grand     const RegionBand* pCurrent = getRegionBand();
573cdf0e10cSrcweir 
574e6f63103SArmin Le Grand     if(!pCurrent)
575e6f63103SArmin Le Grand     {
576e6f63103SArmin Le Grand         // no region band, create using the rectangle
577e6f63103SArmin Le Grand         *this = rRect;
578e6f63103SArmin Le Grand         return true;
579e6f63103SArmin Le Grand     }
580cdf0e10cSrcweir 
581e6f63103SArmin Le Grand     RegionBand* pNew = new RegionBand(*pCurrent);
582e6f63103SArmin Le Grand 
583e6f63103SArmin Le Grand     // get justified rectangle
584e6f63103SArmin Le Grand     const long nLeft(std::min(rRect.Left(), rRect.Right()));
585e6f63103SArmin Le Grand     const long nTop(std::min(rRect.Top(), rRect.Bottom()));
586e6f63103SArmin Le Grand     const long nRight(std::max(rRect.Left(), rRect.Right()));
587e6f63103SArmin Le Grand     const long nBottom(std::max(rRect.Top(), rRect.Bottom()));
588cdf0e10cSrcweir 
589e6f63103SArmin Le Grand     // insert bands if the boundaries are not allready in the list
590e6f63103SArmin Le Grand     pNew->InsertBands(nTop, nBottom);
591cdf0e10cSrcweir 
592e6f63103SArmin Le Grand     // process union
593e6f63103SArmin Le Grand     pNew->Union(nLeft, nTop, nRight, nBottom);
594cdf0e10cSrcweir 
595e6f63103SArmin Le Grand     // cleanup
596e6f63103SArmin Le Grand     if(!pNew->OptimizeBandList())
597e6f63103SArmin Le Grand     {
598e6f63103SArmin Le Grand         delete pNew;
599e6f63103SArmin Le Grand         pNew = 0;
600e6f63103SArmin Le Grand     }
601cdf0e10cSrcweir 
602e6f63103SArmin Le Grand     mpRegionBand.reset(pNew);
603e6f63103SArmin Le Grand     return true;
604cdf0e10cSrcweir }
605cdf0e10cSrcweir 
Intersect(const Rectangle & rRect)606e6f63103SArmin Le Grand bool Region::Intersect( const Rectangle& rRect )
607cdf0e10cSrcweir {
608e6f63103SArmin Le Grand 	if ( rRect.IsEmpty() )
609cdf0e10cSrcweir 	{
610e6f63103SArmin Le Grand     	// empty rectangle will create empty region
611e6f63103SArmin Le Grand         SetEmpty();
612e6f63103SArmin Le Grand 		return true;
613e6f63103SArmin Le Grand 	}
614cdf0e10cSrcweir 
615e6f63103SArmin Le Grand     if(IsNull())
616e6f63103SArmin Le Grand     {
617e6f63103SArmin Le Grand         // null region (everything) intersect with rect will give rect
618e6f63103SArmin Le Grand         *this = rRect;
619e6f63103SArmin Le Grand         return true;
620e6f63103SArmin Le Grand     }
621cdf0e10cSrcweir 
622e6f63103SArmin Le Grand     if(IsEmpty())
623e6f63103SArmin Le Grand     {
624e6f63103SArmin Le Grand         // no content, cannot get more empty
625e6f63103SArmin Le Grand         return true;
626e6f63103SArmin Le Grand     }
627cdf0e10cSrcweir 
628e6f63103SArmin Le Grand     if(HasPolyPolygonOrB2DPolyPolygon())
629e6f63103SArmin Le Grand     {
630e6f63103SArmin Le Grand         // if polygon data prefer double precision, the other will be lost (if buffered)
631e6f63103SArmin Le Grand         if(getB2DPolyPolygon())
632e6f63103SArmin Le Grand         {
633e6f63103SArmin Le Grand             const basegfx::B2DPolyPolygon aPoly(
634e6f63103SArmin Le Grand                 basegfx::tools::clipPolyPolygonOnRange(
635e6f63103SArmin Le Grand                     *getB2DPolyPolygon(),
636e6f63103SArmin Le Grand                     basegfx::B2DRange(
637e6f63103SArmin Le Grand                         rRect.Left(),
638e6f63103SArmin Le Grand                         rRect.Top(),
639e6f63103SArmin Le Grand                         rRect.Right() + 1,
640e6f63103SArmin Le Grand                         rRect.Bottom() + 1),
641e6f63103SArmin Le Grand                     true,
642e6f63103SArmin Le Grand                     false));
643e6f63103SArmin Le Grand 
644e6f63103SArmin Le Grand             mpB2DPolyPolygon.reset(aPoly.count() ? new basegfx::B2DPolyPolygon(aPoly) : 0);
645e6f63103SArmin Le Grand             mpPolyPolygon.reset();
646e6f63103SArmin Le Grand             mpRegionBand.reset();
647e6f63103SArmin Le Grand         }
648e6f63103SArmin Le Grand         else // if(getPolyPolygon())
649e6f63103SArmin Le Grand         {
650e6f63103SArmin Le Grand             PolyPolygon aPoly(*getPolyPolygon());
651cdf0e10cSrcweir 
652e6f63103SArmin Le Grand             // use the PolyPolygon::Clip method for rectangles, this is
653e6f63103SArmin Le Grand             // fairly simple (does not even use GPC) and saves us from
654e6f63103SArmin Le Grand             // unnecessary banding
655e6f63103SArmin Le Grand             aPoly.Clip(rRect);
656cdf0e10cSrcweir 
657e6f63103SArmin Le Grand             mpB2DPolyPolygon.reset();
658e6f63103SArmin Le Grand             mpPolyPolygon.reset(aPoly.Count() ? new PolyPolygon(aPoly) : 0);
659e6f63103SArmin Le Grand             mpRegionBand.reset();
660e6f63103SArmin Le Grand         }
661cdf0e10cSrcweir 
662e6f63103SArmin Le Grand         return true;
663e6f63103SArmin Le Grand     }
664cdf0e10cSrcweir 
665e6f63103SArmin Le Grand     // only region band mode possibility left here or null/empty
666e6f63103SArmin Le Grand     const RegionBand* pCurrent = getRegionBand();
667cdf0e10cSrcweir 
668e6f63103SArmin Le Grand     if(!pCurrent)
669e6f63103SArmin Le Grand     {
670e6f63103SArmin Le Grand         // region is empty -> nothing to do!
671e6f63103SArmin Le Grand         return true;
672e6f63103SArmin Le Grand     }
673cdf0e10cSrcweir 
674e6f63103SArmin Le Grand     RegionBand* pNew = new RegionBand(*pCurrent);
675cdf0e10cSrcweir 
676e6f63103SArmin Le Grand     // get justified rectangle
677e6f63103SArmin Le Grand     const long nLeft(std::min(rRect.Left(), rRect.Right()));
678e6f63103SArmin Le Grand     const long nTop(std::min(rRect.Top(), rRect.Bottom()));
679e6f63103SArmin Le Grand     const long nRight(std::max(rRect.Left(), rRect.Right()));
680e6f63103SArmin Le Grand     const long nBottom(std::max(rRect.Top(), rRect.Bottom()));
681cdf0e10cSrcweir 
682e6f63103SArmin Le Grand     // insert bands if the boundaries are not allready in the list
683e6f63103SArmin Le Grand     pNew->InsertBands(nTop, nBottom);
684cdf0e10cSrcweir 
685e6f63103SArmin Le Grand     // process intersect
686e6f63103SArmin Le Grand     pNew->Intersect(nLeft, nTop, nRight, nBottom);
687cdf0e10cSrcweir 
688e6f63103SArmin Le Grand     // cleanup
689e6f63103SArmin Le Grand     if(!pNew->OptimizeBandList())
690e6f63103SArmin Le Grand     {
691e6f63103SArmin Le Grand         delete pNew;
692e6f63103SArmin Le Grand         pNew = 0;
693e6f63103SArmin Le Grand     }
694cdf0e10cSrcweir 
695e6f63103SArmin Le Grand     mpRegionBand.reset(pNew);
696e6f63103SArmin Le Grand     return true;
697cdf0e10cSrcweir }
698cdf0e10cSrcweir 
Exclude(const Rectangle & rRect)699e6f63103SArmin Le Grand bool Region::Exclude( const Rectangle& rRect )
700cdf0e10cSrcweir {
701e6f63103SArmin Le Grand 	if ( rRect.IsEmpty() )
702cdf0e10cSrcweir     {
703e6f63103SArmin Le Grand     	// excluding nothing will do no change
704e6f63103SArmin Le Grand 		return true;
705cdf0e10cSrcweir     }
706e6f63103SArmin Le Grand 
707e6f63103SArmin Le Grand     if(IsEmpty())
708cdf0e10cSrcweir     {
709e6f63103SArmin Le Grand         // cannot exclude from empty, done
710e6f63103SArmin Le Grand         return true;
711cdf0e10cSrcweir     }
712cdf0e10cSrcweir 
713e6f63103SArmin Le Grand     if(IsNull())
714e6f63103SArmin Le Grand     {
715e6f63103SArmin Le Grand         // error; cannnot exclude from null region since this is not representable
716e6f63103SArmin Le Grand         // in the data
717e6f63103SArmin Le Grand         OSL_ENSURE(false, "Region::Exclude error: Cannot exclude from null region (!)");
718e6f63103SArmin Le Grand         return true;
719e6f63103SArmin Le Grand     }
720cdf0e10cSrcweir 
721e6f63103SArmin Le Grand 	if( HasPolyPolygonOrB2DPolyPolygon() )
722cdf0e10cSrcweir 	{
723e6f63103SArmin Le Grand 	    // get this B2DPolyPolygon
724e6f63103SArmin Le Grand 	    basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
725e6f63103SArmin Le Grand 
726e6f63103SArmin Le Grand         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation(aThisPolyPoly);
727e6f63103SArmin Le Grand 
728e6f63103SArmin Le Grand 	    if(!aThisPolyPoly.count())
729e6f63103SArmin Le Grand         {
730e6f63103SArmin Le Grand             // when local polygon is empty, nothing can be excluded
731e6f63103SArmin Le Grand 	        return true;
732e6f63103SArmin Le Grand         }
733e6f63103SArmin Le Grand 
734e6f63103SArmin Le Grand 	    // get the other B2DPolyPolygon
735e6f63103SArmin Le Grand 	    const basegfx::B2DPolygon aRectPoly(
736e6f63103SArmin Le Grand             basegfx::tools::createPolygonFromRect(
737e6f63103SArmin Le Grand                 basegfx::B2DRectangle(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom())));
738e6f63103SArmin Le Grand 	    const basegfx::B2DPolyPolygon aOtherPolyPoly(aRectPoly);
739e6f63103SArmin Le Grand 	    const basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff(aThisPolyPoly, aOtherPolyPoly);
740cdf0e10cSrcweir 
741e6f63103SArmin Le Grand         *this = Region(aClip);
742cdf0e10cSrcweir 
743e6f63103SArmin Le Grand 	    return true;
744cdf0e10cSrcweir 	}
745cdf0e10cSrcweir 
746e6f63103SArmin Le Grand     // only region band mode possibility left here or null/empty
747e6f63103SArmin Le Grand     const RegionBand* pCurrent = getRegionBand();
748cdf0e10cSrcweir 
749e6f63103SArmin Le Grand     if(!pCurrent)
750e6f63103SArmin Le Grand     {
751e6f63103SArmin Le Grand         // empty? -> done!
752e6f63103SArmin Le Grand         return true;
753e6f63103SArmin Le Grand     }
754cdf0e10cSrcweir 
755e6f63103SArmin Le Grand     RegionBand* pNew = new RegionBand(*pCurrent);
756cdf0e10cSrcweir 
757e6f63103SArmin Le Grand     // get justified rectangle
758e6f63103SArmin Le Grand     const long nLeft(std::min(rRect.Left(), rRect.Right()));
759e6f63103SArmin Le Grand     const long nTop(std::min(rRect.Top(), rRect.Bottom()));
760e6f63103SArmin Le Grand     const long nRight(std::max(rRect.Left(), rRect.Right()));
761e6f63103SArmin Le Grand     const long nBottom(std::max(rRect.Top(), rRect.Bottom()));
762cdf0e10cSrcweir 
763e6f63103SArmin Le Grand     // insert bands if the boundaries are not allready in the list
764e6f63103SArmin Le Grand     pNew->InsertBands(nTop, nBottom);
765cdf0e10cSrcweir 
766e6f63103SArmin Le Grand     // process exclude
767e6f63103SArmin Le Grand     pNew->Exclude(nLeft, nTop, nRight, nBottom);
768cdf0e10cSrcweir 
769e6f63103SArmin Le Grand     // cleanup
770e6f63103SArmin Le Grand     if(!pNew->OptimizeBandList())
771e6f63103SArmin Le Grand     {
772e6f63103SArmin Le Grand         delete pNew;
773e6f63103SArmin Le Grand         pNew = 0;
774e6f63103SArmin Le Grand     }
775cdf0e10cSrcweir 
776e6f63103SArmin Le Grand     mpRegionBand.reset(pNew);
777e6f63103SArmin Le Grand     return true;
778cdf0e10cSrcweir }
779cdf0e10cSrcweir 
XOr(const Rectangle & rRect)780e6f63103SArmin Le Grand bool Region::XOr( const Rectangle& rRect )
781cdf0e10cSrcweir {
782cdf0e10cSrcweir 	if ( rRect.IsEmpty() )
783e6f63103SArmin Le Grand     {
784e6f63103SArmin Le Grand     	// empty rectangle will not change local content
785e6f63103SArmin Le Grand 		return true;
786e6f63103SArmin Le Grand     }
787cdf0e10cSrcweir 
788e6f63103SArmin Le Grand     if(IsEmpty())
789e6f63103SArmin Le Grand     {
790e6f63103SArmin Le Grand         // rRect will be the xored-form (local off, rect on)
791e6f63103SArmin Le Grand         *this = rRect;
792e6f63103SArmin Le Grand         return true;
793e6f63103SArmin Le Grand     }
794cdf0e10cSrcweir 
795e6f63103SArmin Le Grand     if(IsNull())
796e6f63103SArmin Le Grand     {
797e6f63103SArmin Le Grand         // error; cannnot exclude from null region since this is not representable
798e6f63103SArmin Le Grand         // in the data
799e6f63103SArmin Le Grand         OSL_ENSURE(false, "Region::XOr error: Cannot XOr with null region (!)");
800e6f63103SArmin Le Grand         return true;
801e6f63103SArmin Le Grand     }
802cdf0e10cSrcweir 
803e6f63103SArmin Le Grand     if( HasPolyPolygonOrB2DPolyPolygon() )
804cdf0e10cSrcweir 	{
805cdf0e10cSrcweir 	    // get this B2DPolyPolygon
806e6f63103SArmin Le Grand 	    basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
807e6f63103SArmin Le Grand 
808e6f63103SArmin Le Grand         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
809cdf0e10cSrcweir 
810e6f63103SArmin Le Grand 	    if(!aThisPolyPoly.count())
811cdf0e10cSrcweir 	    {
812e6f63103SArmin Le Grand             // no local content, XOr will be equal to rectangle
813cdf0e10cSrcweir 	        *this = rRect;
814cdf0e10cSrcweir 	        return true;
815cdf0e10cSrcweir 	    }
816e6f63103SArmin Le Grand 
817e6f63103SArmin Le Grand 	    // get the other B2DPolyPolygon
818e6f63103SArmin Le Grand 	    const basegfx::B2DPolygon aRectPoly(
819e6f63103SArmin Le Grand             basegfx::tools::createPolygonFromRect(
820e6f63103SArmin Le Grand                 basegfx::B2DRectangle(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom())));
821e6f63103SArmin Le Grand 	    const basegfx::B2DPolyPolygon aOtherPolyPoly(aRectPoly);
822e6f63103SArmin Le Grand 	    const basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor(aThisPolyPoly, aOtherPolyPoly);
823cdf0e10cSrcweir 
824e6f63103SArmin Le Grand         *this = Region(aClip);
825cdf0e10cSrcweir 
826e6f63103SArmin Le Grand 	    return true;
827cdf0e10cSrcweir 	}
828cdf0e10cSrcweir 
829e6f63103SArmin Le Grand     // only region band mode possibility left here or null/empty
830e6f63103SArmin Le Grand     const RegionBand* pCurrent = getRegionBand();
831cdf0e10cSrcweir 
832e6f63103SArmin Le Grand     if(!pCurrent)
833e6f63103SArmin Le Grand     {
834e6f63103SArmin Le Grand         // rRect will be the xored-form (local off, rect on)
835e6f63103SArmin Le Grand         *this = rRect;
836e6f63103SArmin Le Grand         return true;
837e6f63103SArmin Le Grand     }
838cdf0e10cSrcweir 
839e6f63103SArmin Le Grand     // only region band mode possibility left here or null/empty
840e6f63103SArmin Le Grand     RegionBand* pNew = new RegionBand(*getRegionBand());
841cdf0e10cSrcweir 
842e6f63103SArmin Le Grand     // get justified rectangle
843e6f63103SArmin Le Grand     const long nLeft(std::min(rRect.Left(), rRect.Right()));
844e6f63103SArmin Le Grand     const long nTop(std::min(rRect.Top(), rRect.Bottom()));
845e6f63103SArmin Le Grand     const long nRight(std::max(rRect.Left(), rRect.Right()));
846e6f63103SArmin Le Grand     const long nBottom(std::max(rRect.Top(), rRect.Bottom()));
847cdf0e10cSrcweir 
848e6f63103SArmin Le Grand     // insert bands if the boundaries are not allready in the list
849e6f63103SArmin Le Grand     pNew->InsertBands(nTop, nBottom);
850cdf0e10cSrcweir 
851e6f63103SArmin Le Grand     // process xor
852e6f63103SArmin Le Grand     pNew->XOr(nLeft, nTop, nRight, nBottom);
853cdf0e10cSrcweir 
854e6f63103SArmin Le Grand     // cleanup
855e6f63103SArmin Le Grand     if(!pNew->OptimizeBandList())
856e6f63103SArmin Le Grand     {
857e6f63103SArmin Le Grand         delete pNew;
858e6f63103SArmin Le Grand         pNew = 0;
859e6f63103SArmin Le Grand     }
860cdf0e10cSrcweir 
861e6f63103SArmin Le Grand     mpRegionBand.reset(pNew);
862e6f63103SArmin Le Grand     return true;
863cdf0e10cSrcweir }
864cdf0e10cSrcweir 
Union(const Region & rRegion)865e6f63103SArmin Le Grand bool Region::Union( const Region& rRegion )
866cdf0e10cSrcweir {
867e6f63103SArmin Le Grand     if(rRegion.IsEmpty())
868cdf0e10cSrcweir     {
869e6f63103SArmin Le Grand         // no extension at all
870e6f63103SArmin Le Grand         return true;
871cdf0e10cSrcweir     }
8724e8e704fSArmin Le Grand 
873e6f63103SArmin Le Grand     if(rRegion.IsNull())
874e6f63103SArmin Le Grand     {
875e6f63103SArmin Le Grand         // extending with null region -> null region
876e6f63103SArmin Le Grand         *this = Region(true);
877e6f63103SArmin Le Grand 	    return true;
878cdf0e10cSrcweir     }
879cdf0e10cSrcweir 
880e6f63103SArmin Le Grand     if(IsEmpty())
881e6f63103SArmin Le Grand     {
882e6f63103SArmin Le Grand         // local is empty, union will give source region
883e6f63103SArmin Le Grand         *this = rRegion;
884e6f63103SArmin Le Grand 	    return true;
885e6f63103SArmin Le Grand     }
886cdf0e10cSrcweir 
887e6f63103SArmin Le Grand     if(IsNull())
888e6f63103SArmin Le Grand     {
889e6f63103SArmin Le Grand         // already fully expanded (is null region), cannot be extended
890e6f63103SArmin Le Grand         return true;
891e6f63103SArmin Le Grand     }
892cdf0e10cSrcweir 
893e6f63103SArmin Le Grand 	if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() )
894cdf0e10cSrcweir 	{
895e6f63103SArmin Le Grand         // get this B2DPolyPolygon
896e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
897cdf0e10cSrcweir 
898e6f63103SArmin Le Grand         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation(aThisPolyPoly);
899e6f63103SArmin Le Grand 
900e6f63103SArmin Le Grand         if(!aThisPolyPoly.count())
901e6f63103SArmin Le Grand         {
902e6f63103SArmin Le Grand             // when no local content, union will be equal to rRegion
903e6f63103SArmin Le Grand             *this = rRegion;
904e6f63103SArmin Le Grand             return true;
905e6f63103SArmin Le Grand         }
906cdf0e10cSrcweir 
907e6f63103SArmin Le Grand         // get the other B2DPolyPolygon
908e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon());
909e6f63103SArmin Le Grand         aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation(aOtherPolyPoly);
910cdf0e10cSrcweir 
911e6f63103SArmin Le Grand         // use logical OR operation
912e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aClip(basegfx::tools::solvePolygonOperationOr(aThisPolyPoly, aOtherPolyPoly));
913e6f63103SArmin Le Grand 
914e6f63103SArmin Le Grand         *this = Region( aClip );
915e6f63103SArmin Le Grand 	    return true;
916cdf0e10cSrcweir 	}
917cdf0e10cSrcweir 
918e6f63103SArmin Le Grand     // only region band mode possibility left here or null/empty
919e6f63103SArmin Le Grand     const RegionBand* pCurrent = getRegionBand();
920cdf0e10cSrcweir 
921e6f63103SArmin Le Grand     if(!pCurrent)
922e6f63103SArmin Le Grand     {
923e6f63103SArmin Le Grand         // local is empty, union will give source region
924e6f63103SArmin Le Grand         *this = rRegion;
925e6f63103SArmin Le Grand 	    return true;
926e6f63103SArmin Le Grand     }
927cdf0e10cSrcweir 
928e6f63103SArmin Le Grand     const RegionBand* pSource = rRegion.getRegionBand();
929cdf0e10cSrcweir 
930e6f63103SArmin Le Grand     if(!pSource)
931e6f63103SArmin Le Grand     {
932e6f63103SArmin Le Grand         // no extension at all
933e6f63103SArmin Le Grand         return true;
934e6f63103SArmin Le Grand     }
935cdf0e10cSrcweir 
936e6f63103SArmin Le Grand     // prepare source and target
937e6f63103SArmin Le Grand     RegionBand* pNew = new RegionBand(*pCurrent);
938cdf0e10cSrcweir 
939e6f63103SArmin Le Grand     // union with source
940e6f63103SArmin Le Grand     pNew->Union(*pSource);
941cdf0e10cSrcweir 
942e6f63103SArmin Le Grand     // cleanup
943e6f63103SArmin Le Grand     if(!pNew->OptimizeBandList())
944e6f63103SArmin Le Grand     {
945e6f63103SArmin Le Grand         delete pNew;
946e6f63103SArmin Le Grand         pNew = 0;
947e6f63103SArmin Le Grand     }
948cdf0e10cSrcweir 
949e6f63103SArmin Le Grand     mpRegionBand.reset(pNew);
950e6f63103SArmin Le Grand     return true;
951cdf0e10cSrcweir }
952cdf0e10cSrcweir 
Intersect(const Region & rRegion)953e6f63103SArmin Le Grand bool Region::Intersect( const Region& rRegion )
954cdf0e10cSrcweir {
955e6f63103SArmin Le Grand     // same instance data? -> nothing to do!
956e6f63103SArmin Le Grand     if(getB2DPolyPolygon() && getB2DPolyPolygon() == rRegion.getB2DPolyPolygon())
957e6f63103SArmin Le Grand     {
958e6f63103SArmin Le Grand         return true;
959e6f63103SArmin Le Grand     }
960cdf0e10cSrcweir 
961e6f63103SArmin Le Grand     if(getPolyPolygon() && getPolyPolygon() == rRegion.getPolyPolygon())
962e6f63103SArmin Le Grand     {
963e6f63103SArmin Le Grand         return true;
964e6f63103SArmin Le Grand     }
965cdf0e10cSrcweir 
966e6f63103SArmin Le Grand     if(getRegionBand() && getRegionBand() == rRegion.getRegionBand())
967e6f63103SArmin Le Grand     {
968e6f63103SArmin Le Grand         return true;
969e6f63103SArmin Le Grand     }
970cdf0e10cSrcweir 
971e6f63103SArmin Le Grand     if(rRegion.IsNull())
972e6f63103SArmin Le Grand     {
973e6f63103SArmin Le Grand         // source region is null-region, intersect will not change local region
974e6f63103SArmin Le Grand         return true;
975e6f63103SArmin Le Grand     }
976cdf0e10cSrcweir 
977e6f63103SArmin Le Grand     if(IsNull())
978e6f63103SArmin Le Grand     {
979e6f63103SArmin Le Grand         // when local region is null-region, intersect will be equal to source
980e6f63103SArmin Le Grand         *this = rRegion;
981e6f63103SArmin Le Grand         return true;
982e6f63103SArmin Le Grand     }
983cdf0e10cSrcweir 
984e6f63103SArmin Le Grand 	if(rRegion.IsEmpty())
985cdf0e10cSrcweir 	{
986e6f63103SArmin Le Grand         // source region is empty, intersection will always be empty
987e6f63103SArmin Le Grand         SetEmpty();
988e6f63103SArmin Le Grand 		return true;
989cdf0e10cSrcweir 	}
990cdf0e10cSrcweir 
991e6f63103SArmin Le Grand     if(IsEmpty())
992cdf0e10cSrcweir     {
993e6f63103SArmin Le Grand         // local region is empty, cannot get more emty than that. Nothing to do
994e6f63103SArmin Le Grand         return true;
995cdf0e10cSrcweir     }
996cdf0e10cSrcweir 
997e6f63103SArmin Le Grand     if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() )
998e6f63103SArmin Le Grand 	{
999e6f63103SArmin Le Grand         // get this B2DPolyPolygon
1000e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
1001cdf0e10cSrcweir 
1002e6f63103SArmin Le Grand         if(!aThisPolyPoly.count())
1003e6f63103SArmin Le Grand         {
1004e6f63103SArmin Le Grand             // local region is empty, cannot get more emty than that. Nothing to do
1005e6f63103SArmin Le Grand             return true;
1006e6f63103SArmin Le Grand         }
1007cdf0e10cSrcweir 
1008e6f63103SArmin Le Grand         // get the other B2DPolyPolygon
1009e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon());
1010e6f63103SArmin Le Grand 
1011e6f63103SArmin Le Grand         if(!aOtherPolyPoly.count())
1012e6f63103SArmin Le Grand         {
1013e6f63103SArmin Le Grand             // source region is empty, intersection will always be empty
1014e6f63103SArmin Le Grand             SetEmpty();
1015e6f63103SArmin Le Grand 		    return true;
1016e6f63103SArmin Le Grand         }
1017e6f63103SArmin Le Grand 
1018e6f63103SArmin Le Grand         const basegfx::B2DPolyPolygon aClip(
1019e6f63103SArmin Le Grand             basegfx::tools::clipPolyPolygonOnPolyPolygon(
1020e6f63103SArmin Le Grand                 aOtherPolyPoly,
1021e6f63103SArmin Le Grand                 aThisPolyPoly,
1022e6f63103SArmin Le Grand                 true,
1023e6f63103SArmin Le Grand                 false));
1024e6f63103SArmin Le Grand         *this = Region( aClip );
1025e6f63103SArmin Le Grand 	    return true;
1026cdf0e10cSrcweir 	}
1027cdf0e10cSrcweir 
1028e6f63103SArmin Le Grand     // only region band mode possibility left here or null/empty
1029e6f63103SArmin Le Grand     const RegionBand* pCurrent = getRegionBand();
1030cdf0e10cSrcweir 
1031e6f63103SArmin Le Grand     if(!pCurrent)
1032e6f63103SArmin Le Grand     {
1033e6f63103SArmin Le Grand         // local region is empty, cannot get more emty than that. Nothing to do
1034e6f63103SArmin Le Grand         return true;
1035e6f63103SArmin Le Grand     }
1036cdf0e10cSrcweir 
1037e6f63103SArmin Le Grand     const RegionBand* pSource = rRegion.getRegionBand();
1038cdf0e10cSrcweir 
1039e6f63103SArmin Le Grand     if(!pSource)
1040e6f63103SArmin Le Grand     {
1041e6f63103SArmin Le Grand         // source region is empty, intersection will always be empty
1042e6f63103SArmin Le Grand         SetEmpty();
1043e6f63103SArmin Le Grand 		return true;
1044e6f63103SArmin Le Grand     }
1045cdf0e10cSrcweir 
1046e6f63103SArmin Le Grand     // both RegionBands exist and are not empty
1047e6f63103SArmin Le Grand     if(pCurrent->getRectangleCount() + 2 < pSource->getRectangleCount())
1048e6f63103SArmin Le Grand     {
1049e6f63103SArmin Le Grand         // when we have less rectangles, turn around the call
1050e6f63103SArmin Le Grand         Region aTempRegion = rRegion;
1051e6f63103SArmin Le Grand         aTempRegion.Intersect( *this );
1052e6f63103SArmin Le Grand         *this = aTempRegion;
1053e6f63103SArmin Le Grand     }
1054e6f63103SArmin Le Grand     else
1055e6f63103SArmin Le Grand     {
1056e6f63103SArmin Le Grand         // prepare new regionBand
1057e6f63103SArmin Le Grand         RegionBand* pNew = pCurrent ? new RegionBand(*pCurrent) : new RegionBand();
1058cdf0e10cSrcweir 
1059e6f63103SArmin Le Grand         // intersect with source
1060e6f63103SArmin Le Grand         pNew->Intersect(*pSource);
1061cdf0e10cSrcweir 
1062e6f63103SArmin Le Grand         // cleanup
1063e6f63103SArmin Le Grand         if(!pNew->OptimizeBandList())
1064e6f63103SArmin Le Grand         {
1065e6f63103SArmin Le Grand             delete pNew;
1066e6f63103SArmin Le Grand             pNew = 0;
1067e6f63103SArmin Le Grand         }
1068cdf0e10cSrcweir 
1069e6f63103SArmin Le Grand         mpRegionBand.reset(pNew);
1070e6f63103SArmin Le Grand     }
1071cdf0e10cSrcweir 
1072e6f63103SArmin Le Grand     return true;
1073cdf0e10cSrcweir }
1074cdf0e10cSrcweir 
Exclude(const Region & rRegion)1075e6f63103SArmin Le Grand bool Region::Exclude( const Region& rRegion )
1076cdf0e10cSrcweir {
1077e6f63103SArmin Le Grand 	if ( rRegion.IsEmpty() )
1078cdf0e10cSrcweir     {
1079e6f63103SArmin Le Grand     	// excluding nothing will do no change
1080e6f63103SArmin Le Grand 		return true;
1081cdf0e10cSrcweir     }
1082cdf0e10cSrcweir 
1083e6f63103SArmin Le Grand 	if ( rRegion.IsNull() )
1084e6f63103SArmin Le Grand     {
1085e6f63103SArmin Le Grand     	// excluding everything will create empty region
1086e6f63103SArmin Le Grand         SetEmpty();
1087e6f63103SArmin Le Grand 		return true;
1088e6f63103SArmin Le Grand     }
1089cdf0e10cSrcweir 
1090e6f63103SArmin Le Grand     if(IsEmpty())
1091e6f63103SArmin Le Grand     {
1092e6f63103SArmin Le Grand         // cannot exclude from empty, done
1093e6f63103SArmin Le Grand         return true;
1094e6f63103SArmin Le Grand     }
1095cdf0e10cSrcweir 
1096e6f63103SArmin Le Grand     if(IsNull())
1097e6f63103SArmin Le Grand     {
1098e6f63103SArmin Le Grand         // error; cannnot exclude from null region since this is not representable
1099e6f63103SArmin Le Grand         // in the data
1100e6f63103SArmin Le Grand         OSL_ENSURE(false, "Region::Exclude error: Cannot exclude from null region (!)");
1101e6f63103SArmin Le Grand         return true;
1102e6f63103SArmin Le Grand     }
1103cdf0e10cSrcweir 
1104e6f63103SArmin Le Grand 	if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() )
1105e6f63103SArmin Le Grand 	{
1106e6f63103SArmin Le Grand         // get this B2DPolyPolygon
1107e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
1108cdf0e10cSrcweir 
1109e6f63103SArmin Le Grand         if(!aThisPolyPoly.count())
1110e6f63103SArmin Le Grand         {
1111e6f63103SArmin Le Grand             // cannot exclude from empty, done
1112e6f63103SArmin Le Grand             return true;
1113e6f63103SArmin Le Grand         }
1114cdf0e10cSrcweir 
1115e6f63103SArmin Le Grand         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
1116cdf0e10cSrcweir 
1117e6f63103SArmin Le Grand         // get the other B2DPolyPolygon
1118e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon());
1119e6f63103SArmin Le Grand         aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly );
1120e6f63103SArmin Le Grand 
1121e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff( aThisPolyPoly, aOtherPolyPoly );
1122e6f63103SArmin Le Grand         *this = Region( aClip );
1123e6f63103SArmin Le Grand 	    return true;
1124cdf0e10cSrcweir 	}
1125cdf0e10cSrcweir 
1126e6f63103SArmin Le Grand     // only region band mode possibility left here or null/empty
1127e6f63103SArmin Le Grand     const RegionBand* pCurrent = getRegionBand();
1128cdf0e10cSrcweir 
1129e6f63103SArmin Le Grand     if(!pCurrent)
1130e6f63103SArmin Le Grand     {
1131e6f63103SArmin Le Grand         // cannot exclude from empty, done
1132e6f63103SArmin Le Grand         return true;
1133e6f63103SArmin Le Grand     }
1134cdf0e10cSrcweir 
1135e6f63103SArmin Le Grand     const RegionBand* pSource = rRegion.getRegionBand();
1136cdf0e10cSrcweir 
1137e6f63103SArmin Le Grand     if(!pSource)
1138e6f63103SArmin Le Grand     {
1139e6f63103SArmin Le Grand     	// excluding nothing will do no change
1140e6f63103SArmin Le Grand 		return true;
1141e6f63103SArmin Le Grand     }
1142cdf0e10cSrcweir 
1143e6f63103SArmin Le Grand     // prepare source and target
1144e6f63103SArmin Le Grand     RegionBand* pNew = new RegionBand(*pCurrent);
1145cdf0e10cSrcweir 
1146e6f63103SArmin Le Grand     // union with source
1147e6f63103SArmin Le Grand     const bool bSuccess(pNew->Exclude(*pSource));
1148cdf0e10cSrcweir 
1149e6f63103SArmin Le Grand     // cleanup
1150e6f63103SArmin Le Grand     if(!bSuccess)
1151e6f63103SArmin Le Grand     {
1152e6f63103SArmin Le Grand         delete pNew;
1153e6f63103SArmin Le Grand         pNew = 0;
1154e6f63103SArmin Le Grand     }
1155cdf0e10cSrcweir 
1156e6f63103SArmin Le Grand     mpRegionBand.reset(pNew);
1157e6f63103SArmin Le Grand 	return true;
1158cdf0e10cSrcweir }
1159cdf0e10cSrcweir 
XOr(const Region & rRegion)1160e6f63103SArmin Le Grand bool Region::XOr( const Region& rRegion )
1161cdf0e10cSrcweir {
1162e6f63103SArmin Le Grand 	if ( rRegion.IsEmpty() )
1163e6f63103SArmin Le Grand     {
1164e6f63103SArmin Le Grand     	// empty region will not change local content
1165e6f63103SArmin Le Grand 		return true;
1166e6f63103SArmin Le Grand     }
1167cdf0e10cSrcweir 
1168e6f63103SArmin Le Grand 	if ( rRegion.IsNull() )
1169e6f63103SArmin Le Grand     {
1170e6f63103SArmin Le Grand         // error; cannnot exclude null region from local since this is not representable
1171e6f63103SArmin Le Grand         // in the data
1172e6f63103SArmin Le Grand         OSL_ENSURE(false, "Region::XOr error: Cannot XOr with null region (!)");
1173e6f63103SArmin Le Grand 		return true;
1174e6f63103SArmin Le Grand     }
1175cdf0e10cSrcweir 
1176e6f63103SArmin Le Grand     if(IsEmpty())
1177e6f63103SArmin Le Grand     {
1178e6f63103SArmin Le Grand         // rRect will be the xored-form (local off, rect on)
1179e6f63103SArmin Le Grand         *this = rRegion;
1180e6f63103SArmin Le Grand         return true;
1181e6f63103SArmin Le Grand     }
1182cdf0e10cSrcweir 
1183e6f63103SArmin Le Grand     if(IsNull())
1184e6f63103SArmin Le Grand     {
1185e6f63103SArmin Le Grand         // error; cannnot exclude from null region since this is not representable
1186e6f63103SArmin Le Grand         // in the data
1187e6f63103SArmin Le Grand         OSL_ENSURE(false, "Region::XOr error: Cannot XOr with null region (!)");
1188e6f63103SArmin Le Grand         return false;
1189e6f63103SArmin Le Grand     }
1190cdf0e10cSrcweir 
1191e6f63103SArmin Le Grand     if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() )
1192cdf0e10cSrcweir 	{
1193e6f63103SArmin Le Grand         // get this B2DPolyPolygon
1194e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
1195cdf0e10cSrcweir 
1196e6f63103SArmin Le Grand         if(!aThisPolyPoly.count())
1197e6f63103SArmin Le Grand         {
1198e6f63103SArmin Le Grand             // rRect will be the xored-form (local off, rect on)
1199e6f63103SArmin Le Grand             *this = rRegion;
1200e6f63103SArmin Le Grand             return true;
1201e6f63103SArmin Le Grand         }
1202cdf0e10cSrcweir 
1203e6f63103SArmin Le Grand         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
1204cdf0e10cSrcweir 
1205e6f63103SArmin Le Grand         // get the other B2DPolyPolygon
1206e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon());
1207e6f63103SArmin Le Grand         aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly );
1208e6f63103SArmin Le Grand 
1209e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor( aThisPolyPoly, aOtherPolyPoly );
1210e6f63103SArmin Le Grand         *this = Region( aClip );
1211e6f63103SArmin Le Grand 	    return true;
1212cdf0e10cSrcweir 	}
1213cdf0e10cSrcweir 
1214e6f63103SArmin Le Grand     // only region band mode possibility left here or null/empty
1215e6f63103SArmin Le Grand     const RegionBand* pCurrent = getRegionBand();
1216cdf0e10cSrcweir 
1217e6f63103SArmin Le Grand     if(!pCurrent)
1218cdf0e10cSrcweir     {
1219e6f63103SArmin Le Grand         // rRect will be the xored-form (local off, rect on)
1220e6f63103SArmin Le Grand         *this = rRegion;
1221e6f63103SArmin Le Grand         return true;
1222cdf0e10cSrcweir     }
1223cdf0e10cSrcweir 
1224e6f63103SArmin Le Grand     const RegionBand* pSource = rRegion.getRegionBand();
1225cdf0e10cSrcweir 
1226e6f63103SArmin Le Grand     if(!pSource)
1227cdf0e10cSrcweir     {
1228e6f63103SArmin Le Grand     	// empty region will not change local content
1229e6f63103SArmin Le Grand 		return true;
1230cdf0e10cSrcweir     }
1231cdf0e10cSrcweir 
1232e6f63103SArmin Le Grand     // prepare source and target
1233e6f63103SArmin Le Grand     RegionBand* pNew = new RegionBand(*pCurrent);
1234cdf0e10cSrcweir 
1235e6f63103SArmin Le Grand     // union with source
1236e6f63103SArmin Le Grand     pNew->XOr(*pSource);
1237cdf0e10cSrcweir 
1238e6f63103SArmin Le Grand     // cleanup
1239e6f63103SArmin Le Grand     if(!pNew->OptimizeBandList())
1240e6f63103SArmin Le Grand     {
1241e6f63103SArmin Le Grand         delete pNew;
1242e6f63103SArmin Le Grand         pNew = 0;
1243e6f63103SArmin Le Grand     }
1244cdf0e10cSrcweir 
1245e6f63103SArmin Le Grand     mpRegionBand.reset(pNew);
1246cdf0e10cSrcweir 
1247e6f63103SArmin Le Grand 	return true;
1248cdf0e10cSrcweir }
1249cdf0e10cSrcweir 
GetBoundRect() const1250cdf0e10cSrcweir Rectangle Region::GetBoundRect() const
1251cdf0e10cSrcweir {
1252e6f63103SArmin Le Grand 	if(IsEmpty())
1253e6f63103SArmin Le Grand     {
1254e6f63103SArmin Le Grand     	// no internal data? -> region is empty!
1255e6f63103SArmin Le Grand 		return Rectangle();
1256e6f63103SArmin Le Grand     }
1257cdf0e10cSrcweir 
1258e6f63103SArmin Le Grand 	if(IsNull())
1259e6f63103SArmin Le Grand     {
1260e6f63103SArmin Le Grand         // error; null region has no BoundRect
1261e6f63103SArmin Le Grand         // OSL_ENSURE(false, "Region::GetBoundRect error: null region has unlimitied bound rect, not representable (!)");
1262e6f63103SArmin Le Grand 		return Rectangle();
1263e6f63103SArmin Le Grand     }
1264cdf0e10cSrcweir 
1265e6f63103SArmin Le Grand     // prefer double precision source
1266e6f63103SArmin Le Grand 	if(getB2DPolyPolygon())
1267cdf0e10cSrcweir 	{
1268e6f63103SArmin Le Grand 		const basegfx::B2DRange aRange(basegfx::tools::getRange(*getB2DPolyPolygon()));
12694e8e704fSArmin Le Grand 
12704e8e704fSArmin Le Grand         if(aRange.isEmpty())
12714e8e704fSArmin Le Grand         {
12724e8e704fSArmin Le Grand             // emulate PolyPolygon::GetBoundRect() when empty polygon
12734e8e704fSArmin Le Grand             return Rectangle();
12744e8e704fSArmin Le Grand         }
12754e8e704fSArmin Le Grand         else
12764e8e704fSArmin Le Grand         {
1277*d8ed516eSArmin Le Grand             // #122149# corrected rounding, no need for ceil() and floor() here
12784e8e704fSArmin Le Grand             return Rectangle(
1279*d8ed516eSArmin Le Grand                 basegfx::fround(aRange.getMinX()), basegfx::fround(aRange.getMinY()),
1280*d8ed516eSArmin Le Grand                 basegfx::fround(aRange.getMaxX()), basegfx::fround(aRange.getMaxY()));
12814e8e704fSArmin Le Grand         }
1282cdf0e10cSrcweir 	}
1283cdf0e10cSrcweir 
1284e6f63103SArmin Le Grand 	if(getPolyPolygon())
1285e6f63103SArmin Le Grand     {
1286e6f63103SArmin Le Grand 		return getPolyPolygon()->GetBoundRect();
1287e6f63103SArmin Le Grand     }
1288cdf0e10cSrcweir 
1289e6f63103SArmin Le Grand     if(getRegionBand())
1290e6f63103SArmin Le Grand     {
1291e6f63103SArmin Le Grand         return getRegionBand()->GetBoundRect();
1292e6f63103SArmin Le Grand     }
1293cdf0e10cSrcweir 
1294e6f63103SArmin Le Grand 	return Rectangle();
1295cdf0e10cSrcweir }
1296cdf0e10cSrcweir 
GetAsPolyPolygon() const1297e6f63103SArmin Le Grand const PolyPolygon Region::GetAsPolyPolygon() const
1298cdf0e10cSrcweir {
1299e6f63103SArmin Le Grand     if(getPolyPolygon())
1300e6f63103SArmin Le Grand     {
1301e6f63103SArmin Le Grand         return *getPolyPolygon();
1302e6f63103SArmin Le Grand     }
1303cdf0e10cSrcweir 
1304e6f63103SArmin Le Grand     if(getB2DPolyPolygon())
1305e6f63103SArmin Le Grand     {
1306e6f63103SArmin Le Grand         // the polygon needs to be converted, buffer the down converion
1307e6f63103SArmin Le Grand         const PolyPolygon aPolyPolgon(*getB2DPolyPolygon());
1308e6f63103SArmin Le Grand         const_cast< Region* >(this)->mpPolyPolygon.reset(new PolyPolygon(aPolyPolgon));
1309cdf0e10cSrcweir 
1310e6f63103SArmin Le Grand         return *getPolyPolygon();
1311e6f63103SArmin Le Grand     }
1312cdf0e10cSrcweir 
1313e6f63103SArmin Le Grand     if(getRegionBand())
1314e6f63103SArmin Le Grand     {
1315e6f63103SArmin Le Grand         // the BandRegion needs to be converted, buffer the converion
1316e6f63103SArmin Le Grand         const PolyPolygon aPolyPolgon(ImplCreatePolyPolygonFromRegionBand());
1317e6f63103SArmin Le Grand         const_cast< Region* >(this)->mpPolyPolygon.reset(new PolyPolygon(aPolyPolgon));
1318cdf0e10cSrcweir 
1319e6f63103SArmin Le Grand         return *getPolyPolygon();
1320e6f63103SArmin Le Grand     }
1321cdf0e10cSrcweir 
1322e6f63103SArmin Le Grand     return PolyPolygon();
1323cdf0e10cSrcweir }
1324cdf0e10cSrcweir 
GetAsB2DPolyPolygon() const1325e6f63103SArmin Le Grand const basegfx::B2DPolyPolygon Region::GetAsB2DPolyPolygon() const
1326cdf0e10cSrcweir {
1327e6f63103SArmin Le Grand     if(getB2DPolyPolygon())
1328e6f63103SArmin Le Grand     {
1329e6f63103SArmin Le Grand         return *getB2DPolyPolygon();
1330e6f63103SArmin Le Grand     }
1331cdf0e10cSrcweir 
1332e6f63103SArmin Le Grand     if(getPolyPolygon())
1333e6f63103SArmin Le Grand     {
1334e6f63103SArmin Le Grand         // the polygon needs to be converted, buffer the up conversion. This will be preferred from now.
1335e6f63103SArmin Le Grand         const basegfx::B2DPolyPolygon aB2DPolyPolygon(getPolyPolygon()->getB2DPolyPolygon());
1336e6f63103SArmin Le Grand         const_cast< Region* >(this)->mpB2DPolyPolygon.reset(new basegfx::B2DPolyPolygon(aB2DPolyPolygon));
1337cdf0e10cSrcweir 
1338e6f63103SArmin Le Grand         return *getB2DPolyPolygon();
1339e6f63103SArmin Le Grand     }
1340cdf0e10cSrcweir 
1341e6f63103SArmin Le Grand     if(getRegionBand())
1342e6f63103SArmin Le Grand     {
1343e6f63103SArmin Le Grand         // the BandRegion needs to be converted, buffer the converion
1344e6f63103SArmin Le Grand         const basegfx::B2DPolyPolygon aB2DPolyPolygon(ImplCreateB2DPolyPolygonFromRegionBand());
1345e6f63103SArmin Le Grand         const_cast< Region* >(this)->mpB2DPolyPolygon.reset(new basegfx::B2DPolyPolygon(aB2DPolyPolygon));
1346cdf0e10cSrcweir 
1347e6f63103SArmin Le Grand         return *getB2DPolyPolygon();
1348e6f63103SArmin Le Grand     }
1349cdf0e10cSrcweir 
1350e6f63103SArmin Le Grand     return basegfx::B2DPolyPolygon();
1351cdf0e10cSrcweir }
1352cdf0e10cSrcweir 
GetAsRegionBand() const1353e6f63103SArmin Le Grand const RegionBand* Region::GetAsRegionBand() const
1354cdf0e10cSrcweir {
1355e6f63103SArmin Le Grand     if(!getRegionBand())
1356e6f63103SArmin Le Grand     {
1357e6f63103SArmin Le Grand         if(getB2DPolyPolygon())
1358e6f63103SArmin Le Grand         {
1359e6f63103SArmin Le Grand             // convert B2DPolyPolygon to RegionBand, buffer it and return it
1360e6f63103SArmin Le Grand             const_cast< Region* >(this)->mpRegionBand.reset(ImplCreateRegionBandFromPolyPolygon(PolyPolygon(*getB2DPolyPolygon())));
1361e6f63103SArmin Le Grand         }
1362e6f63103SArmin Le Grand         else if(getPolyPolygon())
1363e6f63103SArmin Le Grand         {
1364e6f63103SArmin Le Grand             // convert B2DPolyPolygon to RegionBand, buffer it and return it
1365e6f63103SArmin Le Grand             const_cast< Region* >(this)->mpRegionBand.reset(ImplCreateRegionBandFromPolyPolygon(*getPolyPolygon()));
1366e6f63103SArmin Le Grand         }
1367e6f63103SArmin Le Grand     }
1368cdf0e10cSrcweir 
1369e6f63103SArmin Le Grand     return getRegionBand();
1370cdf0e10cSrcweir }
1371cdf0e10cSrcweir 
IsInside(const Point & rPoint) const1372e6f63103SArmin Le Grand bool Region::IsInside( const Point& rPoint ) const
1373cdf0e10cSrcweir {
1374e6f63103SArmin Le Grand 	if(IsEmpty())
1375e6f63103SArmin Le Grand     {
1376e6f63103SArmin Le Grand         // no point can be in empty region
1377cdf0e10cSrcweir 		return false;
1378e6f63103SArmin Le Grand     }
1379cdf0e10cSrcweir 
1380e6f63103SArmin Le Grand     if(IsNull())
1381e6f63103SArmin Le Grand     {
1382e6f63103SArmin Le Grand         // all points are inside null-region
1383e6f63103SArmin Le Grand         return true;
1384e6f63103SArmin Le Grand     }
1385cdf0e10cSrcweir 
1386e6f63103SArmin Le Grand     // Too expensive (?)
1387e6f63103SArmin Le Grand 	//if(mpImplRegion->getRegionPolyPoly())
1388e6f63103SArmin Le Grand     //{
1389e6f63103SArmin Le Grand 	//	return mpImplRegion->getRegionPolyPoly()->IsInside( rPoint );
1390e6f63103SArmin Le Grand     //}
1391cdf0e10cSrcweir 
1392e6f63103SArmin Le Grand     // ensure RegionBand existance
1393169773a2SArmin Le Grand     const RegionBand* pRegionBand = GetAsRegionBand();
1394cdf0e10cSrcweir 
1395e6f63103SArmin Le Grand     if(pRegionBand)
1396e6f63103SArmin Le Grand     {
1397e6f63103SArmin Le Grand         return pRegionBand->IsInside(rPoint);
1398e6f63103SArmin Le Grand     }
1399cdf0e10cSrcweir 
1400e6f63103SArmin Le Grand     return false;
1401cdf0e10cSrcweir }
1402cdf0e10cSrcweir 
IsInside(const Rectangle & rRect) const1403e6f63103SArmin Le Grand bool Region::IsInside( const Rectangle& rRect ) const
1404cdf0e10cSrcweir {
1405e6f63103SArmin Le Grand 	if(IsEmpty())
1406e6f63103SArmin Le Grand     {
1407e6f63103SArmin Le Grand         // no rectangle can be in empty region
1408e6f63103SArmin Le Grand 		return false;
1409e6f63103SArmin Le Grand     }
1410cdf0e10cSrcweir 
1411e6f63103SArmin Le Grand     if(IsNull())
1412e6f63103SArmin Le Grand     {
1413e6f63103SArmin Le Grand         // rectangle always inside null-region
1414e6f63103SArmin Le Grand         return true;
1415e6f63103SArmin Le Grand     }
1416cdf0e10cSrcweir 
1417e6f63103SArmin Le Grand 	if ( rRect.IsEmpty() )
1418e6f63103SArmin Le Grand     {
1419e6f63103SArmin Le Grand         // is rectangle empty? -> not inside
1420e6f63103SArmin Le Grand 		return false;
1421e6f63103SArmin Le Grand     }
1422cdf0e10cSrcweir 
1423cdf0e10cSrcweir 	// create region from rectangle and intersect own region
1424e6f63103SArmin Le Grand 	Region aRegion(rRect);
1425e6f63103SArmin Le Grand 	aRegion.Exclude(*this);
1426cdf0e10cSrcweir 
1427cdf0e10cSrcweir 	// rectangle is inside if exclusion is empty
1428cdf0e10cSrcweir 	return aRegion.IsEmpty();
1429cdf0e10cSrcweir }
1430cdf0e10cSrcweir 
1431cdf0e10cSrcweir // -----------------------------------------------------------------------
1432cdf0e10cSrcweir 
IsOver(const Rectangle & rRect) const1433e6f63103SArmin Le Grand bool Region::IsOver( const Rectangle& rRect ) const
1434cdf0e10cSrcweir {
1435e6f63103SArmin Le Grand 	if(IsEmpty())
1436e6f63103SArmin Le Grand     {
1437e6f63103SArmin Le Grand         // nothing can be over something empty
1438e6f63103SArmin Le Grand 		return false;
1439e6f63103SArmin Le Grand     }
1440cdf0e10cSrcweir 
1441e6f63103SArmin Le Grand     if(IsNull())
1442e6f63103SArmin Le Grand     {
1443e6f63103SArmin Le Grand         // everything is over null region
1444e6f63103SArmin Le Grand         return true;
1445e6f63103SArmin Le Grand     }
1446cdf0e10cSrcweir 
1447cdf0e10cSrcweir 	// Can we optimize this ??? - is used in StarDraw for brushes pointers
1448cdf0e10cSrcweir 	// Why we have no IsOver for Regions ???
1449cdf0e10cSrcweir 	// create region from rectangle and intersect own region
1450e6f63103SArmin Le Grand 	Region aRegion(rRect);
1451cdf0e10cSrcweir 	aRegion.Intersect( *this );
1452cdf0e10cSrcweir 
1453cdf0e10cSrcweir 	// rectangle is over if include is not empty
1454cdf0e10cSrcweir 	return !aRegion.IsEmpty();
1455cdf0e10cSrcweir }
1456cdf0e10cSrcweir 
SetNull()1457cdf0e10cSrcweir void Region::SetNull()
1458cdf0e10cSrcweir {
1459e6f63103SArmin Le Grand 	// reset all content
1460e6f63103SArmin Le Grand     mpB2DPolyPolygon.reset();
1461e6f63103SArmin Le Grand     mpPolyPolygon.reset();
1462e6f63103SArmin Le Grand     mpRegionBand.reset();
1463e6f63103SArmin Le Grand     mbIsNull = true;
1464cdf0e10cSrcweir }
1465cdf0e10cSrcweir 
SetEmpty()1466cdf0e10cSrcweir void Region::SetEmpty()
1467cdf0e10cSrcweir {
1468e6f63103SArmin Le Grand 	// reset all content
1469e6f63103SArmin Le Grand     mpB2DPolyPolygon.reset();
1470e6f63103SArmin Le Grand     mpPolyPolygon.reset();
1471e6f63103SArmin Le Grand     mpRegionBand.reset();
1472e6f63103SArmin Le Grand     mbIsNull = false;
1473cdf0e10cSrcweir }
1474cdf0e10cSrcweir 
operator =(const Region & rRegion)1475cdf0e10cSrcweir Region& Region::operator=( const Region& rRegion )
1476cdf0e10cSrcweir {
1477e6f63103SArmin Le Grand 	// reset all content
1478e6f63103SArmin Le Grand     mpB2DPolyPolygon = rRegion.mpB2DPolyPolygon;
1479e6f63103SArmin Le Grand     mpPolyPolygon = rRegion.mpPolyPolygon;
1480e6f63103SArmin Le Grand     mpRegionBand = rRegion.mpRegionBand;
1481e6f63103SArmin Le Grand     mbIsNull = rRegion.mbIsNull;
1482cdf0e10cSrcweir 
1483e6f63103SArmin Le Grand     return *this;
1484cdf0e10cSrcweir }
1485cdf0e10cSrcweir 
operator =(const Rectangle & rRect)1486cdf0e10cSrcweir Region& Region::operator=( const Rectangle& rRect )
1487cdf0e10cSrcweir {
1488e6f63103SArmin Le Grand     mpB2DPolyPolygon.reset();
1489e6f63103SArmin Le Grand     mpPolyPolygon.reset();
1490e6f63103SArmin Le Grand     mpRegionBand.reset(rRect.IsEmpty() ? 0 : new RegionBand(rRect));
1491e6f63103SArmin Le Grand     mbIsNull = false;
1492cdf0e10cSrcweir 
1493e6f63103SArmin Le Grand     return *this;
1494cdf0e10cSrcweir }
1495cdf0e10cSrcweir 
operator ==(const Region & rRegion) const1496e6f63103SArmin Le Grand bool Region::operator==( const Region& rRegion ) const
1497cdf0e10cSrcweir {
1498e6f63103SArmin Le Grand     if(IsNull() && rRegion.IsNull())
1499e6f63103SArmin Le Grand     {
1500e6f63103SArmin Le Grand         // both are null region
1501e6f63103SArmin Le Grand         return true;
1502e6f63103SArmin Le Grand     }
1503cdf0e10cSrcweir 
1504e6f63103SArmin Le Grand     if(IsEmpty() && rRegion.IsEmpty())
1505e6f63103SArmin Le Grand     {
1506e6f63103SArmin Le Grand         // both are empty
1507e6f63103SArmin Le Grand         return true;
1508e6f63103SArmin Le Grand     }
1509cdf0e10cSrcweir 
1510e6f63103SArmin Le Grand     if(getB2DPolyPolygon() && getB2DPolyPolygon() == rRegion.getB2DPolyPolygon())
1511e6f63103SArmin Le Grand     {
1512e6f63103SArmin Le Grand         // same instance data? -> equal
1513e6f63103SArmin Le Grand         return true;
1514e6f63103SArmin Le Grand     }
1515cdf0e10cSrcweir 
1516e6f63103SArmin Le Grand     if(getPolyPolygon() && getPolyPolygon() == rRegion.getPolyPolygon())
1517e6f63103SArmin Le Grand     {
1518e6f63103SArmin Le Grand         // same instance data? -> equal
1519e6f63103SArmin Le Grand         return true;
1520e6f63103SArmin Le Grand     }
1521cdf0e10cSrcweir 
1522e6f63103SArmin Le Grand     if(getRegionBand() && getRegionBand() == rRegion.getRegionBand())
1523e6f63103SArmin Le Grand     {
1524e6f63103SArmin Le Grand         // same instance data? -> equal
1525e6f63103SArmin Le Grand         return true;
1526e6f63103SArmin Le Grand     }
1527cdf0e10cSrcweir 
1528e6f63103SArmin Le Grand 	if(IsNull() || IsEmpty())
1529e6f63103SArmin Le Grand     {
1530e6f63103SArmin Le Grand 		return false;
1531e6f63103SArmin Le Grand     }
1532cdf0e10cSrcweir 
1533e6f63103SArmin Le Grand 	if(rRegion.IsNull() || rRegion.IsEmpty())
1534e6f63103SArmin Le Grand     {
1535e6f63103SArmin Le Grand 		return false;
1536e6f63103SArmin Le Grand     }
1537cdf0e10cSrcweir 
1538e6f63103SArmin Le Grand     if(rRegion.getB2DPolyPolygon() || getB2DPolyPolygon())
1539e6f63103SArmin Le Grand     {
1540e6f63103SArmin Le Grand         // one of both has a B2DPolyPolygon based region, ensure both have it
1541e6f63103SArmin Le Grand         // by evtl. conversion
1542e6f63103SArmin Le Grand         const_cast< Region* >(this)->GetAsB2DPolyPolygon();
1543e6f63103SArmin Le Grand         const_cast< Region& >(rRegion).GetAsB2DPolyPolygon();
1544cdf0e10cSrcweir 
1545e6f63103SArmin Le Grand         return *rRegion.getB2DPolyPolygon() == *getB2DPolyPolygon();
1546e6f63103SArmin Le Grand     }
1547cdf0e10cSrcweir 
1548e6f63103SArmin Le Grand     if(rRegion.getPolyPolygon() || getPolyPolygon())
1549e6f63103SArmin Le Grand     {
1550e6f63103SArmin Le Grand         // one of both has a B2DPolyPolygon based region, ensure both have it
1551e6f63103SArmin Le Grand         // by evtl. conversion
1552e6f63103SArmin Le Grand         const_cast< Region* >(this)->GetAsPolyPolygon();
1553e6f63103SArmin Le Grand         const_cast< Region& >(rRegion).GetAsPolyPolygon();
1554cdf0e10cSrcweir 
1555e6f63103SArmin Le Grand         return *rRegion.getPolyPolygon() == *getPolyPolygon();
1556e6f63103SArmin Le Grand     }
1557cdf0e10cSrcweir 
1558e6f63103SArmin Le Grand     // both are not empty or null (see above) and if content supported polygon
1559e6f63103SArmin Le Grand     // data the comparison is already done. Only both on RegionBand base can be left,
1560e6f63103SArmin Le Grand     // but better check
1561e6f63103SArmin Le Grand     if(rRegion.getRegionBand() && getRegionBand())
1562e6f63103SArmin Le Grand     {
1563e6f63103SArmin Le Grand         return *rRegion.getRegionBand() == *getRegionBand();
1564e6f63103SArmin Le Grand     }
1565cdf0e10cSrcweir 
1566e6f63103SArmin Le Grand     // should not happen, but better deny equality
1567e6f63103SArmin Le Grand     return false;
1568cdf0e10cSrcweir }
1569cdf0e10cSrcweir 
operator >>(SvStream & rIStrm,Region & rRegion)1570e6f63103SArmin Le Grand SvStream& operator>>(SvStream& rIStrm, Region& rRegion)
1571cdf0e10cSrcweir {
1572e6f63103SArmin Le Grand     VersionCompat aCompat(rIStrm, STREAM_READ);
1573e6f63103SArmin Le Grand     sal_uInt16 nVersion(0);
1574e6f63103SArmin Le Grand     sal_uInt16 nTmp16(0);
1575cdf0e10cSrcweir 
1576e6f63103SArmin Le Grand     // clear region to be loaded
1577e6f63103SArmin Le Grand     rRegion.SetEmpty();
1578cdf0e10cSrcweir 
1579e6f63103SArmin Le Grand     // get version of streamed region
1580e6f63103SArmin Le Grand     rIStrm >> nVersion;
1581cdf0e10cSrcweir 
1582e6f63103SArmin Le Grand     // get type of region
1583e6f63103SArmin Le Grand     rIStrm >> nTmp16;
1584cdf0e10cSrcweir 
1585e6f63103SArmin Le Grand     enum RegionType { REGION_NULL, REGION_EMPTY, REGION_RECTANGLE, REGION_COMPLEX };
1586e6f63103SArmin Le Grand     RegionType meStreamedType = (RegionType)nTmp16;
1587cdf0e10cSrcweir 
1588e6f63103SArmin Le Grand     switch(meStreamedType)
1589e6f63103SArmin Le Grand     {
1590e6f63103SArmin Le Grand         case REGION_NULL:
1591e6f63103SArmin Le Grand         {
1592e6f63103SArmin Le Grand             rRegion.SetNull();
1593e6f63103SArmin Le Grand             break;
1594e6f63103SArmin Le Grand         }
1595cdf0e10cSrcweir 
1596e6f63103SArmin Le Grand         case REGION_EMPTY:
1597cdf0e10cSrcweir         {
1598e6f63103SArmin Le Grand             rRegion.SetEmpty();
1599e6f63103SArmin Le Grand             break;
1600e6f63103SArmin Le Grand         }
1601cdf0e10cSrcweir 
1602e6f63103SArmin Le Grand         default:
1603e6f63103SArmin Le Grand         {
1604e6f63103SArmin Le Grand             RegionBand* pNewRegionBand = new RegionBand();
1605e6f63103SArmin Le Grand             pNewRegionBand->load(rIStrm);
1606e6f63103SArmin Le Grand             rRegion.mpRegionBand.reset(pNewRegionBand);
1607cdf0e10cSrcweir 
1608e6f63103SArmin Le Grand             if(aCompat.GetVersion() >= 2)
1609cdf0e10cSrcweir             {
1610e6f63103SArmin Le Grand                 sal_Bool bHasPolyPolygon(sal_False);
1611cdf0e10cSrcweir 
1612cdf0e10cSrcweir                 rIStrm >> bHasPolyPolygon;
1613cdf0e10cSrcweir 
1614e6f63103SArmin Le Grand                 if(bHasPolyPolygon)
1615cdf0e10cSrcweir                 {
1616e6f63103SArmin Le Grand                     PolyPolygon* pNewPoly = new PolyPolygon();
1617e6f63103SArmin Le Grand                     rIStrm >> *pNewPoly;
1618e6f63103SArmin Le Grand                     rRegion.mpPolyPolygon.reset(pNewPoly);
1619cdf0e10cSrcweir                 }
1620cdf0e10cSrcweir             }
1621cdf0e10cSrcweir 
1622e6f63103SArmin Le Grand             break;
1623cdf0e10cSrcweir         }
1624cdf0e10cSrcweir     }
1625cdf0e10cSrcweir 
1626e6f63103SArmin Le Grand     return rIStrm;
1627cdf0e10cSrcweir }
1628cdf0e10cSrcweir 
operator <<(SvStream & rOStrm,const Region & rRegion)1629e6f63103SArmin Le Grand SvStream& operator<<( SvStream& rOStrm, const Region& rRegion )
1630cdf0e10cSrcweir {
1631e6f63103SArmin Le Grand     const sal_uInt16 nVersion(2);
1632e6f63103SArmin Le Grand     VersionCompat aCompat(rOStrm, STREAM_WRITE, nVersion);
1633cdf0e10cSrcweir 
1634e6f63103SArmin Le Grand     // put version
1635e6f63103SArmin Le Grand     rOStrm << nVersion;
1636cdf0e10cSrcweir 
1637e6f63103SArmin Le Grand     // put type
1638e6f63103SArmin Le Grand     enum RegionType { REGION_NULL, REGION_EMPTY, REGION_RECTANGLE, REGION_COMPLEX };
1639e6f63103SArmin Le Grand     RegionType aRegionType(REGION_COMPLEX);
1640e6f63103SArmin Le Grand     bool bEmpty(rRegion.IsEmpty());
1641cdf0e10cSrcweir 
1642e6f63103SArmin Le Grand     if(!bEmpty && rRegion.getB2DPolyPolygon() && 0 == rRegion.getB2DPolyPolygon()->count())
1643e6f63103SArmin Le Grand     {
1644e6f63103SArmin Le Grand         OSL_ENSURE(false, "Region with empty B2DPolyPolygon, should not be created (!)");
1645e6f63103SArmin Le Grand         bEmpty = true;
1646e6f63103SArmin Le Grand     }
1647cdf0e10cSrcweir 
1648e6f63103SArmin Le Grand     if(!bEmpty && rRegion.getPolyPolygon() && 0 == rRegion.getPolyPolygon()->Count())
1649e6f63103SArmin Le Grand     {
1650e6f63103SArmin Le Grand         OSL_ENSURE(false, "Region with empty PolyPolygon, should not be created (!)");
1651e6f63103SArmin Le Grand         bEmpty = true;
1652e6f63103SArmin Le Grand     }
1653cdf0e10cSrcweir 
1654e6f63103SArmin Le Grand     if(bEmpty)
1655e6f63103SArmin Le Grand     {
1656e6f63103SArmin Le Grand         aRegionType = REGION_EMPTY;
1657e6f63103SArmin Le Grand     }
1658e6f63103SArmin Le Grand     else if(rRegion.IsNull())
1659e6f63103SArmin Le Grand     {
1660e6f63103SArmin Le Grand         aRegionType = REGION_NULL;
1661e6f63103SArmin Le Grand     }
1662e6f63103SArmin Le Grand     else if(rRegion.getRegionBand() && rRegion.getRegionBand()->isSingleRectangle())
1663e6f63103SArmin Le Grand     {
1664e6f63103SArmin Le Grand         aRegionType = REGION_RECTANGLE;
1665e6f63103SArmin Le Grand     }
1666cdf0e10cSrcweir 
1667e6f63103SArmin Le Grand     rOStrm << (sal_uInt16)aRegionType;
1668cdf0e10cSrcweir 
1669e6f63103SArmin Le Grand     // get RegionBand
1670e6f63103SArmin Le Grand     const RegionBand* pRegionBand = rRegion.getRegionBand();
1671cdf0e10cSrcweir 
1672e6f63103SArmin Le Grand     if(pRegionBand)
1673e6f63103SArmin Le Grand     {
1674e6f63103SArmin Le Grand         pRegionBand->save(rOStrm);
1675e6f63103SArmin Le Grand     }
1676169773a2SArmin Le Grand     else
1677169773a2SArmin Le Grand     {
1678169773a2SArmin Le Grand         // for compatibility, write an empty RegionBand (will only write
1679169773a2SArmin Le Grand         // the end marker STREAMENTRY_END, but this *is* needed)
1680169773a2SArmin Le Grand         const RegionBand aRegionBand;
1681169773a2SArmin Le Grand 
1682169773a2SArmin Le Grand         aRegionBand.save(rOStrm);
1683169773a2SArmin Le Grand     }
1684cdf0e10cSrcweir 
1685e6f63103SArmin Le Grand     // write polypolygon if available
1686e6f63103SArmin Le Grand     const sal_Bool bHasPolyPolygon(rRegion.HasPolyPolygonOrB2DPolyPolygon());
1687e6f63103SArmin Le Grand     rOStrm << bHasPolyPolygon;
1688cdf0e10cSrcweir 
1689e6f63103SArmin Le Grand     if(bHasPolyPolygon)
1690e6f63103SArmin Le Grand     {
1691e6f63103SArmin Le Grand         // #i105373#
1692e6f63103SArmin Le Grand         PolyPolygon aNoCurvePolyPolygon;
1693e6f63103SArmin Le Grand         rRegion.GetAsPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon);
1694cdf0e10cSrcweir 
1695e6f63103SArmin Le Grand         rOStrm << aNoCurvePolyPolygon;
1696e6f63103SArmin Le Grand     }
1697cdf0e10cSrcweir 
1698e6f63103SArmin Le Grand     return rOStrm;
1699cdf0e10cSrcweir }
1700cdf0e10cSrcweir 
GetRegionRectangles(RectangleVector & rTarget) const1701e6f63103SArmin Le Grand void Region::GetRegionRectangles(RectangleVector& rTarget) const
1702cdf0e10cSrcweir {
1703e6f63103SArmin Le Grand     // clear returnvalues
1704e6f63103SArmin Le Grand     rTarget.clear();
1705cdf0e10cSrcweir 
1706e6f63103SArmin Le Grand     // ensure RegionBand existance
1707169773a2SArmin Le Grand     const RegionBand* pRegionBand = GetAsRegionBand();
1708cdf0e10cSrcweir 
1709e6f63103SArmin Le Grand     if(pRegionBand)
1710e6f63103SArmin Le Grand     {
1711e6f63103SArmin Le Grand         pRegionBand->GetRegionRectangles(rTarget);
1712e6f63103SArmin Le Grand     }
1713cdf0e10cSrcweir }
1714cdf0e10cSrcweir 
ImplPolygonRectTest(const Polygon & rPoly,Rectangle * pRectOut=NULL)1715cdf0e10cSrcweir static inline bool ImplPolygonRectTest( const Polygon& rPoly, Rectangle* pRectOut = NULL )
1716cdf0e10cSrcweir {
1717cdf0e10cSrcweir     bool bIsRect = false;
1718cdf0e10cSrcweir     const Point* pPoints = rPoly.GetConstPointAry();
1719cdf0e10cSrcweir     sal_uInt16 nPoints = rPoly.GetSize();
1720e6f63103SArmin Le Grand 
1721cdf0e10cSrcweir     if( nPoints == 4 || (nPoints == 5 && pPoints[0] == pPoints[4]) )
1722cdf0e10cSrcweir     {
1723e6f63103SArmin Le Grand         long nX1 = pPoints[0].X(), nX2 = pPoints[2].X(), nY1 = pPoints[0].Y(), nY2 = pPoints[2].Y();
1724e6f63103SArmin Le Grand 
1725e6f63103SArmin Le Grand         if( ( (pPoints[1].X() == nX1 && pPoints[3].X() == nX2) && (pPoints[1].Y() == nY2 && pPoints[3].Y() == nY1) )
1726e6f63103SArmin Le Grand          || ( (pPoints[1].X() == nX2 && pPoints[3].X() == nX1) && (pPoints[1].Y() == nY1 && pPoints[3].Y() == nY2) ) )
1727cdf0e10cSrcweir         {
1728cdf0e10cSrcweir             bIsRect = true;
1729e6f63103SArmin Le Grand 
1730cdf0e10cSrcweir             if( pRectOut )
1731cdf0e10cSrcweir             {
1732cdf0e10cSrcweir                 long nSwap;
1733e6f63103SArmin Le Grand 
1734cdf0e10cSrcweir                 if( nX2 < nX1 )
1735cdf0e10cSrcweir                 {
1736cdf0e10cSrcweir                     nSwap = nX2;
1737cdf0e10cSrcweir                     nX2 = nX1;
1738cdf0e10cSrcweir                     nX1 = nSwap;
1739cdf0e10cSrcweir                 }
1740e6f63103SArmin Le Grand 
1741cdf0e10cSrcweir                 if( nY2 < nY1 )
1742cdf0e10cSrcweir                 {
1743cdf0e10cSrcweir                     nSwap = nY2;
1744cdf0e10cSrcweir                     nY2 = nY1;
1745cdf0e10cSrcweir                     nY1 = nSwap;
1746cdf0e10cSrcweir                 }
1747e6f63103SArmin Le Grand 
1748cdf0e10cSrcweir                 if( nX2 != nX1 )
1749e6f63103SArmin Le Grand                 {
1750cdf0e10cSrcweir                     nX2--;
1751e6f63103SArmin Le Grand                 }
1752e6f63103SArmin Le Grand 
1753cdf0e10cSrcweir                 if( nY2 != nY1 )
1754e6f63103SArmin Le Grand                 {
1755cdf0e10cSrcweir                     nY2--;
1756e6f63103SArmin Le Grand                 }
1757e6f63103SArmin Le Grand 
1758cdf0e10cSrcweir                 pRectOut->Left()    = nX1;
1759cdf0e10cSrcweir                 pRectOut->Right()   = nX2;
1760cdf0e10cSrcweir                 pRectOut->Top()     = nY1;
1761cdf0e10cSrcweir                 pRectOut->Bottom()  = nY2;
1762cdf0e10cSrcweir             }
1763cdf0e10cSrcweir         }
1764cdf0e10cSrcweir     }
1765e6f63103SArmin Le Grand 
1766cdf0e10cSrcweir     return bIsRect;
1767cdf0e10cSrcweir }
1768cdf0e10cSrcweir 
GetRegionFromPolyPolygon(const PolyPolygon & rPolyPoly)1769cdf0e10cSrcweir Region Region::GetRegionFromPolyPolygon( const PolyPolygon& rPolyPoly )
1770cdf0e10cSrcweir {
1771cdf0e10cSrcweir     //return Region( rPolyPoly );
1772cdf0e10cSrcweir 
1773cdf0e10cSrcweir     // check if it's worth extracting the XOr'ing the Rectangles
1774cdf0e10cSrcweir     // empiricism shows that break even between XOr'ing rectangles separately
1775e6f63103SArmin Le Grand     // and ImplCreateRegionBandFromPolyPolygon is at half rectangles/half polygons
1776cdf0e10cSrcweir     int nPolygonRects = 0, nPolygonPolygons = 0;
1777cdf0e10cSrcweir     int nPolygons = rPolyPoly.Count();
1778cdf0e10cSrcweir 
1779cdf0e10cSrcweir     for( sal_uInt16 i = 0; i < nPolygons; i++ )
1780cdf0e10cSrcweir     {
1781cdf0e10cSrcweir         const Polygon& rPoly = rPolyPoly[i];
1782e6f63103SArmin Le Grand 
1783cdf0e10cSrcweir         if( ImplPolygonRectTest( rPoly ) )
1784e6f63103SArmin Le Grand         {
1785cdf0e10cSrcweir             nPolygonRects++;
1786e6f63103SArmin Le Grand         }
1787cdf0e10cSrcweir         else
1788e6f63103SArmin Le Grand         {
1789cdf0e10cSrcweir             nPolygonPolygons++;
1790e6f63103SArmin Le Grand         }
1791cdf0e10cSrcweir     }
1792e6f63103SArmin Le Grand 
1793cdf0e10cSrcweir     if( nPolygonPolygons > nPolygonRects )
1794e6f63103SArmin Le Grand     {
1795cdf0e10cSrcweir         return Region( rPolyPoly );
1796e6f63103SArmin Le Grand     }
1797cdf0e10cSrcweir 
1798cdf0e10cSrcweir     Region aResult;
1799cdf0e10cSrcweir     Rectangle aRect;
1800e6f63103SArmin Le Grand 
1801cdf0e10cSrcweir     for( sal_uInt16 i = 0; i < nPolygons; i++ )
1802cdf0e10cSrcweir     {
1803cdf0e10cSrcweir         const Polygon& rPoly = rPolyPoly[i];
1804e6f63103SArmin Le Grand 
1805cdf0e10cSrcweir         if( ImplPolygonRectTest( rPoly, &aRect ) )
1806e6f63103SArmin Le Grand         {
1807cdf0e10cSrcweir             aResult.XOr( aRect );
1808e6f63103SArmin Le Grand         }
1809cdf0e10cSrcweir         else
1810e6f63103SArmin Le Grand         {
1811cdf0e10cSrcweir             aResult.XOr( Region(rPoly) );
1812e6f63103SArmin Le Grand         }
1813cdf0e10cSrcweir     }
1814e6f63103SArmin Le Grand 
1815cdf0e10cSrcweir     return aResult;
1816cdf0e10cSrcweir }
1817e6f63103SArmin Le Grand 
1818e6f63103SArmin Le Grand //////////////////////////////////////////////////////////////////////////////
1819e6f63103SArmin Le Grand // eof
1820