diff options
Diffstat (limited to 'chart2/source/view/axes/Tickmarks.cxx')
-rw-r--r-- | chart2/source/view/axes/Tickmarks.cxx | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/chart2/source/view/axes/Tickmarks.cxx b/chart2/source/view/axes/Tickmarks.cxx new file mode 100644 index 000000000..01e4a7216 --- /dev/null +++ b/chart2/source/view/axes/Tickmarks.cxx @@ -0,0 +1,317 @@ +/* -*- 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 "Tickmarks.hxx" +#include "Tickmarks_Equidistant.hxx" +#include "Tickmarks_Dates.hxx" +#include <ViewDefines.hxx> +#include "VAxisProperties.hxx" +#include <osl/diagnose.h> +#include <com/sun/star/chart2/AxisType.hpp> + +using namespace ::com::sun::star; +using ::basegfx::B2DVector; + +namespace chart { + +TickInfo::TickInfo( const uno::Reference<chart2::XScaling>& xInverse ) +: fScaledTickValue( 0.0 ) +, xInverseScaling( xInverse ) +, aTickScreenPosition(0.0,0.0) +, nFactorForLimitedTextWidth(1) +, bPaintIt( true ) +{ +} + +double TickInfo::getUnscaledTickValue() const +{ + if( xInverseScaling.is() ) + return xInverseScaling->doScaling( fScaledTickValue ); + else + return fScaledTickValue; +} + +sal_Int32 TickInfo::getScreenDistanceBetweenTicks( const TickInfo& rOherTickInfo ) const +{ + //return the positive distance between the two first tickmarks in screen values + + B2DVector aDistance = rOherTickInfo.aTickScreenPosition - aTickScreenPosition; + sal_Int32 nRet = static_cast<sal_Int32>(aDistance.getLength()); + if(nRet<0) + nRet *= -1; + return nRet; +} + +PureTickIter::PureTickIter( TickInfoArrayType& rTickInfoVector ) + : m_rTickVector(rTickInfoVector) + , m_aTickIter(m_rTickVector.begin()) +{ +} +PureTickIter::~PureTickIter() +{ +} +TickInfo* PureTickIter::firstInfo() +{ + m_aTickIter = m_rTickVector.begin(); + if(m_aTickIter!=m_rTickVector.end()) + return &*m_aTickIter; + return nullptr; +} +TickInfo* PureTickIter::nextInfo() +{ + if(m_aTickIter!=m_rTickVector.end()) + { + ++m_aTickIter; + if(m_aTickIter!=m_rTickVector.end()) + return &*m_aTickIter; + } + return nullptr; +} + +TickFactory::TickFactory( + const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement ) + : m_rScale( rScale ) + , m_rIncrement( rIncrement ) +{ + //@todo: make sure that the scale is valid for the scaling + + if( m_rScale.Scaling.is() ) + { + m_xInverseScaling = m_rScale.Scaling->getInverseScaling(); + OSL_ENSURE( m_xInverseScaling.is(), "each Scaling needs to return an inverse Scaling" ); + } + + m_fScaledVisibleMin = m_rScale.Minimum; + if( m_xInverseScaling.is() ) + m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin); + + m_fScaledVisibleMax = m_rScale.Maximum; + if( m_xInverseScaling.is() ) + m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax); +} + +TickFactory::~TickFactory() +{ +} + +bool TickFactory::isDateAxis() const +{ + return m_rScale.AxisType == chart2::AxisType::DATE; +} + +void TickFactory::getAllTicks( TickInfoArraysType& rAllTickInfos ) const +{ + if( isDateAxis() ) + DateTickFactory( m_rScale, m_rIncrement ).getAllTicks( rAllTickInfos ); + else + EquidistantTickFactory( m_rScale, m_rIncrement ).getAllTicks( rAllTickInfos ); +} + +void TickFactory::getAllTicksShifted( TickInfoArraysType& rAllTickInfos ) const +{ + if( isDateAxis() ) + DateTickFactory( m_rScale, m_rIncrement ).getAllTicksShifted( rAllTickInfos ); + else + EquidistantTickFactory( m_rScale, m_rIncrement ).getAllTicksShifted( rAllTickInfos ); +} + +// ___TickFactory_2D___ +TickFactory2D::TickFactory2D( + const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement + //, double fStretch_SceneToScreen, double fOffset_SceneToScreen ) + , const B2DVector& rStartScreenPos, const B2DVector& rEndScreenPos + , const B2DVector& rAxisLineToLabelLineShift ) + : TickFactory( rScale, rIncrement ) + , m_aAxisStartScreenPosition2D(rStartScreenPos) + , m_aAxisEndScreenPosition2D(rEndScreenPos) + , m_aAxisLineToLabelLineShift(rAxisLineToLabelLineShift) + , m_fStretch_LogicToScreen(1.0) + , m_fOffset_LogicToScreen(0.0) +{ + double fWidthY = m_fScaledVisibleMax - m_fScaledVisibleMin; + if (m_rScale.Orientation == chart2::AxisOrientation_MATHEMATICAL) + { + m_fStretch_LogicToScreen = 1.0/fWidthY; + m_fOffset_LogicToScreen = -m_fScaledVisibleMin; + } + else + { + B2DVector aSwap(m_aAxisStartScreenPosition2D); + m_aAxisStartScreenPosition2D = m_aAxisEndScreenPosition2D; + m_aAxisEndScreenPosition2D = aSwap; + + m_fStretch_LogicToScreen = -1.0/fWidthY; + m_fOffset_LogicToScreen = -m_fScaledVisibleMax; + } +} + +TickFactory2D::~TickFactory2D() +{ +} + +bool TickFactory2D::isHorizontalAxis() const +{ + // check trivial cases: + if ( m_aAxisStartScreenPosition2D.getY() == m_aAxisEndScreenPosition2D.getY() ) + return true; + if ( m_aAxisStartScreenPosition2D.getX() == m_aAxisEndScreenPosition2D.getX() ) + return false; + + // for skew axes compare angle with horizontal vector + double fInclination = std::abs(B2DVector(m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D).angle(B2DVector(1.0, 0.0))); + return fInclination < M_PI_4 || fInclination > (M_PI-M_PI_4); +} +bool TickFactory2D::isVerticalAxis() const +{ + // check trivial cases: + if ( m_aAxisStartScreenPosition2D.getX() == m_aAxisEndScreenPosition2D.getX() ) + return true; + if ( m_aAxisStartScreenPosition2D.getY() == m_aAxisEndScreenPosition2D.getY() ) + return false; + + // for skew axes compare angle with vertical vector + double fInclination = std::abs(B2DVector(m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D).angle(B2DVector(0.0, -1.0))); + return fInclination < M_PI_4 || fInclination > (M_PI-M_PI_4); +} +//static +sal_Int32 TickFactory2D::getTickScreenDistance( TickIter& rIter ) +{ + //return the positive distance between the two first tickmarks in screen values + //if there are less than two tickmarks -1 is returned + + const TickInfo* pFirstTickInfo = rIter.firstInfo(); + const TickInfo* pSecondTickInfo = rIter.nextInfo(); + if(!pSecondTickInfo || !pFirstTickInfo) + return -1; + + return pFirstTickInfo->getScreenDistanceBetweenTicks( *pSecondTickInfo ); +} + +B2DVector TickFactory2D::getTickScreenPosition2D( double fScaledLogicTickValue ) const +{ + B2DVector aRet(m_aAxisStartScreenPosition2D); + aRet += (m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D) + *((fScaledLogicTickValue+m_fOffset_LogicToScreen)*m_fStretch_LogicToScreen); + return aRet; +} + +void TickFactory2D::addPointSequenceForTickLine( drawing::PointSequenceSequence& rPoints + , sal_Int32 nSequenceIndex + , double fScaledLogicTickValue, double fInnerDirectionSign + , const TickmarkProperties& rTickmarkProperties + , bool bPlaceAtLabels ) const +{ + if( fInnerDirectionSign==0.0 ) + fInnerDirectionSign = 1.0; + + B2DVector aTickScreenPosition = getTickScreenPosition2D(fScaledLogicTickValue); + if( bPlaceAtLabels ) + aTickScreenPosition += m_aAxisLineToLabelLineShift; + + B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D; + aMainDirection.normalize(); + B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX()); + aOrthoDirection *= fInnerDirectionSign; + aOrthoDirection.normalize(); + + B2DVector aStart = aTickScreenPosition + aOrthoDirection*rTickmarkProperties.RelativePos; + B2DVector aEnd = aStart - aOrthoDirection*rTickmarkProperties.Length; + + rPoints.getArray()[nSequenceIndex] + = { { static_cast<sal_Int32>(aStart.getX()), static_cast<sal_Int32>(aStart.getY()) }, + { static_cast<sal_Int32>(aEnd.getX()), static_cast<sal_Int32>(aEnd.getY()) } }; +} + +B2DVector TickFactory2D::getDistanceAxisTickToText( const AxisProperties& rAxisProperties, bool bIncludeFarAwayDistanceIfSo, bool bIncludeSpaceBetweenTickAndText ) const +{ + bool bFarAwayLabels = false; + if( rAxisProperties.m_eLabelPos == css::chart::ChartAxisLabelPosition_OUTSIDE_START + || rAxisProperties.m_eLabelPos == css::chart::ChartAxisLabelPosition_OUTSIDE_END ) + bFarAwayLabels = true; + + double fInnerDirectionSign = rAxisProperties.maLabelAlignment.mfInnerTickDirection; + if( fInnerDirectionSign==0.0 ) + fInnerDirectionSign = 1.0; + + B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D; + aMainDirection.normalize(); + B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX()); + aOrthoDirection *= fInnerDirectionSign; + aOrthoDirection.normalize(); + + B2DVector aStart(0,0), aEnd(0,0); + if( bFarAwayLabels ) + { + TickmarkProperties aProps( AxisProperties::getBiggestTickmarkProperties() ); + aStart = aOrthoDirection*aProps.RelativePos; + aEnd = aStart - aOrthoDirection*aProps.Length; + } + else + { + for( sal_Int32 nN=rAxisProperties.m_aTickmarkPropertiesList.size();nN--;) + { + const TickmarkProperties& rProps = rAxisProperties.m_aTickmarkPropertiesList[nN]; + B2DVector aNewStart = aOrthoDirection*rProps.RelativePos; + B2DVector aNewEnd = aNewStart - aOrthoDirection*rProps.Length; + if(aNewStart.getLength()>aStart.getLength()) + aStart=aNewStart; + if(aNewEnd.getLength()>aEnd.getLength()) + aEnd=aNewEnd; + } + } + + B2DVector aLabelDirection(aStart); + if (rAxisProperties.maLabelAlignment.mfInnerTickDirection != rAxisProperties.maLabelAlignment.mfLabelDirection) + aLabelDirection = aEnd; + + B2DVector aOrthoLabelDirection(aOrthoDirection); + if (rAxisProperties.maLabelAlignment.mfInnerTickDirection != rAxisProperties.maLabelAlignment.mfLabelDirection) + aOrthoLabelDirection*=-1.0; + aOrthoLabelDirection.normalize(); + if( bIncludeSpaceBetweenTickAndText ) + aLabelDirection += aOrthoLabelDirection*AXIS2D_TICKLABELSPACING; + if( bFarAwayLabels && bIncludeFarAwayDistanceIfSo ) + aLabelDirection += m_aAxisLineToLabelLineShift; + return aLabelDirection; +} + +void TickFactory2D::createPointSequenceForAxisMainLine( drawing::PointSequenceSequence& rPoints ) const +{ + rPoints.getArray()[0] = { { static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getX()), + static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getY()) }, + { static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getX()), + static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getY()) } }; +} + +void TickFactory2D::updateScreenValues( TickInfoArraysType& rAllTickInfos ) const +{ + //get the transformed screen values for all tickmarks in rAllTickInfos + for (auto & tickInfos : rAllTickInfos) + { + for (auto & tickInfo : tickInfos) + { + tickInfo.aTickScreenPosition = + getTickScreenPosition2D(tickInfo.fScaledTickValue); + } + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |