Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / chart2 / source / view / main / VDataSeries.cxx
blob0f2749a1f6c782a41b81487d072a775f7cc3f87b
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 <memory>
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>
44 namespace chart {
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 )
52 Model = xModel;
53 Doubles = DataSequenceToDoubleSequence( xModel );
56 bool VDataSequence::is() const
58 return Model.is();
60 void VDataSequence::clear()
62 Model = nullptr;
63 Doubles.realloc(0);
66 double VDataSequence::getValue( sal_Int32 index ) const
68 if( 0<=index && index<Doubles.getLength() )
69 return Doubles[index];
70 else
72 double fNan;
73 ::rtl::math::setNan( & fNan );
74 return 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() &&
84 Model.is())
86 nNumberFormatKey = Model->getNumberFormatKeyByIndex( index );
89 return nNumberFormatKey;
92 sal_Int32 VDataSequence::getLength() const
94 return Doubles.getLength();
97 namespace
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];
108 return false;
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] ) )
119 return;
121 //no double value is contained
122 //is there any text?
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() )
129 rData.clear();
130 return;
133 //no content at all
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)) )
140 rfValue = 0.0;
145 VDataSeries::VDataSeries( const uno::Reference< XDataSeries >& xDataSeries )
146 : m_nPolygonIndex(0)
147 , m_fLogicMinX(0.0)
148 , m_fLogicMaxX(0.0)
149 , m_fLogicZPos(0.0)
150 , m_xDataSeries(xDataSeries)
151 , m_nPointCount(0)
153 , m_pValueSequenceForDataLabelNumberFormatDetection(&m_aValues_Y)
155 , m_fXMeanValue(1.0)
156 , m_fYMeanValue(1.0)
158 , m_aAttributedDataPointIndexList()
160 , m_eStackingDirection(StackingDirection_NO_STACKING)
161 , m_nAxisIndex(0)
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)
172 , mnPercent(0.0)
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())
186 continue;
187 uno::Reference<data::XDataSequence> xDataSequence( aDataSequences[nN]->getValues());
188 uno::Reference<beans::XPropertySet> xProp(xDataSequence, uno::UNO_QUERY );
189 if( xProp.is())
193 uno::Any aARole = xProp->getPropertyValue("Role");
194 OUString aRole;
195 aARole >>= aRole;
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 );
214 else
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 );
244 if( xProp.is())
248 //get AttributedDataPoints
249 xProp->getPropertyValue("AttributedDataPoints") >>= m_aAttributedDataPointIndexList;
251 xProp->getPropertyValue("StackingDirection") >>= m_eStackingDirection;
253 xProp->getPropertyValue("AttachedAxisIndex") >>= m_nAxisIndex;
254 if(m_nAxisIndex<0)
255 m_nAxisIndex=0;
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
274 double fNan;
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 );
285 //do sort
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);
312 m_nPolygonIndex = 0;
315 const uno::Reference<css::chart2::XDataSeries>& VDataSeries::getModel() const
317 return m_xDataSeries;
320 void VDataSeries::setCategoryXAxis()
322 m_aValues_X.clear();
323 m_bAllowPercentValueInDataLabel = true;
326 void VDataSeries::setXValues( const Reference< chart2::data::XDataSequence >& xValues )
328 m_aValues_X.clear();
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() )
336 return;
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;
351 //get CID
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 )
362 + "=" );
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
425 return m_nAxisIndex;
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
437 double fRet = 0.0;
438 if(m_aValues_X.is())
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;
449 else
450 ::rtl::math::setNan( &fRet );
452 else
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
457 else
458 ::rtl::math::setNan( &fRet );
460 lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() );
461 return fRet;
464 double VDataSeries::getYValue( sal_Int32 index ) const
466 double fRet = 0.0;
467 if(m_aValues_Y.is())
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;
478 else
479 ::rtl::math::setNan( &fRet );
481 else
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
486 else
487 ::rtl::math::setNan( &fRet );
489 lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() );
490 return fRet;
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())
502 sal_Int32 i = 0;
503 while ( i < aValuesX.getLength() && ::rtl::math::isNan(aValuesX[i]) )
504 i++;
505 if ( i < aValuesX.getLength() )
506 fMax = fMin = aValuesX[i++];
508 for ( ; i < aValuesX.getLength(); i++)
510 const double aValue = aValuesX[i];
511 if ( aValue > fMax)
513 fMax = aValue;
515 else if ( aValue < fMin)
517 fMin = aValue;
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;
547 return nNewVal;
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 )
589 return false;
590 else if( m_pValueSequenceForDataLabelNumberFormatDetection == &m_aValues_X )
591 return false;
592 return true;
594 sal_Int32 VDataSeries::detectNumberFormatKey( sal_Int32 index ) const
596 sal_Int32 nRet = 0;
597 if( m_pValueSequenceForDataLabelNumberFormatDetection )
598 nRet = m_pValueSequenceForDataLabelNumberFormatDetection->detectNumberFormatKey( index );
599 return nRet;
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
638 double fMin=0.0;
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 );
650 if(fMin>fY_First)
651 fMin=fY_First;
652 if(fMin>fY_Last)
653 fMin=fY_Last;
654 if(fMin>fY_Min)
655 fMin=fY_Min;
656 if(fMin>fY_Max)
657 fMin=fY_Max;
659 else
661 double fY = getYValue( index );
662 if(fMin>fY)
663 fMin=fY;
666 if( ::rtl::math::isInf(fMin) )
667 ::rtl::math::setNan(&fMin);
669 return fMin;
672 double VDataSeries::getMaximumofAllDifferentYValues( sal_Int32 index ) const
674 double fMax=0.0;
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 );
686 if(fMax<fY_First)
687 fMax=fY_First;
688 if(fMax<fY_Last)
689 fMax=fY_Last;
690 if(fMax<fY_Min)
691 fMax=fY_Min;
692 if(fMax<fY_Max)
693 fMax=fY_Max;
695 else
697 double fY = getYValue( index );
698 if(fMax<fY)
699 fMax=fY;
702 if( ::rtl::math::isInf(fMax) )
703 ::rtl::math::setNan(&fMax);
705 return 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;
771 else
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();
813 else
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;
826 if(m_aValues_X.is())
827 nIndex++;
828 pRet->StandardSymbol = nIndex;
831 return pRet;
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) )
857 return false;
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", "" );
868 return false;
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)
875 return false;
876 for(sal_Int32 nN=m_aAttributedDataPointIndexList.getLength();nN--;)
878 if(index==m_aAttributedDataPointIndexList[nN])
879 return true;
881 return false;
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) )
911 apLabel.reset();
913 catch(const uno::Exception &)
915 TOOLS_WARN_EXCEPTION("chart2", "" );
917 return apLabel;
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();
943 else
945 if (!m_apLabel_Series)
946 m_apLabel_Series
947 = getDataPointLabelFromPropertySet(getPropertiesOfPoint(index));
948 pRet = m_apLabel_Series.get();
950 if( !m_bAllowPercentValueInDataLabel )
952 if( pRet )
953 pRet->ShowNumberInPercent = false;
955 return pRet;
958 DataPointLabel* VDataSeries::getDataPointLabelIfLabel( sal_Int32 index ) const
960 DataPointLabel* pLabel = getDataPointLabel( index );
961 if( !pLabel || (!pLabel->ShowNumber && !pLabel->ShowNumberInPercent
962 && !pLabel->ShowCategoryName ) )
963 return nullptr;
964 return pLabel;
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();
990 else
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 &&
1008 xTextProp.is())
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)
1028 , m_fLogicMinX(0)
1029 , m_fLogicMaxX(0)
1030 , m_fLogicZPos(0)
1031 , m_nPointCount(0)
1032 , m_pValueSequenceForDataLabelNumberFormatDetection(nullptr)
1033 , m_fXMeanValue(0)
1034 , m_fYMeanValue(0)
1035 , m_eStackingDirection(chart2::StackingDirection_NO_STACKING)
1036 , m_nAxisIndex(0)
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)
1045 , mnPercent(0)
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;
1071 return pNew;
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())
1079 double fNan;
1080 ::rtl::math::setNan( &fNan );
1081 return 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;
1103 return fValue;
1106 bool VDataSeries::hasPropertyMapping(const OUString& rPropName ) const
1108 return m_PropertyMap.find(rPropName) != m_PropertyMap.end();
1111 } //namespace chart
1113 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */