xref: /AOO41X/main/vcl/source/gdi/region.cxx (revision d3e0dd8eb215533c15e891ee35bd141abe9397ee)
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
10cdf0e10cSrcweir  *
119f62ea84SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
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.
19cdf0e10cSrcweir  *
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
47e6f63103SArmin Le Grand {
48cdf0e10cSrcweir     /** Return <TRUE/> when the given polygon is rectiliner and oriented so that
49cdf0e10cSrcweir         all sides are either horizontal or vertical.
50cdf0e10cSrcweir     */
ImplIsPolygonRectilinear(const PolyPolygon & rPolyPoly)51cdf0e10cSrcweir     bool ImplIsPolygonRectilinear (const PolyPolygon& rPolyPoly)
52cdf0e10cSrcweir     {
53cdf0e10cSrcweir         // Iterate over all polygons.
54cdf0e10cSrcweir         const sal_uInt16 nPolyCount = rPolyPoly.Count();
55cdf0e10cSrcweir         for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly)
56cdf0e10cSrcweir         {
57cdf0e10cSrcweir             const Polygon&	aPoly = rPolyPoly.GetObject(nPoly);
58cdf0e10cSrcweir 
59cdf0e10cSrcweir             // Iterate over all edges of the current polygon.
60cdf0e10cSrcweir             const sal_uInt16 nSize = aPoly.GetSize();
61cdf0e10cSrcweir 
62cdf0e10cSrcweir             if (nSize < 2)
63cdf0e10cSrcweir                 continue;
64cdf0e10cSrcweir             Point aPoint (aPoly.GetPoint(0));
65cdf0e10cSrcweir             const Point aLastPoint (aPoint);
66cdf0e10cSrcweir             for (sal_uInt16 nPoint = 1; nPoint < nSize; ++nPoint)
67cdf0e10cSrcweir             {
68cdf0e10cSrcweir                 const Point aNextPoint (aPoly.GetPoint(nPoint));
69cdf0e10cSrcweir                 // When there is at least one edge that is neither vertical nor
70cdf0e10cSrcweir                 // horizontal then the entire polygon is not rectilinear (and
71cdf0e10cSrcweir                 // oriented along primary axes.)
72cdf0e10cSrcweir                 if (aPoint.X() != aNextPoint.X() && aPoint.Y() != aNextPoint.Y())
73cdf0e10cSrcweir                     return false;
74cdf0e10cSrcweir 
75cdf0e10cSrcweir                 aPoint = aNextPoint;
76cdf0e10cSrcweir             }
77cdf0e10cSrcweir             // Compare closing edge.
78cdf0e10cSrcweir             if (aLastPoint.X() != aPoint.X() && aLastPoint.Y() != aPoint.Y())
79cdf0e10cSrcweir                 return false;
80cdf0e10cSrcweir         }
81cdf0e10cSrcweir         return true;
82cdf0e10cSrcweir     }
83cdf0e10cSrcweir 
84cdf0e10cSrcweir     /** Convert a rectilinear polygon (that is oriented along the primary axes)
85cdf0e10cSrcweir         to a list of bands.  For this special form of polygon we can use an
86cdf0e10cSrcweir         optimization that prevents the creation of one band per y value.
87cdf0e10cSrcweir         However, it still is possible that some temporary bands are created that
88cdf0e10cSrcweir         later can be optimized away.
89cdf0e10cSrcweir         @param rPolyPolygon
90cdf0e10cSrcweir             A set of zero, one, or more polygons, nested or not, that are
91cdf0e10cSrcweir             converted into a list of bands.
92cdf0e10cSrcweir         @return
93e6f63103SArmin Le Grand             A new RegionBand object is returned that contains the bands that
94cdf0e10cSrcweir             represent the given poly-polygon.
95cdf0e10cSrcweir     */
ImplRectilinearPolygonToBands(const PolyPolygon & rPolyPoly)96e6f63103SArmin Le Grand     RegionBand* ImplRectilinearPolygonToBands(const PolyPolygon& rPolyPoly)
97cdf0e10cSrcweir     {
98cdf0e10cSrcweir         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();
102cdf0e10cSrcweir         long nLineId = 0L;
103cdf0e10cSrcweir 
104cdf0e10cSrcweir         // Iterate over all polygons.
105cdf0e10cSrcweir 	    const sal_uInt16 nPolyCount = rPolyPoly.Count();
106cdf0e10cSrcweir         for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly)
107cdf0e10cSrcweir         {
108cdf0e10cSrcweir             const Polygon&	aPoly = rPolyPoly.GetObject(nPoly);
109cdf0e10cSrcweir 
110cdf0e10cSrcweir             // Iterate over all edges of the current polygon.
111cdf0e10cSrcweir             const sal_uInt16 nSize = aPoly.GetSize();
112cdf0e10cSrcweir             if (nSize < 2)
113cdf0e10cSrcweir                 continue;
114cdf0e10cSrcweir             // Avoid fetching every point twice (each point is the start point
115cdf0e10cSrcweir             // of one and the end point of another edge.)
116cdf0e10cSrcweir             Point aStart (aPoly.GetPoint(0));
117cdf0e10cSrcweir             Point aEnd;
118cdf0e10cSrcweir             for (sal_uInt16 nPoint = 1; nPoint <= nSize; ++nPoint, aStart=aEnd)
119cdf0e10cSrcweir             {
120cdf0e10cSrcweir                 // We take the implicit closing edge into account by mapping
121cdf0e10cSrcweir                 // index nSize to 0.
122cdf0e10cSrcweir                 aEnd = aPoly.GetPoint(nPoint%nSize);
123cdf0e10cSrcweir                 if (aStart.Y() == aEnd.Y())
124cdf0e10cSrcweir                 {
125cdf0e10cSrcweir                     // Horizontal lines are ignored.
126cdf0e10cSrcweir                     continue;
127cdf0e10cSrcweir                 }
128cdf0e10cSrcweir 
129cdf0e10cSrcweir                 // At this point the line has to be vertical.
130cdf0e10cSrcweir                 OSL_ASSERT(aStart.X() == aEnd.X());
131cdf0e10cSrcweir 
132cdf0e10cSrcweir                 // Sort y-coordinates to simplify the algorithm and store the
133cdf0e10cSrcweir                 // direction seperately.  The direction is calculated as it is
134cdf0e10cSrcweir                 // in other places (but seems to be the wrong way.)
135cdf0e10cSrcweir                 const long nTop (::std::min(aStart.Y(), aEnd.Y()));
136cdf0e10cSrcweir                 const long nBottom (::std::max(aStart.Y(), aEnd.Y()));
137cdf0e10cSrcweir                 const LineType eLineType (aStart.Y() > aEnd.Y() ? LINE_DESCENDING : LINE_ASCENDING);
138cdf0e10cSrcweir 
139cdf0e10cSrcweir                 // Make sure that the current line is covered by bands.
140e6f63103SArmin Le Grand                 pRegionBand->ImplAddMissingBands(nTop,nBottom);
141cdf0e10cSrcweir 
142cdf0e10cSrcweir                 // Find top-most band that may contain nTop.
143e6f63103SArmin Le Grand                 ImplRegionBand* pBand = pRegionBand->ImplGetFirstRegionBand();
144cdf0e10cSrcweir                 while (pBand!=NULL && pBand->mnYBottom < nTop)
145cdf0e10cSrcweir                     pBand = pBand->mpNextBand;
146cdf0e10cSrcweir                 ImplRegionBand* pTopBand = pBand;
147cdf0e10cSrcweir                 // If necessary split the band at nTop so that nTop is contained
148cdf0e10cSrcweir                 // in the lower band.
149cdf0e10cSrcweir                 if (pBand!=NULL
150cdf0e10cSrcweir                        // Prevent the current band from becoming 0 pixel high
151cdf0e10cSrcweir                     && pBand->mnYTop<nTop
152cdf0e10cSrcweir                        // this allows the lowest pixel of the band to be split off
153cdf0e10cSrcweir                     && pBand->mnYBottom>=nTop
154cdf0e10cSrcweir                        // do not split a band that is just one pixel high
155cdf0e10cSrcweir                     && pBand->mnYTop<pBand->mnYBottom)
156cdf0e10cSrcweir                 {
157cdf0e10cSrcweir                     // Split the top band.
158cdf0e10cSrcweir                     pTopBand = pBand->SplitBand(nTop);
159cdf0e10cSrcweir                 }
160cdf0e10cSrcweir 
161cdf0e10cSrcweir                 // Advance to band that may contain nBottom.
162cdf0e10cSrcweir                 while (pBand!=NULL && pBand->mnYBottom < nBottom)
163cdf0e10cSrcweir                     pBand = pBand->mpNextBand;
164cdf0e10cSrcweir                 // The lowest band may have to be split at nBottom so that
165cdf0e10cSrcweir                 // nBottom itself remains in the upper band.
166cdf0e10cSrcweir                 if (pBand!=NULL
167cdf0e10cSrcweir                        // allow the current band becoming 1 pixel high
168cdf0e10cSrcweir                     && pBand->mnYTop<=nBottom
169cdf0e10cSrcweir                        // prevent splitting off a band that is 0 pixel high
170cdf0e10cSrcweir                     && pBand->mnYBottom>nBottom
171cdf0e10cSrcweir                        // do not split a band that is just one pixel high
172cdf0e10cSrcweir                     && pBand->mnYTop<pBand->mnYBottom)
173cdf0e10cSrcweir                 {
174cdf0e10cSrcweir                     // Split the bottom band.
175cdf0e10cSrcweir                     pBand->SplitBand(nBottom+1);
176cdf0e10cSrcweir                 }
177cdf0e10cSrcweir 
178cdf0e10cSrcweir                 // Note that we remember the top band (in pTopBand) but not the
179cdf0e10cSrcweir                 // bottom band.  The later can be determined by comparing y
180cdf0e10cSrcweir                 // coordinates.
181cdf0e10cSrcweir 
182cdf0e10cSrcweir                 // Add the x-value as point to all bands in the nTop->nBottom range.
183cdf0e10cSrcweir                 for (pBand=pTopBand; pBand!=NULL&&pBand->mnYTop<=nBottom; pBand=pBand->mpNextBand)
184e6f63103SArmin Le Grand                     pBand->InsertPoint(aStart.X(), nLineId++, true, eLineType);
185cdf0e10cSrcweir             }
186cdf0e10cSrcweir         }
187cdf0e10cSrcweir 
188e6f63103SArmin Le Grand         return pRegionBand;
189cdf0e10cSrcweir     }
190cdf0e10cSrcweir 
191cdf0e10cSrcweir     /** Convert a general polygon (one for which ImplIsPolygonRectilinear()
192cdf0e10cSrcweir         returns <FALSE/>) to bands.
193cdf0e10cSrcweir     */
ImplGeneralPolygonToBands(const PolyPolygon & rPolyPoly,const Rectangle & rPolygonBoundingBox)194e6f63103SArmin Le Grand     RegionBand* ImplGeneralPolygonToBands(const PolyPolygon& rPolyPoly, const Rectangle& rPolygonBoundingBox)
195cdf0e10cSrcweir     {
196cdf0e10cSrcweir         long nLineID = 0L;
197cdf0e10cSrcweir 
198cdf0e10cSrcweir         // initialisation and creation of Bands
199e6f63103SArmin Le Grand         RegionBand* pRegionBand = new RegionBand();
200e6f63103SArmin Le Grand         pRegionBand->CreateBandRange(rPolygonBoundingBox.Top(), rPolygonBoundingBox.Bottom());
201cdf0e10cSrcweir 
202cdf0e10cSrcweir         // insert polygons
203cdf0e10cSrcweir 	    const sal_uInt16 nPolyCount = rPolyPoly.Count();
204e6f63103SArmin Le Grand 
205cdf0e10cSrcweir         for ( sal_uInt16 nPoly = 0; nPoly < nPolyCount; nPoly++ )
206cdf0e10cSrcweir         {
207cdf0e10cSrcweir             // get reference to current polygon
208cdf0e10cSrcweir             const Polygon&	aPoly = rPolyPoly.GetObject( nPoly );
209cdf0e10cSrcweir             const sal_uInt16	nSize = aPoly.GetSize();
210cdf0e10cSrcweir 
211cdf0e10cSrcweir             // not enough points ( <= 2 )? -> nothing to do!
212cdf0e10cSrcweir             if ( nSize <= 2 )
213cdf0e10cSrcweir                 continue;
214cdf0e10cSrcweir 
215cdf0e10cSrcweir             // band the polygon
216cdf0e10cSrcweir             for ( sal_uInt16 nPoint = 1; nPoint < nSize; nPoint++ )
217e6f63103SArmin Le Grand             {
218e6f63103SArmin Le Grand                 pRegionBand->InsertLine( aPoly.GetPoint(nPoint-1), aPoly.GetPoint(nPoint), nLineID++ );
219e6f63103SArmin Le Grand             }
220cdf0e10cSrcweir 
221cdf0e10cSrcweir             // close polygon with line from first point to last point, if neccesary
222cdf0e10cSrcweir             const Point rLastPoint = aPoly.GetPoint(nSize-1);
223cdf0e10cSrcweir             const Point rFirstPoint = aPoly.GetPoint(0);
224e6f63103SArmin Le Grand 
225cdf0e10cSrcweir             if ( rLastPoint != rFirstPoint )
226e6f63103SArmin Le Grand             {
227e6f63103SArmin Le Grand                 pRegionBand->InsertLine( rLastPoint, rFirstPoint, nLineID++ );
228e6f63103SArmin Le Grand             }
229cdf0e10cSrcweir         }
230cdf0e10cSrcweir 
231e6f63103SArmin Le Grand         return pRegionBand;
232cdf0e10cSrcweir     }
233cdf0e10cSrcweir } // end of anonymous namespace
234cdf0e10cSrcweir 
235e6f63103SArmin Le Grand //////////////////////////////////////////////////////////////////////////////
236cdf0e10cSrcweir 
IsEmpty() const237e6f63103SArmin Le Grand bool Region::IsEmpty() const
238cdf0e10cSrcweir {
239e6f63103SArmin Le Grand     return !mbIsNull && !mpB2DPolyPolygon.get() && !mpPolyPolygon.get() && !mpRegionBand.get();
240cdf0e10cSrcweir }
241cdf0e10cSrcweir 
IsNull() const242e6f63103SArmin Le Grand bool Region::IsNull() const
243cdf0e10cSrcweir {
244e6f63103SArmin Le Grand     return mbIsNull;
245cdf0e10cSrcweir }
246cdf0e10cSrcweir 
ImplCreateRegionBandFromPolyPolygon(const PolyPolygon & rPolyPolygon)247e6f63103SArmin Le Grand RegionBand* ImplCreateRegionBandFromPolyPolygon(const PolyPolygon& rPolyPolygon)
248cdf0e10cSrcweir {
249e6f63103SArmin Le Grand     RegionBand* pRetval = 0;
250e6f63103SArmin Le Grand 
251e6f63103SArmin Le Grand     if(rPolyPolygon.Count())
252e6f63103SArmin Le Grand     {
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;
256e6f63103SArmin Le Grand 
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());
262e6f63103SArmin Le Grand 
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);
269cdf0e10cSrcweir                 }
270cdf0e10cSrcweir                 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             }
289cdf0e10cSrcweir         }
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     }
309cdf0e10cSrcweir     else
310cdf0e10cSrcweir     {
311e6f63103SArmin Le Grand         OSL_ENSURE(false, "Called with no local RegionBand (!)");
312e6f63103SArmin Le Grand     }
313e6f63103SArmin Le Grand 
314e6f63103SArmin Le Grand     return aRetval;
315e6f63103SArmin Le Grand }
316e6f63103SArmin Le Grand 
ImplCreateB2DPolyPolygonFromRegionBand() const317e6f63103SArmin Le Grand basegfx::B2DPolyPolygon Region::ImplCreateB2DPolyPolygonFromRegionBand() const
318cdf0e10cSrcweir {
319e6f63103SArmin Le Grand     PolyPolygon aPoly(ImplCreatePolyPolygonFromRegionBand());
320e6f63103SArmin Le Grand 
321e6f63103SArmin Le Grand     return aPoly.getB2DPolyPolygon();
322cdf0e10cSrcweir }
323e6f63103SArmin Le Grand 
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)332cdf0e10cSrcweir 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)341cdf0e10cSrcweir Region::Region(const Polygon& rPolygon)
342e6f63103SArmin Le Grand :   mpB2DPolyPolygon(),
343e6f63103SArmin Le Grand     mpPolyPolygon(),
344e6f63103SArmin Le Grand     mpRegionBand(),
345e6f63103SArmin Le Grand     mbIsNull(false)
346cdf0e10cSrcweir {
347cdf0e10cSrcweir 	DBG_CHKOBJ( &rPolygon, Polygon, NULL );
348cdf0e10cSrcweir 
349e6f63103SArmin Le Grand     if(rPolygon.GetSize())
350e6f63103SArmin Le Grand     {
351cdf0e10cSrcweir     	ImplCreatePolyPolyRegion(rPolygon);
352cdf0e10cSrcweir     }
353e6f63103SArmin Le Grand }
354cdf0e10cSrcweir 
Region(const PolyPolygon & rPolyPoly)355cdf0e10cSrcweir Region::Region(const PolyPolygon& rPolyPoly)
356e6f63103SArmin Le Grand :   mpB2DPolyPolygon(),
357e6f63103SArmin Le Grand     mpPolyPolygon(),
358e6f63103SArmin Le Grand     mpRegionBand(),
359e6f63103SArmin Le Grand     mbIsNull(false)
360cdf0e10cSrcweir {
361cdf0e10cSrcweir 	DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
362cdf0e10cSrcweir 
363e6f63103SArmin Le Grand     if(rPolyPoly.Count())
364e6f63103SArmin Le Grand     {
365cdf0e10cSrcweir     	ImplCreatePolyPolyRegion(rPolyPoly);
366cdf0e10cSrcweir     }
367e6f63103SArmin Le Grand }
368cdf0e10cSrcweir 
Region(const basegfx::B2DPolyPolygon & rPolyPoly)369cdf0e10cSrcweir Region::Region(const basegfx::B2DPolyPolygon& rPolyPoly)
370e6f63103SArmin Le Grand :   mpB2DPolyPolygon(),
371e6f63103SArmin Le Grand     mpPolyPolygon(),
372e6f63103SArmin Le Grand     mpRegionBand(),
373e6f63103SArmin Le Grand     mbIsNull(false)
374cdf0e10cSrcweir {
375cdf0e10cSrcweir 	DBG_CHKOBJ( &rPolyPoly, PolyPolygon, NULL );
376cdf0e10cSrcweir 
377e6f63103SArmin Le Grand     if(rPolyPoly.count())
378e6f63103SArmin Le Grand     {
37934fced94SAndre Fischer     	ImplCreatePolyPolyRegion(rPolyPoly);
380cdf0e10cSrcweir     }
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)
388e6f63103SArmin Le Grand {
389e6f63103SArmin Le Grand }
390cdf0e10cSrcweir 
~Region()391cdf0e10cSrcweir Region::~Region()
392cdf0e10cSrcweir {
393cdf0e10cSrcweir }
394cdf0e10cSrcweir 
ImplCreatePolyPolyRegion(const PolyPolygon & rPolyPoly)395cdf0e10cSrcweir void Region::ImplCreatePolyPolyRegion( const PolyPolygon& rPolyPoly )
396cdf0e10cSrcweir {
397cdf0e10cSrcweir 	const sal_uInt16 nPolyCount = rPolyPoly.Count();
398e6f63103SArmin Le Grand 
399cdf0e10cSrcweir     if(nPolyCount)
400cdf0e10cSrcweir 	{
401cdf0e10cSrcweir 		// polypolygon empty? -> empty region
402cdf0e10cSrcweir 		const Rectangle aRect(rPolyPoly.GetBoundRect());
403cdf0e10cSrcweir 
404cdf0e10cSrcweir 		if(!aRect.IsEmpty())
405cdf0e10cSrcweir 		{
406cdf0e10cSrcweir 			// width OR height == 1 ? => Rectangular region
407e6f63103SArmin Le Grand 			if((1 == aRect.GetWidth()) || (1 == aRect.GetHeight()) || rPolyPoly.IsRect())
408cdf0e10cSrcweir             {
409e6f63103SArmin Le Grand                 mpRegionBand.reset(new RegionBand(aRect));
410cdf0e10cSrcweir             }
411cdf0e10cSrcweir 			else
412e6f63103SArmin Le Grand             {
413e6f63103SArmin Le Grand                 mpPolyPolygon.reset(new PolyPolygon(rPolyPoly));
414cdf0e10cSrcweir             }
415cdf0e10cSrcweir 
416e6f63103SArmin Le Grand             mbIsNull = false;
417e6f63103SArmin Le Grand 		}
418e6f63103SArmin Le Grand 	}
419e6f63103SArmin Le Grand }
420cdf0e10cSrcweir 
ImplCreatePolyPolyRegion(const basegfx::B2DPolyPolygon & rPolyPoly)42134fced94SAndre Fischer void Region::ImplCreatePolyPolyRegion( const basegfx::B2DPolyPolygon& rPolyPoly )
42234fced94SAndre Fischer {
423e6f63103SArmin Le Grand     if(rPolyPoly.count() && !rPolyPoly.getB2DRange().isEmpty())
424cdf0e10cSrcweir     {
425e6f63103SArmin Le Grand         mpB2DPolyPolygon.reset(new basegfx::B2DPolyPolygon(rPolyPoly));
426e6f63103SArmin Le Grand         mbIsNull = false;
427cdf0e10cSrcweir     }
428cdf0e10cSrcweir }
429cdf0e10cSrcweir 
Move(long nHorzMove,long nVertMove)430cdf0e10cSrcweir void Region::Move( long nHorzMove, long nVertMove )
431cdf0e10cSrcweir {
432e6f63103SArmin Le Grand 	if(IsNull() || IsEmpty())
433cdf0e10cSrcweir     {
434e6f63103SArmin Le Grand         // empty or null need no move
435e6f63103SArmin Le Grand 		return;
436e6f63103SArmin Le Grand     }
437e6f63103SArmin Le Grand 
438e6f63103SArmin Le Grand     if(!nHorzMove && !nVertMove)
439e6f63103SArmin Le Grand     {
440e6f63103SArmin Le Grand         // no move defined
441e6f63103SArmin Le Grand         return;
442e6f63103SArmin Le Grand     }
443e6f63103SArmin Le Grand 
444e6f63103SArmin Le Grand     if(getB2DPolyPolygon())
445e6f63103SArmin Le Grand     {
446e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aPoly(*getB2DPolyPolygon());
447e6f63103SArmin Le Grand 
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());
456e6f63103SArmin Le Grand 
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());
465e6f63103SArmin Le Grand 
466e6f63103SArmin Le Grand         pNew->Move(nHorzMove, nVertMove);
467e6f63103SArmin Le Grand         mpB2DPolyPolygon.reset();
468e6f63103SArmin Le Grand         mpPolyPolygon.reset();
469e6f63103SArmin Le Grand         mpRegionBand.reset(pNew);
470cdf0e10cSrcweir     }
471cdf0e10cSrcweir     else
472cdf0e10cSrcweir     {
473e6f63103SArmin Le Grand         OSL_ENSURE(false, "Region::Move error: impossible combination (!)");
474cdf0e10cSrcweir     }
475cdf0e10cSrcweir }
476cdf0e10cSrcweir 
Scale(double fScaleX,double fScaleY)477cdf0e10cSrcweir void Region::Scale( double fScaleX, double fScaleY )
478cdf0e10cSrcweir {
479e6f63103SArmin Le Grand 	if(IsNull() || IsEmpty())
480cdf0e10cSrcweir     {
481e6f63103SArmin Le Grand         // empty or null need no scale
482e6f63103SArmin Le Grand 		return;
483e6f63103SArmin Le Grand     }
484e6f63103SArmin Le Grand 
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     }
490e6f63103SArmin Le Grand 
491e6f63103SArmin Le Grand     if(getB2DPolyPolygon())
492e6f63103SArmin Le Grand     {
493e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aPoly(*getB2DPolyPolygon());
494e6f63103SArmin Le Grand 
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());
503e6f63103SArmin Le Grand 
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());
512e6f63103SArmin Le Grand 
513e6f63103SArmin Le Grand         pNew->Scale(fScaleX, fScaleY);
514e6f63103SArmin Le Grand         mpB2DPolyPolygon.reset();
515e6f63103SArmin Le Grand         mpPolyPolygon.reset();
516e6f63103SArmin Le Grand         mpRegionBand.reset(pNew);
517cdf0e10cSrcweir     }
518cdf0e10cSrcweir     else
519cdf0e10cSrcweir     {
520e6f63103SArmin Le Grand         OSL_ENSURE(false, "Region::Scale error: impossible combination (!)");
521e6f63103SArmin Le Grand     }
522e6f63103SArmin Le Grand }
523e6f63103SArmin Le Grand 
Union(const Rectangle & rRect)524e6f63103SArmin Le Grand bool Region::Union( const Rectangle& rRect )
525cdf0e10cSrcweir {
526cdf0e10cSrcweir     if(rRect.IsEmpty())
527cdf0e10cSrcweir     {
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())
533cdf0e10cSrcweir     {
534e6f63103SArmin Le Grand         // no local data, the union will be equal to source. Create using rectangle
535cdf0e10cSrcweir         *this = rRect;
536cdf0e10cSrcweir         return true;
537cdf0e10cSrcweir     }
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());
543cdf0e10cSrcweir 
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)));
565cdf0e10cSrcweir             *this = Region(aClip);
566cdf0e10cSrcweir         }
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     }
580e6f63103SArmin Le Grand 
581e6f63103SArmin Le Grand     RegionBand* pNew = new RegionBand(*pCurrent);
582cdf0e10cSrcweir 
583cdf0e10cSrcweir     // 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 
589cdf0e10cSrcweir     // insert bands if the boundaries are not allready in the list
590e6f63103SArmin Le Grand     pNew->InsertBands(nTop, nBottom);
591cdf0e10cSrcweir 
592cdf0e10cSrcweir     // process union
593e6f63103SArmin Le Grand     pNew->Union(nLeft, nTop, nRight, nBottom);
594cdf0e10cSrcweir 
595cdf0e10cSrcweir     // cleanup
596e6f63103SArmin Le Grand     if(!pNew->OptimizeBandList())
597cdf0e10cSrcweir     {
598e6f63103SArmin Le Grand         delete pNew;
599e6f63103SArmin Le Grand         pNew = 0;
600cdf0e10cSrcweir     }
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 {
608cdf0e10cSrcweir 	if ( rRect.IsEmpty() )
609cdf0e10cSrcweir 	{
610e6f63103SArmin Le Grand     	// empty rectangle will create empty region
611e6f63103SArmin Le Grand         SetEmpty();
612e6f63103SArmin Le Grand 		return true;
613cdf0e10cSrcweir 	}
614cdf0e10cSrcweir 
615e6f63103SArmin Le Grand     if(IsNull())
616cdf0e10cSrcweir     {
617e6f63103SArmin Le Grand         // null region (everything) intersect with rect will give rect
618e6f63103SArmin Le Grand         *this = rRect;
619e6f63103SArmin Le Grand         return true;
620cdf0e10cSrcweir     }
621cdf0e10cSrcweir 
622e6f63103SArmin Le Grand     if(IsEmpty())
6234e8e704fSArmin Le Grand     {
624e6f63103SArmin Le Grand         // no content, cannot get more empty
625e6f63103SArmin Le Grand         return true;
6264e8e704fSArmin Le Grand     }
6274e8e704fSArmin Le Grand 
628e6f63103SArmin Le Grand     if(HasPolyPolygonOrB2DPolyPolygon())
629cdf0e10cSrcweir     {
630e6f63103SArmin Le Grand         // if polygon data prefer double precision, the other will be lost (if buffered)
631e6f63103SArmin Le Grand         if(getB2DPolyPolygon())
632cdf0e10cSrcweir         {
633e6f63103SArmin Le Grand             const basegfx::B2DPolyPolygon aPoly(
6344e8e704fSArmin Le Grand                 basegfx::tools::clipPolyPolygonOnRange(
635e6f63103SArmin Le Grand                     *getB2DPolyPolygon(),
6364e8e704fSArmin Le Grand                     basegfx::B2DRange(
6374e8e704fSArmin Le Grand                         rRect.Left(),
6384e8e704fSArmin Le Grand                         rRect.Top(),
6394e8e704fSArmin Le Grand                         rRect.Right() + 1,
6404e8e704fSArmin Le Grand                         rRect.Bottom() + 1),
6414e8e704fSArmin Le Grand                     true,
642e6f63103SArmin Le Grand                     false));
6434e8e704fSArmin 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())
6494e8e704fSArmin Le Grand         {
650e6f63103SArmin Le Grand             PolyPolygon aPoly(*getPolyPolygon());
651e6f63103SArmin Le Grand 
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);
656e6f63103SArmin Le Grand 
657e6f63103SArmin Le Grand             mpB2DPolyPolygon.reset();
658e6f63103SArmin Le Grand             mpPolyPolygon.reset(aPoly.Count() ? new PolyPolygon(aPoly) : 0);
659e6f63103SArmin Le Grand             mpRegionBand.reset();
6604e8e704fSArmin Le Grand         }
6614e8e704fSArmin Le Grand 
662e6f63103SArmin Le Grand         return true;
663cdf0e10cSrcweir     }
664cdf0e10cSrcweir 
665e6f63103SArmin Le Grand     // only region band mode possibility left here or null/empty
666e6f63103SArmin Le Grand     const RegionBand* pCurrent = getRegionBand();
667e6f63103SArmin Le Grand 
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     }
673e6f63103SArmin Le Grand 
674e6f63103SArmin Le Grand     RegionBand* pNew = new RegionBand(*pCurrent);
675cdf0e10cSrcweir 
676cdf0e10cSrcweir     // 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 
682cdf0e10cSrcweir     // 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 
688cdf0e10cSrcweir     // cleanup
689e6f63103SArmin Le Grand     if(!pNew->OptimizeBandList())
690cdf0e10cSrcweir     {
691e6f63103SArmin Le Grand         delete pNew;
692e6f63103SArmin Le Grand         pNew = 0;
693cdf0e10cSrcweir     }
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 {
701cdf0e10cSrcweir 	if ( rRect.IsEmpty() )
702e6f63103SArmin Le Grand     {
703e6f63103SArmin Le Grand     	// excluding nothing will do no change
704e6f63103SArmin Le Grand 		return true;
705e6f63103SArmin Le Grand     }
706cdf0e10cSrcweir 
707e6f63103SArmin Le Grand     if(IsEmpty())
708e6f63103SArmin Le Grand     {
709e6f63103SArmin Le Grand         // cannot exclude from empty, done
710e6f63103SArmin Le Grand         return true;
711e6f63103SArmin Le Grand     }
712e6f63103SArmin Le Grand 
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     }
720e6f63103SArmin Le Grand 
721e6f63103SArmin Le Grand 	if( HasPolyPolygonOrB2DPolyPolygon() )
722cdf0e10cSrcweir 	{
723cdf0e10cSrcweir 	    // get this B2DPolyPolygon
724e6f63103SArmin Le Grand 	    basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
725e6f63103SArmin Le Grand 
726cdf0e10cSrcweir         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation(aThisPolyPoly);
727cdf0e10cSrcweir 
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;
732cdf0e10cSrcweir         }
733cdf0e10cSrcweir 
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;
744e6f63103SArmin Le Grand 	}
745e6f63103SArmin Le Grand 
746e6f63103SArmin Le Grand     // only region band mode possibility left here or null/empty
747e6f63103SArmin Le Grand     const RegionBand* pCurrent = getRegionBand();
748e6f63103SArmin Le Grand 
749e6f63103SArmin Le Grand     if(!pCurrent)
750e6f63103SArmin Le Grand     {
751e6f63103SArmin Le Grand         // empty? -> done!
752e6f63103SArmin Le Grand         return true;
753e6f63103SArmin Le Grand     }
754e6f63103SArmin Le Grand 
755e6f63103SArmin Le Grand     RegionBand* pNew = new RegionBand(*pCurrent);
756cdf0e10cSrcweir 
757cdf0e10cSrcweir     // 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 
763cdf0e10cSrcweir     // insert bands if the boundaries are not allready in the list
764e6f63103SArmin Le Grand     pNew->InsertBands(nTop, nBottom);
765cdf0e10cSrcweir 
766cdf0e10cSrcweir     // process exclude
767e6f63103SArmin Le Grand     pNew->Exclude(nLeft, nTop, nRight, nBottom);
768cdf0e10cSrcweir 
769cdf0e10cSrcweir     // cleanup
770e6f63103SArmin Le Grand     if(!pNew->OptimizeBandList())
771cdf0e10cSrcweir     {
772e6f63103SArmin Le Grand         delete pNew;
773e6f63103SArmin Le Grand         pNew = 0;
774cdf0e10cSrcweir     }
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     }
794e6f63103SArmin Le Grand 
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     }
802e6f63103SArmin Le Grand 
803e6f63103SArmin Le Grand     if( HasPolyPolygonOrB2DPolyPolygon() )
804cdf0e10cSrcweir 	{
805cdf0e10cSrcweir 	    // get this B2DPolyPolygon
806e6f63103SArmin Le Grand 	    basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
807e6f63103SArmin Le Grand 
808cdf0e10cSrcweir         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;
814e6f63103SArmin Le Grand 	        return true;
815cdf0e10cSrcweir 	    }
816cdf0e10cSrcweir 
817cdf0e10cSrcweir 	    // 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 
824cdf0e10cSrcweir         *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 
842cdf0e10cSrcweir     // 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 
848cdf0e10cSrcweir     // insert bands if the boundaries are not allready in the list
849e6f63103SArmin Le Grand     pNew->InsertBands(nTop, nBottom);
850cdf0e10cSrcweir 
851cdf0e10cSrcweir     // process xor
852e6f63103SArmin Le Grand     pNew->XOr(nLeft, nTop, nRight, nBottom);
853cdf0e10cSrcweir 
854cdf0e10cSrcweir     // cleanup
855e6f63103SArmin Le Grand     if(!pNew->OptimizeBandList())
856cdf0e10cSrcweir     {
857e6f63103SArmin Le Grand         delete pNew;
858e6f63103SArmin Le Grand         pNew = 0;
859cdf0e10cSrcweir     }
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 )
866e6f63103SArmin Le Grand {
867e6f63103SArmin Le Grand     if(rRegion.IsEmpty())
868e6f63103SArmin Le Grand     {
869e6f63103SArmin Le Grand         // no extension at all
870e6f63103SArmin Le Grand         return true;
871e6f63103SArmin Le Grand     }
872e6f63103SArmin 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;
878e6f63103SArmin Le Grand     }
879e6f63103SArmin Le Grand 
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     }
886e6f63103SArmin Le Grand 
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     }
892e6f63103SArmin Le Grand 
893e6f63103SArmin Le Grand 	if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() )
894cdf0e10cSrcweir 	{
895cdf0e10cSrcweir         // get this B2DPolyPolygon
896e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
897e6f63103SArmin Le Grand 
898cdf0e10cSrcweir         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation(aThisPolyPoly);
899cdf0e10cSrcweir 
900e6f63103SArmin Le Grand         if(!aThisPolyPoly.count())
901cdf0e10cSrcweir         {
902e6f63103SArmin Le Grand             // when no local content, union will be equal to rRegion
903e6f63103SArmin Le Grand             *this = rRegion;
904e6f63103SArmin Le Grand             return true;
905cdf0e10cSrcweir         }
906cdf0e10cSrcweir 
907cdf0e10cSrcweir         // get the other B2DPolyPolygon
908e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon());
909cdf0e10cSrcweir         aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation(aOtherPolyPoly);
910cdf0e10cSrcweir 
911e6f63103SArmin Le Grand         // use logical OR operation
912e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aClip(basegfx::tools::solvePolygonOperationOr(aThisPolyPoly, aOtherPolyPoly));
913cdf0e10cSrcweir 
914cdf0e10cSrcweir         *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)
922cdf0e10cSrcweir     {
923e6f63103SArmin Le Grand         // local is empty, union will give source region
924e6f63103SArmin Le Grand         *this = rRegion;
925e6f63103SArmin Le Grand 	    return true;
926cdf0e10cSrcweir     }
927cdf0e10cSrcweir 
928e6f63103SArmin Le Grand     const RegionBand* pSource = rRegion.getRegionBand();
929cdf0e10cSrcweir 
930e6f63103SArmin Le Grand     if(!pSource)
931cdf0e10cSrcweir     {
932e6f63103SArmin Le Grand         // no extension at all
933e6f63103SArmin Le Grand         return true;
934cdf0e10cSrcweir     }
935cdf0e10cSrcweir 
936e6f63103SArmin Le Grand     // prepare source and target
937e6f63103SArmin Le Grand     RegionBand* pNew = new RegionBand(*pCurrent);
938e6f63103SArmin Le Grand 
939e6f63103SArmin Le Grand     // union with source
940e6f63103SArmin Le Grand     pNew->Union(*pSource);
941cdf0e10cSrcweir 
942cdf0e10cSrcweir     // cleanup
943e6f63103SArmin Le Grand     if(!pNew->OptimizeBandList())
944cdf0e10cSrcweir     {
945e6f63103SArmin Le Grand         delete pNew;
946e6f63103SArmin Le Grand         pNew = 0;
947cdf0e10cSrcweir     }
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 )
954e6f63103SArmin Le Grand {
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     }
960e6f63103SArmin Le Grand 
961e6f63103SArmin Le Grand     if(getPolyPolygon() && getPolyPolygon() == rRegion.getPolyPolygon())
962e6f63103SArmin Le Grand     {
963e6f63103SArmin Le Grand         return true;
964e6f63103SArmin Le Grand     }
965e6f63103SArmin Le Grand 
966e6f63103SArmin Le Grand     if(getRegionBand() && getRegionBand() == rRegion.getRegionBand())
967e6f63103SArmin Le Grand     {
968e6f63103SArmin Le Grand         return true;
969e6f63103SArmin Le Grand     }
970e6f63103SArmin Le Grand 
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     }
976e6f63103SArmin Le Grand 
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     }
983e6f63103SArmin Le Grand 
984e6f63103SArmin Le Grand 	if(rRegion.IsEmpty())
985e6f63103SArmin Le Grand 	{
986e6f63103SArmin Le Grand         // source region is empty, intersection will always be empty
987e6f63103SArmin Le Grand         SetEmpty();
988e6f63103SArmin Le Grand 		return true;
989e6f63103SArmin Le Grand 	}
990e6f63103SArmin Le Grand 
991e6f63103SArmin Le Grand     if(IsEmpty())
992e6f63103SArmin Le Grand     {
993e6f63103SArmin Le Grand         // local region is empty, cannot get more emty than that. Nothing to do
994e6f63103SArmin Le Grand         return true;
995e6f63103SArmin Le Grand     }
996e6f63103SArmin Le Grand 
997e6f63103SArmin Le Grand     if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() )
998cdf0e10cSrcweir 	{
999cdf0e10cSrcweir         // get this B2DPolyPolygon
1000e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
1001e6f63103SArmin Le Grand 
1002e6f63103SArmin Le Grand         if(!aThisPolyPoly.count())
1003cdf0e10cSrcweir         {
1004e6f63103SArmin Le Grand             // local region is empty, cannot get more emty than that. Nothing to do
1005e6f63103SArmin Le Grand             return true;
1006cdf0e10cSrcweir         }
1007cdf0e10cSrcweir 
1008cdf0e10cSrcweir         // get the other B2DPolyPolygon
1009e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon());
1010cdf0e10cSrcweir 
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));
1024cdf0e10cSrcweir         *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)
1032cdf0e10cSrcweir     {
1033e6f63103SArmin Le Grand         // local region is empty, cannot get more emty than that. Nothing to do
1034e6f63103SArmin Le Grand         return true;
1035cdf0e10cSrcweir     }
1036cdf0e10cSrcweir 
1037e6f63103SArmin Le Grand     const RegionBand* pSource = rRegion.getRegionBand();
1038cdf0e10cSrcweir 
1039e6f63103SArmin Le Grand     if(!pSource)
1040cdf0e10cSrcweir     {
1041e6f63103SArmin Le Grand         // source region is empty, intersection will always be empty
1042e6f63103SArmin Le Grand         SetEmpty();
1043e6f63103SArmin Le Grand 		return true;
1044cdf0e10cSrcweir     }
1045cdf0e10cSrcweir 
1046e6f63103SArmin Le Grand     // both RegionBands exist and are not empty
1047e6f63103SArmin Le Grand     if(pCurrent->getRectangleCount() + 2 < pSource->getRectangleCount())
1048cdf0e10cSrcweir     {
1049e6f63103SArmin Le Grand         // when we have less rectangles, turn around the call
1050cdf0e10cSrcweir         Region aTempRegion = rRegion;
1051cdf0e10cSrcweir         aTempRegion.Intersect( *this );
1052cdf0e10cSrcweir         *this = aTempRegion;
1053cdf0e10cSrcweir     }
1054cdf0e10cSrcweir     else
1055cdf0e10cSrcweir     {
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 
1062cdf0e10cSrcweir         // cleanup
1063e6f63103SArmin Le Grand         if(!pNew->OptimizeBandList())
1064cdf0e10cSrcweir         {
1065e6f63103SArmin Le Grand             delete pNew;
1066e6f63103SArmin Le Grand             pNew = 0;
1067cdf0e10cSrcweir         }
1068cdf0e10cSrcweir 
1069e6f63103SArmin Le Grand         mpRegionBand.reset(pNew);
1070cdf0e10cSrcweir     }
1071cdf0e10cSrcweir 
1072e6f63103SArmin Le Grand     return true;
1073e6f63103SArmin Le Grand }
1074e6f63103SArmin Le Grand 
Exclude(const Region & rRegion)1075e6f63103SArmin Le Grand bool Region::Exclude( const Region& rRegion )
1076e6f63103SArmin Le Grand {
1077e6f63103SArmin Le Grand 	if ( rRegion.IsEmpty() )
1078e6f63103SArmin Le Grand     {
1079e6f63103SArmin Le Grand     	// excluding nothing will do no change
1080e6f63103SArmin Le Grand 		return true;
1081e6f63103SArmin Le Grand     }
1082e6f63103SArmin Le Grand 
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     }
1089e6f63103SArmin Le Grand 
1090e6f63103SArmin Le Grand     if(IsEmpty())
1091e6f63103SArmin Le Grand     {
1092e6f63103SArmin Le Grand         // cannot exclude from empty, done
1093e6f63103SArmin Le Grand         return true;
1094e6f63103SArmin Le Grand     }
1095e6f63103SArmin Le Grand 
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     }
1103e6f63103SArmin Le Grand 
1104e6f63103SArmin Le Grand 	if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() )
1105cdf0e10cSrcweir 	{
1106cdf0e10cSrcweir         // get this B2DPolyPolygon
1107e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
1108e6f63103SArmin Le Grand 
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         }
1114e6f63103SArmin Le Grand 
1115cdf0e10cSrcweir         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
1116cdf0e10cSrcweir 
1117cdf0e10cSrcweir         // get the other B2DPolyPolygon
1118e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon());
1119cdf0e10cSrcweir         aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly );
1120cdf0e10cSrcweir 
1121cdf0e10cSrcweir         basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationDiff( aThisPolyPoly, aOtherPolyPoly );
1122cdf0e10cSrcweir         *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();
1128e6f63103SArmin Le Grand 
1129e6f63103SArmin Le Grand     if(!pCurrent)
1130cdf0e10cSrcweir     {
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();
1136e6f63103SArmin Le Grand 
1137e6f63103SArmin Le Grand     if(!pSource)
1138cdf0e10cSrcweir     {
1139e6f63103SArmin Le Grand     	// excluding nothing will do no change
1140e6f63103SArmin Le Grand 		return true;
1141cdf0e10cSrcweir     }
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)
1151cdf0e10cSrcweir     {
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;
1158e6f63103SArmin Le Grand }
1159e6f63103SArmin Le Grand 
XOr(const Region & rRegion)1160e6f63103SArmin Le Grand bool Region::XOr( const Region& rRegion )
1161cdf0e10cSrcweir {
1162e6f63103SArmin Le Grand 	if ( rRegion.IsEmpty() )
1163cdf0e10cSrcweir     {
1164e6f63103SArmin Le Grand     	// empty region will not change local content
1165e6f63103SArmin Le Grand 		return true;
1166cdf0e10cSrcweir     }
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;
1174cdf0e10cSrcweir     }
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;
1181cdf0e10cSrcweir     }
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     }
1190e6f63103SArmin Le Grand 
1191e6f63103SArmin Le Grand     if( rRegion.HasPolyPolygonOrB2DPolyPolygon() || HasPolyPolygonOrB2DPolyPolygon() )
1192cdf0e10cSrcweir 	{
1193cdf0e10cSrcweir         // get this B2DPolyPolygon
1194e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aThisPolyPoly(GetAsB2DPolyPolygon());
1195e6f63103SArmin Le Grand 
1196e6f63103SArmin Le Grand         if(!aThisPolyPoly.count())
1197cdf0e10cSrcweir         {
1198e6f63103SArmin Le Grand             // rRect will be the xored-form (local off, rect on)
1199e6f63103SArmin Le Grand             *this = rRegion;
1200e6f63103SArmin Le Grand             return true;
1201cdf0e10cSrcweir         }
1202e6f63103SArmin Le Grand 
1203cdf0e10cSrcweir         aThisPolyPoly = basegfx::tools::prepareForPolygonOperation( aThisPolyPoly );
1204cdf0e10cSrcweir 
1205cdf0e10cSrcweir         // get the other B2DPolyPolygon
1206e6f63103SArmin Le Grand         basegfx::B2DPolyPolygon aOtherPolyPoly(rRegion.GetAsB2DPolyPolygon());
1207cdf0e10cSrcweir         aOtherPolyPoly = basegfx::tools::prepareForPolygonOperation( aOtherPolyPoly );
1208cdf0e10cSrcweir 
1209cdf0e10cSrcweir         basegfx::B2DPolyPolygon aClip = basegfx::tools::solvePolygonOperationXor( aThisPolyPoly, aOtherPolyPoly );
1210cdf0e10cSrcweir         *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();
1216e6f63103SArmin Le Grand 
1217e6f63103SArmin Le Grand     if(!pCurrent)
1218cdf0e10cSrcweir     {
1219e6f63103SArmin Le Grand         // rRect will be the xored-form (local off, rect on)
1220cdf0e10cSrcweir         *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);
1234e6f63103SArmin Le Grand 
1235e6f63103SArmin Le Grand     // union with source
1236e6f63103SArmin Le Grand     pNew->XOr(*pSource);
1237cdf0e10cSrcweir 
1238cdf0e10cSrcweir     // cleanup
1239e6f63103SArmin Le Grand     if(!pNew->OptimizeBandList())
1240cdf0e10cSrcweir     {
1241e6f63103SArmin Le Grand         delete pNew;
1242e6f63103SArmin Le Grand         pNew = 0;
1243cdf0e10cSrcweir     }
1244cdf0e10cSrcweir 
1245e6f63103SArmin Le Grand     mpRegionBand.reset(pNew);
1246cdf0e10cSrcweir 
1247e6f63103SArmin Le Grand 	return true;
1248e6f63103SArmin Le Grand }
1249cdf0e10cSrcweir 
GetBoundRect() const1250cdf0e10cSrcweir Rectangle Region::GetBoundRect() const
1251cdf0e10cSrcweir {
1252e6f63103SArmin Le Grand 	if(IsEmpty())
1253cdf0e10cSrcweir     {
1254e6f63103SArmin Le Grand     	// no internal data? -> region is empty!
1255e6f63103SArmin Le Grand 		return Rectangle();
1256e6f63103SArmin Le Grand     }
1257e6f63103SArmin Le Grand 
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     }
1264e6f63103SArmin Le Grand 
1265e6f63103SArmin Le Grand     // prefer double precision source
1266e6f63103SArmin Le Grand 	if(getB2DPolyPolygon())
1267e6f63103SArmin Le Grand 	{
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())
1285cdf0e10cSrcweir     {
1286e6f63103SArmin Le Grand 		return getPolyPolygon()->GetBoundRect();
1287cdf0e10cSrcweir     }
1288cdf0e10cSrcweir 
1289e6f63103SArmin Le Grand     if(getRegionBand())
1290e6f63103SArmin Le Grand     {
1291e6f63103SArmin Le Grand         return getRegionBand()->GetBoundRect();
1292cdf0e10cSrcweir     }
1293cdf0e10cSrcweir 
1294e6f63103SArmin Le Grand 	return Rectangle();
1295e6f63103SArmin Le Grand }
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     }
1303e6f63103SArmin Le Grand 
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));
1309e6f63103SArmin Le Grand 
1310e6f63103SArmin Le Grand         return *getPolyPolygon();
1311e6f63103SArmin Le Grand     }
1312e6f63103SArmin Le Grand 
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));
1318e6f63103SArmin Le Grand 
1319e6f63103SArmin Le Grand         return *getPolyPolygon();
1320e6f63103SArmin Le Grand     }
1321e6f63103SArmin Le Grand 
1322e6f63103SArmin Le Grand     return PolyPolygon();
1323e6f63103SArmin Le Grand }
1324e6f63103SArmin Le Grand 
GetAsB2DPolyPolygon() const1325e6f63103SArmin Le Grand const basegfx::B2DPolyPolygon Region::GetAsB2DPolyPolygon() const
1326e6f63103SArmin Le Grand {
1327e6f63103SArmin Le Grand     if(getB2DPolyPolygon())
1328e6f63103SArmin Le Grand     {
1329e6f63103SArmin Le Grand         return *getB2DPolyPolygon();
1330e6f63103SArmin Le Grand     }
1331e6f63103SArmin Le Grand 
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));
1337e6f63103SArmin Le Grand 
1338e6f63103SArmin Le Grand         return *getB2DPolyPolygon();
1339e6f63103SArmin Le Grand     }
1340e6f63103SArmin Le Grand 
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));
1346e6f63103SArmin Le Grand 
1347e6f63103SArmin Le Grand         return *getB2DPolyPolygon();
1348e6f63103SArmin Le Grand     }
1349e6f63103SArmin Le Grand 
1350e6f63103SArmin Le Grand     return basegfx::B2DPolyPolygon();
1351e6f63103SArmin Le Grand }
1352e6f63103SArmin Le Grand 
GetAsRegionBand() const1353e6f63103SArmin Le Grand const RegionBand* Region::GetAsRegionBand() const
1354e6f63103SArmin Le Grand {
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     }
1368e6f63103SArmin Le Grand 
1369e6f63103SArmin Le Grand     return getRegionBand();
1370e6f63103SArmin Le Grand }
1371e6f63103SArmin Le Grand 
IsInside(const Point & rPoint) const1372e6f63103SArmin Le Grand bool Region::IsInside( const Point& rPoint ) const
1373e6f63103SArmin Le Grand {
1374e6f63103SArmin Le Grand 	if(IsEmpty())
1375e6f63103SArmin Le Grand     {
1376e6f63103SArmin Le Grand         // no point can be in empty region
1377cdf0e10cSrcweir 		return false;
1378cdf0e10cSrcweir     }
1379cdf0e10cSrcweir 
1380e6f63103SArmin Le Grand     if(IsNull())
1381cdf0e10cSrcweir     {
1382e6f63103SArmin Le Grand         // all points are inside null-region
1383cdf0e10cSrcweir         return true;
1384cdf0e10cSrcweir     }
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();
1394e6f63103SArmin Le Grand 
1395e6f63103SArmin Le Grand     if(pRegionBand)
1396cdf0e10cSrcweir     {
1397e6f63103SArmin Le Grand         return pRegionBand->IsInside(rPoint);
1398cdf0e10cSrcweir     }
1399cdf0e10cSrcweir 
1400e6f63103SArmin Le Grand     return false;
1401e6f63103SArmin Le Grand }
1402cdf0e10cSrcweir 
IsInside(const Rectangle & rRect) const1403e6f63103SArmin Le Grand bool Region::IsInside( const Rectangle& rRect ) const
1404e6f63103SArmin Le Grand {
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
1414cdf0e10cSrcweir         return true;
1415cdf0e10cSrcweir     }
1416cdf0e10cSrcweir 
1417cdf0e10cSrcweir 	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);
1425cdf0e10cSrcweir 	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 
1483cdf0e10cSrcweir     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 
1493cdf0e10cSrcweir     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())
1499cdf0e10cSrcweir     {
1500e6f63103SArmin Le Grand         // both are null region
1501e6f63103SArmin Le Grand         return true;
1502cdf0e10cSrcweir     }
1503cdf0e10cSrcweir 
1504e6f63103SArmin Le Grand     if(IsEmpty() && rRegion.IsEmpty())
1505cdf0e10cSrcweir     {
1506e6f63103SArmin Le Grand         // both are empty
1507e6f63103SArmin Le Grand         return true;
1508e6f63103SArmin Le Grand     }
1509cdf0e10cSrcweir 
1510e6f63103SArmin Le Grand     if(getB2DPolyPolygon() && getB2DPolyPolygon() == rRegion.getB2DPolyPolygon())
1511cdf0e10cSrcweir     {
1512e6f63103SArmin Le Grand         // same instance data? -> equal
1513e6f63103SArmin Le Grand         return true;
1514cdf0e10cSrcweir     }
1515cdf0e10cSrcweir 
1516e6f63103SArmin Le Grand     if(getPolyPolygon() && getPolyPolygon() == rRegion.getPolyPolygon())
1517cdf0e10cSrcweir     {
1518e6f63103SArmin Le Grand         // same instance data? -> equal
1519e6f63103SArmin Le Grand         return true;
1520cdf0e10cSrcweir     }
1521cdf0e10cSrcweir 
1522e6f63103SArmin Le Grand     if(getRegionBand() && getRegionBand() == rRegion.getRegionBand())
1523e6f63103SArmin Le Grand     {
1524e6f63103SArmin Le Grand         // same instance data? -> equal
1525e6f63103SArmin Le Grand         return true;
1526cdf0e10cSrcweir     }
1527cdf0e10cSrcweir 
1528e6f63103SArmin Le Grand 	if(IsNull() || IsEmpty())
1529e6f63103SArmin Le Grand     {
1530e6f63103SArmin Le Grand 		return false;
1531cdf0e10cSrcweir     }
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();
1544e6f63103SArmin Le Grand 
1545e6f63103SArmin Le Grand         return *rRegion.getB2DPolyPolygon() == *getB2DPolyPolygon();
1546e6f63103SArmin Le Grand     }
1547e6f63103SArmin Le Grand 
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();
1554e6f63103SArmin Le Grand 
1555e6f63103SArmin Le Grand         return *rRegion.getPolyPolygon() == *getPolyPolygon();
1556e6f63103SArmin Le Grand     }
1557e6f63103SArmin Le Grand 
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     }
1565e6f63103SArmin Le Grand 
1566e6f63103SArmin Le Grand     // should not happen, but better deny equality
1567e6f63103SArmin Le Grand     return false;
1568e6f63103SArmin Le Grand }
1569cdf0e10cSrcweir 
operator >>(SvStream & rIStrm,Region & rRegion)1570cdf0e10cSrcweir SvStream& operator>>(SvStream& rIStrm, Region& rRegion)
1571cdf0e10cSrcweir {
1572cdf0e10cSrcweir     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 
1579cdf0e10cSrcweir     // get version of streamed region
1580cdf0e10cSrcweir     rIStrm >> nVersion;
1581cdf0e10cSrcweir 
1582cdf0e10cSrcweir     // get type of region
1583cdf0e10cSrcweir     rIStrm >> nTmp16;
1584cdf0e10cSrcweir 
1585e6f63103SArmin Le Grand     enum RegionType { REGION_NULL, REGION_EMPTY, REGION_RECTANGLE, REGION_COMPLEX };
1586cdf0e10cSrcweir     RegionType meStreamedType = (RegionType)nTmp16;
1587cdf0e10cSrcweir 
1588cdf0e10cSrcweir     switch(meStreamedType)
1589cdf0e10cSrcweir     {
1590cdf0e10cSrcweir         case REGION_NULL:
1591e6f63103SArmin Le Grand         {
1592e6f63103SArmin Le Grand             rRegion.SetNull();
1593cdf0e10cSrcweir             break;
1594e6f63103SArmin Le Grand         }
1595cdf0e10cSrcweir 
1596cdf0e10cSrcweir         case REGION_EMPTY:
1597e6f63103SArmin Le Grand         {
1598e6f63103SArmin Le Grand             rRegion.SetEmpty();
1599cdf0e10cSrcweir             break;
1600e6f63103SArmin Le Grand         }
1601cdf0e10cSrcweir 
1602cdf0e10cSrcweir         default:
1603cdf0e10cSrcweir         {
1604e6f63103SArmin Le Grand             RegionBand* pNewRegionBand = new RegionBand();
1605e6f63103SArmin Le Grand             pNewRegionBand->load(rIStrm);
1606e6f63103SArmin Le Grand             rRegion.mpRegionBand.reset(pNewRegionBand);
1607cdf0e10cSrcweir 
1608cdf0e10cSrcweir             if(aCompat.GetVersion() >= 2)
1609cdf0e10cSrcweir             {
1610e6f63103SArmin Le Grand                 sal_Bool bHasPolyPolygon(sal_False);
1611cdf0e10cSrcweir 
1612cdf0e10cSrcweir                 rIStrm >> bHasPolyPolygon;
1613cdf0e10cSrcweir 
1614cdf0e10cSrcweir                 if(bHasPolyPolygon)
1615cdf0e10cSrcweir                 {
1616e6f63103SArmin Le Grand                     PolyPolygon* pNewPoly = new PolyPolygon();
1617e6f63103SArmin Le Grand                     rIStrm >> *pNewPoly;
1618e6f63103SArmin Le Grand                     rRegion.mpPolyPolygon.reset(pNewPoly);
1619cdf0e10cSrcweir                 }
1620cdf0e10cSrcweir             }
1621e6f63103SArmin Le Grand 
1622cdf0e10cSrcweir             break;
1623cdf0e10cSrcweir         }
1624e6f63103SArmin Le Grand     }
1625cdf0e10cSrcweir 
1626cdf0e10cSrcweir     return rIStrm;
1627cdf0e10cSrcweir }
1628cdf0e10cSrcweir 
operator <<(SvStream & rOStrm,const Region & rRegion)1629cdf0e10cSrcweir SvStream& operator<<( SvStream& rOStrm, const Region& rRegion )
1630cdf0e10cSrcweir {
1631e6f63103SArmin Le Grand     const sal_uInt16 nVersion(2);
1632cdf0e10cSrcweir     VersionCompat aCompat(rOStrm, STREAM_WRITE, nVersion);
1633cdf0e10cSrcweir 
1634cdf0e10cSrcweir     // put version
1635cdf0e10cSrcweir     rOStrm << nVersion;
1636cdf0e10cSrcweir 
1637cdf0e10cSrcweir     // 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())
1643cdf0e10cSrcweir     {
1644e6f63103SArmin Le Grand         OSL_ENSURE(false, "Region with empty B2DPolyPolygon, should not be created (!)");
1645e6f63103SArmin Le Grand         bEmpty = true;
1646cdf0e10cSrcweir     }
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;
1652cdf0e10cSrcweir     }
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     }
1666e6f63103SArmin Le Grand 
1667e6f63103SArmin Le Grand     rOStrm << (sal_uInt16)aRegionType;
1668e6f63103SArmin Le Grand 
1669e6f63103SArmin Le Grand     // get RegionBand
1670e6f63103SArmin Le Grand     const RegionBand* pRegionBand = rRegion.getRegionBand();
1671e6f63103SArmin Le Grand 
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 
1685cdf0e10cSrcweir     // write polypolygon if available
1686e6f63103SArmin Le Grand     const sal_Bool bHasPolyPolygon(rRegion.HasPolyPolygonOrB2DPolyPolygon());
1687cdf0e10cSrcweir     rOStrm << bHasPolyPolygon;
1688cdf0e10cSrcweir 
1689cdf0e10cSrcweir     if(bHasPolyPolygon)
1690cdf0e10cSrcweir     {
1691cdf0e10cSrcweir         // #i105373#
1692cdf0e10cSrcweir         PolyPolygon aNoCurvePolyPolygon;
1693e6f63103SArmin Le Grand         rRegion.GetAsPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon);
1694cdf0e10cSrcweir 
1695cdf0e10cSrcweir         rOStrm << aNoCurvePolyPolygon;
1696cdf0e10cSrcweir     }
1697cdf0e10cSrcweir 
1698cdf0e10cSrcweir     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();
1708e6f63103SArmin Le Grand 
1709e6f63103SArmin Le Grand     if(pRegionBand)
1710cdf0e10cSrcweir     {
1711e6f63103SArmin Le Grand         pRegionBand->GetRegionRectangles(rTarget);
1712cdf0e10cSrcweir     }
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++;
1790cdf0e10cSrcweir         }
1791e6f63103SArmin Le Grand     }
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) );
1812cdf0e10cSrcweir         }
1813e6f63103SArmin Le Grand     }
1814e6f63103SArmin Le Grand 
1815cdf0e10cSrcweir     return aResult;
1816cdf0e10cSrcweir }
1817e6f63103SArmin Le Grand 
1818e6f63103SArmin Le Grand //////////////////////////////////////////////////////////////////////////////
1819e6f63103SArmin Le Grand // eof
1820