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