summaryrefslogtreecommitdiffstats
path: root/chart2/source/view/axes/VCoordinateSystem.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'chart2/source/view/axes/VCoordinateSystem.cxx')
-rw-r--r--chart2/source/view/axes/VCoordinateSystem.cxx560
1 files changed, 560 insertions, 0 deletions
diff --git a/chart2/source/view/axes/VCoordinateSystem.cxx b/chart2/source/view/axes/VCoordinateSystem.cxx
new file mode 100644
index 000000000..1c900b392
--- /dev/null
+++ b/chart2/source/view/axes/VCoordinateSystem.cxx
@@ -0,0 +1,560 @@
+/* -*- 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 <BaseGFXHelper.hxx>
+#include <VCoordinateSystem.hxx>
+#include "VCartesianCoordinateSystem.hxx"
+#include "VPolarCoordinateSystem.hxx"
+#include <ScaleAutomatism.hxx>
+#include <ShapeFactory.hxx>
+#include <servicenames_coosystems.hxx>
+#include <ObjectIdentifier.hxx>
+#include <ExplicitCategoriesProvider.hxx>
+#include "VAxisBase.hxx"
+#include <defines.hxx>
+#include <chartview/ExplicitValueProvider.hxx>
+#include <com/sun/star/chart/TimeUnit.hpp>
+#include <com/sun/star/chart2/AxisType.hpp>
+#include <com/sun/star/chart2/XCoordinateSystem.hpp>
+#include <comphelper/sequence.hxx>
+#include <tools/diagnose_ex.h>
+#include <algorithm>
+#include <rtl/math.hxx>
+
+namespace chart
+{
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+std::unique_ptr<VCoordinateSystem> VCoordinateSystem::createCoordinateSystem(
+ const Reference< XCoordinateSystem >& xCooSysModel )
+{
+ if( !xCooSysModel.is() )
+ return nullptr;
+
+ OUString aViewServiceName = xCooSysModel->getViewServiceName();
+
+ //@todo: in future the coordinatesystems should be instantiated via service factory
+ std::unique_ptr<VCoordinateSystem> pRet;
+ if( aViewServiceName == CHART2_COOSYSTEM_CARTESIAN_VIEW_SERVICE_NAME )
+ pRet.reset( new VCartesianCoordinateSystem(xCooSysModel) );
+ else if( aViewServiceName == CHART2_COOSYSTEM_POLAR_VIEW_SERVICE_NAME )
+ pRet.reset( new VPolarCoordinateSystem(xCooSysModel) );
+ if(!pRet)
+ pRet.reset( new VCoordinateSystem(xCooSysModel) );
+ return pRet;
+}
+
+VCoordinateSystem::VCoordinateSystem( const Reference< XCoordinateSystem >& xCooSys )
+ : m_xCooSysModel(xCooSys)
+ , m_aMatrixSceneToScreen()
+ , m_eLeftWallPos(CuboidPlanePosition_Left)
+ , m_eBackWallPos(CuboidPlanePosition_Back)
+ , m_eBottomPos(CuboidPlanePosition_Bottom)
+ , m_aMergedMinMaxSupplier()
+ , m_aExplicitScales(3)
+ , m_aExplicitIncrements(3)
+{
+ if( !m_xCooSysModel.is() || m_xCooSysModel->getDimension()<3 )
+ {
+ m_aExplicitScales[2].Minimum = 1.0;
+ m_aExplicitScales[2].Maximum = 2.0;
+ m_aExplicitScales[2].Orientation = AxisOrientation_MATHEMATICAL;
+ }
+}
+VCoordinateSystem::~VCoordinateSystem()
+{
+}
+
+void VCoordinateSystem::initPlottingTargets( const Reference< drawing::XShapes >& xLogicTarget
+ , const Reference< drawing::XShapes >& xFinalTarget
+ , const Reference< lang::XMultiServiceFactory >& xShapeFactory
+ , Reference< drawing::XShapes >& xLogicTargetForSeriesBehindAxis )
+{
+ OSL_PRECOND(xLogicTarget.is()&&xFinalTarget.is()&&xShapeFactory.is(),"no proper initialization parameters");
+ //is only allowed to be called once
+
+ sal_Int32 nDimensionCount = m_xCooSysModel->getDimension();
+ //create group shape for grids first thus axes are always painted above grids
+ ShapeFactory* pShapeFactory = ShapeFactory::getOrCreateShapeFactory(xShapeFactory);
+ if(nDimensionCount==2)
+ {
+ //create and add to target
+ m_xLogicTargetForGrids = pShapeFactory->createGroup2D( xLogicTarget );
+ xLogicTargetForSeriesBehindAxis = pShapeFactory->createGroup2D( xLogicTarget );
+ m_xLogicTargetForAxes = pShapeFactory->createGroup2D( xLogicTarget );
+ }
+ else
+ {
+ //create and added to target
+ m_xLogicTargetForGrids = pShapeFactory->createGroup3D( xLogicTarget );
+ xLogicTargetForSeriesBehindAxis = pShapeFactory->createGroup3D( xLogicTarget );
+ m_xLogicTargetForAxes = pShapeFactory->createGroup3D( xLogicTarget );
+ }
+ m_xFinalTarget = xFinalTarget;
+ m_xShapeFactory = xShapeFactory;
+}
+
+void VCoordinateSystem::setParticle( const OUString& rCooSysParticle )
+{
+ m_aCooSysParticle = rCooSysParticle;
+}
+
+void VCoordinateSystem::setTransformationSceneToScreen(
+ const drawing::HomogenMatrix& rMatrix )
+{
+ m_aMatrixSceneToScreen = rMatrix;
+
+ //correct transformation for axis
+ for (auto const& elem : m_aAxisMap)
+ {
+ VAxisBase* pVAxis = elem.second.get();
+ if( pVAxis )
+ {
+ if(pVAxis->getDimensionCount()==2)
+ pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen );
+ }
+ }
+}
+
+//better performance for big data
+uno::Sequence< sal_Int32 > VCoordinateSystem::getCoordinateSystemResolution(
+ const awt::Size& rPageSize, const awt::Size& rPageResolution )
+{
+ uno::Sequence<sal_Int32> aResolution(
+ std::max<sal_Int32>(m_xCooSysModel->getDimension(), 2));
+
+ for( auto& i : aResolution )
+ i = 1000;
+
+ ::basegfx::B3DTuple aScale( BaseGFXHelper::GetScaleFromMatrix(
+ BaseGFXHelper::HomogenMatrixToB3DHomMatrix(
+ m_aMatrixSceneToScreen ) ) );
+
+ double fCoosysWidth = fabs(aScale.getX()*FIXED_SIZE_FOR_3D_CHART_VOLUME);
+ double fCoosysHeight = fabs(aScale.getY()*FIXED_SIZE_FOR_3D_CHART_VOLUME);
+
+ double fPageWidth = rPageSize.Width;
+ double fPageHeight = rPageSize.Height;
+
+ //factor 2 to avoid rounding problems
+ sal_Int32 nXResolution = static_cast<sal_Int32>(2.0*static_cast<double>(rPageResolution.Width)*fCoosysWidth/fPageWidth);
+ sal_Int32 nYResolution = static_cast<sal_Int32>(2.0*static_cast<double>(rPageResolution.Height)*fCoosysHeight/fPageHeight);
+
+ if( nXResolution < 10 )
+ nXResolution = 10;
+ if( nYResolution < 10 )
+ nYResolution = 10;
+
+ if( getPropertySwapXAndYAxis() )
+ std::swap(nXResolution,nYResolution);
+
+ //2D
+ if( aResolution.getLength() == 2 )
+ {
+ aResolution[0]=nXResolution;
+ aResolution[1]=nYResolution;
+ }
+ else
+ {
+ //this maybe can be optimized further ...
+ sal_Int32 nMaxResolution = std::max( nXResolution, nYResolution );
+ nMaxResolution*=2;
+ for( auto& i : aResolution )
+ i = nMaxResolution;
+ }
+
+ return aResolution;
+}
+
+Reference< XAxis > VCoordinateSystem::getAxisByDimension( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const
+{
+ if( m_xCooSysModel.is() )
+ return m_xCooSysModel->getAxisByDimension( nDimensionIndex, nAxisIndex );
+ return nullptr;
+}
+
+Sequence< Reference< beans::XPropertySet > > VCoordinateSystem::getGridListFromAxis( const Reference< XAxis >& xAxis )
+{
+ std::vector< Reference< beans::XPropertySet > > aRet;
+
+ if( xAxis.is() )
+ {
+ aRet.push_back( xAxis->getGridProperties() );
+ auto aSubGrids( comphelper::sequenceToContainer<std::vector< Reference< beans::XPropertySet > > >( xAxis->getSubGridProperties() ) );
+ aRet.insert( aRet.end(), aSubGrids.begin(), aSubGrids.end() );
+ }
+
+ return comphelper::containerToSequence( aRet );
+}
+
+void VCoordinateSystem::impl_adjustDimension( sal_Int32& rDimensionIndex )
+{
+ if( rDimensionIndex<0 )
+ rDimensionIndex=0;
+ if( rDimensionIndex>2 )
+ rDimensionIndex=2;
+}
+
+void VCoordinateSystem::impl_adjustDimensionAndIndex( sal_Int32& rDimensionIndex, sal_Int32& rAxisIndex ) const
+{
+ impl_adjustDimension( rDimensionIndex );
+
+ if( rAxisIndex < 0 || rAxisIndex > getMaximumAxisIndexByDimension(rDimensionIndex) )
+ rAxisIndex = 0;
+}
+
+void VCoordinateSystem::setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider /*takes ownership*/ )
+{
+ m_apExplicitCategoriesProvider.reset(pExplicitCategoriesProvider);
+}
+
+ExplicitCategoriesProvider* VCoordinateSystem::getExplicitCategoriesProvider()
+{
+ return m_apExplicitCategoriesProvider.get();
+}
+
+std::vector< ExplicitScaleData > VCoordinateSystem::getExplicitScales( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const
+{
+ std::vector< ExplicitScaleData > aRet(m_aExplicitScales);
+
+ impl_adjustDimensionAndIndex( nDimensionIndex, nAxisIndex );
+ aRet[nDimensionIndex]=getExplicitScale( nDimensionIndex, nAxisIndex );
+
+ return aRet;
+}
+
+std::vector< ExplicitIncrementData > VCoordinateSystem::getExplicitIncrements( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const
+{
+ std::vector< ExplicitIncrementData > aRet(m_aExplicitIncrements);
+
+ impl_adjustDimensionAndIndex( nDimensionIndex, nAxisIndex );
+ aRet[nDimensionIndex]=getExplicitIncrement( nDimensionIndex, nAxisIndex );
+
+ return aRet;
+}
+
+ExplicitScaleData VCoordinateSystem::getExplicitScale( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const
+{
+ ExplicitScaleData aRet;
+
+ impl_adjustDimensionAndIndex( nDimensionIndex, nAxisIndex );
+
+ if( nAxisIndex == 0)
+ {
+ aRet = m_aExplicitScales[nDimensionIndex];
+ }
+ else
+ {
+ tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex );
+ tFullExplicitScaleMap::const_iterator aIt = m_aSecondaryExplicitScales.find( aFullAxisIndex );
+ if( aIt != m_aSecondaryExplicitScales.end() )
+ aRet = aIt->second;
+ else
+ aRet = m_aExplicitScales[nDimensionIndex];
+ }
+
+ return aRet;
+}
+
+ExplicitIncrementData VCoordinateSystem::getExplicitIncrement( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const
+{
+ ExplicitIncrementData aRet;
+
+ impl_adjustDimensionAndIndex( nDimensionIndex, nAxisIndex );
+
+ if( nAxisIndex == 0)
+ {
+ aRet = m_aExplicitIncrements[nDimensionIndex];
+ }
+ else
+ {
+ tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex );
+ tFullExplicitIncrementMap::const_iterator aIt = m_aSecondaryExplicitIncrements.find( aFullAxisIndex );
+ if( aIt != m_aSecondaryExplicitIncrements.end() )
+ aRet = aIt->second;
+ else
+ aRet = m_aExplicitIncrements[nDimensionIndex];
+ }
+
+ return aRet;
+}
+
+OUString VCoordinateSystem::createCIDForAxis( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
+{
+ OUString aAxisParticle( ObjectIdentifier::createParticleForAxis( nDimensionIndex, nAxisIndex ) );
+ return ObjectIdentifier::createClassifiedIdentifierForParticles( m_aCooSysParticle, aAxisParticle );
+}
+OUString VCoordinateSystem::createCIDForGrid( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
+{
+ OUString aGridParticle( ObjectIdentifier::createParticleForGrid( nDimensionIndex, nAxisIndex ) );
+ return ObjectIdentifier::createClassifiedIdentifierForParticles( m_aCooSysParticle, aGridParticle );
+}
+
+sal_Int32 VCoordinateSystem::getMaximumAxisIndexByDimension( sal_Int32 nDimensionIndex ) const
+{
+ sal_Int32 nRet = 0;
+ for (auto const& elem : m_aSecondaryExplicitScales)
+ {
+ if(elem.first.first==nDimensionIndex)
+ {
+ sal_Int32 nLocalIdx = elem.first.second;
+ if( nRet < nLocalIdx )
+ nRet = nLocalIdx;
+ }
+ }
+ return nRet;
+}
+
+void VCoordinateSystem::createVAxisList(
+ const uno::Reference<chart2::XChartDocument> & /* xChartDoc */
+ , const awt::Size& /* rFontReferenceSize */
+ , const awt::Rectangle& /* rMaximumSpaceForLabels */
+ , bool /* bLimitSpaceForLabels */
+ )
+{
+}
+
+void VCoordinateSystem::initVAxisInList()
+{
+}
+void VCoordinateSystem::updateScalesAndIncrementsOnAxes()
+{
+}
+
+void VCoordinateSystem::prepareAutomaticAxisScaling( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex )
+{
+ if( rScaleAutomatism.getScale().AxisType==AxisType::DATE && nDimIndex==0 )
+ {
+ // This is a date X dimension. Determine proper time resolution.
+ sal_Int32 nTimeResolution = css::chart::TimeUnit::MONTH;
+ if( !(rScaleAutomatism.getScale().TimeIncrement.TimeResolution >>= nTimeResolution) )
+ {
+ nTimeResolution = m_aMergedMinMaxSupplier.calculateTimeResolutionOnXAxis();
+ rScaleAutomatism.setAutomaticTimeResolution( nTimeResolution );
+ }
+ m_aMergedMinMaxSupplier.setTimeResolutionOnXAxis( nTimeResolution, rScaleAutomatism.getNullDate() );
+ }
+
+ double fMin = 0.0;
+ double fMax = 0.0;
+ ::rtl::math::setInf(&fMin, false);
+ ::rtl::math::setInf(&fMax, true);
+ if( nDimIndex == 0 )
+ {
+ // x dimension
+ fMin = m_aMergedMinMaxSupplier.getMinimumX();
+ fMax = m_aMergedMinMaxSupplier.getMaximumX();
+ }
+ else if( nDimIndex == 1 )
+ {
+ // y dimension
+ ExplicitScaleData aScale = getExplicitScale( 0, 0 );
+ fMin = m_aMergedMinMaxSupplier.getMinimumYInRange(aScale.Minimum,aScale.Maximum, nAxisIndex);
+ fMax = m_aMergedMinMaxSupplier.getMaximumYInRange(aScale.Minimum,aScale.Maximum, nAxisIndex);
+ }
+ else if( nDimIndex == 2 )
+ {
+ // z dimension
+ fMin = m_aMergedMinMaxSupplier.getMinimumZ();
+ fMax = m_aMergedMinMaxSupplier.getMaximumZ();
+ }
+
+ //merge our values with those already contained in rScaleAutomatism
+ rScaleAutomatism.expandValueRange( fMin, fMax );
+
+ rScaleAutomatism.setAutoScalingOptions(
+ m_aMergedMinMaxSupplier.isExpandBorderToIncrementRhythm( nDimIndex ),
+ m_aMergedMinMaxSupplier.isExpandIfValuesCloseToBorder( nDimIndex ),
+ m_aMergedMinMaxSupplier.isExpandWideValuesToZero( nDimIndex ),
+ m_aMergedMinMaxSupplier.isExpandNarrowValuesTowardZero( nDimIndex ) );
+
+ VAxisBase* pVAxis = getVAxis(nDimIndex, nAxisIndex);
+ if( pVAxis )
+ rScaleAutomatism.setMaximumAutoMainIncrementCount( pVAxis->estimateMaximumAutoMainIncrementCount() );
+}
+
+VAxisBase* VCoordinateSystem::getVAxis( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
+{
+ VAxisBase* pRet = nullptr;
+
+ tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex );
+
+ tVAxisMap::const_iterator aIt = m_aAxisMap.find( aFullAxisIndex );
+ if( aIt != m_aAxisMap.end() )
+ pRet = aIt->second.get();
+
+ return pRet;
+}
+
+void VCoordinateSystem::setExplicitScaleAndIncrement(
+ sal_Int32 nDimensionIndex
+ , sal_Int32 nAxisIndex
+ , const ExplicitScaleData& rExplicitScale
+ , const ExplicitIncrementData& rExplicitIncrement )
+{
+ impl_adjustDimension( nDimensionIndex );
+
+ if( nAxisIndex==0 )
+ {
+ m_aExplicitScales[nDimensionIndex]=rExplicitScale;
+ m_aExplicitIncrements[nDimensionIndex]=rExplicitIncrement;
+ }
+ else
+ {
+ tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex );
+ m_aSecondaryExplicitScales[aFullAxisIndex] = rExplicitScale;
+ m_aSecondaryExplicitIncrements[aFullAxisIndex] = rExplicitIncrement;
+ }
+}
+
+void VCoordinateSystem::set3DWallPositions( CuboidPlanePosition eLeftWallPos, CuboidPlanePosition eBackWallPos, CuboidPlanePosition eBottomPos )
+{
+ m_eLeftWallPos = eLeftWallPos;
+ m_eBackWallPos = eBackWallPos;
+ m_eBottomPos = eBottomPos;
+}
+
+void VCoordinateSystem::createMaximumAxesLabels()
+{
+ for (auto const& elem : m_aAxisMap)
+ {
+ VAxisBase* pVAxis = elem.second.get();
+ if( pVAxis )
+ {
+ if(pVAxis->getDimensionCount()==2)
+ pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen );
+ pVAxis->createMaximumLabels();
+ }
+ }
+}
+void VCoordinateSystem::createAxesLabels()
+{
+ for (auto const& elem : m_aAxisMap)
+ {
+ VAxisBase* pVAxis = elem.second.get();
+ if( pVAxis )
+ {
+ if(pVAxis->getDimensionCount()==2)
+ pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen );
+ pVAxis->createLabels();
+ }
+ }
+}
+
+void VCoordinateSystem::updatePositions()
+{
+ for (auto const& elem : m_aAxisMap)
+ {
+ VAxisBase* pVAxis = elem.second.get();
+ if( pVAxis )
+ {
+ if(pVAxis->getDimensionCount()==2)
+ pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen );
+ pVAxis->updatePositions();
+ }
+ }
+}
+
+void VCoordinateSystem::createAxesShapes()
+{
+ for (auto const& elem : m_aAxisMap)
+ {
+ VAxisBase* pVAxis = elem.second.get();
+ if( pVAxis )
+ {
+ if(pVAxis->getDimensionCount()==2)
+ pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen );
+
+ tFullAxisIndex aFullAxisIndex = elem.first;
+ if( aFullAxisIndex.second == 0 )
+ {
+ if( aFullAxisIndex.first == 0 )
+ {
+ if( m_aExplicitScales[1].AxisType!=AxisType::CATEGORY )
+ pVAxis->setExtraLinePositionAtOtherAxis(
+ m_aExplicitScales[1].Origin );
+ }
+ else if( aFullAxisIndex.first == 1 )
+ {
+ if( m_aExplicitScales[0].AxisType!=AxisType::CATEGORY )
+ pVAxis->setExtraLinePositionAtOtherAxis(
+ m_aExplicitScales[0].Origin );
+ }
+ }
+
+ pVAxis->createShapes();
+ }
+ }
+}
+void VCoordinateSystem::createGridShapes()
+{
+}
+void VCoordinateSystem::addMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier )
+{
+ m_aMergedMinMaxSupplier.addMinimumAndMaximumSupplier(pMinimumAndMaximumSupplier);
+}
+
+bool VCoordinateSystem::hasMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier )
+{
+ return m_aMergedMinMaxSupplier.hasMinimumAndMaximumSupplier(pMinimumAndMaximumSupplier);
+}
+
+void VCoordinateSystem::clearMinimumAndMaximumSupplierList()
+{
+ m_aMergedMinMaxSupplier.clearMinimumAndMaximumSupplierList();
+}
+
+bool VCoordinateSystem::getPropertySwapXAndYAxis() const
+{
+ Reference<beans::XPropertySet> xProp(m_xCooSysModel, uno::UNO_QUERY );
+ bool bSwapXAndY = false;
+ if( xProp.is()) try
+ {
+ xProp->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXAndY;
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+ return bSwapXAndY;
+}
+
+bool VCoordinateSystem::needSeriesNamesForAxis() const
+{
+ return ( m_xCooSysModel.is() && m_xCooSysModel->getDimension() == 3 );
+}
+void VCoordinateSystem::setSeriesNamesForAxis( const Sequence< OUString >& rSeriesNames )
+{
+ m_aSeriesNamesForZAxis = rSeriesNames;
+}
+
+sal_Int32 VCoordinateSystem::getNumberFormatKeyForAxis(
+ const Reference< chart2::XAxis >& xAxis
+ , const Reference<chart2::XChartDocument>& xChartDoc)
+{
+ return ExplicitValueProvider::getExplicitNumberFormatKeyForAxis(
+ xAxis, m_xCooSysModel, xChartDoc);
+}
+
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */