merge the formfield patch from ooo-build
[ooovba.git] / chart2 / source / view / charttypes / BarChart.cxx
blob124d4afcb93f67d6fe261fa34858e189e21b1e99
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: BarChart.cxx,v $
10 * $Revision: 1.25 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_chart2.hxx"
35 #include "BarChart.hxx"
36 #include "ShapeFactory.hxx"
37 //#include "chartview/servicenames_charttypes.hxx"
38 //#include "servicenames_coosystems.hxx"
39 #include "CommonConverters.hxx"
40 #include "ObjectIdentifier.hxx"
41 #include "LabelPositionHelper.hxx"
42 #include "BarPositionHelper.hxx"
43 #include "macros.hxx"
44 #include "AxisIndexDefines.hxx"
45 #include "Clipping.hxx"
47 #include <com/sun/star/chart/DataLabelPlacement.hpp>
49 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
50 #include <tools/debug.hxx>
51 #include <rtl/math.hxx>
53 //.............................................................................
54 namespace chart
56 //.............................................................................
57 using namespace ::com::sun::star;
58 using namespace ::rtl::math;
59 using namespace ::com::sun::star::chart2;
61 //-----------------------------------------------------------------------------
62 //-----------------------------------------------------------------------------
63 //-----------------------------------------------------------------------------
65 BarChart::BarChart( const uno::Reference<XChartType>& xChartTypeModel
66 , sal_Int32 nDimensionCount )
67 : VSeriesPlotter( xChartTypeModel, nDimensionCount )
68 , m_pMainPosHelper( new BarPositionHelper() )
70 PlotterBase::m_pPosHelper = m_pMainPosHelper;
71 VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper;
73 try
75 if( m_xChartTypeModelProps.is() )
77 m_xChartTypeModelProps->getPropertyValue( C2U( "OverlapSequence" ) ) >>= m_aOverlapSequence;
78 m_xChartTypeModelProps->getPropertyValue( C2U( "GapwidthSequence" ) ) >>= m_aGapwidthSequence;
81 catch( uno::Exception& e )
83 ASSERT_EXCEPTION( e );
87 BarChart::~BarChart()
89 delete m_pMainPosHelper;
92 //-------------------------------------------------------------------------
94 PlottingPositionHelper& BarChart::getPlottingPositionHelper( sal_Int32 nAxisIndex ) const
96 PlottingPositionHelper& rPosHelper = VSeriesPlotter::getPlottingPositionHelper( nAxisIndex );
98 BarPositionHelper* pBarPosHelper = dynamic_cast<BarPositionHelper*>(&rPosHelper);
99 if( pBarPosHelper && nAxisIndex >= 0 )
101 if( nAxisIndex < m_aOverlapSequence.getLength() )
102 pBarPosHelper->setInnerDistance( -m_aOverlapSequence[nAxisIndex]/100.0 );
103 if( nAxisIndex < m_aGapwidthSequence.getLength() )
104 pBarPosHelper->setOuterDistance( m_aGapwidthSequence[nAxisIndex]/100.0 );
107 return rPosHelper;
110 drawing::Direction3D BarChart::getPreferredDiagramAspectRatio() const
112 drawing::Direction3D aRet(1.0,1.0,1.0);
113 if( m_nDimension == 3 )
115 aRet = drawing::Direction3D(1.0,-1.0,1.0);
116 drawing::Direction3D aScale( this->getPlottingPositionHelper(MAIN_AXIS_INDEX).getScaledLogicWidth() );
117 if(aScale.DirectionX!=0.0)
118 aRet.DirectionZ = aScale.DirectionZ/aScale.DirectionX;
119 else
120 return VSeriesPlotter::getPreferredDiagramAspectRatio();
121 if(aRet.DirectionZ<0.05)
122 aRet.DirectionZ=0.05;
123 if(aRet.DirectionZ>10)
124 aRet.DirectionZ=10;
126 if( m_pMainPosHelper && m_pMainPosHelper->isSwapXAndY() )
128 double fTemp = aRet.DirectionX;
129 aRet.DirectionX = aRet.DirectionY;
130 aRet.DirectionY = fTemp;
133 else
134 aRet = drawing::Direction3D(-1,-1,-1);
135 return aRet;
138 bool BarChart::keepAspectRatio() const
140 if( m_nDimension == 3 )
141 return true;
142 return true;
145 //-------------------------------------------------------------------------
146 // MinimumAndMaximumSupplier
147 //-------------------------------------------------------------------------
149 double BarChart::getMinimumX()
151 if( m_bCategoryXAxis )
152 return 0.5;//first category (index 0) matches with real number 1.0
153 return VSeriesPlotter::getMinimumX();
155 double BarChart::getMaximumX()
157 if( m_bCategoryXAxis )
159 //return category count
160 sal_Int32 nPointCount = getPointCount();
161 return nPointCount+0.5;//first category (index 0) matches with real number 1.0
163 return VSeriesPlotter::getMaximumX();
166 //-----------------------------------------------------------------
167 // lang::XServiceInfo
168 //-----------------------------------------------------------------
170 APPHELPER_XSERVICEINFO_IMPL(BarChart,CHART2_VIEW_BARCHART_SERVICE_IMPLEMENTATION_NAME)
172 uno::Sequence< rtl::OUString > BarChart
173 ::getSupportedServiceNames_Static()
175 uno::Sequence< rtl::OUString > aSNS( 1 );
176 aSNS.getArray()[ 0 ] = CHART2_VIEW_BARCHART_SERVICE_NAME;
177 return aSNS;
181 //-----------------------------------------------------------------
182 // chart2::XPlotter
183 //-----------------------------------------------------------------
185 ::rtl::OUString SAL_CALL BarChart
186 ::getCoordinateSystemTypeID()
187 throw (uno::RuntimeException)
189 return CHART2_COOSYSTEM_CARTESIAN_SERVICE_NAME;
193 awt::Point BarChart::getLabelScreenPositionAndAlignment(
194 LabelAlignment& rAlignment, sal_Int32 nLabelPlacement
195 , double fScaledX, double fScaledLowerYValue, double fScaledUpperYValue, double fScaledZ
196 , double fScaledLowerBarDepth, double fScaledUpperBarDepth, double fBaseValue
197 , BarPositionHelper* pPosHelper
198 ) const
200 double fX = fScaledX;
201 double fY = fScaledUpperYValue;
202 double fZ = fScaledZ;
203 bool bReverse = !pPosHelper->isMathematicalOrientationY();
204 bool bNormalOutside = (!bReverse == !!(fBaseValue < fScaledUpperYValue));
205 double fDepth = fScaledUpperBarDepth;
207 switch(nLabelPlacement)
209 case ::com::sun::star::chart::DataLabelPlacement::TOP:
211 if( !pPosHelper->isSwapXAndY() )
213 fY = bReverse ? fScaledLowerYValue : fScaledUpperYValue;
214 rAlignment = LABEL_ALIGN_TOP;
215 if(3==m_nDimension)
216 fDepth = bReverse ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
218 else
220 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
221 rAlignment = LABEL_ALIGN_CENTER;
222 DBG_ERROR( "top label placement is not really supported by horizontal bar charts" );
225 break;
226 case ::com::sun::star::chart::DataLabelPlacement::BOTTOM:
228 if(!pPosHelper->isSwapXAndY())
230 fY = bReverse ? fScaledUpperYValue : fScaledLowerYValue;
231 rAlignment = LABEL_ALIGN_BOTTOM;
232 if(3==m_nDimension)
233 fDepth = bReverse ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
235 else
237 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
238 rAlignment = LABEL_ALIGN_CENTER;
239 DBG_ERROR( "bottom label placement is not supported by horizontal bar charts" );
242 break;
243 case ::com::sun::star::chart::DataLabelPlacement::LEFT:
245 if( pPosHelper->isSwapXAndY() )
247 fY = bReverse ? fScaledUpperYValue : fScaledLowerYValue;
248 rAlignment = LABEL_ALIGN_LEFT;
249 if(3==m_nDimension)
250 fDepth = bReverse ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
252 else
254 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
255 rAlignment = LABEL_ALIGN_CENTER;
256 DBG_ERROR( "left label placement is not supported by column charts" );
259 break;
260 case ::com::sun::star::chart::DataLabelPlacement::RIGHT:
262 if( pPosHelper->isSwapXAndY() )
264 fY = bReverse ? fScaledLowerYValue : fScaledUpperYValue;
265 rAlignment = LABEL_ALIGN_RIGHT;
266 if(3==m_nDimension)
267 fDepth = bReverse ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
269 else
271 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
272 rAlignment = LABEL_ALIGN_CENTER;
273 DBG_ERROR( "right label placement is not supported by column charts" );
276 break;
277 case ::com::sun::star::chart::DataLabelPlacement::OUTSIDE:
279 fY = (fBaseValue < fScaledUpperYValue) ? fScaledUpperYValue : fScaledLowerYValue;
280 if( pPosHelper->isSwapXAndY() )
281 rAlignment = bNormalOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT;
282 else
283 rAlignment = bNormalOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM;
284 if(3==m_nDimension)
285 fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
287 break;
288 case ::com::sun::star::chart::DataLabelPlacement::INSIDE:
290 fY = (fBaseValue < fScaledUpperYValue) ? fScaledUpperYValue : fScaledLowerYValue;
291 if( pPosHelper->isSwapXAndY() )
292 rAlignment = bNormalOutside ? LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT;
293 else
294 rAlignment = bNormalOutside ? LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP;
295 if(3==m_nDimension)
296 fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
298 break;
299 case ::com::sun::star::chart::DataLabelPlacement::NEAR_ORIGIN:
301 fY = (fBaseValue < fScaledUpperYValue) ? fScaledLowerYValue : fScaledUpperYValue;
302 if( pPosHelper->isSwapXAndY() )
303 rAlignment = bNormalOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT;
304 else
305 rAlignment = bNormalOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM;
306 if(3==m_nDimension)
307 fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
309 break;
310 case ::com::sun::star::chart::DataLabelPlacement::CENTER:
311 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
312 rAlignment = LABEL_ALIGN_CENTER;
313 if(3==m_nDimension)
314 fDepth = fabs(fScaledUpperBarDepth-fScaledLowerBarDepth)/2.0;
315 break;
316 default:
317 DBG_ERROR("this label alignment is not implemented yet");
319 break;
321 if(3==m_nDimension)
322 fZ -= fDepth/2.0;
324 drawing::Position3D aScenePosition3D( pPosHelper->
325 transformScaledLogicToScene( fX, fY, fZ, true ) );
326 return LabelPositionHelper(pPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory)
327 .transformSceneToScreenPosition( aScenePosition3D );
330 uno::Reference< drawing::XShape > BarChart::createDataPoint3D_Bar(
331 const uno::Reference< drawing::XShapes >& xTarget
332 , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize
333 , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree
334 , const uno::Reference< beans::XPropertySet >& xObjectProperties
335 , sal_Int32 nGeometry3D )
337 bool bRoundedEdges = true;
340 if( xObjectProperties.is() )
342 sal_Int16 nPercentDiagonal = 0;
343 xObjectProperties->getPropertyValue( C2U( "PercentDiagonal" ) ) >>= nPercentDiagonal;
344 if( nPercentDiagonal < 5 )
345 bRoundedEdges = false;
348 catch( uno::Exception& e )
350 ASSERT_EXCEPTION( e );
353 uno::Reference< drawing::XShape > xShape(NULL);
354 switch( nGeometry3D )
356 case DataPointGeometry3D::CYLINDER:
357 xShape = m_pShapeFactory->createCylinder( xTarget, rPosition, rSize, nRotateZAngleHundredthDegree );
358 break;
359 case DataPointGeometry3D::CONE:
360 xShape = m_pShapeFactory->createCone( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree );
361 break;
362 case DataPointGeometry3D::PYRAMID:
363 xShape = m_pShapeFactory->createPyramid( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree );
364 break;
365 case DataPointGeometry3D::CUBOID:
366 default:
367 xShape = m_pShapeFactory->createCube( xTarget, rPosition, rSize
368 , nRotateZAngleHundredthDegree, xObjectProperties
369 , PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), bRoundedEdges );
370 return xShape;
372 this->setMappedProperties( xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
373 return xShape;
376 namespace
378 bool lcl_hasGeometry3DVariableWidth( sal_Int32 nGeometry3D )
380 bool bRet = false;
381 switch( nGeometry3D )
383 case DataPointGeometry3D::PYRAMID:
384 case DataPointGeometry3D::CONE:
385 bRet = true;
386 break;
387 case DataPointGeometry3D::CUBOID:
388 case DataPointGeometry3D::CYLINDER:
389 default:
390 bRet = false;
391 break;
393 return bRet;
395 }// end anonymous namespace
397 void BarChart::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
399 if( !pSeries )
400 return;
401 if(m_nDimension==2)
403 //2ND_AXIS_IN_BARS put series on second scales to different z slot as temporary workaround
404 //this needs to be redesigned if 3d bars are also able to display secondary axes
406 sal_Int32 nAxisIndex = pSeries->getAttachedAxisIndex();
407 zSlot = nAxisIndex;
409 if( !pSeries->getGroupBarsPerAxis() )
410 zSlot = 0;
411 if(zSlot>=static_cast<sal_Int32>(m_aZSlots.size()))
412 m_aZSlots.resize(zSlot+1);
414 VSeriesPlotter::addSeries( pSeries, zSlot, xSlot, ySlot );
417 //better performance for big data
418 struct FormerBarPoint
420 FormerBarPoint( double fX, double fUpperY, double fLowerY, double fZ )
421 : m_fX(fX), m_fUpperY(fUpperY), m_fLowerY(fLowerY), m_fZ(fZ)
423 FormerBarPoint()
425 ::rtl::math::setNan( &m_fX );
426 ::rtl::math::setNan( &m_fUpperY );
427 ::rtl::math::setNan( &m_fLowerY );
428 ::rtl::math::setNan( &m_fZ );
431 double m_fX;
432 double m_fUpperY;
433 double m_fLowerY;
434 double m_fZ;
437 void BarChart::adaptOverlapAndGapwidthForGroupBarsPerAxis()
439 //adapt m_aOverlapSequence and m_aGapwidthSequence for the groupBarsPerAxis feature
440 //thus the different series use the same settings
442 VDataSeries* pFirstSeries = getFirstSeries();
443 if(pFirstSeries && !pFirstSeries->getGroupBarsPerAxis() )
445 sal_Int32 nAxisIndex = pFirstSeries->getAttachedAxisIndex();
446 sal_Int32 nN = 0;
447 sal_Int32 nUseThisIndex = nAxisIndex;
448 if( nUseThisIndex < 0 || nUseThisIndex >= m_aOverlapSequence.getLength() )
449 nUseThisIndex = 0;
450 for( nN = 0; nN < m_aOverlapSequence.getLength(); nN++ )
452 if(nN!=nUseThisIndex)
453 m_aOverlapSequence[nN] = m_aOverlapSequence[nUseThisIndex];
456 nUseThisIndex = nAxisIndex;
457 if( nUseThisIndex < 0 || nUseThisIndex >= m_aGapwidthSequence.getLength() )
458 nUseThisIndex = 0;
459 for( nN = 0; nN < m_aGapwidthSequence.getLength(); nN++ )
461 if(nN!=nUseThisIndex)
462 m_aGapwidthSequence[nN] = m_aGapwidthSequence[nUseThisIndex];
467 void BarChart::createShapes()
469 uno::Reference< beans::XPropertySet > xPropSet(m_xChartTypeModel, uno::UNO_QUERY);
470 sal_Bool bPercent = sal_False;
471 if (xPropSet.is())
475 xPropSet->getPropertyValue(C2U("Percent")) >>= bPercent;
477 catch (const beans::UnknownPropertyException&)
482 if( m_aZSlots.begin() == m_aZSlots.end() ) //no series
483 return;
485 DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"BarChart is not proper initialized");
486 if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()))
487 return;
489 //the text labels should be always on top of the other series shapes
490 //therefore create an own group for the texts to move them to front
491 //(because the text group is created after the series group the texts are displayed on top)
493 //the regression curves should always be on top of the bars but beneath the text labels
494 //to achieve this the regression curve target is created after the series target and before the text target
496 uno::Reference< drawing::XShapes > xSeriesTarget(
497 createGroupShape( m_xLogicTarget,rtl::OUString() ));
498 uno::Reference< drawing::XShapes > xRegressionCurveTarget(
499 createGroupShape( m_xLogicTarget,rtl::OUString() ));
500 uno::Reference< drawing::XShapes > xTextTarget(
501 m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() ));
504 //---------------------------------------------
505 uno::Reference< drawing::XShapes > xRegressionCurveEquationTarget(
506 m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() ));
507 //check necessary here that different Y axis can not be stacked in the same group? ... hm?
509 double fLogicZ = 0.0;//as defined
511 bool bDrawConnectionLines = false;
512 bool bDrawConnectionLinesInited = false;
513 bool bOnlyConnectionLinesForThisPoint = false;
515 adaptOverlapAndGapwidthForGroupBarsPerAxis();
517 //better performance for big data
518 std::map< VDataSeries*, FormerBarPoint > aSeriesFormerPointMap;
519 m_bPointsWereSkipped = false;
520 sal_Int32 nSkippedPoints = 0;
521 sal_Int32 nCreatedPoints = 0;
524 //(@todo maybe different iteration for breaks in axis ?)
525 sal_Int32 nStartCategoryIndex = m_pMainPosHelper->getStartCategoryIndex(); // inclusive
526 sal_Int32 nEndCategoryIndex = m_pMainPosHelper->getEndCategoryIndex(); //inclusive
527 //=============================================================================
528 //iterate through all shown categories
529 for( sal_Int32 nCatIndex = nStartCategoryIndex; nCatIndex < nEndCategoryIndex; nCatIndex++ )
531 ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
532 const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
534 //sum up the values for all series in a complete z zlot per attached axis
535 ::std::map< sal_Int32, double > aLogicYSumMap;
536 for( ; aZSlotIter != aZSlotEnd; aZSlotIter++ )
538 ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
539 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
541 for( aXSlotIter = aZSlotIter->begin(); aXSlotIter != aXSlotEnd; aXSlotIter++ )
543 sal_Int32 nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries();
544 if( aLogicYSumMap.find(nAttachedAxisIndex)==aLogicYSumMap.end() )
545 aLogicYSumMap[nAttachedAxisIndex]=0.0;
547 double fMinimumY = 0.0, fMaximumY = 0.0;
548 aXSlotIter->calculateYMinAndMaxForCategory( nCatIndex
549 , isSeperateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex );
551 if( !::rtl::math::isNan( fMaximumY ) && fMaximumY > 0)
552 aLogicYSumMap[nAttachedAxisIndex] += fMaximumY;
553 if( !::rtl::math::isNan( fMinimumY ) && fMinimumY < 0)
554 aLogicYSumMap[nAttachedAxisIndex] += fabs(fMinimumY);
558 //=============================================================================
559 aZSlotIter = m_aZSlots.begin();
560 for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; aZSlotIter++, nZ++ )
562 ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
563 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
565 //=============================================================================
566 //iterate through all x slots in this category
567 double fSlotX=0;
568 for( aXSlotIter = aZSlotIter->begin(); aXSlotIter != aXSlotEnd; aXSlotIter++, fSlotX+=1.0 )
570 sal_Int32 nAttachedAxisIndex = 0;
571 BarPositionHelper* pPosHelper = m_pMainPosHelper;
572 if( aXSlotIter != aXSlotEnd )
574 nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries();
575 //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
576 pPosHelper = dynamic_cast<BarPositionHelper*>(&( this->getPlottingPositionHelper( nAttachedAxisIndex ) ) );
577 if(!pPosHelper)
578 pPosHelper = m_pMainPosHelper;
580 PlotterBase::m_pPosHelper = pPosHelper;
582 //update/create information for current group
583 pPosHelper->updateSeriesCount( aZSlotIter->size() );
584 double fLogicBaseWidth = pPosHelper->getSlotWidth();
586 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
588 // get distance from base value to maximum and minimum
590 double fMinimumY = 0.0, fMaximumY = 0.0;
591 aXSlotIter->calculateYMinAndMaxForCategory( nCatIndex
592 , isSeperateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex );
594 double fLogicPositiveYSum = 0.0;
595 if( !::rtl::math::isNan( fMaximumY ) )
596 fLogicPositiveYSum = fMaximumY;
598 double fLogicNegativeYSum = 0.0;
599 if( !::rtl::math::isNan( fMinimumY ) )
600 fLogicNegativeYSum = fMinimumY;
602 if( pPosHelper->isPercentY() )
604 /* #i70395# fLogicPositiveYSum contains sum of all positive
605 values, if any, otherwise the highest negative value.
606 fLogicNegativeYSum contains sum of all negative values,
607 if any, otherwise the lowest positive value.
608 Afterwards, fLogicPositiveYSum will contain the maximum
609 (positive) value that is related to 100%. */
611 // do nothing if there are positive values only
612 if( fLogicNegativeYSum < 0.0 )
614 // fLogicPositiveYSum<0 => negative values only, use absolute of negative sum
615 if( fLogicPositiveYSum < 0.0 )
616 fLogicPositiveYSum = -fLogicNegativeYSum;
617 // otherwise there are positive and negative values, calculate total distance
618 else
619 fLogicPositiveYSum -= fLogicNegativeYSum;
621 fLogicNegativeYSum = 0.0;
624 double fBaseValue = 0.0;
625 if( !pPosHelper->isPercentY() && pSeriesList->size()<=1 )
626 fBaseValue = pPosHelper->getBaseValueY();
627 double fPositiveLogicYForNextSeries = fBaseValue;
628 double fNegativeLogicYForNextSeries = fBaseValue;
630 ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
631 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
632 aSeriesIter = pSeriesList->begin();
633 //=============================================================================
634 //iterate through all series in this x slot
635 for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
637 VDataSeries* pSeries( *aSeriesIter );
638 if(!pSeries)
639 continue;
641 bOnlyConnectionLinesForThisPoint = false;
643 if(nCatIndex==nStartCategoryIndex)//do not create a regression line for each point
644 createRegressionCurvesShapes( **aSeriesIter, xRegressionCurveTarget, xRegressionCurveEquationTarget,
645 m_pPosHelper->maySkipPointsInRegressionCalculation());
647 if( !bDrawConnectionLinesInited )
649 bDrawConnectionLines = pSeries->getConnectBars();
650 if( m_nDimension==3 )
651 bDrawConnectionLines = false;
652 if( bDrawConnectionLines && pSeriesList->size()==1 )
654 //detect wether we have a stacked chart or not:
655 StackingDirection eDirection = pSeries->getStackingDirection();
656 if( eDirection != StackingDirection_Y_STACKING )
657 bDrawConnectionLines = false;
659 bDrawConnectionLinesInited = true;
662 //------------
664 uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes(
665 getSeriesGroupShape(*aSeriesIter, xSeriesTarget) );
667 //collect data point information (logic coordinates, style ):
668 double fLogicX = pPosHelper->getSlotPos( (*aSeriesIter)->getXValue( nCatIndex ), fSlotX );
669 double fLogicBarHeight = (*aSeriesIter)->getYValue( nCatIndex );
670 if( ::rtl::math::isNan( fLogicBarHeight )) //no value at this category
671 continue;
673 double fLogicValueForLabeDisplay = fLogicBarHeight;
674 fLogicBarHeight-=fBaseValue;
676 if( pPosHelper->isPercentY() )
678 if(fLogicPositiveYSum!=0.0)
679 fLogicBarHeight = fabs( fLogicBarHeight )/fLogicPositiveYSum;
680 else
681 fLogicBarHeight = 0.0;
684 //sort negative and positive values, to display them on different sides of the x axis
685 bool bPositive = fLogicBarHeight >= 0.0;
686 double fLowerYValue = bPositive ? fPositiveLogicYForNextSeries : fNegativeLogicYForNextSeries;
687 double fUpperYValue = fLowerYValue+fLogicBarHeight;
688 if( bPositive )
689 fPositiveLogicYForNextSeries += fLogicBarHeight;
690 else
691 fNegativeLogicYForNextSeries += fLogicBarHeight;
693 if(m_nDimension==3)
694 fLogicZ = nZ;
696 drawing::Position3D aUnscaledLogicPosition( fLogicX, fUpperYValue, fLogicZ );
698 //@todo ... start an iteration over the different breaks of the axis
699 //each subsystem may add an additional shape to form the whole point
700 //create a group shape for this point and add to the series shape:
701 // uno::Reference< drawing::XShapes > xPointGroupShape_Shapes( createGroupShape(xSeriesGroupShape_Shapes) );
702 // uno::Reference<drawing::XShape> xPointGroupShape_Shape =
703 // uno::Reference<drawing::XShape>( xPointGroupShape_Shapes, uno::UNO_QUERY );
704 //as long as we do not iterate we do not need to create an additional group for each point
705 uno::Reference< drawing::XShapes > xPointGroupShape_Shapes = xSeriesGroupShape_Shapes;
706 uno::Reference< beans::XPropertySet > xDataPointProperties( (*aSeriesIter)->getPropertiesOfPoint( nCatIndex ) );
707 sal_Int32 nGeometry3D = DataPointGeometry3D::CUBOID;
708 if(m_nDimension==3) try
710 xDataPointProperties->getPropertyValue( C2U( "Geometry3D" )) >>= nGeometry3D;
712 catch( uno::Exception& e )
714 ASSERT_EXCEPTION( e );
717 //@todo iterate through all subsystems to create partial points
719 //@todo select a suiteable PositionHelper for this subsystem
720 BarPositionHelper* pSubPosHelper = pPosHelper;
722 double fUnclippedUpperYValue = fUpperYValue;
724 //apply clipping to Y
725 if( !pPosHelper->clipYRange(fLowerYValue,fUpperYValue) )
727 if( bDrawConnectionLines )
728 bOnlyConnectionLinesForThisPoint = true;
729 else
730 continue;
732 //@todo clipping of X and Z is not fully integrated so far, as there is a need to create different objects
734 //apply scaling to Y before calculating width (necessary to maintain gradient in clipped objects)
735 pSubPosHelper->doLogicScaling(NULL,&fLowerYValue,NULL);
736 pSubPosHelper->doLogicScaling(NULL,&fUpperYValue,NULL);
737 //scaling of X and Z is not provided as the created objects should be symmetric in that dimensions
739 pSubPosHelper->doLogicScaling(NULL,&fUnclippedUpperYValue,NULL);
741 //calculate resulting width
742 double fCompleteHeight = bPositive ? fLogicPositiveYSum : fLogicNegativeYSum;
743 if( pPosHelper->isPercentY() )
744 fCompleteHeight = 1.0;
745 double fLogicBarWidth = fLogicBaseWidth;
746 double fTopHeight=approxSub(fCompleteHeight,fUpperYValue);
747 if(!bPositive)
748 fTopHeight=approxSub(fCompleteHeight,fLowerYValue);
749 double fLogicYStart = bPositive ? fLowerYValue : fUpperYValue;
750 double fMiddleHeight = fUpperYValue-fLowerYValue;
751 if(!bPositive)
752 fMiddleHeight*=-1.0;
753 if(m_nDimension==3)
755 if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 )
757 double fHeight = fCompleteHeight-fLowerYValue;
758 if(!bPositive)
759 fHeight = fCompleteHeight-fUpperYValue;
760 fLogicBarWidth = fLogicBaseWidth*fHeight/(fCompleteHeight);
761 if(fLogicBarWidth<=0.0)
762 fLogicBarWidth=fLogicBaseWidth;
765 double fLogicBarDepth = fLogicBarWidth;
767 //better performance for big data
768 FormerBarPoint aFormerPoint( aSeriesFormerPointMap[pSeries] );
769 pPosHelper->setCoordinateSystemResolution( m_aCoordinateSystemResolution );
770 if( !pSeries->isAttributedDataPoint(nCatIndex)
772 pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fUpperY, aFormerPoint.m_fZ
773 , fLogicX, fUpperYValue, fLogicZ )
775 pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fLowerY, aFormerPoint.m_fZ
776 , fLogicX, fLowerYValue, fLogicZ )
779 nSkippedPoints++;
780 m_bPointsWereSkipped = true;
781 continue;
783 aSeriesFormerPointMap[pSeries] = FormerBarPoint(fLogicX,fUpperYValue,fLowerYValue,fLogicZ);
787 if( bDrawConnectionLines )
789 //store point information for connection lines
791 drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ );
792 drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ );
794 if( isValidPosition(aLeftUpperPoint) )
795 AddPointToPoly( (*aSeriesIter)->m_aPolyPolygonShape3D, aLeftUpperPoint );
796 if( isValidPosition(aRightUpperPoint) )
797 AddPointToPoly( (*aSeriesIter)->m_aPolyPolygonShape3D, aRightUpperPoint );
800 if( bOnlyConnectionLinesForThisPoint )
801 continue;
803 //maybe additional possibility for performance improvement
804 //bool bCreateLineInsteadOfComplexGeometryDueToMissingSpace = false;
805 //pPosHelper->isSameForGivenResolution( fLogicX-fLogicBarWidth/2.0, fLowerYValue, fLogicZ
806 // , fLogicX+fLogicBarWidth/2.0, fLowerYValue, fLogicZ );
808 nCreatedPoints++;
809 //create partial point
810 if( !approxEqual(fLowerYValue,fUpperYValue) )
812 uno::Reference< drawing::XShape > xShape;
813 if( m_nDimension==3 )
815 drawing::Position3D aLogicBottom (fLogicX,fLogicYStart,fLogicZ);
816 drawing::Position3D aLogicLeftBottomFront (fLogicX+fLogicBarWidth/2.0,fLogicYStart,fLogicZ-fLogicBarDepth/2.0);
817 drawing::Position3D aLogicRightDeepTop (fLogicX-fLogicBarWidth/2.0,fLogicYStart+fMiddleHeight,fLogicZ+fLogicBarDepth/2.0);
818 drawing::Position3D aLogicTopTop (fLogicX,fLogicYStart+fMiddleHeight+fTopHeight,fLogicZ);
820 uno::Reference< XTransformation > xTransformation = pSubPosHelper->getTransformationScaledLogicToScene();
822 //transformation 3) -> 4)
823 drawing::Position3D aTransformedBottom ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicBottom) ) ) );
824 drawing::Position3D aTransformedLeftBottomFront ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicLeftBottomFront) ) ) );
825 drawing::Position3D aTransformedRightDeepTop ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicRightDeepTop) ) ) );
826 drawing::Position3D aTransformedTopTop ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicTopTop) ) ) );
828 drawing::Direction3D aSize = aTransformedRightDeepTop - aTransformedLeftBottomFront;
829 drawing::Direction3D aTopSize( aTransformedTopTop - aTransformedRightDeepTop );
830 fTopHeight = aTopSize.DirectionY;
832 sal_Int32 nRotateZAngleHundredthDegree = 0;
833 if( pPosHelper->isSwapXAndY() )
835 fTopHeight = aTopSize.DirectionX;
836 nRotateZAngleHundredthDegree = 90*100;
837 aSize = drawing::Direction3D(aSize.DirectionY,aSize.DirectionX,aSize.DirectionZ);
840 if( aSize.DirectionX < 0 )
841 aSize.DirectionX *= -1.0;
842 if( aSize.DirectionZ < 0 )
843 aSize.DirectionZ *= -1.0;
844 if( fTopHeight < 0 )
845 fTopHeight *= -1.0;
847 xShape = createDataPoint3D_Bar(
848 xPointGroupShape_Shapes, aTransformedBottom, aSize, fTopHeight, nRotateZAngleHundredthDegree
849 , xDataPointProperties, nGeometry3D );
851 else //m_nDimension!=3
853 //if( bCreateLineInsteadOfComplexGeometryDueToMissingSpace )
855 // drawing::PolyPolygonShape3D aPoly;
856 // drawing::Position3D aUpperPoint( fLogicX,fUpperYValue,fLogicZ );
857 // drawing::Position3D aLowerPoint( fLogicX,fLowerYValue,fLogicZ );
859 // AddPointToPoly( aPoly, aUpperPoint );
860 // AddPointToPoly( aPoly, aLowerPoint );
862 // VLineProperties aLineProperties;
863 // aLineProperties.initFromPropertySet( xDataPointProperties, true /*bUseSeriesPropertyNames*/ );
864 // if( !aLineProperties.isLineVisible() )
865 // {
866 // //todo
867 // //aLineProperties.Color =
868 // }
870 // xShape = m_pShapeFactory->createLine2D( xPointGroupShape_Shapes
871 // , PolyToPointSequence(aPoly), &aLineProperties );
874 drawing::PolyPolygonShape3D aPoly;
875 drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUpperYValue,fLogicZ );
876 drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUpperYValue,fLogicZ );
878 AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
879 AddPointToPoly( aPoly, drawing::Position3D( fLogicX+fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
880 AddPointToPoly( aPoly, aRightUpperPoint );
881 AddPointToPoly( aPoly, aLeftUpperPoint );
882 AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
883 pPosHelper->transformScaledLogicToScene( aPoly );
884 xShape = m_pShapeFactory->createArea2D( xPointGroupShape_Shapes, aPoly );
885 this->setMappedProperties( xShape, xDataPointProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
887 //set name/classified ObjectID (CID)
888 ShapeFactory::setShapeName(xShape
889 , ObjectIdentifier::createPointCID(
890 (*aSeriesIter)->getPointCID_Stub(),nCatIndex) );
893 //create error bar
894 createErrorBar_Y( aUnscaledLogicPosition, **aSeriesIter, nCatIndex, m_xLogicTarget );
896 //------------
897 //create data point label
898 if( (**aSeriesIter).getDataPointLabelIfLabel(nCatIndex) )
900 double fLogicSum = aLogicYSumMap[nAttachedAxisIndex];
902 LabelAlignment eAlignment(LABEL_ALIGN_CENTER);
903 sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nCatIndex, m_xChartTypeModel, m_nDimension, pPosHelper->isSwapXAndY() );
905 double fLowerBarDepth = fLogicBarDepth;
906 double fUpperBarDepth = fLogicBarDepth;
908 double fOuterBarDepth = fLogicBarDepth;
909 if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 )
911 fOuterBarDepth = fLogicBarDepth * (fTopHeight)/(fabs(fCompleteHeight));
912 fLowerBarDepth = (fBaseValue < fUpperYValue) ? fabs(fLogicBarDepth) : fabs(fOuterBarDepth);
913 fUpperBarDepth = (fBaseValue < fUpperYValue) ? fabs(fOuterBarDepth) : fabs(fLogicBarDepth);
917 awt::Point aScreenPosition2D( this->getLabelScreenPositionAndAlignment(
918 eAlignment, nLabelPlacement
919 , fLogicX, fLowerYValue, fUpperYValue, fLogicZ
920 , fLowerBarDepth, fUpperBarDepth, fBaseValue, pPosHelper ));
921 sal_Int32 nOffset = 0;
922 if(LABEL_ALIGN_CENTER!=eAlignment)
924 nOffset = 100;//add some spacing //@todo maybe get more intelligent values
925 if( m_nDimension == 3 )
926 nOffset = 260;
928 this->createDataLabel( xTextTarget, **aSeriesIter, nCatIndex
929 , fLogicValueForLabeDisplay, fLogicSum, aScreenPosition2D, eAlignment, nOffset );
932 }//end iteration through partial points
934 //remove PointGroupShape if empty
935 // if(!xPointGroupShape_Shapes->getCount())
936 // xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shape);
937 }//next series in x slot (next y slot)
938 }//next x slot
939 }//next z slot
940 }//next category
941 //=============================================================================
942 //=============================================================================
943 //=============================================================================
944 if( bDrawConnectionLines )
946 ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
947 const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
948 //=============================================================================
949 for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; aZSlotIter++, nZ++ )
951 ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
952 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
954 BarPositionHelper* pPosHelper = m_pMainPosHelper;
955 if( aXSlotIter != aXSlotEnd )
957 sal_Int32 nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries();
958 //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
959 pPosHelper = dynamic_cast<BarPositionHelper*>(&( this->getPlottingPositionHelper( nAttachedAxisIndex ) ) );
960 if(!pPosHelper)
961 pPosHelper = m_pMainPosHelper;
963 PlotterBase::m_pPosHelper = pPosHelper;
965 //=============================================================================
966 //iterate through all x slots in this category
967 for( double fSlotX=0; aXSlotIter != aXSlotEnd; aXSlotIter++, fSlotX+=1.0 )
969 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
971 ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
972 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
973 aSeriesIter = pSeriesList->begin();
974 //=============================================================================
975 //iterate through all series in this x slot
976 for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
978 VDataSeries* pSeries( *aSeriesIter );
979 if(!pSeries)
980 continue;
981 drawing::PolyPolygonShape3D* pSeriesPoly = &pSeries->m_aPolyPolygonShape3D;
982 if(!ShapeFactory::hasPolygonAnyLines(*pSeriesPoly))
983 continue;
985 drawing::PolyPolygonShape3D aPoly;
986 Clipping::clipPolygonAtRectangle( *pSeriesPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
988 if(!ShapeFactory::hasPolygonAnyLines(aPoly))
989 continue;
991 //transformation 3) -> 4)
992 pPosHelper->transformScaledLogicToScene( aPoly );
994 uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes(
995 getSeriesGroupShape(*aSeriesIter, xSeriesTarget) );
996 uno::Reference< drawing::XShape > xShape( m_pShapeFactory->createLine2D(
997 xSeriesGroupShape_Shapes, PolyToPointSequence( aPoly ) ) );
998 this->setMappedProperties( xShape, pSeries->getPropertiesOfSeries()
999 , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
1005 /* @todo remove series shapes if empty
1006 //remove and delete point-group-shape if empty
1007 if(!xSeriesGroupShape_Shapes->getCount())
1009 (*aSeriesIter)->m_xShape.set(NULL);
1010 m_xLogicTarget->remove(xSeriesGroupShape_Shape);
1014 //remove and delete series-group-shape if empty
1016 //... todo
1018 OSL_TRACE( "\nPPPPPPPPP<<<<<<<<<<<< bar chart :: createShapes():: skipped points: %d created points: %d", nSkippedPoints, nCreatedPoints );
1021 //.............................................................................
1022 } //namespace chart
1023 //.............................................................................