diff options
author | Armin Le Grand <alg@apache.org> | 2012-08-23 14:03:21 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2013-05-19 16:50:31 +0100 |
commit | 5a6ed660ec74e445a827c7aa41e4793c64a46271 (patch) | |
tree | de8dedebb69847d3e96c371e0c19554051364470 | |
parent | 2d55b2e5ae0d4f1a05e1ce5b20a7b342d6ea8b1d (diff) |
Resolves: #i120596# Optimized grid primitive
added some tooling to basegfx
(cherry picked from commit 97fa4faaa0b09724cf98dbf22390b283ba57b41c)
Conflicts:
basegfx/inc/basegfx/numeric/ftools.hxx
Change-Id: Ib15c43cf4d5b50605ec596dab498e3a678f3734a
-rw-r--r-- | basegfx/source/numeric/ftools.cxx | 77 | ||||
-rw-r--r-- | drawinglayer/source/primitive2d/gridprimitive2d.cxx | 166 | ||||
-rw-r--r-- | include/basegfx/numeric/ftools.hxx | 30 |
3 files changed, 212 insertions, 61 deletions
diff --git a/basegfx/source/numeric/ftools.cxx b/basegfx/source/numeric/ftools.cxx index 0c9a1734ec50..1cbbe5cc2136 100644 --- a/basegfx/source/numeric/ftools.cxx +++ b/basegfx/source/numeric/ftools.cxx @@ -18,11 +18,88 @@ */ #include <basegfx/numeric/ftools.hxx> +#include <algorithm> namespace basegfx { // init static member of class fTools double ::basegfx::fTools::mfSmallValue = 0.000000001; + + double snapToNearestMultiple(double v, const double fStep) + { + if(fTools::equalZero(fStep)) + { + // with a zero step, all snaps to 0.0 + return 0.0; + } + else + { + const double fHalfStep(fStep * 0.5); + const double fChange(fHalfStep - fmod(v + fHalfStep, fStep)); + + if(basegfx::fTools::equal(fabs(v), fabs(fChange))) + { + return 0.0; + } + else + { + return v + fChange; + } + } + } + + double snapToZeroRange(double v, double fWidth) + { + if(fTools::equalZero(fWidth)) + { + // with no range all snaps to range bound + return 0.0; + } + else + { + if(v < 0.0 || v > fWidth) + { + double fRetval(fmod(v, fWidth)); + + if(fRetval < 0.0) + { + fRetval += fWidth; + } + + return fRetval; + } + else + { + return v; + } + } + } + + double snapToRange(double v, double fLow, double fHigh) + { + if(fTools::equal(fLow, fHigh)) + { + // with no range all snaps to range bound + return 0.0; + } + else + { + if(fLow > fHigh) + { + // correct range order. Evtl. assert this (?) + std::swap(fLow, fHigh); + } + + if(v < fLow || v > fHigh) + { + return snapToZeroRange(v - fLow, fHigh - fLow) + fLow; + } + else + { + return v; + } + } + } } // end of namespace basegfx /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/drawinglayer/source/primitive2d/gridprimitive2d.cxx b/drawinglayer/source/primitive2d/gridprimitive2d.cxx index c24173818bb8..1f7dcb1168a3 100644 --- a/drawinglayer/source/primitive2d/gridprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/gridprimitive2d.cxx @@ -122,95 +122,139 @@ namespace drawinglayer nSmallStepsY = (sal_uInt32)(fStepY / fSmallStepY); } - // prepare point vectors for point and cross markers - std::vector< basegfx::B2DPoint > aPositionsPoint; - std::vector< basegfx::B2DPoint > aPositionsCross; + // calculate extended viewport in which grid points may lie at all + basegfx::B2DRange aExtendedViewport; - for(double fX(0.0); fX < aScale.getX(); fX += fStepX) + if(rViewInformation.getDiscreteViewport().isEmpty()) { - const bool bXZero(basegfx::fTools::equalZero(fX)); + // not set, use logic size to travel over all potentioal grid points + aExtendedViewport = basegfx::B2DRange(0.0, 0.0, aScale.getX(), aScale.getY()); + } + else + { + // transform unit range to discrete view + aExtendedViewport = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0); + basegfx::B2DHomMatrix aTrans(rViewInformation.getObjectToViewTransformation() * getTransform()); + aExtendedViewport.transform(aTrans); + + // intersect with visible part + aExtendedViewport.intersect(rViewInformation.getDiscreteViewport()); - for(double fY(0.0); fY < aScale.getY(); fY += fStepY) + if(!aExtendedViewport.isEmpty()) { - const bool bYZero(basegfx::fTools::equalZero(fY)); + // convert back and apply scale + aTrans.invert(); + aTrans.scale(aScale.getX(), aScale.getY()); + aExtendedViewport.transform(aTrans); + + // crop start/end in X/Y to multiples of logical step width + const double fHalfCrossSize((rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(3.0, 0.0)).getLength()); + const double fMinX(floor((aExtendedViewport.getMinX() - fHalfCrossSize) / fStepX) * fStepX); + const double fMaxX(ceil((aExtendedViewport.getMaxX() + fHalfCrossSize) / fStepX) * fStepX); + const double fMinY(floor((aExtendedViewport.getMinY() - fHalfCrossSize) / fStepY) * fStepY); + const double fMaxY(ceil((aExtendedViewport.getMaxY() + fHalfCrossSize) / fStepY) * fStepY); + + // put to aExtendedViewport and crop on object logic size + aExtendedViewport = basegfx::B2DRange( + std::max(fMinX, 0.0), + std::max(fMinY, 0.0), + std::min(fMaxX, aScale.getX()), + std::min(fMaxY, aScale.getY())); + } + } - if(!bXZero && !bYZero) - { - // get discrete position and test against 3x3 area surrounding it - // since it's a cross - const double fHalfCrossSize(3.0 * 0.5); - const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fX, fY)); - const basegfx::B2DRange aDiscreteRangeCross( - aViewPos.getX() - fHalfCrossSize, aViewPos.getY() - fHalfCrossSize, - aViewPos.getX() + fHalfCrossSize, aViewPos.getY() + fHalfCrossSize); - - if(rViewInformation.getDiscreteViewport().overlaps(aDiscreteRangeCross)) - { - const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos); - aPositionsCross.push_back(aLogicPos); - } - } + if(!aExtendedViewport.isEmpty()) + { + // prepare point vectors for point and cross markers + std::vector< basegfx::B2DPoint > aPositionsPoint; + std::vector< basegfx::B2DPoint > aPositionsCross; + + for(double fX(aExtendedViewport.getMinX()); fX < aExtendedViewport.getMaxX(); fX += fStepX) + { + const bool bXZero(basegfx::fTools::equalZero(fX)); - if(getSubdivisionsX() && !bYZero) + for(double fY(aExtendedViewport.getMinY()); fY < aExtendedViewport.getMaxY(); fY += fStepY) { - double fF(fX + fSmallStepX); + const bool bYZero(basegfx::fTools::equalZero(fY)); - for(sal_uInt32 a(1L); a < nSmallStepsX && fF < aScale.getX(); a++, fF += fSmallStepX) + if(!bXZero && !bYZero) { - const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fF, fY)); - - if(rViewInformation.getDiscreteViewport().isInside(aViewPos)) + // get discrete position and test against 3x3 area surrounding it + // since it's a cross + const double fHalfCrossSize(3.0 * 0.5); + const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fX, fY)); + const basegfx::B2DRange aDiscreteRangeCross( + aViewPos.getX() - fHalfCrossSize, aViewPos.getY() - fHalfCrossSize, + aViewPos.getX() + fHalfCrossSize, aViewPos.getY() + fHalfCrossSize); + + if(rViewInformation.getDiscreteViewport().overlaps(aDiscreteRangeCross)) { const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos); - aPositionsPoint.push_back(aLogicPos); + aPositionsCross.push_back(aLogicPos); } } - } - if(getSubdivisionsY() && !bXZero) - { - double fF(fY + fSmallStepY); + if(getSubdivisionsX() && !bYZero) + { + double fF(fX + fSmallStepX); - for(sal_uInt32 a(1L); a < nSmallStepsY && fF < aScale.getY(); a++, fF += fSmallStepY) + for(sal_uInt32 a(1); a < nSmallStepsX && fF < aExtendedViewport.getMaxX(); a++, fF += fSmallStepX) + { + const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fF, fY)); + + if(rViewInformation.getDiscreteViewport().isInside(aViewPos)) + { + const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos); + aPositionsPoint.push_back(aLogicPos); + } + } + } + + if(getSubdivisionsY() && !bXZero) { - const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fX, fF)); + double fF(fY + fSmallStepY); - if(rViewInformation.getDiscreteViewport().isInside(aViewPos)) + for(sal_uInt32 a(1); a < nSmallStepsY && fF < aExtendedViewport.getMaxY(); a++, fF += fSmallStepY) { - const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos); - aPositionsPoint.push_back(aLogicPos); + const basegfx::B2DPoint aViewPos(aRST * basegfx::B2DPoint(fX, fF)); + + if(rViewInformation.getDiscreteViewport().isInside(aViewPos)) + { + const basegfx::B2DPoint aLogicPos(rViewInformation.getInverseObjectToViewTransformation() * aViewPos); + aPositionsPoint.push_back(aLogicPos); + } } } } } - } - - // prepare return value - const sal_uInt32 nCountPoint(aPositionsPoint.size()); - const sal_uInt32 nCountCross(aPositionsCross.size()); - const sal_uInt32 nRetvalCount((nCountPoint ? 1 : 0) + (nCountCross ? 1 : 0)); - sal_uInt32 nInsertCounter(0); - aRetval.realloc(nRetvalCount); + // prepare return value + const sal_uInt32 nCountPoint(aPositionsPoint.size()); + const sal_uInt32 nCountCross(aPositionsCross.size()); + const sal_uInt32 nRetvalCount((nCountPoint ? 1 : 0) + (nCountCross ? 1 : 0)); + sal_uInt32 nInsertCounter(0); - // add PointArrayPrimitive2D if point markers were added - if(nCountPoint) - { - aRetval[nInsertCounter++] = Primitive2DReference(new PointArrayPrimitive2D(aPositionsPoint, getBColor())); - } + aRetval.realloc(nRetvalCount); - // add MarkerArrayPrimitive2D if cross markers were added - if(nCountCross) - { - if(!getSubdivisionsX() && !getSubdivisionsY()) + // add PointArrayPrimitive2D if point markers were added + if(nCountPoint) { - // no subdivisions, so fall back to points at grid positions, no need to - // visualize a difference between divisions and sub-divisions - aRetval[nInsertCounter++] = Primitive2DReference(new PointArrayPrimitive2D(aPositionsCross, getBColor())); + aRetval[nInsertCounter++] = Primitive2DReference(new PointArrayPrimitive2D(aPositionsPoint, getBColor())); } - else + + // add MarkerArrayPrimitive2D if cross markers were added + if(nCountCross) { - aRetval[nInsertCounter++] = Primitive2DReference(new MarkerArrayPrimitive2D(aPositionsCross, getCrossMarker())); + if(!getSubdivisionsX() && !getSubdivisionsY()) + { + // no subdivisions, so fall back to points at grid positions, no need to + // visualize a difference between divisions and sub-divisions + aRetval[nInsertCounter++] = Primitive2DReference(new PointArrayPrimitive2D(aPositionsCross, getBColor())); + } + else + { + aRetval[nInsertCounter++] = Primitive2DReference(new MarkerArrayPrimitive2D(aPositionsCross, getCrossMarker())); + } } } } diff --git a/include/basegfx/numeric/ftools.hxx b/include/basegfx/numeric/ftools.hxx index 70dcabe1a190..75e24b0d8574 100644 --- a/include/basegfx/numeric/ftools.hxx +++ b/include/basegfx/numeric/ftools.hxx @@ -136,6 +136,36 @@ namespace basegfx return v / M_PI_2 * 90.0; } + /** Snap v to nearest multiple of fStep, from negative and + positive side. + + Examples: + + snapToNearestMultiple(-0.1, 0.5) = 0.0 + snapToNearestMultiple(0.1, 0.5) = 0.0 + snapToNearestMultiple(0.25, 0.5) = 0.0 + snapToNearestMultiple(0.26, 0.5) = 0.5 + */ + double snapToNearestMultiple(double v, const double fStep); + + /** Snap v to the range [0.0 .. fWidth] using modulo + */ + double snapToZeroRange(double v, double fWidth); + + /** Snap v to the range [fLow .. fHigh] using modulo + */ + double snapToRange(double v, double fLow, double fHigh); + + /** return fValue with the sign of fSignCarrier, thus evtl. changed + */ + inline double copySign(double fValue, double fSignCarrier) + { +#ifdef WNT + return _copysign(fValue, fSignCarrier); +#else + return copysign(fValue, fSignCarrier); +#endif + } class BASEGFX_DLLPUBLIC fTools { |