bump product version to 4.1.6.2
[LibreOffice.git] / chart2 / source / view / charttypes / VSeriesPlotter.cxx
blobd9041f9503dbec2d1fba4bf8e381d7206b93808d
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 "VSeriesPlotter.hxx"
21 #include "ShapeFactory.hxx"
22 #include "chartview/ExplicitValueProvider.hxx"
24 #include "CommonConverters.hxx"
25 #include "macros.hxx"
26 #include "ViewDefines.hxx"
27 #include "ObjectIdentifier.hxx"
28 #include "StatisticsHelper.hxx"
29 #include "PlottingPositionHelper.hxx"
30 #include "LabelPositionHelper.hxx"
31 #include "ChartTypeHelper.hxx"
32 #include "Clipping.hxx"
33 #include "servicenames_charttypes.hxx"
34 #include "NumberFormatterWrapper.hxx"
35 #include "ContainerHelper.hxx"
36 #include "DataSeriesHelper.hxx"
37 #include "RegressionCurveHelper.hxx"
38 #include "VLegendSymbolFactory.hxx"
39 #include "FormattedStringHelper.hxx"
40 #include "ResId.hxx"
41 #include "Strings.hrc"
42 #include "RelativePositionHelper.hxx"
43 #include "DateHelper.hxx"
44 #include "DiagramHelper.hxx"
45 #include "defines.hxx"
47 //only for creation: @todo remove if all plotter are uno components and instanciated via servicefactory
48 #include "BarChart.hxx"
49 #include "PieChart.hxx"
50 #include "AreaChart.hxx"
51 #include "CandleStickChart.hxx"
52 #include "BubbleChart.hxx"
55 #include <com/sun/star/chart/ErrorBarStyle.hpp>
56 #include <com/sun/star/chart/TimeUnit.hpp>
57 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
58 #include <com/sun/star/container/XChild.hpp>
59 #include <com/sun/star/chart2/RelativePosition.hpp>
60 #include <editeng/unoprnms.hxx>
61 #include <tools/color.hxx>
62 // header for class OUStringBuffer
63 #include <rtl/ustrbuf.hxx>
64 #include <rtl/math.hxx>
65 #include <basegfx/vector/b2dvector.hxx>
66 #include <com/sun/star/drawing/LineStyle.hpp>
67 #include <com/sun/star/util/XCloneable.hpp>
69 #include <svx/unoshape.hxx>
71 #include <functional>
72 #include <map>
74 #include <boost/ptr_container/ptr_map.hpp>
76 namespace chart {
78 using namespace ::com::sun::star;
79 using namespace ::com::sun::star::chart2;
80 using ::com::sun::star::uno::Reference;
81 using ::com::sun::star::uno::Sequence;
83 //-----------------------------------------------------------------------------
85 VDataSeriesGroup::CachedYValues::CachedYValues()
86 : m_bValuesDirty(true)
87 , m_fMinimumY(0.0)
88 , m_fMaximumY(0.0)
92 VDataSeriesGroup::VDataSeriesGroup()
93 : m_aSeriesVector()
94 , m_bMaxPointCountDirty(true)
95 , m_nMaxPointCount(0)
96 , m_aListOfCachedYValues()
100 VDataSeriesGroup::VDataSeriesGroup( VDataSeries* pSeries )
101 : m_aSeriesVector(1,pSeries)
102 , m_bMaxPointCountDirty(true)
103 , m_nMaxPointCount(0)
104 , m_aListOfCachedYValues()
108 VDataSeriesGroup::~VDataSeriesGroup()
112 void VDataSeriesGroup::deleteSeries()
114 //delete all data series help objects:
115 ::std::vector< VDataSeries* >::const_iterator aIter = m_aSeriesVector.begin();
116 const ::std::vector< VDataSeries* >::const_iterator aEnd = m_aSeriesVector.end();
117 for( ; aIter != aEnd; ++aIter )
119 delete *aIter;
121 m_aSeriesVector.clear();
124 void VDataSeriesGroup::addSeries( VDataSeries* pSeries )
126 m_aSeriesVector.push_back(pSeries);
127 m_bMaxPointCountDirty=true;
130 sal_Int32 VDataSeriesGroup::getSeriesCount() const
132 return m_aSeriesVector.size();
135 //-----------------------------------------------------------------------------
137 VSeriesPlotter::VSeriesPlotter( const uno::Reference<XChartType>& xChartTypeModel
138 , sal_Int32 nDimensionCount, bool bCategoryXAxis )
139 : PlotterBase( nDimensionCount )
140 , m_pMainPosHelper( 0 )
141 , m_xChartTypeModel(xChartTypeModel)
142 , m_xChartTypeModelProps( uno::Reference< beans::XPropertySet >::query( xChartTypeModel ))
143 , m_aZSlots()
144 , m_bCategoryXAxis(bCategoryXAxis)
145 , m_nTimeResolution(::com::sun::star::chart::TimeUnit::DAY)
146 , m_aNullDate(30,12,1899)
147 , m_xColorScheme()
148 , m_pExplicitCategoriesProvider(0)
149 , m_bPointsWereSkipped(false)
151 OSL_POSTCOND(m_xChartTypeModel.is(),"no XChartType available in view, fallback to default values may be wrong");
154 VSeriesPlotter::~VSeriesPlotter()
156 //delete all data series help objects:
157 ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
158 const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
159 for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
161 ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
162 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
163 for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
165 aXSlotIter->deleteSeries();
167 aZSlotIter->clear();
169 m_aZSlots.clear();
171 tSecondaryPosHelperMap::iterator aPosIt = m_aSecondaryPosHelperMap.begin();
172 while( aPosIt != m_aSecondaryPosHelperMap.end() )
174 PlottingPositionHelper* pPosHelper = aPosIt->second;
175 if( pPosHelper )
176 delete pPosHelper;
177 ++aPosIt;
179 m_aSecondaryPosHelperMap.clear();
181 m_aSecondaryValueScales.clear();
184 void VSeriesPlotter::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
186 //take ownership of pSeries
188 OSL_PRECOND( pSeries, "series to add is NULL" );
189 if(!pSeries)
190 return;
192 if(m_bCategoryXAxis)
194 if( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() )
195 pSeries->setXValues( m_pExplicitCategoriesProvider->getOriginalCategories() );
196 else
197 pSeries->setCategoryXAxis();
199 else
201 if( m_pExplicitCategoriesProvider )
202 pSeries->setXValuesIfNone( m_pExplicitCategoriesProvider->getOriginalCategories() );
205 if(zSlot<0 || zSlot>=static_cast<sal_Int32>(m_aZSlots.size()))
207 //new z slot
208 ::std::vector< VDataSeriesGroup > aZSlot;
209 aZSlot.push_back( VDataSeriesGroup(pSeries) );
210 m_aZSlots.push_back( aZSlot );
212 else
214 //existing zslot
215 ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[zSlot];
217 if(xSlot<0 || xSlot>=static_cast<sal_Int32>(rXSlots.size()))
219 //append the series to already existing x series
220 rXSlots.push_back( VDataSeriesGroup(pSeries) );
222 else
224 //x slot is already occupied
225 //y slot decides what to do:
227 VDataSeriesGroup& rYSlots = rXSlots[xSlot];
228 sal_Int32 nYSlotCount = rYSlots.getSeriesCount();
230 if( ySlot < -1 )
232 //move all existing series in the xSlot to next slot
233 //@todo
234 OSL_FAIL( "Not implemented yet");
236 else if( ySlot == -1 || ySlot >= nYSlotCount)
238 //append the series to already existing y series
239 rYSlots.addSeries(pSeries);
241 else
243 //y slot is already occupied
244 //insert at given y and x position
246 //@todo
247 OSL_FAIL( "Not implemented yet");
253 drawing::Direction3D VSeriesPlotter::getPreferredDiagramAspectRatio() const
255 drawing::Direction3D aRet(1.0,1.0,1.0);
256 drawing::Direction3D aScale( m_pPosHelper->getScaledLogicWidth() );
257 aRet.DirectionZ = aScale.DirectionZ*0.2;
258 if(aRet.DirectionZ>1.0)
259 aRet.DirectionZ=1.0;
260 if(aRet.DirectionZ>10)
261 aRet.DirectionZ=10;
262 return aRet;
265 bool VSeriesPlotter::keepAspectRatio() const
267 return true;
270 void VSeriesPlotter::releaseShapes()
272 ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
273 const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
274 for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
276 ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
277 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
278 for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
280 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
282 ::std::vector< VDataSeries* >::iterator aSeriesIter = pSeriesList->begin();
283 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
285 //iterate through all series in this x slot
286 for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
288 VDataSeries* pSeries( *aSeriesIter );
289 pSeries->releaseShapes();
295 uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShape( VDataSeries* pDataSeries
296 , const uno::Reference< drawing::XShapes >& xTarget )
298 uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xGroupShape );
299 if( !xShapes.is() )
301 //create a group shape for this series and add to logic target:
302 xShapes = createGroupShape( xTarget,pDataSeries->getCID() );
303 pDataSeries->m_xGroupShape = xShapes;
305 return xShapes;
308 uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShapeFrontChild( VDataSeries* pDataSeries
309 , const uno::Reference< drawing::XShapes >& xTarget )
311 uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xFrontSubGroupShape );
312 if(!xShapes.is())
314 //ensure that the series group shape is already created
315 uno::Reference< drawing::XShapes > xSeriesShapes( this->getSeriesGroupShape( pDataSeries, xTarget ) );
316 //ensure that the back child is created first
317 this->getSeriesGroupShapeBackChild( pDataSeries, xTarget );
318 //use series group shape as parent for the new created front group shape
319 xShapes = createGroupShape( xSeriesShapes );
320 pDataSeries->m_xFrontSubGroupShape = xShapes;
322 return xShapes;
325 uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShapeBackChild( VDataSeries* pDataSeries
326 , const uno::Reference< drawing::XShapes >& xTarget )
328 uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xBackSubGroupShape );
329 if(!xShapes.is())
331 //ensure that the series group shape is already created
332 uno::Reference< drawing::XShapes > xSeriesShapes( this->getSeriesGroupShape( pDataSeries, xTarget ) );
333 //use series group shape as parent for the new created back group shape
334 xShapes = createGroupShape( xSeriesShapes );
335 pDataSeries->m_xBackSubGroupShape = xShapes;
337 return xShapes;
340 uno::Reference< drawing::XShapes > VSeriesPlotter::getLabelsGroupShape( VDataSeries& rDataSeries
341 , const uno::Reference< drawing::XShapes >& xTextTarget )
343 //xTextTarget needs to be a 2D shape container always!
345 uno::Reference< drawing::XShapes > xShapes( rDataSeries.m_xLabelsGroupShape );
346 if(!xShapes.is())
348 //create a 2D group shape for texts of this series and add to text target:
349 xShapes = m_pShapeFactory->createGroup2D( xTextTarget, rDataSeries.getLabelsCID() );
350 rDataSeries.m_xLabelsGroupShape = xShapes;
352 return xShapes;
355 uno::Reference< drawing::XShapes > VSeriesPlotter::getErrorBarsGroupShape( VDataSeries& rDataSeries
356 , const uno::Reference< drawing::XShapes >& xTarget
357 , bool bYError )
359 uno::Reference< ::com::sun::star::drawing::XShapes > &rShapeGroup =
360 bYError ? rDataSeries.m_xErrorYBarsGroupShape : rDataSeries.m_xErrorXBarsGroupShape;
362 uno::Reference< drawing::XShapes > xShapes( rShapeGroup );
363 if(!xShapes.is())
365 //create a group shape for this series and add to logic target:
366 xShapes = this->createGroupShape( xTarget,rDataSeries.getErrorBarsCID(bYError) );
367 rShapeGroup = xShapes;
369 return xShapes;
373 OUString VSeriesPlotter::getLabelTextForValue( VDataSeries& rDataSeries
374 , sal_Int32 nPointIndex
375 , double fValue
376 , bool bAsPercentage )
378 OUString aNumber;
380 if( m_apNumberFormatterWrapper.get())
382 sal_Int32 nNumberFormatKey = 0;
383 if( rDataSeries.hasExplicitNumberFormat(nPointIndex,bAsPercentage) )
384 nNumberFormatKey = rDataSeries.getExplicitNumberFormat(nPointIndex,bAsPercentage);
385 else if( bAsPercentage )
387 sal_Int32 nPercentFormat = DiagramHelper::getPercentNumberFormat( m_apNumberFormatterWrapper->getNumberFormatsSupplier() );
388 if( nPercentFormat != -1 )
389 nNumberFormatKey = nPercentFormat;
391 else
393 if( rDataSeries.shouldLabelNumberFormatKeyBeDetectedFromYAxis() && m_aAxesNumberFormats.hasFormat(1,rDataSeries.getAttachedAxisIndex()) ) //y-axis
394 nNumberFormatKey = m_aAxesNumberFormats.getFormat(1,rDataSeries.getAttachedAxisIndex());
395 else
396 nNumberFormatKey = rDataSeries.detectNumberFormatKey( nPointIndex );
398 if(nNumberFormatKey<0)
399 nNumberFormatKey=0;
401 sal_Int32 nLabelCol = 0;
402 bool bColChanged;
403 aNumber = m_apNumberFormatterWrapper->getFormattedString(
404 nNumberFormatKey, fValue, nLabelCol, bColChanged );
405 //@todo: change color of label if bColChanged is true
407 else
409 sal_Unicode cDecSeparator = '.';//@todo get this locale dependent
410 aNumber = ::rtl::math::doubleToUString( fValue, rtl_math_StringFormat_G /*rtl_math_StringFormat*/
411 , 3/*DecPlaces*/ , cDecSeparator, false /*bEraseTrailingDecZeros*/ );
413 return aNumber;
416 uno::Reference< drawing::XShape > VSeriesPlotter::createDataLabel( const uno::Reference< drawing::XShapes >& xTarget
417 , VDataSeries& rDataSeries
418 , sal_Int32 nPointIndex
419 , double fValue
420 , double fSumValue
421 , const awt::Point& rScreenPosition2D
422 , LabelAlignment eAlignment
423 , sal_Int32 nOffset )
425 uno::Reference< drawing::XShape > xTextShape;
429 awt::Point aScreenPosition2D(rScreenPosition2D);
430 if(LABEL_ALIGN_LEFT==eAlignment)
431 aScreenPosition2D.X -= nOffset;
432 else if(LABEL_ALIGN_RIGHT==eAlignment)
433 aScreenPosition2D.X += nOffset;
434 else if(LABEL_ALIGN_TOP==eAlignment)
435 aScreenPosition2D.Y -= nOffset;
436 else if(LABEL_ALIGN_BOTTOM==eAlignment)
437 aScreenPosition2D.Y += nOffset;
439 uno::Reference< drawing::XShapes > xTarget_(
440 m_pShapeFactory->createGroup2D( this->getLabelsGroupShape(rDataSeries, xTarget)
441 , ObjectIdentifier::createPointCID( rDataSeries.getLabelCID_Stub(),nPointIndex ) ) );
443 //check whether the label needs to be created and how:
444 DataPointLabel* pLabel = rDataSeries.getDataPointLabelIfLabel( nPointIndex );
446 if( !pLabel )
447 return xTextShape;
449 //------------------------------------------------
450 //prepare legend symbol
452 float fViewFontSize( 10.0 );
454 uno::Reference< beans::XPropertySet > xProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) );
455 if( xProps.is() )
456 xProps->getPropertyValue( "CharHeight") >>= fViewFontSize;
457 // pt -> 1/100th mm
458 fViewFontSize *= (2540.0f / 72.0f);
460 Reference< drawing::XShape > xSymbol;
461 if(pLabel->ShowLegendSymbol)
463 sal_Int32 nSymbolHeigth = static_cast< sal_Int32 >( fViewFontSize * 0.6 );
464 awt::Size aCurrentRatio = this->getPreferredLegendKeyAspectRatio();
465 sal_Int32 nSymbolWidth = aCurrentRatio.Width;
466 if( aCurrentRatio.Height > 0 )
468 nSymbolWidth = nSymbolHeigth* aCurrentRatio.Width/aCurrentRatio.Height;
470 awt::Size aMaxSymbolExtent( nSymbolWidth, nSymbolHeigth );
472 if( rDataSeries.isVaryColorsByPoint() )
473 xSymbol.set( VSeriesPlotter::createLegendSymbolForPoint( aMaxSymbolExtent, rDataSeries, nPointIndex, xTarget_, m_xShapeFactory ) );
474 else
475 xSymbol.set( VSeriesPlotter::createLegendSymbolForSeries( aMaxSymbolExtent, rDataSeries, xTarget_, m_xShapeFactory ) );
478 //prepare text
479 OUStringBuffer aText;
480 OUString aSeparator(sal_Unicode(' '));
481 double fRotationDegrees = 0.0;
484 uno::Reference< beans::XPropertySet > xPointProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) );
485 if(xPointProps.is())
487 xPointProps->getPropertyValue( "LabelSeparator" ) >>= aSeparator;
488 xPointProps->getPropertyValue( "TextRotation" ) >>= fRotationDegrees;
491 catch( const uno::Exception& e )
493 ASSERT_EXCEPTION( e );
495 bool bMultiLineLabel = aSeparator.equals("\n");;
496 sal_Int32 nLineCountForSymbolsize = 0;
498 if(pLabel->ShowCategoryName)
500 if( m_pExplicitCategoriesProvider )
502 Sequence< OUString > aCategories( m_pExplicitCategoriesProvider->getSimpleCategories() );
503 if( nPointIndex >= 0 && nPointIndex < aCategories.getLength() )
505 aText.append( aCategories[nPointIndex] );
506 ++nLineCountForSymbolsize;
511 if(pLabel->ShowNumber)
513 OUString aNumber( this->getLabelTextForValue( rDataSeries
514 , nPointIndex, fValue, false /*bAsPercentage*/ ) );
515 if( !aNumber.isEmpty() )
517 if(!aText.isEmpty())
518 aText.append(aSeparator);
519 aText.append(aNumber);
520 ++nLineCountForSymbolsize;
524 if(pLabel->ShowNumberInPercent)
526 if(fSumValue==0.0)
527 fSumValue=1.0;
528 fValue /= fSumValue;
529 if( fValue < 0 )
530 fValue*=-1.0;
532 OUString aPercentage( this->getLabelTextForValue( rDataSeries
533 , nPointIndex, fValue, true /*bAsPercentage*/ ) );
534 if( !aPercentage.isEmpty() )
536 if(!aText.isEmpty())
537 aText.append(aSeparator);
538 aText.append(aPercentage);
539 ++nLineCountForSymbolsize;
543 //------------------------------------------------
544 //prepare properties for multipropertyset-interface of shape
545 tNameSequence* pPropNames;
546 tAnySequence* pPropValues;
547 if( !rDataSeries.getTextLabelMultiPropertyLists( nPointIndex, pPropNames, pPropValues ) )
548 return xTextShape;
549 LabelPositionHelper::changeTextAdjustment( *pPropValues, *pPropNames, eAlignment );
551 //------------------------------------------------
552 //create text shape
553 xTextShape = ShapeFactory(m_xShapeFactory).
554 createText( xTarget_, aText.makeStringAndClear()
555 , *pPropNames, *pPropValues, ShapeFactory::makeTransformation( aScreenPosition2D ) );
557 if( !xTextShape.is() )
558 return xTextShape;
560 const awt::Point aUnrotatedTextPos( xTextShape->getPosition() );
561 if( fRotationDegrees != 0.0 )
563 const double fDegreesPi( fRotationDegrees * ( F_PI / -180.0 ) );
564 uno::Reference< beans::XPropertySet > xProp( xTextShape, uno::UNO_QUERY );
565 if( xProp.is() )
566 xProp->setPropertyValue( "Transformation", ShapeFactory::makeTransformation( aScreenPosition2D, fDegreesPi ) );
567 LabelPositionHelper::correctPositionForRotation( xTextShape, eAlignment, fRotationDegrees, true /*bRotateAroundCenter*/ );
570 if( xSymbol.is() )
572 const awt::Point aOldTextPos( xTextShape->getPosition() );
573 awt::Point aNewTextPos( aOldTextPos );
575 awt::Point aSymbolPosition( aUnrotatedTextPos );
576 awt::Size aSymbolSize( xSymbol->getSize() );
577 awt::Size aTextSize( xTextShape->getSize() );
579 sal_Int32 nXDiff = aSymbolSize.Width + static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.22 ) );//minimum 1mm
580 if( !bMultiLineLabel || nLineCountForSymbolsize <= 0 )
581 nLineCountForSymbolsize = 1;
582 aSymbolPosition.Y += ((aTextSize.Height/nLineCountForSymbolsize)/4);
584 if(LABEL_ALIGN_LEFT==eAlignment
585 || LABEL_ALIGN_LEFT_TOP==eAlignment
586 || LABEL_ALIGN_LEFT_BOTTOM==eAlignment)
588 aSymbolPosition.X -= nXDiff;
590 else if(LABEL_ALIGN_RIGHT==eAlignment
591 || LABEL_ALIGN_RIGHT_TOP==eAlignment
592 || LABEL_ALIGN_RIGHT_BOTTOM==eAlignment )
594 aNewTextPos.X += nXDiff;
596 else if(LABEL_ALIGN_TOP==eAlignment
597 || LABEL_ALIGN_BOTTOM==eAlignment
598 || LABEL_ALIGN_CENTER==eAlignment )
600 aSymbolPosition.X -= nXDiff/2;
601 aNewTextPos.X += nXDiff/2;
604 xSymbol->setPosition( aSymbolPosition );
605 xTextShape->setPosition( aNewTextPos );
608 catch( const uno::Exception& e )
610 ASSERT_EXCEPTION( e );
613 return xTextShape;
616 namespace
618 double lcl_getErrorBarLogicLength(
619 const uno::Sequence< double > & rData,
620 uno::Reference< beans::XPropertySet > xProp,
621 sal_Int32 nErrorBarStyle,
622 sal_Int32 nIndex,
623 bool bPositive,
624 bool bYError )
626 double fResult;
627 ::rtl::math::setNan( & fResult );
630 switch( nErrorBarStyle )
632 case ::com::sun::star::chart::ErrorBarStyle::NONE:
633 break;
634 case ::com::sun::star::chart::ErrorBarStyle::VARIANCE:
635 fResult = StatisticsHelper::getVariance( rData );
636 break;
637 case ::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION:
638 fResult = StatisticsHelper::getStandardDeviation( rData );
639 break;
640 case ::com::sun::star::chart::ErrorBarStyle::RELATIVE:
642 double fPercent = 0;
643 if( xProp->getPropertyValue( bPositive
644 ? OUString("PositiveError")
645 : OUString("NegativeError") ) >>= fPercent )
647 if( nIndex >=0 && nIndex < rData.getLength() &&
648 ! ::rtl::math::isNan( rData[nIndex] ) &&
649 ! ::rtl::math::isNan( fPercent ))
651 fResult = rData[nIndex] * fPercent / 100.0;
655 break;
656 case ::com::sun::star::chart::ErrorBarStyle::ABSOLUTE:
657 xProp->getPropertyValue( bPositive
658 ? OUString("PositiveError")
659 : OUString("NegativeError") ) >>= fResult;
660 break;
661 case ::com::sun::star::chart::ErrorBarStyle::ERROR_MARGIN:
663 // todo: check if this is really what's called error-margin
664 double fPercent = 0;
665 if( xProp->getPropertyValue( bPositive
666 ? OUString("PositiveError")
667 : OUString("NegativeError") ) >>= fPercent )
669 double fMaxValue;
670 ::rtl::math::setInf(&fMaxValue, true);
671 const double* pValues = rData.getConstArray();
672 for(sal_Int32 i=0; i<rData.getLength(); ++i, ++pValues)
674 if(fMaxValue<*pValues)
675 fMaxValue=*pValues;
677 if( ::rtl::math::isFinite( fMaxValue ) &&
678 ::rtl::math::isFinite( fPercent ))
680 fResult = fMaxValue * fPercent / 100.0;
684 break;
685 case ::com::sun::star::chart::ErrorBarStyle::STANDARD_ERROR:
686 fResult = StatisticsHelper::getStandardError( rData );
687 break;
688 case ::com::sun::star::chart::ErrorBarStyle::FROM_DATA:
690 uno::Reference< chart2::data::XDataSource > xErrorBarData( xProp, uno::UNO_QUERY );
691 if( xErrorBarData.is())
692 fResult = StatisticsHelper::getErrorFromDataSource(
693 xErrorBarData, nIndex, bPositive, bYError);
695 break;
698 catch( const uno::Exception & e )
700 ASSERT_EXCEPTION( e );
703 return fResult;
706 void lcl_AddErrorBottomLine( const drawing::Position3D& rPosition, ::basegfx::B2DVector aMainDirection
707 , drawing::PolyPolygonShape3D& rPoly, sal_Int32 nSequenceIndex )
709 double fFixedWidth = 200.0;
711 aMainDirection.normalize();
712 ::basegfx::B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
713 aOrthoDirection.normalize();
715 ::basegfx::B2DVector aAnchor( rPosition.PositionX, rPosition.PositionY );
716 ::basegfx::B2DVector aStart = aAnchor + aOrthoDirection*fFixedWidth/2.0;
717 ::basegfx::B2DVector aEnd = aAnchor - aOrthoDirection*fFixedWidth/2.0;
719 AddPointToPoly( rPoly, drawing::Position3D( aStart.getX(), aStart.getY(), rPosition.PositionZ), nSequenceIndex );
720 AddPointToPoly( rPoly, drawing::Position3D( aEnd.getX(), aEnd.getY(), rPosition.PositionZ), nSequenceIndex );
723 ::basegfx::B2DVector lcl_getErrorBarMainDirection(
724 const drawing::Position3D& rStart
725 , const drawing::Position3D& rBottomEnd
726 , PlottingPositionHelper* pPosHelper
727 , const drawing::Position3D& rUnscaledLogicPosition
728 , bool bYError )
730 ::basegfx::B2DVector aMainDirection = ::basegfx::B2DVector( rStart.PositionX - rBottomEnd.PositionX
731 , rStart.PositionY - rBottomEnd.PositionY );
732 if( !aMainDirection.getLength() )
734 //get logic clip values:
735 double MinX = pPosHelper->getLogicMinX();
736 double MinY = pPosHelper->getLogicMinY();
737 double MaxX = pPosHelper->getLogicMaxX();
738 double MaxY = pPosHelper->getLogicMaxY();
739 double fZ = pPosHelper->getLogicMinZ();
742 if( bYError )
744 //main direction has constant x value
745 MinX = rUnscaledLogicPosition.PositionX;
746 MaxX = rUnscaledLogicPosition.PositionX;
748 else
750 //main direction has constant y value
751 MinY = rUnscaledLogicPosition.PositionY;
752 MaxY = rUnscaledLogicPosition.PositionY;
755 drawing::Position3D aStart = pPosHelper->transformLogicToScene( MinX, MinY, fZ, false );
756 drawing::Position3D aEnd = pPosHelper->transformLogicToScene( MaxX, MaxY, fZ, false );
758 aMainDirection = ::basegfx::B2DVector( aStart.PositionX - aEnd.PositionX
759 , aStart.PositionY - aEnd.PositionY );
761 if( !aMainDirection.getLength() )
763 //@todo
765 return aMainDirection;
768 drawing::Position3D lcl_transformMixedToScene( PlottingPositionHelper* pPosHelper
769 , double fX /*scaled*/, double fY /*unscaled*/, double fZ /*unscaled*/, bool bClip )
771 if(!pPosHelper)
772 return drawing::Position3D(0,0,0);
773 pPosHelper->doLogicScaling( 0,&fY,&fZ );
774 if(bClip)
775 pPosHelper->clipScaledLogicValues( &fX,&fY,&fZ );
776 return pPosHelper->transformScaledLogicToScene( fX, fY, fZ, false );
779 } // anonymous namespace
781 void VSeriesPlotter::createErrorBar(
782 const uno::Reference< drawing::XShapes >& xTarget
783 , const drawing::Position3D& rUnscaledLogicPosition
784 , const uno::Reference< beans::XPropertySet > & xErrorBarProperties
785 , const VDataSeries& rVDataSeries
786 , sal_Int32 nIndex
787 , bool bYError /* = true */
788 , double* pfScaledLogicX
791 if( !ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ) )
792 return;
794 if( ! xErrorBarProperties.is())
795 return;
799 sal_Bool bShowPositive = sal_False;
800 sal_Bool bShowNegative = sal_False;
801 sal_Int32 nErrorBarStyle = ::com::sun::star::chart::ErrorBarStyle::VARIANCE;
803 xErrorBarProperties->getPropertyValue( "ShowPositiveError") >>= bShowPositive;
804 xErrorBarProperties->getPropertyValue( "ShowNegativeError") >>= bShowNegative;
805 xErrorBarProperties->getPropertyValue( "ErrorBarStyle") >>= nErrorBarStyle;
807 if(!bShowPositive && !bShowNegative)
808 return;
810 if(nErrorBarStyle==::com::sun::star::chart::ErrorBarStyle::NONE)
811 return;
813 drawing::Position3D aUnscaledLogicPosition(rUnscaledLogicPosition);
814 if(nErrorBarStyle==::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION)
816 if (bYError)
817 aUnscaledLogicPosition.PositionY = rVDataSeries.getYMeanValue();
818 else
819 aUnscaledLogicPosition.PositionX = rVDataSeries.getXMeanValue();
822 bool bCreateNegativeBorder = false;//make a vertical line at the negative end of the error bar
823 bool bCreatePositiveBorder = false;//make a vertical line at the positive end of the error bar
824 drawing::Position3D aMiddle(aUnscaledLogicPosition);
825 const double fX = aUnscaledLogicPosition.PositionX;
826 const double fY = aUnscaledLogicPosition.PositionY;
827 const double fZ = aUnscaledLogicPosition.PositionZ;
828 double fScaledX = fX;
829 if( pfScaledLogicX )
830 fScaledX = *pfScaledLogicX;
831 else
832 m_pPosHelper->doLogicScaling( &fScaledX, 0, 0 );
834 aMiddle = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fY, fZ, true );
836 drawing::Position3D aNegative(aMiddle);
837 drawing::Position3D aPositive(aMiddle);
839 uno::Sequence< double > aData( bYError ? rVDataSeries.getAllY() : rVDataSeries.getAllX() );
841 if( bShowPositive )
843 double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, true, bYError );
844 if( ::rtl::math::isFinite( fLength ) )
846 double fLocalX = fX;
847 double fLocalY = fY;
848 if( bYError )
850 fLocalY+=fLength;
851 aPositive = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fLocalY, fZ, true );
853 else
855 fLocalX+=fLength;
856 aPositive = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true );
858 bCreatePositiveBorder = m_pPosHelper->isLogicVisible(fLocalX, fLocalY, fZ);
860 else
861 bShowPositive = false;
864 if( bShowNegative )
866 double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, false, bYError );
867 if( ::rtl::math::isFinite( fLength ) )
869 double fLocalX = fX;
870 double fLocalY = fY;
871 if( bYError )
873 fLocalY-=fLength;
874 aNegative = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fLocalY, fZ, true );
876 else
878 fLocalX-=fLength;
879 aNegative = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true );
881 bCreateNegativeBorder = m_pPosHelper->isLogicVisible( fLocalX, fLocalY, fZ);
883 else
884 bShowNegative = false;
887 if(!bShowPositive && !bShowNegative)
888 return;
890 drawing::PolyPolygonShape3D aPoly;
892 sal_Int32 nSequenceIndex=0;
893 if( bShowNegative )
894 AddPointToPoly( aPoly, aNegative, nSequenceIndex );
895 AddPointToPoly( aPoly, aMiddle, nSequenceIndex );
896 if( bShowPositive )
897 AddPointToPoly( aPoly, aPositive, nSequenceIndex );
899 if( bShowNegative && bCreateNegativeBorder )
901 ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aNegative, m_pPosHelper, aUnscaledLogicPosition, bYError );
902 nSequenceIndex++;
903 lcl_AddErrorBottomLine( aNegative, aMainDirection, aPoly, nSequenceIndex );
905 if( bShowPositive && bCreatePositiveBorder )
907 ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aPositive, m_pPosHelper, aUnscaledLogicPosition, bYError );
908 nSequenceIndex++;
909 lcl_AddErrorBottomLine( aPositive, aMainDirection, aPoly, nSequenceIndex );
912 uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D( xTarget, PolyToPointSequence( aPoly) );
913 this->setMappedProperties( xShape, xErrorBarProperties, PropertyMapper::getPropertyNameMapForLineProperties() );
915 catch( const uno::Exception & e )
917 ASSERT_EXCEPTION( e );
922 void VSeriesPlotter::createErrorBar_X( const drawing::Position3D& rUnscaledLogicPosition
923 , VDataSeries& rVDataSeries, sal_Int32 nPointIndex
924 , const uno::Reference< drawing::XShapes >& xTarget
925 , double* pfScaledLogicX )
927 if(m_nDimension!=2)
928 return;
929 // error bars
930 uno::Reference< beans::XPropertySet > xErrorBarProp(rVDataSeries.getXErrorBarProperties(nPointIndex));
931 if( xErrorBarProp.is())
933 uno::Reference< drawing::XShapes > xErrorBarsGroup_Shapes(
934 this->getErrorBarsGroupShape(rVDataSeries, xTarget, false) );
936 createErrorBar( xErrorBarsGroup_Shapes
937 , rUnscaledLogicPosition, xErrorBarProp
938 , rVDataSeries, nPointIndex
939 , false /* bYError */
940 , pfScaledLogicX );
944 void VSeriesPlotter::createErrorBar_Y( const drawing::Position3D& rUnscaledLogicPosition
945 , VDataSeries& rVDataSeries, sal_Int32 nPointIndex
946 , const uno::Reference< drawing::XShapes >& xTarget
947 , double* pfScaledLogicX )
949 if(m_nDimension!=2)
950 return;
951 // error bars
952 uno::Reference< beans::XPropertySet > xErrorBarProp(rVDataSeries.getYErrorBarProperties(nPointIndex));
953 if( xErrorBarProp.is())
955 uno::Reference< drawing::XShapes > xErrorBarsGroup_Shapes(
956 this->getErrorBarsGroupShape(rVDataSeries, xTarget, true) );
958 createErrorBar( xErrorBarsGroup_Shapes
959 , rUnscaledLogicPosition, xErrorBarProp
960 , rVDataSeries, nPointIndex
961 , true /* bYError */
962 , pfScaledLogicX );
966 void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries& rVDataSeries
967 , const uno::Reference< drawing::XShapes >& xTarget
968 , const uno::Reference< drawing::XShapes >& xEquationTarget
969 , bool bMaySkipPointsInRegressionCalculation )
971 if(m_nDimension!=2)
972 return;
973 uno::Reference< XRegressionCurveContainer > xRegressionContainer(
974 rVDataSeries.getModel(), uno::UNO_QUERY );
975 if(!xRegressionContainer.is())
976 return;
977 double fMinX = m_pPosHelper->getLogicMinX();
978 double fMaxX = m_pPosHelper->getLogicMaxX();
980 uno::Sequence< uno::Reference< XRegressionCurve > > aCurveList =
981 xRegressionContainer->getRegressionCurves();
982 for(sal_Int32 nN=0; nN<aCurveList.getLength(); nN++)
984 uno::Reference< XRegressionCurveCalculator > xRegressionCurveCalculator(
985 aCurveList[nN]->getCalculator() );
986 if( ! xRegressionCurveCalculator.is())
987 continue;
988 xRegressionCurveCalculator->recalculateRegression( rVDataSeries.getAllX(), rVDataSeries.getAllY() );
990 sal_Int32 nRegressionPointCount = 50;//@todo find a more optimal solution if more complicated curve types are introduced
991 drawing::PolyPolygonShape3D aRegressionPoly;
992 aRegressionPoly.SequenceX.realloc(1);
993 aRegressionPoly.SequenceY.realloc(1);
994 aRegressionPoly.SequenceZ.realloc(1);
995 aRegressionPoly.SequenceX[0].realloc(nRegressionPointCount);
996 aRegressionPoly.SequenceY[0].realloc(nRegressionPointCount);
997 aRegressionPoly.SequenceZ[0].realloc(nRegressionPointCount);
998 sal_Int32 nRealPointCount=0;
1000 std::vector< ExplicitScaleData > aScales( m_pPosHelper->getScales());
1001 uno::Reference< chart2::XScaling > xScalingX;
1002 uno::Reference< chart2::XScaling > xScalingY;
1003 if( aScales.size() >= 2 )
1005 xScalingX.set( aScales[0].Scaling );
1006 xScalingY.set( aScales[1].Scaling );
1009 uno::Sequence< geometry::RealPoint2D > aCalculatedPoints(
1010 xRegressionCurveCalculator->getCurveValues(
1011 fMinX, fMaxX, nRegressionPointCount, xScalingX, xScalingY, bMaySkipPointsInRegressionCalculation ));
1012 nRegressionPointCount = aCalculatedPoints.getLength();
1013 bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurveList[nN] );
1014 for(sal_Int32 nP=0; nP<nRegressionPointCount; nP++)
1016 double fLogicX = aCalculatedPoints[nP].X;
1017 double fLogicY = aCalculatedPoints[nP].Y;
1018 double fLogicZ = 0.0;//dummy
1020 // fdo#51656: don't scale mean value lines
1021 if(!bAverageLine)
1022 m_pPosHelper->doLogicScaling( &fLogicX, &fLogicY, &fLogicZ );
1024 if( !::rtl::math::isNan(fLogicX) && !::rtl::math::isInf(fLogicX)
1025 && !::rtl::math::isNan(fLogicY) && !::rtl::math::isInf(fLogicY)
1026 && !::rtl::math::isNan(fLogicZ) && !::rtl::math::isInf(fLogicZ) )
1028 aRegressionPoly.SequenceX[0][nRealPointCount] = fLogicX;
1029 aRegressionPoly.SequenceY[0][nRealPointCount] = fLogicY;
1030 nRealPointCount++;
1033 aRegressionPoly.SequenceX[0].realloc(nRealPointCount);
1034 aRegressionPoly.SequenceY[0].realloc(nRealPointCount);
1035 aRegressionPoly.SequenceZ[0].realloc(nRealPointCount);
1037 drawing::PolyPolygonShape3D aClippedPoly;
1038 Clipping::clipPolygonAtRectangle( aRegressionPoly, m_pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly );
1039 aRegressionPoly = aClippedPoly;
1040 m_pPosHelper->transformScaledLogicToScene( aRegressionPoly );
1042 awt::Point aDefaultPos;
1043 if( aRegressionPoly.SequenceX.getLength() && aRegressionPoly.SequenceX[0].getLength() )
1045 uno::Reference< beans::XPropertySet > xCurveModelProp( aCurveList[nN], uno::UNO_QUERY );
1046 VLineProperties aVLineProperties;
1047 aVLineProperties.initFromPropertySet( xCurveModelProp );
1049 //create an extra group shape for each curve for selection handling
1050 uno::Reference< drawing::XShapes > xRegressionGroupShapes =
1051 createGroupShape( xTarget, rVDataSeries.getDataCurveCID( nN, bAverageLine ) );
1052 uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D(
1053 xRegressionGroupShapes, PolyToPointSequence( aRegressionPoly ), &aVLineProperties );
1054 m_pShapeFactory->setShapeName( xShape, "MarkHandles" );
1055 aDefaultPos = xShape->getPosition();
1058 // curve equation and correlation coefficient
1059 uno::Reference< beans::XPropertySet > xEqProp( aCurveList[nN]->getEquationProperties());
1060 if( xEqProp.is())
1062 createRegressionCurveEquationShapes(
1063 rVDataSeries.getDataCurveEquationCID( nN ),
1064 xEqProp, xEquationTarget, xRegressionCurveCalculator,
1065 aDefaultPos );
1070 void VSeriesPlotter::createRegressionCurveEquationShapes(
1071 const OUString & rEquationCID,
1072 const uno::Reference< beans::XPropertySet > & xEquationProperties,
1073 const uno::Reference< drawing::XShapes >& xEquationTarget,
1074 const uno::Reference< chart2::XRegressionCurveCalculator > & xRegressionCurveCalculator,
1075 awt::Point aDefaultPos )
1077 OSL_ASSERT( xEquationProperties.is());
1078 if( !xEquationProperties.is())
1079 return;
1081 bool bShowEquation = false;
1082 bool bShowCorrCoeff = false;
1083 OUString aSep( sal_Unicode('\n'));
1084 if(( xEquationProperties->getPropertyValue( "ShowEquation") >>= bShowEquation ) &&
1085 ( xEquationProperties->getPropertyValue( "ShowCorrelationCoefficient") >>= bShowCorrCoeff ))
1087 if( ! (bShowEquation || bShowCorrCoeff))
1088 return;
1090 OUStringBuffer aFormula;
1091 sal_Int32 nNumberFormatKey = 0;
1092 xEquationProperties->getPropertyValue( "NumberFormat") >>= nNumberFormatKey;
1094 if( bShowEquation )
1096 if( m_apNumberFormatterWrapper.get())
1098 aFormula = xRegressionCurveCalculator->getFormattedRepresentation(
1099 m_apNumberFormatterWrapper->getNumberFormatsSupplier(),
1100 nNumberFormatKey );
1102 else
1104 aFormula = xRegressionCurveCalculator->getRepresentation();
1107 if( bShowCorrCoeff )
1109 aFormula.append( aSep );
1112 if( bShowCorrCoeff )
1114 aFormula.append( sal_Unicode( 'R' ));
1115 aFormula.append( sal_Unicode( 0x00b2 ));
1116 aFormula.append( " = ");
1117 double fR( xRegressionCurveCalculator->getCorrelationCoefficient());
1118 if( m_apNumberFormatterWrapper.get())
1120 sal_Int32 nLabelCol = 0;
1121 bool bColChanged;
1122 aFormula.append(
1123 m_apNumberFormatterWrapper->getFormattedString(
1124 nNumberFormatKey, fR*fR, nLabelCol, bColChanged ));
1125 //@todo: change color of label if bColChanged is true
1127 else
1129 sal_Unicode aDecimalSep( '.' );//@todo get this locale dependent
1130 aFormula.append( ::rtl::math::doubleToUString(
1131 fR*fR, rtl_math_StringFormat_G, 4, aDecimalSep, true ));
1135 awt::Point aScreenPosition2D;
1136 chart2::RelativePosition aRelativePosition;
1137 if( xEquationProperties->getPropertyValue( "RelativePosition") >>= aRelativePosition )
1139 //@todo decide whether x is primary or secondary
1140 double fX = aRelativePosition.Primary*m_aPageReferenceSize.Width;
1141 double fY = aRelativePosition.Secondary*m_aPageReferenceSize.Height;
1142 aScreenPosition2D.X = static_cast< sal_Int32 >( ::rtl::math::round( fX ));
1143 aScreenPosition2D.Y = static_cast< sal_Int32 >( ::rtl::math::round( fY ));
1145 else
1146 aScreenPosition2D = aDefaultPos;
1148 if( !aFormula.isEmpty())
1150 // set fill and line properties on creation
1151 tNameSequence aNames;
1152 tAnySequence aValues;
1153 PropertyMapper::getPreparedTextShapePropertyLists( xEquationProperties, aNames, aValues );
1155 uno::Reference< drawing::XShape > xTextShape = m_pShapeFactory->createText(
1156 xEquationTarget, aFormula.makeStringAndClear(),
1157 aNames, aValues, ShapeFactory::makeTransformation( aScreenPosition2D ));
1159 OSL_ASSERT( xTextShape.is());
1160 if( xTextShape.is())
1162 ShapeFactory::setShapeName( xTextShape, rEquationCID );
1163 awt::Size aSize( xTextShape->getSize() );
1164 awt::Point aPos( RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
1165 aScreenPosition2D, aSize, aRelativePosition.Anchor ) );
1166 //ensure that the equation is fully placed within the page (if possible)
1167 if( (aPos.X + aSize.Width) > m_aPageReferenceSize.Width )
1168 aPos.X = m_aPageReferenceSize.Width - aSize.Width;
1169 if( aPos.X < 0 )
1170 aPos.X = 0;
1171 if( (aPos.Y + aSize.Height) > m_aPageReferenceSize.Height )
1172 aPos.Y = m_aPageReferenceSize.Height - aSize.Height;
1173 if( aPos.Y < 0 )
1174 aPos.Y = 0;
1175 xTextShape->setPosition(aPos);
1182 void VSeriesPlotter::setMappedProperties(
1183 const uno::Reference< drawing::XShape >& xTargetShape
1184 , const uno::Reference< beans::XPropertySet >& xSource
1185 , const tPropertyNameMap& rMap
1186 , tPropertyNameValueMap* pOverwriteMap )
1188 uno::Reference< beans::XPropertySet > xTargetProp( xTargetShape, uno::UNO_QUERY );
1189 PropertyMapper::setMappedProperties(xTargetProp,xSource,rMap,pOverwriteMap);
1192 void VSeriesPlotter::setTimeResolutionOnXAxis( long TimeResolution, const Date& rNullDate )
1194 m_nTimeResolution = TimeResolution;
1195 m_aNullDate = rNullDate;
1198 //-------------------------------------------------------------------------
1199 // MinimumAndMaximumSupplier
1200 //-------------------------------------------------------------------------
1201 long VSeriesPlotter::calculateTimeResolutionOnXAxis()
1203 long nRet = ::com::sun::star::chart::TimeUnit::YEAR;
1204 if( m_pExplicitCategoriesProvider )
1206 const std::vector< DatePlusIndex >& rDateCategories = m_pExplicitCategoriesProvider->getDateCategories();
1207 std::vector< DatePlusIndex >::const_iterator aIt = rDateCategories.begin(), aEnd = rDateCategories.end();
1208 Date aNullDate(30,12,1899);
1209 if( m_apNumberFormatterWrapper.get() )
1210 aNullDate = m_apNumberFormatterWrapper->getNullDate();
1211 if( aIt!=aEnd )
1213 Date aPrevious(aNullDate); aPrevious+=static_cast<long>(rtl::math::approxFloor(aIt->fValue));
1214 ++aIt;
1215 for(;aIt!=aEnd;++aIt)
1217 Date aCurrent(aNullDate); aCurrent+=static_cast<long>(rtl::math::approxFloor(aIt->fValue));
1218 if( ::com::sun::star::chart::TimeUnit::YEAR == nRet )
1220 if( DateHelper::IsInSameYear( aPrevious, aCurrent ) )
1221 nRet = ::com::sun::star::chart::TimeUnit::MONTH;
1223 if( ::com::sun::star::chart::TimeUnit::MONTH == nRet )
1225 if( DateHelper::IsInSameMonth( aPrevious, aCurrent ) )
1226 nRet = ::com::sun::star::chart::TimeUnit::DAY;
1228 if( ::com::sun::star::chart::TimeUnit::DAY == nRet )
1229 break;
1230 aPrevious=aCurrent;
1234 return nRet;
1236 double VSeriesPlotter::getMinimumX()
1238 double fMinimum, fMaximum;
1239 this->getMinimumAndMaximiumX( fMinimum, fMaximum );
1240 return fMinimum;
1242 double VSeriesPlotter::getMaximumX()
1244 double fMinimum, fMaximum;
1245 this->getMinimumAndMaximiumX( fMinimum, fMaximum );
1246 return fMaximum;
1249 double VSeriesPlotter::getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex )
1251 if( !m_bCategoryXAxis || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) )
1253 double fMinY, fMaxY;
1254 this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
1255 return fMinY;
1258 double fMinimum, fMaximum;
1259 ::rtl::math::setInf(&fMinimum, false);
1260 ::rtl::math::setInf(&fMaximum, true);
1261 for(size_t nZ =0; nZ<m_aZSlots.size();nZ++ )
1263 ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[nZ];
1264 for(size_t nN =0; nN<rXSlots.size();nN++ )
1266 double fLocalMinimum, fLocalMaximum;
1267 rXSlots[nN].calculateYMinAndMaxForCategoryRange(
1268 static_cast<sal_Int32>(fMinimumX-1.0) //first category (index 0) matches with real number 1.0
1269 , static_cast<sal_Int32>(fMaximumX-1.0) //first category (index 0) matches with real number 1.0
1270 , isSeparateStackingForDifferentSigns( 1 )
1271 , fLocalMinimum, fLocalMaximum, nAxisIndex );
1272 if(fMaximum<fLocalMaximum)
1273 fMaximum=fLocalMaximum;
1274 if(fMinimum>fLocalMinimum)
1275 fMinimum=fLocalMinimum;
1278 if(::rtl::math::isInf(fMinimum))
1279 ::rtl::math::setNan(&fMinimum);
1280 return fMinimum;
1283 double VSeriesPlotter::getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex )
1285 if( !m_bCategoryXAxis || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) )
1287 double fMinY, fMaxY;
1288 this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
1289 return fMaxY;
1292 double fMinimum, fMaximum;
1293 ::rtl::math::setInf(&fMinimum, false);
1294 ::rtl::math::setInf(&fMaximum, true);
1295 for(size_t nZ =0; nZ<m_aZSlots.size();nZ++ )
1297 ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[nZ];
1298 for(size_t nN =0; nN<rXSlots.size();nN++ )
1300 double fLocalMinimum, fLocalMaximum;
1301 rXSlots[nN].calculateYMinAndMaxForCategoryRange(
1302 static_cast<sal_Int32>(fMinimumX-1.0) //first category (index 0) matches with real number 1.0
1303 , static_cast<sal_Int32>(fMaximumX-1.0) //first category (index 0) matches with real number 1.0
1304 , isSeparateStackingForDifferentSigns( 1 )
1305 , fLocalMinimum, fLocalMaximum, nAxisIndex );
1306 if(fMaximum<fLocalMaximum)
1307 fMaximum=fLocalMaximum;
1308 if(fMinimum>fLocalMinimum)
1309 fMinimum=fLocalMinimum;
1312 if(::rtl::math::isInf(fMaximum))
1313 ::rtl::math::setNan(&fMaximum);
1314 return fMaximum;
1317 double VSeriesPlotter::getMinimumZ()
1319 //this is the default for all charts without a meaningfull z axis
1320 return 1.0;
1322 double VSeriesPlotter::getMaximumZ()
1324 if( 3!=m_nDimension || !m_aZSlots.size() )
1325 return getMinimumZ()+1;
1326 return m_aZSlots.size();
1329 namespace
1331 bool lcl_isValueAxis( sal_Int32 nDimensionIndex, bool bCategoryXAxis )
1333 // default implementation: true for Y axes, and for value X axis
1334 if( nDimensionIndex == 0 )
1335 return !bCategoryXAxis;
1336 if( nDimensionIndex == 1 )
1337 return true;
1338 return false;
1342 bool VSeriesPlotter::isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex )
1344 return lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis );
1347 bool VSeriesPlotter::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex )
1349 // do not expand axes in 3D charts
1350 return (m_nDimension < 3) && lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis );
1353 bool VSeriesPlotter::isExpandWideValuesToZero( sal_Int32 nDimensionIndex )
1355 // default implementation: only for Y axis
1356 return nDimensionIndex == 1;
1359 bool VSeriesPlotter::isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex )
1361 // default implementation: only for Y axis
1362 return nDimensionIndex == 1;
1365 bool VSeriesPlotter::isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex )
1367 // default implementation: only for Y axis
1368 return nDimensionIndex == 1;
1371 void VSeriesPlotter::getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const
1373 ::rtl::math::setInf(&rfMinimum, false);
1374 ::rtl::math::setInf(&rfMaximum, true);
1376 ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter = m_aZSlots.begin();
1377 const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
1378 for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
1380 ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
1381 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
1382 for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
1384 double fLocalMinimum, fLocalMaximum;
1385 aXSlotIter->getMinimumAndMaximiumX( fLocalMinimum, fLocalMaximum );
1386 if( !::rtl::math::isNan(fLocalMinimum) && fLocalMinimum< rfMinimum )
1387 rfMinimum = fLocalMinimum;
1388 if( !::rtl::math::isNan(fLocalMaximum) && fLocalMaximum> rfMaximum )
1389 rfMaximum = fLocalMaximum;
1392 if(::rtl::math::isInf(rfMinimum))
1393 ::rtl::math::setNan(&rfMinimum);
1394 if(::rtl::math::isInf(rfMaximum))
1395 ::rtl::math::setNan(&rfMaximum);
1398 void VSeriesPlotter::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const
1400 ::rtl::math::setInf(&rfMinY, false);
1401 ::rtl::math::setInf(&rfMaxY, true);
1403 ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter = m_aZSlots.begin();
1404 const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
1405 for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
1407 ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
1408 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
1409 for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
1411 double fLocalMinimum, fLocalMaximum;
1412 aXSlotIter->getMinimumAndMaximiumYInContinuousXRange( fLocalMinimum, fLocalMaximum, fMinX, fMaxX, nAxisIndex );
1413 if( !::rtl::math::isNan(fLocalMinimum) && fLocalMinimum< rfMinY )
1414 rfMinY = fLocalMinimum;
1415 if( !::rtl::math::isNan(fLocalMaximum) && fLocalMaximum> rfMaxY )
1416 rfMaxY = fLocalMaximum;
1419 if(::rtl::math::isInf(rfMinY))
1420 ::rtl::math::setNan(&rfMinY);
1421 if(::rtl::math::isInf(rfMaxY))
1422 ::rtl::math::setNan(&rfMaxY);
1425 sal_Int32 VSeriesPlotter::getPointCount() const
1427 sal_Int32 nRet = 0;
1429 ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter = m_aZSlots.begin();
1430 const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
1432 for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
1434 ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
1435 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
1437 for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
1439 sal_Int32 nPointCount = aXSlotIter->getPointCount();
1440 if( nPointCount>nRet )
1441 nRet = nPointCount;
1444 return nRet;
1447 void VSeriesPlotter::setNumberFormatsSupplier(
1448 const uno::Reference< util::XNumberFormatsSupplier > & xNumFmtSupplier )
1450 m_apNumberFormatterWrapper.reset( new NumberFormatterWrapper( xNumFmtSupplier ));
1453 void VSeriesPlotter::setColorScheme( const uno::Reference< XColorScheme >& xColorScheme )
1455 m_xColorScheme = xColorScheme;
1458 void VSeriesPlotter::setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider )
1460 m_pExplicitCategoriesProvider = pExplicitCategoriesProvider;
1463 sal_Int32 VDataSeriesGroup::getPointCount() const
1465 if(!m_bMaxPointCountDirty)
1466 return m_nMaxPointCount;
1468 sal_Int32 nRet = 0;
1469 ::std::vector< VDataSeries* >::const_iterator aSeriesIter = m_aSeriesVector.begin();
1470 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
1472 for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter)
1474 sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount();
1475 if( nPointCount>nRet )
1476 nRet = nPointCount;
1478 m_nMaxPointCount=nRet;
1479 m_aListOfCachedYValues.clear();
1480 m_aListOfCachedYValues.resize(m_nMaxPointCount);
1481 m_bMaxPointCountDirty=false;
1482 return nRet;
1485 sal_Int32 VDataSeriesGroup::getAttachedAxisIndexForFirstSeries() const
1487 sal_Int32 nRet = 0;
1488 ::std::vector< VDataSeries* >::const_iterator aSeriesIter = m_aSeriesVector.begin();
1489 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
1491 if( aSeriesIter != aSeriesEnd )
1492 nRet = (*aSeriesIter)->getAttachedAxisIndex();
1494 return nRet;
1497 void VDataSeriesGroup::getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const
1499 const ::std::vector< VDataSeries* >* pSeriesList = &this->m_aSeriesVector;
1501 ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
1502 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
1504 ::rtl::math::setInf(&rfMinimum, false);
1505 ::rtl::math::setInf(&rfMaximum, true);
1507 for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
1509 sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount();
1510 for(sal_Int32 nN=0;nN<nPointCount;nN++)
1512 double fX = (*aSeriesIter)->getXValue( nN );
1513 if( ::rtl::math::isNan(fX) )
1514 continue;
1515 if(rfMaximum<fX)
1516 rfMaximum=fX;
1517 if(rfMinimum>fX)
1518 rfMinimum=fX;
1521 if(::rtl::math::isInf(rfMinimum))
1522 ::rtl::math::setNan(&rfMinimum);
1523 if(::rtl::math::isInf(rfMaximum))
1524 ::rtl::math::setNan(&rfMaximum);
1527 namespace {
1530 * Keep track of minimum and maximum Y values for one or more data series.
1531 * When multiple data series exist, that indicates that the data series are
1532 * stacked.
1534 * <p>For each X value, we calculate separate Y value ranges for each data
1535 * series in the first pass. In the second pass, we calculate the minimum Y
1536 * value by taking the absolute minimum value of all data series, whereas
1537 * the maxium Y value is the sum of all the series maximum Y values.</p>
1539 * <p>Once that's done for all X values, the final min / max Y values get
1540 * calculated by taking the absolute min / max Y values across all the X
1541 * values.</p>
1543 class PerXMinMaxCalculator
1545 typedef std::pair<double, double> MinMaxType;
1546 typedef std::map<size_t, MinMaxType> SeriesMinMaxType;
1547 typedef boost::ptr_map<double, SeriesMinMaxType> GroupMinMaxType;
1548 typedef boost::unordered_map<double, MinMaxType> TotalStoreType;
1549 GroupMinMaxType maSeriesGroup;
1550 size_t mnCurSeries;
1552 public:
1553 PerXMinMaxCalculator() : mnCurSeries(0) {}
1555 void nextSeries() { ++mnCurSeries; }
1557 void setValue(double fX, double fY)
1559 SeriesMinMaxType* pStore = getByXValue(fX); // get storage for given X value.
1560 if (!pStore)
1561 // This shouldn't happen!
1562 return;
1564 SeriesMinMaxType::iterator it = pStore->lower_bound(mnCurSeries);
1565 if (it != pStore->end() && !pStore->key_comp()(mnCurSeries, it->first))
1567 MinMaxType& r = it->second;
1568 // A min-max pair already exists for this series. Update it.
1569 if (fY < r.first)
1570 r.first = fY;
1571 if (r.second < fY)
1572 r.second = fY;
1574 else
1576 // No existing pair. Insert a new one.
1577 pStore->insert(
1578 it, SeriesMinMaxType::value_type(
1579 mnCurSeries, MinMaxType(fY,fY)));
1583 void getTotalRange(double& rfMin, double& rfMax) const
1585 rtl::math::setNan(&rfMin);
1586 rtl::math::setNan(&rfMax);
1588 TotalStoreType aStore;
1589 getTotalStore(aStore);
1591 if (aStore.empty())
1592 return;
1594 TotalStoreType::const_iterator it = aStore.begin(), itEnd = aStore.end();
1595 rfMin = it->second.first;
1596 rfMax = it->second.second;
1597 for (++it; it != itEnd; ++it)
1599 if (rfMin > it->second.first)
1600 rfMin = it->second.first;
1601 if (rfMax < it->second.second)
1602 rfMax = it->second.second;
1606 private:
1608 * Parse all data and reduce them into a set of global Y value ranges per
1609 * X value.
1611 void getTotalStore(TotalStoreType& rStore) const
1613 TotalStoreType aStore;
1614 GroupMinMaxType::const_iterator it = maSeriesGroup.begin(), itEnd = maSeriesGroup.end();
1615 for (; it != itEnd; ++it)
1617 double fX = it->first;
1619 const SeriesMinMaxType& rSeries = *it->second;
1620 SeriesMinMaxType::const_iterator itSeries = rSeries.begin(), itSeriesEnd = rSeries.end();
1621 for (; itSeries != itSeriesEnd; ++itSeries)
1623 double fYMin = itSeries->second.first, fYMax = itSeries->second.second;
1624 TotalStoreType::iterator itr = aStore.find(fX);
1625 if (itr == aStore.end())
1626 // New min-max pair for give X value.
1627 aStore.insert(
1628 TotalStoreType::value_type(fX, std::pair<double,double>(fYMin,fYMax)));
1629 else
1631 MinMaxType& r = itr->second;
1632 if (fYMin < r.first)
1633 r.first = fYMin; // min y-value
1635 r.second += fYMax; // accumulative max y-value.
1639 rStore.swap(aStore);
1642 SeriesMinMaxType* getByXValue(double fX)
1644 GroupMinMaxType::iterator it = maSeriesGroup.find(fX);
1645 if (it == maSeriesGroup.end())
1647 std::pair<GroupMinMaxType::iterator,bool> r =
1648 maSeriesGroup.insert(fX, new SeriesMinMaxType);
1650 if (!r.second)
1651 // insertion failed.
1652 return NULL;
1654 it = r.first;
1657 return it->second;
1663 void VDataSeriesGroup::getMinimumAndMaximiumYInContinuousXRange(
1664 double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const
1666 ::rtl::math::setNan(&rfMinY);
1667 ::rtl::math::setNan(&rfMaxY);
1669 if (m_aSeriesVector.empty())
1670 // No data series. Bail out.
1671 return;
1673 PerXMinMaxCalculator aRangeCalc;
1674 std::vector<VDataSeries*>::const_iterator it = m_aSeriesVector.begin(), itEnd = m_aSeriesVector.end();
1675 for (; it != itEnd; ++it)
1677 const VDataSeries* pSeries = *it;
1678 if (!pSeries)
1679 continue;
1681 for (sal_Int32 i = 0, n = pSeries->getTotalPointCount(); i < n; ++i)
1683 if (nAxisIndex != pSeries->getAttachedAxisIndex())
1684 continue;
1686 double fX = pSeries->getXValue(i);
1687 if (rtl::math::isNan(fX))
1688 continue;
1690 if (fX < fMinX || fX > fMaxX)
1691 // Outside specified X range. Skip it.
1692 continue;
1694 double fY = pSeries->getYValue(i);
1695 if (::rtl::math::isNan(fY))
1696 continue;
1698 aRangeCalc.setValue(fX, fY);
1700 aRangeCalc.nextSeries();
1703 aRangeCalc.getTotalRange(rfMinY, rfMaxY);
1706 void VDataSeriesGroup::calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
1707 , bool bSeparateStackingForDifferentSigns
1708 , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex )
1710 ::rtl::math::setInf(&rfMinimumY, false);
1711 ::rtl::math::setInf(&rfMaximumY, true);
1713 sal_Int32 nPointCount = getPointCount();//necessary to create m_aListOfCachedYValues
1714 if(nCategoryIndex<0 || nCategoryIndex>=nPointCount || m_aSeriesVector.empty())
1715 return;
1717 CachedYValues aCachedYValues = m_aListOfCachedYValues[nCategoryIndex][nAxisIndex];
1718 if( !aCachedYValues.m_bValuesDirty )
1720 //return cached values
1721 rfMinimumY = aCachedYValues.m_fMinimumY;
1722 rfMaximumY = aCachedYValues.m_fMaximumY;
1723 return;
1726 double fTotalSum, fPositiveSum, fNegativeSum, fFirstPositiveY, fFirstNegativeY;
1727 ::rtl::math::setNan( &fTotalSum );
1728 ::rtl::math::setNan( &fPositiveSum );
1729 ::rtl::math::setNan( &fNegativeSum );
1730 ::rtl::math::setNan( &fFirstPositiveY );
1731 ::rtl::math::setNan( &fFirstNegativeY );
1733 ::std::vector< VDataSeries* >::const_iterator aSeriesIter = m_aSeriesVector.begin();
1734 ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
1736 if( bSeparateStackingForDifferentSigns )
1738 for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
1740 if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
1741 continue;
1743 double fValueMinY = (*aSeriesIter)->getMinimumofAllDifferentYValues( nCategoryIndex );
1744 double fValueMaxY = (*aSeriesIter)->getMaximumofAllDifferentYValues( nCategoryIndex );
1746 if( fValueMaxY >= 0 )
1748 if( ::rtl::math::isNan( fPositiveSum ) )
1749 fPositiveSum = fFirstPositiveY = fValueMaxY;
1750 else
1751 fPositiveSum += fValueMaxY;
1753 if( fValueMinY < 0 )
1755 if(::rtl::math::isNan( fNegativeSum ))
1756 fNegativeSum = fFirstNegativeY = fValueMinY;
1757 else
1758 fNegativeSum += fValueMinY;
1761 rfMinimumY = ::rtl::math::isNan( fNegativeSum ) ? fFirstPositiveY : fNegativeSum;
1762 rfMaximumY = ::rtl::math::isNan( fPositiveSum ) ? fFirstNegativeY : fPositiveSum;
1764 else
1766 for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
1768 if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
1769 continue;
1771 double fValueMinY = (*aSeriesIter)->getMinimumofAllDifferentYValues( nCategoryIndex );
1772 double fValueMaxY = (*aSeriesIter)->getMaximumofAllDifferentYValues( nCategoryIndex );
1774 if( ::rtl::math::isNan( fTotalSum ) )
1776 rfMinimumY = fValueMinY;
1777 rfMaximumY = fTotalSum = fValueMaxY;
1779 else
1781 fTotalSum += fValueMaxY;
1782 if( rfMinimumY > fTotalSum )
1783 rfMinimumY = fTotalSum;
1784 if( rfMaximumY < fTotalSum )
1785 rfMaximumY = fTotalSum;
1790 aCachedYValues.m_fMinimumY = rfMinimumY;
1791 aCachedYValues.m_fMaximumY = rfMaximumY;
1792 aCachedYValues.m_bValuesDirty = false;
1793 m_aListOfCachedYValues[nCategoryIndex][nAxisIndex]=aCachedYValues;
1796 void VDataSeriesGroup::calculateYMinAndMaxForCategoryRange(
1797 sal_Int32 nStartCategoryIndex, sal_Int32 nEndCategoryIndex
1798 , bool bSeparateStackingForDifferentSigns
1799 , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex )
1801 //@todo maybe cache these values
1802 ::rtl::math::setInf(&rfMinimumY, false);
1803 ::rtl::math::setInf(&rfMaximumY, true);
1805 //iterate through the given categories
1806 if(nStartCategoryIndex<0)
1807 nStartCategoryIndex=0;
1808 if(nEndCategoryIndex<0)
1809 nEndCategoryIndex=0;
1810 for( sal_Int32 nCatIndex = nStartCategoryIndex; nCatIndex <= nEndCategoryIndex; nCatIndex++ )
1812 double fMinimumY; ::rtl::math::setNan(&fMinimumY);
1813 double fMaximumY; ::rtl::math::setNan(&fMaximumY);
1815 this->calculateYMinAndMaxForCategory( nCatIndex
1816 , bSeparateStackingForDifferentSigns, fMinimumY, fMaximumY, nAxisIndex );
1818 if(rfMinimumY > fMinimumY)
1819 rfMinimumY = fMinimumY;
1820 if(rfMaximumY < fMaximumY)
1821 rfMaximumY = fMaximumY;
1825 double VSeriesPlotter::getTransformedDepth() const
1827 double MinZ = m_pMainPosHelper->getLogicMinZ();
1828 double MaxZ = m_pMainPosHelper->getLogicMaxZ();
1829 m_pMainPosHelper->doLogicScaling( 0, 0, &MinZ );
1830 m_pMainPosHelper->doLogicScaling( 0, 0, &MaxZ );
1831 return FIXED_SIZE_FOR_3D_CHART_VOLUME/(MaxZ-MinZ);
1834 void VSeriesPlotter::addSecondaryValueScale( const ExplicitScaleData& rScale, sal_Int32 nAxisIndex )
1835 throw (uno::RuntimeException)
1837 if( nAxisIndex<1 )
1838 return;
1840 m_aSecondaryValueScales[nAxisIndex]=rScale;
1843 PlottingPositionHelper& VSeriesPlotter::getPlottingPositionHelper( sal_Int32 nAxisIndex ) const
1845 PlottingPositionHelper* pRet = 0;
1846 if(nAxisIndex>0)
1848 tSecondaryPosHelperMap::const_iterator aPosIt = m_aSecondaryPosHelperMap.find( nAxisIndex );
1849 if( aPosIt != m_aSecondaryPosHelperMap.end() )
1851 pRet = aPosIt->second;
1853 else
1855 tSecondaryValueScales::const_iterator aScaleIt = m_aSecondaryValueScales.find( nAxisIndex );
1856 if( aScaleIt != m_aSecondaryValueScales.end() )
1858 pRet = m_pPosHelper->createSecondaryPosHelper( aScaleIt->second );
1859 m_aSecondaryPosHelperMap[nAxisIndex] = pRet;
1863 if( !pRet )
1864 pRet = m_pMainPosHelper;
1865 if(pRet)
1866 pRet->setTimeResolution( m_nTimeResolution, m_aNullDate );
1867 return *pRet;
1870 void VSeriesPlotter::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& /*rPageSize*/ )
1874 VDataSeries* VSeriesPlotter::getFirstSeries() const
1876 ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter( m_aZSlots.begin() );
1877 ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd( m_aZSlots.end() );
1878 for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
1880 ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
1881 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
1883 if( aXSlotIter != aXSlotEnd )
1885 VDataSeriesGroup aSeriesGroup( *aXSlotIter );
1886 if( aSeriesGroup.m_aSeriesVector.size() )
1888 VDataSeries* pSeries = aSeriesGroup.m_aSeriesVector[0];
1889 if(pSeries)
1890 return pSeries;
1894 return 0;
1897 uno::Sequence< OUString > VSeriesPlotter::getSeriesNames() const
1899 ::std::vector< OUString > aRetVector;
1901 OUString aRole;
1902 if( m_xChartTypeModel.is() )
1903 aRole = m_xChartTypeModel->getRoleOfSequenceForSeriesLabel();
1905 ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter( m_aZSlots.begin() );
1906 ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd( m_aZSlots.end() );
1907 for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
1909 ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
1910 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
1912 if( aXSlotIter != aXSlotEnd )
1914 VDataSeriesGroup aSeriesGroup( *aXSlotIter );
1915 if( aSeriesGroup.m_aSeriesVector.size() )
1917 VDataSeries* pSeries = aSeriesGroup.m_aSeriesVector[0];
1918 uno::Reference< XDataSeries > xSeries( pSeries ? pSeries->getModel() : 0 );
1919 if( xSeries.is() )
1921 OUString aSeriesName( DataSeriesHelper::getDataSeriesLabel( xSeries, aRole ) );
1922 aRetVector.push_back( aSeriesName );
1927 return ContainerHelper::ContainerToSequence( aRetVector );
1930 namespace
1932 struct lcl_setRefSizeAtSeriesGroup : public ::std::unary_function< VDataSeriesGroup, void >
1934 lcl_setRefSizeAtSeriesGroup( awt::Size aRefSize ) : m_aRefSize( aRefSize ) {}
1935 void operator()( VDataSeriesGroup & rGroup )
1937 ::std::vector< VDataSeries* >::iterator aIt( rGroup.m_aSeriesVector.begin());
1938 const ::std::vector< VDataSeries* >::iterator aEndIt( rGroup.m_aSeriesVector.end());
1939 for( ; aIt != aEndIt; ++aIt )
1940 (*aIt)->setPageReferenceSize( m_aRefSize );
1943 private:
1944 awt::Size m_aRefSize;
1946 } // anonymous namespace
1948 void VSeriesPlotter::setPageReferenceSize( const ::com::sun::star::awt::Size & rPageRefSize )
1950 m_aPageReferenceSize = rPageRefSize;
1952 // set reference size also at all data series
1954 ::std::vector< VDataSeriesGroup > aSeriesGroups( FlattenVector( m_aZSlots ));
1955 ::std::for_each( aSeriesGroups.begin(), aSeriesGroups.end(),
1956 lcl_setRefSizeAtSeriesGroup( m_aPageReferenceSize ));
1959 //better performance for big data
1960 void VSeriesPlotter::setCoordinateSystemResolution( const Sequence< sal_Int32 >& rCoordinateSystemResolution )
1962 m_aCoordinateSystemResolution = rCoordinateSystemResolution;
1965 bool VSeriesPlotter::PointsWereSkipped() const
1967 return m_bPointsWereSkipped;
1970 bool VSeriesPlotter::WantToPlotInFrontOfAxisLine()
1972 return ChartTypeHelper::isSeriesInFrontOfAxisLine( m_xChartTypeModel );
1975 bool VSeriesPlotter::shouldSnapRectToUsedArea()
1977 if( m_nDimension == 3 )
1978 return false;
1979 return true;
1982 std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntries(
1983 const awt::Size& rEntryKeyAspectRatio
1984 , ::com::sun::star::chart::ChartLegendExpansion eLegendExpansion
1985 , const Reference< beans::XPropertySet >& xTextProperties
1986 , const Reference< drawing::XShapes >& xTarget
1987 , const Reference< lang::XMultiServiceFactory >& xShapeFactory
1988 , const Reference< uno::XComponentContext >& xContext
1991 std::vector< ViewLegendEntry > aResult;
1993 if( xTarget.is() )
1995 //iterate through all series
1996 bool bBreak = false;
1997 bool bFirstSeries = true;
1998 ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
1999 const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
2000 for( ; aZSlotIter!=aZSlotEnd && !bBreak; ++aZSlotIter )
2002 ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
2003 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
2004 for( ; aXSlotIter!=aXSlotEnd && !bBreak; ++aXSlotIter )
2006 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
2007 ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
2008 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
2009 //iterate through all series in this x slot
2010 for( ; aSeriesIter!=aSeriesEnd && !bBreak; ++aSeriesIter )
2012 VDataSeries* pSeries( *aSeriesIter );
2013 if(!pSeries)
2014 continue;
2016 std::vector< ViewLegendEntry > aSeriesEntries( this->createLegendEntriesForSeries( rEntryKeyAspectRatio,
2017 *pSeries, xTextProperties, xTarget, xShapeFactory, xContext ) );
2019 //add series entries to the result now
2021 // use only the first series if VaryColorsByPoint is set for the first series
2022 if( bFirstSeries && pSeries->isVaryColorsByPoint() )
2023 bBreak = true;
2024 bFirstSeries = false;
2026 // add entries reverse if chart is stacked in y-direction and the legend is not wide.
2027 // If the legend is wide and we have a stacked bar-chart the normal order
2028 // is the correct one
2029 bool bReverse = false;
2030 if( eLegendExpansion != ::com::sun::star::chart::ChartLegendExpansion_WIDE )
2032 StackingDirection eStackingDirection( pSeries->getStackingDirection() );
2033 bReverse = ( eStackingDirection == StackingDirection_Y_STACKING );
2035 //todo: respect direction of axis in future
2038 if(bReverse)
2039 aResult.insert( aResult.begin(), aSeriesEntries.begin(), aSeriesEntries.end() );
2040 else
2041 aResult.insert( aResult.end(), aSeriesEntries.begin(), aSeriesEntries.end() );
2047 return aResult;
2050 ::std::vector< VDataSeries* > VSeriesPlotter::getAllSeries()
2052 ::std::vector< VDataSeries* > aAllSeries;
2053 ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
2054 const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
2055 for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
2057 ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
2058 const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
2059 for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
2061 ::std::vector< VDataSeries* > aSeriesList = aXSlotIter->m_aSeriesVector;
2062 aAllSeries.insert( aAllSeries.end(), aSeriesList.begin(), aSeriesList.end() );
2065 return aAllSeries;
2068 namespace
2070 bool lcl_HasVisibleLine( const uno::Reference< beans::XPropertySet >& xProps, bool& rbHasDashedLine )
2072 bool bHasVisibleLine = false;
2073 rbHasDashedLine = false;
2074 drawing::LineStyle aLineStyle = drawing::LineStyle_NONE;
2075 if( xProps.is() && ( xProps->getPropertyValue( "LineStyle") >>= aLineStyle ) )
2077 if( aLineStyle != drawing::LineStyle_NONE )
2078 bHasVisibleLine = true;
2079 if( aLineStyle == drawing::LineStyle_DASH )
2080 rbHasDashedLine = true;
2082 return bHasVisibleLine;
2085 bool lcl_HasRegressionCurves( const VDataSeries& rSeries, bool& rbHasDashedLine )
2087 bool bHasRegressionCurves = false;
2088 Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
2089 if( xRegrCont.is())
2091 Sequence< Reference< XRegressionCurve > > aCurves( xRegrCont->getRegressionCurves() );
2092 sal_Int32 i = 0, nCount = aCurves.getLength();
2093 for( i=0; i<nCount; ++i )
2095 if( aCurves[i].is() )
2097 bHasRegressionCurves = true;
2098 lcl_HasVisibleLine( uno::Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ), rbHasDashedLine );
2102 return bHasRegressionCurves;
2105 LegendSymbolStyle VSeriesPlotter::getLegendSymbolStyle()
2107 return LegendSymbolStyle_BOX;
2110 awt::Size VSeriesPlotter::getPreferredLegendKeyAspectRatio()
2112 awt::Size aRet(1000,1000);
2113 if( m_nDimension==3 )
2114 return aRet;
2116 bool bSeriesAllowsLines = (getLegendSymbolStyle() == LegendSymbolStyle_LINE);
2117 bool bHasLines = false;
2118 bool bHasDashedLines = false;
2119 ::std::vector< VDataSeries* > aAllSeries( getAllSeries() );
2120 ::std::vector< VDataSeries* >::const_iterator aSeriesIter = aAllSeries.begin();
2121 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = aAllSeries.end();
2122 //iterate through all series
2123 for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
2125 if( bSeriesAllowsLines )
2127 bool bCurrentDashed = false;
2128 if( lcl_HasVisibleLine( (*aSeriesIter)->getPropertiesOfSeries(), bCurrentDashed ) )
2130 bHasLines = true;
2131 if( bCurrentDashed )
2133 bHasDashedLines = true;
2134 break;
2138 bool bRegressionHasDashedLines=false;
2139 if( lcl_HasRegressionCurves( **aSeriesIter, bRegressionHasDashedLines ) )
2141 bHasLines = true;
2142 if( bRegressionHasDashedLines )
2144 bHasDashedLines = true;
2145 break;
2149 if( bHasLines )
2151 if( bHasDashedLines )
2152 aRet = awt::Size(1600,-1);
2153 else
2154 aRet = awt::Size(800,-1);
2156 return aRet;
2159 uno::Any VSeriesPlotter::getExplicitSymbol( const VDataSeries& /*rSeries*/, sal_Int32 /*nPointIndex*/ )
2161 return uno::Any();
2164 Reference< drawing::XShape > VSeriesPlotter::createLegendSymbolForSeries(
2165 const awt::Size& rEntryKeyAspectRatio
2166 , const VDataSeries& rSeries
2167 , const Reference< drawing::XShapes >& xTarget
2168 , const Reference< lang::XMultiServiceFactory >& xShapeFactory )
2171 LegendSymbolStyle eLegendSymbolStyle = this->getLegendSymbolStyle();
2172 uno::Any aExplicitSymbol( this->getExplicitSymbol( rSeries ) );
2174 VLegendSymbolFactory::tPropertyType ePropType =
2175 VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES;
2177 // todo: maybe the property-style does not solely depend on the
2178 // legend-symbol type
2179 switch( eLegendSymbolStyle )
2181 case LegendSymbolStyle_LINE:
2182 ePropType = VLegendSymbolFactory::PROP_TYPE_LINE_SERIES;
2183 break;
2184 default:
2185 break;
2187 Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
2188 xTarget, eLegendSymbolStyle, xShapeFactory
2189 , rSeries.getPropertiesOfSeries(), ePropType, aExplicitSymbol ));
2191 return xShape;
2194 Reference< drawing::XShape > VSeriesPlotter::createLegendSymbolForPoint(
2195 const awt::Size& rEntryKeyAspectRatio
2196 , const VDataSeries& rSeries
2197 , sal_Int32 nPointIndex
2198 , const Reference< drawing::XShapes >& xTarget
2199 , const Reference< lang::XMultiServiceFactory >& xShapeFactory )
2202 LegendSymbolStyle eLegendSymbolStyle = this->getLegendSymbolStyle();
2203 uno::Any aExplicitSymbol( this->getExplicitSymbol(rSeries,nPointIndex) );
2205 VLegendSymbolFactory::tPropertyType ePropType =
2206 VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES;
2208 // todo: maybe the property-style does not solely depend on the
2209 // legend-symbol type
2210 switch( eLegendSymbolStyle )
2212 case LegendSymbolStyle_LINE:
2213 ePropType = VLegendSymbolFactory::PROP_TYPE_LINE_SERIES;
2214 break;
2215 default:
2216 break;
2219 // the default properties for the data point are the data series properties.
2220 // If a data point has own attributes overwrite them
2221 Reference< beans::XPropertySet > xSeriesProps( rSeries.getPropertiesOfSeries() );
2222 Reference< beans::XPropertySet > xPointSet( xSeriesProps );
2223 if( rSeries.isAttributedDataPoint( nPointIndex ) )
2224 xPointSet.set( rSeries.getPropertiesOfPoint( nPointIndex ));
2226 // if a data point has no own color use a color fom the diagram's color scheme
2227 if( ! rSeries.hasPointOwnColor( nPointIndex ))
2229 Reference< util::XCloneable > xCloneable( xPointSet,uno::UNO_QUERY );
2230 if( xCloneable.is() && m_xColorScheme.is() )
2232 xPointSet.set( xCloneable->createClone(), uno::UNO_QUERY );
2233 Reference< container::XChild > xChild( xPointSet, uno::UNO_QUERY );
2234 if( xChild.is())
2235 xChild->setParent( xSeriesProps );
2237 OSL_ASSERT( xPointSet.is());
2238 xPointSet->setPropertyValue(
2239 "Color", uno::makeAny( m_xColorScheme->getColorByIndex( nPointIndex )));
2243 Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
2244 xTarget, eLegendSymbolStyle, xShapeFactory, xPointSet, ePropType, aExplicitSymbol ));
2246 return xShape;
2249 std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntriesForSeries(
2250 const awt::Size& rEntryKeyAspectRatio
2251 , const VDataSeries& rSeries
2252 , const Reference< beans::XPropertySet >& xTextProperties
2253 , const Reference< drawing::XShapes >& xTarget
2254 , const Reference< lang::XMultiServiceFactory >& xShapeFactory
2255 , const Reference< uno::XComponentContext >& xContext
2258 std::vector< ViewLegendEntry > aResult;
2260 if( ! ( xShapeFactory.is() && xTarget.is() && xContext.is() ) )
2261 return aResult;
2265 ViewLegendEntry aEntry;
2266 OUString aLabelText;
2267 bool bVaryColorsByPoint = rSeries.isVaryColorsByPoint();
2268 if( bVaryColorsByPoint )
2270 Sequence< OUString > aCategoryNames;
2271 if( m_pExplicitCategoriesProvider )
2272 aCategoryNames = m_pExplicitCategoriesProvider->getSimpleCategories();
2274 for( sal_Int32 nIdx=0; nIdx<aCategoryNames.getLength(); ++nIdx )
2276 // symbol
2277 uno::Reference< drawing::XShapes > xSymbolGroup( ShapeFactory(xShapeFactory).createGroup2D( xTarget ));
2279 // create the symbol
2280 Reference< drawing::XShape > xShape( this->createLegendSymbolForPoint( rEntryKeyAspectRatio,
2281 rSeries, nIdx, xSymbolGroup, xShapeFactory ) );
2283 // set CID to symbol for selection
2284 if( xShape.is() )
2286 aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
2288 OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_DATA_POINT, nIdx ) );
2289 aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
2290 OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
2291 ShapeFactory::setShapeName( xShape, aCID );
2294 // label
2295 aLabelText = aCategoryNames[nIdx];
2296 if( xShape.is() || !aLabelText.isEmpty() )
2298 aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
2299 aResult.push_back(aEntry);
2303 else
2305 // symbol
2306 uno::Reference< drawing::XShapes > xSymbolGroup( ShapeFactory(xShapeFactory).createGroup2D( xTarget ));
2308 // create the symbol
2309 Reference< drawing::XShape > xShape( this->createLegendSymbolForSeries(
2310 rEntryKeyAspectRatio, rSeries, xSymbolGroup, xShapeFactory ) );
2312 // set CID to symbol for selection
2313 if( xShape.is())
2315 aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
2317 OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
2318 OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
2319 ShapeFactory::setShapeName( xShape, aCID );
2322 // label
2323 aLabelText = ( DataSeriesHelper::getDataSeriesLabel( rSeries.getModel(), m_xChartTypeModel.is() ? m_xChartTypeModel->getRoleOfSequenceForSeriesLabel() : "values-y") );
2324 aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
2326 aResult.push_back(aEntry);
2329 // don't show legend entry of regression curve & friends if this type of chart
2330 // doesn't support statistics #i63016#, fdo#37197
2331 if (!ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ))
2332 return aResult;
2334 Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
2335 if( xRegrCont.is())
2337 Sequence< Reference< XRegressionCurve > > aCurves( xRegrCont->getRegressionCurves());
2338 sal_Int32 i = 0, nCount = aCurves.getLength();
2339 for( i=0; i<nCount; ++i )
2341 if( aCurves[i].is() )
2343 //label
2344 OUString aResStr( RegressionCurveHelper::getUINameForRegressionCurve( aCurves[i] ) );
2345 replaceParamterInString( aResStr, "%SERIESNAME", aLabelText );
2346 aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aResStr, xTextProperties );
2348 // symbol
2349 uno::Reference< drawing::XShapes > xSymbolGroup( ShapeFactory(xShapeFactory).createGroup2D( xTarget ));
2351 // create the symbol
2352 Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
2353 xSymbolGroup, LegendSymbolStyle_LINE, xShapeFactory,
2354 Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ),
2355 VLegendSymbolFactory::PROP_TYPE_LINE, uno::Any() ));
2357 // set CID to symbol for selection
2358 if( xShape.is())
2360 aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
2362 bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurves[i] );
2363 ObjectType eObjectType = bAverageLine ? OBJECTTYPE_DATA_AVERAGE_LINE : OBJECTTYPE_DATA_CURVE;
2364 OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( eObjectType, i ) );
2365 aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
2366 OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
2367 ShapeFactory::setShapeName( xShape, aCID );
2370 aResult.push_back(aEntry);
2375 catch( const uno::Exception & ex )
2377 ASSERT_EXCEPTION( ex );
2379 return aResult;
2382 VSeriesPlotter* VSeriesPlotter::createSeriesPlotter(
2383 const uno::Reference<XChartType>& xChartTypeModel
2384 , sal_Int32 nDimensionCount
2385 , bool bExcludingPositioning )
2387 OUString aChartType = xChartTypeModel->getChartType();
2389 //@todo: in future the plotter should be instanciated via service factory
2390 VSeriesPlotter* pRet=NULL;
2391 if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_COLUMN ) )
2392 pRet = new BarChart(xChartTypeModel,nDimensionCount);
2393 else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_BAR ) )
2394 pRet = new BarChart(xChartTypeModel,nDimensionCount);
2395 else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_AREA ) )
2396 pRet = new AreaChart(xChartTypeModel,nDimensionCount,true);
2397 else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_LINE ) )
2398 pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,true);
2399 else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) )
2400 pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true);
2401 else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE) )
2402 pRet = new BubbleChart(xChartTypeModel,nDimensionCount);
2403 else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
2404 pRet = new PieChart(xChartTypeModel,nDimensionCount, bExcludingPositioning );
2405 else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_NET) )
2406 pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,true,new PolarPlottingPositionHelper(),true,false,1,drawing::Direction3D(1,1,1) );
2407 else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) )
2408 pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,false,new PolarPlottingPositionHelper(),true,false,1,drawing::Direction3D(1,1,1) );
2409 else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) )
2410 pRet = new CandleStickChart(xChartTypeModel,nDimensionCount);
2411 else
2412 pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true);
2413 return pRet;
2416 //.............................................................................
2417 } //namespace chart
2418 //.............................................................................
2420 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */