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 "AreaChart.hxx"
29 #include "PlottingPositionHelper.hxx"
30 #include "ShapeFactory.hxx"
31 //#include "chartview/servicenames_charttypes.hxx"
32 #include "CommonConverters.hxx"
33 #include "macros.hxx"
34 #include "ViewDefines.hxx"
35 #include "ObjectIdentifier.hxx"
36 #include "Splines.hxx"
37 #include "ChartTypeHelper.hxx"
38 #include "LabelPositionHelper.hxx"
39 #include "Clipping.hxx"
40 #include "Stripe.hxx"
41 #include "PolarLabelPositionHelper.hxx"
42 #include "DateHelper.hxx"
43 
44 #include <com/sun/star/chart2/Symbol.hpp>
45 #include <com/sun/star/chart/DataLabelPlacement.hpp>
46 #include <com/sun/star/chart/MissingValueTreatment.hpp>
47 
48 #include <tools/debug.hxx>
49 #include <editeng/unoprnms.hxx>
50 #include <rtl/math.hxx>
51 
52 #include <com/sun/star/drawing/DoubleSequence.hpp>
53 #include <com/sun/star/drawing/NormalsKind.hpp>
54 #include <com/sun/star/lang/XServiceName.hpp>
55 
56 //.............................................................................
57 namespace chart
58 {
59 //.............................................................................
60 using namespace ::com::sun::star;
61 using namespace ::rtl::math;
62 using namespace ::com::sun::star::chart2;
63 
64 //-----------------------------------------------------------------------------
65 //-----------------------------------------------------------------------------
66 //-----------------------------------------------------------------------------
67 
AreaChart(const uno::Reference<XChartType> & xChartTypeModel,sal_Int32 nDimensionCount,bool bCategoryXAxis,bool bNoArea,PlottingPositionHelper * pPlottingPositionHelper,bool bConnectLastToFirstPoint,bool bExpandIfValuesCloseToBorder,sal_Int32 nKeepAspectRatio,const drawing::Direction3D & rAspectRatio)68 AreaChart::AreaChart( const uno::Reference<XChartType>& xChartTypeModel
69                      , sal_Int32 nDimensionCount
70                      , bool bCategoryXAxis
71                      , bool bNoArea
72                      , PlottingPositionHelper* pPlottingPositionHelper
73                      , bool bConnectLastToFirstPoint
74                      , bool bExpandIfValuesCloseToBorder
75                      , sal_Int32 nKeepAspectRatio
76                      , const drawing::Direction3D& rAspectRatio
77                      )
78         : VSeriesPlotter( xChartTypeModel, nDimensionCount, bCategoryXAxis )
79         , m_pMainPosHelper(pPlottingPositionHelper)
80 		, m_bArea(!bNoArea)
81 		, m_bLine(bNoArea)
82 		, m_bSymbol( ChartTypeHelper::isSupportingSymbolProperties(xChartTypeModel,nDimensionCount) )
83         , m_bIsPolarCooSys( bConnectLastToFirstPoint )
84         , m_bConnectLastToFirstPoint( bConnectLastToFirstPoint )
85         , m_bExpandIfValuesCloseToBorder( bExpandIfValuesCloseToBorder )
86         , m_nKeepAspectRatio(nKeepAspectRatio)
87         , m_aGivenAspectRatio(rAspectRatio)
88         , m_eCurveStyle(CurveStyle_LINES)
89         , m_nCurveResolution(20)
90         , m_nSplineOrder(3)
91         , m_xSeriesTarget(0)
92         , m_xErrorBarTarget(0)
93         , m_xTextTarget(0)
94         , m_xRegressionCurveEquationTarget(0)
95 {
96     if( !m_pMainPosHelper )
97         m_pMainPosHelper = new PlottingPositionHelper();
98     if( m_pMainPosHelper )
99     {
100         m_pMainPosHelper->AllowShiftXAxisPos(true);
101         m_pMainPosHelper->AllowShiftZAxisPos(true);
102     }
103     PlotterBase::m_pPosHelper = m_pMainPosHelper;
104     VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper;
105 
106     try
107     {
108         if( m_xChartTypeModelProps.is() )
109         {
110             m_xChartTypeModelProps->getPropertyValue( C2U( "CurveStyle" ) ) >>= m_eCurveStyle;
111             m_xChartTypeModelProps->getPropertyValue( C2U( "CurveResolution" ) ) >>= m_nCurveResolution;
112             m_xChartTypeModelProps->getPropertyValue( C2U( "SplineOrder" ) ) >>= m_nSplineOrder;
113         }
114     }
115     catch( uno::Exception& e )
116 	{
117         //the above properties are not supported by all charttypes supported by this class (e.g. area or net chart)
118         //in that cases this exception is ok
119         e.Context.is();//to have debug information without compilation warnings
120     }
121 }
122 
~AreaChart()123 AreaChart::~AreaChart()
124 {
125     delete m_pMainPosHelper;
126 }
127 
getMaximumX()128 double AreaChart::getMaximumX()
129 {
130     double fMax = VSeriesPlotter::getMaximumX();
131     if( m_bCategoryXAxis && m_bIsPolarCooSys )//the angle axis in net charts needs a different autoscaling
132         fMax += 1.0;
133     return fMax;
134 }
135 
isExpandIfValuesCloseToBorder(sal_Int32 nDimensionIndex)136 bool AreaChart::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex )
137 {
138     return m_bExpandIfValuesCloseToBorder &&
139         VSeriesPlotter::isExpandIfValuesCloseToBorder( nDimensionIndex );
140 }
141 
isSeperateStackingForDifferentSigns(sal_Int32)142 bool AreaChart::isSeperateStackingForDifferentSigns( sal_Int32 /*nDimensionIndex*/ )
143 {
144     // no separate stacking in all types of line/area charts
145     return false;
146 }
147 
148 //-----------------------------------------------------------------
149 
getLegendSymbolStyle()150 LegendSymbolStyle AreaChart::getLegendSymbolStyle()
151 {
152     if( m_bArea || m_nDimension == 3 )
153         return LegendSymbolStyle_BOX;
154     return LegendSymbolStyle_LINE;
155 }
156 
getExplicitSymbol(const VDataSeries & rSeries,sal_Int32 nPointIndex)157 uno::Any AreaChart::getExplicitSymbol( const VDataSeries& rSeries, sal_Int32 nPointIndex )
158 {
159     uno::Any aRet;
160 
161     Symbol* pSymbolProperties = rSeries.getSymbolProperties( nPointIndex );
162     if( pSymbolProperties )
163     {
164         aRet = uno::makeAny(*pSymbolProperties);
165     }
166 
167     return aRet;
168 }
169 
170 //-----------------------------------------------------------------
171 // lang::XServiceInfo
172 //-----------------------------------------------------------------
173 /*
174 APPHELPER_XSERVICEINFO_IMPL(AreaChart,CHART2_VIEW_AREACHART_SERVICE_IMPLEMENTATION_NAME)
175 
176 	uno::Sequence< rtl::OUString > AreaChart
177 ::getSupportedServiceNames_Static()
178 {
179 	uno::Sequence< rtl::OUString > aSNS( 1 );
180 	aSNS.getArray()[ 0 ] = CHART2_VIEW_AREACHART_SERVICE_NAME;
181 	return aSNS;
182 }
183 */
getPreferredDiagramAspectRatio() const184 drawing::Direction3D AreaChart::getPreferredDiagramAspectRatio() const
185 {
186     if( m_nKeepAspectRatio == 1 )
187         return m_aGivenAspectRatio;
188     drawing::Direction3D aRet(1,-1,1);
189     if( m_nDimension == 2 )
190         aRet = drawing::Direction3D(-1,-1,-1);
191     else
192     {
193         drawing::Direction3D aScale( m_pPosHelper->getScaledLogicWidth() );
194         aRet.DirectionZ = aScale.DirectionZ*0.2;
195         if(aRet.DirectionZ>1.0)
196             aRet.DirectionZ=1.0;
197         if(aRet.DirectionZ>10)
198             aRet.DirectionZ=10;
199     }
200     return aRet;
201 }
202 
keepAspectRatio() const203 bool AreaChart::keepAspectRatio() const
204 {
205     if( m_nKeepAspectRatio == 0 )
206         return false;
207     if( m_nKeepAspectRatio == 1 )
208         return true;
209     if( m_nDimension == 2 )
210     {
211         if( !m_bSymbol )
212             return false;
213     }
214     return true;
215 }
216 
addSeries(VDataSeries * pSeries,sal_Int32 zSlot,sal_Int32 xSlot,sal_Int32 ySlot)217 void AreaChart::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
218 {
219     if( m_bArea && !m_bIsPolarCooSys && pSeries )
220     {
221         sal_Int32 nMissingValueTreatment = pSeries->getMissingValueTreatment();
222         if( nMissingValueTreatment == ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP  )
223             pSeries->setMissingValueTreatment( ::com::sun::star::chart::MissingValueTreatment::USE_ZERO );
224     }
225     if( m_nDimension == 3 && !m_bCategoryXAxis )
226     {
227         //3D xy always deep
228         DBG_ASSERT( zSlot==-1,"3D xy charts should be deep stacked in model also" );
229         zSlot=-1;
230         xSlot=0;
231         ySlot=0;
232     }
233     VSeriesPlotter::addSeries( pSeries, zSlot, xSlot, ySlot );
234 }
235 
lcl_removeDuplicatePoints(drawing::PolyPolygonShape3D & rPolyPoly,PlottingPositionHelper & rPosHelper)236 void lcl_removeDuplicatePoints( drawing::PolyPolygonShape3D& rPolyPoly, PlottingPositionHelper& rPosHelper )
237 {
238     sal_Int32 nPolyCount = rPolyPoly.SequenceX.getLength();
239     if(!nPolyCount)
240         return;
241 
242     drawing::PolyPolygonShape3D aTmp;
243     aTmp.SequenceX.realloc(nPolyCount);
244     aTmp.SequenceY.realloc(nPolyCount);
245     aTmp.SequenceZ.realloc(nPolyCount);
246 
247     for( sal_Int32 nPolygonIndex = 0; nPolygonIndex<nPolyCount; nPolygonIndex++ )
248     {
249         drawing::DoubleSequence* pOuterSourceX = &rPolyPoly.SequenceX.getArray()[nPolygonIndex];
250         drawing::DoubleSequence* pOuterSourceY = &rPolyPoly.SequenceY.getArray()[nPolygonIndex];
251         drawing::DoubleSequence* pOuterSourceZ = &rPolyPoly.SequenceZ.getArray()[nPolygonIndex];
252 
253         drawing::DoubleSequence* pOuterTargetX = &aTmp.SequenceX.getArray()[nPolygonIndex];
254         drawing::DoubleSequence* pOuterTargetY = &aTmp.SequenceY.getArray()[nPolygonIndex];
255         drawing::DoubleSequence* pOuterTargetZ = &aTmp.SequenceZ.getArray()[nPolygonIndex];
256 
257         sal_Int32 nPointCount = pOuterSourceX->getLength();
258         if( !nPointCount )
259             continue;
260 
261         pOuterTargetX->realloc(nPointCount);
262         pOuterTargetY->realloc(nPointCount);
263         pOuterTargetZ->realloc(nPointCount);
264 
265         double* pSourceX = pOuterSourceX->getArray();
266         double* pSourceY = pOuterSourceY->getArray();
267         double* pSourceZ = pOuterSourceZ->getArray();
268 
269         double* pTargetX = pOuterTargetX->getArray();
270         double* pTargetY = pOuterTargetY->getArray();
271         double* pTargetZ = pOuterTargetZ->getArray();
272 
273         //copy first point
274         *pTargetX=*pSourceX++;
275         *pTargetY=*pSourceY++;
276         *pTargetZ=*pSourceZ++;
277         sal_Int32 nTargetPointCount=1;
278 
279         for( sal_Int32 nSource=1; nSource<nPointCount; nSource++ )
280         {
281             if( !rPosHelper.isSameForGivenResolution( *pTargetX, *pTargetY, *pTargetZ
282                                                    , *pSourceX, *pSourceY, *pSourceZ ) )
283             {
284                 pTargetX++; pTargetY++; pTargetZ++;
285                 *pTargetX=*pSourceX;
286                 *pTargetY=*pSourceY;
287                 *pTargetZ=*pSourceZ;
288                 nTargetPointCount++;
289             }
290             pSourceX++; pSourceY++; pSourceZ++;
291         }
292 
293         //free unused space
294         if( nTargetPointCount<nPointCount )
295         {
296             pOuterTargetX->realloc(nTargetPointCount);
297             pOuterTargetY->realloc(nTargetPointCount);
298             pOuterTargetZ->realloc(nTargetPointCount);
299         }
300 
301         pOuterSourceX->realloc(0);
302         pOuterSourceY->realloc(0);
303         pOuterSourceZ->realloc(0);
304     }
305 
306     //free space
307     rPolyPoly.SequenceX.realloc(nPolyCount);
308     rPolyPoly.SequenceY.realloc(nPolyCount);
309     rPolyPoly.SequenceZ.realloc(nPolyCount);
310 
311     rPolyPoly=aTmp;
312 }
313 
impl_createLine(VDataSeries * pSeries,drawing::PolyPolygonShape3D * pSeriesPoly,PlottingPositionHelper * pPosHelper)314 bool AreaChart::impl_createLine( VDataSeries* pSeries
315                 , drawing::PolyPolygonShape3D* pSeriesPoly
316                 , PlottingPositionHelper* pPosHelper )
317 {
318     //return true if a line was created successfully
319     uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget);
320 
321     drawing::PolyPolygonShape3D aPoly;
322     if(CurveStyle_CUBIC_SPLINES==m_eCurveStyle)
323     {
324         drawing::PolyPolygonShape3D aSplinePoly;
325         SplineCalculater::CalculateCubicSplines( *pSeriesPoly, aSplinePoly, m_nCurveResolution );
326         lcl_removeDuplicatePoints( aSplinePoly, *pPosHelper );
327         Clipping::clipPolygonAtRectangle( aSplinePoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
328     }
329     else if(CurveStyle_B_SPLINES==m_eCurveStyle)
330     {
331         drawing::PolyPolygonShape3D aSplinePoly;
332         SplineCalculater::CalculateBSplines( *pSeriesPoly, aSplinePoly, m_nCurveResolution, m_nSplineOrder );
333         lcl_removeDuplicatePoints( aSplinePoly, *pPosHelper );
334         Clipping::clipPolygonAtRectangle( aSplinePoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
335     }
336     else
337     {
338         bool bIsClipped = false;
339         if( m_bConnectLastToFirstPoint && !ShapeFactory::isPolygonEmptyOrSinglePoint(*pSeriesPoly) )
340         {
341             // do NOT connect last and first point, if one is NAN, and NAN handling is NAN_AS_GAP
342             double fFirstY = pSeries->getYValue( 0 );
343             double fLastY = pSeries->getYValue( VSeriesPlotter::getPointCount() - 1 );
344             if( (pSeries->getMissingValueTreatment() != ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP)
345                 || (::rtl::math::isFinite( fFirstY ) && ::rtl::math::isFinite( fLastY )) )
346             {
347                 // connect last point in last polygon with first point in first polygon
348                 ::basegfx::B2DRectangle aScaledLogicClipDoubleRect( pPosHelper->getScaledLogicClipDoubleRect() );
349                 drawing::PolyPolygonShape3D aTmpPoly(*pSeriesPoly);
350                 drawing::Position3D aLast(aScaledLogicClipDoubleRect.getMaxX(),aTmpPoly.SequenceY[0][0],aTmpPoly.SequenceZ[0][0]);
351                 // add connector line to last polygon
352                 AddPointToPoly( aTmpPoly, aLast, pSeriesPoly->SequenceX.getLength() - 1 );
353                 Clipping::clipPolygonAtRectangle( aTmpPoly, aScaledLogicClipDoubleRect, aPoly );
354                 bIsClipped = true;
355             }
356         }
357 
358         if( !bIsClipped )
359             Clipping::clipPolygonAtRectangle( *pSeriesPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
360     }
361 
362     if(!ShapeFactory::hasPolygonAnyLines(aPoly))
363         return false;
364 
365     //transformation 3) -> 4)
366     pPosHelper->transformScaledLogicToScene( aPoly );
367 
368     //create line:
369     uno::Reference< drawing::XShape > xShape(NULL);
370     if(m_nDimension==3)
371     {
372         double fDepth = this->getTransformedDepth();
373         sal_Int32 nPolyCount = aPoly.SequenceX.getLength();
374         for(sal_Int32 nPoly=0;nPoly<nPolyCount;nPoly++)
375         {
376             sal_Int32 nPointCount = aPoly.SequenceX[nPoly].getLength();
377             for(sal_Int32 nPoint=0;nPoint<nPointCount-1;nPoint++)
378             {
379                 drawing::Position3D aPoint1, aPoint2;
380                 aPoint1.PositionX = aPoly.SequenceX[nPoly][nPoint+1];
381                 aPoint1.PositionY = aPoly.SequenceY[nPoly][nPoint+1];
382                 aPoint1.PositionZ = aPoly.SequenceZ[nPoly][nPoint+1];
383 
384                 aPoint2.PositionX = aPoly.SequenceX[nPoly][nPoint];
385                 aPoint2.PositionY = aPoly.SequenceY[nPoly][nPoint];
386                 aPoint2.PositionZ = aPoly.SequenceZ[nPoly][nPoint];
387 
388                 Stripe aStripe( aPoint1, aPoint2, fDepth );
389 
390                 m_pShapeFactory->createStripe(xSeriesGroupShape_Shapes
391                     , Stripe( aPoint1, aPoint2, fDepth )
392                     , pSeries->getPropertiesOfSeries(), PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), true, 1 );
393             }
394         }
395     }
396     else //m_nDimension!=3
397     {
398         xShape = m_pShapeFactory->createLine2D( xSeriesGroupShape_Shapes
399                 , PolyToPointSequence( aPoly ) );
400 		this->setMappedProperties( xShape
401                 , pSeries->getPropertiesOfSeries()
402                 , PropertyMapper::getPropertyNameMapForLineSeriesProperties() );
403         //because of this name this line will be used for marking
404         m_pShapeFactory->setShapeName( xShape, C2U("MarkHandles") );
405     }
406     return true;
407 }
408 
impl_createArea(VDataSeries * pSeries,drawing::PolyPolygonShape3D * pSeriesPoly,drawing::PolyPolygonShape3D * pPreviousSeriesPoly,PlottingPositionHelper * pPosHelper)409 bool AreaChart::impl_createArea( VDataSeries* pSeries
410                 , drawing::PolyPolygonShape3D* pSeriesPoly
411                 , drawing::PolyPolygonShape3D* pPreviousSeriesPoly
412                 , PlottingPositionHelper* pPosHelper )
413 {
414     //return true if an area was created successfully
415 
416     uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget);
417     double zValue = pSeries->m_fLogicZPos;
418 
419     drawing::PolyPolygonShape3D aPoly( *pSeriesPoly );
420     //add second part to the polygon (grounding points or previous series points)
421     if( m_bConnectLastToFirstPoint && !ShapeFactory::isPolygonEmptyOrSinglePoint(*pSeriesPoly) )
422     {
423         if( pPreviousSeriesPoly )
424             addPolygon( aPoly, *pPreviousSeriesPoly );
425     }
426     else if(!pPreviousSeriesPoly)
427     {
428         double fMinX = pSeries->m_fLogicMinX;
429         double fMaxX = pSeries->m_fLogicMaxX;
430         double fY = pPosHelper->getBaseValueY();//logic grounding
431         if( m_nDimension==3 )
432             fY = pPosHelper->getLogicMinY();
433 
434         //clip to scale
435         if(fMaxX<pPosHelper->getLogicMinX() || fMinX>pPosHelper->getLogicMaxX())
436             return false;//no visible shape needed
437         pPosHelper->clipLogicValues( &fMinX, &fY, 0 );
438         pPosHelper->clipLogicValues( &fMaxX, 0, 0 );
439 
440         //apply scaling
441         {
442             pPosHelper->doLogicScaling( &fMinX, &fY, &zValue );
443             pPosHelper->doLogicScaling( &fMaxX, 0, 0 );
444         }
445 
446         AddPointToPoly( aPoly, drawing::Position3D( fMaxX,fY,zValue) );
447         AddPointToPoly( aPoly, drawing::Position3D( fMinX,fY,zValue) );
448     }
449     else
450     {
451         appendPoly( aPoly, *pPreviousSeriesPoly );
452     }
453     ShapeFactory::closePolygon(aPoly);
454 
455     //apply clipping
456     {
457         drawing::PolyPolygonShape3D aClippedPoly;
458         Clipping::clipPolygonAtRectangle( aPoly, pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly, false );
459         ShapeFactory::closePolygon(aClippedPoly); //again necessary after clipping
460         aPoly = aClippedPoly;
461     }
462 
463     if(!ShapeFactory::hasPolygonAnyLines(aPoly))
464         return false;
465 
466     //transformation 3) -> 4)
467     pPosHelper->transformScaledLogicToScene( aPoly );
468 
469     //create area:
470     uno::Reference< drawing::XShape > xShape(NULL);
471     if(m_nDimension==3)
472     {
473         xShape = m_pShapeFactory->createArea3D( xSeriesGroupShape_Shapes
474                 , aPoly, this->getTransformedDepth() );
475     }
476     else //m_nDimension!=3
477     {
478         xShape = m_pShapeFactory->createArea2D( xSeriesGroupShape_Shapes
479                 , aPoly );
480     }
481     this->setMappedProperties( xShape
482                 , pSeries->getPropertiesOfSeries()
483                 , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
484     //because of this name this line will be used for marking
485     m_pShapeFactory->setShapeName( xShape, C2U("MarkHandles") );
486     return true;
487 }
488 
impl_createSeriesShapes()489 void AreaChart::impl_createSeriesShapes()
490 {
491     //the polygon shapes for each series need to be created before
492 
493     //iterate through all series again to create the series shapes
494     ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator            aZSlotIter = m_aZSlots.begin();
495     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
496 //=============================================================================
497     for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; aZSlotIter++, nZ++ )
498     {
499         ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
500         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
501 
502     //=============================================================================
503         for( ; aXSlotIter != aXSlotEnd; aXSlotIter++ )
504 	    {
505             ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
506 
507             ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = pSeriesList->begin();
508             const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
509     //=============================================================================
510 
511             std::map< sal_Int32, drawing::PolyPolygonShape3D* > aPreviousSeriesPolyMap;//a PreviousSeriesPoly for each different nAttachedAxisIndex
512             drawing::PolyPolygonShape3D* pSeriesPoly = NULL;
513 
514             //iterate through all series
515 	        for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
516             {
517                 sal_Int32 nAttachedAxisIndex = (*aSeriesIter)->getAttachedAxisIndex();
518                 PlottingPositionHelper* pPosHelper = &(this->getPlottingPositionHelper( nAttachedAxisIndex ));
519                 if(!pPosHelper)
520                     pPosHelper = m_pMainPosHelper;
521                 PlotterBase::m_pPosHelper = pPosHelper;
522 
523                 createRegressionCurvesShapes( **aSeriesIter, m_xErrorBarTarget, m_xRegressionCurveEquationTarget,
524                                               m_pPosHelper->maySkipPointsInRegressionCalculation());
525 
526                 pSeriesPoly = &(*aSeriesIter)->m_aPolyPolygonShape3D;
527                 if( m_bArea )
528                 {
529                     if( !impl_createArea( *aSeriesIter, pSeriesPoly, aPreviousSeriesPolyMap[nAttachedAxisIndex], pPosHelper ) )
530                         continue;
531                 }
532                 if( m_bLine )
533                 {
534                     if( !impl_createLine( *aSeriesIter, pSeriesPoly, pPosHelper ) )
535                         continue;
536                 }
537                 aPreviousSeriesPolyMap[nAttachedAxisIndex] = pSeriesPoly;
538             }//next series in x slot (next y slot)
539         }//next x slot
540     }//next z slot
541 }
542 
543 namespace
544 {
545 
lcl_reorderSeries(::std::vector<::std::vector<VDataSeriesGroup>> & rZSlots)546 void lcl_reorderSeries( ::std::vector< ::std::vector< VDataSeriesGroup > >&  rZSlots )
547 {
548     ::std::vector< ::std::vector< VDataSeriesGroup > >  aRet( rZSlots.size() );
549 
550     ::std::vector< ::std::vector< VDataSeriesGroup > >::reverse_iterator aZIt( rZSlots.rbegin() );
551     ::std::vector< ::std::vector< VDataSeriesGroup > >::reverse_iterator aZEnd( rZSlots.rend() );
552     for( ; aZIt != aZEnd; ++aZIt )
553     {
554         ::std::vector< VDataSeriesGroup > aXSlot( aZIt->size() );
555 
556         ::std::vector< VDataSeriesGroup >::reverse_iterator aXIt( aZIt->rbegin() );
557         ::std::vector< VDataSeriesGroup >::reverse_iterator aXEnd( aZIt->rend() );
558         for( ; aXIt != aXEnd; ++aXIt )
559             aXSlot.push_back(*aXIt);
560 
561         aRet.push_back(aXSlot);
562     }
563 
564     rZSlots.clear();
565     rZSlots = aRet;
566 }
567 
568 }//anonymous namespace
569 
570 //better performance for big data
571 struct FormerPoint
572 {
FormerPointchart::FormerPoint573     FormerPoint( double fX, double fY, double fZ )
574         : m_fX(fX), m_fY(fY), m_fZ(fZ)
575         {}
FormerPointchart::FormerPoint576     FormerPoint()
577     {
578         ::rtl::math::setNan( &m_fX );
579         ::rtl::math::setNan( &m_fY );
580         ::rtl::math::setNan( &m_fZ );
581     }
582 
583     double m_fX;
584     double m_fY;
585     double m_fZ;
586 };
587 
createShapes()588 void AreaChart::createShapes()
589 {
590     if( m_aZSlots.begin() == m_aZSlots.end() ) //no series
591         return;
592 
593     if( m_nDimension == 2 && ( m_bArea || !m_bCategoryXAxis ) )
594         lcl_reorderSeries( m_aZSlots );
595 
596     DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"AreaChart is not proper initialized");
597     if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()))
598         return;
599 
600     //the text labels should be always on top of the other series shapes
601     //for area chart the error bars should be always on top of the other series shapes
602 
603     //therefore create an own group for the texts and the error bars to move them to front
604     //(because the text group is created after the series group the texts are displayed on top)
605     m_xSeriesTarget   = createGroupShape( m_xLogicTarget,rtl::OUString() );
606     if( m_bArea )
607         m_xErrorBarTarget = createGroupShape( m_xLogicTarget,rtl::OUString() );
608     else
609         m_xErrorBarTarget = m_xSeriesTarget;
610     m_xTextTarget     = m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() );
611     m_xRegressionCurveEquationTarget = m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() );
612 
613     //---------------------------------------------
614     //check necessary here that different Y axis can not be stacked in the same group? ... hm?
615 
616     //update/create information for current group
617     double fLogicZ        = 1.0;//as defined
618 
619     sal_Int32 nStartIndex = 0; // inclusive       ;..todo get somehow from x scale
620     sal_Int32 nEndIndex = VSeriesPlotter::getPointCount();
621     if(nEndIndex<=0)
622         nEndIndex=1;
623 
624     //better performance for big data
625     std::map< VDataSeries*, FormerPoint > aSeriesFormerPointMap;
626     m_bPointsWereSkipped = false;
627     sal_Int32 nSkippedPoints = 0;
628     sal_Int32 nCreatedPoints = 0;
629     //
630 
631 //=============================================================================
632     //iterate through all x values per indices
633     for( sal_Int32 nIndex = nStartIndex; nIndex < nEndIndex; nIndex++ )
634 	{
635         ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator             aZSlotIter = m_aZSlots.begin();
636         const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
637 
638         std::map< sal_Int32, double > aLogicYSumMap;//one for each different nAttachedAxisIndex
639         for( ; aZSlotIter != aZSlotEnd; aZSlotIter++ )
640         {
641             ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
642             const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
643 
644             //iterate through all x slots in this category to get 100percent sum
645             for( ; aXSlotIter != aXSlotEnd; aXSlotIter++ )
646 	        {
647                 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
648                 ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = pSeriesList->begin();
649                 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
650 
651                 for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
652                 {
653                     VDataSeries* pSeries( *aSeriesIter );
654                     if(!pSeries)
655                         continue;
656 
657                     sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex();
658                     if( aLogicYSumMap.find(nAttachedAxisIndex)==aLogicYSumMap.end() )
659                         aLogicYSumMap[nAttachedAxisIndex]=0.0;
660 
661                     PlottingPositionHelper* pPosHelper = &(this->getPlottingPositionHelper( nAttachedAxisIndex ));
662                     if(!pPosHelper)
663                         pPosHelper = m_pMainPosHelper;
664                     PlotterBase::m_pPosHelper = pPosHelper;
665 
666                     double fAdd = pSeries->getYValue( nIndex );
667                     if( !::rtl::math::isNan(fAdd) && !::rtl::math::isInf(fAdd) )
668                         aLogicYSumMap[nAttachedAxisIndex] += fabs( fAdd );
669                 }
670             }
671         }
672 
673 //=============================================================================
674         aZSlotIter = m_aZSlots.begin();
675         for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; aZSlotIter++, nZ++ )
676         {
677             ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
678             const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
679 
680             //for the area chart there should be at most one x slot (no side by side stacking available)
681             //attention different: xSlots are always interpreted as independent areas one behind the other: @todo this doesn't work why not???
682             aXSlotIter = aZSlotIter->begin();
683             for( sal_Int32 nX=0; aXSlotIter != aXSlotEnd; aXSlotIter++, nX++ )
684 	        {
685                 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
686                 ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = pSeriesList->begin();
687                 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
688 
689                 std::map< sal_Int32, double > aLogicYForNextSeriesMap;//one for each different nAttachedAxisIndex
690     //=============================================================================
691                 //iterate through all series
692                 for( sal_Int32 nSeriesIndex = 0; aSeriesIter != aSeriesEnd; aSeriesIter++, nSeriesIndex++ )
693                 {
694                     VDataSeries* pSeries( *aSeriesIter );
695                     if(!pSeries)
696                         continue;
697 
698                     /*  #i70133# ignore points outside of series length in standard area
699                         charts. Stacked area charts will use missing points as zeros. In
700                         standard charts, pSeriesList contains only one series. */
701                     if( m_bArea && (pSeriesList->size() == 1) && (nIndex >= (*aSeriesIter)->getTotalPointCount()) )
702                         continue;
703 
704                     uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShapeFrontChild(*aSeriesIter, m_xSeriesTarget);
705 
706                     sal_Int32 nAttachedAxisIndex = (*aSeriesIter)->getAttachedAxisIndex();
707                     PlottingPositionHelper* pPosHelper = &(this->getPlottingPositionHelper( nAttachedAxisIndex ));
708                     if(!pPosHelper)
709                         pPosHelper = m_pMainPosHelper;
710                     PlotterBase::m_pPosHelper = pPosHelper;
711 
712                     if(m_nDimension==3)
713                         fLogicZ = nZ+0.5;
714                     (*aSeriesIter)->m_fLogicZPos = fLogicZ;
715 
716                     //collect data point information (logic coordinates, style ):
717                     double fLogicX = (*aSeriesIter)->getXValue(nIndex);
718                     if( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() )
719                         fLogicX = DateHelper::RasterizeDateValue( fLogicX, m_aNullDate, m_nTimeResolution );
720                     double fLogicY = (*aSeriesIter)->getYValue(nIndex);
721 
722                     if( m_bIsPolarCooSys && m_bArea &&
723                         ( ::rtl::math::isNan(fLogicY) || ::rtl::math::isInf(fLogicY) ) )
724                     {
725                         if( (*aSeriesIter)->getMissingValueTreatment() == ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP )
726                         {
727                             if( pSeriesList->size() == 1 || nSeriesIndex == 0 )
728                             {
729                                 fLogicY = pPosHelper->getLogicMinY();
730                                 if( !pPosHelper->isMathematicalOrientationY() )
731                                     fLogicY = pPosHelper->getLogicMaxY();
732                             }
733                             else
734                                 fLogicY = 0.0;
735                         }
736                     }
737 
738                     if( m_nDimension==3 && m_bArea && pSeriesList->size()!=1 )
739                         fLogicY = fabs( fLogicY );
740 
741                     if( pPosHelper->isPercentY() && !::rtl::math::approxEqual( aLogicYSumMap[nAttachedAxisIndex], 0.0 ) )
742                     {
743                         fLogicY = fabs( fLogicY )/aLogicYSumMap[nAttachedAxisIndex];
744                     }
745 
746                     if(    ::rtl::math::isNan(fLogicX) || ::rtl::math::isInf(fLogicX)
747                         || ::rtl::math::isNan(fLogicY) || ::rtl::math::isInf(fLogicY)
748                         || ::rtl::math::isNan(fLogicZ) || ::rtl::math::isInf(fLogicZ) )
749                     {
750                         if( (*aSeriesIter)->getMissingValueTreatment() == ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP )
751                         {
752                             drawing::PolyPolygonShape3D& rPolygon = (*aSeriesIter)->m_aPolyPolygonShape3D;
753                             sal_Int32& rIndex = (*aSeriesIter)->m_nPolygonIndex;
754                             if( 0<= rIndex && rIndex < rPolygon.SequenceX.getLength() )
755                             {
756                                 if( rPolygon.SequenceX[ rIndex ].getLength() )
757                                     rIndex++; //start a new polygon for the next point if the current poly is not empty
758                             }
759                         }
760                         continue;
761                     }
762 
763                     if( aLogicYForNextSeriesMap.find(nAttachedAxisIndex) == aLogicYForNextSeriesMap.end() )
764                         aLogicYForNextSeriesMap[nAttachedAxisIndex] = 0.0;
765 
766                     double fLogicValueForLabeDisplay = fLogicY;
767 
768                     fLogicY += aLogicYForNextSeriesMap[nAttachedAxisIndex];
769                     aLogicYForNextSeriesMap[nAttachedAxisIndex] = fLogicY;
770 
771                     bool bIsVisible = pPosHelper->isLogicVisible( fLogicX, fLogicY, fLogicZ );
772 
773                     //remind minimal and maximal x values for area 'grounding' points
774                     //only for filled area
775                     {
776                         double& rfMinX = (*aSeriesIter)->m_fLogicMinX;
777                         if(!nIndex||fLogicX<rfMinX)
778                             rfMinX=fLogicX;
779                         double& rfMaxX = (*aSeriesIter)->m_fLogicMaxX;
780                         if(!nIndex||fLogicX>rfMaxX)
781                             rfMaxX=fLogicX;
782                     }
783 
784                     drawing::Position3D aUnscaledLogicPosition( fLogicX, fLogicY, fLogicZ );
785                     drawing::Position3D aScaledLogicPosition(aUnscaledLogicPosition);
786                     pPosHelper->doLogicScaling( aScaledLogicPosition );
787 
788                     //transformation 3) -> 4)
789                     drawing::Position3D aScenePosition( pPosHelper->transformLogicToScene( fLogicX,fLogicY,fLogicZ, false ) );
790 
791                     //better performance for big data
792                     FormerPoint aFormerPoint( aSeriesFormerPointMap[pSeries] );
793                     pPosHelper->setCoordinateSystemResolution( m_aCoordinateSystemResolution );
794                     if( !pSeries->isAttributedDataPoint(nIndex)
795                             &&
796                         pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fY, aFormerPoint.m_fZ
797                                                             , aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ ) )
798                     {
799                         nSkippedPoints++;
800                         m_bPointsWereSkipped = true;
801                         continue;
802                     }
803                     aSeriesFormerPointMap[pSeries] = FormerPoint(aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ);
804                     //
805 
806                     //store point information for series polygon
807                     //for area and/or line (symbols only do not need this)
808                     if( isValidPosition(aScaledLogicPosition) )
809                     {
810                         AddPointToPoly( (*aSeriesIter)->m_aPolyPolygonShape3D, aScaledLogicPosition, (*aSeriesIter)->m_nPolygonIndex );
811 
812                         //prepare clipping for filled net charts
813                         if( !bIsVisible && m_bIsPolarCooSys && m_bArea )
814                         {
815                             drawing::Position3D aClippedPos(aScaledLogicPosition);
816                             pPosHelper->clipScaledLogicValues( 0, &aClippedPos.PositionY, 0 );
817                             if( pPosHelper->isLogicVisible( aClippedPos.PositionX, aClippedPos.PositionY, aClippedPos.PositionZ ) )
818                             {
819                                 AddPointToPoly( (*aSeriesIter)->m_aPolyPolygonShape3D, aClippedPos, (*aSeriesIter)->m_nPolygonIndex );
820                                 AddPointToPoly( (*aSeriesIter)->m_aPolyPolygonShape3D, aScaledLogicPosition, (*aSeriesIter)->m_nPolygonIndex );
821                             }
822                         }
823                     }
824 
825                     //create a single datapoint if point is visible
826                     //apply clipping:
827                     if( !bIsVisible )
828                         continue;
829 
830                     bool bCreateErrorBar = false;
831                     {
832                         uno::Reference< beans::XPropertySet > xErrorBarProp(pSeries->getYErrorBarProperties(nIndex));
833                         if( xErrorBarProp.is() )
834                         {
835                             bool bShowPositive = false;
836                             bool bShowNegative = false;
837                             xErrorBarProp->getPropertyValue( C2U( "ShowPositiveError" )) >>= bShowPositive;
838                             xErrorBarProp->getPropertyValue( C2U( "ShowNegativeError" )) >>= bShowNegative;
839                             bCreateErrorBar = bShowPositive || bShowNegative;
840                         }
841                     }
842 
843                     Symbol* pSymbolProperties = m_bSymbol ? (*aSeriesIter)->getSymbolProperties( nIndex ) : 0;
844                     bool bCreateSymbol = pSymbolProperties && (pSymbolProperties->Style != SymbolStyle_NONE);
845 
846                     if( !bCreateSymbol && !bCreateErrorBar && !pSeries->getDataPointLabelIfLabel(nIndex) )
847                         continue;
848 
849 		            //create a group shape for this point and add to the series shape:
850                     rtl::OUString aPointCID = ObjectIdentifier::createPointCID(
851                         (*aSeriesIter)->getPointCID_Stub(), nIndex );
852 		            uno::Reference< drawing::XShapes > xPointGroupShape_Shapes(
853                         createGroupShape(xSeriesGroupShape_Shapes,aPointCID) );
854 		            uno::Reference<drawing::XShape> xPointGroupShape_Shape =
855 				            uno::Reference<drawing::XShape>( xPointGroupShape_Shapes, uno::UNO_QUERY );
856 
857                     {
858                         nCreatedPoints++;
859 
860                         //create data point
861                         drawing::Direction3D aSymbolSize(0,0,0);
862                         if( bCreateSymbol )
863                         {
864                             if(m_nDimension!=3)
865                             {
866                                 if( pSymbolProperties )
867                                 {
868                                     if( pSymbolProperties->Style != SymbolStyle_NONE )
869                                     {
870                                         aSymbolSize.DirectionX = pSymbolProperties->Size.Width;
871                                         aSymbolSize.DirectionY = pSymbolProperties->Size.Height;
872                                     }
873 
874                                     if( pSymbolProperties->Style == SymbolStyle_STANDARD )
875                                     {
876                                         sal_Int32 nSymbol = pSymbolProperties->StandardSymbol;
877                                         m_pShapeFactory->createSymbol2D( xPointGroupShape_Shapes
878                                                 , aScenePosition, aSymbolSize
879                                                 , nSymbol
880                                                 , pSymbolProperties->BorderColor
881                                                 , pSymbolProperties->FillColor );
882                                     }
883                                     else if( pSymbolProperties->Style == SymbolStyle_GRAPHIC )
884                                     {
885                                         m_pShapeFactory->createGraphic2D( xPointGroupShape_Shapes
886                                                 , aScenePosition , aSymbolSize
887                                                 , pSymbolProperties->Graphic );
888                                     }
889                                     //@todo other symbol styles
890                                 }
891                             }
892                         }
893                         //create error bar
894                         createErrorBar_Y( aUnscaledLogicPosition, **aSeriesIter, nIndex, m_xErrorBarTarget );
895 
896                         //create data point label
897                         if( (**aSeriesIter).getDataPointLabelIfLabel(nIndex) )
898                         {
899                             LabelAlignment eAlignment = LABEL_ALIGN_TOP;
900                             drawing::Position3D aScenePosition3D( aScenePosition.PositionX
901                                         , aScenePosition.PositionY
902                                         , aScenePosition.PositionZ+this->getTransformedDepth() );
903 
904                             sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nIndex, m_xChartTypeModel, m_nDimension, pPosHelper->isSwapXAndY() );
905 
906                             switch(nLabelPlacement)
907                             {
908                             case ::com::sun::star::chart::DataLabelPlacement::TOP:
909                                 aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1);
910                                 eAlignment = LABEL_ALIGN_TOP;
911                                 break;
912                             case ::com::sun::star::chart::DataLabelPlacement::BOTTOM:
913                                 aScenePosition3D.PositionY += (aSymbolSize.DirectionY/2+1);
914                                 eAlignment = LABEL_ALIGN_BOTTOM;
915                                 break;
916                             case ::com::sun::star::chart::DataLabelPlacement::LEFT:
917                                 aScenePosition3D.PositionX -= (aSymbolSize.DirectionX/2+1);
918                                 eAlignment = LABEL_ALIGN_LEFT;
919                                 break;
920                             case ::com::sun::star::chart::DataLabelPlacement::RIGHT:
921                                 aScenePosition3D.PositionX += (aSymbolSize.DirectionX/2+1);
922                                 eAlignment = LABEL_ALIGN_RIGHT;
923                                 break;
924                             case ::com::sun::star::chart::DataLabelPlacement::CENTER:
925                                 eAlignment = LABEL_ALIGN_CENTER;
926                                 //todo implement this different for area charts
927                                 break;
928                             default:
929                                 DBG_ERROR("this label alignment is not implemented yet");
930                                 aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1);
931                                 eAlignment = LABEL_ALIGN_TOP;
932                                 break;
933                             }
934 
935                             awt::Point aScreenPosition2D;//get the screen position for the labels
936                             sal_Int32 nOffset = 100; //todo maybe calculate this font height dependent
937                             if( m_bIsPolarCooSys && nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::OUTSIDE )
938                             {
939                                 PolarPlottingPositionHelper* pPolarPosHelper = dynamic_cast<PolarPlottingPositionHelper*>(pPosHelper);
940                                 if( pPolarPosHelper )
941                                 {
942                                     PolarLabelPositionHelper aPolarLabelPositionHelper(pPolarPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory);
943                                     aScreenPosition2D = awt::Point( aPolarLabelPositionHelper.getLabelScreenPositionAndAlignmentForLogicValues(
944                                         eAlignment, fLogicX, fLogicY, fLogicZ, nOffset ));
945                                 }
946                             }
947                             else
948                             {
949                                 if(LABEL_ALIGN_CENTER==eAlignment || m_nDimension == 3 )
950                                     nOffset = 0;
951                                 aScreenPosition2D = awt::Point( LabelPositionHelper(pPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory)
952                                     .transformSceneToScreenPosition( aScenePosition3D ) );
953                             }
954 
955                             this->createDataLabel( m_xTextTarget, **aSeriesIter, nIndex
956                                             , fLogicValueForLabeDisplay
957                                             , aLogicYSumMap[nAttachedAxisIndex], aScreenPosition2D, eAlignment, nOffset );
958                         }
959                     }
960 
961                     //remove PointGroupShape if empty
962                     if(!xPointGroupShape_Shapes->getCount())
963                         xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shape);
964 
965                 }//next series in x slot (next y slot)
966             }//next x slot
967         }//next z slot
968 	}//next category
969 //=============================================================================
970 //=============================================================================
971 //=============================================================================
972 
973     impl_createSeriesShapes();
974 
975     /* @todo remove series shapes if empty
976     //remove and delete point-group-shape if empty
977     if(!xSeriesGroupShape_Shapes->getCount())
978     {
979         (*aSeriesIter)->m_xShape.set(NULL);
980         m_xLogicTarget->remove(xSeriesGroupShape_Shape);
981     }
982     */
983 
984 	//remove and delete series-group-shape if empty
985 
986     //... todo
987 
988     OSL_TRACE( "\nPPPPPPPPP<<<<<<<<<<<< area chart :: createShapes():: skipped points: %d created points: %d", nSkippedPoints, nCreatedPoints );
989 }
990 
991 //.............................................................................
992 } //namespace chart
993 //.............................................................................
994