summaryrefslogtreecommitdiff
path: root/chart2/source/view/axes/TickmarkHelper.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'chart2/source/view/axes/TickmarkHelper.cxx')
-rw-r--r--chart2/source/view/axes/TickmarkHelper.cxx934
1 files changed, 934 insertions, 0 deletions
diff --git a/chart2/source/view/axes/TickmarkHelper.cxx b/chart2/source/view/axes/TickmarkHelper.cxx
new file mode 100644
index 000000000000..f4f717722bed
--- /dev/null
+++ b/chart2/source/view/axes/TickmarkHelper.cxx
@@ -0,0 +1,934 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_chart2.hxx"
+#include "TickmarkHelper.hxx"
+#include "ViewDefines.hxx"
+#include <rtl/math.hxx>
+#include <tools/debug.hxx>
+#include <memory>
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+using namespace ::rtl::math;
+using ::basegfx::B2DVector;
+
+TickInfo::TickInfo()
+: fScaledTickValue( 0.0 )
+, fUnscaledTickValue( 0.0 )
+, aTickScreenPosition(0.0,0.0)
+, bPaintIt( true )
+, xTextShape( NULL )
+, nFactorForLimitedTextWidth(1)
+{
+}
+
+void TickInfo::updateUnscaledValue( const uno::Reference< XScaling >& xInverseScaling )
+{
+ if( xInverseScaling.is() )
+ this->fUnscaledTickValue = xInverseScaling->doScaling( this->fScaledTickValue );
+ else
+ this->fUnscaledTickValue = this->fScaledTickValue;
+}
+
+sal_Int32 TickInfo::getScreenDistanceBetweenTicks( const TickInfo& rOherTickInfo ) const
+{
+ //return the positive distance between the two first tickmarks in screen values
+
+ B2DVector aDistance = rOherTickInfo.aTickScreenPosition - aTickScreenPosition;
+ sal_Int32 nRet = static_cast<sal_Int32>(aDistance.getLength());
+ if(nRet<0)
+ nRet *= -1;
+ return nRet;
+}
+
+PureTickIter::PureTickIter( ::std::vector< TickInfo >& rTickInfoVector )
+ : m_rTickVector(rTickInfoVector)
+ , m_aTickIter(m_rTickVector.begin())
+{
+}
+PureTickIter::~PureTickIter()
+{
+}
+TickInfo* PureTickIter::firstInfo()
+{
+ m_aTickIter = m_rTickVector.begin();
+ if(m_aTickIter!=m_rTickVector.end())
+ return &*m_aTickIter;
+ return 0;
+}
+TickInfo* PureTickIter::nextInfo()
+{
+ m_aTickIter++;
+ if(m_aTickIter!=m_rTickVector.end())
+ return &*m_aTickIter;
+ return 0;
+}
+
+EquidistantTickIter::EquidistantTickIter( const uno::Sequence< uno::Sequence< double > >& rTicks
+ , const ExplicitIncrementData& rIncrement
+ , sal_Int32 nMinDepth, sal_Int32 nMaxDepth )
+ : m_pSimpleTicks(&rTicks)
+ , m_pInfoTicks(0)
+ , m_rIncrement(rIncrement)
+ , m_nMinDepth(0), m_nMaxDepth(0)
+ , m_nTickCount(0), m_pnPositions(NULL)
+ , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
+ , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
+{
+ initIter( nMinDepth, nMaxDepth );
+}
+
+EquidistantTickIter::EquidistantTickIter( ::std::vector< ::std::vector< TickInfo > >& rTicks
+ , const ExplicitIncrementData& rIncrement
+ , sal_Int32 nMinDepth, sal_Int32 nMaxDepth )
+ : m_pSimpleTicks(NULL)
+ , m_pInfoTicks(&rTicks)
+ , m_rIncrement(rIncrement)
+ , m_nMinDepth(0), m_nMaxDepth(0)
+ , m_nTickCount(0), m_pnPositions(NULL)
+ , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
+ , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
+{
+ initIter( nMinDepth, nMaxDepth );
+}
+
+void EquidistantTickIter::initIter( sal_Int32 /*nMinDepth*/, sal_Int32 nMaxDepth )
+{
+ m_nMaxDepth = nMaxDepth;
+ if(nMaxDepth<0 || m_nMaxDepth>getMaxDepth())
+ m_nMaxDepth=getMaxDepth();
+
+ sal_Int32 nDepth = 0;
+ for( nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
+ m_nTickCount += getTickCount(nDepth);
+
+ if(!m_nTickCount)
+ return;
+
+ m_pnPositions = new sal_Int32[m_nMaxDepth+1];
+
+ m_pnPreParentCount = new sal_Int32[m_nMaxDepth+1];
+ m_pbIntervalFinished = new bool[m_nMaxDepth+1];
+ m_pnPreParentCount[0] = 0;
+ m_pbIntervalFinished[0] = false;
+ double fParentValue = getTickValue(0,0);
+ for( nDepth = 1; nDepth<=m_nMaxDepth ;nDepth++ )
+ {
+ m_pbIntervalFinished[nDepth] = false;
+
+ sal_Int32 nPreParentCount = 0;
+ sal_Int32 nCount = getTickCount(nDepth);
+ for(sal_Int32 nN = 0; nN<nCount; nN++)
+ {
+ if(getTickValue(nDepth,nN) < fParentValue)
+ nPreParentCount++;
+ else
+ break;
+ }
+ m_pnPreParentCount[nDepth] = nPreParentCount;
+ if(nCount)
+ {
+ double fNextParentValue = getTickValue(nDepth,0);
+ if( fNextParentValue < fParentValue )
+ fParentValue = fNextParentValue;
+ }
+ }
+}
+
+EquidistantTickIter::~EquidistantTickIter()
+{
+ delete[] m_pnPositions;
+ delete[] m_pnPreParentCount;
+ delete[] m_pbIntervalFinished;
+}
+
+sal_Int32 EquidistantTickIter::getStartDepth() const
+{
+ //find the depth of the first visible tickmark:
+ //it is the depth of the smallest value
+ sal_Int32 nReturnDepth=0;
+ double fMinValue = DBL_MAX;
+ for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
+ {
+ sal_Int32 nCount = getTickCount(nDepth);
+ if( !nCount )
+ continue;
+ double fThisValue = getTickValue(nDepth,0);
+ if(fThisValue<fMinValue)
+ {
+ nReturnDepth = nDepth;
+ fMinValue = fThisValue;
+ }
+ }
+ return nReturnDepth;
+}
+
+double* EquidistantTickIter::firstValue()
+{
+ if( gotoFirst() )
+ {
+ m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
+ return &m_fCurrentValue;
+ }
+ return NULL;
+}
+
+TickInfo* EquidistantTickIter::firstInfo()
+{
+ if( m_pInfoTicks && gotoFirst() )
+ return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
+ return NULL;
+}
+
+sal_Int32 EquidistantTickIter::getIntervalCount( sal_Int32 nDepth )
+{
+ if(nDepth>m_rIncrement.SubIncrements.getLength() || nDepth<0)
+ return 0;
+
+ if(!nDepth)
+ return m_nTickCount;
+
+ return m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
+}
+
+bool EquidistantTickIter::isAtLastPartTick()
+{
+ if(!m_nCurrentDepth)
+ return false;
+ sal_Int32 nIntervalCount = getIntervalCount( m_nCurrentDepth );
+ if(!nIntervalCount || nIntervalCount == 1)
+ return true;
+ if( m_pbIntervalFinished[m_nCurrentDepth] )
+ return false;
+ sal_Int32 nPos = m_pnPositions[m_nCurrentDepth]+1;
+ if(m_pnPreParentCount[m_nCurrentDepth])
+ nPos += nIntervalCount-1 - m_pnPreParentCount[m_nCurrentDepth];
+ bool bRet = nPos && nPos % (nIntervalCount-1) == 0;
+ if(!nPos && !m_pnPreParentCount[m_nCurrentDepth]
+ && m_pnPositions[m_nCurrentDepth-1]==-1 )
+ bRet = true;
+ return bRet;
+}
+
+bool EquidistantTickIter::gotoFirst()
+{
+ if( m_nMaxDepth<0 )
+ return false;
+ if( !m_nTickCount )
+ return false;
+
+ for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
+ m_pnPositions[nDepth] = -1;
+
+ m_nCurrentPos = 0;
+ m_nCurrentDepth = getStartDepth();
+ m_pnPositions[m_nCurrentDepth] = 0;
+ return true;
+}
+
+bool EquidistantTickIter::gotoNext()
+{
+ if( m_nCurrentPos < 0 )
+ return false;
+ m_nCurrentPos++;
+
+ if( m_nCurrentPos >= m_nTickCount )
+ return false;
+
+ if( m_nCurrentDepth==m_nMaxDepth && isAtLastPartTick() )
+ {
+ do
+ {
+ m_pbIntervalFinished[m_nCurrentDepth] = true;
+ m_nCurrentDepth--;
+ }
+ while( m_nCurrentDepth && isAtLastPartTick() );
+ }
+ else if( m_nCurrentDepth<m_nMaxDepth )
+ {
+ do
+ {
+ m_nCurrentDepth++;
+ }
+ while( m_nCurrentDepth<m_nMaxDepth );
+ }
+ m_pbIntervalFinished[m_nCurrentDepth] = false;
+ m_pnPositions[m_nCurrentDepth] = m_pnPositions[m_nCurrentDepth]+1;
+ return true;
+}
+
+bool EquidistantTickIter::gotoIndex( sal_Int32 nTickIndex )
+{
+ if( nTickIndex < 0 )
+ return false;
+ if( nTickIndex >= m_nTickCount )
+ return false;
+
+ if( nTickIndex < m_nCurrentPos )
+ if( !gotoFirst() )
+ return false;
+
+ while( nTickIndex > m_nCurrentPos )
+ if( !gotoNext() )
+ return false;
+
+ return true;
+}
+
+sal_Int32 EquidistantTickIter::getCurrentIndex() const
+{
+ return m_nCurrentPos;
+}
+sal_Int32 EquidistantTickIter::getMaxIndex() const
+{
+ return m_nTickCount-1;
+}
+
+double* EquidistantTickIter::nextValue()
+{
+ if( gotoNext() )
+ {
+ m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
+ return &m_fCurrentValue;
+ }
+ return NULL;
+}
+
+TickInfo* EquidistantTickIter::nextInfo()
+{
+ if( m_pInfoTicks && gotoNext() &&
+ static_cast< sal_Int32 >(
+ (*m_pInfoTicks)[m_nCurrentDepth].size()) > m_pnPositions[m_nCurrentDepth] )
+ {
+ return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+double TickmarkHelper::getMinimumAtIncrement( double fMin, const ExplicitIncrementData& rIncrement )
+{
+ //the returned value will be <= fMin and on a Major Tick given by rIncrement
+ if(rIncrement.Distance<=0.0)
+ return fMin;
+
+ double fRet = rIncrement.BaseValue +
+ floor( approxSub( fMin, rIncrement.BaseValue )
+ / rIncrement.Distance)
+ *rIncrement.Distance;
+
+ if( fRet > fMin )
+ {
+ if( !approxEqual(fRet, fMin) )
+ fRet -= rIncrement.Distance;
+ }
+ return fRet;
+}
+double TickmarkHelper::getMaximumAtIncrement( double fMax, const ExplicitIncrementData& rIncrement )
+{
+ //the returned value will be >= fMax and on a Major Tick given by rIncrement
+ if(rIncrement.Distance<=0.0)
+ return fMax;
+
+ double fRet = rIncrement.BaseValue +
+ floor( approxSub( fMax, rIncrement.BaseValue )
+ / rIncrement.Distance)
+ *rIncrement.Distance;
+
+ if( fRet < fMax )
+ {
+ if( !approxEqual(fRet, fMax) )
+ fRet += rIncrement.Distance;
+ }
+ return fRet;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+TickmarkHelper::TickmarkHelper(
+ const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement )
+ : m_rScale( rScale )
+ , m_rIncrement( rIncrement )
+ , m_xInverseScaling(NULL)
+ , m_pfCurrentValues(NULL)
+{
+ //@todo: make sure that the scale is valid for the scaling
+
+ m_pfCurrentValues = new double[getTickDepth()];
+
+ if( m_rScale.Scaling.is() )
+ {
+ m_xInverseScaling = m_rScale.Scaling->getInverseScaling();
+ DBG_ASSERT( m_xInverseScaling.is(), "each Scaling needs to return a inverse Scaling" );
+ }
+
+ double fMin = m_fScaledVisibleMin = m_rScale.Minimum;
+ if( m_xInverseScaling.is() )
+ {
+ m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin);
+ if(m_rIncrement.PostEquidistant )
+ fMin = m_fScaledVisibleMin;
+ }
+
+ double fMax = m_fScaledVisibleMax = m_rScale.Maximum;
+ if( m_xInverseScaling.is() )
+ {
+ m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax);
+ if(m_rIncrement.PostEquidistant )
+ fMax = m_fScaledVisibleMax;
+ }
+
+ //--
+ m_fOuterMajorTickBorderMin = TickmarkHelper::getMinimumAtIncrement( fMin, m_rIncrement );
+ m_fOuterMajorTickBorderMax = TickmarkHelper::getMaximumAtIncrement( fMax, m_rIncrement );
+ //--
+
+ m_fOuterMajorTickBorderMin_Scaled = m_fOuterMajorTickBorderMin;
+ m_fOuterMajorTickBorderMax_Scaled = m_fOuterMajorTickBorderMax;
+ if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
+ {
+ m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
+ m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
+
+ //check validity of new range: m_fOuterMajorTickBorderMin <-> m_fOuterMajorTickBorderMax
+ //it is assumed here, that the original range in the given Scale is valid
+ if( !rtl::math::isFinite(m_fOuterMajorTickBorderMin_Scaled) )
+ {
+ m_fOuterMajorTickBorderMin += m_rIncrement.Distance;
+ m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
+ }
+ if( !rtl::math::isFinite(m_fOuterMajorTickBorderMax_Scaled) )
+ {
+ m_fOuterMajorTickBorderMax -= m_rIncrement.Distance;
+ m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
+ }
+ }
+}
+
+TickmarkHelper* TickmarkHelper::createShiftedTickmarkHelper() const
+{
+ ExplicitIncrementData aShiftedIncrement( m_rIncrement );
+ aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
+ return new TickmarkHelper( m_rScale, aShiftedIncrement );
+}
+
+TickmarkHelper::~TickmarkHelper()
+{
+ delete[] m_pfCurrentValues;
+}
+
+sal_Int32 TickmarkHelper::getTickDepth() const
+{
+ return m_rIncrement.SubIncrements.getLength() + 1;
+}
+
+sal_Int32 TickmarkHelper::getMaxTickCount( sal_Int32 nDepth ) const
+{
+ //return the maximum amount of ticks
+ //possibly open intervals at the two ends of the region are handled as if they were completely visible
+ //(this is necessary for calculating the sub ticks at the borders correctly)
+
+ if( nDepth >= getTickDepth() )
+ return 0;
+ if( m_fOuterMajorTickBorderMax < m_fOuterMajorTickBorderMin )
+ return 0;
+ if( m_rIncrement.Distance<=0.0)
+ return 0;
+
+ double fSub;
+ if(m_rIncrement.PostEquidistant )
+ fSub = approxSub( m_fScaledVisibleMax, m_fScaledVisibleMin );
+ else
+ fSub = approxSub( m_rScale.Maximum, m_rScale.Minimum );
+
+ if (!isFinite(fSub))
+ return 0;
+
+ sal_Int32 nIntervalCount = static_cast<sal_Int32>( fSub / m_rIncrement.Distance );
+
+ nIntervalCount+=3;
+ for(sal_Int32 nN=0; nN<nDepth-1; nN++)
+ {
+ if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
+ nIntervalCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
+ }
+
+ sal_Int32 nTickCount = nIntervalCount;
+ if(nDepth>0 && m_rIncrement.SubIncrements[nDepth-1].IntervalCount>1)
+ nTickCount = nIntervalCount * (m_rIncrement.SubIncrements[nDepth-1].IntervalCount-1);
+
+ return nTickCount;
+}
+
+double* TickmarkHelper::getMajorTick( sal_Int32 nTick ) const
+{
+ m_pfCurrentValues[0] = m_fOuterMajorTickBorderMin + nTick*m_rIncrement.Distance;
+
+ if(m_pfCurrentValues[0]>m_fOuterMajorTickBorderMax)
+ {
+ if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMax) )
+ return NULL;
+ }
+ if(m_pfCurrentValues[0]<m_fOuterMajorTickBorderMin)
+ {
+ if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMin) )
+ return NULL;
+ }
+
+ //return always the value after scaling
+ if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
+ m_pfCurrentValues[0] = m_rScale.Scaling->doScaling( m_pfCurrentValues[0] );
+
+ return &m_pfCurrentValues[0];
+}
+
+double* TickmarkHelper::getMinorTick( sal_Int32 nTick, sal_Int32 nDepth
+ , double fStartParentTick, double fNextParentTick ) const
+{
+ //check validity of arguments
+ {
+ //DBG_ASSERT( fStartParentTick < fNextParentTick, "fStartParentTick >= fNextParentTick");
+ if(fStartParentTick >= fNextParentTick)
+ return NULL;
+ if(nDepth>m_rIncrement.SubIncrements.getLength() || nDepth<=0)
+ return NULL;
+
+ //subticks are only calculated if they are laying between parent ticks:
+ if(nTick<=0)
+ return NULL;
+ if(nTick>=m_rIncrement.SubIncrements[nDepth-1].IntervalCount)
+ return NULL;
+ }
+
+ bool bPostEquidistant = m_rIncrement.SubIncrements[nDepth-1].PostEquidistant;
+
+ double fAdaptedStartParent = fStartParentTick;
+ double fAdaptedNextParent = fNextParentTick;
+
+ if( !bPostEquidistant && m_xInverseScaling.is() )
+ {
+ fAdaptedStartParent = m_xInverseScaling->doScaling(fStartParentTick);
+ fAdaptedNextParent = m_xInverseScaling->doScaling(fNextParentTick);
+ }
+
+ double fDistance = (fAdaptedNextParent - fAdaptedStartParent)/m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
+
+ m_pfCurrentValues[nDepth] = fAdaptedStartParent + nTick*fDistance;
+
+ //return always the value after scaling
+ if(!bPostEquidistant && m_xInverseScaling.is() )
+ m_pfCurrentValues[nDepth] = m_rScale.Scaling->doScaling( m_pfCurrentValues[nDepth] );
+
+ if( !isWithinOuterBorder( m_pfCurrentValues[nDepth] ) )
+ return NULL;
+
+ return &m_pfCurrentValues[nDepth];
+}
+
+bool TickmarkHelper::isWithinOuterBorder( double fScaledValue ) const
+{
+ if(fScaledValue>m_fOuterMajorTickBorderMax_Scaled)
+ return false;
+ if(fScaledValue<m_fOuterMajorTickBorderMin_Scaled)
+ return false;
+
+ return true;
+}
+
+
+bool TickmarkHelper::isVisible( double fScaledValue ) const
+{
+ if(fScaledValue>m_fScaledVisibleMax)
+ {
+ if( !approxEqual(fScaledValue,m_fScaledVisibleMax) )
+ return false;
+ }
+ if(fScaledValue<m_fScaledVisibleMin)
+ {
+ if( !approxEqual(fScaledValue,m_fScaledVisibleMin) )
+ return false;
+ }
+ return true;
+}
+
+void TickmarkHelper::getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
+{
+ uno::Sequence< uno::Sequence< double > > aAllTicks;
+
+ //create point sequences for each tick depth
+ sal_Int32 nDepthCount = this->getTickDepth();
+ sal_Int32 nMaxMajorTickCount = this->getMaxTickCount( 0 );
+
+ aAllTicks.realloc(nDepthCount);
+ aAllTicks[0].realloc(nMaxMajorTickCount);
+
+ sal_Int32 nRealMajorTickCount = 0;
+ double* pValue = NULL;
+ for( sal_Int32 nMajorTick=0; nMajorTick<nMaxMajorTickCount; nMajorTick++ )
+ {
+ pValue = this->getMajorTick( nMajorTick );
+ if(!pValue)
+ continue;
+ aAllTicks[0][nRealMajorTickCount] = *pValue;
+ nRealMajorTickCount++;
+ }
+ if(!nRealMajorTickCount)
+ return;
+ aAllTicks[0].realloc(nRealMajorTickCount);
+
+ if(nDepthCount>0)
+ this->addSubTicks( 1, aAllTicks );
+
+ //so far we have added all ticks between the outer major tick marks
+ //this was necessary to create sub ticks correctly
+ //now we reduce all ticks to the visible ones that lie between the real borders
+ sal_Int32 nDepth = 0;
+ sal_Int32 nTick = 0;
+ for( nDepth = 0; nDepth < nDepthCount; nDepth++)
+ {
+ sal_Int32 nInvisibleAtLowerBorder = 0;
+ sal_Int32 nInvisibleAtUpperBorder = 0;
+ //we need only to check all ticks within the first major interval at each border
+ sal_Int32 nCheckCount = 1;
+ for(sal_Int32 nN=0; nN<nDepth; nN++)
+ {
+ if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
+ nCheckCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
+ }
+ uno::Sequence< double >& rTicks = aAllTicks[nDepth];
+ sal_Int32 nCount = rTicks.getLength();
+ //check lower border
+ for( nTick=0; nTick<nCheckCount && nTick<nCount; nTick++)
+ {
+ if( !isVisible( rTicks[nTick] ) )
+ nInvisibleAtLowerBorder++;
+ }
+ //check upper border
+ for( nTick=nCount-1; nTick>nCount-1-nCheckCount && nTick>=0; nTick--)
+ {
+ if( !isVisible( rTicks[nTick] ) )
+ nInvisibleAtUpperBorder++;
+ }
+ //resize sequence
+ if( !nInvisibleAtLowerBorder && !nInvisibleAtUpperBorder)
+ continue;
+ if( !nInvisibleAtLowerBorder )
+ rTicks.realloc(nCount-nInvisibleAtUpperBorder);
+ else
+ {
+ sal_Int32 nNewCount = nCount-nInvisibleAtUpperBorder-nInvisibleAtLowerBorder;
+ if(nNewCount<0)
+ nNewCount=0;
+
+ uno::Sequence< double > aOldTicks(rTicks);
+ rTicks.realloc(nNewCount);
+ for(nTick = 0; nTick<nNewCount; nTick++)
+ rTicks[nTick] = aOldTicks[nInvisibleAtLowerBorder+nTick];
+ }
+ }
+
+ //fill return value
+ rAllTickInfos.resize(aAllTicks.getLength());
+ for( nDepth=0 ;nDepth<aAllTicks.getLength(); nDepth++ )
+ {
+ sal_Int32 nCount = aAllTicks[nDepth].getLength();
+ rAllTickInfos[nDepth].resize( nCount );
+ for(sal_Int32 nN = 0; nN<nCount; nN++)
+ {
+ rAllTickInfos[nDepth][nN].fScaledTickValue = aAllTicks[nDepth][nN];
+ }
+ }
+}
+
+void TickmarkHelper::getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
+{
+ std::auto_ptr< TickmarkHelper > apShiftedTickmarkHelper( createShiftedTickmarkHelper() );
+ apShiftedTickmarkHelper->getAllTicks( rAllTickInfos );
+}
+
+void TickmarkHelper::addSubTicks( sal_Int32 nDepth, uno::Sequence< uno::Sequence< double > >& rParentTicks ) const
+{
+ EquidistantTickIter aIter( rParentTicks, m_rIncrement, 0, nDepth-1 );
+ double* pfNextParentTick = aIter.firstValue();
+ if(!pfNextParentTick)
+ return;
+ double fLastParentTick = *pfNextParentTick;
+ pfNextParentTick = aIter.nextValue();
+ if(!pfNextParentTick)
+ return;
+
+ sal_Int32 nMaxSubTickCount = this->getMaxTickCount( nDepth );
+ if(!nMaxSubTickCount)
+ return;
+
+ uno::Sequence< double > aSubTicks(nMaxSubTickCount);
+ sal_Int32 nRealSubTickCount = 0;
+ sal_Int32 nIntervalCount = m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
+
+ double* pValue = NULL;
+ for(; pfNextParentTick; fLastParentTick=*pfNextParentTick, pfNextParentTick = aIter.nextValue())
+ {
+ for( sal_Int32 nPartTick = 1; nPartTick<nIntervalCount; nPartTick++ )
+ {
+ pValue = this->getMinorTick( nPartTick, nDepth
+ , fLastParentTick, *pfNextParentTick );
+ if(!pValue)
+ continue;
+
+ aSubTicks[nRealSubTickCount] = *pValue;
+ nRealSubTickCount++;
+ }
+ }
+
+ aSubTicks.realloc(nRealSubTickCount);
+ rParentTicks[nDepth] = aSubTicks;
+ if(m_rIncrement.SubIncrements.getLength()>nDepth)
+ addSubTicks( nDepth+1, rParentTicks );
+}
+
+//-----------------------------------------------------------------------------
+// ___TickmarkHelper_2D___
+//-----------------------------------------------------------------------------
+TickmarkHelper_2D::TickmarkHelper_2D(
+ const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement
+ //, double fStrech_SceneToScreen, double fOffset_SceneToScreen )
+ , const B2DVector& rStartScreenPos, const B2DVector& rEndScreenPos
+ , const B2DVector& rAxisLineToLabelLineShift )
+ : TickmarkHelper( rScale, rIncrement )
+ , m_aAxisStartScreenPosition2D(rStartScreenPos)
+ , m_aAxisEndScreenPosition2D(rEndScreenPos)
+ , m_aAxisLineToLabelLineShift(rAxisLineToLabelLineShift)
+ , m_fStrech_LogicToScreen(1.0)
+ , m_fOffset_LogicToScreen(0.0)
+{
+ double fWidthY = m_fScaledVisibleMax - m_fScaledVisibleMin;
+ if( AxisOrientation_MATHEMATICAL==m_rScale.Orientation )
+ {
+ m_fStrech_LogicToScreen = 1.0/fWidthY;
+ m_fOffset_LogicToScreen = -m_fScaledVisibleMin;
+ }
+ else
+ {
+ B2DVector aSwap(m_aAxisStartScreenPosition2D);
+ m_aAxisStartScreenPosition2D = m_aAxisEndScreenPosition2D;
+ m_aAxisEndScreenPosition2D = aSwap;
+
+ m_fStrech_LogicToScreen = -1.0/fWidthY;
+ m_fOffset_LogicToScreen = -m_fScaledVisibleMax;
+ }
+}
+
+TickmarkHelper* TickmarkHelper_2D::createShiftedTickmarkHelper() const
+{
+ ExplicitIncrementData aShiftedIncrement( m_rIncrement );
+ aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
+
+ ::basegfx::B2DVector aStart( m_aAxisStartScreenPosition2D );
+ ::basegfx::B2DVector aEnd( m_aAxisEndScreenPosition2D );
+ if( AxisOrientation_MATHEMATICAL==m_rScale.Orientation )
+ std::swap( aStart, aEnd );
+
+ return new TickmarkHelper_2D( m_rScale, aShiftedIncrement, aStart, aEnd, m_aAxisLineToLabelLineShift );
+}
+
+TickmarkHelper_2D::~TickmarkHelper_2D()
+{
+}
+
+bool TickmarkHelper_2D::isHorizontalAxis() const
+{
+ return ( m_aAxisStartScreenPosition2D.getY() == m_aAxisEndScreenPosition2D.getY() );
+}
+bool TickmarkHelper_2D::isVerticalAxis() const
+{
+ return ( m_aAxisStartScreenPosition2D.getX() == m_aAxisEndScreenPosition2D.getX() );
+}
+
+sal_Int32 TickmarkHelper_2D::getTickScreenDistance( TickIter& rIter )
+{
+ //return the positive distance between the two first tickmarks in screen values
+ //if there are less than two tickmarks -1 is returned
+
+ const TickInfo* pFirstTickInfo = rIter.firstInfo();
+ const TickInfo* pSecondTickInfo = rIter.nextInfo();
+ if(!pSecondTickInfo || !pFirstTickInfo)
+ return -1;
+
+ return pFirstTickInfo->getScreenDistanceBetweenTicks( *pSecondTickInfo );
+}
+
+B2DVector TickmarkHelper_2D::getTickScreenPosition2D( double fScaledLogicTickValue ) const
+{
+ B2DVector aRet(m_aAxisStartScreenPosition2D);
+ aRet += (m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D)
+ *((fScaledLogicTickValue+m_fOffset_LogicToScreen)*m_fStrech_LogicToScreen);
+ return aRet;
+}
+
+void TickmarkHelper_2D::addPointSequenceForTickLine( drawing::PointSequenceSequence& rPoints
+ , sal_Int32 nSequenceIndex
+ , double fScaledLogicTickValue, double fInnerDirectionSign
+ , const TickmarkProperties& rTickmarkProperties
+ , bool bPlaceAtLabels ) const
+{
+ if( fInnerDirectionSign==0.0 )
+ fInnerDirectionSign = 1.0;
+
+ B2DVector aTickScreenPosition = this->getTickScreenPosition2D(fScaledLogicTickValue);
+ if( bPlaceAtLabels )
+ aTickScreenPosition += m_aAxisLineToLabelLineShift;
+
+ B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D;
+ aMainDirection.normalize();
+ B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
+ aOrthoDirection *= fInnerDirectionSign;
+ aOrthoDirection.normalize();
+
+ B2DVector aStart = aTickScreenPosition + aOrthoDirection*rTickmarkProperties.RelativePos;
+ B2DVector aEnd = aStart - aOrthoDirection*rTickmarkProperties.Length;
+
+ rPoints[nSequenceIndex].realloc(2);
+ rPoints[nSequenceIndex][0].X = static_cast<sal_Int32>(aStart.getX());
+ rPoints[nSequenceIndex][0].Y = static_cast<sal_Int32>(aStart.getY());
+ rPoints[nSequenceIndex][1].X = static_cast<sal_Int32>(aEnd.getX());
+ rPoints[nSequenceIndex][1].Y = static_cast<sal_Int32>(aEnd.getY());
+}
+
+B2DVector TickmarkHelper_2D::getDistanceAxisTickToText( const AxisProperties& rAxisProperties, bool bIncludeFarAwayDistanceIfSo, bool bIncludeSpaceBetweenTickAndText ) const
+{
+ bool bFarAwayLabels = false;
+ if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_START == rAxisProperties.m_eLabelPos
+ || ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END == rAxisProperties.m_eLabelPos )
+ bFarAwayLabels = true;
+
+ double fInnerDirectionSign = rAxisProperties.m_fInnerDirectionSign;
+ if( fInnerDirectionSign==0.0 )
+ fInnerDirectionSign = 1.0;
+
+ B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D;
+ aMainDirection.normalize();
+ B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
+ aOrthoDirection *= fInnerDirectionSign;
+ aOrthoDirection.normalize();
+
+ B2DVector aStart(0,0), aEnd(0,0);
+ if( bFarAwayLabels )
+ {
+ TickmarkProperties aProps( AxisProperties::getBiggestTickmarkProperties() );
+ aStart = aOrthoDirection*aProps.RelativePos;
+ aEnd = aStart - aOrthoDirection*aProps.Length;
+ }
+ else
+ {
+ for( sal_Int32 nN=rAxisProperties.m_aTickmarkPropertiesList.size();nN--;)
+ {
+ const TickmarkProperties& rProps = rAxisProperties.m_aTickmarkPropertiesList[nN];
+ B2DVector aNewStart = aOrthoDirection*rProps.RelativePos;
+ B2DVector aNewEnd = aNewStart - aOrthoDirection*rProps.Length;
+ if(aNewStart.getLength()>aStart.getLength())
+ aStart=aNewStart;
+ if(aNewEnd.getLength()>aEnd.getLength())
+ aEnd=aNewEnd;
+ }
+ }
+
+ B2DVector aLabelDirection(aStart);
+ if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign )
+ aLabelDirection = aEnd;
+
+ B2DVector aOrthoLabelDirection(aOrthoDirection);
+ if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign )
+ aOrthoLabelDirection*=-1.0;
+ aOrthoLabelDirection.normalize();
+ if( bIncludeSpaceBetweenTickAndText )
+ aLabelDirection += aOrthoLabelDirection*AXIS2D_TICKLABELSPACING;
+ if( bFarAwayLabels && bIncludeFarAwayDistanceIfSo )
+ aLabelDirection += m_aAxisLineToLabelLineShift;
+ return aLabelDirection;
+}
+
+void TickmarkHelper_2D::createPointSequenceForAxisMainLine( drawing::PointSequenceSequence& rPoints ) const
+{
+ rPoints[0].realloc(2);
+ rPoints[0][0].X = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getX());
+ rPoints[0][0].Y = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getY());
+ rPoints[0][1].X = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getX());
+ rPoints[0][1].Y = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getY());
+}
+
+void TickmarkHelper_2D::updateScreenValues( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
+{
+ //get the transformed screen values for all tickmarks in rAllTickInfos
+ ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter = rAllTickInfos.begin();
+ const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd = rAllTickInfos.end();
+ for( ; aDepthIter != aDepthEnd; aDepthIter++ )
+ {
+ ::std::vector< TickInfo >::iterator aTickIter = (*aDepthIter).begin();
+ const ::std::vector< TickInfo >::const_iterator aTickEnd = (*aDepthIter).end();
+ for( ; aTickIter != aTickEnd; aTickIter++ )
+ {
+ TickInfo& rTickInfo = (*aTickIter);
+ rTickInfo.aTickScreenPosition =
+ this->getTickScreenPosition2D( rTickInfo.fScaledTickValue );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// ___TickmarkHelper_3D___
+//-----------------------------------------------------------------------------
+TickmarkHelper_3D::TickmarkHelper_3D(
+ const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement )
+ : TickmarkHelper( rScale, rIncrement )
+{
+}
+
+TickmarkHelper* TickmarkHelper_3D::createShiftedTickmarkHelper() const
+{
+ ExplicitIncrementData aShiftedIncrement( m_rIncrement );
+ aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
+ return new TickmarkHelper_3D( m_rScale, aShiftedIncrement );
+}
+
+TickmarkHelper_3D::~TickmarkHelper_3D()
+{
+}
+
+//.............................................................................
+} //namespace chart
+//.............................................................................