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