fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / chart2 / source / view / charttypes / BarChart.cxx
blob6184d01e247028a2d4e32cd75ca68fb1bf5536a5
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 namespace chart
38 using namespace ::com::sun::star;
39 using namespace ::rtl::math;
40 using namespace ::com::sun::star::chart2;
42 BarChart::BarChart( const uno::Reference<XChartType>& xChartTypeModel
43 , sal_Int32 nDimensionCount )
44 : VSeriesPlotter( xChartTypeModel, nDimensionCount )
45 , m_pMainPosHelper( new BarPositionHelper() )
47 PlotterBase::m_pPosHelper = m_pMainPosHelper;
48 VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper;
50 try
52 if( m_xChartTypeModelProps.is() )
54 m_xChartTypeModelProps->getPropertyValue( "OverlapSequence" ) >>= m_aOverlapSequence;
55 m_xChartTypeModelProps->getPropertyValue( "GapwidthSequence" ) >>= m_aGapwidthSequence;
58 catch( const uno::Exception& e )
60 ASSERT_EXCEPTION( e );
64 BarChart::~BarChart()
66 delete m_pMainPosHelper;
69 PlottingPositionHelper& BarChart::getPlottingPositionHelper( sal_Int32 nAxisIndex ) const
71 PlottingPositionHelper& rPosHelper = VSeriesPlotter::getPlottingPositionHelper( nAxisIndex );
72 BarPositionHelper* pBarPosHelper = dynamic_cast<BarPositionHelper*>(&rPosHelper);
73 if( pBarPosHelper && nAxisIndex >= 0 )
75 if( nAxisIndex < m_aOverlapSequence.getLength() )
76 pBarPosHelper->setInnerDistance( -m_aOverlapSequence[nAxisIndex]/100.0 );
77 if( nAxisIndex < m_aGapwidthSequence.getLength() )
78 pBarPosHelper->setOuterDistance( m_aGapwidthSequence[nAxisIndex]/100.0 );
80 return rPosHelper;
83 drawing::Direction3D BarChart::getPreferredDiagramAspectRatio() const
85 drawing::Direction3D aRet(1.0,1.0,1.0);
86 if( m_nDimension == 3 )
88 aRet = drawing::Direction3D(1.0,-1.0,1.0);
89 BarPositionHelper* pPosHelper = dynamic_cast<BarPositionHelper*>(&( this->getPlottingPositionHelper( MAIN_AXIS_INDEX) ) );
90 if (pPosHelper)
92 drawing::Direction3D aScale( pPosHelper->getScaledLogicWidth() );
93 if(aScale.DirectionX!=0.0)
95 double fXSlotCount = 1.0;
96 if(!m_aZSlots.empty())
98 fXSlotCount = m_aZSlots.begin()->size();
100 aRet.DirectionZ = aScale.DirectionZ /
101 (aScale.DirectionX + aScale.DirectionX * (fXSlotCount-1.0) * pPosHelper->getScaledSlotWidth());
103 else
105 return VSeriesPlotter::getPreferredDiagramAspectRatio();
108 else
110 return VSeriesPlotter::getPreferredDiagramAspectRatio();
113 if(aRet.DirectionZ<0.05)
115 aRet.DirectionZ=0.05;
117 else if(aRet.DirectionZ>10)
119 aRet.DirectionZ=10;
121 if( m_pMainPosHelper && m_pMainPosHelper->isSwapXAndY() )
123 double fTemp = aRet.DirectionX;
124 aRet.DirectionX = aRet.DirectionY;
125 aRet.DirectionY = fTemp;
128 else
129 aRet = drawing::Direction3D(-1,-1,-1);
130 return aRet;
133 bool BarChart::keepAspectRatio() const
135 return true;
138 awt::Point BarChart::getLabelScreenPositionAndAlignment(
139 LabelAlignment& rAlignment, sal_Int32 nLabelPlacement
140 , double fScaledX, double fScaledLowerYValue, double fScaledUpperYValue, double fScaledZ
141 , double fScaledLowerBarDepth, double fScaledUpperBarDepth, double fBaseValue
142 , BarPositionHelper* pPosHelper
143 ) const
145 double fX = fScaledX;
146 double fY = fScaledUpperYValue;
147 double fZ = fScaledZ;
148 bool bReverse = !pPosHelper->isMathematicalOrientationY();
149 bool bNormalOutside = (!bReverse == !!(fBaseValue < fScaledUpperYValue));
150 double fDepth = fScaledUpperBarDepth;
152 switch(nLabelPlacement)
154 case ::com::sun::star::chart::DataLabelPlacement::TOP:
156 if( !pPosHelper->isSwapXAndY() )
158 fY = bReverse ? fScaledLowerYValue : fScaledUpperYValue;
159 rAlignment = LABEL_ALIGN_TOP;
160 if(3==m_nDimension)
161 fDepth = bReverse ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
163 else
165 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
166 rAlignment = LABEL_ALIGN_CENTER;
167 OSL_FAIL( "top label placement is not really supported by horizontal bar charts" );
170 break;
171 case ::com::sun::star::chart::DataLabelPlacement::BOTTOM:
173 if(!pPosHelper->isSwapXAndY())
175 fY = bReverse ? fScaledUpperYValue : fScaledLowerYValue;
176 rAlignment = LABEL_ALIGN_BOTTOM;
177 if(3==m_nDimension)
178 fDepth = bReverse ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
180 else
182 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
183 rAlignment = LABEL_ALIGN_CENTER;
184 OSL_FAIL( "bottom label placement is not supported by horizontal bar charts" );
187 break;
188 case ::com::sun::star::chart::DataLabelPlacement::LEFT:
190 if( pPosHelper->isSwapXAndY() )
192 fY = bReverse ? fScaledUpperYValue : fScaledLowerYValue;
193 rAlignment = LABEL_ALIGN_LEFT;
194 if(3==m_nDimension)
195 fDepth = bReverse ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
197 else
199 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
200 rAlignment = LABEL_ALIGN_CENTER;
201 OSL_FAIL( "left label placement is not supported by column charts" );
204 break;
205 case ::com::sun::star::chart::DataLabelPlacement::RIGHT:
207 if( pPosHelper->isSwapXAndY() )
209 fY = bReverse ? fScaledLowerYValue : fScaledUpperYValue;
210 rAlignment = LABEL_ALIGN_RIGHT;
211 if(3==m_nDimension)
212 fDepth = bReverse ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
214 else
216 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
217 rAlignment = LABEL_ALIGN_CENTER;
218 OSL_FAIL( "right label placement is not supported by column charts" );
221 break;
222 case ::com::sun::star::chart::DataLabelPlacement::OUTSIDE:
224 fY = (fBaseValue < fScaledUpperYValue) ? fScaledUpperYValue : fScaledLowerYValue;
225 if( pPosHelper->isSwapXAndY() )
226 rAlignment = bNormalOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT;
227 else
228 rAlignment = bNormalOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM;
229 if(3==m_nDimension)
230 fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
232 break;
233 case ::com::sun::star::chart::DataLabelPlacement::INSIDE:
235 fY = (fBaseValue < fScaledUpperYValue) ? fScaledUpperYValue : fScaledLowerYValue;
236 if( pPosHelper->isSwapXAndY() )
237 rAlignment = bNormalOutside ? LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT;
238 else
239 rAlignment = bNormalOutside ? LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP;
240 if(3==m_nDimension)
241 fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
243 break;
244 case ::com::sun::star::chart::DataLabelPlacement::NEAR_ORIGIN:
246 fY = (fBaseValue < fScaledUpperYValue) ? fScaledLowerYValue : fScaledUpperYValue;
247 if( pPosHelper->isSwapXAndY() )
248 rAlignment = bNormalOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT;
249 else
250 rAlignment = bNormalOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM;
251 if(3==m_nDimension)
252 fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
254 break;
255 case ::com::sun::star::chart::DataLabelPlacement::CENTER:
256 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
257 rAlignment = LABEL_ALIGN_CENTER;
258 if(3==m_nDimension)
259 fDepth = fabs(fScaledUpperBarDepth-fScaledLowerBarDepth)/2.0;
260 break;
261 default:
262 OSL_FAIL("this label alignment is not implemented yet");
264 break;
266 if(3==m_nDimension)
267 fZ -= fDepth/2.0;
269 drawing::Position3D aScenePosition3D( pPosHelper->
270 transformScaledLogicToScene( fX, fY, fZ, true ) );
271 return LabelPositionHelper(pPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory)
272 .transformSceneToScreenPosition( aScenePosition3D );
275 uno::Reference< drawing::XShape > BarChart::createDataPoint3D_Bar(
276 const uno::Reference< drawing::XShapes >& xTarget
277 , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize
278 , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree
279 , const uno::Reference< beans::XPropertySet >& xObjectProperties
280 , sal_Int32 nGeometry3D )
282 bool bRoundedEdges = true;
285 if( xObjectProperties.is() )
287 sal_Int16 nPercentDiagonal = 0;
288 xObjectProperties->getPropertyValue( "PercentDiagonal" ) >>= nPercentDiagonal;
289 if( nPercentDiagonal < 5 )
290 bRoundedEdges = false;
293 catch( const uno::Exception& e )
295 ASSERT_EXCEPTION( e );
298 uno::Reference< drawing::XShape > xShape(NULL);
299 switch( nGeometry3D )
301 case DataPointGeometry3D::CYLINDER:
302 xShape = m_pShapeFactory->createCylinder( xTarget, rPosition, rSize, nRotateZAngleHundredthDegree );
303 break;
304 case DataPointGeometry3D::CONE:
305 xShape = m_pShapeFactory->createCone( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree );
306 break;
307 case DataPointGeometry3D::PYRAMID:
308 xShape = m_pShapeFactory->createPyramid( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree>0
309 , xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
310 break;
311 case DataPointGeometry3D::CUBOID:
312 default:
313 xShape = m_pShapeFactory->createCube( xTarget, rPosition, rSize
314 , nRotateZAngleHundredthDegree, xObjectProperties
315 , PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), bRoundedEdges );
316 return xShape;
318 if( nGeometry3D != DataPointGeometry3D::PYRAMID )
319 setMappedProperties( xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
320 return xShape;
323 namespace
325 bool lcl_hasGeometry3DVariableWidth( sal_Int32 nGeometry3D )
327 bool bRet = false;
328 switch( nGeometry3D )
330 case DataPointGeometry3D::PYRAMID:
331 case DataPointGeometry3D::CONE:
332 bRet = true;
333 break;
334 case DataPointGeometry3D::CUBOID:
335 case DataPointGeometry3D::CYLINDER:
336 default:
337 bRet = false;
338 break;
340 return bRet;
342 }// end anonymous namespace
344 void BarChart::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
346 if( !pSeries )
347 return;
348 if(m_nDimension==2)
350 //2ND_AXIS_IN_BARS put series on second scales to different z slot as temporary workaround
351 //this needs to be redesigned if 3d bars are also able to display secondary axes
353 sal_Int32 nAxisIndex = pSeries->getAttachedAxisIndex();
354 zSlot = nAxisIndex;
356 if( !pSeries->getGroupBarsPerAxis() )
357 zSlot = 0;
358 if(zSlot>=static_cast<sal_Int32>(m_aZSlots.size()))
359 m_aZSlots.resize(zSlot+1);
361 VSeriesPlotter::addSeries( pSeries, zSlot, xSlot, ySlot );
364 //better performance for big data
365 struct FormerBarPoint
367 FormerBarPoint( double fX, double fUpperY, double fLowerY, double fZ )
368 : m_fX(fX), m_fUpperY(fUpperY), m_fLowerY(fLowerY), m_fZ(fZ)
370 FormerBarPoint()
372 ::rtl::math::setNan( &m_fX );
373 ::rtl::math::setNan( &m_fUpperY );
374 ::rtl::math::setNan( &m_fLowerY );
375 ::rtl::math::setNan( &m_fZ );
378 double m_fX;
379 double m_fUpperY;
380 double m_fLowerY;
381 double m_fZ;
384 void BarChart::adaptOverlapAndGapwidthForGroupBarsPerAxis()
386 //adapt m_aOverlapSequence and m_aGapwidthSequence for the groupBarsPerAxis feature
387 //thus the different series use the same settings
389 VDataSeries* pFirstSeries = getFirstSeries();
390 if(pFirstSeries && !pFirstSeries->getGroupBarsPerAxis() )
392 sal_Int32 nAxisIndex = pFirstSeries->getAttachedAxisIndex();
393 sal_Int32 nN = 0;
394 sal_Int32 nUseThisIndex = nAxisIndex;
395 if( nUseThisIndex < 0 || nUseThisIndex >= m_aOverlapSequence.getLength() )
396 nUseThisIndex = 0;
397 for( nN = 0; nN < m_aOverlapSequence.getLength(); nN++ )
399 if(nN!=nUseThisIndex)
400 m_aOverlapSequence[nN] = m_aOverlapSequence[nUseThisIndex];
403 nUseThisIndex = nAxisIndex;
404 if( nUseThisIndex < 0 || nUseThisIndex >= m_aGapwidthSequence.getLength() )
405 nUseThisIndex = 0;
406 for( nN = 0; nN < m_aGapwidthSequence.getLength(); nN++ )
408 if(nN!=nUseThisIndex)
409 m_aGapwidthSequence[nN] = m_aGapwidthSequence[nUseThisIndex];
414 void BarChart::createShapes()
416 if( m_aZSlots.begin() == m_aZSlots.end() ) //no series
417 return;
419 OSL_ENSURE(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"BarChart is not proper initialized");
420 if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()))
421 return;
423 //the text labels should be always on top of the other series shapes
424 //therefore create an own group for the texts to move them to front
425 //(because the text group is created after the series group the texts are displayed on top)
427 //the regression curves should always be on top of the bars but beneath the text labels
428 //to achieve this the regression curve target is created after the series target and before the text target
430 uno::Reference< drawing::XShapes > xSeriesTarget(
431 createGroupShape( m_xLogicTarget,OUString() ));
432 uno::Reference< drawing::XShapes > xRegressionCurveTarget(
433 createGroupShape( m_xLogicTarget,OUString() ));
434 uno::Reference< drawing::XShapes > xTextTarget(
435 m_pShapeFactory->createGroup2D( m_xFinalTarget,OUString() ));
437 uno::Reference< drawing::XShapes > xRegressionCurveEquationTarget(
438 m_pShapeFactory->createGroup2D( m_xFinalTarget,OUString() ));
439 //check necessary here that different Y axis can not be stacked in the same group? ... hm?
441 double fLogicZ = 1.0;//as defined
443 bool bDrawConnectionLines = false;
444 bool bDrawConnectionLinesInited = false;
445 bool bOnlyConnectionLinesForThisPoint = false;
447 adaptOverlapAndGapwidthForGroupBarsPerAxis();
449 //better performance for big data
450 std::map< VDataSeries*, FormerBarPoint > aSeriesFormerPointMap;
451 m_bPointsWereSkipped = false;
452 sal_Int32 nSkippedPoints = 0;
453 sal_Int32 nCreatedPoints = 0;
455 sal_Int32 nStartIndex = 0;
456 sal_Int32 nEndIndex = VSeriesPlotter::getPointCount();
457 //iterate through all x values per indices
458 for( sal_Int32 nPointIndex = nStartIndex; nPointIndex < nEndIndex; nPointIndex++ )
460 ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
461 const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
463 //sum up the values for all series in a complete z zlot per attached axis
464 ::std::map< sal_Int32, double > aLogicYSumMap;
465 for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
467 ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
468 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
470 for( aXSlotIter = aZSlotIter->begin(); aXSlotIter != aXSlotEnd; ++aXSlotIter )
472 sal_Int32 nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries();
473 if( aLogicYSumMap.find(nAttachedAxisIndex)==aLogicYSumMap.end() )
474 aLogicYSumMap[nAttachedAxisIndex]=0.0;
476 double fMinimumY = 0.0, fMaximumY = 0.0;
477 aXSlotIter->calculateYMinAndMaxForCategory( nPointIndex
478 , isSeparateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex );
480 if( !::rtl::math::isNan( fMaximumY ) && fMaximumY > 0)
481 aLogicYSumMap[nAttachedAxisIndex] += fMaximumY;
482 if( !::rtl::math::isNan( fMinimumY ) && fMinimumY < 0)
483 aLogicYSumMap[nAttachedAxisIndex] += fabs(fMinimumY);
487 aZSlotIter = m_aZSlots.begin();
488 for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; ++aZSlotIter, nZ++ )
490 ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
491 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
493 //iterate through all x slots in this category
494 double fSlotX=0;
495 for( aXSlotIter = aZSlotIter->begin(); aXSlotIter != aXSlotEnd; ++aXSlotIter, fSlotX+=1.0 )
497 sal_Int32 nAttachedAxisIndex = 0;
498 BarPositionHelper* pPosHelper = m_pMainPosHelper;
499 if( aXSlotIter != aXSlotEnd )
501 nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries();
502 //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
503 pPosHelper = dynamic_cast<BarPositionHelper*>(&( this->getPlottingPositionHelper( nAttachedAxisIndex ) ) );
504 if(!pPosHelper)
505 pPosHelper = m_pMainPosHelper;
507 PlotterBase::m_pPosHelper = pPosHelper;
509 //update/create information for current group
510 pPosHelper->updateSeriesCount( aZSlotIter->size() );
511 double fLogicBaseWidth = pPosHelper->getScaledSlotWidth();
513 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
515 // get distance from base value to maximum and minimum
517 double fMinimumY = 0.0, fMaximumY = 0.0;
518 aXSlotIter->calculateYMinAndMaxForCategory( nPointIndex
519 , isSeparateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex );
521 double fLogicPositiveYSum = 0.0;
522 if( !::rtl::math::isNan( fMaximumY ) )
523 fLogicPositiveYSum = fMaximumY;
525 double fLogicNegativeYSum = 0.0;
526 if( !::rtl::math::isNan( fMinimumY ) )
527 fLogicNegativeYSum = fMinimumY;
529 if( pPosHelper->isPercentY() )
531 /* #i70395# fLogicPositiveYSum contains sum of all positive
532 values, if any, otherwise the highest negative value.
533 fLogicNegativeYSum contains sum of all negative values,
534 if any, otherwise the lowest positive value.
535 Afterwards, fLogicPositiveYSum will contain the maximum
536 (positive) value that is related to 100%. */
538 // do nothing if there are positive values only
539 if( fLogicNegativeYSum < 0.0 )
541 // fLogicPositiveYSum<0 => negative values only, use absolute of negative sum
542 if( fLogicPositiveYSum < 0.0 )
543 fLogicPositiveYSum = -fLogicNegativeYSum;
544 // otherwise there are positive and negative values, calculate total distance
545 else
546 fLogicPositiveYSum -= fLogicNegativeYSum;
548 fLogicNegativeYSum = 0.0;
551 double fBaseValue = 0.0;
552 if( !pPosHelper->isPercentY() && pSeriesList->size()<=1 )
553 fBaseValue = pPosHelper->getBaseValueY();
554 double fPositiveLogicYForNextSeries = fBaseValue;
555 double fNegativeLogicYForNextSeries = fBaseValue;
557 ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
558 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
559 //iterate through all series in this x slot
560 for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
562 VDataSeries* pSeries( *aSeriesIter );
563 if(!pSeries)
564 continue;
566 bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor");
568 bOnlyConnectionLinesForThisPoint = false;
570 if(nPointIndex==nStartIndex)//do not create a regression line for each point
571 createRegressionCurvesShapes( **aSeriesIter, xRegressionCurveTarget, xRegressionCurveEquationTarget,
572 m_pPosHelper->maySkipPointsInRegressionCalculation());
574 if( !bDrawConnectionLinesInited )
576 bDrawConnectionLines = pSeries->getConnectBars();
577 if( m_nDimension==3 )
578 bDrawConnectionLines = false;
579 if( bDrawConnectionLines && pSeriesList->size()==1 )
581 //detect whether we have a stacked chart or not:
582 StackingDirection eDirection = pSeries->getStackingDirection();
583 if( eDirection != StackingDirection_Y_STACKING )
584 bDrawConnectionLines = false;
586 bDrawConnectionLinesInited = true;
589 uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes(
590 getSeriesGroupShape(*aSeriesIter, xSeriesTarget) );
592 //collect data point information (logic coordinates, style ):
593 double fUnscaledLogicX = (*aSeriesIter)->getXValue( nPointIndex );
594 fUnscaledLogicX = DateHelper::RasterizeDateValue( fUnscaledLogicX, m_aNullDate, m_nTimeResolution );
595 if(fUnscaledLogicX<pPosHelper->getLogicMinX())
596 continue;//point not visible
597 if(fUnscaledLogicX>pPosHelper->getLogicMaxX())
598 continue;//point not visible
599 if(pPosHelper->isStrongLowerRequested(0) && fUnscaledLogicX==pPosHelper->getLogicMaxX())
600 continue;//point not visible
601 double fLogicX = pPosHelper->getScaledSlotPos( fUnscaledLogicX, fSlotX );
603 double fLogicBarHeight = (*aSeriesIter)->getYValue( nPointIndex );
604 if( ::rtl::math::isNan( fLogicBarHeight )) //no value at this category
605 continue;
607 double fLogicValueForLabeDisplay = fLogicBarHeight;
608 fLogicBarHeight-=fBaseValue;
610 if( pPosHelper->isPercentY() )
612 if(fLogicPositiveYSum!=0.0)
613 fLogicBarHeight = fabs( fLogicBarHeight )/fLogicPositiveYSum;
614 else
615 fLogicBarHeight = 0.0;
618 //sort negative and positive values, to display them on different sides of the x axis
619 bool bPositive = fLogicBarHeight >= 0.0;
620 double fLowerYValue = bPositive ? fPositiveLogicYForNextSeries : fNegativeLogicYForNextSeries;
621 double fUpperYValue = fLowerYValue+fLogicBarHeight;
622 if( bPositive )
623 fPositiveLogicYForNextSeries += fLogicBarHeight;
624 else
625 fNegativeLogicYForNextSeries += fLogicBarHeight;
627 if(m_nDimension==3)
628 fLogicZ = nZ+0.5;
630 drawing::Position3D aUnscaledLogicPosition( fUnscaledLogicX, fUpperYValue, fLogicZ );
632 //@todo ... start an iteration over the different breaks of the axis
633 //each subsystem may add an additional shape to form the whole point
634 //create a group shape for this point and add to the series shape:
635 // uno::Reference< drawing::XShapes > xPointGroupShape_Shapes( createGroupShape(xSeriesGroupShape_Shapes) );
636 // uno::Reference<drawing::XShape> xPointGroupShape_Shape =
637 // uno::Reference<drawing::XShape>( xPointGroupShape_Shapes, uno::UNO_QUERY );
638 //as long as we do not iterate we do not need to create an additional group for each point
639 uno::Reference< drawing::XShapes > xPointGroupShape_Shapes = xSeriesGroupShape_Shapes;
640 uno::Reference< beans::XPropertySet > xDataPointProperties( (*aSeriesIter)->getPropertiesOfPoint( nPointIndex ) );
641 sal_Int32 nGeometry3D = DataPointGeometry3D::CUBOID;
642 if(m_nDimension==3) try
644 xDataPointProperties->getPropertyValue( "Geometry3D") >>= nGeometry3D;
646 catch( const uno::Exception& e )
648 ASSERT_EXCEPTION( e );
651 //@todo iterate through all subsystems to create partial points
653 //@todo select a suitable PositionHelper for this subsystem
654 BarPositionHelper* pSubPosHelper = pPosHelper;
656 double fUnclippedUpperYValue = fUpperYValue;
658 //apply clipping to Y
659 if( !pPosHelper->clipYRange(fLowerYValue,fUpperYValue) )
661 if( bDrawConnectionLines )
662 bOnlyConnectionLinesForThisPoint = true;
663 else
664 continue;
666 //@todo clipping of X and Z is not fully integrated so far, as there is a need to create different objects
668 //apply scaling to Y before calculating width (necessary to maintain gradient in clipped objects)
669 pSubPosHelper->doLogicScaling(NULL,&fLowerYValue,NULL);
670 pSubPosHelper->doLogicScaling(NULL,&fUpperYValue,NULL);
671 //scaling of X and Z is not provided as the created objects should be symmetric in that dimensions
673 pSubPosHelper->doLogicScaling(NULL,&fUnclippedUpperYValue,NULL);
675 //calculate resulting width
676 double fCompleteHeight = bPositive ? fLogicPositiveYSum : fLogicNegativeYSum;
677 if( pPosHelper->isPercentY() )
678 fCompleteHeight = 1.0;
679 double fLogicBarWidth = fLogicBaseWidth;
680 double fTopHeight=approxSub(fCompleteHeight,fUpperYValue);
681 if(!bPositive)
682 fTopHeight=approxSub(fCompleteHeight,fLowerYValue);
683 double fLogicYStart = bPositive ? fLowerYValue : fUpperYValue;
684 double fMiddleHeight = fUpperYValue-fLowerYValue;
685 if(!bPositive)
686 fMiddleHeight*=-1.0;
687 double fLogicBarDepth = 0.5;
688 if(m_nDimension==3)
690 if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 )
692 double fHeight = fCompleteHeight-fLowerYValue;
693 if(!bPositive)
694 fHeight = fCompleteHeight-fUpperYValue;
695 fLogicBarWidth = fLogicBaseWidth*fHeight/(fCompleteHeight);
696 if(fLogicBarWidth<=0.0)
697 fLogicBarWidth=fLogicBaseWidth;
698 fLogicBarDepth = fLogicBarDepth*fHeight/(fCompleteHeight);
699 if(fLogicBarDepth<=0.0)
700 fLogicBarDepth*=-1.0;
704 //better performance for big data
705 FormerBarPoint aFormerPoint( aSeriesFormerPointMap[pSeries] );
706 pPosHelper->setCoordinateSystemResolution( m_aCoordinateSystemResolution );
707 if( !pSeries->isAttributedDataPoint(nPointIndex)
709 pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fUpperY, aFormerPoint.m_fZ
710 , fLogicX, fUpperYValue, fLogicZ )
712 pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fLowerY, aFormerPoint.m_fZ
713 , fLogicX, fLowerYValue, fLogicZ )
716 nSkippedPoints++;
717 m_bPointsWereSkipped = true;
718 continue;
720 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 // performance improvement: alloc the sequence before the rendering
789 // otherwise we have 2 realloc calls
790 drawing::PolyPolygonShape3D aPoly;
791 aPoly.SequenceX.realloc(1);
792 aPoly.SequenceY.realloc(1);
793 aPoly.SequenceZ.realloc(1);
794 drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUpperYValue,fLogicZ );
795 drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUpperYValue,fLogicZ );
797 AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
798 AddPointToPoly( aPoly, drawing::Position3D( fLogicX+fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
799 AddPointToPoly( aPoly, aRightUpperPoint );
800 AddPointToPoly( aPoly, aLeftUpperPoint );
801 AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
802 pPosHelper->transformScaledLogicToScene( aPoly );
803 xShape = m_pShapeFactory->createArea2D( xPointGroupShape_Shapes, aPoly );
804 setMappedProperties( xShape, xDataPointProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
807 if(bHasFillColorMapping)
809 double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor");
810 if(!rtl::math::isNan(nPropVal))
812 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW );
813 xProps->setPropertyValue("FillColor", uno::makeAny(static_cast<sal_Int32>(nPropVal)));
816 //set name/classified ObjectID (CID)
817 ShapeFactory::setShapeName(xShape
818 , ObjectIdentifier::createPointCID(
819 (*aSeriesIter)->getPointCID_Stub(),nPointIndex) );
822 //create error bar
823 createErrorBar_Y( aUnscaledLogicPosition, **aSeriesIter, nPointIndex, m_xLogicTarget, &fLogicX );
825 //create data point label
826 if( (**aSeriesIter).getDataPointLabelIfLabel(nPointIndex) )
828 double fLogicSum = aLogicYSumMap[nAttachedAxisIndex];
830 LabelAlignment eAlignment(LABEL_ALIGN_CENTER);
831 sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nPointIndex, m_xChartTypeModel, m_nDimension, pPosHelper->isSwapXAndY() );
833 double fLowerBarDepth = fLogicBarDepth;
834 double fUpperBarDepth = fLogicBarDepth;
836 double fOuterBarDepth = fLogicBarDepth;
837 if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 )
839 fOuterBarDepth = fLogicBarDepth * (fTopHeight)/(fabs(fCompleteHeight));
840 fLowerBarDepth = (fBaseValue < fUpperYValue) ? fabs(fLogicBarDepth) : fabs(fOuterBarDepth);
841 fUpperBarDepth = (fBaseValue < fUpperYValue) ? fabs(fOuterBarDepth) : fabs(fLogicBarDepth);
845 awt::Point aScreenPosition2D = getLabelScreenPositionAndAlignment(
846 eAlignment, nLabelPlacement, fLogicX, fLowerYValue, fUpperYValue, fLogicZ,
847 fLowerBarDepth, fUpperBarDepth, fBaseValue, pPosHelper);
848 sal_Int32 nOffset = 0;
849 if(LABEL_ALIGN_CENTER!=eAlignment)
851 nOffset = 100;//add some spacing //@todo maybe get more intelligent values
852 if( m_nDimension == 3 )
853 nOffset = 260;
855 createDataLabel(
856 xTextTarget, **aSeriesIter, nPointIndex,
857 fLogicValueForLabeDisplay, fLogicSum, aScreenPosition2D, eAlignment, nOffset);
860 }//end iteration through partial points
862 }//next series in x slot (next y slot)
863 }//next x slot
864 }//next z slot
865 }//next category
866 if( bDrawConnectionLines )
868 ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
869 const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
870 for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; ++aZSlotIter, nZ++ )
872 ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
873 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
875 BarPositionHelper* pPosHelper = m_pMainPosHelper;
876 if( aXSlotIter != aXSlotEnd )
878 sal_Int32 nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries();
879 //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
880 pPosHelper = dynamic_cast<BarPositionHelper*>(&( this->getPlottingPositionHelper( nAttachedAxisIndex ) ) );
881 if(!pPosHelper)
882 pPosHelper = m_pMainPosHelper;
884 PlotterBase::m_pPosHelper = pPosHelper;
886 //iterate through all x slots in this category
887 for( double fSlotX=0; aXSlotIter != aXSlotEnd; ++aXSlotIter, fSlotX+=1.0 )
889 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
891 ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
892 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
893 //iterate through all series in this x slot
894 for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
896 VDataSeries* pSeries( *aSeriesIter );
897 if(!pSeries)
898 continue;
899 drawing::PolyPolygonShape3D* pSeriesPoly = &pSeries->m_aPolyPolygonShape3D;
900 if(!ShapeFactory::hasPolygonAnyLines(*pSeriesPoly))
901 continue;
903 drawing::PolyPolygonShape3D aPoly;
904 Clipping::clipPolygonAtRectangle( *pSeriesPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
906 if(!ShapeFactory::hasPolygonAnyLines(aPoly))
907 continue;
909 //transformation 3) -> 4)
910 pPosHelper->transformScaledLogicToScene( aPoly );
912 uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes(
913 getSeriesGroupShape(*aSeriesIter, xSeriesTarget) );
914 uno::Reference< drawing::XShape > xShape( m_pShapeFactory->createLine2D(
915 xSeriesGroupShape_Shapes, PolyToPointSequence( aPoly ) ) );
916 setMappedProperties( xShape, pSeries->getPropertiesOfSeries()
917 , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
923 /* @todo remove series shapes if empty
926 SAL_INFO(
927 "chart2",
928 "skipped points: " << nSkippedPoints << " created points: "
929 << nCreatedPoints);
932 } //namespace chart
934 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */