1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_chart2.hxx" 30*cdf0e10cSrcweir #include "ScaleAutomatism.hxx" 31*cdf0e10cSrcweir #include "macros.hxx" 32*cdf0e10cSrcweir #include "Tickmarks_Equidistant.hxx" 33*cdf0e10cSrcweir #include "DateHelper.hxx" 34*cdf0e10cSrcweir #include "DateScaling.hxx" 35*cdf0e10cSrcweir #include "AxisHelper.hxx" 36*cdf0e10cSrcweir #include <com/sun/star/chart/TimeUnit.hpp> 37*cdf0e10cSrcweir 38*cdf0e10cSrcweir #include <rtl/math.hxx> 39*cdf0e10cSrcweir #include <tools/debug.hxx> 40*cdf0e10cSrcweir 41*cdf0e10cSrcweir //............................................................................. 42*cdf0e10cSrcweir namespace chart 43*cdf0e10cSrcweir { 44*cdf0e10cSrcweir //............................................................................. 45*cdf0e10cSrcweir using namespace ::com::sun::star; 46*cdf0e10cSrcweir using namespace ::com::sun::star::chart2; 47*cdf0e10cSrcweir using ::com::sun::star::chart::TimeUnit::DAY; 48*cdf0e10cSrcweir using ::com::sun::star::chart::TimeUnit::MONTH; 49*cdf0e10cSrcweir using ::com::sun::star::chart::TimeUnit::YEAR; 50*cdf0e10cSrcweir 51*cdf0e10cSrcweir const sal_Int32 MAXIMUM_MANUAL_INCREMENT_COUNT = 500; 52*cdf0e10cSrcweir const sal_Int32 MAXIMUM_SUB_INCREMENT_COUNT = 100; 53*cdf0e10cSrcweir 54*cdf0e10cSrcweir sal_Int32 lcl_getMaximumAutoIncrementCount( sal_Int32 nAxisType ) 55*cdf0e10cSrcweir { 56*cdf0e10cSrcweir sal_Int32 nMaximumAutoIncrementCount = 10; 57*cdf0e10cSrcweir if( nAxisType==AxisType::DATE ) 58*cdf0e10cSrcweir nMaximumAutoIncrementCount = MAXIMUM_MANUAL_INCREMENT_COUNT; 59*cdf0e10cSrcweir return nMaximumAutoIncrementCount; 60*cdf0e10cSrcweir } 61*cdf0e10cSrcweir 62*cdf0e10cSrcweir namespace 63*cdf0e10cSrcweir { 64*cdf0e10cSrcweir 65*cdf0e10cSrcweir void lcl_ensureMaximumSubIncrementCount( sal_Int32& rnSubIntervalCount ) 66*cdf0e10cSrcweir { 67*cdf0e10cSrcweir if( rnSubIntervalCount > MAXIMUM_SUB_INCREMENT_COUNT ) 68*cdf0e10cSrcweir rnSubIntervalCount = MAXIMUM_SUB_INCREMENT_COUNT; 69*cdf0e10cSrcweir } 70*cdf0e10cSrcweir 71*cdf0e10cSrcweir }//end anonymous namespace 72*cdf0e10cSrcweir 73*cdf0e10cSrcweir 74*cdf0e10cSrcweir //............................................................................. 75*cdf0e10cSrcweir 76*cdf0e10cSrcweir ExplicitScaleData::ExplicitScaleData() 77*cdf0e10cSrcweir : Minimum(0.0) 78*cdf0e10cSrcweir , Maximum(10.0) 79*cdf0e10cSrcweir , Origin(0.0) 80*cdf0e10cSrcweir , Orientation(::com::sun::star::chart2::AxisOrientation_MATHEMATICAL) 81*cdf0e10cSrcweir , Scaling() 82*cdf0e10cSrcweir , AxisType(::com::sun::star::chart2::AxisType::REALNUMBER) 83*cdf0e10cSrcweir , ShiftedCategoryPosition(false) 84*cdf0e10cSrcweir , TimeResolution(::com::sun::star::chart::TimeUnit::DAY) 85*cdf0e10cSrcweir , NullDate(30,12,1899) 86*cdf0e10cSrcweir { 87*cdf0e10cSrcweir } 88*cdf0e10cSrcweir 89*cdf0e10cSrcweir ExplicitSubIncrement::ExplicitSubIncrement() 90*cdf0e10cSrcweir : IntervalCount(2) 91*cdf0e10cSrcweir , PostEquidistant(true) 92*cdf0e10cSrcweir { 93*cdf0e10cSrcweir } 94*cdf0e10cSrcweir 95*cdf0e10cSrcweir 96*cdf0e10cSrcweir ExplicitIncrementData::ExplicitIncrementData() 97*cdf0e10cSrcweir : MajorTimeInterval(1,::com::sun::star::chart::TimeUnit::DAY) 98*cdf0e10cSrcweir , MinorTimeInterval(1,::com::sun::star::chart::TimeUnit::DAY) 99*cdf0e10cSrcweir , Distance(1.0) 100*cdf0e10cSrcweir , PostEquidistant(true) 101*cdf0e10cSrcweir , BaseValue(0.0) 102*cdf0e10cSrcweir , SubIncrements() 103*cdf0e10cSrcweir { 104*cdf0e10cSrcweir } 105*cdf0e10cSrcweir 106*cdf0e10cSrcweir //............................................................................. 107*cdf0e10cSrcweir 108*cdf0e10cSrcweir ScaleAutomatism::ScaleAutomatism( const ScaleData& rSourceScale, const Date& rNullDate ) 109*cdf0e10cSrcweir : m_aSourceScale( rSourceScale ) 110*cdf0e10cSrcweir , m_fValueMinimum( 0.0 ) 111*cdf0e10cSrcweir , m_fValueMaximum( 0.0 ) 112*cdf0e10cSrcweir , m_nMaximumAutoMainIncrementCount( lcl_getMaximumAutoIncrementCount( rSourceScale.AxisType ) ) 113*cdf0e10cSrcweir , m_bExpandBorderToIncrementRhythm( false ) 114*cdf0e10cSrcweir , m_bExpandIfValuesCloseToBorder( false ) 115*cdf0e10cSrcweir , m_bExpandWideValuesToZero( false ) 116*cdf0e10cSrcweir , m_bExpandNarrowValuesTowardZero( false ) 117*cdf0e10cSrcweir , m_nTimeResolution(::com::sun::star::chart::TimeUnit::DAY) 118*cdf0e10cSrcweir , m_aNullDate(rNullDate) 119*cdf0e10cSrcweir { 120*cdf0e10cSrcweir ::rtl::math::setNan( &m_fValueMinimum ); 121*cdf0e10cSrcweir ::rtl::math::setNan( &m_fValueMaximum ); 122*cdf0e10cSrcweir 123*cdf0e10cSrcweir double fExplicitOrigin = 0.0; 124*cdf0e10cSrcweir if( m_aSourceScale.Origin >>= fExplicitOrigin ) 125*cdf0e10cSrcweir expandValueRange( fExplicitOrigin, fExplicitOrigin); 126*cdf0e10cSrcweir } 127*cdf0e10cSrcweir ScaleAutomatism::~ScaleAutomatism() 128*cdf0e10cSrcweir { 129*cdf0e10cSrcweir } 130*cdf0e10cSrcweir 131*cdf0e10cSrcweir void ScaleAutomatism::expandValueRange( double fMinimum, double fMaximum ) 132*cdf0e10cSrcweir { 133*cdf0e10cSrcweir if( (fMinimum < m_fValueMinimum) || ::rtl::math::isNan( m_fValueMinimum ) ) 134*cdf0e10cSrcweir m_fValueMinimum = fMinimum; 135*cdf0e10cSrcweir if( (fMaximum > m_fValueMaximum) || ::rtl::math::isNan( m_fValueMaximum ) ) 136*cdf0e10cSrcweir m_fValueMaximum = fMaximum; 137*cdf0e10cSrcweir } 138*cdf0e10cSrcweir 139*cdf0e10cSrcweir void ScaleAutomatism::setAutoScalingOptions( 140*cdf0e10cSrcweir bool bExpandBorderToIncrementRhythm, 141*cdf0e10cSrcweir bool bExpandIfValuesCloseToBorder, 142*cdf0e10cSrcweir bool bExpandWideValuesToZero, 143*cdf0e10cSrcweir bool bExpandNarrowValuesTowardZero ) 144*cdf0e10cSrcweir { 145*cdf0e10cSrcweir // if called multiple times, enable an option, if it is set in at least one call 146*cdf0e10cSrcweir m_bExpandBorderToIncrementRhythm |= bExpandBorderToIncrementRhythm; 147*cdf0e10cSrcweir m_bExpandIfValuesCloseToBorder |= bExpandIfValuesCloseToBorder; 148*cdf0e10cSrcweir m_bExpandWideValuesToZero |= bExpandWideValuesToZero; 149*cdf0e10cSrcweir m_bExpandNarrowValuesTowardZero |= bExpandNarrowValuesTowardZero; 150*cdf0e10cSrcweir 151*cdf0e10cSrcweir if( m_aSourceScale.AxisType==AxisType::PERCENT ) 152*cdf0e10cSrcweir m_bExpandIfValuesCloseToBorder = false; 153*cdf0e10cSrcweir } 154*cdf0e10cSrcweir 155*cdf0e10cSrcweir void ScaleAutomatism::setMaximumAutoMainIncrementCount( sal_Int32 nMaximumAutoMainIncrementCount ) 156*cdf0e10cSrcweir { 157*cdf0e10cSrcweir if( nMaximumAutoMainIncrementCount < 2 ) 158*cdf0e10cSrcweir m_nMaximumAutoMainIncrementCount = 2; //#i82006 159*cdf0e10cSrcweir else if( nMaximumAutoMainIncrementCount > lcl_getMaximumAutoIncrementCount( m_aSourceScale.AxisType ) ) 160*cdf0e10cSrcweir m_nMaximumAutoMainIncrementCount = lcl_getMaximumAutoIncrementCount( m_aSourceScale.AxisType ); 161*cdf0e10cSrcweir else 162*cdf0e10cSrcweir m_nMaximumAutoMainIncrementCount = nMaximumAutoMainIncrementCount; 163*cdf0e10cSrcweir } 164*cdf0e10cSrcweir 165*cdf0e10cSrcweir void ScaleAutomatism::setAutomaticTimeResolution( sal_Int32 nTimeResolution ) 166*cdf0e10cSrcweir { 167*cdf0e10cSrcweir m_nTimeResolution = nTimeResolution; 168*cdf0e10cSrcweir } 169*cdf0e10cSrcweir 170*cdf0e10cSrcweir void ScaleAutomatism::calculateExplicitScaleAndIncrement( 171*cdf0e10cSrcweir ExplicitScaleData& rExplicitScale, ExplicitIncrementData& rExplicitIncrement ) const 172*cdf0e10cSrcweir { 173*cdf0e10cSrcweir // fill explicit scale 174*cdf0e10cSrcweir rExplicitScale.Orientation = m_aSourceScale.Orientation; 175*cdf0e10cSrcweir rExplicitScale.Scaling = m_aSourceScale.Scaling; 176*cdf0e10cSrcweir rExplicitScale.AxisType = m_aSourceScale.AxisType; 177*cdf0e10cSrcweir rExplicitScale.NullDate = m_aNullDate; 178*cdf0e10cSrcweir 179*cdf0e10cSrcweir bool bAutoMinimum = !(m_aSourceScale.Minimum >>= rExplicitScale.Minimum); 180*cdf0e10cSrcweir bool bAutoMaximum = !(m_aSourceScale.Maximum >>= rExplicitScale.Maximum); 181*cdf0e10cSrcweir bool bAutoOrigin = !(m_aSourceScale.Origin >>= rExplicitScale.Origin); 182*cdf0e10cSrcweir 183*cdf0e10cSrcweir // automatic scale minimum 184*cdf0e10cSrcweir if( bAutoMinimum ) 185*cdf0e10cSrcweir { 186*cdf0e10cSrcweir if( m_aSourceScale.AxisType==AxisType::PERCENT ) 187*cdf0e10cSrcweir rExplicitScale.Minimum = 0.0; 188*cdf0e10cSrcweir else if( ::rtl::math::isNan( m_fValueMinimum ) ) 189*cdf0e10cSrcweir { 190*cdf0e10cSrcweir if( m_aSourceScale.AxisType==AxisType::DATE ) 191*cdf0e10cSrcweir rExplicitScale.Minimum = 36526.0; //1.1.2000 192*cdf0e10cSrcweir else 193*cdf0e10cSrcweir rExplicitScale.Minimum = 0.0; //@todo get Minimum from scaling or from plotter???? 194*cdf0e10cSrcweir } 195*cdf0e10cSrcweir else 196*cdf0e10cSrcweir rExplicitScale.Minimum = m_fValueMinimum; 197*cdf0e10cSrcweir } 198*cdf0e10cSrcweir 199*cdf0e10cSrcweir // automatic scale maximum 200*cdf0e10cSrcweir if( bAutoMaximum ) 201*cdf0e10cSrcweir { 202*cdf0e10cSrcweir if( m_aSourceScale.AxisType==AxisType::PERCENT ) 203*cdf0e10cSrcweir rExplicitScale.Maximum = 1.0; 204*cdf0e10cSrcweir else if( ::rtl::math::isNan( m_fValueMaximum ) ) 205*cdf0e10cSrcweir { 206*cdf0e10cSrcweir if( m_aSourceScale.AxisType==AxisType::DATE ) 207*cdf0e10cSrcweir rExplicitScale.Maximum = 40179.0; //1.1.2010 208*cdf0e10cSrcweir else 209*cdf0e10cSrcweir rExplicitScale.Maximum = 10.0; //@todo get Maximum from scaling or from plotter???? 210*cdf0e10cSrcweir } 211*cdf0e10cSrcweir else 212*cdf0e10cSrcweir rExplicitScale.Maximum = m_fValueMaximum; 213*cdf0e10cSrcweir } 214*cdf0e10cSrcweir 215*cdf0e10cSrcweir //--------------------------------------------------------------- 216*cdf0e10cSrcweir //fill explicit increment 217*cdf0e10cSrcweir 218*cdf0e10cSrcweir rExplicitScale.ShiftedCategoryPosition = m_aSourceScale.ShiftedCategoryPosition; 219*cdf0e10cSrcweir bool bIsLogarithm = false; 220*cdf0e10cSrcweir 221*cdf0e10cSrcweir //minimum and maximum of the ExplicitScaleData may be changed if allowed 222*cdf0e10cSrcweir if( m_aSourceScale.AxisType==AxisType::DATE ) 223*cdf0e10cSrcweir calculateExplicitIncrementAndScaleForDateTimeAxis( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum ); 224*cdf0e10cSrcweir else if( m_aSourceScale.AxisType==AxisType::CATEGORY || m_aSourceScale.AxisType==AxisType::SERIES ) 225*cdf0e10cSrcweir calculateExplicitIncrementAndScaleForCategory( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum ); 226*cdf0e10cSrcweir else 227*cdf0e10cSrcweir { 228*cdf0e10cSrcweir bIsLogarithm = AxisHelper::isLogarithmic( rExplicitScale.Scaling ); 229*cdf0e10cSrcweir if( bIsLogarithm ) 230*cdf0e10cSrcweir calculateExplicitIncrementAndScaleForLogarithmic( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum ); 231*cdf0e10cSrcweir else 232*cdf0e10cSrcweir calculateExplicitIncrementAndScaleForLinear( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum ); 233*cdf0e10cSrcweir } 234*cdf0e10cSrcweir 235*cdf0e10cSrcweir // automatic origin 236*cdf0e10cSrcweir if( bAutoOrigin ) 237*cdf0e10cSrcweir { 238*cdf0e10cSrcweir // #i71415# automatic origin for logarithmic axis 239*cdf0e10cSrcweir double fDefaulOrigin = bIsLogarithm ? 1.0 : 0.0; 240*cdf0e10cSrcweir 241*cdf0e10cSrcweir if( fDefaulOrigin < rExplicitScale.Minimum ) 242*cdf0e10cSrcweir fDefaulOrigin = rExplicitScale.Minimum; 243*cdf0e10cSrcweir else if( fDefaulOrigin > rExplicitScale.Maximum ) 244*cdf0e10cSrcweir fDefaulOrigin = rExplicitScale.Maximum; 245*cdf0e10cSrcweir 246*cdf0e10cSrcweir rExplicitScale.Origin = fDefaulOrigin; 247*cdf0e10cSrcweir } 248*cdf0e10cSrcweir } 249*cdf0e10cSrcweir 250*cdf0e10cSrcweir ScaleData ScaleAutomatism::getScale() const 251*cdf0e10cSrcweir { 252*cdf0e10cSrcweir return m_aSourceScale; 253*cdf0e10cSrcweir } 254*cdf0e10cSrcweir 255*cdf0e10cSrcweir Date ScaleAutomatism::getNullDate() const 256*cdf0e10cSrcweir { 257*cdf0e10cSrcweir return m_aNullDate; 258*cdf0e10cSrcweir } 259*cdf0e10cSrcweir 260*cdf0e10cSrcweir // private -------------------------------------------------------------------- 261*cdf0e10cSrcweir 262*cdf0e10cSrcweir void ScaleAutomatism::calculateExplicitIncrementAndScaleForCategory( 263*cdf0e10cSrcweir ExplicitScaleData& rExplicitScale, 264*cdf0e10cSrcweir ExplicitIncrementData& rExplicitIncrement, 265*cdf0e10cSrcweir bool bAutoMinimum, bool bAutoMaximum ) const 266*cdf0e10cSrcweir { 267*cdf0e10cSrcweir // no scaling for categories 268*cdf0e10cSrcweir rExplicitScale.Scaling.clear(); 269*cdf0e10cSrcweir 270*cdf0e10cSrcweir if( rExplicitScale.ShiftedCategoryPosition ) 271*cdf0e10cSrcweir rExplicitScale.Maximum += 1.0; 272*cdf0e10cSrcweir 273*cdf0e10cSrcweir // ensure that at least one category is visible 274*cdf0e10cSrcweir if( rExplicitScale.Maximum <= rExplicitScale.Minimum ) 275*cdf0e10cSrcweir rExplicitScale.Maximum = rExplicitScale.Minimum + 1.0; 276*cdf0e10cSrcweir 277*cdf0e10cSrcweir // default increment settings 278*cdf0e10cSrcweir rExplicitIncrement.PostEquidistant = sal_True; // does not matter anyhow 279*cdf0e10cSrcweir rExplicitIncrement.Distance = 1.0; // category axis always have a main increment of 1 280*cdf0e10cSrcweir rExplicitIncrement.BaseValue = 0.0; // category axis always have a base of 0 281*cdf0e10cSrcweir 282*cdf0e10cSrcweir // automatic minimum and maximum 283*cdf0e10cSrcweir if( bAutoMinimum && m_bExpandBorderToIncrementRhythm ) 284*cdf0e10cSrcweir rExplicitScale.Minimum = EquidistantTickFactory::getMinimumAtIncrement( rExplicitScale.Minimum, rExplicitIncrement ); 285*cdf0e10cSrcweir if( bAutoMaximum && m_bExpandBorderToIncrementRhythm ) 286*cdf0e10cSrcweir rExplicitScale.Maximum = EquidistantTickFactory::getMaximumAtIncrement( rExplicitScale.Maximum, rExplicitIncrement ); 287*cdf0e10cSrcweir 288*cdf0e10cSrcweir //prevent performace killover 289*cdf0e10cSrcweir double fDistanceCount = ::rtl::math::approxFloor( (rExplicitScale.Maximum-rExplicitScale.Minimum) / rExplicitIncrement.Distance ); 290*cdf0e10cSrcweir if( static_cast< sal_Int32 >( fDistanceCount ) > MAXIMUM_MANUAL_INCREMENT_COUNT ) 291*cdf0e10cSrcweir { 292*cdf0e10cSrcweir double fMinimumFloor = ::rtl::math::approxFloor( rExplicitScale.Minimum ); 293*cdf0e10cSrcweir double fMaximumCeil = ::rtl::math::approxCeil( rExplicitScale.Maximum ); 294*cdf0e10cSrcweir rExplicitIncrement.Distance = ::rtl::math::approxCeil( (fMaximumCeil - fMinimumFloor) / MAXIMUM_MANUAL_INCREMENT_COUNT ); 295*cdf0e10cSrcweir } 296*cdf0e10cSrcweir 297*cdf0e10cSrcweir //--------------------------------------------------------------- 298*cdf0e10cSrcweir //fill explicit sub increment 299*cdf0e10cSrcweir sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength(); 300*cdf0e10cSrcweir for( sal_Int32 nN=0; nN<nSubCount; nN++ ) 301*cdf0e10cSrcweir { 302*cdf0e10cSrcweir ExplicitSubIncrement aExplicitSubIncrement; 303*cdf0e10cSrcweir const SubIncrement& rSubIncrement= m_aSourceScale.IncrementData.SubIncrements[nN]; 304*cdf0e10cSrcweir if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount)) 305*cdf0e10cSrcweir { 306*cdf0e10cSrcweir //scaling dependent 307*cdf0e10cSrcweir //@todo autocalculate IntervalCount dependent on MainIncrement and scaling 308*cdf0e10cSrcweir aExplicitSubIncrement.IntervalCount = 2; 309*cdf0e10cSrcweir } 310*cdf0e10cSrcweir lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount ); 311*cdf0e10cSrcweir if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant)) 312*cdf0e10cSrcweir { 313*cdf0e10cSrcweir //scaling dependent 314*cdf0e10cSrcweir aExplicitSubIncrement.PostEquidistant = sal_False; 315*cdf0e10cSrcweir } 316*cdf0e10cSrcweir rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement); 317*cdf0e10cSrcweir } 318*cdf0e10cSrcweir } 319*cdf0e10cSrcweir 320*cdf0e10cSrcweir //----------------------------------------------------------------------------------------- 321*cdf0e10cSrcweir 322*cdf0e10cSrcweir void ScaleAutomatism::calculateExplicitIncrementAndScaleForLogarithmic( 323*cdf0e10cSrcweir ExplicitScaleData& rExplicitScale, 324*cdf0e10cSrcweir ExplicitIncrementData& rExplicitIncrement, 325*cdf0e10cSrcweir bool bAutoMinimum, bool bAutoMaximum ) const 326*cdf0e10cSrcweir { 327*cdf0e10cSrcweir // *** STEP 1: initialize the range data *** 328*cdf0e10cSrcweir 329*cdf0e10cSrcweir const double fInputMinimum = rExplicitScale.Minimum; 330*cdf0e10cSrcweir const double fInputMaximum = rExplicitScale.Maximum; 331*cdf0e10cSrcweir 332*cdf0e10cSrcweir double fSourceMinimum = rExplicitScale.Minimum; 333*cdf0e10cSrcweir double fSourceMaximum = rExplicitScale.Maximum; 334*cdf0e10cSrcweir 335*cdf0e10cSrcweir // set automatic PostEquidistant to true (maybe scaling dependent?) 336*cdf0e10cSrcweir // Note: scaling with PostEquidistant==false is untested and needs review 337*cdf0e10cSrcweir if( !(m_aSourceScale.IncrementData.PostEquidistant >>= rExplicitIncrement.PostEquidistant) ) 338*cdf0e10cSrcweir rExplicitIncrement.PostEquidistant = sal_True; 339*cdf0e10cSrcweir 340*cdf0e10cSrcweir /* All following scaling code will operate on the logarithms of the source 341*cdf0e10cSrcweir values. In the last step, the original values will be restored. */ 342*cdf0e10cSrcweir uno::Reference< XScaling > xScaling = rExplicitScale.Scaling; 343*cdf0e10cSrcweir if( !xScaling.is() ) 344*cdf0e10cSrcweir xScaling.set( AxisHelper::createLogarithmicScaling() ); 345*cdf0e10cSrcweir uno::Reference< XScaling > xInverseScaling = xScaling->getInverseScaling(); 346*cdf0e10cSrcweir 347*cdf0e10cSrcweir fSourceMinimum = xScaling->doScaling( fSourceMinimum ); 348*cdf0e10cSrcweir if( !::rtl::math::isFinite( fSourceMinimum ) ) 349*cdf0e10cSrcweir fSourceMinimum = 0.0; 350*cdf0e10cSrcweir else if( ::rtl::math::approxEqual( fSourceMinimum, ::rtl::math::approxFloor( fSourceMinimum ) ) ) 351*cdf0e10cSrcweir fSourceMinimum = ::rtl::math::approxFloor( fSourceMinimum ); 352*cdf0e10cSrcweir 353*cdf0e10cSrcweir fSourceMaximum = xScaling->doScaling( fSourceMaximum ); 354*cdf0e10cSrcweir if( !::rtl::math::isFinite( fSourceMaximum ) ) 355*cdf0e10cSrcweir fSourceMaximum = 0.0; 356*cdf0e10cSrcweir else if( ::rtl::math::approxEqual( fSourceMaximum, ::rtl::math::approxFloor( fSourceMaximum ) ) ) 357*cdf0e10cSrcweir fSourceMaximum = ::rtl::math::approxFloor( fSourceMaximum ); 358*cdf0e10cSrcweir 359*cdf0e10cSrcweir /* If range is invalid (minimum greater than maximum), change one of the 360*cdf0e10cSrcweir variable limits to validate the range. In this step, a zero-sized range 361*cdf0e10cSrcweir is still allowed. */ 362*cdf0e10cSrcweir if( fSourceMinimum > fSourceMaximum ) 363*cdf0e10cSrcweir { 364*cdf0e10cSrcweir // force changing the maximum, if both limits are fixed 365*cdf0e10cSrcweir if( bAutoMaximum || !bAutoMinimum ) 366*cdf0e10cSrcweir fSourceMaximum = fSourceMinimum; 367*cdf0e10cSrcweir else 368*cdf0e10cSrcweir fSourceMinimum = fSourceMaximum; 369*cdf0e10cSrcweir } 370*cdf0e10cSrcweir 371*cdf0e10cSrcweir /* If maximum is less than 0 (and therefore minimum too), minimum and 372*cdf0e10cSrcweir maximum will be negated and swapped to make the following algorithms 373*cdf0e10cSrcweir easier. Example: Both ranges [2,5] and [-5,-2] will be processed as 374*cdf0e10cSrcweir [2,5], and the latter will be swapped back later. The range [0,0] is 375*cdf0e10cSrcweir explicitly excluded from swapping (this would result in [-1,0] instead 376*cdf0e10cSrcweir of the expected [0,1]). */ 377*cdf0e10cSrcweir bool bSwapAndNegateRange = (fSourceMinimum < 0.0) && (fSourceMaximum <= 0.0); 378*cdf0e10cSrcweir if( bSwapAndNegateRange ) 379*cdf0e10cSrcweir { 380*cdf0e10cSrcweir double fTempValue = fSourceMinimum; 381*cdf0e10cSrcweir fSourceMinimum = -fSourceMaximum; 382*cdf0e10cSrcweir fSourceMaximum = -fTempValue; 383*cdf0e10cSrcweir ::std::swap( bAutoMinimum, bAutoMaximum ); 384*cdf0e10cSrcweir } 385*cdf0e10cSrcweir 386*cdf0e10cSrcweir // *** STEP 2: find temporary (unrounded) axis minimum and maximum *** 387*cdf0e10cSrcweir 388*cdf0e10cSrcweir double fTempMinimum = fSourceMinimum; 389*cdf0e10cSrcweir double fTempMaximum = fSourceMaximum; 390*cdf0e10cSrcweir 391*cdf0e10cSrcweir /* If minimum is variable and greater than 0 (and therefore maximum too), 392*cdf0e10cSrcweir means all original values are greater than 1 (or all values are less 393*cdf0e10cSrcweir than 1, and the range has been swapped above), then: */ 394*cdf0e10cSrcweir if( bAutoMinimum && (fTempMinimum > 0.0) ) 395*cdf0e10cSrcweir { 396*cdf0e10cSrcweir /* If minimum is less than 5 (i.e. original source values less than 397*cdf0e10cSrcweir B^5, B being the base of the scaling), or if minimum and maximum 398*cdf0e10cSrcweir are in different increment intervals (means, if minimum and maximum 399*cdf0e10cSrcweir are not both in the range [B^n,B^(n+1)] for a whole number n), set 400*cdf0e10cSrcweir minimum to 0, which results in B^0=1 on the axis. */ 401*cdf0e10cSrcweir double fMinimumFloor = ::rtl::math::approxFloor( fTempMinimum ); 402*cdf0e10cSrcweir double fMaximumFloor = ::rtl::math::approxFloor( fTempMaximum ); 403*cdf0e10cSrcweir // handle the exact value B^(n+1) to be in the range [B^n,B^(n+1)] 404*cdf0e10cSrcweir if( ::rtl::math::approxEqual( fTempMaximum, fMaximumFloor ) ) 405*cdf0e10cSrcweir fMaximumFloor -= 1.0; 406*cdf0e10cSrcweir 407*cdf0e10cSrcweir if( (fMinimumFloor < 5.0) || (fMinimumFloor < fMaximumFloor) ) 408*cdf0e10cSrcweir { 409*cdf0e10cSrcweir if( m_bExpandWideValuesToZero ) 410*cdf0e10cSrcweir fTempMinimum = 0.0; 411*cdf0e10cSrcweir } 412*cdf0e10cSrcweir /* Else (minimum and maximum are in one increment interval), expand 413*cdf0e10cSrcweir minimum toward 0 to make the 'shorter' data points visible. */ 414*cdf0e10cSrcweir else 415*cdf0e10cSrcweir { 416*cdf0e10cSrcweir if( m_bExpandNarrowValuesTowardZero ) 417*cdf0e10cSrcweir fTempMinimum -= 1.0; 418*cdf0e10cSrcweir } 419*cdf0e10cSrcweir } 420*cdf0e10cSrcweir 421*cdf0e10cSrcweir /* If range is still zero-sized (e.g. when minimum is fixed), set minimum 422*cdf0e10cSrcweir to 0, which makes the axis start/stop at the value 1. */ 423*cdf0e10cSrcweir if( fTempMinimum == fTempMaximum ) 424*cdf0e10cSrcweir { 425*cdf0e10cSrcweir if( bAutoMinimum && (fTempMaximum > 0.0) ) 426*cdf0e10cSrcweir fTempMinimum = 0.0; 427*cdf0e10cSrcweir else 428*cdf0e10cSrcweir fTempMaximum += 1.0; // always add one interval, even if maximum is fixed 429*cdf0e10cSrcweir } 430*cdf0e10cSrcweir 431*cdf0e10cSrcweir // *** STEP 3: calculate main interval size *** 432*cdf0e10cSrcweir 433*cdf0e10cSrcweir // base value (anchor position of the intervals), already scaled 434*cdf0e10cSrcweir if( !(m_aSourceScale.IncrementData.BaseValue >>= rExplicitIncrement.BaseValue) ) 435*cdf0e10cSrcweir { 436*cdf0e10cSrcweir //scaling dependent 437*cdf0e10cSrcweir //@maybe todo is this default also plotter dependent ?? 438*cdf0e10cSrcweir if( !bAutoMinimum ) 439*cdf0e10cSrcweir rExplicitIncrement.BaseValue = fTempMinimum; 440*cdf0e10cSrcweir else if( !bAutoMaximum ) 441*cdf0e10cSrcweir rExplicitIncrement.BaseValue = fTempMaximum; 442*cdf0e10cSrcweir else 443*cdf0e10cSrcweir rExplicitIncrement.BaseValue = 0.0; 444*cdf0e10cSrcweir } 445*cdf0e10cSrcweir 446*cdf0e10cSrcweir // calculate automatic interval 447*cdf0e10cSrcweir bool bAutoDistance = !(m_aSourceScale.IncrementData.Distance >>= rExplicitIncrement.Distance); 448*cdf0e10cSrcweir if( bAutoDistance ) 449*cdf0e10cSrcweir rExplicitIncrement.Distance = 0.0; 450*cdf0e10cSrcweir 451*cdf0e10cSrcweir /* Restrict number of allowed intervals with user-defined distance to 452*cdf0e10cSrcweir MAXIMUM_MANUAL_INCREMENT_COUNT. */ 453*cdf0e10cSrcweir sal_Int32 nMaxMainIncrementCount = bAutoDistance ? 454*cdf0e10cSrcweir m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT; 455*cdf0e10cSrcweir 456*cdf0e10cSrcweir // repeat calculation until number of intervals are valid 457*cdf0e10cSrcweir bool bNeedIteration = true; 458*cdf0e10cSrcweir bool bHasCalculatedDistance = false; 459*cdf0e10cSrcweir while( bNeedIteration ) 460*cdf0e10cSrcweir { 461*cdf0e10cSrcweir if( bAutoDistance ) 462*cdf0e10cSrcweir { 463*cdf0e10cSrcweir // first iteration: calculate interval size from axis limits 464*cdf0e10cSrcweir if( !bHasCalculatedDistance ) 465*cdf0e10cSrcweir { 466*cdf0e10cSrcweir double fMinimumFloor = ::rtl::math::approxFloor( fTempMinimum ); 467*cdf0e10cSrcweir double fMaximumCeil = ::rtl::math::approxCeil( fTempMaximum ); 468*cdf0e10cSrcweir rExplicitIncrement.Distance = ::rtl::math::approxCeil( (fMaximumCeil - fMinimumFloor) / nMaxMainIncrementCount ); 469*cdf0e10cSrcweir } 470*cdf0e10cSrcweir else 471*cdf0e10cSrcweir { 472*cdf0e10cSrcweir // following iterations: increase distance 473*cdf0e10cSrcweir rExplicitIncrement.Distance += 1.0; 474*cdf0e10cSrcweir } 475*cdf0e10cSrcweir 476*cdf0e10cSrcweir // for next iteration: distance calculated -> use else path to increase 477*cdf0e10cSrcweir bHasCalculatedDistance = true; 478*cdf0e10cSrcweir } 479*cdf0e10cSrcweir 480*cdf0e10cSrcweir // *** STEP 4: additional space above or below the data points *** 481*cdf0e10cSrcweir 482*cdf0e10cSrcweir double fAxisMinimum = fTempMinimum; 483*cdf0e10cSrcweir double fAxisMaximum = fTempMaximum; 484*cdf0e10cSrcweir 485*cdf0e10cSrcweir // round to entire multiples of the distance and add additional space 486*cdf0e10cSrcweir if( bAutoMinimum && m_bExpandBorderToIncrementRhythm ) 487*cdf0e10cSrcweir { 488*cdf0e10cSrcweir fAxisMinimum = EquidistantTickFactory::getMinimumAtIncrement( fAxisMinimum, rExplicitIncrement ); 489*cdf0e10cSrcweir 490*cdf0e10cSrcweir //ensure valid values after scaling #i100995# 491*cdf0e10cSrcweir if( !bAutoDistance ) 492*cdf0e10cSrcweir { 493*cdf0e10cSrcweir double fCheck = xInverseScaling->doScaling( fAxisMinimum ); 494*cdf0e10cSrcweir if( !::rtl::math::isFinite( fCheck ) || fCheck <= 0 ) 495*cdf0e10cSrcweir { 496*cdf0e10cSrcweir bAutoDistance = true; 497*cdf0e10cSrcweir bHasCalculatedDistance = false; 498*cdf0e10cSrcweir continue; 499*cdf0e10cSrcweir } 500*cdf0e10cSrcweir } 501*cdf0e10cSrcweir } 502*cdf0e10cSrcweir if( bAutoMaximum && m_bExpandBorderToIncrementRhythm ) 503*cdf0e10cSrcweir { 504*cdf0e10cSrcweir fAxisMaximum = EquidistantTickFactory::getMaximumAtIncrement( fAxisMaximum, rExplicitIncrement ); 505*cdf0e10cSrcweir 506*cdf0e10cSrcweir //ensure valid values after scaling #i100995# 507*cdf0e10cSrcweir if( !bAutoDistance ) 508*cdf0e10cSrcweir { 509*cdf0e10cSrcweir double fCheck = xInverseScaling->doScaling( fAxisMaximum ); 510*cdf0e10cSrcweir if( !::rtl::math::isFinite( fCheck ) || fCheck <= 0 ) 511*cdf0e10cSrcweir { 512*cdf0e10cSrcweir bAutoDistance = true; 513*cdf0e10cSrcweir bHasCalculatedDistance = false; 514*cdf0e10cSrcweir continue; 515*cdf0e10cSrcweir } 516*cdf0e10cSrcweir } 517*cdf0e10cSrcweir } 518*cdf0e10cSrcweir 519*cdf0e10cSrcweir // set the resulting limits (swap back to negative range if needed) 520*cdf0e10cSrcweir if( bSwapAndNegateRange ) 521*cdf0e10cSrcweir { 522*cdf0e10cSrcweir rExplicitScale.Minimum = -fAxisMaximum; 523*cdf0e10cSrcweir rExplicitScale.Maximum = -fAxisMinimum; 524*cdf0e10cSrcweir } 525*cdf0e10cSrcweir else 526*cdf0e10cSrcweir { 527*cdf0e10cSrcweir rExplicitScale.Minimum = fAxisMinimum; 528*cdf0e10cSrcweir rExplicitScale.Maximum = fAxisMaximum; 529*cdf0e10cSrcweir } 530*cdf0e10cSrcweir 531*cdf0e10cSrcweir /* If the number of intervals is too high (e.g. due to invalid fixed 532*cdf0e10cSrcweir distance or due to added space above or below data points), 533*cdf0e10cSrcweir calculate again with increased distance. */ 534*cdf0e10cSrcweir double fDistanceCount = ::rtl::math::approxFloor( (fAxisMaximum - fAxisMinimum) / rExplicitIncrement.Distance ); 535*cdf0e10cSrcweir bNeedIteration = static_cast< sal_Int32 >( fDistanceCount ) > nMaxMainIncrementCount; 536*cdf0e10cSrcweir // if manual distance is invalid, trigger automatic calculation 537*cdf0e10cSrcweir if( bNeedIteration ) 538*cdf0e10cSrcweir bAutoDistance = true; 539*cdf0e10cSrcweir 540*cdf0e10cSrcweir // convert limits back to logarithmic scale 541*cdf0e10cSrcweir rExplicitScale.Minimum = xInverseScaling->doScaling( rExplicitScale.Minimum ); 542*cdf0e10cSrcweir rExplicitScale.Maximum = xInverseScaling->doScaling( rExplicitScale.Maximum ); 543*cdf0e10cSrcweir 544*cdf0e10cSrcweir //ensure valid values after scaling #i100995# 545*cdf0e10cSrcweir if( !::rtl::math::isFinite( rExplicitScale.Minimum ) || rExplicitScale.Minimum <= 0) 546*cdf0e10cSrcweir { 547*cdf0e10cSrcweir rExplicitScale.Minimum = fInputMinimum; 548*cdf0e10cSrcweir if( !::rtl::math::isFinite( rExplicitScale.Minimum ) || rExplicitScale.Minimum <= 0 ) 549*cdf0e10cSrcweir rExplicitScale.Minimum = 1.0; 550*cdf0e10cSrcweir } 551*cdf0e10cSrcweir if( !::rtl::math::isFinite( rExplicitScale.Maximum) || rExplicitScale.Maximum <= 0 ) 552*cdf0e10cSrcweir { 553*cdf0e10cSrcweir rExplicitScale.Maximum= fInputMaximum; 554*cdf0e10cSrcweir if( !::rtl::math::isFinite( rExplicitScale.Maximum) || rExplicitScale.Maximum <= 0 ) 555*cdf0e10cSrcweir rExplicitScale.Maximum = 10.0; 556*cdf0e10cSrcweir } 557*cdf0e10cSrcweir if( rExplicitScale.Maximum < rExplicitScale.Minimum ) 558*cdf0e10cSrcweir ::std::swap( rExplicitScale.Maximum, rExplicitScale.Minimum ); 559*cdf0e10cSrcweir } 560*cdf0e10cSrcweir 561*cdf0e10cSrcweir //--------------------------------------------------------------- 562*cdf0e10cSrcweir //fill explicit sub increment 563*cdf0e10cSrcweir sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength(); 564*cdf0e10cSrcweir for( sal_Int32 nN=0; nN<nSubCount; nN++ ) 565*cdf0e10cSrcweir { 566*cdf0e10cSrcweir ExplicitSubIncrement aExplicitSubIncrement; 567*cdf0e10cSrcweir const SubIncrement& rSubIncrement = m_aSourceScale.IncrementData.SubIncrements[nN]; 568*cdf0e10cSrcweir if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount)) 569*cdf0e10cSrcweir { 570*cdf0e10cSrcweir //scaling dependent 571*cdf0e10cSrcweir //@todo autocalculate IntervalCount dependent on MainIncrement and scaling 572*cdf0e10cSrcweir aExplicitSubIncrement.IntervalCount = 9; 573*cdf0e10cSrcweir } 574*cdf0e10cSrcweir lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount ); 575*cdf0e10cSrcweir if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant)) 576*cdf0e10cSrcweir { 577*cdf0e10cSrcweir //scaling dependent 578*cdf0e10cSrcweir aExplicitSubIncrement.PostEquidistant = sal_False; 579*cdf0e10cSrcweir } 580*cdf0e10cSrcweir rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement); 581*cdf0e10cSrcweir } 582*cdf0e10cSrcweir } 583*cdf0e10cSrcweir 584*cdf0e10cSrcweir //----------------------------------------------------------------------------------------- 585*cdf0e10cSrcweir 586*cdf0e10cSrcweir void ScaleAutomatism::calculateExplicitIncrementAndScaleForDateTimeAxis( 587*cdf0e10cSrcweir ExplicitScaleData& rExplicitScale, 588*cdf0e10cSrcweir ExplicitIncrementData& rExplicitIncrement, 589*cdf0e10cSrcweir bool bAutoMinimum, bool bAutoMaximum ) const 590*cdf0e10cSrcweir { 591*cdf0e10cSrcweir Date aMinDate(m_aNullDate); aMinDate += static_cast<long>(::rtl::math::approxFloor(rExplicitScale.Minimum)); 592*cdf0e10cSrcweir Date aMaxDate(m_aNullDate); aMaxDate += static_cast<long>(::rtl::math::approxFloor(rExplicitScale.Maximum)); 593*cdf0e10cSrcweir rExplicitIncrement.PostEquidistant = sal_False; 594*cdf0e10cSrcweir 595*cdf0e10cSrcweir if( aMinDate > aMaxDate ) 596*cdf0e10cSrcweir { 597*cdf0e10cSrcweir std::swap(aMinDate,aMaxDate); 598*cdf0e10cSrcweir } 599*cdf0e10cSrcweir 600*cdf0e10cSrcweir if( !(m_aSourceScale.TimeIncrement.TimeResolution >>= rExplicitScale.TimeResolution) ) 601*cdf0e10cSrcweir rExplicitScale.TimeResolution = m_nTimeResolution; 602*cdf0e10cSrcweir 603*cdf0e10cSrcweir rExplicitScale.Scaling = new DateScaling(m_aNullDate,rExplicitScale.TimeResolution,false); 604*cdf0e10cSrcweir 605*cdf0e10cSrcweir // choose min and max suitable to time resolution 606*cdf0e10cSrcweir switch( rExplicitScale.TimeResolution ) 607*cdf0e10cSrcweir { 608*cdf0e10cSrcweir case DAY: 609*cdf0e10cSrcweir if( rExplicitScale.ShiftedCategoryPosition ) 610*cdf0e10cSrcweir aMaxDate++;//for explicit scales we need one interval more (maximum excluded) 611*cdf0e10cSrcweir break; 612*cdf0e10cSrcweir case MONTH: 613*cdf0e10cSrcweir aMinDate.SetDay(1); 614*cdf0e10cSrcweir aMaxDate.SetDay(1); 615*cdf0e10cSrcweir if( rExplicitScale.ShiftedCategoryPosition ) 616*cdf0e10cSrcweir aMaxDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,1);//for explicit scales we need one interval more (maximum excluded) 617*cdf0e10cSrcweir if( DateHelper::IsLessThanOneMonthAway( aMinDate, aMaxDate ) ) 618*cdf0e10cSrcweir { 619*cdf0e10cSrcweir if( bAutoMaximum || !bAutoMinimum ) 620*cdf0e10cSrcweir aMaxDate = DateHelper::GetDateSomeMonthsAway(aMinDate,1); 621*cdf0e10cSrcweir else 622*cdf0e10cSrcweir aMinDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,-1); 623*cdf0e10cSrcweir } 624*cdf0e10cSrcweir break; 625*cdf0e10cSrcweir case YEAR: 626*cdf0e10cSrcweir aMinDate.SetDay(1); 627*cdf0e10cSrcweir aMinDate.SetMonth(1); 628*cdf0e10cSrcweir aMaxDate.SetDay(1); 629*cdf0e10cSrcweir aMaxDate.SetMonth(1); 630*cdf0e10cSrcweir if( rExplicitScale.ShiftedCategoryPosition ) 631*cdf0e10cSrcweir aMaxDate = DateHelper::GetDateSomeYearsAway(aMaxDate,1);//for explicit scales we need one interval more (maximum excluded) 632*cdf0e10cSrcweir if( DateHelper::IsLessThanOneYearAway( aMinDate, aMaxDate ) ) 633*cdf0e10cSrcweir { 634*cdf0e10cSrcweir if( bAutoMaximum || !bAutoMinimum ) 635*cdf0e10cSrcweir aMaxDate = DateHelper::GetDateSomeYearsAway(aMinDate,1); 636*cdf0e10cSrcweir else 637*cdf0e10cSrcweir aMinDate = DateHelper::GetDateSomeYearsAway(aMaxDate,-1); 638*cdf0e10cSrcweir } 639*cdf0e10cSrcweir break; 640*cdf0e10cSrcweir } 641*cdf0e10cSrcweir 642*cdf0e10cSrcweir // set the resulting limits (swap back to negative range if needed) 643*cdf0e10cSrcweir rExplicitScale.Minimum = aMinDate - m_aNullDate; 644*cdf0e10cSrcweir rExplicitScale.Maximum = aMaxDate - m_aNullDate; 645*cdf0e10cSrcweir 646*cdf0e10cSrcweir bool bAutoMajor = !(m_aSourceScale.TimeIncrement.MajorTimeInterval >>= rExplicitIncrement.MajorTimeInterval); 647*cdf0e10cSrcweir bool bAutoMinor = !(m_aSourceScale.TimeIncrement.MinorTimeInterval >>= rExplicitIncrement.MinorTimeInterval); 648*cdf0e10cSrcweir 649*cdf0e10cSrcweir sal_Int32 nMaxMainIncrementCount = bAutoMajor ? 650*cdf0e10cSrcweir m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT; 651*cdf0e10cSrcweir if( nMaxMainIncrementCount > 1 ) 652*cdf0e10cSrcweir nMaxMainIncrementCount--; 653*cdf0e10cSrcweir 654*cdf0e10cSrcweir 655*cdf0e10cSrcweir //choose major time interval: 656*cdf0e10cSrcweir long nDayCount = (aMaxDate-aMinDate); 657*cdf0e10cSrcweir long nMainIncrementCount = 1; 658*cdf0e10cSrcweir if( !bAutoMajor ) 659*cdf0e10cSrcweir { 660*cdf0e10cSrcweir long nIntervalDayCount = rExplicitIncrement.MajorTimeInterval.Number; 661*cdf0e10cSrcweir if( rExplicitIncrement.MajorTimeInterval.TimeUnit < rExplicitScale.TimeResolution ) 662*cdf0e10cSrcweir rExplicitIncrement.MajorTimeInterval.TimeUnit = rExplicitScale.TimeResolution; 663*cdf0e10cSrcweir switch( rExplicitIncrement.MajorTimeInterval.TimeUnit ) 664*cdf0e10cSrcweir { 665*cdf0e10cSrcweir case DAY: 666*cdf0e10cSrcweir break; 667*cdf0e10cSrcweir case MONTH: 668*cdf0e10cSrcweir nIntervalDayCount*=31;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... 669*cdf0e10cSrcweir break; 670*cdf0e10cSrcweir case YEAR: 671*cdf0e10cSrcweir nIntervalDayCount*=365;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... 672*cdf0e10cSrcweir break; 673*cdf0e10cSrcweir } 674*cdf0e10cSrcweir nMainIncrementCount = nDayCount/nIntervalDayCount; 675*cdf0e10cSrcweir if( nMainIncrementCount > nMaxMainIncrementCount ) 676*cdf0e10cSrcweir bAutoMajor = true; 677*cdf0e10cSrcweir } 678*cdf0e10cSrcweir if( bAutoMajor ) 679*cdf0e10cSrcweir { 680*cdf0e10cSrcweir long nNumer = 1; 681*cdf0e10cSrcweir long nIntervalDays = nDayCount / nMaxMainIncrementCount; 682*cdf0e10cSrcweir double nDaysPerInterval = 1.0; 683*cdf0e10cSrcweir if( nIntervalDays>365 || YEAR==rExplicitScale.TimeResolution ) 684*cdf0e10cSrcweir { 685*cdf0e10cSrcweir rExplicitIncrement.MajorTimeInterval.TimeUnit = YEAR; 686*cdf0e10cSrcweir nDaysPerInterval = 365.0;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... 687*cdf0e10cSrcweir } 688*cdf0e10cSrcweir else if( nIntervalDays>31 || MONTH==rExplicitScale.TimeResolution ) 689*cdf0e10cSrcweir { 690*cdf0e10cSrcweir rExplicitIncrement.MajorTimeInterval.TimeUnit = MONTH; 691*cdf0e10cSrcweir nDaysPerInterval = 31.0;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... 692*cdf0e10cSrcweir } 693*cdf0e10cSrcweir else 694*cdf0e10cSrcweir { 695*cdf0e10cSrcweir rExplicitIncrement.MajorTimeInterval.TimeUnit = DAY; 696*cdf0e10cSrcweir nDaysPerInterval = 1.0; 697*cdf0e10cSrcweir } 698*cdf0e10cSrcweir 699*cdf0e10cSrcweir nNumer = static_cast<sal_Int32>( rtl::math::approxCeil( nIntervalDays/nDaysPerInterval ) ); 700*cdf0e10cSrcweir if(nNumer<=0) 701*cdf0e10cSrcweir nNumer=1; 702*cdf0e10cSrcweir if( rExplicitIncrement.MajorTimeInterval.TimeUnit == DAY ) 703*cdf0e10cSrcweir { 704*cdf0e10cSrcweir if( nNumer>2 && nNumer<7 ) 705*cdf0e10cSrcweir nNumer=7; 706*cdf0e10cSrcweir else if( nNumer>7 ) 707*cdf0e10cSrcweir { 708*cdf0e10cSrcweir rExplicitIncrement.MajorTimeInterval.TimeUnit = MONTH; 709*cdf0e10cSrcweir nDaysPerInterval = 31.0; 710*cdf0e10cSrcweir nNumer = static_cast<sal_Int32>( rtl::math::approxCeil( nIntervalDays/nDaysPerInterval ) ); 711*cdf0e10cSrcweir if(nNumer<=0) 712*cdf0e10cSrcweir nNumer=1; 713*cdf0e10cSrcweir } 714*cdf0e10cSrcweir } 715*cdf0e10cSrcweir rExplicitIncrement.MajorTimeInterval.Number = nNumer; 716*cdf0e10cSrcweir nMainIncrementCount = static_cast<long>(nDayCount/(nNumer*nDaysPerInterval)); 717*cdf0e10cSrcweir } 718*cdf0e10cSrcweir 719*cdf0e10cSrcweir //choose minor time interval: 720*cdf0e10cSrcweir if( !bAutoMinor ) 721*cdf0e10cSrcweir { 722*cdf0e10cSrcweir if( rExplicitIncrement.MinorTimeInterval.TimeUnit > rExplicitIncrement.MajorTimeInterval.TimeUnit ) 723*cdf0e10cSrcweir rExplicitIncrement.MinorTimeInterval.TimeUnit = rExplicitIncrement.MajorTimeInterval.TimeUnit; 724*cdf0e10cSrcweir long nIntervalDayCount = rExplicitIncrement.MinorTimeInterval.Number; 725*cdf0e10cSrcweir switch( rExplicitIncrement.MinorTimeInterval.TimeUnit ) 726*cdf0e10cSrcweir { 727*cdf0e10cSrcweir case DAY: 728*cdf0e10cSrcweir break; 729*cdf0e10cSrcweir case MONTH: 730*cdf0e10cSrcweir nIntervalDayCount*=31;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... 731*cdf0e10cSrcweir break; 732*cdf0e10cSrcweir case YEAR: 733*cdf0e10cSrcweir nIntervalDayCount*=365;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... 734*cdf0e10cSrcweir break; 735*cdf0e10cSrcweir } 736*cdf0e10cSrcweir if( nDayCount/nIntervalDayCount > nMaxMainIncrementCount ) 737*cdf0e10cSrcweir bAutoMinor = true; 738*cdf0e10cSrcweir } 739*cdf0e10cSrcweir if( bAutoMinor ) 740*cdf0e10cSrcweir { 741*cdf0e10cSrcweir rExplicitIncrement.MinorTimeInterval.TimeUnit = rExplicitIncrement.MajorTimeInterval.TimeUnit; 742*cdf0e10cSrcweir rExplicitIncrement.MinorTimeInterval.Number = 1; 743*cdf0e10cSrcweir if( nMainIncrementCount > 100 ) 744*cdf0e10cSrcweir rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number; 745*cdf0e10cSrcweir else 746*cdf0e10cSrcweir { 747*cdf0e10cSrcweir if( rExplicitIncrement.MajorTimeInterval.Number >= 2 ) 748*cdf0e10cSrcweir { 749*cdf0e10cSrcweir if( !(rExplicitIncrement.MajorTimeInterval.Number%2) ) 750*cdf0e10cSrcweir rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/2; 751*cdf0e10cSrcweir else if( !(rExplicitIncrement.MajorTimeInterval.Number%3) ) 752*cdf0e10cSrcweir rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/3; 753*cdf0e10cSrcweir else if( !(rExplicitIncrement.MajorTimeInterval.Number%5) ) 754*cdf0e10cSrcweir rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/5; 755*cdf0e10cSrcweir else if( rExplicitIncrement.MajorTimeInterval.Number > 50 ) 756*cdf0e10cSrcweir rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number; 757*cdf0e10cSrcweir } 758*cdf0e10cSrcweir else 759*cdf0e10cSrcweir { 760*cdf0e10cSrcweir switch( rExplicitIncrement.MajorTimeInterval.TimeUnit ) 761*cdf0e10cSrcweir { 762*cdf0e10cSrcweir case DAY: 763*cdf0e10cSrcweir break; 764*cdf0e10cSrcweir case MONTH: 765*cdf0e10cSrcweir if( rExplicitScale.TimeResolution == DAY ) 766*cdf0e10cSrcweir rExplicitIncrement.MinorTimeInterval.TimeUnit = DAY; 767*cdf0e10cSrcweir break; 768*cdf0e10cSrcweir case YEAR: 769*cdf0e10cSrcweir if( rExplicitScale.TimeResolution <= MONTH ) 770*cdf0e10cSrcweir rExplicitIncrement.MinorTimeInterval.TimeUnit = MONTH; 771*cdf0e10cSrcweir break; 772*cdf0e10cSrcweir } 773*cdf0e10cSrcweir } 774*cdf0e10cSrcweir } 775*cdf0e10cSrcweir } 776*cdf0e10cSrcweir 777*cdf0e10cSrcweir } 778*cdf0e10cSrcweir 779*cdf0e10cSrcweir //----------------------------------------------------------------------------------------- 780*cdf0e10cSrcweir 781*cdf0e10cSrcweir void ScaleAutomatism::calculateExplicitIncrementAndScaleForLinear( 782*cdf0e10cSrcweir ExplicitScaleData& rExplicitScale, 783*cdf0e10cSrcweir ExplicitIncrementData& rExplicitIncrement, 784*cdf0e10cSrcweir bool bAutoMinimum, bool bAutoMaximum ) const 785*cdf0e10cSrcweir { 786*cdf0e10cSrcweir // *** STEP 1: initialize the range data *** 787*cdf0e10cSrcweir 788*cdf0e10cSrcweir double fSourceMinimum = rExplicitScale.Minimum; 789*cdf0e10cSrcweir double fSourceMaximum = rExplicitScale.Maximum; 790*cdf0e10cSrcweir 791*cdf0e10cSrcweir // set automatic PostEquidistant to true (maybe scaling dependent?) 792*cdf0e10cSrcweir if( !(m_aSourceScale.IncrementData.PostEquidistant >>= rExplicitIncrement.PostEquidistant) ) 793*cdf0e10cSrcweir rExplicitIncrement.PostEquidistant = sal_True; 794*cdf0e10cSrcweir 795*cdf0e10cSrcweir /* If range is invalid (minimum greater than maximum), change one of the 796*cdf0e10cSrcweir variable limits to validate the range. In this step, a zero-sized range 797*cdf0e10cSrcweir is still allowed. */ 798*cdf0e10cSrcweir if( fSourceMinimum > fSourceMaximum ) 799*cdf0e10cSrcweir { 800*cdf0e10cSrcweir // force changing the maximum, if both limits are fixed 801*cdf0e10cSrcweir if( bAutoMaximum || !bAutoMinimum ) 802*cdf0e10cSrcweir fSourceMaximum = fSourceMinimum; 803*cdf0e10cSrcweir else 804*cdf0e10cSrcweir fSourceMinimum = fSourceMaximum; 805*cdf0e10cSrcweir } 806*cdf0e10cSrcweir 807*cdf0e10cSrcweir /* If maximum is zero or negative (and therefore minimum too), minimum and 808*cdf0e10cSrcweir maximum will be negated and swapped to make the following algorithms 809*cdf0e10cSrcweir easier. Example: Both ranges [2,5] and [-5,-2] will be processed as 810*cdf0e10cSrcweir [2,5], and the latter will be swapped back later. The range [0,0] is 811*cdf0e10cSrcweir explicitly excluded from swapping (this would result in [-1,0] instead 812*cdf0e10cSrcweir of the expected [0,1]). */ 813*cdf0e10cSrcweir bool bSwapAndNegateRange = (fSourceMinimum < 0.0) && (fSourceMaximum <= 0.0); 814*cdf0e10cSrcweir if( bSwapAndNegateRange ) 815*cdf0e10cSrcweir { 816*cdf0e10cSrcweir double fTempValue = fSourceMinimum; 817*cdf0e10cSrcweir fSourceMinimum = -fSourceMaximum; 818*cdf0e10cSrcweir fSourceMaximum = -fTempValue; 819*cdf0e10cSrcweir ::std::swap( bAutoMinimum, bAutoMaximum ); 820*cdf0e10cSrcweir } 821*cdf0e10cSrcweir 822*cdf0e10cSrcweir // *** STEP 2: find temporary (unrounded) axis minimum and maximum *** 823*cdf0e10cSrcweir 824*cdf0e10cSrcweir double fTempMinimum = fSourceMinimum; 825*cdf0e10cSrcweir double fTempMaximum = fSourceMaximum; 826*cdf0e10cSrcweir 827*cdf0e10cSrcweir /* If minimum is variable and greater than 0 (and therefore maximum too), 828*cdf0e10cSrcweir means all values are positive (or all values are negative, and the 829*cdf0e10cSrcweir range has been swapped above), then: */ 830*cdf0e10cSrcweir if( bAutoMinimum && (fTempMinimum > 0.0) ) 831*cdf0e10cSrcweir { 832*cdf0e10cSrcweir /* If minimum equals maximum, or if minimum is less than 5/6 of 833*cdf0e10cSrcweir maximum, set minimum to 0. */ 834*cdf0e10cSrcweir if( (fTempMinimum == fTempMaximum) || (fTempMinimum / fTempMaximum < 5.0 / 6.0) ) 835*cdf0e10cSrcweir { 836*cdf0e10cSrcweir if( m_bExpandWideValuesToZero ) 837*cdf0e10cSrcweir fTempMinimum = 0.0; 838*cdf0e10cSrcweir } 839*cdf0e10cSrcweir /* Else (minimum is greater than or equal to 5/6 of maximum), add half 840*cdf0e10cSrcweir of the visible range (expand minimum toward 0) to make the 841*cdf0e10cSrcweir 'shorter' data points visible. */ 842*cdf0e10cSrcweir else 843*cdf0e10cSrcweir { 844*cdf0e10cSrcweir if( m_bExpandNarrowValuesTowardZero ) 845*cdf0e10cSrcweir fTempMinimum -= (fTempMaximum - fTempMinimum) / 2.0; 846*cdf0e10cSrcweir } 847*cdf0e10cSrcweir } 848*cdf0e10cSrcweir 849*cdf0e10cSrcweir /* If range is still zero-sized (e.g. when minimum is fixed), add some 850*cdf0e10cSrcweir space to a variable limit. */ 851*cdf0e10cSrcweir if( fTempMinimum == fTempMaximum ) 852*cdf0e10cSrcweir { 853*cdf0e10cSrcweir if( bAutoMaximum || !bAutoMinimum ) 854*cdf0e10cSrcweir { 855*cdf0e10cSrcweir // change 0 to 1, otherwise double the value 856*cdf0e10cSrcweir if( fTempMaximum == 0.0 ) 857*cdf0e10cSrcweir fTempMaximum = 1.0; 858*cdf0e10cSrcweir else 859*cdf0e10cSrcweir fTempMaximum *= 2.0; 860*cdf0e10cSrcweir } 861*cdf0e10cSrcweir else 862*cdf0e10cSrcweir { 863*cdf0e10cSrcweir // change 0 to -1, otherwise halve the value 864*cdf0e10cSrcweir if( fTempMinimum == 0.0 ) 865*cdf0e10cSrcweir fTempMinimum = -1.0; 866*cdf0e10cSrcweir else 867*cdf0e10cSrcweir fTempMinimum /= 2.0; 868*cdf0e10cSrcweir } 869*cdf0e10cSrcweir } 870*cdf0e10cSrcweir 871*cdf0e10cSrcweir // *** STEP 3: calculate main interval size *** 872*cdf0e10cSrcweir 873*cdf0e10cSrcweir // base value (anchor position of the intervals) 874*cdf0e10cSrcweir if( !(m_aSourceScale.IncrementData.BaseValue >>= rExplicitIncrement.BaseValue) ) 875*cdf0e10cSrcweir { 876*cdf0e10cSrcweir if( !bAutoMinimum ) 877*cdf0e10cSrcweir rExplicitIncrement.BaseValue = fTempMinimum; 878*cdf0e10cSrcweir else if( !bAutoMaximum ) 879*cdf0e10cSrcweir rExplicitIncrement.BaseValue = fTempMaximum; 880*cdf0e10cSrcweir else 881*cdf0e10cSrcweir rExplicitIncrement.BaseValue = 0.0; 882*cdf0e10cSrcweir } 883*cdf0e10cSrcweir 884*cdf0e10cSrcweir // calculate automatic interval 885*cdf0e10cSrcweir bool bAutoDistance = !(m_aSourceScale.IncrementData.Distance >>= rExplicitIncrement.Distance); 886*cdf0e10cSrcweir /* Restrict number of allowed intervals with user-defined distance to 887*cdf0e10cSrcweir MAXIMUM_MANUAL_INCREMENT_COUNT. */ 888*cdf0e10cSrcweir sal_Int32 nMaxMainIncrementCount = bAutoDistance ? 889*cdf0e10cSrcweir m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT; 890*cdf0e10cSrcweir 891*cdf0e10cSrcweir double fDistanceMagnitude = 0.0; 892*cdf0e10cSrcweir double fDistanceNormalized = 0.0; 893*cdf0e10cSrcweir bool bHasNormalizedDistance = false; 894*cdf0e10cSrcweir 895*cdf0e10cSrcweir // repeat calculation until number of intervals are valid 896*cdf0e10cSrcweir bool bNeedIteration = true; 897*cdf0e10cSrcweir while( bNeedIteration ) 898*cdf0e10cSrcweir { 899*cdf0e10cSrcweir if( bAutoDistance ) 900*cdf0e10cSrcweir { 901*cdf0e10cSrcweir // first iteration: calculate interval size from axis limits 902*cdf0e10cSrcweir if( !bHasNormalizedDistance ) 903*cdf0e10cSrcweir { 904*cdf0e10cSrcweir // raw size of an interval 905*cdf0e10cSrcweir double fDistance = (fTempMaximum - fTempMinimum) / nMaxMainIncrementCount; 906*cdf0e10cSrcweir 907*cdf0e10cSrcweir // if distance of is less than 1e-307, do not do anything 908*cdf0e10cSrcweir if( fDistance <= 1.0e-307 ) 909*cdf0e10cSrcweir { 910*cdf0e10cSrcweir fDistanceNormalized = 1.0; 911*cdf0e10cSrcweir fDistanceMagnitude = 1.0e-307; 912*cdf0e10cSrcweir } 913*cdf0e10cSrcweir else 914*cdf0e10cSrcweir { 915*cdf0e10cSrcweir // distance magnitude (a power of 10) 916*cdf0e10cSrcweir int nExponent = static_cast< int >( ::rtl::math::approxFloor( log10( fDistance ) ) ); 917*cdf0e10cSrcweir fDistanceMagnitude = ::rtl::math::pow10Exp( 1.0, nExponent ); 918*cdf0e10cSrcweir 919*cdf0e10cSrcweir // stick normalized distance to a few predefined values 920*cdf0e10cSrcweir fDistanceNormalized = fDistance / fDistanceMagnitude; 921*cdf0e10cSrcweir if( fDistanceNormalized <= 1.0 ) 922*cdf0e10cSrcweir fDistanceNormalized = 1.0; 923*cdf0e10cSrcweir else if( fDistanceNormalized <= 2.0 ) 924*cdf0e10cSrcweir fDistanceNormalized = 2.0; 925*cdf0e10cSrcweir else if( fDistanceNormalized <= 5.0 ) 926*cdf0e10cSrcweir fDistanceNormalized = 5.0; 927*cdf0e10cSrcweir else 928*cdf0e10cSrcweir { 929*cdf0e10cSrcweir fDistanceNormalized = 1.0; 930*cdf0e10cSrcweir fDistanceMagnitude *= 10; 931*cdf0e10cSrcweir } 932*cdf0e10cSrcweir } 933*cdf0e10cSrcweir // for next iteration: distance is normalized -> use else path to increase distance 934*cdf0e10cSrcweir bHasNormalizedDistance = true; 935*cdf0e10cSrcweir } 936*cdf0e10cSrcweir // following iterations: increase distance, use only allowed values 937*cdf0e10cSrcweir else 938*cdf0e10cSrcweir { 939*cdf0e10cSrcweir if( fDistanceNormalized == 1.0 ) 940*cdf0e10cSrcweir fDistanceNormalized = 2.0; 941*cdf0e10cSrcweir else if( fDistanceNormalized == 2.0 ) 942*cdf0e10cSrcweir fDistanceNormalized = 5.0; 943*cdf0e10cSrcweir else 944*cdf0e10cSrcweir { 945*cdf0e10cSrcweir fDistanceNormalized = 1.0; 946*cdf0e10cSrcweir fDistanceMagnitude *= 10; 947*cdf0e10cSrcweir } 948*cdf0e10cSrcweir } 949*cdf0e10cSrcweir 950*cdf0e10cSrcweir // set the resulting distance 951*cdf0e10cSrcweir rExplicitIncrement.Distance = fDistanceNormalized * fDistanceMagnitude; 952*cdf0e10cSrcweir } 953*cdf0e10cSrcweir 954*cdf0e10cSrcweir // *** STEP 4: additional space above or below the data points *** 955*cdf0e10cSrcweir 956*cdf0e10cSrcweir double fAxisMinimum = fTempMinimum; 957*cdf0e10cSrcweir double fAxisMaximum = fTempMaximum; 958*cdf0e10cSrcweir 959*cdf0e10cSrcweir // round to entire multiples of the distance and add additional space 960*cdf0e10cSrcweir if( bAutoMinimum ) 961*cdf0e10cSrcweir { 962*cdf0e10cSrcweir // round to entire multiples of the distance, based on the base value 963*cdf0e10cSrcweir if( m_bExpandBorderToIncrementRhythm ) 964*cdf0e10cSrcweir fAxisMinimum = EquidistantTickFactory::getMinimumAtIncrement( fAxisMinimum, rExplicitIncrement ); 965*cdf0e10cSrcweir // additional space, if source minimum is to near at axis minimum 966*cdf0e10cSrcweir if( m_bExpandIfValuesCloseToBorder ) 967*cdf0e10cSrcweir if( (fAxisMinimum != 0.0) && ((fAxisMaximum - fSourceMinimum) / (fAxisMaximum - fAxisMinimum) > 20.0 / 21.0) ) 968*cdf0e10cSrcweir fAxisMinimum -= rExplicitIncrement.Distance; 969*cdf0e10cSrcweir } 970*cdf0e10cSrcweir if( bAutoMaximum ) 971*cdf0e10cSrcweir { 972*cdf0e10cSrcweir // round to entire multiples of the distance, based on the base value 973*cdf0e10cSrcweir if( m_bExpandBorderToIncrementRhythm ) 974*cdf0e10cSrcweir fAxisMaximum = EquidistantTickFactory::getMaximumAtIncrement( fAxisMaximum, rExplicitIncrement ); 975*cdf0e10cSrcweir // additional space, if source maximum is to near at axis maximum 976*cdf0e10cSrcweir if( m_bExpandIfValuesCloseToBorder ) 977*cdf0e10cSrcweir if( (fAxisMaximum != 0.0) && ((fSourceMaximum - fAxisMinimum) / (fAxisMaximum - fAxisMinimum) > 20.0 / 21.0) ) 978*cdf0e10cSrcweir fAxisMaximum += rExplicitIncrement.Distance; 979*cdf0e10cSrcweir } 980*cdf0e10cSrcweir 981*cdf0e10cSrcweir // set the resulting limits (swap back to negative range if needed) 982*cdf0e10cSrcweir if( bSwapAndNegateRange ) 983*cdf0e10cSrcweir { 984*cdf0e10cSrcweir rExplicitScale.Minimum = -fAxisMaximum; 985*cdf0e10cSrcweir rExplicitScale.Maximum = -fAxisMinimum; 986*cdf0e10cSrcweir } 987*cdf0e10cSrcweir else 988*cdf0e10cSrcweir { 989*cdf0e10cSrcweir rExplicitScale.Minimum = fAxisMinimum; 990*cdf0e10cSrcweir rExplicitScale.Maximum = fAxisMaximum; 991*cdf0e10cSrcweir } 992*cdf0e10cSrcweir 993*cdf0e10cSrcweir /* If the number of intervals is too high (e.g. due to invalid fixed 994*cdf0e10cSrcweir distance or due to added space above or below data points), 995*cdf0e10cSrcweir calculate again with increased distance. */ 996*cdf0e10cSrcweir double fDistanceCount = ::rtl::math::approxFloor( (fAxisMaximum - fAxisMinimum) / rExplicitIncrement.Distance ); 997*cdf0e10cSrcweir bNeedIteration = static_cast< sal_Int32 >( fDistanceCount ) > nMaxMainIncrementCount; 998*cdf0e10cSrcweir // if manual distance is invalid, trigger automatic calculation 999*cdf0e10cSrcweir if( bNeedIteration ) 1000*cdf0e10cSrcweir bAutoDistance = true; 1001*cdf0e10cSrcweir } 1002*cdf0e10cSrcweir 1003*cdf0e10cSrcweir //--------------------------------------------------------------- 1004*cdf0e10cSrcweir //fill explicit sub increment 1005*cdf0e10cSrcweir sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength(); 1006*cdf0e10cSrcweir for( sal_Int32 nN=0; nN<nSubCount; nN++ ) 1007*cdf0e10cSrcweir { 1008*cdf0e10cSrcweir ExplicitSubIncrement aExplicitSubIncrement; 1009*cdf0e10cSrcweir const SubIncrement& rSubIncrement= m_aSourceScale.IncrementData.SubIncrements[nN]; 1010*cdf0e10cSrcweir if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount)) 1011*cdf0e10cSrcweir { 1012*cdf0e10cSrcweir //scaling dependent 1013*cdf0e10cSrcweir //@todo autocalculate IntervalCount dependent on MainIncrement and scaling 1014*cdf0e10cSrcweir aExplicitSubIncrement.IntervalCount = 2; 1015*cdf0e10cSrcweir } 1016*cdf0e10cSrcweir lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount ); 1017*cdf0e10cSrcweir if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant)) 1018*cdf0e10cSrcweir { 1019*cdf0e10cSrcweir //scaling dependent 1020*cdf0e10cSrcweir aExplicitSubIncrement.PostEquidistant = sal_False; 1021*cdf0e10cSrcweir } 1022*cdf0e10cSrcweir rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement); 1023*cdf0e10cSrcweir } 1024*cdf0e10cSrcweir } 1025*cdf0e10cSrcweir 1026*cdf0e10cSrcweir //............................................................................. 1027*cdf0e10cSrcweir } //namespace chart 1028*cdf0e10cSrcweir //............................................................................. 1029