bump product version to 4.1.6.2
[LibreOffice.git] / chart2 / source / view / charttypes / BarChart.cxx
blob9caca6e7d23a0f18f6b5570bb33366759cb2b62c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
26 #include "macros.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 //.............................................................................
37 namespace chart
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;
52 try
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 );
66 BarChart::~BarChart()
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 );
84 return rPosHelper;
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());
103 else
104 return VSeriesPlotter::getPreferredDiagramAspectRatio();
105 if(aRet.DirectionZ<0.05)
106 aRet.DirectionZ=0.05;
107 if(aRet.DirectionZ>10)
108 aRet.DirectionZ=10;
110 if( m_pMainPosHelper && m_pMainPosHelper->isSwapXAndY() )
112 double fTemp = aRet.DirectionX;
113 aRet.DirectionX = aRet.DirectionY;
114 aRet.DirectionY = fTemp;
117 else
118 aRet = drawing::Direction3D(-1,-1,-1);
119 return aRet;
122 bool BarChart::keepAspectRatio() const
124 if( m_nDimension == 3 )
125 return true;
126 return true;
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
134 ) const
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;
151 if(3==m_nDimension)
152 fDepth = bReverse ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
154 else
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" );
161 break;
162 case ::com::sun::star::chart::DataLabelPlacement::BOTTOM:
164 if(!pPosHelper->isSwapXAndY())
166 fY = bReverse ? fScaledUpperYValue : fScaledLowerYValue;
167 rAlignment = LABEL_ALIGN_BOTTOM;
168 if(3==m_nDimension)
169 fDepth = bReverse ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
171 else
173 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
174 rAlignment = LABEL_ALIGN_CENTER;
175 OSL_FAIL( "bottom label placement is not supported by horizontal bar charts" );
178 break;
179 case ::com::sun::star::chart::DataLabelPlacement::LEFT:
181 if( pPosHelper->isSwapXAndY() )
183 fY = bReverse ? fScaledUpperYValue : fScaledLowerYValue;
184 rAlignment = LABEL_ALIGN_LEFT;
185 if(3==m_nDimension)
186 fDepth = bReverse ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
188 else
190 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
191 rAlignment = LABEL_ALIGN_CENTER;
192 OSL_FAIL( "left label placement is not supported by column charts" );
195 break;
196 case ::com::sun::star::chart::DataLabelPlacement::RIGHT:
198 if( pPosHelper->isSwapXAndY() )
200 fY = bReverse ? fScaledLowerYValue : fScaledUpperYValue;
201 rAlignment = LABEL_ALIGN_RIGHT;
202 if(3==m_nDimension)
203 fDepth = bReverse ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
205 else
207 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
208 rAlignment = LABEL_ALIGN_CENTER;
209 OSL_FAIL( "right label placement is not supported by column charts" );
212 break;
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;
218 else
219 rAlignment = bNormalOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM;
220 if(3==m_nDimension)
221 fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
223 break;
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;
229 else
230 rAlignment = bNormalOutside ? LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP;
231 if(3==m_nDimension)
232 fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
234 break;
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;
240 else
241 rAlignment = bNormalOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM;
242 if(3==m_nDimension)
243 fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
245 break;
246 case ::com::sun::star::chart::DataLabelPlacement::CENTER:
247 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
248 rAlignment = LABEL_ALIGN_CENTER;
249 if(3==m_nDimension)
250 fDepth = fabs(fScaledUpperBarDepth-fScaledLowerBarDepth)/2.0;
251 break;
252 default:
253 OSL_FAIL("this label alignment is not implemented yet");
255 break;
257 if(3==m_nDimension)
258 fZ -= fDepth/2.0;
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 );
294 break;
295 case DataPointGeometry3D::CONE:
296 xShape = m_pShapeFactory->createCone( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree );
297 break;
298 case DataPointGeometry3D::PYRAMID:
299 xShape = m_pShapeFactory->createPyramid( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree>0
300 , xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
301 break;
302 case DataPointGeometry3D::CUBOID:
303 default:
304 xShape = m_pShapeFactory->createCube( xTarget, rPosition, rSize
305 , nRotateZAngleHundredthDegree, xObjectProperties
306 , PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), bRoundedEdges );
307 return xShape;
309 if( nGeometry3D != DataPointGeometry3D::PYRAMID )
310 this->setMappedProperties( xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
311 return xShape;
314 namespace
316 bool lcl_hasGeometry3DVariableWidth( sal_Int32 nGeometry3D )
318 bool bRet = false;
319 switch( nGeometry3D )
321 case DataPointGeometry3D::PYRAMID:
322 case DataPointGeometry3D::CONE:
323 bRet = true;
324 break;
325 case DataPointGeometry3D::CUBOID:
326 case DataPointGeometry3D::CYLINDER:
327 default:
328 bRet = false;
329 break;
331 return bRet;
333 }// end anonymous namespace
335 void BarChart::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
337 if( !pSeries )
338 return;
339 if(m_nDimension==2)
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();
345 zSlot = nAxisIndex;
347 if( !pSeries->getGroupBarsPerAxis() )
348 zSlot = 0;
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)
361 FormerBarPoint()
363 ::rtl::math::setNan( &m_fX );
364 ::rtl::math::setNan( &m_fUpperY );
365 ::rtl::math::setNan( &m_fLowerY );
366 ::rtl::math::setNan( &m_fZ );
369 double m_fX;
370 double m_fUpperY;
371 double m_fLowerY;
372 double 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();
384 sal_Int32 nN = 0;
385 sal_Int32 nUseThisIndex = nAxisIndex;
386 if( nUseThisIndex < 0 || nUseThisIndex >= m_aOverlapSequence.getLength() )
387 nUseThisIndex = 0;
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() )
396 nUseThisIndex = 0;
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
408 return;
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()))
412 return;
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
491 double fSlotX=0;
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 ) ) );
501 if(!pPosHelper)
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
542 else
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 );
561 if(!pSeries)
562 continue;
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;
585 //------------
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
603 continue;
605 double fLogicValueForLabeDisplay = fLogicBarHeight;
606 fLogicBarHeight-=fBaseValue;
608 if( pPosHelper->isPercentY() )
610 if(fLogicPositiveYSum!=0.0)
611 fLogicBarHeight = fabs( fLogicBarHeight )/fLogicPositiveYSum;
612 else
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;
620 if( bPositive )
621 fPositiveLogicYForNextSeries += fLogicBarHeight;
622 else
623 fNegativeLogicYForNextSeries += fLogicBarHeight;
625 if(m_nDimension==3)
626 fLogicZ = nZ+0.5;
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;
661 else
662 continue;
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);
679 if(!bPositive)
680 fTopHeight=approxSub(fCompleteHeight,fLowerYValue);
681 double fLogicYStart = bPositive ? fLowerYValue : fUpperYValue;
682 double fMiddleHeight = fUpperYValue-fLowerYValue;
683 if(!bPositive)
684 fMiddleHeight*=-1.0;
685 double fLogicBarDepth = 0.5;
686 if(m_nDimension==3)
688 if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 )
690 double fHeight = fCompleteHeight-fLowerYValue;
691 if(!bPositive)
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 )
714 nSkippedPoints++;
715 m_bPointsWereSkipped = true;
716 continue;
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 )
736 continue;
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 );
743 nCreatedPoints++;
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;
779 if( fTopHeight < 0 )
780 fTopHeight *= -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) );
807 //create error bar
808 createErrorBar_Y( aUnscaledLogicPosition, **aSeriesIter, nPointIndex, m_xLogicTarget, &fLogicX );
810 //------------
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 )
840 nOffset = 260;
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)
849 }//next x slot
850 }//next z slot
851 }//next category
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 ) ) );
871 if(!pPosHelper)
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 );
889 if(!pSeries)
890 continue;
891 drawing::PolyPolygonShape3D* pSeriesPoly = &pSeries->m_aPolyPolygonShape3D;
892 if(!ShapeFactory::hasPolygonAnyLines(*pSeriesPoly))
893 continue;
895 drawing::PolyPolygonShape3D aPoly;
896 Clipping::clipPolygonAtRectangle( *pSeriesPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
898 if(!ShapeFactory::hasPolygonAnyLines(aPoly))
899 continue;
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 //.............................................................................
922 } //namespace chart
923 //.............................................................................
925 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */