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 (!)");
336 if(rPolyPoly.
Count())
346 if(rPolyPoly.
count())
355 : mpB2DPolyPolygon(
std::move(rRegion.mpB2DPolyPolygon)),
356 mpPolyPolygon(
std::move(rRegion.mpPolyPolygon)),
357 mpRegionBand(
std::move(rRegion.mpRegionBand)),
358 mbIsNull(rRegion.mbIsNull)
360 rRegion.mbIsNull =
true;
367 const sal_uInt16 nPolyCount = rPolyPoly.
Count();
379 if((1 == aRect.GetWidth()) || (1 == aRect.GetHeight()) || rPolyPoly.
IsRect())
381 mpRegionBand = std::make_shared<RegionBand>(aRect);
385 mpPolyPolygon = rPolyPoly;
395 mpB2DPolyPolygon = rPolyPoly;
402 if(IsNull() || IsEmpty())
408 if(!nHorzMove && !nVertMove)
414 if(getB2DPolyPolygon())
420 mpB2DPolyPolygon = aPoly;
422 mpB2DPolyPolygon.reset();
423 mpPolyPolygon.reset();
424 mpRegionBand.reset();
426 else if(getPolyPolygon())
430 aPoly.
Move(nHorzMove, nVertMove);
431 mpB2DPolyPolygon.reset();
433 mpPolyPolygon = aPoly;
435 mpPolyPolygon.reset();
436 mpRegionBand.reset();
438 else if(getRegionBand())
442 pNew->
Move(nHorzMove, nVertMove);
443 mpB2DPolyPolygon.reset();
444 mpPolyPolygon.reset();
445 mpRegionBand.reset(pNew);
449 OSL_ENSURE(
false,
"Region::Move error: impossible combination (!)");
455 if(IsNull() || IsEmpty())
467 if(getB2DPolyPolygon())
473 mpB2DPolyPolygon = aPoly;
475 mpB2DPolyPolygon.reset();
476 mpPolyPolygon.reset();
477 mpRegionBand.reset();
479 else if(getPolyPolygon())
483 aPoly.
Scale(fScaleX, fScaleY);
484 mpB2DPolyPolygon.reset();
486 mpPolyPolygon = aPoly;
488 mpPolyPolygon.reset();
489 mpRegionBand.reset();
491 else if(getRegionBand())
495 pNew->
Scale(fScaleX, fScaleY);
496 mpB2DPolyPolygon.reset();
497 mpPolyPolygon.reset();
498 mpRegionBand.reset(pNew);
502 OSL_ENSURE(
false,
"Region::Scale error: impossible combination (!)");
521 if(HasPolyPolygonOrB2DPolyPolygon())
528 if(!aThisPolyPoly.
count())
559 std::shared_ptr<RegionBand> pNew = std::make_shared<RegionBand>(*pCurrent);
568 pNew->InsertBands(nTop, nBottom);
571 pNew->Union(nLeft, nTop, nRight, nBottom);
574 if(!pNew->OptimizeBandList())
579 mpRegionBand = std::move(pNew);
604 if(HasPolyPolygonOrB2DPolyPolygon())
607 if(getB2DPolyPolygon())
611 *getB2DPolyPolygon(),
621 mpB2DPolyPolygon = aPoly;
623 mpB2DPolyPolygon.reset();
624 mpPolyPolygon.reset();
625 mpRegionBand.reset();
636 mpB2DPolyPolygon.reset();
638 mpPolyPolygon = aPoly;
640 mpPolyPolygon.reset();
641 mpRegionBand.reset();
656 std::shared_ptr<RegionBand> pNew( std::make_shared<RegionBand>(*pCurrent));
665 pNew->InsertBands(nTop, nBottom);
668 pNew->Intersect(nLeft, nTop, nRight, nBottom);
671 if(!pNew->OptimizeBandList())
676 mpRegionBand = std::move(pNew);
697 OSL_ENSURE(
false,
"Region::Exclude error: Cannot exclude from null region (!)");
701 if( HasPolyPolygonOrB2DPolyPolygon() )
708 if(!aThisPolyPoly.
count())
735 std::shared_ptr<RegionBand> pNew( std::make_shared<RegionBand>(*pCurrent));
744 pNew->InsertBands(nTop, nBottom);
747 pNew->Exclude(nLeft, nTop, nRight, nBottom);
750 if(!pNew->OptimizeBandList())
755 mpRegionBand = std::move(pNew);
777 OSL_ENSURE(
false,
"Region::XOr error: Cannot XOr with null region (!)");
781 if( HasPolyPolygonOrB2DPolyPolygon() )
788 if(!aThisPolyPoly.
count())
818 std::shared_ptr<RegionBand> pNew( std::make_shared<RegionBand>(*getRegionBand()));
827 pNew->InsertBands(nTop, nBottom);
830 pNew->XOr(nLeft, nTop, nRight, nBottom);
833 if(!pNew->OptimizeBandList())
838 mpRegionBand = std::move(pNew);
876 if(!aThisPolyPoly.
count())
913 std::shared_ptr<RegionBand> pNew( std::make_shared<RegionBand>(*pCurrent));
916 pNew->Union(*pSource);
919 if(!pNew->OptimizeBandList())
924 mpRegionBand = std::move(pNew);
935 if(getPolyPolygon() && getPolyPolygon() == rRegion.
getPolyPolygon())
940 if(getRegionBand() && getRegionBand() == rRegion.
getRegionBand())
976 if(!aThisPolyPoly.
count())
985 if(!aOtherPolyPoly.count())
993 size_t nPointLimit(gPointLimit);
1006 const RegionBand* pCurrent = getRegionBand();
1029 *
this = aTempRegion;
1034 std::shared_ptr<RegionBand> pNew( std::make_shared<RegionBand>(*pCurrent));
1037 pNew->Intersect(*pSource);
1040 if(!pNew->OptimizeBandList())
1045 mpRegionBand = std::move(pNew);
1074 OSL_ENSURE(
false,
"Region::Exclude error: Cannot exclude from null region (!)");
1083 if(!aThisPolyPoly.
count())
1101 const RegionBand* pCurrent = getRegionBand();
1118 std::shared_ptr<RegionBand> pNew( std::make_shared<RegionBand>(*pCurrent));
1121 const bool bSuccess(pNew->Exclude(*pSource));
1129 mpRegionBand = std::move(pNew);
1144 OSL_ENSURE(
false,
"Region::XOr error: Cannot XOr with null region (!)");
1159 OSL_ENSURE(
false,
"Region::XOr error: Cannot XOr with null region (!)");
1168 if(!aThisPolyPoly.
count())
1187 const RegionBand* pCurrent = getRegionBand();
1205 std::shared_ptr<RegionBand> pNew( std::make_shared<RegionBand>(*pCurrent));
1208 pNew->XOr(*pSource);
1211 if(!pNew->OptimizeBandList())
1216 mpRegionBand = std::move(pNew);
1237 if(getB2DPolyPolygon())
1255 if(getPolyPolygon())
1257 return getPolyPolygon()->GetBoundRect();
1262 return getRegionBand()->GetBoundRect();
1270 if(getPolyPolygon())
1272 return *getPolyPolygon();
1275 if(getB2DPolyPolygon())
1279 const_cast< vcl::Region*
>(
this)->mpPolyPolygon = aPolyPolgon;
1281 return *getPolyPolygon();
1288 const_cast< vcl::Region*
>(
this)->mpPolyPolygon = aPolyPolgon;
1290 return *getPolyPolygon();
1298 if(getB2DPolyPolygon())
1300 return *getB2DPolyPolygon();
1303 if(getPolyPolygon())
1307 const_cast< vcl::Region*
>(
this)->mpB2DPolyPolygon = aB2DPolyPolygon;
1309 return *getB2DPolyPolygon();
1316 const_cast< vcl::Region*
>(
this)->mpB2DPolyPolygon = aB2DPolyPolygon;
1318 return *getB2DPolyPolygon();
1326 if(!getRegionBand())
1328 if(getB2DPolyPolygon())
1333 else if(getPolyPolygon())
1340 return getRegionBand();
1364 const RegionBand* pRegionBand = GetAsRegionBand();
1368 return pRegionBand->
Contains(rPoint);
1400 if( IsEmpty() || IsNull() )
1403 if( getB2DPolyPolygon() )
1406 if( getPolyPolygon() )
1407 return getPolyPolygon()->IsRect();
1409 if( getRegionBand() )
1410 return (getRegionBand()->getRectangleCount() == 1);
1418 mpB2DPolyPolygon.reset();
1419 mpPolyPolygon.reset();
1420 mpRegionBand.reset();
1427 mpB2DPolyPolygon.reset();
1428 mpPolyPolygon.reset();
1429 mpRegionBand.reset();
1437 mpB2DPolyPolygon = std::move(rRegion.mpB2DPolyPolygon);
1438 mpPolyPolygon = std::move(rRegion.mpPolyPolygon);
1439 mpRegionBand = std::move(rRegion.mpRegionBand);
1440 mbIsNull = rRegion.mbIsNull;
1441 rRegion.mbIsNull =
true;
1448 mpB2DPolyPolygon.reset();
1449 mpPolyPolygon.reset();
1458 if(IsNull() && rRegion.
IsNull())
1464 if(IsEmpty() && rRegion.
IsEmpty())
1476 if(getPolyPolygon() && getPolyPolygon() == rRegion.
getPolyPolygon())
1482 if(getRegionBand() && getRegionBand() == rRegion.
getRegionBand())
1488 if(IsNull() || IsEmpty())
1502 GetAsB2DPolyPolygon();
1534 sal_uInt16 nTmp16(0);
1545 enum RegionType { REGION_NULL, REGION_EMPTY, REGION_RECTANGLE, REGION_COMPLEX };
1546 auto eStreamedType = nTmp16;
1548 switch (eStreamedType)
1564 std::shared_ptr<RegionBand> xNewRegionBand(std::make_shared<RegionBand>());
1565 bool bSuccess = xNewRegionBand->load(rIStrm);
1568 bool bHasPolyPolygon(
false);
1573 if (bHasPolyPolygon)
1577 const auto nPolygons = aNewPoly.
Count();
1578 if (nPolygons > 128)
1580 SAL_WARN(
"vcl.gdi",
"suspiciously high no of polygons in clip:" << nPolygons);
1588 if (!bSuccess && !bHasPolyPolygon)
1590 SAL_WARN(
"vcl.gdi",
"bad region band:" << bHasPolyPolygon);
1610 enum RegionType { REGION_NULL, REGION_EMPTY, REGION_RECTANGLE, REGION_COMPLEX };
1611 RegionType aRegionType(REGION_COMPLEX);
1612 bool bEmpty(rRegion.
IsEmpty());
1616 OSL_ENSURE(
false,
"Region with empty B2DPolyPolygon, should not be created (!)");
1622 OSL_ENSURE(
false,
"Region with empty PolyPolygon, should not be created (!)");
1628 aRegionType = REGION_EMPTY;
1630 else if(rRegion.
IsNull())
1632 aRegionType = REGION_NULL;
1636 aRegionType = REGION_RECTANGLE;
1646 pRegionBand->
save(rOStrm);
1654 aRegionBand.
save(rOStrm);
1679 const RegionBand* pRegionBand = GetAsRegionBand();
1689 bool bIsRect =
false;
1691 sal_uInt16 nPoints = rPoly.
GetSize();
1693 if( nPoints == 4 || (nPoints == 5 && pPoints[0] == pPoints[4]) )
1695 tools::Long nX1 = pPoints[0].X(), nX2 = pPoints[2].X(), nY1 = pPoints[0].Y(), nY2 = pPoints[2].Y();
1697 if( ( (pPoints[1].
X() == nX1 && pPoints[3].
X() == nX2) && (pPoints[1].
Y() == nY2 && pPoints[3].
Y() == nY1) )
1698 || ( (pPoints[1].
X() == nX2 && pPoints[3].
X() == nX1) && (pPoints[1].
Y() == nY1 && pPoints[3].
Y() == nY2) ) )
1730 pRectOut->SetLeft( nX1 );
1731 pRectOut->SetRight( nX2 );
1732 pRectOut->SetTop( nY1 );
1733 pRectOut->SetBottom( nY2 );
1748 int nPolygonRects = 0, nPolygonPolygons = 0;
1749 int nPolygons = rPolyPoly.
Count();
1751 for(
int i = 0;
i < nPolygons;
i++ )
1765 if( nPolygonPolygons > nPolygonRects )
1773 for(
int i = 0;
i < nPolygons;
i++ )
1779 aResult.
XOr( aRect );
SvStream & WriteBool(bool b)
static std::shared_ptr< RegionBand > ImplCreateRegionBandFromPolyPolygon(const tools::PolyPolygon &rPolyPolygon)
SvStream & WriteUInt16(sal_uInt16 nUInt16)
void Move(tools::Long nHorzMove, tools::Long nVertMove)
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
void Union(const tools::Rectangle &rRegion)
SvStream & ReadCharAsBool(bool &rBool)
B2DPolyPolygon solvePolygonOperationOr(const B2DPolyPolygon &rCandidateA, const B2DPolyPolygon &rCandidateB)
tools::Rectangle GetBoundRect() const
B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon &rCandidate, const B2DPolyPolygon &rClip, bool bInside, bool bStroke, size_t *pPointLimit)
const RegionBand * getRegionBand() const
static vcl::Region GetRegionFromPolyPolygon(const tools::PolyPolygon &rPolyPoly)
std::vector< tools::Rectangle > RectangleVector
sal_uInt32 getRectangleCount() const
B2DRange getB2DRange() const
SAL_DLLPRIVATE void ImplCreatePolyPolyRegion(const tools::PolyPolygon &rPolyPoly)
const RegionBand * GetAsRegionBand() const
void save(SvStream &rIStrm) const
B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY)
bool isSingleRectangle() const
std::shared_ptr< RegionBand > mpRegionBand
std::optional< tools::PolyPolygon > mpPolyPolygon
static bool ImplPolygonRectTest(const tools::Polygon &rPoly, tools::Rectangle *pRectOut=nullptr)
B2DPolyPolygon solvePolygonOperationXor(const B2DPolyPolygon &rCandidateA, const B2DPolyPolygon &rCandidateB)
B2IRange fround(const B2DRange &rRange)
B2DPolyPolygon solvePolygonOperationDiff(const B2DPolyPolygon &rCandidateA, const B2DPolyPolygon &rCandidateB)
tools::PolyPolygon GetAsPolyPolygon() const
void Move(tools::Long nHorzMove, tools::Long nVertMove)
ImplRegionBand * SplitBand(const sal_Int32 nY)
Split the called band at the given vertical coordinate.
void XOr(const tools::Rectangle &rRegion)
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
void transform(const basegfx::B2DHomMatrix &rMatrix)
void Intersect(const tools::Rectangle &rRegion)
SvStream & ReadRegion(SvStream &rIStrm, vcl::Region &rRegion)
bool Contains(const Point &rPoint) const
B2DRange getRange(const B2DPolygon &rCandidate)
void GetRegionRectangles(RectangleVector &rTarget) const
const std::optional< basegfx::B2DPolyPolygon > & getB2DPolyPolygon() const
void Scale(double fScaleX, double fScaleY)
void Exclude(const tools::Rectangle &rRegion)
bool Overlaps(const tools::Rectangle &rRect) const
Region(bool bIsNull=false)
bool operator==(const vcl::Region &rRegion) const
sal_uInt16 GetVersion() const
void GetRegionRectangles(RectangleVector &rTarget) const
vcl::Region & operator=(const vcl::Region &rRegion)
bool HasPolyPolygonOrB2DPolyPolygon() const
SAL_DLLPRIVATE tools::PolyPolygon ImplCreatePolyPolygonFromRegionBand() const
void Scale(double fScaleX, double fScaleY)
bool Contains(const Point &rPoint) const
basegfx::B2DPolyPolygon GetAsB2DPolyPolygon() const
const std::optional< tools::PolyPolygon > & getPolyPolygon() const
#define SAL_WARN(area, stream)
bool InsertPoint(tools::Long nX, tools::Long nLineID, bool bEndPoint, LineType eLineType)
B2DPolyPolygon clipPolyPolygonOnRange(const B2DPolyPolygon &rCandidate, const B2DRange &rRange, bool bInside, bool bStroke)
B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
B2DPolyPolygon prepareForPolygonOperation(const B2DPolygon &rCandidate)
bool isRectangle(const B2DPolygon &rPoly)
SvStream & WriteRegion(SvStream &rOStrm, const vcl::Region &rRegion)
SAL_DLLPRIVATE basegfx::B2DPolyPolygon ImplCreateB2DPolyPolygonFromRegionBand() const
ImplRegionBand * mpNextBand
bool m_bDetectedRangeSegmentation false