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