diff options
author | Kurt Zenker <kz@openoffice.org> | 2007-05-09 12:22:58 +0000 |
---|---|---|
committer | Kurt Zenker <kz@openoffice.org> | 2007-05-09 12:22:58 +0000 |
commit | ddc7a5bc9879ae1dc78974b33c61c5a44ec61f5c (patch) | |
tree | 2a531128c1b54f77b65bb9ce245eafc8d3e820c2 /tools/source/generic | |
parent | b4f9d1a35d0b6115d82d14ac885caf080285aeaf (diff) |
INTEGRATION: CWS aw048 (1.13.42); FILE MERGED
2007/04/13 16:36:31 aw 1.13.42.1: #i74631#, #i76339# support better numerical precision at Polygon to B2DPolygon converter for C1 and C2 continuity
Diffstat (limited to 'tools/source/generic')
-rw-r--r-- | tools/source/generic/poly.cxx | 134 |
1 files changed, 103 insertions, 31 deletions
diff --git a/tools/source/generic/poly.cxx b/tools/source/generic/poly.cxx index 39a8fec07cb8..4d786d6aadda 100644 --- a/tools/source/generic/poly.cxx +++ b/tools/source/generic/poly.cxx @@ -4,9 +4,9 @@ * * $RCSfile: poly.cxx,v $ * - * $Revision: 1.13 $ + * $Revision: 1.14 $ * - * last change: $Author: kz $ $Date: 2006-12-13 15:10:36 $ + * last change: $Author: kz $ $Date: 2007-05-09 13:22:58 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. @@ -2183,50 +2183,122 @@ void Polygon::Write( SvStream& rOStream ) const } // ----------------------------------------------------------------------- +// #i74631# numerical correction method for B2DPolygon +bool impCorrectVectorAForContinuity(basegfx::B2DVector& rNewVectorA, BYTE nCFlag, const basegfx::B2DPolygon& rTarget, sal_uInt32 nCurrentIndex, sal_uInt32 nPreviousIndex) +{ + if(POLY_SMOOTH == nCFlag || POLY_SYMMTR == nCFlag) + { + // get previous vectorB + const basegfx::B2DVector aPreviousVectorB(rTarget.getControlVectorB(nPreviousIndex)); + + if(!aPreviousVectorB.equalZero()) + { + // aPreviousVectorB is used. Make it relative to the new start point + const basegfx::B2DVector aRelativeVectorB((rTarget.getB2DPoint(nPreviousIndex) + aPreviousVectorB) - rTarget.getB2DPoint(nCurrentIndex)); + + if(!aRelativeVectorB.equalZero()) + { + if(POLY_SMOOTH == nCFlag) + { + // apply inverse direction of aRelativeVectorB to aVectorA, keep length + const double fOriginalLength(rNewVectorA.getLength()); + rNewVectorA = -aRelativeVectorB; + rNewVectorA.setLength(fOriginalLength); + } + else // POLY_SYMMTR + { + // apply inverse aRelativeVectorB to rNewVectorA + rNewVectorA = -aRelativeVectorB; + } + + return true; + } + } + } + + return false; +} + +// ----------------------------------------------------------------------- // convert to ::basegfx::B2DPolygon and return ::basegfx::B2DPolygon Polygon::getB2DPolygon() const { - ::basegfx::B2DPolygon aRetval; + basegfx::B2DPolygon aRetval; const sal_uInt16 nCount(mpImplPolygon->mnPoints); - for(sal_uInt16 a(0L); a < nCount;) + if(mpImplPolygon->mpFlagAry) { - // get point - Point aPointA = mpImplPolygon->mpPointAry[a++]; + // handling for curves. Will work with non-curves too (add test for mpFlagAry + // again where commented below), but the more used non-curve case is faster this way + for(sal_uInt16 a(0); a < nCount;) + { + // get start point and add + const BYTE nStartPointFlag(mpImplPolygon->mpFlagAry[a]); + const Point aStartPoint(mpImplPolygon->mpPointAry[a++]); + const basegfx::B2DPoint aB2DStartPoint(aStartPoint.X(), aStartPoint.Y()); + aRetval.append(aB2DStartPoint); + + // test flags of next point if available, maybe it's a control point + if(a < nCount && /*mpImplPolygon->mpFlagAry &&*/ POLY_CONTROL == mpImplPolygon->mpFlagAry[a]) + { + // check if there are two control points + if(a + 1 < nCount && POLY_CONTROL == mpImplPolygon->mpFlagAry[a + 1]) + { + // get the two control points and calculate the vectors + const Point aControlA(mpImplPolygon->mpPointAry[a++]); + const Point aControlB(mpImplPolygon->mpPointAry[a++]); + basegfx::B2DVector aVectorA(aControlA.X() - aStartPoint.X(), aControlA.Y() - aStartPoint.Y()); + const basegfx::B2DVector aVectorB(aControlB.X() - aStartPoint.X(), aControlB.Y() - aStartPoint.Y()); + const sal_uInt32 nDestIndex(aRetval.count() - 1L); + + if(nDestIndex) + { + // #i74631# check if we have a C1 or C2 flagged continuity in the source. If yes, + // we will need to correct the to-be-set VectorA to have the numerically + // correct value for double precision + impCorrectVectorAForContinuity(aVectorA, nStartPointFlag, aRetval, nDestIndex, nDestIndex - 1); + } + + // add Vectors + aRetval.setControlVectorA(nDestIndex, aVectorA); + aRetval.setControlVectorB(nDestIndex, aVectorB); + } + else + { + // we have an invalid polygon (!), inform the user + DBG_ASSERT(false, "Polygon::getB2DPolygon(): invalid source polygon (curve edge with only one control point detected)" ); + } + } + } + + // set closed flag + ::basegfx::tools::checkClosed(aRetval); - // test flags of next point if available, maybe it's a control point - if(a < nCount && mpImplPolygon->mpFlagAry && POLY_CONTROL == mpImplPolygon->mpFlagAry[a]) + if(aRetval.isClosed() && nCount && aRetval.count()) { - // get two control points - Point aControlA = mpImplPolygon->mpPointAry[a++]; + // #i74631# when a closed poly is produced we need to evtl. correct continuity in start point, too + const BYTE nStartPointFlag(mpImplPolygon->mpFlagAry[0]); + basegfx::B2DVector aStartVector(aRetval.getControlVectorA(0)); - DBG_ASSERT( a < nCount, "Polygon::getB2DPolygon(): invalid polygon (polygon is ending with only one control point)" ); - if ( a < nCount ) + if(impCorrectVectorAForContinuity(aStartVector, nStartPointFlag, aRetval, 0, aRetval.count() - 1)) { - Point aControlB = mpImplPolygon->mpPointAry[a++]; - - // add point A - ::basegfx::B2DPoint aPoA(aPointA.X(), aPointA.Y()); - aRetval.append(aPoA); - - // calculate Vectors and add them - const sal_uInt32 nDestIndex(aRetval.count() - 1L); - ::basegfx::B2DVector aVeA(aControlA.X() - aPointA.X(), aControlA.Y() - aPointA.Y()); - aRetval.setControlVectorA(nDestIndex, aVeA); - ::basegfx::B2DVector aVeB(aControlB.X() - aPointA.X(), aControlB.Y() - aPointA.Y()); - aRetval.setControlVectorB(nDestIndex, aVeB); + aRetval.setControlVectorA(0, aStartVector); } } - else + } + else + { + // extra handling for non-curves for speedup + for(sal_uInt16 a(0); a < nCount; a++) { - // add point A - ::basegfx::B2DPoint aPoA(aPointA.X(), aPointA.Y()); - aRetval.append(aPoA); + // get point and add + const Point aPoint(mpImplPolygon->mpPointAry[a]); + aRetval.append(basegfx::B2DPoint(aPoint.X(), aPoint.Y())); } - } - // set closed flag - ::basegfx::tools::checkClosed(aRetval); + // set closed flag + ::basegfx::tools::checkClosed(aRetval); + } return aRetval; } |