989 lines
40 KiB
C++
989 lines
40 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <ScaleAutomatism.hxx>
|
|
#include "Tickmarks_Equidistant.hxx"
|
|
#include <DateHelper.hxx>
|
|
#include "DateScaling.hxx"
|
|
#include <AxisHelper.hxx>
|
|
#include <com/sun/star/chart/TimeUnit.hpp>
|
|
#include <com/sun/star/chart2/AxisType.hpp>
|
|
|
|
#include <rtl/math.hxx>
|
|
#include <tools/long.hxx>
|
|
#include <limits>
|
|
|
|
namespace chart
|
|
{
|
|
using namespace ::com::sun::star;
|
|
using namespace ::com::sun::star::chart2;
|
|
using ::com::sun::star::chart::TimeUnit::DAY;
|
|
using ::com::sun::star::chart::TimeUnit::MONTH;
|
|
using ::com::sun::star::chart::TimeUnit::YEAR;
|
|
|
|
const sal_Int32 MAXIMUM_MANUAL_INCREMENT_COUNT = 500;
|
|
const sal_Int32 MAXIMUM_SUB_INCREMENT_COUNT = 100;
|
|
|
|
static sal_Int32 lcl_getMaximumAutoIncrementCount( sal_Int32 nAxisType )
|
|
{
|
|
sal_Int32 nMaximumAutoIncrementCount = 10;
|
|
if( nAxisType==AxisType::DATE )
|
|
nMaximumAutoIncrementCount = MAXIMUM_MANUAL_INCREMENT_COUNT;
|
|
return nMaximumAutoIncrementCount;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
|
|
void lcl_ensureMaximumSubIncrementCount( sal_Int32& rnSubIntervalCount )
|
|
{
|
|
if( rnSubIntervalCount > MAXIMUM_SUB_INCREMENT_COUNT )
|
|
rnSubIntervalCount = MAXIMUM_SUB_INCREMENT_COUNT;
|
|
}
|
|
|
|
}//end anonymous namespace
|
|
|
|
ExplicitScaleData::ExplicitScaleData()
|
|
: Minimum(0.0)
|
|
, Maximum(10.0)
|
|
, Origin(0.0)
|
|
, Orientation(css::chart2::AxisOrientation_MATHEMATICAL)
|
|
, AxisType(css::chart2::AxisType::REALNUMBER)
|
|
, m_bShiftedCategoryPosition(false)
|
|
, TimeResolution(css::chart::TimeUnit::DAY)
|
|
, NullDate(30,12,1899)
|
|
{
|
|
}
|
|
|
|
ExplicitSubIncrement::ExplicitSubIncrement()
|
|
: IntervalCount(2)
|
|
, PostEquidistant(true)
|
|
{
|
|
}
|
|
|
|
ExplicitIncrementData::ExplicitIncrementData()
|
|
: MajorTimeInterval(1,css::chart::TimeUnit::DAY)
|
|
, MinorTimeInterval(1,css::chart::TimeUnit::DAY)
|
|
, Distance(1.0)
|
|
, PostEquidistant(true)
|
|
, BaseValue(0.0)
|
|
{
|
|
}
|
|
|
|
ScaleAutomatism::ScaleAutomatism( const ScaleData& rSourceScale, const Date& rNullDate )
|
|
: m_aSourceScale( rSourceScale )
|
|
, m_fValueMinimum( 0.0 )
|
|
, m_fValueMaximum( 0.0 )
|
|
, m_nMaximumAutoMainIncrementCount( lcl_getMaximumAutoIncrementCount( rSourceScale.AxisType ) )
|
|
, m_bExpandBorderToIncrementRhythm( false )
|
|
, m_bExpandIfValuesCloseToBorder( false )
|
|
, m_bExpandWideValuesToZero( false )
|
|
, m_bExpandNarrowValuesTowardZero( false )
|
|
, m_nTimeResolution(css::chart::TimeUnit::DAY)
|
|
, m_aNullDate(rNullDate)
|
|
{
|
|
resetValueRange();
|
|
|
|
double fExplicitOrigin = 0.0;
|
|
if( m_aSourceScale.Origin >>= fExplicitOrigin )
|
|
expandValueRange( fExplicitOrigin, fExplicitOrigin);
|
|
}
|
|
|
|
void ScaleAutomatism::resetValueRange( )
|
|
{
|
|
m_fValueMinimum = std::numeric_limits<double>::quiet_NaN();
|
|
m_fValueMaximum = std::numeric_limits<double>::quiet_NaN();
|
|
}
|
|
|
|
void ScaleAutomatism::expandValueRange( double fMinimum, double fMaximum )
|
|
{
|
|
// if m_fValueMinimum and m_fValueMaximum == 0, it means that they were not determined.
|
|
// m_fValueMinimum == 0 makes impossible to determine real minimum,
|
|
// so they need to be reset tdf#96807
|
|
if( (m_fValueMinimum == 0.0) && (m_fValueMaximum == 0.0) )
|
|
resetValueRange();
|
|
if( (fMinimum < m_fValueMinimum) || std::isnan( m_fValueMinimum ) )
|
|
m_fValueMinimum = fMinimum;
|
|
if( (fMaximum > m_fValueMaximum) || std::isnan( m_fValueMaximum ) )
|
|
m_fValueMaximum = fMaximum;
|
|
}
|
|
|
|
void ScaleAutomatism::setAutoScalingOptions(
|
|
bool bExpandBorderToIncrementRhythm,
|
|
bool bExpandIfValuesCloseToBorder,
|
|
bool bExpandWideValuesToZero,
|
|
bool bExpandNarrowValuesTowardZero )
|
|
{
|
|
// if called multiple times, enable an option, if it is set in at least one call
|
|
m_bExpandBorderToIncrementRhythm |= bExpandBorderToIncrementRhythm;
|
|
m_bExpandIfValuesCloseToBorder |= bExpandIfValuesCloseToBorder;
|
|
m_bExpandWideValuesToZero |= bExpandWideValuesToZero;
|
|
m_bExpandNarrowValuesTowardZero |= bExpandNarrowValuesTowardZero;
|
|
|
|
if( m_aSourceScale.AxisType==AxisType::PERCENT )
|
|
m_bExpandIfValuesCloseToBorder = false;
|
|
}
|
|
|
|
void ScaleAutomatism::setMaximumAutoMainIncrementCount( sal_Int32 nMaximumAutoMainIncrementCount )
|
|
{
|
|
if( nMaximumAutoMainIncrementCount < 2 )
|
|
m_nMaximumAutoMainIncrementCount = 2; //#i82006
|
|
else if( nMaximumAutoMainIncrementCount > lcl_getMaximumAutoIncrementCount( m_aSourceScale.AxisType ) )
|
|
m_nMaximumAutoMainIncrementCount = lcl_getMaximumAutoIncrementCount( m_aSourceScale.AxisType );
|
|
else
|
|
m_nMaximumAutoMainIncrementCount = nMaximumAutoMainIncrementCount;
|
|
}
|
|
|
|
void ScaleAutomatism::setAutomaticTimeResolution( sal_Int32 nTimeResolution )
|
|
{
|
|
m_nTimeResolution = nTimeResolution;
|
|
}
|
|
|
|
void ScaleAutomatism::calculateExplicitScaleAndIncrement(
|
|
ExplicitScaleData& rExplicitScale, ExplicitIncrementData& rExplicitIncrement ) const
|
|
{
|
|
// fill explicit scale
|
|
rExplicitScale.Orientation = m_aSourceScale.Orientation;
|
|
rExplicitScale.Scaling = m_aSourceScale.Scaling;
|
|
rExplicitScale.AxisType = m_aSourceScale.AxisType;
|
|
rExplicitScale.NullDate = m_aNullDate;
|
|
|
|
bool bAutoMinimum = !(m_aSourceScale.Minimum >>= rExplicitScale.Minimum);
|
|
bool bAutoMaximum = !(m_aSourceScale.Maximum >>= rExplicitScale.Maximum);
|
|
bool bAutoOrigin = !(m_aSourceScale.Origin >>= rExplicitScale.Origin);
|
|
|
|
// automatic scale minimum
|
|
if( bAutoMinimum )
|
|
{
|
|
if( m_aSourceScale.AxisType==AxisType::PERCENT )
|
|
rExplicitScale.Minimum = 0.0;
|
|
else if( std::isnan( m_fValueMinimum ) )
|
|
{
|
|
if( m_aSourceScale.AxisType==AxisType::DATE )
|
|
rExplicitScale.Minimum = 36526.0; //1.1.2000
|
|
else
|
|
rExplicitScale.Minimum = 0.0; //@todo get Minimum from scaling or from plotter????
|
|
}
|
|
else
|
|
rExplicitScale.Minimum = m_fValueMinimum;
|
|
}
|
|
|
|
// automatic scale maximum
|
|
if( bAutoMaximum )
|
|
{
|
|
if( m_aSourceScale.AxisType==AxisType::PERCENT )
|
|
rExplicitScale.Maximum = 1.0;
|
|
else if( std::isnan( m_fValueMaximum ) )
|
|
{
|
|
if( m_aSourceScale.AxisType==AxisType::DATE )
|
|
rExplicitScale.Maximum = 40179.0; //1.1.2010
|
|
else
|
|
rExplicitScale.Maximum = 10.0; //@todo get Maximum from scaling or from plotter????
|
|
}
|
|
else
|
|
rExplicitScale.Maximum = m_fValueMaximum;
|
|
}
|
|
|
|
//fill explicit increment
|
|
|
|
rExplicitScale.m_bShiftedCategoryPosition = m_aSourceScale.ShiftedCategoryPosition;
|
|
bool bIsLogarithm = false;
|
|
|
|
//minimum and maximum of the ExplicitScaleData may be changed if allowed
|
|
if( m_aSourceScale.AxisType==AxisType::DATE )
|
|
calculateExplicitIncrementAndScaleForDateTimeAxis( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum );
|
|
else if( m_aSourceScale.AxisType==AxisType::CATEGORY || m_aSourceScale.AxisType==AxisType::SERIES )
|
|
calculateExplicitIncrementAndScaleForCategory( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum );
|
|
else
|
|
{
|
|
bIsLogarithm = AxisHelper::isLogarithmic( rExplicitScale.Scaling );
|
|
if( bIsLogarithm )
|
|
calculateExplicitIncrementAndScaleForLogarithmic( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum );
|
|
else
|
|
calculateExplicitIncrementAndScaleForLinear( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum );
|
|
}
|
|
|
|
// automatic origin
|
|
if( bAutoOrigin )
|
|
{
|
|
// #i71415# automatic origin for logarithmic axis
|
|
double fDefaulOrigin = bIsLogarithm ? 1.0 : 0.0;
|
|
|
|
if( fDefaulOrigin < rExplicitScale.Minimum )
|
|
fDefaulOrigin = rExplicitScale.Minimum;
|
|
else if( fDefaulOrigin > rExplicitScale.Maximum )
|
|
fDefaulOrigin = rExplicitScale.Maximum;
|
|
|
|
rExplicitScale.Origin = fDefaulOrigin;
|
|
}
|
|
}
|
|
|
|
void ScaleAutomatism::calculateExplicitIncrementAndScaleForCategory(
|
|
ExplicitScaleData& rExplicitScale,
|
|
ExplicitIncrementData& rExplicitIncrement,
|
|
bool bAutoMinimum, bool bAutoMaximum ) const
|
|
{
|
|
// no scaling for categories
|
|
rExplicitScale.Scaling.clear();
|
|
|
|
if( rExplicitScale.m_bShiftedCategoryPosition )
|
|
rExplicitScale.Maximum += 1.0;
|
|
|
|
// ensure that at least one category is visible
|
|
if( rExplicitScale.Maximum <= rExplicitScale.Minimum )
|
|
rExplicitScale.Maximum = rExplicitScale.Minimum + 1.0;
|
|
|
|
// default increment settings
|
|
rExplicitIncrement.PostEquidistant = true; // does not matter anyhow
|
|
rExplicitIncrement.Distance = 1.0; // category axis always have a main increment of 1
|
|
rExplicitIncrement.BaseValue = 0.0; // category axis always have a base of 0
|
|
|
|
// automatic minimum and maximum
|
|
if( bAutoMinimum && m_bExpandBorderToIncrementRhythm )
|
|
rExplicitScale.Minimum = EquidistantTickFactory::getMinimumAtIncrement( rExplicitScale.Minimum, rExplicitIncrement );
|
|
if( bAutoMaximum && m_bExpandBorderToIncrementRhythm )
|
|
rExplicitScale.Maximum = EquidistantTickFactory::getMaximumAtIncrement( rExplicitScale.Maximum, rExplicitIncrement );
|
|
|
|
//prevent performance killover
|
|
double fDistanceCount = ::rtl::math::approxFloor( (rExplicitScale.Maximum-rExplicitScale.Minimum) / rExplicitIncrement.Distance );
|
|
if( static_cast< sal_Int32 >( fDistanceCount ) > MAXIMUM_MANUAL_INCREMENT_COUNT )
|
|
{
|
|
double fMinimumFloor = ::rtl::math::approxFloor( rExplicitScale.Minimum );
|
|
double fMaximumCeil = ::rtl::math::approxCeil( rExplicitScale.Maximum );
|
|
rExplicitIncrement.Distance = ::rtl::math::approxCeil( (fMaximumCeil - fMinimumFloor) / MAXIMUM_MANUAL_INCREMENT_COUNT );
|
|
}
|
|
|
|
//fill explicit sub increment
|
|
sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength();
|
|
for( sal_Int32 nN=0; nN<nSubCount; nN++ )
|
|
{
|
|
ExplicitSubIncrement aExplicitSubIncrement;
|
|
const SubIncrement& rSubIncrement= m_aSourceScale.IncrementData.SubIncrements[nN];
|
|
if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount))
|
|
{
|
|
//scaling dependent
|
|
//@todo autocalculate IntervalCount dependent on MainIncrement and scaling
|
|
aExplicitSubIncrement.IntervalCount = 2;
|
|
}
|
|
lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount );
|
|
if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant))
|
|
{
|
|
//scaling dependent
|
|
aExplicitSubIncrement.PostEquidistant = false;
|
|
}
|
|
rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement);
|
|
}
|
|
}
|
|
|
|
void ScaleAutomatism::calculateExplicitIncrementAndScaleForLogarithmic(
|
|
ExplicitScaleData& rExplicitScale,
|
|
ExplicitIncrementData& rExplicitIncrement,
|
|
bool bAutoMinimum, bool bAutoMaximum ) const
|
|
{
|
|
// *** STEP 1: initialize the range data ***
|
|
|
|
const double fInputMinimum = rExplicitScale.Minimum;
|
|
const double fInputMaximum = rExplicitScale.Maximum;
|
|
|
|
double fSourceMinimum = rExplicitScale.Minimum;
|
|
double fSourceMaximum = rExplicitScale.Maximum;
|
|
|
|
// set automatic PostEquidistant to true (maybe scaling dependent?)
|
|
// Note: scaling with PostEquidistant==false is untested and needs review
|
|
if( !(m_aSourceScale.IncrementData.PostEquidistant >>= rExplicitIncrement.PostEquidistant) )
|
|
rExplicitIncrement.PostEquidistant = true;
|
|
|
|
/* All following scaling code will operate on the logarithms of the source
|
|
values. In the last step, the original values will be restored. */
|
|
uno::Reference< XScaling > xScaling = rExplicitScale.Scaling;
|
|
if( !xScaling.is() )
|
|
xScaling.set( AxisHelper::createLogarithmicScaling() );
|
|
uno::Reference< XScaling > xInverseScaling = xScaling->getInverseScaling();
|
|
|
|
fSourceMinimum = xScaling->doScaling( fSourceMinimum );
|
|
if( !std::isfinite( fSourceMinimum ) )
|
|
fSourceMinimum = 0.0;
|
|
else if( ::rtl::math::approxEqual( fSourceMinimum, ::rtl::math::approxFloor( fSourceMinimum ) ) )
|
|
fSourceMinimum = ::rtl::math::approxFloor( fSourceMinimum );
|
|
|
|
fSourceMaximum = xScaling->doScaling( fSourceMaximum );
|
|
if( !std::isfinite( fSourceMaximum ) )
|
|
fSourceMaximum = 0.0;
|
|
else if( ::rtl::math::approxEqual( fSourceMaximum, ::rtl::math::approxFloor( fSourceMaximum ) ) )
|
|
fSourceMaximum = ::rtl::math::approxFloor( fSourceMaximum );
|
|
|
|
/* If range is invalid (minimum greater than maximum), change one of the
|
|
variable limits to validate the range. In this step, a zero-sized range
|
|
is still allowed. */
|
|
if( fSourceMinimum > fSourceMaximum )
|
|
{
|
|
// force changing the maximum, if both limits are fixed
|
|
if( bAutoMaximum || !bAutoMinimum )
|
|
fSourceMaximum = fSourceMinimum;
|
|
else
|
|
fSourceMinimum = fSourceMaximum;
|
|
}
|
|
|
|
/* If maximum is less than 0 (and therefore minimum too), minimum and
|
|
maximum will be negated and swapped to make the following algorithms
|
|
easier. Example: Both ranges [2,5] and [-5,-2] will be processed as
|
|
[2,5], and the latter will be swapped back later. The range [0,0] is
|
|
explicitly excluded from swapping (this would result in [-1,0] instead
|
|
of the expected [0,1]). */
|
|
bool bSwapAndNegateRange = (fSourceMinimum < 0.0) && (fSourceMaximum <= 0.0);
|
|
if( bSwapAndNegateRange )
|
|
{
|
|
double fTempValue = fSourceMinimum;
|
|
fSourceMinimum = -fSourceMaximum;
|
|
fSourceMaximum = -fTempValue;
|
|
std::swap( bAutoMinimum, bAutoMaximum );
|
|
}
|
|
|
|
// *** STEP 2: find temporary (unrounded) axis minimum and maximum ***
|
|
|
|
double fTempMinimum = fSourceMinimum;
|
|
double fTempMaximum = fSourceMaximum;
|
|
|
|
/* If minimum is variable and greater than 0 (and therefore maximum too),
|
|
means all original values are greater than 1 (or all values are less
|
|
than 1, and the range has been swapped above), then: */
|
|
if( bAutoMinimum && (fTempMinimum > 0.0) )
|
|
{
|
|
double fMinimumFloor = ::rtl::math::approxFloor( fTempMinimum );
|
|
double fMaximumFloor = ::rtl::math::approxFloor( fTempMaximum );
|
|
// handle the exact value B^(n+1) to be in the range [B^n,B^(n+1)]
|
|
if( ::rtl::math::approxEqual( fTempMaximum, fMaximumFloor ) )
|
|
fMaximumFloor -= 1.0;
|
|
|
|
if( fMinimumFloor == fMaximumFloor )
|
|
{
|
|
/* if minimum and maximum are in one increment interval, expand
|
|
minimum toward 0 to make the 'shorter' data points visible. */
|
|
if( m_bExpandNarrowValuesTowardZero )
|
|
fTempMinimum -= 1.0;
|
|
}
|
|
}
|
|
|
|
/* If range is still zero-sized (e.g. when minimum is fixed), set minimum
|
|
to 0, which makes the axis start/stop at the value 1. */
|
|
if( fTempMinimum == fTempMaximum )
|
|
{
|
|
if( bAutoMinimum && (fTempMaximum > 0.0) )
|
|
fTempMinimum = 0.0;
|
|
else
|
|
fTempMaximum += 1.0; // always add one interval, even if maximum is fixed
|
|
}
|
|
|
|
// *** STEP 3: calculate main interval size ***
|
|
|
|
// base value (anchor position of the intervals), already scaled
|
|
if( !(m_aSourceScale.IncrementData.BaseValue >>= rExplicitIncrement.BaseValue) )
|
|
{
|
|
//scaling dependent
|
|
//@maybe todo is this default also plotter dependent ??
|
|
if( !bAutoMinimum )
|
|
rExplicitIncrement.BaseValue = fTempMinimum;
|
|
else if( !bAutoMaximum )
|
|
rExplicitIncrement.BaseValue = fTempMaximum;
|
|
else
|
|
rExplicitIncrement.BaseValue = 0.0;
|
|
}
|
|
|
|
// calculate automatic interval
|
|
bool bAutoDistance = !(m_aSourceScale.IncrementData.Distance >>= rExplicitIncrement.Distance);
|
|
if( bAutoDistance )
|
|
rExplicitIncrement.Distance = 0.0;
|
|
|
|
/* Restrict number of allowed intervals with user-defined distance to
|
|
MAXIMUM_MANUAL_INCREMENT_COUNT. */
|
|
sal_Int32 nMaxMainIncrementCount = bAutoDistance ?
|
|
m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT;
|
|
|
|
// repeat calculation until number of intervals are valid
|
|
bool bNeedIteration = true;
|
|
bool bHasCalculatedDistance = false;
|
|
while( bNeedIteration )
|
|
{
|
|
if( bAutoDistance )
|
|
{
|
|
// first iteration: calculate interval size from axis limits
|
|
if( !bHasCalculatedDistance )
|
|
{
|
|
double fMinimumFloor = ::rtl::math::approxFloor( fTempMinimum );
|
|
double fMaximumCeil = ::rtl::math::approxCeil( fTempMaximum );
|
|
rExplicitIncrement.Distance = ::rtl::math::approxCeil( (fMaximumCeil - fMinimumFloor) / nMaxMainIncrementCount );
|
|
}
|
|
else
|
|
{
|
|
// following iterations: increase distance
|
|
rExplicitIncrement.Distance += 1.0;
|
|
}
|
|
|
|
// for next iteration: distance calculated -> use else path to increase
|
|
bHasCalculatedDistance = true;
|
|
}
|
|
|
|
// *** STEP 4: additional space above or below the data points ***
|
|
|
|
double fAxisMinimum = fTempMinimum;
|
|
double fAxisMaximum = fTempMaximum;
|
|
|
|
// round to entire multiples of the distance and add additional space
|
|
if( bAutoMinimum && m_bExpandBorderToIncrementRhythm )
|
|
{
|
|
fAxisMinimum = EquidistantTickFactory::getMinimumAtIncrement( fAxisMinimum, rExplicitIncrement );
|
|
|
|
//ensure valid values after scaling #i100995#
|
|
if( !bAutoDistance )
|
|
{
|
|
double fCheck = xInverseScaling->doScaling( fAxisMinimum );
|
|
if( !std::isfinite( fCheck ) || fCheck <= 0 )
|
|
{
|
|
bAutoDistance = true;
|
|
bHasCalculatedDistance = false;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if( bAutoMaximum && m_bExpandBorderToIncrementRhythm )
|
|
{
|
|
fAxisMaximum = EquidistantTickFactory::getMaximumAtIncrement( fAxisMaximum, rExplicitIncrement );
|
|
|
|
//ensure valid values after scaling #i100995#
|
|
if( !bAutoDistance )
|
|
{
|
|
double fCheck = xInverseScaling->doScaling( fAxisMaximum );
|
|
if( !std::isfinite( fCheck ) || fCheck <= 0 )
|
|
{
|
|
bAutoDistance = true;
|
|
bHasCalculatedDistance = false;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
// set the resulting limits (swap back to negative range if needed)
|
|
if( bSwapAndNegateRange )
|
|
{
|
|
rExplicitScale.Minimum = -fAxisMaximum;
|
|
rExplicitScale.Maximum = -fAxisMinimum;
|
|
}
|
|
else
|
|
{
|
|
rExplicitScale.Minimum = fAxisMinimum;
|
|
rExplicitScale.Maximum = fAxisMaximum;
|
|
}
|
|
|
|
/* If the number of intervals is too high (e.g. due to invalid fixed
|
|
distance or due to added space above or below data points),
|
|
calculate again with increased distance. */
|
|
double fDistanceCount = ::rtl::math::approxFloor( (fAxisMaximum - fAxisMinimum) / rExplicitIncrement.Distance );
|
|
bNeedIteration = static_cast< sal_Int32 >( fDistanceCount ) > nMaxMainIncrementCount;
|
|
// if manual distance is invalid, trigger automatic calculation
|
|
if( bNeedIteration )
|
|
bAutoDistance = true;
|
|
|
|
// convert limits back to logarithmic scale
|
|
rExplicitScale.Minimum = xInverseScaling->doScaling( rExplicitScale.Minimum );
|
|
rExplicitScale.Maximum = xInverseScaling->doScaling( rExplicitScale.Maximum );
|
|
|
|
//ensure valid values after scaling #i100995#
|
|
if( !std::isfinite( rExplicitScale.Minimum ) || rExplicitScale.Minimum <= 0)
|
|
{
|
|
rExplicitScale.Minimum = fInputMinimum;
|
|
if( !std::isfinite( rExplicitScale.Minimum ) || rExplicitScale.Minimum <= 0 )
|
|
rExplicitScale.Minimum = 1.0;
|
|
}
|
|
if( !std::isfinite( rExplicitScale.Maximum) || rExplicitScale.Maximum <= 0 )
|
|
{
|
|
rExplicitScale.Maximum= fInputMaximum;
|
|
if( !std::isfinite( rExplicitScale.Maximum) || rExplicitScale.Maximum <= 0 )
|
|
rExplicitScale.Maximum = 10.0;
|
|
}
|
|
if( rExplicitScale.Maximum < rExplicitScale.Minimum )
|
|
std::swap( rExplicitScale.Maximum, rExplicitScale.Minimum );
|
|
}
|
|
|
|
//fill explicit sub increment
|
|
sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength();
|
|
for( sal_Int32 nN=0; nN<nSubCount; nN++ )
|
|
{
|
|
ExplicitSubIncrement aExplicitSubIncrement;
|
|
const SubIncrement& rSubIncrement = m_aSourceScale.IncrementData.SubIncrements[nN];
|
|
if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount))
|
|
{
|
|
//scaling dependent
|
|
//@todo autocalculate IntervalCount dependent on MainIncrement and scaling
|
|
aExplicitSubIncrement.IntervalCount = 9;
|
|
}
|
|
lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount );
|
|
if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant))
|
|
{
|
|
//scaling dependent
|
|
aExplicitSubIncrement.PostEquidistant = false;
|
|
}
|
|
rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement);
|
|
}
|
|
}
|
|
|
|
void ScaleAutomatism::calculateExplicitIncrementAndScaleForDateTimeAxis(
|
|
ExplicitScaleData& rExplicitScale,
|
|
ExplicitIncrementData& rExplicitIncrement,
|
|
bool bAutoMinimum, bool bAutoMaximum ) const
|
|
{
|
|
Date aMinDate(m_aNullDate); aMinDate.AddDays(::rtl::math::approxFloor(rExplicitScale.Minimum));
|
|
Date aMaxDate(m_aNullDate); aMaxDate.AddDays(::rtl::math::approxFloor(rExplicitScale.Maximum));
|
|
rExplicitIncrement.PostEquidistant = false;
|
|
|
|
if( aMinDate > aMaxDate )
|
|
{
|
|
std::swap(aMinDate,aMaxDate);
|
|
}
|
|
|
|
if( !(m_aSourceScale.TimeIncrement.TimeResolution >>= rExplicitScale.TimeResolution) )
|
|
rExplicitScale.TimeResolution = m_nTimeResolution;
|
|
|
|
rExplicitScale.Scaling = new DateScaling(m_aNullDate,rExplicitScale.TimeResolution,false);
|
|
|
|
// choose min and max suitable to time resolution
|
|
switch( rExplicitScale.TimeResolution )
|
|
{
|
|
case DAY:
|
|
if( rExplicitScale.m_bShiftedCategoryPosition )
|
|
++aMaxDate; //for explicit scales we need one interval more (maximum excluded)
|
|
break;
|
|
case MONTH:
|
|
aMinDate.SetDay(1);
|
|
aMaxDate.SetDay(1);
|
|
if( rExplicitScale.m_bShiftedCategoryPosition )
|
|
aMaxDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,1);//for explicit scales we need one interval more (maximum excluded)
|
|
if( DateHelper::IsLessThanOneMonthAway( aMinDate, aMaxDate ) )
|
|
{
|
|
if( bAutoMaximum || !bAutoMinimum )
|
|
aMaxDate = DateHelper::GetDateSomeMonthsAway(aMinDate,1);
|
|
else
|
|
aMinDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,-1);
|
|
}
|
|
break;
|
|
case YEAR:
|
|
aMinDate.SetDay(1);
|
|
aMinDate.SetMonth(1);
|
|
aMaxDate.SetDay(1);
|
|
aMaxDate.SetMonth(1);
|
|
if( rExplicitScale.m_bShiftedCategoryPosition )
|
|
aMaxDate = DateHelper::GetDateSomeYearsAway(aMaxDate,1);//for explicit scales we need one interval more (maximum excluded)
|
|
if( DateHelper::IsLessThanOneYearAway( aMinDate, aMaxDate ) )
|
|
{
|
|
if( bAutoMaximum || !bAutoMinimum )
|
|
aMaxDate = DateHelper::GetDateSomeYearsAway(aMinDate,1);
|
|
else
|
|
aMinDate = DateHelper::GetDateSomeYearsAway(aMaxDate,-1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// set the resulting limits (swap back to negative range if needed)
|
|
rExplicitScale.Minimum = aMinDate - m_aNullDate;
|
|
rExplicitScale.Maximum = aMaxDate - m_aNullDate;
|
|
|
|
bool bAutoMajor = !(m_aSourceScale.TimeIncrement.MajorTimeInterval >>= rExplicitIncrement.MajorTimeInterval);
|
|
bool bAutoMinor = !(m_aSourceScale.TimeIncrement.MinorTimeInterval >>= rExplicitIncrement.MinorTimeInterval);
|
|
|
|
sal_Int32 nMaxMainIncrementCount = bAutoMajor ?
|
|
m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT;
|
|
if( nMaxMainIncrementCount > 1 )
|
|
nMaxMainIncrementCount--;
|
|
|
|
//choose major time interval:
|
|
tools::Long nDayCount = aMaxDate - aMinDate;
|
|
tools::Long nMainIncrementCount = 1;
|
|
if( !bAutoMajor )
|
|
{
|
|
tools::Long nIntervalDayCount = rExplicitIncrement.MajorTimeInterval.Number;
|
|
if( rExplicitIncrement.MajorTimeInterval.TimeUnit < rExplicitScale.TimeResolution )
|
|
rExplicitIncrement.MajorTimeInterval.TimeUnit = rExplicitScale.TimeResolution;
|
|
switch( rExplicitIncrement.MajorTimeInterval.TimeUnit )
|
|
{
|
|
case DAY:
|
|
break;
|
|
case MONTH:
|
|
nIntervalDayCount*=31;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ...
|
|
break;
|
|
case YEAR:
|
|
nIntervalDayCount*=365;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ...
|
|
break;
|
|
}
|
|
nMainIncrementCount = nDayCount/nIntervalDayCount;
|
|
if( nMainIncrementCount > nMaxMainIncrementCount )
|
|
bAutoMajor = true;
|
|
}
|
|
if( bAutoMajor )
|
|
{
|
|
tools::Long nNumer = 1;
|
|
tools::Long nIntervalDays = nDayCount / nMaxMainIncrementCount;
|
|
double nDaysPerInterval = 1.0;
|
|
if( nIntervalDays>365 || rExplicitScale.TimeResolution==YEAR )
|
|
{
|
|
rExplicitIncrement.MajorTimeInterval.TimeUnit = YEAR;
|
|
nDaysPerInterval = 365.0;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ...
|
|
}
|
|
else if( nIntervalDays>31 || rExplicitScale.TimeResolution==MONTH )
|
|
{
|
|
rExplicitIncrement.MajorTimeInterval.TimeUnit = MONTH;
|
|
nDaysPerInterval = 31.0;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ...
|
|
}
|
|
else
|
|
{
|
|
rExplicitIncrement.MajorTimeInterval.TimeUnit = DAY;
|
|
nDaysPerInterval = 1.0;
|
|
}
|
|
|
|
nNumer = static_cast<sal_Int32>( rtl::math::approxFloor( nIntervalDays/nDaysPerInterval ) );
|
|
if(nNumer<=0)
|
|
nNumer=1;
|
|
if( rExplicitIncrement.MajorTimeInterval.TimeUnit == DAY )
|
|
{
|
|
if( nNumer>2 && nNumer<7 )
|
|
nNumer=7;
|
|
else if( nNumer>7 )
|
|
{
|
|
rExplicitIncrement.MajorTimeInterval.TimeUnit = MONTH;
|
|
nDaysPerInterval = 31.0;
|
|
nNumer = static_cast<sal_Int32>( rtl::math::approxFloor( nIntervalDays/nDaysPerInterval ) );
|
|
if(nNumer<=0)
|
|
nNumer=1;
|
|
}
|
|
}
|
|
rExplicitIncrement.MajorTimeInterval.Number = nNumer;
|
|
nMainIncrementCount = static_cast<tools::Long>(nDayCount/(nNumer*nDaysPerInterval));
|
|
}
|
|
|
|
//choose minor time interval:
|
|
if( !bAutoMinor )
|
|
{
|
|
if( rExplicitIncrement.MinorTimeInterval.TimeUnit > rExplicitIncrement.MajorTimeInterval.TimeUnit )
|
|
rExplicitIncrement.MinorTimeInterval.TimeUnit = rExplicitIncrement.MajorTimeInterval.TimeUnit;
|
|
tools::Long nIntervalDayCount = rExplicitIncrement.MinorTimeInterval.Number;
|
|
switch( rExplicitIncrement.MinorTimeInterval.TimeUnit )
|
|
{
|
|
case DAY:
|
|
break;
|
|
case MONTH:
|
|
nIntervalDayCount*=31;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ...
|
|
break;
|
|
case YEAR:
|
|
nIntervalDayCount*=365;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ...
|
|
break;
|
|
}
|
|
if( nDayCount/nIntervalDayCount > nMaxMainIncrementCount )
|
|
bAutoMinor = true;
|
|
}
|
|
if( !bAutoMinor )
|
|
return;
|
|
|
|
rExplicitIncrement.MinorTimeInterval.TimeUnit = rExplicitIncrement.MajorTimeInterval.TimeUnit;
|
|
rExplicitIncrement.MinorTimeInterval.Number = 1;
|
|
if( nMainIncrementCount > 100 )
|
|
rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number;
|
|
else
|
|
{
|
|
if( rExplicitIncrement.MajorTimeInterval.Number >= 2 )
|
|
{
|
|
if( !(rExplicitIncrement.MajorTimeInterval.Number%2) )
|
|
rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/2;
|
|
else if( !(rExplicitIncrement.MajorTimeInterval.Number%3) )
|
|
rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/3;
|
|
else if( !(rExplicitIncrement.MajorTimeInterval.Number%5) )
|
|
rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/5;
|
|
else if( rExplicitIncrement.MajorTimeInterval.Number > 50 )
|
|
rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number;
|
|
}
|
|
else
|
|
{
|
|
switch( rExplicitIncrement.MajorTimeInterval.TimeUnit )
|
|
{
|
|
case DAY:
|
|
break;
|
|
case MONTH:
|
|
if( rExplicitScale.TimeResolution == DAY )
|
|
rExplicitIncrement.MinorTimeInterval.TimeUnit = DAY;
|
|
break;
|
|
case YEAR:
|
|
if( rExplicitScale.TimeResolution <= MONTH )
|
|
rExplicitIncrement.MinorTimeInterval.TimeUnit = MONTH;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void ScaleAutomatism::calculateExplicitIncrementAndScaleForLinear(
|
|
ExplicitScaleData& rExplicitScale,
|
|
ExplicitIncrementData& rExplicitIncrement,
|
|
bool bAutoMinimum, bool bAutoMaximum ) const
|
|
{
|
|
// *** STEP 1: initialize the range data ***
|
|
|
|
double fSourceMinimum = rExplicitScale.Minimum;
|
|
double fSourceMaximum = rExplicitScale.Maximum;
|
|
|
|
// set automatic PostEquidistant to true (maybe scaling dependent?)
|
|
if( !(m_aSourceScale.IncrementData.PostEquidistant >>= rExplicitIncrement.PostEquidistant) )
|
|
rExplicitIncrement.PostEquidistant = true;
|
|
|
|
/* If range is invalid (minimum greater than maximum), change one of the
|
|
variable limits to validate the range. In this step, a zero-sized range
|
|
is still allowed. */
|
|
if( fSourceMinimum > fSourceMaximum )
|
|
{
|
|
// force changing the maximum, if both limits are fixed
|
|
if( bAutoMaximum || !bAutoMinimum )
|
|
fSourceMaximum = fSourceMinimum;
|
|
else
|
|
fSourceMinimum = fSourceMaximum;
|
|
}
|
|
|
|
/* If maximum is zero or negative (and therefore minimum too), minimum and
|
|
maximum will be negated and swapped to make the following algorithms
|
|
easier. Example: Both ranges [2,5] and [-5,-2] will be processed as
|
|
[2,5], and the latter will be swapped back later. The range [0,0] is
|
|
explicitly excluded from swapping (this would result in [-1,0] instead
|
|
of the expected [0,1]). */
|
|
bool bSwapAndNegateRange = (fSourceMinimum < 0.0) && (fSourceMaximum <= 0.0);
|
|
if( bSwapAndNegateRange )
|
|
{
|
|
double fTempValue = fSourceMinimum;
|
|
fSourceMinimum = -fSourceMaximum;
|
|
fSourceMaximum = -fTempValue;
|
|
std::swap( bAutoMinimum, bAutoMaximum );
|
|
}
|
|
|
|
// *** STEP 2: find temporary (unrounded) axis minimum and maximum ***
|
|
|
|
double fTempMinimum = fSourceMinimum;
|
|
double fTempMaximum = fSourceMaximum;
|
|
|
|
/* If minimum is variable and greater than 0 (and therefore maximum too),
|
|
means all values are positive (or all values are negative, and the
|
|
range has been swapped above), then: */
|
|
if( bAutoMinimum && (fTempMinimum > 0.0) )
|
|
{
|
|
/* If minimum equals maximum, or if minimum is less than 5/6 of
|
|
maximum, set minimum to 0. */
|
|
if( (fTempMinimum == fTempMaximum) || (fTempMinimum / fTempMaximum < 5.0 / 6.0) )
|
|
{
|
|
if( m_bExpandWideValuesToZero )
|
|
fTempMinimum = 0.0;
|
|
}
|
|
/* Else (minimum is greater than or equal to 5/6 of maximum), add half
|
|
of the visible range (expand minimum toward 0) to make the
|
|
'shorter' data points visible. */
|
|
else
|
|
{
|
|
if( m_bExpandNarrowValuesTowardZero )
|
|
fTempMinimum -= (fTempMaximum - fTempMinimum) / 2.0;
|
|
}
|
|
}
|
|
|
|
/* If range is still zero-sized (e.g. when minimum is fixed), add some
|
|
space to a variable limit. */
|
|
if( fTempMinimum == fTempMaximum )
|
|
{
|
|
if( bAutoMaximum || !bAutoMinimum )
|
|
{
|
|
// change 0 to 1, otherwise double the value
|
|
if( fTempMaximum == 0.0 )
|
|
fTempMaximum = 1.0;
|
|
else
|
|
fTempMaximum *= 2.0;
|
|
}
|
|
else
|
|
{
|
|
// change 0 to -1, otherwise halve the value
|
|
if( fTempMinimum == 0.0 )
|
|
fTempMinimum = -1.0;
|
|
else
|
|
fTempMinimum /= 2.0;
|
|
}
|
|
}
|
|
|
|
// *** STEP 3: calculate main interval size ***
|
|
|
|
// base value (anchor position of the intervals)
|
|
if( !(m_aSourceScale.IncrementData.BaseValue >>= rExplicitIncrement.BaseValue) )
|
|
{
|
|
if( !bAutoMinimum )
|
|
rExplicitIncrement.BaseValue = fTempMinimum;
|
|
else if( !bAutoMaximum )
|
|
rExplicitIncrement.BaseValue = fTempMaximum;
|
|
else
|
|
rExplicitIncrement.BaseValue = 0.0;
|
|
}
|
|
|
|
// calculate automatic interval
|
|
bool bAutoDistance = !(m_aSourceScale.IncrementData.Distance >>= rExplicitIncrement.Distance);
|
|
/* Restrict number of allowed intervals with user-defined distance to
|
|
MAXIMUM_MANUAL_INCREMENT_COUNT. */
|
|
sal_Int32 nMaxMainIncrementCount = bAutoDistance ?
|
|
m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT;
|
|
|
|
double fDistanceMagnitude = 0.0;
|
|
double fDistanceNormalized = 0.0;
|
|
bool bHasNormalizedDistance = false;
|
|
|
|
// repeat calculation until number of intervals are valid
|
|
bool bNeedIteration = true;
|
|
while( bNeedIteration )
|
|
{
|
|
if( bAutoDistance )
|
|
{
|
|
// first iteration: calculate interval size from axis limits
|
|
if( !bHasNormalizedDistance )
|
|
{
|
|
// raw size of an interval
|
|
double fDistance = (fTempMaximum - fTempMinimum) / nMaxMainIncrementCount;
|
|
|
|
// if distance of is less than 1e-307, do not do anything
|
|
if( fDistance <= 1.0e-307 )
|
|
{
|
|
fDistanceNormalized = 1.0;
|
|
fDistanceMagnitude = 1.0e-307;
|
|
}
|
|
else if ( !std::isfinite(fDistance) )
|
|
{
|
|
// fdo#43703: Handle values bigger than limits correctly
|
|
fDistanceNormalized = 1.0;
|
|
fDistanceMagnitude = std::numeric_limits<double>::max();
|
|
}
|
|
else
|
|
{
|
|
// distance magnitude (a power of 10)
|
|
int nExponent = static_cast< int >( ::rtl::math::approxFloor( log10( fDistance ) ) );
|
|
fDistanceMagnitude = ::rtl::math::pow10Exp( 1.0, nExponent );
|
|
|
|
// stick normalized distance to a few predefined values
|
|
fDistanceNormalized = fDistance / fDistanceMagnitude;
|
|
if( fDistanceNormalized <= 1.0 )
|
|
fDistanceNormalized = 1.0;
|
|
else if( fDistanceNormalized <= 2.0 )
|
|
fDistanceNormalized = 2.0;
|
|
else if( fDistanceNormalized <= 5.0 )
|
|
fDistanceNormalized = 5.0;
|
|
else
|
|
{
|
|
fDistanceNormalized = 1.0;
|
|
fDistanceMagnitude *= 10;
|
|
}
|
|
}
|
|
// for next iteration: distance is normalized -> use else path to increase distance
|
|
bHasNormalizedDistance = true;
|
|
}
|
|
// following iterations: increase distance, use only allowed values
|
|
else
|
|
{
|
|
if( fDistanceNormalized == 1.0 )
|
|
fDistanceNormalized = 2.0;
|
|
else if( fDistanceNormalized == 2.0 )
|
|
fDistanceNormalized = 5.0;
|
|
else
|
|
{
|
|
fDistanceNormalized = 1.0;
|
|
fDistanceMagnitude *= 10;
|
|
}
|
|
}
|
|
|
|
// set the resulting distance
|
|
rExplicitIncrement.Distance = fDistanceNormalized * fDistanceMagnitude;
|
|
}
|
|
|
|
// *** STEP 4: additional space above or below the data points ***
|
|
|
|
double fAxisMinimum = fTempMinimum;
|
|
double fAxisMaximum = fTempMaximum;
|
|
|
|
// round to entire multiples of the distance and add additional space
|
|
if( bAutoMinimum )
|
|
{
|
|
// round to entire multiples of the distance, based on the base value
|
|
if( m_bExpandBorderToIncrementRhythm )
|
|
fAxisMinimum = EquidistantTickFactory::getMinimumAtIncrement( fAxisMinimum, rExplicitIncrement );
|
|
// additional space, if source minimum is to near at axis minimum
|
|
if( m_bExpandIfValuesCloseToBorder )
|
|
if( (fAxisMinimum != 0.0) && ((fAxisMaximum - fSourceMinimum) / (fAxisMaximum - fAxisMinimum) > 20.0 / 21.0) )
|
|
fAxisMinimum -= rExplicitIncrement.Distance;
|
|
}
|
|
if( bAutoMaximum )
|
|
{
|
|
// round to entire multiples of the distance, based on the base value
|
|
if( m_bExpandBorderToIncrementRhythm )
|
|
fAxisMaximum = EquidistantTickFactory::getMaximumAtIncrement( fAxisMaximum, rExplicitIncrement );
|
|
// additional space, if source maximum is to near at axis maximum
|
|
if( m_bExpandIfValuesCloseToBorder )
|
|
if( (fAxisMaximum != 0.0) && ((fSourceMaximum - fAxisMinimum) / (fAxisMaximum - fAxisMinimum) > 20.0 / 21.0) )
|
|
fAxisMaximum += rExplicitIncrement.Distance;
|
|
}
|
|
|
|
// set the resulting limits (swap back to negative range if needed)
|
|
if( bSwapAndNegateRange )
|
|
{
|
|
rExplicitScale.Minimum = -fAxisMaximum;
|
|
rExplicitScale.Maximum = -fAxisMinimum;
|
|
}
|
|
else
|
|
{
|
|
rExplicitScale.Minimum = fAxisMinimum;
|
|
rExplicitScale.Maximum = fAxisMaximum;
|
|
}
|
|
|
|
/* If the number of intervals is too high (e.g. due to invalid fixed
|
|
distance or due to added space above or below data points),
|
|
calculate again with increased distance. */
|
|
double fDistanceCount = ::rtl::math::approxFloor( (fAxisMaximum - fAxisMinimum) / rExplicitIncrement.Distance );
|
|
bNeedIteration = static_cast< sal_Int32 >( fDistanceCount ) > nMaxMainIncrementCount;
|
|
// if manual distance is invalid, trigger automatic calculation
|
|
if( bNeedIteration )
|
|
bAutoDistance = true;
|
|
}
|
|
|
|
//fill explicit sub increment
|
|
sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength();
|
|
for( sal_Int32 nN=0; nN<nSubCount; nN++ )
|
|
{
|
|
ExplicitSubIncrement aExplicitSubIncrement;
|
|
const SubIncrement& rSubIncrement= m_aSourceScale.IncrementData.SubIncrements[nN];
|
|
if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount))
|
|
{
|
|
//scaling dependent
|
|
//@todo autocalculate IntervalCount dependent on MainIncrement and scaling
|
|
aExplicitSubIncrement.IntervalCount = 2;
|
|
}
|
|
lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount );
|
|
if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant))
|
|
{
|
|
//scaling dependent
|
|
aExplicitSubIncrement.PostEquidistant = false;
|
|
}
|
|
rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement);
|
|
}
|
|
}
|
|
|
|
} //namespace chart
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|