1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 
25 // MARKER(update_precomp.py): autogen include statement, do not remove
26 #include "precompiled_chart2.hxx"
27 
28 #include "BarChart.hxx"
29 #include "ShapeFactory.hxx"
30 //#include "chartview/servicenames_charttypes.hxx"
31 //#include "servicenames_coosystems.hxx"
32 #include "CommonConverters.hxx"
33 #include "ObjectIdentifier.hxx"
34 #include "LabelPositionHelper.hxx"
35 #include "BarPositionHelper.hxx"
36 #include "macros.hxx"
37 #include "AxisIndexDefines.hxx"
38 #include "Clipping.hxx"
39 #include "DateHelper.hxx"
40 
41 #include <com/sun/star/chart/DataLabelPlacement.hpp>
42 
43 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
44 #include <tools/debug.hxx>
45 #include <rtl/math.hxx>
46 
47 //.............................................................................
48 namespace chart
49 {
50 //.............................................................................
51 using namespace ::com::sun::star;
52 using namespace ::rtl::math;
53 using namespace ::com::sun::star::chart2;
54 
55 //-----------------------------------------------------------------------------
56 //-----------------------------------------------------------------------------
57 //-----------------------------------------------------------------------------
58 
BarChart(const uno::Reference<XChartType> & xChartTypeModel,sal_Int32 nDimensionCount)59 BarChart::BarChart( const uno::Reference<XChartType>& xChartTypeModel
60                     , sal_Int32 nDimensionCount )
61         : VSeriesPlotter( xChartTypeModel, nDimensionCount )
62         , m_pMainPosHelper( new BarPositionHelper() )
63 {
64     PlotterBase::m_pPosHelper = m_pMainPosHelper;
65     VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper;
66 
67     try
68     {
69         if( m_xChartTypeModelProps.is() )
70         {
71             m_xChartTypeModelProps->getPropertyValue( C2U( "OverlapSequence" ) ) >>= m_aOverlapSequence;
72             m_xChartTypeModelProps->getPropertyValue( C2U( "GapwidthSequence" ) ) >>= m_aGapwidthSequence;
73         }
74     }
75     catch( uno::Exception& e )
76 	{
77         ASSERT_EXCEPTION( e );
78     }
79 }
80 
~BarChart()81 BarChart::~BarChart()
82 {
83     delete m_pMainPosHelper;
84 }
85 
86 //-------------------------------------------------------------------------
87 
getPlottingPositionHelper(sal_Int32 nAxisIndex) const88 PlottingPositionHelper& BarChart::getPlottingPositionHelper( sal_Int32 nAxisIndex ) const
89 {
90     PlottingPositionHelper& rPosHelper = VSeriesPlotter::getPlottingPositionHelper( nAxisIndex );
91     BarPositionHelper* pBarPosHelper = dynamic_cast<BarPositionHelper*>(&rPosHelper);
92     if( pBarPosHelper && nAxisIndex >= 0 )
93     {
94         if( nAxisIndex < m_aOverlapSequence.getLength() )
95             pBarPosHelper->setInnerDistance( -m_aOverlapSequence[nAxisIndex]/100.0 );
96         if( nAxisIndex < m_aGapwidthSequence.getLength() )
97             pBarPosHelper->setOuterDistance( m_aGapwidthSequence[nAxisIndex]/100.0 );
98     }
99     return rPosHelper;
100 }
101 
getPreferredDiagramAspectRatio() const102 drawing::Direction3D BarChart::getPreferredDiagramAspectRatio() const
103 {
104     drawing::Direction3D aRet(1.0,1.0,1.0);
105     if( m_nDimension == 3 )
106     {
107         aRet = drawing::Direction3D(1.0,-1.0,1.0);
108                 BarPositionHelper* pPosHelper = dynamic_cast<BarPositionHelper*>(&( this->getPlottingPositionHelper( MAIN_AXIS_INDEX) ) );
109         drawing::Direction3D aScale( pPosHelper->getScaledLogicWidth() );
110         if(aScale.DirectionX!=0.0)
111         {
112             double fXSlotCount = 1.0;
113             if(!m_aZSlots.empty())
114                 fXSlotCount = m_aZSlots.begin()->size();
115 
116             aRet.DirectionZ = aScale.DirectionZ/(aScale.DirectionX + aScale.DirectionX*(fXSlotCount-1.0)*pPosHelper->getScaledSlotWidth());
117         }
118         else
119             return VSeriesPlotter::getPreferredDiagramAspectRatio();
120         if(aRet.DirectionZ<0.05)
121             aRet.DirectionZ=0.05;
122         if(aRet.DirectionZ>10)
123             aRet.DirectionZ=10;
124 
125         if( m_pMainPosHelper && m_pMainPosHelper->isSwapXAndY() )
126         {
127             double fTemp = aRet.DirectionX;
128             aRet.DirectionX = aRet.DirectionY;
129             aRet.DirectionY = fTemp;
130         }
131     }
132     else
133         aRet = drawing::Direction3D(-1,-1,-1);
134     return aRet;
135 }
136 
keepAspectRatio() const137 bool BarChart::keepAspectRatio() const
138 {
139     if( m_nDimension == 3 )
140         return true;
141     return true;
142 }
143 
getLabelScreenPositionAndAlignment(LabelAlignment & rAlignment,sal_Int32 nLabelPlacement,double fScaledX,double fScaledLowerYValue,double fScaledUpperYValue,double fScaledZ,double fScaledLowerBarDepth,double fScaledUpperBarDepth,double fBaseValue,BarPositionHelper * pPosHelper) const144 awt::Point BarChart::getLabelScreenPositionAndAlignment(
145                      LabelAlignment& rAlignment, sal_Int32 nLabelPlacement
146                      , double fScaledX, double fScaledLowerYValue, double fScaledUpperYValue, double fScaledZ
147                      , double fScaledLowerBarDepth, double fScaledUpperBarDepth, double fBaseValue
148                      , BarPositionHelper* pPosHelper
149                      ) const
150 {
151     double fX = fScaledX;
152     double fY = fScaledUpperYValue;
153     double fZ = fScaledZ;
154     bool bReverse = !pPosHelper->isMathematicalOrientationY();
155     bool bNormalOutside = (!bReverse == !!(fBaseValue < fScaledUpperYValue));
156     double fDepth = fScaledUpperBarDepth;
157 
158     switch(nLabelPlacement)
159     {
160     case ::com::sun::star::chart::DataLabelPlacement::TOP:
161         {
162             if( !pPosHelper->isSwapXAndY() )
163             {
164                 fY = bReverse ? fScaledLowerYValue : fScaledUpperYValue;
165                 rAlignment = LABEL_ALIGN_TOP;
166                 if(3==m_nDimension)
167                     fDepth = bReverse ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
168             }
169             else
170             {
171                 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
172                 rAlignment = LABEL_ALIGN_CENTER;
173                 DBG_ERROR( "top label placement is not really supported by horizontal bar charts" );
174             }
175         }
176         break;
177     case ::com::sun::star::chart::DataLabelPlacement::BOTTOM:
178         {
179             if(!pPosHelper->isSwapXAndY())
180             {
181                 fY = bReverse ? fScaledUpperYValue : fScaledLowerYValue;
182                 rAlignment = LABEL_ALIGN_BOTTOM;
183                 if(3==m_nDimension)
184                     fDepth = bReverse ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
185             }
186             else
187             {
188                 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
189                 rAlignment = LABEL_ALIGN_CENTER;
190                 DBG_ERROR( "bottom label placement is not supported by horizontal bar charts" );
191             }
192         }
193         break;
194     case ::com::sun::star::chart::DataLabelPlacement::LEFT:
195         {
196             if( pPosHelper->isSwapXAndY() )
197             {
198                 fY = bReverse ? fScaledUpperYValue : fScaledLowerYValue;
199                 rAlignment = LABEL_ALIGN_LEFT;
200                 if(3==m_nDimension)
201                     fDepth = bReverse ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
202             }
203             else
204             {
205                 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
206                 rAlignment = LABEL_ALIGN_CENTER;
207                 DBG_ERROR( "left label placement is not supported by column charts" );
208             }
209         }
210         break;
211     case ::com::sun::star::chart::DataLabelPlacement::RIGHT:
212         {
213             if( pPosHelper->isSwapXAndY() )
214             {
215                 fY = bReverse ? fScaledLowerYValue : fScaledUpperYValue;
216                 rAlignment = LABEL_ALIGN_RIGHT;
217                 if(3==m_nDimension)
218                     fDepth = bReverse ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
219             }
220             else
221             {
222                 fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
223                 rAlignment = LABEL_ALIGN_CENTER;
224                 DBG_ERROR( "right label placement is not supported by column charts" );
225             }
226         }
227         break;
228     case ::com::sun::star::chart::DataLabelPlacement::OUTSIDE:
229         {
230         fY = (fBaseValue < fScaledUpperYValue) ? fScaledUpperYValue : fScaledLowerYValue;
231         if( pPosHelper->isSwapXAndY() )
232             rAlignment = bNormalOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT;
233         else
234             rAlignment = bNormalOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM;
235         if(3==m_nDimension)
236             fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
237         }
238         break;
239     case ::com::sun::star::chart::DataLabelPlacement::INSIDE:
240         {
241         fY = (fBaseValue < fScaledUpperYValue) ? fScaledUpperYValue : fScaledLowerYValue;
242         if( pPosHelper->isSwapXAndY() )
243             rAlignment = bNormalOutside ? LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT;
244         else
245             rAlignment = bNormalOutside ? LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP;
246         if(3==m_nDimension)
247             fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
248         }
249         break;
250     case ::com::sun::star::chart::DataLabelPlacement::NEAR_ORIGIN:
251         {
252         fY = (fBaseValue < fScaledUpperYValue) ? fScaledLowerYValue : fScaledUpperYValue;
253         if( pPosHelper->isSwapXAndY() )
254             rAlignment = bNormalOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT;
255         else
256             rAlignment = bNormalOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM;
257         if(3==m_nDimension)
258             fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
259         }
260         break;
261     case ::com::sun::star::chart::DataLabelPlacement::CENTER:
262         fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
263         rAlignment = LABEL_ALIGN_CENTER;
264         if(3==m_nDimension)
265             fDepth = fabs(fScaledUpperBarDepth-fScaledLowerBarDepth)/2.0;
266         break;
267     default:
268         DBG_ERROR("this label alignment is not implemented yet");
269 
270         break;
271     }
272     if(3==m_nDimension)
273         fZ -= fDepth/2.0;
274 
275     drawing::Position3D aScenePosition3D( pPosHelper->
276             transformScaledLogicToScene( fX, fY, fZ, true ) );
277     return LabelPositionHelper(pPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory)
278         .transformSceneToScreenPosition( aScenePosition3D );
279 }
280 
createDataPoint3D_Bar(const uno::Reference<drawing::XShapes> & xTarget,const drawing::Position3D & rPosition,const drawing::Direction3D & rSize,double fTopHeight,sal_Int32 nRotateZAngleHundredthDegree,const uno::Reference<beans::XPropertySet> & xObjectProperties,sal_Int32 nGeometry3D)281 uno::Reference< drawing::XShape > BarChart::createDataPoint3D_Bar(
282           const uno::Reference< drawing::XShapes >& xTarget
283         , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize
284         , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree
285         , const uno::Reference< beans::XPropertySet >& xObjectProperties
286         , sal_Int32 nGeometry3D )
287 {
288     bool bRoundedEdges = true;
289     try
290     {
291         if( xObjectProperties.is() )
292         {
293             sal_Int16 nPercentDiagonal = 0;
294             xObjectProperties->getPropertyValue( C2U( "PercentDiagonal" ) ) >>= nPercentDiagonal;
295             if( nPercentDiagonal < 5 )
296                 bRoundedEdges = false;
297         }
298     }
299     catch( uno::Exception& e )
300 	{
301         ASSERT_EXCEPTION( e );
302     }
303 
304     uno::Reference< drawing::XShape > xShape(NULL);
305     switch( nGeometry3D )
306     {
307         case DataPointGeometry3D::CYLINDER:
308             xShape = m_pShapeFactory->createCylinder( xTarget, rPosition, rSize, nRotateZAngleHundredthDegree );
309             break;
310         case DataPointGeometry3D::CONE:
311             xShape = m_pShapeFactory->createCone( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree );
312             break;
313         case DataPointGeometry3D::PYRAMID:
314             xShape = m_pShapeFactory->createPyramid( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree>0
315                 , xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
316             break;
317         case DataPointGeometry3D::CUBOID:
318         default:
319             xShape = m_pShapeFactory->createCube( xTarget, rPosition, rSize
320                     , nRotateZAngleHundredthDegree, xObjectProperties
321                     , PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), bRoundedEdges );
322             return xShape;
323     }
324     if( nGeometry3D != DataPointGeometry3D::PYRAMID )
325         this->setMappedProperties( xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
326     return xShape;
327 }
328 
329 namespace
330 {
lcl_hasGeometry3DVariableWidth(sal_Int32 nGeometry3D)331 bool lcl_hasGeometry3DVariableWidth( sal_Int32 nGeometry3D )
332 {
333     bool bRet = false;
334     switch( nGeometry3D )
335     {
336         case DataPointGeometry3D::PYRAMID:
337         case DataPointGeometry3D::CONE:
338             bRet = true;
339             break;
340         case DataPointGeometry3D::CUBOID:
341         case DataPointGeometry3D::CYLINDER:
342         default:
343             bRet = false;
344             break;
345     }
346     return bRet;
347 }
348 }// end anonymous namespace
349 
addSeries(VDataSeries * pSeries,sal_Int32 zSlot,sal_Int32 xSlot,sal_Int32 ySlot)350 void BarChart::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
351 {
352     if( !pSeries )
353         return;
354     if(m_nDimension==2)
355     {
356         //2ND_AXIS_IN_BARS put series on second scales to different z slot as temporary workaround
357         //this needs to be redesigned if 3d bars are also able to display secondary axes
358 
359         sal_Int32 nAxisIndex = pSeries->getAttachedAxisIndex();
360         zSlot = nAxisIndex;
361 
362         if( !pSeries->getGroupBarsPerAxis() )
363             zSlot = 0;
364         if(zSlot>=static_cast<sal_Int32>(m_aZSlots.size()))
365             m_aZSlots.resize(zSlot+1);
366     }
367     VSeriesPlotter::addSeries( pSeries, zSlot, xSlot, ySlot );
368 }
369 
370 //better performance for big data
371 struct FormerBarPoint
372 {
FormerBarPointchart::FormerBarPoint373     FormerBarPoint( double fX, double fUpperY, double fLowerY, double fZ )
374         : m_fX(fX), m_fUpperY(fUpperY), m_fLowerY(fLowerY), m_fZ(fZ)
375         {}
FormerBarPointchart::FormerBarPoint376     FormerBarPoint()
377     {
378         ::rtl::math::setNan( &m_fX );
379         ::rtl::math::setNan( &m_fUpperY );
380         ::rtl::math::setNan( &m_fLowerY );
381         ::rtl::math::setNan( &m_fZ );
382     }
383 
384     double m_fX;
385     double m_fUpperY;
386     double m_fLowerY;
387     double m_fZ;
388 };
389 
adaptOverlapAndGapwidthForGroupBarsPerAxis()390 void BarChart::adaptOverlapAndGapwidthForGroupBarsPerAxis()
391 {
392     //adapt m_aOverlapSequence and m_aGapwidthSequence for the groupBarsPerAxis feature
393     //thus the different series use the same settings
394 
395     VDataSeries* pFirstSeries = getFirstSeries();
396     if(pFirstSeries && !pFirstSeries->getGroupBarsPerAxis() )
397     {
398         sal_Int32 nAxisIndex = pFirstSeries->getAttachedAxisIndex();
399         sal_Int32 nN = 0;
400         sal_Int32 nUseThisIndex = nAxisIndex;
401         if( nUseThisIndex < 0 || nUseThisIndex >= m_aOverlapSequence.getLength() )
402             nUseThisIndex = 0;
403         for( nN = 0; nN < m_aOverlapSequence.getLength(); nN++ )
404         {
405             if(nN!=nUseThisIndex)
406                 m_aOverlapSequence[nN] = m_aOverlapSequence[nUseThisIndex];
407         }
408 
409         nUseThisIndex = nAxisIndex;
410         if( nUseThisIndex < 0 || nUseThisIndex >= m_aGapwidthSequence.getLength() )
411             nUseThisIndex = 0;
412         for( nN = 0; nN < m_aGapwidthSequence.getLength(); nN++ )
413         {
414             if(nN!=nUseThisIndex)
415                 m_aGapwidthSequence[nN] = m_aGapwidthSequence[nUseThisIndex];
416         }
417     }
418 }
419 
createShapes()420 void BarChart::createShapes()
421 {
422     if( m_aZSlots.begin() == m_aZSlots.end() ) //no series
423         return;
424 
425     DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"BarChart is not proper initialized");
426     if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()))
427         return;
428 
429     //the text labels should be always on top of the other series shapes
430     //therefore create an own group for the texts to move them to front
431     //(because the text group is created after the series group the texts are displayed on top)
432 
433     //the regression curves should always be on top of the bars but beneath the text labels
434     //to achieve this the regression curve target is created after the series target and before the text target
435 
436     uno::Reference< drawing::XShapes > xSeriesTarget(
437         createGroupShape( m_xLogicTarget,rtl::OUString() ));
438     uno::Reference< drawing::XShapes > xRegressionCurveTarget(
439         createGroupShape( m_xLogicTarget,rtl::OUString() ));
440     uno::Reference< drawing::XShapes > xTextTarget(
441         m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() ));
442 
443 
444     //---------------------------------------------
445     uno::Reference< drawing::XShapes > xRegressionCurveEquationTarget(
446         m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() ));
447     //check necessary here that different Y axis can not be stacked in the same group? ... hm?
448 
449     double fLogicZ        = 1.0;//as defined
450 
451     bool bDrawConnectionLines = false;
452     bool bDrawConnectionLinesInited = false;
453     bool bOnlyConnectionLinesForThisPoint = false;
454 
455     adaptOverlapAndGapwidthForGroupBarsPerAxis();
456 
457     //better performance for big data
458     std::map< VDataSeries*, FormerBarPoint > aSeriesFormerPointMap;
459     m_bPointsWereSkipped = false;
460     sal_Int32 nSkippedPoints = 0;
461     sal_Int32 nCreatedPoints = 0;
462     //
463 
464 	sal_Int32 nStartIndex = 0;
465     sal_Int32 nEndIndex = VSeriesPlotter::getPointCount();
466 //=============================================================================
467     //iterate through all x values per indices
468     for( sal_Int32 nPointIndex = nStartIndex; nPointIndex < nEndIndex; nPointIndex++ )
469 	{
470         ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator             aZSlotIter = m_aZSlots.begin();
471         const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
472 
473         //sum up the values for all series in a complete z zlot per attached axis
474         ::std::map< sal_Int32,  double > aLogicYSumMap;
475         for( ; aZSlotIter != aZSlotEnd; aZSlotIter++ )
476         {
477             ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
478             const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
479 
480             for( aXSlotIter = aZSlotIter->begin(); aXSlotIter != aXSlotEnd; aXSlotIter++ )
481 	        {
482                 sal_Int32 nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries();
483                 if( aLogicYSumMap.find(nAttachedAxisIndex)==aLogicYSumMap.end() )
484                     aLogicYSumMap[nAttachedAxisIndex]=0.0;
485 
486                 double fMinimumY = 0.0, fMaximumY = 0.0;
487                 aXSlotIter->calculateYMinAndMaxForCategory( nPointIndex
488                     , isSeperateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex );
489 
490                 if( !::rtl::math::isNan( fMaximumY ) && fMaximumY > 0)
491                     aLogicYSumMap[nAttachedAxisIndex] += fMaximumY;
492                 if( !::rtl::math::isNan( fMinimumY ) && fMinimumY < 0)
493                     aLogicYSumMap[nAttachedAxisIndex] += fabs(fMinimumY);
494             }
495         }
496 
497 //=============================================================================
498         aZSlotIter = m_aZSlots.begin();
499         for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; aZSlotIter++, nZ++ )
500         {
501             ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
502             const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
503 
504 //=============================================================================
505             //iterate through all x slots in this category
506             double fSlotX=0;
507             for( aXSlotIter = aZSlotIter->begin(); aXSlotIter != aXSlotEnd; aXSlotIter++, fSlotX+=1.0 )
508 	        {
509                 sal_Int32 nAttachedAxisIndex = 0;
510                 BarPositionHelper* pPosHelper = m_pMainPosHelper;
511                 if( aXSlotIter != aXSlotEnd )
512                 {
513                     nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries();
514                     //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
515                     pPosHelper = dynamic_cast<BarPositionHelper*>(&( this->getPlottingPositionHelper( nAttachedAxisIndex ) ) );
516                     if(!pPosHelper)
517                         pPosHelper = m_pMainPosHelper;
518                 }
519                 PlotterBase::m_pPosHelper = pPosHelper;
520 
521                 //update/create information for current group
522                 pPosHelper->updateSeriesCount( aZSlotIter->size() );
523                 double fLogicBaseWidth = pPosHelper->getScaledSlotWidth();
524 
525                 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
526 
527                 // get distance from base value to maximum and minimum
528 
529                 double fMinimumY = 0.0, fMaximumY = 0.0;
530                 aXSlotIter->calculateYMinAndMaxForCategory( nPointIndex
531                     , isSeperateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex );
532 
533                 double fLogicPositiveYSum = 0.0;
534                 if( !::rtl::math::isNan( fMaximumY ) )
535                     fLogicPositiveYSum = fMaximumY;
536 
537                 double fLogicNegativeYSum = 0.0;
538                 if( !::rtl::math::isNan( fMinimumY ) )
539                     fLogicNegativeYSum = fMinimumY;
540 
541                 if( pPosHelper->isPercentY() )
542                 {
543                     /*  #i70395# fLogicPositiveYSum contains sum of all positive
544                         values, if any, otherwise the highest negative value.
545                         fLogicNegativeYSum contains sum of all negative values,
546                         if any, otherwise the lowest positive value.
547                         Afterwards, fLogicPositiveYSum will contain the maximum
548                         (positive) value that is related to 100%. */
549 
550                     // do nothing if there are positive values only
551                     if( fLogicNegativeYSum < 0.0 )
552                     {
553                         // fLogicPositiveYSum<0 => negative values only, use absolute of negative sum
554                         if( fLogicPositiveYSum < 0.0 )
555                             fLogicPositiveYSum = -fLogicNegativeYSum;
556                         // otherwise there are positive and negative values, calculate total distance
557                         else
558                             fLogicPositiveYSum -= fLogicNegativeYSum;
559                     }
560                     fLogicNegativeYSum = 0.0;
561                 }
562 
563                 double fBaseValue = 0.0;
564                 if( !pPosHelper->isPercentY() && pSeriesList->size()<=1 )
565                     fBaseValue = pPosHelper->getBaseValueY();
566                 double fPositiveLogicYForNextSeries = fBaseValue;
567                 double fNegativeLogicYForNextSeries = fBaseValue;
568 
569                 ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = pSeriesList->begin();
570                 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
571                 aSeriesIter = pSeriesList->begin();
572     //=============================================================================
573                 //iterate through all series in this x slot
574 	            for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
575                 {
576                     VDataSeries* pSeries( *aSeriesIter );
577                     if(!pSeries)
578                         continue;
579 
580                     bOnlyConnectionLinesForThisPoint = false;
581 
582                     if(nPointIndex==nStartIndex)//do not create a regression line for each point
583                         createRegressionCurvesShapes( **aSeriesIter, xRegressionCurveTarget, xRegressionCurveEquationTarget,
584                                                       m_pPosHelper->maySkipPointsInRegressionCalculation());
585 
586                     if( !bDrawConnectionLinesInited )
587                     {
588                         bDrawConnectionLines = pSeries->getConnectBars();
589                         if( m_nDimension==3 )
590                             bDrawConnectionLines = false;
591                         if( bDrawConnectionLines && pSeriesList->size()==1 )
592                         {
593                             //detect whether we have a stacked chart or not:
594                             StackingDirection eDirection = pSeries->getStackingDirection();
595                             if( eDirection  != StackingDirection_Y_STACKING )
596                                 bDrawConnectionLines = false;
597                         }
598                         bDrawConnectionLinesInited = true;
599                     }
600 
601                     //------------
602 
603                     uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes(
604                         getSeriesGroupShape(*aSeriesIter, xSeriesTarget) );
605 
606                     //collect data point information (logic coordinates, style ):
607                     double fUnscaledLogicX = (*aSeriesIter)->getXValue( nPointIndex );
608                     fUnscaledLogicX = DateHelper::RasterizeDateValue( fUnscaledLogicX, m_aNullDate, m_nTimeResolution );
609                     if(fUnscaledLogicX<pPosHelper->getLogicMinX())
610                         continue;//point not visible
611                     if(fUnscaledLogicX>pPosHelper->getLogicMaxX())
612                         continue;//point not visible
613                     if(pPosHelper->isStrongLowerRequested(0) && fUnscaledLogicX==pPosHelper->getLogicMaxX())
614                         continue;//point not visible
615                     double fLogicX = pPosHelper->getScaledSlotPos( fUnscaledLogicX, fSlotX );
616 
617                     double fLogicBarHeight = (*aSeriesIter)->getYValue( nPointIndex );
618                     if( ::rtl::math::isNan( fLogicBarHeight )) //no value at this category
619                         continue;
620 
621                     double fLogicValueForLabeDisplay = fLogicBarHeight;
622                     fLogicBarHeight-=fBaseValue;
623 
624                     if( pPosHelper->isPercentY() )
625                     {
626                         if(fLogicPositiveYSum!=0.0)
627                             fLogicBarHeight = fabs( fLogicBarHeight )/fLogicPositiveYSum;
628                         else
629                             fLogicBarHeight = 0.0;
630                     }
631 
632                     //sort negative and positive values, to display them on different sides of the x axis
633                     bool bPositive = fLogicBarHeight >= 0.0;
634                     double fLowerYValue = bPositive ? fPositiveLogicYForNextSeries : fNegativeLogicYForNextSeries;
635                     double fUpperYValue = fLowerYValue+fLogicBarHeight;
636                     if( bPositive )
637                         fPositiveLogicYForNextSeries += fLogicBarHeight;
638                     else
639                         fNegativeLogicYForNextSeries += fLogicBarHeight;
640 
641                     if(m_nDimension==3)
642                         fLogicZ = nZ+0.5;
643 
644                     drawing::Position3D aUnscaledLogicPosition( fUnscaledLogicX, fUpperYValue, fLogicZ );
645 
646                     //@todo ... start an iteration over the different breaks of the axis
647                     //each subsystem may add an additional shape to form the whole point
648                     //create a group shape for this point and add to the series shape:
649     //		        uno::Reference< drawing::XShapes > xPointGroupShape_Shapes(	createGroupShape(xSeriesGroupShape_Shapes) );
650     //		        uno::Reference<drawing::XShape> xPointGroupShape_Shape =
651     //				        uno::Reference<drawing::XShape>( xPointGroupShape_Shapes, uno::UNO_QUERY );
652                     //as long as we do not iterate we do not need to create an additional group for each point
653                     uno::Reference< drawing::XShapes > xPointGroupShape_Shapes = xSeriesGroupShape_Shapes;
654                     uno::Reference< beans::XPropertySet > xDataPointProperties( (*aSeriesIter)->getPropertiesOfPoint( nPointIndex ) );
655                     sal_Int32 nGeometry3D = DataPointGeometry3D::CUBOID;
656                     if(m_nDimension==3) try
657                     {
658                         xDataPointProperties->getPropertyValue( C2U( "Geometry3D" )) >>= nGeometry3D;
659                     }
660                     catch( uno::Exception& e )
661 	                {
662                         ASSERT_EXCEPTION( e );
663                     }
664 
665                     //@todo iterate through all subsystems to create partial points
666                     {
667                         //@todo select a suiteable PositionHelper for this subsystem
668                         BarPositionHelper* pSubPosHelper = pPosHelper;
669 
670                         double fUnclippedUpperYValue = fUpperYValue;
671 
672                         //apply clipping to Y
673                         if( !pPosHelper->clipYRange(fLowerYValue,fUpperYValue) )
674                         {
675                             if( bDrawConnectionLines )
676                                 bOnlyConnectionLinesForThisPoint = true;
677                             else
678                                 continue;
679                         }
680                         //@todo clipping of X and Z is not fully integrated so far, as there is a need to create different objects
681 
682                         //apply scaling to Y before calculating width (necessary to maintain gradient in clipped objects)
683                         pSubPosHelper->doLogicScaling(NULL,&fLowerYValue,NULL);
684                         pSubPosHelper->doLogicScaling(NULL,&fUpperYValue,NULL);
685                         //scaling of X and Z is not provided as the created objects should be symmetric in that dimensions
686 
687                         pSubPosHelper->doLogicScaling(NULL,&fUnclippedUpperYValue,NULL);
688 
689                         //calculate resulting width
690                         double fCompleteHeight = bPositive ? fLogicPositiveYSum : fLogicNegativeYSum;
691                         if( pPosHelper->isPercentY() )
692                             fCompleteHeight = 1.0;
693                         double fLogicBarWidth = fLogicBaseWidth;
694                         double fTopHeight=approxSub(fCompleteHeight,fUpperYValue);
695                         if(!bPositive)
696                             fTopHeight=approxSub(fCompleteHeight,fLowerYValue);
697                         double fLogicYStart = bPositive ? fLowerYValue : fUpperYValue;
698                         double fMiddleHeight = fUpperYValue-fLowerYValue;
699                         if(!bPositive)
700                             fMiddleHeight*=-1.0;
701                         double fLogicBarDepth = 0.5;
702                         if(m_nDimension==3)
703                         {
704                             if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 )
705                             {
706                                 double fHeight = fCompleteHeight-fLowerYValue;
707                                 if(!bPositive)
708                                     fHeight = fCompleteHeight-fUpperYValue;
709                                 fLogicBarWidth = fLogicBaseWidth*fHeight/(fCompleteHeight);
710                                 if(fLogicBarWidth<=0.0)
711                                     fLogicBarWidth=fLogicBaseWidth;
712                                 fLogicBarDepth = fLogicBarDepth*fHeight/(fCompleteHeight);
713                                 if(fLogicBarDepth<=0.0)
714                                     fLogicBarDepth*=-1.0;
715                             }
716                         }
717 
718                         //better performance for big data
719                         FormerBarPoint aFormerPoint( aSeriesFormerPointMap[pSeries] );
720                         pPosHelper->setCoordinateSystemResolution( m_aCoordinateSystemResolution );
721                         if( !pSeries->isAttributedDataPoint(nPointIndex)
722                             &&
723                             pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fUpperY, aFormerPoint.m_fZ
724                                                             , fLogicX, fUpperYValue, fLogicZ )
725                             &&
726                             pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fLowerY, aFormerPoint.m_fZ
727                                                             , fLogicX, fLowerYValue, fLogicZ )
728                                                             )
729                         {
730                             nSkippedPoints++;
731                             m_bPointsWereSkipped = true;
732                             continue;
733                         }
734                         aSeriesFormerPointMap[pSeries] = FormerBarPoint(fLogicX,fUpperYValue,fLowerYValue,fLogicZ);
735                         //
736 
737                         //
738                         if( bDrawConnectionLines )
739                         {
740                             //store point information for connection lines
741 
742                             drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ );
743                             drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ );
744 
745                             if( isValidPosition(aLeftUpperPoint) )
746                                 AddPointToPoly( (*aSeriesIter)->m_aPolyPolygonShape3D, aLeftUpperPoint );
747                             if( isValidPosition(aRightUpperPoint) )
748                                 AddPointToPoly( (*aSeriesIter)->m_aPolyPolygonShape3D, aRightUpperPoint );
749                         }
750 
751                         if( bOnlyConnectionLinesForThisPoint )
752                             continue;
753 
754                         //maybe additional possibility for performance improvement
755                         //bool bCreateLineInsteadOfComplexGeometryDueToMissingSpace = false;
756                         //pPosHelper->isSameForGivenResolution( fLogicX-fLogicBarWidth/2.0, fLowerYValue, fLogicZ
757                         //                            , fLogicX+fLogicBarWidth/2.0, fLowerYValue, fLogicZ );
758 
759                         nCreatedPoints++;
760                         //create partial point
761                         if( !approxEqual(fLowerYValue,fUpperYValue) )
762                         {
763                             uno::Reference< drawing::XShape >  xShape;
764                             if( m_nDimension==3 )
765                             {
766                                 drawing::Position3D aLogicBottom            (fLogicX,fLogicYStart,fLogicZ);
767                                 drawing::Position3D aLogicLeftBottomFront   (fLogicX+fLogicBarWidth/2.0,fLogicYStart,fLogicZ-fLogicBarDepth/2.0);
768                                 drawing::Position3D aLogicRightDeepTop      (fLogicX-fLogicBarWidth/2.0,fLogicYStart+fMiddleHeight,fLogicZ+fLogicBarDepth/2.0);
769                                 drawing::Position3D aLogicTopTop            (fLogicX,fLogicYStart+fMiddleHeight+fTopHeight,fLogicZ);
770 
771                                 uno::Reference< XTransformation > xTransformation = pSubPosHelper->getTransformationScaledLogicToScene();
772 
773                                 //transformation 3) -> 4)
774                                 drawing::Position3D aTransformedBottom          ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicBottom) ) ) );
775                                 drawing::Position3D aTransformedLeftBottomFront ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicLeftBottomFront) ) ) );
776                                 drawing::Position3D aTransformedRightDeepTop    ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicRightDeepTop) ) ) );
777                                 drawing::Position3D aTransformedTopTop          ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicTopTop) ) ) );
778 
779                                 drawing::Direction3D aSize = aTransformedRightDeepTop - aTransformedLeftBottomFront;
780                                 drawing::Direction3D aTopSize( aTransformedTopTop - aTransformedRightDeepTop );
781                                 fTopHeight = aTopSize.DirectionY;
782 
783                                 sal_Int32 nRotateZAngleHundredthDegree = 0;
784                                 if( pPosHelper->isSwapXAndY() )
785                                 {
786                                     fTopHeight = aTopSize.DirectionX;
787                                     nRotateZAngleHundredthDegree = 90*100;
788                                     aSize = drawing::Direction3D(aSize.DirectionY,aSize.DirectionX,aSize.DirectionZ);
789                                 }
790 
791                                 if( aSize.DirectionX < 0 )
792                                     aSize.DirectionX *= -1.0;
793                                 if( aSize.DirectionZ < 0 )
794                                     aSize.DirectionZ *= -1.0;
795                                 if( fTopHeight < 0 )
796                                     fTopHeight *= -1.0;
797 
798                                 xShape = createDataPoint3D_Bar(
799                                     xPointGroupShape_Shapes, aTransformedBottom, aSize, fTopHeight, nRotateZAngleHundredthDegree
800                                     , xDataPointProperties, nGeometry3D );
801                             }
802                             else //m_nDimension!=3
803                             {
804                                 //if( bCreateLineInsteadOfComplexGeometryDueToMissingSpace )
805                                 //{
806                                 //    drawing::PolyPolygonShape3D aPoly;
807                                 //    drawing::Position3D aUpperPoint( fLogicX,fUpperYValue,fLogicZ );
808                                 //    drawing::Position3D aLowerPoint( fLogicX,fLowerYValue,fLogicZ );
809 
810                                 //    AddPointToPoly( aPoly, aUpperPoint );
811                                 //    AddPointToPoly( aPoly, aLowerPoint );
812 
813                                 //    VLineProperties aLineProperties;
814                                 //    aLineProperties.initFromPropertySet( xDataPointProperties, true /*bUseSeriesPropertyNames*/ );
815                                 //    if( !aLineProperties.isLineVisible() )
816                                 //    {
817                                 //        //todo
818                                 //        //aLineProperties.Color =
819                                 //    }
820 
821                                 //    xShape = m_pShapeFactory->createLine2D( xPointGroupShape_Shapes
822                                 //                , PolyToPointSequence(aPoly), &aLineProperties );
823                                 //}
824 
825                                 drawing::PolyPolygonShape3D aPoly;
826                                 drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUpperYValue,fLogicZ );
827                                 drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUpperYValue,fLogicZ );
828 
829                                 AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
830                                 AddPointToPoly( aPoly, drawing::Position3D( fLogicX+fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
831                                 AddPointToPoly( aPoly, aRightUpperPoint );
832                                 AddPointToPoly( aPoly, aLeftUpperPoint );
833                                 AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
834                                 pPosHelper->transformScaledLogicToScene( aPoly );
835                                 xShape = m_pShapeFactory->createArea2D( xPointGroupShape_Shapes, aPoly );
836                                 this->setMappedProperties( xShape, xDataPointProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
837                             }
838                             //set name/classified ObjectID (CID)
839                             ShapeFactory::setShapeName(xShape
840                                 , ObjectIdentifier::createPointCID(
841                                     (*aSeriesIter)->getPointCID_Stub(),nPointIndex) );
842                         }
843 
844                         //create error bar
845                         createErrorBar_Y( aUnscaledLogicPosition, **aSeriesIter, nPointIndex, m_xLogicTarget, &fLogicX );
846 
847                         //------------
848                         //create data point label
849                         if( (**aSeriesIter).getDataPointLabelIfLabel(nPointIndex) )
850                         {
851                             double fLogicSum = aLogicYSumMap[nAttachedAxisIndex];
852 
853                             LabelAlignment eAlignment(LABEL_ALIGN_CENTER);
854                             sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nPointIndex, m_xChartTypeModel, m_nDimension, pPosHelper->isSwapXAndY() );
855 
856                             double fLowerBarDepth = fLogicBarDepth;
857                             double fUpperBarDepth = fLogicBarDepth;
858                             {
859                                 double fOuterBarDepth = fLogicBarDepth;
860                                 if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 )
861                                 {
862                                     fOuterBarDepth = fLogicBarDepth * (fTopHeight)/(fabs(fCompleteHeight));
863                                     fLowerBarDepth = (fBaseValue < fUpperYValue) ? fabs(fLogicBarDepth) : fabs(fOuterBarDepth);
864                                     fUpperBarDepth = (fBaseValue < fUpperYValue) ? fabs(fOuterBarDepth) : fabs(fLogicBarDepth);
865                                 }
866                             }
867 
868                             awt::Point aScreenPosition2D( this->getLabelScreenPositionAndAlignment(
869                                 eAlignment, nLabelPlacement
870                                 , fLogicX, fLowerYValue, fUpperYValue, fLogicZ
871                                 , fLowerBarDepth, fUpperBarDepth, fBaseValue, pPosHelper ));
872                             sal_Int32 nOffset = 0;
873                             if(LABEL_ALIGN_CENTER!=eAlignment)
874                             {
875                                 nOffset = 100;//add some spacing //@todo maybe get more intelligent values
876                                 if( m_nDimension == 3 )
877                                     nOffset = 260;
878                             }
879                             this->createDataLabel( xTextTarget, **aSeriesIter, nPointIndex
880                                             , fLogicValueForLabeDisplay, fLogicSum, aScreenPosition2D, eAlignment, nOffset );
881                         }
882 
883                     }//end iteration through partial points
884 
885                     //remove PointGroupShape if empty
886     //                if(!xPointGroupShape_Shapes->getCount())
887     //                    xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shape);
888                 }//next series in x slot (next y slot)
889             }//next x slot
890         }//next z slot
891 	}//next category
892 //=============================================================================
893 //=============================================================================
894 //=============================================================================
895     if( bDrawConnectionLines )
896     {
897         ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator             aZSlotIter = m_aZSlots.begin();
898         const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
899 //=============================================================================
900         for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; aZSlotIter++, nZ++ )
901         {
902             ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
903             const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
904 
905             BarPositionHelper* pPosHelper = m_pMainPosHelper;
906             if( aXSlotIter != aXSlotEnd )
907             {
908                 sal_Int32 nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries();
909                 //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
910                 pPosHelper = dynamic_cast<BarPositionHelper*>(&( this->getPlottingPositionHelper( nAttachedAxisIndex ) ) );
911                 if(!pPosHelper)
912                     pPosHelper = m_pMainPosHelper;
913             }
914             PlotterBase::m_pPosHelper = pPosHelper;
915 
916 //=============================================================================
917             //iterate through all x slots in this category
918             for( double fSlotX=0; aXSlotIter != aXSlotEnd; aXSlotIter++, fSlotX+=1.0 )
919 	        {
920                 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
921 
922                 ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = pSeriesList->begin();
923                 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
924                 aSeriesIter = pSeriesList->begin();
925 //=============================================================================
926                 //iterate through all series in this x slot
927 	            for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
928                 {
929                     VDataSeries* pSeries( *aSeriesIter );
930                     if(!pSeries)
931                         continue;
932                     drawing::PolyPolygonShape3D* pSeriesPoly = &pSeries->m_aPolyPolygonShape3D;
933                     if(!ShapeFactory::hasPolygonAnyLines(*pSeriesPoly))
934                         continue;
935 
936                     drawing::PolyPolygonShape3D aPoly;
937                     Clipping::clipPolygonAtRectangle( *pSeriesPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
938 
939                     if(!ShapeFactory::hasPolygonAnyLines(aPoly))
940                         continue;
941 
942                     //transformation 3) -> 4)
943                     pPosHelper->transformScaledLogicToScene( aPoly );
944 
945                     uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes(
946                         getSeriesGroupShape(*aSeriesIter, xSeriesTarget) );
947                     uno::Reference< drawing::XShape > xShape( m_pShapeFactory->createLine2D(
948                         xSeriesGroupShape_Shapes, PolyToPointSequence( aPoly ) ) );
949 		            this->setMappedProperties( xShape, pSeries->getPropertiesOfSeries()
950                         , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
951                 }
952             }
953         }
954     }
955 
956     /* @todo remove series shapes if empty
957     //remove and delete point-group-shape if empty
958     if(!xSeriesGroupShape_Shapes->getCount())
959     {
960         (*aSeriesIter)->m_xShape.set(NULL);
961         m_xLogicTarget->remove(xSeriesGroupShape_Shape);
962     }
963     */
964 
965 	//remove and delete series-group-shape if empty
966 
967     //... todo
968 
969     OSL_TRACE( "\nPPPPPPPPP<<<<<<<<<<<< bar chart :: createShapes():: skipped points: %d created points: %d", nSkippedPoints, nCreatedPoints );
970 }
971 
972 //.............................................................................
973 } //namespace chart
974 //.............................................................................
975