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 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 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 59 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 70 PureTickIter::PureTickIter( ::std::vector< TickInfo >& rTickInfoVector ) 71 : m_rTickVector(rTickInfoVector) 72 , m_aTickIter(m_rTickVector.begin()) 73 { 74 } 75 PureTickIter::~PureTickIter() 76 { 77 } 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 } 85 TickInfo* PureTickIter::nextInfo() 86 { 87 m_aTickIter++; 88 if(m_aTickIter!=m_rTickVector.end()) 89 return &*m_aTickIter; 90 return 0; 91 } 92 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 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 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 164 EquidistantTickIter::~EquidistantTickIter() 165 { 166 delete[] m_pnPositions; 167 delete[] m_pnPreParentCount; 168 delete[] m_pbIntervalFinished; 169 } 170 171 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 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 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 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 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 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 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 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 304 sal_Int32 EquidistantTickIter::getCurrentIndex() const 305 { 306 return m_nCurrentPos; 307 } 308 sal_Int32 EquidistantTickIter::getMaxIndex() const 309 { 310 return m_nTickCount-1; 311 } 312 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 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 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 } 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 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 439 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 446 TickmarkHelper::~TickmarkHelper() 447 { 448 delete[] m_pfCurrentValues; 449 } 450 451 sal_Int32 TickmarkHelper::getTickDepth() const 452 { 453 return m_rIncrement.SubIncrements.getLength() + 1; 454 } 455 456 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 494 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 516 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 559 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 570 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 585 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 674 void TickmarkHelper::getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const 675 { 676 std::auto_ptr< TickmarkHelper > apShiftedTickmarkHelper( createShiftedTickmarkHelper() ); 677 apShiftedTickmarkHelper->getAllTicks( rAllTickInfos ); 678 } 679 680 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 //----------------------------------------------------------------------------- 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 752 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 765 TickmarkHelper_2D::~TickmarkHelper_2D() 766 { 767 } 768 769 bool TickmarkHelper_2D::isHorizontalAxis() const 770 { 771 return ( m_aAxisStartScreenPosition2D.getY() == m_aAxisEndScreenPosition2D.getY() ); 772 } 773 bool TickmarkHelper_2D::isVerticalAxis() const 774 { 775 return ( m_aAxisStartScreenPosition2D.getX() == m_aAxisEndScreenPosition2D.getX() ); 776 } 777 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 791 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 799 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 828 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 881 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 890 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 //----------------------------------------------------------------------------- 911 TickmarkHelper_3D::TickmarkHelper_3D( 912 const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement ) 913 : TickmarkHelper( rScale, rIncrement ) 914 { 915 } 916 917 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 924 TickmarkHelper_3D::~TickmarkHelper_3D() 925 { 926 } 927 928 //............................................................................. 929 } //namespace chart 930 //............................................................................. 931