LCOV - code coverage report
Current view: top level - chart2/source/view/axes - ScaleAutomatism.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 290 468 62.0 %
Date: 2012-08-25 Functions: 15 19 78.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 216 486 44.4 %

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

Generated by: LCOV version 1.10