25#include <osl/diagnose.h>
49 const B2DPoint* pStart,
57 const B2DPoint& getStart()
const {
return *
mpStart; }
58 const B2DPoint& getEnd()
const {
return *
mpEnd; }
74 class TrDeEdgeEntry :
public TrDeSimpleEdge
82 double getDeltaX()
const {
return mpEnd->getX() -
mpStart->getX(); }
83 double getDeltaY()
const {
return mpEnd->getY() -
mpStart->getY(); }
87 sal_uInt32 getSortValue()
const
94 const double fRadiant(atan2(getDeltaY(), getDeltaX()) * (SAL_MAX_UINT32 / M_PI));
97 const_cast< TrDeEdgeEntry*
>(
this)->
mnSortValue = sal_uInt32(fRadiant);
104 const B2DPoint* pStart,
105 const B2DPoint* pEnd,
106 sal_uInt32 nSortValue)
107 : TrDeSimpleEdge(pStart, pEnd),
117 OSL_ENSURE(
mpEnd->getY() >
mpStart->getY(),
"Illegal TrDeEdgeEntry constructed (!)");
121 void setStart(
const B2DPoint* pNewStart)
123 OSL_ENSURE(pNewStart !=
nullptr,
"No null pointer allowed here (!)");
130 OSL_ENSURE(
mpEnd->getY() >
mpStart->getY(),
"Illegal TrDeEdgeEntry constructed (!)");
135 void setEnd(
const B2DPoint* pNewEnd)
137 OSL_ENSURE(pNewEnd !=
nullptr,
"No null pointer allowed here (!)");
144 OSL_ENSURE(
mpEnd->getY() >
mpStart->getY(),
"Illegal TrDeEdgeEntry constructed (!)");
149 bool operator<(
const TrDeEdgeEntry& rComp)
const
151 if(
fTools::equal(getStart().getY(), rComp.getStart().getY()))
153 if(
fTools::equal(getStart().getX(), rComp.getStart().getX()))
161 return (getSortValue() > rComp.getSortValue());
165 return fTools::less(getStart().getX(), rComp.getStart().getX());
170 return fTools::less(getStart().getY(), rComp.getStart().getY());
175 B2DPoint getCutPointForGivenY(
double fGivenY)
const
178 if (getDeltaY() == 0)
179 return B2DPoint(getStart().getX(), fGivenY);
182 const double fFactor((fGivenY - getStart().getY()) / getDeltaY());
183 const double fDeltaXNew(fFactor * getDeltaX());
185 return B2DPoint(getStart().getX() + fDeltaXNew, fGivenY);
202 class PointBlockAllocator
211 PointBlockAllocator() :
217 ~PointBlockAllocator()
226 B2DPoint *allocatePoint()
237 B2DPoint *allocatePoint(
const B2DTuple &rPoint)
239 B2DPoint *pPoint = allocatePoint();
245 void freeIfLast(B2DPoint
const *pPoint)
254 class TrapezoidSubdivider
264 TrDeEdgeEntries::iterator aCurrent,
265 const TrDeEdgeEntry& rNewEdge)
277 bool splitEdgeAtGivenPoint(
278 TrDeEdgeEntries::reference aEdge,
279 const B2DPoint& rCutPoint,
280 const TrDeEdgeEntries::iterator& aCurrent)
283 if(aEdge.getStart().equal(rCutPoint))
289 if(aEdge.getEnd().equal(rCutPoint))
294 const double fOldDeltaYStart(rCutPoint.getY() - aEdge.getStart().getY());
300 aEdge.setStart(&rCutPoint);
304 const double fNewDeltaYStart(aEdge.getEnd().getY() - rCutPoint.getY());
310 aEdge.setEnd(&rCutPoint);
315 const TrDeEdgeEntry aNewEdge(
318 aEdge.getSortValue());
321 aEdge.setEnd(&rCutPoint);
324 addEdgeSorted(aCurrent, aNewEdge);
329 bool testAndCorrectEdgeIntersection(
330 TrDeEdgeEntries::reference aEdgeA,
331 TrDeEdgeEntries::reference aEdgeB,
332 const TrDeEdgeEntries::iterator& aCurrent)
335 if(aEdgeA.getStart().equal(aEdgeB.getStart()))
340 if(aEdgeA.getStart().equal(aEdgeB.getEnd()))
345 if(aEdgeA.getEnd().equal(aEdgeB.getStart()))
350 if(aEdgeA.getEnd().equal(aEdgeB.getEnd()))
356 if(aEdgeA.getStart().equal(aEdgeA.getEnd()))
361 if(aEdgeB.getStart().equal(aEdgeB.getEnd()))
367 const B2DVector aDeltaB(aEdgeB.getDeltaX(), aEdgeB.getDeltaY());
371 return splitEdgeAtGivenPoint(aEdgeB, aEdgeA.getStart(), aCurrent);
376 return splitEdgeAtGivenPoint(aEdgeB, aEdgeA.getEnd(), aCurrent);
379 const B2DVector aDeltaA(aEdgeA.getDeltaX(), aEdgeA.getDeltaY());
383 return splitEdgeAtGivenPoint(aEdgeA, aEdgeB.getStart(), aCurrent);
388 return splitEdgeAtGivenPoint(aEdgeA, aEdgeB.getEnd(), aCurrent);
397 aEdgeA.getStart(), aDeltaA,
398 aEdgeB.getStart(), aDeltaB,
406 const double fSimpleLengthA(aDeltaA.getX() + aDeltaA.getY());
407 const double fSimpleLengthB(aDeltaB.getX() + aDeltaB.getY());
408 const bool bAIsLonger(fSimpleLengthA > fSimpleLengthB);
409 B2DPoint* pNewPoint = bAIsLonger
410 ?
maNewPoints.allocatePoint(aEdgeA.getStart() + (fCutA * aDeltaA))
411 :
maNewPoints.allocatePoint(aEdgeB.getStart() + (fCutB * aDeltaB));
414 bool bRetval = splitEdgeAtGivenPoint(aEdgeA, *pNewPoint, aCurrent);
415 bRetval |= splitEdgeAtGivenPoint(aEdgeB, *pNewPoint, aCurrent);
431 for(
const TrDeSimpleEdge & rHorEdge : rTrDeSimpleEdges)
434 const B1DRange aRange(rHorEdge.getStart().getX(), rHorEdge.getEnd().getX());
435 const double fFixedY(rHorEdge.getStart().getY());
443 TrDeEdgeEntries::reference aCompare(*aCurrent++);
458 const B1DRange aCompareRange(aCompare.getStart().getX(), aCompare.getEnd().getX());
460 if(aRange.overlaps(aCompareRange))
463 const B2DPoint aSplit(aCompare.getCutPointForGivenY(fFixedY));
469 B2DPoint* pNewPoint =
maNewPoints.allocatePoint(aSplit);
471 if(!splitEdgeAtGivenPoint(aCompare, *pNewPoint, aCurrent))
484 explicit TrapezoidSubdivider(
485 const B2DPolyPolygon& rSourcePolyPolygon)
487 B2DPolyPolygon aSource(rSourcePolyPolygon);
489 sal_uInt32 nAllPointCount(0);
492 if(aSource.areControlPointsUsed())
494 aSource = aSource.getDefaultAdaptiveSubdivision();
497 for(
const auto& aPolygonCandidate : std::as_const(aSource))
500 const sal_uInt32
nCount(aPolygonCandidate.count());
514 for(
const auto& aPolygonCandidate : std::as_const(aSource))
517 const sal_uInt32
nCount(aPolygonCandidate.count());
521 for(sal_uInt32 b = 0; b <
nCount; b++)
523 maPoints.push_back(aPolygonCandidate.getB2DPoint(b));
532 sal_uInt32 nStartIndex(0);
534 for(
const auto& aPolygonCandidate : std::as_const(aSource))
536 const sal_uInt32
nCount(aPolygonCandidate.count());
541 B2DPoint* pPrev(&
maPoints[nCount + nStartIndex - 1]);
543 for(sal_uInt32 b = 0; b <
nCount; b++)
546 B2DPoint* pCurr(&
maPoints[nStartIndex++]);
554 aTrDeSimpleEdges.emplace_back(pPrev, pCurr);
556 const double fMiddle((pPrev->getY() + pCurr->getY()) * 0.5);
557 pPrev->setY(fMiddle);
558 pCurr->setY(fMiddle);
581 solveHorizontalEdges(aTrDeSimpleEdges);
610 B1DRange aRightRange;
623 TrDeEdgeEntries::reference aLeft(*aCurrent++);
631 OSL_FAIL(
"Trapezoid decomposer in illegal state (!)");
637 TrDeEdgeEntries::reference aRight(*aCurrent++);
639 if(!
fTools::equal(aLeft.getStart().getY(), aRight.getStart().getY()))
645 OSL_FAIL(
"Trapezoid decomposer in illegal state (!)");
656 B2DPoint aLeftEnd(aLeft.getEnd());
657 B2DPoint aRightEnd(aRight.getEnd());
661 const bool bEndOnSameLine(
fTools::equal(aLeftEnd.getY(), aRightEnd.getY()));
662 bool bLeftIsLonger(
false);
667 bLeftIsLonger =
fTools::more(aLeftEnd.getY(), aRightEnd.getY());
671 aLeftEnd = aLeft.getCutPointForGivenY(aRightEnd.getY());
675 aRightEnd = aRight.getCutPointForGivenY(aLeftEnd.getY());
680 const bool bSameStartPoint(aLeft.getStart().equal(aRight.getStart()));
681 const bool bSameEndPoint(aLeftEnd.equal(aRightEnd));
684 if(bSameStartPoint && bSameEndPoint)
691 B2DPoint* pNewPoint =
maNewPoints.allocatePoint(aLeftEnd);
693 if(!splitEdgeAtGivenPoint(aLeft, *pNewPoint, aCurrent))
700 B2DPoint* pNewPoint =
maNewPoints.allocatePoint(aRightEnd);
702 if(!splitEdgeAtGivenPoint(aRight, *pNewPoint, aCurrent))
718 bool bRangesSet(
false);
720 if(!(bSameStartPoint || bSameEndPoint))
723 aLeftRange = B1DRange(aLeft.getStart().getX(), aLeftEnd.getX());
724 aRightRange = B1DRange(aRight.getStart().getX(), aRightEnd.getX());
728 if(aLeftRange.overlaps(aRightRange))
732 if(testAndCorrectEdgeIntersection(aLeft, aRight, aCurrent))
742 &&
fTools::less(aCurrent->getStart().getY(), aLeftEnd.getY()))
747 aLeftRange = B1DRange(aLeft.getStart().getX(), aLeftEnd.getX());
748 aRightRange = B1DRange(aRight.getStart().getX(), aRightEnd.getX());
752 B1DRange aAllRange(aLeftRange);
753 aAllRange.expand(aRightRange);
757 TrDeEdgeEntries::iterator aLoop(aCurrent);
763 TrDeEdgeEntries::reference aCompare(*aLoop++);
768 if(aCompare.getStart().equal(aRight.getStart()))
774 const B1DRange aCompareRange(aCompare.getStart().getX(), aCompare.getEnd().getX());
777 if(aAllRange.overlaps(aCompareRange))
780 if(
fTools::more(aCompare.getStart().getY(), aLeft.getStart().getY()))
783 const B2DPoint aSplitLeft(aLeft.getCutPointForGivenY(aCompare.getStart().getY()));
784 const B2DPoint aSplitRight(aRight.getCutPointForGivenY(aCompare.getStart().getY()));
788 if(aCompare.getStart().getX() >= aSplitLeft.getX() &&
789 aCompare.getStart().getX() <= aSplitRight.getX())
792 B2DPoint* pNewLeft =
maNewPoints.allocatePoint(aSplitLeft);
794 if(splitEdgeAtGivenPoint(aLeft, *pNewLeft, aCurrent))
803 B2DPoint* pNewRight =
maNewPoints.allocatePoint(aSplitRight);
805 if(splitEdgeAtGivenPoint(aRight, *pNewRight, aCurrent))
816 if(!bDone && aLeftRange.overlaps(aCompareRange))
819 bDone = testAndCorrectEdgeIntersection(aLeft, aCompare, aCurrent);
822 if(!bDone && aRightRange.overlaps(aCompareRange))
825 bDone = testAndCorrectEdgeIntersection(aRight, aCompare, aCurrent);
831 &&
fTools::less(aLoop->getStart().getY(), aLeftEnd.getY()));
847 B2DPoint* pNewPoint =
maNewPoints.allocatePoint(aLeftEnd);
849 if(!splitEdgeAtGivenPoint(aLeft, *pNewPoint, aCurrent))
856 B2DPoint* pNewPoint =
maNewPoints.allocatePoint(aRightEnd);
858 if(!splitEdgeAtGivenPoint(aRight, *pNewPoint, aCurrent))
868 ro_Result.emplace_back(
869 aLeft.getStart().getX(),
870 aRight.getStart().getX(),
871 aLeft.getStart().getY(),
887 B2DTrapezoid::B2DTrapezoid(
888 const double& rfTopXLeft,
889 const double& rfTopXRight,
890 const double& rfTopY,
891 const double& rfBottomXLeft,
892 const double& rfBottomXRight,
893 const double& rfBottomY)
894 : mfTopXLeft(rfTopXLeft),
895 mfTopXRight(rfTopXRight),
897 mfBottomXLeft(rfBottomXLeft),
898 mfBottomXRight(rfBottomXRight),
902 if(mfTopXLeft > mfTopXRight)
904 std::swap(mfTopXLeft, mfTopXRight);
908 if(mfBottomXLeft > mfBottomXRight)
910 std::swap(mfBottomXLeft, mfBottomXRight);
914 if(mfTopY > mfBottomY)
916 std::swap(mfTopY, mfBottomY);
917 std::swap(mfTopXLeft, mfBottomXLeft);
918 std::swap(mfTopXRight, mfBottomXRight);
922 B2DPolygon B2DTrapezoid::getB2DPolygon()
const
926 aRetval.append(B2DPoint(getTopXLeft(), getTopY()));
927 aRetval.append(B2DPoint(getTopXRight(), getTopY()));
928 aRetval.append(B2DPoint(getBottomXRight(), getBottomY()));
929 aRetval.append(B2DPoint(getBottomXLeft(), getBottomY()));
930 aRetval.setClosed(
true);
941 trapezoidhelper::TrapezoidSubdivider aTrapezoidSubdivider(rSourcePolyPolygon);
943 aTrapezoidSubdivider.Subdivide(ro_Result);
958 if(rPointA.
equal(rPointB))
964 const double fHalfLineWidth(0.5 * fLineWidth);
969 const double fLeftX(rPointA.
getX() - fHalfLineWidth);
970 const double fRightX(rPointA.
getX() + fHalfLineWidth);
972 ro_Result.emplace_back(
975 std::min(rPointA.
getY(), rPointB.
getY()),
978 std::max(rPointA.
getY(), rPointB.
getY()));
983 const double fLeftX(std::min(rPointA.
getX(), rPointB.
getX()));
984 const double fRightX(std::max(rPointA.
getX(), rPointB.
getX()));
986 ro_Result.emplace_back(
989 rPointA.
getY() - fHalfLineWidth,
992 rPointA.
getY() + fHalfLineWidth);
998 const B2DVector aDelta(rPointB - rPointA);
1000 aPerpendicular.
setLength(fHalfLineWidth);
1003 const B2DPoint aStartLow(rPointA + aPerpendicular);
1004 const B2DPoint aStartHigh(rPointA - aPerpendicular);
1005 const B2DPoint aEndHigh(rPointB - aPerpendicular);
1006 const B2DPoint aEndLow(rPointB + aPerpendicular);
1011 aTrDeEdgeEntries.emplace_back(&aStartLow, &aStartHigh, 0);
1012 aTrDeEdgeEntries.emplace_back(&aStartHigh, &aEndHigh, 0);
1013 aTrDeEdgeEntries.emplace_back(&aEndHigh, &aEndLow, 0);
1014 aTrDeEdgeEntries.emplace_back(&aEndLow, &aStartLow, 0);
1015 aTrDeEdgeEntries.sort();
1020 basegfx::trapezoidhelper::TrDeEdgeEntries::iterator aCurrent(aTrDeEdgeEntries.begin());
1021 basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft(*aCurrent++);
1022 basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight(*aCurrent++);
1023 const bool bEndOnSameLine(
fTools::equal(aLeft.getEnd().getY(), aRight.getEnd().getY()));
1028 ro_Result.emplace_back(
1029 aLeft.getStart().getX(),
1030 aRight.getStart().getX(),
1031 aLeft.getStart().getY(),
1032 aLeft.getEnd().getX(),
1033 aRight.getEnd().getX(),
1034 aLeft.getEnd().getY());
1036 basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft2(*aCurrent++);
1037 basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight2(*aCurrent++);
1039 ro_Result.emplace_back(
1040 aLeft2.getStart().getX(),
1041 aRight2.getStart().getX(),
1042 aLeft2.getStart().getY(),
1043 aLeft2.getEnd().getX(),
1044 aRight2.getEnd().getX(),
1045 aLeft2.getEnd().getY());
1051 const bool bLeftIsLonger(
fTools::more(aLeft.getEnd().getY(), aRight.getEnd().getY()));
1055 basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight2(*aCurrent++);
1056 basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft2(*aCurrent++);
1057 const B2DPoint aSplitLeft(aLeft.getCutPointForGivenY(aRight.getEnd().getY()));
1058 const B2DPoint aSplitRight(aRight2.getCutPointForGivenY(aLeft.getEnd().getY()));
1060 ro_Result.emplace_back(
1061 aLeft.getStart().getX(),
1062 aRight.getStart().getX(),
1063 aLeft.getStart().getY(),
1065 aRight.getEnd().getX(),
1066 aRight.getEnd().getY());
1068 ro_Result.emplace_back(
1070 aRight.getEnd().getX(),
1071 aRight.getEnd().getY(),
1072 aLeft2.getStart().getX(),
1074 aLeft2.getStart().getY());
1076 ro_Result.emplace_back(
1077 aLeft2.getStart().getX(),
1079 aLeft2.getStart().getY(),
1080 aLeft2.getEnd().getX(),
1081 aRight2.getEnd().getX(),
1082 aLeft2.getEnd().getY());
1086 basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft2(*aCurrent++);
1087 basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight2(*aCurrent++);
1088 const B2DPoint aSplitRight(aRight.getCutPointForGivenY(aLeft.getEnd().getY()));
1089 const B2DPoint aSplitLeft(aLeft2.getCutPointForGivenY(aRight.getEnd().getY()));
1091 ro_Result.emplace_back(
1092 aLeft.getStart().getX(),
1093 aRight.getStart().getX(),
1094 aLeft.getStart().getY(),
1095 aLeft.getEnd().getX(),
1097 aLeft.getEnd().getY());
1099 ro_Result.emplace_back(
1100 aLeft.getEnd().getX(),
1102 aLeft.getEnd().getY(),
1104 aRight.getEnd().getX(),
1105 aRight2.getStart().getY());
1107 ro_Result.emplace_back(
1109 aRight.getEnd().getX(),
1110 aRight2.getStart().getY(),
1111 aLeft2.getEnd().getX(),
1112 aRight2.getEnd().getX(),
1113 aLeft2.getEnd().getY());
1134 const double fPrecisionFactor = 0.25;
1138 const sal_uInt32 nPointCount(aSource.
count());
1145 const sal_uInt32 nEdgeCount(aSource.
isClosed() ? nPointCount : nPointCount - 1);
1148 ro_Result.reserve(ro_Result.size() + (3 * nEdgeCount));
1150 for(sal_uInt32
a(0);
a < nEdgeCount;
a++)
1152 const sal_uInt32 nNextIndex((
a + 1) % nPointCount);
TrDeEdgeEntries maTrDeEdgeEntries
std::vector< B2DPoint * > maBlocks
PointBlockAllocator maNewPoints
new points allocated for cuts
std::vector< B2DPoint > maPoints
static const size_t nBlockSize
B2DPoint maFirstStackBlock[nBlockSize]
Special case the first allocation to avoid it.
Base Point class with two double values.
bool isClosed() const
closed state interface
basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const
Coordinate interface.
bool areControlPointsUsed() const
ControlPoint checks.
sal_uInt32 count() const
member count
Base Point class with two double values.
B2DVector & setLength(double fLen)
Set the length of this 2D Vector.
bool equal(const Tuple2D< TYPE > &rTup) const
TYPE getX() const
Get X-Coordinate of 2D Tuple.
TYPE getY() const
Get Y-Coordinate of 2D Tuple.
std::list< TrDeEdgeEntry > TrDeEdgeEntries
std::vector< TrDeSimpleEdge > TrDeSimpleEdges
CutFlagValue findCut(const B2DPoint &rEdge1Start, const B2DVector &rEdge1Delta, const B2DPoint &rEdge2Start, const B2DVector &rEdge2Delta, CutFlagValue aCutFlags, double *pCut1, double *pCut2)
void createLineTrapezoidFromEdge(B2DTrapezoidVector &ro_Result, const B2DPoint &rPointA, const B2DPoint &rPointB, double fLineWidth)
B2DPolygon adaptiveSubdivideByDistance(const B2DPolygon &rCandidate, double fDistanceBound, int nRecurseLimit)
bool isPointOnEdge(const B2DPoint &rPoint, const B2DPoint &rEdgeStart, const B2DVector &rEdgeDelta, double *pCut)
void trapezoidSubdivide(B2DTrapezoidVector &ro_Result, const B2DPolyPolygon &rSourcePolyPolygon)
void createLineTrapezoidFromB2DPolygon(B2DTrapezoidVector &ro_Result, const B2DPolygon &rPolygon, double fLineWidth)
::std::vector< B2DTrapezoid > B2DTrapezoidVector
bool operator<(const wwFont &r1, const wwFont &r2)