LCOV - code coverage report
Current view: top level - chart2/source/view/charttypes - VSeriesPlotter.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 1032 1243 83.0 %
Date: 2014-04-11 Functions: 81 88 92.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #include "VSeriesPlotter.hxx"
      21             : #include "AbstractShapeFactory.hxx"
      22             : #include "chartview/ExplicitValueProvider.hxx"
      23             : 
      24             : #include "CommonConverters.hxx"
      25             : #include "macros.hxx"
      26             : #include "ViewDefines.hxx"
      27             : #include "ObjectIdentifier.hxx"
      28             : #include "StatisticsHelper.hxx"
      29             : #include "PlottingPositionHelper.hxx"
      30             : #include "LabelPositionHelper.hxx"
      31             : #include "ChartTypeHelper.hxx"
      32             : #include "Clipping.hxx"
      33             : #include "servicenames_charttypes.hxx"
      34             : #include "NumberFormatterWrapper.hxx"
      35             : #include "ContainerHelper.hxx"
      36             : #include "DataSeriesHelper.hxx"
      37             : #include "RegressionCurveHelper.hxx"
      38             : #include "VLegendSymbolFactory.hxx"
      39             : #include "FormattedStringHelper.hxx"
      40             : #include "ResId.hxx"
      41             : #include "Strings.hrc"
      42             : #include "RelativePositionHelper.hxx"
      43             : #include "DateHelper.hxx"
      44             : #include "DiagramHelper.hxx"
      45             : #include "defines.hxx"
      46             : 
      47             : //only for creation: @todo remove if all plotter are uno components and instanciated via servicefactory
      48             : #include "BarChart.hxx"
      49             : #include "PieChart.hxx"
      50             : #include "AreaChart.hxx"
      51             : #include "CandleStickChart.hxx"
      52             : #include "BubbleChart.hxx"
      53             : #include "NetChart.hxx"
      54             : 
      55             : #include <com/sun/star/chart/ErrorBarStyle.hpp>
      56             : #include <com/sun/star/chart/TimeUnit.hpp>
      57             : #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
      58             : #include <com/sun/star/container/XChild.hpp>
      59             : #include <com/sun/star/chart2/RelativePosition.hpp>
      60             : #include <editeng/unoprnms.hxx>
      61             : #include <tools/color.hxx>
      62             : // header for class OUStringBuffer
      63             : #include <rtl/ustrbuf.hxx>
      64             : #include <rtl/math.hxx>
      65             : #include <basegfx/vector/b2dvector.hxx>
      66             : #include <com/sun/star/drawing/LineStyle.hpp>
      67             : #include <com/sun/star/util/XCloneable.hpp>
      68             : 
      69             : #include <svx/unoshape.hxx>
      70             : 
      71             : #include <functional>
      72             : #include <map>
      73             : 
      74             : #include <boost/ptr_container/ptr_map.hpp>
      75             : 
      76             : namespace chart {
      77             : 
      78             : using namespace ::com::sun::star;
      79             : using namespace ::com::sun::star::chart2;
      80             : using ::com::sun::star::uno::Reference;
      81             : using ::com::sun::star::uno::Sequence;
      82             : 
      83        7935 : VDataSeriesGroup::CachedYValues::CachedYValues()
      84             :         : m_bValuesDirty(true)
      85             :         , m_fMinimumY(0.0)
      86        7935 :         , m_fMaximumY(0.0)
      87             : {
      88        7935 : }
      89             : 
      90          18 : VDataSeriesGroup::VDataSeriesGroup()
      91             :         : m_aSeriesVector()
      92             :         , m_bMaxPointCountDirty(true)
      93             :         , m_nMaxPointCount(0)
      94          18 :         , m_aListOfCachedYValues()
      95             : {
      96          18 : }
      97             : 
      98        1963 : VDataSeriesGroup::VDataSeriesGroup( VDataSeries* pSeries )
      99             :         : m_aSeriesVector(1,pSeries)
     100             :         , m_bMaxPointCountDirty(true)
     101             :         , m_nMaxPointCount(0)
     102        1963 :         , m_aListOfCachedYValues()
     103             : {
     104        1963 : }
     105             : 
     106       10571 : VDataSeriesGroup::~VDataSeriesGroup()
     107             : {
     108       10571 : }
     109             : 
     110        1981 : void VDataSeriesGroup::deleteSeries()
     111             : {
     112             :     //delete all data series help objects:
     113        1981 :     ::std::vector< VDataSeries* >::const_iterator aIter = m_aSeriesVector.begin();
     114        1981 :     const ::std::vector< VDataSeries* >::const_iterator aEnd  = m_aSeriesVector.end();
     115        3961 :     for( ; aIter != aEnd; ++aIter )
     116             :     {
     117        1980 :         delete *aIter;
     118             :     }
     119        1981 :     m_aSeriesVector.clear();
     120        1981 : }
     121             : 
     122          17 : void VDataSeriesGroup::addSeries( VDataSeries* pSeries )
     123             : {
     124          17 :     m_aSeriesVector.push_back(pSeries);
     125          17 :     m_bMaxPointCountDirty=true;
     126          17 : }
     127             : 
     128          17 : sal_Int32 VDataSeriesGroup::getSeriesCount() const
     129             : {
     130          17 :     return m_aSeriesVector.size();
     131             : }
     132             : 
     133         620 : VSeriesPlotter::VSeriesPlotter( const uno::Reference<XChartType>& xChartTypeModel
     134             :                                , sal_Int32 nDimensionCount, bool bCategoryXAxis )
     135             :         : PlotterBase( nDimensionCount )
     136             :         , m_pMainPosHelper( 0 )
     137             :         , m_xChartTypeModel(xChartTypeModel)
     138             :         , m_xChartTypeModelProps( uno::Reference< beans::XPropertySet >::query( xChartTypeModel ))
     139             :         , m_aZSlots()
     140             :         , m_bCategoryXAxis(bCategoryXAxis)
     141             :         , m_nTimeResolution(::com::sun::star::chart::TimeUnit::DAY)
     142             :         , m_aNullDate(30,12,1899)
     143             :         , m_xColorScheme()
     144             :         , m_pExplicitCategoriesProvider(0)
     145         620 :         , m_bPointsWereSkipped(false)
     146             : {
     147             :     SAL_WARN_IF(!m_xChartTypeModel.is(),"chart2","no XChartType available in view, fallback to default values may be wrong");
     148         620 : }
     149             : 
     150        1240 : VSeriesPlotter::~VSeriesPlotter()
     151             : {
     152             :     //delete all data series help objects:
     153         620 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator             aZSlotIter = m_aZSlots.begin();
     154         620 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
     155        1263 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
     156             :     {
     157         643 :         ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
     158         643 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
     159        2624 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
     160             :         {
     161        1981 :             aXSlotIter->deleteSeries();
     162             :         }
     163         643 :         aZSlotIter->clear();
     164             :     }
     165         620 :     m_aZSlots.clear();
     166             : 
     167         620 :     tSecondaryPosHelperMap::iterator aPosIt = m_aSecondaryPosHelperMap.begin();
     168        1242 :     while( aPosIt != m_aSecondaryPosHelperMap.end() )
     169             :     {
     170           2 :         PlottingPositionHelper* pPosHelper = aPosIt->second;
     171           2 :         delete pPosHelper;
     172             : 
     173           2 :         ++aPosIt;
     174             :     }
     175         620 :     m_aSecondaryPosHelperMap.clear();
     176             : 
     177         620 :     m_aSecondaryValueScales.clear();
     178         620 : }
     179             : 
     180        1980 : void VSeriesPlotter::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
     181             : {
     182             :     //take ownership of pSeries
     183             : 
     184             :     OSL_PRECOND( pSeries, "series to add is NULL" );
     185        1980 :     if(!pSeries)
     186        1980 :         return;
     187             : 
     188        1980 :     if(m_bCategoryXAxis)
     189             :     {
     190        1962 :         if( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() )
     191           0 :             pSeries->setXValues( m_pExplicitCategoriesProvider->getOriginalCategories() );
     192             :         else
     193        1962 :             pSeries->setCategoryXAxis();
     194             :     }
     195             :     else
     196             :     {
     197          18 :         if( m_pExplicitCategoriesProvider )
     198          18 :             pSeries->setXValuesIfNone( m_pExplicitCategoriesProvider->getOriginalCategories() );
     199             :     }
     200             : 
     201        1980 :     if(zSlot<0 || zSlot>=static_cast<sal_Int32>(m_aZSlots.size()))
     202             :     {
     203             :         //new z slot
     204          84 :         ::std::vector< VDataSeriesGroup > aZSlot;
     205          84 :         aZSlot.push_back( VDataSeriesGroup(pSeries) );
     206          84 :         m_aZSlots.push_back( aZSlot );
     207             :     }
     208             :     else
     209             :     {
     210             :         //existing zslot
     211        1896 :         ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[zSlot];
     212             : 
     213        1896 :         if(xSlot<0 || xSlot>=static_cast<sal_Int32>(rXSlots.size()))
     214             :         {
     215             :             //append the series to already existing x series
     216        1879 :             rXSlots.push_back( VDataSeriesGroup(pSeries) );
     217             :         }
     218             :         else
     219             :         {
     220             :             //x slot is already occupied
     221             :             //y slot decides what to do:
     222             : 
     223          17 :             VDataSeriesGroup& rYSlots = rXSlots[xSlot];
     224          17 :             sal_Int32 nYSlotCount = rYSlots.getSeriesCount();
     225             : 
     226          17 :             if( ySlot < -1 )
     227             :             {
     228             :                 //move all existing series in the xSlot to next slot
     229             :                 //@todo
     230             :                 OSL_FAIL( "Not implemented yet");
     231             :             }
     232          17 :             else if( ySlot == -1 || ySlot >= nYSlotCount)
     233             :             {
     234             :                 //append the series to already existing y series
     235          17 :                 rYSlots.addSeries(pSeries);
     236             :             }
     237             :             else
     238             :             {
     239             :                 //y slot is already occupied
     240             :                 //insert at given y and x position
     241             : 
     242             :                 //@todo
     243             :                 OSL_FAIL( "Not implemented yet");
     244             :             }
     245             :         }
     246             :     }
     247             : }
     248             : 
     249           0 : drawing::Direction3D VSeriesPlotter::getPreferredDiagramAspectRatio() const
     250             : {
     251           0 :     drawing::Direction3D aRet(1.0,1.0,1.0);
     252           0 :     if (!m_pPosHelper)
     253           0 :         return aRet;
     254             : 
     255           0 :     drawing::Direction3D aScale( m_pPosHelper->getScaledLogicWidth() );
     256           0 :     aRet.DirectionZ = aScale.DirectionZ*0.2;
     257           0 :     if(aRet.DirectionZ>1.0)
     258           0 :         aRet.DirectionZ=1.0;
     259           0 :     if(aRet.DirectionZ>10)
     260           0 :         aRet.DirectionZ=10;
     261           0 :     return aRet;
     262             : }
     263             : 
     264           0 : bool VSeriesPlotter::keepAspectRatio() const
     265             : {
     266           0 :     return true;
     267             : }
     268             : 
     269          15 : void VSeriesPlotter::releaseShapes()
     270             : {
     271          15 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator             aZSlotIter = m_aZSlots.begin();
     272          15 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
     273          30 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
     274             :     {
     275          15 :         ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
     276          15 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
     277          57 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
     278             :         {
     279          42 :             ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
     280             : 
     281          42 :             ::std::vector< VDataSeries* >::iterator             aSeriesIter = pSeriesList->begin();
     282          42 :             const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
     283             : 
     284             :             //iterate through all series in this x slot
     285          84 :             for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
     286             :             {
     287          42 :                 VDataSeries* pSeries( *aSeriesIter );
     288          42 :                 pSeries->releaseShapes();
     289             :             }
     290             :         }
     291             :     }
     292          15 : }
     293             : 
     294        7363 : uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShape( VDataSeries* pDataSeries
     295             :                                         , const uno::Reference< drawing::XShapes >& xTarget )
     296             : {
     297        7363 :     uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xGroupShape );
     298        7363 :     if( !xShapes.is() )
     299             :     {
     300             :         //create a group shape for this series and add to logic target:
     301        1968 :         xShapes = createGroupShape( xTarget,pDataSeries->getCID() );
     302        1968 :         pDataSeries->m_xGroupShape = xShapes;
     303             :     }
     304        7363 :     return xShapes;
     305             : }
     306             : 
     307         151 : uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShapeFrontChild( VDataSeries* pDataSeries
     308             :                                         , const uno::Reference< drawing::XShapes >& xTarget )
     309             : {
     310         151 :     uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xFrontSubGroupShape );
     311         151 :     if(!xShapes.is())
     312             :     {
     313             :         //ensure that the series group shape is already created
     314         151 :         uno::Reference< drawing::XShapes > xSeriesShapes( this->getSeriesGroupShape( pDataSeries, xTarget ) );
     315             :         //ensure that the back child is created first
     316         151 :         this->getSeriesGroupShapeBackChild( pDataSeries, xTarget );
     317             :         //use series group shape as parent for the new created front group shape
     318         151 :         xShapes = createGroupShape( xSeriesShapes );
     319         151 :         pDataSeries->m_xFrontSubGroupShape = xShapes;
     320             :     }
     321         151 :     return xShapes;
     322             : }
     323             : 
     324         302 : uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShapeBackChild( VDataSeries* pDataSeries
     325             :                                         , const uno::Reference< drawing::XShapes >& xTarget )
     326             : {
     327         302 :     uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xBackSubGroupShape );
     328         302 :     if(!xShapes.is())
     329             :     {
     330             :         //ensure that the series group shape is already created
     331         151 :         uno::Reference< drawing::XShapes > xSeriesShapes( this->getSeriesGroupShape( pDataSeries, xTarget ) );
     332             :         //use series group shape as parent for the new created back group shape
     333         151 :         xShapes = createGroupShape( xSeriesShapes );
     334         151 :         pDataSeries->m_xBackSubGroupShape = xShapes;
     335             :     }
     336         302 :     return xShapes;
     337             : }
     338             : 
     339         893 : uno::Reference< drawing::XShapes > VSeriesPlotter::getLabelsGroupShape( VDataSeries& rDataSeries
     340             :                                         , const uno::Reference< drawing::XShapes >& xTextTarget )
     341             : {
     342             :     //xTextTarget needs to be a 2D shape container always!
     343             : 
     344         893 :     uno::Reference< drawing::XShapes > xShapes( rDataSeries.m_xLabelsGroupShape );
     345         893 :     if(!xShapes.is())
     346             :     {
     347             :         //create a 2D group shape for texts of this series and add to text target:
     348         192 :         xShapes = m_pShapeFactory->createGroup2D( xTextTarget, rDataSeries.getLabelsCID() );
     349         192 :         rDataSeries.m_xLabelsGroupShape = xShapes;
     350             :     }
     351         893 :     return xShapes;
     352             : }
     353             : 
     354        2417 : uno::Reference< drawing::XShapes > VSeriesPlotter::getErrorBarsGroupShape( VDataSeries& rDataSeries
     355             :                                         , const uno::Reference< drawing::XShapes >& xTarget
     356             :                                         , bool bYError )
     357             : {
     358             :     uno::Reference< ::com::sun::star::drawing::XShapes > &rShapeGroup =
     359        2417 :             bYError ? rDataSeries.m_xErrorYBarsGroupShape : rDataSeries.m_xErrorXBarsGroupShape;
     360             : 
     361        2417 :     uno::Reference< drawing::XShapes > xShapes( rShapeGroup );
     362        2417 :     if(!xShapes.is())
     363             :     {
     364             :         //create a group shape for this series and add to logic target:
     365         565 :         xShapes = this->createGroupShape( xTarget,rDataSeries.getErrorBarsCID(bYError) );
     366         565 :         rShapeGroup = xShapes;
     367             :     }
     368        2417 :     return xShapes;
     369             : 
     370             : }
     371             : 
     372         895 : OUString VSeriesPlotter::getLabelTextForValue( VDataSeries& rDataSeries
     373             :                 , sal_Int32 nPointIndex
     374             :                 , double fValue
     375             :                 , bool bAsPercentage )
     376             : {
     377         895 :     OUString aNumber;
     378             : 
     379         895 :     if( m_apNumberFormatterWrapper.get())
     380             :     {
     381         895 :         sal_Int32 nNumberFormatKey = 0;
     382         895 :         if( rDataSeries.hasExplicitNumberFormat(nPointIndex,bAsPercentage) )
     383          23 :             nNumberFormatKey = rDataSeries.getExplicitNumberFormat(nPointIndex,bAsPercentage);
     384         872 :         else if( bAsPercentage )
     385             :         {
     386          49 :             sal_Int32 nPercentFormat = DiagramHelper::getPercentNumberFormat( m_apNumberFormatterWrapper->getNumberFormatsSupplier() );
     387          49 :             if( nPercentFormat != -1 )
     388          49 :                 nNumberFormatKey = nPercentFormat;
     389             :         }
     390             :         else
     391             :         {
     392         823 :             if( rDataSeries.shouldLabelNumberFormatKeyBeDetectedFromYAxis() && m_aAxesNumberFormats.hasFormat(1,rDataSeries.getAttachedAxisIndex()) ) //y-axis
     393           0 :                 nNumberFormatKey = m_aAxesNumberFormats.getFormat(1,rDataSeries.getAttachedAxisIndex());
     394             :             else
     395         823 :                 nNumberFormatKey = rDataSeries.detectNumberFormatKey( nPointIndex );
     396             :         }
     397         895 :         if(nNumberFormatKey<0)
     398           0 :             nNumberFormatKey=0;
     399             : 
     400         895 :         sal_Int32 nLabelCol = 0;
     401             :         bool bColChanged;
     402        1790 :         aNumber = m_apNumberFormatterWrapper->getFormattedString(
     403         895 :                 nNumberFormatKey, fValue, nLabelCol, bColChanged );
     404             :         //@todo: change color of label if bColChanged is true
     405             :     }
     406             :     else
     407             :     {
     408           0 :         sal_Unicode cDecSeparator = '.';//@todo get this locale dependent
     409           0 :         aNumber = ::rtl::math::doubleToUString( fValue, rtl_math_StringFormat_G /*rtl_math_StringFormat*/
     410           0 :             , 3/*DecPlaces*/ , cDecSeparator, false /*bEraseTrailingDecZeros*/ );
     411             :     }
     412         895 :     return aNumber;
     413             : }
     414             : 
     415         893 : uno::Reference< drawing::XShape > VSeriesPlotter::createDataLabel( const uno::Reference< drawing::XShapes >& xTarget
     416             :                     , VDataSeries& rDataSeries
     417             :                     , sal_Int32 nPointIndex
     418             :                     , double fValue
     419             :                     , double fSumValue
     420             :                     , const awt::Point& rScreenPosition2D
     421             :                     , LabelAlignment eAlignment
     422             :                     , sal_Int32 nOffset )
     423             : {
     424         893 :     uno::Reference< drawing::XShape > xTextShape;
     425             : 
     426             :     try
     427             :     {
     428         893 :         awt::Point aScreenPosition2D(rScreenPosition2D);
     429         893 :         if(LABEL_ALIGN_LEFT==eAlignment)
     430           0 :             aScreenPosition2D.X -= nOffset;
     431         893 :         else if(LABEL_ALIGN_RIGHT==eAlignment)
     432           0 :             aScreenPosition2D.X += nOffset;
     433         893 :         else if(LABEL_ALIGN_TOP==eAlignment)
     434         870 :             aScreenPosition2D.Y -= nOffset;
     435          23 :         else if(LABEL_ALIGN_BOTTOM==eAlignment)
     436           0 :             aScreenPosition2D.Y += nOffset;
     437             : 
     438             :         uno::Reference< drawing::XShapes > xTarget_(
     439             :                 m_pShapeFactory->createGroup2D( this->getLabelsGroupShape(rDataSeries, xTarget)
     440         893 :                     , ObjectIdentifier::createPointCID( rDataSeries.getLabelCID_Stub(),nPointIndex ) ) );
     441             : 
     442             :         //check whether the label needs to be created and how:
     443         893 :         DataPointLabel* pLabel = rDataSeries.getDataPointLabelIfLabel( nPointIndex );
     444             : 
     445         893 :         if( !pLabel )
     446           0 :             return xTextShape;
     447             : 
     448             :         //prepare legend symbol
     449             : 
     450         893 :         float fViewFontSize( 10.0 );
     451             :         {
     452         893 :             uno::Reference< beans::XPropertySet > xProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) );
     453         893 :             if( xProps.is() )
     454         893 :                 xProps->getPropertyValue( "CharHeight") >>= fViewFontSize;
     455             :             // pt -> 1/100th mm
     456         893 :             fViewFontSize *= (2540.0f / 72.0f);
     457             :         }
     458        1786 :         Reference< drawing::XShape > xSymbol;
     459         893 :         if(pLabel->ShowLegendSymbol)
     460             :         {
     461           0 :             sal_Int32 nSymbolHeight = static_cast< sal_Int32 >( fViewFontSize * 0.6  );
     462           0 :             awt::Size aCurrentRatio = this->getPreferredLegendKeyAspectRatio();
     463           0 :             sal_Int32 nSymbolWidth = aCurrentRatio.Width;
     464           0 :             if( aCurrentRatio.Height > 0 )
     465             :             {
     466           0 :                 nSymbolWidth = nSymbolHeight* aCurrentRatio.Width/aCurrentRatio.Height;
     467             :             }
     468           0 :             awt::Size aMaxSymbolExtent( nSymbolWidth, nSymbolHeight );
     469             : 
     470           0 :             if( rDataSeries.isVaryColorsByPoint() )
     471           0 :                 xSymbol.set( VSeriesPlotter::createLegendSymbolForPoint( aMaxSymbolExtent, rDataSeries, nPointIndex, xTarget_, m_xShapeFactory ) );
     472             :             else
     473           0 :                 xSymbol.set( VSeriesPlotter::createLegendSymbolForSeries( aMaxSymbolExtent, rDataSeries, xTarget_, m_xShapeFactory ) );
     474             : 
     475             :         }
     476             :         //prepare text
     477        1786 :         OUStringBuffer aText;
     478        1786 :         OUString aSeparator(" ");
     479         893 :         double fRotationDegrees = 0.0;
     480             :         try
     481             :         {
     482         893 :             uno::Reference< beans::XPropertySet > xPointProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) );
     483         893 :             if(xPointProps.is())
     484             :             {
     485         893 :                 xPointProps->getPropertyValue( "LabelSeparator" ) >>= aSeparator;
     486         893 :                 xPointProps->getPropertyValue( "TextRotation" ) >>= fRotationDegrees;
     487         893 :             }
     488             :         }
     489           0 :         catch( const uno::Exception& e )
     490             :         {
     491             :             ASSERT_EXCEPTION( e );
     492             :         }
     493         893 :         bool bMultiLineLabel = aSeparator.equals("\n");;
     494         893 :         sal_Int32 nLineCountForSymbolsize = 0;
     495             :         {
     496         893 :             if(pLabel->ShowCategoryName)
     497             :             {
     498         841 :                 if( m_pExplicitCategoriesProvider )
     499             :                 {
     500         841 :                     Sequence< OUString > aCategories( m_pExplicitCategoriesProvider->getSimpleCategories() );
     501         841 :                     if( nPointIndex >= 0 && nPointIndex < aCategories.getLength() )
     502             :                     {
     503         841 :                         aText.append( aCategories[nPointIndex] );
     504         841 :                         ++nLineCountForSymbolsize;
     505         841 :                     }
     506             :                 }
     507             :             }
     508             : 
     509         893 :             if(pLabel->ShowNumber)
     510             :             {
     511             :                 OUString aNumber( this->getLabelTextForValue( rDataSeries
     512         846 :                     , nPointIndex, fValue, false /*bAsPercentage*/ ) );
     513         846 :                 if( !aNumber.isEmpty() )
     514             :                 {
     515         846 :                     if(!aText.isEmpty())
     516         818 :                         aText.append(aSeparator);
     517         846 :                     aText.append(aNumber);
     518         846 :                     ++nLineCountForSymbolsize;
     519         846 :                 }
     520             :             }
     521             : 
     522         893 :             if(pLabel->ShowNumberInPercent)
     523             :             {
     524          49 :                 if(fSumValue==0.0)
     525           0 :                     fSumValue=1.0;
     526          49 :                 fValue /= fSumValue;
     527          49 :                 if( fValue < 0 )
     528           0 :                     fValue*=-1.0;
     529             : 
     530             :                 OUString aPercentage( this->getLabelTextForValue( rDataSeries
     531          49 :                     , nPointIndex, fValue, true /*bAsPercentage*/ ) );
     532          49 :                 if( !aPercentage.isEmpty() )
     533             :                 {
     534          49 :                     if(!aText.isEmpty())
     535          25 :                         aText.append(aSeparator);
     536          49 :                     aText.append(aPercentage);
     537          49 :                     ++nLineCountForSymbolsize;
     538          49 :                 }
     539             :             }
     540             :         }
     541             :         //prepare properties for multipropertyset-interface of shape
     542             :         tNameSequence* pPropNames;
     543             :         tAnySequence* pPropValues;
     544         893 :         if( !rDataSeries.getTextLabelMultiPropertyLists( nPointIndex, pPropNames, pPropValues ) )
     545           0 :             return xTextShape;
     546         893 :         LabelPositionHelper::changeTextAdjustment( *pPropValues, *pPropNames, eAlignment );
     547             : 
     548             :         //create text shape
     549        2679 :         xTextShape = AbstractShapeFactory::getOrCreateShapeFactory(m_xShapeFactory)->
     550             :             createText( xTarget_, aText.makeStringAndClear()
     551        1786 :                         , *pPropNames, *pPropValues, AbstractShapeFactory::makeTransformation( aScreenPosition2D ) );
     552             : 
     553         893 :         if( !xTextShape.is() )
     554           0 :             return xTextShape;
     555             : 
     556         893 :         const awt::Point aUnrotatedTextPos( xTextShape->getPosition() );
     557         893 :         if( fRotationDegrees != 0.0 )
     558             :         {
     559          74 :             const double fDegreesPi( fRotationDegrees * ( F_PI / -180.0 ) );
     560          74 :             uno::Reference< beans::XPropertySet > xProp( xTextShape, uno::UNO_QUERY );
     561          74 :             if( xProp.is() )
     562          74 :                 xProp->setPropertyValue( "Transformation", AbstractShapeFactory::makeTransformation( aScreenPosition2D, fDegreesPi ) );
     563          74 :             LabelPositionHelper::correctPositionForRotation( xTextShape, eAlignment, fRotationDegrees, true /*bRotateAroundCenter*/ );
     564             :         }
     565             : 
     566         893 :         if( xSymbol.is() )
     567             :         {
     568           0 :             const awt::Point aOldTextPos( xTextShape->getPosition() );
     569           0 :             awt::Point aNewTextPos( aOldTextPos );
     570             : 
     571           0 :             awt::Point aSymbolPosition( aUnrotatedTextPos );
     572           0 :             awt::Size aSymbolSize( xSymbol->getSize() );
     573           0 :             awt::Size aTextSize( xTextShape->getSize() );
     574             : 
     575           0 :             sal_Int32 nXDiff = aSymbolSize.Width + static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.22 ) );//minimum 1mm
     576           0 :             if( !bMultiLineLabel || nLineCountForSymbolsize <= 0 )
     577           0 :                 nLineCountForSymbolsize = 1;
     578           0 :             aSymbolPosition.Y += ((aTextSize.Height/nLineCountForSymbolsize)/4);
     579             : 
     580           0 :             if(LABEL_ALIGN_LEFT==eAlignment
     581           0 :                 || LABEL_ALIGN_LEFT_TOP==eAlignment
     582           0 :                 || LABEL_ALIGN_LEFT_BOTTOM==eAlignment)
     583             :             {
     584           0 :                 aSymbolPosition.X -= nXDiff;
     585             :             }
     586           0 :             else if(LABEL_ALIGN_RIGHT==eAlignment
     587           0 :                 || LABEL_ALIGN_RIGHT_TOP==eAlignment
     588           0 :                 || LABEL_ALIGN_RIGHT_BOTTOM==eAlignment )
     589             :             {
     590           0 :                 aNewTextPos.X += nXDiff;
     591             :             }
     592           0 :             else if(LABEL_ALIGN_TOP==eAlignment
     593           0 :                 || LABEL_ALIGN_BOTTOM==eAlignment
     594           0 :                 || LABEL_ALIGN_CENTER==eAlignment )
     595             :             {
     596           0 :                 aSymbolPosition.X -= nXDiff/2;
     597           0 :                 aNewTextPos.X += nXDiff/2;
     598             :             }
     599             : 
     600           0 :             xSymbol->setPosition( aSymbolPosition );
     601           0 :             xTextShape->setPosition( aNewTextPos );
     602         893 :         }
     603             :     }
     604           0 :     catch( const uno::Exception& e )
     605             :     {
     606             :         ASSERT_EXCEPTION( e );
     607             :     }
     608             : 
     609         893 :     return xTextShape;
     610             : }
     611             : 
     612             : namespace
     613             : {
     614         514 : double lcl_getErrorBarLogicLength(
     615             :     const uno::Sequence< double > & rData,
     616             :     uno::Reference< beans::XPropertySet > xProp,
     617             :     sal_Int32 nErrorBarStyle,
     618             :     sal_Int32 nIndex,
     619             :     bool bPositive,
     620             :     bool bYError )
     621             : {
     622             :     double fResult;
     623         514 :     ::rtl::math::setNan( & fResult );
     624             :     try
     625             :     {
     626         514 :         switch( nErrorBarStyle )
     627             :         {
     628             :             case ::com::sun::star::chart::ErrorBarStyle::NONE:
     629           0 :                 break;
     630             :             case ::com::sun::star::chart::ErrorBarStyle::VARIANCE:
     631           0 :                 fResult = StatisticsHelper::getVariance( rData );
     632           0 :                 break;
     633             :             case ::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION:
     634           0 :                 fResult = StatisticsHelper::getStandardDeviation( rData );
     635           0 :                 break;
     636             :             case ::com::sun::star::chart::ErrorBarStyle::RELATIVE:
     637             :             {
     638         496 :                 double fPercent = 0;
     639        1736 :                 if( xProp->getPropertyValue( bPositive
     640             :                                              ? OUString("PositiveError")
     641        1240 :                                              : OUString("NegativeError") ) >>= fPercent )
     642             :                 {
     643        1488 :                     if( nIndex >=0 && nIndex < rData.getLength() &&
     644        1488 :                         ! ::rtl::math::isNan( rData[nIndex] ) &&
     645         496 :                         ! ::rtl::math::isNan( fPercent ))
     646             :                     {
     647         496 :                         fResult = rData[nIndex] * fPercent / 100.0;
     648             :                     }
     649             :                 }
     650             :             }
     651         496 :             break;
     652             :             case ::com::sun::star::chart::ErrorBarStyle::ABSOLUTE:
     653           0 :                 xProp->getPropertyValue( bPositive
     654             :                                          ? OUString("PositiveError")
     655           0 :                                          : OUString("NegativeError") ) >>= fResult;
     656           0 :                 break;
     657             :             case ::com::sun::star::chart::ErrorBarStyle::ERROR_MARGIN:
     658             :             {
     659             :                 // todo: check if this is really what's called error-margin
     660           0 :                 double fPercent = 0;
     661           0 :                 if( xProp->getPropertyValue( bPositive
     662             :                                              ? OUString("PositiveError")
     663           0 :                                              : OUString("NegativeError") ) >>= fPercent )
     664             :                 {
     665             :                     double fMaxValue;
     666           0 :                     ::rtl::math::setInf(&fMaxValue, true);
     667           0 :                     const double* pValues = rData.getConstArray();
     668           0 :                     for(sal_Int32 i=0; i<rData.getLength(); ++i, ++pValues)
     669             :                     {
     670           0 :                         if(fMaxValue<*pValues)
     671           0 :                             fMaxValue=*pValues;
     672             :                     }
     673           0 :                     if( ::rtl::math::isFinite( fMaxValue ) &&
     674           0 :                         ::rtl::math::isFinite( fPercent ))
     675             :                     {
     676           0 :                         fResult = fMaxValue * fPercent / 100.0;
     677             :                     }
     678             :                 }
     679             :             }
     680           0 :             break;
     681             :             case ::com::sun::star::chart::ErrorBarStyle::STANDARD_ERROR:
     682           0 :                 fResult = StatisticsHelper::getStandardError( rData );
     683           0 :                 break;
     684             :             case ::com::sun::star::chart::ErrorBarStyle::FROM_DATA:
     685             :             {
     686          18 :                 uno::Reference< chart2::data::XDataSource > xErrorBarData( xProp, uno::UNO_QUERY );
     687          18 :                 if( xErrorBarData.is())
     688             :                     fResult = StatisticsHelper::getErrorFromDataSource(
     689          18 :                         xErrorBarData, nIndex, bPositive, bYError);
     690             :             }
     691          18 :             break;
     692             :         }
     693             :     }
     694           0 :     catch( const uno::Exception & e )
     695             :     {
     696             :         ASSERT_EXCEPTION( e );
     697             :     }
     698             : 
     699         514 :     return fResult;
     700             : }
     701             : 
     702         434 : void lcl_AddErrorBottomLine( const drawing::Position3D& rPosition, ::basegfx::B2DVector aMainDirection
     703             :                 , drawing::PolyPolygonShape3D& rPoly, sal_Int32 nSequenceIndex )
     704             : {
     705         434 :     double fFixedWidth = 200.0;
     706             : 
     707         434 :     aMainDirection.normalize();
     708         434 :     ::basegfx::B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
     709         434 :     aOrthoDirection.normalize();
     710             : 
     711         868 :     ::basegfx::B2DVector aAnchor( rPosition.PositionX, rPosition.PositionY );
     712         868 :     ::basegfx::B2DVector aStart = aAnchor + aOrthoDirection*fFixedWidth/2.0;
     713         868 :     ::basegfx::B2DVector aEnd = aAnchor - aOrthoDirection*fFixedWidth/2.0;
     714             : 
     715         434 :     AddPointToPoly( rPoly, drawing::Position3D( aStart.getX(), aStart.getY(), rPosition.PositionZ), nSequenceIndex );
     716         868 :     AddPointToPoly( rPoly, drawing::Position3D( aEnd.getX(), aEnd.getY(), rPosition.PositionZ), nSequenceIndex );
     717         434 : }
     718             : 
     719         434 : ::basegfx::B2DVector lcl_getErrorBarMainDirection(
     720             :               const drawing::Position3D& rStart
     721             :             , const drawing::Position3D& rBottomEnd
     722             :             , PlottingPositionHelper* pPosHelper
     723             :             , const drawing::Position3D& rUnscaledLogicPosition
     724             :             , bool bYError )
     725             : {
     726             :     ::basegfx::B2DVector aMainDirection = ::basegfx::B2DVector( rStart.PositionX - rBottomEnd.PositionX
     727         434 :                                               , rStart.PositionY - rBottomEnd.PositionY );
     728         434 :     if( !aMainDirection.getLength() )
     729             :     {
     730             :         //get logic clip values:
     731           0 :         double MinX = pPosHelper->getLogicMinX();
     732           0 :         double MinY = pPosHelper->getLogicMinY();
     733           0 :         double MaxX = pPosHelper->getLogicMaxX();
     734           0 :         double MaxY = pPosHelper->getLogicMaxY();
     735           0 :         double fZ = pPosHelper->getLogicMinZ();
     736             : 
     737           0 :         if( bYError )
     738             :         {
     739             :             //main direction has constant x value
     740           0 :             MinX = rUnscaledLogicPosition.PositionX;
     741           0 :             MaxX = rUnscaledLogicPosition.PositionX;
     742             :         }
     743             :         else
     744             :         {
     745             :             //main direction has constant y value
     746           0 :             MinY = rUnscaledLogicPosition.PositionY;
     747           0 :             MaxY = rUnscaledLogicPosition.PositionY;
     748             :         }
     749             : 
     750           0 :         drawing::Position3D aStart = pPosHelper->transformLogicToScene( MinX, MinY, fZ, false );
     751           0 :         drawing::Position3D aEnd = pPosHelper->transformLogicToScene( MaxX, MaxY, fZ, false );
     752             : 
     753           0 :         aMainDirection = ::basegfx::B2DVector( aStart.PositionX - aEnd.PositionX
     754           0 :                                               , aStart.PositionY - aEnd.PositionY );
     755             :     }
     756         434 :     if( !aMainDirection.getLength() )
     757             :     {
     758             :         //@todo
     759             :     }
     760         434 :     return aMainDirection;
     761             : }
     762             : 
     763         771 : drawing::Position3D lcl_transformMixedToScene( PlottingPositionHelper* pPosHelper
     764             :     , double fX /*scaled*/, double fY /*unscaled*/, double fZ /*unscaled*/, bool bClip )
     765             : {
     766         771 :     if(!pPosHelper)
     767           0 :         return drawing::Position3D(0,0,0);
     768         771 :     pPosHelper->doLogicScaling( 0,&fY,&fZ );
     769         771 :     if(bClip)
     770         771 :         pPosHelper->clipScaledLogicValues( &fX,&fY,&fZ );
     771         771 :     return pPosHelper->transformScaledLogicToScene( fX, fY, fZ, false );
     772             : }
     773             : 
     774             : } // anonymous namespace
     775             : 
     776        2417 : void VSeriesPlotter::createErrorBar(
     777             :       const uno::Reference< drawing::XShapes >& xTarget
     778             :     , const drawing::Position3D& rUnscaledLogicPosition
     779             :     , const uno::Reference< beans::XPropertySet > & xErrorBarProperties
     780             :     , const VDataSeries& rVDataSeries
     781             :     , sal_Int32 nIndex
     782             :     , bool bYError /* = true */
     783             :     , double* pfScaledLogicX
     784             :     )
     785             : {
     786        2417 :     if( !ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ) )
     787           0 :         return;
     788             : 
     789        2417 :     if( ! xErrorBarProperties.is())
     790           0 :         return;
     791             : 
     792             :     try
     793             :     {
     794        2417 :         sal_Bool bShowPositive = sal_False;
     795        2417 :         sal_Bool bShowNegative = sal_False;
     796        2417 :         sal_Int32 nErrorBarStyle = ::com::sun::star::chart::ErrorBarStyle::VARIANCE;
     797             : 
     798        2417 :         xErrorBarProperties->getPropertyValue( "ShowPositiveError") >>= bShowPositive;
     799        2417 :         xErrorBarProperties->getPropertyValue( "ShowNegativeError") >>= bShowNegative;
     800        2417 :         xErrorBarProperties->getPropertyValue( "ErrorBarStyle") >>= nErrorBarStyle;
     801             : 
     802        2417 :         if(!bShowPositive && !bShowNegative)
     803        4320 :             return;
     804             : 
     805         257 :         if(nErrorBarStyle==::com::sun::star::chart::ErrorBarStyle::NONE)
     806           0 :             return;
     807             : 
     808         257 :         if (!m_pPosHelper)
     809           0 :             return;
     810             : 
     811         257 :         drawing::Position3D aUnscaledLogicPosition(rUnscaledLogicPosition);
     812         257 :         if(nErrorBarStyle==::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION)
     813             :         {
     814           0 :             if (bYError)
     815           0 :                 aUnscaledLogicPosition.PositionY = rVDataSeries.getYMeanValue();
     816             :             else
     817           0 :                 aUnscaledLogicPosition.PositionX = rVDataSeries.getXMeanValue();
     818             :         }
     819             : 
     820         257 :         bool bCreateNegativeBorder = false;//make a vertical line at the negative end of the error bar
     821         257 :         bool bCreatePositiveBorder = false;//make a vertical line at the positive end of the error bar
     822         257 :         drawing::Position3D aMiddle(aUnscaledLogicPosition);
     823         257 :         const double fX = aUnscaledLogicPosition.PositionX;
     824         257 :         const double fY = aUnscaledLogicPosition.PositionY;
     825         257 :         const double fZ = aUnscaledLogicPosition.PositionZ;
     826         257 :         double fScaledX = fX;
     827         257 :         if( pfScaledLogicX )
     828           0 :             fScaledX = *pfScaledLogicX;
     829             :         else
     830         257 :             m_pPosHelper->doLogicScaling( &fScaledX, 0, 0 );
     831             : 
     832         257 :         aMiddle = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fY, fZ, true );
     833             : 
     834         257 :         drawing::Position3D aNegative(aMiddle);
     835         257 :         drawing::Position3D aPositive(aMiddle);
     836             : 
     837         257 :         uno::Sequence< double > aData( bYError ? rVDataSeries.getAllY() : rVDataSeries.getAllX() );
     838             : 
     839         257 :         if( bShowPositive )
     840             :         {
     841         257 :             double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, true, bYError );
     842         257 :             if( ::rtl::math::isFinite( fLength ) )
     843             :             {
     844         257 :                 double fLocalX = fX;
     845         257 :                 double fLocalY = fY;
     846         257 :                 if( bYError )
     847             :                 {
     848         257 :                     fLocalY+=fLength;
     849         257 :                     aPositive = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fLocalY, fZ, true );
     850             :                 }
     851             :                 else
     852             :                 {
     853           0 :                     fLocalX+=fLength;
     854           0 :                     aPositive = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true );
     855             :                 }
     856         257 :                 bCreatePositiveBorder = m_pPosHelper->isLogicVisible(fLocalX, fLocalY, fZ);
     857             :             }
     858             :             else
     859           0 :                 bShowPositive = false;
     860             :         }
     861             : 
     862         257 :         if( bShowNegative )
     863             :         {
     864         257 :             double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, false, bYError );
     865         257 :             if( ::rtl::math::isFinite( fLength ) )
     866             :             {
     867         257 :                 double fLocalX = fX;
     868         257 :                 double fLocalY = fY;
     869         257 :                 if( bYError )
     870             :                 {
     871         257 :                     fLocalY-=fLength;
     872         257 :                     aNegative = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fLocalY, fZ, true );
     873             :                 }
     874             :                 else
     875             :                 {
     876           0 :                     fLocalX-=fLength;
     877           0 :                     aNegative = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true );
     878             :                 }
     879         257 :                 bCreateNegativeBorder = m_pPosHelper->isLogicVisible( fLocalX, fLocalY, fZ);
     880             :             }
     881             :             else
     882           0 :                 bShowNegative = false;
     883             :         }
     884             : 
     885         257 :         if(!bShowPositive && !bShowNegative)
     886           0 :             return;
     887             : 
     888         514 :         drawing::PolyPolygonShape3D aPoly;
     889             : 
     890         257 :         sal_Int32 nSequenceIndex=0;
     891         257 :         if( bShowNegative )
     892         257 :             AddPointToPoly( aPoly, aNegative, nSequenceIndex );
     893         257 :         AddPointToPoly( aPoly, aMiddle, nSequenceIndex );
     894         257 :         if( bShowPositive )
     895         257 :             AddPointToPoly( aPoly, aPositive, nSequenceIndex );
     896             : 
     897         257 :         if( bShowNegative && bCreateNegativeBorder )
     898             :         {
     899         218 :             ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aNegative, m_pPosHelper, aUnscaledLogicPosition, bYError );
     900         218 :             nSequenceIndex++;
     901         218 :             lcl_AddErrorBottomLine( aNegative, aMainDirection, aPoly, nSequenceIndex );
     902             :         }
     903         257 :         if( bShowPositive && bCreatePositiveBorder )
     904             :         {
     905         216 :             ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aPositive, m_pPosHelper, aUnscaledLogicPosition, bYError );
     906         216 :             nSequenceIndex++;
     907         216 :             lcl_AddErrorBottomLine( aPositive, aMainDirection, aPoly, nSequenceIndex );
     908             :         }
     909             : 
     910         514 :         uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D( xTarget, PolyToPointSequence( aPoly) );
     911         514 :         this->setMappedProperties( xShape, xErrorBarProperties, PropertyMapper::getPropertyNameMapForLineProperties() );
     912             :     }
     913           0 :     catch( const uno::Exception & e )
     914             :     {
     915             :         ASSERT_EXCEPTION( e );
     916             :     }
     917             : 
     918             : }
     919             : 
     920           0 : void VSeriesPlotter::createErrorBar_X( const drawing::Position3D& rUnscaledLogicPosition
     921             :                             , VDataSeries& rVDataSeries, sal_Int32 nPointIndex
     922             :                             , const uno::Reference< drawing::XShapes >& xTarget
     923             :                             , double* pfScaledLogicX )
     924             : {
     925           0 :     if(m_nDimension!=2)
     926           0 :         return;
     927             :     // error bars
     928           0 :     uno::Reference< beans::XPropertySet > xErrorBarProp(rVDataSeries.getXErrorBarProperties(nPointIndex));
     929           0 :     if( xErrorBarProp.is())
     930             :     {
     931             :         uno::Reference< drawing::XShapes > xErrorBarsGroup_Shapes(
     932           0 :             this->getErrorBarsGroupShape(rVDataSeries, xTarget, false) );
     933             : 
     934             :         createErrorBar( xErrorBarsGroup_Shapes
     935             :             , rUnscaledLogicPosition, xErrorBarProp
     936             :             , rVDataSeries, nPointIndex
     937             :             , false /* bYError */
     938           0 :             , pfScaledLogicX );
     939           0 :     }
     940             : }
     941             : 
     942        7092 : void VSeriesPlotter::createErrorBar_Y( const drawing::Position3D& rUnscaledLogicPosition
     943             :                             , VDataSeries& rVDataSeries, sal_Int32 nPointIndex
     944             :                             , const uno::Reference< drawing::XShapes >& xTarget
     945             :                             , double* pfScaledLogicX )
     946             : {
     947        7092 :     if(m_nDimension!=2)
     948        7176 :         return;
     949             :     // error bars
     950        7008 :     uno::Reference< beans::XPropertySet > xErrorBarProp(rVDataSeries.getYErrorBarProperties(nPointIndex));
     951        7008 :     if( xErrorBarProp.is())
     952             :     {
     953             :         uno::Reference< drawing::XShapes > xErrorBarsGroup_Shapes(
     954        2417 :             this->getErrorBarsGroupShape(rVDataSeries, xTarget, true) );
     955             : 
     956             :         createErrorBar( xErrorBarsGroup_Shapes
     957             :             , rUnscaledLogicPosition, xErrorBarProp
     958             :             , rVDataSeries, nPointIndex
     959             :             , true /* bYError */
     960        2417 :             , pfScaledLogicX );
     961        7008 :     }
     962             : }
     963             : 
     964        1927 : void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries& rVDataSeries,
     965             :                             const uno::Reference< drawing::XShapes >& xTarget,
     966             :                             const uno::Reference< drawing::XShapes >& xEquationTarget,
     967             :                             bool bMaySkipPoints )
     968             : {
     969        1927 :     if(m_nDimension!=2)
     970          66 :         return;
     971        1894 :     uno::Reference< XRegressionCurveContainer > xContainer( rVDataSeries.getModel(), uno::UNO_QUERY );
     972        1894 :     if(!xContainer.is())
     973           0 :         return;
     974             : 
     975        1894 :     if (!m_pPosHelper)
     976           0 :         return;
     977             : 
     978        3788 :     uno::Sequence< uno::Reference< XRegressionCurve > > aCurveList = xContainer->getRegressionCurves();
     979             : 
     980        1947 :     for(sal_Int32 nN=0; nN<aCurveList.getLength(); nN++)
     981             :     {
     982          53 :         uno::Reference< XRegressionCurveCalculator > xCalculator( aCurveList[nN]->getCalculator() );
     983          53 :         if( !xCalculator.is())
     984           0 :             continue;
     985             : 
     986         106 :         uno::Reference< beans::XPropertySet > xProperties( aCurveList[nN], uno::UNO_QUERY );
     987             : 
     988          53 :         bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurveList[nN] );
     989             : 
     990          53 :         sal_Int32 aDegree = 2;
     991          53 :         sal_Int32 aPeriod = 2;
     992          53 :         double aExtrapolateForward = 0.0;
     993          53 :         double aExtrapolateBackward = 0.0;
     994          53 :         sal_Bool aForceIntercept = false;
     995          53 :         double aInterceptValue = 0.0;
     996             : 
     997          53 :         if ( xProperties.is() && !bAverageLine )
     998             :         {
     999          21 :             xProperties->getPropertyValue( "PolynomialDegree") >>= aDegree;
    1000          21 :             xProperties->getPropertyValue( "MovingAveragePeriod") >>= aPeriod;
    1001          21 :             xProperties->getPropertyValue( "ExtrapolateForward") >>= aExtrapolateForward;
    1002          21 :             xProperties->getPropertyValue( "ExtrapolateBackward") >>= aExtrapolateBackward;
    1003          21 :             xProperties->getPropertyValue( "ForceIntercept") >>= aForceIntercept;
    1004          21 :             if (aForceIntercept)
    1005           7 :                 xProperties->getPropertyValue( "InterceptValue") >>= aInterceptValue;
    1006             :         }
    1007             : 
    1008          53 :         double fChartMinX = m_pPosHelper->getLogicMinX();
    1009          53 :         double fChartMaxX = m_pPosHelper->getLogicMaxX();
    1010             : 
    1011          53 :         double fMinX = fChartMinX;
    1012          53 :         double fMaxX = fChartMaxX;
    1013             : 
    1014          53 :         double fPointScale = 1.0;
    1015             : 
    1016          53 :         if( !bAverageLine )
    1017             :         {
    1018          21 :             rVDataSeries.getMinMaxXValue(fMinX, fMaxX);
    1019          21 :             fMaxX += aExtrapolateForward;
    1020          21 :             fMinX -= aExtrapolateBackward;
    1021             : 
    1022          21 :             fPointScale = (fMaxX - fMinX) / (fChartMaxX - fChartMinX);
    1023             :         }
    1024             : 
    1025          53 :         xCalculator->setRegressionProperties(aDegree, aForceIntercept, aInterceptValue, aPeriod);
    1026          53 :         xCalculator->recalculateRegression( rVDataSeries.getAllX(), rVDataSeries.getAllY() );
    1027          53 :         sal_Int32 nPointCount = 100 * fPointScale;
    1028             : 
    1029          53 :         if ( nPointCount < 2 )
    1030           0 :             nPointCount = 2;
    1031             : 
    1032         106 :         std::vector< ExplicitScaleData > aScales( m_pPosHelper->getScales());
    1033         106 :         uno::Reference< chart2::XScaling > xScalingX;
    1034         106 :         uno::Reference< chart2::XScaling > xScalingY;
    1035          53 :         if( aScales.size() >= 2 )
    1036             :         {
    1037          53 :             xScalingX.set( aScales[0].Scaling );
    1038          53 :             xScalingY.set( aScales[1].Scaling );
    1039             :         }
    1040             : 
    1041             :         uno::Sequence< geometry::RealPoint2D > aCalculatedPoints(
    1042          53 :             xCalculator->getCurveValues(
    1043             :                             fMinX, fMaxX, nPointCount,
    1044         106 :                             xScalingX, xScalingY, bMaySkipPoints ));
    1045             : 
    1046          53 :         nPointCount = aCalculatedPoints.getLength();
    1047             : 
    1048         106 :         drawing::PolyPolygonShape3D aRegressionPoly;
    1049          53 :         aRegressionPoly.SequenceX.realloc(1);
    1050          53 :         aRegressionPoly.SequenceY.realloc(1);
    1051          53 :         aRegressionPoly.SequenceZ.realloc(1);
    1052          53 :         aRegressionPoly.SequenceX[0].realloc(nPointCount);
    1053          53 :         aRegressionPoly.SequenceY[0].realloc(nPointCount);
    1054          53 :         aRegressionPoly.SequenceZ[0].realloc(nPointCount);
    1055             : 
    1056          53 :         sal_Int32 nRealPointCount = 0;
    1057             : 
    1058         691 :         for(sal_Int32 nP = 0; nP < aCalculatedPoints.getLength(); ++nP)
    1059             :         {
    1060         638 :             double fLogicX = aCalculatedPoints[nP].X;
    1061         638 :             double fLogicY = aCalculatedPoints[nP].Y;
    1062         638 :             double fLogicZ = 0.0; //dummy
    1063             : 
    1064             :             // fdo#51656: don't scale mean value lines
    1065         638 :             if(!bAverageLine)
    1066         574 :                 m_pPosHelper->doLogicScaling( &fLogicX, &fLogicY, &fLogicZ );
    1067             : 
    1068        2552 :             if(!rtl::math::isNan(fLogicX) && !rtl::math::isInf(fLogicX) &&
    1069        1914 :                !rtl::math::isNan(fLogicY) && !rtl::math::isInf(fLogicY) &&
    1070        1914 :                !rtl::math::isNan(fLogicZ) && !rtl::math::isInf(fLogicZ) )
    1071             :             {
    1072         638 :                 aRegressionPoly.SequenceX[0][nRealPointCount] = fLogicX;
    1073         638 :                 aRegressionPoly.SequenceY[0][nRealPointCount] = fLogicY;
    1074         638 :                 nRealPointCount++;
    1075             :             }
    1076             :         }
    1077          53 :         aRegressionPoly.SequenceX[0].realloc(nRealPointCount);
    1078          53 :         aRegressionPoly.SequenceY[0].realloc(nRealPointCount);
    1079          53 :         aRegressionPoly.SequenceZ[0].realloc(nRealPointCount);
    1080             : 
    1081         106 :         drawing::PolyPolygonShape3D aClippedPoly;
    1082          53 :         Clipping::clipPolygonAtRectangle( aRegressionPoly, m_pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly );
    1083          53 :         aRegressionPoly = aClippedPoly;
    1084          53 :         m_pPosHelper->transformScaledLogicToScene( aRegressionPoly );
    1085             : 
    1086          53 :         awt::Point aDefaultPos;
    1087          53 :         if( aRegressionPoly.SequenceX.getLength() && aRegressionPoly.SequenceX[0].getLength() )
    1088             :         {
    1089          50 :             VLineProperties aVLineProperties;
    1090          50 :             aVLineProperties.initFromPropertySet( xProperties );
    1091             : 
    1092             :             //create an extra group shape for each curve for selection handling
    1093             :             uno::Reference< drawing::XShapes > xRegressionGroupShapes =
    1094         100 :                 createGroupShape( xTarget, rVDataSeries.getDataCurveCID( nN, bAverageLine ) );
    1095             :             uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D(
    1096         100 :                 xRegressionGroupShapes, PolyToPointSequence( aRegressionPoly ), &aVLineProperties );
    1097          50 :             AbstractShapeFactory::setShapeName( xShape, "MarkHandles" );
    1098         100 :             aDefaultPos = xShape->getPosition();
    1099             :         }
    1100             : 
    1101             :         // curve equation and correlation coefficient
    1102         106 :         uno::Reference< beans::XPropertySet > xEquationProperties( aCurveList[nN]->getEquationProperties());
    1103          53 :         if( xEquationProperties.is())
    1104             :         {
    1105             :             createRegressionCurveEquationShapes(
    1106             :                 rVDataSeries.getDataCurveEquationCID( nN ),
    1107             :                 xEquationProperties, xEquationTarget, xCalculator,
    1108          53 :                 aDefaultPos );
    1109             :         }
    1110        1947 :     }
    1111             : }
    1112             : 
    1113          53 : void VSeriesPlotter::createRegressionCurveEquationShapes(
    1114             :     const OUString & rEquationCID,
    1115             :     const uno::Reference< beans::XPropertySet > & xEquationProperties,
    1116             :     const uno::Reference< drawing::XShapes >& xEquationTarget,
    1117             :     const uno::Reference< chart2::XRegressionCurveCalculator > & xRegressionCurveCalculator,
    1118             :     awt::Point aDefaultPos )
    1119             : {
    1120             :     OSL_ASSERT( xEquationProperties.is());
    1121          53 :     if( !xEquationProperties.is())
    1122          39 :         return;
    1123             : 
    1124          53 :     bool bShowEquation = false;
    1125          53 :     bool bShowCorrCoeff = false;
    1126          53 :     OUString aSep( "\n" );
    1127         212 :     if(( xEquationProperties->getPropertyValue( "ShowEquation") >>= bShowEquation ) &&
    1128         159 :        ( xEquationProperties->getPropertyValue( "ShowCorrelationCoefficient") >>= bShowCorrCoeff ))
    1129             :     {
    1130          53 :         if( ! (bShowEquation || bShowCorrCoeff))
    1131          39 :             return;
    1132             : 
    1133          14 :         OUStringBuffer aFormula;
    1134          14 :         sal_Int32 nNumberFormatKey = 0;
    1135          14 :         xEquationProperties->getPropertyValue( "NumberFormat") >>= nNumberFormatKey;
    1136             : 
    1137          14 :         if( bShowEquation )
    1138             :         {
    1139          14 :             if( m_apNumberFormatterWrapper.get())
    1140             :             {
    1141          42 :                 aFormula = xRegressionCurveCalculator->getFormattedRepresentation(
    1142             :                     m_apNumberFormatterWrapper->getNumberFormatsSupplier(),
    1143          28 :                     nNumberFormatKey );
    1144             :             }
    1145             :             else
    1146             :             {
    1147           0 :                 aFormula = xRegressionCurveCalculator->getRepresentation();
    1148             :             }
    1149             : 
    1150          14 :             if( bShowCorrCoeff )
    1151             :             {
    1152           7 :                 aFormula.append( aSep );
    1153             :             }
    1154             :         }
    1155          14 :         if( bShowCorrCoeff )
    1156             :         {
    1157           7 :             aFormula.append( "R" );
    1158           7 :             aFormula.append( sal_Unicode( 0x00b2 ));
    1159           7 :             aFormula.append( " = ");
    1160           7 :             double fR( xRegressionCurveCalculator->getCorrelationCoefficient());
    1161           7 :             if( m_apNumberFormatterWrapper.get())
    1162             :             {
    1163           7 :                 sal_Int32 nLabelCol = 0;
    1164             :                 bool bColChanged;
    1165             :                 aFormula.append(
    1166             :                     m_apNumberFormatterWrapper->getFormattedString(
    1167           7 :                         nNumberFormatKey, fR*fR, nLabelCol, bColChanged ));
    1168             :                 //@todo: change color of label if bColChanged is true
    1169             :             }
    1170             :             else
    1171             :             {
    1172           0 :                 sal_Unicode aDecimalSep( '.' );//@todo get this locale dependent
    1173             :                 aFormula.append( ::rtl::math::doubleToUString(
    1174           0 :                                      fR*fR, rtl_math_StringFormat_G, 4, aDecimalSep, true ));
    1175             :             }
    1176             :         }
    1177             : 
    1178          14 :         awt::Point aScreenPosition2D;
    1179          14 :         chart2::RelativePosition aRelativePosition;
    1180          14 :         if( xEquationProperties->getPropertyValue( "RelativePosition") >>= aRelativePosition )
    1181             :         {
    1182             :             //@todo decide whether x is primary or secondary
    1183          12 :             double fX = aRelativePosition.Primary*m_aPageReferenceSize.Width;
    1184          12 :             double fY = aRelativePosition.Secondary*m_aPageReferenceSize.Height;
    1185          12 :             aScreenPosition2D.X = static_cast< sal_Int32 >( ::rtl::math::round( fX ));
    1186          12 :             aScreenPosition2D.Y = static_cast< sal_Int32 >( ::rtl::math::round( fY ));
    1187             :         }
    1188             :         else
    1189           2 :             aScreenPosition2D = aDefaultPos;
    1190             : 
    1191          14 :         if( !aFormula.isEmpty())
    1192             :         {
    1193             :             // set fill and line properties on creation
    1194          14 :             tNameSequence aNames;
    1195          28 :             tAnySequence  aValues;
    1196          14 :             PropertyMapper::getPreparedTextShapePropertyLists( xEquationProperties, aNames, aValues );
    1197             : 
    1198             :             uno::Reference< drawing::XShape > xTextShape = m_pShapeFactory->createText(
    1199             :                 xEquationTarget, aFormula.makeStringAndClear(),
    1200          28 :                 aNames, aValues, AbstractShapeFactory::makeTransformation( aScreenPosition2D ));
    1201             : 
    1202             :             OSL_ASSERT( xTextShape.is());
    1203          14 :             if( xTextShape.is())
    1204             :             {
    1205          14 :                 AbstractShapeFactory::setShapeName( xTextShape, rEquationCID );
    1206          14 :                 awt::Size aSize( xTextShape->getSize() );
    1207             :                 awt::Point aPos( RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
    1208          14 :                     aScreenPosition2D, aSize, aRelativePosition.Anchor ) );
    1209             :                 //ensure that the equation is fully placed within the page (if possible)
    1210          14 :                 if( (aPos.X + aSize.Width) > m_aPageReferenceSize.Width )
    1211           0 :                     aPos.X = m_aPageReferenceSize.Width - aSize.Width;
    1212          14 :                 if( aPos.X < 0 )
    1213           0 :                     aPos.X = 0;
    1214          14 :                 if( (aPos.Y + aSize.Height) > m_aPageReferenceSize.Height )
    1215           0 :                     aPos.Y = m_aPageReferenceSize.Height - aSize.Height;
    1216          14 :                 if( aPos.Y < 0 )
    1217           0 :                     aPos.Y = 0;
    1218          14 :                 xTextShape->setPosition(aPos);
    1219          14 :             }
    1220          14 :         }
    1221          14 :     }
    1222             : }
    1223             : 
    1224        7360 : void VSeriesPlotter::setMappedProperties(
    1225             :           const uno::Reference< drawing::XShape >& xTargetShape
    1226             :         , const uno::Reference< beans::XPropertySet >& xSource
    1227             :         , const tPropertyNameMap& rMap
    1228             :         , tPropertyNameValueMap* pOverwriteMap )
    1229             : {
    1230        7360 :     uno::Reference< beans::XPropertySet > xTargetProp( xTargetShape, uno::UNO_QUERY );
    1231        7360 :     PropertyMapper::setMappedProperties(xTargetProp,xSource,rMap,pOverwriteMap);
    1232        7360 : }
    1233             : 
    1234           0 : void VSeriesPlotter::setTimeResolutionOnXAxis( long TimeResolution, const Date& rNullDate )
    1235             : {
    1236           0 :     m_nTimeResolution = TimeResolution;
    1237           0 :     m_aNullDate = rNullDate;
    1238           0 : }
    1239             : 
    1240             : // MinimumAndMaximumSupplier
    1241           0 : long VSeriesPlotter::calculateTimeResolutionOnXAxis()
    1242             : {
    1243           0 :     long nRet = ::com::sun::star::chart::TimeUnit::YEAR;
    1244           0 :     if( m_pExplicitCategoriesProvider )
    1245             :     {
    1246           0 :         const std::vector< DatePlusIndex >&  rDateCategories = m_pExplicitCategoriesProvider->getDateCategories();
    1247           0 :         std::vector< DatePlusIndex >::const_iterator aIt = rDateCategories.begin(), aEnd = rDateCategories.end();
    1248           0 :         Date aNullDate(30,12,1899);
    1249           0 :         if( m_apNumberFormatterWrapper.get() )
    1250           0 :             aNullDate = m_apNumberFormatterWrapper->getNullDate();
    1251           0 :         if( aIt!=aEnd )
    1252             :         {
    1253           0 :             Date aPrevious(aNullDate); aPrevious+=static_cast<long>(rtl::math::approxFloor(aIt->fValue));
    1254           0 :             ++aIt;
    1255           0 :             for(;aIt!=aEnd;++aIt)
    1256             :             {
    1257           0 :                 Date aCurrent(aNullDate); aCurrent+=static_cast<long>(rtl::math::approxFloor(aIt->fValue));
    1258           0 :                 if( ::com::sun::star::chart::TimeUnit::YEAR == nRet )
    1259             :                 {
    1260           0 :                     if( DateHelper::IsInSameYear( aPrevious, aCurrent ) )
    1261           0 :                         nRet = ::com::sun::star::chart::TimeUnit::MONTH;
    1262             :                 }
    1263           0 :                 if( ::com::sun::star::chart::TimeUnit::MONTH == nRet )
    1264             :                 {
    1265           0 :                     if( DateHelper::IsInSameMonth( aPrevious, aCurrent ) )
    1266           0 :                         nRet = ::com::sun::star::chart::TimeUnit::DAY;
    1267             :                 }
    1268           0 :                 if( ::com::sun::star::chart::TimeUnit::DAY == nRet )
    1269           0 :                     break;
    1270           0 :                 aPrevious=aCurrent;
    1271             :             }
    1272             :         }
    1273             :     }
    1274           0 :     return nRet;
    1275             : }
    1276        1222 : double VSeriesPlotter::getMinimumX()
    1277             : {
    1278             :     double fMinimum, fMaximum;
    1279        1222 :     this->getMinimumAndMaximiumX( fMinimum, fMaximum );
    1280        1222 :     return fMinimum;
    1281             : }
    1282        1222 : double VSeriesPlotter::getMaximumX()
    1283             : {
    1284             :     double fMinimum, fMaximum;
    1285        1222 :     this->getMinimumAndMaximiumX( fMinimum, fMaximum );
    1286        1222 :     return fMaximum;
    1287             : }
    1288             : 
    1289        1224 : double VSeriesPlotter::getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex )
    1290             : {
    1291        1224 :     if( !m_bCategoryXAxis || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) )
    1292             :     {
    1293             :         double fMinY, fMaxY;
    1294          36 :         this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
    1295          36 :         return fMinY;
    1296             :     }
    1297             : 
    1298             :     double fMinimum, fMaximum;
    1299        1188 :     ::rtl::math::setInf(&fMinimum, false);
    1300        1188 :     ::rtl::math::setInf(&fMaximum, true);
    1301        2404 :     for(size_t nZ =0; nZ<m_aZSlots.size();nZ++ )
    1302             :     {
    1303        1216 :         ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[nZ];
    1304        5054 :         for(size_t nN =0; nN<rXSlots.size();nN++ )
    1305             :         {
    1306             :             double fLocalMinimum, fLocalMaximum;
    1307        3838 :             rXSlots[nN].calculateYMinAndMaxForCategoryRange(
    1308        3838 :                                 static_cast<sal_Int32>(fMinimumX-1.0) //first category (index 0) matches with real number 1.0
    1309        3838 :                                 , static_cast<sal_Int32>(fMaximumX-1.0) //first category (index 0) matches with real number 1.0
    1310        3838 :                                 , isSeparateStackingForDifferentSigns( 1 )
    1311       15352 :                                 , fLocalMinimum, fLocalMaximum, nAxisIndex );
    1312        3838 :             if(fMaximum<fLocalMaximum)
    1313        2396 :                 fMaximum=fLocalMaximum;
    1314        3838 :             if(fMinimum>fLocalMinimum)
    1315        2372 :                 fMinimum=fLocalMinimum;
    1316             :         }
    1317             :     }
    1318        1188 :     if(::rtl::math::isInf(fMinimum))
    1319          12 :         ::rtl::math::setNan(&fMinimum);
    1320        1188 :     return fMinimum;
    1321             : }
    1322             : 
    1323        1224 : double VSeriesPlotter::getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex )
    1324             : {
    1325        1224 :     if( !m_bCategoryXAxis || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) )
    1326             :     {
    1327             :         double fMinY, fMaxY;
    1328          36 :         this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
    1329          36 :         return fMaxY;
    1330             :     }
    1331             : 
    1332             :     double fMinimum, fMaximum;
    1333        1188 :     ::rtl::math::setInf(&fMinimum, false);
    1334        1188 :     ::rtl::math::setInf(&fMaximum, true);
    1335        2404 :     for(size_t nZ =0; nZ<m_aZSlots.size();nZ++ )
    1336             :     {
    1337        1216 :         ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[nZ];
    1338        5054 :         for(size_t nN =0; nN<rXSlots.size();nN++ )
    1339             :         {
    1340             :             double fLocalMinimum, fLocalMaximum;
    1341        3838 :             rXSlots[nN].calculateYMinAndMaxForCategoryRange(
    1342        3838 :                                 static_cast<sal_Int32>(fMinimumX-1.0) //first category (index 0) matches with real number 1.0
    1343        3838 :                                 , static_cast<sal_Int32>(fMaximumX-1.0) //first category (index 0) matches with real number 1.0
    1344        3838 :                                 , isSeparateStackingForDifferentSigns( 1 )
    1345       15352 :                                 , fLocalMinimum, fLocalMaximum, nAxisIndex );
    1346        3838 :             if(fMaximum<fLocalMaximum)
    1347        2396 :                 fMaximum=fLocalMaximum;
    1348        3838 :             if(fMinimum>fLocalMinimum)
    1349        2372 :                 fMinimum=fLocalMinimum;
    1350             :         }
    1351             :     }
    1352        1188 :     if(::rtl::math::isInf(fMaximum))
    1353          12 :         ::rtl::math::setNan(&fMaximum);
    1354        1188 :     return fMaximum;
    1355             : }
    1356             : 
    1357          23 : double VSeriesPlotter::getMinimumZ()
    1358             : {
    1359             :     //this is the default for all charts without a meaningfull z axis
    1360          23 :     return 1.0;
    1361             : }
    1362          23 : double VSeriesPlotter::getMaximumZ()
    1363             : {
    1364          23 :     if( 3!=m_nDimension || !m_aZSlots.size() )
    1365           0 :         return getMinimumZ()+1;
    1366          23 :     return m_aZSlots.size();
    1367             : }
    1368             : 
    1369             : namespace
    1370             : {
    1371        4840 :     bool lcl_isValueAxis( sal_Int32 nDimensionIndex, bool bCategoryXAxis )
    1372             :     {
    1373             :         // default implementation: true for Y axes, and for value X axis
    1374        4840 :         if( nDimensionIndex == 0 )
    1375        2400 :             return !bCategoryXAxis;
    1376        2440 :         if( nDimensionIndex == 1 )
    1377        2418 :             return true;
    1378          22 :         return false;
    1379             :     }
    1380             : }
    1381             : 
    1382        2460 : bool VSeriesPlotter::isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex )
    1383             : {
    1384        2460 :     return lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis );
    1385             : }
    1386             : 
    1387        2460 : bool VSeriesPlotter::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex )
    1388             : {
    1389             :     // do not expand axes in 3D charts
    1390        2460 :     return (m_nDimension < 3) && lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis );
    1391             : }
    1392             : 
    1393        2460 : bool VSeriesPlotter::isExpandWideValuesToZero( sal_Int32 nDimensionIndex )
    1394             : {
    1395             :     // default implementation: only for Y axis
    1396        2460 :     return nDimensionIndex == 1;
    1397             : }
    1398             : 
    1399        2460 : bool VSeriesPlotter::isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex )
    1400             : {
    1401             :     // default implementation: only for Y axis
    1402        2460 :     return nDimensionIndex == 1;
    1403             : }
    1404             : 
    1405       20832 : bool VSeriesPlotter::isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex )
    1406             : {
    1407             :     // default implementation: only for Y axis
    1408       20832 :     return nDimensionIndex == 1;
    1409             : }
    1410             : 
    1411        2444 : void VSeriesPlotter::getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const
    1412             : {
    1413        2444 :     ::rtl::math::setInf(&rfMinimum, false);
    1414        2444 :     ::rtl::math::setInf(&rfMaximum, true);
    1415             : 
    1416        2444 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator       aZSlotIter = m_aZSlots.begin();
    1417        2444 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
    1418        4936 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1419             :     {
    1420        2492 :         ::std::vector< VDataSeriesGroup >::const_iterator      aXSlotIter = aZSlotIter->begin();
    1421        2492 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    1422       10228 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
    1423             :         {
    1424             :             double fLocalMinimum, fLocalMaximum;
    1425        7736 :             aXSlotIter->getMinimumAndMaximiumX( fLocalMinimum, fLocalMaximum );
    1426        7736 :             if( !::rtl::math::isNan(fLocalMinimum) && fLocalMinimum< rfMinimum )
    1427        2444 :                 rfMinimum = fLocalMinimum;
    1428        7736 :             if( !::rtl::math::isNan(fLocalMaximum) && fLocalMaximum> rfMaximum )
    1429        2444 :                 rfMaximum = fLocalMaximum;
    1430             :         }
    1431             :     }
    1432        2444 :     if(::rtl::math::isInf(rfMinimum))
    1433           0 :         ::rtl::math::setNan(&rfMinimum);
    1434        2444 :     if(::rtl::math::isInf(rfMaximum))
    1435           0 :         ::rtl::math::setNan(&rfMaximum);
    1436        2444 : }
    1437             : 
    1438          72 : void VSeriesPlotter::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const
    1439             : {
    1440          72 :     ::rtl::math::setInf(&rfMinY, false);
    1441          72 :     ::rtl::math::setInf(&rfMaxY, true);
    1442             : 
    1443          72 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator       aZSlotIter = m_aZSlots.begin();
    1444          72 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
    1445         144 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1446             :     {
    1447          72 :         ::std::vector< VDataSeriesGroup >::const_iterator      aXSlotIter = aZSlotIter->begin();
    1448          72 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    1449         144 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
    1450             :         {
    1451             :             double fLocalMinimum, fLocalMaximum;
    1452          72 :             aXSlotIter->getMinimumAndMaximiumYInContinuousXRange( fLocalMinimum, fLocalMaximum, fMinX, fMaxX, nAxisIndex );
    1453          72 :             if( !::rtl::math::isNan(fLocalMinimum) && fLocalMinimum< rfMinY )
    1454          72 :                 rfMinY = fLocalMinimum;
    1455          72 :             if( !::rtl::math::isNan(fLocalMaximum) && fLocalMaximum> rfMaxY )
    1456          72 :                 rfMaxY = fLocalMaximum;
    1457             :         }
    1458             :     }
    1459          72 :     if(::rtl::math::isInf(rfMinY))
    1460           0 :         ::rtl::math::setNan(&rfMinY);
    1461          72 :     if(::rtl::math::isInf(rfMaxY))
    1462           0 :         ::rtl::math::setNan(&rfMaxY);
    1463          72 : }
    1464             : 
    1465         604 : sal_Int32 VSeriesPlotter::getPointCount() const
    1466             : {
    1467         604 :     sal_Int32 nRet = 0;
    1468             : 
    1469         604 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator       aZSlotIter = m_aZSlots.begin();
    1470         604 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
    1471             : 
    1472        1232 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1473             :     {
    1474         628 :         ::std::vector< VDataSeriesGroup >::const_iterator       aXSlotIter = aZSlotIter->begin();
    1475         628 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    1476             : 
    1477        2567 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
    1478             :         {
    1479        1939 :             sal_Int32 nPointCount = aXSlotIter->getPointCount();
    1480        1939 :             if( nPointCount>nRet )
    1481         604 :                 nRet = nPointCount;
    1482             :         }
    1483             :     }
    1484         604 :     return nRet;
    1485             : }
    1486             : 
    1487         620 : void VSeriesPlotter::setNumberFormatsSupplier(
    1488             :     const uno::Reference< util::XNumberFormatsSupplier > & xNumFmtSupplier )
    1489             : {
    1490         620 :     m_apNumberFormatterWrapper.reset( new NumberFormatterWrapper( xNumFmtSupplier ));
    1491         620 : }
    1492             : 
    1493         620 : void VSeriesPlotter::setColorScheme( const uno::Reference< XColorScheme >& xColorScheme )
    1494             : {
    1495         620 :     m_xColorScheme = xColorScheme;
    1496         620 : }
    1497             : 
    1498         620 : void VSeriesPlotter::setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider )
    1499             : {
    1500         620 :     m_pExplicitCategoriesProvider = pExplicitCategoriesProvider;
    1501         620 : }
    1502             : 
    1503       54879 : sal_Int32 VDataSeriesGroup::getPointCount() const
    1504             : {
    1505       54879 :     if(!m_bMaxPointCountDirty)
    1506       52940 :         return m_nMaxPointCount;
    1507             : 
    1508        1939 :     sal_Int32 nRet = 0;
    1509        1939 :     ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = m_aSeriesVector.begin();
    1510        1939 :     const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
    1511             : 
    1512        3877 :     for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter)
    1513             :     {
    1514        1938 :         sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount();
    1515        1938 :         if( nPointCount>nRet )
    1516        1921 :             nRet = nPointCount;
    1517             :     }
    1518        1939 :     m_nMaxPointCount=nRet;
    1519        1939 :     m_aListOfCachedYValues.clear();
    1520        1939 :     m_aListOfCachedYValues.resize(m_nMaxPointCount);
    1521        1939 :     m_bMaxPointCountDirty=false;
    1522        1939 :     return nRet;
    1523             : }
    1524             : 
    1525       13763 : sal_Int32 VDataSeriesGroup::getAttachedAxisIndexForFirstSeries() const
    1526             : {
    1527       13763 :     sal_Int32 nRet = 0;
    1528       13763 :     ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = m_aSeriesVector.begin();
    1529       13763 :     const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
    1530             : 
    1531       13763 :     if( aSeriesIter != aSeriesEnd )
    1532       13763 :         nRet = (*aSeriesIter)->getAttachedAxisIndex();
    1533             : 
    1534       13763 :     return nRet;
    1535             : }
    1536             : 
    1537        7736 : void VDataSeriesGroup::getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const
    1538             : {
    1539        7736 :     const ::std::vector< VDataSeries* >* pSeriesList = &this->m_aSeriesVector;
    1540             : 
    1541        7736 :     ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = pSeriesList->begin();
    1542        7736 :     const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
    1543             : 
    1544        7736 :     ::rtl::math::setInf(&rfMinimum, false);
    1545        7736 :     ::rtl::math::setInf(&rfMaximum, true);
    1546             : 
    1547       15540 :     for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
    1548             :     {
    1549        7804 :         sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount();
    1550       40652 :         for(sal_Int32 nN=0;nN<nPointCount;nN++)
    1551             :         {
    1552       32848 :             double fX = (*aSeriesIter)->getXValue( nN );
    1553       32848 :             if( ::rtl::math::isNan(fX) )
    1554           0 :                 continue;
    1555       32848 :             if(rfMaximum<fX)
    1556       32252 :                 rfMaximum=fX;
    1557       32848 :             if(rfMinimum>fX)
    1558        7736 :                 rfMinimum=fX;
    1559             :         }
    1560             :     }
    1561        7736 :     if(::rtl::math::isInf(rfMinimum))
    1562           0 :         ::rtl::math::setNan(&rfMinimum);
    1563        7736 :     if(::rtl::math::isInf(rfMaximum))
    1564           0 :         ::rtl::math::setNan(&rfMaximum);
    1565        7736 : }
    1566             : 
    1567             : namespace {
    1568             : 
    1569             : /**
    1570             :  * Keep track of minimum and maximum Y values for one or more data series.
    1571             :  * When multiple data series exist, that indicates that the data series are
    1572             :  * stacked.
    1573             :  *
    1574             :  * <p>For each X value, we calculate separate Y value ranges for each data
    1575             :  * series in the first pass.  In the second pass, we calculate the minimum Y
    1576             :  * value by taking the absolute minimum value of all data series, whereas
    1577             :  * the maxium Y value is the sum of all the series maximum Y values.</p>
    1578             :  *
    1579             :  * <p>Once that's done for all X values, the final min / max Y values get
    1580             :  * calculated by taking the absolute min / max Y values across all the X
    1581             :  * values.</p>
    1582             :  */
    1583          72 : class PerXMinMaxCalculator
    1584             : {
    1585             :     typedef std::pair<double, double> MinMaxType;
    1586             :     typedef std::map<size_t, MinMaxType> SeriesMinMaxType;
    1587             :     typedef boost::ptr_map<double, SeriesMinMaxType> GroupMinMaxType;
    1588             :     typedef boost::unordered_map<double, MinMaxType> TotalStoreType;
    1589             :     GroupMinMaxType maSeriesGroup;
    1590             :     size_t mnCurSeries;
    1591             : 
    1592             : public:
    1593          72 :     PerXMinMaxCalculator() : mnCurSeries(0) {}
    1594             : 
    1595          72 :     void nextSeries() { ++mnCurSeries; }
    1596             : 
    1597         356 :     void setValue(double fX, double fY)
    1598             :     {
    1599         356 :         SeriesMinMaxType* pStore = getByXValue(fX); // get storage for given X value.
    1600         356 :         if (!pStore)
    1601             :             // This shouldn't happen!
    1602         356 :             return;
    1603             : 
    1604         356 :         SeriesMinMaxType::iterator it = pStore->lower_bound(mnCurSeries);
    1605         356 :         if (it != pStore->end() && !pStore->key_comp()(mnCurSeries, it->first))
    1606             :         {
    1607           0 :             MinMaxType& r = it->second;
    1608             :             // A min-max pair already exists for this series.  Update it.
    1609           0 :             if (fY < r.first)
    1610           0 :                 r.first = fY;
    1611           0 :             if (r.second < fY)
    1612           0 :                 r.second = fY;
    1613             :         }
    1614             :         else
    1615             :         {
    1616             :             // No existing pair. Insert a new one.
    1617             :             pStore->insert(
    1618             :                 it, SeriesMinMaxType::value_type(
    1619         356 :                     mnCurSeries, MinMaxType(fY,fY)));
    1620             :         }
    1621             :     }
    1622             : 
    1623          72 :     void getTotalRange(double& rfMin, double& rfMax) const
    1624             :     {
    1625          72 :         rtl::math::setNan(&rfMin);
    1626          72 :         rtl::math::setNan(&rfMax);
    1627             : 
    1628          72 :         TotalStoreType aStore;
    1629          72 :         getTotalStore(aStore);
    1630             : 
    1631          72 :         if (aStore.empty())
    1632          72 :             return;
    1633             : 
    1634          72 :         TotalStoreType::const_iterator it = aStore.begin(), itEnd = aStore.end();
    1635          72 :         rfMin = it->second.first;
    1636          72 :         rfMax = it->second.second;
    1637         356 :         for (++it; it != itEnd; ++it)
    1638             :         {
    1639         284 :             if (rfMin > it->second.first)
    1640          92 :                 rfMin = it->second.first;
    1641         284 :             if (rfMax < it->second.second)
    1642          32 :                 rfMax = it->second.second;
    1643          72 :         }
    1644             :     }
    1645             : 
    1646             : private:
    1647             :     /**
    1648             :      * Parse all data and reduce them into a set of global Y value ranges per
    1649             :      * X value.
    1650             :      */
    1651          72 :     void getTotalStore(TotalStoreType& rStore) const
    1652             :     {
    1653          72 :         TotalStoreType aStore;
    1654          72 :         GroupMinMaxType::const_iterator it = maSeriesGroup.begin(), itEnd = maSeriesGroup.end();
    1655         428 :         for (; it != itEnd; ++it)
    1656             :         {
    1657         356 :             double fX = it->first;
    1658             : 
    1659         356 :             const SeriesMinMaxType& rSeries = *it->second;
    1660         356 :             SeriesMinMaxType::const_iterator itSeries = rSeries.begin(), itSeriesEnd = rSeries.end();
    1661         712 :             for (; itSeries != itSeriesEnd; ++itSeries)
    1662             :             {
    1663         356 :                 double fYMin = itSeries->second.first, fYMax = itSeries->second.second;
    1664         356 :                 TotalStoreType::iterator itr = aStore.find(fX);
    1665         356 :                 if (itr == aStore.end())
    1666             :                     // New min-max pair for give X value.
    1667             :                     aStore.insert(
    1668         356 :                         TotalStoreType::value_type(fX, std::pair<double,double>(fYMin,fYMax)));
    1669             :                 else
    1670             :                 {
    1671           0 :                     MinMaxType& r = itr->second;
    1672           0 :                     if (fYMin < r.first)
    1673           0 :                         r.first = fYMin; // min y-value
    1674             : 
    1675           0 :                     r.second += fYMax; // accumulative max y-value.
    1676             :                 }
    1677             :             }
    1678             :         }
    1679          72 :         rStore.swap(aStore);
    1680          72 :     }
    1681             : 
    1682         356 :     SeriesMinMaxType* getByXValue(double fX)
    1683             :     {
    1684         356 :         GroupMinMaxType::iterator it = maSeriesGroup.find(fX);
    1685         356 :         if (it == maSeriesGroup.end())
    1686             :         {
    1687             :             std::pair<GroupMinMaxType::iterator,bool> r =
    1688         356 :                 maSeriesGroup.insert(fX, new SeriesMinMaxType);
    1689             : 
    1690         356 :             if (!r.second)
    1691             :                 // insertion failed.
    1692           0 :                 return NULL;
    1693             : 
    1694         356 :             it = r.first;
    1695             :         }
    1696             : 
    1697         356 :         return it->second;
    1698             :     }
    1699             : };
    1700             : 
    1701             : }
    1702             : 
    1703          72 : void VDataSeriesGroup::getMinimumAndMaximiumYInContinuousXRange(
    1704             :     double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const
    1705             : {
    1706          72 :     ::rtl::math::setNan(&rfMinY);
    1707          72 :     ::rtl::math::setNan(&rfMaxY);
    1708             : 
    1709          72 :     if (m_aSeriesVector.empty())
    1710             :         // No data series.  Bail out.
    1711          72 :         return;
    1712             : 
    1713          72 :     PerXMinMaxCalculator aRangeCalc;
    1714          72 :     std::vector<VDataSeries*>::const_iterator it = m_aSeriesVector.begin(), itEnd = m_aSeriesVector.end();
    1715         144 :     for (; it != itEnd; ++it)
    1716             :     {
    1717          72 :         const VDataSeries* pSeries = *it;
    1718          72 :         if (!pSeries)
    1719           0 :             continue;
    1720             : 
    1721         428 :         for (sal_Int32 i = 0, n = pSeries->getTotalPointCount(); i < n; ++i)
    1722             :         {
    1723         356 :             if (nAxisIndex != pSeries->getAttachedAxisIndex())
    1724           0 :                 continue;
    1725             : 
    1726         356 :             double fX = pSeries->getXValue(i);
    1727         356 :             if (rtl::math::isNan(fX))
    1728           0 :                 continue;
    1729             : 
    1730         356 :             if (fX < fMinX || fX > fMaxX)
    1731             :                 // Outside specified X range.  Skip it.
    1732           0 :                 continue;
    1733             : 
    1734         356 :             double fY = pSeries->getYValue(i);
    1735         356 :             if (::rtl::math::isNan(fY))
    1736           0 :                 continue;
    1737             : 
    1738         356 :             aRangeCalc.setValue(fX, fY);
    1739             :         }
    1740          72 :         aRangeCalc.nextSeries();
    1741             :     }
    1742             : 
    1743          72 :     aRangeCalc.getTotalRange(rfMinY, rfMaxY);
    1744             : }
    1745             : 
    1746       52940 : void VDataSeriesGroup::calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
    1747             :         , bool bSeparateStackingForDifferentSigns
    1748             :         , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex )
    1749             : {
    1750       52940 :     ::rtl::math::setInf(&rfMinimumY, false);
    1751       52940 :     ::rtl::math::setInf(&rfMaximumY, true);
    1752             : 
    1753       52940 :     sal_Int32 nPointCount = getPointCount();//necessary to create m_aListOfCachedYValues
    1754       52940 :     if(nCategoryIndex<0 || nCategoryIndex>=nPointCount || m_aSeriesVector.empty())
    1755       52141 :         return;
    1756             : 
    1757       45804 :     CachedYValues aCachedYValues = m_aListOfCachedYValues[nCategoryIndex][nAxisIndex];
    1758       45804 :     if( !aCachedYValues.m_bValuesDirty )
    1759             :     {
    1760             :         //return cached values
    1761       37869 :         rfMinimumY = aCachedYValues.m_fMinimumY;
    1762       37869 :         rfMaximumY = aCachedYValues.m_fMaximumY;
    1763       37869 :         return;
    1764             :     }
    1765             : 
    1766             :     double fTotalSum, fPositiveSum, fNegativeSum, fFirstPositiveY, fFirstNegativeY;
    1767        7935 :     ::rtl::math::setNan( &fTotalSum );
    1768        7935 :     ::rtl::math::setNan( &fPositiveSum );
    1769        7935 :     ::rtl::math::setNan( &fNegativeSum );
    1770        7935 :     ::rtl::math::setNan( &fFirstPositiveY );
    1771        7935 :     ::rtl::math::setNan( &fFirstNegativeY );
    1772             : 
    1773        7935 :     ::std::vector< VDataSeries* >::const_iterator aSeriesIter = m_aSeriesVector.begin();
    1774        7935 :     ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = m_aSeriesVector.end();
    1775             : 
    1776        7935 :     if( bSeparateStackingForDifferentSigns )
    1777             :     {
    1778       13820 :         for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
    1779             :         {
    1780        6926 :             if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
    1781          18 :                 continue;
    1782             : 
    1783        6908 :             double fValueMinY = (*aSeriesIter)->getMinimumofAllDifferentYValues( nCategoryIndex );
    1784        6908 :             double fValueMaxY = (*aSeriesIter)->getMaximumofAllDifferentYValues( nCategoryIndex );
    1785             : 
    1786        6908 :             if( fValueMaxY >= 0 )
    1787             :             {
    1788        6746 :                 if( ::rtl::math::isNan( fPositiveSum ) )
    1789        6714 :                     fPositiveSum = fFirstPositiveY = fValueMaxY;
    1790             :                 else
    1791          32 :                     fPositiveSum += fValueMaxY;
    1792             :             }
    1793        6908 :             if( fValueMinY < 0 )
    1794             :             {
    1795         146 :                 if(::rtl::math::isNan( fNegativeSum ))
    1796         146 :                     fNegativeSum = fFirstNegativeY = fValueMinY;
    1797             :                 else
    1798           0 :                     fNegativeSum += fValueMinY;
    1799             :             }
    1800             :         }
    1801        6894 :         rfMinimumY = ::rtl::math::isNan( fNegativeSum ) ? fFirstPositiveY : fNegativeSum;
    1802        6894 :         rfMaximumY = ::rtl::math::isNan( fPositiveSum ) ? fFirstNegativeY : fPositiveSum;
    1803             :     }
    1804             :     else
    1805             :     {
    1806        2199 :         for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
    1807             :         {
    1808        1158 :             if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
    1809          96 :                 continue;
    1810             : 
    1811        1062 :             double fValueMinY = (*aSeriesIter)->getMinimumofAllDifferentYValues( nCategoryIndex );
    1812        1062 :             double fValueMaxY = (*aSeriesIter)->getMaximumofAllDifferentYValues( nCategoryIndex );
    1813             : 
    1814        1062 :             if( ::rtl::math::isNan( fTotalSum ) )
    1815             :             {
    1816         945 :                 rfMinimumY = fValueMinY;
    1817         945 :                 rfMaximumY = fTotalSum = fValueMaxY;
    1818             :             }
    1819             :             else
    1820             :             {
    1821         117 :                 fTotalSum += fValueMaxY;
    1822         117 :                 if( rfMinimumY > fTotalSum )
    1823          27 :                     rfMinimumY = fTotalSum;
    1824         117 :                 if( rfMaximumY < fTotalSum )
    1825          78 :                     rfMaximumY = fTotalSum;
    1826             :             }
    1827             :         }
    1828             :     }
    1829             : 
    1830        7935 :     aCachedYValues.m_fMinimumY = rfMinimumY;
    1831        7935 :     aCachedYValues.m_fMaximumY = rfMaximumY;
    1832        7935 :     aCachedYValues.m_bValuesDirty = false;
    1833        7935 :     m_aListOfCachedYValues[nCategoryIndex][nAxisIndex]=aCachedYValues;
    1834             : }
    1835             : 
    1836        7676 : void VDataSeriesGroup::calculateYMinAndMaxForCategoryRange(
    1837             :         sal_Int32 nStartCategoryIndex, sal_Int32 nEndCategoryIndex
    1838             :         , bool bSeparateStackingForDifferentSigns
    1839             :         , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex )
    1840             : {
    1841             :     //@todo maybe cache these values
    1842        7676 :     ::rtl::math::setInf(&rfMinimumY, false);
    1843        7676 :     ::rtl::math::setInf(&rfMaximumY, true);
    1844             : 
    1845             :     //iterate through the given categories
    1846        7676 :     if(nStartCategoryIndex<0)
    1847           0 :         nStartCategoryIndex=0;
    1848        7676 :     if(nEndCategoryIndex<0)
    1849           0 :         nEndCategoryIndex=0;
    1850       46864 :     for( sal_Int32 nCatIndex = nStartCategoryIndex; nCatIndex <= nEndCategoryIndex; nCatIndex++ )
    1851             :     {
    1852       39188 :         double fMinimumY; ::rtl::math::setNan(&fMinimumY);
    1853       39188 :         double fMaximumY; ::rtl::math::setNan(&fMaximumY);
    1854             : 
    1855             :         this->calculateYMinAndMaxForCategory( nCatIndex
    1856       39188 :             , bSeparateStackingForDifferentSigns, fMinimumY, fMaximumY, nAxisIndex );
    1857             : 
    1858       39188 :         if(rfMinimumY > fMinimumY)
    1859       15176 :             rfMinimumY = fMinimumY;
    1860       39188 :         if(rfMaximumY < fMaximumY)
    1861       15664 :             rfMaximumY = fMaximumY;
    1862             :     }
    1863        7676 : }
    1864             : 
    1865         868 : double VSeriesPlotter::getTransformedDepth() const
    1866             : {
    1867         868 :     double MinZ = m_pMainPosHelper->getLogicMinZ();
    1868         868 :     double MaxZ = m_pMainPosHelper->getLogicMaxZ();
    1869         868 :     m_pMainPosHelper->doLogicScaling( 0, 0, &MinZ );
    1870         868 :     m_pMainPosHelper->doLogicScaling( 0, 0, &MaxZ );
    1871         868 :     return FIXED_SIZE_FOR_3D_CHART_VOLUME/(MaxZ-MinZ);
    1872             : }
    1873             : 
    1874          12 : void VSeriesPlotter::addSecondaryValueScale( const ExplicitScaleData& rScale, sal_Int32 nAxisIndex )
    1875             :                 throw (uno::RuntimeException)
    1876             : {
    1877          12 :     if( nAxisIndex<1 )
    1878          12 :         return;
    1879             : 
    1880          12 :     m_aSecondaryValueScales[nAxisIndex]=rScale;
    1881             : }
    1882             : 
    1883        8313 : PlottingPositionHelper& VSeriesPlotter::getPlottingPositionHelper( sal_Int32 nAxisIndex ) const
    1884             : {
    1885        8313 :     PlottingPositionHelper* pRet = 0;
    1886        8313 :     if(nAxisIndex>0)
    1887             :     {
    1888          20 :         tSecondaryPosHelperMap::const_iterator aPosIt = m_aSecondaryPosHelperMap.find( nAxisIndex );
    1889          20 :         if( aPosIt != m_aSecondaryPosHelperMap.end() )
    1890             :         {
    1891          18 :             pRet = aPosIt->second;
    1892             :         }
    1893           2 :         else if (m_pPosHelper)
    1894             :         {
    1895           2 :             tSecondaryValueScales::const_iterator aScaleIt = m_aSecondaryValueScales.find( nAxisIndex );
    1896           2 :             if( aScaleIt != m_aSecondaryValueScales.end() )
    1897             :             {
    1898           2 :                 pRet = m_pPosHelper->createSecondaryPosHelper( aScaleIt->second );
    1899           2 :                 m_aSecondaryPosHelperMap[nAxisIndex] = pRet;
    1900             :             }
    1901             :         }
    1902             :     }
    1903        8313 :     if( !pRet )
    1904        8293 :         pRet = m_pMainPosHelper;
    1905        8313 :     if(pRet)
    1906        8313 :         pRet->setTimeResolution( m_nTimeResolution, m_aNullDate );
    1907        8313 :     return *pRet;
    1908             : }
    1909             : 
    1910           0 : void VSeriesPlotter::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& /*rPageSize*/ )
    1911             : {
    1912           0 : }
    1913             : 
    1914         549 : VDataSeries* VSeriesPlotter::getFirstSeries() const
    1915             : {
    1916         549 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter( m_aZSlots.begin() );
    1917         549 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd( m_aZSlots.end() );
    1918         549 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1919             :     {
    1920         549 :         ::std::vector< VDataSeriesGroup >::const_iterator       aXSlotIter = aZSlotIter->begin();
    1921         549 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd  = aZSlotIter->end();
    1922             : 
    1923         549 :         if( aXSlotIter != aXSlotEnd )
    1924             :         {
    1925         549 :             VDataSeriesGroup aSeriesGroup( *aXSlotIter );
    1926         549 :             if( aSeriesGroup.m_aSeriesVector.size() )
    1927             :             {
    1928         549 :                 VDataSeries* pSeries = aSeriesGroup.m_aSeriesVector[0];
    1929         549 :                 if(pSeries)
    1930         549 :                     return pSeries;
    1931           0 :             }
    1932             :         }
    1933             :     }
    1934           0 :     return 0;
    1935             : }
    1936             : 
    1937          12 : uno::Sequence< OUString > VSeriesPlotter::getSeriesNames() const
    1938             : {
    1939          12 :     ::std::vector< OUString > aRetVector;
    1940             : 
    1941          24 :     OUString aRole;
    1942          12 :     if( m_xChartTypeModel.is() )
    1943          12 :         aRole = m_xChartTypeModel->getRoleOfSequenceForSeriesLabel();
    1944             : 
    1945          12 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter( m_aZSlots.begin() );
    1946          12 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd( m_aZSlots.end() );
    1947          30 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1948             :     {
    1949          18 :         ::std::vector< VDataSeriesGroup >::const_iterator       aXSlotIter = aZSlotIter->begin();
    1950          18 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd  = aZSlotIter->end();
    1951             : 
    1952          18 :         if( aXSlotIter != aXSlotEnd )
    1953             :         {
    1954          18 :             VDataSeriesGroup aSeriesGroup( *aXSlotIter );
    1955          18 :             if( aSeriesGroup.m_aSeriesVector.size() )
    1956             :             {
    1957          18 :                 VDataSeries* pSeries = aSeriesGroup.m_aSeriesVector[0];
    1958          18 :                 uno::Reference< XDataSeries > xSeries( pSeries ? pSeries->getModel() : 0 );
    1959          18 :                 if( xSeries.is() )
    1960             :                 {
    1961          18 :                     OUString aSeriesName( DataSeriesHelper::getDataSeriesLabel( xSeries, aRole ) );
    1962          18 :                     aRetVector.push_back( aSeriesName );
    1963          18 :                 }
    1964          18 :             }
    1965             :         }
    1966             :     }
    1967          24 :     return ContainerHelper::ContainerToSequence( aRetVector );
    1968             : }
    1969             : 
    1970             : namespace
    1971             : {
    1972             : struct lcl_setRefSizeAtSeriesGroup : public ::std::unary_function< VDataSeriesGroup, void >
    1973             : {
    1974         619 :     lcl_setRefSizeAtSeriesGroup( awt::Size aRefSize ) : m_aRefSize( aRefSize ) {}
    1975        1963 :     void operator()( VDataSeriesGroup & rGroup )
    1976             :     {
    1977        1963 :         ::std::vector< VDataSeries* >::iterator aIt( rGroup.m_aSeriesVector.begin());
    1978        1963 :         const ::std::vector< VDataSeries* >::iterator aEndIt( rGroup.m_aSeriesVector.end());
    1979        3943 :         for( ; aIt != aEndIt; ++aIt )
    1980        1980 :             (*aIt)->setPageReferenceSize( m_aRefSize );
    1981        1963 :     }
    1982             : 
    1983             : private:
    1984             :     awt::Size m_aRefSize;
    1985             : };
    1986             : } // anonymous namespace
    1987             : 
    1988         619 : void VSeriesPlotter::setPageReferenceSize( const ::com::sun::star::awt::Size & rPageRefSize )
    1989             : {
    1990         619 :     m_aPageReferenceSize = rPageRefSize;
    1991             : 
    1992             :     // set reference size also at all data series
    1993             : 
    1994         619 :     ::std::vector< VDataSeriesGroup > aSeriesGroups( FlattenVector( m_aZSlots ));
    1995             :     ::std::for_each( aSeriesGroups.begin(), aSeriesGroups.end(),
    1996         619 :                      lcl_setRefSizeAtSeriesGroup( m_aPageReferenceSize ));
    1997         619 : }
    1998             : 
    1999             : //better performance for big data
    2000         619 : void VSeriesPlotter::setCoordinateSystemResolution( const Sequence< sal_Int32 >& rCoordinateSystemResolution )
    2001             : {
    2002         619 :     m_aCoordinateSystemResolution = rCoordinateSystemResolution;
    2003         619 : }
    2004             : 
    2005         634 : bool VSeriesPlotter::PointsWereSkipped() const
    2006             : {
    2007         634 :     return m_bPointsWereSkipped;
    2008             : }
    2009             : 
    2010         619 : bool VSeriesPlotter::WantToPlotInFrontOfAxisLine()
    2011             : {
    2012         619 :     return ChartTypeHelper::isSeriesInFrontOfAxisLine( m_xChartTypeModel );
    2013             : }
    2014             : 
    2015         602 : bool VSeriesPlotter::shouldSnapRectToUsedArea()
    2016             : {
    2017         602 :     if( m_nDimension == 3 )
    2018          11 :         return false;
    2019         591 :     return true;
    2020             : }
    2021             : 
    2022         597 : std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntries(
    2023             :               const awt::Size& rEntryKeyAspectRatio
    2024             :             , ::com::sun::star::chart::ChartLegendExpansion eLegendExpansion
    2025             :             , const Reference< beans::XPropertySet >& xTextProperties
    2026             :             , const Reference< drawing::XShapes >& xTarget
    2027             :             , const Reference< lang::XMultiServiceFactory >& xShapeFactory
    2028             :             , const Reference< uno::XComponentContext >& xContext
    2029             :             )
    2030             : {
    2031         597 :     std::vector< ViewLegendEntry > aResult;
    2032             : 
    2033         597 :     if( xTarget.is() )
    2034             :     {
    2035             :         //iterate through all series
    2036         597 :         bool bBreak = false;
    2037         597 :         bool bFirstSeries = true;
    2038         597 :         ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator             aZSlotIter = m_aZSlots.begin();
    2039         597 :         const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
    2040        1199 :         for( ; aZSlotIter!=aZSlotEnd && !bBreak; ++aZSlotIter )
    2041             :         {
    2042         602 :             ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
    2043         602 :             const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    2044        2481 :             for( ; aXSlotIter!=aXSlotEnd && !bBreak; ++aXSlotIter )
    2045             :             {
    2046        1879 :                 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
    2047        1879 :                 ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = pSeriesList->begin();
    2048        1879 :                 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
    2049             :                 //iterate through all series in this x slot
    2050        3775 :                 for( ; aSeriesIter!=aSeriesEnd && !bBreak; ++aSeriesIter )
    2051             :                 {
    2052        1896 :                     VDataSeries* pSeries( *aSeriesIter );
    2053        1896 :                     if(!pSeries)
    2054           0 :                         continue;
    2055             : 
    2056             :                     std::vector< ViewLegendEntry > aSeriesEntries( this->createLegendEntriesForSeries( rEntryKeyAspectRatio,
    2057        1896 :                             *pSeries, xTextProperties, xTarget, xShapeFactory, xContext ) );
    2058             : 
    2059             :                     //add series entries to the result now
    2060             : 
    2061             :                     // use only the first series if VaryColorsByPoint is set for the first series
    2062        1896 :                     if( bFirstSeries && pSeries->isVaryColorsByPoint() )
    2063          11 :                         bBreak = true;
    2064        1896 :                     bFirstSeries = false;
    2065             : 
    2066             :                     // add entries reverse if chart is stacked in y-direction and the legend is not wide.
    2067             :                     // If the legend is wide and we have a stacked bar-chart the normal order
    2068             :                     // is the correct one
    2069        1896 :                     bool bReverse = false;
    2070        1896 :                     if( eLegendExpansion != ::com::sun::star::chart::ChartLegendExpansion_WIDE )
    2071             :                     {
    2072        1877 :                         StackingDirection eStackingDirection( pSeries->getStackingDirection() );
    2073        1877 :                         bReverse = ( eStackingDirection == StackingDirection_Y_STACKING );
    2074             : 
    2075             :                         //todo: respect direction of axis in future
    2076             :                     }
    2077             : 
    2078        1896 :                     if(bReverse)
    2079          20 :                         aResult.insert( aResult.begin(), aSeriesEntries.begin(), aSeriesEntries.end() );
    2080             :                     else
    2081        1876 :                         aResult.insert( aResult.end(), aSeriesEntries.begin(), aSeriesEntries.end() );
    2082        1896 :                 }
    2083             :             }
    2084             :         }
    2085             :     }
    2086             : 
    2087         597 :     return aResult;
    2088             : }
    2089             : 
    2090         585 : ::std::vector< VDataSeries* > VSeriesPlotter::getAllSeries()
    2091             : {
    2092         585 :     ::std::vector< VDataSeries* > aAllSeries;
    2093         585 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator            aZSlotIter = m_aZSlots.begin();
    2094         585 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
    2095        1169 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    2096             :     {
    2097         584 :         ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
    2098         584 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    2099        2456 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
    2100             :         {
    2101        1872 :             ::std::vector< VDataSeries* > aSeriesList = aXSlotIter->m_aSeriesVector;
    2102        1872 :             aAllSeries.insert( aAllSeries.end(), aSeriesList.begin(), aSeriesList.end() );
    2103        1872 :         }
    2104             :     }
    2105         585 :     return aAllSeries;
    2106             : }
    2107             : 
    2108             : namespace
    2109             : {
    2110         205 : bool lcl_HasVisibleLine( const uno::Reference< beans::XPropertySet >& xProps, bool& rbHasDashedLine )
    2111             : {
    2112         205 :     bool bHasVisibleLine = false;
    2113         205 :     rbHasDashedLine = false;
    2114         205 :     drawing::LineStyle aLineStyle = drawing::LineStyle_NONE;
    2115         205 :     if( xProps.is() && ( xProps->getPropertyValue( "LineStyle") >>= aLineStyle ) )
    2116             :     {
    2117         205 :         if( aLineStyle != drawing::LineStyle_NONE )
    2118         183 :             bHasVisibleLine = true;
    2119         205 :         if( aLineStyle == drawing::LineStyle_DASH )
    2120           0 :             rbHasDashedLine = true;
    2121             :     }
    2122         205 :     return bHasVisibleLine;
    2123             : }
    2124             : 
    2125        1881 : bool lcl_HasRegressionCurves( const VDataSeries& rSeries, bool& rbHasDashedLine )
    2126             : {
    2127        1881 :     bool bHasRegressionCurves = false;
    2128        1881 :     Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
    2129        1881 :     if( xRegrCont.is())
    2130             :     {
    2131        1881 :         Sequence< Reference< XRegressionCurve > > aCurves( xRegrCont->getRegressionCurves() );
    2132        1881 :         sal_Int32 i = 0, nCount = aCurves.getLength();
    2133        1934 :         for( i=0; i<nCount; ++i )
    2134             :         {
    2135          53 :             if( aCurves[i].is() )
    2136             :             {
    2137          53 :                 bHasRegressionCurves = true;
    2138          53 :                 lcl_HasVisibleLine( uno::Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ), rbHasDashedLine );
    2139             :             }
    2140        1881 :         }
    2141             :     }
    2142        1881 :     return bHasRegressionCurves;
    2143             : }
    2144             : }
    2145        2295 : LegendSymbolStyle VSeriesPlotter::getLegendSymbolStyle()
    2146             : {
    2147        2295 :     return LegendSymbolStyle_BOX;
    2148             : }
    2149             : 
    2150         597 : awt::Size VSeriesPlotter::getPreferredLegendKeyAspectRatio()
    2151             : {
    2152         597 :     awt::Size aRet(1000,1000);
    2153         597 :     if( m_nDimension==3 )
    2154          12 :         return aRet;
    2155             : 
    2156         585 :     bool bSeriesAllowsLines = (getLegendSymbolStyle() == LegendSymbolStyle_LINE);
    2157         585 :     bool bHasLines = false;
    2158         585 :     bool bHasDashedLines = false;
    2159         585 :     ::std::vector< VDataSeries* > aAllSeries( getAllSeries() );
    2160         585 :     ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = aAllSeries.begin();
    2161         585 :     const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = aAllSeries.end();
    2162             :     //iterate through all series
    2163        2466 :     for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
    2164             :     {
    2165        1881 :         if( bSeriesAllowsLines )
    2166             :         {
    2167         152 :             bool bCurrentDashed = false;
    2168         152 :             if( lcl_HasVisibleLine( (*aSeriesIter)->getPropertiesOfSeries(), bCurrentDashed ) )
    2169             :             {
    2170         133 :                 bHasLines = true;
    2171         133 :                 if( bCurrentDashed )
    2172             :                 {
    2173           0 :                     bHasDashedLines = true;
    2174           0 :                     break;
    2175             :                 }
    2176             :             }
    2177             :         }
    2178        1881 :         bool bRegressionHasDashedLines=false;
    2179        1881 :         if( lcl_HasRegressionCurves( **aSeriesIter, bRegressionHasDashedLines ) )
    2180             :         {
    2181          39 :             bHasLines = true;
    2182          39 :             if( bRegressionHasDashedLines )
    2183             :             {
    2184           0 :                 bHasDashedLines = true;
    2185           0 :                 break;
    2186             :             }
    2187             :         }
    2188             :     }
    2189         585 :     if( bHasLines )
    2190             :     {
    2191          39 :         if( bHasDashedLines )
    2192           0 :             aRet = awt::Size(1600,-1);
    2193             :         else
    2194          39 :             aRet = awt::Size(800,-1);
    2195             :     }
    2196         585 :     return aRet;
    2197             : }
    2198             : 
    2199        1772 : uno::Any VSeriesPlotter::getExplicitSymbol( const VDataSeries& /*rSeries*/, sal_Int32 /*nPointIndex*/ )
    2200             : {
    2201        1772 :     return uno::Any();
    2202             : }
    2203             : 
    2204        1885 : Reference< drawing::XShape > VSeriesPlotter::createLegendSymbolForSeries(
    2205             :                   const awt::Size& rEntryKeyAspectRatio
    2206             :                 , const VDataSeries& rSeries
    2207             :                 , const Reference< drawing::XShapes >& xTarget
    2208             :                 , const Reference< lang::XMultiServiceFactory >& xShapeFactory )
    2209             : {
    2210             : 
    2211        1885 :     LegendSymbolStyle eLegendSymbolStyle = this->getLegendSymbolStyle();
    2212        1885 :     uno::Any aExplicitSymbol( this->getExplicitSymbol( rSeries ) );
    2213             : 
    2214             :     VLegendSymbolFactory::tPropertyType ePropType =
    2215        1885 :         VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES;
    2216             : 
    2217             :     // todo: maybe the property-style does not solely depend on the
    2218             :     // legend-symbol type
    2219        1885 :     switch( eLegendSymbolStyle )
    2220             :     {
    2221             :         case LegendSymbolStyle_LINE:
    2222         152 :             ePropType = VLegendSymbolFactory::PROP_TYPE_LINE_SERIES;
    2223         152 :             break;
    2224             :         default:
    2225        1733 :             break;
    2226             :     };
    2227             :     Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
    2228             :         xTarget, eLegendSymbolStyle, xShapeFactory
    2229        1885 :             , rSeries.getPropertiesOfSeries(), ePropType, aExplicitSymbol ));
    2230             : 
    2231        1885 :     return xShape;
    2232             : }
    2233             : 
    2234          37 : Reference< drawing::XShape > VSeriesPlotter::createLegendSymbolForPoint(
    2235             :                   const awt::Size& rEntryKeyAspectRatio
    2236             :                 , const VDataSeries& rSeries
    2237             :                 , sal_Int32 nPointIndex
    2238             :                 , const Reference< drawing::XShapes >& xTarget
    2239             :                 , const Reference< lang::XMultiServiceFactory >& xShapeFactory )
    2240             : {
    2241             : 
    2242          37 :     LegendSymbolStyle eLegendSymbolStyle = this->getLegendSymbolStyle();
    2243          37 :     uno::Any aExplicitSymbol( this->getExplicitSymbol(rSeries,nPointIndex) );
    2244             : 
    2245             :     VLegendSymbolFactory::tPropertyType ePropType =
    2246          37 :         VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES;
    2247             : 
    2248             :     // todo: maybe the property-style does not solely depend on the
    2249             :     // legend-symbol type
    2250          37 :     switch( eLegendSymbolStyle )
    2251             :     {
    2252             :         case LegendSymbolStyle_LINE:
    2253           0 :             ePropType = VLegendSymbolFactory::PROP_TYPE_LINE_SERIES;
    2254           0 :             break;
    2255             :         default:
    2256          37 :             break;
    2257             :     };
    2258             : 
    2259             :     // the default properties for the data point are the data series properties.
    2260             :     // If a data point has own attributes overwrite them
    2261          37 :     Reference< beans::XPropertySet > xSeriesProps( rSeries.getPropertiesOfSeries() );
    2262          74 :     Reference< beans::XPropertySet > xPointSet( xSeriesProps );
    2263          37 :     if( rSeries.isAttributedDataPoint( nPointIndex ) )
    2264           7 :         xPointSet.set( rSeries.getPropertiesOfPoint( nPointIndex ));
    2265             : 
    2266             :     // if a data point has no own color use a color fom the diagram's color scheme
    2267          37 :     if( ! rSeries.hasPointOwnColor( nPointIndex ))
    2268             :     {
    2269          30 :         Reference< util::XCloneable > xCloneable( xPointSet,uno::UNO_QUERY );
    2270          30 :         if( xCloneable.is() && m_xColorScheme.is() )
    2271             :         {
    2272          30 :             xPointSet.set( xCloneable->createClone(), uno::UNO_QUERY );
    2273          30 :             Reference< container::XChild > xChild( xPointSet, uno::UNO_QUERY );
    2274          30 :             if( xChild.is())
    2275           0 :                 xChild->setParent( xSeriesProps );
    2276             : 
    2277             :             OSL_ASSERT( xPointSet.is());
    2278          30 :             xPointSet->setPropertyValue(
    2279          30 :                 "Color", uno::makeAny( m_xColorScheme->getColorByIndex( nPointIndex )));
    2280          30 :         }
    2281             :     }
    2282             : 
    2283             :     Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
    2284          74 :         xTarget, eLegendSymbolStyle, xShapeFactory, xPointSet, ePropType, aExplicitSymbol ));
    2285             : 
    2286          74 :     return xShape;
    2287             : }
    2288             : 
    2289        1896 : std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntriesForSeries(
    2290             :               const awt::Size& rEntryKeyAspectRatio
    2291             :             , const VDataSeries& rSeries
    2292             :             , const Reference< beans::XPropertySet >& xTextProperties
    2293             :             , const Reference< drawing::XShapes >& xTarget
    2294             :             , const Reference< lang::XMultiServiceFactory >& xShapeFactory
    2295             :             , const Reference< uno::XComponentContext >& xContext
    2296             :             )
    2297             : {
    2298        1896 :     std::vector< ViewLegendEntry > aResult;
    2299             : 
    2300        1896 :     if( ! ( xShapeFactory.is() && xTarget.is() && xContext.is() ) )
    2301           0 :         return aResult;
    2302             : 
    2303             :     try
    2304             :     {
    2305        1896 :         ViewLegendEntry aEntry;
    2306        3737 :         OUString aLabelText;
    2307        1896 :         bool bVaryColorsByPoint = rSeries.isVaryColorsByPoint();
    2308        1896 :         if( bVaryColorsByPoint )
    2309             :         {
    2310          11 :             Sequence< OUString > aCategoryNames;
    2311          11 :             if( m_pExplicitCategoriesProvider )
    2312          11 :                 aCategoryNames = m_pExplicitCategoriesProvider->getSimpleCategories();
    2313             : 
    2314          48 :             for( sal_Int32 nIdx=0; nIdx<aCategoryNames.getLength(); ++nIdx )
    2315             :             {
    2316             :                 // symbol
    2317          37 :                 uno::Reference< drawing::XShapes > xSymbolGroup( AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory)->createGroup2D( xTarget ));
    2318             : 
    2319             :                 // create the symbol
    2320             :                 Reference< drawing::XShape > xShape( this->createLegendSymbolForPoint( rEntryKeyAspectRatio,
    2321          74 :                     rSeries, nIdx, xSymbolGroup, xShapeFactory ) );
    2322             : 
    2323             :                 // set CID to symbol for selection
    2324          37 :                 if( xShape.is() )
    2325             :                 {
    2326          37 :                     aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
    2327             : 
    2328          37 :                     OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_DATA_POINT, nIdx ) );
    2329          37 :                     aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
    2330          74 :                     OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
    2331          74 :                     AbstractShapeFactory::setShapeName( xShape, aCID );
    2332             :                 }
    2333             : 
    2334             :                 // label
    2335          37 :                 aLabelText = aCategoryNames[nIdx];
    2336          37 :                 if( xShape.is() || !aLabelText.isEmpty() )
    2337             :                 {
    2338          37 :                     aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
    2339          37 :                     aResult.push_back(aEntry);
    2340             :                 }
    2341          48 :             }
    2342             :         }
    2343             :         else
    2344             :         {
    2345             :             // symbol
    2346        1885 :             uno::Reference< drawing::XShapes > xSymbolGroup( AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory)->createGroup2D( xTarget ));
    2347             : 
    2348             :             // create the symbol
    2349             :             Reference< drawing::XShape > xShape( this->createLegendSymbolForSeries(
    2350        3770 :                 rEntryKeyAspectRatio, rSeries, xSymbolGroup, xShapeFactory ) );
    2351             : 
    2352             :             // set CID to symbol for selection
    2353        1885 :             if( xShape.is())
    2354             :             {
    2355        1885 :                 aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
    2356             : 
    2357        1885 :                 OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
    2358        3770 :                 OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
    2359        3770 :                 AbstractShapeFactory::setShapeName( xShape, aCID );
    2360             :             }
    2361             : 
    2362             :             // label
    2363        1885 :             aLabelText = ( DataSeriesHelper::getDataSeriesLabel( rSeries.getModel(), m_xChartTypeModel.is() ? m_xChartTypeModel->getRoleOfSequenceForSeriesLabel() : "values-y") );
    2364        1885 :             aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
    2365             : 
    2366        3770 :             aResult.push_back(aEntry);
    2367             :         }
    2368             : 
    2369             :         // don't show legend entry of regression curve & friends if this type of chart
    2370             :         // doesn't support statistics #i63016#, fdo#37197
    2371        1896 :         if (!ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ))
    2372          55 :             return aResult;
    2373             : 
    2374        3682 :         Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
    2375        1841 :         if( xRegrCont.is())
    2376             :         {
    2377        1841 :             Sequence< Reference< XRegressionCurve > > aCurves( xRegrCont->getRegressionCurves());
    2378        1841 :             sal_Int32 i = 0, nCount = aCurves.getLength();
    2379        1894 :             for( i=0; i<nCount; ++i )
    2380             :             {
    2381          53 :                 if( aCurves[i].is() )
    2382             :                 {
    2383             :                     //label
    2384          53 :                     OUString aResStr( RegressionCurveHelper::getUINameForRegressionCurve( aCurves[i] ) );
    2385          53 :                     replaceParamterInString( aResStr, "%SERIESNAME", aLabelText );
    2386          53 :                     aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aResStr, xTextProperties );
    2387             : 
    2388             :                     // symbol
    2389         106 :                     uno::Reference< drawing::XShapes > xSymbolGroup( AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory)->createGroup2D( xTarget ));
    2390             : 
    2391             :                     // create the symbol
    2392             :                     Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
    2393             :                         xSymbolGroup, LegendSymbolStyle_LINE, xShapeFactory,
    2394          53 :                         Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ),
    2395         159 :                         VLegendSymbolFactory::PROP_TYPE_LINE, uno::Any() ));
    2396             : 
    2397             :                     // set CID to symbol for selection
    2398          53 :                     if( xShape.is())
    2399             :                     {
    2400          53 :                         aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
    2401             : 
    2402          53 :                         bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurves[i] );
    2403          53 :                         ObjectType eObjectType = bAverageLine ? OBJECTTYPE_DATA_AVERAGE_LINE : OBJECTTYPE_DATA_CURVE;
    2404          53 :                         OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( eObjectType, i ) );
    2405          53 :                         aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
    2406         106 :                         OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
    2407         106 :                         AbstractShapeFactory::setShapeName( xShape, aCID );
    2408             :                     }
    2409             : 
    2410         106 :                     aResult.push_back(aEntry);
    2411             :                 }
    2412        1841 :             }
    2413        1841 :         }
    2414             :     }
    2415           0 :     catch( const uno::Exception & ex )
    2416             :     {
    2417             :         ASSERT_EXCEPTION( ex );
    2418             :     }
    2419        1841 :     return aResult;
    2420             : }
    2421             : 
    2422         620 : VSeriesPlotter* VSeriesPlotter::createSeriesPlotter(
    2423             :     const uno::Reference<XChartType>& xChartTypeModel
    2424             :     , sal_Int32 nDimensionCount
    2425             :     , bool bExcludingPositioning )
    2426             : {
    2427         620 :     if (!xChartTypeModel.is())
    2428           0 :         return NULL;
    2429             : 
    2430         620 :     OUString aChartType = xChartTypeModel->getChartType();
    2431             : 
    2432         620 :     VSeriesPlotter* pRet=NULL;
    2433         620 :     if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_COLUMN ) )
    2434         550 :         pRet = new BarChart(xChartTypeModel,nDimensionCount);
    2435          70 :     else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_BAR ) )
    2436           0 :         pRet = new BarChart(xChartTypeModel,nDimensionCount);
    2437          70 :     else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_AREA ) )
    2438           0 :         pRet = new AreaChart(xChartTypeModel,nDimensionCount,true);
    2439          70 :     else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_LINE ) )
    2440          34 :         pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,true);
    2441          36 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) )
    2442          18 :         pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true);
    2443          18 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE) )
    2444           0 :         pRet = new BubbleChart(xChartTypeModel,nDimensionCount);
    2445          18 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
    2446          15 :         pRet = new PieChart(xChartTypeModel,nDimensionCount, bExcludingPositioning );
    2447           3 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_NET) )
    2448           0 :         pRet = new NetChart(xChartTypeModel,nDimensionCount,true,new PolarPlottingPositionHelper());
    2449           3 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) )
    2450           0 :         pRet = new NetChart(xChartTypeModel,nDimensionCount,false,new PolarPlottingPositionHelper());
    2451           3 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) )
    2452           3 :         pRet = new CandleStickChart(xChartTypeModel,nDimensionCount);
    2453             :     else
    2454           0 :         pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true);
    2455         620 :     return pRet;
    2456             : }
    2457             : 
    2458             : } //namespace chart
    2459             : 
    2460             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10