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