LCOV - code coverage report
Current view: top level - chart2/source/view/charttypes - VSeriesPlotter.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 1243 0.0 %
Date: 2014-04-14 Functions: 0 88 0.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           0 : VDataSeriesGroup::CachedYValues::CachedYValues()
      84             :         : m_bValuesDirty(true)
      85             :         , m_fMinimumY(0.0)
      86           0 :         , m_fMaximumY(0.0)
      87             : {
      88           0 : }
      89             : 
      90           0 : VDataSeriesGroup::VDataSeriesGroup()
      91             :         : m_aSeriesVector()
      92             :         , m_bMaxPointCountDirty(true)
      93             :         , m_nMaxPointCount(0)
      94           0 :         , m_aListOfCachedYValues()
      95             : {
      96           0 : }
      97             : 
      98           0 : VDataSeriesGroup::VDataSeriesGroup( VDataSeries* pSeries )
      99             :         : m_aSeriesVector(1,pSeries)
     100             :         , m_bMaxPointCountDirty(true)
     101             :         , m_nMaxPointCount(0)
     102           0 :         , m_aListOfCachedYValues()
     103             : {
     104           0 : }
     105             : 
     106           0 : VDataSeriesGroup::~VDataSeriesGroup()
     107             : {
     108           0 : }
     109             : 
     110           0 : void VDataSeriesGroup::deleteSeries()
     111             : {
     112             :     //delete all data series help objects:
     113           0 :     ::std::vector< VDataSeries* >::const_iterator aIter = m_aSeriesVector.begin();
     114           0 :     const ::std::vector< VDataSeries* >::const_iterator aEnd  = m_aSeriesVector.end();
     115           0 :     for( ; aIter != aEnd; ++aIter )
     116             :     {
     117           0 :         delete *aIter;
     118             :     }
     119           0 :     m_aSeriesVector.clear();
     120           0 : }
     121             : 
     122           0 : void VDataSeriesGroup::addSeries( VDataSeries* pSeries )
     123             : {
     124           0 :     m_aSeriesVector.push_back(pSeries);
     125           0 :     m_bMaxPointCountDirty=true;
     126           0 : }
     127             : 
     128           0 : sal_Int32 VDataSeriesGroup::getSeriesCount() const
     129             : {
     130           0 :     return m_aSeriesVector.size();
     131             : }
     132             : 
     133           0 : 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           0 :         , 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           0 : }
     149             : 
     150           0 : VSeriesPlotter::~VSeriesPlotter()
     151             : {
     152             :     //delete all data series help objects:
     153           0 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator             aZSlotIter = m_aZSlots.begin();
     154           0 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
     155           0 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
     156             :     {
     157           0 :         ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
     158           0 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
     159           0 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
     160             :         {
     161           0 :             aXSlotIter->deleteSeries();
     162             :         }
     163           0 :         aZSlotIter->clear();
     164             :     }
     165           0 :     m_aZSlots.clear();
     166             : 
     167           0 :     tSecondaryPosHelperMap::iterator aPosIt = m_aSecondaryPosHelperMap.begin();
     168           0 :     while( aPosIt != m_aSecondaryPosHelperMap.end() )
     169             :     {
     170           0 :         PlottingPositionHelper* pPosHelper = aPosIt->second;
     171           0 :         delete pPosHelper;
     172             : 
     173           0 :         ++aPosIt;
     174             :     }
     175           0 :     m_aSecondaryPosHelperMap.clear();
     176             : 
     177           0 :     m_aSecondaryValueScales.clear();
     178           0 : }
     179             : 
     180           0 : 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           0 :     if(!pSeries)
     186           0 :         return;
     187             : 
     188           0 :     if(m_bCategoryXAxis)
     189             :     {
     190           0 :         if( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() )
     191           0 :             pSeries->setXValues( m_pExplicitCategoriesProvider->getOriginalCategories() );
     192             :         else
     193           0 :             pSeries->setCategoryXAxis();
     194             :     }
     195             :     else
     196             :     {
     197           0 :         if( m_pExplicitCategoriesProvider )
     198           0 :             pSeries->setXValuesIfNone( m_pExplicitCategoriesProvider->getOriginalCategories() );
     199             :     }
     200             : 
     201           0 :     if(zSlot<0 || zSlot>=static_cast<sal_Int32>(m_aZSlots.size()))
     202             :     {
     203             :         //new z slot
     204           0 :         ::std::vector< VDataSeriesGroup > aZSlot;
     205           0 :         aZSlot.push_back( VDataSeriesGroup(pSeries) );
     206           0 :         m_aZSlots.push_back( aZSlot );
     207             :     }
     208             :     else
     209             :     {
     210             :         //existing zslot
     211           0 :         ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[zSlot];
     212             : 
     213           0 :         if(xSlot<0 || xSlot>=static_cast<sal_Int32>(rXSlots.size()))
     214             :         {
     215             :             //append the series to already existing x series
     216           0 :             rXSlots.push_back( VDataSeriesGroup(pSeries) );
     217             :         }
     218             :         else
     219             :         {
     220             :             //x slot is already occupied
     221             :             //y slot decides what to do:
     222             : 
     223           0 :             VDataSeriesGroup& rYSlots = rXSlots[xSlot];
     224           0 :             sal_Int32 nYSlotCount = rYSlots.getSeriesCount();
     225             : 
     226           0 :             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           0 :             else if( ySlot == -1 || ySlot >= nYSlotCount)
     233             :             {
     234             :                 //append the series to already existing y series
     235           0 :                 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           0 : void VSeriesPlotter::releaseShapes()
     270             : {
     271           0 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator             aZSlotIter = m_aZSlots.begin();
     272           0 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
     273           0 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
     274             :     {
     275           0 :         ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
     276           0 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
     277           0 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
     278             :         {
     279           0 :             ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
     280             : 
     281           0 :             ::std::vector< VDataSeries* >::iterator             aSeriesIter = pSeriesList->begin();
     282           0 :             const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
     283             : 
     284             :             //iterate through all series in this x slot
     285           0 :             for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
     286             :             {
     287           0 :                 VDataSeries* pSeries( *aSeriesIter );
     288           0 :                 pSeries->releaseShapes();
     289             :             }
     290             :         }
     291             :     }
     292           0 : }
     293             : 
     294           0 : uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShape( VDataSeries* pDataSeries
     295             :                                         , const uno::Reference< drawing::XShapes >& xTarget )
     296             : {
     297           0 :     uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xGroupShape );
     298           0 :     if( !xShapes.is() )
     299             :     {
     300             :         //create a group shape for this series and add to logic target:
     301           0 :         xShapes = createGroupShape( xTarget,pDataSeries->getCID() );
     302           0 :         pDataSeries->m_xGroupShape = xShapes;
     303             :     }
     304           0 :     return xShapes;
     305             : }
     306             : 
     307           0 : uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShapeFrontChild( VDataSeries* pDataSeries
     308             :                                         , const uno::Reference< drawing::XShapes >& xTarget )
     309             : {
     310           0 :     uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xFrontSubGroupShape );
     311           0 :     if(!xShapes.is())
     312             :     {
     313             :         //ensure that the series group shape is already created
     314           0 :         uno::Reference< drawing::XShapes > xSeriesShapes( this->getSeriesGroupShape( pDataSeries, xTarget ) );
     315             :         //ensure that the back child is created first
     316           0 :         this->getSeriesGroupShapeBackChild( pDataSeries, xTarget );
     317             :         //use series group shape as parent for the new created front group shape
     318           0 :         xShapes = createGroupShape( xSeriesShapes );
     319           0 :         pDataSeries->m_xFrontSubGroupShape = xShapes;
     320             :     }
     321           0 :     return xShapes;
     322             : }
     323             : 
     324           0 : uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShapeBackChild( VDataSeries* pDataSeries
     325             :                                         , const uno::Reference< drawing::XShapes >& xTarget )
     326             : {
     327           0 :     uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xBackSubGroupShape );
     328           0 :     if(!xShapes.is())
     329             :     {
     330             :         //ensure that the series group shape is already created
     331           0 :         uno::Reference< drawing::XShapes > xSeriesShapes( this->getSeriesGroupShape( pDataSeries, xTarget ) );
     332             :         //use series group shape as parent for the new created back group shape
     333           0 :         xShapes = createGroupShape( xSeriesShapes );
     334           0 :         pDataSeries->m_xBackSubGroupShape = xShapes;
     335             :     }
     336           0 :     return xShapes;
     337             : }
     338             : 
     339           0 : 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           0 :     uno::Reference< drawing::XShapes > xShapes( rDataSeries.m_xLabelsGroupShape );
     345           0 :     if(!xShapes.is())
     346             :     {
     347             :         //create a 2D group shape for texts of this series and add to text target:
     348           0 :         xShapes = m_pShapeFactory->createGroup2D( xTextTarget, rDataSeries.getLabelsCID() );
     349           0 :         rDataSeries.m_xLabelsGroupShape = xShapes;
     350             :     }
     351           0 :     return xShapes;
     352             : }
     353             : 
     354           0 : 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           0 :             bYError ? rDataSeries.m_xErrorYBarsGroupShape : rDataSeries.m_xErrorXBarsGroupShape;
     360             : 
     361           0 :     uno::Reference< drawing::XShapes > xShapes( rShapeGroup );
     362           0 :     if(!xShapes.is())
     363             :     {
     364             :         //create a group shape for this series and add to logic target:
     365           0 :         xShapes = this->createGroupShape( xTarget,rDataSeries.getErrorBarsCID(bYError) );
     366           0 :         rShapeGroup = xShapes;
     367             :     }
     368           0 :     return xShapes;
     369             : 
     370             : }
     371             : 
     372           0 : OUString VSeriesPlotter::getLabelTextForValue( VDataSeries& rDataSeries
     373             :                 , sal_Int32 nPointIndex
     374             :                 , double fValue
     375             :                 , bool bAsPercentage )
     376             : {
     377           0 :     OUString aNumber;
     378             : 
     379           0 :     if( m_apNumberFormatterWrapper.get())
     380             :     {
     381           0 :         sal_Int32 nNumberFormatKey = 0;
     382           0 :         if( rDataSeries.hasExplicitNumberFormat(nPointIndex,bAsPercentage) )
     383           0 :             nNumberFormatKey = rDataSeries.getExplicitNumberFormat(nPointIndex,bAsPercentage);
     384           0 :         else if( bAsPercentage )
     385             :         {
     386           0 :             sal_Int32 nPercentFormat = DiagramHelper::getPercentNumberFormat( m_apNumberFormatterWrapper->getNumberFormatsSupplier() );
     387           0 :             if( nPercentFormat != -1 )
     388           0 :                 nNumberFormatKey = nPercentFormat;
     389             :         }
     390             :         else
     391             :         {
     392           0 :             if( rDataSeries.shouldLabelNumberFormatKeyBeDetectedFromYAxis() && m_aAxesNumberFormats.hasFormat(1,rDataSeries.getAttachedAxisIndex()) ) //y-axis
     393           0 :                 nNumberFormatKey = m_aAxesNumberFormats.getFormat(1,rDataSeries.getAttachedAxisIndex());
     394             :             else
     395           0 :                 nNumberFormatKey = rDataSeries.detectNumberFormatKey( nPointIndex );
     396             :         }
     397           0 :         if(nNumberFormatKey<0)
     398           0 :             nNumberFormatKey=0;
     399             : 
     400           0 :         sal_Int32 nLabelCol = 0;
     401             :         bool bColChanged;
     402           0 :         aNumber = m_apNumberFormatterWrapper->getFormattedString(
     403           0 :                 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           0 :     return aNumber;
     413             : }
     414             : 
     415           0 : 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           0 :     uno::Reference< drawing::XShape > xTextShape;
     425             : 
     426             :     try
     427             :     {
     428           0 :         awt::Point aScreenPosition2D(rScreenPosition2D);
     429           0 :         if(LABEL_ALIGN_LEFT==eAlignment)
     430           0 :             aScreenPosition2D.X -= nOffset;
     431           0 :         else if(LABEL_ALIGN_RIGHT==eAlignment)
     432           0 :             aScreenPosition2D.X += nOffset;
     433           0 :         else if(LABEL_ALIGN_TOP==eAlignment)
     434           0 :             aScreenPosition2D.Y -= nOffset;
     435           0 :         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           0 :                     , ObjectIdentifier::createPointCID( rDataSeries.getLabelCID_Stub(),nPointIndex ) ) );
     441             : 
     442             :         //check whether the label needs to be created and how:
     443           0 :         DataPointLabel* pLabel = rDataSeries.getDataPointLabelIfLabel( nPointIndex );
     444             : 
     445           0 :         if( !pLabel )
     446           0 :             return xTextShape;
     447             : 
     448             :         //prepare legend symbol
     449             : 
     450           0 :         float fViewFontSize( 10.0 );
     451             :         {
     452           0 :             uno::Reference< beans::XPropertySet > xProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) );
     453           0 :             if( xProps.is() )
     454           0 :                 xProps->getPropertyValue( "CharHeight") >>= fViewFontSize;
     455             :             // pt -> 1/100th mm
     456           0 :             fViewFontSize *= (2540.0f / 72.0f);
     457             :         }
     458           0 :         Reference< drawing::XShape > xSymbol;
     459           0 :         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           0 :         OUStringBuffer aText;
     478           0 :         OUString aSeparator(" ");
     479           0 :         double fRotationDegrees = 0.0;
     480             :         try
     481             :         {
     482           0 :             uno::Reference< beans::XPropertySet > xPointProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) );
     483           0 :             if(xPointProps.is())
     484             :             {
     485           0 :                 xPointProps->getPropertyValue( "LabelSeparator" ) >>= aSeparator;
     486           0 :                 xPointProps->getPropertyValue( "TextRotation" ) >>= fRotationDegrees;
     487           0 :             }
     488             :         }
     489           0 :         catch( const uno::Exception& e )
     490             :         {
     491             :             ASSERT_EXCEPTION( e );
     492             :         }
     493           0 :         bool bMultiLineLabel = aSeparator.equals("\n");;
     494           0 :         sal_Int32 nLineCountForSymbolsize = 0;
     495             :         {
     496           0 :             if(pLabel->ShowCategoryName)
     497             :             {
     498           0 :                 if( m_pExplicitCategoriesProvider )
     499             :                 {
     500           0 :                     Sequence< OUString > aCategories( m_pExplicitCategoriesProvider->getSimpleCategories() );
     501           0 :                     if( nPointIndex >= 0 && nPointIndex < aCategories.getLength() )
     502             :                     {
     503           0 :                         aText.append( aCategories[nPointIndex] );
     504           0 :                         ++nLineCountForSymbolsize;
     505           0 :                     }
     506             :                 }
     507             :             }
     508             : 
     509           0 :             if(pLabel->ShowNumber)
     510             :             {
     511             :                 OUString aNumber( this->getLabelTextForValue( rDataSeries
     512           0 :                     , nPointIndex, fValue, false /*bAsPercentage*/ ) );
     513           0 :                 if( !aNumber.isEmpty() )
     514             :                 {
     515           0 :                     if(!aText.isEmpty())
     516           0 :                         aText.append(aSeparator);
     517           0 :                     aText.append(aNumber);
     518           0 :                     ++nLineCountForSymbolsize;
     519           0 :                 }
     520             :             }
     521             : 
     522           0 :             if(pLabel->ShowNumberInPercent)
     523             :             {
     524           0 :                 if(fSumValue==0.0)
     525           0 :                     fSumValue=1.0;
     526           0 :                 fValue /= fSumValue;
     527           0 :                 if( fValue < 0 )
     528           0 :                     fValue*=-1.0;
     529             : 
     530             :                 OUString aPercentage( this->getLabelTextForValue( rDataSeries
     531           0 :                     , nPointIndex, fValue, true /*bAsPercentage*/ ) );
     532           0 :                 if( !aPercentage.isEmpty() )
     533             :                 {
     534           0 :                     if(!aText.isEmpty())
     535           0 :                         aText.append(aSeparator);
     536           0 :                     aText.append(aPercentage);
     537           0 :                     ++nLineCountForSymbolsize;
     538           0 :                 }
     539             :             }
     540             :         }
     541             :         //prepare properties for multipropertyset-interface of shape
     542             :         tNameSequence* pPropNames;
     543             :         tAnySequence* pPropValues;
     544           0 :         if( !rDataSeries.getTextLabelMultiPropertyLists( nPointIndex, pPropNames, pPropValues ) )
     545           0 :             return xTextShape;
     546           0 :         LabelPositionHelper::changeTextAdjustment( *pPropValues, *pPropNames, eAlignment );
     547             : 
     548             :         //create text shape
     549           0 :         xTextShape = AbstractShapeFactory::getOrCreateShapeFactory(m_xShapeFactory)->
     550             :             createText( xTarget_, aText.makeStringAndClear()
     551           0 :                         , *pPropNames, *pPropValues, AbstractShapeFactory::makeTransformation( aScreenPosition2D ) );
     552             : 
     553           0 :         if( !xTextShape.is() )
     554           0 :             return xTextShape;
     555             : 
     556           0 :         const awt::Point aUnrotatedTextPos( xTextShape->getPosition() );
     557           0 :         if( fRotationDegrees != 0.0 )
     558             :         {
     559           0 :             const double fDegreesPi( fRotationDegrees * ( F_PI / -180.0 ) );
     560           0 :             uno::Reference< beans::XPropertySet > xProp( xTextShape, uno::UNO_QUERY );
     561           0 :             if( xProp.is() )
     562           0 :                 xProp->setPropertyValue( "Transformation", AbstractShapeFactory::makeTransformation( aScreenPosition2D, fDegreesPi ) );
     563           0 :             LabelPositionHelper::correctPositionForRotation( xTextShape, eAlignment, fRotationDegrees, true /*bRotateAroundCenter*/ );
     564             :         }
     565             : 
     566           0 :         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           0 :         }
     603             :     }
     604           0 :     catch( const uno::Exception& e )
     605             :     {
     606             :         ASSERT_EXCEPTION( e );
     607             :     }
     608             : 
     609           0 :     return xTextShape;
     610             : }
     611             : 
     612             : namespace
     613             : {
     614           0 : 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           0 :     ::rtl::math::setNan( & fResult );
     624             :     try
     625             :     {
     626           0 :         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           0 :                 double fPercent = 0;
     639           0 :                 if( xProp->getPropertyValue( bPositive
     640             :                                              ? OUString("PositiveError")
     641           0 :                                              : OUString("NegativeError") ) >>= fPercent )
     642             :                 {
     643           0 :                     if( nIndex >=0 && nIndex < rData.getLength() &&
     644           0 :                         ! ::rtl::math::isNan( rData[nIndex] ) &&
     645           0 :                         ! ::rtl::math::isNan( fPercent ))
     646             :                     {
     647           0 :                         fResult = rData[nIndex] * fPercent / 100.0;
     648             :                     }
     649             :                 }
     650             :             }
     651           0 :             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           0 :                 uno::Reference< chart2::data::XDataSource > xErrorBarData( xProp, uno::UNO_QUERY );
     687           0 :                 if( xErrorBarData.is())
     688             :                     fResult = StatisticsHelper::getErrorFromDataSource(
     689           0 :                         xErrorBarData, nIndex, bPositive, bYError);
     690             :             }
     691           0 :             break;
     692             :         }
     693             :     }
     694           0 :     catch( const uno::Exception & e )
     695             :     {
     696             :         ASSERT_EXCEPTION( e );
     697             :     }
     698             : 
     699           0 :     return fResult;
     700             : }
     701             : 
     702           0 : void lcl_AddErrorBottomLine( const drawing::Position3D& rPosition, ::basegfx::B2DVector aMainDirection
     703             :                 , drawing::PolyPolygonShape3D& rPoly, sal_Int32 nSequenceIndex )
     704             : {
     705           0 :     double fFixedWidth = 200.0;
     706             : 
     707           0 :     aMainDirection.normalize();
     708           0 :     ::basegfx::B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
     709           0 :     aOrthoDirection.normalize();
     710             : 
     711           0 :     ::basegfx::B2DVector aAnchor( rPosition.PositionX, rPosition.PositionY );
     712           0 :     ::basegfx::B2DVector aStart = aAnchor + aOrthoDirection*fFixedWidth/2.0;
     713           0 :     ::basegfx::B2DVector aEnd = aAnchor - aOrthoDirection*fFixedWidth/2.0;
     714             : 
     715           0 :     AddPointToPoly( rPoly, drawing::Position3D( aStart.getX(), aStart.getY(), rPosition.PositionZ), nSequenceIndex );
     716           0 :     AddPointToPoly( rPoly, drawing::Position3D( aEnd.getX(), aEnd.getY(), rPosition.PositionZ), nSequenceIndex );
     717           0 : }
     718             : 
     719           0 : ::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           0 :                                               , rStart.PositionY - rBottomEnd.PositionY );
     728           0 :     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           0 :     if( !aMainDirection.getLength() )
     757             :     {
     758             :         //@todo
     759             :     }
     760           0 :     return aMainDirection;
     761             : }
     762             : 
     763           0 : drawing::Position3D lcl_transformMixedToScene( PlottingPositionHelper* pPosHelper
     764             :     , double fX /*scaled*/, double fY /*unscaled*/, double fZ /*unscaled*/, bool bClip )
     765             : {
     766           0 :     if(!pPosHelper)
     767           0 :         return drawing::Position3D(0,0,0);
     768           0 :     pPosHelper->doLogicScaling( 0,&fY,&fZ );
     769           0 :     if(bClip)
     770           0 :         pPosHelper->clipScaledLogicValues( &fX,&fY,&fZ );
     771           0 :     return pPosHelper->transformScaledLogicToScene( fX, fY, fZ, false );
     772             : }
     773             : 
     774             : } // anonymous namespace
     775             : 
     776           0 : 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           0 :     if( !ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ) )
     787           0 :         return;
     788             : 
     789           0 :     if( ! xErrorBarProperties.is())
     790           0 :         return;
     791             : 
     792             :     try
     793             :     {
     794           0 :         sal_Bool bShowPositive = sal_False;
     795           0 :         sal_Bool bShowNegative = sal_False;
     796           0 :         sal_Int32 nErrorBarStyle = ::com::sun::star::chart::ErrorBarStyle::VARIANCE;
     797             : 
     798           0 :         xErrorBarProperties->getPropertyValue( "ShowPositiveError") >>= bShowPositive;
     799           0 :         xErrorBarProperties->getPropertyValue( "ShowNegativeError") >>= bShowNegative;
     800           0 :         xErrorBarProperties->getPropertyValue( "ErrorBarStyle") >>= nErrorBarStyle;
     801             : 
     802           0 :         if(!bShowPositive && !bShowNegative)
     803           0 :             return;
     804             : 
     805           0 :         if(nErrorBarStyle==::com::sun::star::chart::ErrorBarStyle::NONE)
     806           0 :             return;
     807             : 
     808           0 :         if (!m_pPosHelper)
     809           0 :             return;
     810             : 
     811           0 :         drawing::Position3D aUnscaledLogicPosition(rUnscaledLogicPosition);
     812           0 :         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           0 :         bool bCreateNegativeBorder = false;//make a vertical line at the negative end of the error bar
     821           0 :         bool bCreatePositiveBorder = false;//make a vertical line at the positive end of the error bar
     822           0 :         drawing::Position3D aMiddle(aUnscaledLogicPosition);
     823           0 :         const double fX = aUnscaledLogicPosition.PositionX;
     824           0 :         const double fY = aUnscaledLogicPosition.PositionY;
     825           0 :         const double fZ = aUnscaledLogicPosition.PositionZ;
     826           0 :         double fScaledX = fX;
     827           0 :         if( pfScaledLogicX )
     828           0 :             fScaledX = *pfScaledLogicX;
     829             :         else
     830           0 :             m_pPosHelper->doLogicScaling( &fScaledX, 0, 0 );
     831             : 
     832           0 :         aMiddle = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fY, fZ, true );
     833             : 
     834           0 :         drawing::Position3D aNegative(aMiddle);
     835           0 :         drawing::Position3D aPositive(aMiddle);
     836             : 
     837           0 :         uno::Sequence< double > aData( bYError ? rVDataSeries.getAllY() : rVDataSeries.getAllX() );
     838             : 
     839           0 :         if( bShowPositive )
     840             :         {
     841           0 :             double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, true, bYError );
     842           0 :             if( ::rtl::math::isFinite( fLength ) )
     843             :             {
     844           0 :                 double fLocalX = fX;
     845           0 :                 double fLocalY = fY;
     846           0 :                 if( bYError )
     847             :                 {
     848           0 :                     fLocalY+=fLength;
     849           0 :                     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           0 :                 bCreatePositiveBorder = m_pPosHelper->isLogicVisible(fLocalX, fLocalY, fZ);
     857             :             }
     858             :             else
     859           0 :                 bShowPositive = false;
     860             :         }
     861             : 
     862           0 :         if( bShowNegative )
     863             :         {
     864           0 :             double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, false, bYError );
     865           0 :             if( ::rtl::math::isFinite( fLength ) )
     866             :             {
     867           0 :                 double fLocalX = fX;
     868           0 :                 double fLocalY = fY;
     869           0 :                 if( bYError )
     870             :                 {
     871           0 :                     fLocalY-=fLength;
     872           0 :                     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           0 :                 bCreateNegativeBorder = m_pPosHelper->isLogicVisible( fLocalX, fLocalY, fZ);
     880             :             }
     881             :             else
     882           0 :                 bShowNegative = false;
     883             :         }
     884             : 
     885           0 :         if(!bShowPositive && !bShowNegative)
     886           0 :             return;
     887             : 
     888           0 :         drawing::PolyPolygonShape3D aPoly;
     889             : 
     890           0 :         sal_Int32 nSequenceIndex=0;
     891           0 :         if( bShowNegative )
     892           0 :             AddPointToPoly( aPoly, aNegative, nSequenceIndex );
     893           0 :         AddPointToPoly( aPoly, aMiddle, nSequenceIndex );
     894           0 :         if( bShowPositive )
     895           0 :             AddPointToPoly( aPoly, aPositive, nSequenceIndex );
     896             : 
     897           0 :         if( bShowNegative && bCreateNegativeBorder )
     898             :         {
     899           0 :             ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aNegative, m_pPosHelper, aUnscaledLogicPosition, bYError );
     900           0 :             nSequenceIndex++;
     901           0 :             lcl_AddErrorBottomLine( aNegative, aMainDirection, aPoly, nSequenceIndex );
     902             :         }
     903           0 :         if( bShowPositive && bCreatePositiveBorder )
     904             :         {
     905           0 :             ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aPositive, m_pPosHelper, aUnscaledLogicPosition, bYError );
     906           0 :             nSequenceIndex++;
     907           0 :             lcl_AddErrorBottomLine( aPositive, aMainDirection, aPoly, nSequenceIndex );
     908             :         }
     909             : 
     910           0 :         uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D( xTarget, PolyToPointSequence( aPoly) );
     911           0 :         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           0 : 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           0 :     if(m_nDimension!=2)
     948           0 :         return;
     949             :     // error bars
     950           0 :     uno::Reference< beans::XPropertySet > xErrorBarProp(rVDataSeries.getYErrorBarProperties(nPointIndex));
     951           0 :     if( xErrorBarProp.is())
     952             :     {
     953             :         uno::Reference< drawing::XShapes > xErrorBarsGroup_Shapes(
     954           0 :             this->getErrorBarsGroupShape(rVDataSeries, xTarget, true) );
     955             : 
     956             :         createErrorBar( xErrorBarsGroup_Shapes
     957             :             , rUnscaledLogicPosition, xErrorBarProp
     958             :             , rVDataSeries, nPointIndex
     959             :             , true /* bYError */
     960           0 :             , pfScaledLogicX );
     961           0 :     }
     962             : }
     963             : 
     964           0 : void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries& rVDataSeries,
     965             :                             const uno::Reference< drawing::XShapes >& xTarget,
     966             :                             const uno::Reference< drawing::XShapes >& xEquationTarget,
     967             :                             bool bMaySkipPoints )
     968             : {
     969           0 :     if(m_nDimension!=2)
     970           0 :         return;
     971           0 :     uno::Reference< XRegressionCurveContainer > xContainer( rVDataSeries.getModel(), uno::UNO_QUERY );
     972           0 :     if(!xContainer.is())
     973           0 :         return;
     974             : 
     975           0 :     if (!m_pPosHelper)
     976           0 :         return;
     977             : 
     978           0 :     uno::Sequence< uno::Reference< XRegressionCurve > > aCurveList = xContainer->getRegressionCurves();
     979             : 
     980           0 :     for(sal_Int32 nN=0; nN<aCurveList.getLength(); nN++)
     981             :     {
     982           0 :         uno::Reference< XRegressionCurveCalculator > xCalculator( aCurveList[nN]->getCalculator() );
     983           0 :         if( !xCalculator.is())
     984           0 :             continue;
     985             : 
     986           0 :         uno::Reference< beans::XPropertySet > xProperties( aCurveList[nN], uno::UNO_QUERY );
     987             : 
     988           0 :         bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurveList[nN] );
     989             : 
     990           0 :         sal_Int32 aDegree = 2;
     991           0 :         sal_Int32 aPeriod = 2;
     992           0 :         double aExtrapolateForward = 0.0;
     993           0 :         double aExtrapolateBackward = 0.0;
     994           0 :         sal_Bool aForceIntercept = false;
     995           0 :         double aInterceptValue = 0.0;
     996             : 
     997           0 :         if ( xProperties.is() && !bAverageLine )
     998             :         {
     999           0 :             xProperties->getPropertyValue( "PolynomialDegree") >>= aDegree;
    1000           0 :             xProperties->getPropertyValue( "MovingAveragePeriod") >>= aPeriod;
    1001           0 :             xProperties->getPropertyValue( "ExtrapolateForward") >>= aExtrapolateForward;
    1002           0 :             xProperties->getPropertyValue( "ExtrapolateBackward") >>= aExtrapolateBackward;
    1003           0 :             xProperties->getPropertyValue( "ForceIntercept") >>= aForceIntercept;
    1004           0 :             if (aForceIntercept)
    1005           0 :                 xProperties->getPropertyValue( "InterceptValue") >>= aInterceptValue;
    1006             :         }
    1007             : 
    1008           0 :         double fChartMinX = m_pPosHelper->getLogicMinX();
    1009           0 :         double fChartMaxX = m_pPosHelper->getLogicMaxX();
    1010             : 
    1011           0 :         double fMinX = fChartMinX;
    1012           0 :         double fMaxX = fChartMaxX;
    1013             : 
    1014           0 :         double fPointScale = 1.0;
    1015             : 
    1016           0 :         if( !bAverageLine )
    1017             :         {
    1018           0 :             rVDataSeries.getMinMaxXValue(fMinX, fMaxX);
    1019           0 :             fMaxX += aExtrapolateForward;
    1020           0 :             fMinX -= aExtrapolateBackward;
    1021             : 
    1022           0 :             fPointScale = (fMaxX - fMinX) / (fChartMaxX - fChartMinX);
    1023             :         }
    1024             : 
    1025           0 :         xCalculator->setRegressionProperties(aDegree, aForceIntercept, aInterceptValue, aPeriod);
    1026           0 :         xCalculator->recalculateRegression( rVDataSeries.getAllX(), rVDataSeries.getAllY() );
    1027           0 :         sal_Int32 nPointCount = 100 * fPointScale;
    1028             : 
    1029           0 :         if ( nPointCount < 2 )
    1030           0 :             nPointCount = 2;
    1031             : 
    1032           0 :         std::vector< ExplicitScaleData > aScales( m_pPosHelper->getScales());
    1033           0 :         uno::Reference< chart2::XScaling > xScalingX;
    1034           0 :         uno::Reference< chart2::XScaling > xScalingY;
    1035           0 :         if( aScales.size() >= 2 )
    1036             :         {
    1037           0 :             xScalingX.set( aScales[0].Scaling );
    1038           0 :             xScalingY.set( aScales[1].Scaling );
    1039             :         }
    1040             : 
    1041             :         uno::Sequence< geometry::RealPoint2D > aCalculatedPoints(
    1042           0 :             xCalculator->getCurveValues(
    1043             :                             fMinX, fMaxX, nPointCount,
    1044           0 :                             xScalingX, xScalingY, bMaySkipPoints ));
    1045             : 
    1046           0 :         nPointCount = aCalculatedPoints.getLength();
    1047             : 
    1048           0 :         drawing::PolyPolygonShape3D aRegressionPoly;
    1049           0 :         aRegressionPoly.SequenceX.realloc(1);
    1050           0 :         aRegressionPoly.SequenceY.realloc(1);
    1051           0 :         aRegressionPoly.SequenceZ.realloc(1);
    1052           0 :         aRegressionPoly.SequenceX[0].realloc(nPointCount);
    1053           0 :         aRegressionPoly.SequenceY[0].realloc(nPointCount);
    1054           0 :         aRegressionPoly.SequenceZ[0].realloc(nPointCount);
    1055             : 
    1056           0 :         sal_Int32 nRealPointCount = 0;
    1057             : 
    1058           0 :         for(sal_Int32 nP = 0; nP < aCalculatedPoints.getLength(); ++nP)
    1059             :         {
    1060           0 :             double fLogicX = aCalculatedPoints[nP].X;
    1061           0 :             double fLogicY = aCalculatedPoints[nP].Y;
    1062           0 :             double fLogicZ = 0.0; //dummy
    1063             : 
    1064             :             // fdo#51656: don't scale mean value lines
    1065           0 :             if(!bAverageLine)
    1066           0 :                 m_pPosHelper->doLogicScaling( &fLogicX, &fLogicY, &fLogicZ );
    1067             : 
    1068           0 :             if(!rtl::math::isNan(fLogicX) && !rtl::math::isInf(fLogicX) &&
    1069           0 :                !rtl::math::isNan(fLogicY) && !rtl::math::isInf(fLogicY) &&
    1070           0 :                !rtl::math::isNan(fLogicZ) && !rtl::math::isInf(fLogicZ) )
    1071             :             {
    1072           0 :                 aRegressionPoly.SequenceX[0][nRealPointCount] = fLogicX;
    1073           0 :                 aRegressionPoly.SequenceY[0][nRealPointCount] = fLogicY;
    1074           0 :                 nRealPointCount++;
    1075             :             }
    1076             :         }
    1077           0 :         aRegressionPoly.SequenceX[0].realloc(nRealPointCount);
    1078           0 :         aRegressionPoly.SequenceY[0].realloc(nRealPointCount);
    1079           0 :         aRegressionPoly.SequenceZ[0].realloc(nRealPointCount);
    1080             : 
    1081           0 :         drawing::PolyPolygonShape3D aClippedPoly;
    1082           0 :         Clipping::clipPolygonAtRectangle( aRegressionPoly, m_pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly );
    1083           0 :         aRegressionPoly = aClippedPoly;
    1084           0 :         m_pPosHelper->transformScaledLogicToScene( aRegressionPoly );
    1085             : 
    1086           0 :         awt::Point aDefaultPos;
    1087           0 :         if( aRegressionPoly.SequenceX.getLength() && aRegressionPoly.SequenceX[0].getLength() )
    1088             :         {
    1089           0 :             VLineProperties aVLineProperties;
    1090           0 :             aVLineProperties.initFromPropertySet( xProperties );
    1091             : 
    1092             :             //create an extra group shape for each curve for selection handling
    1093             :             uno::Reference< drawing::XShapes > xRegressionGroupShapes =
    1094           0 :                 createGroupShape( xTarget, rVDataSeries.getDataCurveCID( nN, bAverageLine ) );
    1095             :             uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D(
    1096           0 :                 xRegressionGroupShapes, PolyToPointSequence( aRegressionPoly ), &aVLineProperties );
    1097           0 :             AbstractShapeFactory::setShapeName( xShape, "MarkHandles" );
    1098           0 :             aDefaultPos = xShape->getPosition();
    1099             :         }
    1100             : 
    1101             :         // curve equation and correlation coefficient
    1102           0 :         uno::Reference< beans::XPropertySet > xEquationProperties( aCurveList[nN]->getEquationProperties());
    1103           0 :         if( xEquationProperties.is())
    1104             :         {
    1105             :             createRegressionCurveEquationShapes(
    1106             :                 rVDataSeries.getDataCurveEquationCID( nN ),
    1107             :                 xEquationProperties, xEquationTarget, xCalculator,
    1108           0 :                 aDefaultPos );
    1109             :         }
    1110           0 :     }
    1111             : }
    1112             : 
    1113           0 : 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           0 :     if( !xEquationProperties.is())
    1122           0 :         return;
    1123             : 
    1124           0 :     bool bShowEquation = false;
    1125           0 :     bool bShowCorrCoeff = false;
    1126           0 :     OUString aSep( "\n" );
    1127           0 :     if(( xEquationProperties->getPropertyValue( "ShowEquation") >>= bShowEquation ) &&
    1128           0 :        ( xEquationProperties->getPropertyValue( "ShowCorrelationCoefficient") >>= bShowCorrCoeff ))
    1129             :     {
    1130           0 :         if( ! (bShowEquation || bShowCorrCoeff))
    1131           0 :             return;
    1132             : 
    1133           0 :         OUStringBuffer aFormula;
    1134           0 :         sal_Int32 nNumberFormatKey = 0;
    1135           0 :         xEquationProperties->getPropertyValue( "NumberFormat") >>= nNumberFormatKey;
    1136             : 
    1137           0 :         if( bShowEquation )
    1138             :         {
    1139           0 :             if( m_apNumberFormatterWrapper.get())
    1140             :             {
    1141           0 :                 aFormula = xRegressionCurveCalculator->getFormattedRepresentation(
    1142             :                     m_apNumberFormatterWrapper->getNumberFormatsSupplier(),
    1143           0 :                     nNumberFormatKey );
    1144             :             }
    1145             :             else
    1146             :             {
    1147           0 :                 aFormula = xRegressionCurveCalculator->getRepresentation();
    1148             :             }
    1149             : 
    1150           0 :             if( bShowCorrCoeff )
    1151             :             {
    1152           0 :                 aFormula.append( aSep );
    1153             :             }
    1154             :         }
    1155           0 :         if( bShowCorrCoeff )
    1156             :         {
    1157           0 :             aFormula.append( "R" );
    1158           0 :             aFormula.append( sal_Unicode( 0x00b2 ));
    1159           0 :             aFormula.append( " = ");
    1160           0 :             double fR( xRegressionCurveCalculator->getCorrelationCoefficient());
    1161           0 :             if( m_apNumberFormatterWrapper.get())
    1162             :             {
    1163           0 :                 sal_Int32 nLabelCol = 0;
    1164             :                 bool bColChanged;
    1165             :                 aFormula.append(
    1166             :                     m_apNumberFormatterWrapper->getFormattedString(
    1167           0 :                         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           0 :         awt::Point aScreenPosition2D;
    1179           0 :         chart2::RelativePosition aRelativePosition;
    1180           0 :         if( xEquationProperties->getPropertyValue( "RelativePosition") >>= aRelativePosition )
    1181             :         {
    1182             :             //@todo decide whether x is primary or secondary
    1183           0 :             double fX = aRelativePosition.Primary*m_aPageReferenceSize.Width;
    1184           0 :             double fY = aRelativePosition.Secondary*m_aPageReferenceSize.Height;
    1185           0 :             aScreenPosition2D.X = static_cast< sal_Int32 >( ::rtl::math::round( fX ));
    1186           0 :             aScreenPosition2D.Y = static_cast< sal_Int32 >( ::rtl::math::round( fY ));
    1187             :         }
    1188             :         else
    1189           0 :             aScreenPosition2D = aDefaultPos;
    1190             : 
    1191           0 :         if( !aFormula.isEmpty())
    1192             :         {
    1193             :             // set fill and line properties on creation
    1194           0 :             tNameSequence aNames;
    1195           0 :             tAnySequence  aValues;
    1196           0 :             PropertyMapper::getPreparedTextShapePropertyLists( xEquationProperties, aNames, aValues );
    1197             : 
    1198             :             uno::Reference< drawing::XShape > xTextShape = m_pShapeFactory->createText(
    1199             :                 xEquationTarget, aFormula.makeStringAndClear(),
    1200           0 :                 aNames, aValues, AbstractShapeFactory::makeTransformation( aScreenPosition2D ));
    1201             : 
    1202             :             OSL_ASSERT( xTextShape.is());
    1203           0 :             if( xTextShape.is())
    1204             :             {
    1205           0 :                 AbstractShapeFactory::setShapeName( xTextShape, rEquationCID );
    1206           0 :                 awt::Size aSize( xTextShape->getSize() );
    1207             :                 awt::Point aPos( RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
    1208           0 :                     aScreenPosition2D, aSize, aRelativePosition.Anchor ) );
    1209             :                 //ensure that the equation is fully placed within the page (if possible)
    1210           0 :                 if( (aPos.X + aSize.Width) > m_aPageReferenceSize.Width )
    1211           0 :                     aPos.X = m_aPageReferenceSize.Width - aSize.Width;
    1212           0 :                 if( aPos.X < 0 )
    1213           0 :                     aPos.X = 0;
    1214           0 :                 if( (aPos.Y + aSize.Height) > m_aPageReferenceSize.Height )
    1215           0 :                     aPos.Y = m_aPageReferenceSize.Height - aSize.Height;
    1216           0 :                 if( aPos.Y < 0 )
    1217           0 :                     aPos.Y = 0;
    1218           0 :                 xTextShape->setPosition(aPos);
    1219           0 :             }
    1220           0 :         }
    1221           0 :     }
    1222             : }
    1223             : 
    1224           0 : 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           0 :     uno::Reference< beans::XPropertySet > xTargetProp( xTargetShape, uno::UNO_QUERY );
    1231           0 :     PropertyMapper::setMappedProperties(xTargetProp,xSource,rMap,pOverwriteMap);
    1232           0 : }
    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           0 : double VSeriesPlotter::getMinimumX()
    1277             : {
    1278             :     double fMinimum, fMaximum;
    1279           0 :     this->getMinimumAndMaximiumX( fMinimum, fMaximum );
    1280           0 :     return fMinimum;
    1281             : }
    1282           0 : double VSeriesPlotter::getMaximumX()
    1283             : {
    1284             :     double fMinimum, fMaximum;
    1285           0 :     this->getMinimumAndMaximiumX( fMinimum, fMaximum );
    1286           0 :     return fMaximum;
    1287             : }
    1288             : 
    1289           0 : double VSeriesPlotter::getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex )
    1290             : {
    1291           0 :     if( !m_bCategoryXAxis || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) )
    1292             :     {
    1293             :         double fMinY, fMaxY;
    1294           0 :         this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
    1295           0 :         return fMinY;
    1296             :     }
    1297             : 
    1298             :     double fMinimum, fMaximum;
    1299           0 :     ::rtl::math::setInf(&fMinimum, false);
    1300           0 :     ::rtl::math::setInf(&fMaximum, true);
    1301           0 :     for(size_t nZ =0; nZ<m_aZSlots.size();nZ++ )
    1302             :     {
    1303           0 :         ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[nZ];
    1304           0 :         for(size_t nN =0; nN<rXSlots.size();nN++ )
    1305             :         {
    1306             :             double fLocalMinimum, fLocalMaximum;
    1307           0 :             rXSlots[nN].calculateYMinAndMaxForCategoryRange(
    1308           0 :                                 static_cast<sal_Int32>(fMinimumX-1.0) //first category (index 0) matches with real number 1.0
    1309           0 :                                 , static_cast<sal_Int32>(fMaximumX-1.0) //first category (index 0) matches with real number 1.0
    1310           0 :                                 , isSeparateStackingForDifferentSigns( 1 )
    1311           0 :                                 , fLocalMinimum, fLocalMaximum, nAxisIndex );
    1312           0 :             if(fMaximum<fLocalMaximum)
    1313           0 :                 fMaximum=fLocalMaximum;
    1314           0 :             if(fMinimum>fLocalMinimum)
    1315           0 :                 fMinimum=fLocalMinimum;
    1316             :         }
    1317             :     }
    1318           0 :     if(::rtl::math::isInf(fMinimum))
    1319           0 :         ::rtl::math::setNan(&fMinimum);
    1320           0 :     return fMinimum;
    1321             : }
    1322             : 
    1323           0 : double VSeriesPlotter::getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex )
    1324             : {
    1325           0 :     if( !m_bCategoryXAxis || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) )
    1326             :     {
    1327             :         double fMinY, fMaxY;
    1328           0 :         this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
    1329           0 :         return fMaxY;
    1330             :     }
    1331             : 
    1332             :     double fMinimum, fMaximum;
    1333           0 :     ::rtl::math::setInf(&fMinimum, false);
    1334           0 :     ::rtl::math::setInf(&fMaximum, true);
    1335           0 :     for(size_t nZ =0; nZ<m_aZSlots.size();nZ++ )
    1336             :     {
    1337           0 :         ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[nZ];
    1338           0 :         for(size_t nN =0; nN<rXSlots.size();nN++ )
    1339             :         {
    1340             :             double fLocalMinimum, fLocalMaximum;
    1341           0 :             rXSlots[nN].calculateYMinAndMaxForCategoryRange(
    1342           0 :                                 static_cast<sal_Int32>(fMinimumX-1.0) //first category (index 0) matches with real number 1.0
    1343           0 :                                 , static_cast<sal_Int32>(fMaximumX-1.0) //first category (index 0) matches with real number 1.0
    1344           0 :                                 , isSeparateStackingForDifferentSigns( 1 )
    1345           0 :                                 , fLocalMinimum, fLocalMaximum, nAxisIndex );
    1346           0 :             if(fMaximum<fLocalMaximum)
    1347           0 :                 fMaximum=fLocalMaximum;
    1348           0 :             if(fMinimum>fLocalMinimum)
    1349           0 :                 fMinimum=fLocalMinimum;
    1350             :         }
    1351             :     }
    1352           0 :     if(::rtl::math::isInf(fMaximum))
    1353           0 :         ::rtl::math::setNan(&fMaximum);
    1354           0 :     return fMaximum;
    1355             : }
    1356             : 
    1357           0 : double VSeriesPlotter::getMinimumZ()
    1358             : {
    1359             :     //this is the default for all charts without a meaningfull z axis
    1360           0 :     return 1.0;
    1361             : }
    1362           0 : double VSeriesPlotter::getMaximumZ()
    1363             : {
    1364           0 :     if( 3!=m_nDimension || !m_aZSlots.size() )
    1365           0 :         return getMinimumZ()+1;
    1366           0 :     return m_aZSlots.size();
    1367             : }
    1368             : 
    1369             : namespace
    1370             : {
    1371           0 :     bool lcl_isValueAxis( sal_Int32 nDimensionIndex, bool bCategoryXAxis )
    1372             :     {
    1373             :         // default implementation: true for Y axes, and for value X axis
    1374           0 :         if( nDimensionIndex == 0 )
    1375           0 :             return !bCategoryXAxis;
    1376           0 :         if( nDimensionIndex == 1 )
    1377           0 :             return true;
    1378           0 :         return false;
    1379             :     }
    1380             : }
    1381             : 
    1382           0 : bool VSeriesPlotter::isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex )
    1383             : {
    1384           0 :     return lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis );
    1385             : }
    1386             : 
    1387           0 : bool VSeriesPlotter::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex )
    1388             : {
    1389             :     // do not expand axes in 3D charts
    1390           0 :     return (m_nDimension < 3) && lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis );
    1391             : }
    1392             : 
    1393           0 : bool VSeriesPlotter::isExpandWideValuesToZero( sal_Int32 nDimensionIndex )
    1394             : {
    1395             :     // default implementation: only for Y axis
    1396           0 :     return nDimensionIndex == 1;
    1397             : }
    1398             : 
    1399           0 : bool VSeriesPlotter::isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex )
    1400             : {
    1401             :     // default implementation: only for Y axis
    1402           0 :     return nDimensionIndex == 1;
    1403             : }
    1404             : 
    1405           0 : bool VSeriesPlotter::isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex )
    1406             : {
    1407             :     // default implementation: only for Y axis
    1408           0 :     return nDimensionIndex == 1;
    1409             : }
    1410             : 
    1411           0 : void VSeriesPlotter::getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const
    1412             : {
    1413           0 :     ::rtl::math::setInf(&rfMinimum, false);
    1414           0 :     ::rtl::math::setInf(&rfMaximum, true);
    1415             : 
    1416           0 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator       aZSlotIter = m_aZSlots.begin();
    1417           0 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
    1418           0 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1419             :     {
    1420           0 :         ::std::vector< VDataSeriesGroup >::const_iterator      aXSlotIter = aZSlotIter->begin();
    1421           0 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    1422           0 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
    1423             :         {
    1424             :             double fLocalMinimum, fLocalMaximum;
    1425           0 :             aXSlotIter->getMinimumAndMaximiumX( fLocalMinimum, fLocalMaximum );
    1426           0 :             if( !::rtl::math::isNan(fLocalMinimum) && fLocalMinimum< rfMinimum )
    1427           0 :                 rfMinimum = fLocalMinimum;
    1428           0 :             if( !::rtl::math::isNan(fLocalMaximum) && fLocalMaximum> rfMaximum )
    1429           0 :                 rfMaximum = fLocalMaximum;
    1430             :         }
    1431             :     }
    1432           0 :     if(::rtl::math::isInf(rfMinimum))
    1433           0 :         ::rtl::math::setNan(&rfMinimum);
    1434           0 :     if(::rtl::math::isInf(rfMaximum))
    1435           0 :         ::rtl::math::setNan(&rfMaximum);
    1436           0 : }
    1437             : 
    1438           0 : void VSeriesPlotter::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const
    1439             : {
    1440           0 :     ::rtl::math::setInf(&rfMinY, false);
    1441           0 :     ::rtl::math::setInf(&rfMaxY, true);
    1442             : 
    1443           0 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator       aZSlotIter = m_aZSlots.begin();
    1444           0 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
    1445           0 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1446             :     {
    1447           0 :         ::std::vector< VDataSeriesGroup >::const_iterator      aXSlotIter = aZSlotIter->begin();
    1448           0 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    1449           0 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
    1450             :         {
    1451             :             double fLocalMinimum, fLocalMaximum;
    1452           0 :             aXSlotIter->getMinimumAndMaximiumYInContinuousXRange( fLocalMinimum, fLocalMaximum, fMinX, fMaxX, nAxisIndex );
    1453           0 :             if( !::rtl::math::isNan(fLocalMinimum) && fLocalMinimum< rfMinY )
    1454           0 :                 rfMinY = fLocalMinimum;
    1455           0 :             if( !::rtl::math::isNan(fLocalMaximum) && fLocalMaximum> rfMaxY )
    1456           0 :                 rfMaxY = fLocalMaximum;
    1457             :         }
    1458             :     }
    1459           0 :     if(::rtl::math::isInf(rfMinY))
    1460           0 :         ::rtl::math::setNan(&rfMinY);
    1461           0 :     if(::rtl::math::isInf(rfMaxY))
    1462           0 :         ::rtl::math::setNan(&rfMaxY);
    1463           0 : }
    1464             : 
    1465           0 : sal_Int32 VSeriesPlotter::getPointCount() const
    1466             : {
    1467           0 :     sal_Int32 nRet = 0;
    1468             : 
    1469           0 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator       aZSlotIter = m_aZSlots.begin();
    1470           0 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
    1471             : 
    1472           0 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1473             :     {
    1474           0 :         ::std::vector< VDataSeriesGroup >::const_iterator       aXSlotIter = aZSlotIter->begin();
    1475           0 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    1476             : 
    1477           0 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
    1478             :         {
    1479           0 :             sal_Int32 nPointCount = aXSlotIter->getPointCount();
    1480           0 :             if( nPointCount>nRet )
    1481           0 :                 nRet = nPointCount;
    1482             :         }
    1483             :     }
    1484           0 :     return nRet;
    1485             : }
    1486             : 
    1487           0 : void VSeriesPlotter::setNumberFormatsSupplier(
    1488             :     const uno::Reference< util::XNumberFormatsSupplier > & xNumFmtSupplier )
    1489             : {
    1490           0 :     m_apNumberFormatterWrapper.reset( new NumberFormatterWrapper( xNumFmtSupplier ));
    1491           0 : }
    1492             : 
    1493           0 : void VSeriesPlotter::setColorScheme( const uno::Reference< XColorScheme >& xColorScheme )
    1494             : {
    1495           0 :     m_xColorScheme = xColorScheme;
    1496           0 : }
    1497             : 
    1498           0 : void VSeriesPlotter::setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider )
    1499             : {
    1500           0 :     m_pExplicitCategoriesProvider = pExplicitCategoriesProvider;
    1501           0 : }
    1502             : 
    1503           0 : sal_Int32 VDataSeriesGroup::getPointCount() const
    1504             : {
    1505           0 :     if(!m_bMaxPointCountDirty)
    1506           0 :         return m_nMaxPointCount;
    1507             : 
    1508           0 :     sal_Int32 nRet = 0;
    1509           0 :     ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = m_aSeriesVector.begin();
    1510           0 :     const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
    1511             : 
    1512           0 :     for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter)
    1513             :     {
    1514           0 :         sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount();
    1515           0 :         if( nPointCount>nRet )
    1516           0 :             nRet = nPointCount;
    1517             :     }
    1518           0 :     m_nMaxPointCount=nRet;
    1519           0 :     m_aListOfCachedYValues.clear();
    1520           0 :     m_aListOfCachedYValues.resize(m_nMaxPointCount);
    1521           0 :     m_bMaxPointCountDirty=false;
    1522           0 :     return nRet;
    1523             : }
    1524             : 
    1525           0 : sal_Int32 VDataSeriesGroup::getAttachedAxisIndexForFirstSeries() const
    1526             : {
    1527           0 :     sal_Int32 nRet = 0;
    1528           0 :     ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = m_aSeriesVector.begin();
    1529           0 :     const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
    1530             : 
    1531           0 :     if( aSeriesIter != aSeriesEnd )
    1532           0 :         nRet = (*aSeriesIter)->getAttachedAxisIndex();
    1533             : 
    1534           0 :     return nRet;
    1535             : }
    1536             : 
    1537           0 : void VDataSeriesGroup::getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const
    1538             : {
    1539           0 :     const ::std::vector< VDataSeries* >* pSeriesList = &this->m_aSeriesVector;
    1540             : 
    1541           0 :     ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = pSeriesList->begin();
    1542           0 :     const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
    1543             : 
    1544           0 :     ::rtl::math::setInf(&rfMinimum, false);
    1545           0 :     ::rtl::math::setInf(&rfMaximum, true);
    1546             : 
    1547           0 :     for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
    1548             :     {
    1549           0 :         sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount();
    1550           0 :         for(sal_Int32 nN=0;nN<nPointCount;nN++)
    1551             :         {
    1552           0 :             double fX = (*aSeriesIter)->getXValue( nN );
    1553           0 :             if( ::rtl::math::isNan(fX) )
    1554           0 :                 continue;
    1555           0 :             if(rfMaximum<fX)
    1556           0 :                 rfMaximum=fX;
    1557           0 :             if(rfMinimum>fX)
    1558           0 :                 rfMinimum=fX;
    1559             :         }
    1560             :     }
    1561           0 :     if(::rtl::math::isInf(rfMinimum))
    1562           0 :         ::rtl::math::setNan(&rfMinimum);
    1563           0 :     if(::rtl::math::isInf(rfMaximum))
    1564           0 :         ::rtl::math::setNan(&rfMaximum);
    1565           0 : }
    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           0 : 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           0 :     PerXMinMaxCalculator() : mnCurSeries(0) {}
    1594             : 
    1595           0 :     void nextSeries() { ++mnCurSeries; }
    1596             : 
    1597           0 :     void setValue(double fX, double fY)
    1598             :     {
    1599           0 :         SeriesMinMaxType* pStore = getByXValue(fX); // get storage for given X value.
    1600           0 :         if (!pStore)
    1601             :             // This shouldn't happen!
    1602           0 :             return;
    1603             : 
    1604           0 :         SeriesMinMaxType::iterator it = pStore->lower_bound(mnCurSeries);
    1605           0 :         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           0 :                     mnCurSeries, MinMaxType(fY,fY)));
    1620             :         }
    1621             :     }
    1622             : 
    1623           0 :     void getTotalRange(double& rfMin, double& rfMax) const
    1624             :     {
    1625           0 :         rtl::math::setNan(&rfMin);
    1626           0 :         rtl::math::setNan(&rfMax);
    1627             : 
    1628           0 :         TotalStoreType aStore;
    1629           0 :         getTotalStore(aStore);
    1630             : 
    1631           0 :         if (aStore.empty())
    1632           0 :             return;
    1633             : 
    1634           0 :         TotalStoreType::const_iterator it = aStore.begin(), itEnd = aStore.end();
    1635           0 :         rfMin = it->second.first;
    1636           0 :         rfMax = it->second.second;
    1637           0 :         for (++it; it != itEnd; ++it)
    1638             :         {
    1639           0 :             if (rfMin > it->second.first)
    1640           0 :                 rfMin = it->second.first;
    1641           0 :             if (rfMax < it->second.second)
    1642           0 :                 rfMax = it->second.second;
    1643           0 :         }
    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           0 :     void getTotalStore(TotalStoreType& rStore) const
    1652             :     {
    1653           0 :         TotalStoreType aStore;
    1654           0 :         GroupMinMaxType::const_iterator it = maSeriesGroup.begin(), itEnd = maSeriesGroup.end();
    1655           0 :         for (; it != itEnd; ++it)
    1656             :         {
    1657           0 :             double fX = it->first;
    1658             : 
    1659           0 :             const SeriesMinMaxType& rSeries = *it->second;
    1660           0 :             SeriesMinMaxType::const_iterator itSeries = rSeries.begin(), itSeriesEnd = rSeries.end();
    1661           0 :             for (; itSeries != itSeriesEnd; ++itSeries)
    1662             :             {
    1663           0 :                 double fYMin = itSeries->second.first, fYMax = itSeries->second.second;
    1664           0 :                 TotalStoreType::iterator itr = aStore.find(fX);
    1665           0 :                 if (itr == aStore.end())
    1666             :                     // New min-max pair for give X value.
    1667             :                     aStore.insert(
    1668           0 :                         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           0 :         rStore.swap(aStore);
    1680           0 :     }
    1681             : 
    1682           0 :     SeriesMinMaxType* getByXValue(double fX)
    1683             :     {
    1684           0 :         GroupMinMaxType::iterator it = maSeriesGroup.find(fX);
    1685           0 :         if (it == maSeriesGroup.end())
    1686             :         {
    1687             :             std::pair<GroupMinMaxType::iterator,bool> r =
    1688           0 :                 maSeriesGroup.insert(fX, new SeriesMinMaxType);
    1689             : 
    1690           0 :             if (!r.second)
    1691             :                 // insertion failed.
    1692           0 :                 return NULL;
    1693             : 
    1694           0 :             it = r.first;
    1695             :         }
    1696             : 
    1697           0 :         return it->second;
    1698             :     }
    1699             : };
    1700             : 
    1701             : }
    1702             : 
    1703           0 : void VDataSeriesGroup::getMinimumAndMaximiumYInContinuousXRange(
    1704             :     double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const
    1705             : {
    1706           0 :     ::rtl::math::setNan(&rfMinY);
    1707           0 :     ::rtl::math::setNan(&rfMaxY);
    1708             : 
    1709           0 :     if (m_aSeriesVector.empty())
    1710             :         // No data series.  Bail out.
    1711           0 :         return;
    1712             : 
    1713           0 :     PerXMinMaxCalculator aRangeCalc;
    1714           0 :     std::vector<VDataSeries*>::const_iterator it = m_aSeriesVector.begin(), itEnd = m_aSeriesVector.end();
    1715           0 :     for (; it != itEnd; ++it)
    1716             :     {
    1717           0 :         const VDataSeries* pSeries = *it;
    1718           0 :         if (!pSeries)
    1719           0 :             continue;
    1720             : 
    1721           0 :         for (sal_Int32 i = 0, n = pSeries->getTotalPointCount(); i < n; ++i)
    1722             :         {
    1723           0 :             if (nAxisIndex != pSeries->getAttachedAxisIndex())
    1724           0 :                 continue;
    1725             : 
    1726           0 :             double fX = pSeries->getXValue(i);
    1727           0 :             if (rtl::math::isNan(fX))
    1728           0 :                 continue;
    1729             : 
    1730           0 :             if (fX < fMinX || fX > fMaxX)
    1731             :                 // Outside specified X range.  Skip it.
    1732           0 :                 continue;
    1733             : 
    1734           0 :             double fY = pSeries->getYValue(i);
    1735           0 :             if (::rtl::math::isNan(fY))
    1736           0 :                 continue;
    1737             : 
    1738           0 :             aRangeCalc.setValue(fX, fY);
    1739             :         }
    1740           0 :         aRangeCalc.nextSeries();
    1741             :     }
    1742             : 
    1743           0 :     aRangeCalc.getTotalRange(rfMinY, rfMaxY);
    1744             : }
    1745             : 
    1746           0 : void VDataSeriesGroup::calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
    1747             :         , bool bSeparateStackingForDifferentSigns
    1748             :         , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex )
    1749             : {
    1750           0 :     ::rtl::math::setInf(&rfMinimumY, false);
    1751           0 :     ::rtl::math::setInf(&rfMaximumY, true);
    1752             : 
    1753           0 :     sal_Int32 nPointCount = getPointCount();//necessary to create m_aListOfCachedYValues
    1754           0 :     if(nCategoryIndex<0 || nCategoryIndex>=nPointCount || m_aSeriesVector.empty())
    1755           0 :         return;
    1756             : 
    1757           0 :     CachedYValues aCachedYValues = m_aListOfCachedYValues[nCategoryIndex][nAxisIndex];
    1758           0 :     if( !aCachedYValues.m_bValuesDirty )
    1759             :     {
    1760             :         //return cached values
    1761           0 :         rfMinimumY = aCachedYValues.m_fMinimumY;
    1762           0 :         rfMaximumY = aCachedYValues.m_fMaximumY;
    1763           0 :         return;
    1764             :     }
    1765             : 
    1766             :     double fTotalSum, fPositiveSum, fNegativeSum, fFirstPositiveY, fFirstNegativeY;
    1767           0 :     ::rtl::math::setNan( &fTotalSum );
    1768           0 :     ::rtl::math::setNan( &fPositiveSum );
    1769           0 :     ::rtl::math::setNan( &fNegativeSum );
    1770           0 :     ::rtl::math::setNan( &fFirstPositiveY );
    1771           0 :     ::rtl::math::setNan( &fFirstNegativeY );
    1772             : 
    1773           0 :     ::std::vector< VDataSeries* >::const_iterator aSeriesIter = m_aSeriesVector.begin();
    1774           0 :     ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = m_aSeriesVector.end();
    1775             : 
    1776           0 :     if( bSeparateStackingForDifferentSigns )
    1777             :     {
    1778           0 :         for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
    1779             :         {
    1780           0 :             if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
    1781           0 :                 continue;
    1782             : 
    1783           0 :             double fValueMinY = (*aSeriesIter)->getMinimumofAllDifferentYValues( nCategoryIndex );
    1784           0 :             double fValueMaxY = (*aSeriesIter)->getMaximumofAllDifferentYValues( nCategoryIndex );
    1785             : 
    1786           0 :             if( fValueMaxY >= 0 )
    1787             :             {
    1788           0 :                 if( ::rtl::math::isNan( fPositiveSum ) )
    1789           0 :                     fPositiveSum = fFirstPositiveY = fValueMaxY;
    1790             :                 else
    1791           0 :                     fPositiveSum += fValueMaxY;
    1792             :             }
    1793           0 :             if( fValueMinY < 0 )
    1794             :             {
    1795           0 :                 if(::rtl::math::isNan( fNegativeSum ))
    1796           0 :                     fNegativeSum = fFirstNegativeY = fValueMinY;
    1797             :                 else
    1798           0 :                     fNegativeSum += fValueMinY;
    1799             :             }
    1800             :         }
    1801           0 :         rfMinimumY = ::rtl::math::isNan( fNegativeSum ) ? fFirstPositiveY : fNegativeSum;
    1802           0 :         rfMaximumY = ::rtl::math::isNan( fPositiveSum ) ? fFirstNegativeY : fPositiveSum;
    1803             :     }
    1804             :     else
    1805             :     {
    1806           0 :         for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
    1807             :         {
    1808           0 :             if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
    1809           0 :                 continue;
    1810             : 
    1811           0 :             double fValueMinY = (*aSeriesIter)->getMinimumofAllDifferentYValues( nCategoryIndex );
    1812           0 :             double fValueMaxY = (*aSeriesIter)->getMaximumofAllDifferentYValues( nCategoryIndex );
    1813             : 
    1814           0 :             if( ::rtl::math::isNan( fTotalSum ) )
    1815             :             {
    1816           0 :                 rfMinimumY = fValueMinY;
    1817           0 :                 rfMaximumY = fTotalSum = fValueMaxY;
    1818             :             }
    1819             :             else
    1820             :             {
    1821           0 :                 fTotalSum += fValueMaxY;
    1822           0 :                 if( rfMinimumY > fTotalSum )
    1823           0 :                     rfMinimumY = fTotalSum;
    1824           0 :                 if( rfMaximumY < fTotalSum )
    1825           0 :                     rfMaximumY = fTotalSum;
    1826             :             }
    1827             :         }
    1828             :     }
    1829             : 
    1830           0 :     aCachedYValues.m_fMinimumY = rfMinimumY;
    1831           0 :     aCachedYValues.m_fMaximumY = rfMaximumY;
    1832           0 :     aCachedYValues.m_bValuesDirty = false;
    1833           0 :     m_aListOfCachedYValues[nCategoryIndex][nAxisIndex]=aCachedYValues;
    1834             : }
    1835             : 
    1836           0 : 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           0 :     ::rtl::math::setInf(&rfMinimumY, false);
    1843           0 :     ::rtl::math::setInf(&rfMaximumY, true);
    1844             : 
    1845             :     //iterate through the given categories
    1846           0 :     if(nStartCategoryIndex<0)
    1847           0 :         nStartCategoryIndex=0;
    1848           0 :     if(nEndCategoryIndex<0)
    1849           0 :         nEndCategoryIndex=0;
    1850           0 :     for( sal_Int32 nCatIndex = nStartCategoryIndex; nCatIndex <= nEndCategoryIndex; nCatIndex++ )
    1851             :     {
    1852           0 :         double fMinimumY; ::rtl::math::setNan(&fMinimumY);
    1853           0 :         double fMaximumY; ::rtl::math::setNan(&fMaximumY);
    1854             : 
    1855             :         this->calculateYMinAndMaxForCategory( nCatIndex
    1856           0 :             , bSeparateStackingForDifferentSigns, fMinimumY, fMaximumY, nAxisIndex );
    1857             : 
    1858           0 :         if(rfMinimumY > fMinimumY)
    1859           0 :             rfMinimumY = fMinimumY;
    1860           0 :         if(rfMaximumY < fMaximumY)
    1861           0 :             rfMaximumY = fMaximumY;
    1862             :     }
    1863           0 : }
    1864             : 
    1865           0 : double VSeriesPlotter::getTransformedDepth() const
    1866             : {
    1867           0 :     double MinZ = m_pMainPosHelper->getLogicMinZ();
    1868           0 :     double MaxZ = m_pMainPosHelper->getLogicMaxZ();
    1869           0 :     m_pMainPosHelper->doLogicScaling( 0, 0, &MinZ );
    1870           0 :     m_pMainPosHelper->doLogicScaling( 0, 0, &MaxZ );
    1871           0 :     return FIXED_SIZE_FOR_3D_CHART_VOLUME/(MaxZ-MinZ);
    1872             : }
    1873             : 
    1874           0 : void VSeriesPlotter::addSecondaryValueScale( const ExplicitScaleData& rScale, sal_Int32 nAxisIndex )
    1875             :                 throw (uno::RuntimeException)
    1876             : {
    1877           0 :     if( nAxisIndex<1 )
    1878           0 :         return;
    1879             : 
    1880           0 :     m_aSecondaryValueScales[nAxisIndex]=rScale;
    1881             : }
    1882             : 
    1883           0 : PlottingPositionHelper& VSeriesPlotter::getPlottingPositionHelper( sal_Int32 nAxisIndex ) const
    1884             : {
    1885           0 :     PlottingPositionHelper* pRet = 0;
    1886           0 :     if(nAxisIndex>0)
    1887             :     {
    1888           0 :         tSecondaryPosHelperMap::const_iterator aPosIt = m_aSecondaryPosHelperMap.find( nAxisIndex );
    1889           0 :         if( aPosIt != m_aSecondaryPosHelperMap.end() )
    1890             :         {
    1891           0 :             pRet = aPosIt->second;
    1892             :         }
    1893           0 :         else if (m_pPosHelper)
    1894             :         {
    1895           0 :             tSecondaryValueScales::const_iterator aScaleIt = m_aSecondaryValueScales.find( nAxisIndex );
    1896           0 :             if( aScaleIt != m_aSecondaryValueScales.end() )
    1897             :             {
    1898           0 :                 pRet = m_pPosHelper->createSecondaryPosHelper( aScaleIt->second );
    1899           0 :                 m_aSecondaryPosHelperMap[nAxisIndex] = pRet;
    1900             :             }
    1901             :         }
    1902             :     }
    1903           0 :     if( !pRet )
    1904           0 :         pRet = m_pMainPosHelper;
    1905           0 :     if(pRet)
    1906           0 :         pRet->setTimeResolution( m_nTimeResolution, m_aNullDate );
    1907           0 :     return *pRet;
    1908             : }
    1909             : 
    1910           0 : void VSeriesPlotter::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& /*rPageSize*/ )
    1911             : {
    1912           0 : }
    1913             : 
    1914           0 : VDataSeries* VSeriesPlotter::getFirstSeries() const
    1915             : {
    1916           0 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter( m_aZSlots.begin() );
    1917           0 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd( m_aZSlots.end() );
    1918           0 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1919             :     {
    1920           0 :         ::std::vector< VDataSeriesGroup >::const_iterator       aXSlotIter = aZSlotIter->begin();
    1921           0 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd  = aZSlotIter->end();
    1922             : 
    1923           0 :         if( aXSlotIter != aXSlotEnd )
    1924             :         {
    1925           0 :             VDataSeriesGroup aSeriesGroup( *aXSlotIter );
    1926           0 :             if( aSeriesGroup.m_aSeriesVector.size() )
    1927             :             {
    1928           0 :                 VDataSeries* pSeries = aSeriesGroup.m_aSeriesVector[0];
    1929           0 :                 if(pSeries)
    1930           0 :                     return pSeries;
    1931           0 :             }
    1932             :         }
    1933             :     }
    1934           0 :     return 0;
    1935             : }
    1936             : 
    1937           0 : uno::Sequence< OUString > VSeriesPlotter::getSeriesNames() const
    1938             : {
    1939           0 :     ::std::vector< OUString > aRetVector;
    1940             : 
    1941           0 :     OUString aRole;
    1942           0 :     if( m_xChartTypeModel.is() )
    1943           0 :         aRole = m_xChartTypeModel->getRoleOfSequenceForSeriesLabel();
    1944             : 
    1945           0 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter( m_aZSlots.begin() );
    1946           0 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd( m_aZSlots.end() );
    1947           0 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    1948             :     {
    1949           0 :         ::std::vector< VDataSeriesGroup >::const_iterator       aXSlotIter = aZSlotIter->begin();
    1950           0 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd  = aZSlotIter->end();
    1951             : 
    1952           0 :         if( aXSlotIter != aXSlotEnd )
    1953             :         {
    1954           0 :             VDataSeriesGroup aSeriesGroup( *aXSlotIter );
    1955           0 :             if( aSeriesGroup.m_aSeriesVector.size() )
    1956             :             {
    1957           0 :                 VDataSeries* pSeries = aSeriesGroup.m_aSeriesVector[0];
    1958           0 :                 uno::Reference< XDataSeries > xSeries( pSeries ? pSeries->getModel() : 0 );
    1959           0 :                 if( xSeries.is() )
    1960             :                 {
    1961           0 :                     OUString aSeriesName( DataSeriesHelper::getDataSeriesLabel( xSeries, aRole ) );
    1962           0 :                     aRetVector.push_back( aSeriesName );
    1963           0 :                 }
    1964           0 :             }
    1965             :         }
    1966             :     }
    1967           0 :     return ContainerHelper::ContainerToSequence( aRetVector );
    1968             : }
    1969             : 
    1970             : namespace
    1971             : {
    1972             : struct lcl_setRefSizeAtSeriesGroup : public ::std::unary_function< VDataSeriesGroup, void >
    1973             : {
    1974           0 :     lcl_setRefSizeAtSeriesGroup( awt::Size aRefSize ) : m_aRefSize( aRefSize ) {}
    1975           0 :     void operator()( VDataSeriesGroup & rGroup )
    1976             :     {
    1977           0 :         ::std::vector< VDataSeries* >::iterator aIt( rGroup.m_aSeriesVector.begin());
    1978           0 :         const ::std::vector< VDataSeries* >::iterator aEndIt( rGroup.m_aSeriesVector.end());
    1979           0 :         for( ; aIt != aEndIt; ++aIt )
    1980           0 :             (*aIt)->setPageReferenceSize( m_aRefSize );
    1981           0 :     }
    1982             : 
    1983             : private:
    1984             :     awt::Size m_aRefSize;
    1985             : };
    1986             : } // anonymous namespace
    1987             : 
    1988           0 : void VSeriesPlotter::setPageReferenceSize( const ::com::sun::star::awt::Size & rPageRefSize )
    1989             : {
    1990           0 :     m_aPageReferenceSize = rPageRefSize;
    1991             : 
    1992             :     // set reference size also at all data series
    1993             : 
    1994           0 :     ::std::vector< VDataSeriesGroup > aSeriesGroups( FlattenVector( m_aZSlots ));
    1995             :     ::std::for_each( aSeriesGroups.begin(), aSeriesGroups.end(),
    1996           0 :                      lcl_setRefSizeAtSeriesGroup( m_aPageReferenceSize ));
    1997           0 : }
    1998             : 
    1999             : //better performance for big data
    2000           0 : void VSeriesPlotter::setCoordinateSystemResolution( const Sequence< sal_Int32 >& rCoordinateSystemResolution )
    2001             : {
    2002           0 :     m_aCoordinateSystemResolution = rCoordinateSystemResolution;
    2003           0 : }
    2004             : 
    2005           0 : bool VSeriesPlotter::PointsWereSkipped() const
    2006             : {
    2007           0 :     return m_bPointsWereSkipped;
    2008             : }
    2009             : 
    2010           0 : bool VSeriesPlotter::WantToPlotInFrontOfAxisLine()
    2011             : {
    2012           0 :     return ChartTypeHelper::isSeriesInFrontOfAxisLine( m_xChartTypeModel );
    2013             : }
    2014             : 
    2015           0 : bool VSeriesPlotter::shouldSnapRectToUsedArea()
    2016             : {
    2017           0 :     if( m_nDimension == 3 )
    2018           0 :         return false;
    2019           0 :     return true;
    2020             : }
    2021             : 
    2022           0 : 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           0 :     std::vector< ViewLegendEntry > aResult;
    2032             : 
    2033           0 :     if( xTarget.is() )
    2034             :     {
    2035             :         //iterate through all series
    2036           0 :         bool bBreak = false;
    2037           0 :         bool bFirstSeries = true;
    2038           0 :         ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator             aZSlotIter = m_aZSlots.begin();
    2039           0 :         const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator  aZSlotEnd = m_aZSlots.end();
    2040           0 :         for( ; aZSlotIter!=aZSlotEnd && !bBreak; ++aZSlotIter )
    2041             :         {
    2042           0 :             ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
    2043           0 :             const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    2044           0 :             for( ; aXSlotIter!=aXSlotEnd && !bBreak; ++aXSlotIter )
    2045             :             {
    2046           0 :                 ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
    2047           0 :                 ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = pSeriesList->begin();
    2048           0 :                 const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = pSeriesList->end();
    2049             :                 //iterate through all series in this x slot
    2050           0 :                 for( ; aSeriesIter!=aSeriesEnd && !bBreak; ++aSeriesIter )
    2051             :                 {
    2052           0 :                     VDataSeries* pSeries( *aSeriesIter );
    2053           0 :                     if(!pSeries)
    2054           0 :                         continue;
    2055             : 
    2056             :                     std::vector< ViewLegendEntry > aSeriesEntries( this->createLegendEntriesForSeries( rEntryKeyAspectRatio,
    2057           0 :                             *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           0 :                     if( bFirstSeries && pSeries->isVaryColorsByPoint() )
    2063           0 :                         bBreak = true;
    2064           0 :                     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           0 :                     bool bReverse = false;
    2070           0 :                     if( eLegendExpansion != ::com::sun::star::chart::ChartLegendExpansion_WIDE )
    2071             :                     {
    2072           0 :                         StackingDirection eStackingDirection( pSeries->getStackingDirection() );
    2073           0 :                         bReverse = ( eStackingDirection == StackingDirection_Y_STACKING );
    2074             : 
    2075             :                         //todo: respect direction of axis in future
    2076             :                     }
    2077             : 
    2078           0 :                     if(bReverse)
    2079           0 :                         aResult.insert( aResult.begin(), aSeriesEntries.begin(), aSeriesEntries.end() );
    2080             :                     else
    2081           0 :                         aResult.insert( aResult.end(), aSeriesEntries.begin(), aSeriesEntries.end() );
    2082           0 :                 }
    2083             :             }
    2084             :         }
    2085             :     }
    2086             : 
    2087           0 :     return aResult;
    2088             : }
    2089             : 
    2090           0 : ::std::vector< VDataSeries* > VSeriesPlotter::getAllSeries()
    2091             : {
    2092           0 :     ::std::vector< VDataSeries* > aAllSeries;
    2093           0 :     ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator            aZSlotIter = m_aZSlots.begin();
    2094           0 :     const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
    2095           0 :     for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
    2096             :     {
    2097           0 :         ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = aZSlotIter->begin();
    2098           0 :         const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
    2099           0 :         for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
    2100             :         {
    2101           0 :             ::std::vector< VDataSeries* > aSeriesList = aXSlotIter->m_aSeriesVector;
    2102           0 :             aAllSeries.insert( aAllSeries.end(), aSeriesList.begin(), aSeriesList.end() );
    2103           0 :         }
    2104             :     }
    2105           0 :     return aAllSeries;
    2106             : }
    2107             : 
    2108             : namespace
    2109             : {
    2110           0 : bool lcl_HasVisibleLine( const uno::Reference< beans::XPropertySet >& xProps, bool& rbHasDashedLine )
    2111             : {
    2112           0 :     bool bHasVisibleLine = false;
    2113           0 :     rbHasDashedLine = false;
    2114           0 :     drawing::LineStyle aLineStyle = drawing::LineStyle_NONE;
    2115           0 :     if( xProps.is() && ( xProps->getPropertyValue( "LineStyle") >>= aLineStyle ) )
    2116             :     {
    2117           0 :         if( aLineStyle != drawing::LineStyle_NONE )
    2118           0 :             bHasVisibleLine = true;
    2119           0 :         if( aLineStyle == drawing::LineStyle_DASH )
    2120           0 :             rbHasDashedLine = true;
    2121             :     }
    2122           0 :     return bHasVisibleLine;
    2123             : }
    2124             : 
    2125           0 : bool lcl_HasRegressionCurves( const VDataSeries& rSeries, bool& rbHasDashedLine )
    2126             : {
    2127           0 :     bool bHasRegressionCurves = false;
    2128           0 :     Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
    2129           0 :     if( xRegrCont.is())
    2130             :     {
    2131           0 :         Sequence< Reference< XRegressionCurve > > aCurves( xRegrCont->getRegressionCurves() );
    2132           0 :         sal_Int32 i = 0, nCount = aCurves.getLength();
    2133           0 :         for( i=0; i<nCount; ++i )
    2134             :         {
    2135           0 :             if( aCurves[i].is() )
    2136             :             {
    2137           0 :                 bHasRegressionCurves = true;
    2138           0 :                 lcl_HasVisibleLine( uno::Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ), rbHasDashedLine );
    2139             :             }
    2140           0 :         }
    2141             :     }
    2142           0 :     return bHasRegressionCurves;
    2143             : }
    2144             : }
    2145           0 : LegendSymbolStyle VSeriesPlotter::getLegendSymbolStyle()
    2146             : {
    2147           0 :     return LegendSymbolStyle_BOX;
    2148             : }
    2149             : 
    2150           0 : awt::Size VSeriesPlotter::getPreferredLegendKeyAspectRatio()
    2151             : {
    2152           0 :     awt::Size aRet(1000,1000);
    2153           0 :     if( m_nDimension==3 )
    2154           0 :         return aRet;
    2155             : 
    2156           0 :     bool bSeriesAllowsLines = (getLegendSymbolStyle() == LegendSymbolStyle_LINE);
    2157           0 :     bool bHasLines = false;
    2158           0 :     bool bHasDashedLines = false;
    2159           0 :     ::std::vector< VDataSeries* > aAllSeries( getAllSeries() );
    2160           0 :     ::std::vector< VDataSeries* >::const_iterator       aSeriesIter = aAllSeries.begin();
    2161           0 :     const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd  = aAllSeries.end();
    2162             :     //iterate through all series
    2163           0 :     for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
    2164             :     {
    2165           0 :         if( bSeriesAllowsLines )
    2166             :         {
    2167           0 :             bool bCurrentDashed = false;
    2168           0 :             if( lcl_HasVisibleLine( (*aSeriesIter)->getPropertiesOfSeries(), bCurrentDashed ) )
    2169             :             {
    2170           0 :                 bHasLines = true;
    2171           0 :                 if( bCurrentDashed )
    2172             :                 {
    2173           0 :                     bHasDashedLines = true;
    2174           0 :                     break;
    2175             :                 }
    2176             :             }
    2177             :         }
    2178           0 :         bool bRegressionHasDashedLines=false;
    2179           0 :         if( lcl_HasRegressionCurves( **aSeriesIter, bRegressionHasDashedLines ) )
    2180             :         {
    2181           0 :             bHasLines = true;
    2182           0 :             if( bRegressionHasDashedLines )
    2183             :             {
    2184           0 :                 bHasDashedLines = true;
    2185           0 :                 break;
    2186             :             }
    2187             :         }
    2188             :     }
    2189           0 :     if( bHasLines )
    2190             :     {
    2191           0 :         if( bHasDashedLines )
    2192           0 :             aRet = awt::Size(1600,-1);
    2193             :         else
    2194           0 :             aRet = awt::Size(800,-1);
    2195             :     }
    2196           0 :     return aRet;
    2197             : }
    2198             : 
    2199           0 : uno::Any VSeriesPlotter::getExplicitSymbol( const VDataSeries& /*rSeries*/, sal_Int32 /*nPointIndex*/ )
    2200             : {
    2201           0 :     return uno::Any();
    2202             : }
    2203             : 
    2204           0 : 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           0 :     LegendSymbolStyle eLegendSymbolStyle = this->getLegendSymbolStyle();
    2212           0 :     uno::Any aExplicitSymbol( this->getExplicitSymbol( rSeries ) );
    2213             : 
    2214             :     VLegendSymbolFactory::tPropertyType ePropType =
    2215           0 :         VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES;
    2216             : 
    2217             :     // todo: maybe the property-style does not solely depend on the
    2218             :     // legend-symbol type
    2219           0 :     switch( eLegendSymbolStyle )
    2220             :     {
    2221             :         case LegendSymbolStyle_LINE:
    2222           0 :             ePropType = VLegendSymbolFactory::PROP_TYPE_LINE_SERIES;
    2223           0 :             break;
    2224             :         default:
    2225           0 :             break;
    2226             :     };
    2227             :     Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
    2228             :         xTarget, eLegendSymbolStyle, xShapeFactory
    2229           0 :             , rSeries.getPropertiesOfSeries(), ePropType, aExplicitSymbol ));
    2230             : 
    2231           0 :     return xShape;
    2232             : }
    2233             : 
    2234           0 : 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           0 :     LegendSymbolStyle eLegendSymbolStyle = this->getLegendSymbolStyle();
    2243           0 :     uno::Any aExplicitSymbol( this->getExplicitSymbol(rSeries,nPointIndex) );
    2244             : 
    2245             :     VLegendSymbolFactory::tPropertyType ePropType =
    2246           0 :         VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES;
    2247             : 
    2248             :     // todo: maybe the property-style does not solely depend on the
    2249             :     // legend-symbol type
    2250           0 :     switch( eLegendSymbolStyle )
    2251             :     {
    2252             :         case LegendSymbolStyle_LINE:
    2253           0 :             ePropType = VLegendSymbolFactory::PROP_TYPE_LINE_SERIES;
    2254           0 :             break;
    2255             :         default:
    2256           0 :             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           0 :     Reference< beans::XPropertySet > xSeriesProps( rSeries.getPropertiesOfSeries() );
    2262           0 :     Reference< beans::XPropertySet > xPointSet( xSeriesProps );
    2263           0 :     if( rSeries.isAttributedDataPoint( nPointIndex ) )
    2264           0 :         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           0 :     if( ! rSeries.hasPointOwnColor( nPointIndex ))
    2268             :     {
    2269           0 :         Reference< util::XCloneable > xCloneable( xPointSet,uno::UNO_QUERY );
    2270           0 :         if( xCloneable.is() && m_xColorScheme.is() )
    2271             :         {
    2272           0 :             xPointSet.set( xCloneable->createClone(), uno::UNO_QUERY );
    2273           0 :             Reference< container::XChild > xChild( xPointSet, uno::UNO_QUERY );
    2274           0 :             if( xChild.is())
    2275           0 :                 xChild->setParent( xSeriesProps );
    2276             : 
    2277             :             OSL_ASSERT( xPointSet.is());
    2278           0 :             xPointSet->setPropertyValue(
    2279           0 :                 "Color", uno::makeAny( m_xColorScheme->getColorByIndex( nPointIndex )));
    2280           0 :         }
    2281             :     }
    2282             : 
    2283             :     Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
    2284           0 :         xTarget, eLegendSymbolStyle, xShapeFactory, xPointSet, ePropType, aExplicitSymbol ));
    2285             : 
    2286           0 :     return xShape;
    2287             : }
    2288             : 
    2289           0 : 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           0 :     std::vector< ViewLegendEntry > aResult;
    2299             : 
    2300           0 :     if( ! ( xShapeFactory.is() && xTarget.is() && xContext.is() ) )
    2301           0 :         return aResult;
    2302             : 
    2303             :     try
    2304             :     {
    2305           0 :         ViewLegendEntry aEntry;
    2306           0 :         OUString aLabelText;
    2307           0 :         bool bVaryColorsByPoint = rSeries.isVaryColorsByPoint();
    2308           0 :         if( bVaryColorsByPoint )
    2309             :         {
    2310           0 :             Sequence< OUString > aCategoryNames;
    2311           0 :             if( m_pExplicitCategoriesProvider )
    2312           0 :                 aCategoryNames = m_pExplicitCategoriesProvider->getSimpleCategories();
    2313             : 
    2314           0 :             for( sal_Int32 nIdx=0; nIdx<aCategoryNames.getLength(); ++nIdx )
    2315             :             {
    2316             :                 // symbol
    2317           0 :                 uno::Reference< drawing::XShapes > xSymbolGroup( AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory)->createGroup2D( xTarget ));
    2318             : 
    2319             :                 // create the symbol
    2320             :                 Reference< drawing::XShape > xShape( this->createLegendSymbolForPoint( rEntryKeyAspectRatio,
    2321           0 :                     rSeries, nIdx, xSymbolGroup, xShapeFactory ) );
    2322             : 
    2323             :                 // set CID to symbol for selection
    2324           0 :                 if( xShape.is() )
    2325             :                 {
    2326           0 :                     aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
    2327             : 
    2328           0 :                     OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_DATA_POINT, nIdx ) );
    2329           0 :                     aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
    2330           0 :                     OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
    2331           0 :                     AbstractShapeFactory::setShapeName( xShape, aCID );
    2332             :                 }
    2333             : 
    2334             :                 // label
    2335           0 :                 aLabelText = aCategoryNames[nIdx];
    2336           0 :                 if( xShape.is() || !aLabelText.isEmpty() )
    2337             :                 {
    2338           0 :                     aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
    2339           0 :                     aResult.push_back(aEntry);
    2340             :                 }
    2341           0 :             }
    2342             :         }
    2343             :         else
    2344             :         {
    2345             :             // symbol
    2346           0 :             uno::Reference< drawing::XShapes > xSymbolGroup( AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory)->createGroup2D( xTarget ));
    2347             : 
    2348             :             // create the symbol
    2349             :             Reference< drawing::XShape > xShape( this->createLegendSymbolForSeries(
    2350           0 :                 rEntryKeyAspectRatio, rSeries, xSymbolGroup, xShapeFactory ) );
    2351             : 
    2352             :             // set CID to symbol for selection
    2353           0 :             if( xShape.is())
    2354             :             {
    2355           0 :                 aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
    2356             : 
    2357           0 :                 OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
    2358           0 :                 OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
    2359           0 :                 AbstractShapeFactory::setShapeName( xShape, aCID );
    2360             :             }
    2361             : 
    2362             :             // label
    2363           0 :             aLabelText = ( DataSeriesHelper::getDataSeriesLabel( rSeries.getModel(), m_xChartTypeModel.is() ? m_xChartTypeModel->getRoleOfSequenceForSeriesLabel() : "values-y") );
    2364           0 :             aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
    2365             : 
    2366           0 :             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           0 :         if (!ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ))
    2372           0 :             return aResult;
    2373             : 
    2374           0 :         Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
    2375           0 :         if( xRegrCont.is())
    2376             :         {
    2377           0 :             Sequence< Reference< XRegressionCurve > > aCurves( xRegrCont->getRegressionCurves());
    2378           0 :             sal_Int32 i = 0, nCount = aCurves.getLength();
    2379           0 :             for( i=0; i<nCount; ++i )
    2380             :             {
    2381           0 :                 if( aCurves[i].is() )
    2382             :                 {
    2383             :                     //label
    2384           0 :                     OUString aResStr( RegressionCurveHelper::getUINameForRegressionCurve( aCurves[i] ) );
    2385           0 :                     replaceParamterInString( aResStr, "%SERIESNAME", aLabelText );
    2386           0 :                     aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aResStr, xTextProperties );
    2387             : 
    2388             :                     // symbol
    2389           0 :                     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           0 :                         Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ),
    2395           0 :                         VLegendSymbolFactory::PROP_TYPE_LINE, uno::Any() ));
    2396             : 
    2397             :                     // set CID to symbol for selection
    2398           0 :                     if( xShape.is())
    2399             :                     {
    2400           0 :                         aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
    2401             : 
    2402           0 :                         bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurves[i] );
    2403           0 :                         ObjectType eObjectType = bAverageLine ? OBJECTTYPE_DATA_AVERAGE_LINE : OBJECTTYPE_DATA_CURVE;
    2404           0 :                         OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( eObjectType, i ) );
    2405           0 :                         aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
    2406           0 :                         OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
    2407           0 :                         AbstractShapeFactory::setShapeName( xShape, aCID );
    2408             :                     }
    2409             : 
    2410           0 :                     aResult.push_back(aEntry);
    2411             :                 }
    2412           0 :             }
    2413           0 :         }
    2414             :     }
    2415           0 :     catch( const uno::Exception & ex )
    2416             :     {
    2417             :         ASSERT_EXCEPTION( ex );
    2418             :     }
    2419           0 :     return aResult;
    2420             : }
    2421             : 
    2422           0 : VSeriesPlotter* VSeriesPlotter::createSeriesPlotter(
    2423             :     const uno::Reference<XChartType>& xChartTypeModel
    2424             :     , sal_Int32 nDimensionCount
    2425             :     , bool bExcludingPositioning )
    2426             : {
    2427           0 :     if (!xChartTypeModel.is())
    2428           0 :         return NULL;
    2429             : 
    2430           0 :     OUString aChartType = xChartTypeModel->getChartType();
    2431             : 
    2432           0 :     VSeriesPlotter* pRet=NULL;
    2433           0 :     if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_COLUMN ) )
    2434           0 :         pRet = new BarChart(xChartTypeModel,nDimensionCount);
    2435           0 :     else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_BAR ) )
    2436           0 :         pRet = new BarChart(xChartTypeModel,nDimensionCount);
    2437           0 :     else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_AREA ) )
    2438           0 :         pRet = new AreaChart(xChartTypeModel,nDimensionCount,true);
    2439           0 :     else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_LINE ) )
    2440           0 :         pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,true);
    2441           0 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) )
    2442           0 :         pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true);
    2443           0 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE) )
    2444           0 :         pRet = new BubbleChart(xChartTypeModel,nDimensionCount);
    2445           0 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
    2446           0 :         pRet = new PieChart(xChartTypeModel,nDimensionCount, bExcludingPositioning );
    2447           0 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_NET) )
    2448           0 :         pRet = new NetChart(xChartTypeModel,nDimensionCount,true,new PolarPlottingPositionHelper());
    2449           0 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) )
    2450           0 :         pRet = new NetChart(xChartTypeModel,nDimensionCount,false,new PolarPlottingPositionHelper());
    2451           0 :     else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) )
    2452           0 :         pRet = new CandleStickChart(xChartTypeModel,nDimensionCount);
    2453             :     else
    2454           0 :         pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true);
    2455           0 :     return pRet;
    2456             : }
    2457             : 
    2458             : } //namespace chart
    2459             : 
    2460             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10