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