summaryrefslogtreecommitdiff
path: root/chart2/source/view/charttypes
diff options
context:
space:
mode:
Diffstat (limited to 'chart2/source/view/charttypes')
-rw-r--r--chart2/source/view/charttypes/AreaChart.cxx981
-rw-r--r--chart2/source/view/charttypes/AreaChart.hxx137
-rw-r--r--chart2/source/view/charttypes/BarChart.cxx969
-rw-r--r--chart2/source/view/charttypes/BarChart.hxx113
-rw-r--r--chart2/source/view/charttypes/BarPositionHelper.cxx141
-rw-r--r--chart2/source/view/charttypes/BarPositionHelper.hxx79
-rw-r--r--chart2/source/view/charttypes/BubbleChart.cxx420
-rw-r--r--chart2/source/view/charttypes/BubbleChart.hxx97
-rw-r--r--chart2/source/view/charttypes/CandleStickChart.cxx372
-rw-r--r--chart2/source/view/charttypes/CandleStickChart.hxx92
-rw-r--r--chart2/source/view/charttypes/CategoryPositionHelper.cxx103
-rw-r--r--chart2/source/view/charttypes/CategoryPositionHelper.hxx71
-rw-r--r--chart2/source/view/charttypes/PieChart.cxx883
-rw-r--r--chart2/source/view/charttypes/PieChart.hxx148
-rw-r--r--chart2/source/view/charttypes/Splines.cxx547
-rw-r--r--chart2/source/view/charttypes/Splines.hxx64
-rw-r--r--chart2/source/view/charttypes/VSeriesPlotter.cxx2113
-rw-r--r--chart2/source/view/charttypes/makefile.mk55
18 files changed, 7385 insertions, 0 deletions
diff --git a/chart2/source/view/charttypes/AreaChart.cxx b/chart2/source/view/charttypes/AreaChart.cxx
new file mode 100644
index 000000000000..4d2f5ad8716b
--- /dev/null
+++ b/chart2/source/view/charttypes/AreaChart.cxx
@@ -0,0 +1,981 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_chart2.hxx"
+
+#include "AreaChart.hxx"
+#include "PlottingPositionHelper.hxx"
+#include "ShapeFactory.hxx"
+#include "CommonConverters.hxx"
+#include "macros.hxx"
+#include "ViewDefines.hxx"
+#include "ObjectIdentifier.hxx"
+#include "Splines.hxx"
+#include "ChartTypeHelper.hxx"
+#include "LabelPositionHelper.hxx"
+#include "Clipping.hxx"
+#include "Stripe.hxx"
+#include "PolarLabelPositionHelper.hxx"
+
+#include <com/sun/star/chart2/Symbol.hpp>
+#include <com/sun/star/chart/DataLabelPlacement.hpp>
+#include <com/sun/star/chart/MissingValueTreatment.hpp>
+#include <tools/debug.hxx>
+#include <editeng/unoprnms.hxx>
+#include <rtl/math.hxx>
+#include <com/sun/star/drawing/DoubleSequence.hpp>
+#include <com/sun/star/drawing/NormalsKind.hpp>
+#include <com/sun/star/lang/XServiceName.hpp>
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+using namespace ::com::sun::star;
+using namespace ::rtl::math;
+using namespace ::com::sun::star::chart2;
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+AreaChart::AreaChart( const uno::Reference<XChartType>& xChartTypeModel
+ , sal_Int32 nDimensionCount
+ , bool bCategoryXAxis
+ , bool bNoArea
+ , PlottingPositionHelper* pPlottingPositionHelper
+ , bool bConnectLastToFirstPoint
+ , bool bExpandIfValuesCloseToBorder
+ , sal_Int32 nKeepAspectRatio
+ , const drawing::Direction3D& rAspectRatio
+ )
+ : VSeriesPlotter( xChartTypeModel, nDimensionCount, bCategoryXAxis )
+ , m_pMainPosHelper(pPlottingPositionHelper)
+ , m_bArea(!bNoArea)
+ , m_bLine(bNoArea)
+ , m_bSymbol( ChartTypeHelper::isSupportingSymbolProperties(xChartTypeModel,nDimensionCount) )
+ , m_bIsPolarCooSys( bConnectLastToFirstPoint )
+ , m_bConnectLastToFirstPoint( bConnectLastToFirstPoint )
+ , m_bExpandIfValuesCloseToBorder( bExpandIfValuesCloseToBorder )
+ , m_nKeepAspectRatio(nKeepAspectRatio)
+ , m_aGivenAspectRatio(rAspectRatio)
+ , m_eCurveStyle(CurveStyle_LINES)
+ , m_nCurveResolution(20)
+ , m_nSplineOrder(3)
+ , m_xSeriesTarget(0)
+ , m_xErrorBarTarget(0)
+ , m_xTextTarget(0)
+ , m_xRegressionCurveEquationTarget(0)
+{
+ if( !m_pMainPosHelper )
+ m_pMainPosHelper = new PlottingPositionHelper();
+ PlotterBase::m_pPosHelper = m_pMainPosHelper;
+ VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper;
+
+ try
+ {
+ if( m_xChartTypeModelProps.is() )
+ {
+ m_xChartTypeModelProps->getPropertyValue( C2U( "CurveStyle" ) ) >>= m_eCurveStyle;
+ m_xChartTypeModelProps->getPropertyValue( C2U( "CurveResolution" ) ) >>= m_nCurveResolution;
+ m_xChartTypeModelProps->getPropertyValue( C2U( "SplineOrder" ) ) >>= m_nSplineOrder;
+ }
+ }
+ catch( uno::Exception& e )
+ {
+ //the above properties are not supported by all charttypes supported by this class (e.g. area or net chart)
+ //in that cases this exception is ok
+ e.Context.is();//to have debug information without compilation warnings
+ }
+}
+
+AreaChart::~AreaChart()
+{
+ delete m_pMainPosHelper;
+}
+
+double AreaChart::getMinimumX()
+{
+ if( m_bCategoryXAxis && m_bIsPolarCooSys )//the angle axis in net charts needs a different autoscaling
+ return 1.0;//first category (index 0) matches with real number 1.0
+ return VSeriesPlotter::getMinimumX();
+}
+
+double AreaChart::getMaximumX()
+{
+ if( m_bCategoryXAxis && m_bIsPolarCooSys )//the angle axis in net charts needs a different autoscaling
+ return getPointCount()+1;
+ return VSeriesPlotter::getMaximumX();
+}
+
+bool AreaChart::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex )
+{
+ return m_bExpandIfValuesCloseToBorder &&
+ VSeriesPlotter::isExpandIfValuesCloseToBorder( nDimensionIndex );
+}
+
+bool AreaChart::isSeperateStackingForDifferentSigns( sal_Int32 /*nDimensionIndex*/ )
+{
+ // no separate stacking in all types of line/area charts
+ return false;
+}
+
+//-----------------------------------------------------------------
+
+LegendSymbolStyle AreaChart::getLegendSymbolStyle()
+{
+ if( m_bArea || m_nDimension == 3 )
+ return chart2::LegendSymbolStyle_BOX;
+ return chart2::LegendSymbolStyle_LINE_WITH_SYMBOL;
+}
+
+uno::Any AreaChart::getExplicitSymbol( const VDataSeries& rSeries, sal_Int32 nPointIndex )
+{
+ uno::Any aRet;
+
+ Symbol* pSymbolProperties = rSeries.getSymbolProperties( nPointIndex );
+ if( pSymbolProperties )
+ {
+ aRet = uno::makeAny(*pSymbolProperties);
+ }
+
+ return aRet;
+}
+
+drawing::Direction3D AreaChart::getPreferredDiagramAspectRatio() const
+{
+ if( m_nKeepAspectRatio == 1 )
+ return m_aGivenAspectRatio;
+ drawing::Direction3D aRet(1,-1,1);
+ if( m_nDimension == 2 )
+ aRet = drawing::Direction3D(-1,-1,-1);
+ else
+ {
+ drawing::Direction3D aScale( m_pPosHelper->getScaledLogicWidth() );
+ aRet.DirectionZ = aScale.DirectionZ*0.2;
+ if(aRet.DirectionZ>1.0)
+ aRet.DirectionZ=1.0;
+ if(aRet.DirectionZ>10)
+ aRet.DirectionZ=10;
+ }
+ return aRet;
+}
+
+bool AreaChart::keepAspectRatio() const
+{
+ if( m_nKeepAspectRatio == 0 )
+ return false;
+ if( m_nKeepAspectRatio == 1 )
+ return true;
+ if( m_nDimension == 2 )
+ {
+ if( !m_bSymbol )
+ return false;
+ }
+ return true;
+}
+
+void AreaChart::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
+{
+ if( m_bArea && !m_bIsPolarCooSys && pSeries )
+ {
+ sal_Int32 nMissingValueTreatment = pSeries->getMissingValueTreatment();
+ if( nMissingValueTreatment == ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP )
+ pSeries->setMissingValueTreatment( ::com::sun::star::chart::MissingValueTreatment::USE_ZERO );
+ }
+ if( m_nDimension == 3 && !m_bCategoryXAxis )
+ {
+ //3D xy always deep
+ DBG_ASSERT( zSlot==-1,"3D xy charts should be deep stacked in model also" );
+ zSlot=-1;
+ xSlot=0;
+ ySlot=0;
+ }
+ VSeriesPlotter::addSeries( pSeries, zSlot, xSlot, ySlot );
+}
+
+void lcl_removeDuplicatePoints( drawing::PolyPolygonShape3D& rPolyPoly, PlottingPositionHelper& rPosHelper )
+{
+ sal_Int32 nPolyCount = rPolyPoly.SequenceX.getLength();
+ if(!nPolyCount)
+ return;
+
+ drawing::PolyPolygonShape3D aTmp;
+ aTmp.SequenceX.realloc(nPolyCount);
+ aTmp.SequenceY.realloc(nPolyCount);
+ aTmp.SequenceZ.realloc(nPolyCount);
+
+ for( sal_Int32 nPolygonIndex = 0; nPolygonIndex<nPolyCount; nPolygonIndex++ )
+ {
+ drawing::DoubleSequence* pOuterSourceX = &rPolyPoly.SequenceX.getArray()[nPolygonIndex];
+ drawing::DoubleSequence* pOuterSourceY = &rPolyPoly.SequenceY.getArray()[nPolygonIndex];
+ drawing::DoubleSequence* pOuterSourceZ = &rPolyPoly.SequenceZ.getArray()[nPolygonIndex];
+
+ drawing::DoubleSequence* pOuterTargetX = &aTmp.SequenceX.getArray()[nPolygonIndex];
+ drawing::DoubleSequence* pOuterTargetY = &aTmp.SequenceY.getArray()[nPolygonIndex];
+ drawing::DoubleSequence* pOuterTargetZ = &aTmp.SequenceZ.getArray()[nPolygonIndex];
+
+ sal_Int32 nPointCount = pOuterSourceX->getLength();
+ if( !nPointCount )
+ continue;
+
+ pOuterTargetX->realloc(nPointCount);
+ pOuterTargetY->realloc(nPointCount);
+ pOuterTargetZ->realloc(nPointCount);
+
+ double* pSourceX = pOuterSourceX->getArray();
+ double* pSourceY = pOuterSourceY->getArray();
+ double* pSourceZ = pOuterSourceZ->getArray();
+
+ double* pTargetX = pOuterTargetX->getArray();
+ double* pTargetY = pOuterTargetY->getArray();
+ double* pTargetZ = pOuterTargetZ->getArray();
+
+ //copy first point
+ *pTargetX=*pSourceX++;
+ *pTargetY=*pSourceY++;
+ *pTargetZ=*pSourceZ++;
+ sal_Int32 nTargetPointCount=1;
+
+ for( sal_Int32 nSource=1; nSource<nPointCount; nSource++ )
+ {
+ if( !rPosHelper.isSameForGivenResolution( *pTargetX, *pTargetY, *pTargetZ
+ , *pSourceX, *pSourceY, *pSourceZ ) )
+ {
+ pTargetX++; pTargetY++; pTargetZ++;
+ *pTargetX=*pSourceX;
+ *pTargetY=*pSourceY;
+ *pTargetZ=*pSourceZ;
+ nTargetPointCount++;
+ }
+ pSourceX++; pSourceY++; pSourceZ++;
+ }
+
+ //free unused space
+ if( nTargetPointCount<nPointCount )
+ {
+ pOuterTargetX->realloc(nTargetPointCount);
+ pOuterTargetY->realloc(nTargetPointCount);
+ pOuterTargetZ->realloc(nTargetPointCount);
+ }
+
+ pOuterSourceX->realloc(0);
+ pOuterSourceY->realloc(0);
+ pOuterSourceZ->realloc(0);
+ }
+
+ //free space
+ rPolyPoly.SequenceX.realloc(nPolyCount);
+ rPolyPoly.SequenceY.realloc(nPolyCount);
+ rPolyPoly.SequenceZ.realloc(nPolyCount);
+
+ rPolyPoly=aTmp;
+}
+
+bool AreaChart::impl_createLine( VDataSeries* pSeries
+ , drawing::PolyPolygonShape3D* pSeriesPoly
+ , PlottingPositionHelper* pPosHelper )
+{
+ //return true if a line was created successfully
+ uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget);
+
+ drawing::PolyPolygonShape3D aPoly;
+ if(CurveStyle_CUBIC_SPLINES==m_eCurveStyle)
+ {
+ drawing::PolyPolygonShape3D aSplinePoly;
+ SplineCalculater::CalculateCubicSplines( *pSeriesPoly, aSplinePoly, m_nCurveResolution );
+ lcl_removeDuplicatePoints( aSplinePoly, *pPosHelper );
+ Clipping::clipPolygonAtRectangle( aSplinePoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
+ }
+ else if(CurveStyle_B_SPLINES==m_eCurveStyle)
+ {
+ drawing::PolyPolygonShape3D aSplinePoly;
+ SplineCalculater::CalculateBSplines( *pSeriesPoly, aSplinePoly, m_nCurveResolution, m_nSplineOrder );
+ lcl_removeDuplicatePoints( aSplinePoly, *pPosHelper );
+ Clipping::clipPolygonAtRectangle( aSplinePoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
+ }
+ else
+ {
+ bool bIsClipped = false;
+ if( m_bConnectLastToFirstPoint && !ShapeFactory::isPolygonEmptyOrSinglePoint(*pSeriesPoly) )
+ {
+ // do NOT connect last and first point, if one is NAN, and NAN handling is NAN_AS_GAP
+ double fFirstY = pSeries->getYValue( 0 );
+ double fLastY = pSeries->getYValue( VSeriesPlotter::getPointCount() - 1 );
+ if( (pSeries->getMissingValueTreatment() != ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP)
+ || (::rtl::math::isFinite( fFirstY ) && ::rtl::math::isFinite( fLastY )) )
+ {
+ // connect last point in last polygon with first point in first polygon
+ ::basegfx::B2DRectangle aScaledLogicClipDoubleRect( pPosHelper->getScaledLogicClipDoubleRect() );
+ drawing::PolyPolygonShape3D aTmpPoly(*pSeriesPoly);
+ drawing::Position3D aLast(aScaledLogicClipDoubleRect.getMaxX(),aTmpPoly.SequenceY[0][0],aTmpPoly.SequenceZ[0][0]);
+ // add connector line to last polygon
+ AddPointToPoly( aTmpPoly, aLast, pSeriesPoly->SequenceX.getLength() - 1 );
+ Clipping::clipPolygonAtRectangle( aTmpPoly, aScaledLogicClipDoubleRect, aPoly );
+ bIsClipped = true;
+ }
+ }
+
+ if( !bIsClipped )
+ Clipping::clipPolygonAtRectangle( *pSeriesPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
+ }
+
+ if(!ShapeFactory::hasPolygonAnyLines(aPoly))
+ return false;
+
+ //transformation 3) -> 4)
+ pPosHelper->transformScaledLogicToScene( aPoly );
+
+ //create line:
+ uno::Reference< drawing::XShape > xShape(NULL);
+ if(m_nDimension==3)
+ {
+ double fDepth = this->getTransformedDepth();
+ sal_Int32 nPolyCount = aPoly.SequenceX.getLength();
+ for(sal_Int32 nPoly=0;nPoly<nPolyCount;nPoly++)
+ {
+ sal_Int32 nPointCount = aPoly.SequenceX[nPoly].getLength();
+ for(sal_Int32 nPoint=0;nPoint<nPointCount-1;nPoint++)
+ {
+ drawing::Position3D aPoint1, aPoint2;
+ aPoint1.PositionX = aPoly.SequenceX[nPoly][nPoint+1];
+ aPoint1.PositionY = aPoly.SequenceY[nPoly][nPoint+1];
+ aPoint1.PositionZ = aPoly.SequenceZ[nPoly][nPoint+1];
+
+ aPoint2.PositionX = aPoly.SequenceX[nPoly][nPoint];
+ aPoint2.PositionY = aPoly.SequenceY[nPoly][nPoint];
+ aPoint2.PositionZ = aPoly.SequenceZ[nPoly][nPoint];
+
+ Stripe aStripe( aPoint1, aPoint2, fDepth );
+
+ m_pShapeFactory->createStripe(xSeriesGroupShape_Shapes
+ , Stripe( aPoint1, aPoint2, fDepth )
+ , pSeries->getPropertiesOfSeries(), PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), true, 1 );
+ }
+ }
+ }
+ else //m_nDimension!=3
+ {
+ xShape = m_pShapeFactory->createLine2D( xSeriesGroupShape_Shapes
+ , PolyToPointSequence( aPoly ) );
+ this->setMappedProperties( xShape
+ , pSeries->getPropertiesOfSeries()
+ , PropertyMapper::getPropertyNameMapForLineSeriesProperties() );
+ //because of this name this line will be used for marking
+ m_pShapeFactory->setShapeName( xShape, C2U("MarkHandles") );
+ }
+ return true;
+}
+
+bool AreaChart::impl_createArea( VDataSeries* pSeries
+ , drawing::PolyPolygonShape3D* pSeriesPoly
+ , drawing::PolyPolygonShape3D* pPreviousSeriesPoly
+ , PlottingPositionHelper* pPosHelper )
+{
+ //return true if an area was created successfully
+
+ uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget);
+ double zValue = pSeries->m_fLogicZPos;
+
+ drawing::PolyPolygonShape3D aPoly( *pSeriesPoly );
+ //add second part to the polygon (grounding points or previous series points)
+ if( m_bConnectLastToFirstPoint && !ShapeFactory::isPolygonEmptyOrSinglePoint(*pSeriesPoly) )
+ {
+ if( pPreviousSeriesPoly )
+ addPolygon( aPoly, *pPreviousSeriesPoly );
+ }
+ else if(!pPreviousSeriesPoly)
+ {
+ double fMinX = pSeries->m_fLogicMinX;
+ double fMaxX = pSeries->m_fLogicMaxX;
+ double fY = pPosHelper->getBaseValueY();//logic grounding
+ if( m_nDimension==3 )
+ fY = pPosHelper->getLogicMinY();
+
+ //clip to scale
+ if(fMaxX<pPosHelper->getLogicMinX() || fMinX>pPosHelper->getLogicMaxX())
+ return false;//no visible shape needed
+ pPosHelper->clipLogicValues( &fMinX, &fY, 0 );
+ pPosHelper->clipLogicValues( &fMaxX, 0, 0 );
+
+ //apply scaling
+ {
+ pPosHelper->doLogicScaling( &fMinX, &fY, &zValue );
+ pPosHelper->doLogicScaling( &fMaxX, 0, 0 );
+ }
+
+ AddPointToPoly( aPoly, drawing::Position3D( fMaxX,fY,zValue) );
+ AddPointToPoly( aPoly, drawing::Position3D( fMinX,fY,zValue) );
+ }
+ else
+ {
+ appendPoly( aPoly, *pPreviousSeriesPoly );
+ }
+ ShapeFactory::closePolygon(aPoly);
+
+ //apply clipping
+ {
+ drawing::PolyPolygonShape3D aClippedPoly;
+ Clipping::clipPolygonAtRectangle( aPoly, pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly, false );
+ ShapeFactory::closePolygon(aClippedPoly); //again necessary after clipping
+ aPoly = aClippedPoly;
+ }
+
+ if(!ShapeFactory::hasPolygonAnyLines(aPoly))
+ return false;
+
+ //transformation 3) -> 4)
+ pPosHelper->transformScaledLogicToScene( aPoly );
+
+ //create area:
+ uno::Reference< drawing::XShape > xShape(NULL);
+ if(m_nDimension==3)
+ {
+ xShape = m_pShapeFactory->createArea3D( xSeriesGroupShape_Shapes
+ , aPoly, this->getTransformedDepth() );
+ }
+ else //m_nDimension!=3
+ {
+ xShape = m_pShapeFactory->createArea2D( xSeriesGroupShape_Shapes
+ , aPoly );
+ }
+ this->setMappedProperties( xShape
+ , pSeries->getPropertiesOfSeries()
+ , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
+ //because of this name this line will be used for marking
+ m_pShapeFactory->setShapeName( xShape, C2U("MarkHandles") );
+ return true;
+}
+
+void AreaChart::impl_createSeriesShapes()
+{
+ //the polygon shapes for each series need to be created before
+
+ //iterate through all series again to create the series shapes
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
+ const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
+//=============================================================================
+ for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; aZSlotIter++, nZ++ )
+ {
+ ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+
+ //=============================================================================
+ for( ; aXSlotIter != aXSlotEnd; aXSlotIter++ )
+ {
+ ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
+
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
+ //=============================================================================
+
+ std::map< sal_Int32, drawing::PolyPolygonShape3D* > aPreviousSeriesPolyMap;//a PreviousSeriesPoly for each different nAttachedAxisIndex
+ drawing::PolyPolygonShape3D* pSeriesPoly = NULL;
+
+ //iterate through all series
+ for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
+ {
+ sal_Int32 nAttachedAxisIndex = (*aSeriesIter)->getAttachedAxisIndex();
+ PlottingPositionHelper* pPosHelper = &(this->getPlottingPositionHelper( nAttachedAxisIndex ));
+ if(!pPosHelper)
+ pPosHelper = m_pMainPosHelper;
+ PlotterBase::m_pPosHelper = pPosHelper;
+
+ createRegressionCurvesShapes( **aSeriesIter, m_xErrorBarTarget, m_xRegressionCurveEquationTarget,
+ m_pPosHelper->maySkipPointsInRegressionCalculation());
+
+ pSeriesPoly = &(*aSeriesIter)->m_aPolyPolygonShape3D;
+ if( m_bArea )
+ {
+ if( !impl_createArea( *aSeriesIter, pSeriesPoly, aPreviousSeriesPolyMap[nAttachedAxisIndex], pPosHelper ) )
+ continue;
+ }
+ if( m_bLine )
+ {
+ if( !impl_createLine( *aSeriesIter, pSeriesPoly, pPosHelper ) )
+ continue;
+ }
+ aPreviousSeriesPolyMap[nAttachedAxisIndex] = pSeriesPoly;
+ }//next series in x slot (next y slot)
+ }//next x slot
+ }//next z slot
+}
+
+namespace
+{
+
+void lcl_reorderSeries( ::std::vector< ::std::vector< VDataSeriesGroup > >& rZSlots )
+{
+ ::std::vector< ::std::vector< VDataSeriesGroup > > aRet( rZSlots.size() );
+
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::reverse_iterator aZIt( rZSlots.rbegin() );
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::reverse_iterator aZEnd( rZSlots.rend() );
+ for( ; aZIt != aZEnd; ++aZIt )
+ {
+ ::std::vector< VDataSeriesGroup > aXSlot( aZIt->size() );
+
+ ::std::vector< VDataSeriesGroup >::reverse_iterator aXIt( aZIt->rbegin() );
+ ::std::vector< VDataSeriesGroup >::reverse_iterator aXEnd( aZIt->rend() );
+ for( ; aXIt != aXEnd; ++aXIt )
+ aXSlot.push_back(*aXIt);
+
+ aRet.push_back(aXSlot);
+ }
+
+ rZSlots.clear();
+ rZSlots = aRet;
+}
+
+}//anonymous namespace
+
+//better performance for big data
+struct FormerPoint
+{
+ FormerPoint( double fX, double fY, double fZ )
+ : m_fX(fX), m_fY(fY), m_fZ(fZ)
+ {}
+ FormerPoint()
+ {
+ ::rtl::math::setNan( &m_fX );
+ ::rtl::math::setNan( &m_fY );
+ ::rtl::math::setNan( &m_fZ );
+ }
+
+ double m_fX;
+ double m_fY;
+ double m_fZ;
+};
+
+void AreaChart::createShapes()
+{
+ if( m_aZSlots.begin() == m_aZSlots.end() ) //no series
+ return;
+
+ if( m_nDimension == 2 && ( m_bArea || !m_bCategoryXAxis ) )
+ lcl_reorderSeries( m_aZSlots );
+
+ DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"AreaChart is not proper initialized");
+ if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()))
+ return;
+
+ //the text labels should be always on top of the other series shapes
+ //for area chart the error bars should be always on top of the other series shapes
+
+ //therefore create an own group for the texts and the error bars to move them to front
+ //(because the text group is created after the series group the texts are displayed on top)
+ m_xSeriesTarget = createGroupShape( m_xLogicTarget,rtl::OUString() );
+ if( m_bArea )
+ m_xErrorBarTarget = createGroupShape( m_xLogicTarget,rtl::OUString() );
+ else
+ m_xErrorBarTarget = m_xSeriesTarget;
+ m_xTextTarget = m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() );
+ m_xRegressionCurveEquationTarget = m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() );
+
+ //---------------------------------------------
+ //check necessary here that different Y axis can not be stacked in the same group? ... hm?
+
+ //update/create information for current group
+ double fLogicZ = 0.5;//as defined
+
+ sal_Int32 nStartIndex = 0; // inclusive ;..todo get somehow from x scale
+ sal_Int32 nEndIndex = VSeriesPlotter::getPointCount();
+ if(nEndIndex<=0)
+ nEndIndex=1;
+
+ //better performance for big data
+ std::map< VDataSeries*, FormerPoint > aSeriesFormerPointMap;
+ m_bPointsWereSkipped = false;
+ sal_Int32 nSkippedPoints = 0;
+ sal_Int32 nCreatedPoints = 0;
+ //
+
+//=============================================================================
+ //iterate through all x values per indices
+ for( sal_Int32 nIndex = nStartIndex; nIndex < nEndIndex; nIndex++ )
+ {
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
+ const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
+
+ std::map< sal_Int32, double > aLogicYSumMap;//one for each different nAttachedAxisIndex
+ for( ; aZSlotIter != aZSlotEnd; aZSlotIter++ )
+ {
+ ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+
+ //iterate through all x slots in this category to get 100percent sum
+ for( ; aXSlotIter != aXSlotEnd; aXSlotIter++ )
+ {
+ ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
+
+ for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
+ {
+ VDataSeries* pSeries( *aSeriesIter );
+ if(!pSeries)
+ continue;
+
+ sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex();
+ if( aLogicYSumMap.find(nAttachedAxisIndex)==aLogicYSumMap.end() )
+ aLogicYSumMap[nAttachedAxisIndex]=0.0;
+
+ PlottingPositionHelper* pPosHelper = &(this->getPlottingPositionHelper( nAttachedAxisIndex ));
+ if(!pPosHelper)
+ pPosHelper = m_pMainPosHelper;
+ PlotterBase::m_pPosHelper = pPosHelper;
+
+ double fAdd = pSeries->getYValue( nIndex );
+ if( !::rtl::math::isNan(fAdd) && !::rtl::math::isInf(fAdd) )
+ aLogicYSumMap[nAttachedAxisIndex] += fabs( fAdd );
+ }
+ }
+ }
+
+//=============================================================================
+ aZSlotIter = m_aZSlots.begin();
+ for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; aZSlotIter++, nZ++ )
+ {
+ ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+
+ //for the area chart there should be at most one x slot (no side by side stacking available)
+ //attention different: xSlots are always interpreted as independent areas one behind the other: @todo this doesn't work why not???
+ aXSlotIter = aZSlotIter->begin();
+ for( sal_Int32 nX=0; aXSlotIter != aXSlotEnd; aXSlotIter++, nX++ )
+ {
+ ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
+
+ std::map< sal_Int32, double > aLogicYForNextSeriesMap;//one for each different nAttachedAxisIndex
+ //=============================================================================
+ //iterate through all series
+ for( sal_Int32 nSeriesIndex = 0; aSeriesIter != aSeriesEnd; aSeriesIter++, nSeriesIndex++ )
+ {
+ VDataSeries* pSeries( *aSeriesIter );
+ if(!pSeries)
+ continue;
+
+ /* #i70133# ignore points outside of series length in standard area
+ charts. Stacked area charts will use missing points as zeros. In
+ standard charts, pSeriesList contains only one series. */
+ if( m_bArea && (pSeriesList->size() == 1) && (nIndex >= (*aSeriesIter)->getTotalPointCount()) )
+ continue;
+
+ uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShapeFrontChild(*aSeriesIter, m_xSeriesTarget);
+
+ sal_Int32 nAttachedAxisIndex = (*aSeriesIter)->getAttachedAxisIndex();
+ PlottingPositionHelper* pPosHelper = &(this->getPlottingPositionHelper( nAttachedAxisIndex ));
+ if(!pPosHelper)
+ pPosHelper = m_pMainPosHelper;
+ PlotterBase::m_pPosHelper = pPosHelper;
+
+ if(m_nDimension==3)
+ fLogicZ = nZ+0.5;
+ (*aSeriesIter)->m_fLogicZPos = fLogicZ;
+
+ //collect data point information (logic coordinates, style ):
+ double fLogicX = (*aSeriesIter)->getXValue(nIndex);
+ double fLogicY = (*aSeriesIter)->getYValue(nIndex);
+
+ if( m_bIsPolarCooSys && m_bArea &&
+ ( ::rtl::math::isNan(fLogicY) || ::rtl::math::isInf(fLogicY) ) )
+ {
+ if( (*aSeriesIter)->getMissingValueTreatment() == ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP )
+ {
+ if( pSeriesList->size() == 1 || nSeriesIndex == 0 )
+ {
+ fLogicY = pPosHelper->getLogicMinY();
+ if( !pPosHelper->isMathematicalOrientationY() )
+ fLogicY = pPosHelper->getLogicMaxY();
+ }
+ else
+ fLogicY = 0.0;
+ }
+ }
+
+ if( m_nDimension==3 && m_bArea && pSeriesList->size()!=1 )
+ fLogicY = fabs( fLogicY );
+
+ if( pPosHelper->isPercentY() && !::rtl::math::approxEqual( aLogicYSumMap[nAttachedAxisIndex], 0.0 ) )
+ {
+ fLogicY = fabs( fLogicY )/aLogicYSumMap[nAttachedAxisIndex];
+ }
+
+ if( ::rtl::math::isNan(fLogicX) || ::rtl::math::isInf(fLogicX)
+ || ::rtl::math::isNan(fLogicY) || ::rtl::math::isInf(fLogicY)
+ || ::rtl::math::isNan(fLogicZ) || ::rtl::math::isInf(fLogicZ) )
+ {
+ if( (*aSeriesIter)->getMissingValueTreatment() == ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP )
+ {
+ drawing::PolyPolygonShape3D& rPolygon = (*aSeriesIter)->m_aPolyPolygonShape3D;
+ sal_Int32& rIndex = (*aSeriesIter)->m_nPolygonIndex;
+ if( 0<= rIndex && rIndex < rPolygon.SequenceX.getLength() )
+ {
+ if( rPolygon.SequenceX[ rIndex ].getLength() )
+ rIndex++; //start a new polygon for the next point if the current poly is not empty
+ }
+ }
+ continue;
+ }
+
+ if( aLogicYForNextSeriesMap.find(nAttachedAxisIndex) == aLogicYForNextSeriesMap.end() )
+ aLogicYForNextSeriesMap[nAttachedAxisIndex] = 0.0;
+
+ double fLogicValueForLabeDisplay = fLogicY;
+
+ fLogicY += aLogicYForNextSeriesMap[nAttachedAxisIndex];
+ aLogicYForNextSeriesMap[nAttachedAxisIndex] = fLogicY;
+
+ bool bIsVisible = pPosHelper->isLogicVisible( fLogicX, fLogicY, fLogicZ );
+
+ //remind minimal and maximal x values for area 'grounding' points
+ //only for filled area
+ {
+ double& rfMinX = (*aSeriesIter)->m_fLogicMinX;
+ if(!nIndex||fLogicX<rfMinX)
+ rfMinX=fLogicX;
+ double& rfMaxX = (*aSeriesIter)->m_fLogicMaxX;
+ if(!nIndex||fLogicX>rfMaxX)
+ rfMaxX=fLogicX;
+ }
+
+ drawing::Position3D aUnscaledLogicPosition( fLogicX, fLogicY, fLogicZ );
+ drawing::Position3D aScaledLogicPosition(aUnscaledLogicPosition);
+ pPosHelper->doLogicScaling( aScaledLogicPosition );
+
+ //transformation 3) -> 4)
+ drawing::Position3D aScenePosition( pPosHelper->transformLogicToScene( fLogicX,fLogicY,fLogicZ, false ) );
+
+ //better performance for big data
+ FormerPoint aFormerPoint( aSeriesFormerPointMap[pSeries] );
+ pPosHelper->setCoordinateSystemResolution( m_aCoordinateSystemResolution );
+ if( !pSeries->isAttributedDataPoint(nIndex)
+ &&
+ pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fY, aFormerPoint.m_fZ
+ , aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ ) )
+ {
+ nSkippedPoints++;
+ m_bPointsWereSkipped = true;
+ continue;
+ }
+ aSeriesFormerPointMap[pSeries] = FormerPoint(aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ);
+ //
+
+ //store point information for series polygon
+ //for area and/or line (symbols only do not need this)
+ if( isValidPosition(aScaledLogicPosition) )
+ {
+ AddPointToPoly( (*aSeriesIter)->m_aPolyPolygonShape3D, aScaledLogicPosition, (*aSeriesIter)->m_nPolygonIndex );
+
+ //prepare clipping for filled net charts
+ if( !bIsVisible && m_bIsPolarCooSys && m_bArea )
+ {
+ drawing::Position3D aClippedPos(aScaledLogicPosition);
+ pPosHelper->clipScaledLogicValues( 0, &aClippedPos.PositionY, 0 );
+ if( pPosHelper->isLogicVisible( aClippedPos.PositionX, aClippedPos.PositionY, aClippedPos.PositionZ ) )
+ {
+ AddPointToPoly( (*aSeriesIter)->m_aPolyPolygonShape3D, aClippedPos, (*aSeriesIter)->m_nPolygonIndex );
+ AddPointToPoly( (*aSeriesIter)->m_aPolyPolygonShape3D, aScaledLogicPosition, (*aSeriesIter)->m_nPolygonIndex );
+ }
+ }
+ }
+
+ //create a single datapoint if point is visible
+ //apply clipping:
+ if( !bIsVisible )
+ continue;
+
+ bool bCreateErrorBar = false;
+ {
+ uno::Reference< beans::XPropertySet > xErrorBarProp(pSeries->getYErrorBarProperties(nIndex));
+ if( xErrorBarProp.is() )
+ {
+ bool bShowPositive = false;
+ bool bShowNegative = false;
+ xErrorBarProp->getPropertyValue( C2U( "ShowPositiveError" )) >>= bShowPositive;
+ xErrorBarProp->getPropertyValue( C2U( "ShowNegativeError" )) >>= bShowNegative;
+ bCreateErrorBar = bShowPositive || bShowNegative;
+ }
+ }
+
+ Symbol* pSymbolProperties = m_bSymbol ? (*aSeriesIter)->getSymbolProperties( nIndex ) : 0;
+ bool bCreateSymbol = pSymbolProperties && (pSymbolProperties->Style != SymbolStyle_NONE);
+
+ if( !bCreateSymbol && !bCreateErrorBar && !pSeries->getDataPointLabelIfLabel(nIndex) )
+ continue;
+
+ //create a group shape for this point and add to the series shape:
+ rtl::OUString aPointCID = ObjectIdentifier::createPointCID(
+ (*aSeriesIter)->getPointCID_Stub(), nIndex );
+ uno::Reference< drawing::XShapes > xPointGroupShape_Shapes(
+ createGroupShape(xSeriesGroupShape_Shapes,aPointCID) );
+ uno::Reference<drawing::XShape> xPointGroupShape_Shape =
+ uno::Reference<drawing::XShape>( xPointGroupShape_Shapes, uno::UNO_QUERY );
+
+ {
+ nCreatedPoints++;
+
+ //create data point
+ drawing::Direction3D aSymbolSize(0,0,0);
+ if( bCreateSymbol )
+ {
+ if(m_nDimension!=3)
+ {
+ if( pSymbolProperties )
+ {
+ if( pSymbolProperties->Style != SymbolStyle_NONE )
+ {
+ aSymbolSize.DirectionX = pSymbolProperties->Size.Width;
+ aSymbolSize.DirectionY = pSymbolProperties->Size.Height;
+ }
+
+ if( pSymbolProperties->Style == SymbolStyle_STANDARD )
+ {
+ sal_Int32 nSymbol = pSymbolProperties->StandardSymbol;
+ m_pShapeFactory->createSymbol2D( xPointGroupShape_Shapes
+ , aScenePosition, aSymbolSize
+ , nSymbol
+ , pSymbolProperties->BorderColor
+ , pSymbolProperties->FillColor );
+ }
+ else if( pSymbolProperties->Style == SymbolStyle_GRAPHIC )
+ {
+ m_pShapeFactory->createGraphic2D( xPointGroupShape_Shapes
+ , aScenePosition , aSymbolSize
+ , pSymbolProperties->Graphic );
+ }
+ //@todo other symbol styles
+ }
+ }
+ }
+ //create error bar
+ createErrorBar_Y( aUnscaledLogicPosition, **aSeriesIter, nIndex, m_xErrorBarTarget );
+
+ //create data point label
+ if( (**aSeriesIter).getDataPointLabelIfLabel(nIndex) )
+ {
+ LabelAlignment eAlignment = LABEL_ALIGN_TOP;
+ drawing::Position3D aScenePosition3D( aScenePosition.PositionX
+ , aScenePosition.PositionY
+ , aScenePosition.PositionZ+this->getTransformedDepth() );
+
+ sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nIndex, m_xChartTypeModel, m_nDimension, pPosHelper->isSwapXAndY() );
+
+ switch(nLabelPlacement)
+ {
+ case ::com::sun::star::chart::DataLabelPlacement::TOP:
+ aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1);
+ eAlignment = LABEL_ALIGN_TOP;
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::BOTTOM:
+ aScenePosition3D.PositionY += (aSymbolSize.DirectionY/2+1);
+ eAlignment = LABEL_ALIGN_BOTTOM;
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::LEFT:
+ aScenePosition3D.PositionX -= (aSymbolSize.DirectionX/2+1);
+ eAlignment = LABEL_ALIGN_LEFT;
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::RIGHT:
+ aScenePosition3D.PositionX += (aSymbolSize.DirectionX/2+1);
+ eAlignment = LABEL_ALIGN_RIGHT;
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::CENTER:
+ eAlignment = LABEL_ALIGN_CENTER;
+ //todo implement this different for area charts
+ break;
+ default:
+ DBG_ERROR("this label alignment is not implemented yet");
+ aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1);
+ eAlignment = LABEL_ALIGN_TOP;
+ break;
+ }
+
+ awt::Point aScreenPosition2D;//get the screen position for the labels
+ sal_Int32 nOffset = 100; //todo maybe calculate this font height dependent
+ if( m_bIsPolarCooSys && nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::OUTSIDE )
+ {
+ PolarPlottingPositionHelper* pPolarPosHelper = dynamic_cast<PolarPlottingPositionHelper*>(pPosHelper);
+ if( pPolarPosHelper )
+ {
+ PolarLabelPositionHelper aPolarLabelPositionHelper(pPolarPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory);
+ aScreenPosition2D = awt::Point( aPolarLabelPositionHelper.getLabelScreenPositionAndAlignmentForLogicValues(
+ eAlignment, fLogicX, fLogicY, fLogicZ, nOffset ));
+ }
+ }
+ else
+ {
+ if(LABEL_ALIGN_CENTER==eAlignment || m_nDimension == 3 )
+ nOffset = 0;
+ aScreenPosition2D = awt::Point( LabelPositionHelper(pPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory)
+ .transformSceneToScreenPosition( aScenePosition3D ) );
+ }
+
+ this->createDataLabel( m_xTextTarget, **aSeriesIter, nIndex
+ , fLogicValueForLabeDisplay
+ , aLogicYSumMap[nAttachedAxisIndex], aScreenPosition2D, eAlignment, nOffset );
+ }
+ }
+
+ //remove PointGroupShape if empty
+ if(!xPointGroupShape_Shapes->getCount())
+ xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shape);
+
+ }//next series in x slot (next y slot)
+ }//next x slot
+ }//next z slot
+ }//next category
+//=============================================================================
+//=============================================================================
+//=============================================================================
+
+ impl_createSeriesShapes();
+
+ /* @todo remove series shapes if empty
+ //remove and delete point-group-shape if empty
+ if(!xSeriesGroupShape_Shapes->getCount())
+ {
+ (*aSeriesIter)->m_xShape.set(NULL);
+ m_xLogicTarget->remove(xSeriesGroupShape_Shape);
+ }
+ */
+
+ //remove and delete series-group-shape if empty
+
+ //... todo
+
+ OSL_TRACE( "\nPPPPPPPPP<<<<<<<<<<<< area chart :: createShapes():: skipped points: %d created points: %d", nSkippedPoints, nCreatedPoints );
+}
+
+//.............................................................................
+} //namespace chart
+//.............................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/AreaChart.hxx b/chart2/source/view/charttypes/AreaChart.hxx
new file mode 100644
index 000000000000..c3bd1ed3fbb4
--- /dev/null
+++ b/chart2/source/view/charttypes/AreaChart.hxx
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _CHART2_AREACHART_HXX
+#define _CHART2_AREACHART_HXX
+
+#include "VSeriesPlotter.hxx"
+#include <com/sun/star/chart2/CurveStyle.hpp>
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+class AreaPositionHelper;
+
+class AreaChart : public VSeriesPlotter
+{
+ //-------------------------------------------------------------------------
+ // public methods
+ //-------------------------------------------------------------------------
+public:
+ AreaChart( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::chart2::XChartType >& xChartTypeModel
+ , sal_Int32 nDimensionCount
+ , bool bCategoryXAxis, bool bNoArea=false
+ , PlottingPositionHelper* pPlottingPositionHelper=NULL //takes owner ship
+ , bool bConnectLastToFirstPoint=false
+ , bool bExpandIfValuesCloseToBorder=true
+ , sal_Int32 nKeepAspectRatio=-1 //0->no 1->yes other value->automatic
+ , const ::com::sun::star::drawing::Direction3D& rAspectRatio=::com::sun::star::drawing::Direction3D(1,1,1)//only taken into account if nKeepAspectRatio==1
+ );
+ virtual ~AreaChart();
+
+ //-------------------------------------------------------------------------
+ // chart2::XPlotter
+ //-------------------------------------------------------------------------
+
+ virtual void SAL_CALL createShapes();
+ /*
+ virtual ::rtl::OUString SAL_CALL getCoordinateSystemTypeID( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setScales( const ::com::sun::star::uno::Sequence< ::com::sun::star::chart2::ExplicitScaleData >& rScales ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setTransformation( const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTransformation >& xTransformationToLogicTarget, const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTransformation >& xTransformationToFinalPage ) throw (::com::sun::star::uno::RuntimeException);
+ */
+
+ virtual void addSeries( VDataSeries* pSeries, sal_Int32 zSlot = -1, sal_Int32 xSlot = -1,sal_Int32 ySlot = -1 );
+
+ //-------------------
+ virtual ::com::sun::star::drawing::Direction3D getPreferredDiagramAspectRatio() const;
+ virtual bool keepAspectRatio() const;
+
+ //-------------------------------------------------------------------------
+ // MinimumAndMaximumSupplier
+ //-------------------------------------------------------------------------
+ virtual double getMinimumX();
+ virtual double getMaximumX();
+ virtual bool isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex );
+ virtual bool isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex );
+
+ //-------------------------------------------------------------------------
+
+ virtual ::com::sun::star::chart2::LegendSymbolStyle getLegendSymbolStyle();
+ virtual ::com::sun::star::uno::Any getExplicitSymbol( const VDataSeries& rSeries, sal_Int32 nPointIndex=-1/*-1 for series symbol*/ );
+
+ //-------------------------------------------------------------------------
+ //-------------------------------------------------------------------------
+ //-------------------------------------------------------------------------
+private: //methods
+ //no default constructor
+ AreaChart();
+
+ void impl_createSeriesShapes();
+ bool impl_createArea( VDataSeries* pSeries
+ , ::com::sun::star::drawing::PolyPolygonShape3D* pSeriesPoly
+ , ::com::sun::star::drawing::PolyPolygonShape3D* pPreviousSeriesPoly
+ , PlottingPositionHelper* pPosHelper );
+ bool impl_createLine( VDataSeries* pSeries
+ , ::com::sun::star::drawing::PolyPolygonShape3D* pSeriesPoly
+ , PlottingPositionHelper* pPosHelper );
+
+private: //member
+ PlottingPositionHelper* m_pMainPosHelper;
+
+ bool m_bArea;//false -> line or symbol only
+ bool m_bLine;
+ bool m_bSymbol;
+ bool m_bIsPolarCooSys;//used e.g. for net chart (the data labels need to be placed different)
+ bool m_bConnectLastToFirstPoint;//used e.g. for net chart
+ bool m_bExpandIfValuesCloseToBorder; // e.g. false for net charts
+
+ sal_Int32 m_nKeepAspectRatio; //0->no 1->yes other value->automatic
+ ::com::sun::star::drawing::Direction3D m_aGivenAspectRatio; //only used if nKeepAspectRatio==1
+
+ //Properties for splines:
+ ::com::sun::star::chart2::CurveStyle m_eCurveStyle;
+ sal_Int32 m_nCurveResolution;
+ sal_Int32 m_nSplineOrder;
+
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShapes > m_xSeriesTarget;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShapes > m_xErrorBarTarget;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShapes > m_xTextTarget;
+ ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShapes > m_xRegressionCurveEquationTarget;
+};
+//.............................................................................
+} //namespace chart
+//.............................................................................
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/BarChart.cxx b/chart2/source/view/charttypes/BarChart.cxx
new file mode 100644
index 000000000000..cbcfd48f0f9d
--- /dev/null
+++ b/chart2/source/view/charttypes/BarChart.cxx
@@ -0,0 +1,969 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_chart2.hxx"
+
+#include "BarChart.hxx"
+#include "ShapeFactory.hxx"
+#include "CommonConverters.hxx"
+#include "ObjectIdentifier.hxx"
+#include "LabelPositionHelper.hxx"
+#include "BarPositionHelper.hxx"
+#include "macros.hxx"
+#include "AxisIndexDefines.hxx"
+#include "Clipping.hxx"
+
+#include <com/sun/star/chart/DataLabelPlacement.hpp>
+
+#include <com/sun/star/chart2/DataPointGeometry3D.hpp>
+#include <tools/debug.hxx>
+#include <rtl/math.hxx>
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+using namespace ::com::sun::star;
+using namespace ::rtl::math;
+using namespace ::com::sun::star::chart2;
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+BarChart::BarChart( const uno::Reference<XChartType>& xChartTypeModel
+ , sal_Int32 nDimensionCount )
+ : VSeriesPlotter( xChartTypeModel, nDimensionCount )
+ , m_pMainPosHelper( new BarPositionHelper() )
+{
+ PlotterBase::m_pPosHelper = m_pMainPosHelper;
+ VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper;
+
+ try
+ {
+ if( m_xChartTypeModelProps.is() )
+ {
+ m_xChartTypeModelProps->getPropertyValue( C2U( "OverlapSequence" ) ) >>= m_aOverlapSequence;
+ m_xChartTypeModelProps->getPropertyValue( C2U( "GapwidthSequence" ) ) >>= m_aGapwidthSequence;
+ }
+ }
+ catch( uno::Exception& e )
+ {
+ ASSERT_EXCEPTION( e );
+ }
+}
+
+BarChart::~BarChart()
+{
+ delete m_pMainPosHelper;
+}
+
+//-------------------------------------------------------------------------
+
+PlottingPositionHelper& BarChart::getPlottingPositionHelper( sal_Int32 nAxisIndex ) const
+{
+ PlottingPositionHelper& rPosHelper = VSeriesPlotter::getPlottingPositionHelper( nAxisIndex );
+
+ BarPositionHelper* pBarPosHelper = dynamic_cast<BarPositionHelper*>(&rPosHelper);
+ if( pBarPosHelper && nAxisIndex >= 0 )
+ {
+ if( nAxisIndex < m_aOverlapSequence.getLength() )
+ pBarPosHelper->setInnerDistance( -m_aOverlapSequence[nAxisIndex]/100.0 );
+ if( nAxisIndex < m_aGapwidthSequence.getLength() )
+ pBarPosHelper->setOuterDistance( m_aGapwidthSequence[nAxisIndex]/100.0 );
+ }
+
+ return rPosHelper;
+}
+
+drawing::Direction3D BarChart::getPreferredDiagramAspectRatio() const
+{
+ drawing::Direction3D aRet(1.0,1.0,1.0);
+ if( m_nDimension == 3 )
+ {
+ aRet = drawing::Direction3D(1.0,-1.0,1.0);
+ BarPositionHelper* pPosHelper = dynamic_cast<BarPositionHelper*>(&( this->getPlottingPositionHelper( MAIN_AXIS_INDEX) ) );
+ drawing::Direction3D aScale( pPosHelper->getScaledLogicWidth() );
+ if(aScale.DirectionX!=0.0)
+ {
+ double fXSlotCount = 1.0;
+ if(!m_aZSlots.empty())
+ fXSlotCount = m_aZSlots.begin()->size();
+
+ aRet.DirectionZ = aScale.DirectionZ/(aScale.DirectionX + aScale.DirectionX*(fXSlotCount-1.0)*pPosHelper->getSlotWidth());
+ }
+ else
+ return VSeriesPlotter::getPreferredDiagramAspectRatio();
+ if(aRet.DirectionZ<0.05)
+ aRet.DirectionZ=0.05;
+ if(aRet.DirectionZ>10)
+ aRet.DirectionZ=10;
+
+ if( m_pMainPosHelper && m_pMainPosHelper->isSwapXAndY() )
+ {
+ double fTemp = aRet.DirectionX;
+ aRet.DirectionX = aRet.DirectionY;
+ aRet.DirectionY = fTemp;
+ }
+ }
+ else
+ aRet = drawing::Direction3D(-1,-1,-1);
+ return aRet;
+}
+
+bool BarChart::keepAspectRatio() const
+{
+ if( m_nDimension == 3 )
+ return true;
+ return true;
+}
+
+//-------------------------------------------------------------------------
+// MinimumAndMaximumSupplier
+//-------------------------------------------------------------------------
+
+double BarChart::getMinimumX()
+{
+ if( m_bCategoryXAxis )
+ return 0.5;//first category (index 0) matches with real number 1.0
+ return VSeriesPlotter::getMinimumX();
+}
+double BarChart::getMaximumX()
+{
+ if( m_bCategoryXAxis )
+ {
+ //return category count
+ sal_Int32 nPointCount = getPointCount();
+ return nPointCount+0.5;//first category (index 0) matches with real number 1.0
+ }
+ return VSeriesPlotter::getMaximumX();
+}
+
+awt::Point BarChart::getLabelScreenPositionAndAlignment(
+ LabelAlignment& rAlignment, sal_Int32 nLabelPlacement
+ , double fScaledX, double fScaledLowerYValue, double fScaledUpperYValue, double fScaledZ
+ , double fScaledLowerBarDepth, double fScaledUpperBarDepth, double fBaseValue
+ , BarPositionHelper* pPosHelper
+ ) const
+{
+ double fX = fScaledX;
+ double fY = fScaledUpperYValue;
+ double fZ = fScaledZ;
+ bool bReverse = !pPosHelper->isMathematicalOrientationY();
+ bool bNormalOutside = (!bReverse == !!(fBaseValue < fScaledUpperYValue));
+ double fDepth = fScaledUpperBarDepth;
+
+ switch(nLabelPlacement)
+ {
+ case ::com::sun::star::chart::DataLabelPlacement::TOP:
+ {
+ if( !pPosHelper->isSwapXAndY() )
+ {
+ fY = bReverse ? fScaledLowerYValue : fScaledUpperYValue;
+ rAlignment = LABEL_ALIGN_TOP;
+ if(3==m_nDimension)
+ fDepth = bReverse ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
+ }
+ else
+ {
+ fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
+ rAlignment = LABEL_ALIGN_CENTER;
+ DBG_ERROR( "top label placement is not really supported by horizontal bar charts" );
+ }
+ }
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::BOTTOM:
+ {
+ if(!pPosHelper->isSwapXAndY())
+ {
+ fY = bReverse ? fScaledUpperYValue : fScaledLowerYValue;
+ rAlignment = LABEL_ALIGN_BOTTOM;
+ if(3==m_nDimension)
+ fDepth = bReverse ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
+ }
+ else
+ {
+ fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
+ rAlignment = LABEL_ALIGN_CENTER;
+ DBG_ERROR( "bottom label placement is not supported by horizontal bar charts" );
+ }
+ }
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::LEFT:
+ {
+ if( pPosHelper->isSwapXAndY() )
+ {
+ fY = bReverse ? fScaledUpperYValue : fScaledLowerYValue;
+ rAlignment = LABEL_ALIGN_LEFT;
+ if(3==m_nDimension)
+ fDepth = bReverse ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
+ }
+ else
+ {
+ fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
+ rAlignment = LABEL_ALIGN_CENTER;
+ DBG_ERROR( "left label placement is not supported by column charts" );
+ }
+ }
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::RIGHT:
+ {
+ if( pPosHelper->isSwapXAndY() )
+ {
+ fY = bReverse ? fScaledLowerYValue : fScaledUpperYValue;
+ rAlignment = LABEL_ALIGN_RIGHT;
+ if(3==m_nDimension)
+ fDepth = bReverse ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
+ }
+ else
+ {
+ fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
+ rAlignment = LABEL_ALIGN_CENTER;
+ DBG_ERROR( "right label placement is not supported by column charts" );
+ }
+ }
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::OUTSIDE:
+ {
+ fY = (fBaseValue < fScaledUpperYValue) ? fScaledUpperYValue : fScaledLowerYValue;
+ if( pPosHelper->isSwapXAndY() )
+ rAlignment = bNormalOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT;
+ else
+ rAlignment = bNormalOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM;
+ if(3==m_nDimension)
+ fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
+ }
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::INSIDE:
+ {
+ fY = (fBaseValue < fScaledUpperYValue) ? fScaledUpperYValue : fScaledLowerYValue;
+ if( pPosHelper->isSwapXAndY() )
+ rAlignment = bNormalOutside ? LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT;
+ else
+ rAlignment = bNormalOutside ? LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP;
+ if(3==m_nDimension)
+ fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth);
+ }
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::NEAR_ORIGIN:
+ {
+ fY = (fBaseValue < fScaledUpperYValue) ? fScaledLowerYValue : fScaledUpperYValue;
+ if( pPosHelper->isSwapXAndY() )
+ rAlignment = bNormalOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT;
+ else
+ rAlignment = bNormalOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM;
+ if(3==m_nDimension)
+ fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth);
+ }
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::CENTER:
+ fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0;
+ rAlignment = LABEL_ALIGN_CENTER;
+ if(3==m_nDimension)
+ fDepth = fabs(fScaledUpperBarDepth-fScaledLowerBarDepth)/2.0;
+ break;
+ default:
+ DBG_ERROR("this label alignment is not implemented yet");
+
+ break;
+ }
+ if(3==m_nDimension)
+ fZ -= fDepth/2.0;
+
+ drawing::Position3D aScenePosition3D( pPosHelper->
+ transformScaledLogicToScene( fX, fY, fZ, true ) );
+ return LabelPositionHelper(pPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory)
+ .transformSceneToScreenPosition( aScenePosition3D );
+}
+
+uno::Reference< drawing::XShape > BarChart::createDataPoint3D_Bar(
+ const uno::Reference< drawing::XShapes >& xTarget
+ , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize
+ , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree
+ , const uno::Reference< beans::XPropertySet >& xObjectProperties
+ , sal_Int32 nGeometry3D )
+{
+ bool bRoundedEdges = true;
+ try
+ {
+ if( xObjectProperties.is() )
+ {
+ sal_Int16 nPercentDiagonal = 0;
+ xObjectProperties->getPropertyValue( C2U( "PercentDiagonal" ) ) >>= nPercentDiagonal;
+ if( nPercentDiagonal < 5 )
+ bRoundedEdges = false;
+ }
+ }
+ catch( uno::Exception& e )
+ {
+ ASSERT_EXCEPTION( e );
+ }
+
+ uno::Reference< drawing::XShape > xShape(NULL);
+ switch( nGeometry3D )
+ {
+ case DataPointGeometry3D::CYLINDER:
+ xShape = m_pShapeFactory->createCylinder( xTarget, rPosition, rSize, nRotateZAngleHundredthDegree );
+ break;
+ case DataPointGeometry3D::CONE:
+ xShape = m_pShapeFactory->createCone( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree );
+ break;
+ case DataPointGeometry3D::PYRAMID:
+ xShape = m_pShapeFactory->createPyramid( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree>0
+ , xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
+ break;
+ case DataPointGeometry3D::CUBOID:
+ default:
+ xShape = m_pShapeFactory->createCube( xTarget, rPosition, rSize
+ , nRotateZAngleHundredthDegree, xObjectProperties
+ , PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), bRoundedEdges );
+ return xShape;
+ }
+ if( nGeometry3D != DataPointGeometry3D::PYRAMID )
+ this->setMappedProperties( xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
+ return xShape;
+}
+
+namespace
+{
+bool lcl_hasGeometry3DVariableWidth( sal_Int32 nGeometry3D )
+{
+ bool bRet = false;
+ switch( nGeometry3D )
+ {
+ case DataPointGeometry3D::PYRAMID:
+ case DataPointGeometry3D::CONE:
+ bRet = true;
+ break;
+ case DataPointGeometry3D::CUBOID:
+ case DataPointGeometry3D::CYLINDER:
+ default:
+ bRet = false;
+ break;
+ }
+ return bRet;
+}
+}// end anonymous namespace
+
+void BarChart::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
+{
+ if( !pSeries )
+ return;
+ if(m_nDimension==2)
+ {
+ //2ND_AXIS_IN_BARS put series on second scales to different z slot as temporary workaround
+ //this needs to be redesigned if 3d bars are also able to display secondary axes
+
+ sal_Int32 nAxisIndex = pSeries->getAttachedAxisIndex();
+ zSlot = nAxisIndex;
+
+ if( !pSeries->getGroupBarsPerAxis() )
+ zSlot = 0;
+ if(zSlot>=static_cast<sal_Int32>(m_aZSlots.size()))
+ m_aZSlots.resize(zSlot+1);
+ }
+ VSeriesPlotter::addSeries( pSeries, zSlot, xSlot, ySlot );
+}
+
+//better performance for big data
+struct FormerBarPoint
+{
+ FormerBarPoint( double fX, double fUpperY, double fLowerY, double fZ )
+ : m_fX(fX), m_fUpperY(fUpperY), m_fLowerY(fLowerY), m_fZ(fZ)
+ {}
+ FormerBarPoint()
+ {
+ ::rtl::math::setNan( &m_fX );
+ ::rtl::math::setNan( &m_fUpperY );
+ ::rtl::math::setNan( &m_fLowerY );
+ ::rtl::math::setNan( &m_fZ );
+ }
+
+ double m_fX;
+ double m_fUpperY;
+ double m_fLowerY;
+ double m_fZ;
+};
+
+void BarChart::adaptOverlapAndGapwidthForGroupBarsPerAxis()
+{
+ //adapt m_aOverlapSequence and m_aGapwidthSequence for the groupBarsPerAxis feature
+ //thus the different series use the same settings
+
+ VDataSeries* pFirstSeries = getFirstSeries();
+ if(pFirstSeries && !pFirstSeries->getGroupBarsPerAxis() )
+ {
+ sal_Int32 nAxisIndex = pFirstSeries->getAttachedAxisIndex();
+ sal_Int32 nN = 0;
+ sal_Int32 nUseThisIndex = nAxisIndex;
+ if( nUseThisIndex < 0 || nUseThisIndex >= m_aOverlapSequence.getLength() )
+ nUseThisIndex = 0;
+ for( nN = 0; nN < m_aOverlapSequence.getLength(); nN++ )
+ {
+ if(nN!=nUseThisIndex)
+ m_aOverlapSequence[nN] = m_aOverlapSequence[nUseThisIndex];
+ }
+
+ nUseThisIndex = nAxisIndex;
+ if( nUseThisIndex < 0 || nUseThisIndex >= m_aGapwidthSequence.getLength() )
+ nUseThisIndex = 0;
+ for( nN = 0; nN < m_aGapwidthSequence.getLength(); nN++ )
+ {
+ if(nN!=nUseThisIndex)
+ m_aGapwidthSequence[nN] = m_aGapwidthSequence[nUseThisIndex];
+ }
+ }
+}
+
+void BarChart::createShapes()
+{
+ if( m_aZSlots.begin() == m_aZSlots.end() ) //no series
+ return;
+
+ DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"BarChart is not proper initialized");
+ if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()))
+ return;
+
+ //the text labels should be always on top of the other series shapes
+ //therefore create an own group for the texts to move them to front
+ //(because the text group is created after the series group the texts are displayed on top)
+
+ //the regression curves should always be on top of the bars but beneath the text labels
+ //to achieve this the regression curve target is created after the series target and before the text target
+
+ uno::Reference< drawing::XShapes > xSeriesTarget(
+ createGroupShape( m_xLogicTarget,rtl::OUString() ));
+ uno::Reference< drawing::XShapes > xRegressionCurveTarget(
+ createGroupShape( m_xLogicTarget,rtl::OUString() ));
+ uno::Reference< drawing::XShapes > xTextTarget(
+ m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() ));
+
+
+ //---------------------------------------------
+ uno::Reference< drawing::XShapes > xRegressionCurveEquationTarget(
+ m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() ));
+ //check necessary here that different Y axis can not be stacked in the same group? ... hm?
+
+ double fLogicZ = 0.0;//as defined
+
+ bool bDrawConnectionLines = false;
+ bool bDrawConnectionLinesInited = false;
+ bool bOnlyConnectionLinesForThisPoint = false;
+
+ adaptOverlapAndGapwidthForGroupBarsPerAxis();
+
+ //better performance for big data
+ std::map< VDataSeries*, FormerBarPoint > aSeriesFormerPointMap;
+ m_bPointsWereSkipped = false;
+ sal_Int32 nSkippedPoints = 0;
+ sal_Int32 nCreatedPoints = 0;
+ //
+
+ //(@todo maybe different iteration for breaks in axis ?)
+ sal_Int32 nStartCategoryIndex = m_pMainPosHelper->getStartCategoryIndex(); // inclusive
+ sal_Int32 nEndCategoryIndex = m_pMainPosHelper->getEndCategoryIndex(); //inclusive
+//=============================================================================
+ //iterate through all shown categories
+ for( sal_Int32 nCatIndex = nStartCategoryIndex; nCatIndex < nEndCategoryIndex; nCatIndex++ )
+ {
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
+ const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
+
+ //sum up the values for all series in a complete z zlot per attached axis
+ ::std::map< sal_Int32, double > aLogicYSumMap;
+ for( ; aZSlotIter != aZSlotEnd; aZSlotIter++ )
+ {
+ ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+
+ for( aXSlotIter = aZSlotIter->begin(); aXSlotIter != aXSlotEnd; aXSlotIter++ )
+ {
+ sal_Int32 nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries();
+ if( aLogicYSumMap.find(nAttachedAxisIndex)==aLogicYSumMap.end() )
+ aLogicYSumMap[nAttachedAxisIndex]=0.0;
+
+ double fMinimumY = 0.0, fMaximumY = 0.0;
+ aXSlotIter->calculateYMinAndMaxForCategory( nCatIndex
+ , isSeperateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex );
+
+ if( !::rtl::math::isNan( fMaximumY ) && fMaximumY > 0)
+ aLogicYSumMap[nAttachedAxisIndex] += fMaximumY;
+ if( !::rtl::math::isNan( fMinimumY ) && fMinimumY < 0)
+ aLogicYSumMap[nAttachedAxisIndex] += fabs(fMinimumY);
+ }
+ }
+
+//=============================================================================
+ aZSlotIter = m_aZSlots.begin();
+ for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; aZSlotIter++, nZ++ )
+ {
+ ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+
+//=============================================================================
+ //iterate through all x slots in this category
+ double fSlotX=0;
+ for( aXSlotIter = aZSlotIter->begin(); aXSlotIter != aXSlotEnd; aXSlotIter++, fSlotX+=1.0 )
+ {
+ sal_Int32 nAttachedAxisIndex = 0;
+ BarPositionHelper* pPosHelper = m_pMainPosHelper;
+ if( aXSlotIter != aXSlotEnd )
+ {
+ nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries();
+ //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
+ pPosHelper = dynamic_cast<BarPositionHelper*>(&( this->getPlottingPositionHelper( nAttachedAxisIndex ) ) );
+ if(!pPosHelper)
+ pPosHelper = m_pMainPosHelper;
+ }
+ PlotterBase::m_pPosHelper = pPosHelper;
+
+ //update/create information for current group
+ pPosHelper->updateSeriesCount( aZSlotIter->size() );
+ double fLogicBaseWidth = pPosHelper->getSlotWidth();
+
+ ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
+
+ // get distance from base value to maximum and minimum
+
+ double fMinimumY = 0.0, fMaximumY = 0.0;
+ aXSlotIter->calculateYMinAndMaxForCategory( nCatIndex
+ , isSeperateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex );
+
+ double fLogicPositiveYSum = 0.0;
+ if( !::rtl::math::isNan( fMaximumY ) )
+ fLogicPositiveYSum = fMaximumY;
+
+ double fLogicNegativeYSum = 0.0;
+ if( !::rtl::math::isNan( fMinimumY ) )
+ fLogicNegativeYSum = fMinimumY;
+
+ if( pPosHelper->isPercentY() )
+ {
+ /* #i70395# fLogicPositiveYSum contains sum of all positive
+ values, if any, otherwise the highest negative value.
+ fLogicNegativeYSum contains sum of all negative values,
+ if any, otherwise the lowest positive value.
+ Afterwards, fLogicPositiveYSum will contain the maximum
+ (positive) value that is related to 100%. */
+
+ // do nothing if there are positive values only
+ if( fLogicNegativeYSum < 0.0 )
+ {
+ // fLogicPositiveYSum<0 => negative values only, use absolute of negative sum
+ if( fLogicPositiveYSum < 0.0 )
+ fLogicPositiveYSum = -fLogicNegativeYSum;
+ // otherwise there are positive and negative values, calculate total distance
+ else
+ fLogicPositiveYSum -= fLogicNegativeYSum;
+ }
+ fLogicNegativeYSum = 0.0;
+ }
+
+ double fBaseValue = 0.0;
+ if( !pPosHelper->isPercentY() && pSeriesList->size()<=1 )
+ fBaseValue = pPosHelper->getBaseValueY();
+ double fPositiveLogicYForNextSeries = fBaseValue;
+ double fNegativeLogicYForNextSeries = fBaseValue;
+
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
+ aSeriesIter = pSeriesList->begin();
+ //=============================================================================
+ //iterate through all series in this x slot
+ for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
+ {
+ VDataSeries* pSeries( *aSeriesIter );
+ if(!pSeries)
+ continue;
+
+ bOnlyConnectionLinesForThisPoint = false;
+
+ if(nCatIndex==nStartCategoryIndex)//do not create a regression line for each point
+ createRegressionCurvesShapes( **aSeriesIter, xRegressionCurveTarget, xRegressionCurveEquationTarget,
+ m_pPosHelper->maySkipPointsInRegressionCalculation());
+
+ if( !bDrawConnectionLinesInited )
+ {
+ bDrawConnectionLines = pSeries->getConnectBars();
+ if( m_nDimension==3 )
+ bDrawConnectionLines = false;
+ if( bDrawConnectionLines && pSeriesList->size()==1 )
+ {
+ //detect wether we have a stacked chart or not:
+ StackingDirection eDirection = pSeries->getStackingDirection();
+ if( eDirection != StackingDirection_Y_STACKING )
+ bDrawConnectionLines = false;
+ }
+ bDrawConnectionLinesInited = true;
+ }
+
+ //------------
+
+ uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes(
+ getSeriesGroupShape(*aSeriesIter, xSeriesTarget) );
+
+ //collect data point information (logic coordinates, style ):
+ double fLogicX = pPosHelper->getSlotPos( (*aSeriesIter)->getXValue( nCatIndex ), fSlotX );
+ double fLogicBarHeight = (*aSeriesIter)->getYValue( nCatIndex );
+ if( ::rtl::math::isNan( fLogicBarHeight )) //no value at this category
+ continue;
+
+ double fLogicValueForLabeDisplay = fLogicBarHeight;
+ fLogicBarHeight-=fBaseValue;
+
+ if( pPosHelper->isPercentY() )
+ {
+ if(fLogicPositiveYSum!=0.0)
+ fLogicBarHeight = fabs( fLogicBarHeight )/fLogicPositiveYSum;
+ else
+ fLogicBarHeight = 0.0;
+ }
+
+ //sort negative and positive values, to display them on different sides of the x axis
+ bool bPositive = fLogicBarHeight >= 0.0;
+ double fLowerYValue = bPositive ? fPositiveLogicYForNextSeries : fNegativeLogicYForNextSeries;
+ double fUpperYValue = fLowerYValue+fLogicBarHeight;
+ if( bPositive )
+ fPositiveLogicYForNextSeries += fLogicBarHeight;
+ else
+ fNegativeLogicYForNextSeries += fLogicBarHeight;
+
+ if(m_nDimension==3)
+ fLogicZ = nZ;
+
+ drawing::Position3D aUnscaledLogicPosition( fLogicX, fUpperYValue, fLogicZ );
+
+ //@todo ... start an iteration over the different breaks of the axis
+ //each subsystem may add an additional shape to form the whole point
+ //create a group shape for this point and add to the series shape:
+ // uno::Reference< drawing::XShapes > xPointGroupShape_Shapes( createGroupShape(xSeriesGroupShape_Shapes) );
+ // uno::Reference<drawing::XShape> xPointGroupShape_Shape =
+ // uno::Reference<drawing::XShape>( xPointGroupShape_Shapes, uno::UNO_QUERY );
+ //as long as we do not iterate we do not need to create an additional group for each point
+ uno::Reference< drawing::XShapes > xPointGroupShape_Shapes = xSeriesGroupShape_Shapes;
+ uno::Reference< beans::XPropertySet > xDataPointProperties( (*aSeriesIter)->getPropertiesOfPoint( nCatIndex ) );
+ sal_Int32 nGeometry3D = DataPointGeometry3D::CUBOID;
+ if(m_nDimension==3) try
+ {
+ xDataPointProperties->getPropertyValue( C2U( "Geometry3D" )) >>= nGeometry3D;
+ }
+ catch( uno::Exception& e )
+ {
+ ASSERT_EXCEPTION( e );
+ }
+
+ //@todo iterate through all subsystems to create partial points
+ {
+ //@todo select a suiteable PositionHelper for this subsystem
+ BarPositionHelper* pSubPosHelper = pPosHelper;
+
+ double fUnclippedUpperYValue = fUpperYValue;
+
+ //apply clipping to Y
+ if( !pPosHelper->clipYRange(fLowerYValue,fUpperYValue) )
+ {
+ if( bDrawConnectionLines )
+ bOnlyConnectionLinesForThisPoint = true;
+ else
+ continue;
+ }
+ //@todo clipping of X and Z is not fully integrated so far, as there is a need to create different objects
+
+ //apply scaling to Y before calculating width (necessary to maintain gradient in clipped objects)
+ pSubPosHelper->doLogicScaling(NULL,&fLowerYValue,NULL);
+ pSubPosHelper->doLogicScaling(NULL,&fUpperYValue,NULL);
+ //scaling of X and Z is not provided as the created objects should be symmetric in that dimensions
+
+ pSubPosHelper->doLogicScaling(NULL,&fUnclippedUpperYValue,NULL);
+
+ //calculate resulting width
+ double fCompleteHeight = bPositive ? fLogicPositiveYSum : fLogicNegativeYSum;
+ if( pPosHelper->isPercentY() )
+ fCompleteHeight = 1.0;
+ double fLogicBarWidth = fLogicBaseWidth;
+ double fTopHeight=approxSub(fCompleteHeight,fUpperYValue);
+ if(!bPositive)
+ fTopHeight=approxSub(fCompleteHeight,fLowerYValue);
+ double fLogicYStart = bPositive ? fLowerYValue : fUpperYValue;
+ double fMiddleHeight = fUpperYValue-fLowerYValue;
+ if(!bPositive)
+ fMiddleHeight*=-1.0;
+ double fLogicBarDepth = 0.5;
+ if(m_nDimension==3)
+ {
+ if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 )
+ {
+ double fHeight = fCompleteHeight-fLowerYValue;
+ if(!bPositive)
+ fHeight = fCompleteHeight-fUpperYValue;
+ fLogicBarWidth = fLogicBaseWidth*fHeight/(fCompleteHeight);
+ if(fLogicBarWidth<=0.0)
+ fLogicBarWidth=fLogicBaseWidth;
+ fLogicBarDepth = fLogicBarDepth*fHeight/(fCompleteHeight);
+ if(fLogicBarDepth<=0.0)
+ fLogicBarDepth*=-1.0;
+ }
+ }
+
+ //better performance for big data
+ FormerBarPoint aFormerPoint( aSeriesFormerPointMap[pSeries] );
+ pPosHelper->setCoordinateSystemResolution( m_aCoordinateSystemResolution );
+ if( !pSeries->isAttributedDataPoint(nCatIndex)
+ &&
+ pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fUpperY, aFormerPoint.m_fZ
+ , fLogicX, fUpperYValue, fLogicZ )
+ &&
+ pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fLowerY, aFormerPoint.m_fZ
+ , fLogicX, fLowerYValue, fLogicZ )
+ )
+ {
+ nSkippedPoints++;
+ m_bPointsWereSkipped = true;
+ continue;
+ }
+ aSeriesFormerPointMap[pSeries] = FormerBarPoint(fLogicX,fUpperYValue,fLowerYValue,fLogicZ);
+ //
+
+ //
+ if( bDrawConnectionLines )
+ {
+ //store point information for connection lines
+
+ drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ );
+ drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ );
+
+ if( isValidPosition(aLeftUpperPoint) )
+ AddPointToPoly( (*aSeriesIter)->m_aPolyPolygonShape3D, aLeftUpperPoint );
+ if( isValidPosition(aRightUpperPoint) )
+ AddPointToPoly( (*aSeriesIter)->m_aPolyPolygonShape3D, aRightUpperPoint );
+ }
+
+ if( bOnlyConnectionLinesForThisPoint )
+ continue;
+
+ //maybe additional possibility for performance improvement
+ //bool bCreateLineInsteadOfComplexGeometryDueToMissingSpace = false;
+ //pPosHelper->isSameForGivenResolution( fLogicX-fLogicBarWidth/2.0, fLowerYValue, fLogicZ
+ // , fLogicX+fLogicBarWidth/2.0, fLowerYValue, fLogicZ );
+
+ nCreatedPoints++;
+ //create partial point
+ if( !approxEqual(fLowerYValue,fUpperYValue) )
+ {
+ uno::Reference< drawing::XShape > xShape;
+ if( m_nDimension==3 )
+ {
+ drawing::Position3D aLogicBottom (fLogicX,fLogicYStart,fLogicZ);
+ drawing::Position3D aLogicLeftBottomFront (fLogicX+fLogicBarWidth/2.0,fLogicYStart,fLogicZ-fLogicBarDepth/2.0);
+ drawing::Position3D aLogicRightDeepTop (fLogicX-fLogicBarWidth/2.0,fLogicYStart+fMiddleHeight,fLogicZ+fLogicBarDepth/2.0);
+ drawing::Position3D aLogicTopTop (fLogicX,fLogicYStart+fMiddleHeight+fTopHeight,fLogicZ);
+
+ uno::Reference< XTransformation > xTransformation = pSubPosHelper->getTransformationScaledLogicToScene();
+
+ //transformation 3) -> 4)
+ drawing::Position3D aTransformedBottom ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicBottom) ) ) );
+ drawing::Position3D aTransformedLeftBottomFront ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicLeftBottomFront) ) ) );
+ drawing::Position3D aTransformedRightDeepTop ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicRightDeepTop) ) ) );
+ drawing::Position3D aTransformedTopTop ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicTopTop) ) ) );
+
+ drawing::Direction3D aSize = aTransformedRightDeepTop - aTransformedLeftBottomFront;
+ drawing::Direction3D aTopSize( aTransformedTopTop - aTransformedRightDeepTop );
+ fTopHeight = aTopSize.DirectionY;
+
+ sal_Int32 nRotateZAngleHundredthDegree = 0;
+ if( pPosHelper->isSwapXAndY() )
+ {
+ fTopHeight = aTopSize.DirectionX;
+ nRotateZAngleHundredthDegree = 90*100;
+ aSize = drawing::Direction3D(aSize.DirectionY,aSize.DirectionX,aSize.DirectionZ);
+ }
+
+ if( aSize.DirectionX < 0 )
+ aSize.DirectionX *= -1.0;
+ if( aSize.DirectionZ < 0 )
+ aSize.DirectionZ *= -1.0;
+ if( fTopHeight < 0 )
+ fTopHeight *= -1.0;
+
+ xShape = createDataPoint3D_Bar(
+ xPointGroupShape_Shapes, aTransformedBottom, aSize, fTopHeight, nRotateZAngleHundredthDegree
+ , xDataPointProperties, nGeometry3D );
+ }
+ else //m_nDimension!=3
+ {
+ drawing::PolyPolygonShape3D aPoly;
+ drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUpperYValue,fLogicZ );
+ drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUpperYValue,fLogicZ );
+
+ AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
+ AddPointToPoly( aPoly, drawing::Position3D( fLogicX+fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
+ AddPointToPoly( aPoly, aRightUpperPoint );
+ AddPointToPoly( aPoly, aLeftUpperPoint );
+ AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
+ pPosHelper->transformScaledLogicToScene( aPoly );
+ xShape = m_pShapeFactory->createArea2D( xPointGroupShape_Shapes, aPoly );
+ this->setMappedProperties( xShape, xDataPointProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
+ }
+ //set name/classified ObjectID (CID)
+ ShapeFactory::setShapeName(xShape
+ , ObjectIdentifier::createPointCID(
+ (*aSeriesIter)->getPointCID_Stub(),nCatIndex) );
+ }
+
+ //create error bar
+ createErrorBar_Y( aUnscaledLogicPosition, **aSeriesIter, nCatIndex, m_xLogicTarget );
+
+ //------------
+ //create data point label
+ if( (**aSeriesIter).getDataPointLabelIfLabel(nCatIndex) )
+ {
+ double fLogicSum = aLogicYSumMap[nAttachedAxisIndex];
+
+ LabelAlignment eAlignment(LABEL_ALIGN_CENTER);
+ sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nCatIndex, m_xChartTypeModel, m_nDimension, pPosHelper->isSwapXAndY() );
+
+ double fLowerBarDepth = fLogicBarDepth;
+ double fUpperBarDepth = fLogicBarDepth;
+ {
+ double fOuterBarDepth = fLogicBarDepth;
+ if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 )
+ {
+ fOuterBarDepth = fLogicBarDepth * (fTopHeight)/(fabs(fCompleteHeight));
+ fLowerBarDepth = (fBaseValue < fUpperYValue) ? fabs(fLogicBarDepth) : fabs(fOuterBarDepth);
+ fUpperBarDepth = (fBaseValue < fUpperYValue) ? fabs(fOuterBarDepth) : fabs(fLogicBarDepth);
+ }
+ }
+
+ awt::Point aScreenPosition2D( this->getLabelScreenPositionAndAlignment(
+ eAlignment, nLabelPlacement
+ , fLogicX, fLowerYValue, fUpperYValue, fLogicZ
+ , fLowerBarDepth, fUpperBarDepth, fBaseValue, pPosHelper ));
+ sal_Int32 nOffset = 0;
+ if(LABEL_ALIGN_CENTER!=eAlignment)
+ {
+ nOffset = 100;//add some spacing //@todo maybe get more intelligent values
+ if( m_nDimension == 3 )
+ nOffset = 260;
+ }
+ this->createDataLabel( xTextTarget, **aSeriesIter, nCatIndex
+ , fLogicValueForLabeDisplay, fLogicSum, aScreenPosition2D, eAlignment, nOffset );
+ }
+
+ }//end iteration through partial points
+
+ }//next series in x slot (next y slot)
+ }//next x slot
+ }//next z slot
+ }//next category
+//=============================================================================
+//=============================================================================
+//=============================================================================
+ if( bDrawConnectionLines )
+ {
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
+ const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
+//=============================================================================
+ for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; aZSlotIter++, nZ++ )
+ {
+ ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+
+ BarPositionHelper* pPosHelper = m_pMainPosHelper;
+ if( aXSlotIter != aXSlotEnd )
+ {
+ sal_Int32 nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries();
+ //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
+ pPosHelper = dynamic_cast<BarPositionHelper*>(&( this->getPlottingPositionHelper( nAttachedAxisIndex ) ) );
+ if(!pPosHelper)
+ pPosHelper = m_pMainPosHelper;
+ }
+ PlotterBase::m_pPosHelper = pPosHelper;
+
+//=============================================================================
+ //iterate through all x slots in this category
+ for( double fSlotX=0; aXSlotIter != aXSlotEnd; aXSlotIter++, fSlotX+=1.0 )
+ {
+ ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
+
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
+ aSeriesIter = pSeriesList->begin();
+//=============================================================================
+ //iterate through all series in this x slot
+ for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
+ {
+ VDataSeries* pSeries( *aSeriesIter );
+ if(!pSeries)
+ continue;
+ drawing::PolyPolygonShape3D* pSeriesPoly = &pSeries->m_aPolyPolygonShape3D;
+ if(!ShapeFactory::hasPolygonAnyLines(*pSeriesPoly))
+ continue;
+
+ drawing::PolyPolygonShape3D aPoly;
+ Clipping::clipPolygonAtRectangle( *pSeriesPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly );
+
+ if(!ShapeFactory::hasPolygonAnyLines(aPoly))
+ continue;
+
+ //transformation 3) -> 4)
+ pPosHelper->transformScaledLogicToScene( aPoly );
+
+ uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes(
+ getSeriesGroupShape(*aSeriesIter, xSeriesTarget) );
+ uno::Reference< drawing::XShape > xShape( m_pShapeFactory->createLine2D(
+ xSeriesGroupShape_Shapes, PolyToPointSequence( aPoly ) ) );
+ this->setMappedProperties( xShape, pSeries->getPropertiesOfSeries()
+ , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
+ }
+ }
+ }
+ }
+
+ /* @todo remove series shapes if empty
+ //remove and delete point-group-shape if empty
+ if(!xSeriesGroupShape_Shapes->getCount())
+ {
+ (*aSeriesIter)->m_xShape.set(NULL);
+ m_xLogicTarget->remove(xSeriesGroupShape_Shape);
+ }
+ */
+
+ //remove and delete series-group-shape if empty
+
+ //... todo
+
+ OSL_TRACE( "\nPPPPPPPPP<<<<<<<<<<<< bar chart :: createShapes():: skipped points: %d created points: %d", nSkippedPoints, nCreatedPoints );
+}
+
+//.............................................................................
+} //namespace chart
+//.............................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/BarChart.hxx b/chart2/source/view/charttypes/BarChart.hxx
new file mode 100644
index 000000000000..cfd3c0e618ce
--- /dev/null
+++ b/chart2/source/view/charttypes/BarChart.hxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _CHART2_BARCHART_HXX
+#define _CHART2_BARCHART_HXX
+
+#include "VSeriesPlotter.hxx"
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+class BarPositionHelper;
+
+class BarChart : public VSeriesPlotter
+{
+ //-------------------------------------------------------------------------
+ // public methods
+ //-------------------------------------------------------------------------
+public:
+ BarChart( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::chart2::XChartType >& xChartTypeModel
+ , sal_Int32 nDimensionCount );
+ virtual ~BarChart();
+
+ //-------------------------------------------------------------------------
+ // chart2::XPlotter
+ //-------------------------------------------------------------------------
+
+ virtual void SAL_CALL createShapes();
+ /*
+ virtual ::rtl::OUString SAL_CALL getCoordinateSystemTypeID( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setScales( const ::com::sun::star::uno::Sequence< ::com::sun::star::chart2::ExplicitScaleData >& rScales ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setTransformation( const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTransformation >& xTransformationToLogicTarget, const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTransformation >& xTransformationToFinalPage ) throw (::com::sun::star::uno::RuntimeException);
+ */
+
+ virtual void addSeries( VDataSeries* pSeries, sal_Int32 zSlot = -1, sal_Int32 xSlot = -1,sal_Int32 ySlot = -1 );
+
+ //-------------------
+ virtual ::com::sun::star::drawing::Direction3D getPreferredDiagramAspectRatio() const;
+ virtual bool keepAspectRatio() const;
+
+ //-------------------------------------------------------------------------
+ // MinimumAndMaximumSupplier
+ //-------------------------------------------------------------------------
+ virtual double getMinimumX();
+ virtual double getMaximumX();
+
+ //-------------------------------------------------------------------------
+ //-------------------------------------------------------------------------
+ //-------------------------------------------------------------------------
+
+private: //methods
+ //no default constructor
+ BarChart();
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
+ createDataPoint3D_Bar(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShapes >& xTarget
+ , const ::com::sun::star::drawing::Position3D& rPosition
+ , const ::com::sun::star::drawing::Direction3D& rSize
+ , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree
+ , const ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertySet >& xObjectProperties
+ , sal_Int32 nGeometry3D );
+
+ ::com::sun::star::awt::Point getLabelScreenPositionAndAlignment(
+ LabelAlignment& rAlignment, sal_Int32 nLabelPlacement
+ , double fScaledX, double fScaledLowerYValue, double fScaledUpperYValue, double fScaledZ
+ , double fScaledLowerBarDepth, double fScaledUpperBarDepth, double fBaseValue
+ , BarPositionHelper* pPosHelper ) const;
+
+ virtual PlottingPositionHelper& getPlottingPositionHelper( sal_Int32 nAxisIndex ) const;//nAxisIndex indicates wether the position belongs to the main axis ( nAxisIndex==0 ) or secondary axis ( nAxisIndex==1 )
+
+ void adaptOverlapAndGapwidthForGroupBarsPerAxis();
+
+private: //member
+ BarPositionHelper* m_pMainPosHelper;
+ ::com::sun::star::uno::Sequence< sal_Int32 > m_aOverlapSequence;
+ ::com::sun::star::uno::Sequence< sal_Int32 > m_aGapwidthSequence;
+};
+//.............................................................................
+} //namespace chart
+//.............................................................................
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/BarPositionHelper.cxx b/chart2/source/view/charttypes/BarPositionHelper.cxx
new file mode 100644
index 000000000000..271e0c5dd636
--- /dev/null
+++ b/chart2/source/view/charttypes/BarPositionHelper.cxx
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_chart2.hxx"
+
+#include "BarPositionHelper.hxx"
+#include "Linear3DTransformation.hxx"
+#include "ViewDefines.hxx"
+#include "CommonConverters.hxx"
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+
+BarPositionHelper::BarPositionHelper( bool /* bSwapXAndY */ )
+ : CategoryPositionHelper( 1 )
+{
+}
+
+BarPositionHelper::BarPositionHelper( const BarPositionHelper& rSource )
+ : CategoryPositionHelper( rSource )
+ , PlottingPositionHelper( rSource )
+{
+}
+
+BarPositionHelper::~BarPositionHelper()
+{
+}
+
+PlottingPositionHelper* BarPositionHelper::clone() const
+{
+ BarPositionHelper* pRet = new BarPositionHelper(*this);
+ return pRet;
+}
+
+void BarPositionHelper::updateSeriesCount( double fSeriesCount )
+{
+ m_fSeriesCount = fSeriesCount;
+}
+
+uno::Reference< XTransformation > BarPositionHelper::getTransformationScaledLogicToScene() const
+{
+ //transformation from 2) to 4) //@todo 2) and 4) need a link to a document
+
+ //we need to apply this transformation to each geometric object because of a bug/problem
+ //of the old drawing layer (the UNO_NAME_3D_EXTRUDE_DEPTH is an integer value instead of an double )
+
+ if( !m_xTransformationLogicToScene.is() )
+ {
+ ::basegfx::B3DHomMatrix aMatrix;
+
+ double MinX = getLogicMinX();
+ double MinY = getLogicMinY();
+ double MinZ = getLogicMinZ();
+ double MaxX = getLogicMaxX();
+ double MaxY = getLogicMaxY();
+ double MaxZ = getLogicMaxZ();
+
+ AxisOrientation nXAxisOrientation = m_aScales[0].Orientation;
+ AxisOrientation nYAxisOrientation = m_aScales[1].Orientation;
+ AxisOrientation nZAxisOrientation = m_aScales[2].Orientation;
+
+ //apply scaling
+ //scaling of x axis is refused/ignored
+ doLogicScaling( NULL, &MinY, &MinZ );
+ doLogicScaling( NULL, &MaxY, &MaxZ);
+
+ if(m_bSwapXAndY)
+ {
+ std::swap(MinX,MinY);
+ std::swap(MaxX,MaxY);
+ std::swap(nXAxisOrientation,nYAxisOrientation);
+ }
+
+ if( AxisOrientation_MATHEMATICAL==nXAxisOrientation )
+ aMatrix.translate(-MinX,0.0,0.0);
+ else
+ aMatrix.translate(-MaxX,0.0,0.0);
+ if( AxisOrientation_MATHEMATICAL==nYAxisOrientation )
+ aMatrix.translate(0.0,-MinY,0.0);
+ else
+ aMatrix.translate(0.0,-MaxY,0.0);
+ if( AxisOrientation_MATHEMATICAL==nZAxisOrientation )
+ aMatrix.translate(0.0,0.0,-MaxZ);//z direction in draw is reverse mathematical direction
+ else
+ aMatrix.translate(0.0,0.0,-MinZ);
+
+ double fWidthX = MaxX - MinX;
+ double fWidthY = MaxY - MinY;
+ double fWidthZ = MaxZ - MinZ;
+
+ double fScaleDirectionX = AxisOrientation_MATHEMATICAL==nXAxisOrientation ? 1.0 : -1.0;
+ double fScaleDirectionY = AxisOrientation_MATHEMATICAL==nYAxisOrientation ? 1.0 : -1.0;
+ double fScaleDirectionZ = AxisOrientation_MATHEMATICAL==nZAxisOrientation ? -1.0 : 1.0;
+
+ aMatrix.scale(fScaleDirectionX*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthX
+ , fScaleDirectionY*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthY
+ , fScaleDirectionZ*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthZ);
+
+ //if(nDim==2)
+ aMatrix = m_aMatrixScreenToScene*aMatrix;
+
+ m_xTransformationLogicToScene = new Linear3DTransformation(B3DHomMatrixToHomogenMatrix( aMatrix ),m_bSwapXAndY);
+ }
+ return m_xTransformationLogicToScene;
+}
+
+//.............................................................................
+} //namespace chart
+//.............................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/BarPositionHelper.hxx b/chart2/source/view/charttypes/BarPositionHelper.hxx
new file mode 100644
index 000000000000..293a277cd332
--- /dev/null
+++ b/chart2/source/view/charttypes/BarPositionHelper.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _CHART2_BARPOSITIONHELPER_HXX
+#define _CHART2_BARPOSITIONHELPER_HXX
+
+#include "PlottingPositionHelper.hxx"
+#include "CategoryPositionHelper.hxx"
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+
+//-----------------------------------------------------------------------------
+/**
+*/
+
+class BarPositionHelper : public CategoryPositionHelper, public PlottingPositionHelper
+{
+public:
+ BarPositionHelper( bool bSwapXAndY=true );
+ BarPositionHelper( const BarPositionHelper& rSource );
+ virtual ~BarPositionHelper();
+
+ virtual PlottingPositionHelper* clone() const;
+
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTransformation >
+ getTransformationScaledLogicToScene() const;
+
+ void updateSeriesCount( double fSeriesCount ); /*only enter the size of x stacked series*/
+
+ sal_Int32 getStartCategoryIndex() const {
+ //first category (index 0) matches with real number 1.0
+ sal_Int32 nStart = static_cast<sal_Int32>(getLogicMinX() - 0.5);
+ if( nStart < 0 )
+ nStart = 0;
+ return nStart;
+ }
+ sal_Int32 getEndCategoryIndex() const {
+ //first category (index 0) matches with real number 1.0
+ sal_Int32 nEnd = static_cast<sal_Int32>(getLogicMaxX() - 0.5);
+ if( nEnd < 0 )
+ nEnd = 0;
+ return nEnd;
+ }
+};
+
+//.............................................................................
+} //namespace chart
+//.............................................................................
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/BubbleChart.cxx b/chart2/source/view/charttypes/BubbleChart.cxx
new file mode 100644
index 000000000000..27b952938b82
--- /dev/null
+++ b/chart2/source/view/charttypes/BubbleChart.cxx
@@ -0,0 +1,420 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_chart2.hxx"
+
+#include "BubbleChart.hxx"
+#include "PlottingPositionHelper.hxx"
+#include "ShapeFactory.hxx"
+#include "CommonConverters.hxx"
+#include "macros.hxx"
+#include "ViewDefines.hxx"
+#include "ObjectIdentifier.hxx"
+#include "Splines.hxx"
+#include "LabelPositionHelper.hxx"
+#include "Clipping.hxx"
+#include "Stripe.hxx"
+
+#include <com/sun/star/chart2/Symbol.hpp>
+#include <com/sun/star/chart/DataLabelPlacement.hpp>
+#include <tools/debug.hxx>
+#include <editeng/unoprnms.hxx>
+#include <rtl/math.hxx>
+#include <com/sun/star/drawing/DoubleSequence.hpp>
+#include <com/sun/star/drawing/NormalsKind.hpp>
+#include <com/sun/star/lang/XServiceName.hpp>
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+using namespace ::com::sun::star;
+using namespace ::rtl::math;
+using namespace ::com::sun::star::chart2;
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+BubbleChart::BubbleChart( const uno::Reference<XChartType>& xChartTypeModel
+ , sal_Int32 nDimensionCount )
+ : VSeriesPlotter( xChartTypeModel, nDimensionCount, false )
+ , m_bShowNegativeValues(false)
+ , m_bBubbleSizeAsArea(true)
+ , m_fBubbleSizeScaling(1.0)
+ , m_fMaxLogicBubbleSize( 0.0 )
+ , m_fBubbleSizeFactorToScreen( 1.0 )
+{
+ if( !m_pMainPosHelper )
+ m_pMainPosHelper = new PlottingPositionHelper();
+ PlotterBase::m_pPosHelper = m_pMainPosHelper;
+ VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper;
+}
+
+BubbleChart::~BubbleChart()
+{
+ delete m_pMainPosHelper;
+}
+
+void BubbleChart::calculateMaximumLogicBubbleSize()
+{
+ double fMaxSize = 0.0;
+
+ sal_Int32 nStartIndex = 0;
+ sal_Int32 nEndIndex = VSeriesPlotter::getPointCount();
+ for( sal_Int32 nIndex = nStartIndex; nIndex < nEndIndex; nIndex++ )
+ {
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
+ const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
+ for( ; aZSlotIter != aZSlotEnd; aZSlotIter++ )
+ {
+ ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+ for( ; aXSlotIter != aXSlotEnd; aXSlotIter++ )
+ {
+ ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
+ for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
+ {
+ VDataSeries* pSeries( *aSeriesIter );
+ if(!pSeries)
+ continue;
+
+ double fSize = pSeries->getBubble_Size( nIndex );
+ if( m_bShowNegativeValues )
+ fSize = fabs(fSize);
+ if( fSize > fMaxSize )
+ fMaxSize = fSize;
+ }
+ }
+ }
+ }
+
+ m_fMaxLogicBubbleSize = fMaxSize;
+}
+
+void BubbleChart::calculateBubbleSizeScalingFactor()
+{
+ double fLogicZ=0.5;
+ drawing::Position3D aSceneMinPos( m_pMainPosHelper->transformLogicToScene( m_pMainPosHelper->getLogicMinX(),m_pMainPosHelper->getLogicMinY(),fLogicZ, false ) );
+ drawing::Position3D aSceneMaxPos( m_pMainPosHelper->transformLogicToScene( m_pMainPosHelper->getLogicMaxX(),m_pMainPosHelper->getLogicMaxY(),fLogicZ, false ) );
+
+ awt::Point aScreenMinPos( LabelPositionHelper(m_pMainPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory).transformSceneToScreenPosition( aSceneMinPos ) );
+ awt::Point aScreenMaxPos( LabelPositionHelper(m_pMainPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory).transformSceneToScreenPosition( aSceneMaxPos ) );
+
+ sal_Int32 nWidth = abs( aScreenMaxPos.X - aScreenMinPos.X );
+ sal_Int32 nHeight = abs( aScreenMaxPos.Y - aScreenMinPos.Y );
+
+ sal_Int32 nMinExtend = std::min( nWidth, nHeight );
+ m_fBubbleSizeFactorToScreen = nMinExtend * 0.25;//max bubble size is 25 percent of diagram size
+}
+
+drawing::Direction3D BubbleChart::transformToScreenBubbleSize( double fLogicSize )
+{
+ drawing::Direction3D aRet(0,0,0);
+
+ if( ::rtl::math::isNan(fLogicSize) || ::rtl::math::isInf(fLogicSize) )
+ return aRet;
+
+ if( m_bShowNegativeValues )
+ fLogicSize = fabs(fLogicSize);
+
+ double fMaxSize = m_fMaxLogicBubbleSize;
+
+ double fMaxRadius = fMaxSize;
+ double fRaduis = fLogicSize;
+ if( m_bBubbleSizeAsArea )
+ {
+ fMaxRadius = sqrt( fMaxSize / F_PI );
+ fRaduis = sqrt( fLogicSize / F_PI );
+ }
+
+ aRet.DirectionX = m_fBubbleSizeScaling * m_fBubbleSizeFactorToScreen * fRaduis / fMaxRadius;
+ aRet.DirectionY = aRet.DirectionX;
+
+ return aRet;
+}
+
+bool BubbleChart::isExpandIfValuesCloseToBorder( sal_Int32 /*nDimensionIndex*/ )
+{
+ return true;
+}
+
+bool BubbleChart::isSeperateStackingForDifferentSigns( sal_Int32 /*nDimensionIndex*/ )
+{
+ return false;
+}
+
+//-----------------------------------------------------------------
+
+LegendSymbolStyle BubbleChart::getLegendSymbolStyle()
+{
+ return chart2::LegendSymbolStyle_CIRCLE;
+}
+
+drawing::Direction3D BubbleChart::getPreferredDiagramAspectRatio() const
+{
+ return drawing::Direction3D(-1,-1,-1);
+}
+
+void BubbleChart::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
+{
+ VSeriesPlotter::addSeries( pSeries, zSlot, xSlot, ySlot );
+}
+
+//better performance for big data
+struct FormerPoint
+{
+ FormerPoint( double fX, double fY, double fZ )
+ : m_fX(fX), m_fY(fY), m_fZ(fZ)
+ {}
+ FormerPoint()
+ {
+ ::rtl::math::setNan( &m_fX );
+ ::rtl::math::setNan( &m_fY );
+ ::rtl::math::setNan( &m_fZ );
+ }
+
+ double m_fX;
+ double m_fY;
+ double m_fZ;
+};
+
+void BubbleChart::createShapes()
+{
+ if( m_aZSlots.begin() == m_aZSlots.end() ) //no series
+ return;
+
+ DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"BubbleChart is not proper initialized");
+ if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()))
+ return;
+
+ //therefore create an own group for the texts and the error bars to move them to front
+ //(because the text group is created after the series group the texts are displayed on top)
+ uno::Reference< drawing::XShapes > xSeriesTarget(
+ createGroupShape( m_xLogicTarget,rtl::OUString() ));
+ uno::Reference< drawing::XShapes > xTextTarget(
+ m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() ));
+
+ //update/create information for current group
+ double fLogicZ = 0.5;//as defined
+
+ sal_Int32 nStartIndex = 0; // inclusive ;..todo get somehow from x scale
+ sal_Int32 nEndIndex = VSeriesPlotter::getPointCount();
+ if(nEndIndex<=0)
+ nEndIndex=1;
+
+ //better performance for big data
+ std::map< VDataSeries*, FormerPoint > aSeriesFormerPointMap;
+ m_bPointsWereSkipped = false;
+ sal_Int32 nSkippedPoints = 0;
+ sal_Int32 nCreatedPoints = 0;
+ //
+
+ calculateMaximumLogicBubbleSize();
+ calculateBubbleSizeScalingFactor();
+ if( m_fMaxLogicBubbleSize <= 0 || m_fBubbleSizeFactorToScreen <= 0 )
+ return;
+
+//=============================================================================
+ //iterate through all x values per indices
+ for( sal_Int32 nIndex = nStartIndex; nIndex < nEndIndex; nIndex++ )
+ {
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
+ const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
+
+ aZSlotIter = m_aZSlots.begin();
+ for( sal_Int32 nZ=1; aZSlotIter != aZSlotEnd; aZSlotIter++, nZ++ )
+ {
+ ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+
+ aXSlotIter = aZSlotIter->begin();
+ for( sal_Int32 nX=0; aXSlotIter != aXSlotEnd; aXSlotIter++, nX++ )
+ {
+ ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
+
+ //=============================================================================
+ //iterate through all series
+ for( sal_Int32 nSeriesIndex = 0; aSeriesIter != aSeriesEnd; aSeriesIter++, nSeriesIndex++ )
+ {
+ VDataSeries* pSeries( *aSeriesIter );
+ if(!pSeries)
+ continue;
+
+ uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShape(*aSeriesIter, xSeriesTarget);
+
+ sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex();
+ PlottingPositionHelper* pPosHelper = &(this->getPlottingPositionHelper( nAttachedAxisIndex ));
+ if(!pPosHelper)
+ pPosHelper = m_pMainPosHelper;
+ PlotterBase::m_pPosHelper = pPosHelper;
+
+ if(m_nDimension==3)
+ fLogicZ = nZ+0.5;
+
+ //collect data point information (logic coordinates, style ):
+ double fLogicX = pSeries->getXValue(nIndex);
+ double fLogicY = pSeries->getYValue(nIndex);
+ double fBubbleSize = pSeries->getBubble_Size( nIndex );
+
+ if( !m_bShowNegativeValues && fBubbleSize<0.0 )
+ continue;
+
+ if( ::rtl::math::approxEqual( fBubbleSize, 0.0 ) || ::rtl::math::isNan(fBubbleSize) )
+ continue;
+
+ if( ::rtl::math::isNan(fLogicX) || ::rtl::math::isInf(fLogicX)
+ || ::rtl::math::isNan(fLogicY) || ::rtl::math::isInf(fLogicY) )
+ continue;
+
+ bool bIsVisible = pPosHelper->isLogicVisible( fLogicX, fLogicY, fLogicZ );
+
+ drawing::Position3D aUnscaledLogicPosition( fLogicX, fLogicY, fLogicZ );
+ drawing::Position3D aScaledLogicPosition(aUnscaledLogicPosition);
+ pPosHelper->doLogicScaling( aScaledLogicPosition );
+
+ //transformation 3) -> 4)
+ drawing::Position3D aScenePosition( pPosHelper->transformLogicToScene( fLogicX,fLogicY,fLogicZ, false ) );
+
+ //better performance for big data
+ FormerPoint aFormerPoint( aSeriesFormerPointMap[pSeries] );
+ pPosHelper->setCoordinateSystemResolution( m_aCoordinateSystemResolution );
+ if( !pSeries->isAttributedDataPoint(nIndex)
+ &&
+ pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fY, aFormerPoint.m_fZ
+ , aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ ) )
+ {
+ nSkippedPoints++;
+ m_bPointsWereSkipped = true;
+ continue;
+ }
+ aSeriesFormerPointMap[pSeries] = FormerPoint(aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ);
+
+ //create a single datapoint if point is visible
+ if( !bIsVisible )
+ continue;
+
+ //create a group shape for this point and add to the series shape:
+ rtl::OUString aPointCID = ObjectIdentifier::createPointCID(
+ pSeries->getPointCID_Stub(), nIndex );
+ uno::Reference< drawing::XShapes > xPointGroupShape_Shapes(
+ createGroupShape(xSeriesGroupShape_Shapes,aPointCID) );
+ uno::Reference<drawing::XShape> xPointGroupShape_Shape =
+ uno::Reference<drawing::XShape>( xPointGroupShape_Shapes, uno::UNO_QUERY );
+
+ {
+ nCreatedPoints++;
+
+ //create data point
+ drawing::Direction3D aSymbolSize = transformToScreenBubbleSize( fBubbleSize );
+ if(m_nDimension!=3)
+ {
+ uno::Reference<drawing::XShape> xShape;
+ xShape = m_pShapeFactory->createCircle2D( xPointGroupShape_Shapes
+ , aScenePosition, aSymbolSize );
+
+ this->setMappedProperties( xShape
+ , pSeries->getPropertiesOfPoint( nIndex )
+ , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
+
+ m_pShapeFactory->setShapeName( xShape, C2U("MarkHandles") );
+ }
+
+ //create data point label
+ if( (**aSeriesIter).getDataPointLabelIfLabel(nIndex) )
+ {
+ LabelAlignment eAlignment = LABEL_ALIGN_TOP;
+ drawing::Position3D aScenePosition3D( aScenePosition.PositionX
+ , aScenePosition.PositionY
+ , aScenePosition.PositionZ+this->getTransformedDepth() );
+
+ sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nIndex, m_xChartTypeModel, m_nDimension, pPosHelper->isSwapXAndY() );
+
+ switch(nLabelPlacement)
+ {
+ case ::com::sun::star::chart::DataLabelPlacement::TOP:
+ aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1);
+ eAlignment = LABEL_ALIGN_TOP;
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::BOTTOM:
+ aScenePosition3D.PositionY += (aSymbolSize.DirectionY/2+1);
+ eAlignment = LABEL_ALIGN_BOTTOM;
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::LEFT:
+ aScenePosition3D.PositionX -= (aSymbolSize.DirectionX/2+1);
+ eAlignment = LABEL_ALIGN_LEFT;
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::RIGHT:
+ aScenePosition3D.PositionX += (aSymbolSize.DirectionX/2+1);
+ eAlignment = LABEL_ALIGN_RIGHT;
+ break;
+ case ::com::sun::star::chart::DataLabelPlacement::CENTER:
+ eAlignment = LABEL_ALIGN_CENTER;
+ break;
+ default:
+ DBG_ERROR("this label alignment is not implemented yet");
+ aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1);
+ eAlignment = LABEL_ALIGN_TOP;
+ break;
+ }
+
+
+ awt::Point aScreenPosition2D( LabelPositionHelper(pPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory)
+ .transformSceneToScreenPosition( aScenePosition3D ) );
+ sal_Int32 nOffset = 0;
+ if(LABEL_ALIGN_CENTER!=eAlignment)
+ nOffset = 100;//add some spacing //@todo maybe get more intelligent values
+ this->createDataLabel( xTextTarget, **aSeriesIter, nIndex
+ , fBubbleSize, fBubbleSize, aScreenPosition2D, eAlignment, nOffset );
+ }
+ }
+
+ //remove PointGroupShape if empty
+ if(!xPointGroupShape_Shapes->getCount())
+ xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shape);
+
+ }//next series in x slot (next y slot)
+ }//next x slot
+ }//next z slot
+ }//next category
+//=============================================================================
+//=============================================================================
+//=============================================================================
+ OSL_TRACE( "\nPPPPPPPPP<<<<<<<<<<<< area chart :: createShapes():: skipped points: %d created points: %d", nSkippedPoints, nCreatedPoints );
+}
+
+//.............................................................................
+} //namespace chart
+//.............................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/BubbleChart.hxx b/chart2/source/view/charttypes/BubbleChart.hxx
new file mode 100644
index 000000000000..2216d6499f7a
--- /dev/null
+++ b/chart2/source/view/charttypes/BubbleChart.hxx
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+#ifndef _CHART2_BUBBLECHART_HXX
+#define _CHART2_BUBBLECHART_HXX
+
+#include "VSeriesPlotter.hxx"
+#include <com/sun/star/drawing/Direction3D.hpp>
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+
+class BubbleChart : public VSeriesPlotter
+{
+ //-------------------------------------------------------------------------
+ // public methods
+ //-------------------------------------------------------------------------
+public:
+ BubbleChart( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::chart2::XChartType >& xChartTypeModel
+ , sal_Int32 nDimensionCount );
+ virtual ~BubbleChart();
+
+ //-------------------------------------------------------------------------
+ // chart2::XPlotter
+ //-------------------------------------------------------------------------
+
+ virtual void SAL_CALL createShapes();
+
+ virtual void addSeries( VDataSeries* pSeries, sal_Int32 zSlot = -1, sal_Int32 xSlot = -1,sal_Int32 ySlot = -1 );
+
+ //-------------------
+ virtual ::com::sun::star::drawing::Direction3D getPreferredDiagramAspectRatio() const;
+
+ //-------------------------------------------------------------------------
+ // MinimumAndMaximumSupplier
+ //-------------------------------------------------------------------------
+ virtual bool isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex );
+ virtual bool isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex );
+
+ //-------------------------------------------------------------------------
+
+ virtual ::com::sun::star::chart2::LegendSymbolStyle getLegendSymbolStyle();
+
+ //-------------------------------------------------------------------------
+ //-------------------------------------------------------------------------
+ //-------------------------------------------------------------------------
+private: //methods
+ //no default constructor
+ BubbleChart();
+
+ void calculateMaximumLogicBubbleSize();
+ void calculateBubbleSizeScalingFactor();
+
+ com::sun::star::drawing::Direction3D transformToScreenBubbleSize( double fLogicSize );
+
+private: //member
+
+ bool m_bShowNegativeValues;//input parameter
+ bool m_bBubbleSizeAsArea;//input parameter
+ double m_fBubbleSizeScaling;//input parameter
+
+ double m_fMaxLogicBubbleSize;//calculated values
+ double m_fBubbleSizeFactorToScreen;//calculated values
+};
+//.............................................................................
+} //namespace chart
+//.............................................................................
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/CandleStickChart.cxx b/chart2/source/view/charttypes/CandleStickChart.cxx
new file mode 100644
index 000000000000..971545c98415
--- /dev/null
+++ b/chart2/source/view/charttypes/CandleStickChart.cxx
@@ -0,0 +1,372 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_chart2.hxx"
+
+#include "CandleStickChart.hxx"
+#include "ShapeFactory.hxx"
+#include "CommonConverters.hxx"
+#include "ObjectIdentifier.hxx"
+#include "LabelPositionHelper.hxx"
+#include "BarPositionHelper.hxx"
+#include "macros.hxx"
+#include "VLegendSymbolFactory.hxx"
+#include "FormattedStringHelper.hxx"
+#include "DataSeriesHelper.hxx"
+#include <tools/debug.hxx>
+#include <rtl/math.hxx>
+#include <editeng/unoprnms.hxx>
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+using namespace ::com::sun::star;
+using namespace ::rtl::math;
+using namespace ::com::sun::star::chart2;
+using ::com::sun::star::uno::Reference;
+using ::rtl::OUString;
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+CandleStickChart::CandleStickChart( const uno::Reference<XChartType>& xChartTypeModel
+ , sal_Int32 nDimensionCount )
+ : VSeriesPlotter( xChartTypeModel, nDimensionCount )
+ , m_pMainPosHelper( new BarPositionHelper() )
+{
+ PlotterBase::m_pPosHelper = m_pMainPosHelper;
+ VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper;
+}
+
+CandleStickChart::~CandleStickChart()
+{
+ delete m_pMainPosHelper;
+}
+
+//-------------------------------------------------------------------------
+// MinimumAndMaximumSupplier
+//-------------------------------------------------------------------------
+
+double CandleStickChart::getMinimumX()
+{
+ if( m_bCategoryXAxis )
+ return 0.5;//first category (index 0) matches with real number 1.0
+ return VSeriesPlotter::getMinimumX();
+}
+double CandleStickChart::getMaximumX()
+{
+ if( m_bCategoryXAxis )
+ {
+ //return category count
+ sal_Int32 nPointCount = getPointCount();
+ return nPointCount+0.5;//first category (index 0) matches with real number 1.0
+ }
+ return VSeriesPlotter::getMaximumX();
+}
+bool CandleStickChart::isSeperateStackingForDifferentSigns( sal_Int32 /* nDimensionIndex */ )
+{
+ return false;
+}
+
+//-----------------------------------------------------------------
+//-----------------------------------------------------------------
+//-----------------------------------------------------------------
+
+LegendSymbolStyle CandleStickChart::getLegendSymbolStyle()
+{
+ return chart2::LegendSymbolStyle_VERTICAL_LINE;
+}
+
+drawing::Direction3D CandleStickChart::getPreferredDiagramAspectRatio() const
+{
+ return drawing::Direction3D(-1,-1,-1);
+}
+
+void CandleStickChart::addSeries( VDataSeries* pSeries, sal_Int32 /* zSlot */, sal_Int32 xSlot, sal_Int32 ySlot )
+{
+ //ignore y stacking for candle stick chart
+ VSeriesPlotter::addSeries( pSeries, 0, xSlot, ySlot );
+}
+
+void CandleStickChart::createShapes()
+{
+ if( m_aZSlots.begin() == m_aZSlots.end() ) //no series
+ return;
+
+ if( m_nDimension!=2 )
+ return;
+
+ DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"CandleStickChart is not proper initialized");
+ if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()))
+ return;
+
+ //the text labels should be always on top of the other series shapes
+ //therefore create an own group for the texts to move them to front
+ //(because the text group is created after the series group the texts are displayed on top)
+
+ uno::Reference< drawing::XShapes > xSeriesTarget(
+ createGroupShape( m_xLogicTarget,rtl::OUString() ));
+ uno::Reference< drawing::XShapes > xLossTarget(
+ createGroupShape( m_xLogicTarget, ObjectIdentifier::createClassifiedIdentifier(
+ OBJECTTYPE_DATA_STOCK_LOSS, rtl::OUString() )));
+ uno::Reference< drawing::XShapes > xGainTarget(
+ createGroupShape( m_xLogicTarget, ObjectIdentifier::createClassifiedIdentifier(
+ OBJECTTYPE_DATA_STOCK_GAIN, rtl::OUString() )));
+ uno::Reference< drawing::XShapes > xTextTarget(
+ m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() ));
+
+ //---------------------------------------------
+ //check necessary here that different Y axis can not be stacked in the same group? ... hm?
+
+ bool bJapaneseStyle=true;//@todo is this the correct default?
+ bool bShowFirst = true;//is only important if bJapaneseStyle == false
+ tNameSequence aWhiteBox_Names, aBlackBox_Names;
+ tAnySequence aWhiteBox_Values, aBlackBox_Values;
+ try
+ {
+ if( m_xChartTypeModelProps.is() )
+ {
+ m_xChartTypeModelProps->getPropertyValue( C2U( "ShowFirst" ) ) >>= bShowFirst;
+
+ uno::Reference< beans::XPropertySet > xWhiteDayProps(0);
+ uno::Reference< beans::XPropertySet > xBlackDayProps(0);
+ m_xChartTypeModelProps->getPropertyValue( C2U( "Japanese" ) ) >>= bJapaneseStyle;
+ m_xChartTypeModelProps->getPropertyValue( C2U( "WhiteDay" ) ) >>= xWhiteDayProps;
+ m_xChartTypeModelProps->getPropertyValue( C2U( "BlackDay" ) ) >>= xBlackDayProps;
+
+ tPropertyNameValueMap aWhiteBox_Map;
+ PropertyMapper::getValueMap( aWhiteBox_Map, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xWhiteDayProps );
+ PropertyMapper::getMultiPropertyListsFromValueMap( aWhiteBox_Names, aWhiteBox_Values, aWhiteBox_Map );
+
+ tPropertyNameValueMap aBlackBox_Map;
+ PropertyMapper::getValueMap( aBlackBox_Map, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xBlackDayProps );
+ PropertyMapper::getMultiPropertyListsFromValueMap( aBlackBox_Names, aBlackBox_Values, aBlackBox_Map );
+ }
+ }
+ catch( uno::Exception& e )
+ {
+ ASSERT_EXCEPTION( e );
+ }
+
+ //(@todo maybe different iteration for breaks in axis ?)
+ sal_Int32 nStartCategoryIndex = m_pMainPosHelper->getStartCategoryIndex(); // inclusive
+ sal_Int32 nEndCategoryIndex = m_pMainPosHelper->getEndCategoryIndex(); //inclusive
+//=============================================================================
+ //iterate through all shown categories
+ for( sal_Int32 nIndex = nStartCategoryIndex; nIndex < nEndCategoryIndex; nIndex++ )
+ {
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
+ const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
+//=============================================================================
+ for( sal_Int32 nZ=0; aZSlotIter != aZSlotEnd; aZSlotIter++, nZ++ )
+ {
+ ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+
+ sal_Int32 nAttachedAxisIndex = 0;
+ BarPositionHelper* pPosHelper = m_pMainPosHelper;
+ if( aXSlotIter != aXSlotEnd )
+ {
+ nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries();
+ //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
+ pPosHelper = dynamic_cast<BarPositionHelper*>(&( this->getPlottingPositionHelper( nAttachedAxisIndex ) ) );
+ if(!pPosHelper)
+ pPosHelper = m_pMainPosHelper;
+ }
+ PlotterBase::m_pPosHelper = pPosHelper;
+
+ //update/create information for current group
+ pPosHelper->updateSeriesCount( aZSlotIter->size() );
+//=============================================================================
+ //iterate through all x slots in this category
+ for( double fSlotX=0; aXSlotIter != aXSlotEnd; aXSlotIter++, fSlotX+=1.0 )
+ {
+ ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
+
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
+ aSeriesIter = pSeriesList->begin();
+ //=============================================================================
+ //iterate through all series in this x slot
+ for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
+ {
+ //collect data point information (logic coordinates, style ):
+ double fLogicX = pPosHelper->getSlotPos( (*aSeriesIter)->getXValue( nIndex ), fSlotX );
+ double fY_First = (*aSeriesIter)->getY_First( nIndex );
+ double fY_Last = (*aSeriesIter)->getY_Last( nIndex );
+ double fY_Min = (*aSeriesIter)->getY_Min( nIndex );
+ double fY_Max = (*aSeriesIter)->getY_Max( nIndex );
+
+ bool bBlack=false;
+ if(fY_Last<=fY_First)
+ {
+ std::swap(fY_First,fY_Last);
+ bBlack=true;
+ }
+ if(fY_Max<fY_Min)
+ std::swap(fY_Min,fY_Max);
+ //transformation 3) -> 4)
+ double fHalfWidth = pPosHelper->getSlotWidth()/2.0;
+ drawing::Position3D aPosLeftFirst( pPosHelper->transformLogicToScene( fLogicX-fHalfWidth, fY_First ,0 ,true ) );
+ drawing::Position3D aPosRightLast( pPosHelper->transformLogicToScene( fLogicX+fHalfWidth, fY_Last ,0 ,true ) );
+ drawing::Position3D aPosMiddleFirst( pPosHelper->transformLogicToScene( fLogicX, fY_First ,0 ,true ) );
+ drawing::Position3D aPosMiddleLast( pPosHelper->transformLogicToScene( fLogicX, fY_Last ,0 ,true ) );
+ drawing::Position3D aPosMiddleMinimum( pPosHelper->transformLogicToScene( fLogicX, fY_Min ,0 ,true ) );
+ drawing::Position3D aPosMiddleMaximum( pPosHelper->transformLogicToScene( fLogicX, fY_Max ,0 ,true ) );
+
+ uno::Reference< drawing::XShapes > xLossGainTarget( xGainTarget );
+ if(bBlack)
+ xLossGainTarget = xLossTarget;
+
+ uno::Reference< beans::XPropertySet > xPointProp( (*aSeriesIter)->getPropertiesOfPoint( nIndex ));
+ uno::Reference< drawing::XShapes > xPointGroupShape_Shapes(0);
+ {
+ rtl::OUString aPointCID = ObjectIdentifier::createPointCID( (*aSeriesIter)->getPointCID_Stub(), nIndex );
+ uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes( getSeriesGroupShape(*aSeriesIter, xSeriesTarget) );
+ xPointGroupShape_Shapes = createGroupShape(xSeriesGroupShape_Shapes,aPointCID);
+ }
+
+ //create min-max line
+ if( isValidPosition(aPosMiddleMinimum) && isValidPosition(aPosMiddleMaximum) )
+ {
+ uno::Reference< drawing::XShape > xShape( m_xShapeFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.drawing.PolyLineShape" ) ) ), uno::UNO_QUERY );
+ xPointGroupShape_Shapes->add(xShape);
+ uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY );
+ if(xProp.is())
+ {
+ drawing::PolyPolygonShape3D aPoly;
+ sal_Int32 nLineIndex =0;
+ AddPointToPoly( aPoly, aPosMiddleMinimum, nLineIndex);
+ AddPointToPoly( aPoly, aPosMiddleMaximum, nLineIndex);
+ xProp->setPropertyValue( C2U( UNO_NAME_POLYPOLYGON ), uno::makeAny( PolyToPointSequence(aPoly) ) );
+ }
+ this->setMappedProperties( xShape, xPointProp, PropertyMapper::getPropertyNameMapForLineSeriesProperties() );
+ }
+
+ //create first-last shape
+ if(bJapaneseStyle && isValidPosition(aPosLeftFirst) && isValidPosition(aPosRightLast) )
+ {
+ uno::Reference< drawing::XShape > xShape( m_xShapeFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.drawing.RectangleShape" ) ) ), uno::UNO_QUERY );
+ xLossGainTarget->add(xShape);
+
+ xShape->setPosition( Position3DToAWTPoint( aPosLeftFirst ) );
+ drawing::Direction3D aDiff = aPosRightLast-aPosLeftFirst;
+ awt::Size aAWTSize( Direction3DToAWTSize( aDiff ));
+ // workaround for bug in drawing: if height is 0 the box gets infinitely large
+ if( aAWTSize.Height == 0 )
+ aAWTSize.Height = 1;
+ xShape->setSize( aAWTSize );
+
+ uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY );
+ if(xProp.is())
+ {
+ if(bBlack)
+ PropertyMapper::setMultiProperties( aBlackBox_Names, aBlackBox_Values, xProp );
+ else
+ PropertyMapper::setMultiProperties( aWhiteBox_Names, aWhiteBox_Values, xProp );
+ }
+ }
+ else
+ {
+ drawing::PolyPolygonShape3D aPoly;
+
+ sal_Int32 nLineIndex = 0;
+ if( bShowFirst && pPosHelper->isLogicVisible( fLogicX, fY_First ,0 )
+ && isValidPosition(aPosLeftFirst) && isValidPosition(aPosMiddleFirst) )
+ {
+ AddPointToPoly( aPoly, aPosLeftFirst, nLineIndex );
+ AddPointToPoly( aPoly, aPosMiddleFirst, nLineIndex++ );
+ }
+ if( pPosHelper->isLogicVisible( fLogicX, fY_Last ,0 )
+ && isValidPosition(aPosMiddleLast) && isValidPosition(aPosRightLast) )
+ {
+ AddPointToPoly( aPoly, aPosMiddleLast, nLineIndex );
+ AddPointToPoly( aPoly, aPosRightLast, nLineIndex );
+ }
+
+ if( aPoly.SequenceX.getLength() )
+ {
+ uno::Reference< drawing::XShape > xShape( m_xShapeFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.drawing.PolyLineShape" ) ) ), uno::UNO_QUERY );
+ xPointGroupShape_Shapes->add(xShape);
+ uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY );
+ if(xProp.is())
+ {
+ xProp->setPropertyValue( C2U( UNO_NAME_POLYPOLYGON ), uno::makeAny( PolyToPointSequence(aPoly) ) );
+ this->setMappedProperties( xShape, xPointProp, PropertyMapper::getPropertyNameMapForLineSeriesProperties() );
+ }
+ }
+ }
+
+ //create data point label
+ if( (**aSeriesIter).getDataPointLabelIfLabel(nIndex) )
+ {
+ if(isValidPosition(aPosMiddleFirst))
+ this->createDataLabel( xTextTarget, **aSeriesIter, nIndex
+ , fY_First, 1.0, Position3DToAWTPoint(aPosMiddleFirst), LABEL_ALIGN_LEFT_BOTTOM );
+ if(isValidPosition(aPosMiddleLast))
+ this->createDataLabel( xTextTarget, **aSeriesIter, nIndex
+ , fY_Last, 1.0, Position3DToAWTPoint(aPosMiddleLast), LABEL_ALIGN_RIGHT_TOP );
+ if(isValidPosition(aPosMiddleMinimum))
+ this->createDataLabel( xTextTarget, **aSeriesIter, nIndex
+ , fY_Min, 1.0, Position3DToAWTPoint(aPosMiddleMinimum), LABEL_ALIGN_BOTTOM );
+ if(isValidPosition(aPosMiddleMaximum))
+ this->createDataLabel( xTextTarget, **aSeriesIter, nIndex
+ , fY_Max, 1.0, Position3DToAWTPoint(aPosMiddleMaximum), LABEL_ALIGN_TOP );
+ }
+ }//next series in x slot (next y slot)
+ }//next x slot
+ }//next z slot
+ }//next category
+//=============================================================================
+//=============================================================================
+//=============================================================================
+ /* @todo remove series shapes if empty
+ //remove and delete point-group-shape if empty
+ if(!xSeriesGroupShape_Shapes->getCount())
+ {
+ (*aSeriesIter)->m_xShape.set(NULL);
+ m_xLogicTarget->remove(xSeriesGroupShape_Shape);
+ }
+ */
+
+ //remove and delete series-group-shape if empty
+
+ //... todo
+}
+
+//.............................................................................
+} //namespace chart
+//.............................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/CandleStickChart.hxx b/chart2/source/view/charttypes/CandleStickChart.hxx
new file mode 100644
index 000000000000..cd33e54af5e9
--- /dev/null
+++ b/chart2/source/view/charttypes/CandleStickChart.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _CHART2_CANDLESTICKCHART_HXX
+#define _CHART2_CANDLESTICKCHART_HXX
+
+#include "VSeriesPlotter.hxx"
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+class BarPositionHelper;
+
+class CandleStickChart : public VSeriesPlotter
+{
+ //-------------------------------------------------------------------------
+ // public methods
+ //-------------------------------------------------------------------------
+public:
+ CandleStickChart( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::chart2::XChartType >& xChartTypeModel
+ , sal_Int32 nDimensionCount );
+ virtual ~CandleStickChart();
+
+ //-------------------------------------------------------------------------
+ // chart2::XPlotter
+ //-------------------------------------------------------------------------
+
+ virtual void SAL_CALL createShapes();
+ /*
+ virtual ::rtl::OUString SAL_CALL getCoordinateSystemTypeID( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setScales( const ::com::sun::star::uno::Sequence< ::com::sun::star::chart2::ExplicitScaleData >& rScales ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setTransformation( const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTransformation >& xTransformationToLogicTarget, const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTransformation >& xTransformationToFinalPage ) throw (::com::sun::star::uno::RuntimeException);
+ */
+ virtual void addSeries( VDataSeries* pSeries, sal_Int32 zSlot = -1, sal_Int32 xSlot = -1,sal_Int32 ySlot = -1 );
+
+ virtual ::com::sun::star::drawing::Direction3D getPreferredDiagramAspectRatio() const;
+
+ //-------------------------------------------------------------------------
+ // MinimumAndMaximumSupplier
+ //-------------------------------------------------------------------------
+ virtual double getMinimumX();
+ virtual double getMaximumX();
+ virtual bool isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex );
+
+ //-------------------------------------------------------------------------
+
+ virtual ::com::sun::star::chart2::LegendSymbolStyle getLegendSymbolStyle();
+
+ //-------------------------------------------------------------------------
+ //-------------------------------------------------------------------------
+ //-------------------------------------------------------------------------
+
+private: //methods
+ //no default constructor
+ CandleStickChart();
+
+private: //member
+ BarPositionHelper* m_pMainPosHelper;
+};
+//.............................................................................
+} //namespace chart
+//.............................................................................
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/CategoryPositionHelper.cxx b/chart2/source/view/charttypes/CategoryPositionHelper.cxx
new file mode 100644
index 000000000000..657004706e81
--- /dev/null
+++ b/chart2/source/view/charttypes/CategoryPositionHelper.cxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_chart2.hxx"
+#include "CategoryPositionHelper.hxx"
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+//using namespace ::com::sun::star;
+//using namespace ::com::sun::star::chart2;
+
+CategoryPositionHelper::CategoryPositionHelper( double fSeriesCount, double fCategoryWidth )
+ : m_fSeriesCount(fSeriesCount)
+ , m_fCategoryWidth(fCategoryWidth)
+ , m_fInnerDistance(0.0)
+ , m_fOuterDistance(1.0)
+{
+}
+
+CategoryPositionHelper::CategoryPositionHelper( const CategoryPositionHelper& rSource )
+ : m_fSeriesCount( rSource.m_fSeriesCount )
+ , m_fCategoryWidth( rSource.m_fCategoryWidth )
+ , m_fInnerDistance( rSource.m_fInnerDistance )
+ , m_fOuterDistance( rSource.m_fOuterDistance )
+{
+}
+
+CategoryPositionHelper::~CategoryPositionHelper()
+{
+}
+
+double CategoryPositionHelper::getSlotWidth() const
+{
+ double fWidth = m_fCategoryWidth /
+ ( m_fSeriesCount
+ + m_fOuterDistance
+ + m_fInnerDistance*( m_fSeriesCount - 1.0) );
+ return fWidth;
+}
+
+double CategoryPositionHelper::getSlotPos( double fCategoryX, double fSeriesNumber ) const
+{
+ //the returned position is in the middle of the rect
+ //fSeriesNumber 0...n-1
+ double fPos = fCategoryX - (m_fCategoryWidth/2.0)
+ + (m_fOuterDistance/2.0 + fSeriesNumber*(1.0+m_fInnerDistance)) * getSlotWidth()
+ + getSlotWidth()/2.0;
+
+ return fPos;
+}
+
+void CategoryPositionHelper::setInnerDistance( double fInnerDistance )
+{
+ if( fInnerDistance < -1.0 )
+ fInnerDistance = -1.0;
+ if( fInnerDistance > 1.0 )
+ fInnerDistance = 1.0;
+ m_fInnerDistance = fInnerDistance;
+}
+
+void CategoryPositionHelper::setOuterDistance( double fOuterDistance )
+{
+ if( fOuterDistance < 0.0 )
+ fOuterDistance = 0.0;
+ if( fOuterDistance > 6.0 )
+ fOuterDistance = 6.0;
+ m_fOuterDistance = fOuterDistance;
+}
+
+//.............................................................................
+} //namespace chart
+//.............................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/CategoryPositionHelper.hxx b/chart2/source/view/charttypes/CategoryPositionHelper.hxx
new file mode 100644
index 000000000000..c48fbf98b150
--- /dev/null
+++ b/chart2/source/view/charttypes/CategoryPositionHelper.hxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _CHART2_CATEGORYPOSITIONHELPER_HXX
+#define _CHART2_CATEGORYPOSITIONHELPER_HXX
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+
+//-----------------------------------------------------------------------------
+/**
+*/
+
+class CategoryPositionHelper
+{
+public:
+ CategoryPositionHelper( double fSeriesCount, double CategoryWidth = 1.0);
+ CategoryPositionHelper( const CategoryPositionHelper& rSource );
+ virtual ~CategoryPositionHelper();
+
+ double getSlotWidth() const;
+ double getSlotPos( double fCategoryX, double fSeriesNumber ) const;
+
+ //Distance between two neighboring bars in same category, seen relative to width of the bar
+ void setInnerDistance( double fInnerDistance );
+
+ //Distance between two neighboring bars in different category, seen relative to width of the bar:
+ void setOuterDistance( double fOuterDistance );
+
+protected:
+ double m_fSeriesCount;
+ double m_fCategoryWidth;
+ //Distance between two neighboring bars in same category, seen relative to width of the bar:
+ double m_fInnerDistance; //[-1,1] m_fInnerDistance=1 --> distance == width; m_fInnerDistance=-1-->all rects are painted on the same position
+ //Distance between two neighboring bars in different category, seen relative to width of the bar:
+ double m_fOuterDistance; //>=0 m_fOuterDistance=1 --> distance == width
+};
+
+//.............................................................................
+} //namespace chart
+//.............................................................................
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/PieChart.cxx b/chart2/source/view/charttypes/PieChart.cxx
new file mode 100644
index 000000000000..edb9e08b8018
--- /dev/null
+++ b/chart2/source/view/charttypes/PieChart.cxx
@@ -0,0 +1,883 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_chart2.hxx"
+
+#include "PieChart.hxx"
+#include "PlottingPositionHelper.hxx"
+#include "ShapeFactory.hxx"
+#include "PolarLabelPositionHelper.hxx"
+#include "macros.hxx"
+#include "CommonConverters.hxx"
+#include "ViewDefines.hxx"
+#include "ObjectIdentifier.hxx"
+
+#include <com/sun/star/chart/DataLabelPlacement.hpp>
+#include <com/sun/star/chart2/XColorScheme.hpp>
+
+#include <com/sun/star/container/XChild.hpp>
+
+#include <tools/debug.hxx>
+#include <rtl/math.hxx>
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+
+class PiePositionHelper : public PolarPlottingPositionHelper
+{
+public:
+ PiePositionHelper( NormalAxis eNormalAxis, double fAngleDegreeOffset );
+ virtual ~PiePositionHelper();
+
+ bool getInnerAndOuterRadius( double fCategoryX, double& fLogicInnerRadius, double& fLogicOuterRadius, bool bUseRings, double fMaxOffset ) const;
+
+public:
+ //Distance between different category rings, seen relative to width of a ring:
+ double m_fRingDistance; //>=0 m_fRingDistance=1 --> distance == width
+};
+
+PiePositionHelper::PiePositionHelper( NormalAxis eNormalAxis, double fAngleDegreeOffset )
+ : PolarPlottingPositionHelper(eNormalAxis)
+ , m_fRingDistance(0.0)
+{
+ m_fRadiusOffset = 0.0;
+ m_fAngleDegreeOffset = fAngleDegreeOffset;
+}
+
+PiePositionHelper::~PiePositionHelper()
+{
+}
+
+bool PiePositionHelper::getInnerAndOuterRadius( double fCategoryX
+ , double& fLogicInnerRadius, double& fLogicOuterRadius
+ , bool bUseRings, double fMaxOffset ) const
+{
+ if( !bUseRings )
+ fCategoryX = 1.0;
+
+ bool bIsVisible = true;
+ double fLogicInner = fCategoryX -0.5+m_fRingDistance/2.0;
+ double fLogicOuter = fCategoryX +0.5-m_fRingDistance/2.0;
+
+ if( !isMathematicalOrientationRadius() )
+ {
+ //in this case the given getMaximumX() was not corrcect instead the minimum should have been smaller by fMaxOffset
+ //but during getMaximumX and getMimumX we do not know the axis orientation
+ fLogicInner += fMaxOffset;
+ fLogicOuter += fMaxOffset;
+ }
+
+ if( fLogicInner >= getLogicMaxX() )
+ return false;
+ if( fLogicOuter <= getLogicMinX() )
+ return false;
+
+ if( fLogicInner < getLogicMinX() )
+ fLogicInner = getLogicMinX();
+ if( fLogicOuter > getLogicMaxX() )
+ fLogicOuter = getLogicMaxX();
+
+ fLogicInnerRadius = fLogicInner;
+ fLogicOuterRadius = fLogicOuter;
+ if( !isMathematicalOrientationRadius() )
+ std::swap(fLogicInnerRadius,fLogicOuterRadius);
+ return bIsVisible;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+PieChart::PieChart( const uno::Reference<XChartType>& xChartTypeModel
+ , sal_Int32 nDimensionCount
+ , bool bExcludingPositioning )
+ : VSeriesPlotter( xChartTypeModel, nDimensionCount )
+ , m_pPosHelper( new PiePositionHelper( NormalAxis_Z, (m_nDimension==3)?0.0:90.0 ) )
+ , m_bUseRings(false)
+ , m_bSizeExcludesLabelsAndExplodedSegments(bExcludingPositioning)
+{
+ ::rtl::math::setNan(&m_fMaxOffset);
+
+ PlotterBase::m_pPosHelper = m_pPosHelper;
+ VSeriesPlotter::m_pMainPosHelper = m_pPosHelper;
+ m_pPosHelper->m_fRadiusOffset = 0.0;
+ m_pPosHelper->m_fRingDistance = 0.0;
+
+ uno::Reference< beans::XPropertySet > xChartTypeProps( xChartTypeModel, uno::UNO_QUERY );
+ if( xChartTypeProps.is() ) try
+ {
+ xChartTypeProps->getPropertyValue( C2U( "UseRings" )) >>= m_bUseRings;
+ if( m_bUseRings )
+ {
+ m_pPosHelper->m_fRadiusOffset = 1.0;
+ if( nDimensionCount==3 )
+ m_pPosHelper->m_fRingDistance = 0.1;
+ }
+ }
+ catch( uno::Exception& e )
+ {
+ ASSERT_EXCEPTION( e );
+ }
+}
+
+PieChart::~PieChart()
+{
+ delete m_pPosHelper;
+}
+
+//-----------------------------------------------------------------
+
+void SAL_CALL PieChart::setScales( const uno::Sequence< ExplicitScaleData >& rScales
+ , sal_Bool /* bSwapXAndYAxis */ )
+ throw (uno::RuntimeException)
+{
+ DBG_ASSERT(m_nDimension<=rScales.getLength(),"Dimension of Plotter does not fit two dimension of given scale sequence");
+ m_pPosHelper->setScales( rScales, true );
+}
+
+//-----------------------------------------------------------------
+
+drawing::Direction3D PieChart::getPreferredDiagramAspectRatio() const
+{
+ if( m_nDimension == 3 )
+ return drawing::Direction3D(1,1,0.25);
+ return drawing::Direction3D(1,1,1);
+}
+
+bool PieChart::keepAspectRatio() const
+{
+ if( m_nDimension == 3 )
+ return false;
+ return true;
+}
+
+bool PieChart::shouldSnapRectToUsedArea()
+{
+ return true;
+}
+
+uno::Reference< drawing::XShape > PieChart::createDataPoint(
+ const uno::Reference< drawing::XShapes >& xTarget
+ , const uno::Reference< beans::XPropertySet >& xObjectProperties
+ , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree
+ , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius
+ , double fLogicZ, double fDepth, double fExplodePercentage
+ , tPropertyNameValueMap* pOverwritePropertiesMap )
+{
+ //---------------------------
+ //transform position:
+ drawing::Direction3D aOffset;
+ if( !::rtl::math::approxEqual( fExplodePercentage, 0.0 ) )
+ {
+ double fAngle = fUnitCircleStartAngleDegree + fUnitCircleWidthAngleDegree/2.0;
+ double fRadius = (fUnitCircleOuterRadius-fUnitCircleInnerRadius)*fExplodePercentage;
+ drawing::Position3D aOrigin = m_pPosHelper->transformUnitCircleToScene( 0, 0, fLogicZ );
+ drawing::Position3D aNewOrigin = m_pPosHelper->transformUnitCircleToScene( fAngle, fRadius, fLogicZ );
+ aOffset = aNewOrigin - aOrigin;
+ }
+
+ //---------------------------
+ //create point
+ uno::Reference< drawing::XShape > xShape(0);
+ if(m_nDimension==3)
+ {
+ xShape = m_pShapeFactory->createPieSegment( xTarget
+ , fUnitCircleStartAngleDegree, fUnitCircleWidthAngleDegree
+ , fUnitCircleInnerRadius, fUnitCircleOuterRadius
+ , aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() )
+ , fDepth );
+ }
+ else
+ {
+ xShape = m_pShapeFactory->createPieSegment2D( xTarget
+ , fUnitCircleStartAngleDegree, fUnitCircleWidthAngleDegree
+ , fUnitCircleInnerRadius, fUnitCircleOuterRadius
+ , aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() ) );
+ }
+ this->setMappedProperties( xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), pOverwritePropertiesMap );
+ return xShape;
+}
+
+void PieChart::addSeries( VDataSeries* pSeries, sal_Int32 /* zSlot */, sal_Int32 /* xSlot */, sal_Int32 /* ySlot */ )
+{
+ VSeriesPlotter::addSeries( pSeries, 0, -1, 0 );
+}
+
+double PieChart::getMinimumX()
+{
+ return 0.5;
+}
+double PieChart::getMaxOffset()
+{
+ if (!::rtl::math::isNan(m_fMaxOffset))
+ // Value already cached. Use it.
+ return m_fMaxOffset;
+
+ m_fMaxOffset = 0.0;
+ if( m_aZSlots.size()<=0 )
+ return m_fMaxOffset;
+ if( m_aZSlots[0].size()<=0 )
+ return m_fMaxOffset;
+
+ const ::std::vector< VDataSeries* >& rSeriesList( m_aZSlots[0][0].m_aSeriesVector );
+ if( rSeriesList.size()<=0 )
+ return m_fMaxOffset;
+
+ VDataSeries* pSeries = rSeriesList[0];
+ uno::Reference< beans::XPropertySet > xSeriesProp( pSeries->getPropertiesOfSeries() );
+ if( !xSeriesProp.is() )
+ return m_fMaxOffset;
+
+ double fExplodePercentage=0.0;
+ xSeriesProp->getPropertyValue( C2U( "Offset" )) >>= fExplodePercentage;
+ if(fExplodePercentage>m_fMaxOffset)
+ m_fMaxOffset=fExplodePercentage;
+
+ if(!m_bSizeExcludesLabelsAndExplodedSegments)
+ {
+ uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
+ if( xSeriesProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList )
+ {
+ for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;)
+ {
+ uno::Reference< beans::XPropertySet > xPointProp( pSeries->getPropertiesOfPoint(aAttributedDataPointIndexList[nN]) );
+ if(xPointProp.is())
+ {
+ fExplodePercentage=0.0;
+ xPointProp->getPropertyValue( C2U( "Offset" )) >>= fExplodePercentage;
+ if(fExplodePercentage>m_fMaxOffset)
+ m_fMaxOffset=fExplodePercentage;
+ }
+ }
+ }
+ }
+ return m_fMaxOffset;
+}
+double PieChart::getMaximumX()
+{
+ double fMaxOffset = getMaxOffset();
+ if( m_aZSlots.size()>0 && m_bUseRings)
+ return m_aZSlots[0].size()+0.5+fMaxOffset;
+ return 1.5+fMaxOffset;
+}
+double PieChart::getMinimumYInRange( double /* fMinimumX */, double /* fMaximumX */, sal_Int32 /* nAxisIndex */ )
+{
+ return 0.0;
+}
+
+double PieChart::getMaximumYInRange( double /* fMinimumX */, double /* fMaximumX */, sal_Int32 /* nAxisIndex */ )
+{
+ return 1.0;
+}
+
+bool PieChart::isExpandBorderToIncrementRhythm( sal_Int32 /* nDimensionIndex */ )
+{
+ return false;
+}
+
+bool PieChart::isExpandIfValuesCloseToBorder( sal_Int32 /* nDimensionIndex */ )
+{
+ return false;
+}
+
+bool PieChart::isExpandWideValuesToZero( sal_Int32 /* nDimensionIndex */ )
+{
+ return false;
+}
+
+bool PieChart::isExpandNarrowValuesTowardZero( sal_Int32 /* nDimensionIndex */ )
+{
+ return false;
+}
+
+bool PieChart::isSeperateStackingForDifferentSigns( sal_Int32 /* nDimensionIndex */ )
+{
+ return false;
+}
+
+void PieChart::createShapes()
+{
+ if( m_aZSlots.begin() == m_aZSlots.end() ) //no series
+ return;
+
+ DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"PieChart is not proper initialized");
+ if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()))
+ return;
+
+ //the text labels should be always on top of the other series shapes
+ //therefore create an own group for the texts to move them to front
+ //(because the text group is created after the series group the texts are displayed on top)
+ uno::Reference< drawing::XShapes > xSeriesTarget(
+ createGroupShape( m_xLogicTarget,rtl::OUString() ));
+ uno::Reference< drawing::XShapes > xTextTarget(
+ m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() ));
+ //---------------------------------------------
+ //check necessary here that different Y axis can not be stacked in the same group? ... hm?
+
+//=============================================================================
+ ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = m_aZSlots[0].begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = m_aZSlots[0].end();
+
+ ::std::vector< VDataSeriesGroup >::size_type nExplodeableSlot = 0;
+ if( m_pPosHelper->isMathematicalOrientationRadius() && m_bUseRings )
+ nExplodeableSlot = m_aZSlots[0].size()-1;
+
+ m_aLabelInfoList.clear();
+ ::rtl::math::setNan(&m_fMaxOffset);
+
+//=============================================================================
+ for( double fSlotX=0; aXSlotIter != aXSlotEnd && (m_bUseRings||fSlotX<0.5 ); aXSlotIter++, fSlotX+=1.0 )
+ {
+ ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
+ if( pSeriesList->size()<=0 )//there should be only one series in each x slot
+ continue;
+ VDataSeries* pSeries = (*pSeriesList)[0];
+ if(!pSeries)
+ continue;
+
+ m_pPosHelper->m_fAngleDegreeOffset = pSeries->getStartingAngle();
+
+ double fLogicYSum = 0.0;
+ //iterate through all points to get the sum
+ sal_Int32 nPointIndex=0;
+ sal_Int32 nPointCount=pSeries->getTotalPointCount();
+ for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
+ {
+ double fY = pSeries->getYValue( nPointIndex );
+ if(fY<0.0)
+ {
+ //@todo warn somehow that negative values are treated as positive
+ }
+ if( ::rtl::math::isNan(fY) )
+ continue;
+ fLogicYSum += fabs(fY);
+ }
+ if(fLogicYSum==0.0)
+ continue;
+ double fLogicYForNextPoint = 0.0;
+ //iterate through all points to create shapes
+ for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
+ {
+ double fLogicInnerRadius, fLogicOuterRadius;
+ double fOffset = getMaxOffset();
+ bool bIsVisible = m_pPosHelper->getInnerAndOuterRadius( fSlotX+1.0, fLogicInnerRadius, fLogicOuterRadius, m_bUseRings, fOffset );
+ if( !bIsVisible )
+ continue;
+
+ double fLogicZ = -0.5;//as defined
+ double fDepth = this->getTransformedDepth();
+//=============================================================================
+
+ uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShape(pSeries, xSeriesTarget);
+ //collect data point information (logic coordinates, style ):
+ double fLogicYValue = fabs(pSeries->getYValue( nPointIndex ));
+ if( ::rtl::math::isNan(fLogicYValue) )
+ continue;
+ if(fLogicYValue==0.0)//@todo: continue also if the resolution to small
+ continue;
+ double fLogicYPos = fLogicYForNextPoint;
+ fLogicYForNextPoint += fLogicYValue;
+
+ uno::Reference< beans::XPropertySet > xPointProperties = pSeries->getPropertiesOfPoint( nPointIndex );
+
+ //iterate through all subsystems to create partial points
+ {
+ //logic values on angle axis:
+ double fLogicStartAngleValue = fLogicYPos/fLogicYSum;
+ double fLogicEndAngleValue = (fLogicYPos+fLogicYValue)/fLogicYSum;
+
+ double fExplodePercentage=0.0;
+ bool bDoExplode = ( nExplodeableSlot == static_cast< ::std::vector< VDataSeriesGroup >::size_type >(fSlotX) );
+ if(bDoExplode) try
+ {
+ xPointProperties->getPropertyValue( C2U( "Offset" )) >>= fExplodePercentage;
+ }
+ catch( uno::Exception& e )
+ {
+ ASSERT_EXCEPTION( e );
+ }
+
+ //---------------------------
+ //transforme to unit circle:
+ double fUnitCircleWidthAngleDegree = m_pPosHelper->getWidthAngleDegree( fLogicStartAngleValue, fLogicEndAngleValue );
+ double fUnitCircleStartAngleDegree = m_pPosHelper->transformToAngleDegree( fLogicStartAngleValue );
+ double fUnitCircleInnerRadius = m_pPosHelper->transformToRadius( fLogicInnerRadius );
+ double fUnitCircleOuterRadius = m_pPosHelper->transformToRadius( fLogicOuterRadius );
+
+ //---------------------------
+ //point color:
+ std::auto_ptr< tPropertyNameValueMap > apOverwritePropertiesMap(0);
+ {
+ if(!pSeries->hasPointOwnColor(nPointIndex) && m_xColorScheme.is())
+ {
+ apOverwritePropertiesMap = std::auto_ptr< tPropertyNameValueMap >( new tPropertyNameValueMap() );
+ (*apOverwritePropertiesMap)[C2U("FillColor")] = uno::makeAny(
+ m_xColorScheme->getColorByIndex( nPointIndex ));
+ }
+ }
+
+ //create data point
+ uno::Reference<drawing::XShape> xPointShape(
+ createDataPoint( xSeriesGroupShape_Shapes, xPointProperties
+ , fUnitCircleStartAngleDegree, fUnitCircleWidthAngleDegree
+ , fUnitCircleInnerRadius, fUnitCircleOuterRadius
+ , fLogicZ, fDepth, fExplodePercentage, apOverwritePropertiesMap.get() ) );
+
+ //create label
+ if( pSeries->getDataPointLabelIfLabel(nPointIndex) )
+ {
+ if( !::rtl::math::approxEqual( fExplodePercentage, 0.0 ) )
+ {
+ double fExplodeOffset = (fUnitCircleOuterRadius-fUnitCircleInnerRadius)*fExplodePercentage;
+ fUnitCircleInnerRadius += fExplodeOffset;
+ fUnitCircleOuterRadius += fExplodeOffset;
+ }
+
+ sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nPointIndex, m_xChartTypeModel, m_nDimension, m_pPosHelper->isSwapXAndY() );
+ bool bMovementAllowed = ( nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::AVOID_OVERLAP );
+ if( bMovementAllowed )
+ nLabelPlacement = ::com::sun::star::chart::DataLabelPlacement::OUTSIDE;
+
+ LabelAlignment eAlignment(LABEL_ALIGN_CENTER);
+ sal_Int32 nScreenValueOffsetInRadiusDirection = 0 ;
+ if( nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::OUTSIDE )
+ nScreenValueOffsetInRadiusDirection = (3!=m_nDimension) ? 150 : 0;//todo maybe calculate this font height dependent
+ else if( nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::INSIDE )
+ nScreenValueOffsetInRadiusDirection = (3!=m_nDimension) ? -150 : 0;//todo maybe calculate this font height dependent
+ PolarLabelPositionHelper aPolarPosHelper(m_pPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory);
+ awt::Point aScreenPosition2D(
+ aPolarPosHelper.getLabelScreenPositionAndAlignmentForUnitCircleValues(eAlignment, nLabelPlacement
+ , fUnitCircleStartAngleDegree, fUnitCircleWidthAngleDegree
+ , fUnitCircleInnerRadius, fUnitCircleOuterRadius, 0.0, 0 ));
+
+ PieLabelInfo aPieLabelInfo;
+ aPieLabelInfo.aFirstPosition = basegfx::B2IVector( aScreenPosition2D.X, aScreenPosition2D.Y );
+ awt::Point aOrigin( aPolarPosHelper.transformSceneToScreenPosition( m_pPosHelper->transformUnitCircleToScene( 0.0, 0.0, 0.5 ) ) );
+ aPieLabelInfo.aOrigin = basegfx::B2IVector( aOrigin.X, aOrigin.Y );
+
+ //add a scaling independent Offset if requested
+ if( nScreenValueOffsetInRadiusDirection != 0)
+ {
+ basegfx::B2IVector aDirection( aScreenPosition2D.X- aOrigin.X, aScreenPosition2D.Y- aOrigin.Y );
+ aDirection.setLength(nScreenValueOffsetInRadiusDirection);
+ aScreenPosition2D.X += aDirection.getX();
+ aScreenPosition2D.Y += aDirection.getY();
+ }
+
+ aPieLabelInfo.xTextShape = this->createDataLabel( xTextTarget, *pSeries, nPointIndex
+ , fLogicYValue, fLogicYSum, aScreenPosition2D, eAlignment );
+
+ uno::Reference< container::XChild > xChild( aPieLabelInfo.xTextShape, uno::UNO_QUERY );
+ if( xChild.is() )
+ aPieLabelInfo.xLabelGroupShape = uno::Reference<drawing::XShape>( xChild->getParent(), uno::UNO_QUERY );
+ aPieLabelInfo.fValue = fLogicYValue;
+ aPieLabelInfo.bMovementAllowed = bMovementAllowed;
+ aPieLabelInfo.bMoved= false;
+ aPieLabelInfo.xTextTarget = xTextTarget;
+ m_aLabelInfoList.push_back(aPieLabelInfo);
+ }
+
+ if(!bDoExplode)
+ {
+ ShapeFactory::setShapeName( xPointShape
+ , ObjectIdentifier::createPointCID( pSeries->getPointCID_Stub(), nPointIndex ) );
+ }
+ else try
+ {
+ //enable dragging of outer segments
+
+ double fAngle = fUnitCircleStartAngleDegree + fUnitCircleWidthAngleDegree/2.0;
+ double fMaxDeltaRadius = fUnitCircleOuterRadius-fUnitCircleInnerRadius;
+ drawing::Position3D aOrigin = m_pPosHelper->transformUnitCircleToScene( fAngle, fUnitCircleOuterRadius, fLogicZ );
+ drawing::Position3D aNewOrigin = m_pPosHelper->transformUnitCircleToScene( fAngle, fUnitCircleOuterRadius + fMaxDeltaRadius, fLogicZ );
+
+ sal_Int32 nOffsetPercent( static_cast<sal_Int32>(fExplodePercentage * 100.0) );
+
+ awt::Point aMinimumPosition( PlottingPositionHelper::transformSceneToScreenPosition(
+ aOrigin, m_xLogicTarget, m_pShapeFactory, m_nDimension ) );
+ awt::Point aMaximumPosition( PlottingPositionHelper::transformSceneToScreenPosition(
+ aNewOrigin, m_xLogicTarget, m_pShapeFactory, m_nDimension ) );
+
+ //enable draging of piesegments
+ rtl::OUString aPointCIDStub( ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT
+ , pSeries->getSeriesParticle()
+ , ObjectIdentifier::getPieSegmentDragMethodServiceName()
+ , ObjectIdentifier::createPieSegmentDragParameterString(
+ nOffsetPercent, aMinimumPosition, aMaximumPosition )
+ ) );
+
+ ShapeFactory::setShapeName( xPointShape
+ , ObjectIdentifier::createPointCID( aPointCIDStub, nPointIndex ) );
+ }
+ catch( uno::Exception& e )
+ {
+ ASSERT_EXCEPTION( e );
+ }
+ }//next series in x slot (next y slot)
+ }//next category
+ }//next x slot
+//=============================================================================
+//=============================================================================
+//=============================================================================
+ /* @todo remove series shapes if empty
+ //remove and delete point-group-shape if empty
+ if(!xSeriesGroupShape_Shapes->getCount())
+ {
+ (*aSeriesIter)->m_xShape.set(NULL);
+ m_xLogicTarget->remove(xSeriesGroupShape_Shape);
+ }
+ */
+
+ //remove and delete series-group-shape if empty
+
+ //... todo
+}
+
+namespace
+{
+
+::basegfx::B2IRectangle lcl_getRect( const uno::Reference< drawing::XShape >& xShape )
+{
+ ::basegfx::B2IRectangle aRect;
+ if( xShape.is() )
+ aRect = BaseGFXHelper::makeRectangle(xShape->getPosition(),xShape->getSize() );
+ return aRect;
+}
+
+bool lcl_isInsidePage( const awt::Point& rPos, const awt::Size& rSize, const awt::Size& rPageSize )
+{
+ if( rPos.X < 0 || rPos.Y < 0 )
+ return false;
+ if( (rPos.X + rSize.Width) > rPageSize.Width )
+ return false;
+ if( (rPos.Y + rSize.Height) > rPageSize.Height )
+ return false;
+ return true;
+}
+
+}//end anonymous namespace
+
+PieChart::PieLabelInfo::PieLabelInfo()
+ : xTextShape(0), xLabelGroupShape(0), aFirstPosition(), aOrigin(), fValue(0.0)
+ , bMovementAllowed(false), bMoved(false), xTextTarget(0), pPrevious(0),pNext(0)
+{
+}
+
+bool PieChart::PieLabelInfo::moveAwayFrom( const PieChart::PieLabelInfo* pFix, const awt::Size& rPageSize, bool bMoveHalfWay, bool bMoveClockwise, bool bAlternativeMoveDirection )
+{
+ //return true if the move was successful
+ if(!this->bMovementAllowed)
+ return false;
+
+ const sal_Int32 nLabelDistanceX = rPageSize.Width/50;
+ const sal_Int32 nLabelDistanceY = rPageSize.Height/50;
+
+ ::basegfx::B2IRectangle aOverlap( lcl_getRect( this->xLabelGroupShape ) );
+ aOverlap.intersect( lcl_getRect( pFix->xLabelGroupShape ) );
+ if( !aOverlap.isEmpty() )
+ {
+ (void)bAlternativeMoveDirection;//todo
+
+ basegfx::B2IVector aRadiusDirection = this->aFirstPosition - this->aOrigin;
+ aRadiusDirection.setLength(1.0);
+ basegfx::B2IVector aTangentialDirection( -aRadiusDirection.getY(), aRadiusDirection.getX() );
+ bool bShiftHorizontal = abs(aTangentialDirection.getX()) > abs(aTangentialDirection.getY());
+
+ sal_Int32 nShift = bShiftHorizontal ? static_cast<sal_Int32>(aOverlap.getWidth()) : static_cast<sal_Int32>(aOverlap.getHeight());
+ nShift += (bShiftHorizontal ? nLabelDistanceX : nLabelDistanceY);
+ if( bMoveHalfWay )
+ nShift/=2;
+ if(!bMoveClockwise)
+ nShift*=-1;
+ awt::Point aOldPos( this->xLabelGroupShape->getPosition() );
+ basegfx::B2IVector aNewPos = basegfx::B2IVector( aOldPos.X, aOldPos.Y ) + nShift*aTangentialDirection;
+
+ //check whether the new position is ok
+ awt::Point aNewAWTPos( aNewPos.getX(), aNewPos.getY() );
+ if( !lcl_isInsidePage( aNewAWTPos, this->xLabelGroupShape->getSize(), rPageSize ) )
+ return false;
+
+ this->xLabelGroupShape->setPosition( aNewAWTPos );
+ this->bMoved = true;
+ }
+ return true;
+}
+
+void PieChart::resetLabelPositionsToPreviousState()
+{
+ std::vector< PieLabelInfo >::iterator aIt = m_aLabelInfoList.begin();
+ std::vector< PieLabelInfo >::const_iterator aEnd = m_aLabelInfoList.end();
+ for( ;aIt!=aEnd; ++aIt )
+ aIt->xLabelGroupShape->setPosition(aIt->aPreviousPosition);
+}
+
+bool PieChart::detectLabelOverlapsAndMove( const awt::Size& rPageSize )
+{
+ //returns true when there might be more to do
+
+ //find borders of a group of overlapping labels
+ bool bOverlapFound = false;
+ PieLabelInfo* pStart = &(*(m_aLabelInfoList.rbegin()));
+ PieLabelInfo* pFirstBorder = 0;
+ PieLabelInfo* pSecondBorder = 0;
+ PieLabelInfo* pCurrent = pStart;
+ do
+ {
+ ::basegfx::B2IRectangle aPreviousOverlap( lcl_getRect( pCurrent->xLabelGroupShape ) );
+ ::basegfx::B2IRectangle aNextOverlap( aPreviousOverlap );
+ aPreviousOverlap.intersect( lcl_getRect( pCurrent->pPrevious->xLabelGroupShape ) );
+ aNextOverlap.intersect( lcl_getRect( pCurrent->pNext->xLabelGroupShape ) );
+
+ bool bPreviousOverlap = !aPreviousOverlap.isEmpty();
+ bool bNextOverlap = !aNextOverlap.isEmpty();
+ if( bPreviousOverlap || bNextOverlap )
+ bOverlapFound = true;
+ if( !bPreviousOverlap && bNextOverlap )
+ {
+ pFirstBorder = pCurrent;
+ break;
+ }
+ pCurrent = pCurrent->pNext;
+ }
+ while( pCurrent != pStart );
+
+ if( !bOverlapFound )
+ return false;
+
+ if( pFirstBorder )
+ {
+ pCurrent = pFirstBorder;
+ do
+ {
+ ::basegfx::B2IRectangle aPreviousOverlap( lcl_getRect( pCurrent->xLabelGroupShape ) );
+ ::basegfx::B2IRectangle aNextOverlap( aPreviousOverlap );
+ aPreviousOverlap.intersect( lcl_getRect( pCurrent->pPrevious->xLabelGroupShape ) );
+ aNextOverlap.intersect( lcl_getRect( pCurrent->pNext->xLabelGroupShape ) );
+
+ if( !aPreviousOverlap.isEmpty() && aNextOverlap.isEmpty() )
+ {
+ pSecondBorder = pCurrent;
+ break;
+ }
+ pCurrent = pCurrent->pNext;
+ }
+ while( pCurrent != pFirstBorder );
+ }
+
+ if( !pFirstBorder || !pSecondBorder )
+ {
+ pFirstBorder = &(*(m_aLabelInfoList.rbegin()));
+ pSecondBorder = &(*(m_aLabelInfoList.begin()));
+ }
+
+ //find center
+ PieLabelInfo* pCenter = pFirstBorder;
+ sal_Int32 nOverlapGroupCount = 1;
+ for( pCurrent = pFirstBorder ;pCurrent != pSecondBorder; pCurrent = pCurrent->pNext )
+ nOverlapGroupCount++;
+ sal_Int32 nCenterPos = nOverlapGroupCount/2;
+ bool bSingleCenter = nOverlapGroupCount%2 != 0;
+ if( bSingleCenter )
+ nCenterPos++;
+ if(nCenterPos>1)
+ {
+ pCurrent = pFirstBorder;
+ while( --nCenterPos )
+ pCurrent = pCurrent->pNext;
+ pCenter = pCurrent;
+ }
+
+ //remind current positions
+ pCurrent = pStart;
+ do
+ {
+ pCurrent->aPreviousPosition = pCurrent->xLabelGroupShape->getPosition();
+ pCurrent = pCurrent->pNext;
+ }
+ while( pCurrent != pStart );
+
+ //
+ bool bAlternativeMoveDirection = false;
+ if( !tryMoveLabels( pFirstBorder, pSecondBorder, pCenter, bSingleCenter, bAlternativeMoveDirection, rPageSize ) )
+ tryMoveLabels( pFirstBorder, pSecondBorder, pCenter, bSingleCenter, bAlternativeMoveDirection, rPageSize );
+ return true;
+}
+
+bool PieChart::tryMoveLabels( PieLabelInfo* pFirstBorder, PieLabelInfo* pSecondBorder
+ , PieLabelInfo* pCenter
+ , bool bSingleCenter, bool& rbAlternativeMoveDirection, const awt::Size& rPageSize )
+{
+ PieLabelInfo* p1 = bSingleCenter ? pCenter->pPrevious : pCenter;
+ PieLabelInfo* p2 = pCenter->pNext;
+ //return true when successful
+
+ bool bLabelOrderIsAntiClockWise = m_pPosHelper->isMathematicalOrientationAngle();
+
+ PieLabelInfo* pCurrent = 0;
+ for( pCurrent = p2 ;pCurrent->pPrevious != pSecondBorder; pCurrent = pCurrent->pNext )
+ {
+ PieLabelInfo* pFix = 0;
+ for( pFix = p2->pPrevious ;pFix != pCurrent; pFix = pFix->pNext )
+ {
+ if( !pCurrent->moveAwayFrom( pFix, rPageSize, !bSingleCenter && pCurrent == p2, !bLabelOrderIsAntiClockWise, rbAlternativeMoveDirection ) )
+ {
+ if( !rbAlternativeMoveDirection )
+ {
+ rbAlternativeMoveDirection = true;
+ resetLabelPositionsToPreviousState();
+ return false;
+ }
+ }
+ }
+ }
+ for( pCurrent = p1 ;pCurrent->pNext != pFirstBorder; pCurrent = pCurrent->pPrevious )
+ {
+ PieLabelInfo* pFix = 0;
+ for( pFix = p2->pNext ;pFix != pCurrent; pFix = pFix->pPrevious )
+ {
+ if( !pCurrent->moveAwayFrom( pFix, rPageSize, false, bLabelOrderIsAntiClockWise, rbAlternativeMoveDirection ) )
+ {
+ if( !rbAlternativeMoveDirection )
+ {
+ rbAlternativeMoveDirection = true;
+ resetLabelPositionsToPreviousState();
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void PieChart::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& rPageSize )
+{
+ //------------------------------------------------------------------
+ //check whether there are any labels that should be moved
+ std::vector< PieLabelInfo >::iterator aIt1 = m_aLabelInfoList.begin();
+ std::vector< PieLabelInfo >::const_iterator aEnd = m_aLabelInfoList.end();
+ bool bMoveableFound = false;
+ for( ;aIt1!=aEnd; ++aIt1 )
+ {
+ if(aIt1->bMovementAllowed)
+ {
+ bMoveableFound = true;
+ break;
+ }
+ }
+ if(!bMoveableFound)
+ return;
+
+ double fPageDiagonaleLength = sqrt( double( rPageSize.Width*rPageSize.Width + rPageSize.Height*rPageSize.Height) );
+ if( ::rtl::math::approxEqual( fPageDiagonaleLength, 0.0 ) )
+ return;
+
+ //------------------------------------------------------------------
+ //init next and previous
+ aIt1 = m_aLabelInfoList.begin();
+ std::vector< PieLabelInfo >::iterator aIt2 = aIt1;
+ if( aIt1==aEnd )//no need to do anything when we only have one label
+ return;
+ aIt1->pPrevious = &(*(m_aLabelInfoList.rbegin()));
+ ++aIt2;
+ for( ;aIt2!=aEnd; ++aIt1, ++aIt2 )
+ {
+ PieLabelInfo& rInfo1( *aIt1 );
+ PieLabelInfo& rInfo2( *aIt2 );
+ rInfo1.pNext = &rInfo2;
+ rInfo2.pPrevious = &rInfo1;
+ }
+ aIt1->pNext = &(*(m_aLabelInfoList.begin()));
+
+
+ //------------------------------------------------------------------
+ //detect overlaps and move
+ sal_Int32 nMaxIterations = 50;
+ while( detectLabelOverlapsAndMove( rPageSize ) && nMaxIterations > 0 )
+ nMaxIterations--;
+
+ //------------------------------------------------------------------
+ //create connection lines for the moved labels
+ aEnd = m_aLabelInfoList.end();
+ VLineProperties aVLineProperties;
+ for( aIt1 = m_aLabelInfoList.begin(); aIt1!=aEnd; ++aIt1 )
+ {
+ PieLabelInfo& rInfo( *aIt1 );
+ if( rInfo.bMoved )
+ {
+ sal_Int32 nX1 = rInfo.aFirstPosition.getX();
+ sal_Int32 nY1 = rInfo.aFirstPosition.getY();
+ sal_Int32 nX2 = nX1;
+ sal_Int32 nY2 = nY1;
+ ::basegfx::B2IRectangle aRect( lcl_getRect( rInfo.xLabelGroupShape ) );
+ if( nX1 < aRect.getMinX() )
+ nX2 = aRect.getMinX();
+ else if( nX1 > aRect.getMaxX() )
+ nX2 = aRect.getMaxX();
+
+ if( nY1 < aRect.getMinY() )
+ nY2 = aRect.getMinY();
+ else if( nY1 > aRect.getMaxY() )
+ nY2 = aRect.getMaxY();
+
+
+ //when the line is very short compared to the page size don't create one
+ ::basegfx::B2DVector aLength(nX1-nX2, nY1-nY2);
+ if( (aLength.getLength()/fPageDiagonaleLength) < 0.01 )
+ continue;
+
+ drawing::PointSequenceSequence aPoints(1);
+ aPoints[0].realloc(2);
+ aPoints[0][0].X = nX1;
+ aPoints[0][0].Y = nY1;
+ aPoints[0][1].X = nX2;
+ aPoints[0][1].Y = nY2;
+
+ uno::Reference< beans::XPropertySet > xProp( rInfo.xTextShape, uno::UNO_QUERY);
+ if( xProp.is() )
+ {
+ sal_Int32 nColor = 0;
+ xProp->getPropertyValue(C2U("CharColor")) >>= nColor;
+ if( nColor != -1 )//automatic font color does not work for lines -> fallback to black
+ aVLineProperties.Color = uno::makeAny(nColor);
+ }
+ m_pShapeFactory->createLine2D( rInfo.xTextTarget, aPoints, &aVLineProperties );
+ }
+ }
+}
+
+//.............................................................................
+} //namespace chart
+//.............................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/PieChart.hxx b/chart2/source/view/charttypes/PieChart.hxx
new file mode 100644
index 000000000000..3f2443732899
--- /dev/null
+++ b/chart2/source/view/charttypes/PieChart.hxx
@@ -0,0 +1,148 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _CHART2_PIECHART_HXX
+#define _CHART2_PIECHART_HXX
+
+#include "VSeriesPlotter.hxx"
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/range/b2irectangle.hxx>
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+class PiePositionHelper;
+
+class PieChart : public VSeriesPlotter
+{
+ //-------------------------------------------------------------------------
+ // public methods
+ //-------------------------------------------------------------------------
+public:
+ PieChart( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::chart2::XChartType >& xChartTypeModel
+ , sal_Int32 nDimensionCount, bool bExcludingPositioning );
+ virtual ~PieChart();
+
+ //-------------------------------------------------------------------------
+ // chart2::XPlotter
+ //-------------------------------------------------------------------------
+
+ virtual void SAL_CALL createShapes();
+ virtual void rearrangeLabelToAvoidOverlapIfRequested( const ::com::sun::star::awt::Size& rPageSize );
+
+ virtual void SAL_CALL setScales(
+ const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::chart2::ExplicitScaleData >& rScales
+ , sal_Bool bSwapXAndYAxis )
+ throw (::com::sun::star::uno::RuntimeException);
+ /*
+ virtual ::rtl::OUString SAL_CALL getCoordinateSystemTypeID( ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setScales( const ::com::sun::star::uno::Sequence< ::com::sun::star::chart2::ExplicitScaleData >& rScales ) throw (::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setTransformation( const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTransformation >& xTransformationToLogicTarget, const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTransformation >& xTransformationToFinalPage ) throw (::com::sun::star::uno::RuntimeException);
+ */
+
+ virtual void addSeries( VDataSeries* pSeries, sal_Int32 zSlot = -1, sal_Int32 xSlot = -1,sal_Int32 ySlot = -1 );
+
+ //-------------------
+ virtual ::com::sun::star::drawing::Direction3D getPreferredDiagramAspectRatio() const;
+ virtual bool keepAspectRatio() const;
+ virtual bool shouldSnapRectToUsedArea();
+
+ //MinimumAndMaximumSupplier
+ virtual double getMinimumX();
+ virtual double getMaximumX();
+ virtual double getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex );
+ virtual double getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex );
+
+ virtual bool isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex );
+ virtual bool isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex );
+ virtual bool isExpandWideValuesToZero( sal_Int32 nDimensionIndex );
+ virtual bool isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex );
+ virtual bool isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex );
+
+ //-------------------------------------------------------------------------
+ //-------------------------------------------------------------------------
+ //-------------------------------------------------------------------------
+private: //methods
+ //no default constructor
+ PieChart();
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >
+ createDataPoint( const ::com::sun::star::uno::Reference<
+ ::com::sun::star::drawing::XShapes >& xTarget
+ , const ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertySet >& xObjectProperties
+ , double fUnitCircleStartAngleDegree, double fWidthAngleDegree
+ , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius
+ , double fLogicZ, double fDepth, double fExplodePercentage
+ , tPropertyNameValueMap* pOverWritePropertiesMap );
+
+ double getMaxOffset();
+ bool detectLabelOverlapsAndMove(const ::com::sun::star::awt::Size& rPageSize);//returns true when there might be more to do
+ void resetLabelPositionsToPreviousState();
+struct PieLabelInfo;
+ bool tryMoveLabels( PieLabelInfo* pFirstBorder, PieLabelInfo* pSecondBorder
+ , PieLabelInfo* pCenter, bool bSingleCenter, bool& rbAlternativeMoveDirection
+ , const ::com::sun::star::awt::Size& rPageSize );
+
+private: //member
+ PiePositionHelper* m_pPosHelper;
+ bool m_bUseRings;
+ bool m_bSizeExcludesLabelsAndExplodedSegments;
+
+ struct PieLabelInfo
+ {
+ PieLabelInfo();
+ bool moveAwayFrom( const PieLabelInfo* pFix, const ::com::sun::star::awt::Size& rPageSize
+ , bool bMoveHalfWay, bool bMoveClockwise, bool bAlternativeMoveDirection );
+
+ ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > xTextShape;
+ ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > xLabelGroupShape;
+ ::basegfx::B2IVector aFirstPosition;
+ ::basegfx::B2IVector aOrigin;
+ double fValue;
+ bool bMovementAllowed;
+ bool bMoved;
+ ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > xTextTarget;
+ PieLabelInfo* pPrevious;
+ PieLabelInfo* pNext;
+ ::com::sun::star::awt::Point aPreviousPosition;
+ };
+
+ ::std::vector< PieLabelInfo > m_aLabelInfoList;
+
+ double m_fMaxOffset; /// cached max offset value (init'ed to NaN)
+};
+//.............................................................................
+} //namespace chart
+//.............................................................................
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/Splines.cxx b/chart2/source/view/charttypes/Splines.cxx
new file mode 100644
index 000000000000..1865ab87c779
--- /dev/null
+++ b/chart2/source/view/charttypes/Splines.cxx
@@ -0,0 +1,547 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_chart2.hxx"
+
+#include "Splines.hxx"
+#include <rtl/math.hxx>
+
+#include <vector>
+#include <algorithm>
+#include <functional>
+
+// header for DBG_ASSERT
+#include <tools/debug.hxx>
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+using namespace ::com::sun::star;
+
+namespace
+{
+
+template< typename T >
+struct lcl_EqualsFirstDoubleOfPair : ::std::binary_function< ::std::pair< double, T >, ::std::pair< double, T >, bool >
+{
+ inline bool operator() ( const ::std::pair< double, T > & rOne, const ::std::pair< double, T > & rOther )
+ {
+ return ( ::rtl::math::approxEqual( rOne.first, rOther.first ) );
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+typedef ::std::pair< double, double > tPointType;
+typedef ::std::vector< tPointType > tPointVecType;
+typedef tPointVecType::size_type lcl_tSizeType;
+
+class lcl_SplineCalculation
+{
+public:
+ /** @descr creates an object that calculates cublic splines on construction
+
+ @param rSortedPoints the points for which splines shall be calculated, they need to be sorted in x values
+ @param fY1FirstDerivation the resulting spline should have the first
+ derivation equal to this value at the x-value of the first point
+ of rSortedPoints. If fY1FirstDerivation is set to infinity, a natural
+ spline is calculated.
+ @param fYnFirstDerivation the resulting spline should have the first
+ derivation equal to this value at the x-value of the last point
+ of rSortedPoints
+ */
+ lcl_SplineCalculation( const tPointVecType & rSortedPoints,
+ double fY1FirstDerivation,
+ double fYnFirstDerivation );
+
+ /** @descr this function corresponds to the function splint in [1].
+
+ [1] Numerical Recipies in C, 2nd edition
+ William H. Press, et al.,
+ Section 3.3, page 116
+ */
+ double GetInterpolatedValue( double x );
+
+private:
+ /// a copy of the points given in the CTOR
+ tPointVecType m_aPoints;
+
+ /// the result of the Calculate() method
+ ::std::vector< double > m_aSecDerivY;
+
+ double m_fYp1;
+ double m_fYpN;
+
+ // these values are cached for performance reasons
+ tPointVecType::size_type m_nKLow;
+ tPointVecType::size_type m_nKHigh;
+ double m_fLastInterpolatedValue;
+
+ /** @descr this function corresponds to the function spline in [1].
+
+ [1] Numerical Recipies in C, 2nd edition
+ William H. Press, et al.,
+ Section 3.3, page 115
+ */
+ void Calculate();
+};
+
+//-----------------------------------------------------------------------------
+
+lcl_SplineCalculation::lcl_SplineCalculation(
+ const tPointVecType & rSortedPoints,
+ double fY1FirstDerivation,
+ double fYnFirstDerivation )
+ : m_aPoints( rSortedPoints ),
+ m_fYp1( fY1FirstDerivation ),
+ m_fYpN( fYnFirstDerivation ),
+ m_nKLow( 0 ),
+ m_nKHigh( rSortedPoints.size() - 1 )
+{
+ ::rtl::math::setInf( &m_fLastInterpolatedValue, sal_False );
+
+ // #108301# remove points that have equal x-values
+ m_aPoints.erase( ::std::unique( m_aPoints.begin(), m_aPoints.end(),
+ lcl_EqualsFirstDoubleOfPair< double >() ),
+ m_aPoints.end() );
+ Calculate();
+}
+
+void lcl_SplineCalculation::Calculate()
+{
+ if( m_aPoints.size() <= 1 )
+ return;
+
+ // n is the last valid index to m_aPoints
+ const tPointVecType::size_type n = m_aPoints.size() - 1;
+ ::std::vector< double > u( n );
+ m_aSecDerivY.resize( n + 1, 0.0 );
+
+ if( ::rtl::math::isInf( m_fYp1 ) )
+ {
+ // natural spline
+ m_aSecDerivY[ 0 ] = 0.0;
+ u[ 0 ] = 0.0;
+ }
+ else
+ {
+ m_aSecDerivY[ 0 ] = -0.5;
+ double xDiff = ( m_aPoints[ 1 ].first - m_aPoints[ 0 ].first );
+ u[ 0 ] = ( 3.0 / xDiff ) *
+ ((( m_aPoints[ 1 ].second - m_aPoints[ 0 ].second ) / xDiff ) - m_fYp1 );
+ }
+
+ for( tPointVecType::size_type i = 1; i < n; ++i )
+ {
+ ::std::pair< double, double >
+ p_i = m_aPoints[ i ],
+ p_im1 = m_aPoints[ i - 1 ],
+ p_ip1 = m_aPoints[ i + 1 ];
+
+ double sig = ( p_i.first - p_im1.first ) /
+ ( p_ip1.first - p_im1.first );
+ double p = sig * m_aSecDerivY[ i - 1 ] + 2.0;
+
+ m_aSecDerivY[ i ] = ( sig - 1.0 ) / p;
+ u[ i ] =
+ ( ( p_ip1.second - p_i.second ) /
+ ( p_ip1.first - p_i.first ) ) -
+ ( ( p_i.second - p_im1.second ) /
+ ( p_i.first - p_im1.first ) );
+ u[ i ] =
+ ( 6.0 * u[ i ] / ( p_ip1.first - p_im1.first )
+ - sig * u[ i - 1 ] ) / p;
+ }
+
+ // initialize to values for natural splines (used for m_fYpN equal to
+ // infinity)
+ double qn = 0.0;
+ double un = 0.0;
+
+ if( ! ::rtl::math::isInf( m_fYpN ) )
+ {
+ qn = 0.5;
+ double xDiff = ( m_aPoints[ n ].first - m_aPoints[ n - 1 ].first );
+ un = ( 3.0 / xDiff ) *
+ ( m_fYpN - ( m_aPoints[ n ].second - m_aPoints[ n - 1 ].second ) / xDiff );
+ }
+
+ m_aSecDerivY[ n ] = ( un - qn * u[ n - 1 ] ) * ( qn * m_aSecDerivY[ n - 1 ] + 1.0 );
+
+ // note: the algorithm in [1] iterates from n-1 to 0, but as size_type
+ // may be (usuall is) an unsigned type, we can not write k >= 0, as this
+ // is always true.
+ for( tPointVecType::size_type k = n; k > 0; --k )
+ {
+ ( m_aSecDerivY[ k - 1 ] *= m_aSecDerivY[ k ] ) += u[ k - 1 ];
+ }
+}
+
+double lcl_SplineCalculation::GetInterpolatedValue( double x )
+{
+ DBG_ASSERT( ( m_aPoints[ 0 ].first <= x ) &&
+ ( x <= m_aPoints[ m_aPoints.size() - 1 ].first ),
+ "Trying to extrapolate" );
+
+ const tPointVecType::size_type n = m_aPoints.size() - 1;
+ if( x < m_fLastInterpolatedValue )
+ {
+ m_nKLow = 0;
+ m_nKHigh = n;
+
+ // calculate m_nKLow and m_nKHigh
+ // first initialization is done in CTOR
+ while( m_nKHigh - m_nKLow > 1 )
+ {
+ tPointVecType::size_type k = ( m_nKHigh + m_nKLow ) / 2;
+ if( m_aPoints[ k ].first > x )
+ m_nKHigh = k;
+ else
+ m_nKLow = k;
+ }
+ }
+ else
+ {
+ while( ( m_aPoints[ m_nKHigh ].first < x ) &&
+ ( m_nKHigh <= n ) )
+ {
+ ++m_nKHigh;
+ ++m_nKLow;
+ }
+ DBG_ASSERT( m_nKHigh <= n, "Out of Bounds" );
+ }
+ m_fLastInterpolatedValue = x;
+
+ double h = m_aPoints[ m_nKHigh ].first - m_aPoints[ m_nKLow ].first;
+ DBG_ASSERT( h != 0, "Bad input to GetInterpolatedValue()" );
+
+ double a = ( m_aPoints[ m_nKHigh ].first - x ) / h;
+ double b = ( x - m_aPoints[ m_nKLow ].first ) / h;
+
+ return ( a * m_aPoints[ m_nKLow ].second +
+ b * m_aPoints[ m_nKHigh ].second +
+ (( a*a*a - a ) * m_aSecDerivY[ m_nKLow ] +
+ ( b*b*b - b ) * m_aSecDerivY[ m_nKHigh ] ) *
+ ( h*h ) / 6.0 );
+}
+
+//-----------------------------------------------------------------------------
+
+//create knot vector for B-spline
+double* createTVector( sal_Int32 n, sal_Int32 k )
+{
+ double* t = new double [n + k + 1];
+ for (sal_Int32 i=0; i<=n+k; i++ )
+ {
+ if(i < k)
+ t[i] = 0;
+ else if(i <= n)
+ t[i] = i-k+1;
+ else
+ t[i] = n-k+2;
+ }
+ return t;
+}
+
+//calculate left knot vector
+double TLeft (double x, sal_Int32 i, sal_Int32 k, const double *t )
+{
+ double deltaT = t[i + k - 1] - t[i];
+ return (deltaT == 0.0)
+ ? 0.0
+ : (x - t[i]) / deltaT;
+}
+
+//calculate right knot vector
+double TRight(double x, sal_Int32 i, sal_Int32 k, const double *t )
+{
+ double deltaT = t[i + k] - t[i + 1];
+ return (deltaT == 0.0)
+ ? 0.0
+ : (t[i + k] - x) / deltaT;
+}
+
+//calculate weight vector
+void BVector(double x, sal_Int32 n, sal_Int32 k, double *b, const double *t)
+{
+ sal_Int32 i = 0;
+ for( i=0; i<=n+k; i++ )
+ b[i]=0;
+
+ sal_Int32 i0 = (sal_Int32)floor(x) + k - 1;
+ b [i0] = 1;
+
+ for( sal_Int32 j=2; j<=k; j++ )
+ for( i=0; i<=i0; i++ )
+ b[i] = TLeft(x, i, j, t) * b[i] + TRight(x, i, j, t) * b [i + 1];
+}
+
+} // anonymous namespace
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+void SplineCalculater::CalculateCubicSplines(
+ const drawing::PolyPolygonShape3D& rInput
+ , drawing::PolyPolygonShape3D& rResult
+ , sal_Int32 nGranularity )
+{
+ DBG_ASSERT( nGranularity > 0, "Granularity is invalid" );
+
+ rResult.SequenceX.realloc(0);
+ rResult.SequenceY.realloc(0);
+ rResult.SequenceZ.realloc(0);
+
+ sal_Int32 nOuterCount = rInput.SequenceX.getLength();
+ if( !nOuterCount )
+ return;
+
+ rResult.SequenceX.realloc(nOuterCount);
+ rResult.SequenceY.realloc(nOuterCount);
+ rResult.SequenceZ.realloc(nOuterCount);
+
+ for( sal_Int32 nOuter = 0; nOuter < nOuterCount; ++nOuter )
+ {
+ if( rInput.SequenceX[nOuter].getLength() <= 1 )
+ continue; //we need at least two points
+
+ sal_Int32 nMaxIndexPoints = rInput.SequenceX[nOuter].getLength()-1; // is >=1
+ const double* pOldX = rInput.SequenceX[nOuter].getConstArray();
+ const double* pOldY = rInput.SequenceY[nOuter].getConstArray();
+ const double* pOldZ = rInput.SequenceZ[nOuter].getConstArray();
+
+ // #i13699# The curve gets a parameter and then for each coordinate a
+ // separate spline will be calculated using the parameter as first argument
+ // and the point coordinate as second argument. Therefore the points need
+ // not to be sorted in its x-coordinates. The parameter is sorted by
+ // construction.
+
+ ::std::vector < double > aParameter(nMaxIndexPoints+1);
+ aParameter[0]=0.0;
+ for( sal_Int32 nIndex=1; nIndex<=nMaxIndexPoints; nIndex++ )
+ {
+ // The euclidian distance leads to curve loops for functions having single extreme points
+ //aParameter[nIndex]=aParameter[nIndex-1]+
+ //sqrt( (pOldX[nIndex]-pOldX[nIndex-1])*(pOldX[nIndex]-pOldX[nIndex-1])+
+ //(pOldY[nIndex]-pOldY[nIndex-1])*(pOldY[nIndex]-pOldY[nIndex-1])+
+ //(pOldZ[nIndex]-pOldZ[nIndex-1])*(pOldZ[nIndex]-pOldZ[nIndex-1]));
+
+ // use increment of 1 instead
+ aParameter[nIndex]=aParameter[nIndex-1]+1;
+ }
+ // Split the calculation to X, Y and Z coordinate
+ tPointVecType aInputX;
+ aInputX.resize(nMaxIndexPoints+1);
+ tPointVecType aInputY;
+ aInputY.resize(nMaxIndexPoints+1);
+ tPointVecType aInputZ;
+ aInputZ.resize(nMaxIndexPoints+1);
+ for (sal_Int32 nN=0;nN<=nMaxIndexPoints; nN++ )
+ {
+ aInputX[ nN ].first=aParameter[nN];
+ aInputX[ nN ].second=pOldX[ nN ];
+ aInputY[ nN ].first=aParameter[nN];
+ aInputY[ nN ].second=pOldY[ nN ];
+ aInputZ[ nN ].first=aParameter[nN];
+ aInputZ[ nN ].second=pOldZ[ nN ];
+ }
+
+ // generate a spline for each coordinate. It holds the complete
+ // information to calculate each point of the curve
+ double fXDerivation;
+ double fYDerivation;
+ double fZDerivation;
+ if( pOldX[ 0 ] == pOldX[nMaxIndexPoints] &&
+ pOldY[ 0 ] == pOldY[nMaxIndexPoints] &&
+ pOldZ[ 0 ] == pOldZ[nMaxIndexPoints] )
+ {
+ // #i101050# avoid a corner in closed lines, which are smoothed by spline
+ // This derivation are special for parameter of kind 0,1,2,3... If you
+ // change generating parameters (see above), then adapt derivations too.)
+ fXDerivation = 0.5 * (pOldX[1]-pOldX[nMaxIndexPoints-1]);
+ fYDerivation = 0.5 * (pOldY[1]-pOldY[nMaxIndexPoints-1]);
+ fZDerivation = 0.5 * (pOldZ[1]-pOldZ[nMaxIndexPoints-1]);
+ }
+ else // generate the kind "natural spline"
+ {
+ double fInfty;
+ ::rtl::math::setInf( &fInfty, sal_False );
+ fXDerivation = fInfty;
+ fYDerivation = fInfty;
+ fZDerivation = fInfty;
+ }
+ lcl_SplineCalculation aSplineX( aInputX, fXDerivation, fXDerivation );
+ lcl_SplineCalculation aSplineY( aInputY, fYDerivation, fYDerivation );
+ lcl_SplineCalculation aSplineZ( aInputZ, fZDerivation, fZDerivation );
+
+ // fill result polygon with calculated values
+ rResult.SequenceX[nOuter].realloc( nMaxIndexPoints*nGranularity + 1);
+ rResult.SequenceY[nOuter].realloc( nMaxIndexPoints*nGranularity + 1);
+ rResult.SequenceZ[nOuter].realloc( nMaxIndexPoints*nGranularity + 1);
+
+ double* pNewX = rResult.SequenceX[nOuter].getArray();
+ double* pNewY = rResult.SequenceY[nOuter].getArray();
+ double* pNewZ = rResult.SequenceZ[nOuter].getArray();
+
+ sal_Int32 nNewPointIndex = 0; // Index in result points
+ // needed for inner loop
+ double fInc; // step for intermediate points
+ sal_Int32 nj; // for loop
+ double fParam; // a intermediate parameter value
+
+ for( sal_Int32 ni = 0; ni < nMaxIndexPoints; ni++ )
+ {
+ // given point is surely a curve point
+ pNewX[nNewPointIndex] = pOldX[ni];
+ pNewY[nNewPointIndex] = pOldY[ni];
+ pNewZ[nNewPointIndex] = pOldZ[ni];
+ nNewPointIndex++;
+
+ // calculate intermediate points
+ fInc = ( aParameter[ ni+1 ] - aParameter[ni] ) / static_cast< double >( nGranularity );
+ for(nj = 1; nj < nGranularity; nj++)
+ {
+ fParam = aParameter[ni] + ( fInc * static_cast< double >( nj ) );
+
+ pNewX[nNewPointIndex]=aSplineX.GetInterpolatedValue( fParam );
+ pNewY[nNewPointIndex]=aSplineY.GetInterpolatedValue( fParam );
+ pNewZ[nNewPointIndex]=aSplineZ.GetInterpolatedValue( fParam );
+ nNewPointIndex++;
+ }
+ }
+ // add last point
+ pNewX[nNewPointIndex] = pOldX[nMaxIndexPoints];
+ pNewY[nNewPointIndex] = pOldY[nMaxIndexPoints];
+ pNewZ[nNewPointIndex] = pOldZ[nMaxIndexPoints];
+ }
+}
+
+void SplineCalculater::CalculateBSplines(
+ const ::com::sun::star::drawing::PolyPolygonShape3D& rInput
+ , ::com::sun::star::drawing::PolyPolygonShape3D& rResult
+ , sal_Int32 nGranularity
+ , sal_Int32 nDegree )
+{
+ // #issue 72216#
+ // k is the order of the BSpline, nDegree is the degree of its polynoms
+ sal_Int32 k = nDegree + 1;
+
+ rResult.SequenceX.realloc(0);
+ rResult.SequenceY.realloc(0);
+ rResult.SequenceZ.realloc(0);
+
+ sal_Int32 nOuterCount = rInput.SequenceX.getLength();
+ if( !nOuterCount )
+ return; // no input
+
+ rResult.SequenceX.realloc(nOuterCount);
+ rResult.SequenceY.realloc(nOuterCount);
+ rResult.SequenceZ.realloc(nOuterCount);
+
+ for( sal_Int32 nOuter = 0; nOuter < nOuterCount; ++nOuter )
+ {
+ if( rInput.SequenceX[nOuter].getLength() <= 1 )
+ continue; // need at least 2 control points
+
+ sal_Int32 n = rInput.SequenceX[nOuter].getLength()-1; // maximum index of control points
+
+ double fCurveparam =0.0; // parameter for the curve
+ // 0<= fCurveparam < fMaxCurveparam
+ double fMaxCurveparam = 2.0+ n - k;
+ if (fMaxCurveparam <= 0.0)
+ return; // not enough control points for desired spline order
+
+ if (nGranularity < 1)
+ return; //need at least 1 line for each part beween the control points
+
+ const double* pOldX = rInput.SequenceX[nOuter].getConstArray();
+ const double* pOldY = rInput.SequenceY[nOuter].getConstArray();
+ const double* pOldZ = rInput.SequenceZ[nOuter].getConstArray();
+
+ // keep this amount of steps to go well with old version
+ sal_Int32 nNewSectorCount = nGranularity * n;
+ double fCurveStep = fMaxCurveparam/static_cast< double >(nNewSectorCount);
+
+ double *b = new double [n + k + 1]; // values of blending functions
+
+ const double* t = createTVector(n, k); // knot vector
+
+ rResult.SequenceX[nOuter].realloc(nNewSectorCount+1);
+ rResult.SequenceY[nOuter].realloc(nNewSectorCount+1);
+ rResult.SequenceZ[nOuter].realloc(nNewSectorCount+1);
+ double* pNewX = rResult.SequenceX[nOuter].getArray();
+ double* pNewY = rResult.SequenceY[nOuter].getArray();
+ double* pNewZ = rResult.SequenceZ[nOuter].getArray();
+
+ // variables needed inside loop, when calculating one point of output
+ sal_Int32 nPointIndex =0; //index of given contol points
+ double fX=0.0;
+ double fY=0.0;
+ double fZ=0.0; //coordinates of a new BSpline point
+
+ for(sal_Int32 nNewSector=0; nNewSector<nNewSectorCount; nNewSector++)
+ { // in first looping fCurveparam has value 0.0
+
+ // Calculate the values of the blending functions for actual curve parameter
+ BVector(fCurveparam, n, k, b, t);
+
+ // output point(fCurveparam) = sum over {input point * value of blending function}
+ fX = 0.0;
+ fY = 0.0;
+ fZ = 0.0;
+ for (nPointIndex=0;nPointIndex<=n;nPointIndex++)
+ {
+ fX +=pOldX[nPointIndex]*b[nPointIndex];
+ fY +=pOldY[nPointIndex]*b[nPointIndex];
+ fZ +=pOldZ[nPointIndex]*b[nPointIndex];
+ }
+ pNewX[nNewSector] = fX;
+ pNewY[nNewSector] = fY;
+ pNewZ[nNewSector] = fZ;
+
+ fCurveparam += fCurveStep; //for next looping
+ }
+ // add last control point to BSpline curve
+ pNewX[nNewSectorCount] = pOldX[n];
+ pNewY[nNewSectorCount] = pOldY[n];
+ pNewZ[nNewSectorCount] = pOldZ[n];
+
+ delete[] t;
+ delete[] b;
+ }
+}
+
+//.............................................................................
+} //namespace chart
+//.............................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/Splines.hxx b/chart2/source/view/charttypes/Splines.hxx
new file mode 100644
index 000000000000..0e8206fcade1
--- /dev/null
+++ b/chart2/source/view/charttypes/Splines.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef _CHART2_SPLINECALCULATOR_HXX
+#define _CHART2_SPLINECALCULATOR_HXX
+
+#include <com/sun/star/drawing/PolyPolygonShape3D.hpp>
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+
+//-----------------------------------------------------------------------------
+/**
+*/
+
+class SplineCalculater
+{
+public:
+ static void CalculateCubicSplines(
+ const ::com::sun::star::drawing::PolyPolygonShape3D& rPoints
+ , ::com::sun::star::drawing::PolyPolygonShape3D& rResult
+ , sal_Int32 nGranularity );
+
+ static void CalculateBSplines(
+ const ::com::sun::star::drawing::PolyPolygonShape3D& rPoints
+ , ::com::sun::star::drawing::PolyPolygonShape3D& rResult
+ , sal_Int32 nGranularity
+ , sal_Int32 nSplineDepth );
+};
+
+
+//.............................................................................
+} //namespace chart
+//.............................................................................
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/VSeriesPlotter.cxx b/chart2/source/view/charttypes/VSeriesPlotter.cxx
new file mode 100644
index 000000000000..97a3cbd86f2d
--- /dev/null
+++ b/chart2/source/view/charttypes/VSeriesPlotter.cxx
@@ -0,0 +1,2113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_chart2.hxx"
+
+#include "VSeriesPlotter.hxx"
+#include "ShapeFactory.hxx"
+#include "chartview/ExplicitValueProvider.hxx"
+
+#include "CommonConverters.hxx"
+#include "macros.hxx"
+#include "ViewDefines.hxx"
+#include "ObjectIdentifier.hxx"
+#include "StatisticsHelper.hxx"
+#include "PlottingPositionHelper.hxx"
+#include "LabelPositionHelper.hxx"
+#include "ChartTypeHelper.hxx"
+#include "Clipping.hxx"
+#include "servicenames_charttypes.hxx"
+#include "chartview/NumberFormatterWrapper.hxx"
+#include "ContainerHelper.hxx"
+#include "DataSeriesHelper.hxx"
+#include "RegressionCurveHelper.hxx"
+#include "VLegendSymbolFactory.hxx"
+#include "FormattedStringHelper.hxx"
+#include "ResId.hxx"
+#include "Strings.hrc"
+#include "RelativePositionHelper.hxx"
+
+//only for creation: @todo remove if all plotter are uno components and instanciated via servicefactory
+#include "BarChart.hxx"
+#include "PieChart.hxx"
+#include "AreaChart.hxx"
+#include "CandleStickChart.hxx"
+#include "BubbleChart.hxx"
+//
+
+#include <com/sun/star/chart/ErrorBarStyle.hpp>
+#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/chart2/RelativePosition.hpp>
+#include <editeng/unoprnms.hxx>
+#include <tools/color.hxx>
+// header for class OUStringBuffer
+#include <rtl/ustrbuf.hxx>
+#include <rtl/math.hxx>
+#include <tools/debug.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <com/sun/star/util/XCloneable.hpp>
+
+#include <svx/unoshape.hxx>
+
+#include <functional>
+
+//.............................................................................
+namespace chart
+{
+//.............................................................................
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using rtl::OUString;
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+VDataSeriesGroup::CachedYValues::CachedYValues()
+ : m_bValuesDirty(true)
+ , m_fMinimumY(0.0)
+ , m_fMaximumY(0.0)
+{
+}
+
+VDataSeriesGroup::VDataSeriesGroup()
+ : m_aSeriesVector()
+ , m_bMaxPointCountDirty(true)
+ , m_nMaxPointCount(0)
+ , m_aListOfCachedYValues()
+
+{
+}
+
+VDataSeriesGroup::VDataSeriesGroup( VDataSeries* pSeries )
+ : m_aSeriesVector(1,pSeries)
+ , m_bMaxPointCountDirty(true)
+ , m_nMaxPointCount(0)
+ , m_aListOfCachedYValues()
+{
+}
+
+VDataSeriesGroup::~VDataSeriesGroup()
+{
+}
+
+void VDataSeriesGroup::deleteSeries()
+{
+ //delete all data series help objects:
+ ::std::vector< VDataSeries* >::const_iterator aIter = m_aSeriesVector.begin();
+ const ::std::vector< VDataSeries* >::const_iterator aEnd = m_aSeriesVector.end();
+ for( ; aIter != aEnd; aIter++ )
+ {
+ delete *aIter;
+ }
+ m_aSeriesVector.clear();
+}
+
+void VDataSeriesGroup::addSeries( VDataSeries* pSeries )
+{
+ m_aSeriesVector.push_back(pSeries);
+ m_bMaxPointCountDirty=true;
+}
+
+sal_Int32 VDataSeriesGroup::getSeriesCount() const
+{
+ return m_aSeriesVector.size();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+VSeriesPlotter::VSeriesPlotter( const uno::Reference<XChartType>& xChartTypeModel
+ , sal_Int32 nDimensionCount, bool bCategoryXAxis )
+ : PlotterBase( nDimensionCount )
+ , m_pMainPosHelper( 0 )
+ , m_xChartTypeModel(xChartTypeModel)
+ , m_xChartTypeModelProps( uno::Reference< beans::XPropertySet >::query( xChartTypeModel ))
+ , m_aZSlots()
+ , m_bCategoryXAxis(bCategoryXAxis)
+ , m_xColorScheme()
+ , m_pExplicitCategoriesProvider(0)
+ , m_bPointsWereSkipped(false)
+{
+ DBG_ASSERT(m_xChartTypeModel.is(),"no XChartType available in view, fallback to default values may be wrong");
+}
+
+VSeriesPlotter::~VSeriesPlotter()
+{
+ //delete all data series help objects:
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
+ const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
+ for( ; aZSlotIter != aZSlotEnd; aZSlotIter++ )
+ {
+ ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+ for( ; aXSlotIter != aXSlotEnd; aXSlotIter++ )
+ {
+ aXSlotIter->deleteSeries();
+ }
+ aZSlotIter->clear();
+ }
+ m_aZSlots.clear();
+
+ tSecondaryPosHelperMap::iterator aPosIt = m_aSecondaryPosHelperMap.begin();
+ while( aPosIt != m_aSecondaryPosHelperMap.end() )
+ {
+ PlottingPositionHelper* pPosHelper = aPosIt->second;
+ if( pPosHelper )
+ delete pPosHelper;
+ ++aPosIt;
+ }
+ m_aSecondaryPosHelperMap.clear();
+
+ m_aSecondaryValueScales.clear();
+}
+
+void VSeriesPlotter::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
+{
+ //take ownership of pSeries
+
+ DBG_ASSERT( pSeries, "series to add is NULL" );
+ if(!pSeries)
+ return;
+
+ if(m_bCategoryXAxis)
+ pSeries->setCategoryXAxis();
+
+ if(zSlot<0 || zSlot>=static_cast<sal_Int32>(m_aZSlots.size()))
+ {
+ //new z slot
+ ::std::vector< VDataSeriesGroup > aZSlot;
+ aZSlot.push_back( VDataSeriesGroup(pSeries) );
+ m_aZSlots.push_back( aZSlot );
+ }
+ else
+ {
+ //existing zslot
+ ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[zSlot];
+
+ if(xSlot<0 || xSlot>=static_cast<sal_Int32>(rXSlots.size()))
+ {
+ //append the series to already existing x series
+ rXSlots.push_back( VDataSeriesGroup(pSeries) );
+ }
+ else
+ {
+ //x slot is already occupied
+ //y slot decides what to do:
+
+ VDataSeriesGroup& rYSlots = rXSlots[xSlot];
+ sal_Int32 nYSlotCount = rYSlots.getSeriesCount();
+
+ if( ySlot < -1 )
+ {
+ //move all existing series in the xSlot to next slot
+ //@todo
+ OSL_ENSURE( false, "Not implemented yet");
+ }
+ else if( ySlot == -1 || ySlot >= nYSlotCount)
+ {
+ //append the series to already existing y series
+ rYSlots.addSeries(pSeries);
+ }
+ else
+ {
+ //y slot is already occupied
+ //insert at given y and x position
+
+ //@todo
+ OSL_ENSURE( false, "Not implemented yet");
+ }
+ }
+ }
+}
+
+drawing::Direction3D VSeriesPlotter::getPreferredDiagramAspectRatio() const
+{
+ drawing::Direction3D aRet(1.0,1.0,1.0);
+ drawing::Direction3D aScale( m_pPosHelper->getScaledLogicWidth() );
+ aRet.DirectionZ = aScale.DirectionZ*0.2;
+ if(aRet.DirectionZ>1.0)
+ aRet.DirectionZ=1.0;
+ if(aRet.DirectionZ>10)
+ aRet.DirectionZ=10;
+ return aRet;
+}
+
+bool VSeriesPlotter::keepAspectRatio() const
+{
+ return true;
+}
+
+void VSeriesPlotter::releaseShapes()
+{
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
+ const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
+ for( ; aZSlotIter != aZSlotEnd; aZSlotIter++ )
+ {
+ ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+ for( ; aXSlotIter != aXSlotEnd; aXSlotIter++ )
+ {
+ ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
+
+ ::std::vector< VDataSeries* >::iterator aSeriesIter = pSeriesList->begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
+
+ //iterate through all series in this x slot
+ for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
+ {
+ VDataSeries* pSeries( *aSeriesIter );
+ pSeries->releaseShapes();
+ }
+ }
+ }
+}
+
+uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShape( VDataSeries* pDataSeries
+ , const uno::Reference< drawing::XShapes >& xTarget )
+{
+ uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xGroupShape );
+ if( !xShapes.is() )
+ {
+ //create a group shape for this series and add to logic target:
+ xShapes = createGroupShape( xTarget,pDataSeries->getCID() );
+ pDataSeries->m_xGroupShape = xShapes;
+ }
+ return xShapes;
+}
+
+uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShapeFrontChild( VDataSeries* pDataSeries
+ , const uno::Reference< drawing::XShapes >& xTarget )
+{
+ uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xFrontSubGroupShape );
+ if(!xShapes.is())
+ {
+ //ensure that the series group shape is already created
+ uno::Reference< drawing::XShapes > xSeriesShapes( this->getSeriesGroupShape( pDataSeries, xTarget ) );
+ //ensure that the back child is created first
+ this->getSeriesGroupShapeBackChild( pDataSeries, xTarget );
+ //use series group shape as parent for the new created front group shape
+ xShapes = createGroupShape( xSeriesShapes );
+ pDataSeries->m_xFrontSubGroupShape = xShapes;
+ }
+ return xShapes;
+}
+
+uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShapeBackChild( VDataSeries* pDataSeries
+ , const uno::Reference< drawing::XShapes >& xTarget )
+{
+ uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xBackSubGroupShape );
+ if(!xShapes.is())
+ {
+ //ensure that the series group shape is already created
+ uno::Reference< drawing::XShapes > xSeriesShapes( this->getSeriesGroupShape( pDataSeries, xTarget ) );
+ //use series group shape as parent for the new created back group shape
+ xShapes = createGroupShape( xSeriesShapes );
+ pDataSeries->m_xBackSubGroupShape = xShapes;
+ }
+ return xShapes;
+}
+
+uno::Reference< drawing::XShapes > VSeriesPlotter::getLabelsGroupShape( VDataSeries& rDataSeries
+ , const uno::Reference< drawing::XShapes >& xTextTarget )
+{
+ //xTextTarget needs to be a 2D shape container always!
+
+ uno::Reference< drawing::XShapes > xShapes( rDataSeries.m_xLabelsGroupShape );
+ if(!xShapes.is())
+ {
+ //create a 2D group shape for texts of this series and add to text target:
+ xShapes = m_pShapeFactory->createGroup2D( xTextTarget, rDataSeries.getLabelsCID() );
+ rDataSeries.m_xLabelsGroupShape = xShapes;
+ }
+ return xShapes;
+}
+
+uno::Reference< drawing::XShapes > VSeriesPlotter::getErrorBarsGroupShape( VDataSeries& rDataSeries
+ , const uno::Reference< drawing::XShapes >& xTarget )
+{
+ uno::Reference< drawing::XShapes > xShapes( rDataSeries.m_xErrorBarsGroupShape );
+ if(!xShapes.is())
+ {
+ //create a group shape for this series and add to logic target:
+ xShapes = this->createGroupShape( xTarget,rDataSeries.getErrorBarsCID() );
+ rDataSeries.m_xErrorBarsGroupShape = xShapes;
+ }
+ return xShapes;
+
+}
+
+OUString VSeriesPlotter::getLabelTextForValue( VDataSeries& rDataSeries
+ , sal_Int32 nPointIndex
+ , double fValue
+ , bool bAsPercentage )
+{
+ OUString aNumber;
+
+ if( m_apNumberFormatterWrapper.get())
+ {
+ sal_Int32 nNumberFormatKey = 0;
+ if( rDataSeries.hasExplicitNumberFormat(nPointIndex,bAsPercentage) )
+ nNumberFormatKey = rDataSeries.getExplicitNumberFormat(nPointIndex,bAsPercentage);
+ else if( bAsPercentage )
+ {
+ sal_Int32 nPercentFormat = ExplicitValueProvider::getPercentNumberFormat( m_apNumberFormatterWrapper->getNumberFormatsSupplier() );
+ if( nPercentFormat != -1 )
+ nNumberFormatKey = nPercentFormat;
+ }
+ else
+ {
+ if( rDataSeries.shouldLabelNumberFormatKeyBeDetectedFromYAxis() && m_aAxesNumberFormats.hasFormat(1,rDataSeries.getAttachedAxisIndex()) ) //y-axis
+ nNumberFormatKey = m_aAxesNumberFormats.getFormat(1,rDataSeries.getAttachedAxisIndex());
+ else
+ nNumberFormatKey = rDataSeries.detectNumberFormatKey( nPointIndex );
+ }
+ if(nNumberFormatKey<0)
+ nNumberFormatKey=0;
+
+ sal_Int32 nLabelCol = 0;
+ bool bColChanged;
+ aNumber = m_apNumberFormatterWrapper->getFormattedString(
+ nNumberFormatKey, fValue, nLabelCol, bColChanged );
+ //@todo: change color of label if bColChanged is true
+ }
+ else
+ {
+ sal_Unicode cDecSeparator = '.';//@todo get this locale dependent
+ aNumber = ::rtl::math::doubleToUString( fValue, rtl_math_StringFormat_G /*rtl_math_StringFormat*/
+ , 3/*DecPlaces*/ , cDecSeparator /*,sal_Int32 const * pGroups*/ /*,sal_Unicode cGroupSeparator*/ ,false /*bEraseTrailingDecZeros*/ );
+ }
+ return aNumber;
+}
+
+uno::Reference< drawing::XShape > VSeriesPlotter::createDataLabel( const uno::Reference< drawing::XShapes >& xTarget
+ , VDataSeries& rDataSeries
+ , sal_Int32 nPointIndex
+ , double fValue
+ , double fSumValue
+ , const awt::Point& rScreenPosition2D
+ , LabelAlignment eAlignment
+ , sal_Int32 nOffset )
+{
+ uno::Reference< drawing::XShape > xTextShape;
+
+ try
+ {
+ awt::Point aScreenPosition2D(rScreenPosition2D);
+ if(LABEL_ALIGN_LEFT==eAlignment)
+ aScreenPosition2D.X -= nOffset;
+ else if(LABEL_ALIGN_RIGHT==eAlignment)
+ aScreenPosition2D.X += nOffset;
+ else if(LABEL_ALIGN_TOP==eAlignment)
+ aScreenPosition2D.Y -= nOffset;
+ else if(LABEL_ALIGN_BOTTOM==eAlignment)
+ aScreenPosition2D.Y += nOffset;
+
+ uno::Reference< drawing::XShapes > xTarget_(
+ m_pShapeFactory->createGroup2D( this->getLabelsGroupShape(rDataSeries, xTarget)
+ , ObjectIdentifier::createPointCID( rDataSeries.getLabelCID_Stub(),nPointIndex ) ) );
+
+ //check wether the label needs to be created and how:
+ DataPointLabel* pLabel = rDataSeries.getDataPointLabelIfLabel( nPointIndex );
+
+ if( !pLabel )
+ return xTextShape;
+
+ //------------------------------------------------
+ //prepare legend symbol
+
+ Reference< drawing::XShape > xSymbol;
+ if(pLabel->ShowLegendSymbol)
+ {
+ if( rDataSeries.isVaryColorsByPoint() )
+ xSymbol.set( VSeriesPlotter::createLegendSymbolForPoint( rDataSeries, nPointIndex, xTarget_, m_xShapeFactory ) );
+ else
+ xSymbol.set( VSeriesPlotter::createLegendSymbolForSeries( rDataSeries, xTarget_, m_xShapeFactory ) );
+
+ }
+ //prepare text
+ ::rtl::OUStringBuffer aText;
+ ::rtl::OUString aSeparator(sal_Unicode(' '));
+ double fRotationDegrees = 0.0;
+ try
+ {
+ uno::Reference< beans::XPropertySet > xPointProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) );
+ if(xPointProps.is())
+ {
+ xPointProps->getPropertyValue( C2U( "LabelSeparator" ) ) >>= aSeparator;
+ xPointProps->getPropertyValue( C2U( "TextRotation" ) ) >>= fRotationDegrees;
+ }
+ }
+ catch( uno::Exception& e )
+ {
+ ASSERT_EXCEPTION( e );
+ }
+ bool bMultiLineLabel = aSeparator.equals(C2U("\n"));;
+ sal_Int32 nLineCountForSymbolsize = 0;
+ {
+ if(pLabel->ShowCategoryName)
+ {
+ if( m_pExplicitCategoriesProvider )
+ {
+ Sequence< OUString > aCategories( m_pExplicitCategoriesProvider->getSimpleCategories() );
+ if( nPointIndex >= 0 && nPointIndex < aCategories.getLength() )
+ {
+ aText.append( aCategories[nPointIndex] );
+ ++nLineCountForSymbolsize;
+ }
+ }
+ }
+
+ if(pLabel->ShowNumber)
+ {
+ OUString aNumber( this->getLabelTextForValue( rDataSeries
+ , nPointIndex, fValue, false /*bAsPercentage*/ ) );
+ if( aNumber.getLength() )
+ {
+ if(aText.getLength())
+ aText.append(aSeparator);
+ aText.append(aNumber);
+ ++nLineCountForSymbolsize;
+ }
+ }
+
+ if(pLabel->ShowNumberInPercent)
+ {
+ if(fSumValue==0.0)
+ fSumValue=1.0;
+ fValue /= fSumValue;
+ if( fValue < 0 )
+ fValue*=-1.0;
+
+ OUString aPercentage( this->getLabelTextForValue( rDataSeries
+ , nPointIndex, fValue, true /*bAsPercentage*/ ) );
+ if( aPercentage.getLength() )
+ {
+ if(aText.getLength())
+ aText.append(aSeparator);
+ aText.append(aPercentage);
+ ++nLineCountForSymbolsize;
+ }
+ }
+ }
+ //------------------------------------------------
+ //prepare properties for multipropertyset-interface of shape
+ tNameSequence* pPropNames;
+ tAnySequence* pPropValues;
+ if( !rDataSeries.getTextLabelMultiPropertyLists( nPointIndex, pPropNames, pPropValues ) )
+ return xTextShape;
+ LabelPositionHelper::changeTextAdjustment( *pPropValues, *pPropNames, eAlignment );
+
+ //------------------------------------------------
+ //create text shape
+ xTextShape = ShapeFactory(m_xShapeFactory).
+ createText( xTarget_, aText.makeStringAndClear()
+ , *pPropNames, *pPropValues, ShapeFactory::makeTransformation( aScreenPosition2D ) );
+
+ if( !xTextShape.is() )
+ return xTextShape;
+
+ const awt::Point aUnrotatedTextPos( xTextShape->getPosition() );
+ if( fRotationDegrees != 0.0 )
+ {
+ const double fDegreesPi( fRotationDegrees * ( F_PI / -180.0 ) );
+ uno::Reference< beans::XPropertySet > xProp( xTextShape, uno::UNO_QUERY );
+ if( xProp.is() )
+ xProp->setPropertyValue( C2U( "Transformation" ), ShapeFactory::makeTransformation( aScreenPosition2D, fDegreesPi ) );
+ LabelPositionHelper::correctPositionForRotation( xTextShape, eAlignment, fRotationDegrees, true /*bRotateAroundCenter*/ );
+ }
+
+ if( xSymbol.is() )
+ {
+ const awt::Point aOldTextPos( xTextShape->getPosition() );
+ awt::Point aNewTextPos( aOldTextPos );
+
+ awt::Size aSymbolSize( xSymbol->getSize() );
+ awt::Size aTextSize( xTextShape->getSize() );
+
+ if( !bMultiLineLabel || nLineCountForSymbolsize <= 0 )
+ nLineCountForSymbolsize = 1;
+ sal_Int32 nYDiff = aTextSize.Height/nLineCountForSymbolsize;
+ sal_Int32 nXDiff = aSymbolSize.Width * nYDiff/aSymbolSize.Height;
+
+ // #i109336# Improve auto positioning in chart
+ nXDiff = nXDiff * 80 / 100;
+ nYDiff = nYDiff * 80 / 100;
+
+ aSymbolSize.Width = nXDiff * 75/100;
+ aSymbolSize.Height = nYDiff * 75/100;
+
+ awt::Point aSymbolPosition( aUnrotatedTextPos );
+
+ // #i109336# Improve auto positioning in chart
+ aSymbolPosition.Y += ( nYDiff / 4 );
+
+ if(LABEL_ALIGN_LEFT==eAlignment
+ || LABEL_ALIGN_LEFT_TOP==eAlignment
+ || LABEL_ALIGN_LEFT_BOTTOM==eAlignment)
+ {
+ aSymbolPosition.X -= nXDiff;
+ }
+ else if(LABEL_ALIGN_RIGHT==eAlignment
+ || LABEL_ALIGN_RIGHT_TOP==eAlignment
+ || LABEL_ALIGN_RIGHT_BOTTOM==eAlignment )
+ {
+ aNewTextPos.X += nXDiff;
+ }
+ else if(LABEL_ALIGN_TOP==eAlignment
+ || LABEL_ALIGN_BOTTOM==eAlignment
+ || LABEL_ALIGN_CENTER==eAlignment )
+ {
+ aSymbolPosition.X -= nXDiff/2;
+ aNewTextPos.X += nXDiff/2;
+ }
+
+ xSymbol->setSize( aSymbolSize );
+ xSymbol->setPosition( aSymbolPosition );
+
+ //set position
+ xTextShape->setPosition( aNewTextPos );
+ }
+ }
+ catch( uno::Exception& e )
+ {
+ ASSERT_EXCEPTION( e );
+ }
+
+ return xTextShape;
+}
+
+namespace
+{
+double lcl_getErrorBarLogicLength(
+ const uno::Sequence< double > & rData,
+ uno::Reference< beans::XPropertySet > xProp,
+ sal_Int32 nErrorBarStyle,
+ sal_Int32 nIndex,
+ bool bPositive )
+{
+ double fResult;
+ ::rtl::math::setNan( & fResult );
+ try
+ {
+ switch( nErrorBarStyle )
+ {
+ case ::com::sun::star::chart::ErrorBarStyle::NONE:
+ break;
+ case ::com::sun::star::chart::ErrorBarStyle::VARIANCE:
+ fResult = StatisticsHelper::getVariance( rData );
+ break;
+ case ::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION:
+ fResult = StatisticsHelper::getStandardDeviation( rData );
+ break;
+ case ::com::sun::star::chart::ErrorBarStyle::RELATIVE:
+ {
+ double fPercent = 0;
+ if( xProp->getPropertyValue( bPositive
+ ? C2U("PositiveError")
+ : C2U("NegativeError")) >>= fPercent )
+ {
+ if( nIndex >=0 && nIndex < rData.getLength() &&
+ ! ::rtl::math::isNan( rData[nIndex] ) &&
+ ! ::rtl::math::isNan( fPercent ))
+ {
+ fResult = rData[nIndex] * fPercent / 100.0;
+ }
+ }
+ }
+ break;
+ case ::com::sun::star::chart::ErrorBarStyle::ABSOLUTE:
+ xProp->getPropertyValue( bPositive
+ ? C2U("PositiveError")
+ : C2U("NegativeError")) >>= fResult;
+ break;
+ case ::com::sun::star::chart::ErrorBarStyle::ERROR_MARGIN:
+ {
+ // todo: check if this is really what's called error-margin
+ double fPercent = 0;
+ if( xProp->getPropertyValue( bPositive
+ ? C2U("PositiveError")
+ : C2U("NegativeError")) >>= fPercent )
+ {
+ double fMaxValue;
+ ::rtl::math::setInf(&fMaxValue, true);
+ const double* pValues = rData.getConstArray();
+ for(sal_Int32 i=0; i<rData.getLength(); ++i, ++pValues)
+ {
+ if(fMaxValue<*pValues)
+ fMaxValue=*pValues;
+ }
+ if( ::rtl::math::isFinite( fMaxValue ) &&
+ ::rtl::math::isFinite( fPercent ))
+ {
+ fResult = fMaxValue * fPercent / 100.0;
+ }
+ }
+ }
+ break;
+ case ::com::sun::star::chart::ErrorBarStyle::STANDARD_ERROR:
+ fResult = StatisticsHelper::getStandardError( rData );
+ break;
+ case ::com::sun::star::chart::ErrorBarStyle::FROM_DATA:
+ {
+ uno::Reference< chart2::data::XDataSource > xErrorBarData( xProp, uno::UNO_QUERY );
+ if( xErrorBarData.is())
+ fResult = StatisticsHelper::getErrorFromDataSource(
+ xErrorBarData, nIndex, bPositive /*, true */ /* y-error */ );
+ }
+ break;
+ }
+ }
+ catch( uno::Exception & e )
+ {
+ ASSERT_EXCEPTION( e );
+ }
+
+ return fResult;
+}
+
+void lcl_AddErrorBottomLine( const drawing::Position3D& rPosition, ::basegfx::B2DVector aMainDirection
+ , drawing::PolyPolygonShape3D& rPoly, sal_Int32 nSequenceIndex )
+{
+ double fFixedWidth = 200.0;
+
+ aMainDirection.normalize();
+ ::basegfx::B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
+ aOrthoDirection.normalize();
+
+ ::basegfx::B2DVector aAnchor( rPosition.PositionX, rPosition.PositionY );
+ ::basegfx::B2DVector aStart = aAnchor + aOrthoDirection*fFixedWidth/2.0;
+ ::basegfx::B2DVector aEnd = aAnchor - aOrthoDirection*fFixedWidth/2.0;
+
+ AddPointToPoly( rPoly, drawing::Position3D( aStart.getX(), aStart.getY(), rPosition.PositionZ), nSequenceIndex );
+ AddPointToPoly( rPoly, drawing::Position3D( aEnd.getX(), aEnd.getY(), rPosition.PositionZ), nSequenceIndex );
+}
+
+::basegfx::B2DVector lcl_getErrorBarMainDirection(
+ const drawing::Position3D& rStart
+ , const drawing::Position3D& rBottomEnd
+ , PlottingPositionHelper* pPosHelper
+ , const drawing::Position3D& rUnscaledLogicPosition
+ , bool bYError )
+{
+ ::basegfx::B2DVector aMainDirection = ::basegfx::B2DVector( rStart.PositionX - rBottomEnd.PositionX
+ , rStart.PositionY - rBottomEnd.PositionY );
+ if( !aMainDirection.getLength() )
+ {
+ //get logic clip values:
+ double MinX = pPosHelper->getLogicMinX();
+ double MinY = pPosHelper->getLogicMinY();
+ double MaxX = pPosHelper->getLogicMaxX();
+ double MaxY = pPosHelper->getLogicMaxY();
+ double fZ = pPosHelper->getLogicMinZ();
+
+
+ if( bYError )
+ {
+ //main direction has constant x value
+ MinX = rUnscaledLogicPosition.PositionX;
+ MaxX = rUnscaledLogicPosition.PositionX;
+ }
+ else
+ {
+ //main direction has constant y value
+ MinY = rUnscaledLogicPosition.PositionY;
+ MaxY = rUnscaledLogicPosition.PositionY;
+ }
+
+ drawing::Position3D aStart = pPosHelper->transformLogicToScene( MinX, MinY, fZ, false );
+ drawing::Position3D aEnd = pPosHelper->transformLogicToScene( MaxX, MaxY, fZ, false );
+
+ aMainDirection = ::basegfx::B2DVector( aStart.PositionX - aEnd.PositionX
+ , aStart.PositionY - aEnd.PositionY );
+ }
+ if( !aMainDirection.getLength() )
+ {
+ //@todo
+ }
+ return aMainDirection;
+}
+
+} // anonymous namespace
+
+// virtual
+void VSeriesPlotter::createErrorBar(
+ const uno::Reference< drawing::XShapes >& xTarget
+ , const drawing::Position3D& rUnscaledLogicPosition
+ , const uno::Reference< beans::XPropertySet > & xErrorBarProperties
+ , const VDataSeries& rVDataSeries
+ , sal_Int32 nIndex
+ , bool bYError /* = true */
+ )
+{
+ if( !ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ) )
+ return;
+
+ if( ! xErrorBarProperties.is())
+ return;
+
+ try
+ {
+ sal_Bool bShowPositive = sal_False;
+ sal_Bool bShowNegative = sal_False;
+ sal_Int32 nErrorBarStyle = ::com::sun::star::chart::ErrorBarStyle::VARIANCE;
+
+ xErrorBarProperties->getPropertyValue( C2U( "ShowPositiveError" )) >>= bShowPositive;
+ xErrorBarProperties->getPropertyValue( C2U( "ShowNegativeError" )) >>= bShowNegative;
+ xErrorBarProperties->getPropertyValue( C2U( "ErrorBarStyle" )) >>= nErrorBarStyle;
+
+ if(!bShowPositive && !bShowNegative)
+ return;
+
+ if(nErrorBarStyle==::com::sun::star::chart::ErrorBarStyle::NONE)
+ return;
+
+ drawing::Position3D aUnscaledLogicPosition(rUnscaledLogicPosition);
+ if(nErrorBarStyle==::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION)
+ aUnscaledLogicPosition.PositionY = rVDataSeries.getYMeanValue();
+
+ bool bCreateNegativeBorder = false;//make a vertical line at the negative end of the error bar
+ bool bCreatePositiveBorder = false;//make a vertical line at the positive end of the error bar
+ drawing::Position3D aMiddle(aUnscaledLogicPosition);
+ const double fX = aUnscaledLogicPosition.PositionX;
+ const double fY = aUnscaledLogicPosition.PositionY;
+ const double fZ = aUnscaledLogicPosition.PositionZ;
+ aMiddle = m_pPosHelper->transformLogicToScene( fX, fY, fZ, true );
+
+ drawing::Position3D aNegative(aMiddle);
+ drawing::Position3D aPositive(aMiddle);
+
+ uno::Sequence< double > aData( bYError ? rVDataSeries.getAllY() : rVDataSeries.getAllX() );
+
+ if( bShowPositive )
+ {
+ double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, true );
+ if( ::rtl::math::isFinite( fLength ) )
+ {
+ double fLocalX = fX;
+ double fLocalY = fY;
+ if( bYError )
+ fLocalY+=fLength;
+ else
+ fLocalX+=fLength;
+ bCreatePositiveBorder = m_pPosHelper->isLogicVisible(fLocalX, fLocalY, fZ);
+ aPositive = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true );
+ }
+ else
+ bShowPositive = false;
+ }
+
+ if( bShowNegative )
+ {
+ double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, false );
+ if( ::rtl::math::isFinite( fLength ) )
+ {
+ double fLocalX = fX;
+ double fLocalY = fY;
+ if( bYError )
+ fLocalY-=fLength;
+ else
+ fLocalX-=fLength;
+
+ bCreateNegativeBorder = m_pPosHelper->isLogicVisible( fLocalX, fLocalY, fZ);
+ aNegative = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true );
+ }
+ else
+ bShowNegative = false;
+ }
+
+ if(!bShowPositive && !bShowNegative)
+ return;
+
+ drawing::PolyPolygonShape3D aPoly;
+
+ sal_Int32 nSequenceIndex=0;
+ if( bShowNegative )
+ AddPointToPoly( aPoly, aNegative, nSequenceIndex );
+ AddPointToPoly( aPoly, aMiddle, nSequenceIndex );
+ if( bShowPositive )
+ AddPointToPoly( aPoly, aPositive, nSequenceIndex );
+
+ if( bShowNegative && bCreateNegativeBorder )
+ {
+ ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aNegative, m_pPosHelper, aUnscaledLogicPosition, bYError );
+ nSequenceIndex++;
+ lcl_AddErrorBottomLine( aNegative, aMainDirection, aPoly, nSequenceIndex );
+ }
+ if( bShowPositive && bCreatePositiveBorder )
+ {
+ ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aPositive, m_pPosHelper, aUnscaledLogicPosition, bYError );
+ nSequenceIndex++;
+ lcl_AddErrorBottomLine( aPositive, aMainDirection, aPoly, nSequenceIndex );
+ }
+
+ uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D( xTarget, PolyToPointSequence( aPoly) );
+ this->setMappedProperties( xShape, xErrorBarProperties, PropertyMapper::getPropertyNameMapForLineProperties() );
+ }
+ catch( uno::Exception & e )
+ {
+ ASSERT_EXCEPTION( e );
+ }
+
+}
+
+// virtual
+void VSeriesPlotter::createErrorBar_Y( const drawing::Position3D& rUnscaledLogicPosition
+ , VDataSeries& rVDataSeries, sal_Int32 nPointIndex
+ , const uno::Reference< drawing::XShapes >& xTarget )
+{
+ if(m_nDimension!=2)
+ return;
+ // error bars
+ uno::Reference< beans::XPropertySet > xErrorBarProp(rVDataSeries.getYErrorBarProperties(nPointIndex));
+ if( xErrorBarProp.is())
+ {
+ uno::Reference< drawing::XShapes > xErrorBarsGroup_Shapes(
+ this->getErrorBarsGroupShape(rVDataSeries, xTarget) );
+
+ createErrorBar( xErrorBarsGroup_Shapes
+ , rUnscaledLogicPosition, xErrorBarProp
+ , rVDataSeries, nPointIndex
+ , true /* bYError */ );
+ }
+}
+
+void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries& rVDataSeries
+ , const uno::Reference< drawing::XShapes >& xTarget
+ , const uno::Reference< drawing::XShapes >& xEquationTarget
+ , bool bMaySkipPointsInRegressionCalculation )
+{
+ if(m_nDimension!=2)
+ return;
+ uno::Reference< XRegressionCurveContainer > xRegressionContainer(
+ rVDataSeries.getModel(), uno::UNO_QUERY );
+ if(!xRegressionContainer.is())
+ return;
+ double fMinX = m_pPosHelper->getLogicMinX();
+ double fMaxX = m_pPosHelper->getLogicMaxX();
+
+ uno::Sequence< uno::Reference< XRegressionCurve > > aCurveList =
+ xRegressionContainer->getRegressionCurves();
+ for(sal_Int32 nN=0; nN<aCurveList.getLength(); nN++)
+ {
+ uno::Reference< XRegressionCurveCalculator > xRegressionCurveCalculator(
+ aCurveList[nN]->getCalculator() );
+ if( ! xRegressionCurveCalculator.is())
+ continue;
+ xRegressionCurveCalculator->recalculateRegression( rVDataSeries.getAllX(), rVDataSeries.getAllY() );
+
+ sal_Int32 nRegressionPointCount = 50;//@todo find a more optimal solution if more complicated curve types are introduced
+ drawing::PolyPolygonShape3D aRegressionPoly;
+ aRegressionPoly.SequenceX.realloc(1);
+ aRegressionPoly.SequenceY.realloc(1);
+ aRegressionPoly.SequenceZ.realloc(1);
+ aRegressionPoly.SequenceX[0].realloc(nRegressionPointCount);
+ aRegressionPoly.SequenceY[0].realloc(nRegressionPointCount);
+ aRegressionPoly.SequenceZ[0].realloc(nRegressionPointCount);
+ sal_Int32 nRealPointCount=0;
+
+ uno::Sequence< chart2::ExplicitScaleData > aScaleDataSeq( m_pPosHelper->getScales());
+ uno::Reference< chart2::XScaling > xScalingX;
+ uno::Reference< chart2::XScaling > xScalingY;
+ if( aScaleDataSeq.getLength() >= 2 )
+ {
+ xScalingX.set( aScaleDataSeq[0].Scaling );
+ xScalingY.set( aScaleDataSeq[1].Scaling );
+ }
+
+ uno::Sequence< geometry::RealPoint2D > aCalculatedPoints(
+ xRegressionCurveCalculator->getCurveValues(
+ fMinX, fMaxX, nRegressionPointCount, xScalingX, xScalingY, bMaySkipPointsInRegressionCalculation ));
+ nRegressionPointCount = aCalculatedPoints.getLength();
+ for(sal_Int32 nP=0; nP<nRegressionPointCount; nP++)
+ {
+ double fLogicX = aCalculatedPoints[nP].X;
+ double fLogicY = aCalculatedPoints[nP].Y;
+ double fLogicZ = 0.0;//dummy
+
+ m_pPosHelper->doLogicScaling( &fLogicX, &fLogicY, &fLogicZ );
+
+ if( !::rtl::math::isNan(fLogicX) && !::rtl::math::isInf(fLogicX)
+ && !::rtl::math::isNan(fLogicY) && !::rtl::math::isInf(fLogicY)
+ && !::rtl::math::isNan(fLogicZ) && !::rtl::math::isInf(fLogicZ) )
+ {
+ aRegressionPoly.SequenceX[0][nRealPointCount] = fLogicX;
+ aRegressionPoly.SequenceY[0][nRealPointCount] = fLogicY;
+ nRealPointCount++;
+ }
+ }
+ aRegressionPoly.SequenceX[0].realloc(nRealPointCount);
+ aRegressionPoly.SequenceY[0].realloc(nRealPointCount);
+ aRegressionPoly.SequenceZ[0].realloc(nRealPointCount);
+
+ drawing::PolyPolygonShape3D aClippedPoly;
+ Clipping::clipPolygonAtRectangle( aRegressionPoly, m_pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly );
+ aRegressionPoly = aClippedPoly;
+ m_pPosHelper->transformScaledLogicToScene( aRegressionPoly );
+
+ awt::Point aDefaultPos;
+ if( aRegressionPoly.SequenceX.getLength() && aRegressionPoly.SequenceX[0].getLength() )
+ {
+ uno::Reference< beans::XPropertySet > xCurveModelProp( aCurveList[nN], uno::UNO_QUERY );
+ VLineProperties aVLineProperties;
+ aVLineProperties.initFromPropertySet( xCurveModelProp );
+
+ //create an extra group shape for each curve for selection handling
+ bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurveList[nN] );
+ uno::Reference< drawing::XShapes > xRegressionGroupShapes =
+ createGroupShape( xTarget, rVDataSeries.getDataCurveCID( nN, bAverageLine ) );
+ uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D(
+ xRegressionGroupShapes, PolyToPointSequence( aRegressionPoly ), &aVLineProperties );
+ m_pShapeFactory->setShapeName( xShape, C2U("MarkHandles") );
+ aDefaultPos = xShape->getPosition();
+ }
+
+ // curve equation and correlation coefficient
+ uno::Reference< beans::XPropertySet > xEqProp( aCurveList[nN]->getEquationProperties());
+ if( xEqProp.is())
+ {
+ createRegressionCurveEquationShapes(
+ rVDataSeries.getDataCurveEquationCID( nN ),
+ xEqProp, xEquationTarget, xRegressionCurveCalculator,
+ aDefaultPos );
+ }
+ }
+}
+
+void VSeriesPlotter::createRegressionCurveEquationShapes(
+ const OUString & rEquationCID,
+ const uno::Reference< beans::XPropertySet > & xEquationProperties,
+ const uno::Reference< drawing::XShapes >& xEquationTarget,
+ const uno::Reference< chart2::XRegressionCurveCalculator > & xRegressionCurveCalculator,
+ awt::Point aDefaultPos )
+{
+ OSL_ASSERT( xEquationProperties.is());
+ if( !xEquationProperties.is())
+ return;
+
+ bool bShowEquation = false;
+ bool bShowCorrCoeff = false;
+ OUString aSep( sal_Unicode('\n'));
+ if(( xEquationProperties->getPropertyValue( C2U("ShowEquation")) >>= bShowEquation ) &&
+ ( xEquationProperties->getPropertyValue( C2U("ShowCorrelationCoefficient")) >>= bShowCorrCoeff ))
+ {
+ if( ! (bShowEquation || bShowCorrCoeff))
+ return;
+
+ ::rtl::OUStringBuffer aFormula;
+ sal_Int32 nNumberFormatKey = 0;
+ xEquationProperties->getPropertyValue( C2U("NumberFormat")) >>= nNumberFormatKey;
+
+ if( bShowEquation )
+ {
+ if( m_apNumberFormatterWrapper.get())
+ {
+ aFormula = xRegressionCurveCalculator->getFormattedRepresentation(
+ m_apNumberFormatterWrapper->getNumberFormatsSupplier(),
+ nNumberFormatKey );
+ }
+ else
+ {
+ aFormula = xRegressionCurveCalculator->getRepresentation();
+ }
+
+ if( bShowCorrCoeff )
+ {
+// xEquationProperties->getPropertyValue( C2U("Separator")) >>= aSep;
+ aFormula.append( aSep );
+ }
+ }
+ if( bShowCorrCoeff )
+ {
+ aFormula.append( sal_Unicode( 'R' ));
+ aFormula.append( sal_Unicode( 0x00b2 ));
+ aFormula.append( C2U( " = " ));
+ double fR( xRegressionCurveCalculator->getCorrelationCoefficient());
+ if( m_apNumberFormatterWrapper.get())
+ {
+ sal_Int32 nLabelCol = 0;
+ bool bColChanged;
+ aFormula.append(
+ m_apNumberFormatterWrapper->getFormattedString(
+ nNumberFormatKey, fR*fR, nLabelCol, bColChanged ));
+ //@todo: change color of label if bColChanged is true
+ }
+ else
+ {
+ sal_Unicode aDecimalSep( '.' );//@todo get this locale dependent
+ aFormula.append( ::rtl::math::doubleToUString(
+ fR*fR, rtl_math_StringFormat_G, 4, aDecimalSep, true ));
+ }
+ }
+
+ awt::Point aScreenPosition2D;
+ chart2::RelativePosition aRelativePosition;
+ if( xEquationProperties->getPropertyValue( C2U("RelativePosition")) >>= aRelativePosition )
+ {
+ //@todo decide wether x is primary or secondary
+ double fX = aRelativePosition.Primary*m_aPageReferenceSize.Width;
+ double fY = aRelativePosition.Secondary*m_aPageReferenceSize.Height;
+ aScreenPosition2D.X = static_cast< sal_Int32 >( ::rtl::math::round( fX ));
+ aScreenPosition2D.Y = static_cast< sal_Int32 >( ::rtl::math::round( fY ));
+ }
+ else
+ aScreenPosition2D = aDefaultPos;
+
+ if( aFormula.getLength())
+ {
+ // set fill and line properties on creation
+ tNameSequence aNames;
+ tAnySequence aValues;
+ PropertyMapper::getPreparedTextShapePropertyLists( xEquationProperties, aNames, aValues );
+
+ uno::Reference< drawing::XShape > xTextShape = m_pShapeFactory->createText(
+ xEquationTarget, aFormula.makeStringAndClear(),
+ aNames, aValues, ShapeFactory::makeTransformation( aScreenPosition2D ));
+
+// // adapt font sizes
+// awt::Size aOldRefSize;
+// if( xTitleProperties->getPropertyValue( C2U("ReferencePageSize")) >>= aOldRefSize )
+// {
+// uno::Reference< beans::XPropertySet > xShapeProp( xTextShape, uno::UNO_QUERY );
+// if( xShapeProp.is())
+// RelativeSizeHelper::adaptFontSizes( xShapeProp, aOldRefSize, m_aPageReferenceSize );
+// }
+
+ OSL_ASSERT( xTextShape.is());
+ if( xTextShape.is())
+ {
+ ShapeFactory::setShapeName( xTextShape, rEquationCID );
+ xTextShape->setPosition(
+ RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
+ aScreenPosition2D, xTextShape->getSize(), aRelativePosition.Anchor ));
+ }
+ }
+ }
+}
+
+
+void VSeriesPlotter::setMappedProperties(
+ const uno::Reference< drawing::XShape >& xTargetShape
+ , const uno::Reference< beans::XPropertySet >& xSource
+ , const tPropertyNameMap& rMap
+ , tPropertyNameValueMap* pOverwriteMap )
+{
+ uno::Reference< beans::XPropertySet > xTargetProp( xTargetShape, uno::UNO_QUERY );
+ PropertyMapper::setMappedProperties(xTargetProp,xSource,rMap,pOverwriteMap);
+}
+
+//-------------------------------------------------------------------------
+// MinimumAndMaximumSupplier
+//-------------------------------------------------------------------------
+
+double VSeriesPlotter::getMinimumX()
+{
+ if( m_bCategoryXAxis )
+ {
+ double fRet = 1.0;//first category (index 0) matches with real number 1.0
+ if( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->hasComplexCategories() )
+ fRet -= 0.5;
+ return fRet;
+ }
+
+ double fMinimum, fMaximum;
+ this->getMinimumAndMaximiumX( fMinimum, fMaximum );
+ return fMinimum;
+}
+double VSeriesPlotter::getMaximumX()
+{
+ if( m_bCategoryXAxis )
+ {
+ //return category count
+ double fRet = getPointCount();//first category (index 0) matches with real number 1.0
+ if( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->hasComplexCategories() )
+ fRet += 0.5;
+ return fRet;
+ }
+
+ double fMinimum, fMaximum;
+ this->getMinimumAndMaximiumX( fMinimum, fMaximum );
+ return fMaximum;
+}
+
+double VSeriesPlotter::getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex )
+{
+ if( !m_bCategoryXAxis )
+ {
+ double fMinY, fMaxY;
+ this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
+ return fMinY;
+ }
+
+ double fMinimum, fMaximum;
+ ::rtl::math::setInf(&fMinimum, false);
+ ::rtl::math::setInf(&fMaximum, true);
+ for(size_t nZ =0; nZ<m_aZSlots.size();nZ++ )
+ {
+ ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[nZ];
+ for(size_t nN =0; nN<rXSlots.size();nN++ )
+ {
+ double fLocalMinimum, fLocalMaximum;
+ rXSlots[nN].calculateYMinAndMaxForCategoryRange(
+ static_cast<sal_Int32>(fMinimumX-1.0) //first category (index 0) matches with real number 1.0
+ , static_cast<sal_Int32>(fMaximumX-1.0) //first category (index 0) matches with real number 1.0
+ , isSeperateStackingForDifferentSigns( 1 )
+ , fLocalMinimum, fLocalMaximum, nAxisIndex );
+ if(fMaximum<fLocalMaximum)
+ fMaximum=fLocalMaximum;
+ if(fMinimum>fLocalMinimum)
+ fMinimum=fLocalMinimum;
+ }
+ }
+ if(::rtl::math::isInf(fMinimum))
+ ::rtl::math::setNan(&fMinimum);
+ return fMinimum;
+}
+
+double VSeriesPlotter::getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex )
+{
+ if( !m_bCategoryXAxis )
+ {
+ double fMinY, fMaxY;
+ this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
+ return fMaxY;
+ }
+
+ double fMinimum, fMaximum;
+ ::rtl::math::setInf(&fMinimum, false);
+ ::rtl::math::setInf(&fMaximum, true);
+ for(size_t nZ =0; nZ<m_aZSlots.size();nZ++ )
+ {
+ ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[nZ];
+ for(size_t nN =0; nN<rXSlots.size();nN++ )
+ {
+ double fLocalMinimum, fLocalMaximum;
+ rXSlots[nN].calculateYMinAndMaxForCategoryRange(
+ static_cast<sal_Int32>(fMinimumX-1.0) //first category (index 0) matches with real number 1.0
+ , static_cast<sal_Int32>(fMaximumX-1.0) //first category (index 0) matches with real number 1.0
+ , isSeperateStackingForDifferentSigns( 1 )
+ , fLocalMinimum, fLocalMaximum, nAxisIndex );
+ if(fMaximum<fLocalMaximum)
+ fMaximum=fLocalMaximum;
+ if(fMinimum>fLocalMinimum)
+ fMinimum=fLocalMinimum;
+ }
+ }
+ if(::rtl::math::isInf(fMaximum))
+ ::rtl::math::setNan(&fMaximum);
+ return fMaximum;
+}
+
+double VSeriesPlotter::getMinimumZ()
+{
+ //this is the default for all charts without a meaningfull z axis
+ return 0.5;
+}
+double VSeriesPlotter::getMaximumZ()
+{
+ if( 3!=m_nDimension )
+ return 0.5;
+ return m_aZSlots.size()+0.5;
+}
+
+namespace
+{
+ bool lcl_isValueAxis( sal_Int32 nDimensionIndex, bool bCategoryXAxis )
+ {
+ // default implementation: true for Y axes, and for value X axis
+ if( nDimensionIndex == 0 )
+ return !bCategoryXAxis;
+ if( nDimensionIndex == 1 )
+ return true;
+ return false;
+ }
+}
+
+bool VSeriesPlotter::isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex )
+{
+ return lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis );
+}
+
+bool VSeriesPlotter::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex )
+{
+ // do not expand axes in 3D charts
+ return (m_nDimension < 3) && lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis );
+}
+
+bool VSeriesPlotter::isExpandWideValuesToZero( sal_Int32 nDimensionIndex )
+{
+ // default implementation: only for Y axis
+ return nDimensionIndex == 1;
+}
+
+bool VSeriesPlotter::isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex )
+{
+ // default implementation: only for Y axis
+ return nDimensionIndex == 1;
+}
+
+bool VSeriesPlotter::isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex )
+{
+ // default implementation: only for Y axis
+ return nDimensionIndex == 1;
+}
+
+void VSeriesPlotter::getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const
+{
+ ::rtl::math::setInf(&rfMinimum, false);
+ ::rtl::math::setInf(&rfMaximum, true);
+
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter = m_aZSlots.begin();
+ const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
+ for( ; aZSlotIter != aZSlotEnd; aZSlotIter++ )
+ {
+ ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+ for( ; aXSlotIter != aXSlotEnd; aXSlotIter++ )
+ {
+ double fLocalMinimum, fLocalMaximum;
+ aXSlotIter->getMinimumAndMaximiumX( fLocalMinimum, fLocalMaximum );
+ if( !::rtl::math::isNan(fLocalMinimum) && fLocalMinimum< rfMinimum )
+ rfMinimum = fLocalMinimum;
+ if( !::rtl::math::isNan(fLocalMaximum) && fLocalMaximum> rfMaximum )
+ rfMaximum = fLocalMaximum;
+ }
+ }
+ if(::rtl::math::isInf(rfMinimum))
+ ::rtl::math::setNan(&rfMinimum);
+ if(::rtl::math::isInf(rfMaximum))
+ ::rtl::math::setNan(&rfMaximum);
+}
+
+void VSeriesPlotter::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const
+{
+ ::rtl::math::setInf(&rfMinY, false);
+ ::rtl::math::setInf(&rfMaxY, true);
+
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter = m_aZSlots.begin();
+ const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
+ for( ; aZSlotIter != aZSlotEnd; aZSlotIter++ )
+ {
+ ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+ for( ; aXSlotIter != aXSlotEnd; aXSlotIter++ )
+ {
+ double fLocalMinimum, fLocalMaximum;
+ aXSlotIter->getMinimumAndMaximiumYInContinuousXRange( fLocalMinimum, fLocalMaximum, fMinX, fMaxX, nAxisIndex );
+ if( !::rtl::math::isNan(fLocalMinimum) && fLocalMinimum< rfMinY )
+ rfMinY = fLocalMinimum;
+ if( !::rtl::math::isNan(fLocalMaximum) && fLocalMaximum> rfMaxY )
+ rfMaxY = fLocalMaximum;
+ }
+ }
+ if(::rtl::math::isInf(rfMinY))
+ ::rtl::math::setNan(&rfMinY);
+ if(::rtl::math::isInf(rfMaxY))
+ ::rtl::math::setNan(&rfMaxY);
+}
+
+sal_Int32 VSeriesPlotter::getPointCount() const
+{
+ sal_Int32 nRet = 0;
+
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter = m_aZSlots.begin();
+ const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
+
+ for( ; aZSlotIter != aZSlotEnd; aZSlotIter++ )
+ {
+ ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+
+ for( ; aXSlotIter != aXSlotEnd; aXSlotIter++ )
+ {
+ sal_Int32 nPointCount = aXSlotIter->getPointCount();
+ if( nPointCount>nRet )
+ nRet = nPointCount;
+ }
+ }
+ return nRet;
+}
+
+void VSeriesPlotter::setNumberFormatsSupplier(
+ const uno::Reference< util::XNumberFormatsSupplier > & xNumFmtSupplier )
+{
+ m_apNumberFormatterWrapper.reset( new NumberFormatterWrapper( xNumFmtSupplier ));
+}
+
+void VSeriesPlotter::setColorScheme( const uno::Reference< XColorScheme >& xColorScheme )
+{
+ m_xColorScheme = xColorScheme;
+}
+
+void VSeriesPlotter::setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider )
+{
+ m_pExplicitCategoriesProvider = pExplicitCategoriesProvider;
+}
+
+sal_Int32 VDataSeriesGroup::getPointCount() const
+{
+ if(!m_bMaxPointCountDirty)
+ return m_nMaxPointCount;
+
+ sal_Int32 nRet = 0;
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = m_aSeriesVector.begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
+
+ for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
+ {
+ sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount();
+ if( nPointCount>nRet )
+ nRet = nPointCount;
+ }
+ m_nMaxPointCount=nRet;
+ m_aListOfCachedYValues.clear();
+ m_aListOfCachedYValues.resize(m_nMaxPointCount);
+ m_bMaxPointCountDirty=false;
+ return nRet;
+}
+
+sal_Int32 VDataSeriesGroup::getAttachedAxisIndexForFirstSeries() const
+{
+ sal_Int32 nRet = 0;
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = m_aSeriesVector.begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
+
+ if( aSeriesIter != aSeriesEnd )
+ nRet = (*aSeriesIter)->getAttachedAxisIndex();
+
+ return nRet;
+}
+
+void VDataSeriesGroup::getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const
+{
+ const ::std::vector< VDataSeries* >* pSeriesList = &this->m_aSeriesVector;
+
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
+
+ ::rtl::math::setInf(&rfMinimum, false);
+ ::rtl::math::setInf(&rfMaximum, true);
+
+ for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
+ {
+ sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount();
+ for(sal_Int32 nN=0;nN<nPointCount;nN++)
+ {
+ double fX = (*aSeriesIter)->getXValue( nN );
+ if( ::rtl::math::isNan(fX) )
+ continue;
+ if(rfMaximum<fX)
+ rfMaximum=fX;
+ if(rfMinimum>fX)
+ rfMinimum=fX;
+ }
+ }
+ if(::rtl::math::isInf(rfMinimum))
+ ::rtl::math::setNan(&rfMinimum);
+ if(::rtl::math::isInf(rfMaximum))
+ ::rtl::math::setNan(&rfMaximum);
+}
+void VDataSeriesGroup::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const
+{
+ const ::std::vector< VDataSeries* >* pSeriesList = &this->m_aSeriesVector;
+
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
+
+ ::rtl::math::setInf(&rfMinY, false);
+ ::rtl::math::setInf(&rfMaxY, true);
+
+ for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ )
+ {
+ sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount();
+ for(sal_Int32 nN=0;nN<nPointCount;nN++)
+ {
+ if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
+ continue;
+
+ double fX = (*aSeriesIter)->getXValue( nN );
+ if( ::rtl::math::isNan(fX) )
+ continue;
+ if( fX < fMinX || fX > fMaxX )
+ continue;
+ double fY = (*aSeriesIter)->getYValue( nN );
+ if( ::rtl::math::isNan(fY) )
+ continue;
+ if(rfMaxY<fY)
+ rfMaxY=fY;
+ if(rfMinY>fY)
+ rfMinY=fY;
+ }
+ }
+ if(::rtl::math::isInf(rfMinY))
+ ::rtl::math::setNan(&rfMinY);
+ if(::rtl::math::isInf(rfMaxY))
+ ::rtl::math::setNan(&rfMaxY);
+}
+
+void VDataSeriesGroup::calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
+ , bool bSeperateStackingForDifferentSigns
+ , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex )
+{
+ ::rtl::math::setInf(&rfMinimumY, false);
+ ::rtl::math::setInf(&rfMaximumY, true);
+
+ sal_Int32 nPointCount = getPointCount();//necessary to create m_aListOfCachedYValues
+ if(nCategoryIndex<0 || nCategoryIndex>=nPointCount || m_aSeriesVector.empty())
+ return;
+
+ CachedYValues aCachedYValues = m_aListOfCachedYValues[nCategoryIndex][nAxisIndex];
+ if( !aCachedYValues.m_bValuesDirty )
+ {
+ //return cached values
+ rfMinimumY = aCachedYValues.m_fMinimumY;
+ rfMaximumY = aCachedYValues.m_fMaximumY;
+ return;
+ }
+
+ double fTotalSum, fPositiveSum, fNegativeSum, fFirstPositiveY, fFirstNegativeY;
+ ::rtl::math::setNan( &fTotalSum );
+ ::rtl::math::setNan( &fPositiveSum );
+ ::rtl::math::setNan( &fNegativeSum );
+ ::rtl::math::setNan( &fFirstPositiveY );
+ ::rtl::math::setNan( &fFirstNegativeY );
+
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = m_aSeriesVector.begin();
+ ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
+
+ if( bSeperateStackingForDifferentSigns )
+ {
+ for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
+ {
+ if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
+ continue;
+
+ double fValueMinY = (*aSeriesIter)->getMinimumofAllDifferentYValues( nCategoryIndex );
+ double fValueMaxY = (*aSeriesIter)->getMaximumofAllDifferentYValues( nCategoryIndex );
+
+ if( fValueMaxY >= 0 )
+ {
+ if( ::rtl::math::isNan( fPositiveSum ) )
+ fPositiveSum = fFirstPositiveY = fValueMaxY;
+ else
+ fPositiveSum += fValueMaxY;
+ }
+ if( fValueMinY < 0 )
+ {
+ if(::rtl::math::isNan( fNegativeSum ))
+ fNegativeSum = fFirstNegativeY = fValueMinY;
+ else
+ fNegativeSum += fValueMinY;
+ }
+ }
+ rfMinimumY = ::rtl::math::isNan( fNegativeSum ) ? fFirstPositiveY : fNegativeSum;
+ rfMaximumY = ::rtl::math::isNan( fPositiveSum ) ? fFirstNegativeY : fPositiveSum;
+ }
+ else
+ {
+ for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
+ {
+ if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
+ continue;
+
+ double fValueMinY = (*aSeriesIter)->getMinimumofAllDifferentYValues( nCategoryIndex );
+ double fValueMaxY = (*aSeriesIter)->getMaximumofAllDifferentYValues( nCategoryIndex );
+
+ if( ::rtl::math::isNan( fTotalSum ) )
+ {
+ rfMinimumY = fValueMinY;
+ rfMaximumY = fTotalSum = fValueMaxY;
+ }
+ else
+ {
+ fTotalSum += fValueMaxY;
+ if( rfMinimumY > fTotalSum )
+ rfMinimumY = fTotalSum;
+ if( rfMaximumY < fTotalSum )
+ rfMaximumY = fTotalSum;
+ }
+ }
+ }
+
+ aCachedYValues.m_fMinimumY = rfMinimumY;
+ aCachedYValues.m_fMaximumY = rfMaximumY;
+ aCachedYValues.m_bValuesDirty = false;
+ m_aListOfCachedYValues[nCategoryIndex][nAxisIndex]=aCachedYValues;
+}
+
+void VDataSeriesGroup::calculateYMinAndMaxForCategoryRange(
+ sal_Int32 nStartCategoryIndex, sal_Int32 nEndCategoryIndex
+ , bool bSeperateStackingForDifferentSigns
+ , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex )
+{
+ //@todo maybe cache these values
+ ::rtl::math::setInf(&rfMinimumY, false);
+ ::rtl::math::setInf(&rfMaximumY, true);
+
+ //iterate through the given categories
+ if(nStartCategoryIndex<0)
+ nStartCategoryIndex=0;
+ if(nEndCategoryIndex<0)
+ nEndCategoryIndex=0;
+ for( sal_Int32 nCatIndex = nStartCategoryIndex; nCatIndex <= nEndCategoryIndex; nCatIndex++ )
+ {
+ double fMinimumY; ::rtl::math::setNan(&fMinimumY);
+ double fMaximumY; ::rtl::math::setNan(&fMaximumY);
+
+ this->calculateYMinAndMaxForCategory( nCatIndex
+ , bSeperateStackingForDifferentSigns, fMinimumY, fMaximumY, nAxisIndex );
+
+ if(rfMinimumY > fMinimumY)
+ rfMinimumY = fMinimumY;
+ if(rfMaximumY < fMaximumY)
+ rfMaximumY = fMaximumY;
+ }
+}
+
+double VSeriesPlotter::getTransformedDepth() const
+{
+ double MinZ = m_pMainPosHelper->getLogicMinZ();
+ double MaxZ = m_pMainPosHelper->getLogicMaxZ();
+ m_pMainPosHelper->doLogicScaling( 0, 0, &MinZ );
+ m_pMainPosHelper->doLogicScaling( 0, 0, &MaxZ );
+ return FIXED_SIZE_FOR_3D_CHART_VOLUME/(MaxZ-MinZ);
+}
+
+void SAL_CALL VSeriesPlotter::addSecondaryValueScale( const ExplicitScaleData& rScale, sal_Int32 nAxisIndex )
+ throw (uno::RuntimeException)
+{
+ if( nAxisIndex<1 )
+ return;
+
+ m_aSecondaryValueScales[nAxisIndex]=rScale;
+}
+
+PlottingPositionHelper& VSeriesPlotter::getPlottingPositionHelper( sal_Int32 nAxisIndex ) const
+{
+ PlottingPositionHelper* pRet = 0;
+ if(nAxisIndex>0)
+ {
+ tSecondaryPosHelperMap::const_iterator aPosIt = m_aSecondaryPosHelperMap.find( nAxisIndex );
+ if( aPosIt != m_aSecondaryPosHelperMap.end() )
+ {
+ pRet = aPosIt->second;
+ }
+ else
+ {
+ tSecondaryValueScales::const_iterator aScaleIt = m_aSecondaryValueScales.find( nAxisIndex );
+ if( aScaleIt != m_aSecondaryValueScales.end() )
+ {
+ pRet = m_pPosHelper->createSecondaryPosHelper( aScaleIt->second );
+ m_aSecondaryPosHelperMap[nAxisIndex] = pRet;
+ }
+ }
+ }
+ if( !pRet )
+ {
+ pRet = m_pMainPosHelper;
+ }
+ return *pRet;
+}
+
+void VSeriesPlotter::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& /*rPageSize*/ )
+{
+}
+
+VDataSeries* VSeriesPlotter::getFirstSeries() const
+{
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter( m_aZSlots.begin() );
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd( m_aZSlots.end() );
+ for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
+ {
+ ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+
+ if( aXSlotIter != aXSlotEnd )
+ {
+ VDataSeriesGroup aSeriesGroup( *aXSlotIter );
+ if( aSeriesGroup.m_aSeriesVector.size() )
+ {
+ VDataSeries* pSeries = aSeriesGroup.m_aSeriesVector[0];
+ if(pSeries)
+ return pSeries;
+ }
+ }
+ }
+ return 0;
+}
+
+uno::Sequence< rtl::OUString > VSeriesPlotter::getSeriesNames() const
+{
+ ::std::vector< rtl::OUString > aRetVector;
+
+ rtl::OUString aRole;
+ if( m_xChartTypeModel.is() )
+ aRole = m_xChartTypeModel->getRoleOfSequenceForSeriesLabel();
+
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter( m_aZSlots.begin() );
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd( m_aZSlots.end() );
+ for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
+ {
+ ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+
+ if( aXSlotIter != aXSlotEnd )
+ {
+ VDataSeriesGroup aSeriesGroup( *aXSlotIter );
+ if( aSeriesGroup.m_aSeriesVector.size() )
+ {
+ VDataSeries* pSeries = aSeriesGroup.m_aSeriesVector[0];
+ uno::Reference< XDataSeries > xSeries( pSeries ? pSeries->getModel() : 0 );
+ if( xSeries.is() )
+ {
+ rtl::OUString aSeriesName( DataSeriesHelper::getDataSeriesLabel( xSeries, aRole ) );
+ aRetVector.push_back( aSeriesName );
+ }
+ }
+ }
+ }
+ return ContainerHelper::ContainerToSequence( aRetVector );
+}
+
+namespace
+{
+struct lcl_setRefSizeAtSeriesGroup : public ::std::unary_function< VDataSeriesGroup, void >
+{
+ lcl_setRefSizeAtSeriesGroup( awt::Size aRefSize ) : m_aRefSize( aRefSize ) {}
+ void operator()( VDataSeriesGroup & rGroup )
+ {
+ ::std::vector< VDataSeries* >::iterator aIt( rGroup.m_aSeriesVector.begin());
+ const ::std::vector< VDataSeries* >::iterator aEndIt( rGroup.m_aSeriesVector.end());
+ for( ; aIt != aEndIt; ++aIt )
+ (*aIt)->setPageReferenceSize( m_aRefSize );
+ }
+
+private:
+ awt::Size m_aRefSize;
+};
+} // anonymous namespace
+
+void VSeriesPlotter::setPageReferenceSize( const ::com::sun::star::awt::Size & rPageRefSize )
+{
+ m_aPageReferenceSize = rPageRefSize;
+
+ // set reference size also at all data series
+
+ ::std::vector< VDataSeriesGroup > aSeriesGroups( FlattenVector( m_aZSlots ));
+ ::std::for_each( aSeriesGroups.begin(), aSeriesGroups.end(),
+ lcl_setRefSizeAtSeriesGroup( m_aPageReferenceSize ));
+}
+
+//better performance for big data
+void VSeriesPlotter::setCoordinateSystemResolution( const Sequence< sal_Int32 >& rCoordinateSystemResolution )
+{
+ m_aCoordinateSystemResolution = rCoordinateSystemResolution;
+}
+
+bool VSeriesPlotter::PointsWereSkipped() const
+{
+ return m_bPointsWereSkipped;
+}
+
+bool VSeriesPlotter::WantToPlotInFrontOfAxisLine()
+{
+ return ChartTypeHelper::isSeriesInFrontOfAxisLine( m_xChartTypeModel );
+}
+
+bool VSeriesPlotter::shouldSnapRectToUsedArea()
+{
+ if( m_nDimension == 3 )
+ return false;
+ return true;
+}
+
+Sequence< ViewLegendEntry > SAL_CALL VSeriesPlotter::createLegendEntries(
+ LegendExpansion eLegendExpansion
+ , const Reference< beans::XPropertySet >& xTextProperties
+ , const Reference< drawing::XShapes >& xTarget
+ , const Reference< lang::XMultiServiceFactory >& xShapeFactory
+ , const Reference< uno::XComponentContext >& xContext
+ ) throw (uno::RuntimeException)
+{
+ std::vector< ViewLegendEntry > aResult;
+
+ if( xTarget.is() )
+ {
+ //iterate through all series
+ bool bBreak = false;
+ bool bFirstSeries = true;
+ ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
+ const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
+ for( ; aZSlotIter!=aZSlotEnd && !bBreak; aZSlotIter++ )
+ {
+ ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
+ const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
+ for( ; aXSlotIter!=aXSlotEnd && !bBreak; aXSlotIter++ )
+ {
+ ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
+ ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
+ const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
+ //iterate through all series in this x slot
+ for( ; aSeriesIter!=aSeriesEnd && !bBreak; ++aSeriesIter )
+ {
+ VDataSeries* pSeries( *aSeriesIter );
+ if(!pSeries)
+ continue;
+
+ std::vector< ViewLegendEntry > aSeriesEntries( this->createLegendEntriesForSeries(
+ *pSeries, xTextProperties, xTarget, xShapeFactory, xContext ) );
+
+ //add series entries to the result now
+
+ // use only the first series if VaryColorsByPoint is set for the first series
+ if( bFirstSeries && pSeries->isVaryColorsByPoint() )
+ bBreak = true;
+ bFirstSeries = false;
+
+ // add entries reverse if chart is stacked in y-direction and the legend is not wide.
+ // If the legend is wide and we have a stacked bar-chart the normal order
+ // is the correct one
+ bool bReverse = false;
+ if( eLegendExpansion != LegendExpansion_WIDE )
+ {
+ StackingDirection eStackingDirection( pSeries->getStackingDirection() );
+ bReverse = ( eStackingDirection == StackingDirection_Y_STACKING );
+
+ //todo: respect direction of axis in future
+ }
+
+ if(bReverse)
+ aResult.insert( aResult.begin(), aSeriesEntries.begin(), aSeriesEntries.end() );
+ else
+ aResult.insert( aResult.end(), aSeriesEntries.begin(), aSeriesEntries.end() );
+ }
+ }
+ }
+
+ //add charttype specific entries if any
+ {
+ std::vector< ViewLegendEntry > aChartTypeEntries( this->createLegendEntriesForChartType(
+ xTextProperties, xTarget, xShapeFactory, xContext ) );
+ aResult.insert( aResult.end(), aChartTypeEntries.begin(), aChartTypeEntries.end() );
+ }
+ }
+
+ return ::chart::ContainerHelper::ContainerToSequence( aResult );
+}
+
+
+LegendSymbolStyle VSeriesPlotter::getLegendSymbolStyle()
+{
+ return chart2::LegendSymbolStyle_BOX;
+}
+
+
+uno::Any VSeriesPlotter::getExplicitSymbol( const VDataSeries& /*rSeries*/, sal_Int32 /*nPointIndex*/ )
+{
+ return uno::Any();
+}
+
+Reference< drawing::XShape > VSeriesPlotter::createLegendSymbolForSeries(
+ const VDataSeries& rSeries
+ , const Reference< drawing::XShapes >& xTarget
+ , const Reference< lang::XMultiServiceFactory >& xShapeFactory )
+{
+
+ LegendSymbolStyle eLegendSymbolStyle = this->getLegendSymbolStyle();
+ uno::Any aExplicitSymbol( this->getExplicitSymbol( rSeries ) );
+
+ VLegendSymbolFactory::tPropertyType ePropType =
+ VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES;
+
+ // todo: maybe the property-style does not solely depend on the
+ // legend-symbol type
+ switch( eLegendSymbolStyle )
+ {
+ case LegendSymbolStyle_HORIZONTAL_LINE:
+ case LegendSymbolStyle_VERTICAL_LINE:
+ case LegendSymbolStyle_DIAGONAL_LINE:
+ case LegendSymbolStyle_LINE_WITH_BOX:
+ case LegendSymbolStyle_LINE_WITH_SYMBOL:
+ ePropType = VLegendSymbolFactory::PROP_TYPE_LINE_SERIES;
+ break;
+ default:
+ break;
+ };
+ Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol(
+ xTarget, eLegendSymbolStyle, xShapeFactory
+ , rSeries.getPropertiesOfSeries(), ePropType, aExplicitSymbol ));
+
+ return xShape;
+}
+
+Reference< drawing::XShape > VSeriesPlotter::createLegendSymbolForPoint(
+ const VDataSeries& rSeries
+ , sal_Int32 nPointIndex
+ , const Reference< drawing::XShapes >& xTarget
+ , const Reference< lang::XMultiServiceFactory >& xShapeFactory )
+{
+
+ LegendSymbolStyle eLegendSymbolStyle = this->getLegendSymbolStyle();
+ uno::Any aExplicitSymbol( this->getExplicitSymbol(rSeries,nPointIndex) );
+
+ VLegendSymbolFactory::tPropertyType ePropType =
+ VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES;
+
+ // todo: maybe the property-style does not solely depend on the
+ // legend-symbol type
+ switch( eLegendSymbolStyle )
+ {
+ case LegendSymbolStyle_HORIZONTAL_LINE:
+ case LegendSymbolStyle_VERTICAL_LINE:
+ case LegendSymbolStyle_DIAGONAL_LINE:
+ case LegendSymbolStyle_LINE_WITH_BOX:
+ case LegendSymbolStyle_LINE_WITH_SYMBOL:
+ ePropType = VLegendSymbolFactory::PROP_TYPE_LINE_SERIES;
+ break;
+ default:
+ break;
+ };
+
+ // the default properties for the data point are the data series properties.
+ // If a data point has own attributes overwrite them
+ Reference< beans::XPropertySet > xSeriesProps( rSeries.getPropertiesOfSeries() );
+ Reference< beans::XPropertySet > xPointSet( xSeriesProps );
+ if( rSeries.isAttributedDataPoint( nPointIndex ) )
+ xPointSet.set( rSeries.getPropertiesOfPoint( nPointIndex ));
+
+ // if a data point has no own color use a color fom the diagram's color scheme
+ if( ! rSeries.hasPointOwnColor( nPointIndex ))
+ {
+ Reference< util::XCloneable > xCloneable( xPointSet,uno::UNO_QUERY );
+ if( xCloneable.is() && m_xColorScheme.is() )
+ {
+ xPointSet.set( xCloneable->createClone(), uno::UNO_QUERY );
+ Reference< container::XChild > xChild( xPointSet, uno::UNO_QUERY );
+ if( xChild.is())
+ xChild->setParent( xSeriesProps );
+
+ OSL_ASSERT( xPointSet.is());
+ xPointSet->setPropertyValue(
+ C2U("Color"), uno::makeAny( m_xColorScheme->getColorByIndex( nPointIndex )));
+ }
+ }
+
+ Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol(
+ xTarget, eLegendSymbolStyle, xShapeFactory, xPointSet, ePropType, aExplicitSymbol ));
+
+ return xShape;
+}
+
+std::vector< ViewLegendEntry > SAL_CALL VSeriesPlotter::createLegendEntriesForSeries(
+ const VDataSeries& rSeries
+ , const Reference< beans::XPropertySet >& xTextProperties
+ , const Reference< drawing::XShapes >& xTarget
+ , const Reference< lang::XMultiServiceFactory >& xShapeFactory
+ , const Reference< uno::XComponentContext >& xContext
+ )
+{
+ std::vector< ViewLegendEntry > aResult;
+
+ if( ! ( xShapeFactory.is() && xTarget.is() && xContext.is() ) )
+ return aResult;
+
+ try
+ {
+ ViewLegendEntry aEntry;
+ OUString aLabelText;
+ bool bVaryColorsByPoint = rSeries.isVaryColorsByPoint();
+ if( bVaryColorsByPoint )
+ {
+ Sequence< OUString > aCategoryNames;
+ if( m_pExplicitCategoriesProvider )
+ aCategoryNames = m_pExplicitCategoriesProvider->getSimpleCategories();
+
+ for( sal_Int32 nIdx=0; nIdx<aCategoryNames.getLength(); ++nIdx )
+ {
+ // symbol
+ uno::Reference< drawing::XShapes > xSymbolGroup( ShapeFactory(xShapeFactory).createGroup2D( xTarget ));
+
+ // create the symbol
+ Reference< drawing::XShape > xShape( this->createLegendSymbolForPoint(
+ rSeries, nIdx, xSymbolGroup, xShapeFactory ) );
+
+ // set CID to symbol for selection
+ if( xShape.is() )
+ {
+ aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
+
+ OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_DATA_POINT, nIdx ) );
+ aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
+ OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
+ ShapeFactory::setShapeName( xShape, aCID );
+ }
+
+ // label
+ aLabelText = aCategoryNames[nIdx];
+ if( xShape.is() || aLabelText.getLength() )
+ {
+ aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
+ aResult.push_back(aEntry);
+ }
+ }
+ }
+ else
+ {
+ // symbol
+ uno::Reference< drawing::XShapes > xSymbolGroup( ShapeFactory(xShapeFactory).createGroup2D( xTarget ));
+
+ // create the symbol
+ Reference< drawing::XShape > xShape( this->createLegendSymbolForSeries(
+ rSeries, xSymbolGroup, xShapeFactory ) );
+
+ // set CID to symbol for selection
+ if( xShape.is())
+ {
+ aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
+
+ OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
+ OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
+ ShapeFactory::setShapeName( xShape, aCID );
+ }
+
+ // label
+ aLabelText = ( DataSeriesHelper::getDataSeriesLabel( rSeries.getModel(), m_xChartTypeModel.is() ? m_xChartTypeModel->getRoleOfSequenceForSeriesLabel() : C2U("values-y")) );
+ aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
+
+ aResult.push_back(aEntry);
+ }
+
+ // regression curves
+ if ( 3 == m_nDimension ) // #i63016#
+ return aResult;
+
+ Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
+ if( xRegrCont.is())
+ {
+ Sequence< Reference< XRegressionCurve > > aCurves( xRegrCont->getRegressionCurves());
+ sal_Int32 i = 0, nCount = aCurves.getLength();
+ for( i=0; i<nCount; ++i )
+ {
+ if( aCurves[i].is() && !RegressionCurveHelper::isMeanValueLine( aCurves[i] ) )
+ {
+ //label
+ OUString aResStr( SchResId::getResString( STR_STATISTICS_IN_LEGEND ));
+ replaceParamterInString( aResStr, C2U("%REGRESSIONCURVE"), RegressionCurveHelper::getUINameForRegressionCurve( aCurves[i] ));
+ replaceParamterInString( aResStr, C2U("%SERIESNAME"), aLabelText );
+ aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aResStr, xTextProperties );
+
+ // symbol
+ uno::Reference< drawing::XShapes > xSymbolGroup( ShapeFactory(xShapeFactory).createGroup2D( xTarget ));
+
+ // create the symbol
+ Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol(
+ xSymbolGroup, chart2::LegendSymbolStyle_DIAGONAL_LINE, xShapeFactory,
+ Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ),
+ VLegendSymbolFactory::PROP_TYPE_LINE, uno::Any() ));
+
+ // set CID to symbol for selection
+ if( xShape.is())
+ {
+ aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
+
+ bool bAverageLine = false;//@todo find out wether this is an average line or a regression curve
+ ObjectType eObjectType = bAverageLine ? OBJECTTYPE_DATA_AVERAGE_LINE : OBJECTTYPE_DATA_CURVE;
+ OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( eObjectType, i ) );
+ aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
+ OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
+ ShapeFactory::setShapeName( xShape, aCID );
+ }
+
+ aResult.push_back(aEntry);
+ }
+ }
+ }
+ }
+ catch( uno::Exception & ex )
+ {
+ ASSERT_EXCEPTION( ex );
+ }
+ return aResult;
+}
+
+std::vector< ViewLegendEntry > SAL_CALL VSeriesPlotter::createLegendEntriesForChartType(
+ const Reference< beans::XPropertySet >& /* xTextProperties */,
+ const Reference< drawing::XShapes >& /* xTarget */,
+ const Reference< lang::XMultiServiceFactory >& /* xShapeFactory */,
+ const Reference< uno::XComponentContext >& /* xContext */
+ )
+{
+ return std::vector< ViewLegendEntry >();
+}
+
+//static
+VSeriesPlotter* VSeriesPlotter::createSeriesPlotter(
+ const uno::Reference<XChartType>& xChartTypeModel
+ , sal_Int32 nDimensionCount
+ , bool bExcludingPositioning )
+{
+ rtl::OUString aChartType = xChartTypeModel->getChartType();
+
+ //@todo: in future the plotter should be instanciated via service factory
+ VSeriesPlotter* pRet=NULL;
+ if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_COLUMN ) )
+ pRet = new BarChart(xChartTypeModel,nDimensionCount);
+ else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_BAR ) )
+ pRet = new BarChart(xChartTypeModel,nDimensionCount);
+ else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_AREA ) )
+ pRet = new AreaChart(xChartTypeModel,nDimensionCount,true);
+ else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_LINE ) )
+ pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,true);
+ else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) )
+ pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true);
+ else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE) )
+ pRet = new BubbleChart(xChartTypeModel,nDimensionCount);
+ else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
+ pRet = new PieChart(xChartTypeModel,nDimensionCount, bExcludingPositioning );
+ else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_NET) )
+ pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,true,new PolarPlottingPositionHelper(),true,false,1,drawing::Direction3D(1,1,1) );
+ else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) )
+ pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,false,new PolarPlottingPositionHelper(),true,false,1,drawing::Direction3D(1,1,1) );
+ else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) )
+ pRet = new CandleStickChart(xChartTypeModel,nDimensionCount);
+ else
+ pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true);
+ return pRet;
+}
+
+//.............................................................................
+} //namespace chart
+//.............................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/makefile.mk b/chart2/source/view/charttypes/makefile.mk
new file mode 100644
index 000000000000..b6cb14edbf14
--- /dev/null
+++ b/chart2/source/view/charttypes/makefile.mk
@@ -0,0 +1,55 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2000, 2010 Oracle and/or its affiliates.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ= ..$/..$/..
+PRJINC= $(PRJ)$/source
+PRJNAME= chart2
+TARGET= chvtypes
+
+ENABLE_EXCEPTIONS= TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE: settings.mk
+.INCLUDE: $(PRJ)$/chartview.pmk
+
+# --- export library -------------------------------------------------
+
+#object files to build and link together to lib $(SLB)$/$(TARGET).lib
+SLOFILES = $(SLO)$/Splines.obj \
+ $(SLO)$/CategoryPositionHelper.obj \
+ $(SLO)$/BarPositionHelper.obj \
+ $(SLO)$/VSeriesPlotter.obj \
+ $(SLO)$/BarChart.obj \
+ $(SLO)$/PieChart.obj \
+ $(SLO)$/AreaChart.obj \
+ $(SLO)$/CandleStickChart.obj \
+ $(SLO)$/BubbleChart.obj
+
+# --- Targets -----------------------------------------------------------------
+
+.INCLUDE: target.mk