23#include <osl/diagnose.h>
46 const sal_uInt16 nPolyCount = rPolyPoly.
Count();
47 for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly)
52 const sal_uInt16 nSize = aPoly.
GetSize();
57 const Point aLastPoint (aPoint);
58 for (sal_uInt16 nPoint = 1; nPoint < nSize; ++nPoint)
64 if (aPoint.X() != aNextPoint.X() && aPoint.Y() != aNextPoint.Y())
70 if (aLastPoint.X() != aPoint.X() && aLastPoint.Y() != aPoint.Y())
88 std::shared_ptr<RegionBand> ImplRectilinearPolygonToBands(
const tools::PolyPolygon& rPolyPoly)
90 OSL_ASSERT(ImplIsPolygonRectilinear (rPolyPoly));
93 std::shared_ptr<RegionBand> pRegionBand( std::make_shared<RegionBand>() );
97 const sal_uInt16 nPolyCount = rPolyPoly.
Count();
98 for (sal_uInt16 nPoly = 0; nPoly < nPolyCount; ++nPoly)
103 const sal_uInt16 nSize = aPoly.
GetSize();
110 for (sal_uInt16 nPoint = 1; nPoint <= nSize; ++nPoint, aStart=aEnd)
114 aEnd = aPoly.
GetPoint(nPoint%nSize);
115 if (aStart.Y() == aEnd.
Y())
122 OSL_ASSERT(aStart.X() == aEnd.
X());
127 const tools::Long nTop (::std::min(aStart.Y(), aEnd.
Y()));
128 const tools::Long nBottom (::std::max(aStart.Y(), aEnd.
Y()));
132 pRegionBand->ImplAddMissingBands(nTop,nBottom);
136 while (pBand!=
nullptr && pBand->
mnYBottom < nTop)
154 while (pBand!=
nullptr && pBand->
mnYBottom < nBottom)
175 for (pBand=pTopBand; pBand!=
nullptr&&pBand->
mnYTop<=nBottom; pBand=pBand->
mpNextBand)
176 pBand->
InsertPoint(aStart.X(), nLineId++,
true, eLineType);
191 std::shared_ptr<RegionBand> pRegionBand( std::make_shared<RegionBand>() );
192 pRegionBand->CreateBandRange(rPolygonBoundingBox.
Top(), rPolygonBoundingBox.
Bottom());
195 const sal_uInt16 nPolyCount = rPolyPoly.
Count();
197 for ( sal_uInt16 nPoly = 0; nPoly < nPolyCount; nPoly++ )
201 const sal_uInt16 nSize = aPoly.
GetSize();
208 for ( sal_uInt16 nPoint = 1; nPoint < nSize; nPoint++ )
210 pRegionBand->InsertLine( aPoly.
GetPoint(nPoint-1), aPoly.
GetPoint(nPoint), nLineID++ );
217 if ( rLastPoint != rFirstPoint )
219 pRegionBand->InsertLine( rLastPoint, rFirstPoint, nLineID++ );
231 return !mbIsNull && !mpB2DPolyPolygon && !mpPolyPolygon && !mpRegionBand;
237 std::shared_ptr<RegionBand> pRetval;
239 if(rPolyPolygon.
Count())
247 if(aPolyPolygon.
Count())
253 if(ImplIsPolygonRectilinear(aPolyPolygon))
256 pRetval = ImplRectilinearPolygonToBands(aPolyPolygon);
260 pRetval = ImplGeneralPolygonToBands(aPolyPolygon, aRect);
266 pRetval->processPoints();
270 if(!pRetval->OptimizeBandList())
289 GetRegionRectangles(aRectangles);
291 for (
auto const&
rectangle : aRectangles)
298 OSL_ENSURE(
false,
"Called with no local RegionBand (!)");
337 if(rPolyPoly.
Count())
347 if(rPolyPoly.
count())
356: mpB2DPolyPolygon(std::move(rRegion.mpB2DPolyPolygon)),
357 mpPolyPolygon(std::move(rRegion.mpPolyPolygon)),
358 mpRegionBand(std::move(rRegion.mpRegionBand)),
359 mbIsNull(rRegion.mbIsNull)
361 rRegion.mbIsNull =
true;
368 const sal_uInt16 nPolyCount = rPolyPoly.
Count();
382 mpRegionBand = std::make_shared<RegionBand>(aRect);
386 mpPolyPolygon = rPolyPoly;
396 mpB2DPolyPolygon = rPolyPoly;
403 if(IsNull() || IsEmpty())
409 if(!nHorzMove && !nVertMove)
415 if(getB2DPolyPolygon())
421 mpB2DPolyPolygon = aPoly;
423 mpB2DPolyPolygon.reset();
424 mpPolyPolygon.reset();
425 mpRegionBand.reset();
427 else if(getPolyPolygon())
431 aPoly.
Move(nHorzMove, nVertMove);
432 mpB2DPolyPolygon.reset();
434 mpPolyPolygon = aPoly;
436 mpPolyPolygon.reset();
437 mpRegionBand.reset();
439 else if(getRegionBand())
441 std::shared_ptr<RegionBand> pNew = std::make_shared<RegionBand>(*getRegionBand());
443 pNew->Move(nHorzMove, nVertMove);
444 mpB2DPolyPolygon.reset();
445 mpPolyPolygon.reset();
446 mpRegionBand = std::move(pNew);
450 OSL_ENSURE(
false,
"Region::Move error: impossible combination (!)");
456 if(IsNull() || IsEmpty())
468 if(getB2DPolyPolygon())
474 mpB2DPolyPolygon = aPoly;
476 mpB2DPolyPolygon.reset();
477 mpPolyPolygon.reset();
478 mpRegionBand.reset();
480 else if(getPolyPolygon())
484 aPoly.
Scale(fScaleX, fScaleY);
485 mpB2DPolyPolygon.reset();
487 mpPolyPolygon = aPoly;
489 mpPolyPolygon.reset();
490 mpRegionBand.reset();
492 else if(getRegionBand())
494 std::shared_ptr<RegionBand> pNew = std::make_shared<RegionBand>(*getRegionBand());
496 pNew->Scale(fScaleX, fScaleY);
497 mpB2DPolyPolygon.reset();
498 mpPolyPolygon.reset();
499 mpRegionBand = std::move(pNew);
503 OSL_ENSURE(
false,
"Region::Scale error: impossible combination (!)");
522 if(HasPolyPolygonOrB2DPolyPolygon())
529 if(!aThisPolyPoly.
count())
560 std::shared_ptr<RegionBand> pNew = std::make_shared<RegionBand>(*pCurrent);
569 pNew->InsertBands(nTop, nBottom);
572 pNew->Union(nLeft, nTop, nRight, nBottom);
575 if(!pNew->OptimizeBandList())
580 mpRegionBand = std::move(pNew);
605 if(HasPolyPolygonOrB2DPolyPolygon())
608 if(getB2DPolyPolygon())
612 *getB2DPolyPolygon(),
622 mpB2DPolyPolygon = aPoly;
624 mpB2DPolyPolygon.reset();
625 mpPolyPolygon.reset();
626 mpRegionBand.reset();
637 mpB2DPolyPolygon.reset();
639 mpPolyPolygon = aPoly;
641 mpPolyPolygon.reset();
642 mpRegionBand.reset();
657 std::shared_ptr<RegionBand> pNew( std::make_shared<RegionBand>(*pCurrent));
666 pNew->InsertBands(nTop, nBottom);
669 pNew->Intersect(nLeft, nTop, nRight, nBottom);
672 if(!pNew->OptimizeBandList())
677 mpRegionBand = std::move(pNew);
698 OSL_ENSURE(
false,
"Region::Exclude error: Cannot exclude from null region (!)");
702 if( HasPolyPolygonOrB2DPolyPolygon() )
709 if(!aThisPolyPoly.
count())
734 std::shared_ptr<RegionBand>& pNew = mpRegionBand;
736 if (pNew.use_count() > 1)
737 pNew = std::make_shared<RegionBand>(*pNew);
746 pNew->InsertBands(nTop, nBottom);
749 pNew->Exclude(nLeft, nTop, nRight, nBottom);
752 if(!pNew->OptimizeBandList())
775 OSL_ENSURE(
false,
"Region::XOr error: Cannot XOr with null region (!)");
779 if( HasPolyPolygonOrB2DPolyPolygon() )
786 if(!aThisPolyPoly.
count())
816 std::shared_ptr<RegionBand> pNew( std::make_shared<RegionBand>(*getRegionBand()));
825 pNew->InsertBands(nTop, nBottom);
828 pNew->XOr(nLeft, nTop, nRight, nBottom);
831 if(!pNew->OptimizeBandList())
836 mpRegionBand = std::move(pNew);
874 if(!aThisPolyPoly.
count())
911 std::shared_ptr<RegionBand> pNew( std::make_shared<RegionBand>(*pCurrent));
914 pNew->Union(*pSource);
917 if(!pNew->OptimizeBandList())
922 mpRegionBand = std::move(pNew);
933 if(getPolyPolygon() && getPolyPolygon() == rRegion.
getPolyPolygon())
938 if(getRegionBand() && getRegionBand() == rRegion.
getRegionBand())
974 if(!aThisPolyPoly.
count())
983 if(!aOtherPolyPoly.
count())
991 size_t nPointLimit(gPointLimit);
1004 const RegionBand* pCurrent = getRegionBand();
1027 *
this = aTempRegion;
1032 std::shared_ptr<RegionBand> pNew( std::make_shared<RegionBand>(*pCurrent));
1035 pNew->Intersect(*pSource);
1038 if(!pNew->OptimizeBandList())
1043 mpRegionBand = std::move(pNew);
1072 OSL_ENSURE(
false,
"Region::Exclude error: Cannot exclude from null region (!)");
1081 if(!aThisPolyPoly.
count())
1099 const RegionBand* pCurrent = getRegionBand();
1116 std::shared_ptr<RegionBand> pNew( std::make_shared<RegionBand>(*pCurrent));
1119 const bool bSuccess(pNew->Exclude(*pSource));
1127 mpRegionBand = std::move(pNew);
1142 OSL_ENSURE(
false,
"Region::XOr error: Cannot XOr with null region (!)");
1157 OSL_ENSURE(
false,
"Region::XOr error: Cannot XOr with null region (!)");
1166 if(!aThisPolyPoly.
count())
1185 const RegionBand* pCurrent = getRegionBand();
1203 std::shared_ptr<RegionBand> pNew( std::make_shared<RegionBand>(*pCurrent));
1206 pNew->XOr(*pSource);
1209 if(!pNew->OptimizeBandList())
1214 mpRegionBand = std::move(pNew);
1235 if(getB2DPolyPolygon())
1253 if(getPolyPolygon())
1255 return getPolyPolygon()->GetBoundRect();
1260 return getRegionBand()->GetBoundRect();
1268 if(getPolyPolygon())
1270 return *getPolyPolygon();
1273 if(getB2DPolyPolygon())
1277 const_cast< vcl::Region*
>(
this)->mpPolyPolygon = aPolyPolgon;
1279 return *getPolyPolygon();
1286 const_cast< vcl::Region*
>(
this)->mpPolyPolygon = aPolyPolgon;
1288 return *getPolyPolygon();
1296 if(getB2DPolyPolygon())
1298 return *getB2DPolyPolygon();
1301 if(getPolyPolygon())
1305 const_cast< vcl::Region*
>(
this)->mpB2DPolyPolygon = aB2DPolyPolygon;
1307 return *getB2DPolyPolygon();
1314 const_cast< vcl::Region*
>(
this)->mpB2DPolyPolygon = aB2DPolyPolygon;
1316 return *getB2DPolyPolygon();
1324 if(!getRegionBand())
1326 if(getB2DPolyPolygon())
1331 else if(getPolyPolygon())
1338 return getRegionBand();
1362 const RegionBand* pRegionBand = GetAsRegionBand();
1366 return pRegionBand->
Contains(rPoint);
1398 if( IsEmpty() || IsNull() )
1401 if( getB2DPolyPolygon() )
1404 if( getPolyPolygon() )
1405 return getPolyPolygon()->IsRect();
1407 if( getRegionBand() )
1408 return (getRegionBand()->getRectangleCount() == 1);
1416 mpB2DPolyPolygon.reset();
1417 mpPolyPolygon.reset();
1418 mpRegionBand.reset();
1425 mpB2DPolyPolygon.reset();
1426 mpPolyPolygon.reset();
1427 mpRegionBand.reset();
1435 mpB2DPolyPolygon = std::move(rRegion.mpB2DPolyPolygon);
1436 mpPolyPolygon = std::move(rRegion.mpPolyPolygon);
1437 mpRegionBand = std::move(rRegion.mpRegionBand);
1438 mbIsNull = rRegion.mbIsNull;
1439 rRegion.mbIsNull =
true;
1446 mpB2DPolyPolygon.reset();
1447 mpPolyPolygon.reset();
1449 mpRegionBand = std::make_shared<RegionBand>(rRect);
1451 mpRegionBand.reset();
1459 if(IsNull() && rRegion.
IsNull())
1465 if(IsEmpty() && rRegion.
IsEmpty())
1477 if(getPolyPolygon() && getPolyPolygon() == rRegion.
getPolyPolygon())
1483 if(getRegionBand() && getRegionBand() == rRegion.
getRegionBand())
1489 if(IsNull() || IsEmpty())
1503 GetAsB2DPolyPolygon();
1535 sal_uInt16 nTmp16(0);
1546 enum RegionType { REGION_NULL, REGION_EMPTY, REGION_RECTANGLE, REGION_COMPLEX };
1547 auto eStreamedType = nTmp16;
1549 switch (eStreamedType)
1565 std::shared_ptr<RegionBand> xNewRegionBand(std::make_shared<RegionBand>());
1566 bool bSuccess = xNewRegionBand->load(rIStrm);
1569 bool bHasPolyPolygon(
false);
1574 if (bHasPolyPolygon)
1578 const auto nPolygons = aNewPoly.
Count();
1579 if (nPolygons > 128)
1581 SAL_WARN(
"vcl.gdi",
"suspiciously high no of polygons in clip:" << nPolygons);
1589 if (!bSuccess && !bHasPolyPolygon)
1591 SAL_WARN(
"vcl.gdi",
"bad region band:" << bHasPolyPolygon);
1611 enum RegionType { REGION_NULL, REGION_EMPTY, REGION_RECTANGLE, REGION_COMPLEX };
1612 RegionType aRegionType(REGION_COMPLEX);
1613 bool bEmpty(rRegion.
IsEmpty());
1617 OSL_ENSURE(
false,
"Region with empty B2DPolyPolygon, should not be created (!)");
1623 OSL_ENSURE(
false,
"Region with empty PolyPolygon, should not be created (!)");
1629 aRegionType = REGION_EMPTY;
1631 else if(rRegion.
IsNull())
1633 aRegionType = REGION_NULL;
1637 aRegionType = REGION_RECTANGLE;
1647 pRegionBand->
save(rOStrm);
1655 aRegionBand.
save(rOStrm);
1680 const RegionBand* pRegionBand = GetAsRegionBand();
1690 bool bIsRect =
false;
1692 sal_uInt16 nPoints = rPoly.
GetSize();
1694 if( nPoints == 4 || (nPoints == 5 && pPoints[0] == pPoints[4]) )
1696 tools::Long nX1 = pPoints[0].
X(), nX2 = pPoints[2].
X(), nY1 = pPoints[0].
Y(), nY2 = pPoints[2].
Y();
1698 if( ( (pPoints[1].
X() == nX1 && pPoints[3].
X() == nX2) && (pPoints[1].
Y() == nY2 && pPoints[3].
Y() == nY1) )
1699 || ( (pPoints[1].
X() == nX2 && pPoints[3].
X() == nX1) && (pPoints[1].
Y() == nY1 && pPoints[3].
Y() == nY2) ) )
1731 pRectOut->SetLeft( nX1 );
1732 pRectOut->SetRight( nX2 );
1733 pRectOut->SetTop( nY1 );
1734 pRectOut->SetBottom( nY2 );
1749 int nPolygonRects = 0, nPolygonPolygons = 0;
1750 int nPolygons = rPolyPoly.
Count();
1752 for(
int i = 0;
i < nPolygons;
i++ )
1766 if( nPolygonPolygons > nPolygonRects )
1774 for(
int i = 0;
i < nPolygons;
i++ )
1780 aResult.
XOr( aRect );
bool InsertPoint(tools::Long nX, tools::Long nLineID, bool bEndPoint, LineType eLineType)
ImplRegionBand * mpNextBand
ImplRegionBand * SplitBand(const sal_Int32 nY)
Split the called band at the given vertical coordinate.
constexpr tools::Long Y() const
constexpr tools::Long X() const
bool Contains(const Point &rPoint) const
void save(SvStream &rIStrm) const
void GetRegionRectangles(RectangleVector &rTarget) const
sal_uInt32 getRectangleCount() const
bool isSingleRectangle() const
SvStream & ReadCharAsBool(bool &rBool)
SvStream & WriteBool(bool b)
SvStream & WriteUInt16(sal_uInt16 nUInt16)
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
sal_uInt16 GetVersion() const
void transform(const basegfx::B2DHomMatrix &rMatrix)
B2DRange getB2DRange() const
Region(bool bIsNull=false)
basegfx::B2DPolyPolygon GetAsB2DPolyPolygon() const
tools::PolyPolygon GetAsPolyPolygon() const
void Move(tools::Long nHorzMove, tools::Long nVertMove)
const RegionBand * getRegionBand() const
const RegionBand * GetAsRegionBand() const
void Intersect(const tools::Rectangle &rRegion)
std::optional< tools::PolyPolygon > mpPolyPolygon
void Scale(double fScaleX, double fScaleY)
static vcl::Region GetRegionFromPolyPolygon(const tools::PolyPolygon &rPolyPoly)
SAL_DLLPRIVATE tools::PolyPolygon ImplCreatePolyPolygonFromRegionBand() const
bool operator==(const vcl::Region &rRegion) const
const std::optional< basegfx::B2DPolyPolygon > & getB2DPolyPolygon() const
SAL_DLLPRIVATE void ImplCreatePolyPolyRegion(const tools::PolyPolygon &rPolyPoly)
bool Contains(const Point &rPoint) const
bool Overlaps(const tools::Rectangle &rRect) const
bool HasPolyPolygonOrB2DPolyPolygon() const
tools::Rectangle GetBoundRect() const
void XOr(const tools::Rectangle &rRegion)
void Union(const tools::Rectangle &rRegion)
SAL_DLLPRIVATE basegfx::B2DPolyPolygon ImplCreateB2DPolyPolygonFromRegionBand() const
void Exclude(const tools::Rectangle &rRegion)
void GetRegionRectangles(RectangleVector &rTarget) const
const std::optional< tools::PolyPolygon > & getPolyPolygon() const
vcl::Region & operator=(const vcl::Region &rRegion)
std::shared_ptr< RegionBand > mpRegionBand
#define SAL_WARN(area, stream)
B2DPolyPolygon prepareForPolygonOperation(const B2DPolygon &rCandidate)
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
B2DPolyPolygon solvePolygonOperationOr(const B2DPolyPolygon &rCandidateA, const B2DPolyPolygon &rCandidateB)
B2DPolyPolygon clipPolyPolygonOnRange(const B2DPolyPolygon &rCandidate, const B2DRange &rRange, bool bInside, bool bStroke)
B2DPolyPolygon solvePolygonOperationXor(const B2DPolyPolygon &rCandidateA, const B2DPolyPolygon &rCandidateB)
bool isRectangle(const B2DPolygon &rPoly)
B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon &rCandidate, const B2DPolyPolygon &rClip, bool bInside, bool bStroke, size_t *pPointLimit)
B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY)
B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
B2DPolyPolygon solvePolygonOperationDiff(const B2DPolyPolygon &rCandidateA, const B2DPolyPolygon &rCandidateB)
B2DRange getRange(const B2DPolygon &rCandidate)
B2IRange fround(const B2DRange &rRange)
SvStream & ReadRegion(SvStream &rIStrm, vcl::Region &rRegion)
SvStream & WriteRegion(SvStream &rOStrm, const vcl::Region &rRegion)
static bool ImplPolygonRectTest(const tools::Polygon &rPoly, tools::Rectangle *pRectOut=nullptr)
static std::shared_ptr< RegionBand > ImplCreateRegionBandFromPolyPolygon(const tools::PolyPolygon &rPolyPolygon)
std::vector< tools::Rectangle > RectangleVector