diff options
author | Oliver Bolte <obo@openoffice.org> | 2007-07-18 10:09:35 +0000 |
---|---|---|
committer | Oliver Bolte <obo@openoffice.org> | 2007-07-18 10:09:35 +0000 |
commit | 1f5899f9b78718c5c13f3cce9a651be873601e5e (patch) | |
tree | 71b3fd10cce71274c6ca21c68e653b814459dbf5 /tools/source/generic/poly.cxx | |
parent | 252e5a2f9d473d67c5b1a15fb64d46a490385591 (diff) |
INTEGRATION: CWS aw051 (1.14.6); FILE MERGED
2007/06/12 16:31:57 aw 1.14.6.4: #i77162# Continued adaptions to bezier handling
2007/06/11 14:38:17 aw 1.14.6.3: #i77162# 2nd adaptions to new bezier handling
2007/06/07 11:26:58 aw 1.14.6.2: #i77162# adaptions to changed B2DPolygon bezier handling
2007/05/30 13:16:47 aw 1.14.6.1: #i76891# reworked B2DPolygon to Polygon converter to produce minimal Polygons when curves are used
Diffstat (limited to 'tools/source/generic/poly.cxx')
-rw-r--r-- | tools/source/generic/poly.cxx | 312 |
1 files changed, 164 insertions, 148 deletions
diff --git a/tools/source/generic/poly.cxx b/tools/source/generic/poly.cxx index 24f71a479d21..f87ba350b6da 100644 --- a/tools/source/generic/poly.cxx +++ b/tools/source/generic/poly.cxx @@ -4,9 +4,9 @@ * * $RCSfile: poly.cxx,v $ * - * $Revision: 1.15 $ + * $Revision: 1.16 $ * - * last change: $Author: hr $ $Date: 2007-06-27 22:14:17 $ + * last change: $Author: obo $ $Date: 2007-07-18 11:09:35 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. @@ -82,6 +82,10 @@ #include <basegfx/polygon/b2dpolygontools.hxx> #endif +#ifndef _BGFX_CURVE_B2DCUBICBEZIER_HXX +#include <basegfx/curve/b2dcubicbezier.hxx> +#endif + #include <vector> #include <iterator> #include <algorithm> @@ -2184,133 +2188,138 @@ 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) +void impCorrectContinuity(basegfx::B2DPolygon& roPolygon, sal_uInt32 nIndex, BYTE nCFlag) { - if(POLY_SMOOTH == nCFlag || POLY_SYMMTR == nCFlag) - { - // get previous vectorB - const basegfx::B2DVector aPreviousVectorB(rTarget.getControlVectorB(nPreviousIndex)); + const sal_uInt32 nPointCount(roPolygon.count()); + OSL_ENSURE(nIndex < nPointCount, "impCorrectContinuity: index access out of range (!)"); - if(!aPreviousVectorB.equalZero()) + if(nIndex < nPointCount && (POLY_SMOOTH == nCFlag || POLY_SYMMTR == nCFlag)) + { + if(roPolygon.isPrevControlPointUsed(nIndex) && roPolygon.isNextControlPointUsed(nIndex)) { - // aPreviousVectorB is used. Make it relative to the new start point - const basegfx::B2DVector aRelativeVectorB((rTarget.getB2DPoint(nPreviousIndex) + aPreviousVectorB) - rTarget.getB2DPoint(nCurrentIndex)); + const basegfx::B2DPoint aPoint(roPolygon.getB2DPoint(nIndex)); - if(!aRelativeVectorB.equalZero()) + if(POLY_SMOOTH == nCFlag) { - 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; - } + // C1: apply inverse direction of prev to next, keep length of next + const basegfx::B2DVector aOriginalNext(roPolygon.getNextControlPoint(nIndex) - aPoint); + basegfx::B2DVector aNewNext(aPoint - roPolygon.getPrevControlPoint(nIndex)); - return true; + aNewNext.setLength(aOriginalNext.getLength()); + roPolygon.setNextControlPoint(nIndex, basegfx::B2DPoint(aPoint + aNewNext)); + } + else // POLY_SYMMTR + { + // C2: apply inverse control point to next + roPolygon.setNextControlPoint(nIndex, (2.0 * aPoint) - roPolygon.getPrevControlPoint(nIndex)); } } } - - return false; } // ----------------------------------------------------------------------- -// convert to ::basegfx::B2DPolygon and return -::basegfx::B2DPolygon Polygon::getB2DPolygon() const +// convert to basegfx::B2DPolygon and return +basegfx::B2DPolygon Polygon::getB2DPolygon() const { basegfx::B2DPolygon aRetval; const sal_uInt16 nCount(mpImplPolygon->mnPoints); - if(mpImplPolygon->mpFlagAry) + if(nCount) { - // 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;) + if(mpImplPolygon->mpFlagAry) { - // 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]) + // handling for curves. Add start point + const Point aStartPoint(mpImplPolygon->mpPointAry[0]); + BYTE nPointFlag(mpImplPolygon->mpFlagAry[0]); + aRetval.append(basegfx::B2DPoint(aStartPoint.X(), aStartPoint.Y())); + Point aControlA, aControlB; + + for(sal_uInt16 a(1); a < nCount;) { - // check if there are two control points - if(a + 1 < nCount && POLY_CONTROL == mpImplPolygon->mpFlagAry[a + 1]) + bool bControlA(false); + bool bControlB(false); + + if(POLY_CONTROL == mpImplPolygon->mpFlagAry[a]) { - // 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); - } + aControlA = mpImplPolygon->mpPointAry[a++]; + bControlA = true; + } - // add Vectors - aRetval.setControlVectorA(nDestIndex, aVectorA); - aRetval.setControlVectorB(nDestIndex, aVectorB); + if(a < nCount && POLY_CONTROL == mpImplPolygon->mpFlagAry[a]) + { + aControlB = mpImplPolygon->mpPointAry[a++]; + bControlB = true; } - else + + // assert invalid polygons + OSL_ENSURE(bControlA == bControlB, "Polygon::getB2DPolygon: Invalid source polygon (!)"); + + if(a < nCount) { - // we have an invalid polygon (!), inform the user - DBG_ASSERT(false, "Polygon::getB2DPolygon(): invalid source polygon (curve edge with only one control point detected)" ); + const Point aEndPoint(mpImplPolygon->mpPointAry[a]); + + if(bControlA) + { + // bezier edge, add + aRetval.appendBezierSegment( + basegfx::B2DPoint(aControlA.X(), aControlA.Y()), + basegfx::B2DPoint(aControlB.X(), aControlB.Y()), + basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y())); + + impCorrectContinuity(aRetval, aRetval.count() - 2, nPointFlag); + } + else + { + // no bezier edge, add end point + aRetval.append(basegfx::B2DPoint(aEndPoint.X(), aEndPoint.Y())); + } + + nPointFlag = mpImplPolygon->mpFlagAry[a++]; } } - } - - // set closed flag - ::basegfx::tools::checkClosed(aRetval); - if(aRetval.isClosed() && nCount && aRetval.count()) - { - // #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)); + // if exist, remove double first/last points, set closed and correct control points + basegfx::tools::checkClosed(aRetval); - if(impCorrectVectorAForContinuity(aStartVector, nStartPointFlag, aRetval, 0, aRetval.count() - 1)) + if(aRetval.isClosed()) { - aRetval.setControlVectorA(0, aStartVector); + // closeWithGeometryChange did really close, so last point(s) were removed. + // Correct the continuity in the changed point + impCorrectContinuity(aRetval, 0, mpImplPolygon->mpFlagAry[0]); } } - } - else - { - // extra handling for non-curves for speedup - for(sal_uInt16 a(0); a < nCount; a++) + else { - // get point and add - const Point aPoint(mpImplPolygon->mpPointAry[a]); - aRetval.append(basegfx::B2DPoint(aPoint.X(), aPoint.Y())); - } + // extra handling for non-curves (most-used case) for speedup + for(sal_uInt16 a(0); a < nCount; a++) + { + // 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; } // ----------------------------------------------------------------------- -// constructor to convert from ::basegfx::B2DPolygon -Polygon::Polygon(const ::basegfx::B2DPolygon& rPolygon) +// constructor to convert from basegfx::B2DPolygon +// #i76891# Needed to change from adding all control points (even for unused +// edges) and creating a fixed-size Polygon in the first run to creating the +// minimal Polygon. This requires a temporary Point- and Flag-Array for curves +// and a memcopy at ImplPolygon creation, but contains no zero-controlpoints +// for straight edges. +Polygon::Polygon(const basegfx::B2DPolygon& rPolygon) +: mpImplPolygon(0) { DBG_CTOR( Polygon, NULL ); - const sal_Bool bCurve(rPolygon.areControlPointsUsed()); - const sal_Bool bClosed(rPolygon.isClosed()); + const bool bCurve(rPolygon.areControlPointsUsed()); + const bool bClosed(rPolygon.isClosed()); sal_uInt32 nB2DLocalCount(rPolygon.count()); if(bCurve) @@ -2322,86 +2331,88 @@ Polygon::Polygon(const ::basegfx::B2DPolygon& rPolygon) nB2DLocalCount = ((0x0000ffff / 3L) - 1L); } - // curve creation + // calculate target point count const sal_uInt32 nLoopCount(bClosed ? nB2DLocalCount : (nB2DLocalCount ? nB2DLocalCount - 1L : 0L )); - const sal_uInt32 nTargetCount(nLoopCount ? (nLoopCount * 3L) + 1L : 0L); - mpImplPolygon = new ImplPolygon( sal_uInt16(nTargetCount) ); - mpImplPolygon->ImplCreateFlagArray(); if(nLoopCount) { - sal_uInt16 nIndex(0); + // calculate maximum array size and allocate; prepare insert index + const sal_uInt32 nMaxTargetCount((nLoopCount * 3) + 1); + mpImplPolygon = new ImplPolygon(static_cast< sal_uInt16 >(nMaxTargetCount), true); + + // prepare insert index and current point + sal_uInt32 nArrayInsert(0); + basegfx::B2DCubicBezier aBezier; + aBezier.setStartPoint(rPolygon.getB2DPoint(0)); for(sal_uInt32 a(0L); a < nLoopCount; a++) { - // get and add start point - ::basegfx::B2DPoint aB2DPointA(rPolygon.getB2DPoint(a)); - Point aPointA(FRound(aB2DPointA.getX()), FRound(aB2DPointA.getY())); - sal_uInt16 nPointIndex(nIndex++); - mpImplPolygon->mpPointAry[nPointIndex] = aPointA; - mpImplPolygon->mpFlagAry[nPointIndex] = (BYTE)POLY_NORMAL; - - // get and add first control point - ::basegfx::B2DVector aB2DVectorA(rPolygon.getControlVectorA(a)); - const sal_Bool bVectorAUsed(!aB2DVectorA.equalZero()); - Point aVecA(aPointA); - - if(bVectorAUsed) - { - aVecA = Point( - FRound(aB2DPointA.getX() + aB2DVectorA.getX()), - FRound(aB2DPointA.getY() + aB2DVectorA.getY())); - } - - mpImplPolygon->mpPointAry[nIndex] = aVecA; - mpImplPolygon->mpFlagAry[nIndex++] = (BYTE)POLY_CONTROL; - - // get and add second control point - ::basegfx::B2DVector aB2DVectorB(rPolygon.getControlVectorB(a)); - const sal_Bool bVectorBUsed(!aB2DVectorB.equalZero()); - Point aVecB(aPointA); - - if(bVectorBUsed) + // add current point (always) and remember StartPointIndex for evtl. later corrections + const Point aStartPoint(FRound(aBezier.getStartPoint().getX()), FRound(aBezier.getStartPoint().getY())); + const sal_uInt32 nStartPointIndex(nArrayInsert); + mpImplPolygon->mpPointAry[nStartPointIndex] = aStartPoint; + mpImplPolygon->mpFlagAry[nStartPointIndex] = (BYTE)POLY_NORMAL; + nArrayInsert++; + + // prepare next segment + const sal_uInt32 nNextIndex((a + 1) % nB2DLocalCount); + aBezier.setEndPoint(rPolygon.getB2DPoint(nNextIndex)); + aBezier.setControlPointA(rPolygon.getNextControlPoint(a)); + aBezier.setControlPointB(rPolygon.getPrevControlPoint(nNextIndex)); + + if(aBezier.isBezier()) { - aVecB = Point( - FRound(aB2DPointA.getX() + aB2DVectorB.getX()), - FRound(aB2DPointA.getY() + aB2DVectorB.getY())); + // if one is used, add always two control points due to the old schema + mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointA().getX()), FRound(aBezier.getControlPointA().getY())); + mpImplPolygon->mpFlagAry[nArrayInsert] = (BYTE)POLY_CONTROL; + nArrayInsert++; + + mpImplPolygon->mpPointAry[nArrayInsert] = Point(FRound(aBezier.getControlPointB().getX()), FRound(aBezier.getControlPointB().getY())); + mpImplPolygon->mpFlagAry[nArrayInsert] = (BYTE)POLY_CONTROL; + nArrayInsert++; } - mpImplPolygon->mpPointAry[nIndex] = aVecB; - mpImplPolygon->mpFlagAry[nIndex++] = (BYTE)POLY_CONTROL; - - // test continuity with previous control point - if(bVectorAUsed && (bClosed || a)) + // test continuity with previous control point to set flag value + if(aBezier.getControlPointA() != aBezier.getStartPoint() && (bClosed || a)) { - const sal_uInt32 nPrevInd(a == 0L ? nB2DLocalCount - 1L : a - 1L); - ::basegfx::B2DVector aB2DVectorPrev(rPolygon.getControlPointB(nPrevInd) - aB2DPointA); - ::basegfx::B2VectorContinuity eCont = ::basegfx::getContinuity(aB2DVectorPrev, aB2DVectorA); + const basegfx::B2VectorContinuity eCont(rPolygon.getContinuityInPoint(a)); - if(::basegfx::CONTINUITY_C1 == eCont) + if(basegfx::CONTINUITY_C1 == eCont) { - mpImplPolygon->mpFlagAry[nPointIndex] = (BYTE)POLY_SMOOTH; + mpImplPolygon->mpFlagAry[nStartPointIndex] = (BYTE)POLY_SMOOTH; } - else if(::basegfx::CONTINUITY_C2 == eCont) + else if(basegfx::CONTINUITY_C2 == eCont) { - mpImplPolygon->mpFlagAry[nPointIndex] = (BYTE)POLY_SYMMTR; + mpImplPolygon->mpFlagAry[nStartPointIndex] = (BYTE)POLY_SYMMTR; } } + + // prepare next polygon step + aBezier.setStartPoint(aBezier.getEndPoint()); } if(bClosed) { - // add first point as closing point - mpImplPolygon->mpPointAry[nIndex] = mpImplPolygon->mpPointAry[0]; - mpImplPolygon->mpFlagAry[nIndex] = (BYTE)POLY_NORMAL; + // add first point again as closing point due to old definition + mpImplPolygon->mpPointAry[nArrayInsert] = mpImplPolygon->mpPointAry[0]; + mpImplPolygon->mpFlagAry[nArrayInsert] = (BYTE)POLY_NORMAL; + nArrayInsert++; } else { // add last point as closing point - ::basegfx::B2DPoint aClosingPoint(rPolygon.getB2DPoint(nB2DLocalCount - 1L)); - Point aEnd(FRound(aClosingPoint.getX()), FRound(aClosingPoint.getY())); - mpImplPolygon->mpPointAry[nIndex] = aEnd; - mpImplPolygon->mpFlagAry[nIndex] = (BYTE)POLY_NORMAL; + const basegfx::B2DPoint aClosingPoint(rPolygon.getB2DPoint(nB2DLocalCount - 1L)); + const Point aEnd(FRound(aClosingPoint.getX()), FRound(aClosingPoint.getY())); + mpImplPolygon->mpPointAry[nArrayInsert] = aEnd; + mpImplPolygon->mpFlagAry[nArrayInsert] = (BYTE)POLY_NORMAL; + nArrayInsert++; + } + + DBG_ASSERT(nArrayInsert <= nMaxTargetCount, "Polygon::Polygon from basegfx::B2DPolygon: wrong max point count estimation (!)"); + + if(nArrayInsert != nMaxTargetCount) + { + mpImplPolygon->ImplSetSize(static_cast< sal_uInt16 >(nArrayInsert), true); } } } @@ -2414,17 +2425,16 @@ Polygon::Polygon(const ::basegfx::B2DPolygon& rPolygon) nB2DLocalCount = (0x0000ffff - 1L); } - // point list creation - const sal_uInt32 nTargetCount(nB2DLocalCount + (bClosed ? 1L : 0L)); - mpImplPolygon = new ImplPolygon( sal_uInt16(nTargetCount) ); - if(nB2DLocalCount) { + // point list creation + const sal_uInt32 nTargetCount(nB2DLocalCount + (bClosed ? 1L : 0L)); + mpImplPolygon = new ImplPolygon( static_cast< sal_uInt16 >(nTargetCount) ); sal_uInt16 nIndex(0); for(sal_uInt32 a(0L); a < nB2DLocalCount; a++) { - ::basegfx::B2DPoint aB2DPoint(rPolygon.getB2DPoint(a)); + basegfx::B2DPoint aB2DPoint(rPolygon.getB2DPoint(a)); Point aPoint(FRound(aB2DPoint.getX()), FRound(aB2DPoint.getY())); mpImplPolygon->mpPointAry[nIndex++] = aPoint; } @@ -2436,6 +2446,12 @@ Polygon::Polygon(const ::basegfx::B2DPolygon& rPolygon) } } } + + if(!mpImplPolygon) + { + // no content yet, create empty polygon + mpImplPolygon = (ImplPolygon*)(&aStaticImplPolygon); + } } // eof |