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