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