1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <VDataSeries.hxx>
22 #include <ObjectIdentifier.hxx>
23 #include <CommonConverters.hxx>
24 #include <LabelPositionHelper.hxx>
25 #include <ChartTypeHelper.hxx>
26 #include <RegressionCurveHelper.hxx>
27 #include <unonames.hxx>
29 #include <com/sun/star/chart/MissingValueTreatment.hpp>
30 #include <com/sun/star/chart2/DataPointLabel.hpp>
31 #include <com/sun/star/chart2/Symbol.hpp>
32 #include <com/sun/star/chart2/XDataSeries.hpp>
33 #include <com/sun/star/chart2/XRegressionCurveCalculator.hpp>
35 #include <rtl/math.hxx>
36 #include <sal/log.hxx>
37 #include <osl/diagnose.h>
38 #include <tools/color.hxx>
39 #include <tools/diagnose_ex.h>
40 #include <com/sun/star/beans/XPropertySet.hpp>
41 #include <com/sun/star/beans/XPropertyState.hpp>
42 #include <com/sun/star/chart2/data/XDataSource.hpp>
46 using namespace ::com::sun::star
;
47 using namespace ::com::sun::star::chart2
;
48 using ::com::sun::star::uno::Reference
;
50 void VDataSequence::init( const uno::Reference
< data::XDataSequence
>& xModel
)
53 Doubles
= DataSequenceToDoubleSequence( xModel
);
56 bool VDataSequence::is() const
60 void VDataSequence::clear()
66 double VDataSequence::getValue( sal_Int32 index
) const
68 if( 0<=index
&& index
<Doubles
.getLength() )
69 return Doubles
[index
];
73 ::rtl::math::setNan( & fNan
);
78 sal_Int32
VDataSequence::detectNumberFormatKey( sal_Int32 index
) const
80 sal_Int32 nNumberFormatKey
= -1;
82 // -1 is allowed and means a key for the whole sequence
83 if( -1<=index
&& index
<Doubles
.getLength() &&
86 nNumberFormatKey
= Model
->getNumberFormatKeyByIndex( index
);
89 return nNumberFormatKey
;
92 sal_Int32
VDataSequence::getLength() const
94 return Doubles
.getLength();
99 struct lcl_LessXOfPoint
101 bool operator() ( const std::vector
< double >& first
,
102 const std::vector
< double >& second
)
104 if( !first
.empty() && !second
.empty() )
106 return first
[0]<second
[0];
112 void lcl_clearIfNoValuesButTextIsContained( VDataSequence
& rData
, const uno::Reference
<data::XDataSequence
>& xDataSequence
)
114 //#i71686#, #i101968#, #i102428#
115 sal_Int32 nCount
= rData
.Doubles
.getLength();
116 for( sal_Int32 i
= 0; i
< nCount
; ++i
)
118 if( !::rtl::math::isNan( rData
.Doubles
[i
] ) )
121 //no double value is contained
123 uno::Sequence
< OUString
> aStrings( DataSequenceToStringSequence( xDataSequence
) );
124 sal_Int32 nTextCount
= aStrings
.getLength();
125 for( sal_Int32 j
= 0; j
< nTextCount
; ++j
)
127 if( !aStrings
[j
].isEmpty() )
136 void lcl_maybeReplaceNanWithZero( double& rfValue
, sal_Int32 nMissingValueTreatment
)
138 if( nMissingValueTreatment
== css::chart::MissingValueTreatment::USE_ZERO
139 && (::rtl::math::isNan(rfValue
) || ::rtl::math::isInf(rfValue
)) )
145 VDataSeries::VDataSeries( const uno::Reference
< XDataSeries
>& xDataSeries
)
150 , m_xDataSeries(xDataSeries
)
153 , m_pValueSequenceForDataLabelNumberFormatDetection(&m_aValues_Y
)
158 , m_aAttributedDataPointIndexList()
160 , m_eStackingDirection(StackingDirection_NO_STACKING
)
162 , m_bConnectBars(false)
163 , m_bGroupBarsPerAxis(true)
164 , m_nStartingAngle(90)
166 , m_nGlobalSeriesIndex(0)
168 , m_nCurrentAttributedPoint(-1)
169 , m_nMissingValueTreatment(css::chart::MissingValueTreatment::LEAVE_GAP
)
170 , m_bAllowPercentValueInDataLabel(false)
171 , mpOldSeries(nullptr)
174 ::rtl::math::setNan( & m_fXMeanValue
);
175 ::rtl::math::setNan( & m_fYMeanValue
);
177 uno::Reference
<data::XDataSource
> xDataSource( xDataSeries
, uno::UNO_QUERY
);
179 uno::Sequence
< uno::Reference
<
180 chart2::data::XLabeledDataSequence
> > aDataSequences
=
181 xDataSource
->getDataSequences();
183 for(sal_Int32 nN
= aDataSequences
.getLength();nN
--;)
185 if(!aDataSequences
[nN
].is())
187 uno::Reference
<data::XDataSequence
> xDataSequence( aDataSequences
[nN
]->getValues());
188 uno::Reference
<beans::XPropertySet
> xProp(xDataSequence
, uno::UNO_QUERY
);
193 uno::Any aARole
= xProp
->getPropertyValue("Role");
197 if (aRole
== "values-x")
199 m_aValues_X
.init( xDataSequence
);
200 lcl_clearIfNoValuesButTextIsContained( m_aValues_X
, xDataSequence
);
202 else if (aRole
=="values-y")
203 m_aValues_Y
.init( xDataSequence
);
204 else if (aRole
== "values-min")
205 m_aValues_Y_Min
.init( xDataSequence
);
206 else if (aRole
== "values-max")
207 m_aValues_Y_Max
.init( xDataSequence
);
208 else if (aRole
== "values-first")
209 m_aValues_Y_First
.init( xDataSequence
);
210 else if (aRole
== "values-last")
211 m_aValues_Y_Last
.init( xDataSequence
);
212 else if (aRole
== "values-size")
213 m_aValues_Bubble_Size
.init( xDataSequence
);
216 VDataSequence aSequence
;
217 aSequence
.init(xDataSequence
);
218 m_PropertyMap
.insert(std::make_pair(aRole
, aSequence
));
221 catch( const uno::Exception
& )
223 TOOLS_WARN_EXCEPTION("chart2", "" );
228 //determine the point count
229 m_nPointCount
= m_aValues_Y
.getLength();
231 if( m_nPointCount
< m_aValues_Bubble_Size
.getLength() )
232 m_nPointCount
= m_aValues_Bubble_Size
.getLength();
233 if( m_nPointCount
< m_aValues_Y_Min
.getLength() )
234 m_nPointCount
= m_aValues_Y_Min
.getLength();
235 if( m_nPointCount
< m_aValues_Y_Max
.getLength() )
236 m_nPointCount
= m_aValues_Y_Max
.getLength();
237 if( m_nPointCount
< m_aValues_Y_First
.getLength() )
238 m_nPointCount
= m_aValues_Y_First
.getLength();
239 if( m_nPointCount
< m_aValues_Y_Last
.getLength() )
240 m_nPointCount
= m_aValues_Y_Last
.getLength();
243 uno::Reference
<beans::XPropertySet
> xProp(xDataSeries
, uno::UNO_QUERY
);
248 //get AttributedDataPoints
249 xProp
->getPropertyValue("AttributedDataPoints") >>= m_aAttributedDataPointIndexList
;
251 xProp
->getPropertyValue("StackingDirection") >>= m_eStackingDirection
;
253 xProp
->getPropertyValue("AttachedAxisIndex") >>= m_nAxisIndex
;
257 catch( const uno::Exception
& )
259 TOOLS_WARN_EXCEPTION("chart2", "" );
264 VDataSeries::~VDataSeries()
268 void VDataSeries::doSortByXValues()
270 if( m_aValues_X
.is() && m_aValues_X
.Doubles
.hasElements() )
272 //prepare a vector for sorting
273 std::vector
< std::vector
< double > > aTmp
;//outer vector are points, inner vector are the different values of the point
275 ::rtl::math::setNan( & fNan
);
276 sal_Int32 nPointIndex
= 0;
277 for( nPointIndex
=0; nPointIndex
< m_nPointCount
; nPointIndex
++ )
279 std::vector
< double > aSinglePoint
;
280 aSinglePoint
.push_back( (nPointIndex
< m_aValues_X
.Doubles
.getLength()) ? m_aValues_X
.Doubles
[nPointIndex
] : fNan
);
281 aSinglePoint
.push_back( (nPointIndex
< m_aValues_Y
.Doubles
.getLength()) ? m_aValues_Y
.Doubles
[nPointIndex
] : fNan
);
282 aTmp
.push_back( aSinglePoint
);
286 std::stable_sort( aTmp
.begin(), aTmp
.end(), lcl_LessXOfPoint() );
288 //fill the sorted points back to the members
289 m_aValues_X
.Doubles
.realloc( m_nPointCount
);
290 m_aValues_Y
.Doubles
.realloc( m_nPointCount
);
292 for( nPointIndex
=0; nPointIndex
< m_nPointCount
; nPointIndex
++ )
294 m_aValues_X
.Doubles
[nPointIndex
]=aTmp
[nPointIndex
][0];
295 m_aValues_Y
.Doubles
[nPointIndex
]=aTmp
[nPointIndex
][1];
300 void VDataSeries::releaseShapes()
302 m_xGroupShape
.set(nullptr);
303 m_xLabelsGroupShape
.set(nullptr);
304 m_xErrorXBarsGroupShape
.set(nullptr);
305 m_xErrorYBarsGroupShape
.set(nullptr);
306 m_xFrontSubGroupShape
.set(nullptr);
307 m_xBackSubGroupShape
.set(nullptr);
309 m_aPolyPolygonShape3D
.SequenceX
.realloc(0);
310 m_aPolyPolygonShape3D
.SequenceY
.realloc(0);
311 m_aPolyPolygonShape3D
.SequenceZ
.realloc(0);
315 const uno::Reference
<css::chart2::XDataSeries
>& VDataSeries::getModel() const
317 return m_xDataSeries
;
320 void VDataSeries::setCategoryXAxis()
323 m_bAllowPercentValueInDataLabel
= true;
326 void VDataSeries::setXValues( const Reference
< chart2::data::XDataSequence
>& xValues
)
329 m_aValues_X
.init( xValues
);
330 m_bAllowPercentValueInDataLabel
= true;
333 void VDataSeries::setXValuesIfNone( const Reference
< chart2::data::XDataSequence
>& xValues
)
335 if( m_aValues_X
.is() )
338 m_aValues_X
.init( xValues
);
339 lcl_clearIfNoValuesButTextIsContained( m_aValues_X
, xValues
);
342 void VDataSeries::setGlobalSeriesIndex( sal_Int32 nGlobalSeriesIndex
)
344 m_nGlobalSeriesIndex
= nGlobalSeriesIndex
;
347 void VDataSeries::setParticle( const OUString
& rSeriesParticle
)
349 m_aSeriesParticle
= rSeriesParticle
;
352 m_aCID
= ObjectIdentifier::createClassifiedIdentifierForParticle( m_aSeriesParticle
);
353 m_aPointCID_Stub
= ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT
, m_aSeriesParticle
);
355 m_aLabelCID_Stub
= ObjectIdentifier::createClassifiedIdentifierWithParent(
356 OBJECTTYPE_DATA_LABEL
, OUString(), getLabelsCID() );
358 OUString
VDataSeries::getErrorBarsCID(bool bYError
) const
360 OUString
aChildParticle( ObjectIdentifier::getStringForType(
361 bYError
? OBJECTTYPE_DATA_ERRORS_Y
: OBJECTTYPE_DATA_ERRORS_X
)
364 return ObjectIdentifier::createClassifiedIdentifierForParticles(
365 m_aSeriesParticle
, aChildParticle
);
367 OUString
VDataSeries::getLabelsCID() const
369 OUString
aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS
) + "=" );
371 return ObjectIdentifier::createClassifiedIdentifierForParticles(
372 m_aSeriesParticle
, aChildParticle
);
374 OUString
VDataSeries::getDataCurveCID( sal_Int32 nCurveIndex
, bool bAverageLine
) const
376 return ObjectIdentifier::createDataCurveCID( m_aSeriesParticle
, nCurveIndex
, bAverageLine
);
379 OUString
VDataSeries::getDataCurveEquationCID( sal_Int32 nCurveIndex
) const
381 return ObjectIdentifier::createDataCurveEquationCID( m_aSeriesParticle
, nCurveIndex
);
383 void VDataSeries::setPageReferenceSize( const awt::Size
& rPageRefSize
)
385 m_aReferenceSize
= rPageRefSize
;
388 void VDataSeries::setConnectBars( bool bConnectBars
)
390 m_bConnectBars
= bConnectBars
;
393 bool VDataSeries::getConnectBars() const
395 return m_bConnectBars
;
398 void VDataSeries::setGroupBarsPerAxis( bool bGroupBarsPerAxis
)
400 m_bGroupBarsPerAxis
= bGroupBarsPerAxis
;
403 bool VDataSeries::getGroupBarsPerAxis() const
405 return m_bGroupBarsPerAxis
;
408 void VDataSeries::setStartingAngle( sal_Int32 nStartingAngle
)
410 m_nStartingAngle
= nStartingAngle
;
413 sal_Int32
VDataSeries::getStartingAngle() const
415 return m_nStartingAngle
;
418 chart2::StackingDirection
VDataSeries::getStackingDirection() const
420 return m_eStackingDirection
;
423 sal_Int32
VDataSeries::getAttachedAxisIndex() const
428 void VDataSeries::setAttachedAxisIndex( sal_Int32 nAttachedAxisIndex
)
430 if( nAttachedAxisIndex
< 0 )
431 nAttachedAxisIndex
= 0;
432 m_nAxisIndex
= nAttachedAxisIndex
;
435 double VDataSeries::getXValue( sal_Int32 index
) const
440 if( 0<=index
&& index
<m_aValues_X
.getLength() )
442 fRet
= m_aValues_X
.Doubles
[index
];
443 if(mpOldSeries
&& index
< mpOldSeries
->m_aValues_X
.getLength())
445 double nOldVal
= mpOldSeries
->m_aValues_X
.Doubles
[index
];
446 fRet
= nOldVal
+ (fRet
- nOldVal
) * mnPercent
;
450 ::rtl::math::setNan( &fRet
);
454 // #i70133# always return correct X position - needed for short data series
455 if( 0<=index
/*&& index < m_nPointCount*/ )
456 fRet
= index
+1;//first category (index 0) matches with real number 1.0
458 ::rtl::math::setNan( &fRet
);
460 lcl_maybeReplaceNanWithZero( fRet
, getMissingValueTreatment() );
464 double VDataSeries::getYValue( sal_Int32 index
) const
469 if( 0<=index
&& index
<m_aValues_Y
.getLength() )
471 fRet
= m_aValues_Y
.Doubles
[index
];
472 if(mpOldSeries
&& index
< mpOldSeries
->m_aValues_Y
.getLength())
474 double nOldVal
= mpOldSeries
->m_aValues_Y
.Doubles
[index
];
475 fRet
= nOldVal
+ (fRet
- nOldVal
) * mnPercent
;
479 ::rtl::math::setNan( &fRet
);
483 // #i70133# always return correct X position - needed for short data series
484 if( 0<=index
/*&& index < m_nPointCount*/ )
485 fRet
= index
+1;//first category (index 0) matches with real number 1.0
487 ::rtl::math::setNan( &fRet
);
489 lcl_maybeReplaceNanWithZero( fRet
, getMissingValueTreatment() );
493 void VDataSeries::getMinMaxXValue(double& fMin
, double& fMax
) const
495 rtl::math::setNan( &fMax
);
496 rtl::math::setNan( &fMin
);
498 uno::Sequence
< double > aValuesX
= getAllX();
500 if(aValuesX
.hasElements())
503 while ( i
< aValuesX
.getLength() && ::rtl::math::isNan(aValuesX
[i
]) )
505 if ( i
< aValuesX
.getLength() )
506 fMax
= fMin
= aValuesX
[i
++];
508 for ( ; i
< aValuesX
.getLength(); i
++)
510 const double aValue
= aValuesX
[i
];
515 else if ( aValue
< fMin
)
522 double VDataSeries::getY_Min( sal_Int32 index
) const
524 return m_aValues_Y_Min
.getValue( index
);
526 double VDataSeries::getY_Max( sal_Int32 index
) const
528 return m_aValues_Y_Max
.getValue( index
);
530 double VDataSeries::getY_First( sal_Int32 index
) const
532 return m_aValues_Y_First
.getValue( index
);
534 double VDataSeries::getY_Last( sal_Int32 index
) const
536 return m_aValues_Y_Last
.getValue( index
);
538 double VDataSeries::getBubble_Size( sal_Int32 index
) const
540 double nNewVal
= m_aValues_Bubble_Size
.getValue( index
);
541 if(mpOldSeries
&& index
< mpOldSeries
->m_aValues_Bubble_Size
.getLength())
543 double nOldVal
= mpOldSeries
->m_aValues_Bubble_Size
.getValue( index
);
544 nNewVal
= nOldVal
+ (nNewVal
- nOldVal
) * mnPercent
;
550 bool VDataSeries::hasExplicitNumberFormat( sal_Int32 nPointIndex
, bool bForPercentage
) const
552 OUString aPropName
= bForPercentage
? OUString("PercentageNumberFormat") : OUString(CHART_UNONAME_NUMFMT
);
553 bool bHasNumberFormat
= false;
554 uno::Reference
< beans::XPropertySet
> xPointProp( getPropertiesOfPoint( nPointIndex
));
555 sal_Int32 nNumberFormat
= -1;
556 if( xPointProp
.is() && (xPointProp
->getPropertyValue(aPropName
) >>= nNumberFormat
) )
557 bHasNumberFormat
= true;
558 return bHasNumberFormat
;
560 sal_Int32
VDataSeries::getExplicitNumberFormat( sal_Int32 nPointIndex
, bool bForPercentage
) const
562 OUString aPropName
= bForPercentage
? OUString("PercentageNumberFormat") : OUString(CHART_UNONAME_NUMFMT
);
563 sal_Int32 nNumberFormat
= -1;
564 uno::Reference
< beans::XPropertySet
> xPointProp( getPropertiesOfPoint( nPointIndex
));
565 if( xPointProp
.is() )
566 xPointProp
->getPropertyValue(aPropName
) >>= nNumberFormat
;
567 return nNumberFormat
;
569 void VDataSeries::setRoleOfSequenceForDataLabelNumberFormatDetection( const OUString
& rRole
)
571 if (rRole
== "values-y")
572 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y
;
573 else if (rRole
== "values-size")
574 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Bubble_Size
;
575 else if (rRole
== "values-min")
576 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y_Min
;
577 else if (rRole
== "values-max")
578 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y_Max
;
579 else if (rRole
== "values-first")
580 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y_First
;
581 else if (rRole
== "values-last")
582 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_Y_Last
;
583 else if (rRole
== "values-x")
584 m_pValueSequenceForDataLabelNumberFormatDetection
= &m_aValues_X
;
586 bool VDataSeries::shouldLabelNumberFormatKeyBeDetectedFromYAxis() const
588 if( m_pValueSequenceForDataLabelNumberFormatDetection
== &m_aValues_Bubble_Size
)
590 else if( m_pValueSequenceForDataLabelNumberFormatDetection
== &m_aValues_X
)
594 sal_Int32
VDataSeries::detectNumberFormatKey( sal_Int32 index
) const
597 if( m_pValueSequenceForDataLabelNumberFormatDetection
)
598 nRet
= m_pValueSequenceForDataLabelNumberFormatDetection
->detectNumberFormatKey( index
);
602 sal_Int32
VDataSeries::getLabelPlacement( sal_Int32 nPointIndex
, const uno::Reference
< chart2::XChartType
>& xChartType
, bool bSwapXAndY
) const
604 sal_Int32 nLabelPlacement
=0;
607 uno::Reference
< beans::XPropertySet
> xPointProps( getPropertiesOfPoint( nPointIndex
) );
608 if( xPointProps
.is() )
609 xPointProps
->getPropertyValue("LabelPlacement") >>= nLabelPlacement
;
611 //ensure that the set label placement is supported by this charttype
613 uno::Sequence
< sal_Int32
> aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements(
614 xChartType
, bSwapXAndY
, m_xDataSeries
) );
616 for( sal_Int32 nN
= 0; nN
< aAvailablePlacements
.getLength(); nN
++ )
617 if( aAvailablePlacements
[nN
] == nLabelPlacement
)
618 return nLabelPlacement
; //ok
620 //otherwise use the first supported one
621 if( aAvailablePlacements
.hasElements() )
623 nLabelPlacement
= aAvailablePlacements
[0];
624 return nLabelPlacement
;
627 OSL_FAIL("no label placement supported");
629 catch( const uno::Exception
& )
631 TOOLS_WARN_EXCEPTION("chart2", "" );
633 return nLabelPlacement
;
636 double VDataSeries::getMinimumofAllDifferentYValues( sal_Int32 index
) const
639 ::rtl::math::setInf(&fMin
, false);
641 if( !m_aValues_Y
.is() &&
642 (m_aValues_Y_Min
.is() || m_aValues_Y_Max
.is()
643 || m_aValues_Y_First
.is() || m_aValues_Y_Last
.is() ) )
645 double fY_Min
= getY_Min( index
);
646 double fY_Max
= getY_Max( index
);
647 double fY_First
= getY_First( index
);
648 double fY_Last
= getY_Last( index
);
661 double fY
= getYValue( index
);
666 if( ::rtl::math::isInf(fMin
) )
667 ::rtl::math::setNan(&fMin
);
672 double VDataSeries::getMaximumofAllDifferentYValues( sal_Int32 index
) const
675 ::rtl::math::setInf(&fMax
, true);
677 if( !m_aValues_Y
.is() &&
678 (m_aValues_Y_Min
.is() || m_aValues_Y_Max
.is()
679 || m_aValues_Y_First
.is() || m_aValues_Y_Last
.is() ) )
681 double fY_Min
= getY_Min( index
);
682 double fY_Max
= getY_Max( index
);
683 double fY_First
= getY_First( index
);
684 double fY_Last
= getY_Last( index
);
697 double fY
= getYValue( index
);
702 if( ::rtl::math::isInf(fMax
) )
703 ::rtl::math::setNan(&fMax
);
708 uno::Sequence
< double > const & VDataSeries::getAllX() const
710 if(!m_aValues_X
.is() && !m_aValues_X
.getLength() && m_nPointCount
)
712 //init x values from category indexes
713 //first category (index 0) matches with real number 1.0
714 m_aValues_X
.Doubles
.realloc( m_nPointCount
);
715 for(sal_Int32 nN
=m_aValues_X
.getLength();nN
--;)
716 m_aValues_X
.Doubles
[nN
] = nN
+1;
718 return m_aValues_X
.Doubles
;
721 uno::Sequence
< double > const & VDataSeries::getAllY() const
723 if(!m_aValues_Y
.is() && !m_aValues_Y
.getLength() && m_nPointCount
)
725 //init y values from indexes
726 //first y-value (index 0) matches with real number 1.0
727 m_aValues_Y
.Doubles
.realloc( m_nPointCount
);
728 for(sal_Int32 nN
=m_aValues_Y
.getLength();nN
--;)
729 m_aValues_Y
.Doubles
[nN
] = nN
+1;
731 return m_aValues_Y
.Doubles
;
734 double VDataSeries::getXMeanValue() const
736 if( ::rtl::math::isNan( m_fXMeanValue
) )
738 uno::Reference
< XRegressionCurveCalculator
> xCalculator( RegressionCurveHelper::createRegressionCurveCalculatorByServiceName( "com.sun.star.chart2.MeanValueRegressionCurve" ) );
739 uno::Sequence
< double > aXValuesDummy
;
740 xCalculator
->recalculateRegression( aXValuesDummy
, getAllX() );
741 m_fXMeanValue
= xCalculator
->getCurveValue( 1.0 );
743 return m_fXMeanValue
;
746 double VDataSeries::getYMeanValue() const
748 if( ::rtl::math::isNan( m_fYMeanValue
) )
750 uno::Reference
< XRegressionCurveCalculator
> xCalculator(
751 RegressionCurveHelper::createRegressionCurveCalculatorByServiceName("com.sun.star.chart2.MeanValueRegressionCurve"));
752 uno::Sequence
< double > aXValuesDummy
;
753 xCalculator
->recalculateRegression( aXValuesDummy
, getAllY() );
754 m_fYMeanValue
= xCalculator
->getCurveValue( 1.0 );
756 return m_fYMeanValue
;
759 static std::unique_ptr
<Symbol
> getSymbolPropertiesFromPropertySet( const uno::Reference
< beans::XPropertySet
>& xProp
)
761 std::unique_ptr
< Symbol
> apSymbolProps( new Symbol() );
764 if( xProp
->getPropertyValue("Symbol") >>= *apSymbolProps
)
766 //use main color to fill symbols
767 xProp
->getPropertyValue("Color") >>= apSymbolProps
->FillColor
;
768 // border of symbols always same as fill color
769 apSymbolProps
->BorderColor
= apSymbolProps
->FillColor
;
772 apSymbolProps
.reset();
774 catch(const uno::Exception
&)
776 TOOLS_WARN_EXCEPTION("chart2", "" );
778 return apSymbolProps
;
781 Symbol
* VDataSeries::getSymbolProperties( sal_Int32 index
) const
783 Symbol
* pRet
=nullptr;
784 if( isAttributedDataPoint( index
) )
786 adaptPointCache( index
);
787 if (!m_apSymbolProperties_AttributedPoint
)
788 m_apSymbolProperties_AttributedPoint
789 = getSymbolPropertiesFromPropertySet(getPropertiesOfPoint(index
));
790 pRet
= m_apSymbolProperties_AttributedPoint
.get();
791 //if a single data point does not have symbols but the dataseries itself has symbols
792 //we create an invisible symbol shape to enable selection of that point
793 if( !pRet
|| pRet
->Style
== SymbolStyle_NONE
)
795 if (!m_apSymbolProperties_Series
)
796 m_apSymbolProperties_Series
797 = getSymbolPropertiesFromPropertySet(getPropertiesOfSeries());
798 if( m_apSymbolProperties_Series
.get() && m_apSymbolProperties_Series
->Style
!= SymbolStyle_NONE
)
800 if (!m_apSymbolProperties_InvisibleSymbolForSelection
)
802 m_apSymbolProperties_InvisibleSymbolForSelection
.reset(new Symbol
);
803 m_apSymbolProperties_InvisibleSymbolForSelection
->Style
= SymbolStyle_STANDARD
;
804 m_apSymbolProperties_InvisibleSymbolForSelection
->StandardSymbol
= 0;//square
805 m_apSymbolProperties_InvisibleSymbolForSelection
->Size
= com::sun::star::awt::Size(0, 0);//tdf#126033
806 m_apSymbolProperties_InvisibleSymbolForSelection
->BorderColor
= 0xff000000;//invisible
807 m_apSymbolProperties_InvisibleSymbolForSelection
->FillColor
= 0xff000000;//invisible
809 pRet
= m_apSymbolProperties_InvisibleSymbolForSelection
.get();
815 if (!m_apSymbolProperties_Series
)
816 m_apSymbolProperties_Series
817 = getSymbolPropertiesFromPropertySet(getPropertiesOfSeries());
818 pRet
= m_apSymbolProperties_Series
.get();
821 if( pRet
&& pRet
->Style
== SymbolStyle_AUTO
)
823 pRet
->Style
= SymbolStyle_STANDARD
;
825 sal_Int32 nIndex
= m_nGlobalSeriesIndex
;
828 pRet
->StandardSymbol
= nIndex
;
834 uno::Reference
< beans::XPropertySet
> VDataSeries::getXErrorBarProperties( sal_Int32 index
) const
836 uno::Reference
< beans::XPropertySet
> xErrorBarProp
;
838 uno::Reference
< beans::XPropertySet
> xPointProp( getPropertiesOfPoint( index
));
839 if( xPointProp
.is() )
840 xPointProp
->getPropertyValue(CHART_UNONAME_ERRORBAR_X
) >>= xErrorBarProp
;
841 return xErrorBarProp
;
844 uno::Reference
< beans::XPropertySet
> VDataSeries::getYErrorBarProperties( sal_Int32 index
) const
846 uno::Reference
< beans::XPropertySet
> xErrorBarProp
;
848 uno::Reference
< beans::XPropertySet
> xPointProp( getPropertiesOfPoint( index
));
849 if( xPointProp
.is() )
850 xPointProp
->getPropertyValue(CHART_UNONAME_ERRORBAR_Y
) >>= xErrorBarProp
;
851 return xErrorBarProp
;
854 bool VDataSeries::hasPointOwnColor( sal_Int32 index
) const
856 if( !isAttributedDataPoint(index
) )
861 uno::Reference
< beans::XPropertyState
> xPointState( getPropertiesOfPoint(index
), uno::UNO_QUERY_THROW
);
862 return (xPointState
->getPropertyState("Color") != beans::PropertyState_DEFAULT_VALUE
);
864 catch(const uno::Exception
&)
866 TOOLS_WARN_EXCEPTION("chart2", "" );
871 bool VDataSeries::isAttributedDataPoint( sal_Int32 index
) const
873 //returns true if the data point assigned by the given index has set its own properties
874 if( index
>=m_nPointCount
|| m_nPointCount
==0)
876 for(sal_Int32 nN
=m_aAttributedDataPointIndexList
.getLength();nN
--;)
878 if(index
==m_aAttributedDataPointIndexList
[nN
])
884 bool VDataSeries::isVaryColorsByPoint() const
886 bool bVaryColorsByPoint
= false;
887 Reference
< beans::XPropertySet
> xSeriesProp( getPropertiesOfSeries() );
888 if( xSeriesProp
.is() )
889 xSeriesProp
->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint
;
890 return bVaryColorsByPoint
;
893 uno::Reference
< beans::XPropertySet
> VDataSeries::getPropertiesOfPoint( sal_Int32 index
) const
895 if( isAttributedDataPoint( index
) )
896 return m_xDataSeries
->getDataPointByIndex(index
);
897 return getPropertiesOfSeries();
900 uno::Reference
<beans::XPropertySet
> VDataSeries::getPropertiesOfSeries() const
902 return uno::Reference
<css::beans::XPropertySet
>(m_xDataSeries
, css::uno::UNO_QUERY
);
905 static std::unique_ptr
<DataPointLabel
> getDataPointLabelFromPropertySet( const uno::Reference
< beans::XPropertySet
>& xProp
)
907 std::unique_ptr
< DataPointLabel
> apLabel( new DataPointLabel() );
910 if( !(xProp
->getPropertyValue(CHART_UNONAME_LABEL
) >>= *apLabel
) )
913 catch(const uno::Exception
&)
915 TOOLS_WARN_EXCEPTION("chart2", "" );
920 void VDataSeries::adaptPointCache( sal_Int32 nNewPointIndex
) const
922 if( m_nCurrentAttributedPoint
!= nNewPointIndex
)
924 m_apLabel_AttributedPoint
.reset();
925 m_apLabelPropNames_AttributedPoint
.reset();
926 m_apLabelPropValues_AttributedPoint
.reset();
927 m_apSymbolProperties_AttributedPoint
.reset();
928 m_nCurrentAttributedPoint
= nNewPointIndex
;
932 DataPointLabel
* VDataSeries::getDataPointLabel( sal_Int32 index
) const
934 DataPointLabel
* pRet
= nullptr;
935 if( isAttributedDataPoint( index
) )
937 adaptPointCache( index
);
938 if (!m_apLabel_AttributedPoint
)
939 m_apLabel_AttributedPoint
940 = getDataPointLabelFromPropertySet(getPropertiesOfPoint(index
));
941 pRet
= m_apLabel_AttributedPoint
.get();
945 if (!m_apLabel_Series
)
947 = getDataPointLabelFromPropertySet(getPropertiesOfPoint(index
));
948 pRet
= m_apLabel_Series
.get();
950 if( !m_bAllowPercentValueInDataLabel
)
953 pRet
->ShowNumberInPercent
= false;
958 DataPointLabel
* VDataSeries::getDataPointLabelIfLabel( sal_Int32 index
) const
960 DataPointLabel
* pLabel
= getDataPointLabel( index
);
961 if( !pLabel
|| (!pLabel
->ShowNumber
&& !pLabel
->ShowNumberInPercent
962 && !pLabel
->ShowCategoryName
) )
967 bool VDataSeries::getTextLabelMultiPropertyLists( sal_Int32 index
968 , tNameSequence
*& pPropNames
969 , tAnySequence
*& pPropValues
) const
971 pPropNames
= nullptr; pPropValues
= nullptr;
972 uno::Reference
< beans::XPropertySet
> xTextProp
;
973 bool bDoDynamicFontResize
= false;
974 if( isAttributedDataPoint( index
) )
976 adaptPointCache( index
);
977 if (!m_apLabelPropValues_AttributedPoint
)
979 // Cache these properties for this point.
980 m_apLabelPropNames_AttributedPoint
.reset(new tNameSequence
);
981 m_apLabelPropValues_AttributedPoint
.reset(new tAnySequence
);
982 xTextProp
.set( getPropertiesOfPoint( index
));
983 PropertyMapper::getTextLabelMultiPropertyLists(
984 xTextProp
, *m_apLabelPropNames_AttributedPoint
, *m_apLabelPropValues_AttributedPoint
);
985 bDoDynamicFontResize
= true;
987 pPropNames
= m_apLabelPropNames_AttributedPoint
.get();
988 pPropValues
= m_apLabelPropValues_AttributedPoint
.get();
992 if (!m_apLabelPropValues_Series
)
994 // Cache these properties for the whole series.
995 m_apLabelPropNames_Series
.reset(new tNameSequence
);
996 m_apLabelPropValues_Series
.reset(new tAnySequence
);
997 xTextProp
.set( getPropertiesOfPoint( index
));
998 PropertyMapper::getTextLabelMultiPropertyLists(
999 xTextProp
, *m_apLabelPropNames_Series
, *m_apLabelPropValues_Series
);
1000 bDoDynamicFontResize
= true;
1002 pPropNames
= m_apLabelPropNames_Series
.get();
1003 pPropValues
= m_apLabelPropValues_Series
.get();
1006 if( bDoDynamicFontResize
&&
1007 pPropNames
&& pPropValues
&&
1010 LabelPositionHelper::doDynamicFontResize( *pPropValues
, *pPropNames
, xTextProp
, m_aReferenceSize
);
1013 return (pPropNames
&& pPropValues
);
1016 void VDataSeries::setMissingValueTreatment( sal_Int32 nMissingValueTreatment
)
1018 m_nMissingValueTreatment
= nMissingValueTreatment
;
1021 sal_Int32
VDataSeries::getMissingValueTreatment() const
1023 return m_nMissingValueTreatment
;
1026 VDataSeries::VDataSeries()
1027 : m_nPolygonIndex(0)
1032 , m_pValueSequenceForDataLabelNumberFormatDetection(nullptr)
1035 , m_eStackingDirection(chart2::StackingDirection_NO_STACKING
)
1037 , m_bConnectBars(false)
1038 , m_bGroupBarsPerAxis(false)
1039 , m_nStartingAngle(0)
1040 , m_nGlobalSeriesIndex(0)
1041 , m_nCurrentAttributedPoint(0)
1042 , m_nMissingValueTreatment(0)
1043 , m_bAllowPercentValueInDataLabel(false)
1044 , mpOldSeries(nullptr)
1049 void VDataSeries::setOldTimeBased( VDataSeries
* pOldSeries
, double nPercent
)
1051 mnPercent
= nPercent
;
1052 mpOldSeries
= pOldSeries
;
1053 mpOldSeries
->mpOldSeries
= nullptr;
1056 VDataSeries
* VDataSeries::createCopyForTimeBased() const
1058 VDataSeries
* pNew
= new VDataSeries();
1059 pNew
->m_aValues_X
= m_aValues_X
;
1060 pNew
->m_aValues_Y
= m_aValues_Y
;
1061 pNew
->m_aValues_Z
= m_aValues_Z
;
1062 pNew
->m_aValues_Y_Min
= m_aValues_Y_Min
;
1063 pNew
->m_aValues_Y_Max
= m_aValues_Y_Max
;
1064 pNew
->m_aValues_Y_First
= m_aValues_Y_First
;
1065 pNew
->m_aValues_Y_Last
= m_aValues_Y_Last
;
1066 pNew
->m_aValues_Bubble_Size
= m_aValues_Bubble_Size
;
1067 pNew
->m_PropertyMap
= m_PropertyMap
;
1069 pNew
->m_nPointCount
= m_nPointCount
;
1074 double VDataSeries::getValueByProperty( sal_Int32 nIndex
, const OUString
& rPropName
) const
1076 auto const itr
= m_PropertyMap
.find(rPropName
);
1077 if (itr
== m_PropertyMap
.end())
1080 ::rtl::math::setNan( &fNan
);
1084 const VDataSequence
* pData
= &itr
->second
;
1085 double fValue
= pData
->getValue(nIndex
);
1086 if(mpOldSeries
&& mpOldSeries
->hasPropertyMapping(rPropName
))
1088 double fOldValue
= mpOldSeries
->getValueByProperty( nIndex
, rPropName
);
1089 if(rPropName
.endsWith("Color"))
1091 //optimized interpolation for color values
1092 Color
aColor(static_cast<sal_uInt32
>(fValue
));
1093 Color
aOldColor(static_cast<sal_uInt32
>(fOldValue
));
1094 sal_uInt8 r
= aOldColor
.GetRed() + (aColor
.GetRed() - aOldColor
.GetRed()) * mnPercent
;
1095 sal_uInt8 g
= aOldColor
.GetGreen() + (aColor
.GetGreen() - aOldColor
.GetGreen()) * mnPercent
;
1096 sal_uInt8 b
= aOldColor
.GetBlue() + (aColor
.GetBlue() - aOldColor
.GetBlue()) * mnPercent
;
1097 sal_uInt8 t
= aOldColor
.GetTransparency() + (aColor
.GetTransparency() - aOldColor
.GetTransparency()) * mnPercent
;
1098 Color
aRet(t
, r
, g
, b
);
1099 return sal_uInt32(aRet
);
1101 return fOldValue
+ (fValue
- fOldValue
) * mnPercent
;
1106 bool VDataSeries::hasPropertyMapping(const OUString
& rPropName
) const
1108 return m_PropertyMap
.find(rPropName
) != m_PropertyMap
.end();
1113 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */