summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Le Grand <alg@apache.org>2012-08-23 14:03:21 +0000
committerCaolán McNamara <caolanm@redhat.com>2013-05-19 16:50:31 +0100
commit5a6ed660ec74e445a827c7aa41e4793c64a46271 (patch)
treede8dedebb69847d3e96c371e0c19554051364470
parent2d55b2e5ae0d4f1a05e1ce5b20a7b342d6ea8b1d (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.cxx77
-rw-r--r--drawinglayer/source/primitive2d/gridprimitive2d.cxx166
-rw-r--r--include/basegfx/numeric/ftools.hxx30
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
{