fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / chart2 / source / view / charttypes / AreaChart.cxx
blob7763f2cfe9e97e7cf8f66e2cc554a7595460550f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "AreaChart.hxx"
21 #include "PlottingPositionHelper.hxx"
22 #include "AbstractShapeFactory.hxx"
23 #include "CommonConverters.hxx"
24 #include "macros.hxx"
25 #include "ViewDefines.hxx"
26 #include "ObjectIdentifier.hxx"
27 #include "Splines.hxx"
28 #include "ChartTypeHelper.hxx"
29 #include "LabelPositionHelper.hxx"
30 #include "Clipping.hxx"
31 #include "Stripe.hxx"
32 #include "DateHelper.hxx"
33 #include <unonames.hxx>
35 #include <com/sun/star/chart2/Symbol.hpp>
36 #include <com/sun/star/chart/DataLabelPlacement.hpp>
37 #include <com/sun/star/chart/MissingValueTreatment.hpp>
39 #include <editeng/unoprnms.hxx>
40 #include <rtl/math.hxx>
42 #include <com/sun/star/drawing/DoubleSequence.hpp>
43 #include <com/sun/star/drawing/NormalsKind.hpp>
44 #include <com/sun/star/lang/XServiceName.hpp>
46 namespace chart
48 using namespace ::com::sun::star;
49 using namespace ::rtl::math;
50 using namespace ::com::sun::star::chart2;
52 AreaChart::AreaChart( const uno::Reference<XChartType>& xChartTypeModel
53 , sal_Int32 nDimensionCount
54 , bool bCategoryXAxis
55 , bool bNoArea
57 : VSeriesPlotter( xChartTypeModel, nDimensionCount, bCategoryXAxis )
58 , m_pMainPosHelper(new PlottingPositionHelper())
59 , m_bArea(!bNoArea)
60 , m_bLine(bNoArea)
61 , m_bSymbol( ChartTypeHelper::isSupportingSymbolProperties(xChartTypeModel,nDimensionCount) )
62 , m_eCurveStyle(CurveStyle_LINES)
63 , m_nCurveResolution(20)
64 , m_nSplineOrder(3)
65 , m_xSeriesTarget(0)
66 , m_xErrorBarTarget(0)
67 , m_xTextTarget(0)
68 , m_xRegressionCurveEquationTarget(0)
70 m_pMainPosHelper->AllowShiftXAxisPos(true);
71 m_pMainPosHelper->AllowShiftZAxisPos(true);
73 PlotterBase::m_pPosHelper = m_pMainPosHelper;
74 VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper;
76 try
78 if( m_xChartTypeModelProps.is() )
80 m_xChartTypeModelProps->getPropertyValue(CHART_UNONAME_CURVE_STYLE) >>= m_eCurveStyle;
81 m_xChartTypeModelProps->getPropertyValue(CHART_UNONAME_CURVE_RESOLUTION) >>= m_nCurveResolution;
82 m_xChartTypeModelProps->getPropertyValue(CHART_UNONAME_SPLINE_ORDER) >>= m_nSplineOrder;
85 catch( uno::Exception& e )
87 //the above properties are not supported by all charttypes supported by this class (e.g. area or net chart)
88 //in that cases this exception is ok
89 e.Context.is();//to have debug information without compilation warnings
93 AreaChart::~AreaChart()
95 delete m_pMainPosHelper;
98 double AreaChart::getMaximumX()
100 double fMax = VSeriesPlotter::getMaximumX();
101 return fMax;
104 bool AreaChart::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex )
106 return VSeriesPlotter::isExpandIfValuesCloseToBorder( nDimensionIndex );
109 bool AreaChart::isSeparateStackingForDifferentSigns( sal_Int32 /*nDimensionIndex*/ )
111 // no separate stacking in all types of line/area charts
112 return false;
115 LegendSymbolStyle AreaChart::getLegendSymbolStyle()
117 if( m_bArea || m_nDimension == 3 )
118 return LegendSymbolStyle_BOX;
119 return LegendSymbolStyle_LINE;
122 uno::Any AreaChart::getExplicitSymbol( const VDataSeries& rSeries, sal_Int32 nPointIndex )
124 uno::Any aRet;
126 Symbol* pSymbolProperties = rSeries.getSymbolProperties( nPointIndex );
127 if( pSymbolProperties )
129 aRet = uno::makeAny(*pSymbolProperties);
132 return aRet;
135 drawing::Direction3D AreaChart::getPreferredDiagramAspectRatio() const
137 drawing::Direction3D aRet(1,-1,1);
138 if( m_nDimension == 2 )
139 aRet = drawing::Direction3D(-1,-1,-1);
140 else if (m_pPosHelper)
142 drawing::Direction3D aScale( m_pPosHelper->getScaledLogicWidth() );
143 aRet.DirectionZ = aScale.DirectionZ*0.2;
144 if(aRet.DirectionZ>1.0)
145 aRet.DirectionZ=1.0;
146 if(aRet.DirectionZ>10)
147 aRet.DirectionZ=10;
149 return aRet;
152 bool AreaChart::keepAspectRatio() const
154 if( m_nDimension == 2 )
156 if( !m_bSymbol )
157 return false;
159 return true;
162 void AreaChart::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
164 if( m_bArea && pSeries )
166 sal_Int32 nMissingValueTreatment = pSeries->getMissingValueTreatment();
167 if( nMissingValueTreatment == ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP )
168 pSeries->setMissingValueTreatment( ::com::sun::star::chart::MissingValueTreatment::USE_ZERO );
170 if( m_nDimension == 3 && !m_bCategoryXAxis )
172 //3D xy always deep
173 OSL_ENSURE( zSlot==-1,"3D xy charts should be deep stacked in model also" );
174 zSlot=-1;
175 xSlot=0;
176 ySlot=0;
178 VSeriesPlotter::addSeries( pSeries, zSlot, xSlot, ySlot );
181 void lcl_removeDuplicatePoints( drawing::PolyPolygonShape3D& rPolyPoly, PlottingPositionHelper& rPosHelper )
183 sal_Int32 nPolyCount = rPolyPoly.SequenceX.getLength();
184 if(!nPolyCount)
185 return;
187 drawing::PolyPolygonShape3D aTmp;
188 aTmp.SequenceX.realloc(nPolyCount);
189 aTmp.SequenceY.realloc(nPolyCount);
190 aTmp.SequenceZ.realloc(nPolyCount);
192 for( sal_Int32 nPolygonIndex = 0; nPolygonIndex<nPolyCount; nPolygonIndex++ )
194 drawing::DoubleSequence* pOuterSourceX = &rPolyPoly.SequenceX.getArray()[nPolygonIndex];
195 drawing::DoubleSequence* pOuterSourceY = &rPolyPoly.SequenceY.getArray()[nPolygonIndex];
196 drawing::DoubleSequence* pOuterSourceZ = &rPolyPoly.SequenceZ.getArray()[nPolygonIndex];
198 drawing::DoubleSequence* pOuterTargetX = &aTmp.SequenceX.getArray()[nPolygonIndex];
199 drawing::DoubleSequence* pOuterTargetY = &aTmp.SequenceY.getArray()[nPolygonIndex];
200 drawing::DoubleSequence* pOuterTargetZ = &aTmp.SequenceZ.getArray()[nPolygonIndex];
202 sal_Int32 nPointCount = pOuterSourceX->getLength();
203 if( !nPointCount )
204 continue;
206 pOuterTargetX->realloc(nPointCount);
207 pOuterTargetY->realloc(nPointCount);
208 pOuterTargetZ->realloc(nPointCount);
210 double* pSourceX = pOuterSourceX->getArray();
211 double* pSourceY = pOuterSourceY->getArray();
212 double* pSourceZ = pOuterSourceZ->getArray();
214 double* pTargetX = pOuterTargetX->getArray();
215 double* pTargetY = pOuterTargetY->getArray();
216 double* pTargetZ = pOuterTargetZ->getArray();
218 //copy first point
219 *pTargetX=*pSourceX++;
220 *pTargetY=*pSourceY++;
221 *pTargetZ=*pSourceZ++;
222 sal_Int32 nTargetPointCount=1;
224 for( sal_Int32 nSource=1; nSource<nPointCount; nSource++ )
226 if( !rPosHelper.isSameForGivenResolution( *pTargetX, *pTargetY, *pTargetZ
227 , *pSourceX, *pSourceY, *pSourceZ ) )
229 pTargetX++; pTargetY++; pTargetZ++;
230 *pTargetX=*pSourceX;
231 *pTargetY=*pSourceY;
232 *pTargetZ=*pSourceZ;
233 nTargetPointCount++;
235 pSourceX++; pSourceY++; pSourceZ++;
238 //free unused space
239 if( nTargetPointCount<nPointCount )
241 pOuterTargetX->realloc(nTargetPointCount);
242 pOuterTargetY->realloc(nTargetPointCount);
243 pOuterTargetZ->realloc(nTargetPointCount);
246 pOuterSourceX->realloc(0);
247 pOuterSourceY->realloc(0);
248 pOuterSourceZ->realloc(0);
251 //free space
252 rPolyPoly.SequenceX.realloc(nPolyCount);
253 rPolyPoly.SequenceY.realloc(nPolyCount);
254 rPolyPoly.SequenceZ.realloc(nPolyCount);
256 rPolyPoly=aTmp;
259 bool AreaChart::create_stepped_line( drawing::PolyPolygonShape3D aStartPoly, chart2::CurveStyle eCurveStyle, PlottingPositionHelper* pPosHelper, drawing::PolyPolygonShape3D &aPoly )
261 drawing::PolyPolygonShape3D aSteppedPoly;
263 aSteppedPoly.SequenceX.realloc(0);
264 aSteppedPoly.SequenceY.realloc(0);
265 aSteppedPoly.SequenceZ.realloc(0);
267 sal_uInt32 nOuterCount = aStartPoly.SequenceX.getLength();
268 if ( !nOuterCount )
269 return false;
271 aSteppedPoly.SequenceX.realloc(nOuterCount);
272 aSteppedPoly.SequenceY.realloc(nOuterCount);
273 aSteppedPoly.SequenceZ.realloc(nOuterCount);
274 for( sal_uInt32 nOuter = 0; nOuter < nOuterCount; ++nOuter )
276 if( aStartPoly.SequenceX[nOuter].getLength() <= 1 )
277 continue; //we need at least two points
279 sal_uInt32 nMaxIndexPoints = aStartPoly.SequenceX[nOuter].getLength()-1; // is >1
280 sal_uInt32 nNewIndexPoints = 0;
281 if ( CurveStyle_STEP_START==eCurveStyle || CurveStyle_STEP_END==eCurveStyle)
282 nNewIndexPoints = nMaxIndexPoints * 2 + 1;
283 else
284 nNewIndexPoints = nMaxIndexPoints * 3 + 1;
286 const double* pOldX = aStartPoly.SequenceX[nOuter].getConstArray();
287 const double* pOldY = aStartPoly.SequenceY[nOuter].getConstArray();
288 const double* pOldZ = aStartPoly.SequenceZ[nOuter].getConstArray();
290 aSteppedPoly.SequenceX[nOuter].realloc( nNewIndexPoints );
291 aSteppedPoly.SequenceY[nOuter].realloc( nNewIndexPoints );
292 aSteppedPoly.SequenceZ[nOuter].realloc( nNewIndexPoints );
294 double* pNewX = aSteppedPoly.SequenceX[nOuter].getArray();
295 double* pNewY = aSteppedPoly.SequenceY[nOuter].getArray();
296 double* pNewZ = aSteppedPoly.SequenceZ[nOuter].getArray();
298 pNewX[0] = pOldX[0];
299 pNewY[0] = pOldY[0];
300 pNewZ[0] = pOldZ[0];
301 for( sal_uInt32 oi = 0; oi < nMaxIndexPoints; oi++ )
303 switch ( eCurveStyle )
305 case CurveStyle_STEP_START:
306 /** O
310 O-----+
312 // create the intermediate point
313 pNewX[1+oi*2] = pOldX[oi+1];
314 pNewY[1+oi*2] = pOldY[oi];
315 pNewZ[1+oi*2] = pOldZ[oi];
316 // and now the normal one
317 pNewX[1+oi*2+1] = pOldX[oi+1];
318 pNewY[1+oi*2+1] = pOldY[oi+1];
319 pNewZ[1+oi*2+1] = pOldZ[oi+1];
320 break;
321 case CurveStyle_STEP_END:
322 /** +------O
328 // create the intermediate point
329 pNewX[1+oi*2] = pOldX[oi];
330 pNewY[1+oi*2] = pOldY[oi+1];
331 pNewZ[1+oi*2] = pOldZ[oi];
332 // and now the normal one
333 pNewX[1+oi*2+1] = pOldX[oi+1];
334 pNewY[1+oi*2+1] = pOldY[oi+1];
335 pNewZ[1+oi*2+1] = pOldZ[oi+1];
336 break;
337 case CurveStyle_STEP_CENTER_X:
338 /** +--O
342 O--+
344 // create the first intermediate point
345 pNewX[1+oi*3] = (pOldX[oi]+pOldX[oi+1])/2;
346 pNewY[1+oi*3] = pOldY[oi];
347 pNewZ[1+oi*3] = pOldZ[oi];
348 // create the second intermediate point
349 pNewX[1+oi*3+1] = (pOldX[oi]+pOldX[oi+1])/2;
350 pNewY[1+oi*3+1] = pOldY[oi+1];
351 pNewZ[1+oi*3+1] = pOldZ[oi];
352 // and now the normal one
353 pNewX[1+oi*3+2] = pOldX[oi+1];
354 pNewY[1+oi*3+2] = pOldY[oi+1];
355 pNewZ[1+oi*3+2] = pOldZ[oi+1];
356 break;
357 case CurveStyle_STEP_CENTER_Y:
358 /** O
360 +-----+
364 // create the first intermediate point
365 pNewX[1+oi*3] = pOldX[oi];
366 pNewY[1+oi*3] = (pOldY[oi]+pOldY[oi+1])/2;
367 pNewZ[1+oi*3] = pOldZ[oi];
368 // create the second intermediate point
369 pNewX[1+oi*3+1] = pOldX[oi+1];
370 pNewY[1+oi*3+1] = (pOldY[oi]+pOldY[oi+1])/2;
371 pNewZ[1+oi*3+1] = pOldZ[oi];
372 // and now the normal one
373 pNewX[1+oi*3+2] = pOldX[oi+1];
374 pNewY[1+oi*3+2] = pOldY[oi+1];
375 pNewZ[1+oi*3+2] = pOldZ[oi+1];
376 break;
377 default:
378 // this should never be executed
379 OSL_FAIL("Unknown curvestyle in AreaChart::create_stepped_line");
383 Clipping::clipPolygonAtRectangle( aSteppedPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
385 return true;
388 bool AreaChart::impl_createLine( VDataSeries* pSeries
389 , drawing::PolyPolygonShape3D* pSeriesPoly
390 , PlottingPositionHelper* pPosHelper )
392 //return true if a line was created successfully
393 uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget);
395 drawing::PolyPolygonShape3D aPoly;
396 if(CurveStyle_CUBIC_SPLINES==m_eCurveStyle)
398 drawing::PolyPolygonShape3D aSplinePoly;
399 SplineCalculater::CalculateCubicSplines( *pSeriesPoly, aSplinePoly, m_nCurveResolution );
400 lcl_removeDuplicatePoints( aSplinePoly, *pPosHelper );
401 Clipping::clipPolygonAtRectangle( aSplinePoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
403 else if(CurveStyle_B_SPLINES==m_eCurveStyle)
405 drawing::PolyPolygonShape3D aSplinePoly;
406 SplineCalculater::CalculateBSplines( *pSeriesPoly, aSplinePoly, m_nCurveResolution, m_nSplineOrder );
407 lcl_removeDuplicatePoints( aSplinePoly, *pPosHelper );
408 Clipping::clipPolygonAtRectangle( aSplinePoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
410 else if (CurveStyle_STEP_START==m_eCurveStyle ||
411 CurveStyle_STEP_END==m_eCurveStyle ||
412 CurveStyle_STEP_CENTER_Y==m_eCurveStyle ||
413 CurveStyle_STEP_CENTER_X==m_eCurveStyle
416 if (!create_stepped_line(*pSeriesPoly, m_eCurveStyle, pPosHelper, aPoly))
418 return false;
421 else
422 { // default to creating a straight line
423 SAL_WARN_IF(CurveStyle_LINES != m_eCurveStyle, "chart2.areachart", "Unknown curve style");
424 Clipping::clipPolygonAtRectangle( *pSeriesPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
427 if(!AbstractShapeFactory::hasPolygonAnyLines(aPoly))
428 return false;
430 //transformation 3) -> 4)
431 pPosHelper->transformScaledLogicToScene( aPoly );
433 //create line:
434 uno::Reference< drawing::XShape > xShape(NULL);
435 if(m_nDimension==3)
437 double fDepth = this->getTransformedDepth();
438 sal_Int32 nPolyCount = aPoly.SequenceX.getLength();
439 for(sal_Int32 nPoly=0;nPoly<nPolyCount;nPoly++)
441 sal_Int32 nPointCount = aPoly.SequenceX[nPoly].getLength();
442 for(sal_Int32 nPoint=0;nPoint<nPointCount-1;nPoint++)
444 drawing::Position3D aPoint1, aPoint2;
445 aPoint1.PositionX = aPoly.SequenceX[nPoly][nPoint+1];
446 aPoint1.PositionY = aPoly.SequenceY[nPoly][nPoint+1];
447 aPoint1.PositionZ = aPoly.SequenceZ[nPoly][nPoint+1];
449 aPoint2.PositionX = aPoly.SequenceX[nPoly][nPoint];
450 aPoint2.PositionY = aPoly.SequenceY[nPoly][nPoint];
451 aPoint2.PositionZ = aPoly.SequenceZ[nPoly][nPoint];
453 Stripe aStripe( aPoint1, aPoint2, fDepth );
455 m_pShapeFactory->createStripe(xSeriesGroupShape_Shapes
456 , Stripe( aPoint1, aPoint2, fDepth )
457 , pSeries->getPropertiesOfSeries(), PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), true, 1 );
461 else //m_nDimension!=3
463 xShape = m_pShapeFactory->createLine2D( xSeriesGroupShape_Shapes
464 , PolyToPointSequence( aPoly ) );
465 setMappedProperties( xShape
466 , pSeries->getPropertiesOfSeries()
467 , PropertyMapper::getPropertyNameMapForLineSeriesProperties() );
468 //because of this name this line will be used for marking
469 ::chart::AbstractShapeFactory::setShapeName(xShape, "MarkHandles");
471 return true;
474 bool AreaChart::impl_createArea( VDataSeries* pSeries
475 , drawing::PolyPolygonShape3D* pSeriesPoly
476 , drawing::PolyPolygonShape3D* pPreviousSeriesPoly
477 , PlottingPositionHelper* pPosHelper )
479 //return true if an area was created successfully
481 uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget);
482 double zValue = pSeries->m_fLogicZPos;
484 drawing::PolyPolygonShape3D aPoly( *pSeriesPoly );
485 //add second part to the polygon (grounding points or previous series points)
486 if(!pPreviousSeriesPoly)
488 double fMinX = pSeries->m_fLogicMinX;
489 double fMaxX = pSeries->m_fLogicMaxX;
490 double fY = pPosHelper->getBaseValueY();//logic grounding
491 if( m_nDimension==3 )
492 fY = pPosHelper->getLogicMinY();
494 //clip to scale
495 if(fMaxX<pPosHelper->getLogicMinX() || fMinX>pPosHelper->getLogicMaxX())
496 return false;//no visible shape needed
497 pPosHelper->clipLogicValues( &fMinX, &fY, 0 );
498 pPosHelper->clipLogicValues( &fMaxX, 0, 0 );
500 //apply scaling
502 pPosHelper->doLogicScaling( &fMinX, &fY, &zValue );
503 pPosHelper->doLogicScaling( &fMaxX, 0, 0 );
506 AddPointToPoly( aPoly, drawing::Position3D( fMaxX,fY,zValue) );
507 AddPointToPoly( aPoly, drawing::Position3D( fMinX,fY,zValue) );
509 else
511 appendPoly( aPoly, *pPreviousSeriesPoly );
513 AbstractShapeFactory::closePolygon(aPoly);
515 //apply clipping
517 drawing::PolyPolygonShape3D aClippedPoly;
518 Clipping::clipPolygonAtRectangle( aPoly, pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly, false );
519 AbstractShapeFactory::closePolygon(aClippedPoly); //again necessary after clipping
520 aPoly = aClippedPoly;
523 if(!AbstractShapeFactory::hasPolygonAnyLines(aPoly))
524 return false;
526 //transformation 3) -> 4)
527 pPosHelper->transformScaledLogicToScene( aPoly );
529 //create area:
530 uno::Reference< drawing::XShape > xShape(NULL);
531 if(m_nDimension==3)
533 xShape = m_pShapeFactory->createArea3D( xSeriesGroupShape_Shapes
534 , aPoly, this->getTransformedDepth() );
536 else //m_nDimension!=3
538 xShape = m_pShapeFactory->createArea2D( xSeriesGroupShape_Shapes
539 , aPoly );
541 setMappedProperties( xShape
542 , pSeries->getPropertiesOfSeries()
543 , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
544 //because of this name this line will be used for marking
545 ::chart::AbstractShapeFactory::setShapeName(xShape, "MarkHandles");
546 return true;
549 void AreaChart::impl_createSeriesShapes()
551 //the polygon shapes for each series need to be created before
553 //iterate through all series again to create the series shapes
554 ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
555 const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
556 for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; ++aZSlotIter, ++nZ )
558 ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
559 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
561 for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
563 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
565 ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
566 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
568 std::map< sal_Int32, drawing::PolyPolygonShape3D* > aPreviousSeriesPolyMap;//a PreviousSeriesPoly for each different nAttachedAxisIndex
569 drawing::PolyPolygonShape3D* pSeriesPoly = NULL;
571 //iterate through all series
572 for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
574 sal_Int32 nAttachedAxisIndex = (*aSeriesIter)->getAttachedAxisIndex();
575 PlottingPositionHelper* pPosHelper = &(this->getPlottingPositionHelper( nAttachedAxisIndex ));
576 if(!pPosHelper)
577 pPosHelper = m_pMainPosHelper;
578 PlotterBase::m_pPosHelper = pPosHelper;
580 createRegressionCurvesShapes( **aSeriesIter, m_xErrorBarTarget, m_xRegressionCurveEquationTarget,
581 m_pPosHelper->maySkipPointsInRegressionCalculation());
583 pSeriesPoly = &(*aSeriesIter)->m_aPolyPolygonShape3D;
584 if( m_bArea )
586 if( !impl_createArea( *aSeriesIter, pSeriesPoly, aPreviousSeriesPolyMap[nAttachedAxisIndex], pPosHelper ) )
587 continue;
589 if( m_bLine )
591 if( !impl_createLine( *aSeriesIter, pSeriesPoly, pPosHelper ) )
592 continue;
594 aPreviousSeriesPolyMap[nAttachedAxisIndex] = pSeriesPoly;
595 }//next series in x slot (next y slot)
596 }//next x slot
597 }//next z slot
600 namespace
603 void lcl_reorderSeries( ::std::vector< ::std::vector< VDataSeriesGroup > >& rZSlots )
605 ::std::vector< ::std::vector< VDataSeriesGroup > > aRet( rZSlots.size() );
607 ::std::vector< ::std::vector< VDataSeriesGroup > >::reverse_iterator aZIt( rZSlots.rbegin() );
608 ::std::vector< ::std::vector< VDataSeriesGroup > >::reverse_iterator aZEnd( rZSlots.rend() );
609 for( ; aZIt != aZEnd; ++aZIt )
611 ::std::vector< VDataSeriesGroup > aXSlot( aZIt->size() );
613 ::std::vector< VDataSeriesGroup >::reverse_iterator aXIt( aZIt->rbegin() );
614 ::std::vector< VDataSeriesGroup >::reverse_iterator aXEnd( aZIt->rend() );
615 for( ; aXIt != aXEnd; ++aXIt )
616 aXSlot.push_back(*aXIt);
618 aRet.push_back(aXSlot);
621 rZSlots.clear();
622 rZSlots = aRet;
625 }//anonymous namespace
627 //better performance for big data
628 struct FormerPoint
630 FormerPoint( double fX, double fY, double fZ )
631 : m_fX(fX), m_fY(fY), m_fZ(fZ)
633 FormerPoint()
635 ::rtl::math::setNan( &m_fX );
636 ::rtl::math::setNan( &m_fY );
637 ::rtl::math::setNan( &m_fZ );
640 double m_fX;
641 double m_fY;
642 double m_fZ;
645 void AreaChart::createShapes()
647 if( m_aZSlots.begin() == m_aZSlots.end() ) //no series
648 return;
650 if( m_nDimension == 2 && ( m_bArea || !m_bCategoryXAxis ) )
651 lcl_reorderSeries( m_aZSlots );
653 OSL_ENSURE(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"AreaChart is not proper initialized");
654 if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()))
655 return;
657 //the text labels should be always on top of the other series shapes
658 //for area chart the error bars should be always on top of the other series shapes
660 //therefore create an own group for the texts and the error bars to move them to front
661 //(because the text group is created after the series group the texts are displayed on top)
662 m_xSeriesTarget = createGroupShape( m_xLogicTarget,OUString() );
663 if( m_bArea )
664 m_xErrorBarTarget = createGroupShape( m_xLogicTarget,OUString() );
665 else
666 m_xErrorBarTarget = m_xSeriesTarget;
667 m_xTextTarget = m_pShapeFactory->createGroup2D( m_xFinalTarget,OUString() );
668 m_xRegressionCurveEquationTarget = m_pShapeFactory->createGroup2D( m_xFinalTarget,OUString() );
670 //check necessary here that different Y axis can not be stacked in the same group? ... hm?
672 //update/create information for current group
673 double fLogicZ = 1.0;//as defined
675 sal_Int32 nStartIndex = 0; // inclusive ;..todo get somehow from x scale
676 sal_Int32 nEndIndex = VSeriesPlotter::getPointCount();
677 if(nEndIndex<=0)
678 nEndIndex=1;
680 //better performance for big data
681 std::map< VDataSeries*, FormerPoint > aSeriesFormerPointMap;
682 m_bPointsWereSkipped = false;
683 sal_Int32 nSkippedPoints = 0;
684 sal_Int32 nCreatedPoints = 0;
686 bool bDateCategory = (m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis());
688 ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
689 const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
691 std::vector<std::map< sal_Int32, double > > aLogicYSumMapByX(nEndIndex);//one for each different nAttachedAxisIndex
692 for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
694 ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
695 const ::std::vector< VDataSeriesGroup >::iterator aXSlotEnd = aZSlotIter->end();
697 //iterate through all x slots in this category to get 100percent sum
698 for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
700 std::vector<VDataSeries*>& rSeriesList = aXSlotIter->m_aSeriesVector;
701 std::vector<VDataSeries*>::iterator aSeriesIter = rSeriesList.begin();
702 std::vector<VDataSeries*>::iterator aSeriesEnd = rSeriesList.end();
704 for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
706 VDataSeries* pSeries( *aSeriesIter );
707 if(!pSeries)
708 continue;
710 if (bDateCategory)
711 pSeries->doSortByXValues();
713 for( sal_Int32 nIndex = nStartIndex; nIndex < nEndIndex; nIndex++ )
715 std::map< sal_Int32, double >& rLogicYSumMap = aLogicYSumMapByX[nIndex];
716 sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex();
717 if( rLogicYSumMap.find(nAttachedAxisIndex)==rLogicYSumMap.end() )
718 rLogicYSumMap[nAttachedAxisIndex]=0.0;
720 PlottingPositionHelper* pPosHelper = &(this->getPlottingPositionHelper( nAttachedAxisIndex ));
721 if(!pPosHelper)
722 pPosHelper = m_pMainPosHelper;
723 PlotterBase::m_pPosHelper = pPosHelper;
725 double fAdd = pSeries->getYValue( nIndex );
726 if( !::rtl::math::isNan(fAdd) && !::rtl::math::isInf(fAdd) )
727 rLogicYSumMap[nAttachedAxisIndex] += fabs( fAdd );
733 aZSlotIter = m_aZSlots.begin();
734 for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; ++aZSlotIter, ++nZ )
736 ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
737 ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
739 //for the area chart there should be at most one x slot (no side by side stacking available)
740 //attention different: xSlots are always interpreted as independent areas one behind the other: @todo this doesn't work why not???
741 for( sal_Int32 nX=0; aXSlotIter != aXSlotEnd; ++aXSlotIter, ++nX )
743 const std::vector<VDataSeries*>& rSeriesList = aXSlotIter->m_aSeriesVector;
744 std::vector<VDataSeries*>::const_iterator aSeriesIter = rSeriesList.begin();
745 const std::vector<VDataSeries*>::const_iterator aSeriesEnd = rSeriesList.end();
747 std::vector<std::map< sal_Int32, double > > aLogicYForNextSeriesMapByX(nEndIndex); //one for each different nAttachedAxisIndex
748 //iterate through all series
749 for( sal_Int32 nSeriesIndex = 0; aSeriesIter != aSeriesEnd; ++aSeriesIter, ++nSeriesIndex )
751 VDataSeries* pSeries( *aSeriesIter );
752 if(!pSeries)
753 continue;
755 uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShapeFrontChild(*aSeriesIter, m_xSeriesTarget);
757 sal_Int32 nAttachedAxisIndex = (*aSeriesIter)->getAttachedAxisIndex();
758 PlottingPositionHelper* pPosHelper = &(this->getPlottingPositionHelper( nAttachedAxisIndex ));
759 if(!pPosHelper)
760 pPosHelper = m_pMainPosHelper;
761 PlotterBase::m_pPosHelper = pPosHelper;
763 if(m_nDimension==3)
764 fLogicZ = nZ+0.5;
765 (*aSeriesIter)->m_fLogicZPos = fLogicZ;
767 for( sal_Int32 nIndex = nStartIndex; nIndex < nEndIndex; nIndex++ )
770 /* #i70133# ignore points outside of series length in standard area
771 charts. Stacked area charts will use missing points as zeros. In
772 standard charts, pSeriesList contains only one series. */
773 if( m_bArea && (rSeriesList.size() == 1) && (nIndex >= (*aSeriesIter)->getTotalPointCount()) )
774 continue;
776 //collect data point information (logic coordinates, style ):
777 double fLogicX = (*aSeriesIter)->getXValue(nIndex);
778 if (bDateCategory)
779 fLogicX = DateHelper::RasterizeDateValue( fLogicX, m_aNullDate, m_nTimeResolution );
780 double fLogicY = (*aSeriesIter)->getYValue(nIndex);
782 if( m_nDimension==3 && m_bArea && rSeriesList.size()!=1 )
783 fLogicY = fabs( fLogicY );
785 std::map< sal_Int32, double >& rLogicYSumMap = aLogicYSumMapByX[nIndex];
786 if( pPosHelper->isPercentY() && !::rtl::math::approxEqual( rLogicYSumMap[nAttachedAxisIndex], 0.0 ) )
788 fLogicY = fabs( fLogicY )/rLogicYSumMap[nAttachedAxisIndex];
791 if( ::rtl::math::isNan(fLogicX) || ::rtl::math::isInf(fLogicX)
792 || ::rtl::math::isNan(fLogicY) || ::rtl::math::isInf(fLogicY)
793 || ::rtl::math::isNan(fLogicZ) || ::rtl::math::isInf(fLogicZ) )
795 if( (*aSeriesIter)->getMissingValueTreatment() == ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP )
797 drawing::PolyPolygonShape3D& rPolygon = (*aSeriesIter)->m_aPolyPolygonShape3D;
798 sal_Int32& rIndex = (*aSeriesIter)->m_nPolygonIndex;
799 if( 0<= rIndex && rIndex < rPolygon.SequenceX.getLength() )
801 if( rPolygon.SequenceX[ rIndex ].getLength() )
802 rIndex++; //start a new polygon for the next point if the current poly is not empty
805 continue;
808 std::map< sal_Int32, double >& rLogicYForNextSeriesMap = aLogicYForNextSeriesMapByX[nIndex];
809 if( rLogicYForNextSeriesMap.find(nAttachedAxisIndex) == rLogicYForNextSeriesMap.end() )
810 rLogicYForNextSeriesMap[nAttachedAxisIndex] = 0.0;
812 double fLogicValueForLabeDisplay = fLogicY;
814 fLogicY += rLogicYForNextSeriesMap[nAttachedAxisIndex];
815 rLogicYForNextSeriesMap[nAttachedAxisIndex] = fLogicY;
817 bool bIsVisible = pPosHelper->isLogicVisible( fLogicX, fLogicY, fLogicZ );
819 //remind minimal and maximal x values for area 'grounding' points
820 //only for filled area
822 double& rfMinX = (*aSeriesIter)->m_fLogicMinX;
823 if(!nIndex||fLogicX<rfMinX)
824 rfMinX=fLogicX;
825 double& rfMaxX = (*aSeriesIter)->m_fLogicMaxX;
826 if(!nIndex||fLogicX>rfMaxX)
827 rfMaxX=fLogicX;
830 drawing::Position3D aUnscaledLogicPosition( fLogicX, fLogicY, fLogicZ );
831 drawing::Position3D aScaledLogicPosition(aUnscaledLogicPosition);
832 pPosHelper->doLogicScaling( aScaledLogicPosition );
834 //transformation 3) -> 4)
835 drawing::Position3D aScenePosition( pPosHelper->transformLogicToScene( fLogicX,fLogicY,fLogicZ, false ) );
837 //better performance for big data
838 FormerPoint aFormerPoint( aSeriesFormerPointMap[pSeries] );
839 pPosHelper->setCoordinateSystemResolution( m_aCoordinateSystemResolution );
840 if( !pSeries->isAttributedDataPoint(nIndex)
842 pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fY, aFormerPoint.m_fZ
843 , aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ ) )
845 ++nSkippedPoints;
846 m_bPointsWereSkipped = true;
847 continue;
849 aSeriesFormerPointMap[pSeries] = FormerPoint(aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ);
851 //store point information for series polygon
852 //for area and/or line (symbols only do not need this)
853 if( isValidPosition(aScaledLogicPosition) )
855 AddPointToPoly( (*aSeriesIter)->m_aPolyPolygonShape3D, aScaledLogicPosition, (*aSeriesIter)->m_nPolygonIndex );
858 //create a single datapoint if point is visible
859 //apply clipping:
860 if( !bIsVisible )
861 continue;
863 bool bCreateYErrorBar = false, bCreateXErrorBar = false;
865 uno::Reference< beans::XPropertySet > xErrorBarProp(pSeries->getYErrorBarProperties(nIndex));
866 if( xErrorBarProp.is() )
868 bool bShowPositive = false;
869 bool bShowNegative = false;
870 xErrorBarProp->getPropertyValue("ShowPositiveError") >>= bShowPositive;
871 xErrorBarProp->getPropertyValue("ShowNegativeError") >>= bShowNegative;
872 bCreateYErrorBar = bShowPositive || bShowNegative;
875 xErrorBarProp = pSeries->getXErrorBarProperties(nIndex);
876 if ( xErrorBarProp.is() )
878 bool bShowPositive = false;
879 bool bShowNegative = false;
880 xErrorBarProp->getPropertyValue("ShowPositiveError") >>= bShowPositive;
881 xErrorBarProp->getPropertyValue("ShowNegativeError") >>= bShowNegative;
882 bCreateXErrorBar = bShowPositive || bShowNegative;
886 Symbol* pSymbolProperties = m_bSymbol ? (*aSeriesIter)->getSymbolProperties( nIndex ) : 0;
887 bool bCreateSymbol = pSymbolProperties && (pSymbolProperties->Style != SymbolStyle_NONE);
889 if( !bCreateSymbol && !bCreateYErrorBar &&
890 !bCreateXErrorBar && !pSeries->getDataPointLabelIfLabel(nIndex) )
891 continue;
893 //create a group shape for this point and add to the series shape:
894 OUString aPointCID = ObjectIdentifier::createPointCID(
895 (*aSeriesIter)->getPointCID_Stub(), nIndex );
896 uno::Reference< drawing::XShapes > xPointGroupShape_Shapes(
897 createGroupShape(xSeriesGroupShape_Shapes,aPointCID) );
898 uno::Reference<drawing::XShape> xPointGroupShape_Shape =
899 uno::Reference<drawing::XShape>( xPointGroupShape_Shapes, uno::UNO_QUERY );
902 nCreatedPoints++;
904 //create data point
905 drawing::Direction3D aSymbolSize(0,0,0);
906 if( bCreateSymbol )
908 if(m_nDimension!=3)
910 if( pSymbolProperties )
912 if( pSymbolProperties->Style != SymbolStyle_NONE )
914 aSymbolSize.DirectionX = pSymbolProperties->Size.Width;
915 aSymbolSize.DirectionY = pSymbolProperties->Size.Height;
918 if( pSymbolProperties->Style == SymbolStyle_STANDARD )
920 sal_Int32 nSymbol = pSymbolProperties->StandardSymbol;
921 m_pShapeFactory->createSymbol2D( xPointGroupShape_Shapes
922 , aScenePosition, aSymbolSize
923 , nSymbol
924 , pSymbolProperties->BorderColor
925 , pSymbolProperties->FillColor );
927 else if( pSymbolProperties->Style == SymbolStyle_GRAPHIC )
929 m_pShapeFactory->createGraphic2D( xPointGroupShape_Shapes
930 , aScenePosition , aSymbolSize
931 , pSymbolProperties->Graphic );
933 //@todo other symbol styles
937 //create error bars
938 if (bCreateXErrorBar)
939 createErrorBar_X( aUnscaledLogicPosition, **aSeriesIter, nIndex, m_xErrorBarTarget );
941 if (bCreateYErrorBar)
942 createErrorBar_Y( aUnscaledLogicPosition, **aSeriesIter, nIndex, m_xErrorBarTarget );
944 //create data point label
945 if( (**aSeriesIter).getDataPointLabelIfLabel(nIndex) )
947 LabelAlignment eAlignment = LABEL_ALIGN_TOP;
948 drawing::Position3D aScenePosition3D( aScenePosition.PositionX
949 , aScenePosition.PositionY
950 , aScenePosition.PositionZ+this->getTransformedDepth() );
952 sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nIndex, m_xChartTypeModel, m_nDimension, pPosHelper->isSwapXAndY() );
954 switch(nLabelPlacement)
956 case ::com::sun::star::chart::DataLabelPlacement::TOP:
957 aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1);
958 eAlignment = LABEL_ALIGN_TOP;
959 break;
960 case ::com::sun::star::chart::DataLabelPlacement::BOTTOM:
961 aScenePosition3D.PositionY += (aSymbolSize.DirectionY/2+1);
962 eAlignment = LABEL_ALIGN_BOTTOM;
963 break;
964 case ::com::sun::star::chart::DataLabelPlacement::LEFT:
965 aScenePosition3D.PositionX -= (aSymbolSize.DirectionX/2+1);
966 eAlignment = LABEL_ALIGN_LEFT;
967 break;
968 case ::com::sun::star::chart::DataLabelPlacement::RIGHT:
969 aScenePosition3D.PositionX += (aSymbolSize.DirectionX/2+1);
970 eAlignment = LABEL_ALIGN_RIGHT;
971 break;
972 case ::com::sun::star::chart::DataLabelPlacement::CENTER:
973 eAlignment = LABEL_ALIGN_CENTER;
974 //todo implement this different for area charts
975 break;
976 default:
977 OSL_FAIL("this label alignment is not implemented yet");
978 aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1);
979 eAlignment = LABEL_ALIGN_TOP;
980 break;
983 awt::Point aScreenPosition2D;//get the screen position for the labels
984 sal_Int32 nOffset = 100; //todo maybe calculate this font height dependent
986 if(LABEL_ALIGN_CENTER==eAlignment || m_nDimension == 3 )
987 nOffset = 0;
988 aScreenPosition2D = awt::Point( LabelPositionHelper(pPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory)
989 .transformSceneToScreenPosition( aScenePosition3D ) );
992 createDataLabel( m_xTextTarget, **aSeriesIter, nIndex
993 , fLogicValueForLabeDisplay
994 , rLogicYSumMap[nAttachedAxisIndex], aScreenPosition2D, eAlignment, nOffset );
998 //remove PointGroupShape if empty
999 if(!xPointGroupShape_Shapes->getCount())
1000 xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shape);
1003 }//next series in x slot (next y slot)
1004 }//next x slot
1005 }//next z slot
1007 impl_createSeriesShapes();
1009 /* @todo remove series shapes if empty
1010 //remove and delete point-group-shape if empty
1011 if(!xSeriesGroupShape_Shapes->getCount())
1013 (*aSeriesIter)->m_xShape.set(NULL);
1014 m_xLogicTarget->remove(xSeriesGroupShape_Shape);
1018 //remove and delete series-group-shape if empty
1020 //... todo
1022 SAL_INFO(
1023 "chart2",
1024 "skipped points: " << nSkippedPoints << " created points: "
1025 << nCreatedPoints);
1028 } //namespace chart
1030 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */