1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <BaseGFXHelper.hxx>
21 #include <VCoordinateSystem.hxx>
22 #include "VCartesianCoordinateSystem.hxx"
23 #include "VPolarCoordinateSystem.hxx"
24 #include <ScaleAutomatism.hxx>
25 #include <ShapeFactory.hxx>
26 #include <servicenames_coosystems.hxx>
27 #include <ObjectIdentifier.hxx>
28 #include <ExplicitCategoriesProvider.hxx>
29 #include "VAxisBase.hxx"
30 #include <defines.hxx>
31 #include <chartview/ExplicitValueProvider.hxx>
32 #include <com/sun/star/chart/TimeUnit.hpp>
33 #include <com/sun/star/chart2/AxisType.hpp>
34 #include <com/sun/star/chart2/XCoordinateSystem.hpp>
35 #include <comphelper/sequence.hxx>
36 #include <tools/diagnose_ex.h>
38 #include <rtl/math.hxx>
42 using namespace ::com::sun::star
;
43 using namespace ::com::sun::star::chart2
;
44 using ::com::sun::star::uno::Reference
;
45 using ::com::sun::star::uno::Sequence
;
47 std::unique_ptr
<VCoordinateSystem
> VCoordinateSystem::createCoordinateSystem(
48 const Reference
< XCoordinateSystem
>& xCooSysModel
)
50 if( !xCooSysModel
.is() )
53 OUString aViewServiceName
= xCooSysModel
->getViewServiceName();
55 //@todo: in future the coordinatesystems should be instantiated via service factory
56 std::unique_ptr
<VCoordinateSystem
> pRet
;
57 if( aViewServiceName
== CHART2_COOSYSTEM_CARTESIAN_VIEW_SERVICE_NAME
)
58 pRet
.reset( new VCartesianCoordinateSystem(xCooSysModel
) );
59 else if( aViewServiceName
== CHART2_COOSYSTEM_POLAR_VIEW_SERVICE_NAME
)
60 pRet
.reset( new VPolarCoordinateSystem(xCooSysModel
) );
62 pRet
.reset( new VCoordinateSystem(xCooSysModel
) );
66 VCoordinateSystem::VCoordinateSystem( const Reference
< XCoordinateSystem
>& xCooSys
)
67 : m_xCooSysModel(xCooSys
)
68 , m_aMatrixSceneToScreen()
69 , m_eLeftWallPos(CuboidPlanePosition_Left
)
70 , m_eBackWallPos(CuboidPlanePosition_Back
)
71 , m_eBottomPos(CuboidPlanePosition_Bottom
)
72 , m_aMergedMinMaxSupplier()
73 , m_aExplicitScales(3)
74 , m_aExplicitIncrements(3)
76 if( !m_xCooSysModel
.is() || m_xCooSysModel
->getDimension()<3 )
78 m_aExplicitScales
[2].Minimum
= 1.0;
79 m_aExplicitScales
[2].Maximum
= 2.0;
80 m_aExplicitScales
[2].Orientation
= AxisOrientation_MATHEMATICAL
;
83 VCoordinateSystem::~VCoordinateSystem()
87 void VCoordinateSystem::initPlottingTargets( const Reference
< drawing::XShapes
>& xLogicTarget
88 , const Reference
< drawing::XShapes
>& xFinalTarget
89 , const Reference
< lang::XMultiServiceFactory
>& xShapeFactory
90 , Reference
< drawing::XShapes
>& xLogicTargetForSeriesBehindAxis
)
92 OSL_PRECOND(xLogicTarget
.is()&&xFinalTarget
.is()&&xShapeFactory
.is(),"no proper initialization parameters");
93 //is only allowed to be called once
95 sal_Int32 nDimensionCount
= m_xCooSysModel
->getDimension();
96 //create group shape for grids first thus axes are always painted above grids
97 ShapeFactory
* pShapeFactory
= ShapeFactory::getOrCreateShapeFactory(xShapeFactory
);
98 if(nDimensionCount
==2)
100 //create and add to target
101 m_xLogicTargetForGrids
= pShapeFactory
->createGroup2D( xLogicTarget
);
102 xLogicTargetForSeriesBehindAxis
= pShapeFactory
->createGroup2D( xLogicTarget
);
103 m_xLogicTargetForAxes
= pShapeFactory
->createGroup2D( xLogicTarget
);
107 //create and added to target
108 m_xLogicTargetForGrids
= pShapeFactory
->createGroup3D( xLogicTarget
);
109 xLogicTargetForSeriesBehindAxis
= pShapeFactory
->createGroup3D( xLogicTarget
);
110 m_xLogicTargetForAxes
= pShapeFactory
->createGroup3D( xLogicTarget
);
112 m_xFinalTarget
= xFinalTarget
;
113 m_xShapeFactory
= xShapeFactory
;
116 void VCoordinateSystem::setParticle( const OUString
& rCooSysParticle
)
118 m_aCooSysParticle
= rCooSysParticle
;
121 void VCoordinateSystem::setTransformationSceneToScreen(
122 const drawing::HomogenMatrix
& rMatrix
)
124 m_aMatrixSceneToScreen
= rMatrix
;
126 //correct transformation for axis
127 for (auto const& elem
: m_aAxisMap
)
129 VAxisBase
* pVAxis
= elem
.second
.get();
132 if(pVAxis
->getDimensionCount()==2)
133 pVAxis
->setTransformationSceneToScreen( m_aMatrixSceneToScreen
);
138 //better performance for big data
139 uno::Sequence
< sal_Int32
> VCoordinateSystem::getCoordinateSystemResolution(
140 const awt::Size
& rPageSize
, const awt::Size
& rPageResolution
)
142 uno::Sequence
<sal_Int32
> aResolution(
143 std::max
<sal_Int32
>(m_xCooSysModel
->getDimension(), 2));
145 for( auto& i
: aResolution
)
148 ::basegfx::B3DTuple
aScale( BaseGFXHelper::GetScaleFromMatrix(
149 BaseGFXHelper::HomogenMatrixToB3DHomMatrix(
150 m_aMatrixSceneToScreen
) ) );
152 double fCoosysWidth
= fabs(aScale
.getX()*FIXED_SIZE_FOR_3D_CHART_VOLUME
);
153 double fCoosysHeight
= fabs(aScale
.getY()*FIXED_SIZE_FOR_3D_CHART_VOLUME
);
155 double fPageWidth
= rPageSize
.Width
;
156 double fPageHeight
= rPageSize
.Height
;
158 //factor 2 to avoid rounding problems
159 sal_Int32 nXResolution
= static_cast<sal_Int32
>(2.0*static_cast<double>(rPageResolution
.Width
)*fCoosysWidth
/fPageWidth
);
160 sal_Int32 nYResolution
= static_cast<sal_Int32
>(2.0*static_cast<double>(rPageResolution
.Height
)*fCoosysHeight
/fPageHeight
);
162 if( nXResolution
< 10 )
164 if( nYResolution
< 10 )
167 if( getPropertySwapXAndYAxis() )
168 std::swap(nXResolution
,nYResolution
);
171 if( aResolution
.getLength() == 2 )
173 aResolution
[0]=nXResolution
;
174 aResolution
[1]=nYResolution
;
178 //this maybe can be optimized further ...
179 sal_Int32 nMaxResolution
= std::max( nXResolution
, nYResolution
);
181 for( auto& i
: aResolution
)
188 Reference
< XAxis
> VCoordinateSystem::getAxisByDimension( sal_Int32 nDimensionIndex
, sal_Int32 nAxisIndex
) const
190 if( m_xCooSysModel
.is() )
191 return m_xCooSysModel
->getAxisByDimension( nDimensionIndex
, nAxisIndex
);
195 Sequence
< Reference
< beans::XPropertySet
> > VCoordinateSystem::getGridListFromAxis( const Reference
< XAxis
>& xAxis
)
197 std::vector
< Reference
< beans::XPropertySet
> > aRet
;
201 aRet
.push_back( xAxis
->getGridProperties() );
202 auto aSubGrids( comphelper::sequenceToContainer
<std::vector
< Reference
< beans::XPropertySet
> > >( xAxis
->getSubGridProperties() ) );
203 aRet
.insert( aRet
.end(), aSubGrids
.begin(), aSubGrids
.end() );
206 return comphelper::containerToSequence( aRet
);
209 void VCoordinateSystem::impl_adjustDimension( sal_Int32
& rDimensionIndex
)
211 if( rDimensionIndex
<0 )
213 if( rDimensionIndex
>2 )
217 void VCoordinateSystem::impl_adjustDimensionAndIndex( sal_Int32
& rDimensionIndex
, sal_Int32
& rAxisIndex
) const
219 impl_adjustDimension( rDimensionIndex
);
221 if( rAxisIndex
< 0 || rAxisIndex
> getMaximumAxisIndexByDimension(rDimensionIndex
) )
225 void VCoordinateSystem::setExplicitCategoriesProvider( ExplicitCategoriesProvider
* pExplicitCategoriesProvider
/*takes ownership*/ )
227 m_apExplicitCategoriesProvider
.reset(pExplicitCategoriesProvider
);
230 ExplicitCategoriesProvider
* VCoordinateSystem::getExplicitCategoriesProvider()
232 return m_apExplicitCategoriesProvider
.get();
235 std::vector
< ExplicitScaleData
> VCoordinateSystem::getExplicitScales( sal_Int32 nDimensionIndex
, sal_Int32 nAxisIndex
) const
237 std::vector
< ExplicitScaleData
> aRet(m_aExplicitScales
);
239 impl_adjustDimensionAndIndex( nDimensionIndex
, nAxisIndex
);
240 aRet
[nDimensionIndex
]=getExplicitScale( nDimensionIndex
, nAxisIndex
);
245 std::vector
< ExplicitIncrementData
> VCoordinateSystem::getExplicitIncrements( sal_Int32 nDimensionIndex
, sal_Int32 nAxisIndex
) const
247 std::vector
< ExplicitIncrementData
> aRet(m_aExplicitIncrements
);
249 impl_adjustDimensionAndIndex( nDimensionIndex
, nAxisIndex
);
250 aRet
[nDimensionIndex
]=getExplicitIncrement( nDimensionIndex
, nAxisIndex
);
255 ExplicitScaleData
VCoordinateSystem::getExplicitScale( sal_Int32 nDimensionIndex
, sal_Int32 nAxisIndex
) const
257 ExplicitScaleData aRet
;
259 impl_adjustDimensionAndIndex( nDimensionIndex
, nAxisIndex
);
263 aRet
= m_aExplicitScales
[nDimensionIndex
];
267 tFullAxisIndex
aFullAxisIndex( nDimensionIndex
, nAxisIndex
);
268 tFullExplicitScaleMap::const_iterator aIt
= m_aSecondaryExplicitScales
.find( aFullAxisIndex
);
269 if( aIt
!= m_aSecondaryExplicitScales
.end() )
272 aRet
= m_aExplicitScales
[nDimensionIndex
];
278 ExplicitIncrementData
VCoordinateSystem::getExplicitIncrement( sal_Int32 nDimensionIndex
, sal_Int32 nAxisIndex
) const
280 ExplicitIncrementData aRet
;
282 impl_adjustDimensionAndIndex( nDimensionIndex
, nAxisIndex
);
286 aRet
= m_aExplicitIncrements
[nDimensionIndex
];
290 tFullAxisIndex
aFullAxisIndex( nDimensionIndex
, nAxisIndex
);
291 tFullExplicitIncrementMap::const_iterator aIt
= m_aSecondaryExplicitIncrements
.find( aFullAxisIndex
);
292 if( aIt
!= m_aSecondaryExplicitIncrements
.end() )
295 aRet
= m_aExplicitIncrements
[nDimensionIndex
];
301 OUString
VCoordinateSystem::createCIDForAxis( sal_Int32 nDimensionIndex
, sal_Int32 nAxisIndex
)
303 OUString
aAxisParticle( ObjectIdentifier::createParticleForAxis( nDimensionIndex
, nAxisIndex
) );
304 return ObjectIdentifier::createClassifiedIdentifierForParticles( m_aCooSysParticle
, aAxisParticle
);
306 OUString
VCoordinateSystem::createCIDForGrid( sal_Int32 nDimensionIndex
, sal_Int32 nAxisIndex
)
308 OUString
aGridParticle( ObjectIdentifier::createParticleForGrid( nDimensionIndex
, nAxisIndex
) );
309 return ObjectIdentifier::createClassifiedIdentifierForParticles( m_aCooSysParticle
, aGridParticle
);
312 sal_Int32
VCoordinateSystem::getMaximumAxisIndexByDimension( sal_Int32 nDimensionIndex
) const
315 for (auto const& elem
: m_aSecondaryExplicitScales
)
317 if(elem
.first
.first
==nDimensionIndex
)
319 sal_Int32 nLocalIdx
= elem
.first
.second
;
320 if( nRet
< nLocalIdx
)
327 void VCoordinateSystem::createVAxisList(
328 const uno::Reference
<chart2::XChartDocument
> & /* xChartDoc */
329 , const awt::Size
& /* rFontReferenceSize */
330 , const awt::Rectangle
& /* rMaximumSpaceForLabels */
331 , bool /* bLimitSpaceForLabels */
336 void VCoordinateSystem::initVAxisInList()
339 void VCoordinateSystem::updateScalesAndIncrementsOnAxes()
343 void VCoordinateSystem::prepareAutomaticAxisScaling( ScaleAutomatism
& rScaleAutomatism
, sal_Int32 nDimIndex
, sal_Int32 nAxisIndex
)
345 if( rScaleAutomatism
.getScale().AxisType
==AxisType::DATE
&& nDimIndex
==0 )
347 // This is a date X dimension. Determine proper time resolution.
348 sal_Int32 nTimeResolution
= css::chart::TimeUnit::MONTH
;
349 if( !(rScaleAutomatism
.getScale().TimeIncrement
.TimeResolution
>>= nTimeResolution
) )
351 nTimeResolution
= m_aMergedMinMaxSupplier
.calculateTimeResolutionOnXAxis();
352 rScaleAutomatism
.setAutomaticTimeResolution( nTimeResolution
);
354 m_aMergedMinMaxSupplier
.setTimeResolutionOnXAxis( nTimeResolution
, rScaleAutomatism
.getNullDate() );
359 ::rtl::math::setInf(&fMin
, false);
360 ::rtl::math::setInf(&fMax
, true);
364 fMin
= m_aMergedMinMaxSupplier
.getMinimumX();
365 fMax
= m_aMergedMinMaxSupplier
.getMaximumX();
367 else if( nDimIndex
== 1 )
370 ExplicitScaleData aScale
= getExplicitScale( 0, 0 );
371 fMin
= m_aMergedMinMaxSupplier
.getMinimumYInRange(aScale
.Minimum
,aScale
.Maximum
, nAxisIndex
);
372 fMax
= m_aMergedMinMaxSupplier
.getMaximumYInRange(aScale
.Minimum
,aScale
.Maximum
, nAxisIndex
);
374 else if( nDimIndex
== 2 )
377 fMin
= m_aMergedMinMaxSupplier
.getMinimumZ();
378 fMax
= m_aMergedMinMaxSupplier
.getMaximumZ();
381 //merge our values with those already contained in rScaleAutomatism
382 rScaleAutomatism
.expandValueRange( fMin
, fMax
);
384 rScaleAutomatism
.setAutoScalingOptions(
385 m_aMergedMinMaxSupplier
.isExpandBorderToIncrementRhythm( nDimIndex
),
386 m_aMergedMinMaxSupplier
.isExpandIfValuesCloseToBorder( nDimIndex
),
387 m_aMergedMinMaxSupplier
.isExpandWideValuesToZero( nDimIndex
),
388 m_aMergedMinMaxSupplier
.isExpandNarrowValuesTowardZero( nDimIndex
) );
390 VAxisBase
* pVAxis
= getVAxis(nDimIndex
, nAxisIndex
);
392 rScaleAutomatism
.setMaximumAutoMainIncrementCount( pVAxis
->estimateMaximumAutoMainIncrementCount() );
395 VAxisBase
* VCoordinateSystem::getVAxis( sal_Int32 nDimensionIndex
, sal_Int32 nAxisIndex
)
397 VAxisBase
* pRet
= nullptr;
399 tFullAxisIndex
aFullAxisIndex( nDimensionIndex
, nAxisIndex
);
401 tVAxisMap::const_iterator aIt
= m_aAxisMap
.find( aFullAxisIndex
);
402 if( aIt
!= m_aAxisMap
.end() )
403 pRet
= aIt
->second
.get();
408 void VCoordinateSystem::setExplicitScaleAndIncrement(
409 sal_Int32 nDimensionIndex
410 , sal_Int32 nAxisIndex
411 , const ExplicitScaleData
& rExplicitScale
412 , const ExplicitIncrementData
& rExplicitIncrement
)
414 impl_adjustDimension( nDimensionIndex
);
418 m_aExplicitScales
[nDimensionIndex
]=rExplicitScale
;
419 m_aExplicitIncrements
[nDimensionIndex
]=rExplicitIncrement
;
423 tFullAxisIndex
aFullAxisIndex( nDimensionIndex
, nAxisIndex
);
424 m_aSecondaryExplicitScales
[aFullAxisIndex
] = rExplicitScale
;
425 m_aSecondaryExplicitIncrements
[aFullAxisIndex
] = rExplicitIncrement
;
429 void VCoordinateSystem::set3DWallPositions( CuboidPlanePosition eLeftWallPos
, CuboidPlanePosition eBackWallPos
, CuboidPlanePosition eBottomPos
)
431 m_eLeftWallPos
= eLeftWallPos
;
432 m_eBackWallPos
= eBackWallPos
;
433 m_eBottomPos
= eBottomPos
;
436 void VCoordinateSystem::createMaximumAxesLabels()
438 for (auto const& elem
: m_aAxisMap
)
440 VAxisBase
* pVAxis
= elem
.second
.get();
443 if(pVAxis
->getDimensionCount()==2)
444 pVAxis
->setTransformationSceneToScreen( m_aMatrixSceneToScreen
);
445 pVAxis
->createMaximumLabels();
449 void VCoordinateSystem::createAxesLabels()
451 for (auto const& elem
: m_aAxisMap
)
453 VAxisBase
* pVAxis
= elem
.second
.get();
456 if(pVAxis
->getDimensionCount()==2)
457 pVAxis
->setTransformationSceneToScreen( m_aMatrixSceneToScreen
);
458 pVAxis
->createLabels();
463 void VCoordinateSystem::updatePositions()
465 for (auto const& elem
: m_aAxisMap
)
467 VAxisBase
* pVAxis
= elem
.second
.get();
470 if(pVAxis
->getDimensionCount()==2)
471 pVAxis
->setTransformationSceneToScreen( m_aMatrixSceneToScreen
);
472 pVAxis
->updatePositions();
477 void VCoordinateSystem::createAxesShapes()
479 for (auto const& elem
: m_aAxisMap
)
481 VAxisBase
* pVAxis
= elem
.second
.get();
484 if(pVAxis
->getDimensionCount()==2)
485 pVAxis
->setTransformationSceneToScreen( m_aMatrixSceneToScreen
);
487 tFullAxisIndex aFullAxisIndex
= elem
.first
;
488 if( aFullAxisIndex
.second
== 0 )
490 if( aFullAxisIndex
.first
== 0 )
492 if( m_aExplicitScales
[1].AxisType
!=AxisType::CATEGORY
)
493 pVAxis
->setExtraLinePositionAtOtherAxis(
494 m_aExplicitScales
[1].Origin
);
496 else if( aFullAxisIndex
.first
== 1 )
498 if( m_aExplicitScales
[0].AxisType
!=AxisType::CATEGORY
)
499 pVAxis
->setExtraLinePositionAtOtherAxis(
500 m_aExplicitScales
[0].Origin
);
504 pVAxis
->createShapes();
508 void VCoordinateSystem::createGridShapes()
511 void VCoordinateSystem::addMinimumAndMaximumSupplier( MinimumAndMaximumSupplier
* pMinimumAndMaximumSupplier
)
513 m_aMergedMinMaxSupplier
.addMinimumAndMaximumSupplier(pMinimumAndMaximumSupplier
);
516 bool VCoordinateSystem::hasMinimumAndMaximumSupplier( MinimumAndMaximumSupplier
* pMinimumAndMaximumSupplier
)
518 return m_aMergedMinMaxSupplier
.hasMinimumAndMaximumSupplier(pMinimumAndMaximumSupplier
);
521 void VCoordinateSystem::clearMinimumAndMaximumSupplierList()
523 m_aMergedMinMaxSupplier
.clearMinimumAndMaximumSupplierList();
526 bool VCoordinateSystem::getPropertySwapXAndYAxis() const
528 Reference
<beans::XPropertySet
> xProp(m_xCooSysModel
, uno::UNO_QUERY
);
529 bool bSwapXAndY
= false;
532 xProp
->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXAndY
;
534 catch( const uno::Exception
& )
536 TOOLS_WARN_EXCEPTION("chart2", "" );
541 bool VCoordinateSystem::needSeriesNamesForAxis() const
543 return ( m_xCooSysModel
.is() && m_xCooSysModel
->getDimension() == 3 );
545 void VCoordinateSystem::setSeriesNamesForAxis( const Sequence
< OUString
>& rSeriesNames
)
547 m_aSeriesNamesForZAxis
= rSeriesNames
;
550 sal_Int32
VCoordinateSystem::getNumberFormatKeyForAxis(
551 const Reference
< chart2::XAxis
>& xAxis
552 , const Reference
<chart2::XChartDocument
>& xChartDoc
)
554 return ExplicitValueProvider::getExplicitNumberFormatKeyForAxis(
555 xAxis
, m_xCooSysModel
, xChartDoc
);
560 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */