xref: /AOO41X/main/chart2/source/view/axes/TickmarkHelper.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_chart2.hxx"
30*cdf0e10cSrcweir #include "TickmarkHelper.hxx"
31*cdf0e10cSrcweir #include "ViewDefines.hxx"
32*cdf0e10cSrcweir #include <rtl/math.hxx>
33*cdf0e10cSrcweir #include <tools/debug.hxx>
34*cdf0e10cSrcweir #include <memory>
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir //.............................................................................
37*cdf0e10cSrcweir namespace chart
38*cdf0e10cSrcweir {
39*cdf0e10cSrcweir //.............................................................................
40*cdf0e10cSrcweir using namespace ::com::sun::star;
41*cdf0e10cSrcweir using namespace ::com::sun::star::chart2;
42*cdf0e10cSrcweir using namespace ::rtl::math;
43*cdf0e10cSrcweir using ::basegfx::B2DVector;
44*cdf0e10cSrcweir 
45*cdf0e10cSrcweir TickInfo::TickInfo()
46*cdf0e10cSrcweir : fScaledTickValue( 0.0 )
47*cdf0e10cSrcweir , fUnscaledTickValue( 0.0 )
48*cdf0e10cSrcweir , aTickScreenPosition(0.0,0.0)
49*cdf0e10cSrcweir , bPaintIt( true )
50*cdf0e10cSrcweir , xTextShape( NULL )
51*cdf0e10cSrcweir , nFactorForLimitedTextWidth(1)
52*cdf0e10cSrcweir {
53*cdf0e10cSrcweir }
54*cdf0e10cSrcweir 
55*cdf0e10cSrcweir void TickInfo::updateUnscaledValue( const uno::Reference< XScaling >& xInverseScaling )
56*cdf0e10cSrcweir {
57*cdf0e10cSrcweir     if( xInverseScaling.is() )
58*cdf0e10cSrcweir         this->fUnscaledTickValue = xInverseScaling->doScaling( this->fScaledTickValue );
59*cdf0e10cSrcweir     else
60*cdf0e10cSrcweir         this->fUnscaledTickValue = this->fScaledTickValue;
61*cdf0e10cSrcweir }
62*cdf0e10cSrcweir 
63*cdf0e10cSrcweir sal_Int32 TickInfo::getScreenDistanceBetweenTicks( const TickInfo& rOherTickInfo ) const
64*cdf0e10cSrcweir {
65*cdf0e10cSrcweir     //return the positive distance between the two first tickmarks in screen values
66*cdf0e10cSrcweir 
67*cdf0e10cSrcweir     B2DVector aDistance = rOherTickInfo.aTickScreenPosition - aTickScreenPosition;
68*cdf0e10cSrcweir     sal_Int32 nRet = static_cast<sal_Int32>(aDistance.getLength());
69*cdf0e10cSrcweir     if(nRet<0)
70*cdf0e10cSrcweir         nRet *= -1;
71*cdf0e10cSrcweir     return nRet;
72*cdf0e10cSrcweir }
73*cdf0e10cSrcweir 
74*cdf0e10cSrcweir PureTickIter::PureTickIter( ::std::vector< TickInfo >& rTickInfoVector )
75*cdf0e10cSrcweir             : m_rTickVector(rTickInfoVector)
76*cdf0e10cSrcweir             , m_aTickIter(m_rTickVector.begin())
77*cdf0e10cSrcweir {
78*cdf0e10cSrcweir }
79*cdf0e10cSrcweir PureTickIter::~PureTickIter()
80*cdf0e10cSrcweir {
81*cdf0e10cSrcweir }
82*cdf0e10cSrcweir TickInfo* PureTickIter::firstInfo()
83*cdf0e10cSrcweir {
84*cdf0e10cSrcweir     m_aTickIter = m_rTickVector.begin();
85*cdf0e10cSrcweir     if(m_aTickIter!=m_rTickVector.end())
86*cdf0e10cSrcweir         return &*m_aTickIter;
87*cdf0e10cSrcweir     return 0;
88*cdf0e10cSrcweir }
89*cdf0e10cSrcweir TickInfo* PureTickIter::nextInfo()
90*cdf0e10cSrcweir {
91*cdf0e10cSrcweir     m_aTickIter++;
92*cdf0e10cSrcweir     if(m_aTickIter!=m_rTickVector.end())
93*cdf0e10cSrcweir         return &*m_aTickIter;
94*cdf0e10cSrcweir     return 0;
95*cdf0e10cSrcweir }
96*cdf0e10cSrcweir 
97*cdf0e10cSrcweir EquidistantTickIter::EquidistantTickIter( const uno::Sequence< uno::Sequence< double > >& rTicks
98*cdf0e10cSrcweir                    , const ExplicitIncrementData& rIncrement
99*cdf0e10cSrcweir                    , sal_Int32 nMinDepth, sal_Int32 nMaxDepth )
100*cdf0e10cSrcweir                 : m_pSimpleTicks(&rTicks)
101*cdf0e10cSrcweir                 , m_pInfoTicks(0)
102*cdf0e10cSrcweir                 , m_rIncrement(rIncrement)
103*cdf0e10cSrcweir                 , m_nMinDepth(0), m_nMaxDepth(0)
104*cdf0e10cSrcweir                 , m_nTickCount(0), m_pnPositions(NULL)
105*cdf0e10cSrcweir                 , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
106*cdf0e10cSrcweir                 , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
107*cdf0e10cSrcweir {
108*cdf0e10cSrcweir     initIter( nMinDepth, nMaxDepth );
109*cdf0e10cSrcweir }
110*cdf0e10cSrcweir 
111*cdf0e10cSrcweir EquidistantTickIter::EquidistantTickIter( ::std::vector< ::std::vector< TickInfo > >& rTicks
112*cdf0e10cSrcweir                    , const ExplicitIncrementData& rIncrement
113*cdf0e10cSrcweir                    , sal_Int32 nMinDepth, sal_Int32 nMaxDepth )
114*cdf0e10cSrcweir                 : m_pSimpleTicks(NULL)
115*cdf0e10cSrcweir                 , m_pInfoTicks(&rTicks)
116*cdf0e10cSrcweir                 , m_rIncrement(rIncrement)
117*cdf0e10cSrcweir                 , m_nMinDepth(0), m_nMaxDepth(0)
118*cdf0e10cSrcweir                 , m_nTickCount(0), m_pnPositions(NULL)
119*cdf0e10cSrcweir                 , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
120*cdf0e10cSrcweir                 , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
121*cdf0e10cSrcweir {
122*cdf0e10cSrcweir     initIter( nMinDepth, nMaxDepth );
123*cdf0e10cSrcweir }
124*cdf0e10cSrcweir 
125*cdf0e10cSrcweir void EquidistantTickIter::initIter( sal_Int32 /*nMinDepth*/, sal_Int32 nMaxDepth )
126*cdf0e10cSrcweir {
127*cdf0e10cSrcweir     m_nMaxDepth = nMaxDepth;
128*cdf0e10cSrcweir     if(nMaxDepth<0 || m_nMaxDepth>getMaxDepth())
129*cdf0e10cSrcweir         m_nMaxDepth=getMaxDepth();
130*cdf0e10cSrcweir 
131*cdf0e10cSrcweir     sal_Int32 nDepth = 0;
132*cdf0e10cSrcweir     for( nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
133*cdf0e10cSrcweir         m_nTickCount += getTickCount(nDepth);
134*cdf0e10cSrcweir 
135*cdf0e10cSrcweir     if(!m_nTickCount)
136*cdf0e10cSrcweir         return;
137*cdf0e10cSrcweir 
138*cdf0e10cSrcweir     m_pnPositions      = new sal_Int32[m_nMaxDepth+1];
139*cdf0e10cSrcweir 
140*cdf0e10cSrcweir     m_pnPreParentCount = new sal_Int32[m_nMaxDepth+1];
141*cdf0e10cSrcweir     m_pbIntervalFinished = new bool[m_nMaxDepth+1];
142*cdf0e10cSrcweir     m_pnPreParentCount[0] = 0;
143*cdf0e10cSrcweir     m_pbIntervalFinished[0] = false;
144*cdf0e10cSrcweir     double fParentValue = getTickValue(0,0);
145*cdf0e10cSrcweir     for( nDepth = 1; nDepth<=m_nMaxDepth ;nDepth++ )
146*cdf0e10cSrcweir     {
147*cdf0e10cSrcweir         m_pbIntervalFinished[nDepth] = false;
148*cdf0e10cSrcweir 
149*cdf0e10cSrcweir         sal_Int32 nPreParentCount = 0;
150*cdf0e10cSrcweir         sal_Int32 nCount = getTickCount(nDepth);
151*cdf0e10cSrcweir         for(sal_Int32 nN = 0; nN<nCount; nN++)
152*cdf0e10cSrcweir         {
153*cdf0e10cSrcweir             if(getTickValue(nDepth,nN) < fParentValue)
154*cdf0e10cSrcweir                 nPreParentCount++;
155*cdf0e10cSrcweir             else
156*cdf0e10cSrcweir                 break;
157*cdf0e10cSrcweir         }
158*cdf0e10cSrcweir         m_pnPreParentCount[nDepth] = nPreParentCount;
159*cdf0e10cSrcweir         if(nCount)
160*cdf0e10cSrcweir         {
161*cdf0e10cSrcweir             double fNextParentValue = getTickValue(nDepth,0);
162*cdf0e10cSrcweir             if( fNextParentValue < fParentValue )
163*cdf0e10cSrcweir                 fParentValue = fNextParentValue;
164*cdf0e10cSrcweir         }
165*cdf0e10cSrcweir     }
166*cdf0e10cSrcweir }
167*cdf0e10cSrcweir 
168*cdf0e10cSrcweir EquidistantTickIter::~EquidistantTickIter()
169*cdf0e10cSrcweir {
170*cdf0e10cSrcweir     delete[] m_pnPositions;
171*cdf0e10cSrcweir     delete[] m_pnPreParentCount;
172*cdf0e10cSrcweir     delete[] m_pbIntervalFinished;
173*cdf0e10cSrcweir }
174*cdf0e10cSrcweir 
175*cdf0e10cSrcweir sal_Int32 EquidistantTickIter::getStartDepth() const
176*cdf0e10cSrcweir {
177*cdf0e10cSrcweir     //find the depth of the first visible tickmark:
178*cdf0e10cSrcweir     //it is the depth of the smallest value
179*cdf0e10cSrcweir     sal_Int32 nReturnDepth=0;
180*cdf0e10cSrcweir     double fMinValue = DBL_MAX;
181*cdf0e10cSrcweir     for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
182*cdf0e10cSrcweir     {
183*cdf0e10cSrcweir         sal_Int32 nCount = getTickCount(nDepth);
184*cdf0e10cSrcweir         if( !nCount )
185*cdf0e10cSrcweir             continue;
186*cdf0e10cSrcweir         double fThisValue = getTickValue(nDepth,0);
187*cdf0e10cSrcweir         if(fThisValue<fMinValue)
188*cdf0e10cSrcweir         {
189*cdf0e10cSrcweir             nReturnDepth = nDepth;
190*cdf0e10cSrcweir             fMinValue = fThisValue;
191*cdf0e10cSrcweir         }
192*cdf0e10cSrcweir     }
193*cdf0e10cSrcweir     return nReturnDepth;
194*cdf0e10cSrcweir }
195*cdf0e10cSrcweir 
196*cdf0e10cSrcweir double* EquidistantTickIter::firstValue()
197*cdf0e10cSrcweir {
198*cdf0e10cSrcweir     if( gotoFirst() )
199*cdf0e10cSrcweir     {
200*cdf0e10cSrcweir         m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
201*cdf0e10cSrcweir         return &m_fCurrentValue;
202*cdf0e10cSrcweir     }
203*cdf0e10cSrcweir     return NULL;
204*cdf0e10cSrcweir }
205*cdf0e10cSrcweir 
206*cdf0e10cSrcweir TickInfo* EquidistantTickIter::firstInfo()
207*cdf0e10cSrcweir {
208*cdf0e10cSrcweir     if( m_pInfoTicks && gotoFirst() )
209*cdf0e10cSrcweir         return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
210*cdf0e10cSrcweir     return NULL;
211*cdf0e10cSrcweir }
212*cdf0e10cSrcweir 
213*cdf0e10cSrcweir sal_Int32 EquidistantTickIter::getIntervalCount( sal_Int32 nDepth )
214*cdf0e10cSrcweir {
215*cdf0e10cSrcweir     if(nDepth>m_rIncrement.SubIncrements.getLength() || nDepth<0)
216*cdf0e10cSrcweir         return 0;
217*cdf0e10cSrcweir 
218*cdf0e10cSrcweir     if(!nDepth)
219*cdf0e10cSrcweir         return m_nTickCount;
220*cdf0e10cSrcweir 
221*cdf0e10cSrcweir     return m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
222*cdf0e10cSrcweir }
223*cdf0e10cSrcweir 
224*cdf0e10cSrcweir bool EquidistantTickIter::isAtLastPartTick()
225*cdf0e10cSrcweir {
226*cdf0e10cSrcweir     if(!m_nCurrentDepth)
227*cdf0e10cSrcweir         return false;
228*cdf0e10cSrcweir     sal_Int32 nIntervalCount = getIntervalCount( m_nCurrentDepth );
229*cdf0e10cSrcweir     if(!nIntervalCount || nIntervalCount == 1)
230*cdf0e10cSrcweir         return true;
231*cdf0e10cSrcweir     if( m_pbIntervalFinished[m_nCurrentDepth] )
232*cdf0e10cSrcweir         return false;
233*cdf0e10cSrcweir     sal_Int32 nPos = m_pnPositions[m_nCurrentDepth]+1;
234*cdf0e10cSrcweir     if(m_pnPreParentCount[m_nCurrentDepth])
235*cdf0e10cSrcweir         nPos += nIntervalCount-1 - m_pnPreParentCount[m_nCurrentDepth];
236*cdf0e10cSrcweir     bool bRet = nPos && nPos % (nIntervalCount-1) == 0;
237*cdf0e10cSrcweir     if(!nPos && !m_pnPreParentCount[m_nCurrentDepth]
238*cdf0e10cSrcweir              && m_pnPositions[m_nCurrentDepth-1]==-1 )
239*cdf0e10cSrcweir          bRet = true;
240*cdf0e10cSrcweir     return bRet;
241*cdf0e10cSrcweir }
242*cdf0e10cSrcweir 
243*cdf0e10cSrcweir bool EquidistantTickIter::gotoFirst()
244*cdf0e10cSrcweir {
245*cdf0e10cSrcweir     if( m_nMaxDepth<0 )
246*cdf0e10cSrcweir         return false;
247*cdf0e10cSrcweir     if( !m_nTickCount )
248*cdf0e10cSrcweir         return false;
249*cdf0e10cSrcweir 
250*cdf0e10cSrcweir     for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
251*cdf0e10cSrcweir         m_pnPositions[nDepth] = -1;
252*cdf0e10cSrcweir 
253*cdf0e10cSrcweir     m_nCurrentPos   = 0;
254*cdf0e10cSrcweir     m_nCurrentDepth = getStartDepth();
255*cdf0e10cSrcweir     m_pnPositions[m_nCurrentDepth] = 0;
256*cdf0e10cSrcweir     return true;
257*cdf0e10cSrcweir }
258*cdf0e10cSrcweir 
259*cdf0e10cSrcweir bool EquidistantTickIter::gotoNext()
260*cdf0e10cSrcweir {
261*cdf0e10cSrcweir     if( m_nCurrentPos < 0 )
262*cdf0e10cSrcweir         return false;
263*cdf0e10cSrcweir     m_nCurrentPos++;
264*cdf0e10cSrcweir 
265*cdf0e10cSrcweir     if( m_nCurrentPos >= m_nTickCount )
266*cdf0e10cSrcweir         return false;
267*cdf0e10cSrcweir 
268*cdf0e10cSrcweir     if( m_nCurrentDepth==m_nMaxDepth && isAtLastPartTick() )
269*cdf0e10cSrcweir     {
270*cdf0e10cSrcweir         do
271*cdf0e10cSrcweir         {
272*cdf0e10cSrcweir             m_pbIntervalFinished[m_nCurrentDepth] = true;
273*cdf0e10cSrcweir             m_nCurrentDepth--;
274*cdf0e10cSrcweir         }
275*cdf0e10cSrcweir         while( m_nCurrentDepth && isAtLastPartTick() );
276*cdf0e10cSrcweir     }
277*cdf0e10cSrcweir     else if( m_nCurrentDepth<m_nMaxDepth )
278*cdf0e10cSrcweir     {
279*cdf0e10cSrcweir         do
280*cdf0e10cSrcweir         {
281*cdf0e10cSrcweir             m_nCurrentDepth++;
282*cdf0e10cSrcweir         }
283*cdf0e10cSrcweir         while( m_nCurrentDepth<m_nMaxDepth );
284*cdf0e10cSrcweir     }
285*cdf0e10cSrcweir     m_pbIntervalFinished[m_nCurrentDepth] = false;
286*cdf0e10cSrcweir     m_pnPositions[m_nCurrentDepth] = m_pnPositions[m_nCurrentDepth]+1;
287*cdf0e10cSrcweir     return true;
288*cdf0e10cSrcweir }
289*cdf0e10cSrcweir 
290*cdf0e10cSrcweir bool EquidistantTickIter::gotoIndex( sal_Int32 nTickIndex )
291*cdf0e10cSrcweir {
292*cdf0e10cSrcweir     if( nTickIndex < 0 )
293*cdf0e10cSrcweir         return false;
294*cdf0e10cSrcweir     if( nTickIndex >= m_nTickCount )
295*cdf0e10cSrcweir         return false;
296*cdf0e10cSrcweir 
297*cdf0e10cSrcweir     if( nTickIndex < m_nCurrentPos )
298*cdf0e10cSrcweir         if( !gotoFirst() )
299*cdf0e10cSrcweir             return false;
300*cdf0e10cSrcweir 
301*cdf0e10cSrcweir     while( nTickIndex > m_nCurrentPos )
302*cdf0e10cSrcweir         if( !gotoNext() )
303*cdf0e10cSrcweir             return false;
304*cdf0e10cSrcweir 
305*cdf0e10cSrcweir     return true;
306*cdf0e10cSrcweir }
307*cdf0e10cSrcweir 
308*cdf0e10cSrcweir sal_Int32 EquidistantTickIter::getCurrentIndex() const
309*cdf0e10cSrcweir {
310*cdf0e10cSrcweir     return m_nCurrentPos;
311*cdf0e10cSrcweir }
312*cdf0e10cSrcweir sal_Int32 EquidistantTickIter::getMaxIndex() const
313*cdf0e10cSrcweir {
314*cdf0e10cSrcweir     return m_nTickCount-1;
315*cdf0e10cSrcweir }
316*cdf0e10cSrcweir 
317*cdf0e10cSrcweir double* EquidistantTickIter::nextValue()
318*cdf0e10cSrcweir {
319*cdf0e10cSrcweir     if( gotoNext() )
320*cdf0e10cSrcweir     {
321*cdf0e10cSrcweir         m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
322*cdf0e10cSrcweir         return &m_fCurrentValue;
323*cdf0e10cSrcweir     }
324*cdf0e10cSrcweir     return NULL;
325*cdf0e10cSrcweir }
326*cdf0e10cSrcweir 
327*cdf0e10cSrcweir TickInfo* EquidistantTickIter::nextInfo()
328*cdf0e10cSrcweir {
329*cdf0e10cSrcweir     if( m_pInfoTicks && gotoNext() &&
330*cdf0e10cSrcweir         static_cast< sal_Int32 >(
331*cdf0e10cSrcweir             (*m_pInfoTicks)[m_nCurrentDepth].size()) > m_pnPositions[m_nCurrentDepth] )
332*cdf0e10cSrcweir     {
333*cdf0e10cSrcweir         return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
334*cdf0e10cSrcweir     }
335*cdf0e10cSrcweir     return NULL;
336*cdf0e10cSrcweir }
337*cdf0e10cSrcweir 
338*cdf0e10cSrcweir //-----------------------------------------------------------------------------
339*cdf0e10cSrcweir //-----------------------------------------------------------------------------
340*cdf0e10cSrcweir //-----------------------------------------------------------------------------
341*cdf0e10cSrcweir 
342*cdf0e10cSrcweir double TickmarkHelper::getMinimumAtIncrement( double fMin, const ExplicitIncrementData& rIncrement )
343*cdf0e10cSrcweir {
344*cdf0e10cSrcweir     //the returned value will be <= fMin and on a Major Tick given by rIncrement
345*cdf0e10cSrcweir     if(rIncrement.Distance<=0.0)
346*cdf0e10cSrcweir         return fMin;
347*cdf0e10cSrcweir 
348*cdf0e10cSrcweir     double fRet = rIncrement.BaseValue +
349*cdf0e10cSrcweir         floor( approxSub( fMin, rIncrement.BaseValue )
350*cdf0e10cSrcweir                     / rIncrement.Distance)
351*cdf0e10cSrcweir             *rIncrement.Distance;
352*cdf0e10cSrcweir 
353*cdf0e10cSrcweir     if( fRet > fMin )
354*cdf0e10cSrcweir     {
355*cdf0e10cSrcweir         if( !approxEqual(fRet, fMin) )
356*cdf0e10cSrcweir             fRet -= rIncrement.Distance;
357*cdf0e10cSrcweir     }
358*cdf0e10cSrcweir     return fRet;
359*cdf0e10cSrcweir }
360*cdf0e10cSrcweir double TickmarkHelper::getMaximumAtIncrement( double fMax, const ExplicitIncrementData& rIncrement )
361*cdf0e10cSrcweir {
362*cdf0e10cSrcweir     //the returned value will be >= fMax and on a Major Tick given by rIncrement
363*cdf0e10cSrcweir     if(rIncrement.Distance<=0.0)
364*cdf0e10cSrcweir         return fMax;
365*cdf0e10cSrcweir 
366*cdf0e10cSrcweir     double fRet = rIncrement.BaseValue +
367*cdf0e10cSrcweir         floor( approxSub( fMax, rIncrement.BaseValue )
368*cdf0e10cSrcweir                     / rIncrement.Distance)
369*cdf0e10cSrcweir             *rIncrement.Distance;
370*cdf0e10cSrcweir 
371*cdf0e10cSrcweir     if( fRet < fMax )
372*cdf0e10cSrcweir     {
373*cdf0e10cSrcweir         if( !approxEqual(fRet, fMax) )
374*cdf0e10cSrcweir             fRet += rIncrement.Distance;
375*cdf0e10cSrcweir     }
376*cdf0e10cSrcweir     return fRet;
377*cdf0e10cSrcweir }
378*cdf0e10cSrcweir 
379*cdf0e10cSrcweir //-----------------------------------------------------------------------------
380*cdf0e10cSrcweir //-----------------------------------------------------------------------------
381*cdf0e10cSrcweir //-----------------------------------------------------------------------------
382*cdf0e10cSrcweir 
383*cdf0e10cSrcweir TickmarkHelper::TickmarkHelper(
384*cdf0e10cSrcweir           const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement )
385*cdf0e10cSrcweir             : m_rScale( rScale )
386*cdf0e10cSrcweir             , m_rIncrement( rIncrement )
387*cdf0e10cSrcweir             , m_xInverseScaling(NULL)
388*cdf0e10cSrcweir             , m_pfCurrentValues(NULL)
389*cdf0e10cSrcweir {
390*cdf0e10cSrcweir     //@todo: make sure that the scale is valid for the scaling
391*cdf0e10cSrcweir 
392*cdf0e10cSrcweir     m_pfCurrentValues = new double[getTickDepth()];
393*cdf0e10cSrcweir 
394*cdf0e10cSrcweir     if( m_rScale.Scaling.is() )
395*cdf0e10cSrcweir     {
396*cdf0e10cSrcweir         m_xInverseScaling = m_rScale.Scaling->getInverseScaling();
397*cdf0e10cSrcweir         DBG_ASSERT( m_xInverseScaling.is(), "each Scaling needs to return a inverse Scaling" );
398*cdf0e10cSrcweir     }
399*cdf0e10cSrcweir 
400*cdf0e10cSrcweir     double fMin = m_fScaledVisibleMin = m_rScale.Minimum;
401*cdf0e10cSrcweir     if( m_xInverseScaling.is() )
402*cdf0e10cSrcweir     {
403*cdf0e10cSrcweir         m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin);
404*cdf0e10cSrcweir         if(m_rIncrement.PostEquidistant )
405*cdf0e10cSrcweir             fMin = m_fScaledVisibleMin;
406*cdf0e10cSrcweir     }
407*cdf0e10cSrcweir 
408*cdf0e10cSrcweir     double fMax = m_fScaledVisibleMax = m_rScale.Maximum;
409*cdf0e10cSrcweir     if( m_xInverseScaling.is() )
410*cdf0e10cSrcweir     {
411*cdf0e10cSrcweir         m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax);
412*cdf0e10cSrcweir         if(m_rIncrement.PostEquidistant )
413*cdf0e10cSrcweir             fMax = m_fScaledVisibleMax;
414*cdf0e10cSrcweir     }
415*cdf0e10cSrcweir 
416*cdf0e10cSrcweir     //--
417*cdf0e10cSrcweir     m_fOuterMajorTickBorderMin = TickmarkHelper::getMinimumAtIncrement( fMin, m_rIncrement );
418*cdf0e10cSrcweir     m_fOuterMajorTickBorderMax = TickmarkHelper::getMaximumAtIncrement( fMax, m_rIncrement );
419*cdf0e10cSrcweir     //--
420*cdf0e10cSrcweir 
421*cdf0e10cSrcweir     m_fOuterMajorTickBorderMin_Scaled = m_fOuterMajorTickBorderMin;
422*cdf0e10cSrcweir     m_fOuterMajorTickBorderMax_Scaled = m_fOuterMajorTickBorderMax;
423*cdf0e10cSrcweir     if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
424*cdf0e10cSrcweir     {
425*cdf0e10cSrcweir         m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
426*cdf0e10cSrcweir         m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
427*cdf0e10cSrcweir 
428*cdf0e10cSrcweir         //check validity of new range: m_fOuterMajorTickBorderMin <-> m_fOuterMajorTickBorderMax
429*cdf0e10cSrcweir         //it is assumed here, that the original range in the given Scale is valid
430*cdf0e10cSrcweir         if( !rtl::math::isFinite(m_fOuterMajorTickBorderMin_Scaled) )
431*cdf0e10cSrcweir         {
432*cdf0e10cSrcweir             m_fOuterMajorTickBorderMin += m_rIncrement.Distance;
433*cdf0e10cSrcweir             m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
434*cdf0e10cSrcweir         }
435*cdf0e10cSrcweir         if( !rtl::math::isFinite(m_fOuterMajorTickBorderMax_Scaled) )
436*cdf0e10cSrcweir         {
437*cdf0e10cSrcweir             m_fOuterMajorTickBorderMax -= m_rIncrement.Distance;
438*cdf0e10cSrcweir             m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
439*cdf0e10cSrcweir         }
440*cdf0e10cSrcweir     }
441*cdf0e10cSrcweir }
442*cdf0e10cSrcweir 
443*cdf0e10cSrcweir TickmarkHelper* TickmarkHelper::createShiftedTickmarkHelper() const
444*cdf0e10cSrcweir {
445*cdf0e10cSrcweir     ExplicitIncrementData aShiftedIncrement( m_rIncrement );
446*cdf0e10cSrcweir     aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
447*cdf0e10cSrcweir     return new TickmarkHelper( m_rScale, aShiftedIncrement );
448*cdf0e10cSrcweir }
449*cdf0e10cSrcweir 
450*cdf0e10cSrcweir TickmarkHelper::~TickmarkHelper()
451*cdf0e10cSrcweir {
452*cdf0e10cSrcweir     delete[] m_pfCurrentValues;
453*cdf0e10cSrcweir }
454*cdf0e10cSrcweir 
455*cdf0e10cSrcweir sal_Int32 TickmarkHelper::getTickDepth() const
456*cdf0e10cSrcweir {
457*cdf0e10cSrcweir     return m_rIncrement.SubIncrements.getLength() + 1;
458*cdf0e10cSrcweir }
459*cdf0e10cSrcweir 
460*cdf0e10cSrcweir sal_Int32 TickmarkHelper::getMaxTickCount( sal_Int32 nDepth ) const
461*cdf0e10cSrcweir {
462*cdf0e10cSrcweir     //return the maximum amount of ticks
463*cdf0e10cSrcweir     //possibly open intervals at the two ends of the region are handled as if they were completely visible
464*cdf0e10cSrcweir     //(this is necessary for calculating the sub ticks at the borders correctly)
465*cdf0e10cSrcweir 
466*cdf0e10cSrcweir     if( nDepth >= getTickDepth() )
467*cdf0e10cSrcweir         return 0;
468*cdf0e10cSrcweir     if( m_fOuterMajorTickBorderMax < m_fOuterMajorTickBorderMin )
469*cdf0e10cSrcweir         return 0;
470*cdf0e10cSrcweir     if( m_rIncrement.Distance<=0.0)
471*cdf0e10cSrcweir         return 0;
472*cdf0e10cSrcweir 
473*cdf0e10cSrcweir     double fSub;
474*cdf0e10cSrcweir     if(m_rIncrement.PostEquidistant  )
475*cdf0e10cSrcweir         fSub = approxSub( m_fScaledVisibleMax, m_fScaledVisibleMin );
476*cdf0e10cSrcweir     else
477*cdf0e10cSrcweir         fSub = approxSub( m_rScale.Maximum, m_rScale.Minimum );
478*cdf0e10cSrcweir 
479*cdf0e10cSrcweir     if (!isFinite(fSub))
480*cdf0e10cSrcweir         return 0;
481*cdf0e10cSrcweir 
482*cdf0e10cSrcweir     sal_Int32 nIntervalCount = static_cast<sal_Int32>( fSub / m_rIncrement.Distance );
483*cdf0e10cSrcweir 
484*cdf0e10cSrcweir     nIntervalCount+=3;
485*cdf0e10cSrcweir     for(sal_Int32 nN=0; nN<nDepth-1; nN++)
486*cdf0e10cSrcweir     {
487*cdf0e10cSrcweir         if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
488*cdf0e10cSrcweir             nIntervalCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
489*cdf0e10cSrcweir     }
490*cdf0e10cSrcweir 
491*cdf0e10cSrcweir     sal_Int32 nTickCount = nIntervalCount;
492*cdf0e10cSrcweir     if(nDepth>0 && m_rIncrement.SubIncrements[nDepth-1].IntervalCount>1)
493*cdf0e10cSrcweir         nTickCount = nIntervalCount * (m_rIncrement.SubIncrements[nDepth-1].IntervalCount-1);
494*cdf0e10cSrcweir 
495*cdf0e10cSrcweir     return nTickCount;
496*cdf0e10cSrcweir }
497*cdf0e10cSrcweir 
498*cdf0e10cSrcweir double* TickmarkHelper::getMajorTick( sal_Int32 nTick ) const
499*cdf0e10cSrcweir {
500*cdf0e10cSrcweir     m_pfCurrentValues[0] = m_fOuterMajorTickBorderMin + nTick*m_rIncrement.Distance;
501*cdf0e10cSrcweir 
502*cdf0e10cSrcweir     if(m_pfCurrentValues[0]>m_fOuterMajorTickBorderMax)
503*cdf0e10cSrcweir     {
504*cdf0e10cSrcweir         if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMax) )
505*cdf0e10cSrcweir             return NULL;
506*cdf0e10cSrcweir     }
507*cdf0e10cSrcweir     if(m_pfCurrentValues[0]<m_fOuterMajorTickBorderMin)
508*cdf0e10cSrcweir     {
509*cdf0e10cSrcweir         if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMin) )
510*cdf0e10cSrcweir             return NULL;
511*cdf0e10cSrcweir     }
512*cdf0e10cSrcweir 
513*cdf0e10cSrcweir     //return always the value after scaling
514*cdf0e10cSrcweir     if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
515*cdf0e10cSrcweir         m_pfCurrentValues[0] = m_rScale.Scaling->doScaling( m_pfCurrentValues[0] );
516*cdf0e10cSrcweir 
517*cdf0e10cSrcweir     return &m_pfCurrentValues[0];
518*cdf0e10cSrcweir }
519*cdf0e10cSrcweir 
520*cdf0e10cSrcweir double* TickmarkHelper::getMinorTick( sal_Int32 nTick, sal_Int32 nDepth
521*cdf0e10cSrcweir                             , double fStartParentTick, double fNextParentTick ) const
522*cdf0e10cSrcweir {
523*cdf0e10cSrcweir     //check validity of arguments
524*cdf0e10cSrcweir     {
525*cdf0e10cSrcweir         //DBG_ASSERT( fStartParentTick < fNextParentTick, "fStartParentTick >= fNextParentTick");
526*cdf0e10cSrcweir         if(fStartParentTick >= fNextParentTick)
527*cdf0e10cSrcweir             return NULL;
528*cdf0e10cSrcweir         if(nDepth>m_rIncrement.SubIncrements.getLength() || nDepth<=0)
529*cdf0e10cSrcweir             return NULL;
530*cdf0e10cSrcweir 
531*cdf0e10cSrcweir         //subticks are only calculated if they are laying between parent ticks:
532*cdf0e10cSrcweir         if(nTick<=0)
533*cdf0e10cSrcweir             return NULL;
534*cdf0e10cSrcweir         if(nTick>=m_rIncrement.SubIncrements[nDepth-1].IntervalCount)
535*cdf0e10cSrcweir             return NULL;
536*cdf0e10cSrcweir     }
537*cdf0e10cSrcweir 
538*cdf0e10cSrcweir     bool    bPostEquidistant = m_rIncrement.SubIncrements[nDepth-1].PostEquidistant;
539*cdf0e10cSrcweir 
540*cdf0e10cSrcweir     double fAdaptedStartParent = fStartParentTick;
541*cdf0e10cSrcweir     double fAdaptedNextParent  = fNextParentTick;
542*cdf0e10cSrcweir 
543*cdf0e10cSrcweir     if( !bPostEquidistant && m_xInverseScaling.is() )
544*cdf0e10cSrcweir     {
545*cdf0e10cSrcweir         fAdaptedStartParent = m_xInverseScaling->doScaling(fStartParentTick);
546*cdf0e10cSrcweir         fAdaptedNextParent  = m_xInverseScaling->doScaling(fNextParentTick);
547*cdf0e10cSrcweir     }
548*cdf0e10cSrcweir 
549*cdf0e10cSrcweir     double fDistance = (fAdaptedNextParent - fAdaptedStartParent)/m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
550*cdf0e10cSrcweir 
551*cdf0e10cSrcweir     m_pfCurrentValues[nDepth] = fAdaptedStartParent + nTick*fDistance;
552*cdf0e10cSrcweir 
553*cdf0e10cSrcweir     //return always the value after scaling
554*cdf0e10cSrcweir     if(!bPostEquidistant && m_xInverseScaling.is() )
555*cdf0e10cSrcweir         m_pfCurrentValues[nDepth] = m_rScale.Scaling->doScaling( m_pfCurrentValues[nDepth] );
556*cdf0e10cSrcweir 
557*cdf0e10cSrcweir     if( !isWithinOuterBorder( m_pfCurrentValues[nDepth] ) )
558*cdf0e10cSrcweir         return NULL;
559*cdf0e10cSrcweir 
560*cdf0e10cSrcweir     return &m_pfCurrentValues[nDepth];
561*cdf0e10cSrcweir }
562*cdf0e10cSrcweir 
563*cdf0e10cSrcweir bool TickmarkHelper::isWithinOuterBorder( double fScaledValue ) const
564*cdf0e10cSrcweir {
565*cdf0e10cSrcweir     if(fScaledValue>m_fOuterMajorTickBorderMax_Scaled)
566*cdf0e10cSrcweir         return false;
567*cdf0e10cSrcweir     if(fScaledValue<m_fOuterMajorTickBorderMin_Scaled)
568*cdf0e10cSrcweir         return false;
569*cdf0e10cSrcweir 
570*cdf0e10cSrcweir     return true;
571*cdf0e10cSrcweir }
572*cdf0e10cSrcweir 
573*cdf0e10cSrcweir 
574*cdf0e10cSrcweir bool TickmarkHelper::isVisible( double fScaledValue ) const
575*cdf0e10cSrcweir {
576*cdf0e10cSrcweir     if(fScaledValue>m_fScaledVisibleMax)
577*cdf0e10cSrcweir     {
578*cdf0e10cSrcweir         if( !approxEqual(fScaledValue,m_fScaledVisibleMax) )
579*cdf0e10cSrcweir             return false;
580*cdf0e10cSrcweir     }
581*cdf0e10cSrcweir     if(fScaledValue<m_fScaledVisibleMin)
582*cdf0e10cSrcweir     {
583*cdf0e10cSrcweir         if( !approxEqual(fScaledValue,m_fScaledVisibleMin) )
584*cdf0e10cSrcweir             return false;
585*cdf0e10cSrcweir     }
586*cdf0e10cSrcweir     return true;
587*cdf0e10cSrcweir }
588*cdf0e10cSrcweir 
589*cdf0e10cSrcweir void TickmarkHelper::getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
590*cdf0e10cSrcweir {
591*cdf0e10cSrcweir     uno::Sequence< uno::Sequence< double > > aAllTicks;
592*cdf0e10cSrcweir 
593*cdf0e10cSrcweir     //create point sequences for each tick depth
594*cdf0e10cSrcweir     sal_Int32 nDepthCount = this->getTickDepth();
595*cdf0e10cSrcweir     sal_Int32 nMaxMajorTickCount = this->getMaxTickCount( 0 );
596*cdf0e10cSrcweir 
597*cdf0e10cSrcweir     aAllTicks.realloc(nDepthCount);
598*cdf0e10cSrcweir     aAllTicks[0].realloc(nMaxMajorTickCount);
599*cdf0e10cSrcweir 
600*cdf0e10cSrcweir     sal_Int32 nRealMajorTickCount = 0;
601*cdf0e10cSrcweir     double* pValue = NULL;
602*cdf0e10cSrcweir     for( sal_Int32 nMajorTick=0; nMajorTick<nMaxMajorTickCount; nMajorTick++ )
603*cdf0e10cSrcweir     {
604*cdf0e10cSrcweir         pValue = this->getMajorTick( nMajorTick );
605*cdf0e10cSrcweir         if(!pValue)
606*cdf0e10cSrcweir             continue;
607*cdf0e10cSrcweir         aAllTicks[0][nRealMajorTickCount] = *pValue;
608*cdf0e10cSrcweir         nRealMajorTickCount++;
609*cdf0e10cSrcweir     }
610*cdf0e10cSrcweir     if(!nRealMajorTickCount)
611*cdf0e10cSrcweir         return;
612*cdf0e10cSrcweir     aAllTicks[0].realloc(nRealMajorTickCount);
613*cdf0e10cSrcweir 
614*cdf0e10cSrcweir     if(nDepthCount>0)
615*cdf0e10cSrcweir         this->addSubTicks( 1, aAllTicks );
616*cdf0e10cSrcweir 
617*cdf0e10cSrcweir     //so far we have added all ticks between the outer major tick marks
618*cdf0e10cSrcweir     //this was necessary to create sub ticks correctly
619*cdf0e10cSrcweir     //now we reduce all ticks to the visible ones that lie between the real borders
620*cdf0e10cSrcweir     sal_Int32 nDepth = 0;
621*cdf0e10cSrcweir     sal_Int32 nTick = 0;
622*cdf0e10cSrcweir     for( nDepth = 0; nDepth < nDepthCount; nDepth++)
623*cdf0e10cSrcweir     {
624*cdf0e10cSrcweir         sal_Int32 nInvisibleAtLowerBorder = 0;
625*cdf0e10cSrcweir         sal_Int32 nInvisibleAtUpperBorder = 0;
626*cdf0e10cSrcweir         //we need only to check all ticks within the first major interval at each border
627*cdf0e10cSrcweir         sal_Int32 nCheckCount = 1;
628*cdf0e10cSrcweir         for(sal_Int32 nN=0; nN<nDepth; nN++)
629*cdf0e10cSrcweir         {
630*cdf0e10cSrcweir             if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
631*cdf0e10cSrcweir                 nCheckCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
632*cdf0e10cSrcweir         }
633*cdf0e10cSrcweir         uno::Sequence< double >& rTicks = aAllTicks[nDepth];
634*cdf0e10cSrcweir         sal_Int32 nCount = rTicks.getLength();
635*cdf0e10cSrcweir         //check lower border
636*cdf0e10cSrcweir         for( nTick=0; nTick<nCheckCount && nTick<nCount; nTick++)
637*cdf0e10cSrcweir         {
638*cdf0e10cSrcweir             if( !isVisible( rTicks[nTick] ) )
639*cdf0e10cSrcweir                 nInvisibleAtLowerBorder++;
640*cdf0e10cSrcweir         }
641*cdf0e10cSrcweir         //check upper border
642*cdf0e10cSrcweir         for( nTick=nCount-1; nTick>nCount-1-nCheckCount && nTick>=0; nTick--)
643*cdf0e10cSrcweir         {
644*cdf0e10cSrcweir             if( !isVisible( rTicks[nTick] ) )
645*cdf0e10cSrcweir                 nInvisibleAtUpperBorder++;
646*cdf0e10cSrcweir         }
647*cdf0e10cSrcweir         //resize sequence
648*cdf0e10cSrcweir         if( !nInvisibleAtLowerBorder && !nInvisibleAtUpperBorder)
649*cdf0e10cSrcweir             continue;
650*cdf0e10cSrcweir         if( !nInvisibleAtLowerBorder )
651*cdf0e10cSrcweir             rTicks.realloc(nCount-nInvisibleAtUpperBorder);
652*cdf0e10cSrcweir         else
653*cdf0e10cSrcweir         {
654*cdf0e10cSrcweir             sal_Int32 nNewCount = nCount-nInvisibleAtUpperBorder-nInvisibleAtLowerBorder;
655*cdf0e10cSrcweir             if(nNewCount<0)
656*cdf0e10cSrcweir                 nNewCount=0;
657*cdf0e10cSrcweir 
658*cdf0e10cSrcweir             uno::Sequence< double > aOldTicks(rTicks);
659*cdf0e10cSrcweir             rTicks.realloc(nNewCount);
660*cdf0e10cSrcweir             for(nTick = 0; nTick<nNewCount; nTick++)
661*cdf0e10cSrcweir                 rTicks[nTick] = aOldTicks[nInvisibleAtLowerBorder+nTick];
662*cdf0e10cSrcweir         }
663*cdf0e10cSrcweir     }
664*cdf0e10cSrcweir 
665*cdf0e10cSrcweir     //fill return value
666*cdf0e10cSrcweir     rAllTickInfos.resize(aAllTicks.getLength());
667*cdf0e10cSrcweir     for( nDepth=0 ;nDepth<aAllTicks.getLength(); nDepth++ )
668*cdf0e10cSrcweir     {
669*cdf0e10cSrcweir         sal_Int32 nCount = aAllTicks[nDepth].getLength();
670*cdf0e10cSrcweir         rAllTickInfos[nDepth].resize( nCount );
671*cdf0e10cSrcweir         for(sal_Int32 nN = 0; nN<nCount; nN++)
672*cdf0e10cSrcweir         {
673*cdf0e10cSrcweir             rAllTickInfos[nDepth][nN].fScaledTickValue = aAllTicks[nDepth][nN];
674*cdf0e10cSrcweir         }
675*cdf0e10cSrcweir     }
676*cdf0e10cSrcweir }
677*cdf0e10cSrcweir 
678*cdf0e10cSrcweir void TickmarkHelper::getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
679*cdf0e10cSrcweir {
680*cdf0e10cSrcweir     std::auto_ptr< TickmarkHelper > apShiftedTickmarkHelper( createShiftedTickmarkHelper() );
681*cdf0e10cSrcweir     apShiftedTickmarkHelper->getAllTicks( rAllTickInfos );
682*cdf0e10cSrcweir }
683*cdf0e10cSrcweir 
684*cdf0e10cSrcweir void TickmarkHelper::addSubTicks( sal_Int32 nDepth, uno::Sequence< uno::Sequence< double > >& rParentTicks ) const
685*cdf0e10cSrcweir {
686*cdf0e10cSrcweir     EquidistantTickIter aIter( rParentTicks, m_rIncrement, 0, nDepth-1 );
687*cdf0e10cSrcweir     double* pfNextParentTick = aIter.firstValue();
688*cdf0e10cSrcweir     if(!pfNextParentTick)
689*cdf0e10cSrcweir         return;
690*cdf0e10cSrcweir     double fLastParentTick = *pfNextParentTick;
691*cdf0e10cSrcweir     pfNextParentTick = aIter.nextValue();
692*cdf0e10cSrcweir     if(!pfNextParentTick)
693*cdf0e10cSrcweir         return;
694*cdf0e10cSrcweir 
695*cdf0e10cSrcweir     sal_Int32 nMaxSubTickCount = this->getMaxTickCount( nDepth );
696*cdf0e10cSrcweir     if(!nMaxSubTickCount)
697*cdf0e10cSrcweir         return;
698*cdf0e10cSrcweir 
699*cdf0e10cSrcweir     uno::Sequence< double > aSubTicks(nMaxSubTickCount);
700*cdf0e10cSrcweir     sal_Int32 nRealSubTickCount = 0;
701*cdf0e10cSrcweir     sal_Int32 nIntervalCount = m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
702*cdf0e10cSrcweir 
703*cdf0e10cSrcweir     double* pValue = NULL;
704*cdf0e10cSrcweir     for(; pfNextParentTick; fLastParentTick=*pfNextParentTick, pfNextParentTick = aIter.nextValue())
705*cdf0e10cSrcweir     {
706*cdf0e10cSrcweir         for( sal_Int32 nPartTick = 1; nPartTick<nIntervalCount; nPartTick++ )
707*cdf0e10cSrcweir         {
708*cdf0e10cSrcweir             pValue = this->getMinorTick( nPartTick, nDepth
709*cdf0e10cSrcweir                         , fLastParentTick, *pfNextParentTick );
710*cdf0e10cSrcweir             if(!pValue)
711*cdf0e10cSrcweir                 continue;
712*cdf0e10cSrcweir 
713*cdf0e10cSrcweir             aSubTicks[nRealSubTickCount] = *pValue;
714*cdf0e10cSrcweir             nRealSubTickCount++;
715*cdf0e10cSrcweir         }
716*cdf0e10cSrcweir     }
717*cdf0e10cSrcweir 
718*cdf0e10cSrcweir     aSubTicks.realloc(nRealSubTickCount);
719*cdf0e10cSrcweir     rParentTicks[nDepth] = aSubTicks;
720*cdf0e10cSrcweir     if(m_rIncrement.SubIncrements.getLength()>nDepth)
721*cdf0e10cSrcweir         addSubTicks( nDepth+1, rParentTicks );
722*cdf0e10cSrcweir }
723*cdf0e10cSrcweir 
724*cdf0e10cSrcweir //-----------------------------------------------------------------------------
725*cdf0e10cSrcweir // ___TickmarkHelper_2D___
726*cdf0e10cSrcweir //-----------------------------------------------------------------------------
727*cdf0e10cSrcweir TickmarkHelper_2D::TickmarkHelper_2D(
728*cdf0e10cSrcweir           const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement
729*cdf0e10cSrcweir           //, double fStrech_SceneToScreen, double fOffset_SceneToScreen )
730*cdf0e10cSrcweir           , const B2DVector& rStartScreenPos, const B2DVector& rEndScreenPos
731*cdf0e10cSrcweir           , const B2DVector& rAxisLineToLabelLineShift )
732*cdf0e10cSrcweir           : TickmarkHelper( rScale, rIncrement )
733*cdf0e10cSrcweir           , m_aAxisStartScreenPosition2D(rStartScreenPos)
734*cdf0e10cSrcweir           , m_aAxisEndScreenPosition2D(rEndScreenPos)
735*cdf0e10cSrcweir           , m_aAxisLineToLabelLineShift(rAxisLineToLabelLineShift)
736*cdf0e10cSrcweir           , m_fStrech_LogicToScreen(1.0)
737*cdf0e10cSrcweir           , m_fOffset_LogicToScreen(0.0)
738*cdf0e10cSrcweir {
739*cdf0e10cSrcweir     double fWidthY = m_fScaledVisibleMax - m_fScaledVisibleMin;
740*cdf0e10cSrcweir     if( AxisOrientation_MATHEMATICAL==m_rScale.Orientation )
741*cdf0e10cSrcweir     {
742*cdf0e10cSrcweir         m_fStrech_LogicToScreen = 1.0/fWidthY;
743*cdf0e10cSrcweir         m_fOffset_LogicToScreen = -m_fScaledVisibleMin;
744*cdf0e10cSrcweir     }
745*cdf0e10cSrcweir     else
746*cdf0e10cSrcweir     {
747*cdf0e10cSrcweir         B2DVector aSwap(m_aAxisStartScreenPosition2D);
748*cdf0e10cSrcweir         m_aAxisStartScreenPosition2D = m_aAxisEndScreenPosition2D;
749*cdf0e10cSrcweir         m_aAxisEndScreenPosition2D = aSwap;
750*cdf0e10cSrcweir 
751*cdf0e10cSrcweir         m_fStrech_LogicToScreen = -1.0/fWidthY;
752*cdf0e10cSrcweir         m_fOffset_LogicToScreen = -m_fScaledVisibleMax;
753*cdf0e10cSrcweir     }
754*cdf0e10cSrcweir }
755*cdf0e10cSrcweir 
756*cdf0e10cSrcweir TickmarkHelper* TickmarkHelper_2D::createShiftedTickmarkHelper() const
757*cdf0e10cSrcweir {
758*cdf0e10cSrcweir     ExplicitIncrementData aShiftedIncrement( m_rIncrement );
759*cdf0e10cSrcweir     aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
760*cdf0e10cSrcweir 
761*cdf0e10cSrcweir     ::basegfx::B2DVector aStart( m_aAxisStartScreenPosition2D );
762*cdf0e10cSrcweir     ::basegfx::B2DVector aEnd( m_aAxisEndScreenPosition2D );
763*cdf0e10cSrcweir     if( AxisOrientation_MATHEMATICAL==m_rScale.Orientation )
764*cdf0e10cSrcweir         std::swap( aStart, aEnd );
765*cdf0e10cSrcweir 
766*cdf0e10cSrcweir     return new TickmarkHelper_2D( m_rScale, aShiftedIncrement, aStart, aEnd, m_aAxisLineToLabelLineShift );
767*cdf0e10cSrcweir }
768*cdf0e10cSrcweir 
769*cdf0e10cSrcweir TickmarkHelper_2D::~TickmarkHelper_2D()
770*cdf0e10cSrcweir {
771*cdf0e10cSrcweir }
772*cdf0e10cSrcweir 
773*cdf0e10cSrcweir bool TickmarkHelper_2D::isHorizontalAxis() const
774*cdf0e10cSrcweir {
775*cdf0e10cSrcweir     return ( m_aAxisStartScreenPosition2D.getY() == m_aAxisEndScreenPosition2D.getY() );
776*cdf0e10cSrcweir }
777*cdf0e10cSrcweir bool TickmarkHelper_2D::isVerticalAxis() const
778*cdf0e10cSrcweir {
779*cdf0e10cSrcweir     return ( m_aAxisStartScreenPosition2D.getX() == m_aAxisEndScreenPosition2D.getX() );
780*cdf0e10cSrcweir }
781*cdf0e10cSrcweir 
782*cdf0e10cSrcweir sal_Int32 TickmarkHelper_2D::getTickScreenDistance( TickIter& rIter )
783*cdf0e10cSrcweir {
784*cdf0e10cSrcweir     //return the positive distance between the two first tickmarks in screen values
785*cdf0e10cSrcweir     //if there are less than two tickmarks -1 is returned
786*cdf0e10cSrcweir 
787*cdf0e10cSrcweir     const TickInfo* pFirstTickInfo = rIter.firstInfo();
788*cdf0e10cSrcweir     const TickInfo* pSecondTickInfo = rIter.nextInfo();
789*cdf0e10cSrcweir     if(!pSecondTickInfo  || !pFirstTickInfo)
790*cdf0e10cSrcweir         return -1;
791*cdf0e10cSrcweir 
792*cdf0e10cSrcweir     return pFirstTickInfo->getScreenDistanceBetweenTicks( *pSecondTickInfo );
793*cdf0e10cSrcweir }
794*cdf0e10cSrcweir 
795*cdf0e10cSrcweir B2DVector TickmarkHelper_2D::getTickScreenPosition2D( double fScaledLogicTickValue ) const
796*cdf0e10cSrcweir {
797*cdf0e10cSrcweir     B2DVector aRet(m_aAxisStartScreenPosition2D);
798*cdf0e10cSrcweir     aRet += (m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D)
799*cdf0e10cSrcweir                 *((fScaledLogicTickValue+m_fOffset_LogicToScreen)*m_fStrech_LogicToScreen);
800*cdf0e10cSrcweir     return aRet;
801*cdf0e10cSrcweir }
802*cdf0e10cSrcweir 
803*cdf0e10cSrcweir void TickmarkHelper_2D::addPointSequenceForTickLine( drawing::PointSequenceSequence& rPoints
804*cdf0e10cSrcweir                                 , sal_Int32 nSequenceIndex
805*cdf0e10cSrcweir                                 , double fScaledLogicTickValue, double fInnerDirectionSign
806*cdf0e10cSrcweir                                 , const TickmarkProperties& rTickmarkProperties
807*cdf0e10cSrcweir                                 , bool bPlaceAtLabels ) const
808*cdf0e10cSrcweir {
809*cdf0e10cSrcweir     if( fInnerDirectionSign==0.0 )
810*cdf0e10cSrcweir         fInnerDirectionSign = 1.0;
811*cdf0e10cSrcweir 
812*cdf0e10cSrcweir     B2DVector aTickScreenPosition = this->getTickScreenPosition2D(fScaledLogicTickValue);
813*cdf0e10cSrcweir     if( bPlaceAtLabels )
814*cdf0e10cSrcweir         aTickScreenPosition += m_aAxisLineToLabelLineShift;
815*cdf0e10cSrcweir 
816*cdf0e10cSrcweir     B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D;
817*cdf0e10cSrcweir     aMainDirection.normalize();
818*cdf0e10cSrcweir     B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
819*cdf0e10cSrcweir     aOrthoDirection *= fInnerDirectionSign;
820*cdf0e10cSrcweir     aOrthoDirection.normalize();
821*cdf0e10cSrcweir 
822*cdf0e10cSrcweir     B2DVector aStart = aTickScreenPosition + aOrthoDirection*rTickmarkProperties.RelativePos;
823*cdf0e10cSrcweir     B2DVector aEnd = aStart - aOrthoDirection*rTickmarkProperties.Length;
824*cdf0e10cSrcweir 
825*cdf0e10cSrcweir     rPoints[nSequenceIndex].realloc(2);
826*cdf0e10cSrcweir     rPoints[nSequenceIndex][0].X = static_cast<sal_Int32>(aStart.getX());
827*cdf0e10cSrcweir     rPoints[nSequenceIndex][0].Y = static_cast<sal_Int32>(aStart.getY());
828*cdf0e10cSrcweir     rPoints[nSequenceIndex][1].X = static_cast<sal_Int32>(aEnd.getX());
829*cdf0e10cSrcweir     rPoints[nSequenceIndex][1].Y = static_cast<sal_Int32>(aEnd.getY());
830*cdf0e10cSrcweir }
831*cdf0e10cSrcweir 
832*cdf0e10cSrcweir B2DVector TickmarkHelper_2D::getDistanceAxisTickToText( const AxisProperties& rAxisProperties, bool bIncludeFarAwayDistanceIfSo, bool bIncludeSpaceBetweenTickAndText ) const
833*cdf0e10cSrcweir {
834*cdf0e10cSrcweir     bool bFarAwayLabels = false;
835*cdf0e10cSrcweir     if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_START == rAxisProperties.m_eLabelPos
836*cdf0e10cSrcweir         || ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END == rAxisProperties.m_eLabelPos )
837*cdf0e10cSrcweir         bFarAwayLabels = true;
838*cdf0e10cSrcweir 
839*cdf0e10cSrcweir     double fInnerDirectionSign = rAxisProperties.m_fInnerDirectionSign;
840*cdf0e10cSrcweir     if( fInnerDirectionSign==0.0 )
841*cdf0e10cSrcweir         fInnerDirectionSign = 1.0;
842*cdf0e10cSrcweir 
843*cdf0e10cSrcweir     B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D;
844*cdf0e10cSrcweir     aMainDirection.normalize();
845*cdf0e10cSrcweir     B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
846*cdf0e10cSrcweir     aOrthoDirection *= fInnerDirectionSign;
847*cdf0e10cSrcweir     aOrthoDirection.normalize();
848*cdf0e10cSrcweir 
849*cdf0e10cSrcweir     B2DVector aStart(0,0), aEnd(0,0);
850*cdf0e10cSrcweir     if( bFarAwayLabels )
851*cdf0e10cSrcweir     {
852*cdf0e10cSrcweir         TickmarkProperties aProps( AxisProperties::getBiggestTickmarkProperties() );
853*cdf0e10cSrcweir         aStart = aOrthoDirection*aProps.RelativePos;
854*cdf0e10cSrcweir         aEnd = aStart - aOrthoDirection*aProps.Length;
855*cdf0e10cSrcweir     }
856*cdf0e10cSrcweir     else
857*cdf0e10cSrcweir     {
858*cdf0e10cSrcweir         for( sal_Int32 nN=rAxisProperties.m_aTickmarkPropertiesList.size();nN--;)
859*cdf0e10cSrcweir         {
860*cdf0e10cSrcweir             const TickmarkProperties& rProps = rAxisProperties.m_aTickmarkPropertiesList[nN];
861*cdf0e10cSrcweir             B2DVector aNewStart = aOrthoDirection*rProps.RelativePos;
862*cdf0e10cSrcweir             B2DVector aNewEnd = aNewStart - aOrthoDirection*rProps.Length;
863*cdf0e10cSrcweir             if(aNewStart.getLength()>aStart.getLength())
864*cdf0e10cSrcweir                 aStart=aNewStart;
865*cdf0e10cSrcweir             if(aNewEnd.getLength()>aEnd.getLength())
866*cdf0e10cSrcweir                 aEnd=aNewEnd;
867*cdf0e10cSrcweir         }
868*cdf0e10cSrcweir     }
869*cdf0e10cSrcweir 
870*cdf0e10cSrcweir     B2DVector aLabelDirection(aStart);
871*cdf0e10cSrcweir     if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign )
872*cdf0e10cSrcweir         aLabelDirection = aEnd;
873*cdf0e10cSrcweir 
874*cdf0e10cSrcweir     B2DVector aOrthoLabelDirection(aOrthoDirection);
875*cdf0e10cSrcweir     if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign )
876*cdf0e10cSrcweir         aOrthoLabelDirection*=-1.0;
877*cdf0e10cSrcweir     aOrthoLabelDirection.normalize();
878*cdf0e10cSrcweir     if( bIncludeSpaceBetweenTickAndText )
879*cdf0e10cSrcweir         aLabelDirection += aOrthoLabelDirection*AXIS2D_TICKLABELSPACING;
880*cdf0e10cSrcweir     if( bFarAwayLabels && bIncludeFarAwayDistanceIfSo )
881*cdf0e10cSrcweir         aLabelDirection += m_aAxisLineToLabelLineShift;
882*cdf0e10cSrcweir     return aLabelDirection;
883*cdf0e10cSrcweir }
884*cdf0e10cSrcweir 
885*cdf0e10cSrcweir void TickmarkHelper_2D::createPointSequenceForAxisMainLine( drawing::PointSequenceSequence& rPoints ) const
886*cdf0e10cSrcweir {
887*cdf0e10cSrcweir     rPoints[0].realloc(2);
888*cdf0e10cSrcweir     rPoints[0][0].X = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getX());
889*cdf0e10cSrcweir     rPoints[0][0].Y = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getY());
890*cdf0e10cSrcweir     rPoints[0][1].X = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getX());
891*cdf0e10cSrcweir     rPoints[0][1].Y = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getY());
892*cdf0e10cSrcweir }
893*cdf0e10cSrcweir 
894*cdf0e10cSrcweir void TickmarkHelper_2D::updateScreenValues( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
895*cdf0e10cSrcweir {
896*cdf0e10cSrcweir     //get the transformed screen values for all tickmarks in rAllTickInfos
897*cdf0e10cSrcweir     ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter       = rAllTickInfos.begin();
898*cdf0e10cSrcweir     const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd  = rAllTickInfos.end();
899*cdf0e10cSrcweir     for( ; aDepthIter != aDepthEnd; aDepthIter++ )
900*cdf0e10cSrcweir     {
901*cdf0e10cSrcweir         ::std::vector< TickInfo >::iterator       aTickIter = (*aDepthIter).begin();
902*cdf0e10cSrcweir         const ::std::vector< TickInfo >::const_iterator aTickEnd  = (*aDepthIter).end();
903*cdf0e10cSrcweir         for( ; aTickIter != aTickEnd; aTickIter++ )
904*cdf0e10cSrcweir         {
905*cdf0e10cSrcweir             TickInfo& rTickInfo = (*aTickIter);
906*cdf0e10cSrcweir             rTickInfo.aTickScreenPosition =
907*cdf0e10cSrcweir                 this->getTickScreenPosition2D( rTickInfo.fScaledTickValue );
908*cdf0e10cSrcweir         }
909*cdf0e10cSrcweir     }
910*cdf0e10cSrcweir }
911*cdf0e10cSrcweir 
912*cdf0e10cSrcweir //-----------------------------------------------------------------------------
913*cdf0e10cSrcweir // ___TickmarkHelper_3D___
914*cdf0e10cSrcweir //-----------------------------------------------------------------------------
915*cdf0e10cSrcweir TickmarkHelper_3D::TickmarkHelper_3D(
916*cdf0e10cSrcweir           const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement )
917*cdf0e10cSrcweir           : TickmarkHelper( rScale, rIncrement )
918*cdf0e10cSrcweir {
919*cdf0e10cSrcweir }
920*cdf0e10cSrcweir 
921*cdf0e10cSrcweir TickmarkHelper* TickmarkHelper_3D::createShiftedTickmarkHelper() const
922*cdf0e10cSrcweir {
923*cdf0e10cSrcweir     ExplicitIncrementData aShiftedIncrement( m_rIncrement );
924*cdf0e10cSrcweir     aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
925*cdf0e10cSrcweir     return new TickmarkHelper_3D( m_rScale, aShiftedIncrement );
926*cdf0e10cSrcweir }
927*cdf0e10cSrcweir 
928*cdf0e10cSrcweir TickmarkHelper_3D::~TickmarkHelper_3D()
929*cdf0e10cSrcweir {
930*cdf0e10cSrcweir }
931*cdf0e10cSrcweir 
932*cdf0e10cSrcweir //.............................................................................
933*cdf0e10cSrcweir } //namespace chart
934*cdf0e10cSrcweir //.............................................................................
935