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 "BarChart.hxx"
21 #include "ShapeFactory.hxx"
22 #include "CommonConverters.hxx"
23 #include "ObjectIdentifier.hxx"
24 #include "LabelPositionHelper.hxx"
25 #include "BarPositionHelper.hxx"
27 #include "AxisIndexDefines.hxx"
28 #include "Clipping.hxx"
29 #include "DateHelper.hxx"
31 #include <com/sun/star/chart/DataLabelPlacement.hpp>
33 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
34 #include <rtl/math.hxx>
36 //.............................................................................
39 //.............................................................................
40 using namespace ::com::sun::star
;
41 using namespace ::rtl::math
;
42 using namespace ::com::sun::star::chart2
;
44 BarChart::BarChart( const uno::Reference
<XChartType
>& xChartTypeModel
45 , sal_Int32 nDimensionCount
)
46 : VSeriesPlotter( xChartTypeModel
, nDimensionCount
)
47 , m_pMainPosHelper( new BarPositionHelper() )
49 PlotterBase::m_pPosHelper
= m_pMainPosHelper
;
50 VSeriesPlotter::m_pMainPosHelper
= m_pMainPosHelper
;
54 if( m_xChartTypeModelProps
.is() )
56 m_xChartTypeModelProps
->getPropertyValue( "OverlapSequence" ) >>= m_aOverlapSequence
;
57 m_xChartTypeModelProps
->getPropertyValue( "GapwidthSequence" ) >>= m_aGapwidthSequence
;
60 catch( const uno::Exception
& e
)
62 ASSERT_EXCEPTION( e
);
68 delete m_pMainPosHelper
;
71 //-------------------------------------------------------------------------
73 PlottingPositionHelper
& BarChart::getPlottingPositionHelper( sal_Int32 nAxisIndex
) const
75 PlottingPositionHelper
& rPosHelper
= VSeriesPlotter::getPlottingPositionHelper( nAxisIndex
);
76 BarPositionHelper
* pBarPosHelper
= dynamic_cast<BarPositionHelper
*>(&rPosHelper
);
77 if( pBarPosHelper
&& nAxisIndex
>= 0 )
79 if( nAxisIndex
< m_aOverlapSequence
.getLength() )
80 pBarPosHelper
->setInnerDistance( -m_aOverlapSequence
[nAxisIndex
]/100.0 );
81 if( nAxisIndex
< m_aGapwidthSequence
.getLength() )
82 pBarPosHelper
->setOuterDistance( m_aGapwidthSequence
[nAxisIndex
]/100.0 );
87 drawing::Direction3D
BarChart::getPreferredDiagramAspectRatio() const
89 drawing::Direction3D
aRet(1.0,1.0,1.0);
90 if( m_nDimension
== 3 )
92 aRet
= drawing::Direction3D(1.0,-1.0,1.0);
93 BarPositionHelper
* pPosHelper
= dynamic_cast<BarPositionHelper
*>(&( this->getPlottingPositionHelper( MAIN_AXIS_INDEX
) ) );
94 drawing::Direction3D
aScale( pPosHelper
->getScaledLogicWidth() );
95 if(aScale
.DirectionX
!=0.0)
97 double fXSlotCount
= 1.0;
98 if(!m_aZSlots
.empty())
99 fXSlotCount
= m_aZSlots
.begin()->size();
101 aRet
.DirectionZ
= aScale
.DirectionZ
/(aScale
.DirectionX
+ aScale
.DirectionX
*(fXSlotCount
-1.0)*pPosHelper
->getScaledSlotWidth());
104 return VSeriesPlotter::getPreferredDiagramAspectRatio();
105 if(aRet
.DirectionZ
<0.05)
106 aRet
.DirectionZ
=0.05;
107 if(aRet
.DirectionZ
>10)
110 if( m_pMainPosHelper
&& m_pMainPosHelper
->isSwapXAndY() )
112 double fTemp
= aRet
.DirectionX
;
113 aRet
.DirectionX
= aRet
.DirectionY
;
114 aRet
.DirectionY
= fTemp
;
118 aRet
= drawing::Direction3D(-1,-1,-1);
122 bool BarChart::keepAspectRatio() const
124 if( m_nDimension
== 3 )
129 awt::Point
BarChart::getLabelScreenPositionAndAlignment(
130 LabelAlignment
& rAlignment
, sal_Int32 nLabelPlacement
131 , double fScaledX
, double fScaledLowerYValue
, double fScaledUpperYValue
, double fScaledZ
132 , double fScaledLowerBarDepth
, double fScaledUpperBarDepth
, double fBaseValue
133 , BarPositionHelper
* pPosHelper
136 double fX
= fScaledX
;
137 double fY
= fScaledUpperYValue
;
138 double fZ
= fScaledZ
;
139 bool bReverse
= !pPosHelper
->isMathematicalOrientationY();
140 bool bNormalOutside
= (!bReverse
== !!(fBaseValue
< fScaledUpperYValue
));
141 double fDepth
= fScaledUpperBarDepth
;
143 switch(nLabelPlacement
)
145 case ::com::sun::star::chart::DataLabelPlacement::TOP
:
147 if( !pPosHelper
->isSwapXAndY() )
149 fY
= bReverse
? fScaledLowerYValue
: fScaledUpperYValue
;
150 rAlignment
= LABEL_ALIGN_TOP
;
152 fDepth
= bReverse
? fabs(fScaledLowerBarDepth
) : fabs(fScaledUpperBarDepth
);
156 fY
-= (fScaledUpperYValue
-fScaledLowerYValue
)/2.0;
157 rAlignment
= LABEL_ALIGN_CENTER
;
158 OSL_FAIL( "top label placement is not really supported by horizontal bar charts" );
162 case ::com::sun::star::chart::DataLabelPlacement::BOTTOM
:
164 if(!pPosHelper
->isSwapXAndY())
166 fY
= bReverse
? fScaledUpperYValue
: fScaledLowerYValue
;
167 rAlignment
= LABEL_ALIGN_BOTTOM
;
169 fDepth
= bReverse
? fabs(fScaledUpperBarDepth
) : fabs(fScaledLowerBarDepth
);
173 fY
-= (fScaledUpperYValue
-fScaledLowerYValue
)/2.0;
174 rAlignment
= LABEL_ALIGN_CENTER
;
175 OSL_FAIL( "bottom label placement is not supported by horizontal bar charts" );
179 case ::com::sun::star::chart::DataLabelPlacement::LEFT
:
181 if( pPosHelper
->isSwapXAndY() )
183 fY
= bReverse
? fScaledUpperYValue
: fScaledLowerYValue
;
184 rAlignment
= LABEL_ALIGN_LEFT
;
186 fDepth
= bReverse
? fabs(fScaledUpperBarDepth
) : fabs(fScaledLowerBarDepth
);
190 fY
-= (fScaledUpperYValue
-fScaledLowerYValue
)/2.0;
191 rAlignment
= LABEL_ALIGN_CENTER
;
192 OSL_FAIL( "left label placement is not supported by column charts" );
196 case ::com::sun::star::chart::DataLabelPlacement::RIGHT
:
198 if( pPosHelper
->isSwapXAndY() )
200 fY
= bReverse
? fScaledLowerYValue
: fScaledUpperYValue
;
201 rAlignment
= LABEL_ALIGN_RIGHT
;
203 fDepth
= bReverse
? fabs(fScaledLowerBarDepth
) : fabs(fScaledUpperBarDepth
);
207 fY
-= (fScaledUpperYValue
-fScaledLowerYValue
)/2.0;
208 rAlignment
= LABEL_ALIGN_CENTER
;
209 OSL_FAIL( "right label placement is not supported by column charts" );
213 case ::com::sun::star::chart::DataLabelPlacement::OUTSIDE
:
215 fY
= (fBaseValue
< fScaledUpperYValue
) ? fScaledUpperYValue
: fScaledLowerYValue
;
216 if( pPosHelper
->isSwapXAndY() )
217 rAlignment
= bNormalOutside
? LABEL_ALIGN_RIGHT
: LABEL_ALIGN_LEFT
;
219 rAlignment
= bNormalOutside
? LABEL_ALIGN_TOP
: LABEL_ALIGN_BOTTOM
;
221 fDepth
= (fBaseValue
< fScaledUpperYValue
) ? fabs(fScaledUpperBarDepth
) : fabs(fScaledLowerBarDepth
);
224 case ::com::sun::star::chart::DataLabelPlacement::INSIDE
:
226 fY
= (fBaseValue
< fScaledUpperYValue
) ? fScaledUpperYValue
: fScaledLowerYValue
;
227 if( pPosHelper
->isSwapXAndY() )
228 rAlignment
= bNormalOutside
? LABEL_ALIGN_LEFT
: LABEL_ALIGN_RIGHT
;
230 rAlignment
= bNormalOutside
? LABEL_ALIGN_BOTTOM
: LABEL_ALIGN_TOP
;
232 fDepth
= (fBaseValue
< fScaledUpperYValue
) ? fabs(fScaledUpperBarDepth
) : fabs(fScaledLowerBarDepth
);
235 case ::com::sun::star::chart::DataLabelPlacement::NEAR_ORIGIN
:
237 fY
= (fBaseValue
< fScaledUpperYValue
) ? fScaledLowerYValue
: fScaledUpperYValue
;
238 if( pPosHelper
->isSwapXAndY() )
239 rAlignment
= bNormalOutside
? LABEL_ALIGN_RIGHT
: LABEL_ALIGN_LEFT
;
241 rAlignment
= bNormalOutside
? LABEL_ALIGN_TOP
: LABEL_ALIGN_BOTTOM
;
243 fDepth
= (fBaseValue
< fScaledUpperYValue
) ? fabs(fScaledLowerBarDepth
) : fabs(fScaledUpperBarDepth
);
246 case ::com::sun::star::chart::DataLabelPlacement::CENTER
:
247 fY
-= (fScaledUpperYValue
-fScaledLowerYValue
)/2.0;
248 rAlignment
= LABEL_ALIGN_CENTER
;
250 fDepth
= fabs(fScaledUpperBarDepth
-fScaledLowerBarDepth
)/2.0;
253 OSL_FAIL("this label alignment is not implemented yet");
260 drawing::Position3D
aScenePosition3D( pPosHelper
->
261 transformScaledLogicToScene( fX
, fY
, fZ
, true ) );
262 return LabelPositionHelper(pPosHelper
,m_nDimension
,m_xLogicTarget
,m_pShapeFactory
)
263 .transformSceneToScreenPosition( aScenePosition3D
);
266 uno::Reference
< drawing::XShape
> BarChart::createDataPoint3D_Bar(
267 const uno::Reference
< drawing::XShapes
>& xTarget
268 , const drawing::Position3D
& rPosition
, const drawing::Direction3D
& rSize
269 , double fTopHeight
, sal_Int32 nRotateZAngleHundredthDegree
270 , const uno::Reference
< beans::XPropertySet
>& xObjectProperties
271 , sal_Int32 nGeometry3D
)
273 bool bRoundedEdges
= true;
276 if( xObjectProperties
.is() )
278 sal_Int16 nPercentDiagonal
= 0;
279 xObjectProperties
->getPropertyValue( "PercentDiagonal" ) >>= nPercentDiagonal
;
280 if( nPercentDiagonal
< 5 )
281 bRoundedEdges
= false;
284 catch( const uno::Exception
& e
)
286 ASSERT_EXCEPTION( e
);
289 uno::Reference
< drawing::XShape
> xShape(NULL
);
290 switch( nGeometry3D
)
292 case DataPointGeometry3D::CYLINDER
:
293 xShape
= m_pShapeFactory
->createCylinder( xTarget
, rPosition
, rSize
, nRotateZAngleHundredthDegree
);
295 case DataPointGeometry3D::CONE
:
296 xShape
= m_pShapeFactory
->createCone( xTarget
, rPosition
, rSize
, fTopHeight
, nRotateZAngleHundredthDegree
);
298 case DataPointGeometry3D::PYRAMID
:
299 xShape
= m_pShapeFactory
->createPyramid( xTarget
, rPosition
, rSize
, fTopHeight
, nRotateZAngleHundredthDegree
>0
300 , xObjectProperties
, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
302 case DataPointGeometry3D::CUBOID
:
304 xShape
= m_pShapeFactory
->createCube( xTarget
, rPosition
, rSize
305 , nRotateZAngleHundredthDegree
, xObjectProperties
306 , PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), bRoundedEdges
);
309 if( nGeometry3D
!= DataPointGeometry3D::PYRAMID
)
310 this->setMappedProperties( xShape
, xObjectProperties
, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
316 bool lcl_hasGeometry3DVariableWidth( sal_Int32 nGeometry3D
)
319 switch( nGeometry3D
)
321 case DataPointGeometry3D::PYRAMID
:
322 case DataPointGeometry3D::CONE
:
325 case DataPointGeometry3D::CUBOID
:
326 case DataPointGeometry3D::CYLINDER
:
333 }// end anonymous namespace
335 void BarChart::addSeries( VDataSeries
* pSeries
, sal_Int32 zSlot
, sal_Int32 xSlot
, sal_Int32 ySlot
)
341 //2ND_AXIS_IN_BARS put series on second scales to different z slot as temporary workaround
342 //this needs to be redesigned if 3d bars are also able to display secondary axes
344 sal_Int32 nAxisIndex
= pSeries
->getAttachedAxisIndex();
347 if( !pSeries
->getGroupBarsPerAxis() )
349 if(zSlot
>=static_cast<sal_Int32
>(m_aZSlots
.size()))
350 m_aZSlots
.resize(zSlot
+1);
352 VSeriesPlotter::addSeries( pSeries
, zSlot
, xSlot
, ySlot
);
355 //better performance for big data
356 struct FormerBarPoint
358 FormerBarPoint( double fX
, double fUpperY
, double fLowerY
, double fZ
)
359 : m_fX(fX
), m_fUpperY(fUpperY
), m_fLowerY(fLowerY
), m_fZ(fZ
)
363 ::rtl::math::setNan( &m_fX
);
364 ::rtl::math::setNan( &m_fUpperY
);
365 ::rtl::math::setNan( &m_fLowerY
);
366 ::rtl::math::setNan( &m_fZ
);
375 void BarChart::adaptOverlapAndGapwidthForGroupBarsPerAxis()
377 //adapt m_aOverlapSequence and m_aGapwidthSequence for the groupBarsPerAxis feature
378 //thus the different series use the same settings
380 VDataSeries
* pFirstSeries
= getFirstSeries();
381 if(pFirstSeries
&& !pFirstSeries
->getGroupBarsPerAxis() )
383 sal_Int32 nAxisIndex
= pFirstSeries
->getAttachedAxisIndex();
385 sal_Int32 nUseThisIndex
= nAxisIndex
;
386 if( nUseThisIndex
< 0 || nUseThisIndex
>= m_aOverlapSequence
.getLength() )
388 for( nN
= 0; nN
< m_aOverlapSequence
.getLength(); nN
++ )
390 if(nN
!=nUseThisIndex
)
391 m_aOverlapSequence
[nN
] = m_aOverlapSequence
[nUseThisIndex
];
394 nUseThisIndex
= nAxisIndex
;
395 if( nUseThisIndex
< 0 || nUseThisIndex
>= m_aGapwidthSequence
.getLength() )
397 for( nN
= 0; nN
< m_aGapwidthSequence
.getLength(); nN
++ )
399 if(nN
!=nUseThisIndex
)
400 m_aGapwidthSequence
[nN
] = m_aGapwidthSequence
[nUseThisIndex
];
405 void BarChart::createShapes()
407 if( m_aZSlots
.begin() == m_aZSlots
.end() ) //no series
410 OSL_ENSURE(m_pShapeFactory
&&m_xLogicTarget
.is()&&m_xFinalTarget
.is(),"BarChart is not proper initialized");
411 if(!(m_pShapeFactory
&&m_xLogicTarget
.is()&&m_xFinalTarget
.is()))
414 //the text labels should be always on top of the other series shapes
415 //therefore create an own group for the texts to move them to front
416 //(because the text group is created after the series group the texts are displayed on top)
418 //the regression curves should always be on top of the bars but beneath the text labels
419 //to achieve this the regression curve target is created after the series target and before the text target
421 uno::Reference
< drawing::XShapes
> xSeriesTarget(
422 createGroupShape( m_xLogicTarget
,OUString() ));
423 uno::Reference
< drawing::XShapes
> xRegressionCurveTarget(
424 createGroupShape( m_xLogicTarget
,OUString() ));
425 uno::Reference
< drawing::XShapes
> xTextTarget(
426 m_pShapeFactory
->createGroup2D( m_xFinalTarget
,OUString() ));
429 //---------------------------------------------
430 uno::Reference
< drawing::XShapes
> xRegressionCurveEquationTarget(
431 m_pShapeFactory
->createGroup2D( m_xFinalTarget
,OUString() ));
432 //check necessary here that different Y axis can not be stacked in the same group? ... hm?
434 double fLogicZ
= 1.0;//as defined
436 bool bDrawConnectionLines
= false;
437 bool bDrawConnectionLinesInited
= false;
438 bool bOnlyConnectionLinesForThisPoint
= false;
440 adaptOverlapAndGapwidthForGroupBarsPerAxis();
442 //better performance for big data
443 std::map
< VDataSeries
*, FormerBarPoint
> aSeriesFormerPointMap
;
444 m_bPointsWereSkipped
= false;
445 sal_Int32 nSkippedPoints
= 0;
446 sal_Int32 nCreatedPoints
= 0;
449 sal_Int32 nStartIndex
= 0;
450 sal_Int32 nEndIndex
= VSeriesPlotter::getPointCount();
451 //=============================================================================
452 //iterate through all x values per indices
453 for( sal_Int32 nPointIndex
= nStartIndex
; nPointIndex
< nEndIndex
; nPointIndex
++ )
455 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
456 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
458 //sum up the values for all series in a complete z zlot per attached axis
459 ::std::map
< sal_Int32
, double > aLogicYSumMap
;
460 for( ; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
)
462 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
463 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
465 for( aXSlotIter
= aZSlotIter
->begin(); aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
)
467 sal_Int32 nAttachedAxisIndex
= aXSlotIter
->getAttachedAxisIndexForFirstSeries();
468 if( aLogicYSumMap
.find(nAttachedAxisIndex
)==aLogicYSumMap
.end() )
469 aLogicYSumMap
[nAttachedAxisIndex
]=0.0;
471 double fMinimumY
= 0.0, fMaximumY
= 0.0;
472 aXSlotIter
->calculateYMinAndMaxForCategory( nPointIndex
473 , isSeparateStackingForDifferentSigns( 1 ), fMinimumY
, fMaximumY
, nAttachedAxisIndex
);
475 if( !::rtl::math::isNan( fMaximumY
) && fMaximumY
> 0)
476 aLogicYSumMap
[nAttachedAxisIndex
] += fMaximumY
;
477 if( !::rtl::math::isNan( fMinimumY
) && fMinimumY
< 0)
478 aLogicYSumMap
[nAttachedAxisIndex
] += fabs(fMinimumY
);
482 //=============================================================================
483 aZSlotIter
= m_aZSlots
.begin();
484 for( sal_Int32 nZ
=1; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
, nZ
++ )
486 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
487 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
489 //=============================================================================
490 //iterate through all x slots in this category
492 for( aXSlotIter
= aZSlotIter
->begin(); aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
, fSlotX
+=1.0 )
494 sal_Int32 nAttachedAxisIndex
= 0;
495 BarPositionHelper
* pPosHelper
= m_pMainPosHelper
;
496 if( aXSlotIter
!= aXSlotEnd
)
498 nAttachedAxisIndex
= aXSlotIter
->getAttachedAxisIndexForFirstSeries();
499 //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
500 pPosHelper
= dynamic_cast<BarPositionHelper
*>(&( this->getPlottingPositionHelper( nAttachedAxisIndex
) ) );
502 pPosHelper
= m_pMainPosHelper
;
504 PlotterBase::m_pPosHelper
= pPosHelper
;
506 //update/create information for current group
507 pPosHelper
->updateSeriesCount( aZSlotIter
->size() );
508 double fLogicBaseWidth
= pPosHelper
->getScaledSlotWidth();
510 ::std::vector
< VDataSeries
* >* pSeriesList
= &(aXSlotIter
->m_aSeriesVector
);
512 // get distance from base value to maximum and minimum
514 double fMinimumY
= 0.0, fMaximumY
= 0.0;
515 aXSlotIter
->calculateYMinAndMaxForCategory( nPointIndex
516 , isSeparateStackingForDifferentSigns( 1 ), fMinimumY
, fMaximumY
, nAttachedAxisIndex
);
518 double fLogicPositiveYSum
= 0.0;
519 if( !::rtl::math::isNan( fMaximumY
) )
520 fLogicPositiveYSum
= fMaximumY
;
522 double fLogicNegativeYSum
= 0.0;
523 if( !::rtl::math::isNan( fMinimumY
) )
524 fLogicNegativeYSum
= fMinimumY
;
526 if( pPosHelper
->isPercentY() )
528 /* #i70395# fLogicPositiveYSum contains sum of all positive
529 values, if any, otherwise the highest negative value.
530 fLogicNegativeYSum contains sum of all negative values,
531 if any, otherwise the lowest positive value.
532 Afterwards, fLogicPositiveYSum will contain the maximum
533 (positive) value that is related to 100%. */
535 // do nothing if there are positive values only
536 if( fLogicNegativeYSum
< 0.0 )
538 // fLogicPositiveYSum<0 => negative values only, use absolute of negative sum
539 if( fLogicPositiveYSum
< 0.0 )
540 fLogicPositiveYSum
= -fLogicNegativeYSum
;
541 // otherwise there are positive and negative values, calculate total distance
543 fLogicPositiveYSum
-= fLogicNegativeYSum
;
545 fLogicNegativeYSum
= 0.0;
548 double fBaseValue
= 0.0;
549 if( !pPosHelper
->isPercentY() && pSeriesList
->size()<=1 )
550 fBaseValue
= pPosHelper
->getBaseValueY();
551 double fPositiveLogicYForNextSeries
= fBaseValue
;
552 double fNegativeLogicYForNextSeries
= fBaseValue
;
554 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= pSeriesList
->begin();
555 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
556 //=============================================================================
557 //iterate through all series in this x slot
558 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
560 VDataSeries
* pSeries( *aSeriesIter
);
564 bOnlyConnectionLinesForThisPoint
= false;
566 if(nPointIndex
==nStartIndex
)//do not create a regression line for each point
567 createRegressionCurvesShapes( **aSeriesIter
, xRegressionCurveTarget
, xRegressionCurveEquationTarget
,
568 m_pPosHelper
->maySkipPointsInRegressionCalculation());
570 if( !bDrawConnectionLinesInited
)
572 bDrawConnectionLines
= pSeries
->getConnectBars();
573 if( m_nDimension
==3 )
574 bDrawConnectionLines
= false;
575 if( bDrawConnectionLines
&& pSeriesList
->size()==1 )
577 //detect whether we have a stacked chart or not:
578 StackingDirection eDirection
= pSeries
->getStackingDirection();
579 if( eDirection
!= StackingDirection_Y_STACKING
)
580 bDrawConnectionLines
= false;
582 bDrawConnectionLinesInited
= true;
587 uno::Reference
< drawing::XShapes
> xSeriesGroupShape_Shapes(
588 getSeriesGroupShape(*aSeriesIter
, xSeriesTarget
) );
590 //collect data point information (logic coordinates, style ):
591 double fUnscaledLogicX
= (*aSeriesIter
)->getXValue( nPointIndex
);
592 fUnscaledLogicX
= DateHelper::RasterizeDateValue( fUnscaledLogicX
, m_aNullDate
, m_nTimeResolution
);
593 if(fUnscaledLogicX
<pPosHelper
->getLogicMinX())
594 continue;//point not visible
595 if(fUnscaledLogicX
>pPosHelper
->getLogicMaxX())
596 continue;//point not visible
597 if(pPosHelper
->isStrongLowerRequested(0) && fUnscaledLogicX
==pPosHelper
->getLogicMaxX())
598 continue;//point not visible
599 double fLogicX
= pPosHelper
->getScaledSlotPos( fUnscaledLogicX
, fSlotX
);
601 double fLogicBarHeight
= (*aSeriesIter
)->getYValue( nPointIndex
);
602 if( ::rtl::math::isNan( fLogicBarHeight
)) //no value at this category
605 double fLogicValueForLabeDisplay
= fLogicBarHeight
;
606 fLogicBarHeight
-=fBaseValue
;
608 if( pPosHelper
->isPercentY() )
610 if(fLogicPositiveYSum
!=0.0)
611 fLogicBarHeight
= fabs( fLogicBarHeight
)/fLogicPositiveYSum
;
613 fLogicBarHeight
= 0.0;
616 //sort negative and positive values, to display them on different sides of the x axis
617 bool bPositive
= fLogicBarHeight
>= 0.0;
618 double fLowerYValue
= bPositive
? fPositiveLogicYForNextSeries
: fNegativeLogicYForNextSeries
;
619 double fUpperYValue
= fLowerYValue
+fLogicBarHeight
;
621 fPositiveLogicYForNextSeries
+= fLogicBarHeight
;
623 fNegativeLogicYForNextSeries
+= fLogicBarHeight
;
628 drawing::Position3D
aUnscaledLogicPosition( fUnscaledLogicX
, fUpperYValue
, fLogicZ
);
630 //@todo ... start an iteration over the different breaks of the axis
631 //each subsystem may add an additional shape to form the whole point
632 //create a group shape for this point and add to the series shape:
633 // uno::Reference< drawing::XShapes > xPointGroupShape_Shapes( createGroupShape(xSeriesGroupShape_Shapes) );
634 // uno::Reference<drawing::XShape> xPointGroupShape_Shape =
635 // uno::Reference<drawing::XShape>( xPointGroupShape_Shapes, uno::UNO_QUERY );
636 //as long as we do not iterate we do not need to create an additional group for each point
637 uno::Reference
< drawing::XShapes
> xPointGroupShape_Shapes
= xSeriesGroupShape_Shapes
;
638 uno::Reference
< beans::XPropertySet
> xDataPointProperties( (*aSeriesIter
)->getPropertiesOfPoint( nPointIndex
) );
639 sal_Int32 nGeometry3D
= DataPointGeometry3D::CUBOID
;
640 if(m_nDimension
==3) try
642 xDataPointProperties
->getPropertyValue( "Geometry3D") >>= nGeometry3D
;
644 catch( const uno::Exception
& e
)
646 ASSERT_EXCEPTION( e
);
649 //@todo iterate through all subsystems to create partial points
651 //@todo select a suiteable PositionHelper for this subsystem
652 BarPositionHelper
* pSubPosHelper
= pPosHelper
;
654 double fUnclippedUpperYValue
= fUpperYValue
;
656 //apply clipping to Y
657 if( !pPosHelper
->clipYRange(fLowerYValue
,fUpperYValue
) )
659 if( bDrawConnectionLines
)
660 bOnlyConnectionLinesForThisPoint
= true;
664 //@todo clipping of X and Z is not fully integrated so far, as there is a need to create different objects
666 //apply scaling to Y before calculating width (necessary to maintain gradient in clipped objects)
667 pSubPosHelper
->doLogicScaling(NULL
,&fLowerYValue
,NULL
);
668 pSubPosHelper
->doLogicScaling(NULL
,&fUpperYValue
,NULL
);
669 //scaling of X and Z is not provided as the created objects should be symmetric in that dimensions
671 pSubPosHelper
->doLogicScaling(NULL
,&fUnclippedUpperYValue
,NULL
);
673 //calculate resulting width
674 double fCompleteHeight
= bPositive
? fLogicPositiveYSum
: fLogicNegativeYSum
;
675 if( pPosHelper
->isPercentY() )
676 fCompleteHeight
= 1.0;
677 double fLogicBarWidth
= fLogicBaseWidth
;
678 double fTopHeight
=approxSub(fCompleteHeight
,fUpperYValue
);
680 fTopHeight
=approxSub(fCompleteHeight
,fLowerYValue
);
681 double fLogicYStart
= bPositive
? fLowerYValue
: fUpperYValue
;
682 double fMiddleHeight
= fUpperYValue
-fLowerYValue
;
685 double fLogicBarDepth
= 0.5;
688 if( lcl_hasGeometry3DVariableWidth(nGeometry3D
) && fCompleteHeight
!=0.0 )
690 double fHeight
= fCompleteHeight
-fLowerYValue
;
692 fHeight
= fCompleteHeight
-fUpperYValue
;
693 fLogicBarWidth
= fLogicBaseWidth
*fHeight
/(fCompleteHeight
);
694 if(fLogicBarWidth
<=0.0)
695 fLogicBarWidth
=fLogicBaseWidth
;
696 fLogicBarDepth
= fLogicBarDepth
*fHeight
/(fCompleteHeight
);
697 if(fLogicBarDepth
<=0.0)
698 fLogicBarDepth
*=-1.0;
702 //better performance for big data
703 FormerBarPoint
aFormerPoint( aSeriesFormerPointMap
[pSeries
] );
704 pPosHelper
->setCoordinateSystemResolution( m_aCoordinateSystemResolution
);
705 if( !pSeries
->isAttributedDataPoint(nPointIndex
)
707 pPosHelper
->isSameForGivenResolution( aFormerPoint
.m_fX
, aFormerPoint
.m_fUpperY
, aFormerPoint
.m_fZ
708 , fLogicX
, fUpperYValue
, fLogicZ
)
710 pPosHelper
->isSameForGivenResolution( aFormerPoint
.m_fX
, aFormerPoint
.m_fLowerY
, aFormerPoint
.m_fZ
711 , fLogicX
, fLowerYValue
, fLogicZ
)
715 m_bPointsWereSkipped
= true;
718 aSeriesFormerPointMap
[pSeries
] = FormerBarPoint(fLogicX
,fUpperYValue
,fLowerYValue
,fLogicZ
);
722 if( bDrawConnectionLines
)
724 //store point information for connection lines
726 drawing::Position3D
aLeftUpperPoint( fLogicX
-fLogicBarWidth
/2.0,fUnclippedUpperYValue
,fLogicZ
);
727 drawing::Position3D
aRightUpperPoint( fLogicX
+fLogicBarWidth
/2.0,fUnclippedUpperYValue
,fLogicZ
);
729 if( isValidPosition(aLeftUpperPoint
) )
730 AddPointToPoly( (*aSeriesIter
)->m_aPolyPolygonShape3D
, aLeftUpperPoint
);
731 if( isValidPosition(aRightUpperPoint
) )
732 AddPointToPoly( (*aSeriesIter
)->m_aPolyPolygonShape3D
, aRightUpperPoint
);
735 if( bOnlyConnectionLinesForThisPoint
)
738 //maybe additional possibility for performance improvement
739 //bool bCreateLineInsteadOfComplexGeometryDueToMissingSpace = false;
740 //pPosHelper->isSameForGivenResolution( fLogicX-fLogicBarWidth/2.0, fLowerYValue, fLogicZ
741 // , fLogicX+fLogicBarWidth/2.0, fLowerYValue, fLogicZ );
744 //create partial point
745 if( !approxEqual(fLowerYValue
,fUpperYValue
) )
747 uno::Reference
< drawing::XShape
> xShape
;
748 if( m_nDimension
==3 )
750 drawing::Position3D
aLogicBottom (fLogicX
,fLogicYStart
,fLogicZ
);
751 drawing::Position3D
aLogicLeftBottomFront (fLogicX
+fLogicBarWidth
/2.0,fLogicYStart
,fLogicZ
-fLogicBarDepth
/2.0);
752 drawing::Position3D
aLogicRightDeepTop (fLogicX
-fLogicBarWidth
/2.0,fLogicYStart
+fMiddleHeight
,fLogicZ
+fLogicBarDepth
/2.0);
753 drawing::Position3D
aLogicTopTop (fLogicX
,fLogicYStart
+fMiddleHeight
+fTopHeight
,fLogicZ
);
755 uno::Reference
< XTransformation
> xTransformation
= pSubPosHelper
->getTransformationScaledLogicToScene();
757 //transformation 3) -> 4)
758 drawing::Position3D
aTransformedBottom ( SequenceToPosition3D( xTransformation
->transform( Position3DToSequence(aLogicBottom
) ) ) );
759 drawing::Position3D
aTransformedLeftBottomFront ( SequenceToPosition3D( xTransformation
->transform( Position3DToSequence(aLogicLeftBottomFront
) ) ) );
760 drawing::Position3D
aTransformedRightDeepTop ( SequenceToPosition3D( xTransformation
->transform( Position3DToSequence(aLogicRightDeepTop
) ) ) );
761 drawing::Position3D
aTransformedTopTop ( SequenceToPosition3D( xTransformation
->transform( Position3DToSequence(aLogicTopTop
) ) ) );
763 drawing::Direction3D aSize
= aTransformedRightDeepTop
- aTransformedLeftBottomFront
;
764 drawing::Direction3D
aTopSize( aTransformedTopTop
- aTransformedRightDeepTop
);
765 fTopHeight
= aTopSize
.DirectionY
;
767 sal_Int32 nRotateZAngleHundredthDegree
= 0;
768 if( pPosHelper
->isSwapXAndY() )
770 fTopHeight
= aTopSize
.DirectionX
;
771 nRotateZAngleHundredthDegree
= 90*100;
772 aSize
= drawing::Direction3D(aSize
.DirectionY
,aSize
.DirectionX
,aSize
.DirectionZ
);
775 if( aSize
.DirectionX
< 0 )
776 aSize
.DirectionX
*= -1.0;
777 if( aSize
.DirectionZ
< 0 )
778 aSize
.DirectionZ
*= -1.0;
782 xShape
= createDataPoint3D_Bar(
783 xPointGroupShape_Shapes
, aTransformedBottom
, aSize
, fTopHeight
, nRotateZAngleHundredthDegree
784 , xDataPointProperties
, nGeometry3D
);
786 else //m_nDimension!=3
788 drawing::PolyPolygonShape3D aPoly
;
789 drawing::Position3D
aLeftUpperPoint( fLogicX
-fLogicBarWidth
/2.0,fUpperYValue
,fLogicZ
);
790 drawing::Position3D
aRightUpperPoint( fLogicX
+fLogicBarWidth
/2.0,fUpperYValue
,fLogicZ
);
792 AddPointToPoly( aPoly
, drawing::Position3D( fLogicX
-fLogicBarWidth
/2.0,fLowerYValue
,fLogicZ
) );
793 AddPointToPoly( aPoly
, drawing::Position3D( fLogicX
+fLogicBarWidth
/2.0,fLowerYValue
,fLogicZ
) );
794 AddPointToPoly( aPoly
, aRightUpperPoint
);
795 AddPointToPoly( aPoly
, aLeftUpperPoint
);
796 AddPointToPoly( aPoly
, drawing::Position3D( fLogicX
-fLogicBarWidth
/2.0,fLowerYValue
,fLogicZ
) );
797 pPosHelper
->transformScaledLogicToScene( aPoly
);
798 xShape
= m_pShapeFactory
->createArea2D( xPointGroupShape_Shapes
, aPoly
);
799 this->setMappedProperties( xShape
, xDataPointProperties
, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
801 //set name/classified ObjectID (CID)
802 ShapeFactory::setShapeName(xShape
803 , ObjectIdentifier::createPointCID(
804 (*aSeriesIter
)->getPointCID_Stub(),nPointIndex
) );
808 createErrorBar_Y( aUnscaledLogicPosition
, **aSeriesIter
, nPointIndex
, m_xLogicTarget
, &fLogicX
);
811 //create data point label
812 if( (**aSeriesIter
).getDataPointLabelIfLabel(nPointIndex
) )
814 double fLogicSum
= aLogicYSumMap
[nAttachedAxisIndex
];
816 LabelAlignment
eAlignment(LABEL_ALIGN_CENTER
);
817 sal_Int32 nLabelPlacement
= pSeries
->getLabelPlacement( nPointIndex
, m_xChartTypeModel
, m_nDimension
, pPosHelper
->isSwapXAndY() );
819 double fLowerBarDepth
= fLogicBarDepth
;
820 double fUpperBarDepth
= fLogicBarDepth
;
822 double fOuterBarDepth
= fLogicBarDepth
;
823 if( lcl_hasGeometry3DVariableWidth(nGeometry3D
) && fCompleteHeight
!=0.0 )
825 fOuterBarDepth
= fLogicBarDepth
* (fTopHeight
)/(fabs(fCompleteHeight
));
826 fLowerBarDepth
= (fBaseValue
< fUpperYValue
) ? fabs(fLogicBarDepth
) : fabs(fOuterBarDepth
);
827 fUpperBarDepth
= (fBaseValue
< fUpperYValue
) ? fabs(fOuterBarDepth
) : fabs(fLogicBarDepth
);
831 awt::Point
aScreenPosition2D( this->getLabelScreenPositionAndAlignment(
832 eAlignment
, nLabelPlacement
833 , fLogicX
, fLowerYValue
, fUpperYValue
, fLogicZ
834 , fLowerBarDepth
, fUpperBarDepth
, fBaseValue
, pPosHelper
));
835 sal_Int32 nOffset
= 0;
836 if(LABEL_ALIGN_CENTER
!=eAlignment
)
838 nOffset
= 100;//add some spacing //@todo maybe get more intelligent values
839 if( m_nDimension
== 3 )
842 this->createDataLabel( xTextTarget
, **aSeriesIter
, nPointIndex
843 , fLogicValueForLabeDisplay
, fLogicSum
, aScreenPosition2D
, eAlignment
, nOffset
);
846 }//end iteration through partial points
848 }//next series in x slot (next y slot)
852 //=============================================================================
853 //=============================================================================
854 //=============================================================================
855 if( bDrawConnectionLines
)
857 ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::iterator aZSlotIter
= m_aZSlots
.begin();
858 const ::std::vector
< ::std::vector
< VDataSeriesGroup
> >::const_iterator aZSlotEnd
= m_aZSlots
.end();
859 //=============================================================================
860 for( sal_Int32 nZ
=1; aZSlotIter
!= aZSlotEnd
; ++aZSlotIter
, nZ
++ )
862 ::std::vector
< VDataSeriesGroup
>::iterator aXSlotIter
= aZSlotIter
->begin();
863 const ::std::vector
< VDataSeriesGroup
>::const_iterator aXSlotEnd
= aZSlotIter
->end();
865 BarPositionHelper
* pPosHelper
= m_pMainPosHelper
;
866 if( aXSlotIter
!= aXSlotEnd
)
868 sal_Int32 nAttachedAxisIndex
= aXSlotIter
->getAttachedAxisIndexForFirstSeries();
869 //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
870 pPosHelper
= dynamic_cast<BarPositionHelper
*>(&( this->getPlottingPositionHelper( nAttachedAxisIndex
) ) );
872 pPosHelper
= m_pMainPosHelper
;
874 PlotterBase::m_pPosHelper
= pPosHelper
;
876 //=============================================================================
877 //iterate through all x slots in this category
878 for( double fSlotX
=0; aXSlotIter
!= aXSlotEnd
; ++aXSlotIter
, fSlotX
+=1.0 )
880 ::std::vector
< VDataSeries
* >* pSeriesList
= &(aXSlotIter
->m_aSeriesVector
);
882 ::std::vector
< VDataSeries
* >::const_iterator aSeriesIter
= pSeriesList
->begin();
883 const ::std::vector
< VDataSeries
* >::const_iterator aSeriesEnd
= pSeriesList
->end();
884 //=============================================================================
885 //iterate through all series in this x slot
886 for( ; aSeriesIter
!= aSeriesEnd
; ++aSeriesIter
)
888 VDataSeries
* pSeries( *aSeriesIter
);
891 drawing::PolyPolygonShape3D
* pSeriesPoly
= &pSeries
->m_aPolyPolygonShape3D
;
892 if(!ShapeFactory::hasPolygonAnyLines(*pSeriesPoly
))
895 drawing::PolyPolygonShape3D aPoly
;
896 Clipping::clipPolygonAtRectangle( *pSeriesPoly
, pPosHelper
->getScaledLogicClipDoubleRect(), aPoly
);
898 if(!ShapeFactory::hasPolygonAnyLines(aPoly
))
901 //transformation 3) -> 4)
902 pPosHelper
->transformScaledLogicToScene( aPoly
);
904 uno::Reference
< drawing::XShapes
> xSeriesGroupShape_Shapes(
905 getSeriesGroupShape(*aSeriesIter
, xSeriesTarget
) );
906 uno::Reference
< drawing::XShape
> xShape( m_pShapeFactory
->createLine2D(
907 xSeriesGroupShape_Shapes
, PolyToPointSequence( aPoly
) ) );
908 this->setMappedProperties( xShape
, pSeries
->getPropertiesOfSeries()
909 , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
915 /* @todo remove series shapes if empty
918 OSL_TRACE( "\nPPPPPPPPP<<<<<<<<<<<< bar chart :: createShapes():: skipped points: %d created points: %d", nSkippedPoints
, nCreatedPoints
);
921 //.............................................................................
923 //.............................................................................
925 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */