/* -*- 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 #include #include "VCartesianCoordinateSystem.hxx" #include "VPolarCoordinateSystem.hxx" #include #include #include #include #include #include "VAxisBase.hxx" #include #include #include #include #include #include #include #include #include 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::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 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 aResolution( std::max(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(2.0*static_cast(rPageResolution.Width)*fCoosysWidth/fPageWidth); sal_Int32 nYResolution = static_cast(2.0*static_cast(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 > >( 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 & /* 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 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& xChartDoc) { return ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( xAxis, m_xCooSysModel, xChartDoc); } } //namespace chart /* vim:set shiftwidth=4 softtabstop=4 expandtab: */