diff options
Diffstat (limited to 'chart2/source/view/charttypes')
-rw-r--r-- | chart2/source/view/charttypes/AreaChart.cxx | 114 | ||||
-rw-r--r-- | chart2/source/view/charttypes/AreaChart.hxx | 12 | ||||
-rw-r--r-- | chart2/source/view/charttypes/BarChart.cxx | 12 | ||||
-rw-r--r-- | chart2/source/view/charttypes/BubbleChart.cxx | 420 | ||||
-rw-r--r-- | chart2/source/view/charttypes/BubbleChart.hxx | 97 | ||||
-rw-r--r-- | chart2/source/view/charttypes/CandleStickChart.cxx | 2 | ||||
-rw-r--r-- | chart2/source/view/charttypes/PieChart.cxx | 4 | ||||
-rw-r--r-- | chart2/source/view/charttypes/Splines.cxx | 350 | ||||
-rw-r--r-- | chart2/source/view/charttypes/VSeriesPlotter.cxx | 70 | ||||
-rw-r--r-- | chart2/source/view/charttypes/makefile.mk | 3 |
10 files changed, 826 insertions, 258 deletions
diff --git a/chart2/source/view/charttypes/AreaChart.cxx b/chart2/source/view/charttypes/AreaChart.cxx index 1401ab43a159..406e5d119cd6 100644 --- a/chart2/source/view/charttypes/AreaChart.cxx +++ b/chart2/source/view/charttypes/AreaChart.cxx @@ -45,6 +45,7 @@ #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> @@ -84,12 +85,12 @@ AreaChart::AreaChart( const uno::Reference<XChartType>& xChartTypeModel , m_bArea(!bNoArea) , m_bLine(bNoArea) , m_bSymbol( ChartTypeHelper::isSupportingSymbolProperties(xChartTypeModel,nDimensionCount) ) + , m_bIsPolarCooSys( bConnectLastToFirstPoint ) , m_bConnectLastToFirstPoint( bConnectLastToFirstPoint ) , m_bAddOneToXMax(bAddOneToXMax) , m_bExpandIfValuesCloseToBorder( bExpandIfValuesCloseToBorder ) , m_nKeepAspectRatio(nKeepAspectRatio) , m_aGivenAspectRatio(rAspectRatio) - , m_eNanHandling( bCategoryXAxis ? NAN_AS_GAP : NAN_AS_INTERPOLATED ) , m_eCurveStyle(CurveStyle_LINES) , m_nCurveResolution(20) , m_nSplineOrder(3) @@ -103,9 +104,6 @@ AreaChart::AreaChart( const uno::Reference<XChartType>& xChartTypeModel PlotterBase::m_pPosHelper = m_pMainPosHelper; VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper; - if( m_bArea ) - m_eNanHandling = NAN_AS_ZERO; - try { if( m_xChartTypeModelProps.is() ) @@ -234,6 +232,12 @@ bool AreaChart::keepAspectRatio() const 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 @@ -351,9 +355,10 @@ bool AreaChart::impl_createLine( VDataSeries* pSeries 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->getY( 0 ); - double fLastY = pSeries->getY( VSeriesPlotter::getPointCount() - 1 ); - if( (m_eNanHandling != NAN_AS_GAP) || (::rtl::math::isFinite( fFirstY ) && ::rtl::math::isFinite( fLastY )) ) + 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() ); @@ -429,7 +434,12 @@ bool AreaChart::impl_createArea( VDataSeries* pSeries drawing::PolyPolygonShape3D aPoly( *pSeriesPoly ); //add second part to the polygon (grounding points or previous series points) - if(!pPreviousSeriesPoly) + if( m_bConnectLastToFirstPoint && !ShapeFactory::isPolygonEmptyOrSinglePoint(*pSeriesPoly) ) + { + if( pPreviousSeriesPoly ) + addPolygon( aPoly, *pPreviousSeriesPoly ); + } + else if(!pPreviousSeriesPoly) { double fMinX = pSeries->m_fLogicMinX; double fMaxX = pSeries->m_fLogicMaxX; @@ -573,13 +583,6 @@ void lcl_reorderSeries( ::std::vector< ::std::vector< VDataSeriesGroup > >& rZS }//anonymous namespace -void AreaChart::impl_maybeReplaceNanWithZero( double& rfValue ) -{ - if( m_eNanHandling == NAN_AS_ZERO && - ( ::rtl::math::isNan(rfValue) || ::rtl::math::isInf(rfValue) ) ) - rfValue = 0.0; -} - //better performance for big data struct FormerPoint { @@ -676,8 +679,7 @@ void AreaChart::createShapes() pPosHelper = m_pMainPosHelper; PlotterBase::m_pPosHelper = pPosHelper; - double fAdd = pSeries->getY( nIndex ); - impl_maybeReplaceNanWithZero( fAdd ); + double fAdd = pSeries->getYValue( nIndex ); if( !::rtl::math::isNan(fAdd) && !::rtl::math::isInf(fAdd) ) aLogicYSumMap[nAttachedAxisIndex] += fabs( fAdd ); } @@ -709,23 +711,6 @@ void AreaChart::createShapes() if(!pSeries) continue; - sal_Int32 nMissingValueTreatment = pSeries->getMissingValueTreatment(); - switch( nMissingValueTreatment ) - { - case ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP: - if( !m_bArea ) - m_eNanHandling = NAN_AS_GAP; - break; - case ::com::sun::star::chart::MissingValueTreatment::USE_ZERO: - m_eNanHandling = NAN_AS_ZERO; - break; - case ::com::sun::star::chart::MissingValueTreatment::CONTINUE: - m_eNanHandling = NAN_AS_INTERPOLATED; - break; - default: - break; - } - /* #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. */ @@ -745,10 +730,24 @@ void AreaChart::createShapes() (*aSeriesIter)->m_fLogicZPos = fLogicZ; //collect data point information (logic coordinates, style ): - double fLogicX = (*aSeriesIter)->getX(nIndex); - double fLogicY = (*aSeriesIter)->getY(nIndex); - impl_maybeReplaceNanWithZero( fLogicX ); - impl_maybeReplaceNanWithZero( fLogicY ); + 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 ); @@ -762,7 +761,7 @@ void AreaChart::createShapes() || ::rtl::math::isNan(fLogicY) || ::rtl::math::isInf(fLogicY) || ::rtl::math::isNan(fLogicZ) || ::rtl::math::isInf(fLogicZ) ) { - if( m_eNanHandling == NAN_AS_GAP ) + if( (*aSeriesIter)->getMissingValueTreatment() == ::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP ) { drawing::PolyPolygonShape3D& rPolygon = (*aSeriesIter)->m_aPolyPolygonShape3D; sal_Int32& rIndex = (*aSeriesIter)->m_nPolygonIndex; @@ -821,8 +820,22 @@ void AreaChart::createShapes() //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 ) @@ -933,12 +946,29 @@ void AreaChart::createShapes() 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 ) ); + } - awt::Point aScreenPosition2D( LabelPositionHelper(pPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory) - .transformSceneToScreenPosition( aScenePosition3D ) ); this->createDataLabel( m_xTextTarget, **aSeriesIter, nIndex , fLogicValueForLabeDisplay - , aLogicYSumMap[nAttachedAxisIndex], aScreenPosition2D, eAlignment ); + , aLogicYSumMap[nAttachedAxisIndex], aScreenPosition2D, eAlignment, nOffset ); } } diff --git a/chart2/source/view/charttypes/AreaChart.hxx b/chart2/source/view/charttypes/AreaChart.hxx index 89790912893d..ec90e92ba1a4 100644 --- a/chart2/source/view/charttypes/AreaChart.hxx +++ b/chart2/source/view/charttypes/AreaChart.hxx @@ -104,28 +104,20 @@ private: //methods , ::com::sun::star::drawing::PolyPolygonShape3D* pSeriesPoly , PlottingPositionHelper* pPosHelper ); - void impl_maybeReplaceNanWithZero( double& rfValue ); - 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_bAddOneToXMax;//used e.g. for net chart (the angle axis needs a different autoscaling) 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 - enum tNanHandling - { - NAN_AS_ZERO, - NAN_AS_GAP, - NAN_AS_INTERPOLATED - }; - tNanHandling m_eNanHandling; - //Properties for splines: ::com::sun::star::chart2::CurveStyle m_eCurveStyle; sal_Int32 m_nCurveResolution; diff --git a/chart2/source/view/charttypes/BarChart.cxx b/chart2/source/view/charttypes/BarChart.cxx index baeac4a29cf1..41cef61561bb 100644 --- a/chart2/source/view/charttypes/BarChart.cxx +++ b/chart2/source/view/charttypes/BarChart.cxx @@ -45,7 +45,6 @@ #include "Clipping.hxx" #include <com/sun/star/chart/DataLabelPlacement.hpp> -#include <com/sun/star/chart/MissingValueTreatment.hpp> #include <com/sun/star/chart2/DataPointGeometry3D.hpp> #include <tools/debug.hxx> @@ -653,15 +652,10 @@ void BarChart::createShapes() getSeriesGroupShape(*aSeriesIter, xSeriesTarget) ); //collect data point information (logic coordinates, style ): - double fLogicX = pPosHelper->getSlotPos( (*aSeriesIter)->getX( nCatIndex ), fSlotX ); - double fLogicBarHeight = (*aSeriesIter)->getY( nCatIndex ); + double fLogicX = pPosHelper->getSlotPos( (*aSeriesIter)->getXValue( nCatIndex ), fSlotX ); + double fLogicBarHeight = (*aSeriesIter)->getYValue( nCatIndex ); if( ::rtl::math::isNan( fLogicBarHeight )) //no value at this category - { - if( pSeries->getMissingValueTreatment() == ::com::sun::star::chart::MissingValueTreatment::USE_ZERO ) - fLogicBarHeight = 0.0; - else - continue; - } + continue; double fLogicValueForLabeDisplay = fLogicBarHeight; fLogicBarHeight-=fBaseValue; diff --git a/chart2/source/view/charttypes/BubbleChart.cxx b/chart2/source/view/charttypes/BubbleChart.cxx new file mode 100644 index 000000000000..6069189ff0ac --- /dev/null +++ b/chart2/source/view/charttypes/BubbleChart.cxx @@ -0,0 +1,420 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ,v $ + * $Revision: $ + * + * 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 <svx/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 +//............................................................................. diff --git a/chart2/source/view/charttypes/BubbleChart.hxx b/chart2/source/view/charttypes/BubbleChart.hxx new file mode 100644 index 000000000000..4771a4cccee3 --- /dev/null +++ b/chart2/source/view/charttypes/BubbleChart.hxx @@ -0,0 +1,97 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ,v $ + * $Revision: $ + * + * 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 diff --git a/chart2/source/view/charttypes/CandleStickChart.cxx b/chart2/source/view/charttypes/CandleStickChart.cxx index 46fdf3d8f04d..e19a44cdcda6 100644 --- a/chart2/source/view/charttypes/CandleStickChart.cxx +++ b/chart2/source/view/charttypes/CandleStickChart.cxx @@ -250,7 +250,7 @@ void CandleStickChart::createShapes() for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ ) { //collect data point information (logic coordinates, style ): - double fLogicX = pPosHelper->getSlotPos( (*aSeriesIter)->getX( nIndex ), fSlotX ); + 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 ); diff --git a/chart2/source/view/charttypes/PieChart.cxx b/chart2/source/view/charttypes/PieChart.cxx index 7759f3110cbd..608adb49290b 100644 --- a/chart2/source/view/charttypes/PieChart.cxx +++ b/chart2/source/view/charttypes/PieChart.cxx @@ -376,7 +376,7 @@ void PieChart::createShapes() sal_Int32 nPointCount=pSeries->getTotalPointCount(); for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ ) { - double fY = pSeries->getY( nPointIndex ); + double fY = pSeries->getYValue( nPointIndex ); if(fY<0.0) { //@todo warn somehow that negative values are treated as positive @@ -402,7 +402,7 @@ void PieChart::createShapes() uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShape(pSeries, xSeriesTarget); //collect data point information (logic coordinates, style ): - double fLogicYValue = fabs(pSeries->getY( nPointIndex )); + double fLogicYValue = fabs(pSeries->getYValue( nPointIndex )); if( ::rtl::math::isNan(fLogicYValue) ) continue; if(fLogicYValue==0.0)//@todo: continue also if the resolution to small diff --git a/chart2/source/view/charttypes/Splines.cxx b/chart2/source/view/charttypes/Splines.cxx index a684b9a3228e..6d37d7444868 100644 --- a/chart2/source/view/charttypes/Splines.cxx +++ b/chart2/source/view/charttypes/Splines.cxx @@ -318,108 +318,133 @@ void SplineCalculater::CalculateCubicSplines( , sal_Int32 nGranularity ) { DBG_ASSERT( nGranularity > 0, "Granularity is invalid" ); + rResult.SequenceX.realloc(0); rResult.SequenceY.realloc(0); rResult.SequenceZ.realloc(0); - if( !rInput.SequenceX.getLength() ) + sal_Int32 nOuterCount = rInput.SequenceX.getLength();
+ if( !nOuterCount )
return; - if( rInput.SequenceX[0].getLength() <= 1 ) - return; //we need at least two points - - sal_Int32 nMaxIndexPoints = rInput.SequenceX[0].getLength()-1; // is >=1 - const double* pOldX = rInput.SequenceX[0].getConstArray(); - const double* pOldY = rInput.SequenceY[0].getConstArray(); - const double* pOldZ = rInput.SequenceZ[0].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 - - // generate the kind "natural spline" - double fInfty; - ::rtl::math::setInf( &fInfty, sal_False ); - lcl_SplineCalculation aSplineX( aInputX, fInfty, fInfty ); - lcl_SplineCalculation aSplineY( aInputY, fInfty, fInfty ); - lcl_SplineCalculation aSplineZ( aInputZ, fInfty, fInfty ); - - // fill result polygon with calculated values - rResult.SequenceX.realloc(1); - rResult.SequenceY.realloc(1); - rResult.SequenceZ.realloc(1); - rResult.SequenceX[0].realloc( nMaxIndexPoints*nGranularity + 1); - rResult.SequenceY[0].realloc( nMaxIndexPoints*nGranularity + 1); - rResult.SequenceZ[0].realloc( nMaxIndexPoints*nGranularity + 1); - - double* pNewX = rResult.SequenceX[0].getArray(); - double* pNewY = rResult.SequenceY[0].getArray(); - double* pNewZ = rResult.SequenceZ[0].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++) + 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++ ) { - fParam = aParameter[ni] + ( fInc * static_cast< double >( nj ) ); + 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 ]; + } - pNewX[nNewPointIndex]=aSplineX.GetInterpolatedValue( fParam ); - pNewY[nNewPointIndex]=aSplineY.GetInterpolatedValue( fParam ); - pNewZ[nNewPointIndex]=aSplineZ.GetInterpolatedValue( fParam ); + // 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]; } - // add last point - pNewX[nNewPointIndex] = pOldX[nMaxIndexPoints]; - pNewY[nNewPointIndex] = pOldY[nMaxIndexPoints]; - pNewZ[nNewPointIndex] = pOldZ[nMaxIndexPoints]; } void SplineCalculater::CalculateBSplines( @@ -436,80 +461,85 @@ void SplineCalculater::CalculateBSplines( rResult.SequenceY.realloc(0); rResult.SequenceZ.realloc(0); - if( !rInput.SequenceX.getLength() ) + sal_Int32 nOuterCount = rInput.SequenceX.getLength();
+ if( !nOuterCount )
return; // no input - if( rInput.SequenceX[0].getLength() <= 1 ) - return; // need at least 2 control points - - sal_Int32 n = rInput.SequenceX[0].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[0].getConstArray(); - const double* pOldY = rInput.SequenceY[0].getConstArray(); - const double* pOldZ = rInput.SequenceZ[0].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.realloc(1); - rResult.SequenceY.realloc(1); - rResult.SequenceZ.realloc(1); - rResult.SequenceX[0].realloc(nNewSectorCount+1); - rResult.SequenceY[0].realloc(nNewSectorCount+1); - rResult.SequenceZ[0].realloc(nNewSectorCount+1); - double* pNewX = rResult.SequenceX[0].getArray(); - double* pNewY = rResult.SequenceY[0].getArray(); - double* pNewZ = rResult.SequenceZ[0].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]; + 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 } - pNewX[nNewSector] = fX; - pNewY[nNewSector] = fY; - pNewZ[nNewSector] = fZ; + // add last control point to BSpline curve + pNewX[nNewSectorCount] = pOldX[n]; + pNewY[nNewSectorCount] = pOldY[n]; + pNewZ[nNewSectorCount] = pOldZ[n]; - fCurveparam += fCurveStep; //for next looping + delete[] t; + delete[] b; } - // add last control point to BSpline curve - pNewX[nNewSectorCount] = pOldX[n]; - pNewY[nNewSectorCount] = pOldY[n]; - pNewZ[nNewSectorCount] = pOldZ[n]; - - delete[] t; - delete[] b; } //............................................................................. diff --git a/chart2/source/view/charttypes/VSeriesPlotter.cxx b/chart2/source/view/charttypes/VSeriesPlotter.cxx index 1f37ae7c3aea..c8f473d226d0 100644 --- a/chart2/source/view/charttypes/VSeriesPlotter.cxx +++ b/chart2/source/view/charttypes/VSeriesPlotter.cxx @@ -61,6 +61,7 @@ #include "PieChart.hxx" #include "AreaChart.hxx" #include "CandleStickChart.hxx" +#include "BubbleChart.hxx" // #include <com/sun/star/chart/ErrorBarStyle.hpp> @@ -76,6 +77,8 @@ #include <basegfx/vector/b2dvector.hxx> #include <com/sun/star/util/XCloneable.hpp> +#include <svx/unoshape.hxx> + #include <functional> //............................................................................. @@ -116,13 +119,6 @@ VDataSeriesGroup::VDataSeriesGroup( VDataSeries* pSeries ) { } -VDataSeriesGroup::VDataSeriesGroup( const ::std::vector< VDataSeries* >& rSeriesVector ) - : m_aSeriesVector(rSeriesVector) - , m_bMaxPointCountDirty(true) - , m_nMaxPointCount(0) - , m_aListOfCachedYValues() -{ -} VDataSeriesGroup::~VDataSeriesGroup() { } @@ -394,7 +390,7 @@ OUString VSeriesPlotter::getLabelTextForValue( VDataSeries& rDataSeries } else { - if( m_aAxesNumberFormats.hasFormat(1,rDataSeries.getAttachedAxisIndex()) ) //y-axis + if( rDataSeries.shouldLabelNumberFormatKeyBeDetectedFromYAxis() && m_aAxesNumberFormats.hasFormat(1,rDataSeries.getAttachedAxisIndex()) ) //y-axis nNumberFormatKey = m_aAxesNumberFormats.getFormat(1,rDataSeries.getAttachedAxisIndex()); else nNumberFormatKey = rDataSeries.detectNumberFormatKey( nPointIndex ); @@ -465,11 +461,15 @@ uno::Reference< drawing::XShape > VSeriesPlotter::createDataLabel( const uno::Re //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 ) { @@ -537,8 +537,21 @@ uno::Reference< drawing::XShape > VSeriesPlotter::createDataLabel( const uno::Re createText( xTarget_, aText.makeStringAndClear() , *pPropNames, *pPropValues, ShapeFactory::makeTransformation( aScreenPosition2D ) ); + 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() && xTextShape.is() ) { + const awt::Point aOldTextPos( xTextShape->getPosition() ); + awt::Point aNewTextPos( aOldTextPos ); + awt::Size aSymbolSize( xSymbol->getSize() ); awt::Size aTextSize( xTextShape->getSize() ); @@ -550,7 +563,7 @@ uno::Reference< drawing::XShape > VSeriesPlotter::createDataLabel( const uno::Re aSymbolSize.Width = nXDiff * 75/100; aSymbolSize.Height = nYDiff * 75/100; - awt::Point aSymbolPosition( xTextShape->getPosition() ); + awt::Point aSymbolPosition( aUnrotatedTextPos ); aSymbolPosition.Y += (nYDiff * 25/200); if(LABEL_ALIGN_LEFT==eAlignment @@ -563,39 +576,21 @@ uno::Reference< drawing::XShape > VSeriesPlotter::createDataLabel( const uno::Re || LABEL_ALIGN_RIGHT_TOP==eAlignment || LABEL_ALIGN_RIGHT_BOTTOM==eAlignment ) { - aScreenPosition2D.X += nXDiff; + aNewTextPos.X += nXDiff; } else if(LABEL_ALIGN_TOP==eAlignment || LABEL_ALIGN_BOTTOM==eAlignment || LABEL_ALIGN_CENTER==eAlignment ) { aSymbolPosition.X -= nXDiff/2; - aScreenPosition2D.X += nXDiff/2; + aNewTextPos.X += nXDiff/2; } xSymbol->setSize( aSymbolSize ); xSymbol->setPosition( aSymbolPosition ); - /* - ::basegfx::B2DHomMatrix aM; - //As autogrow is active the rectangle is automatically expanded to that side - //to which the text is not adjusted. - aM.scale( aSymbolSize.Width, aSymbolSize.Height ); - aM.translate( aSymbolPosition.X, aSymbolPosition.Y ); - uno::Any aATransformation( uno::makeAny( B2DHomMatrixToHomogenMatrix3(aM) ) ); - - //set position - uno::Reference< beans::XPropertySet > xSymbolProp( xSymbol, uno::UNO_QUERY ); - if( xSymbolProp.is() ) - { - xSymbolProp->setPropertyValue( C2U( "Transformation" ), aATransformation ); - } - */ - //set position - uno::Reference< beans::XPropertySet > xProp( xTextShape, uno::UNO_QUERY ); - if( xProp.is() ) - xProp->setPropertyValue( C2U( "Transformation" ), ShapeFactory::makeTransformation( aScreenPosition2D ) ); + xTextShape->setPosition( aNewTextPos ); } } catch( uno::Exception& e ) @@ -1415,7 +1410,7 @@ void VDataSeriesGroup::getMinimumAndMaximiumX( double& rfMinimum, double& rfMaxi sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount(); for(sal_Int32 nN=0;nN<nPointCount;nN++) { - double fX = (*aSeriesIter)->getX( nN ); + double fX = (*aSeriesIter)->getXValue( nN ); if( ::rtl::math::isNan(fX) ) continue; if(rfMaximum<fX) @@ -1447,12 +1442,12 @@ void VDataSeriesGroup::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY, if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() ) continue; - double fX = (*aSeriesIter)->getX( nN ); + double fX = (*aSeriesIter)->getXValue( nN ); if( ::rtl::math::isNan(fX) ) continue; if( fX < fMinX || fX > fMaxX ) continue; - double fY = (*aSeriesIter)->getY( nN ); + double fY = (*aSeriesIter)->getYValue( nN ); if( ::rtl::math::isNan(fY) ) continue; if(rfMaxY<fY) @@ -1731,6 +1726,11 @@ bool VSeriesPlotter::PointsWereSkipped() const return m_bPointsWereSkipped; } +bool VSeriesPlotter::WantToPlotInFrontOfAxisLine() +{ + return ChartTypeHelper::isSeriesInFrontOfAxisLine( m_xChartTypeModel ); +} + Sequence< ViewLegendEntry > SAL_CALL VSeriesPlotter::createLegendEntries( LegendExpansion eLegendExpansion , const Reference< beans::XPropertySet >& xTextProperties @@ -2069,10 +2069,14 @@ VSeriesPlotter* VSeriesPlotter::createSeriesPlotter( 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); else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_NET) ) pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,true,new PolarPlottingPositionHelper(),true,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,true,false,1,drawing::Direction3D(1,1,1) ); else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) ) pRet = new CandleStickChart(xChartTypeModel,nDimensionCount); else diff --git a/chart2/source/view/charttypes/makefile.mk b/chart2/source/view/charttypes/makefile.mk index 434db9304788..1da5697fd25f 100644 --- a/chart2/source/view/charttypes/makefile.mk +++ b/chart2/source/view/charttypes/makefile.mk @@ -51,7 +51,8 @@ SLOFILES = $(SLO)$/Splines.obj \ $(SLO)$/BarChart.obj \ $(SLO)$/PieChart.obj \ $(SLO)$/AreaChart.obj \ - $(SLO)$/CandleStickChart.obj + $(SLO)$/CandleStickChart.obj \ + $(SLO)$/BubbleChart.obj # --- Targets ----------------------------------------------------------------- |