Remove non-const Sequence::begin()/end() in internal code
[LibreOffice.git] / chart2 / source / view / main / VDataSeries.cxx
blob0d3123a8cb132d1df22ef3be392f59108ef7498e
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 <limits>
21 #include <memory>
22 #include <VDataSeries.hxx>
23 #include <ObjectIdentifier.hxx>
24 #include <CommonConverters.hxx>
25 #include <LabelPositionHelper.hxx>
26 #include <ChartTypeHelper.hxx>
27 #include <RegressionCurveHelper.hxx>
28 #include <unonames.hxx>
30 #include <com/sun/star/chart/MissingValueTreatment.hpp>
31 #include <com/sun/star/chart2/DataPointLabel.hpp>
32 #include <com/sun/star/chart2/Symbol.hpp>
33 #include <com/sun/star/chart2/XDataSeries.hpp>
34 #include <com/sun/star/chart2/XRegressionCurveCalculator.hpp>
35 #include <com/sun/star/chart2/RelativePosition.hpp>
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 return std::numeric_limits<double>::quiet_NaN();
73 sal_Int32 VDataSequence::detectNumberFormatKey( sal_Int32 index ) const
75 sal_Int32 nNumberFormatKey = -1;
77 // -1 is allowed and means a key for the whole sequence
78 if( -1<=index && index<Doubles.getLength() &&
79 Model.is())
81 nNumberFormatKey = Model->getNumberFormatKeyByIndex( index );
84 return nNumberFormatKey;
87 sal_Int32 VDataSequence::getLength() const
89 return Doubles.getLength();
92 namespace
94 struct lcl_LessXOfPoint
96 bool operator() ( const std::vector< double >& first,
97 const std::vector< double >& second )
99 if( !first.empty() && !second.empty() )
101 return first[0]<second[0];
103 return false;
107 void lcl_clearIfNoValuesButTextIsContained( VDataSequence& rData, const uno::Reference<data::XDataSequence>& xDataSequence )
109 //#i71686#, #i101968#, #i102428#
110 sal_Int32 nCount = rData.Doubles.getLength();
111 for( sal_Int32 i = 0; i < nCount; ++i )
113 if( !std::isnan( rData.Doubles[i] ) )
114 return;
116 //no double value is contained
117 //is there any text?
118 uno::Sequence< OUString > aStrings( DataSequenceToStringSequence( xDataSequence ) );
119 sal_Int32 nTextCount = aStrings.getLength();
120 for( sal_Int32 j = 0; j < nTextCount; ++j )
122 if( !aStrings[j].isEmpty() )
124 rData.clear();
125 return;
128 //no content at all
131 void lcl_maybeReplaceNanWithZero( double& rfValue, sal_Int32 nMissingValueTreatment )
133 if( nMissingValueTreatment == css::chart::MissingValueTreatment::USE_ZERO
134 && (std::isnan(rfValue) || std::isinf(rfValue)) )
135 rfValue = 0.0;
140 VDataSeries::VDataSeries( const uno::Reference< XDataSeries >& xDataSeries )
141 : m_nPolygonIndex(0)
142 , m_fLogicMinX(0.0)
143 , m_fLogicMaxX(0.0)
144 , m_fLogicZPos(0.0)
145 , m_xDataSeries(xDataSeries)
146 , m_nPointCount(0)
147 , m_pValueSequenceForDataLabelNumberFormatDetection(&m_aValues_Y)
148 , m_fXMeanValue(std::numeric_limits<double>::quiet_NaN())
149 , m_fYMeanValue(std::numeric_limits<double>::quiet_NaN())
150 , m_eStackingDirection(StackingDirection_NO_STACKING)
151 , m_nAxisIndex(0)
152 , m_bConnectBars(false)
153 , m_bGroupBarsPerAxis(true)
154 , m_nStartingAngle(90)
155 , m_nGlobalSeriesIndex(0)
156 , m_nCurrentAttributedPoint(-1)
157 , m_nMissingValueTreatment(css::chart::MissingValueTreatment::LEAVE_GAP)
158 , m_bAllowPercentValueInDataLabel(false)
159 , mpOldSeries(nullptr)
160 , mnPercent(0.0)
162 uno::Reference<data::XDataSource> xDataSource( xDataSeries, uno::UNO_QUERY );
164 uno::Sequence< uno::Reference<
165 chart2::data::XLabeledDataSequence > > aDataSequences =
166 xDataSource->getDataSequences();
168 for(sal_Int32 nN = aDataSequences.getLength();nN--;)
170 if(!aDataSequences[nN].is())
171 continue;
172 uno::Reference<data::XDataSequence> xDataSequence( aDataSequences[nN]->getValues());
173 uno::Reference<beans::XPropertySet> xProp(xDataSequence, uno::UNO_QUERY );
174 if( xProp.is())
178 uno::Any aARole = xProp->getPropertyValue("Role");
179 OUString aRole;
180 aARole >>= aRole;
182 if (aRole == "values-x")
184 m_aValues_X.init( xDataSequence );
185 lcl_clearIfNoValuesButTextIsContained( m_aValues_X, xDataSequence );
187 else if (aRole =="values-y")
188 m_aValues_Y.init( xDataSequence );
189 else if (aRole == "values-min")
190 m_aValues_Y_Min.init( xDataSequence );
191 else if (aRole == "values-max")
192 m_aValues_Y_Max.init( xDataSequence );
193 else if (aRole == "values-first")
194 m_aValues_Y_First.init( xDataSequence );
195 else if (aRole == "values-last")
196 m_aValues_Y_Last.init( xDataSequence );
197 else if (aRole == "values-size")
198 m_aValues_Bubble_Size.init( xDataSequence );
199 else
201 VDataSequence aSequence;
202 aSequence.init(xDataSequence);
203 m_PropertyMap.insert(std::make_pair(aRole, aSequence));
206 catch( const uno::Exception& )
208 TOOLS_WARN_EXCEPTION("chart2", "" );
213 //determine the point count
214 m_nPointCount = m_aValues_Y.getLength();
216 if( m_nPointCount < m_aValues_Bubble_Size.getLength() )
217 m_nPointCount = m_aValues_Bubble_Size.getLength();
218 if( m_nPointCount < m_aValues_Y_Min.getLength() )
219 m_nPointCount = m_aValues_Y_Min.getLength();
220 if( m_nPointCount < m_aValues_Y_Max.getLength() )
221 m_nPointCount = m_aValues_Y_Max.getLength();
222 if( m_nPointCount < m_aValues_Y_First.getLength() )
223 m_nPointCount = m_aValues_Y_First.getLength();
224 if( m_nPointCount < m_aValues_Y_Last.getLength() )
225 m_nPointCount = m_aValues_Y_Last.getLength();
228 uno::Reference<beans::XPropertySet> xProp(xDataSeries, uno::UNO_QUERY );
229 if( !xProp.is())
230 return;
234 //get AttributedDataPoints
235 xProp->getPropertyValue("AttributedDataPoints") >>= m_aAttributedDataPointIndexList;
237 xProp->getPropertyValue("StackingDirection") >>= m_eStackingDirection;
239 xProp->getPropertyValue("AttachedAxisIndex") >>= m_nAxisIndex;
240 if(m_nAxisIndex<0)
241 m_nAxisIndex=0;
243 catch( const uno::Exception& )
245 TOOLS_WARN_EXCEPTION("chart2", "" );
249 VDataSeries::~VDataSeries()
253 void VDataSeries::doSortByXValues()
255 if( !(m_aValues_X.is() && m_aValues_X.Doubles.hasElements()) )
256 return;
258 //prepare a vector for sorting
259 std::vector< std::vector< double > > aTmp;//outer vector are points, inner vector are the different values of the point
260 sal_Int32 nPointIndex = 0;
261 for( nPointIndex=0; nPointIndex < m_nPointCount; nPointIndex++ )
263 aTmp.push_back(
264 { ((nPointIndex < m_aValues_X.Doubles.getLength()) ? m_aValues_X.Doubles[nPointIndex]
265 : std::numeric_limits<double>::quiet_NaN()),
266 ((nPointIndex < m_aValues_Y.Doubles.getLength()) ? m_aValues_Y.Doubles[nPointIndex]
267 : std::numeric_limits<double>::quiet_NaN())
272 //do sort
273 std::stable_sort( aTmp.begin(), aTmp.end(), lcl_LessXOfPoint() );
275 //fill the sorted points back to the members
276 m_aValues_X.Doubles.realloc( m_nPointCount );
277 m_aValues_Y.Doubles.realloc( m_nPointCount );
279 for( nPointIndex=0; nPointIndex < m_nPointCount; nPointIndex++ )
281 m_aValues_X.Doubles[nPointIndex]=aTmp[nPointIndex][0];
282 m_aValues_Y.Doubles[nPointIndex]=aTmp[nPointIndex][1];
286 void VDataSeries::releaseShapes()
288 m_xGroupShape.set(nullptr);
289 m_xLabelsGroupShape.set(nullptr);
290 m_xErrorXBarsGroupShape.set(nullptr);
291 m_xErrorYBarsGroupShape.set(nullptr);
292 m_xFrontSubGroupShape.set(nullptr);
293 m_xBackSubGroupShape.set(nullptr);
295 m_aPolyPolygonShape3D.SequenceX.realloc(0);
296 m_aPolyPolygonShape3D.SequenceY.realloc(0);
297 m_aPolyPolygonShape3D.SequenceZ.realloc(0);
298 m_nPolygonIndex = 0;
301 const uno::Reference<css::chart2::XDataSeries>& VDataSeries::getModel() const
303 return m_xDataSeries;
306 void VDataSeries::setCategoryXAxis()
308 m_aValues_X.clear();
309 m_bAllowPercentValueInDataLabel = true;
312 void VDataSeries::setXValues( const Reference< chart2::data::XDataSequence >& xValues )
314 m_aValues_X.clear();
315 m_aValues_X.init( xValues );
316 m_bAllowPercentValueInDataLabel = true;
319 void VDataSeries::setXValuesIfNone( const Reference< chart2::data::XDataSequence >& xValues )
321 if( m_aValues_X.is() )
322 return;
324 m_aValues_X.init( xValues );
325 lcl_clearIfNoValuesButTextIsContained( m_aValues_X, xValues );
328 void VDataSeries::setGlobalSeriesIndex( sal_Int32 nGlobalSeriesIndex )
330 m_nGlobalSeriesIndex = nGlobalSeriesIndex;
333 void VDataSeries::setParticle( const OUString& rSeriesParticle )
335 m_aSeriesParticle = rSeriesParticle;
337 //get CID
338 m_aCID = ObjectIdentifier::createClassifiedIdentifierForParticle( m_aSeriesParticle );
339 m_aPointCID_Stub = ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT, m_aSeriesParticle );
341 m_aLabelCID_Stub = ObjectIdentifier::createClassifiedIdentifierWithParent(
342 OBJECTTYPE_DATA_LABEL, u"", getLabelsCID() );
344 OUString VDataSeries::getErrorBarsCID(bool bYError) const
346 OUString aChildParticle( ObjectIdentifier::getStringForType(
347 bYError ? OBJECTTYPE_DATA_ERRORS_Y : OBJECTTYPE_DATA_ERRORS_X )
348 + "=" );
350 return ObjectIdentifier::createClassifiedIdentifierForParticles(
351 m_aSeriesParticle, aChildParticle );
353 OUString VDataSeries::getLabelsCID() const
355 OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) + "=" );
357 return ObjectIdentifier::createClassifiedIdentifierForParticles(
358 m_aSeriesParticle, aChildParticle );
360 OUString VDataSeries::getDataCurveCID( sal_Int32 nCurveIndex, bool bAverageLine ) const
362 return ObjectIdentifier::createDataCurveCID( m_aSeriesParticle, nCurveIndex, bAverageLine );
365 OUString VDataSeries::getDataCurveEquationCID( sal_Int32 nCurveIndex ) const
367 return ObjectIdentifier::createDataCurveEquationCID( m_aSeriesParticle, nCurveIndex );
369 void VDataSeries::setPageReferenceSize( const awt::Size & rPageRefSize )
371 m_aReferenceSize = rPageRefSize;
374 void VDataSeries::setConnectBars( bool bConnectBars )
376 m_bConnectBars = bConnectBars;
379 bool VDataSeries::getConnectBars() const
381 return m_bConnectBars;
384 void VDataSeries::setGroupBarsPerAxis( bool bGroupBarsPerAxis )
386 m_bGroupBarsPerAxis = bGroupBarsPerAxis;
389 bool VDataSeries::getGroupBarsPerAxis() const
391 return m_bGroupBarsPerAxis;
394 void VDataSeries::setStartingAngle( sal_Int32 nStartingAngle )
396 m_nStartingAngle = nStartingAngle;
399 sal_Int32 VDataSeries::getStartingAngle() const
401 return m_nStartingAngle;
404 chart2::StackingDirection VDataSeries::getStackingDirection() const
406 return m_eStackingDirection;
409 sal_Int32 VDataSeries::getAttachedAxisIndex() const
411 return m_nAxisIndex;
414 void VDataSeries::setAttachedAxisIndex( sal_Int32 nAttachedAxisIndex )
416 if( nAttachedAxisIndex < 0 )
417 nAttachedAxisIndex = 0;
418 m_nAxisIndex = nAttachedAxisIndex;
421 double VDataSeries::getXValue( sal_Int32 index ) const
423 double fRet = std::numeric_limits<double>::quiet_NaN();
424 if(m_aValues_X.is())
426 if( 0<=index && index<m_aValues_X.getLength() )
428 fRet = m_aValues_X.Doubles[index];
429 if(mpOldSeries && index < mpOldSeries->m_aValues_X.getLength())
431 double nOldVal = mpOldSeries->m_aValues_X.Doubles[index];
432 fRet = nOldVal + (fRet - nOldVal) * mnPercent;
436 else
438 // #i70133# always return correct X position - needed for short data series
439 if( 0<=index /*&& index < m_nPointCount*/ )
440 fRet = index+1;//first category (index 0) matches with real number 1.0
442 lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() );
443 return fRet;
446 double VDataSeries::getYValue( sal_Int32 index ) const
448 double fRet = std::numeric_limits<double>::quiet_NaN();
449 if(m_aValues_Y.is())
451 if( 0<=index && index<m_aValues_Y.getLength() )
453 fRet = m_aValues_Y.Doubles[index];
454 if(mpOldSeries && index < mpOldSeries->m_aValues_Y.getLength())
456 double nOldVal = mpOldSeries->m_aValues_Y.Doubles[index];
457 fRet = nOldVal + (fRet - nOldVal) * mnPercent;
461 else
463 // #i70133# always return correct X position - needed for short data series
464 if( 0<=index /*&& index < m_nPointCount*/ )
465 fRet = index+1;//first category (index 0) matches with real number 1.0
467 lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() );
468 return fRet;
471 void VDataSeries::getMinMaxXValue(double& fMin, double& fMax) const
473 fMax = std::numeric_limits<double>::quiet_NaN();
474 fMin = std::numeric_limits<double>::quiet_NaN();
476 uno::Sequence< double > aValuesX = getAllX();
478 if(!aValuesX.hasElements())
479 return;
481 sal_Int32 i = 0;
482 while ( i < aValuesX.getLength() && std::isnan(aValuesX[i]) )
483 i++;
484 if ( i < aValuesX.getLength() )
485 fMax = fMin = aValuesX[i++];
487 for ( ; i < aValuesX.getLength(); i++)
489 const double aValue = aValuesX[i];
490 if ( aValue > fMax)
492 fMax = aValue;
494 else if ( aValue < fMin)
496 fMin = aValue;
500 double VDataSeries::getY_Min( sal_Int32 index ) const
502 return m_aValues_Y_Min.getValue( index );
504 double VDataSeries::getY_Max( sal_Int32 index ) const
506 return m_aValues_Y_Max.getValue( index );
508 double VDataSeries::getY_First( sal_Int32 index ) const
510 return m_aValues_Y_First.getValue( index );
512 double VDataSeries::getY_Last( sal_Int32 index ) const
514 return m_aValues_Y_Last.getValue( index );
516 double VDataSeries::getBubble_Size( sal_Int32 index ) const
518 double nNewVal = m_aValues_Bubble_Size.getValue( index );
519 if(mpOldSeries && index < mpOldSeries->m_aValues_Bubble_Size.getLength())
521 double nOldVal = mpOldSeries->m_aValues_Bubble_Size.getValue( index );
522 nNewVal = nOldVal + (nNewVal - nOldVal) * mnPercent;
525 return nNewVal;
528 bool VDataSeries::hasExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const
530 OUString aPropName = bForPercentage ? OUString("PercentageNumberFormat") : OUString(CHART_UNONAME_NUMFMT);
531 bool bHasNumberFormat = false;
532 bool bLinkToSource = true;
533 uno::Reference< beans::XPropertySet > xPointProp( getPropertiesOfPoint( nPointIndex ));
534 if( xPointProp.is() && (xPointProp->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bLinkToSource))
536 sal_Int32 nNumberFormat = -1;
537 if( !bLinkToSource && (xPointProp->getPropertyValue(aPropName) >>= nNumberFormat))
538 bHasNumberFormat = true;
540 return bHasNumberFormat;
542 sal_Int32 VDataSeries::getExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const
544 OUString aPropName = bForPercentage ? OUString("PercentageNumberFormat") : OUString(CHART_UNONAME_NUMFMT);
545 sal_Int32 nNumberFormat = -1;
546 uno::Reference< beans::XPropertySet > xPointProp( getPropertiesOfPoint( nPointIndex ));
547 if( xPointProp.is() )
548 xPointProp->getPropertyValue(aPropName) >>= nNumberFormat;
549 return nNumberFormat;
551 void VDataSeries::setRoleOfSequenceForDataLabelNumberFormatDetection( std::u16string_view rRole )
553 if (rRole == u"values-y")
554 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y;
555 else if (rRole == u"values-size")
556 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Bubble_Size;
557 else if (rRole == u"values-min")
558 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Min;
559 else if (rRole == u"values-max")
560 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Max;
561 else if (rRole == u"values-first")
562 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_First;
563 else if (rRole == u"values-last")
564 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Last;
565 else if (rRole == u"values-x")
566 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_X;
568 sal_Int32 VDataSeries::detectNumberFormatKey( sal_Int32 index ) const
570 sal_Int32 nRet = 0;
571 if( m_pValueSequenceForDataLabelNumberFormatDetection )
572 nRet = m_pValueSequenceForDataLabelNumberFormatDetection->detectNumberFormatKey( index );
573 return nRet;
576 sal_Int32 VDataSeries::getLabelPlacement( sal_Int32 nPointIndex, const uno::Reference< chart2::XChartType >& xChartType, bool bSwapXAndY ) const
578 sal_Int32 nLabelPlacement=0;
581 uno::Reference< beans::XPropertySet > xPointProps( getPropertiesOfPoint( nPointIndex ) );
582 if( xPointProps.is() )
583 xPointProps->getPropertyValue("LabelPlacement") >>= nLabelPlacement;
585 const uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements(
586 xChartType, bSwapXAndY, m_xDataSeries ) );
588 for( sal_Int32 n : aAvailablePlacements )
589 if( n == nLabelPlacement )
590 return nLabelPlacement; //ok
592 //otherwise use the first supported one
593 if( aAvailablePlacements.hasElements() )
595 nLabelPlacement = aAvailablePlacements[0];
596 if( xPointProps.is() )
597 xPointProps->setPropertyValue("LabelPlacement", uno::Any(nLabelPlacement));
598 return nLabelPlacement;
601 OSL_FAIL("no label placement supported");
603 catch( const uno::Exception& )
605 TOOLS_WARN_EXCEPTION("chart2", "" );
607 return nLabelPlacement;
610 awt::Point VDataSeries::getLabelPosition( awt::Point aTextShapePos, sal_Int32 nPointIndex ) const
612 awt::Point aPos(-1, -1);
615 RelativePosition aCustomLabelPosition;
616 uno::Reference< beans::XPropertySet > xPointProps(getPropertiesOfPoint(nPointIndex));
617 if( xPointProps.is() && (xPointProps->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition))
619 aPos.X = static_cast<sal_Int32>(aCustomLabelPosition.Primary * m_aReferenceSize.Width) + aTextShapePos.X;
620 aPos.Y = static_cast<sal_Int32>(aCustomLabelPosition.Secondary * m_aReferenceSize.Height) + aTextShapePos.Y;
623 catch (const uno::Exception&)
625 TOOLS_WARN_EXCEPTION("chart2", "");
627 return aPos;
630 bool VDataSeries::isLabelCustomPos(sal_Int32 nPointIndex) const
632 bool bCustom = false;
635 if( isAttributedDataPoint(nPointIndex) )
637 uno::Reference< beans::XPropertySet > xPointProps(m_xDataSeries->getDataPointByIndex(nPointIndex));
638 RelativePosition aCustomLabelPosition;
639 if( xPointProps.is() && (xPointProps->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition) )
640 bCustom = true;
643 catch (const uno::Exception&)
645 TOOLS_WARN_EXCEPTION("chart2", "");
647 return bCustom;
650 double VDataSeries::getMinimumofAllDifferentYValues( sal_Int32 index ) const
652 double fMin = std::numeric_limits<double>::infinity();
654 if( !m_aValues_Y.is() &&
655 (m_aValues_Y_Min.is() || m_aValues_Y_Max.is()
656 || m_aValues_Y_First.is() || m_aValues_Y_Last.is() ) )
658 double fY_Min = getY_Min( index );
659 double fY_Max = getY_Max( index );
660 double fY_First = getY_First( index );
661 double fY_Last = getY_Last( index );
663 if(fMin>fY_First)
664 fMin=fY_First;
665 if(fMin>fY_Last)
666 fMin=fY_Last;
667 if(fMin>fY_Min)
668 fMin=fY_Min;
669 if(fMin>fY_Max)
670 fMin=fY_Max;
672 else
674 double fY = getYValue( index );
675 if(fMin>fY)
676 fMin=fY;
679 if( std::isinf(fMin) )
680 return std::numeric_limits<double>::quiet_NaN();
682 return fMin;
685 double VDataSeries::getMaximumofAllDifferentYValues( sal_Int32 index ) const
687 double fMax = -std::numeric_limits<double>::infinity();
689 if( !m_aValues_Y.is() &&
690 (m_aValues_Y_Min.is() || m_aValues_Y_Max.is()
691 || m_aValues_Y_First.is() || m_aValues_Y_Last.is() ) )
693 double fY_Min = getY_Min( index );
694 double fY_Max = getY_Max( index );
695 double fY_First = getY_First( index );
696 double fY_Last = getY_Last( index );
698 if(fMax<fY_First)
699 fMax=fY_First;
700 if(fMax<fY_Last)
701 fMax=fY_Last;
702 if(fMax<fY_Min)
703 fMax=fY_Min;
704 if(fMax<fY_Max)
705 fMax=fY_Max;
707 else
709 double fY = getYValue( index );
710 if(fMax<fY)
711 fMax=fY;
714 if( std::isinf(fMax) )
715 return std::numeric_limits<double>::quiet_NaN();
717 return fMax;
720 uno::Sequence< double > const & VDataSeries::getAllX() const
722 if(!m_aValues_X.is() && !m_aValues_X.getLength() && m_nPointCount)
724 //init x values from category indexes
725 //first category (index 0) matches with real number 1.0
726 m_aValues_X.Doubles.realloc( m_nPointCount );
727 for(sal_Int32 nN=m_aValues_X.getLength();nN--;)
728 m_aValues_X.Doubles[nN] = nN+1;
730 return m_aValues_X.Doubles;
733 uno::Sequence< double > const & VDataSeries::getAllY() const
735 if(!m_aValues_Y.is() && !m_aValues_Y.getLength() && m_nPointCount)
737 //init y values from indexes
738 //first y-value (index 0) matches with real number 1.0
739 m_aValues_Y.Doubles.realloc( m_nPointCount );
740 for(sal_Int32 nN=m_aValues_Y.getLength();nN--;)
741 m_aValues_Y.Doubles[nN] = nN+1;
743 return m_aValues_Y.Doubles;
746 double VDataSeries::getXMeanValue() const
748 if( std::isnan( m_fXMeanValue ) )
750 uno::Reference< XRegressionCurveCalculator > xCalculator( RegressionCurveHelper::createRegressionCurveCalculatorByServiceName( u"com.sun.star.chart2.MeanValueRegressionCurve" ) );
751 uno::Sequence< double > aXValuesDummy;
752 xCalculator->recalculateRegression( aXValuesDummy, getAllX() );
753 m_fXMeanValue = xCalculator->getCurveValue( 1.0 );
755 return m_fXMeanValue;
758 double VDataSeries::getYMeanValue() const
760 if( std::isnan( m_fYMeanValue ) )
762 uno::Reference< XRegressionCurveCalculator > xCalculator(
763 RegressionCurveHelper::createRegressionCurveCalculatorByServiceName(u"com.sun.star.chart2.MeanValueRegressionCurve"));
764 uno::Sequence< double > aXValuesDummy;
765 xCalculator->recalculateRegression( aXValuesDummy, getAllY() );
766 m_fYMeanValue = xCalculator->getCurveValue( 1.0 );
768 return m_fYMeanValue;
771 static std::unique_ptr<Symbol> getSymbolPropertiesFromPropertySet( const uno::Reference< beans::XPropertySet >& xProp )
773 std::unique_ptr< Symbol > apSymbolProps( new Symbol() );
776 if( xProp->getPropertyValue("Symbol") >>= *apSymbolProps )
778 //use main color to fill symbols
779 xProp->getPropertyValue("Color") >>= apSymbolProps->FillColor;
780 // border of symbols always same as fill color
781 apSymbolProps->BorderColor = apSymbolProps->FillColor;
783 else
784 apSymbolProps.reset();
786 catch(const uno::Exception &)
788 TOOLS_WARN_EXCEPTION("chart2", "" );
790 return apSymbolProps;
793 Symbol* VDataSeries::getSymbolProperties( sal_Int32 index ) const
795 Symbol* pRet=nullptr;
796 if( isAttributedDataPoint( index ) )
798 adaptPointCache( index );
799 if (!m_apSymbolProperties_AttributedPoint)
800 m_apSymbolProperties_AttributedPoint
801 = getSymbolPropertiesFromPropertySet(getPropertiesOfPoint(index));
802 pRet = m_apSymbolProperties_AttributedPoint.get();
803 //if a single data point does not have symbols but the dataseries itself has symbols
804 //we create an invisible symbol shape to enable selection of that point
805 if( !pRet || pRet->Style == SymbolStyle_NONE )
807 if (!m_apSymbolProperties_Series)
808 m_apSymbolProperties_Series
809 = getSymbolPropertiesFromPropertySet(getPropertiesOfSeries());
810 if( m_apSymbolProperties_Series && m_apSymbolProperties_Series->Style != SymbolStyle_NONE )
812 if (!m_apSymbolProperties_InvisibleSymbolForSelection)
814 m_apSymbolProperties_InvisibleSymbolForSelection.reset(new Symbol);
815 m_apSymbolProperties_InvisibleSymbolForSelection->Style = SymbolStyle_STANDARD;
816 m_apSymbolProperties_InvisibleSymbolForSelection->StandardSymbol = 0;//square
817 m_apSymbolProperties_InvisibleSymbolForSelection->Size = com::sun::star::awt::Size(0, 0);//tdf#126033
818 m_apSymbolProperties_InvisibleSymbolForSelection->BorderColor = 0xff000000;//invisible
819 m_apSymbolProperties_InvisibleSymbolForSelection->FillColor = 0xff000000;//invisible
821 pRet = m_apSymbolProperties_InvisibleSymbolForSelection.get();
825 else
827 if (!m_apSymbolProperties_Series)
828 m_apSymbolProperties_Series
829 = getSymbolPropertiesFromPropertySet(getPropertiesOfSeries());
830 pRet = m_apSymbolProperties_Series.get();
833 if( pRet && pRet->Style == SymbolStyle_AUTO )
835 pRet->Style = SymbolStyle_STANDARD;
837 sal_Int32 nIndex = m_nGlobalSeriesIndex;
838 if(m_aValues_X.is())
839 nIndex++;
840 pRet->StandardSymbol = nIndex;
843 return pRet;
846 uno::Reference< beans::XPropertySet > VDataSeries::getXErrorBarProperties( sal_Int32 index ) const
848 uno::Reference< beans::XPropertySet > xErrorBarProp;
850 uno::Reference< beans::XPropertySet > xPointProp( getPropertiesOfPoint( index ));
851 if( xPointProp.is() )
852 xPointProp->getPropertyValue(CHART_UNONAME_ERRORBAR_X) >>= xErrorBarProp;
853 return xErrorBarProp;
856 uno::Reference< beans::XPropertySet > VDataSeries::getYErrorBarProperties( sal_Int32 index ) const
858 uno::Reference< beans::XPropertySet > xErrorBarProp;
860 uno::Reference< beans::XPropertySet > xPointProp( getPropertiesOfPoint( index ));
861 if( xPointProp.is() )
862 xPointProp->getPropertyValue(CHART_UNONAME_ERRORBAR_Y) >>= xErrorBarProp;
863 return xErrorBarProp;
866 bool VDataSeries::hasPointOwnColor( sal_Int32 index ) const
868 if( !isAttributedDataPoint(index) )
869 return false;
873 uno::Reference< beans::XPropertyState > xPointState( getPropertiesOfPoint(index), uno::UNO_QUERY_THROW );
874 return (xPointState->getPropertyState("Color") != beans::PropertyState_DEFAULT_VALUE );
876 catch(const uno::Exception&)
878 TOOLS_WARN_EXCEPTION("chart2", "" );
880 return false;
883 bool VDataSeries::isAttributedDataPoint( sal_Int32 index ) const
885 //returns true if the data point assigned by the given index has set its own properties
886 if( index>=m_nPointCount || m_nPointCount==0)
887 return false;
888 for(sal_Int32 n : m_aAttributedDataPointIndexList)
890 if(index == n)
891 return true;
893 return false;
896 bool VDataSeries::isVaryColorsByPoint() const
898 bool bVaryColorsByPoint = false;
899 Reference< beans::XPropertySet > xSeriesProp( getPropertiesOfSeries() );
900 if( xSeriesProp.is() )
901 xSeriesProp->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint;
902 return bVaryColorsByPoint;
905 uno::Reference< beans::XPropertySet > VDataSeries::getPropertiesOfPoint( sal_Int32 index ) const
907 if( isAttributedDataPoint( index ) )
908 return m_xDataSeries->getDataPointByIndex(index);
909 return getPropertiesOfSeries();
912 uno::Reference<beans::XPropertySet> VDataSeries::getPropertiesOfSeries() const
914 return uno::Reference<css::beans::XPropertySet>(m_xDataSeries, css::uno::UNO_QUERY);
917 static std::unique_ptr<DataPointLabel> getDataPointLabelFromPropertySet( const uno::Reference< beans::XPropertySet >& xProp )
919 std::unique_ptr< DataPointLabel > apLabel( new DataPointLabel() );
922 if( !(xProp->getPropertyValue(CHART_UNONAME_LABEL) >>= *apLabel) )
923 apLabel.reset();
925 catch(const uno::Exception &)
927 TOOLS_WARN_EXCEPTION("chart2", "" );
929 return apLabel;
932 void VDataSeries::adaptPointCache( sal_Int32 nNewPointIndex ) const
934 if( m_nCurrentAttributedPoint != nNewPointIndex )
936 m_apLabel_AttributedPoint.reset();
937 m_apLabelPropNames_AttributedPoint.reset();
938 m_apLabelPropValues_AttributedPoint.reset();
939 m_apSymbolProperties_AttributedPoint.reset();
940 m_nCurrentAttributedPoint = nNewPointIndex;
944 DataPointLabel* VDataSeries::getDataPointLabel( sal_Int32 index ) const
946 DataPointLabel* pRet = nullptr;
947 if( isAttributedDataPoint( index ) )
949 adaptPointCache( index );
950 if (!m_apLabel_AttributedPoint)
951 m_apLabel_AttributedPoint
952 = getDataPointLabelFromPropertySet(getPropertiesOfPoint(index));
953 pRet = m_apLabel_AttributedPoint.get();
955 else
957 if (!m_apLabel_Series)
958 m_apLabel_Series
959 = getDataPointLabelFromPropertySet(getPropertiesOfPoint(index));
960 pRet = m_apLabel_Series.get();
962 if( !m_bAllowPercentValueInDataLabel )
964 if( pRet )
965 pRet->ShowNumberInPercent = false;
967 return pRet;
970 DataPointLabel* VDataSeries::getDataPointLabelIfLabel( sal_Int32 index ) const
972 DataPointLabel* pLabel = getDataPointLabel( index );
973 if( !pLabel || (!pLabel->ShowNumber && !pLabel->ShowNumberInPercent
974 && !pLabel->ShowCategoryName && !pLabel->ShowCustomLabel && !pLabel->ShowSeriesName ) )
975 return nullptr;
976 return pLabel;
979 bool VDataSeries::getTextLabelMultiPropertyLists( sal_Int32 index
980 , tNameSequence*& pPropNames
981 , tAnySequence*& pPropValues ) const
983 pPropNames = nullptr; pPropValues = nullptr;
984 uno::Reference< beans::XPropertySet > xTextProp;
985 bool bDoDynamicFontResize = false;
986 if( isAttributedDataPoint( index ) )
988 adaptPointCache( index );
989 if (!m_apLabelPropValues_AttributedPoint)
991 // Cache these properties for this point.
992 m_apLabelPropNames_AttributedPoint.reset(new tNameSequence);
993 m_apLabelPropValues_AttributedPoint.reset(new tAnySequence);
994 xTextProp.set( getPropertiesOfPoint( index ));
995 PropertyMapper::getTextLabelMultiPropertyLists(
996 xTextProp, *m_apLabelPropNames_AttributedPoint, *m_apLabelPropValues_AttributedPoint);
997 bDoDynamicFontResize = true;
999 pPropNames = m_apLabelPropNames_AttributedPoint.get();
1000 pPropValues = m_apLabelPropValues_AttributedPoint.get();
1002 else
1004 if (!m_apLabelPropValues_Series)
1006 // Cache these properties for the whole series.
1007 m_apLabelPropNames_Series.reset(new tNameSequence);
1008 m_apLabelPropValues_Series.reset(new tAnySequence);
1009 xTextProp.set( getPropertiesOfPoint( index ));
1010 PropertyMapper::getTextLabelMultiPropertyLists(
1011 xTextProp, *m_apLabelPropNames_Series, *m_apLabelPropValues_Series);
1012 bDoDynamicFontResize = true;
1014 pPropNames = m_apLabelPropNames_Series.get();
1015 pPropValues = m_apLabelPropValues_Series.get();
1018 if( bDoDynamicFontResize &&
1019 pPropNames && pPropValues &&
1020 xTextProp.is())
1022 LabelPositionHelper::doDynamicFontResize( *pPropValues, *pPropNames, xTextProp, m_aReferenceSize );
1025 return (pPropNames && pPropValues);
1028 void VDataSeries::setMissingValueTreatment( sal_Int32 nMissingValueTreatment )
1030 m_nMissingValueTreatment = nMissingValueTreatment;
1033 sal_Int32 VDataSeries::getMissingValueTreatment() const
1035 return m_nMissingValueTreatment;
1038 VDataSeries::VDataSeries()
1039 : m_nPolygonIndex(0)
1040 , m_fLogicMinX(0)
1041 , m_fLogicMaxX(0)
1042 , m_fLogicZPos(0)
1043 , m_nPointCount(0)
1044 , m_pValueSequenceForDataLabelNumberFormatDetection(nullptr)
1045 , m_fXMeanValue(0)
1046 , m_fYMeanValue(0)
1047 , m_eStackingDirection(chart2::StackingDirection_NO_STACKING)
1048 , m_nAxisIndex(0)
1049 , m_bConnectBars(false)
1050 , m_bGroupBarsPerAxis(false)
1051 , m_nStartingAngle(0)
1052 , m_nGlobalSeriesIndex(0)
1053 , m_nCurrentAttributedPoint(0)
1054 , m_nMissingValueTreatment(0)
1055 , m_bAllowPercentValueInDataLabel(false)
1056 , mpOldSeries(nullptr)
1057 , mnPercent(0)
1061 void VDataSeries::setOldTimeBased( VDataSeries* pOldSeries, double nPercent )
1063 mnPercent = nPercent;
1064 mpOldSeries = pOldSeries;
1065 mpOldSeries->mpOldSeries = nullptr;
1068 VDataSeries* VDataSeries::createCopyForTimeBased() const
1070 VDataSeries* pNew = new VDataSeries();
1071 pNew->m_aValues_X = m_aValues_X;
1072 pNew->m_aValues_Y = m_aValues_Y;
1073 pNew->m_aValues_Z = m_aValues_Z;
1074 pNew->m_aValues_Y_Min = m_aValues_Y_Min;
1075 pNew->m_aValues_Y_Max = m_aValues_Y_Max;
1076 pNew->m_aValues_Y_First = m_aValues_Y_First;
1077 pNew->m_aValues_Y_Last = m_aValues_Y_Last;
1078 pNew->m_aValues_Bubble_Size = m_aValues_Bubble_Size;
1079 pNew->m_PropertyMap = m_PropertyMap;
1081 pNew->m_nPointCount = m_nPointCount;
1083 return pNew;
1086 double VDataSeries::getValueByProperty( sal_Int32 nIndex, const OUString& rPropName ) const
1088 auto const itr = m_PropertyMap.find(rPropName);
1089 if (itr == m_PropertyMap.end())
1090 return std::numeric_limits<double>::quiet_NaN();
1092 const VDataSequence* pData = &itr->second;
1093 double fValue = pData->getValue(nIndex);
1094 if(mpOldSeries && mpOldSeries->hasPropertyMapping(rPropName))
1096 double fOldValue = mpOldSeries->getValueByProperty( nIndex, rPropName );
1097 if(rPropName.endsWith("Color"))
1099 //optimized interpolation for color values
1100 Color aColor(ColorTransparency, static_cast<sal_uInt32>(fValue));
1101 Color aOldColor(ColorTransparency, static_cast<sal_uInt32>(fOldValue));
1102 sal_uInt8 r = aOldColor.GetRed() + (aColor.GetRed() - aOldColor.GetRed()) * mnPercent;
1103 sal_uInt8 g = aOldColor.GetGreen() + (aColor.GetGreen() - aOldColor.GetGreen()) * mnPercent;
1104 sal_uInt8 b = aOldColor.GetBlue() + (aColor.GetBlue() - aOldColor.GetBlue()) * mnPercent;
1105 sal_uInt8 a = aOldColor.GetAlpha() + (aColor.GetAlpha() - aOldColor.GetAlpha()) * mnPercent;
1106 Color aRet(ColorAlpha, a, r, g, b);
1107 return sal_uInt32(aRet);
1109 return fOldValue + (fValue - fOldValue) * mnPercent;
1111 return fValue;
1114 bool VDataSeries::hasPropertyMapping(const OUString& rPropName ) const
1116 return m_PropertyMap.find(rPropName) != m_PropertyMap.end();
1119 } //namespace chart
1121 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */