1*cde9e8dcSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*cde9e8dcSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*cde9e8dcSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*cde9e8dcSAndrew Rist  * distributed with this work for additional information
6*cde9e8dcSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*cde9e8dcSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*cde9e8dcSAndrew Rist  * "License"); you may not use this file except in compliance
9*cde9e8dcSAndrew Rist  * with the License.  You may obtain a copy of the License at
10*cde9e8dcSAndrew Rist  *
11*cde9e8dcSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*cde9e8dcSAndrew Rist  *
13*cde9e8dcSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*cde9e8dcSAndrew Rist  * software distributed under the License is distributed on an
15*cde9e8dcSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*cde9e8dcSAndrew Rist  * KIND, either express or implied.  See the License for the
17*cde9e8dcSAndrew Rist  * specific language governing permissions and limitations
18*cde9e8dcSAndrew Rist  * under the License.
19*cde9e8dcSAndrew Rist  *
20*cde9e8dcSAndrew Rist  *************************************************************/
21*cde9e8dcSAndrew Rist 
22*cde9e8dcSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_chart2.hxx"
26cdf0e10cSrcweir #include "Tickmarks_Equidistant.hxx"
27cdf0e10cSrcweir #include "ViewDefines.hxx"
28cdf0e10cSrcweir #include <rtl/math.hxx>
29cdf0e10cSrcweir #include <tools/debug.hxx>
30cdf0e10cSrcweir #include <memory>
31cdf0e10cSrcweir 
32cdf0e10cSrcweir //.............................................................................
33cdf0e10cSrcweir namespace chart
34cdf0e10cSrcweir {
35cdf0e10cSrcweir //.............................................................................
36cdf0e10cSrcweir using namespace ::com::sun::star;
37cdf0e10cSrcweir using namespace ::com::sun::star::chart2;
38cdf0e10cSrcweir using namespace ::rtl::math;
39cdf0e10cSrcweir using ::basegfx::B2DVector;
40cdf0e10cSrcweir 
41cdf0e10cSrcweir //static
getMinimumAtIncrement(double fMin,const ExplicitIncrementData & rIncrement)42cdf0e10cSrcweir double EquidistantTickFactory::getMinimumAtIncrement( double fMin, const ExplicitIncrementData& rIncrement )
43cdf0e10cSrcweir {
44cdf0e10cSrcweir     //the returned value will be <= fMin and on a Major Tick given by rIncrement
45cdf0e10cSrcweir     if(rIncrement.Distance<=0.0)
46cdf0e10cSrcweir         return fMin;
47cdf0e10cSrcweir 
48cdf0e10cSrcweir     double fRet = rIncrement.BaseValue +
49cdf0e10cSrcweir         floor( approxSub( fMin, rIncrement.BaseValue )
50cdf0e10cSrcweir                     / rIncrement.Distance)
51cdf0e10cSrcweir             *rIncrement.Distance;
52cdf0e10cSrcweir 
53cdf0e10cSrcweir     if( fRet > fMin )
54cdf0e10cSrcweir     {
55cdf0e10cSrcweir         if( !approxEqual(fRet, fMin) )
56cdf0e10cSrcweir             fRet -= rIncrement.Distance;
57cdf0e10cSrcweir     }
58cdf0e10cSrcweir     return fRet;
59cdf0e10cSrcweir }
60cdf0e10cSrcweir //static
getMaximumAtIncrement(double fMax,const ExplicitIncrementData & rIncrement)61cdf0e10cSrcweir double EquidistantTickFactory::getMaximumAtIncrement( double fMax, const ExplicitIncrementData& rIncrement )
62cdf0e10cSrcweir {
63cdf0e10cSrcweir     //the returned value will be >= fMax and on a Major Tick given by rIncrement
64cdf0e10cSrcweir     if(rIncrement.Distance<=0.0)
65cdf0e10cSrcweir         return fMax;
66cdf0e10cSrcweir 
67cdf0e10cSrcweir     double fRet = rIncrement.BaseValue +
68cdf0e10cSrcweir         floor( approxSub( fMax, rIncrement.BaseValue )
69cdf0e10cSrcweir                     / rIncrement.Distance)
70cdf0e10cSrcweir             *rIncrement.Distance;
71cdf0e10cSrcweir 
72cdf0e10cSrcweir     if( fRet < fMax )
73cdf0e10cSrcweir     {
74cdf0e10cSrcweir         if( !approxEqual(fRet, fMax) )
75cdf0e10cSrcweir             fRet += rIncrement.Distance;
76cdf0e10cSrcweir     }
77cdf0e10cSrcweir     return fRet;
78cdf0e10cSrcweir }
79cdf0e10cSrcweir 
EquidistantTickFactory(const ExplicitScaleData & rScale,const ExplicitIncrementData & rIncrement)80cdf0e10cSrcweir EquidistantTickFactory::EquidistantTickFactory(
81cdf0e10cSrcweir           const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement )
82cdf0e10cSrcweir             : m_rScale( rScale )
83cdf0e10cSrcweir             , m_rIncrement( rIncrement )
84cdf0e10cSrcweir             , m_xInverseScaling(NULL)
85cdf0e10cSrcweir             , m_pfCurrentValues(NULL)
86cdf0e10cSrcweir {
87cdf0e10cSrcweir     //@todo: make sure that the scale is valid for the scaling
88cdf0e10cSrcweir 
89cdf0e10cSrcweir     m_pfCurrentValues = new double[getTickDepth()];
90cdf0e10cSrcweir 
91cdf0e10cSrcweir     if( m_rScale.Scaling.is() )
92cdf0e10cSrcweir     {
93cdf0e10cSrcweir         m_xInverseScaling = m_rScale.Scaling->getInverseScaling();
94cdf0e10cSrcweir         DBG_ASSERT( m_xInverseScaling.is(), "each Scaling needs to return a inverse Scaling" );
95cdf0e10cSrcweir     }
96cdf0e10cSrcweir 
97cdf0e10cSrcweir     double fMin = m_fScaledVisibleMin = m_rScale.Minimum;
98cdf0e10cSrcweir     if( m_xInverseScaling.is() )
99cdf0e10cSrcweir     {
100cdf0e10cSrcweir         m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin);
101cdf0e10cSrcweir         if(m_rIncrement.PostEquidistant )
102cdf0e10cSrcweir             fMin = m_fScaledVisibleMin;
103cdf0e10cSrcweir     }
104cdf0e10cSrcweir 
105cdf0e10cSrcweir     double fMax = m_fScaledVisibleMax = m_rScale.Maximum;
106cdf0e10cSrcweir     if( m_xInverseScaling.is() )
107cdf0e10cSrcweir     {
108cdf0e10cSrcweir         m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax);
109cdf0e10cSrcweir         if(m_rIncrement.PostEquidistant )
110cdf0e10cSrcweir             fMax = m_fScaledVisibleMax;
111cdf0e10cSrcweir     }
112cdf0e10cSrcweir 
113cdf0e10cSrcweir     //--
114cdf0e10cSrcweir     m_fOuterMajorTickBorderMin = EquidistantTickFactory::getMinimumAtIncrement( fMin, m_rIncrement );
115cdf0e10cSrcweir     m_fOuterMajorTickBorderMax = EquidistantTickFactory::getMaximumAtIncrement( fMax, m_rIncrement );
116cdf0e10cSrcweir     //--
117cdf0e10cSrcweir 
118cdf0e10cSrcweir     m_fOuterMajorTickBorderMin_Scaled = m_fOuterMajorTickBorderMin;
119cdf0e10cSrcweir     m_fOuterMajorTickBorderMax_Scaled = m_fOuterMajorTickBorderMax;
120cdf0e10cSrcweir     if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
121cdf0e10cSrcweir     {
122cdf0e10cSrcweir         m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
123cdf0e10cSrcweir         m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
124cdf0e10cSrcweir 
125cdf0e10cSrcweir         //check validity of new range: m_fOuterMajorTickBorderMin <-> m_fOuterMajorTickBorderMax
126cdf0e10cSrcweir         //it is assumed here, that the original range in the given Scale is valid
127cdf0e10cSrcweir         if( !rtl::math::isFinite(m_fOuterMajorTickBorderMin_Scaled) )
128cdf0e10cSrcweir         {
129cdf0e10cSrcweir             m_fOuterMajorTickBorderMin += m_rIncrement.Distance;
130cdf0e10cSrcweir             m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
131cdf0e10cSrcweir         }
132cdf0e10cSrcweir         if( !rtl::math::isFinite(m_fOuterMajorTickBorderMax_Scaled) )
133cdf0e10cSrcweir         {
134cdf0e10cSrcweir             m_fOuterMajorTickBorderMax -= m_rIncrement.Distance;
135cdf0e10cSrcweir             m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
136cdf0e10cSrcweir         }
137cdf0e10cSrcweir     }
138cdf0e10cSrcweir }
139cdf0e10cSrcweir 
~EquidistantTickFactory()140cdf0e10cSrcweir EquidistantTickFactory::~EquidistantTickFactory()
141cdf0e10cSrcweir {
142cdf0e10cSrcweir     delete[] m_pfCurrentValues;
143cdf0e10cSrcweir }
144cdf0e10cSrcweir 
getTickDepth() const145cdf0e10cSrcweir sal_Int32 EquidistantTickFactory::getTickDepth() const
146cdf0e10cSrcweir {
147cdf0e10cSrcweir     return static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) + 1;
148cdf0e10cSrcweir }
149cdf0e10cSrcweir 
addSubTicks(sal_Int32 nDepth,uno::Sequence<uno::Sequence<double>> & rParentTicks) const150cdf0e10cSrcweir void EquidistantTickFactory::addSubTicks( sal_Int32 nDepth, uno::Sequence< uno::Sequence< double > >& rParentTicks ) const
151cdf0e10cSrcweir {
152cdf0e10cSrcweir     EquidistantTickIter aIter( rParentTicks, m_rIncrement, 0, nDepth-1 );
153cdf0e10cSrcweir     double* pfNextParentTick = aIter.firstValue();
154cdf0e10cSrcweir     if(!pfNextParentTick)
155cdf0e10cSrcweir         return;
156cdf0e10cSrcweir     double fLastParentTick = *pfNextParentTick;
157cdf0e10cSrcweir     pfNextParentTick = aIter.nextValue();
158cdf0e10cSrcweir     if(!pfNextParentTick)
159cdf0e10cSrcweir         return;
160cdf0e10cSrcweir 
161cdf0e10cSrcweir     sal_Int32 nMaxSubTickCount = this->getMaxTickCount( nDepth );
162cdf0e10cSrcweir     if(!nMaxSubTickCount)
163cdf0e10cSrcweir         return;
164cdf0e10cSrcweir 
165cdf0e10cSrcweir     uno::Sequence< double > aSubTicks(nMaxSubTickCount);
166cdf0e10cSrcweir     sal_Int32 nRealSubTickCount = 0;
167cdf0e10cSrcweir     sal_Int32 nIntervalCount = m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
168cdf0e10cSrcweir 
169cdf0e10cSrcweir     double* pValue = NULL;
170cdf0e10cSrcweir     for(; pfNextParentTick; fLastParentTick=*pfNextParentTick, pfNextParentTick = aIter.nextValue())
171cdf0e10cSrcweir     {
172cdf0e10cSrcweir         for( sal_Int32 nPartTick = 1; nPartTick<nIntervalCount; nPartTick++ )
173cdf0e10cSrcweir         {
174cdf0e10cSrcweir             pValue = this->getMinorTick( nPartTick, nDepth
175cdf0e10cSrcweir                         , fLastParentTick, *pfNextParentTick );
176cdf0e10cSrcweir             if(!pValue)
177cdf0e10cSrcweir                 continue;
178cdf0e10cSrcweir 
179cdf0e10cSrcweir             aSubTicks[nRealSubTickCount] = *pValue;
180cdf0e10cSrcweir             nRealSubTickCount++;
181cdf0e10cSrcweir         }
182cdf0e10cSrcweir     }
183cdf0e10cSrcweir 
184cdf0e10cSrcweir     aSubTicks.realloc(nRealSubTickCount);
185cdf0e10cSrcweir     rParentTicks[nDepth] = aSubTicks;
186cdf0e10cSrcweir     if(static_cast<sal_Int32>(m_rIncrement.SubIncrements.size())>nDepth)
187cdf0e10cSrcweir         addSubTicks( nDepth+1, rParentTicks );
188cdf0e10cSrcweir }
189cdf0e10cSrcweir 
190cdf0e10cSrcweir 
getMaxTickCount(sal_Int32 nDepth) const191cdf0e10cSrcweir sal_Int32 EquidistantTickFactory::getMaxTickCount( sal_Int32 nDepth ) const
192cdf0e10cSrcweir {
193cdf0e10cSrcweir     //return the maximum amount of ticks
194cdf0e10cSrcweir     //possibly open intervals at the two ends of the region are handled as if they were completely visible
195cdf0e10cSrcweir     //(this is necessary for calculating the sub ticks at the borders correctly)
196cdf0e10cSrcweir 
197cdf0e10cSrcweir     if( nDepth >= getTickDepth() )
198cdf0e10cSrcweir         return 0;
199cdf0e10cSrcweir     if( m_fOuterMajorTickBorderMax < m_fOuterMajorTickBorderMin )
200cdf0e10cSrcweir         return 0;
201cdf0e10cSrcweir     if( m_rIncrement.Distance<=0.0)
202cdf0e10cSrcweir         return 0;
203cdf0e10cSrcweir 
204cdf0e10cSrcweir     double fSub;
205cdf0e10cSrcweir     if(m_rIncrement.PostEquidistant  )
206cdf0e10cSrcweir         fSub = approxSub( m_fScaledVisibleMax, m_fScaledVisibleMin );
207cdf0e10cSrcweir     else
208cdf0e10cSrcweir         fSub = approxSub( m_rScale.Maximum, m_rScale.Minimum );
209cdf0e10cSrcweir 
210cdf0e10cSrcweir     if (!isFinite(fSub))
211cdf0e10cSrcweir         return 0;
212cdf0e10cSrcweir 
213cdf0e10cSrcweir     sal_Int32 nIntervalCount = static_cast<sal_Int32>( fSub / m_rIncrement.Distance );
214cdf0e10cSrcweir 
215cdf0e10cSrcweir     nIntervalCount+=3;
216cdf0e10cSrcweir     for(sal_Int32 nN=0; nN<nDepth-1; nN++)
217cdf0e10cSrcweir     {
218cdf0e10cSrcweir         if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
219cdf0e10cSrcweir             nIntervalCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
220cdf0e10cSrcweir     }
221cdf0e10cSrcweir 
222cdf0e10cSrcweir     sal_Int32 nTickCount = nIntervalCount;
223cdf0e10cSrcweir     if(nDepth>0 && m_rIncrement.SubIncrements[nDepth-1].IntervalCount>1)
224cdf0e10cSrcweir         nTickCount = nIntervalCount * (m_rIncrement.SubIncrements[nDepth-1].IntervalCount-1);
225cdf0e10cSrcweir 
226cdf0e10cSrcweir     return nTickCount;
227cdf0e10cSrcweir }
228cdf0e10cSrcweir 
getMajorTick(sal_Int32 nTick) const229cdf0e10cSrcweir double* EquidistantTickFactory::getMajorTick( sal_Int32 nTick ) const
230cdf0e10cSrcweir {
231cdf0e10cSrcweir     m_pfCurrentValues[0] = m_fOuterMajorTickBorderMin + nTick*m_rIncrement.Distance;
232cdf0e10cSrcweir 
233cdf0e10cSrcweir     if(m_pfCurrentValues[0]>m_fOuterMajorTickBorderMax)
234cdf0e10cSrcweir     {
235cdf0e10cSrcweir         if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMax) )
236cdf0e10cSrcweir             return NULL;
237cdf0e10cSrcweir     }
238cdf0e10cSrcweir     if(m_pfCurrentValues[0]<m_fOuterMajorTickBorderMin)
239cdf0e10cSrcweir     {
240cdf0e10cSrcweir         if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMin) )
241cdf0e10cSrcweir             return NULL;
242cdf0e10cSrcweir     }
243cdf0e10cSrcweir 
244cdf0e10cSrcweir     //return always the value after scaling
245cdf0e10cSrcweir     if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
246cdf0e10cSrcweir         m_pfCurrentValues[0] = m_rScale.Scaling->doScaling( m_pfCurrentValues[0] );
247cdf0e10cSrcweir 
248cdf0e10cSrcweir     return &m_pfCurrentValues[0];
249cdf0e10cSrcweir }
250cdf0e10cSrcweir 
getMinorTick(sal_Int32 nTick,sal_Int32 nDepth,double fStartParentTick,double fNextParentTick) const251cdf0e10cSrcweir double* EquidistantTickFactory::getMinorTick( sal_Int32 nTick, sal_Int32 nDepth
252cdf0e10cSrcweir                             , double fStartParentTick, double fNextParentTick ) const
253cdf0e10cSrcweir {
254cdf0e10cSrcweir     //check validity of arguments
255cdf0e10cSrcweir     {
256cdf0e10cSrcweir         //DBG_ASSERT( fStartParentTick < fNextParentTick, "fStartParentTick >= fNextParentTick");
257cdf0e10cSrcweir         if(fStartParentTick >= fNextParentTick)
258cdf0e10cSrcweir             return NULL;
259cdf0e10cSrcweir         if(nDepth>static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) || nDepth<=0)
260cdf0e10cSrcweir             return NULL;
261cdf0e10cSrcweir 
262cdf0e10cSrcweir         //subticks are only calculated if they are laying between parent ticks:
263cdf0e10cSrcweir         if(nTick<=0)
264cdf0e10cSrcweir             return NULL;
265cdf0e10cSrcweir         if(nTick>=m_rIncrement.SubIncrements[nDepth-1].IntervalCount)
266cdf0e10cSrcweir             return NULL;
267cdf0e10cSrcweir     }
268cdf0e10cSrcweir 
269cdf0e10cSrcweir     bool    bPostEquidistant = m_rIncrement.SubIncrements[nDepth-1].PostEquidistant;
270cdf0e10cSrcweir 
271cdf0e10cSrcweir     double fAdaptedStartParent = fStartParentTick;
272cdf0e10cSrcweir     double fAdaptedNextParent  = fNextParentTick;
273cdf0e10cSrcweir 
274cdf0e10cSrcweir     if( !bPostEquidistant && m_xInverseScaling.is() )
275cdf0e10cSrcweir     {
276cdf0e10cSrcweir         fAdaptedStartParent = m_xInverseScaling->doScaling(fStartParentTick);
277cdf0e10cSrcweir         fAdaptedNextParent  = m_xInverseScaling->doScaling(fNextParentTick);
278cdf0e10cSrcweir     }
279cdf0e10cSrcweir 
280cdf0e10cSrcweir     double fDistance = (fAdaptedNextParent - fAdaptedStartParent)/m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
281cdf0e10cSrcweir 
282cdf0e10cSrcweir     m_pfCurrentValues[nDepth] = fAdaptedStartParent + nTick*fDistance;
283cdf0e10cSrcweir 
284cdf0e10cSrcweir     //return always the value after scaling
285cdf0e10cSrcweir     if(!bPostEquidistant && m_xInverseScaling.is() )
286cdf0e10cSrcweir         m_pfCurrentValues[nDepth] = m_rScale.Scaling->doScaling( m_pfCurrentValues[nDepth] );
287cdf0e10cSrcweir 
288cdf0e10cSrcweir     if( !isWithinOuterBorder( m_pfCurrentValues[nDepth] ) )
289cdf0e10cSrcweir         return NULL;
290cdf0e10cSrcweir 
291cdf0e10cSrcweir     return &m_pfCurrentValues[nDepth];
292cdf0e10cSrcweir }
293cdf0e10cSrcweir 
isWithinOuterBorder(double fScaledValue) const294cdf0e10cSrcweir bool EquidistantTickFactory::isWithinOuterBorder( double fScaledValue ) const
295cdf0e10cSrcweir {
296cdf0e10cSrcweir     if(fScaledValue>m_fOuterMajorTickBorderMax_Scaled)
297cdf0e10cSrcweir         return false;
298cdf0e10cSrcweir     if(fScaledValue<m_fOuterMajorTickBorderMin_Scaled)
299cdf0e10cSrcweir         return false;
300cdf0e10cSrcweir 
301cdf0e10cSrcweir     return true;
302cdf0e10cSrcweir }
303cdf0e10cSrcweir 
isVisible(double fScaledValue) const304cdf0e10cSrcweir bool EquidistantTickFactory::isVisible( double fScaledValue ) const
305cdf0e10cSrcweir {
306cdf0e10cSrcweir     if(fScaledValue>m_fScaledVisibleMax)
307cdf0e10cSrcweir     {
308cdf0e10cSrcweir         if( !approxEqual(fScaledValue,m_fScaledVisibleMax) )
309cdf0e10cSrcweir             return false;
310cdf0e10cSrcweir     }
311cdf0e10cSrcweir     if(fScaledValue<m_fScaledVisibleMin)
312cdf0e10cSrcweir     {
313cdf0e10cSrcweir         if( !approxEqual(fScaledValue,m_fScaledVisibleMin) )
314cdf0e10cSrcweir             return false;
315cdf0e10cSrcweir     }
316cdf0e10cSrcweir     return true;
317cdf0e10cSrcweir }
318cdf0e10cSrcweir 
getAllTicks(::std::vector<::std::vector<TickInfo>> & rAllTickInfos) const319cdf0e10cSrcweir void EquidistantTickFactory::getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
320cdf0e10cSrcweir {
321cdf0e10cSrcweir     uno::Sequence< uno::Sequence< double > > aAllTicks;
322cdf0e10cSrcweir 
323cdf0e10cSrcweir     //create point sequences for each tick depth
324cdf0e10cSrcweir     sal_Int32 nDepthCount = this->getTickDepth();
325cdf0e10cSrcweir     sal_Int32 nMaxMajorTickCount = this->getMaxTickCount( 0 );
326cdf0e10cSrcweir 
327cdf0e10cSrcweir     aAllTicks.realloc(nDepthCount);
328cdf0e10cSrcweir     aAllTicks[0].realloc(nMaxMajorTickCount);
329cdf0e10cSrcweir 
330cdf0e10cSrcweir     sal_Int32 nRealMajorTickCount = 0;
331cdf0e10cSrcweir     double* pValue = NULL;
332cdf0e10cSrcweir     for( sal_Int32 nMajorTick=0; nMajorTick<nMaxMajorTickCount; nMajorTick++ )
333cdf0e10cSrcweir     {
334cdf0e10cSrcweir         pValue = this->getMajorTick( nMajorTick );
335cdf0e10cSrcweir         if(!pValue)
336cdf0e10cSrcweir             continue;
337cdf0e10cSrcweir         aAllTicks[0][nRealMajorTickCount] = *pValue;
338cdf0e10cSrcweir         nRealMajorTickCount++;
339cdf0e10cSrcweir     }
340cdf0e10cSrcweir     if(!nRealMajorTickCount)
341cdf0e10cSrcweir         return;
342cdf0e10cSrcweir     aAllTicks[0].realloc(nRealMajorTickCount);
343cdf0e10cSrcweir 
344cdf0e10cSrcweir     if(nDepthCount>0)
345cdf0e10cSrcweir         this->addSubTicks( 1, aAllTicks );
346cdf0e10cSrcweir 
347cdf0e10cSrcweir     //so far we have added all ticks between the outer major tick marks
348cdf0e10cSrcweir     //this was necessary to create sub ticks correctly
349cdf0e10cSrcweir     //now we reduce all ticks to the visible ones that lie between the real borders
350cdf0e10cSrcweir     sal_Int32 nDepth = 0;
351cdf0e10cSrcweir     sal_Int32 nTick = 0;
352cdf0e10cSrcweir     for( nDepth = 0; nDepth < nDepthCount; nDepth++)
353cdf0e10cSrcweir     {
354cdf0e10cSrcweir         sal_Int32 nInvisibleAtLowerBorder = 0;
355cdf0e10cSrcweir         sal_Int32 nInvisibleAtUpperBorder = 0;
356cdf0e10cSrcweir         //we need only to check all ticks within the first major interval at each border
357cdf0e10cSrcweir         sal_Int32 nCheckCount = 1;
358cdf0e10cSrcweir         for(sal_Int32 nN=0; nN<nDepth; nN++)
359cdf0e10cSrcweir         {
360cdf0e10cSrcweir             if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
361cdf0e10cSrcweir                 nCheckCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
362cdf0e10cSrcweir         }
363cdf0e10cSrcweir         uno::Sequence< double >& rTicks = aAllTicks[nDepth];
364cdf0e10cSrcweir         sal_Int32 nCount = rTicks.getLength();
365cdf0e10cSrcweir         //check lower border
366cdf0e10cSrcweir         for( nTick=0; nTick<nCheckCount && nTick<nCount; nTick++)
367cdf0e10cSrcweir         {
368cdf0e10cSrcweir             if( !isVisible( rTicks[nTick] ) )
369cdf0e10cSrcweir                 nInvisibleAtLowerBorder++;
370cdf0e10cSrcweir         }
371cdf0e10cSrcweir         //check upper border
372cdf0e10cSrcweir         for( nTick=nCount-1; nTick>nCount-1-nCheckCount && nTick>=0; nTick--)
373cdf0e10cSrcweir         {
374cdf0e10cSrcweir             if( !isVisible( rTicks[nTick] ) )
375cdf0e10cSrcweir                 nInvisibleAtUpperBorder++;
376cdf0e10cSrcweir         }
377cdf0e10cSrcweir         //resize sequence
378cdf0e10cSrcweir         if( !nInvisibleAtLowerBorder && !nInvisibleAtUpperBorder)
379cdf0e10cSrcweir             continue;
380cdf0e10cSrcweir         if( !nInvisibleAtLowerBorder )
381cdf0e10cSrcweir             rTicks.realloc(nCount-nInvisibleAtUpperBorder);
382cdf0e10cSrcweir         else
383cdf0e10cSrcweir         {
384cdf0e10cSrcweir             sal_Int32 nNewCount = nCount-nInvisibleAtUpperBorder-nInvisibleAtLowerBorder;
385cdf0e10cSrcweir             if(nNewCount<0)
386cdf0e10cSrcweir                 nNewCount=0;
387cdf0e10cSrcweir 
388cdf0e10cSrcweir             uno::Sequence< double > aOldTicks(rTicks);
389cdf0e10cSrcweir             rTicks.realloc(nNewCount);
390cdf0e10cSrcweir             for(nTick = 0; nTick<nNewCount; nTick++)
391cdf0e10cSrcweir                 rTicks[nTick] = aOldTicks[nInvisibleAtLowerBorder+nTick];
392cdf0e10cSrcweir         }
393cdf0e10cSrcweir     }
394cdf0e10cSrcweir 
395cdf0e10cSrcweir     //fill return value
396cdf0e10cSrcweir     rAllTickInfos.resize(aAllTicks.getLength());
397cdf0e10cSrcweir     for( nDepth=0 ;nDepth<aAllTicks.getLength(); nDepth++ )
398cdf0e10cSrcweir     {
399cdf0e10cSrcweir         sal_Int32 nCount = aAllTicks[nDepth].getLength();
400cdf0e10cSrcweir 
401cdf0e10cSrcweir         ::std::vector< TickInfo >& rTickInfoVector = rAllTickInfos[nDepth];
402cdf0e10cSrcweir         rTickInfoVector.clear();
403cdf0e10cSrcweir         rTickInfoVector.reserve( nCount );
404cdf0e10cSrcweir         for(sal_Int32 nN = 0; nN<nCount; nN++)
405cdf0e10cSrcweir         {
406cdf0e10cSrcweir             TickInfo aTickInfo(m_xInverseScaling);
407cdf0e10cSrcweir             aTickInfo.fScaledTickValue = aAllTicks[nDepth][nN];
408cdf0e10cSrcweir             rTickInfoVector.push_back(aTickInfo);
409cdf0e10cSrcweir         }
410cdf0e10cSrcweir     }
411cdf0e10cSrcweir }
412cdf0e10cSrcweir 
getAllTicksShifted(::std::vector<::std::vector<TickInfo>> & rAllTickInfos) const413cdf0e10cSrcweir void EquidistantTickFactory::getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
414cdf0e10cSrcweir {
415cdf0e10cSrcweir     ExplicitIncrementData aShiftedIncrement( m_rIncrement );
416cdf0e10cSrcweir     aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
417cdf0e10cSrcweir     EquidistantTickFactory( m_rScale, aShiftedIncrement ).getAllTicks(rAllTickInfos);
418cdf0e10cSrcweir }
419cdf0e10cSrcweir 
420cdf0e10cSrcweir //-----------------------------------------------------------------------------
421cdf0e10cSrcweir //-----------------------------------------------------------------------------
422cdf0e10cSrcweir //-----------------------------------------------------------------------------
423cdf0e10cSrcweir 
EquidistantTickIter(const uno::Sequence<uno::Sequence<double>> & rTicks,const ExplicitIncrementData & rIncrement,sal_Int32 nMinDepth,sal_Int32 nMaxDepth)424cdf0e10cSrcweir EquidistantTickIter::EquidistantTickIter( const uno::Sequence< uno::Sequence< double > >& rTicks
425cdf0e10cSrcweir                    , const ExplicitIncrementData& rIncrement
426cdf0e10cSrcweir                    , sal_Int32 nMinDepth, sal_Int32 nMaxDepth )
427cdf0e10cSrcweir                 : m_pSimpleTicks(&rTicks)
428cdf0e10cSrcweir                 , m_pInfoTicks(0)
429cdf0e10cSrcweir                 , m_rIncrement(rIncrement)
430cdf0e10cSrcweir                 , m_nMinDepth(0), m_nMaxDepth(0)
431cdf0e10cSrcweir                 , m_nTickCount(0), m_pnPositions(NULL)
432cdf0e10cSrcweir                 , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
433cdf0e10cSrcweir                 , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
434cdf0e10cSrcweir {
435cdf0e10cSrcweir     initIter( nMinDepth, nMaxDepth );
436cdf0e10cSrcweir }
437cdf0e10cSrcweir 
EquidistantTickIter(::std::vector<::std::vector<TickInfo>> & rTicks,const ExplicitIncrementData & rIncrement,sal_Int32 nMinDepth,sal_Int32 nMaxDepth)438cdf0e10cSrcweir EquidistantTickIter::EquidistantTickIter( ::std::vector< ::std::vector< TickInfo > >& rTicks
439cdf0e10cSrcweir                    , const ExplicitIncrementData& rIncrement
440cdf0e10cSrcweir                    , sal_Int32 nMinDepth, sal_Int32 nMaxDepth )
441cdf0e10cSrcweir                 : m_pSimpleTicks(NULL)
442cdf0e10cSrcweir                 , m_pInfoTicks(&rTicks)
443cdf0e10cSrcweir                 , m_rIncrement(rIncrement)
444cdf0e10cSrcweir                 , m_nMinDepth(0), m_nMaxDepth(0)
445cdf0e10cSrcweir                 , m_nTickCount(0), m_pnPositions(NULL)
446cdf0e10cSrcweir                 , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
447cdf0e10cSrcweir                 , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
448cdf0e10cSrcweir {
449cdf0e10cSrcweir     initIter( nMinDepth, nMaxDepth );
450cdf0e10cSrcweir }
451cdf0e10cSrcweir 
initIter(sal_Int32,sal_Int32 nMaxDepth)452cdf0e10cSrcweir void EquidistantTickIter::initIter( sal_Int32 /*nMinDepth*/, sal_Int32 nMaxDepth )
453cdf0e10cSrcweir {
454cdf0e10cSrcweir     m_nMaxDepth = nMaxDepth;
455cdf0e10cSrcweir     if(nMaxDepth<0 || m_nMaxDepth>getMaxDepth())
456cdf0e10cSrcweir         m_nMaxDepth=getMaxDepth();
457cdf0e10cSrcweir 
458cdf0e10cSrcweir     sal_Int32 nDepth = 0;
459cdf0e10cSrcweir     for( nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
460cdf0e10cSrcweir         m_nTickCount += getTickCount(nDepth);
461cdf0e10cSrcweir 
462cdf0e10cSrcweir     if(!m_nTickCount)
463cdf0e10cSrcweir         return;
464cdf0e10cSrcweir 
465cdf0e10cSrcweir     m_pnPositions      = new sal_Int32[m_nMaxDepth+1];
466cdf0e10cSrcweir 
467cdf0e10cSrcweir     m_pnPreParentCount = new sal_Int32[m_nMaxDepth+1];
468cdf0e10cSrcweir     m_pbIntervalFinished = new bool[m_nMaxDepth+1];
469cdf0e10cSrcweir     m_pnPreParentCount[0] = 0;
470cdf0e10cSrcweir     m_pbIntervalFinished[0] = false;
471cdf0e10cSrcweir     double fParentValue = getTickValue(0,0);
472cdf0e10cSrcweir     for( nDepth = 1; nDepth<=m_nMaxDepth ;nDepth++ )
473cdf0e10cSrcweir     {
474cdf0e10cSrcweir         m_pbIntervalFinished[nDepth] = false;
475cdf0e10cSrcweir 
476cdf0e10cSrcweir         sal_Int32 nPreParentCount = 0;
477cdf0e10cSrcweir         sal_Int32 nCount = getTickCount(nDepth);
478cdf0e10cSrcweir         for(sal_Int32 nN = 0; nN<nCount; nN++)
479cdf0e10cSrcweir         {
480cdf0e10cSrcweir             if(getTickValue(nDepth,nN) < fParentValue)
481cdf0e10cSrcweir                 nPreParentCount++;
482cdf0e10cSrcweir             else
483cdf0e10cSrcweir                 break;
484cdf0e10cSrcweir         }
485cdf0e10cSrcweir         m_pnPreParentCount[nDepth] = nPreParentCount;
486cdf0e10cSrcweir         if(nCount)
487cdf0e10cSrcweir         {
488cdf0e10cSrcweir             double fNextParentValue = getTickValue(nDepth,0);
489cdf0e10cSrcweir             if( fNextParentValue < fParentValue )
490cdf0e10cSrcweir                 fParentValue = fNextParentValue;
491cdf0e10cSrcweir         }
492cdf0e10cSrcweir     }
493cdf0e10cSrcweir }
494cdf0e10cSrcweir 
~EquidistantTickIter()495cdf0e10cSrcweir EquidistantTickIter::~EquidistantTickIter()
496cdf0e10cSrcweir {
497cdf0e10cSrcweir     delete[] m_pnPositions;
498cdf0e10cSrcweir     delete[] m_pnPreParentCount;
499cdf0e10cSrcweir     delete[] m_pbIntervalFinished;
500cdf0e10cSrcweir }
501cdf0e10cSrcweir 
getStartDepth() const502cdf0e10cSrcweir sal_Int32 EquidistantTickIter::getStartDepth() const
503cdf0e10cSrcweir {
504cdf0e10cSrcweir     //find the depth of the first visible tickmark:
505cdf0e10cSrcweir     //it is the depth of the smallest value
506cdf0e10cSrcweir     sal_Int32 nReturnDepth=0;
507cdf0e10cSrcweir     double fMinValue = DBL_MAX;
508cdf0e10cSrcweir     for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
509cdf0e10cSrcweir     {
510cdf0e10cSrcweir         sal_Int32 nCount = getTickCount(nDepth);
511cdf0e10cSrcweir         if( !nCount )
512cdf0e10cSrcweir             continue;
513cdf0e10cSrcweir         double fThisValue = getTickValue(nDepth,0);
514cdf0e10cSrcweir         if(fThisValue<fMinValue)
515cdf0e10cSrcweir         {
516cdf0e10cSrcweir             nReturnDepth = nDepth;
517cdf0e10cSrcweir             fMinValue = fThisValue;
518cdf0e10cSrcweir         }
519cdf0e10cSrcweir     }
520cdf0e10cSrcweir     return nReturnDepth;
521cdf0e10cSrcweir }
522cdf0e10cSrcweir 
firstValue()523cdf0e10cSrcweir double* EquidistantTickIter::firstValue()
524cdf0e10cSrcweir {
525cdf0e10cSrcweir     if( gotoFirst() )
526cdf0e10cSrcweir     {
527cdf0e10cSrcweir         m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
528cdf0e10cSrcweir         return &m_fCurrentValue;
529cdf0e10cSrcweir     }
530cdf0e10cSrcweir     return NULL;
531cdf0e10cSrcweir }
532cdf0e10cSrcweir 
firstInfo()533cdf0e10cSrcweir TickInfo* EquidistantTickIter::firstInfo()
534cdf0e10cSrcweir {
535cdf0e10cSrcweir     if( m_pInfoTicks && gotoFirst() )
536cdf0e10cSrcweir         return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
537cdf0e10cSrcweir     return NULL;
538cdf0e10cSrcweir }
539cdf0e10cSrcweir 
getIntervalCount(sal_Int32 nDepth)540cdf0e10cSrcweir sal_Int32 EquidistantTickIter::getIntervalCount( sal_Int32 nDepth )
541cdf0e10cSrcweir {
542cdf0e10cSrcweir     if(nDepth>static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) || nDepth<0)
543cdf0e10cSrcweir         return 0;
544cdf0e10cSrcweir 
545cdf0e10cSrcweir     if(!nDepth)
546cdf0e10cSrcweir         return m_nTickCount;
547cdf0e10cSrcweir 
548cdf0e10cSrcweir     return m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
549cdf0e10cSrcweir }
550cdf0e10cSrcweir 
isAtLastPartTick()551cdf0e10cSrcweir bool EquidistantTickIter::isAtLastPartTick()
552cdf0e10cSrcweir {
553cdf0e10cSrcweir     if(!m_nCurrentDepth)
554cdf0e10cSrcweir         return false;
555cdf0e10cSrcweir     sal_Int32 nIntervalCount = getIntervalCount( m_nCurrentDepth );
556cdf0e10cSrcweir     if(!nIntervalCount || nIntervalCount == 1)
557cdf0e10cSrcweir         return true;
558cdf0e10cSrcweir     if( m_pbIntervalFinished[m_nCurrentDepth] )
559cdf0e10cSrcweir         return false;
560cdf0e10cSrcweir     sal_Int32 nPos = m_pnPositions[m_nCurrentDepth]+1;
561cdf0e10cSrcweir     if(m_pnPreParentCount[m_nCurrentDepth])
562cdf0e10cSrcweir         nPos += nIntervalCount-1 - m_pnPreParentCount[m_nCurrentDepth];
563cdf0e10cSrcweir     bool bRet = nPos && nPos % (nIntervalCount-1) == 0;
564cdf0e10cSrcweir     if(!nPos && !m_pnPreParentCount[m_nCurrentDepth]
565cdf0e10cSrcweir              && m_pnPositions[m_nCurrentDepth-1]==-1 )
566cdf0e10cSrcweir          bRet = true;
567cdf0e10cSrcweir     return bRet;
568cdf0e10cSrcweir }
569cdf0e10cSrcweir 
gotoFirst()570cdf0e10cSrcweir bool EquidistantTickIter::gotoFirst()
571cdf0e10cSrcweir {
572cdf0e10cSrcweir     if( m_nMaxDepth<0 )
573cdf0e10cSrcweir         return false;
574cdf0e10cSrcweir     if( !m_nTickCount )
575cdf0e10cSrcweir         return false;
576cdf0e10cSrcweir 
577cdf0e10cSrcweir     for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
578cdf0e10cSrcweir         m_pnPositions[nDepth] = -1;
579cdf0e10cSrcweir 
580cdf0e10cSrcweir     m_nCurrentPos   = 0;
581cdf0e10cSrcweir     m_nCurrentDepth = getStartDepth();
582cdf0e10cSrcweir     m_pnPositions[m_nCurrentDepth] = 0;
583cdf0e10cSrcweir     return true;
584cdf0e10cSrcweir }
585cdf0e10cSrcweir 
gotoNext()586cdf0e10cSrcweir bool EquidistantTickIter::gotoNext()
587cdf0e10cSrcweir {
588cdf0e10cSrcweir     if( m_nCurrentPos < 0 )
589cdf0e10cSrcweir         return false;
590cdf0e10cSrcweir     m_nCurrentPos++;
591cdf0e10cSrcweir 
592cdf0e10cSrcweir     if( m_nCurrentPos >= m_nTickCount )
593cdf0e10cSrcweir         return false;
594cdf0e10cSrcweir 
595cdf0e10cSrcweir     if( m_nCurrentDepth==m_nMaxDepth && isAtLastPartTick() )
596cdf0e10cSrcweir     {
597cdf0e10cSrcweir         do
598cdf0e10cSrcweir         {
599cdf0e10cSrcweir             m_pbIntervalFinished[m_nCurrentDepth] = true;
600cdf0e10cSrcweir             m_nCurrentDepth--;
601cdf0e10cSrcweir         }
602cdf0e10cSrcweir         while( m_nCurrentDepth && isAtLastPartTick() );
603cdf0e10cSrcweir     }
604cdf0e10cSrcweir     else if( m_nCurrentDepth<m_nMaxDepth )
605cdf0e10cSrcweir     {
606cdf0e10cSrcweir         do
607cdf0e10cSrcweir         {
608cdf0e10cSrcweir             m_nCurrentDepth++;
609cdf0e10cSrcweir         }
610cdf0e10cSrcweir         while( m_nCurrentDepth<m_nMaxDepth );
611cdf0e10cSrcweir     }
612cdf0e10cSrcweir     m_pbIntervalFinished[m_nCurrentDepth] = false;
613cdf0e10cSrcweir     m_pnPositions[m_nCurrentDepth] = m_pnPositions[m_nCurrentDepth]+1;
614cdf0e10cSrcweir     return true;
615cdf0e10cSrcweir }
616cdf0e10cSrcweir 
gotoIndex(sal_Int32 nTickIndex)617cdf0e10cSrcweir bool EquidistantTickIter::gotoIndex( sal_Int32 nTickIndex )
618cdf0e10cSrcweir {
619cdf0e10cSrcweir     if( nTickIndex < 0 )
620cdf0e10cSrcweir         return false;
621cdf0e10cSrcweir     if( nTickIndex >= m_nTickCount )
622cdf0e10cSrcweir         return false;
623cdf0e10cSrcweir 
624cdf0e10cSrcweir     if( nTickIndex < m_nCurrentPos )
625cdf0e10cSrcweir         if( !gotoFirst() )
626cdf0e10cSrcweir             return false;
627cdf0e10cSrcweir 
628cdf0e10cSrcweir     while( nTickIndex > m_nCurrentPos )
629cdf0e10cSrcweir         if( !gotoNext() )
630cdf0e10cSrcweir             return false;
631cdf0e10cSrcweir 
632cdf0e10cSrcweir     return true;
633cdf0e10cSrcweir }
634cdf0e10cSrcweir 
getCurrentIndex() const635cdf0e10cSrcweir sal_Int32 EquidistantTickIter::getCurrentIndex() const
636cdf0e10cSrcweir {
637cdf0e10cSrcweir     return m_nCurrentPos;
638cdf0e10cSrcweir }
getMaxIndex() const639cdf0e10cSrcweir sal_Int32 EquidistantTickIter::getMaxIndex() const
640cdf0e10cSrcweir {
641cdf0e10cSrcweir     return m_nTickCount-1;
642cdf0e10cSrcweir }
643cdf0e10cSrcweir 
nextValue()644cdf0e10cSrcweir double* EquidistantTickIter::nextValue()
645cdf0e10cSrcweir {
646cdf0e10cSrcweir     if( gotoNext() )
647cdf0e10cSrcweir     {
648cdf0e10cSrcweir         m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
649cdf0e10cSrcweir         return &m_fCurrentValue;
650cdf0e10cSrcweir     }
651cdf0e10cSrcweir     return NULL;
652cdf0e10cSrcweir }
653cdf0e10cSrcweir 
nextInfo()654cdf0e10cSrcweir TickInfo* EquidistantTickIter::nextInfo()
655cdf0e10cSrcweir {
656cdf0e10cSrcweir     if( m_pInfoTicks && gotoNext() &&
657cdf0e10cSrcweir         static_cast< sal_Int32 >(
658cdf0e10cSrcweir             (*m_pInfoTicks)[m_nCurrentDepth].size()) > m_pnPositions[m_nCurrentDepth] )
659cdf0e10cSrcweir     {
660cdf0e10cSrcweir         return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
661cdf0e10cSrcweir     }
662cdf0e10cSrcweir     return NULL;
663cdf0e10cSrcweir }
664cdf0e10cSrcweir 
665cdf0e10cSrcweir //.............................................................................
666cdf0e10cSrcweir } //namespace chart
667cdf0e10cSrcweir //.............................................................................
668