81 return (
mpPN->mnI < rComp.mpPN->mnI);
95 typedef std::vector< PN > PNV;
96 typedef std::vector< VN > VNV;
97 typedef std::vector< SN > SNV;
107 std::vector< CorrectionPair >
113 void impAddPolygon(
const sal_uInt32 aPos,
const B2DPolygon& rGeometry)
115 const sal_uInt32
nCount(rGeometry.count());
122 const B2DPoint aPoint(rGeometry.getB2DPoint(
a));
123 aNewPN.maPoint = aPoint;
124 aNewPN.mnI = aPos +
a;
125 aNewPN.mnIP = aPos + ((
a != 0) ?
a - 1 :
nCount - 1);
126 aNewPN.mnIN = aPos + ((
a + 1 ==
nCount) ? 0 :
a + 1);
127 maPNV.push_back(aNewPN);
131 aNewVN.maPrev = rGeometry.getPrevControlPoint(
a) - aPoint;
132 aNewVN.maNext = rGeometry.getNextControlPoint(
a) - aPoint;
133 aNewVN.maOriginalNext = aNewVN.maNext;
134 maVNV.push_back(aNewVN);
138 maSNV.push_back(aNewSN);
142 static bool impLeftOfEdges(
const B2DVector& rVecA,
const B2DVector& rVecB,
const B2DVector& rTest)
146 if(rVecA.cross(rVecB) > 0.0)
152 return (bBoolA && bBoolB);
160 return (!(bBoolA && bBoolB));
164 void impSwitchNext(PN& rPNa, PN& rPNb)
166 std::swap(rPNa.mnIN, rPNb.mnIN);
170 VN& rVNa =
maVNV[rPNa.mnI];
171 VN& rVNb =
maVNV[rPNb.mnI];
173 std::swap(rVNa.maNext, rVNb.maNext);
182 B2DCubicBezier createSegment(
const PN& rPN,
bool bPrev)
const
184 const B2DPoint& rStart(rPN.maPoint);
185 const B2DPoint& rEnd(
maPNV[bPrev ? rPN.mnIP : rPN.mnIN].maPoint);
186 const B2DVector& rCPA(bPrev ?
maVNV[rPN.mnI].maPrev :
maVNV[rPN.mnI].maNext);
189 const B2DVector& rCPB(bPrev ?
maVNV[
maPNV[rPN.mnIP].mnI].maOriginalNext :
maVNV[
maPNV[rPN.mnIN].mnI].maPrev);
191 return B2DCubicBezier(rStart, rStart + rCPA, rEnd + rCPB, rEnd);
194 void impHandleCommon(PN& rPNa, PN& rPNb)
198 const B2DCubicBezier aNextA(createSegment(rPNa,
false));
199 const B2DCubicBezier aPrevA(createSegment(rPNa,
true));
201 if(aNextA.equal(aPrevA))
207 const B2DCubicBezier aNextB(createSegment(rPNb,
false));
208 const B2DCubicBezier aPrevB(createSegment(rPNb,
true));
210 if(aNextB.equal(aPrevB))
216 if(aPrevA.equal(aPrevB))
221 else if(aPrevA.equal(aNextB))
224 if(aNextA.equal(aPrevB))
232 impSwitchNext(rPNa, rPNb);
235 else if(aNextA.equal(aNextB))
245 const B2DCubicBezier aNextA2(createSegment(*pPNa2,
false));
246 const B2DCubicBezier aNextB2(createSegment(*pPNb2,
false));
248 if(aNextA2.equal(aNextB2))
250 pPNa2 = &
maPNV[pPNa2->mnIN];
251 pPNb2 = &
maPNV[pPNb2->mnIN];
258 while(bOnEdge && pPNa2 != &rPNa && pPNb2 != &rPNb);
269 const B2DVector aPrevCA(aPrevA.interpolatePoint(0.5) - aPrevA.getStartPoint());
270 const B2DVector aNextCA(aNextA.interpolatePoint(0.5) - aNextA.getStartPoint());
271 const B2DVector aPrevCB(aPrevB.interpolatePoint(0.5) - aPrevB.getStartPoint());
272 const bool bEnter(impLeftOfEdges(aPrevCA, aNextCA, aPrevCB));
274 const B2DCubicBezier aNextA2(createSegment(*pPNa2,
false));
275 const B2DCubicBezier aPrevA2(createSegment(*pPNa2,
true));
276 const B2DCubicBezier aNextB2(createSegment(*pPNb2,
false));
277 const B2DVector aPrevCA2(aPrevA2.interpolatePoint(0.5) - aPrevA2.getStartPoint());
278 const B2DVector aNextCA2(aNextA2.interpolatePoint(0.5) - aNextA2.getStartPoint());
279 const B2DVector aNextCB2(aNextB2.interpolatePoint(0.5) - aNextB2.getStartPoint());
280 const bool bLeave(impLeftOfEdges(aPrevCA2, aNextCA2, aNextCB2));
285 impSwitchNext(rPNa, rPNb);
289 else if(aNextA.equal(aPrevB))
292 impSwitchNext(rPNa, rPNb);
297 const B2DVector aPrevCA(aPrevA.interpolatePoint(0.5) - aPrevA.getStartPoint());
298 const B2DVector aNextCA(aNextA.interpolatePoint(0.5) - aNextA.getStartPoint());
299 const B2DVector aPrevCB(aPrevB.interpolatePoint(0.5) - aPrevB.getStartPoint());
300 const B2DVector aNextCB(aNextB.interpolatePoint(0.5) - aNextB.getStartPoint());
302 const bool bEnter(impLeftOfEdges(aPrevCA, aNextCA, aPrevCB));
303 const bool bLeave(impLeftOfEdges(aPrevCA, aNextCA, aNextCB));
308 impSwitchNext(rPNa, rPNb);
314 const B2DPoint& rNextA(
maPNV[rPNa.mnIN].maPoint);
315 const B2DPoint& rPrevA(
maPNV[rPNa.mnIP].maPoint);
317 if(rNextA.equal(rPrevA))
323 const B2DPoint& rNextB(
maPNV[rPNb.mnIN].maPoint);
324 const B2DPoint& rPrevB(
maPNV[rPNb.mnIP].maPoint);
326 if(rNextB.equal(rPrevB))
332 if(rPrevA.equal(rPrevB))
337 else if(rPrevA.equal(rNextB))
340 if(rNextA.equal(rPrevB))
348 impSwitchNext(rPNa, rPNb);
351 else if(rNextA.equal(rNextB))
361 const B2DPoint& rNextA2(
maPNV[pPNa2->mnIN].maPoint);
362 const B2DPoint& rNextB2(
maPNV[pPNb2->mnIN].maPoint);
364 if(rNextA2.equal(rNextB2))
366 pPNa2 = &
maPNV[pPNa2->mnIN];
367 pPNb2 = &
maPNV[pPNb2->mnIN];
374 while(bOnEdge && pPNa2 != &rPNa && pPNb2 != &rPNb);
385 const B2DPoint& aPointE(rPNa.maPoint);
386 const B2DVector aPrevAE(rPrevA - aPointE);
387 const B2DVector aNextAE(rNextA - aPointE);
388 const B2DVector aPrevBE(rPrevB - aPointE);
390 const B2DPoint& aPointL(pPNa2->maPoint);
391 const B2DVector aPrevAL(
maPNV[pPNa2->mnIP].maPoint - aPointL);
392 const B2DVector aNextAL(
maPNV[pPNa2->mnIN].maPoint - aPointL);
393 const B2DVector aNextBL(
maPNV[pPNb2->mnIN].maPoint - aPointL);
395 const bool bEnter(impLeftOfEdges(aPrevAE, aNextAE, aPrevBE));
396 const bool bLeave(impLeftOfEdges(aPrevAL, aNextAL, aNextBL));
401 impSwitchNext(rPNa, rPNb);
405 else if(rNextA.equal(rPrevB))
408 impSwitchNext(rPNa, rPNb);
413 const B2DPoint& aPoint(rPNa.maPoint);
414 const B2DVector aPrevA(rPrevA - aPoint);
415 const B2DVector aNextA(rNextA - aPoint);
416 const B2DVector aPrevB(rPrevB - aPoint);
417 const B2DVector aNextB(rNextB - aPoint);
419 const bool bEnter(impLeftOfEdges(aPrevA, aNextA, aPrevB));
420 const bool bLeave(impLeftOfEdges(aPrevA, aNextA, aNextB));
425 impSwitchNext(rPNa, rPNb);
437 const sal_uInt32 nNodeCount(
maSNV.size());
445 for(
const auto& rSN :
maSNV)
449 if(pLast->equal(*pCurrent) && (pLast->getX() != pCurrent->getX() || pLast->getY() != pCurrent->getY()))
453 if(pLast->getX() != aMiddle.getX() || pLast->getY() != aMiddle.getY())
459 if(pCurrent->getX() != aMiddle.getX() || pCurrent->getY() != aMiddle.getY())
470 for(a = 0;
a < nNodeCount - 1;
a++)
475 for(sal_uInt32 b(a + 1); b < nNodeCount && rPNb.maPoint.equal(
maSNV[b].
mpPN->maPoint); b++)
483 explicit solver(
const B2DPolygon& rOriginal)
488 const sal_uInt32 nOriginalCount(rOriginal.count());
494 aGeometry.removeDoublePoints();
496 mbIsCurve = aGeometry.areControlPointsUsed();
498 const sal_uInt32 nPointCount(aGeometry.count());
503 if(!(nPointCount > 3 || (nPointCount > 1 &&
mbIsCurve)))
507 maSNV.reserve(nPointCount);
508 maPNV.reserve(nPointCount);
512 impAddPolygon(0, aGeometry);
518 explicit solver(B2DPolyPolygon aOriginal,
size_t* pPointLimit =
nullptr)
523 sal_uInt32 nOriginalCount(
maOriginal.count());
529 aGeometry.removeDoublePoints();
531 mbIsCurve = aGeometry.areControlPointsUsed();
532 nOriginalCount = aGeometry.count();
542 sal_uInt32 nPointCount = std::accumulate( aGeometry.begin(), aGeometry.end(), sal_uInt32(0),
549 maSNV.reserve(nPointCount);
550 maPNV.reserve(nPointCount);
554 sal_uInt32 nInsertIndex(0);
556 for(
const auto& rCandidate : aGeometry )
558 const sal_uInt32 nCandCount(rCandidate.count());
564 impAddPolygon(nInsertIndex, rCandidate);
565 nInsertIndex += nCandCount;
573 B2DPolyPolygon getB2DPolyPolygon()
577 B2DPolyPolygon aRetval;
579 sal_uInt32 nCountdown(nCount);
581 for(sal_uInt32
a(0); nCountdown &&
a <
nCount;
a++)
585 if(rPN.mnI != SAL_MAX_UINT32)
593 const B2DPoint& rPoint = pPNCurr->maPoint;
594 aNewPart.append(rPoint);
598 const VN& rVNCurr =
maVNV[pPNCurr->mnI];
600 if(!rVNCurr.maPrev.equalZero())
602 aNewPart.setPrevControlPoint(aNewPart.count() - 1, rPoint + rVNCurr.maPrev);
605 if(!rVNCurr.maNext.equalZero())
607 aNewPart.setNextControlPoint(aNewPart.count() - 1, rPoint + rVNCurr.maNext);
613 pPNCurr = &(
maPNV[pPNCurr->mnIN]);
615 while(pPNCurr != &rPN && pPNCurr->mnI != SAL_MAX_UINT32);
618 aNewPart.setClosed(
true);
619 aRetval.append(aNewPart);
636 const sal_uInt32 nPolygonCount(
maOriginal.count());
639 for(sal_uInt32
a(0);
a < nPolygonCount;
a++)
642 const sal_uInt32 nPointCount(aTemp.count());
643 bool bChanged(
false);
645 for(sal_uInt32 b(0); b < nPointCount; b++)
649 for(sal_uInt32 c(0); c < nCorrectionSize; c++)
661 aRetval.setB2DPolygon(a, aTemp);
678 if(rCandidate.
count() > 0)
680 solver aSolver(rCandidate, pPointLimit);
681 return aSolver.getB2DPolyPolygon();
691 solver aSolver(rCandidate);
692 return aSolver.getB2DPolyPolygon();
699 for(
const auto& rPolygon : rCandidate)
712 if (rCandidate.
count() > 1000)
714 SAL_WARN(
"basegfx",
"this poly is too large, " << rCandidate.
count() <<
" elements, to be able to process timeously, falling back to ignoring the winding rule, which is likely to cause rendering artifacts");
721 if(rCandidate.
count() == 1)
739 std::vector< StripHelper > aHelpers;
745 StripHelper* pNewHelper = &(aHelpers[
a]);
756 StripHelper& rHelperA = aHelpers[
a];
758 for(b =
a + 1; b <
nCount; b++)
761 StripHelper& rHelperB = aHelpers[b];
762 const bool bAInB(rHelperB.maRange.isInside(rHelperA.maRange) &&
utils::isInside(aCandB, aCandA,
true));
770 const bool bBInA(rHelperA.maRange.isInside(rHelperB.maRange) &&
utils::isInside(aCandA, aCandB,
true));
785 const StripHelper& rHelper = aHelpers[
a];
790 bool bAcceptEntry(rHelper.mnDepth >= -1 && rHelper.mnDepth <= 1);
813 aRetval = rCandidate;
819 std::vector< StripHelper > aHelpers;
825 StripHelper* pNewHelper = &(aHelpers[
a]);
834 StripHelper& rHelperA = aHelpers[
a];
836 for(b =
a + 1; b <
nCount; b++)
839 StripHelper& rHelperB = aHelpers[b];
840 const bool bAInB(rHelperB.maRange.isInside(rHelperA.maRange) &&
utils::isInside(aCandB, aCandA,
true));
841 const bool bBInA(rHelperA.maRange.isInside(rHelperB.maRange) &&
utils::isInside(aCandA, aCandB,
true));
846 if(rHelperA.meOrinetation == rHelperB.meOrinetation)
856 rHelperA.mnDepth = -
static_cast<sal_Int32
>(
nCount);
857 rHelperB.mnDepth = -
static_cast<sal_Int32
>(
nCount);
890 const StripHelper& rHelper = aHelpers[
a];
891 bool bAcceptEntry(bKeepAboveZero ? 1 <= rHelper.mnDepth : rHelper.mnDepth == 0);
906 solver aSolver(rCandidate);
914 solver aSolver(rCandidate);
922 if(!rCandidateA.
count())
926 else if(!rCandidateB.
count())
936 aRetval.
append(rCandidateB);
946 if(!rCandidateA.
count())
950 else if(!rCandidateB.
count())
961 aRetval.
append(rCandidateB);
971 if(!rCandidateA.
count())
975 else if(!rCandidateB.
count())
1022 aRetval.
append(rCandidateB);
1032 if(!rCandidateA.
count())
1036 else if(!rCandidateB.
count())
1046 aRetval.
append(rCandidateA);
1065 aResult.reserve(rInput.size());
1071 if(!aResult.empty())
1074 bool bCouldMergeSimple(
false);
1076 for(
auto & b: aResult)
1081 if(!aCandidateRange.
overlaps(aTargetRange))
1083 aTarget.
append(aCandidate);
1085 bCouldMergeSimple =
true;
1090 if(!bCouldMergeSimple)
1092 aResult.push_back(aCandidate);
1097 aResult.push_back(aCandidate);
1102 while(aResult.size() > 1)
1105 aResult2.
reserve((aResult.size() / 2) + 1);
1107 for(
size_t a(0);
a < aResult.size();
a += 2)
1109 if(
a + 1 < aResult.size())
1117 aResult2.push_back(aResult[
a]);
1125 if(aResult.size() == 1)
B2VectorOrientation meOrinetation
std::vector< CorrectionPair > maCorrectionTable
const B2DPolyPolygon maOriginal
Base Point class with two double values.
B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) const
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
B2DRange getB2DRange() const
Get the B2DRange (Rectangle dimensions) of this B2DPolyPolygon.
void reserve(sal_uInt32 nCount)
sal_uInt32 count() const
member count
A two-dimensional interval over doubles.
void intersect(const Range2D &rRange)
calc set intersection
bool isInside(const Tuple2D< TYPE > &rTuple) const
yields true if given point is contained in set
bool isEmpty() const
Check if the interval set is empty.
bool overlaps(const Range2D &rRange) const
yields true if rRange at least partly inside set
#define SAL_WARN(area, stream)
B2DPolyPolygon createNonzeroConform(const B2DPolyPolygon &rCandidate)
Emulate nonzero winding rule filling.
B2DPolyPolygon prepareForPolygonOperation(const B2DPolygon &rCandidate)
prep for ops - solve self-intersections and intersections, remove neutral parts and check orientation...
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
Create a polygon from a rectangle.
B2VectorOrientation getOrientation(const B2DPolygon &rCandidate)
B2DPolyPolygon solvePolygonOperationOr(const B2DPolyPolygon &rCandidateA, const B2DPolyPolygon &rCandidateB)
OR: Return all areas where CandidateA or CandidateB exist.
B2DPolyPolygon solvePolygonOperationAnd(const B2DPolyPolygon &rCandidateA, const B2DPolyPolygon &rCandidateB)
AND: Return all areas where CandidateA and CandidateB exist.
bool isInside(const B2DPolygon &rCandidate, const B2DPoint &rPoint, bool bWithBorder)
B2DPolyPolygon correctOrientations(const B2DPolyPolygon &rCandidate)
B2DPolyPolygon solvePolygonOperationXor(const B2DPolyPolygon &rCandidateA, const B2DPolyPolygon &rCandidateB)
XOR: Return all areas where CandidateA or CandidateB exist, but not both.
B2DPolyPolygon stripNeutralPolygons(const B2DPolyPolygon &rCandidate)
Strip neutral polygons from PolyPolygon.
bool isRectangle(const B2DPolygon &rPoly)
Predicate whether a given polygon is a rectangle.
B2DPolygon addPointsAtCutsAndTouches(const B2DPolygon &rCandidate, size_t *pPointLimit)
B2DPolyPolygon solveCrossovers(const B2DPolyPolygon &rCandidate, size_t *pPointLimit)
Solve all crossovers (aka self-intersections) in a polyPolygon.
B2DPolyPolygon mergeToSinglePolyPolygon(const B2DPolyPolygonVector &rInput)
merge all single PolyPolygons to a single, OR-ed PolyPolygon
B2DPolygon simplifyCurveSegments(const B2DPolygon &rCandidate)
B2DPolyPolygon stripDispensablePolygons(const B2DPolyPolygon &rCandidate, bool bKeepAboveZero)
Remove unnecessary/non-displayed polygons.
B2DPolyPolygon solvePolygonOperationDiff(const B2DPolyPolygon &rCandidateA, const B2DPolyPolygon &rCandidateB)
DIFF: Return all areas where CandidateA is not covered by CandidateB (cut B out of A)
B2DRange getRange(const B2DPolygon &rCandidate)
Get the range of a polygon.
B2VectorOrientation
Descriptor for the mathematical orientations of two 2D Vectors.
@ Positive
mathematically positive oriented
@ Neutral
mathematically neutral, thus parallel
@ Negative
mathematically negative oriented
::std::vector< B2DPolyPolygon > B2DPolyPolygonVector
constexpr OUStringLiteral first
bool operator<(const wwFont &r1, const wwFont &r2)