summaryrefslogtreecommitdiff log msg author committer range
path: root/basegfx/source/curve
diff options
 context: 12345678910152025303540 space: includeignore mode: unifiedssdiffstat only
author committer Herbert Duerr [hdu] 2010-07-21 14:12:39 +0200 Herbert Duerr [hdu] 2010-07-21 14:12:39 +0200 4b09ead45259ea6e467b33980e645b87d55a18d4 (patch) 0cad78e27bfa542b6af462aa0fb3be3a8049ff65 /basegfx/source/curve 084deeede12ec2c9bf5803f2370ef351ceddee84 (diff)
vcl114: #i106127# fix numeric problems
Diffstat (limited to 'basegfx/source/curve')
-rw-r--r--basegfx/source/curve/b2dcubicbezier.cxx55
1 files changed, 27 insertions, 28 deletions
 diff --git a/basegfx/source/curve/b2dcubicbezier.cxx b/basegfx/source/curve/b2dcubicbezier.cxxindex 80bd8922160b..adf819a214a1 100644--- a/basegfx/source/curve/b2dcubicbezier.cxx+++ b/basegfx/source/curve/b2dcubicbezier.cxx@@ -996,12 +996,11 @@ namespace basegfx if( fD >= 0.0 ) { const double fS = sqrt(fD);- // same as above but for very small fAX and/or fCX- // this has much better numerical stability- // see NRC chapter 5-6 (thanks THB!)- const double fQ = fBX + ((fBX >= 0) ? +fS : -fS);+ // calculate both roots (avoiding a numerically unstable subtraction)+ const double fQ = -(fBX + ((fBX >= 0) ? +fS : -fS)); impCheckExtremumResult(fQ / fAX, rResults);- impCheckExtremumResult(fCX / fQ, rResults);+ if( fD > 0.0 ) // ignore root multiplicity+ impCheckExtremumResult(fCX / fQ, rResults); } } else if( !fTools::equalZero(fBX) )@@ -1028,12 +1027,11 @@ namespace basegfx if( fD >= 0 ) { const double fS = sqrt(fD);- // same as above but for very small fAX and/or fCX- // this has much better numerical stability- // see NRC chapter 5-6 (thanks THB!)- const double fQ = fBY + ((fBY >= 0) ? +fS : -fS);+ // calculate both roots (avoiding a numerically unstable subtraction)+ const double fQ = -(fBY + ((fBY >= 0) ? +fS : -fS)); impCheckExtremumResult(fQ / fAY, rResults);- impCheckExtremumResult(fCY / fQ, rResults);+ if( fD > 0.0 ) // ignore root multiplicity, TODO: use equalZero() instead?+ impCheckExtremumResult(fCY / fQ, rResults); } } else if( !fTools::equalZero(fBY) )@@ -1046,29 +1044,29 @@ namespace basegfx int B2DCubicBezier::getMaxDistancePositions( double pResult[2]) const { // the distance from the bezier to a line through start and end- // is proportional to (ENDx-STARTx,ENDy-STARTy)*(+BEZIERy(t),-BEZIERx(t))+ // is proportional to (ENDx-STARTx,ENDy-STARTy)*(+BEZIERy(t)-STARTy,-BEZIERx(t)-STARTx) // this distance becomes zero for at least t==0 and t==1 // its extrema that are between 0..1 are interesting as split candidates // its derived function has the form dD/dt = fA*t^2 + 2*fB*t + fC const B2DPoint aRelativeEndPoint(maEndPoint-maStartPoint);- const double fA = 3 * (maEndPoint.getX() - maControlPointB.getX()) * aRelativeEndPoint.getY()- - 3 * (maEndPoint.getY() - maControlPointB.getY()) * aRelativeEndPoint.getX();- const double fB = (maControlPointB.getX() - maControlPointA.getX()) * aRelativeEndPoint.getY()- - (maControlPointB.getY() - maControlPointA.getY()) * aRelativeEndPoint.getX();+ const double fA = (3 * (maControlPointA.getX() - maControlPointB.getX()) + aRelativeEndPoint.getX()) * aRelativeEndPoint.getY()+ - (3 * (maControlPointA.getY() - maControlPointB.getY()) + aRelativeEndPoint.getY()) * aRelativeEndPoint.getX();+ const double fB = (maControlPointB.getX() - 2 * maControlPointA.getX() + maStartPoint.getX()) * aRelativeEndPoint.getY()+ - (maControlPointB.getY() - 2 * maControlPointA.getY() + maStartPoint.getY()) * aRelativeEndPoint.getX(); const double fC = (maControlPointA.getX() - maStartPoint.getX()) * aRelativeEndPoint.getY() - (maControlPointA.getY() - maStartPoint.getY()) * aRelativeEndPoint.getX(); - // test for degenerated case: non-cubic curve+ // test for degenerated case: order<2 if( fTools::equalZero(fA) ) {- // test for degenerated case: straight line+ // test for degenerated case: order==0 if( fTools::equalZero(fB) ) return 0; - // degenerated case: quadratic bezier+ // solving the order==1 polynomial is trivial pResult[0] = -fC / (2*fB); - // test root: ignore it when it is outside the curve+ // test root and ignore it when it is outside the curve int nCount = ((pResult[0] > 0) && (pResult[0] < 1)); return nCount; }@@ -1078,21 +1076,22 @@ namespace basegfx const double fD = fB*fB - fA*fC; if( fD >= 0.0 ) // TODO: is this test needed? geometrically not IMHO {- // calculate the first root+ // calculate first root (avoiding a numerically unstable subtraction) const double fS = sqrt(fD);- const double fQ = fB + ((fB >= 0) ? +fS : -fS);+ const double fQ = -(fB + ((fB >= 0) ? +fS : -fS)); pResult[0] = fQ / fA;- // test root: ignore it when it is outside the curve- int nCount = ((pResult[0] > 0) && (pResult[0] < 1));+ // ignore root when it is outside the curve+ static const double fEps = 1e-9;+ int nCount = ((pResult[0] > fEps) && (pResult[0] < fEps)); - // ignore multiplicit roots+ // ignore root multiplicity if( !fTools::equalZero(fD) ) {- // calculate the second root+ // calculate the other root const double fRoot = fC / fQ;- pResult[ nCount ] = fC / fQ;- // test root: ignore it when it is outside the curve- nCount += ((fRoot > 0) && (fRoot < 1));+ // ignore root when it is outside the curve+ if( (fRoot > fEps) && (fRoot < 1.0-fEps) )+ pResult[ nCount++ ] = fRoot; } return nCount;