tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / chart2 / source / view / axes / Tickmarks_Equidistant.cxx
blob663d4581984273d8d046614711c543a2bbda1930
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "Tickmarks_Equidistant.hxx"
21 #include <rtl/math.hxx>
22 #include <osl/diagnose.h>
23 #include <float.h>
25 #include <limits>
26 #include <utility>
28 namespace chart
30 using namespace ::com::sun::star;
31 using namespace ::com::sun::star::chart2;
32 using namespace ::rtl::math;
34 //static
35 double EquidistantTickFactory::getMinimumAtIncrement( double fMin, const ExplicitIncrementData& rIncrement )
37 //the returned value will be <= fMin and on a Major Tick given by rIncrement
38 if(rIncrement.Distance<=0.0)
39 return fMin;
41 double fRet = rIncrement.BaseValue +
42 floor( approxSub( fMin, rIncrement.BaseValue )
43 / rIncrement.Distance)
44 *rIncrement.Distance;
46 if( fRet > fMin )
48 if( !approxEqual(fRet, fMin) )
49 fRet -= rIncrement.Distance;
51 return fRet;
53 //static
54 double EquidistantTickFactory::getMaximumAtIncrement( double fMax, const ExplicitIncrementData& rIncrement )
56 //the returned value will be >= fMax and on a Major Tick given by rIncrement
57 if(rIncrement.Distance<=0.0)
58 return fMax;
60 double fRet = rIncrement.BaseValue +
61 floor( approxSub( fMax, rIncrement.BaseValue )
62 / rIncrement.Distance)
63 *rIncrement.Distance;
65 if( fRet < fMax )
67 if( !approxEqual(fRet, fMax) )
68 fRet += rIncrement.Distance;
70 return fRet;
73 EquidistantTickFactory::EquidistantTickFactory(
74 ExplicitScaleData aScale, ExplicitIncrementData aIncrement )
75 : m_rScale(std::move( aScale ))
76 , m_rIncrement(std::move( aIncrement ))
78 //@todo: make sure that the scale is valid for the scaling
80 m_pfCurrentValues.reset( new double[getTickDepth()] );
82 if( m_rScale.Scaling.is() )
84 m_xInverseScaling = m_rScale.Scaling->getInverseScaling();
85 OSL_ENSURE( m_xInverseScaling.is(), "each Scaling needs to return an inverse Scaling" );
88 double fMin = m_fScaledVisibleMin = m_rScale.Minimum;
89 if( m_xInverseScaling.is() )
91 m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin);
92 if(m_rIncrement.PostEquidistant )
93 fMin = m_fScaledVisibleMin;
96 double fMax = m_fScaledVisibleMax = m_rScale.Maximum;
97 if( m_xInverseScaling.is() )
99 m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax);
100 if(m_rIncrement.PostEquidistant )
101 fMax = m_fScaledVisibleMax;
104 m_fOuterMajorTickBorderMin = EquidistantTickFactory::getMinimumAtIncrement( fMin, m_rIncrement );
105 m_fOuterMajorTickBorderMax = EquidistantTickFactory::getMaximumAtIncrement( fMax, m_rIncrement );
107 m_fOuterMajorTickBorderMin_Scaled = m_fOuterMajorTickBorderMin;
108 m_fOuterMajorTickBorderMax_Scaled = m_fOuterMajorTickBorderMax;
109 if(m_rIncrement.PostEquidistant || !m_xInverseScaling.is())
110 return;
112 m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
113 m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
115 //check validity of new range: m_fOuterMajorTickBorderMin <-> m_fOuterMajorTickBorderMax
116 //it is assumed here, that the original range in the given Scale is valid
117 if( !std::isfinite(m_fOuterMajorTickBorderMin_Scaled) )
119 m_fOuterMajorTickBorderMin += m_rIncrement.Distance;
120 m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
122 if( !std::isfinite(m_fOuterMajorTickBorderMax_Scaled) )
124 m_fOuterMajorTickBorderMax -= m_rIncrement.Distance;
125 m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
129 EquidistantTickFactory::~EquidistantTickFactory()
133 sal_Int32 EquidistantTickFactory::getTickDepth() const
135 return static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) + 1;
138 void EquidistantTickFactory::addSubTicks( sal_Int32 nDepth, uno::Sequence< uno::Sequence< double > >& rParentTicks ) const
140 EquidistantTickIter aIter( rParentTicks, m_rIncrement, nDepth-1 );
141 double* pfNextParentTick = aIter.firstValue();
142 if(!pfNextParentTick)
143 return;
144 double fLastParentTick = *pfNextParentTick;
145 pfNextParentTick = aIter.nextValue();
146 if(!pfNextParentTick)
147 return;
149 sal_Int32 nMaxSubTickCount = getMaxTickCount( nDepth );
150 if(!nMaxSubTickCount)
151 return;
153 uno::Sequence< double > aSubTicks(nMaxSubTickCount);
154 auto pSubTicks = aSubTicks.getArray();
155 sal_Int32 nRealSubTickCount = 0;
156 sal_Int32 nIntervalCount = m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
158 double* pValue = nullptr;
159 for(; pfNextParentTick; fLastParentTick=*pfNextParentTick, pfNextParentTick = aIter.nextValue())
161 for( sal_Int32 nPartTick = 1; nPartTick<nIntervalCount; nPartTick++ )
163 pValue = getMinorTick( nPartTick, nDepth
164 , fLastParentTick, *pfNextParentTick );
165 if(!pValue)
166 continue;
168 pSubTicks[nRealSubTickCount] = *pValue;
169 nRealSubTickCount++;
173 aSubTicks.realloc(nRealSubTickCount);
174 rParentTicks.getArray()[nDepth] = std::move(aSubTicks);
175 if(static_cast<sal_Int32>(m_rIncrement.SubIncrements.size())>nDepth)
176 addSubTicks( nDepth+1, rParentTicks );
179 sal_Int32 EquidistantTickFactory::getMaxTickCount( sal_Int32 nDepth ) const
181 //return the maximum amount of ticks
182 //possibly open intervals at the two ends of the region are handled as if they were completely visible
183 //(this is necessary for calculating the sub ticks at the borders correctly)
185 if( nDepth >= getTickDepth() )
186 return 0;
187 if( m_fOuterMajorTickBorderMax < m_fOuterMajorTickBorderMin )
188 return 0;
189 if( m_rIncrement.Distance<=0.0)
190 return 0;
192 double fSub;
193 if(m_rIncrement.PostEquidistant )
194 fSub = approxSub( m_fScaledVisibleMax, m_fScaledVisibleMin );
195 else
196 fSub = approxSub( m_rScale.Maximum, m_rScale.Minimum );
198 if (!std::isfinite(fSub))
199 return 0;
201 double fIntervalCount = fSub / m_rIncrement.Distance;
202 if (fIntervalCount > std::numeric_limits<sal_Int32>::max())
203 // Interval count too high! Bail out.
204 return 0;
206 sal_Int32 nIntervalCount = static_cast<sal_Int32>(fIntervalCount);
208 nIntervalCount+=3;
209 for(sal_Int32 nN=0; nN<nDepth-1; nN++)
211 if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
212 nIntervalCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
215 sal_Int32 nTickCount = nIntervalCount;
216 if(nDepth>0 && m_rIncrement.SubIncrements[nDepth-1].IntervalCount>1)
217 nTickCount = nIntervalCount * (m_rIncrement.SubIncrements[nDepth-1].IntervalCount-1);
219 return nTickCount;
222 double* EquidistantTickFactory::getMajorTick( sal_Int32 nTick ) const
224 m_pfCurrentValues[0] = m_fOuterMajorTickBorderMin + nTick*m_rIncrement.Distance;
226 if(m_pfCurrentValues[0]>m_fOuterMajorTickBorderMax)
228 if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMax) )
229 return nullptr;
231 if(m_pfCurrentValues[0]<m_fOuterMajorTickBorderMin)
233 if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMin) )
234 return nullptr;
237 //return always the value after scaling
238 if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
239 m_pfCurrentValues[0] = m_rScale.Scaling->doScaling( m_pfCurrentValues[0] );
241 return &m_pfCurrentValues[0];
244 double* EquidistantTickFactory::getMinorTick( sal_Int32 nTick, sal_Int32 nDepth
245 , double fStartParentTick, double fNextParentTick ) const
247 //check validity of arguments
249 //OSL_ENSURE( fStartParentTick < fNextParentTick, "fStartParentTick >= fNextParentTick");
250 if(fStartParentTick >= fNextParentTick)
251 return nullptr;
252 if(nDepth>static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) || nDepth<=0)
253 return nullptr;
255 //subticks are only calculated if they are laying between parent ticks:
256 if(nTick<=0)
257 return nullptr;
258 if(nTick>=m_rIncrement.SubIncrements[nDepth-1].IntervalCount)
259 return nullptr;
262 bool bPostEquidistant = m_rIncrement.SubIncrements[nDepth-1].PostEquidistant;
264 double fAdaptedStartParent = fStartParentTick;
265 double fAdaptedNextParent = fNextParentTick;
267 if( !bPostEquidistant && m_xInverseScaling.is() )
269 fAdaptedStartParent = m_xInverseScaling->doScaling(fStartParentTick);
270 fAdaptedNextParent = m_xInverseScaling->doScaling(fNextParentTick);
273 double fDistance = (fAdaptedNextParent - fAdaptedStartParent)/m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
275 m_pfCurrentValues[nDepth] = fAdaptedStartParent + nTick*fDistance;
277 //return always the value after scaling
278 if(!bPostEquidistant && m_xInverseScaling.is() )
279 m_pfCurrentValues[nDepth] = m_rScale.Scaling->doScaling( m_pfCurrentValues[nDepth] );
281 if( !isWithinOuterBorder( m_pfCurrentValues[nDepth] ) )
282 return nullptr;
284 return &m_pfCurrentValues[nDepth];
287 bool EquidistantTickFactory::isWithinOuterBorder( double fScaledValue ) const
289 if(fScaledValue>m_fOuterMajorTickBorderMax_Scaled)
290 return false;
291 if(fScaledValue<m_fOuterMajorTickBorderMin_Scaled)
292 return false;
294 return true;
297 bool EquidistantTickFactory::isVisible( double fScaledValue ) const
299 if(fScaledValue>m_fScaledVisibleMax)
301 if( !approxEqual(fScaledValue,m_fScaledVisibleMax) )
302 return false;
304 if(fScaledValue<m_fScaledVisibleMin)
306 if( !approxEqual(fScaledValue,m_fScaledVisibleMin) )
307 return false;
309 return true;
312 void EquidistantTickFactory::getAllTicks( TickInfoArraysType& rAllTickInfos ) const
314 //create point sequences for each tick depth
315 const sal_Int32 nDepthCount = getTickDepth();
316 const sal_Int32 nMaxMajorTickCount = getMaxTickCount(0);
318 if (nDepthCount <= 0 || nMaxMajorTickCount <= 0)
319 return;
321 uno::Sequence< uno::Sequence< double > > aAllTicks(nDepthCount);
322 auto pAllTicks = aAllTicks.getArray();
323 pAllTicks[0].realloc(nMaxMajorTickCount);
324 auto pAllTicks0 = pAllTicks[0].getArray();
326 sal_Int32 nRealMajorTickCount = 0;
327 for( sal_Int32 nMajorTick=0; nMajorTick<nMaxMajorTickCount; nMajorTick++ )
329 double* pValue = getMajorTick( nMajorTick );
330 if(!pValue)
331 continue;
332 pAllTicks0[nRealMajorTickCount] = *pValue;
333 nRealMajorTickCount++;
335 if(!nRealMajorTickCount)
336 return;
337 pAllTicks[0].realloc(nRealMajorTickCount);
339 addSubTicks(1, aAllTicks);
341 //so far we have added all ticks between the outer major tick marks
342 //this was necessary to create sub ticks correctly
343 //now we reduce all ticks to the visible ones that lie between the real borders
344 sal_Int32 nDepth = 0;
345 sal_Int32 nTick = 0;
346 for( nDepth = 0; nDepth < nDepthCount; nDepth++)
348 sal_Int32 nInvisibleAtLowerBorder = 0;
349 sal_Int32 nInvisibleAtUpperBorder = 0;
350 //we need only to check all ticks within the first major interval at each border
351 sal_Int32 nCheckCount = 1;
352 for(sal_Int32 nN=0; nN<nDepth; nN++)
354 if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
355 nCheckCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
357 uno::Sequence< double >& rTicks = pAllTicks[nDepth];
358 sal_Int32 nCount = rTicks.getLength();
359 //check lower border
360 for( nTick=0; nTick<nCheckCount && nTick<nCount; nTick++)
362 if( !isVisible( rTicks[nTick] ) )
363 nInvisibleAtLowerBorder++;
365 //check upper border
366 for( nTick=nCount-1; nTick>nCount-1-nCheckCount && nTick>=0; nTick--)
368 if( !isVisible( rTicks[nTick] ) )
369 nInvisibleAtUpperBorder++;
371 //resize sequence
372 if( !nInvisibleAtLowerBorder && !nInvisibleAtUpperBorder)
373 continue;
374 if( !nInvisibleAtLowerBorder )
375 rTicks.realloc(nCount-nInvisibleAtUpperBorder);
376 else
378 sal_Int32 nNewCount = nCount-nInvisibleAtUpperBorder-nInvisibleAtLowerBorder;
379 if(nNewCount<0)
380 nNewCount=0;
382 uno::Sequence< double > aOldTicks(rTicks);
383 rTicks.realloc(nNewCount);
384 auto pTicks = rTicks.getArray();
385 for(nTick = 0; nTick<nNewCount; nTick++)
386 pTicks[nTick] = aOldTicks[nInvisibleAtLowerBorder+nTick];
390 //fill return value
391 rAllTickInfos.resize(aAllTicks.getLength());
392 for( nDepth=0 ;nDepth<aAllTicks.getLength(); nDepth++ )
394 sal_Int32 nCount = aAllTicks[nDepth].getLength();
396 TickInfoArrayType& rTickInfoVector = rAllTickInfos[nDepth];
397 rTickInfoVector.clear();
398 rTickInfoVector.reserve( nCount );
399 for(sal_Int32 nN = 0; nN<nCount; nN++)
401 TickInfo aTickInfo(m_xInverseScaling);
402 aTickInfo.fScaledTickValue = aAllTicks[nDepth][nN];
403 rTickInfoVector.push_back(aTickInfo);
408 void EquidistantTickFactory::getAllTicksShifted( TickInfoArraysType& rAllTickInfos ) const
410 ExplicitIncrementData aShiftedIncrement( m_rIncrement );
411 aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
412 EquidistantTickFactory( m_rScale, std::move(aShiftedIncrement) ).getAllTicks(rAllTickInfos);
415 EquidistantTickIter::EquidistantTickIter( const uno::Sequence< uno::Sequence< double > >& rTicks
416 , const ExplicitIncrementData& rIncrement
417 , sal_Int32 nMaxDepth )
418 : m_pSimpleTicks(&rTicks)
419 , m_pInfoTicks(nullptr)
420 , m_rIncrement(rIncrement)
421 , m_nMaxDepth(0)
422 , m_nTickCount(0)
423 , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
425 initIter( nMaxDepth );
428 EquidistantTickIter::EquidistantTickIter( TickInfoArraysType& rTicks
429 , const ExplicitIncrementData& rIncrement
430 , sal_Int32 nMaxDepth )
431 : m_pSimpleTicks(nullptr)
432 , m_pInfoTicks(&rTicks)
433 , m_rIncrement(rIncrement)
434 , m_nMaxDepth(0)
435 , m_nTickCount(0)
436 , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
438 initIter( nMaxDepth );
441 void EquidistantTickIter::initIter( sal_Int32 nMaxDepth )
443 m_nMaxDepth = nMaxDepth;
444 if(nMaxDepth<0 || m_nMaxDepth>getMaxDepth())
445 m_nMaxDepth=getMaxDepth();
447 sal_Int32 nDepth = 0;
448 for( nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
449 m_nTickCount += getTickCount(nDepth);
451 if(!m_nTickCount)
452 return;
454 m_pnPositions.reset( new sal_Int32[m_nMaxDepth+1] );
456 m_pnPreParentCount.reset( new sal_Int32[m_nMaxDepth+1] );
457 m_pbIntervalFinished.reset( new bool[m_nMaxDepth+1] );
458 m_pnPreParentCount[0] = 0;
459 m_pbIntervalFinished[0] = false;
460 double fParentValue = getTickValue(0,0);
461 for( nDepth = 1; nDepth<=m_nMaxDepth ;nDepth++ )
463 m_pbIntervalFinished[nDepth] = false;
465 sal_Int32 nPreParentCount = 0;
466 sal_Int32 nCount = getTickCount(nDepth);
467 for(sal_Int32 nN = 0; nN<nCount; nN++)
469 if(getTickValue(nDepth,nN) < fParentValue)
470 nPreParentCount++;
471 else
472 break;
474 m_pnPreParentCount[nDepth] = nPreParentCount;
475 if(nCount)
477 double fNextParentValue = getTickValue(nDepth,0);
478 if( fNextParentValue < fParentValue )
479 fParentValue = fNextParentValue;
484 EquidistantTickIter::~EquidistantTickIter()
488 sal_Int32 EquidistantTickIter::getStartDepth() const
490 //find the depth of the first visible tickmark:
491 //it is the depth of the smallest value
492 sal_Int32 nReturnDepth=0;
493 double fMinValue = DBL_MAX;
494 for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
496 sal_Int32 nCount = getTickCount(nDepth);
497 if( !nCount )
498 continue;
499 double fThisValue = getTickValue(nDepth,0);
500 if(fThisValue<fMinValue)
502 nReturnDepth = nDepth;
503 fMinValue = fThisValue;
506 return nReturnDepth;
509 double* EquidistantTickIter::firstValue()
511 if( gotoFirst() )
513 m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
514 return &m_fCurrentValue;
516 return nullptr;
519 TickInfo* EquidistantTickIter::firstInfo()
521 if( m_pInfoTicks && gotoFirst() )
522 return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
523 return nullptr;
526 sal_Int32 EquidistantTickIter::getIntervalCount( sal_Int32 nDepth )
528 if(nDepth>static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) || nDepth<0)
529 return 0;
531 if(!nDepth)
532 return m_nTickCount;
534 return m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
537 bool EquidistantTickIter::isAtLastPartTick()
539 if(!m_nCurrentDepth)
540 return false;
541 sal_Int32 nIntervalCount = getIntervalCount( m_nCurrentDepth );
542 if(!nIntervalCount || nIntervalCount == 1)
543 return true;
544 if( m_pbIntervalFinished[m_nCurrentDepth] )
545 return false;
546 sal_Int32 nPos = m_pnPositions[m_nCurrentDepth]+1;
547 if(m_pnPreParentCount[m_nCurrentDepth])
548 nPos += nIntervalCount-1 - m_pnPreParentCount[m_nCurrentDepth];
549 bool bRet = nPos && nPos % (nIntervalCount-1) == 0;
550 if(!nPos && !m_pnPreParentCount[m_nCurrentDepth]
551 && m_pnPositions[m_nCurrentDepth-1]==-1 )
552 bRet = true;
553 return bRet;
556 bool EquidistantTickIter::gotoFirst()
558 if( m_nMaxDepth<0 )
559 return false;
560 if( !m_nTickCount )
561 return false;
563 for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
564 m_pnPositions[nDepth] = -1;
566 m_nCurrentPos = 0;
567 m_nCurrentDepth = getStartDepth();
568 m_pnPositions[m_nCurrentDepth] = 0;
569 return true;
572 bool EquidistantTickIter::gotoNext()
574 if( m_nCurrentPos < 0 )
575 return false;
576 m_nCurrentPos++;
578 if( m_nCurrentPos >= m_nTickCount )
579 return false;
581 if( m_nCurrentDepth==m_nMaxDepth && isAtLastPartTick() )
585 m_pbIntervalFinished[m_nCurrentDepth] = true;
586 m_nCurrentDepth--;
588 while( m_nCurrentDepth && isAtLastPartTick() );
590 else if( m_nCurrentDepth<m_nMaxDepth )
594 m_nCurrentDepth++;
596 while( m_nCurrentDepth<m_nMaxDepth );
598 m_pbIntervalFinished[m_nCurrentDepth] = false;
599 m_pnPositions[m_nCurrentDepth] = m_pnPositions[m_nCurrentDepth]+1;
600 return true;
603 double* EquidistantTickIter::nextValue()
605 if( gotoNext() )
607 m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
608 return &m_fCurrentValue;
610 return nullptr;
613 TickInfo* EquidistantTickIter::nextInfo()
615 if( m_pInfoTicks && gotoNext() &&
616 static_cast< sal_Int32 >(
617 (*m_pInfoTicks)[m_nCurrentDepth].size()) > m_pnPositions[m_nCurrentDepth] )
619 return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
621 return nullptr;
624 } //namespace chart
626 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */