LCOV - code coverage report
Current view: top level - chart2/source/view/axes - ScaleAutomatism.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 468 0.0 %
Date: 2014-04-14 Functions: 0 19 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10