26#include <osl/diagnose.h>
31#define FACTOR_FOR_UNSHARPEN (1.6)
48 sal_uInt16 nMaxRecursionDepth)
50 if(nMaxRecursionDepth)
53 B2DVector aLeft(rfEA - rfPA);
54 B2DVector aRight(rfEB - rfPB);
62 if(aRight.equalZero())
67 const double fCurrentAngle(aLeft.angle(aRight));
69 if(fabs(fCurrentAngle) > (M_PI - fAngleBound))
72 nMaxRecursionDepth = 0;
88 if(nMaxRecursionDepth)
91 const B2DPoint aS1L(
average(rfPA, rfEA));
92 const B2DPoint aS1C(
average(rfEA, rfEB));
93 const B2DPoint aS1R(
average(rfEB, rfPB));
94 const B2DPoint aS2L(
average(aS1L, aS1C));
95 const B2DPoint aS2R(
average(aS1C, aS1R));
96 const B2DPoint aS3C(
average(aS2L, aS2R));
99 ImpSubDivAngle(rfPA, aS1L, aS2L, aS3C,
rTarget, fAngleBound, bAllowUnsharpen, nMaxRecursionDepth - 1);
102 ImpSubDivAngle(aS3C, aS2R, aS1R, rfPB,
rTarget, fAngleBound, bAllowUnsharpen, nMaxRecursionDepth - 1);
110 void ImpSubDivAngleStart(
111 const B2DPoint& rfPA,
112 const B2DPoint& rfEA,
113 const B2DPoint& rfEB,
114 const B2DPoint& rfPB,
116 const double& rfAngleBound)
118 sal_uInt16 nMaxRecursionDepth(8);
119 const B2DVector aLeft(rfEA - rfPA);
120 const B2DVector aRight(rfEB - rfPB);
121 bool bLeftEqualZero(aLeft.equalZero());
122 bool bRightEqualZero(aRight.equalZero());
123 bool bAllParallel(
false);
125 if(bLeftEqualZero && bRightEqualZero)
127 nMaxRecursionDepth = 0;
131 const B2DVector aBase(rfPB - rfPA);
132 const bool bBaseEqualZero(aBase.equalZero());
136 const bool bLeftParallel(bLeftEqualZero ||
areParallel(aLeft, aBase));
137 const bool bRightParallel(bRightEqualZero ||
areParallel(aRight, aBase));
139 if(bLeftParallel && bRightParallel)
147 if(fabs(aBase.getX()) > fabs(aBase.getY()))
149 fFactor = aLeft.getX() / aBase.getX();
153 fFactor = aLeft.getY() / aBase.getY();
156 if(fFactor >= 0.0 && fFactor <= 1.0)
158 bLeftEqualZero =
true;
166 if(fabs(aBase.getX()) > fabs(aBase.getY()))
168 fFactor = aRight.getX() / -aBase.getX();
172 fFactor = aRight.getY() / -aBase.getY();
175 if(fFactor >= 0.0 && fFactor <= 1.0)
177 bRightEqualZero =
true;
181 if(bLeftEqualZero && bRightEqualZero)
183 nMaxRecursionDepth = 0;
189 if(nMaxRecursionDepth)
192 const B2DPoint aS1L(
average(rfPA, rfEA));
193 const B2DPoint aS1C(
average(rfEA, rfEB));
194 const B2DPoint aS1R(
average(rfEB, rfPB));
195 const B2DPoint aS2L(
average(aS1L, aS1C));
196 const B2DPoint aS2R(
average(aS1C, aS1R));
197 const B2DPoint aS3C(
average(aS2L, aS2R));
200 bool bAngleIsSmallerLeft(bAllParallel && bLeftEqualZero);
201 if(!bAngleIsSmallerLeft)
203 const B2DVector aLeftLeft(bLeftEqualZero ? aS2L - aS1L : aS1L - rfPA);
204 const B2DVector aRightLeft(aS2L - aS3C);
205 const double fCurrentAngleLeft(aLeftLeft.angle(aRightLeft));
206 bAngleIsSmallerLeft = (fabs(fCurrentAngleLeft) > (M_PI - rfAngleBound));
210 bool bAngleIsSmallerRight(bAllParallel && bRightEqualZero);
211 if(!bAngleIsSmallerRight)
213 const B2DVector aLeftRight(aS2R - aS3C);
214 const B2DVector aRightRight(bRightEqualZero ? aS2R - aS1R : aS1R - rfPB);
215 const double fCurrentAngleRight(aLeftRight.angle(aRightRight));
216 bAngleIsSmallerRight = (fabs(fCurrentAngleRight) > (M_PI - rfAngleBound));
219 if(bAngleIsSmallerLeft && bAngleIsSmallerRight)
222 nMaxRecursionDepth = 0;
227 if(bAngleIsSmallerLeft)
233 ImpSubDivAngle(rfPA, aS1L, aS2L, aS3C,
rTarget, rfAngleBound,
true, nMaxRecursionDepth);
237 if(bAngleIsSmallerRight)
243 ImpSubDivAngle(aS3C, aS2R, aS1R, rfPB,
rTarget, rfAngleBound,
true, nMaxRecursionDepth);
248 if(!nMaxRecursionDepth)
254 void ImpSubDivDistance(
255 const B2DPoint& rfPA,
256 const B2DPoint& rfEA,
257 const B2DPoint& rfEB,
258 const B2DPoint& rfPB,
260 double fDistanceBound2,
261 double fLastDistanceError2,
262 sal_uInt16 nMaxRecursionDepth)
264 if(nMaxRecursionDepth)
279 const double fJ1x(rfEA.getX() - rfPA.getX() - 1.0/3.0*(rfPB.getX() - rfPA.getX()));
280 const double fJ1y(rfEA.getY() - rfPA.getY() - 1.0/3.0*(rfPB.getY() - rfPA.getY()));
281 const double fJ2x(rfEB.getX() - rfPA.getX() - 2.0/3.0*(rfPB.getX() - rfPA.getX()));
282 const double fJ2y(rfEB.getY() - rfPA.getY() - 2.0/3.0*(rfPB.getY() - rfPA.getY()));
283 const double fDistanceError2(std::max(fJ1x*fJ1x + fJ1y*fJ1y, fJ2x*fJ2x + fJ2y*fJ2y));
288 const bool bFurtherDivision(fLastDistanceError2 > fDistanceError2 && fDistanceError2 >= fDistanceBound2);
293 fLastDistanceError2 = fDistanceError2;
298 nMaxRecursionDepth = 0;
302 if(nMaxRecursionDepth)
305 const B2DPoint aS1L(
average(rfPA, rfEA));
306 const B2DPoint aS1C(
average(rfEA, rfEB));
307 const B2DPoint aS1R(
average(rfEB, rfPB));
308 const B2DPoint aS2L(
average(aS1L, aS1C));
309 const B2DPoint aS2R(
average(aS1C, aS1R));
310 const B2DPoint aS3C(
average(aS2L, aS2R));
313 ImpSubDivDistance(rfPA, aS1L, aS2L, aS3C,
rTarget, fDistanceBound2, fLastDistanceError2, nMaxRecursionDepth - 1);
316 ImpSubDivDistance(aS3C, aS2R, aS1R, rfPB,
rTarget, fDistanceBound2, fLastDistanceError2, nMaxRecursionDepth - 1);
335 maControlPointA(rControlPointA),
336 maControlPointB(rControlPointB)
407 const double fInverseEdgeLength(bAIsTrivial && bBIsTrivial
416 const double fCross(aVecA.
cross(aEdge) * fInverseEdgeLength);
421 const double fScale(fabs(aEdge.
getX()) > fabs(aEdge.
getY())
435 if(bAIsTrivial && !bBIsTrivial)
438 const double fCross(aVecB.
cross(aEdge) * fInverseEdgeLength);
443 const double fScale(fabs(aEdge.
getX()) > fabs(aEdge.
getY())
457 if(bAIsTrivial && bBIsTrivial)
465 double impGetLength(
const B2DCubicBezier& rEdge,
double fDeviation, sal_uInt32 nRecursionWatch)
469 const double fCurrentDeviation(
fTools::equalZero(fControlPolygonLength) ? 0.0 : 1.0 - (fEdgeLength / fControlPolygonLength));
473 return (fEdgeLength + fControlPolygonLength) * 0.5;
477 B2DCubicBezier aLeft, aRight;
478 const double fNewDeviation(fDeviation * 0.5);
479 const sal_uInt32 nNewRecursionWatch(nRecursionWatch - 1);
481 rEdge.
split(0.5, &aLeft, &aRight);
483 return impGetLength(aLeft, fNewDeviation, nNewRecursionWatch)
484 + impGetLength(aRight, fNewDeviation, nNewRecursionWatch);
493 if(fDeviation < 0.00000001)
495 fDeviation = 0.00000001;
498 return impGetLength(*
this, fDeviation, 6);
592 split(
t,
nullptr, &aRight);
601 const double fLenFact(1.0 /
static_cast< double >(
nCount + 1));
605 const double fPos(
static_cast< double >(
a) * fLenFact);
618 fDistanceBound * fDistanceBound, std::numeric_limits<double>::max(), nRecurseLimit);
628 OSL_ENSURE(
t >= 0.0 &&
t <= 1.0,
"B2DCubicBezier::interpolatePoint: Access out of range (!)");
648 const sal_uInt32 nInitialDivisions(3);
656 const sal_uInt32 nPointCount(aInitialPolygon.
count());
658 double fQuadDist(aVector.
getX() * aVector.
getX() + aVector.
getY() * aVector.
getY());
660 sal_uInt32 nSmallestIndex(0);
662 for(sal_uInt32
a(1);
a < nPointCount;
a++)
665 fNewQuadDist = aVector.
getX() * aVector.
getX() + aVector.
getY() * aVector.
getY();
667 if(fNewQuadDist < fQuadDist)
669 fQuadDist = fNewQuadDist;
675 double fStepValue(1.0 /
static_cast<double>((nPointCount - 1) * 2));
676 double fPosition(
static_cast<double>(nSmallestIndex) /
static_cast<double>(nPointCount - 1));
681 double fPosLeft(fPosition - fStepValue);
693 fNewQuadDist = aVector.
getX() * aVector.
getX() + aVector.
getY() * aVector.
getY();
697 fQuadDist = fNewQuadDist;
698 fPosition = fPosLeft;
703 double fPosRight(fPosition + fStepValue);
715 fNewQuadDist = aVector.
getX() * aVector.
getX() + aVector.
getY() * aVector.
getY();
719 fQuadDist = fNewQuadDist;
720 fPosition = fPosRight;
729 if(fPosition == 0.0 || fPosition == 1.0)
740 return sqrt(fQuadDist);
745 OSL_ENSURE(
t >= 0.0 &&
t <= 1.0,
"B2DCubicBezier::split: Access out of range (!)");
747 if(!pBezierA && !pBezierB)
824 const double fSplit((fEnd + fStart) * 0.5);
843 aRetval.
split(fEnd, &aRetval,
nullptr);
853 aRetval.
split(fStart,
nullptr, &aRetval);
883 std::vector< double > aAllResults;
885 aAllResults.reserve(4);
888 const sal_uInt32
nCount(aAllResults.size());
896 rfResult = aAllResults[0];
901 rfResult = *(std::min_element(aAllResults.begin(), aAllResults.end()));
908 void impCheckExtremumResult(
double fCandidate, std::vector< double >& rResult)
917 rResult.push_back(fCandidate);
932 const double fBX = fCX + aControlDiff.
getX();
944 const double fD = fBX*fBX - fAX*fCX;
947 const double fS = sqrt(fD);
949 const double fQ = fBX + ((fBX >= 0) ? +fS : -fS);
950 impCheckExtremumResult(fQ / fAX, rResults);
952 impCheckExtremumResult(fCX / fQ, rResults);
958 impCheckExtremumResult(fCX / (2 * fBX), rResults);
963 const double fBY = fCY + aControlDiff.
getY();
975 const double fD = fBY*fBY - fAY*fCY;
978 const double fS = sqrt(fD);
980 const double fQ = fBY + ((fBY >= 0) ? +fS : -fS);
981 impCheckExtremumResult(fQ / fAY, rResults);
983 impCheckExtremumResult(fCY / fQ, rResults);
989 impCheckExtremumResult(fCY / (2 * fBY), rResults);
#define FACTOR_FOR_UNSHARPEN
const double fMultFactUnsharpen
B2DCubicBezier & operator=(const B2DCubicBezier &rBezier)
void setStartPoint(const B2DPoint &rValue)
const B2DPoint & getStartPoint() const
SAL_DLLPRIVATE B2DCubicBezier snippet(double fStart, double fEnd) const
bool operator!=(const B2DCubicBezier &rBezier) const
SAL_DLLPRIVATE void fround()
fround content
SAL_DLLPRIVATE void getAllExtremumPositions(::std::vector< double > &rResults) const
Get all extremum pos of this segment.
const B2DPoint & getControlPointB() const
SAL_DLLPRIVATE bool getMinimumExtremumPosition(double &rfResult) const
Get the minimum extremum position t.
SAL_DLLPRIVATE void adaptiveSubdivideByAngle(B2DPolygon &rTarget, double fAngleBound) const
adaptive subdivide by angle criteria no start point is added, but all necessary created edges and the...
double getLength(double fDeviation=0.01) const
get length of edge
SAL_DLLPRIVATE double getSmallestDistancePointToBezierSegment(const B2DPoint &rTestPoint, double &rCut) const
void setControlPointA(const B2DPoint &rValue)
void setEndPoint(const B2DPoint &rValue)
B2DRange getRange() const
void setControlPointB(const B2DPoint &rValue)
B2DPoint interpolatePoint(double t) const
void testAndSolveTrivialBezier()
void transform(const basegfx::B2DHomMatrix &rMatrix)
apply transformation given in matrix form
bool operator==(const B2DCubicBezier &rBezier) const
void split(double t, B2DCubicBezier *pBezierA, B2DCubicBezier *pBezierB) const
const B2DPoint & getEndPoint() const
const B2DPoint & getControlPointA() const
SAL_DLLPRIVATE double getControlPolygonLength() const
bool equal(const B2DCubicBezier &rBezier) const
B2DVector getTangent(double t) const
get the tangent in point t
SAL_DLLPRIVATE double getEdgeLength() const
SAL_DLLPRIVATE void adaptiveSubdivideByCount(B2DPolygon &rTarget, sal_uInt32 nCount) const
#i37443# adaptive subdivide by nCount subdivisions no start point is added, but all necessary created...
void adaptiveSubdivideByDistance(B2DPolygon &rTarget, double fDistanceBound, int nRecurseLimit=30) const
Subdivide cubic bezier segment.
Base Point class with two double values.
basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const
Coordinate interface.
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
sal_uInt32 count() const
member count
A two-dimensional interval over doubles.
Base Point class with two double values.
double cross(const B2DVector &rVec) const
Calculate the length of the cross product with another 2D Vector.
double getLength() const
Calculate the length of this 2D Vector.
void expand(const Tuple2D< TYPE > &rTuple)
add point to the set, expanding as necessary
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.
::basegfx::B2DPoint maStartPoint
::basegfx::B2DPoint maEndPoint
B2DTuple interpolate(const B2DTuple &rOld1, const B2DTuple &rOld2, double t)
bool areParallel(const B2DVector &rVecA, const B2DVector &rVecB)
Test two vectors which need not to be normalized for parallelism.
B2DTuple average(const B2DTuple &rOld1, const B2DTuple &rOld2)
B2IRange fround(const B2DRange &rRange)
Round double to nearest integer for 2D range.
constexpr double deg2rad(double v)
Convert value from degrees to radians.