1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: BarChart.cxx,v $
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"
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 //.............................................................................
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
;
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
);
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 );
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
;
120 return VSeriesPlotter::getPreferredDiagramAspectRatio();
121 if(aRet
.DirectionZ
<0.05)
122 aRet
.DirectionZ
=0.05;
123 if(aRet
.DirectionZ
>10)
126 if( m_pMainPosHelper
&& m_pMainPosHelper
->isSwapXAndY() )
128 double fTemp
= aRet
.DirectionX
;
129 aRet
.DirectionX
= aRet
.DirectionY
;
130 aRet
.DirectionY
= fTemp
;
134 aRet
= drawing::Direction3D(-1,-1,-1);
138 bool BarChart::keepAspectRatio() const
140 if( m_nDimension
== 3 )
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;
181 //-----------------------------------------------------------------
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
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
;
216 fDepth
= bReverse
? fabs(fScaledLowerBarDepth
) : fabs(fScaledUpperBarDepth
);
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" );
226 case ::com::sun::star::chart::DataLabelPlacement::BOTTOM
:
228 if(!pPosHelper
->isSwapXAndY())
230 fY
= bReverse
? fScaledUpperYValue
: fScaledLowerYValue
;
231 rAlignment
= LABEL_ALIGN_BOTTOM
;
233 fDepth
= bReverse
? fabs(fScaledUpperBarDepth
) : fabs(fScaledLowerBarDepth
);
237 fY
-= (fScaledUpperYValue
-fScaledLowerYValue
)/2.0;
238 rAlignment
= LABEL_ALIGN_CENTER
;
239 DBG_ERROR( "bottom label placement is not supported by horizontal bar charts" );
243 case ::com::sun::star::chart::DataLabelPlacement::LEFT
:
245 if( pPosHelper
->isSwapXAndY() )
247 fY
= bReverse
? fScaledUpperYValue
: fScaledLowerYValue
;
248 rAlignment
= LABEL_ALIGN_LEFT
;
250 fDepth
= bReverse
? fabs(fScaledUpperBarDepth
) : fabs(fScaledLowerBarDepth
);
254 fY
-= (fScaledUpperYValue
-fScaledLowerYValue
)/2.0;
255 rAlignment
= LABEL_ALIGN_CENTER
;
256 DBG_ERROR( "left label placement is not supported by column charts" );
260 case ::com::sun::star::chart::DataLabelPlacement::RIGHT
:
262 if( pPosHelper
->isSwapXAndY() )
264 fY
= bReverse
? fScaledLowerYValue
: fScaledUpperYValue
;
265 rAlignment
= LABEL_ALIGN_RIGHT
;
267 fDepth
= bReverse
? fabs(fScaledLowerBarDepth
) : fabs(fScaledUpperBarDepth
);
271 fY
-= (fScaledUpperYValue
-fScaledLowerYValue
)/2.0;
272 rAlignment
= LABEL_ALIGN_CENTER
;
273 DBG_ERROR( "right label placement is not supported by column charts" );
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
;
283 rAlignment
= bNormalOutside
? LABEL_ALIGN_TOP
: LABEL_ALIGN_BOTTOM
;
285 fDepth
= (fBaseValue
< fScaledUpperYValue
) ? fabs(fScaledUpperBarDepth
) : fabs(fScaledLowerBarDepth
);
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
;
294 rAlignment
= bNormalOutside
? LABEL_ALIGN_BOTTOM
: LABEL_ALIGN_TOP
;
296 fDepth
= (fBaseValue
< fScaledUpperYValue
) ? fabs(fScaledUpperBarDepth
) : fabs(fScaledLowerBarDepth
);
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
;
305 rAlignment
= bNormalOutside
? LABEL_ALIGN_TOP
: LABEL_ALIGN_BOTTOM
;
307 fDepth
= (fBaseValue
< fScaledUpperYValue
) ? fabs(fScaledLowerBarDepth
) : fabs(fScaledUpperBarDepth
);
310 case ::com::sun::star::chart::DataLabelPlacement::CENTER
:
311 fY
-= (fScaledUpperYValue
-fScaledLowerYValue
)/2.0;
312 rAlignment
= LABEL_ALIGN_CENTER
;
314 fDepth
= fabs(fScaledUpperBarDepth
-fScaledLowerBarDepth
)/2.0;
317 DBG_ERROR("this label alignment is not implemented yet");
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
);
359 case DataPointGeometry3D::CONE
:
360 xShape
= m_pShapeFactory
->createCone( xTarget
, rPosition
, rSize
, fTopHeight
, nRotateZAngleHundredthDegree
);
362 case DataPointGeometry3D::PYRAMID
:
363 xShape
= m_pShapeFactory
->createPyramid( xTarget
, rPosition
, rSize
, fTopHeight
, nRotateZAngleHundredthDegree
);
365 case DataPointGeometry3D::CUBOID
:
367 xShape
= m_pShapeFactory
->createCube( xTarget
, rPosition
, rSize
368 , nRotateZAngleHundredthDegree
, xObjectProperties
369 , PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), bRoundedEdges
);
372 this->setMappedProperties( xShape
, xObjectProperties
, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
378 bool lcl_hasGeometry3DVariableWidth( sal_Int32 nGeometry3D
)
381 switch( nGeometry3D
)
383 case DataPointGeometry3D::PYRAMID
:
384 case DataPointGeometry3D::CONE
:
387 case DataPointGeometry3D::CUBOID
:
388 case DataPointGeometry3D::CYLINDER
:
395 }// end anonymous namespace
397 void BarChart::addSeries( VDataSeries
* pSeries
, sal_Int32 zSlot
, sal_Int32 xSlot
, sal_Int32 ySlot
)
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();
409 if( !pSeries
->getGroupBarsPerAxis() )
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
)
425 ::rtl::math::setNan( &m_fX
);
426 ::rtl::math::setNan( &m_fUpperY
);
427 ::rtl::math::setNan( &m_fLowerY
);
428 ::rtl::math::setNan( &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();
447 sal_Int32 nUseThisIndex
= nAxisIndex
;
448 if( nUseThisIndex
< 0 || nUseThisIndex
>= m_aOverlapSequence
.getLength() )
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() )
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
;
475 xPropSet
->getPropertyValue(C2U("Percent")) >>= bPercent
;
477 catch (const beans::UnknownPropertyException
&)
482 if( m_aZSlots
.begin() == m_aZSlots
.end() ) //no series
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()))
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
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
) ) );
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
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
);
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;
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
673 double fLogicValueForLabeDisplay
= fLogicBarHeight
;
674 fLogicBarHeight
-=fBaseValue
;
676 if( pPosHelper
->isPercentY() )
678 if(fLogicPositiveYSum
!=0.0)
679 fLogicBarHeight
= fabs( fLogicBarHeight
)/fLogicPositiveYSum
;
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
;
689 fPositiveLogicYForNextSeries
+= fLogicBarHeight
;
691 fNegativeLogicYForNextSeries
+= fLogicBarHeight
;
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;
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
);
748 fTopHeight
=approxSub(fCompleteHeight
,fLowerYValue
);
749 double fLogicYStart
= bPositive
? fLowerYValue
: fUpperYValue
;
750 double fMiddleHeight
= fUpperYValue
-fLowerYValue
;
755 if( lcl_hasGeometry3DVariableWidth(nGeometry3D
) && fCompleteHeight
!=0.0 )
757 double fHeight
= fCompleteHeight
-fLowerYValue
;
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
)
780 m_bPointsWereSkipped
= true;
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
)
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 );
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;
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() )
867 // //aLineProperties.Color =
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
) );
894 createErrorBar_Y( aUnscaledLogicPosition
, **aSeriesIter
, nCatIndex
, m_xLogicTarget
);
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 )
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)
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
) ) );
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
);
981 drawing::PolyPolygonShape3D
* pSeriesPoly
= &pSeries
->m_aPolyPolygonShape3D
;
982 if(!ShapeFactory::hasPolygonAnyLines(*pSeriesPoly
))
985 drawing::PolyPolygonShape3D aPoly
;
986 Clipping::clipPolygonAtRectangle( *pSeriesPoly
, pPosHelper
->getScaledLogicClipDoubleRect(), aPoly
);
988 if(!ShapeFactory::hasPolygonAnyLines(aPoly
))
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
1018 OSL_TRACE( "\nPPPPPPPPP<<<<<<<<<<<< bar chart :: createShapes():: skipped points: %d created points: %d", nSkippedPoints
, nCreatedPoints
);
1021 //.............................................................................
1023 //.............................................................................