fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / chart2 / source / view / main / VDataSeries.cxx
blob18614b14c821903334ffa37157095144442b72db
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 "VDataSeries.hxx"
21 #include "ObjectIdentifier.hxx"
22 #include "macros.hxx"
23 #include "CommonConverters.hxx"
24 #include "LabelPositionHelper.hxx"
25 #include "ChartTypeHelper.hxx"
26 #include "ContainerHelper.hxx"
27 #include "DataSeriesHelper.hxx"
28 #include "RegressionCurveHelper.hxx"
29 #include <unonames.hxx>
31 #include <com/sun/star/chart/MissingValueTreatment.hpp>
32 #include <com/sun/star/chart2/Symbol.hpp>
34 #include <rtl/math.hxx>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/beans/XPropertyState.hpp>
37 #include <com/sun/star/drawing/LineStyle.hpp>
38 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
39 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
40 #include <com/sun/star/text/WritingMode.hpp>
41 #include <com/sun/star/chart2/data/XDataSource.hpp>
43 namespace chart {
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::chart2;
47 using ::com::sun::star::uno::Reference;
49 void VDataSequence::init( const uno::Reference< data::XDataSequence >& xModel )
51 Model = xModel;
52 Doubles = DataSequenceToDoubleSequence( xModel );
55 bool VDataSequence::is() const
57 return Model.is();
59 void VDataSequence::clear()
61 Model = NULL;
62 Doubles.realloc(0);
65 double VDataSequence::getValue( sal_Int32 index ) const
67 if( 0<=index && index<Doubles.getLength() )
68 return Doubles[index];
69 else
71 double fNan;
72 ::rtl::math::setNan( & fNan );
73 return fNan;
77 sal_Int32 VDataSequence::detectNumberFormatKey( sal_Int32 index ) const
79 sal_Int32 nNumberFormatKey = -1;
81 // -1 is allowed and means a key for the whole sequence
82 if( -1<=index && index<Doubles.getLength() &&
83 Model.is())
85 nNumberFormatKey = Model->getNumberFormatKeyByIndex( index );
88 return nNumberFormatKey;
91 sal_Int32 VDataSequence::getLength() const
93 return Doubles.getLength();
96 namespace
98 struct lcl_LessXOfPoint
100 inline bool operator() ( const std::vector< double >& first,
101 const std::vector< double >& second )
103 if( !first.empty() && !second.empty() )
105 return first[0]<second[0];
107 return false;
111 void lcl_clearIfNoValuesButTextIsContained( VDataSequence& rData, const uno::Reference<data::XDataSequence>& xDataSequence )
113 //#i71686#, #i101968#, #i102428#
114 sal_Int32 nCount = rData.Doubles.getLength();
115 for( sal_Int32 i = 0; i < nCount; ++i )
117 if( !::rtl::math::isNan( rData.Doubles[i] ) )
118 return;
120 //no double value is countained
121 //is there any text?
122 uno::Sequence< OUString > aStrings( DataSequenceToStringSequence( xDataSequence ) );
123 sal_Int32 nTextCount = aStrings.getLength();
124 for( sal_Int32 j = 0; j < nTextCount; ++j )
126 if( !aStrings[j].isEmpty() )
128 rData.clear();
129 return;
132 //no content at all
135 void lcl_maybeReplaceNanWithZero( double& rfValue, sal_Int32 nMissingValueTreatment )
137 if( nMissingValueTreatment == ::com::sun::star::chart::MissingValueTreatment::USE_ZERO
138 && (::rtl::math::isNan(rfValue) || ::rtl::math::isInf(rfValue)) )
139 rfValue = 0.0;
144 VDataSeries::VDataSeries( const uno::Reference< XDataSeries >& xDataSeries )
145 : m_nPolygonIndex(0)
146 , m_fLogicMinX(0.0)
147 , m_fLogicMaxX(0.0)
148 , m_fLogicZPos(0.0)
149 , m_xGroupShape(NULL)
150 , m_xLabelsGroupShape(NULL)
151 , m_xErrorXBarsGroupShape(NULL)
152 , m_xErrorYBarsGroupShape(NULL)
153 , m_xFrontSubGroupShape(NULL)
154 , m_xBackSubGroupShape(NULL)
155 , m_xDataSeries(xDataSeries)
156 , m_nPointCount(0)
158 , m_pValueSequenceForDataLabelNumberFormatDetection(&m_aValues_Y)
160 , m_fXMeanValue(1.0)
161 , m_fYMeanValue(1.0)
163 , m_aAttributedDataPointIndexList()
165 , m_eStackingDirection(StackingDirection_NO_STACKING)
166 , m_nAxisIndex(0)
167 , m_bConnectBars(false)
168 , m_bGroupBarsPerAxis(true)
169 , m_nStartingAngle(90)
171 , m_nGlobalSeriesIndex(0)
173 , m_apLabel_Series(NULL)
174 , m_apLabelPropNames_Series(NULL)
175 , m_apLabelPropValues_Series(NULL)
176 , m_apSymbolProperties_Series(NULL)
178 , m_apLabel_AttributedPoint(NULL)
179 , m_apLabelPropNames_AttributedPoint(NULL)
180 , m_apLabelPropValues_AttributedPoint(NULL)
181 , m_apSymbolProperties_AttributedPoint(NULL)
182 , m_apSymbolProperties_InvisibleSymbolForSelection(NULL)
183 , m_nCurrentAttributedPoint(-1)
184 , m_nMissingValueTreatment(::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP)
185 , m_bAllowPercentValueInDataLabel(false)
186 , mpOldSeries(NULL)
187 , mnPercent(0.0)
189 ::rtl::math::setNan( & m_fXMeanValue );
190 ::rtl::math::setNan( & m_fYMeanValue );
192 uno::Reference<data::XDataSource> xDataSource =
193 uno::Reference<data::XDataSource>( xDataSeries, uno::UNO_QUERY );
195 uno::Sequence< uno::Reference<
196 chart2::data::XLabeledDataSequence > > aDataSequences =
197 xDataSource->getDataSequences();
199 for(sal_Int32 nN = aDataSequences.getLength();nN--;)
201 if(!aDataSequences[nN].is())
202 continue;
203 uno::Reference<data::XDataSequence> xDataSequence( aDataSequences[nN]->getValues());
204 uno::Reference<beans::XPropertySet> xProp(xDataSequence, uno::UNO_QUERY );
205 if( xProp.is())
209 uno::Any aARole = xProp->getPropertyValue("Role");
210 OUString aRole;
211 aARole >>= aRole;
213 if (aRole == "values-x")
215 m_aValues_X.init( xDataSequence );
216 lcl_clearIfNoValuesButTextIsContained( m_aValues_X, xDataSequence );
218 else if (aRole =="values-y")
219 m_aValues_Y.init( xDataSequence );
220 else if (aRole == "values-min")
221 m_aValues_Y_Min.init( xDataSequence );
222 else if (aRole == "values-max")
223 m_aValues_Y_Max.init( xDataSequence );
224 else if (aRole == "values-first")
225 m_aValues_Y_First.init( xDataSequence );
226 else if (aRole == "values-last")
227 m_aValues_Y_Last.init( xDataSequence );
228 else if (aRole == "values-size")
229 m_aValues_Bubble_Size.init( xDataSequence );
230 else
232 VDataSequence* pSequence = new VDataSequence();
233 pSequence->init( xDataSequence );
234 maPropertyMap.insert(aRole, pSequence);
237 catch( const uno::Exception& e )
239 ASSERT_EXCEPTION( e );
244 //determine the point count
245 m_nPointCount = m_aValues_Y.getLength();
247 if( m_nPointCount < m_aValues_Bubble_Size.getLength() )
248 m_nPointCount = m_aValues_Bubble_Size.getLength();
249 if( m_nPointCount < m_aValues_Y_Min.getLength() )
250 m_nPointCount = m_aValues_Y_Min.getLength();
251 if( m_nPointCount < m_aValues_Y_Max.getLength() )
252 m_nPointCount = m_aValues_Y_Max.getLength();
253 if( m_nPointCount < m_aValues_Y_First.getLength() )
254 m_nPointCount = m_aValues_Y_First.getLength();
255 if( m_nPointCount < m_aValues_Y_Last.getLength() )
256 m_nPointCount = m_aValues_Y_Last.getLength();
259 uno::Reference<beans::XPropertySet> xProp(xDataSeries, uno::UNO_QUERY );
260 if( xProp.is())
264 //get AttributedDataPoints
265 xProp->getPropertyValue("AttributedDataPoints") >>= m_aAttributedDataPointIndexList;
267 xProp->getPropertyValue("StackingDirection") >>= m_eStackingDirection;
269 xProp->getPropertyValue("AttachedAxisIndex") >>= m_nAxisIndex;
270 if(m_nAxisIndex<0)
271 m_nAxisIndex=0;
273 catch( const uno::Exception& e )
275 ASSERT_EXCEPTION( e );
280 VDataSeries::~VDataSeries()
284 void VDataSeries::doSortByXValues()
286 if( m_aValues_X.is() && m_aValues_X.Doubles.getLength() )
288 //prepare a vector for sorting
289 std::vector< ::std::vector< double > > aTmp;//outer vector are points, inner vector are the different values of athe point
290 double fNan;
291 ::rtl::math::setNan( & fNan );
292 sal_Int32 nPointIndex = 0;
293 for( nPointIndex=0; nPointIndex < m_nPointCount; nPointIndex++ )
295 std::vector< double > aSinglePoint;
296 aSinglePoint.push_back( (nPointIndex < m_aValues_X.Doubles.getLength()) ? m_aValues_X.Doubles[nPointIndex] : fNan );
297 aSinglePoint.push_back( (nPointIndex < m_aValues_Y.Doubles.getLength()) ? m_aValues_Y.Doubles[nPointIndex] : fNan );
298 aTmp.push_back( aSinglePoint );
301 //do sort
302 std::stable_sort( aTmp.begin(), aTmp.end(), lcl_LessXOfPoint() );
304 //fill the sorted points back to the members
305 m_aValues_X.Doubles.realloc( m_nPointCount );
306 m_aValues_Y.Doubles.realloc( m_nPointCount );
308 for( nPointIndex=0; nPointIndex < m_nPointCount; nPointIndex++ )
310 m_aValues_X.Doubles[nPointIndex]=aTmp[nPointIndex][0];
311 m_aValues_Y.Doubles[nPointIndex]=aTmp[nPointIndex][1];
316 void VDataSeries::releaseShapes()
318 m_xGroupShape.set(0);
319 m_xLabelsGroupShape.set(0);
320 m_xErrorXBarsGroupShape.set(0);
321 m_xErrorYBarsGroupShape.set(0);
322 m_xFrontSubGroupShape.set(0);
323 m_xBackSubGroupShape.set(0);
325 m_aPolyPolygonShape3D.SequenceX.realloc(0);
326 m_aPolyPolygonShape3D.SequenceY.realloc(0);
327 m_aPolyPolygonShape3D.SequenceZ.realloc(0);
328 m_nPolygonIndex = 0;
331 uno::Reference<css::chart2::XDataSeries> VDataSeries::getModel() const
333 return m_xDataSeries;
336 void VDataSeries::setCategoryXAxis()
338 m_aValues_X.clear();
339 m_bAllowPercentValueInDataLabel = true;
342 void VDataSeries::setXValues( const Reference< chart2::data::XDataSequence >& xValues )
344 m_aValues_X.clear();
345 m_aValues_X.init( xValues );
346 m_bAllowPercentValueInDataLabel = true;
349 void VDataSeries::setXValuesIfNone( const Reference< chart2::data::XDataSequence >& xValues )
351 if( m_aValues_X.is() )
352 return;
354 m_aValues_X.init( xValues );
355 lcl_clearIfNoValuesButTextIsContained( m_aValues_X, xValues );
358 void VDataSeries::setGlobalSeriesIndex( sal_Int32 nGlobalSeriesIndex )
360 m_nGlobalSeriesIndex = nGlobalSeriesIndex;
363 void VDataSeries::setParticle( const OUString& rSeriesParticle )
365 m_aSeriesParticle = rSeriesParticle;
367 //get CID
368 m_aCID = ObjectIdentifier::createClassifiedIdentifierForParticle( m_aSeriesParticle );
369 m_aPointCID_Stub = ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT, m_aSeriesParticle );
371 m_aLabelCID_Stub = ObjectIdentifier::createClassifiedIdentifierWithParent(
372 OBJECTTYPE_DATA_LABEL, OUString(), getLabelsCID() );
374 OUString VDataSeries::getErrorBarsCID(bool bYError) const
376 OUString aChildParticle( ObjectIdentifier::getStringForType(
377 bYError ? OBJECTTYPE_DATA_ERRORS_Y : OBJECTTYPE_DATA_ERRORS_X ) );
378 aChildParticle += "=";
380 return ObjectIdentifier::createClassifiedIdentifierForParticles(
381 m_aSeriesParticle, aChildParticle );
383 OUString VDataSeries::getLabelsCID() const
385 OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) );
386 aChildParticle += "=";
388 return ObjectIdentifier::createClassifiedIdentifierForParticles(
389 m_aSeriesParticle, aChildParticle );
391 OUString VDataSeries::getDataCurveCID( sal_Int32 nCurveIndex, bool bAverageLine ) const
393 OUString aRet;
394 aRet = ObjectIdentifier::createDataCurveCID( m_aSeriesParticle, nCurveIndex, bAverageLine );
395 return aRet;
398 OUString VDataSeries::getDataCurveEquationCID( sal_Int32 nCurveIndex ) const
400 OUString aRet;
401 aRet = ObjectIdentifier::createDataCurveEquationCID( m_aSeriesParticle, nCurveIndex );
402 return aRet;
404 void VDataSeries::setPageReferenceSize( const awt::Size & rPageRefSize )
406 m_aReferenceSize = rPageRefSize;
409 void VDataSeries::setConnectBars( bool bConnectBars )
411 m_bConnectBars = bConnectBars;
414 bool VDataSeries::getConnectBars() const
416 return m_bConnectBars;
419 void VDataSeries::setGroupBarsPerAxis( bool bGroupBarsPerAxis )
421 m_bGroupBarsPerAxis = bGroupBarsPerAxis;
424 bool VDataSeries::getGroupBarsPerAxis() const
426 return m_bGroupBarsPerAxis;
429 void VDataSeries::setStartingAngle( sal_Int32 nStartingAngle )
431 m_nStartingAngle = nStartingAngle;
434 sal_Int32 VDataSeries::getStartingAngle() const
436 return m_nStartingAngle;
439 chart2::StackingDirection VDataSeries::getStackingDirection() const
441 return m_eStackingDirection;
444 sal_Int32 VDataSeries::getAttachedAxisIndex() const
446 return m_nAxisIndex;
449 void VDataSeries::setAttachedAxisIndex( sal_Int32 nAttachedAxisIndex )
451 if( nAttachedAxisIndex < 0 )
452 nAttachedAxisIndex = 0;
453 m_nAxisIndex = nAttachedAxisIndex;
456 double VDataSeries::getXValue( sal_Int32 index ) const
458 double fRet = 0.0;
459 if(m_aValues_X.is())
461 if( 0<=index && index<m_aValues_X.getLength() )
463 fRet = m_aValues_X.Doubles[index];
464 if(mpOldSeries && index < mpOldSeries->m_aValues_X.getLength())
466 double nOldVal = mpOldSeries->m_aValues_X.Doubles[index];
467 fRet = nOldVal + (fRet - nOldVal) * mnPercent;
470 else
471 ::rtl::math::setNan( &fRet );
473 else
475 // #i70133# always return correct X position - needed for short data series
476 if( 0<=index /*&& index < m_nPointCount*/ )
477 fRet = index+1;//first category (index 0) matches with real number 1.0
478 else
479 ::rtl::math::setNan( &fRet );
481 lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() );
482 return fRet;
485 double VDataSeries::getYValue( sal_Int32 index ) const
487 double fRet = 0.0;
488 if(m_aValues_Y.is())
490 if( 0<=index && index<m_aValues_Y.getLength() )
492 fRet = m_aValues_Y.Doubles[index];
493 if(mpOldSeries && index < mpOldSeries->m_aValues_Y.getLength())
495 double nOldVal = mpOldSeries->m_aValues_Y.Doubles[index];
496 fRet = nOldVal + (fRet - nOldVal) * mnPercent;
499 else
500 ::rtl::math::setNan( &fRet );
502 else
504 // #i70133# always return correct X position - needed for short data series
505 if( 0<=index /*&& index < m_nPointCount*/ )
506 fRet = index+1;//first category (index 0) matches with real number 1.0
507 else
508 ::rtl::math::setNan( &fRet );
510 lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() );
511 return fRet;
514 void VDataSeries::getMinMaxXValue(double& fMin, double& fMax) const
516 rtl::math::setNan( &fMax );
517 rtl::math::setNan( &fMin );
519 uno::Sequence< double > aValuesX = getAllX();
521 if(aValuesX.getLength() > 0)
523 sal_Int32 i = 0;
524 while ( i < aValuesX.getLength() && ::rtl::math::isNan( aValuesX[i] ) )
525 i++;
526 if ( i < aValuesX.getLength() )
527 fMax = fMin = aValuesX[i++];
529 for ( ; i < aValuesX.getLength(); i++)
531 const double aValue = aValuesX[i];
532 if ( aValue > fMax)
534 fMax = aValue;
536 else if ( aValue < fMin)
538 fMin = aValue;
543 double VDataSeries::getY_Min( sal_Int32 index ) const
545 return m_aValues_Y_Min.getValue( index );
547 double VDataSeries::getY_Max( sal_Int32 index ) const
549 return m_aValues_Y_Max.getValue( index );
551 double VDataSeries::getY_First( sal_Int32 index ) const
553 return m_aValues_Y_First.getValue( index );
555 double VDataSeries::getY_Last( sal_Int32 index ) const
557 return m_aValues_Y_Last.getValue( index );
559 double VDataSeries::getBubble_Size( sal_Int32 index ) const
561 double nNewVal = m_aValues_Bubble_Size.getValue( index );
562 if(mpOldSeries && index < mpOldSeries->m_aValues_Bubble_Size.getLength())
564 double nOldVal = mpOldSeries->m_aValues_Bubble_Size.getValue( index );
565 nNewVal = nOldVal + (nNewVal - nOldVal) * mnPercent;
568 return nNewVal;
571 bool VDataSeries::hasExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const
573 OUString aPropName = bForPercentage ? OUString("PercentageNumberFormat") : OUString(CHART_UNONAME_NUMFMT);
574 bool bHasNumberFormat = false;
575 uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( nPointIndex ));
576 sal_Int32 nNumberFormat = -1;
577 if( xPointProp.is() && (xPointProp->getPropertyValue(aPropName) >>= nNumberFormat) )
578 bHasNumberFormat = true;
579 return bHasNumberFormat;
581 sal_Int32 VDataSeries::getExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const
583 OUString aPropName = bForPercentage ? OUString("PercentageNumberFormat") : OUString(CHART_UNONAME_NUMFMT);
584 sal_Int32 nNumberFormat = -1;
585 uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( nPointIndex ));
586 if( xPointProp.is() )
587 xPointProp->getPropertyValue(aPropName) >>= nNumberFormat;
588 return nNumberFormat;
590 void VDataSeries::setRoleOfSequenceForDataLabelNumberFormatDetection( const OUString& rRole )
592 if (rRole == "values-y")
593 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y;
594 else if (rRole == "values-size")
595 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Bubble_Size;
596 else if (rRole == "values-min")
597 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Min;
598 else if (rRole == "values-max")
599 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Max;
600 else if (rRole == "values-first")
601 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_First;
602 else if (rRole == "values-last")
603 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Last;
604 else if (rRole == "values-x")
605 m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_X;
607 bool VDataSeries::shouldLabelNumberFormatKeyBeDetectedFromYAxis() const
609 if( m_pValueSequenceForDataLabelNumberFormatDetection == &m_aValues_Bubble_Size )
610 return false;
611 else if( m_pValueSequenceForDataLabelNumberFormatDetection == &m_aValues_X )
612 return false;
613 return true;
615 sal_Int32 VDataSeries::detectNumberFormatKey( sal_Int32 index ) const
617 sal_Int32 nRet = 0;
618 if( m_pValueSequenceForDataLabelNumberFormatDetection )
619 nRet = m_pValueSequenceForDataLabelNumberFormatDetection->detectNumberFormatKey( index );
620 return nRet;
623 sal_Int32 VDataSeries::getLabelPlacement( sal_Int32 nPointIndex, const uno::Reference< chart2::XChartType >& xChartType, sal_Int32 nDimensionCount, bool bSwapXAndY ) const
625 sal_Int32 nLabelPlacement=0;
628 uno::Reference< beans::XPropertySet > xPointProps( this->getPropertiesOfPoint( nPointIndex ) );
629 if( xPointProps.is() )
630 xPointProps->getPropertyValue("LabelPlacement") >>= nLabelPlacement;
632 //ensure that the set label placement is supported by this charttype
634 uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements(
635 xChartType, nDimensionCount, bSwapXAndY, m_xDataSeries ) );
637 for( sal_Int32 nN = 0; nN < aAvailablePlacements.getLength(); nN++ )
638 if( aAvailablePlacements[nN] == nLabelPlacement )
639 return nLabelPlacement; //ok
641 //otherwise use the first supported one
642 if( aAvailablePlacements.getLength() )
644 nLabelPlacement = aAvailablePlacements[0];
645 return nLabelPlacement;
648 OSL_FAIL("no label placement supported");
650 catch( const uno::Exception& e )
652 ASSERT_EXCEPTION( e );
654 return nLabelPlacement;
657 double VDataSeries::getMinimumofAllDifferentYValues( sal_Int32 index ) const
659 double fMin=0.0;
660 ::rtl::math::setInf(&fMin, false);
662 if( !m_aValues_Y.is() &&
663 (m_aValues_Y_Min.is() || m_aValues_Y_Max.is()
664 || m_aValues_Y_First.is() || m_aValues_Y_Last.is() ) )
666 double fY_Min = getY_Min( index );
667 double fY_Max = getY_Max( index );
668 double fY_First = getY_First( index );
669 double fY_Last = getY_Last( index );
671 if(fMin>fY_First)
672 fMin=fY_First;
673 if(fMin>fY_Last)
674 fMin=fY_Last;
675 if(fMin>fY_Min)
676 fMin=fY_Min;
677 if(fMin>fY_Max)
678 fMin=fY_Max;
680 else
682 double fY = getYValue( index );
683 if(fMin>fY)
684 fMin=fY;
687 if( ::rtl::math::isInf(fMin) )
688 ::rtl::math::setNan(&fMin);
690 return fMin;
693 double VDataSeries::getMaximumofAllDifferentYValues( sal_Int32 index ) const
695 double fMax=0.0;
696 ::rtl::math::setInf(&fMax, true);
698 if( !m_aValues_Y.is() &&
699 (m_aValues_Y_Min.is() || m_aValues_Y_Max.is()
700 || m_aValues_Y_First.is() || m_aValues_Y_Last.is() ) )
702 double fY_Min = getY_Min( index );
703 double fY_Max = getY_Max( index );
704 double fY_First = getY_First( index );
705 double fY_Last = getY_Last( index );
707 if(fMax<fY_First)
708 fMax=fY_First;
709 if(fMax<fY_Last)
710 fMax=fY_Last;
711 if(fMax<fY_Min)
712 fMax=fY_Min;
713 if(fMax<fY_Max)
714 fMax=fY_Max;
716 else
718 double fY = getYValue( index );
719 if(fMax<fY)
720 fMax=fY;
723 if( ::rtl::math::isInf(fMax) )
724 ::rtl::math::setNan(&fMax);
726 return fMax;
729 uno::Sequence< double > VDataSeries::getAllX() const
731 if(!m_aValues_X.is() && !m_aValues_X.getLength() && m_nPointCount)
733 //init x values from category indexes
734 //first category (index 0) matches with real number 1.0
735 m_aValues_X.Doubles.realloc( m_nPointCount );
736 for(sal_Int32 nN=m_aValues_X.getLength();nN--;)
737 m_aValues_X.Doubles[nN] = nN+1;
739 return m_aValues_X.Doubles;
742 uno::Sequence< double > VDataSeries::getAllY() const
744 if(!m_aValues_Y.is() && !m_aValues_Y.getLength() && m_nPointCount)
746 //init y values from indexes
747 //first y-value (index 0) matches with real number 1.0
748 m_aValues_Y.Doubles.realloc( m_nPointCount );
749 for(sal_Int32 nN=m_aValues_Y.getLength();nN--;)
750 m_aValues_Y.Doubles[nN] = nN+1;
752 return m_aValues_Y.Doubles;
755 double VDataSeries::getXMeanValue() const
757 if( ::rtl::math::isNan( m_fXMeanValue ) )
759 uno::Reference< XRegressionCurveCalculator > xCalculator( RegressionCurveHelper::createRegressionCurveCalculatorByServiceName( "com.sun.star.chart2.MeanValueRegressionCurve" ) );
760 uno::Sequence< double > aXValuesDummy;
761 xCalculator->recalculateRegression( aXValuesDummy, getAllX() );
762 double fXDummy = 1.0;
763 m_fXMeanValue = xCalculator->getCurveValue( fXDummy );
765 return m_fXMeanValue;
768 double VDataSeries::getYMeanValue() const
770 if( ::rtl::math::isNan( m_fYMeanValue ) )
772 uno::Reference< XRegressionCurveCalculator > xCalculator(
773 RegressionCurveHelper::createRegressionCurveCalculatorByServiceName("com.sun.star.chart2.MeanValueRegressionCurve"));
774 uno::Sequence< double > aXValuesDummy;
775 xCalculator->recalculateRegression( aXValuesDummy, getAllY() );
776 double fXDummy = 1.0;
777 m_fYMeanValue = xCalculator->getCurveValue( fXDummy );
779 return m_fYMeanValue;
782 Symbol* getSymbolPropertiesFromPropertySet( const uno::Reference< beans::XPropertySet >& xProp )
784 ::std::unique_ptr< Symbol > apSymbolProps( new Symbol() );
787 if( xProp->getPropertyValue("Symbol") >>= *apSymbolProps )
789 //use main color to fill symbols
790 xProp->getPropertyValue("Color") >>= apSymbolProps->FillColor;
791 // border of symbols always same as fill color
792 apSymbolProps->BorderColor = apSymbolProps->FillColor;
794 else
795 apSymbolProps.reset();
797 catch(const uno::Exception &e)
799 ASSERT_EXCEPTION( e );
801 return apSymbolProps.release();
804 Symbol* VDataSeries::getSymbolProperties( sal_Int32 index ) const
806 Symbol* pRet=NULL;
807 if( isAttributedDataPoint( index ) )
809 adaptPointCache( index );
810 if (!m_apSymbolProperties_AttributedPoint)
811 m_apSymbolProperties_AttributedPoint.reset(
812 getSymbolPropertiesFromPropertySet(this->getPropertiesOfPoint(index)));
813 pRet = m_apSymbolProperties_AttributedPoint.get();
814 //if a single data point does not have symbols but the dataseries itself has symbols
815 //we create an invisible symbol shape to enable selection of that point
816 if( !pRet || pRet->Style == SymbolStyle_NONE )
818 if (!m_apSymbolProperties_Series)
819 m_apSymbolProperties_Series.reset(
820 getSymbolPropertiesFromPropertySet(this->getPropertiesOfSeries()));
821 if( m_apSymbolProperties_Series.get() && m_apSymbolProperties_Series->Style != SymbolStyle_NONE )
823 if (!m_apSymbolProperties_InvisibleSymbolForSelection)
825 m_apSymbolProperties_InvisibleSymbolForSelection.reset(new Symbol);
826 m_apSymbolProperties_InvisibleSymbolForSelection->Style = SymbolStyle_STANDARD;
827 m_apSymbolProperties_InvisibleSymbolForSelection->StandardSymbol = 0;//square
828 m_apSymbolProperties_InvisibleSymbolForSelection->Size = m_apSymbolProperties_Series->Size;
829 m_apSymbolProperties_InvisibleSymbolForSelection->BorderColor = 0xff000000;//invisible
830 m_apSymbolProperties_InvisibleSymbolForSelection->FillColor = 0xff000000;//invisible
832 pRet = m_apSymbolProperties_InvisibleSymbolForSelection.get();
836 else
838 if (!m_apSymbolProperties_Series)
839 m_apSymbolProperties_Series.reset(
840 getSymbolPropertiesFromPropertySet(this->getPropertiesOfSeries()));
841 pRet = m_apSymbolProperties_Series.get();
844 if( pRet && pRet->Style == SymbolStyle_AUTO )
846 pRet->Style = SymbolStyle_STANDARD;
848 sal_Int32 nIndex = m_nGlobalSeriesIndex;
849 if(m_aValues_X.is())
850 nIndex++;
851 pRet->StandardSymbol = nIndex;
854 return pRet;
857 uno::Reference< beans::XPropertySet > VDataSeries::getXErrorBarProperties( sal_Int32 index ) const
859 uno::Reference< beans::XPropertySet > xErrorBarProp;
861 uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( index ));
862 if( xPointProp.is() )
863 xPointProp->getPropertyValue(CHART_UNONAME_ERRORBAR_X) >>= xErrorBarProp;
864 return xErrorBarProp;
867 uno::Reference< beans::XPropertySet > VDataSeries::getYErrorBarProperties( sal_Int32 index ) const
869 uno::Reference< beans::XPropertySet > xErrorBarProp;
871 uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( index ));
872 if( xPointProp.is() )
873 xPointProp->getPropertyValue(CHART_UNONAME_ERRORBAR_Y) >>= xErrorBarProp;
874 return xErrorBarProp;
877 bool VDataSeries::hasPointOwnColor( sal_Int32 index ) const
879 if( !isAttributedDataPoint(index) )
880 return false;
884 uno::Reference< beans::XPropertyState > xPointState( this->getPropertiesOfPoint(index), uno::UNO_QUERY_THROW );
885 return (xPointState->getPropertyState("Color") != beans::PropertyState_DEFAULT_VALUE );
887 catch(const uno::Exception& e)
889 ASSERT_EXCEPTION( e );
891 return false;
894 bool VDataSeries::isAttributedDataPoint( sal_Int32 index ) const
896 //returns true if the data point assigned by the given index has set it's own properties
897 if( index>=m_nPointCount || m_nPointCount==0)
898 return false;
899 for(sal_Int32 nN=m_aAttributedDataPointIndexList.getLength();nN--;)
901 if(index==m_aAttributedDataPointIndexList[nN])
902 return true;
904 return false;
907 bool VDataSeries::isVaryColorsByPoint() const
909 bool bVaryColorsByPoint = false;
910 Reference< beans::XPropertySet > xSeriesProp( this->getPropertiesOfSeries() );
911 if( xSeriesProp.is() )
912 xSeriesProp->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint;
913 return bVaryColorsByPoint;
916 uno::Reference< beans::XPropertySet > VDataSeries::getPropertiesOfPoint( sal_Int32 index ) const
918 if( isAttributedDataPoint( index ) )
919 return m_xDataSeries->getDataPointByIndex(index);
920 return this->getPropertiesOfSeries();
923 uno::Reference<beans::XPropertySet> VDataSeries::getPropertiesOfSeries() const
925 return uno::Reference<css::beans::XPropertySet>(m_xDataSeries, css::uno::UNO_QUERY);
928 DataPointLabel* getDataPointLabelFromPropertySet( const uno::Reference< beans::XPropertySet >& xProp )
930 ::std::unique_ptr< DataPointLabel > apLabel( new DataPointLabel() );
933 if( !(xProp->getPropertyValue(CHART_UNONAME_LABEL) >>= *apLabel) )
934 apLabel.reset();
936 catch(const uno::Exception &e)
938 ASSERT_EXCEPTION( e );
940 return apLabel.release();
943 void VDataSeries::adaptPointCache( sal_Int32 nNewPointIndex ) const
945 if( m_nCurrentAttributedPoint != nNewPointIndex )
947 m_apLabel_AttributedPoint.reset();
948 m_apLabelPropNames_AttributedPoint.reset();
949 m_apLabelPropValues_AttributedPoint.reset();
950 m_apSymbolProperties_AttributedPoint.reset();
951 m_nCurrentAttributedPoint = nNewPointIndex;
955 DataPointLabel* VDataSeries::getDataPointLabel( sal_Int32 index ) const
957 DataPointLabel* pRet = NULL;
958 if( isAttributedDataPoint( index ) )
960 adaptPointCache( index );
961 if( !m_apLabel_AttributedPoint.get() )
962 m_apLabel_AttributedPoint.reset(
963 getDataPointLabelFromPropertySet(this->getPropertiesOfPoint(index)));
964 pRet = m_apLabel_AttributedPoint.get();
966 else
968 if (!m_apLabel_Series)
969 m_apLabel_Series.reset(
970 getDataPointLabelFromPropertySet(this->getPropertiesOfPoint(index)));
971 pRet = m_apLabel_Series.get();
973 if( !m_bAllowPercentValueInDataLabel )
975 if( pRet )
976 pRet->ShowNumberInPercent = false;
978 return pRet;
981 DataPointLabel* VDataSeries::getDataPointLabelIfLabel( sal_Int32 index ) const
983 DataPointLabel* pLabel = this->getDataPointLabel( index );
984 if( !pLabel || (!pLabel->ShowNumber && !pLabel->ShowNumberInPercent
985 && !pLabel->ShowCategoryName ) )
986 return 0;
987 return pLabel;
990 bool VDataSeries::getTextLabelMultiPropertyLists( sal_Int32 index
991 , tNameSequence*& pPropNames
992 , tAnySequence*& pPropValues ) const
994 pPropNames = NULL; pPropValues = NULL;
995 uno::Reference< beans::XPropertySet > xTextProp;
996 bool bDoDynamicFontResize = false;
997 if( isAttributedDataPoint( index ) )
999 adaptPointCache( index );
1000 if (!m_apLabelPropValues_AttributedPoint)
1002 // Cache these properties for this point.
1003 m_apLabelPropNames_AttributedPoint.reset(new tNameSequence);
1004 m_apLabelPropValues_AttributedPoint.reset(new tAnySequence);
1005 xTextProp.set( this->getPropertiesOfPoint( index ));
1006 PropertyMapper::getTextLabelMultiPropertyLists(
1007 xTextProp, *m_apLabelPropNames_AttributedPoint, *m_apLabelPropValues_AttributedPoint);
1008 bDoDynamicFontResize = true;
1010 pPropNames = m_apLabelPropNames_AttributedPoint.get();
1011 pPropValues = m_apLabelPropValues_AttributedPoint.get();
1013 else
1015 if (!m_apLabelPropValues_Series)
1017 // Cache these properties for the whole series.
1018 m_apLabelPropNames_Series.reset(new tNameSequence);
1019 m_apLabelPropValues_Series.reset(new tAnySequence);
1020 xTextProp.set( this->getPropertiesOfPoint( index ));
1021 PropertyMapper::getTextLabelMultiPropertyLists(
1022 xTextProp, *m_apLabelPropNames_Series, *m_apLabelPropValues_Series);
1023 bDoDynamicFontResize = true;
1025 pPropNames = m_apLabelPropNames_Series.get();
1026 pPropValues = m_apLabelPropValues_Series.get();
1029 if( bDoDynamicFontResize &&
1030 pPropNames && pPropValues &&
1031 xTextProp.is())
1033 LabelPositionHelper::doDynamicFontResize( *pPropValues, *pPropNames, xTextProp, m_aReferenceSize );
1036 return (pPropNames && pPropValues);
1039 void VDataSeries::setMissingValueTreatment( sal_Int32 nMissingValueTreatment )
1041 m_nMissingValueTreatment = nMissingValueTreatment;
1044 sal_Int32 VDataSeries::getMissingValueTreatment() const
1046 return m_nMissingValueTreatment;
1049 VDataSeries::VDataSeries()
1050 : m_nPolygonIndex(0)
1051 , m_fLogicMinX(0)
1052 , m_fLogicMaxX(0)
1053 , m_fLogicZPos(0)
1054 , m_nPointCount(0)
1055 , m_pValueSequenceForDataLabelNumberFormatDetection(NULL)
1056 , m_fXMeanValue(0)
1057 , m_fYMeanValue(0)
1058 , m_eStackingDirection(chart2::StackingDirection_NO_STACKING)
1059 , m_nAxisIndex(0)
1060 , m_bConnectBars(false)
1061 , m_bGroupBarsPerAxis(false)
1062 , m_nStartingAngle(0)
1063 , m_nGlobalSeriesIndex(0)
1064 , m_nCurrentAttributedPoint(0)
1065 , m_nMissingValueTreatment(0)
1066 , m_bAllowPercentValueInDataLabel(false)
1067 , mpOldSeries(NULL)
1068 , mnPercent(0)
1072 void VDataSeries::setOldTimeBased( VDataSeries* pOldSeries, double nPercent )
1074 mnPercent = nPercent;
1075 mpOldSeries = pOldSeries;
1076 mpOldSeries->mpOldSeries = NULL;
1079 VDataSeries* VDataSeries::createCopyForTimeBased() const
1081 VDataSeries* pNew = new VDataSeries();
1082 pNew->m_aValues_X = m_aValues_X;
1083 pNew->m_aValues_Y = m_aValues_Y;
1084 pNew->m_aValues_Z = m_aValues_Z;
1085 pNew->m_aValues_Y_Min = m_aValues_Y_Min;
1086 pNew->m_aValues_Y_Max = m_aValues_Y_Max;
1087 pNew->m_aValues_Y_First = m_aValues_Y_First;
1088 pNew->m_aValues_Y_Last = m_aValues_Y_Last;
1089 pNew->m_aValues_Bubble_Size = m_aValues_Bubble_Size;
1090 pNew->maPropertyMap = maPropertyMap;
1092 pNew->m_nPointCount = m_nPointCount;
1094 return pNew;
1097 double VDataSeries::getValueByProperty( sal_Int32 nIndex, const OUString& rPropName ) const
1099 boost::ptr_map<OUString, VDataSequence>::const_iterator itr =
1100 maPropertyMap.find(rPropName);
1101 if(itr == maPropertyMap.end())
1103 double fNan;
1104 ::rtl::math::setNan( &fNan );
1105 return fNan;
1108 const VDataSequence* pData = itr->second;
1109 double fValue = pData->getValue(nIndex);
1110 if(mpOldSeries && mpOldSeries->hasPropertyMapping(rPropName))
1112 double fOldValue = mpOldSeries->getValueByProperty( nIndex, rPropName );
1113 if(rPropName.endsWith("Color"))
1115 //optimized interpolation for color values
1116 Color aColor(static_cast<sal_uInt32>(fValue));
1117 Color aOldColor(static_cast<sal_uInt32>(fOldValue));
1118 sal_uInt8 r = aOldColor.GetRed() + (aColor.GetRed() - aOldColor.GetRed()) * mnPercent;
1119 sal_uInt8 g = aOldColor.GetGreen() + (aColor.GetGreen() - aOldColor.GetGreen()) * mnPercent;
1120 sal_uInt8 b = aOldColor.GetBlue() + (aColor.GetBlue() - aOldColor.GetBlue()) * mnPercent;
1121 sal_uInt8 t = aOldColor.GetTransparency() + (aColor.GetTransparency() - aOldColor.GetTransparency()) * mnPercent;
1122 Color aRet(t, r, g, b);
1123 return aRet.GetColor();
1125 return fOldValue + (fValue - fOldValue) * mnPercent;
1127 return fValue;
1130 bool VDataSeries::hasPropertyMapping(const OUString& rPropName ) const
1132 return maPropertyMap.find(rPropName) != maPropertyMap.end();
1135 } //namespace chart
1137 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */