summaryrefslogtreecommitdiff
path: root/basegfx/source/curve
diff options
context:
space:
mode:
authorRĂ¼diger Timm <rt@openoffice.org>2004-12-13 07:47:52 +0000
committerRĂ¼diger Timm <rt@openoffice.org>2004-12-13 07:47:52 +0000
commit11cb3daead3bf3a6c43522b05af4fcf57ff147ab (patch)
tree524bdfbc3b53c350ccdcdfc3b800e2811d4565e2 /basegfx/source/curve
parent56e9190d2c98dae0811af2be79775c10b2413078 (diff)
INTEGRATION: CWS aw022 (1.8.38); FILE MERGED
2004/11/25 11:09:19 aw 1.8.38.2: #i37443# 2004/11/18 11:47:37 aw 1.8.38.1: #i37380#
Diffstat (limited to 'basegfx/source/curve')
-rw-r--r--basegfx/source/curve/b2dcubicbezier.cxx301
1 files changed, 292 insertions, 9 deletions
diff --git a/basegfx/source/curve/b2dcubicbezier.cxx b/basegfx/source/curve/b2dcubicbezier.cxx
index ff6430d7fa13..15f5e061d3e2 100644
--- a/basegfx/source/curve/b2dcubicbezier.cxx
+++ b/basegfx/source/curve/b2dcubicbezier.cxx
@@ -2,9 +2,9 @@
*
* $RCSfile: b2dcubicbezier.cxx,v $
*
- * $Revision: 1.8 $
+ * $Revision: 1.9 $
*
- * last change: $Author: aw $ $Date: 2004-02-12 17:11:42 $
+ * last change: $Author: rt $ $Date: 2004-12-13 08:47:52 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
@@ -67,6 +67,255 @@
#include <basegfx/vector/b2dvector.hxx>
#endif
+#ifndef _BGFX_POLYGON_B2DPOLYGON_HXX
+#include <basegfx/polygon/b2dpolygon.hxx>
+#endif
+
+#ifndef _BGFX_NUMERIC_FTOOLS_HXX
+#include <basegfx/numeric/ftools.hxx>
+#endif
+
+// #i37443#
+#define FACTOR_FOR_UNSHARPEN (1.6)
+#ifdef DBG_UTIL
+static double fMultFactUnsharpen = FACTOR_FOR_UNSHARPEN;
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace basegfx
+{
+ namespace
+ {
+ void ImpSubDiv(
+ const B2DPoint& rfPA, // start point
+ const B2DPoint& rfEA, // edge on A
+ const B2DPoint& rfEB, // edge on B
+ const B2DPoint& rfPB, // end point
+ B2DPolygon& rTarget, // target polygon
+ double fAngleBound, // angle bound in [0.0 .. 2PI]
+ bool bAddLastPoint, // should last point be added?
+ bool bAllowUnsharpen, // #i37443# allow the criteria to get unsharp in recursions
+ sal_uInt16 nMaxRecursionDepth) // endless loop protection
+ {
+ if(nMaxRecursionDepth)
+ {
+ // do angle test
+ const B2DVector aLeft(rfEA - rfPA);
+ const B2DVector aRight(rfEB - rfPB);
+ const double fCurrentAngle(aLeft.angle(aRight));
+
+ if(fabs(fCurrentAngle) > (F_PI - fAngleBound))
+ {
+ // end recursion
+ nMaxRecursionDepth = 0;
+ }
+ else
+ {
+ if(bAllowUnsharpen)
+ {
+ // #i37443# unsharpen criteria
+#ifdef DBG_UTIL
+ fAngleBound *= fMultFactUnsharpen;
+#else
+ fAngleBound *= FACTOR_FOR_UNSHARPEN;
+#endif
+ }
+ }
+ }
+
+ if(nMaxRecursionDepth)
+ {
+ // divide at 0.5
+ const B2DPoint aS1L(average(rfPA, rfEA));
+ const B2DPoint aS1C(average(rfEA, rfEB));
+ const B2DPoint aS1R(average(rfEB, rfPB));
+ const B2DPoint aS2L(average(aS1L, aS1C));
+ const B2DPoint aS2R(average(aS1C, aS1R));
+ const B2DPoint aS3C(average(aS2L, aS2R));
+
+ // left recursion
+ ImpSubDiv(rfPA, aS1L, aS2L, aS3C, rTarget, fAngleBound,
+ bAddLastPoint, bAllowUnsharpen, nMaxRecursionDepth - 1);
+
+ // right recursion
+ ImpSubDiv(aS3C, aS2R, aS1R, rfPB, rTarget, fAngleBound,
+ bAddLastPoint, bAllowUnsharpen, nMaxRecursionDepth - 1);
+ }
+ else
+ {
+ // add points
+ rTarget.append(rfPA);
+
+ if(bAddLastPoint)
+ {
+ rTarget.append(rfPB);
+ }
+ }
+ }
+
+ void ImpSubDivStart(
+ const B2DPoint& rfPA, // start point
+ const B2DPoint& rfEA, // edge on A
+ const B2DPoint& rfEB, // edge on B
+ const B2DPoint& rfPB, // end point
+ B2DPolygon& rTarget, // target polygon
+ const double& rfAngleBound, // angle bound in [0.0 .. 2PI]
+ bool bAddLastPoint, // should last point be added?
+ bool bAllowUnsharpen) // #i37443# allow the criteria to get unsharp in recursions
+ {
+ sal_uInt16 nMaxRecursionDepth(8);
+ const B2DVector aLeft(rfEA - rfPA);
+ const B2DVector aRight(rfEB - rfPB);
+ bool bLeftEqualZero(aLeft.equalZero());
+ bool bRightEqualZero(aRight.equalZero());
+ bool bAllParallel(false);
+
+ if(bLeftEqualZero && bRightEqualZero)
+ {
+ nMaxRecursionDepth = 0;
+ }
+ else
+ {
+ const B2DVector aBase(rfPB - rfPA);
+ const bool bBaseEqualZero(aLeft.equalZero());
+
+ if(!bBaseEqualZero)
+ {
+ const bool bLeftParallel(bLeftEqualZero ? true : areParallel(aLeft, aBase));
+ const bool bRightParallel(bRightEqualZero ? true : areParallel(aRight, aBase));
+
+ if(bLeftParallel && bRightParallel)
+ {
+ bAllParallel = true;
+
+ if(!bLeftEqualZero)
+ {
+ double fFactor;
+
+ if(fabs(aBase.getX()) > fabs(aBase.getY()))
+ {
+ fFactor = aLeft.getX() / aBase.getX();
+ }
+ else
+ {
+ fFactor = aLeft.getY() / aBase.getY();
+ }
+
+ if(fFactor >= 0.0 && fFactor <= 1.0)
+ {
+ bLeftEqualZero = true;
+ }
+ }
+
+ if(!bRightEqualZero)
+ {
+ double fFactor;
+
+ if(fabs(aBase.getX()) > fabs(aBase.getY()))
+ {
+ fFactor = aRight.getX() / -aBase.getX();
+ }
+ else
+ {
+ fFactor = aRight.getY() / -aBase.getY();
+ }
+
+ if(fFactor >= 0.0 && fFactor <= 1.0)
+ {
+ bRightEqualZero = true;
+ }
+ }
+
+ if(bLeftEqualZero && bRightEqualZero)
+ {
+ nMaxRecursionDepth = 0;
+ }
+ }
+ }
+ }
+
+ if(nMaxRecursionDepth)
+ {
+ // divide at 0.5 ad test both edges for angle criteria
+ const B2DPoint aS1L(average(rfPA, rfEA));
+ const B2DPoint aS1C(average(rfEA, rfEB));
+ const B2DPoint aS1R(average(rfEB, rfPB));
+ const B2DPoint aS2L(average(aS1L, aS1C));
+ const B2DPoint aS2R(average(aS1C, aS1R));
+ const B2DPoint aS3C(average(aS2L, aS2R));
+
+ // test left
+ bool bAngleIsSmallerLeft(bAllParallel && bLeftEqualZero);
+ if(!bAngleIsSmallerLeft)
+ {
+ const B2DVector aLeftLeft(aS1L - rfPA);
+ const B2DVector aRightLeft(aS2L - aS3C);
+ const double fCurrentAngleLeft(aLeftLeft.angle(aRightLeft));
+ bAngleIsSmallerLeft = (fabs(fCurrentAngleLeft) > (F_PI - rfAngleBound));
+ }
+
+ // test right
+ bool bAngleIsSmallerRight(bAllParallel && bRightEqualZero);
+ if(!bAngleIsSmallerRight)
+ {
+ const B2DVector aLeftRight(aS2R - aS3C);
+ const B2DVector aRightRight(aS1R - rfPB);
+ const double fCurrentAngleRight(aLeftRight.angle(aRightRight));
+ bAngleIsSmallerRight = (fabs(fCurrentAngleRight) > (F_PI - rfAngleBound));
+ }
+
+ if(bAngleIsSmallerLeft && bAngleIsSmallerRight)
+ {
+ // no recursion necessary at all
+ nMaxRecursionDepth = 0;
+ }
+ else
+ {
+ // left
+ if(bAngleIsSmallerLeft)
+ {
+ rTarget.append(rfPA);
+ if(bAddLastPoint)
+ {
+ rTarget.append(aS3C);
+ }
+ }
+ else
+ {
+ ImpSubDiv(rfPA, aS1L, aS2L, aS3C, rTarget, rfAngleBound,
+ bAddLastPoint, bAllowUnsharpen, nMaxRecursionDepth);
+ }
+
+ // right
+ if(bAngleIsSmallerRight)
+ {
+ rTarget.append(aS3C);
+ if(bAddLastPoint)
+ {
+ rTarget.append(rfPB);
+ }
+ }
+ else
+ {
+ ImpSubDiv(aS3C, aS2R, aS1R, rfPB, rTarget, rfAngleBound,
+ bAddLastPoint, bAllowUnsharpen, nMaxRecursionDepth);
+ }
+ }
+ }
+
+ if(!nMaxRecursionDepth)
+ {
+ rTarget.append(rfPA);
+ if(bAddLastPoint)
+ {
+ rTarget.append(rfPB);
+ }
+ }
+ }
+ } // end of anonymous namespace
+} // end of namespace basegfx
+
//////////////////////////////////////////////////////////////////////////////
namespace basegfx
@@ -83,7 +332,7 @@ namespace basegfx
{
}
- B2DCubicBezier::B2DCubicBezier(const ::basegfx::B2DPoint& rStart, const ::basegfx::B2DPoint& rEnd)
+ B2DCubicBezier::B2DCubicBezier(const B2DPoint& rStart, const B2DPoint& rEnd)
: maStartPoint(rStart),
maEndPoint(rEnd),
maControlPointA(rStart),
@@ -91,8 +340,8 @@ namespace basegfx
{
}
- B2DCubicBezier::B2DCubicBezier(const ::basegfx::B2DPoint& rStart, const ::basegfx::B2DPoint& rControlPointA,
- const ::basegfx::B2DPoint& rControlPointB, const ::basegfx::B2DPoint& rEnd)
+ B2DCubicBezier::B2DCubicBezier(const B2DPoint& rStart, const B2DPoint& rControlPointA,
+ const B2DPoint& rControlPointB, const B2DPoint& rEnd)
: maStartPoint(rStart),
maEndPoint(rEnd),
maControlPointA(rControlPointA),
@@ -154,17 +403,51 @@ namespace basegfx
double B2DCubicBezier::getEdgeLength() const
{
- ::basegfx::B2DVector aEdge(maEndPoint - maStartPoint);
+ const B2DVector aEdge(maEndPoint - maStartPoint);
return aEdge.getLength();
}
double B2DCubicBezier::getControlPolygonLength() const
{
- ::basegfx::B2DVector aVectorA(maControlPointA - maStartPoint);
- ::basegfx::B2DVector aVectorB(maEndPoint - maControlPointB);
- ::basegfx::B2DVector aTop(maControlPointB - maControlPointA);
+ const B2DVector aVectorA(maControlPointA - maStartPoint);
+ const B2DVector aVectorB(maEndPoint - maControlPointB);
+ const B2DVector aTop(maControlPointB - maControlPointA);
return (aVectorA.getLength() + aVectorB.getLength() + aTop.getLength());
}
+
+ void B2DCubicBezier::adaptiveSubdivideByAngle(B2DPolygon& rTarget, double fAngleBound,
+ bool bAddLastPoint, bool bAllowUnsharpen) const
+ {
+ // use support method #i37443# and allow unsharpen the criteria
+ ImpSubDivStart(maStartPoint, maControlPointA, maControlPointB, maEndPoint,
+ rTarget, fAngleBound * F_PI180, bAddLastPoint, bAllowUnsharpen);
+ }
+
+ // #i37443# adaptive subdivide by nCount subdivisions
+ void B2DCubicBezier::adaptiveSubdivideByCount(B2DPolygon& rTarget, sal_uInt32 nCount, bool bAddLastPoint) const
+ {
+ rTarget.append(maStartPoint);
+
+ if(nCount)
+ {
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ const double fPos(double(a + 1L) / double(nCount + 1L));
+ const B2DPoint aS1L(interpolate(maStartPoint, maControlPointA, fPos));
+ const B2DPoint aS1C(interpolate(maControlPointA, maControlPointB, fPos));
+ const B2DPoint aS1R(interpolate(maControlPointB, maEndPoint, fPos));
+ const B2DPoint aS2L(interpolate(aS1L, aS1C, fPos));
+ const B2DPoint aS2R(interpolate(aS1C, aS1R, fPos));
+ const B2DPoint aS3C(interpolate(aS2L, aS2R, fPos));
+ rTarget.append(aS3C);
+ }
+ }
+
+ if(bAddLastPoint)
+ {
+ rTarget.append(maEndPoint);
+ }
+ }
} // end of namespace basegfx
// eof