diff options
Diffstat (limited to 'chart2/source/view')
107 files changed, 33656 insertions, 0 deletions
diff --git a/chart2/source/view/axes/DateHelper.cxx b/chart2/source/view/axes/DateHelper.cxx new file mode 100644 index 000000000000..7159a733498f --- /dev/null +++ b/chart2/source/view/axes/DateHelper.cxx @@ -0,0 +1,132 @@ +/************************************************************************* + * + * 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 "DateHelper.hxx" +#include "DateScaling.hxx" +#include <rtl/math.hxx> +#include <com/sun/star/chart/TimeUnit.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; + +bool DateHelper::IsInSameYear( const Date& rD1, const Date& rD2 ) +{ + return rD1.GetYear() == rD2.GetYear(); +} +bool DateHelper::IsInSameMonth( const Date& rD1, const Date& rD2 ) +{ + return (rD1.GetYear() == rD2.GetYear()) + && (rD1.GetMonth() == rD2.GetMonth()); +} +long DateHelper::GetMonthsBetweenDates( Date aD1, Date aD2 ) +{ + Date aHelp = aD1; + long nSign = 1; + if( aD1 < aD2 ) + { + aD1 = aD2; + aD2 = aHelp; + nSign = -1; + } + + return nSign*( ( aD1.GetMonth() - aD2.GetMonth() ) + + ( aD1.GetYear() - aD2.GetYear() )*12 ); +} + +Date DateHelper::GetDateSomeMonthsAway( const Date& rD, long nMonthDistance ) +{ + Date aRet(rD); + long nMonth = rD.GetMonth()+nMonthDistance; + long nNewMonth = nMonth%12; + long nNewYear = rD.GetYear() + nMonth/12; + if( nMonth <= 0 || !nNewMonth ) + nNewYear--; + if( nNewMonth <= 0 ) + nNewMonth += 12; + aRet.SetMonth( sal_uInt16(nNewMonth) ); + aRet.SetYear( sal_uInt16(nNewYear) ); + while(!aRet.IsValid()) + aRet--; + return aRet; +} + +Date DateHelper::GetDateSomeYearsAway( const Date& rD, long nYearDistance ) +{ + Date aRet(rD); + aRet.SetYear( static_cast<sal_uInt16>(rD.GetYear()+nYearDistance) ); + while(!aRet.IsValid()) + aRet--; + return aRet; +} + +bool DateHelper::IsLessThanOneMonthAway( const Date& rD1, const Date& rD2 ) +{ + Date aDMin( DateHelper::GetDateSomeMonthsAway( rD1, -1 ) ); + Date aDMax( DateHelper::GetDateSomeMonthsAway( rD1, 1 ) ); + + if( rD2 > aDMin && rD2 < aDMax ) + return true; + return false; +} + +bool DateHelper::IsLessThanOneYearAway( const Date& rD1, const Date& rD2 ) +{ + Date aDMin( DateHelper::GetDateSomeYearsAway( rD1, -1 ) ); + Date aDMax( DateHelper::GetDateSomeYearsAway( rD1, 1 ) ); + + if( rD2 > aDMin && rD2 < aDMax ) + return true; + return false; +} + +double DateHelper::RasterizeDateValue( double fValue, const Date& rNullDate, long TimeResolution ) +{ + Date aDate(rNullDate); aDate += static_cast<long>(::rtl::math::approxFloor(fValue)); + switch(TimeResolution) + { + case ::com::sun::star::chart::TimeUnit::DAY: + break; + case ::com::sun::star::chart::TimeUnit::YEAR: + aDate.SetMonth(1); + aDate.SetDay(1); + break; + case ::com::sun::star::chart::TimeUnit::MONTH: + default: + aDate.SetDay(1); + break; + } + return aDate - rNullDate; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/DateScaling.cxx b/chart2/source/view/axes/DateScaling.cxx new file mode 100644 index 000000000000..8a69e83abbc8 --- /dev/null +++ b/chart2/source/view/axes/DateScaling.cxx @@ -0,0 +1,216 @@ +/************************************************************************* + * + * 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 "DateScaling.hxx" +#include <com/sun/star/chart/TimeUnit.hpp> +#include <rtl/math.hxx> +#include "com/sun/star/uno/RuntimeException.hpp" + +namespace +{ + +static const ::rtl::OUString lcl_aServiceName_DateScaling( + RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.chart2.DateScaling" )); +static const ::rtl::OUString lcl_aServiceName_InverseDateScaling( + RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.chart2.InverseDateScaling" )); + +static const ::rtl::OUString lcl_aImplementationName_DateScaling( + RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.chart2.DateScaling" )); +static const ::rtl::OUString lcl_aImplementationName_InverseDateScaling( + RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.chart2.InverseDateScaling" )); + +static const double lcl_fNumberOfMonths = 12.0;//todo: this needs to be offered by basic tools Date class if it should be more generic +} + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::chart::TimeUnit::DAY; +using ::com::sun::star::chart::TimeUnit::MONTH; +using ::com::sun::star::chart::TimeUnit::YEAR; + +DateScaling::DateScaling( const Date& rNullDate, sal_Int32 nTimeUnit, bool bShifted ) + : m_aNullDate( rNullDate ) + , m_nTimeUnit( nTimeUnit ) + , m_bShifted( bShifted ) +{ +} + +DateScaling::~DateScaling() +{ +} + +double SAL_CALL DateScaling::doScaling( double value ) + throw (uno::RuntimeException) +{ + double fResult(value); + if( ::rtl::math::isNan( value ) || ::rtl::math::isInf( value ) ) + ::rtl::math::setNan( & fResult ); + else + { + Date aDate(m_aNullDate); + aDate += static_cast<long>(::rtl::math::approxFloor(value)); + switch( m_nTimeUnit ) + { + case DAY: + fResult = value; + if(m_bShifted) + fResult+=0.5; + break; + case YEAR: + case MONTH: + default: + fResult = aDate.GetYear(); + fResult *= lcl_fNumberOfMonths;//asssuming equal count of months in each year + fResult += aDate.GetMonth(); + + double fDayOfMonth = aDate.GetDay(); + fDayOfMonth -= 1.0; + double fDaysInMonth = aDate.GetDaysInMonth(); + fResult += fDayOfMonth/fDaysInMonth; + if(m_bShifted) + { + if( YEAR==m_nTimeUnit ) + fResult += 0.5*lcl_fNumberOfMonths; + else + fResult += 0.5; + } + break; + } + } + return fResult; +} + +uno::Reference< XScaling > SAL_CALL DateScaling::getInverseScaling() + throw (uno::RuntimeException) +{ + return new InverseDateScaling( m_aNullDate, m_nTimeUnit, m_bShifted ); +} + +::rtl::OUString SAL_CALL DateScaling::getServiceName() + throw (uno::RuntimeException) +{ + return lcl_aServiceName_DateScaling; +} + +uno::Sequence< ::rtl::OUString > DateScaling::getSupportedServiceNames_Static() +{ + return uno::Sequence< ::rtl::OUString >( & lcl_aServiceName_DateScaling, 1 ); +} + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +APPHELPER_XSERVICEINFO_IMPL( DateScaling, lcl_aServiceName_DateScaling ) + +// ---------------------------------------- + +InverseDateScaling::InverseDateScaling( const Date& rNullDate, sal_Int32 nTimeUnit, bool bShifted ) + : m_aNullDate( rNullDate ) + , m_nTimeUnit( nTimeUnit ) + , m_bShifted( bShifted ) +{ +} + +InverseDateScaling::~InverseDateScaling() +{ +} + +double SAL_CALL InverseDateScaling::doScaling( double value ) + throw (uno::RuntimeException) +{ + double fResult(value); + if( ::rtl::math::isNan( value ) || ::rtl::math::isInf( value ) ) + ::rtl::math::setNan( & fResult ); + else + { + switch( m_nTimeUnit ) + { + case DAY: + if(m_bShifted) + value -= 0.5; + fResult = value; + break; + case YEAR: + case MONTH: + default: + //Date aDate(m_aNullDate); + if(m_bShifted) + { + if( YEAR==m_nTimeUnit ) + value -= 0.5*lcl_fNumberOfMonths; + else + value -= 0.5; + } + Date aDate; + double fYear = ::rtl::math::approxFloor(value/lcl_fNumberOfMonths); + double fMonth = ::rtl::math::approxFloor(value-(fYear*lcl_fNumberOfMonths)); + if( fMonth==0.0 ) + { + fYear--; + fMonth=12.0; + } + aDate.SetYear( static_cast<sal_uInt16>(fYear) ); + aDate.SetMonth( static_cast<sal_uInt16>(fMonth) ); + aDate.SetDay( 1 ); + double fMonthCount = (fYear*lcl_fNumberOfMonths)+fMonth; + double fDay = (value-fMonthCount)*aDate.GetDaysInMonth(); + fDay += 1.0; + aDate.SetDay( static_cast<sal_uInt16>(::rtl::math::round(fDay)) ); + fResult = aDate - m_aNullDate; + break; + } + } + return fResult; +} + +uno::Reference< XScaling > SAL_CALL InverseDateScaling::getInverseScaling() + throw (uno::RuntimeException) +{ + return new DateScaling( m_aNullDate, m_nTimeUnit, m_bShifted ); +} + +::rtl::OUString SAL_CALL InverseDateScaling::getServiceName() + throw (uno::RuntimeException) +{ + return lcl_aServiceName_InverseDateScaling; +} + +uno::Sequence< ::rtl::OUString > InverseDateScaling::getSupportedServiceNames_Static() +{ + return uno::Sequence< ::rtl::OUString >( & lcl_aServiceName_InverseDateScaling, 1 ); +} + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +APPHELPER_XSERVICEINFO_IMPL( InverseDateScaling, lcl_aServiceName_InverseDateScaling ) + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/DateScaling.hxx b/chart2/source/view/axes/DateScaling.hxx new file mode 100644 index 000000000000..5e550604a957 --- /dev/null +++ b/chart2/source/view/axes/DateScaling.hxx @@ -0,0 +1,114 @@ +/************************************************************************* + * + * 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_DATESCALING_HXX +#define _CHART2_DATESCALING_HXX +#include "ServiceMacros.hxx" +#include <com/sun/star/chart2/XScaling.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XServiceName.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/implbase3.hxx> +#include <tools/date.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +class DateScaling : + public ::cppu::WeakImplHelper3 < + ::com::sun::star::chart2::XScaling, + ::com::sun::star::lang::XServiceName, + ::com::sun::star::lang::XServiceInfo + > +{ +public: + DateScaling( const Date& rNullDate, sal_Int32 nTimeUnit, bool bShifted ); + virtual ~DateScaling(); + + /// declare XServiceInfo methods + APPHELPER_XSERVICEINFO_DECL() + + // ____ XScaling ____ + virtual double SAL_CALL doScaling( double value ) + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XScaling > SAL_CALL + getInverseScaling() throw (::com::sun::star::uno::RuntimeException); + + // ____ XServiceName ____ + virtual ::rtl::OUString SAL_CALL getServiceName() + throw (::com::sun::star::uno::RuntimeException); + +private: + const Date m_aNullDate; + const sal_Int32 m_nTimeUnit; + const bool m_bShifted; +}; + +class InverseDateScaling : + public ::cppu::WeakImplHelper3 < + ::com::sun::star::chart2::XScaling, + ::com::sun::star::lang::XServiceName, + ::com::sun::star::lang::XServiceInfo + > +{ +public: + InverseDateScaling( const Date& rNullDate, sal_Int32 nTimeUnit, bool bShifted ); + virtual ~InverseDateScaling(); + + /// declare XServiceInfo methods + APPHELPER_XSERVICEINFO_DECL() + + // ____ XScaling ____ + virtual double SAL_CALL doScaling( double value ) + throw (::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XScaling > SAL_CALL + getInverseScaling() throw (::com::sun::star::uno::RuntimeException); + + // ____ XServiceName ____ + virtual ::rtl::OUString SAL_CALL getServiceName() + throw (::com::sun::star::uno::RuntimeException); + +private: + const Date m_aNullDate; + const sal_Int32 m_nTimeUnit; + const bool m_bShifted; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif + diff --git a/chart2/source/view/axes/MinimumAndMaximumSupplier.cxx b/chart2/source/view/axes/MinimumAndMaximumSupplier.cxx new file mode 100644 index 000000000000..97523d38758f --- /dev/null +++ b/chart2/source/view/axes/MinimumAndMaximumSupplier.cxx @@ -0,0 +1,222 @@ +/************************************************************************* + * + * 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 "MinimumAndMaximumSupplier.hxx" + +#include <com/sun/star/chart/TimeUnit.hpp> + +#include <rtl/math.hxx> +#include <com/sun/star/awt/Size.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; + +MergedMinimumAndMaximumSupplier::MergedMinimumAndMaximumSupplier() +{ +} + +MergedMinimumAndMaximumSupplier::~MergedMinimumAndMaximumSupplier() +{ +} + +void MergedMinimumAndMaximumSupplier::addMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ) +{ + m_aMinimumAndMaximumSupplierList.insert( pMinimumAndMaximumSupplier ); +} + +bool MergedMinimumAndMaximumSupplier::hasMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ) +{ + return m_aMinimumAndMaximumSupplierList.count( pMinimumAndMaximumSupplier ) != 0; +} + +double MergedMinimumAndMaximumSupplier::getMinimumX() +{ + double fGlobalExtremum; + ::rtl::math::setInf(&fGlobalExtremum, false); + for( MinimumAndMaximumSupplierSet::iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + { + double fLocalExtremum = (*aIt)->getMinimumX(); + if(fLocalExtremum<fGlobalExtremum) + fGlobalExtremum=fLocalExtremum; + } + if(::rtl::math::isInf(fGlobalExtremum)) + ::rtl::math::setNan(&fGlobalExtremum); + return fGlobalExtremum; +} + +double MergedMinimumAndMaximumSupplier::getMaximumX() +{ + double fGlobalExtremum; + ::rtl::math::setInf(&fGlobalExtremum, true); + for( MinimumAndMaximumSupplierSet::iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + { + double fLocalExtremum = (*aIt)->getMaximumX(); + if(fLocalExtremum>fGlobalExtremum) + fGlobalExtremum=fLocalExtremum; + } + if(::rtl::math::isInf(fGlobalExtremum)) + ::rtl::math::setNan(&fGlobalExtremum); + return fGlobalExtremum; +} + +double MergedMinimumAndMaximumSupplier::getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) +{ + double fGlobalExtremum; + ::rtl::math::setInf(&fGlobalExtremum, false); + for( MinimumAndMaximumSupplierSet::iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + { + double fLocalExtremum = (*aIt)->getMinimumYInRange( fMinimumX, fMaximumX, nAxisIndex ); + if(fLocalExtremum<fGlobalExtremum) + fGlobalExtremum=fLocalExtremum; + } + if(::rtl::math::isInf(fGlobalExtremum)) + ::rtl::math::setNan(&fGlobalExtremum); + return fGlobalExtremum; +} + +double MergedMinimumAndMaximumSupplier::getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) +{ + double fGlobalExtremum; + ::rtl::math::setInf(&fGlobalExtremum, true); + for( MinimumAndMaximumSupplierSet::iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + { + double fLocalExtremum = (*aIt)->getMaximumYInRange( fMinimumX, fMaximumX, nAxisIndex ); + if(fLocalExtremum>fGlobalExtremum) + fGlobalExtremum=fLocalExtremum; + } + if(::rtl::math::isInf(fGlobalExtremum)) + ::rtl::math::setNan(&fGlobalExtremum); + return fGlobalExtremum; +} + +double MergedMinimumAndMaximumSupplier::getMinimumZ() +{ + double fGlobalExtremum; + ::rtl::math::setInf(&fGlobalExtremum, false); + for( MinimumAndMaximumSupplierSet::iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + { + double fLocalExtremum = (*aIt)->getMinimumZ(); + if(fLocalExtremum<fGlobalExtremum) + fGlobalExtremum=fLocalExtremum; + } + if(::rtl::math::isInf(fGlobalExtremum)) + ::rtl::math::setNan(&fGlobalExtremum); + return fGlobalExtremum; +} + +double MergedMinimumAndMaximumSupplier::getMaximumZ() +{ + double fGlobalExtremum; + ::rtl::math::setInf(&fGlobalExtremum, true); + for( MinimumAndMaximumSupplierSet::iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + { + double fLocalExtremum = (*aIt)->getMaximumZ(); + if(fLocalExtremum>fGlobalExtremum) + fGlobalExtremum=fLocalExtremum; + } + if(::rtl::math::isInf(fGlobalExtremum)) + ::rtl::math::setNan(&fGlobalExtremum); + return fGlobalExtremum; +} + +bool MergedMinimumAndMaximumSupplier::isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex ) +{ + // only return true, if *all* suppliers want to scale to the main tick marks + for( MinimumAndMaximumSupplierSet::iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + if( !(*aIt)->isExpandBorderToIncrementRhythm( nDimensionIndex ) ) + return false; + return true; +} + +bool MergedMinimumAndMaximumSupplier::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex ) +{ + // only return true, if *all* suppliers want to expand the range + for( MinimumAndMaximumSupplierSet::iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + if( !(*aIt)->isExpandIfValuesCloseToBorder( nDimensionIndex ) ) + return false; + return true; +} + +bool MergedMinimumAndMaximumSupplier::isExpandWideValuesToZero( sal_Int32 nDimensionIndex ) +{ + // already return true, if at least one supplier wants to expand the range + for( MinimumAndMaximumSupplierSet::iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + if( (*aIt)->isExpandWideValuesToZero( nDimensionIndex ) ) + return true; + return false; +} + +bool MergedMinimumAndMaximumSupplier::isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex ) +{ + // already return true, if at least one supplier wants to expand the range + for( MinimumAndMaximumSupplierSet::iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + if( (*aIt)->isExpandNarrowValuesTowardZero( nDimensionIndex ) ) + return true; + return false; +} + +bool MergedMinimumAndMaximumSupplier::isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) +{ + // should not be called + for( MinimumAndMaximumSupplierSet::iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + if( (*aIt)->isSeperateStackingForDifferentSigns( nDimensionIndex ) ) + return true; + return false; +} + +void MergedMinimumAndMaximumSupplier::clearMinimumAndMaximumSupplierList() +{ + m_aMinimumAndMaximumSupplierList.clear(); +} + +long MergedMinimumAndMaximumSupplier::calculateTimeResolutionOnXAxis() +{ + long nRet = ::com::sun::star::chart::TimeUnit::YEAR; + for( MinimumAndMaximumSupplierSet::iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + { + long nCurrent = (*aIt)->calculateTimeResolutionOnXAxis(); + if(nRet>nCurrent) + nRet=nCurrent; + } + return nRet; +} + +void MergedMinimumAndMaximumSupplier::setTimeResolutionOnXAxis( long nTimeResolution, const Date& rNullDate ) +{ + for( MinimumAndMaximumSupplierSet::iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + (*aIt)->setTimeResolutionOnXAxis( nTimeResolution, rNullDate ); +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/ScaleAutomatism.cxx b/chart2/source/view/axes/ScaleAutomatism.cxx new file mode 100644 index 000000000000..075ad16347c2 --- /dev/null +++ b/chart2/source/view/axes/ScaleAutomatism.cxx @@ -0,0 +1,1008 @@ +/************************************************************************* + * + * 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 "ScaleAutomatism.hxx" +#include "macros.hxx" +#include "Tickmarks_Equidistant.hxx" +#include "DateHelper.hxx" +#include "DateScaling.hxx" +#include "AxisHelper.hxx" +#include <com/sun/star/chart/TimeUnit.hpp> + +#include <rtl/math.hxx> +#include <tools/debug.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::chart::TimeUnit::DAY; +using ::com::sun::star::chart::TimeUnit::MONTH; +using ::com::sun::star::chart::TimeUnit::YEAR; + +const sal_Int32 MAXIMUM_MANUAL_INCREMENT_COUNT = 500; +const sal_Int32 MAXIMUM_AUTO_INCREMENT_COUNT = 10; +const sal_Int32 MAXIMUM_SUB_INCREMENT_COUNT = 100; + +namespace +{ + +void lcl_ensureMaximumSubIncrementCount( sal_Int32& rnSubIntervalCount ) +{ + if( rnSubIntervalCount > MAXIMUM_SUB_INCREMENT_COUNT ) + rnSubIntervalCount = MAXIMUM_SUB_INCREMENT_COUNT; +} + +}//end anonymous namespace + + +//............................................................................. + +ExplicitScaleData::ExplicitScaleData() + : Minimum(0.0) + , Maximum(10.0) + , Origin(0.0) + , Orientation(::com::sun::star::chart2::AxisOrientation_MATHEMATICAL) + , Scaling() + , AxisType(::com::sun::star::chart2::AxisType::REALNUMBER) + , ShiftedCategoryPosition(false) + , TimeResolution(::com::sun::star::chart::TimeUnit::DAY) + , NullDate(30,12,1899) +{ +} + +ExplicitSubIncrement::ExplicitSubIncrement() + : IntervalCount(2) + , PostEquidistant(true) +{ +} + + +ExplicitIncrementData::ExplicitIncrementData() + : MajorTimeInterval(1,::com::sun::star::chart::TimeUnit::DAY) + , MinorTimeInterval(1,::com::sun::star::chart::TimeUnit::DAY) + , Distance(1.0) + , PostEquidistant(true) + , BaseValue(0.0) + , SubIncrements() +{ +} + +//............................................................................. + +ScaleAutomatism::ScaleAutomatism( const ScaleData& rSourceScale, const Date& rNullDate ) + : m_aSourceScale( rSourceScale ) + , m_fValueMinimum( 0.0 ) + , m_fValueMaximum( 0.0 ) + , m_nMaximumAutoMainIncrementCount( MAXIMUM_AUTO_INCREMENT_COUNT ) + , m_bExpandBorderToIncrementRhythm( false ) + , m_bExpandIfValuesCloseToBorder( false ) + , m_bExpandWideValuesToZero( false ) + , m_bExpandNarrowValuesTowardZero( false ) + , m_nTimeResolution(::com::sun::star::chart::TimeUnit::DAY) + , m_aNullDate(rNullDate) +{ + ::rtl::math::setNan( &m_fValueMinimum ); + ::rtl::math::setNan( &m_fValueMaximum ); + + double fExplicitOrigin = 0.0; + if( m_aSourceScale.Origin >>= fExplicitOrigin ) + expandValueRange( fExplicitOrigin, fExplicitOrigin); +} +ScaleAutomatism::~ScaleAutomatism() +{ +} + +void ScaleAutomatism::expandValueRange( double fMinimum, double fMaximum ) +{ + if( (fMinimum < m_fValueMinimum) || ::rtl::math::isNan( m_fValueMinimum ) ) + m_fValueMinimum = fMinimum; + if( (fMaximum > m_fValueMaximum) || ::rtl::math::isNan( m_fValueMaximum ) ) + m_fValueMaximum = fMaximum; +} + +void ScaleAutomatism::setAutoScalingOptions( + bool bExpandBorderToIncrementRhythm, + bool bExpandIfValuesCloseToBorder, + bool bExpandWideValuesToZero, + bool bExpandNarrowValuesTowardZero ) +{ + // if called multiple times, enable an option, if it is set in at least one call + m_bExpandBorderToIncrementRhythm |= bExpandBorderToIncrementRhythm; + m_bExpandIfValuesCloseToBorder |= bExpandIfValuesCloseToBorder; + m_bExpandWideValuesToZero |= bExpandWideValuesToZero; + m_bExpandNarrowValuesTowardZero |= bExpandNarrowValuesTowardZero; + + if( m_aSourceScale.AxisType==AxisType::PERCENT ) + m_bExpandIfValuesCloseToBorder = false; +} + +void ScaleAutomatism::setMaximumAutoMainIncrementCount( sal_Int32 nMaximumAutoMainIncrementCount ) +{ + if( nMaximumAutoMainIncrementCount < 2 ) + m_nMaximumAutoMainIncrementCount = 2; //#i82006 + else if( nMaximumAutoMainIncrementCount > MAXIMUM_AUTO_INCREMENT_COUNT ) + m_nMaximumAutoMainIncrementCount = MAXIMUM_AUTO_INCREMENT_COUNT; + else + m_nMaximumAutoMainIncrementCount = nMaximumAutoMainIncrementCount; +} + +void ScaleAutomatism::setAutomaticTimeResolution( sal_Int32 nTimeResolution ) +{ + m_nTimeResolution = nTimeResolution; +} + +void ScaleAutomatism::calculateExplicitScaleAndIncrement( + ExplicitScaleData& rExplicitScale, ExplicitIncrementData& rExplicitIncrement ) const +{ + // fill explicit scale + rExplicitScale.Orientation = m_aSourceScale.Orientation; + rExplicitScale.Scaling = m_aSourceScale.Scaling; + rExplicitScale.AxisType = m_aSourceScale.AxisType; + rExplicitScale.NullDate = m_aNullDate; + + bool bAutoMinimum = !(m_aSourceScale.Minimum >>= rExplicitScale.Minimum); + bool bAutoMaximum = !(m_aSourceScale.Maximum >>= rExplicitScale.Maximum); + bool bAutoOrigin = !(m_aSourceScale.Origin >>= rExplicitScale.Origin); + + // automatic scale minimum + if( bAutoMinimum ) + { + if( m_aSourceScale.AxisType==AxisType::PERCENT ) + rExplicitScale.Minimum = 0.0; + else if( ::rtl::math::isNan( m_fValueMinimum ) ) + { + if( m_aSourceScale.AxisType==AxisType::DATE ) + rExplicitScale.Minimum = 36526.0; //1.1.2000 + else + rExplicitScale.Minimum = 0.0; //@todo get Minimum from scaling or from plotter???? + } + else + rExplicitScale.Minimum = m_fValueMinimum; + } + + // automatic scale maximum + if( bAutoMaximum ) + { + if( m_aSourceScale.AxisType==AxisType::PERCENT ) + rExplicitScale.Maximum = 1.0; + else if( ::rtl::math::isNan( m_fValueMaximum ) ) + { + if( m_aSourceScale.AxisType==AxisType::DATE ) + rExplicitScale.Maximum = 40179.0; //1.1.2010 + else + rExplicitScale.Maximum = 10.0; //@todo get Maximum from scaling or from plotter???? + } + else + rExplicitScale.Maximum = m_fValueMaximum; + } + + //--------------------------------------------------------------- + //fill explicit increment + + rExplicitScale.ShiftedCategoryPosition = m_aSourceScale.ShiftedCategoryPosition; + bool bIsLogarithm = false; + + //minimum and maximum of the ExplicitScaleData may be changed if allowed + if( m_aSourceScale.AxisType==AxisType::DATE ) + calculateExplicitIncrementAndScaleForDateTimeAxis( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum ); + else if( m_aSourceScale.AxisType==AxisType::CATEGORY || m_aSourceScale.AxisType==AxisType::SERIES ) + calculateExplicitIncrementAndScaleForCategory( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum ); + else + { + bIsLogarithm = AxisHelper::isLogarithmic( rExplicitScale.Scaling ); + if( bIsLogarithm ) + calculateExplicitIncrementAndScaleForLogarithmic( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum ); + else + calculateExplicitIncrementAndScaleForLinear( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum ); + } + + // automatic origin + if( bAutoOrigin ) + { + // #i71415# automatic origin for logarithmic axis + double fDefaulOrigin = bIsLogarithm ? 1.0 : 0.0; + + if( fDefaulOrigin < rExplicitScale.Minimum ) + fDefaulOrigin = rExplicitScale.Minimum; + else if( fDefaulOrigin > rExplicitScale.Maximum ) + fDefaulOrigin = rExplicitScale.Maximum; + + rExplicitScale.Origin = fDefaulOrigin; + } +} + +ScaleData ScaleAutomatism::getScale() const +{ + return m_aSourceScale; +} + +Date ScaleAutomatism::getNullDate() const +{ + return m_aNullDate; +} + +// private -------------------------------------------------------------------- + +void ScaleAutomatism::calculateExplicitIncrementAndScaleForCategory( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const +{ + // no scaling for categories + rExplicitScale.Scaling.clear(); + + if( rExplicitScale.ShiftedCategoryPosition ) + rExplicitScale.Maximum += 1.0; + + // ensure that at least one category is visible + if( rExplicitScale.Maximum <= rExplicitScale.Minimum ) + rExplicitScale.Maximum = rExplicitScale.Minimum + 1.0; + + // default increment settings + rExplicitIncrement.PostEquidistant = sal_True; // does not matter anyhow + rExplicitIncrement.Distance = 1.0; // category axis always have a main increment of 1 + rExplicitIncrement.BaseValue = 0.0; // category axis always have a base of 0 + + // automatic minimum and maximum + if( bAutoMinimum && m_bExpandBorderToIncrementRhythm ) + rExplicitScale.Minimum = EquidistantTickFactory::getMinimumAtIncrement( rExplicitScale.Minimum, rExplicitIncrement ); + if( bAutoMaximum && m_bExpandBorderToIncrementRhythm ) + rExplicitScale.Maximum = EquidistantTickFactory::getMaximumAtIncrement( rExplicitScale.Maximum, rExplicitIncrement ); + + //prevent performace killover + double fDistanceCount = ::rtl::math::approxFloor( (rExplicitScale.Maximum-rExplicitScale.Minimum) / rExplicitIncrement.Distance ); + if( static_cast< sal_Int32 >( fDistanceCount ) > MAXIMUM_MANUAL_INCREMENT_COUNT ) + { + double fMinimumFloor = ::rtl::math::approxFloor( rExplicitScale.Minimum ); + double fMaximumCeil = ::rtl::math::approxCeil( rExplicitScale.Maximum ); + rExplicitIncrement.Distance = ::rtl::math::approxCeil( (fMaximumCeil - fMinimumFloor) / MAXIMUM_MANUAL_INCREMENT_COUNT ); + } + + //--------------------------------------------------------------- + //fill explicit sub increment + sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength(); + for( sal_Int32 nN=0; nN<nSubCount; nN++ ) + { + ExplicitSubIncrement aExplicitSubIncrement; + const SubIncrement& rSubIncrement= m_aSourceScale.IncrementData.SubIncrements[nN]; + if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount)) + { + //scaling dependent + //@todo autocalculate IntervalCount dependent on MainIncrement and scaling + aExplicitSubIncrement.IntervalCount = 2; + } + lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount ); + if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant)) + { + //scaling dependent + aExplicitSubIncrement.PostEquidistant = sal_False; + } + rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement); + } +} + +//----------------------------------------------------------------------------------------- + +void ScaleAutomatism::calculateExplicitIncrementAndScaleForLogarithmic( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const +{ + // *** STEP 1: initialize the range data *** + + const double fInputMinimum = rExplicitScale.Minimum; + const double fInputMaximum = rExplicitScale.Maximum; + + double fSourceMinimum = rExplicitScale.Minimum; + double fSourceMaximum = rExplicitScale.Maximum; + + // set automatic PostEquidistant to true (maybe scaling dependent?) + // Note: scaling with PostEquidistant==false is untested and needs review + if( !(m_aSourceScale.IncrementData.PostEquidistant >>= rExplicitIncrement.PostEquidistant) ) + rExplicitIncrement.PostEquidistant = sal_True; + + /* All following scaling code will operate on the logarithms of the source + values. In the last step, the original values will be restored. */ + uno::Reference< XScaling > xScaling = rExplicitScale.Scaling; + if( !xScaling.is() ) + xScaling.set( AxisHelper::createLogarithmicScaling() ); + uno::Reference< XScaling > xInverseScaling = xScaling->getInverseScaling(); + + fSourceMinimum = xScaling->doScaling( fSourceMinimum ); + if( !::rtl::math::isFinite( fSourceMinimum ) ) + fSourceMinimum = 0.0; + else if( ::rtl::math::approxEqual( fSourceMinimum, ::rtl::math::approxFloor( fSourceMinimum ) ) ) + fSourceMinimum = ::rtl::math::approxFloor( fSourceMinimum ); + + fSourceMaximum = xScaling->doScaling( fSourceMaximum ); + if( !::rtl::math::isFinite( fSourceMaximum ) ) + fSourceMaximum = 0.0; + else if( ::rtl::math::approxEqual( fSourceMaximum, ::rtl::math::approxFloor( fSourceMaximum ) ) ) + fSourceMaximum = ::rtl::math::approxFloor( fSourceMaximum ); + + /* If range is invalid (minimum greater than maximum), change one of the + variable limits to validate the range. In this step, a zero-sized range + is still allowed. */ + if( fSourceMinimum > fSourceMaximum ) + { + // force changing the maximum, if both limits are fixed + if( bAutoMaximum || !bAutoMinimum ) + fSourceMaximum = fSourceMinimum; + else + fSourceMinimum = fSourceMaximum; + } + + /* If maximum is less than 0 (and therefore minimum too), minimum and + maximum will be negated and swapped to make the following algorithms + easier. Example: Both ranges [2,5] and [-5,-2] will be processed as + [2,5], and the latter will be swapped back later. The range [0,0] is + explicitly excluded from swapping (this would result in [-1,0] instead + of the expected [0,1]). */ + bool bSwapAndNegateRange = (fSourceMinimum < 0.0) && (fSourceMaximum <= 0.0); + if( bSwapAndNegateRange ) + { + double fTempValue = fSourceMinimum; + fSourceMinimum = -fSourceMaximum; + fSourceMaximum = -fTempValue; + ::std::swap( bAutoMinimum, bAutoMaximum ); + } + + // *** STEP 2: find temporary (unrounded) axis minimum and maximum *** + + double fTempMinimum = fSourceMinimum; + double fTempMaximum = fSourceMaximum; + + /* If minimum is variable and greater than 0 (and therefore maximum too), + means all original values are greater than 1 (or all values are less + than 1, and the range has been swapped above), then: */ + if( bAutoMinimum && (fTempMinimum > 0.0) ) + { + /* If minimum is less than 5 (i.e. original source values less than + B^5, B being the base of the scaling), or if minimum and maximum + are in different increment intervals (means, if minimum and maximum + are not both in the range [B^n,B^(n+1)] for a whole number n), set + minimum to 0, which results in B^0=1 on the axis. */ + double fMinimumFloor = ::rtl::math::approxFloor( fTempMinimum ); + double fMaximumFloor = ::rtl::math::approxFloor( fTempMaximum ); + // handle the exact value B^(n+1) to be in the range [B^n,B^(n+1)] + if( ::rtl::math::approxEqual( fTempMaximum, fMaximumFloor ) ) + fMaximumFloor -= 1.0; + + if( (fMinimumFloor < 5.0) || (fMinimumFloor < fMaximumFloor) ) + { + if( m_bExpandWideValuesToZero ) + fTempMinimum = 0.0; + } + /* Else (minimum and maximum are in one increment interval), expand + minimum toward 0 to make the 'shorter' data points visible. */ + else + { + if( m_bExpandNarrowValuesTowardZero ) + fTempMinimum -= 1.0; + } + } + + /* If range is still zero-sized (e.g. when minimum is fixed), set minimum + to 0, which makes the axis start/stop at the value 1. */ + if( fTempMinimum == fTempMaximum ) + { + if( bAutoMinimum && (fTempMaximum > 0.0) ) + fTempMinimum = 0.0; + else + fTempMaximum += 1.0; // always add one interval, even if maximum is fixed + } + + // *** STEP 3: calculate main interval size *** + + // base value (anchor position of the intervals), already scaled + if( !(m_aSourceScale.IncrementData.BaseValue >>= rExplicitIncrement.BaseValue) ) + { + //scaling dependent + //@maybe todo is this default also plotter dependent ?? + if( !bAutoMinimum ) + rExplicitIncrement.BaseValue = fTempMinimum; + else if( !bAutoMaximum ) + rExplicitIncrement.BaseValue = fTempMaximum; + else + rExplicitIncrement.BaseValue = 0.0; + } + + // calculate automatic interval + bool bAutoDistance = !(m_aSourceScale.IncrementData.Distance >>= rExplicitIncrement.Distance); + if( bAutoDistance ) + rExplicitIncrement.Distance = 0.0; + + /* Restrict number of allowed intervals with user-defined distance to + MAXIMUM_MANUAL_INCREMENT_COUNT. */ + sal_Int32 nMaxMainIncrementCount = bAutoDistance ? + m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT; + + // repeat calculation until number of intervals are valid + bool bNeedIteration = true; + bool bHasCalculatedDistance = false; + while( bNeedIteration ) + { + if( bAutoDistance ) + { + // first iteration: calculate interval size from axis limits + if( !bHasCalculatedDistance ) + { + double fMinimumFloor = ::rtl::math::approxFloor( fTempMinimum ); + double fMaximumCeil = ::rtl::math::approxCeil( fTempMaximum ); + rExplicitIncrement.Distance = ::rtl::math::approxCeil( (fMaximumCeil - fMinimumFloor) / nMaxMainIncrementCount ); + } + else + { + // following iterations: increase distance + rExplicitIncrement.Distance += 1.0; + } + + // for next iteration: distance calculated -> use else path to increase + bHasCalculatedDistance = true; + } + + // *** STEP 4: additional space above or below the data points *** + + double fAxisMinimum = fTempMinimum; + double fAxisMaximum = fTempMaximum; + + // round to entire multiples of the distance and add additional space + if( bAutoMinimum && m_bExpandBorderToIncrementRhythm ) + { + fAxisMinimum = EquidistantTickFactory::getMinimumAtIncrement( fAxisMinimum, rExplicitIncrement ); + + //ensure valid values after scaling #i100995# + if( !bAutoDistance ) + { + double fCheck = xInverseScaling->doScaling( fAxisMinimum ); + if( !::rtl::math::isFinite( fCheck ) || fCheck <= 0 ) + { + bAutoDistance = true; + bHasCalculatedDistance = false; + continue; + } + } + } + if( bAutoMaximum && m_bExpandBorderToIncrementRhythm ) + { + fAxisMaximum = EquidistantTickFactory::getMaximumAtIncrement( fAxisMaximum, rExplicitIncrement ); + + //ensure valid values after scaling #i100995# + if( !bAutoDistance ) + { + double fCheck = xInverseScaling->doScaling( fAxisMaximum ); + if( !::rtl::math::isFinite( fCheck ) || fCheck <= 0 ) + { + bAutoDistance = true; + bHasCalculatedDistance = false; + continue; + } + } + } + + // set the resulting limits (swap back to negative range if needed) + if( bSwapAndNegateRange ) + { + rExplicitScale.Minimum = -fAxisMaximum; + rExplicitScale.Maximum = -fAxisMinimum; + } + else + { + rExplicitScale.Minimum = fAxisMinimum; + rExplicitScale.Maximum = fAxisMaximum; + } + + /* If the number of intervals is too high (e.g. due to invalid fixed + distance or due to added space above or below data points), + calculate again with increased distance. */ + double fDistanceCount = ::rtl::math::approxFloor( (fAxisMaximum - fAxisMinimum) / rExplicitIncrement.Distance ); + bNeedIteration = static_cast< sal_Int32 >( fDistanceCount ) > nMaxMainIncrementCount; + // if manual distance is invalid, trigger automatic calculation + if( bNeedIteration ) + bAutoDistance = true; + + // convert limits back to logarithmic scale + rExplicitScale.Minimum = xInverseScaling->doScaling( rExplicitScale.Minimum ); + rExplicitScale.Maximum = xInverseScaling->doScaling( rExplicitScale.Maximum ); + + //ensure valid values after scaling #i100995# + if( !::rtl::math::isFinite( rExplicitScale.Minimum ) || rExplicitScale.Minimum <= 0) + { + rExplicitScale.Minimum = fInputMinimum; + if( !::rtl::math::isFinite( rExplicitScale.Minimum ) || rExplicitScale.Minimum <= 0 ) + rExplicitScale.Minimum = 1.0; + } + if( !::rtl::math::isFinite( rExplicitScale.Maximum) || rExplicitScale.Maximum <= 0 ) + { + rExplicitScale.Maximum= fInputMaximum; + if( !::rtl::math::isFinite( rExplicitScale.Maximum) || rExplicitScale.Maximum <= 0 ) + rExplicitScale.Maximum = 10.0; + } + if( rExplicitScale.Maximum < rExplicitScale.Minimum ) + ::std::swap( rExplicitScale.Maximum, rExplicitScale.Minimum ); + } + + //--------------------------------------------------------------- + //fill explicit sub increment + sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength(); + for( sal_Int32 nN=0; nN<nSubCount; nN++ ) + { + ExplicitSubIncrement aExplicitSubIncrement; + const SubIncrement& rSubIncrement = m_aSourceScale.IncrementData.SubIncrements[nN]; + if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount)) + { + //scaling dependent + //@todo autocalculate IntervalCount dependent on MainIncrement and scaling + aExplicitSubIncrement.IntervalCount = 9; + } + lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount ); + if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant)) + { + //scaling dependent + aExplicitSubIncrement.PostEquidistant = sal_False; + } + rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement); + } +} + +//----------------------------------------------------------------------------------------- + +void ScaleAutomatism::calculateExplicitIncrementAndScaleForDateTimeAxis( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const +{ + Date aMinDate(m_aNullDate); aMinDate += static_cast<long>(::rtl::math::approxFloor(rExplicitScale.Minimum)); + Date aMaxDate(m_aNullDate); aMaxDate += static_cast<long>(::rtl::math::approxFloor(rExplicitScale.Maximum)); + rExplicitIncrement.PostEquidistant = sal_False; + + if( aMinDate > aMaxDate ) + { + std::swap(aMinDate,aMaxDate); + } + + if( !(m_aSourceScale.TimeIncrement.TimeResolution >>= rExplicitScale.TimeResolution) ) + rExplicitScale.TimeResolution = m_nTimeResolution; + + rExplicitScale.Scaling = new DateScaling(m_aNullDate,rExplicitScale.TimeResolution,false); + + // choose min and max suitable to time resolution + switch( rExplicitScale.TimeResolution ) + { + case DAY: + if( rExplicitScale.ShiftedCategoryPosition ) + aMaxDate++;//for explicit scales we need one interval more (maximum excluded) + break; + case MONTH: + aMinDate.SetDay(1); + aMaxDate.SetDay(1); + if( rExplicitScale.ShiftedCategoryPosition ) + aMaxDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,1);//for explicit scales we need one interval more (maximum excluded) + if( DateHelper::IsLessThanOneMonthAway( aMinDate, aMaxDate ) ) + { + if( bAutoMaximum || !bAutoMinimum ) + aMaxDate = DateHelper::GetDateSomeMonthsAway(aMinDate,1); + else + aMinDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,-1); + } + break; + case YEAR: + aMinDate.SetDay(1); + aMinDate.SetMonth(1); + aMaxDate.SetDay(1); + aMaxDate.SetMonth(1); + if( rExplicitScale.ShiftedCategoryPosition ) + aMaxDate = DateHelper::GetDateSomeYearsAway(aMaxDate,1);//for explicit scales we need one interval more (maximum excluded) + if( DateHelper::IsLessThanOneYearAway( aMinDate, aMaxDate ) ) + { + if( bAutoMaximum || !bAutoMinimum ) + aMaxDate = DateHelper::GetDateSomeYearsAway(aMinDate,1); + else + aMinDate = DateHelper::GetDateSomeYearsAway(aMaxDate,-1); + } + break; + } + + // set the resulting limits (swap back to negative range if needed) + rExplicitScale.Minimum = aMinDate - m_aNullDate; + rExplicitScale.Maximum = aMaxDate - m_aNullDate; + + bool bAutoMajor = !(m_aSourceScale.TimeIncrement.MajorTimeInterval >>= rExplicitIncrement.MajorTimeInterval); + bool bAutoMinor = !(m_aSourceScale.TimeIncrement.MinorTimeInterval >>= rExplicitIncrement.MinorTimeInterval); + + sal_Int32 nMaxMainIncrementCount = bAutoMajor ? + m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT; + if( nMaxMainIncrementCount > 1 ) + nMaxMainIncrementCount--; + + + //choose major time interval: + long nDayCount = (aMaxDate-aMinDate); + long nMainIncrementCount = 1; + if( !bAutoMajor ) + { + long nIntervalDayCount = rExplicitIncrement.MajorTimeInterval.Number; + if( rExplicitIncrement.MajorTimeInterval.TimeUnit < rExplicitScale.TimeResolution ) + rExplicitIncrement.MajorTimeInterval.TimeUnit = rExplicitScale.TimeResolution; + switch( rExplicitIncrement.MajorTimeInterval.TimeUnit ) + { + case DAY: + break; + case MONTH: + nIntervalDayCount*=31;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... + break; + case YEAR: + nIntervalDayCount*=365;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... + break; + } + nMainIncrementCount = nDayCount/nIntervalDayCount; + if( nMainIncrementCount > nMaxMainIncrementCount ) + bAutoMajor = true; + } + if( bAutoMajor ) + { + long nNumer = 1; + long nIntervalDays = nDayCount / nMaxMainIncrementCount; + double nDaysPerInterval = 1.0; + if( nIntervalDays>365 || YEAR==rExplicitScale.TimeResolution ) + { + rExplicitIncrement.MajorTimeInterval.TimeUnit = YEAR; + nDaysPerInterval = 365.0;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... + } + else if( nIntervalDays>31 || MONTH==rExplicitScale.TimeResolution ) + { + rExplicitIncrement.MajorTimeInterval.TimeUnit = MONTH; + nDaysPerInterval = 31.0;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... + } + else + { + rExplicitIncrement.MajorTimeInterval.TimeUnit = DAY; + nDaysPerInterval = 1.0; + } + + nNumer = static_cast<sal_Int32>( rtl::math::approxCeil( nIntervalDays/nDaysPerInterval ) ); + if(nNumer<=0) + nNumer=1; + rExplicitIncrement.MajorTimeInterval.Number = nNumer; + nMainIncrementCount = nDayCount/(nNumer*nDaysPerInterval); + } + + //choose minor time interval: + if( !bAutoMinor ) + { + if( rExplicitIncrement.MinorTimeInterval.TimeUnit > rExplicitIncrement.MajorTimeInterval.TimeUnit ) + rExplicitIncrement.MinorTimeInterval.TimeUnit = rExplicitIncrement.MajorTimeInterval.TimeUnit; + long nIntervalDayCount = rExplicitIncrement.MinorTimeInterval.Number; + switch( rExplicitIncrement.MinorTimeInterval.TimeUnit ) + { + case DAY: + break; + case MONTH: + nIntervalDayCount*=31;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... + break; + case YEAR: + nIntervalDayCount*=365;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... + break; + } + if( nDayCount/nIntervalDayCount > nMaxMainIncrementCount ) + bAutoMinor = true; + } + if( bAutoMinor ) + { + rExplicitIncrement.MinorTimeInterval.TimeUnit = rExplicitIncrement.MajorTimeInterval.TimeUnit; + rExplicitIncrement.MinorTimeInterval.Number = 1; + if( nMainIncrementCount > 100 ) + rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number; + else + { + if( rExplicitIncrement.MajorTimeInterval.Number >= 2 ) + { + if( !(rExplicitIncrement.MajorTimeInterval.Number%2) ) + rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/2; + else if( !(rExplicitIncrement.MajorTimeInterval.Number%3) ) + rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/3; + else if( !(rExplicitIncrement.MajorTimeInterval.Number%5) ) + rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/5; + else if( rExplicitIncrement.MajorTimeInterval.Number > 50 ) + rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number; + } + else + { + switch( rExplicitIncrement.MajorTimeInterval.TimeUnit ) + { + case DAY: + break; + case MONTH: + if( rExplicitScale.TimeResolution == DAY ) + rExplicitIncrement.MinorTimeInterval.TimeUnit = DAY; + break; + case YEAR: + if( rExplicitScale.TimeResolution <= MONTH ) + rExplicitIncrement.MinorTimeInterval.TimeUnit = MONTH; + break; + } + } + } + } + +} + +//----------------------------------------------------------------------------------------- + +void ScaleAutomatism::calculateExplicitIncrementAndScaleForLinear( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const +{ + // *** STEP 1: initialize the range data *** + + double fSourceMinimum = rExplicitScale.Minimum; + double fSourceMaximum = rExplicitScale.Maximum; + + // set automatic PostEquidistant to true (maybe scaling dependent?) + if( !(m_aSourceScale.IncrementData.PostEquidistant >>= rExplicitIncrement.PostEquidistant) ) + rExplicitIncrement.PostEquidistant = sal_True; + + /* If range is invalid (minimum greater than maximum), change one of the + variable limits to validate the range. In this step, a zero-sized range + is still allowed. */ + if( fSourceMinimum > fSourceMaximum ) + { + // force changing the maximum, if both limits are fixed + if( bAutoMaximum || !bAutoMinimum ) + fSourceMaximum = fSourceMinimum; + else + fSourceMinimum = fSourceMaximum; + } + + /* If maximum is zero or negative (and therefore minimum too), minimum and + maximum will be negated and swapped to make the following algorithms + easier. Example: Both ranges [2,5] and [-5,-2] will be processed as + [2,5], and the latter will be swapped back later. The range [0,0] is + explicitly excluded from swapping (this would result in [-1,0] instead + of the expected [0,1]). */ + bool bSwapAndNegateRange = (fSourceMinimum < 0.0) && (fSourceMaximum <= 0.0); + if( bSwapAndNegateRange ) + { + double fTempValue = fSourceMinimum; + fSourceMinimum = -fSourceMaximum; + fSourceMaximum = -fTempValue; + ::std::swap( bAutoMinimum, bAutoMaximum ); + } + + // *** STEP 2: find temporary (unrounded) axis minimum and maximum *** + + double fTempMinimum = fSourceMinimum; + double fTempMaximum = fSourceMaximum; + + /* If minimum is variable and greater than 0 (and therefore maximum too), + means all values are positive (or all values are negative, and the + range has been swapped above), then: */ + if( bAutoMinimum && (fTempMinimum > 0.0) ) + { + /* If minimum equals maximum, or if minimum is less than 5/6 of + maximum, set minimum to 0. */ + if( (fTempMinimum == fTempMaximum) || (fTempMinimum / fTempMaximum < 5.0 / 6.0) ) + { + if( m_bExpandWideValuesToZero ) + fTempMinimum = 0.0; + } + /* Else (minimum is greater than or equal to 5/6 of maximum), add half + of the visible range (expand minimum toward 0) to make the + 'shorter' data points visible. */ + else + { + if( m_bExpandNarrowValuesTowardZero ) + fTempMinimum -= (fTempMaximum - fTempMinimum) / 2.0; + } + } + + /* If range is still zero-sized (e.g. when minimum is fixed), add some + space to a variable limit. */ + if( fTempMinimum == fTempMaximum ) + { + if( bAutoMaximum || !bAutoMinimum ) + { + // change 0 to 1, otherwise double the value + if( fTempMaximum == 0.0 ) + fTempMaximum = 1.0; + else + fTempMaximum *= 2.0; + } + else + { + // change 0 to -1, otherwise halve the value + if( fTempMinimum == 0.0 ) + fTempMinimum = -1.0; + else + fTempMinimum /= 2.0; + } + } + + // *** STEP 3: calculate main interval size *** + + // base value (anchor position of the intervals) + if( !(m_aSourceScale.IncrementData.BaseValue >>= rExplicitIncrement.BaseValue) ) + { + if( !bAutoMinimum ) + rExplicitIncrement.BaseValue = fTempMinimum; + else if( !bAutoMaximum ) + rExplicitIncrement.BaseValue = fTempMaximum; + else + rExplicitIncrement.BaseValue = 0.0; + } + + // calculate automatic interval + bool bAutoDistance = !(m_aSourceScale.IncrementData.Distance >>= rExplicitIncrement.Distance); + /* Restrict number of allowed intervals with user-defined distance to + MAXIMUM_MANUAL_INCREMENT_COUNT. */ + sal_Int32 nMaxMainIncrementCount = bAutoDistance ? + m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT; + + double fDistanceMagnitude = 0.0; + double fDistanceNormalized = 0.0; + bool bHasNormalizedDistance = false; + + // repeat calculation until number of intervals are valid + bool bNeedIteration = true; + while( bNeedIteration ) + { + if( bAutoDistance ) + { + // first iteration: calculate interval size from axis limits + if( !bHasNormalizedDistance ) + { + // raw size of an interval + double fDistance = (fTempMaximum - fTempMinimum) / nMaxMainIncrementCount; + + // if distance of is less than 1e-307, do not do anything + if( fDistance <= 1.0e-307 ) + { + fDistanceNormalized = 1.0; + fDistanceMagnitude = 1.0e-307; + } + else + { + // distance magnitude (a power of 10) + int nExponent = static_cast< int >( ::rtl::math::approxFloor( log10( fDistance ) ) ); + fDistanceMagnitude = ::rtl::math::pow10Exp( 1.0, nExponent ); + + // stick normalized distance to a few predefined values + fDistanceNormalized = fDistance / fDistanceMagnitude; + if( fDistanceNormalized <= 1.0 ) + fDistanceNormalized = 1.0; + else if( fDistanceNormalized <= 2.0 ) + fDistanceNormalized = 2.0; + else if( fDistanceNormalized <= 5.0 ) + fDistanceNormalized = 5.0; + else + { + fDistanceNormalized = 1.0; + fDistanceMagnitude *= 10; + } + } + // for next iteration: distance is normalized -> use else path to increase distance + bHasNormalizedDistance = true; + } + // following iterations: increase distance, use only allowed values + else + { + if( fDistanceNormalized == 1.0 ) + fDistanceNormalized = 2.0; + else if( fDistanceNormalized == 2.0 ) + fDistanceNormalized = 5.0; + else + { + fDistanceNormalized = 1.0; + fDistanceMagnitude *= 10; + } + } + + // set the resulting distance + rExplicitIncrement.Distance = fDistanceNormalized * fDistanceMagnitude; + } + + // *** STEP 4: additional space above or below the data points *** + + double fAxisMinimum = fTempMinimum; + double fAxisMaximum = fTempMaximum; + + // round to entire multiples of the distance and add additional space + if( bAutoMinimum ) + { + // round to entire multiples of the distance, based on the base value + if( m_bExpandBorderToIncrementRhythm ) + fAxisMinimum = EquidistantTickFactory::getMinimumAtIncrement( fAxisMinimum, rExplicitIncrement ); + // additional space, if source minimum is to near at axis minimum + if( m_bExpandIfValuesCloseToBorder ) + if( (fAxisMinimum != 0.0) && ((fAxisMaximum - fSourceMinimum) / (fAxisMaximum - fAxisMinimum) > 20.0 / 21.0) ) + fAxisMinimum -= rExplicitIncrement.Distance; + } + if( bAutoMaximum ) + { + // round to entire multiples of the distance, based on the base value + if( m_bExpandBorderToIncrementRhythm ) + fAxisMaximum = EquidistantTickFactory::getMaximumAtIncrement( fAxisMaximum, rExplicitIncrement ); + // additional space, if source maximum is to near at axis maximum + if( m_bExpandIfValuesCloseToBorder ) + if( (fAxisMaximum != 0.0) && ((fSourceMaximum - fAxisMinimum) / (fAxisMaximum - fAxisMinimum) > 20.0 / 21.0) ) + fAxisMaximum += rExplicitIncrement.Distance; + } + + // set the resulting limits (swap back to negative range if needed) + if( bSwapAndNegateRange ) + { + rExplicitScale.Minimum = -fAxisMaximum; + rExplicitScale.Maximum = -fAxisMinimum; + } + else + { + rExplicitScale.Minimum = fAxisMinimum; + rExplicitScale.Maximum = fAxisMaximum; + } + + /* If the number of intervals is too high (e.g. due to invalid fixed + distance or due to added space above or below data points), + calculate again with increased distance. */ + double fDistanceCount = ::rtl::math::approxFloor( (fAxisMaximum - fAxisMinimum) / rExplicitIncrement.Distance ); + bNeedIteration = static_cast< sal_Int32 >( fDistanceCount ) > nMaxMainIncrementCount; + // if manual distance is invalid, trigger automatic calculation + if( bNeedIteration ) + bAutoDistance = true; + } + + //--------------------------------------------------------------- + //fill explicit sub increment + sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength(); + for( sal_Int32 nN=0; nN<nSubCount; nN++ ) + { + ExplicitSubIncrement aExplicitSubIncrement; + const SubIncrement& rSubIncrement= m_aSourceScale.IncrementData.SubIncrements[nN]; + if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount)) + { + //scaling dependent + //@todo autocalculate IntervalCount dependent on MainIncrement and scaling + aExplicitSubIncrement.IntervalCount = 2; + } + lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount ); + if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant)) + { + //scaling dependent + aExplicitSubIncrement.PostEquidistant = sal_False; + } + rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement); + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/TickmarkHelper.cxx b/chart2/source/view/axes/TickmarkHelper.cxx new file mode 100644 index 000000000000..f4f717722bed --- /dev/null +++ b/chart2/source/view/axes/TickmarkHelper.cxx @@ -0,0 +1,934 @@ +/************************************************************************* + * + * 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 "TickmarkHelper.hxx" +#include "ViewDefines.hxx" +#include <rtl/math.hxx> +#include <tools/debug.hxx> +#include <memory> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::rtl::math; +using ::basegfx::B2DVector; + +TickInfo::TickInfo() +: fScaledTickValue( 0.0 ) +, fUnscaledTickValue( 0.0 ) +, aTickScreenPosition(0.0,0.0) +, bPaintIt( true ) +, xTextShape( NULL ) +, nFactorForLimitedTextWidth(1) +{ +} + +void TickInfo::updateUnscaledValue( const uno::Reference< XScaling >& xInverseScaling ) +{ + if( xInverseScaling.is() ) + this->fUnscaledTickValue = xInverseScaling->doScaling( this->fScaledTickValue ); + else + this->fUnscaledTickValue = this->fScaledTickValue; +} + +sal_Int32 TickInfo::getScreenDistanceBetweenTicks( const TickInfo& rOherTickInfo ) const +{ + //return the positive distance between the two first tickmarks in screen values + + B2DVector aDistance = rOherTickInfo.aTickScreenPosition - aTickScreenPosition; + sal_Int32 nRet = static_cast<sal_Int32>(aDistance.getLength()); + if(nRet<0) + nRet *= -1; + return nRet; +} + +PureTickIter::PureTickIter( ::std::vector< TickInfo >& rTickInfoVector ) + : m_rTickVector(rTickInfoVector) + , m_aTickIter(m_rTickVector.begin()) +{ +} +PureTickIter::~PureTickIter() +{ +} +TickInfo* PureTickIter::firstInfo() +{ + m_aTickIter = m_rTickVector.begin(); + if(m_aTickIter!=m_rTickVector.end()) + return &*m_aTickIter; + return 0; +} +TickInfo* PureTickIter::nextInfo() +{ + m_aTickIter++; + if(m_aTickIter!=m_rTickVector.end()) + return &*m_aTickIter; + return 0; +} + +EquidistantTickIter::EquidistantTickIter( const uno::Sequence< uno::Sequence< double > >& rTicks + , const ExplicitIncrementData& rIncrement + , sal_Int32 nMinDepth, sal_Int32 nMaxDepth ) + : m_pSimpleTicks(&rTicks) + , m_pInfoTicks(0) + , m_rIncrement(rIncrement) + , m_nMinDepth(0), m_nMaxDepth(0) + , m_nTickCount(0), m_pnPositions(NULL) + , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL) + , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 ) +{ + initIter( nMinDepth, nMaxDepth ); +} + +EquidistantTickIter::EquidistantTickIter( ::std::vector< ::std::vector< TickInfo > >& rTicks + , const ExplicitIncrementData& rIncrement + , sal_Int32 nMinDepth, sal_Int32 nMaxDepth ) + : m_pSimpleTicks(NULL) + , m_pInfoTicks(&rTicks) + , m_rIncrement(rIncrement) + , m_nMinDepth(0), m_nMaxDepth(0) + , m_nTickCount(0), m_pnPositions(NULL) + , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL) + , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 ) +{ + initIter( nMinDepth, nMaxDepth ); +} + +void EquidistantTickIter::initIter( sal_Int32 /*nMinDepth*/, sal_Int32 nMaxDepth ) +{ + m_nMaxDepth = nMaxDepth; + if(nMaxDepth<0 || m_nMaxDepth>getMaxDepth()) + m_nMaxDepth=getMaxDepth(); + + sal_Int32 nDepth = 0; + for( nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ ) + m_nTickCount += getTickCount(nDepth); + + if(!m_nTickCount) + return; + + m_pnPositions = new sal_Int32[m_nMaxDepth+1]; + + m_pnPreParentCount = new sal_Int32[m_nMaxDepth+1]; + m_pbIntervalFinished = new bool[m_nMaxDepth+1]; + m_pnPreParentCount[0] = 0; + m_pbIntervalFinished[0] = false; + double fParentValue = getTickValue(0,0); + for( nDepth = 1; nDepth<=m_nMaxDepth ;nDepth++ ) + { + m_pbIntervalFinished[nDepth] = false; + + sal_Int32 nPreParentCount = 0; + sal_Int32 nCount = getTickCount(nDepth); + for(sal_Int32 nN = 0; nN<nCount; nN++) + { + if(getTickValue(nDepth,nN) < fParentValue) + nPreParentCount++; + else + break; + } + m_pnPreParentCount[nDepth] = nPreParentCount; + if(nCount) + { + double fNextParentValue = getTickValue(nDepth,0); + if( fNextParentValue < fParentValue ) + fParentValue = fNextParentValue; + } + } +} + +EquidistantTickIter::~EquidistantTickIter() +{ + delete[] m_pnPositions; + delete[] m_pnPreParentCount; + delete[] m_pbIntervalFinished; +} + +sal_Int32 EquidistantTickIter::getStartDepth() const +{ + //find the depth of the first visible tickmark: + //it is the depth of the smallest value + sal_Int32 nReturnDepth=0; + double fMinValue = DBL_MAX; + for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ ) + { + sal_Int32 nCount = getTickCount(nDepth); + if( !nCount ) + continue; + double fThisValue = getTickValue(nDepth,0); + if(fThisValue<fMinValue) + { + nReturnDepth = nDepth; + fMinValue = fThisValue; + } + } + return nReturnDepth; +} + +double* EquidistantTickIter::firstValue() +{ + if( gotoFirst() ) + { + m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]); + return &m_fCurrentValue; + } + return NULL; +} + +TickInfo* EquidistantTickIter::firstInfo() +{ + if( m_pInfoTicks && gotoFirst() ) + return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]]; + return NULL; +} + +sal_Int32 EquidistantTickIter::getIntervalCount( sal_Int32 nDepth ) +{ + if(nDepth>m_rIncrement.SubIncrements.getLength() || nDepth<0) + return 0; + + if(!nDepth) + return m_nTickCount; + + return m_rIncrement.SubIncrements[nDepth-1].IntervalCount; +} + +bool EquidistantTickIter::isAtLastPartTick() +{ + if(!m_nCurrentDepth) + return false; + sal_Int32 nIntervalCount = getIntervalCount( m_nCurrentDepth ); + if(!nIntervalCount || nIntervalCount == 1) + return true; + if( m_pbIntervalFinished[m_nCurrentDepth] ) + return false; + sal_Int32 nPos = m_pnPositions[m_nCurrentDepth]+1; + if(m_pnPreParentCount[m_nCurrentDepth]) + nPos += nIntervalCount-1 - m_pnPreParentCount[m_nCurrentDepth]; + bool bRet = nPos && nPos % (nIntervalCount-1) == 0; + if(!nPos && !m_pnPreParentCount[m_nCurrentDepth] + && m_pnPositions[m_nCurrentDepth-1]==-1 ) + bRet = true; + return bRet; +} + +bool EquidistantTickIter::gotoFirst() +{ + if( m_nMaxDepth<0 ) + return false; + if( !m_nTickCount ) + return false; + + for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ ) + m_pnPositions[nDepth] = -1; + + m_nCurrentPos = 0; + m_nCurrentDepth = getStartDepth(); + m_pnPositions[m_nCurrentDepth] = 0; + return true; +} + +bool EquidistantTickIter::gotoNext() +{ + if( m_nCurrentPos < 0 ) + return false; + m_nCurrentPos++; + + if( m_nCurrentPos >= m_nTickCount ) + return false; + + if( m_nCurrentDepth==m_nMaxDepth && isAtLastPartTick() ) + { + do + { + m_pbIntervalFinished[m_nCurrentDepth] = true; + m_nCurrentDepth--; + } + while( m_nCurrentDepth && isAtLastPartTick() ); + } + else if( m_nCurrentDepth<m_nMaxDepth ) + { + do + { + m_nCurrentDepth++; + } + while( m_nCurrentDepth<m_nMaxDepth ); + } + m_pbIntervalFinished[m_nCurrentDepth] = false; + m_pnPositions[m_nCurrentDepth] = m_pnPositions[m_nCurrentDepth]+1; + return true; +} + +bool EquidistantTickIter::gotoIndex( sal_Int32 nTickIndex ) +{ + if( nTickIndex < 0 ) + return false; + if( nTickIndex >= m_nTickCount ) + return false; + + if( nTickIndex < m_nCurrentPos ) + if( !gotoFirst() ) + return false; + + while( nTickIndex > m_nCurrentPos ) + if( !gotoNext() ) + return false; + + return true; +} + +sal_Int32 EquidistantTickIter::getCurrentIndex() const +{ + return m_nCurrentPos; +} +sal_Int32 EquidistantTickIter::getMaxIndex() const +{ + return m_nTickCount-1; +} + +double* EquidistantTickIter::nextValue() +{ + if( gotoNext() ) + { + m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]); + return &m_fCurrentValue; + } + return NULL; +} + +TickInfo* EquidistantTickIter::nextInfo() +{ + if( m_pInfoTicks && gotoNext() && + static_cast< sal_Int32 >( + (*m_pInfoTicks)[m_nCurrentDepth].size()) > m_pnPositions[m_nCurrentDepth] ) + { + return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]]; + } + return NULL; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +double TickmarkHelper::getMinimumAtIncrement( double fMin, const ExplicitIncrementData& rIncrement ) +{ + //the returned value will be <= fMin and on a Major Tick given by rIncrement + if(rIncrement.Distance<=0.0) + return fMin; + + double fRet = rIncrement.BaseValue + + floor( approxSub( fMin, rIncrement.BaseValue ) + / rIncrement.Distance) + *rIncrement.Distance; + + if( fRet > fMin ) + { + if( !approxEqual(fRet, fMin) ) + fRet -= rIncrement.Distance; + } + return fRet; +} +double TickmarkHelper::getMaximumAtIncrement( double fMax, const ExplicitIncrementData& rIncrement ) +{ + //the returned value will be >= fMax and on a Major Tick given by rIncrement + if(rIncrement.Distance<=0.0) + return fMax; + + double fRet = rIncrement.BaseValue + + floor( approxSub( fMax, rIncrement.BaseValue ) + / rIncrement.Distance) + *rIncrement.Distance; + + if( fRet < fMax ) + { + if( !approxEqual(fRet, fMax) ) + fRet += rIncrement.Distance; + } + return fRet; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +TickmarkHelper::TickmarkHelper( + const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement ) + : m_rScale( rScale ) + , m_rIncrement( rIncrement ) + , m_xInverseScaling(NULL) + , m_pfCurrentValues(NULL) +{ + //@todo: make sure that the scale is valid for the scaling + + m_pfCurrentValues = new double[getTickDepth()]; + + if( m_rScale.Scaling.is() ) + { + m_xInverseScaling = m_rScale.Scaling->getInverseScaling(); + DBG_ASSERT( m_xInverseScaling.is(), "each Scaling needs to return a inverse Scaling" ); + } + + double fMin = m_fScaledVisibleMin = m_rScale.Minimum; + if( m_xInverseScaling.is() ) + { + m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin); + if(m_rIncrement.PostEquidistant ) + fMin = m_fScaledVisibleMin; + } + + double fMax = m_fScaledVisibleMax = m_rScale.Maximum; + if( m_xInverseScaling.is() ) + { + m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax); + if(m_rIncrement.PostEquidistant ) + fMax = m_fScaledVisibleMax; + } + + //-- + m_fOuterMajorTickBorderMin = TickmarkHelper::getMinimumAtIncrement( fMin, m_rIncrement ); + m_fOuterMajorTickBorderMax = TickmarkHelper::getMaximumAtIncrement( fMax, m_rIncrement ); + //-- + + m_fOuterMajorTickBorderMin_Scaled = m_fOuterMajorTickBorderMin; + m_fOuterMajorTickBorderMax_Scaled = m_fOuterMajorTickBorderMax; + if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() ) + { + m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin); + m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax); + + //check validity of new range: m_fOuterMajorTickBorderMin <-> m_fOuterMajorTickBorderMax + //it is assumed here, that the original range in the given Scale is valid + if( !rtl::math::isFinite(m_fOuterMajorTickBorderMin_Scaled) ) + { + m_fOuterMajorTickBorderMin += m_rIncrement.Distance; + m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin); + } + if( !rtl::math::isFinite(m_fOuterMajorTickBorderMax_Scaled) ) + { + m_fOuterMajorTickBorderMax -= m_rIncrement.Distance; + m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax); + } + } +} + +TickmarkHelper* TickmarkHelper::createShiftedTickmarkHelper() const +{ + ExplicitIncrementData aShiftedIncrement( m_rIncrement ); + aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0; + return new TickmarkHelper( m_rScale, aShiftedIncrement ); +} + +TickmarkHelper::~TickmarkHelper() +{ + delete[] m_pfCurrentValues; +} + +sal_Int32 TickmarkHelper::getTickDepth() const +{ + return m_rIncrement.SubIncrements.getLength() + 1; +} + +sal_Int32 TickmarkHelper::getMaxTickCount( sal_Int32 nDepth ) const +{ + //return the maximum amount of ticks + //possibly open intervals at the two ends of the region are handled as if they were completely visible + //(this is necessary for calculating the sub ticks at the borders correctly) + + if( nDepth >= getTickDepth() ) + return 0; + if( m_fOuterMajorTickBorderMax < m_fOuterMajorTickBorderMin ) + return 0; + if( m_rIncrement.Distance<=0.0) + return 0; + + double fSub; + if(m_rIncrement.PostEquidistant ) + fSub = approxSub( m_fScaledVisibleMax, m_fScaledVisibleMin ); + else + fSub = approxSub( m_rScale.Maximum, m_rScale.Minimum ); + + if (!isFinite(fSub)) + return 0; + + sal_Int32 nIntervalCount = static_cast<sal_Int32>( fSub / m_rIncrement.Distance ); + + nIntervalCount+=3; + for(sal_Int32 nN=0; nN<nDepth-1; nN++) + { + if( m_rIncrement.SubIncrements[nN].IntervalCount>1 ) + nIntervalCount *= m_rIncrement.SubIncrements[nN].IntervalCount; + } + + sal_Int32 nTickCount = nIntervalCount; + if(nDepth>0 && m_rIncrement.SubIncrements[nDepth-1].IntervalCount>1) + nTickCount = nIntervalCount * (m_rIncrement.SubIncrements[nDepth-1].IntervalCount-1); + + return nTickCount; +} + +double* TickmarkHelper::getMajorTick( sal_Int32 nTick ) const +{ + m_pfCurrentValues[0] = m_fOuterMajorTickBorderMin + nTick*m_rIncrement.Distance; + + if(m_pfCurrentValues[0]>m_fOuterMajorTickBorderMax) + { + if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMax) ) + return NULL; + } + if(m_pfCurrentValues[0]<m_fOuterMajorTickBorderMin) + { + if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMin) ) + return NULL; + } + + //return always the value after scaling + if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() ) + m_pfCurrentValues[0] = m_rScale.Scaling->doScaling( m_pfCurrentValues[0] ); + + return &m_pfCurrentValues[0]; +} + +double* TickmarkHelper::getMinorTick( sal_Int32 nTick, sal_Int32 nDepth + , double fStartParentTick, double fNextParentTick ) const +{ + //check validity of arguments + { + //DBG_ASSERT( fStartParentTick < fNextParentTick, "fStartParentTick >= fNextParentTick"); + if(fStartParentTick >= fNextParentTick) + return NULL; + if(nDepth>m_rIncrement.SubIncrements.getLength() || nDepth<=0) + return NULL; + + //subticks are only calculated if they are laying between parent ticks: + if(nTick<=0) + return NULL; + if(nTick>=m_rIncrement.SubIncrements[nDepth-1].IntervalCount) + return NULL; + } + + bool bPostEquidistant = m_rIncrement.SubIncrements[nDepth-1].PostEquidistant; + + double fAdaptedStartParent = fStartParentTick; + double fAdaptedNextParent = fNextParentTick; + + if( !bPostEquidistant && m_xInverseScaling.is() ) + { + fAdaptedStartParent = m_xInverseScaling->doScaling(fStartParentTick); + fAdaptedNextParent = m_xInverseScaling->doScaling(fNextParentTick); + } + + double fDistance = (fAdaptedNextParent - fAdaptedStartParent)/m_rIncrement.SubIncrements[nDepth-1].IntervalCount; + + m_pfCurrentValues[nDepth] = fAdaptedStartParent + nTick*fDistance; + + //return always the value after scaling + if(!bPostEquidistant && m_xInverseScaling.is() ) + m_pfCurrentValues[nDepth] = m_rScale.Scaling->doScaling( m_pfCurrentValues[nDepth] ); + + if( !isWithinOuterBorder( m_pfCurrentValues[nDepth] ) ) + return NULL; + + return &m_pfCurrentValues[nDepth]; +} + +bool TickmarkHelper::isWithinOuterBorder( double fScaledValue ) const +{ + if(fScaledValue>m_fOuterMajorTickBorderMax_Scaled) + return false; + if(fScaledValue<m_fOuterMajorTickBorderMin_Scaled) + return false; + + return true; +} + + +bool TickmarkHelper::isVisible( double fScaledValue ) const +{ + if(fScaledValue>m_fScaledVisibleMax) + { + if( !approxEqual(fScaledValue,m_fScaledVisibleMax) ) + return false; + } + if(fScaledValue<m_fScaledVisibleMin) + { + if( !approxEqual(fScaledValue,m_fScaledVisibleMin) ) + return false; + } + return true; +} + +void TickmarkHelper::getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const +{ + uno::Sequence< uno::Sequence< double > > aAllTicks; + + //create point sequences for each tick depth + sal_Int32 nDepthCount = this->getTickDepth(); + sal_Int32 nMaxMajorTickCount = this->getMaxTickCount( 0 ); + + aAllTicks.realloc(nDepthCount); + aAllTicks[0].realloc(nMaxMajorTickCount); + + sal_Int32 nRealMajorTickCount = 0; + double* pValue = NULL; + for( sal_Int32 nMajorTick=0; nMajorTick<nMaxMajorTickCount; nMajorTick++ ) + { + pValue = this->getMajorTick( nMajorTick ); + if(!pValue) + continue; + aAllTicks[0][nRealMajorTickCount] = *pValue; + nRealMajorTickCount++; + } + if(!nRealMajorTickCount) + return; + aAllTicks[0].realloc(nRealMajorTickCount); + + if(nDepthCount>0) + this->addSubTicks( 1, aAllTicks ); + + //so far we have added all ticks between the outer major tick marks + //this was necessary to create sub ticks correctly + //now we reduce all ticks to the visible ones that lie between the real borders + sal_Int32 nDepth = 0; + sal_Int32 nTick = 0; + for( nDepth = 0; nDepth < nDepthCount; nDepth++) + { + sal_Int32 nInvisibleAtLowerBorder = 0; + sal_Int32 nInvisibleAtUpperBorder = 0; + //we need only to check all ticks within the first major interval at each border + sal_Int32 nCheckCount = 1; + for(sal_Int32 nN=0; nN<nDepth; nN++) + { + if( m_rIncrement.SubIncrements[nN].IntervalCount>1 ) + nCheckCount *= m_rIncrement.SubIncrements[nN].IntervalCount; + } + uno::Sequence< double >& rTicks = aAllTicks[nDepth]; + sal_Int32 nCount = rTicks.getLength(); + //check lower border + for( nTick=0; nTick<nCheckCount && nTick<nCount; nTick++) + { + if( !isVisible( rTicks[nTick] ) ) + nInvisibleAtLowerBorder++; + } + //check upper border + for( nTick=nCount-1; nTick>nCount-1-nCheckCount && nTick>=0; nTick--) + { + if( !isVisible( rTicks[nTick] ) ) + nInvisibleAtUpperBorder++; + } + //resize sequence + if( !nInvisibleAtLowerBorder && !nInvisibleAtUpperBorder) + continue; + if( !nInvisibleAtLowerBorder ) + rTicks.realloc(nCount-nInvisibleAtUpperBorder); + else + { + sal_Int32 nNewCount = nCount-nInvisibleAtUpperBorder-nInvisibleAtLowerBorder; + if(nNewCount<0) + nNewCount=0; + + uno::Sequence< double > aOldTicks(rTicks); + rTicks.realloc(nNewCount); + for(nTick = 0; nTick<nNewCount; nTick++) + rTicks[nTick] = aOldTicks[nInvisibleAtLowerBorder+nTick]; + } + } + + //fill return value + rAllTickInfos.resize(aAllTicks.getLength()); + for( nDepth=0 ;nDepth<aAllTicks.getLength(); nDepth++ ) + { + sal_Int32 nCount = aAllTicks[nDepth].getLength(); + rAllTickInfos[nDepth].resize( nCount ); + for(sal_Int32 nN = 0; nN<nCount; nN++) + { + rAllTickInfos[nDepth][nN].fScaledTickValue = aAllTicks[nDepth][nN]; + } + } +} + +void TickmarkHelper::getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const +{ + std::auto_ptr< TickmarkHelper > apShiftedTickmarkHelper( createShiftedTickmarkHelper() ); + apShiftedTickmarkHelper->getAllTicks( rAllTickInfos ); +} + +void TickmarkHelper::addSubTicks( sal_Int32 nDepth, uno::Sequence< uno::Sequence< double > >& rParentTicks ) const +{ + EquidistantTickIter aIter( rParentTicks, m_rIncrement, 0, nDepth-1 ); + double* pfNextParentTick = aIter.firstValue(); + if(!pfNextParentTick) + return; + double fLastParentTick = *pfNextParentTick; + pfNextParentTick = aIter.nextValue(); + if(!pfNextParentTick) + return; + + sal_Int32 nMaxSubTickCount = this->getMaxTickCount( nDepth ); + if(!nMaxSubTickCount) + return; + + uno::Sequence< double > aSubTicks(nMaxSubTickCount); + sal_Int32 nRealSubTickCount = 0; + sal_Int32 nIntervalCount = m_rIncrement.SubIncrements[nDepth-1].IntervalCount; + + double* pValue = NULL; + for(; pfNextParentTick; fLastParentTick=*pfNextParentTick, pfNextParentTick = aIter.nextValue()) + { + for( sal_Int32 nPartTick = 1; nPartTick<nIntervalCount; nPartTick++ ) + { + pValue = this->getMinorTick( nPartTick, nDepth + , fLastParentTick, *pfNextParentTick ); + if(!pValue) + continue; + + aSubTicks[nRealSubTickCount] = *pValue; + nRealSubTickCount++; + } + } + + aSubTicks.realloc(nRealSubTickCount); + rParentTicks[nDepth] = aSubTicks; + if(m_rIncrement.SubIncrements.getLength()>nDepth) + addSubTicks( nDepth+1, rParentTicks ); +} + +//----------------------------------------------------------------------------- +// ___TickmarkHelper_2D___ +//----------------------------------------------------------------------------- +TickmarkHelper_2D::TickmarkHelper_2D( + const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement + //, double fStrech_SceneToScreen, double fOffset_SceneToScreen ) + , const B2DVector& rStartScreenPos, const B2DVector& rEndScreenPos + , const B2DVector& rAxisLineToLabelLineShift ) + : TickmarkHelper( rScale, rIncrement ) + , m_aAxisStartScreenPosition2D(rStartScreenPos) + , m_aAxisEndScreenPosition2D(rEndScreenPos) + , m_aAxisLineToLabelLineShift(rAxisLineToLabelLineShift) + , m_fStrech_LogicToScreen(1.0) + , m_fOffset_LogicToScreen(0.0) +{ + double fWidthY = m_fScaledVisibleMax - m_fScaledVisibleMin; + if( AxisOrientation_MATHEMATICAL==m_rScale.Orientation ) + { + m_fStrech_LogicToScreen = 1.0/fWidthY; + m_fOffset_LogicToScreen = -m_fScaledVisibleMin; + } + else + { + B2DVector aSwap(m_aAxisStartScreenPosition2D); + m_aAxisStartScreenPosition2D = m_aAxisEndScreenPosition2D; + m_aAxisEndScreenPosition2D = aSwap; + + m_fStrech_LogicToScreen = -1.0/fWidthY; + m_fOffset_LogicToScreen = -m_fScaledVisibleMax; + } +} + +TickmarkHelper* TickmarkHelper_2D::createShiftedTickmarkHelper() const +{ + ExplicitIncrementData aShiftedIncrement( m_rIncrement ); + aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0; + + ::basegfx::B2DVector aStart( m_aAxisStartScreenPosition2D ); + ::basegfx::B2DVector aEnd( m_aAxisEndScreenPosition2D ); + if( AxisOrientation_MATHEMATICAL==m_rScale.Orientation ) + std::swap( aStart, aEnd ); + + return new TickmarkHelper_2D( m_rScale, aShiftedIncrement, aStart, aEnd, m_aAxisLineToLabelLineShift ); +} + +TickmarkHelper_2D::~TickmarkHelper_2D() +{ +} + +bool TickmarkHelper_2D::isHorizontalAxis() const +{ + return ( m_aAxisStartScreenPosition2D.getY() == m_aAxisEndScreenPosition2D.getY() ); +} +bool TickmarkHelper_2D::isVerticalAxis() const +{ + return ( m_aAxisStartScreenPosition2D.getX() == m_aAxisEndScreenPosition2D.getX() ); +} + +sal_Int32 TickmarkHelper_2D::getTickScreenDistance( TickIter& rIter ) +{ + //return the positive distance between the two first tickmarks in screen values + //if there are less than two tickmarks -1 is returned + + const TickInfo* pFirstTickInfo = rIter.firstInfo(); + const TickInfo* pSecondTickInfo = rIter.nextInfo(); + if(!pSecondTickInfo || !pFirstTickInfo) + return -1; + + return pFirstTickInfo->getScreenDistanceBetweenTicks( *pSecondTickInfo ); +} + +B2DVector TickmarkHelper_2D::getTickScreenPosition2D( double fScaledLogicTickValue ) const +{ + B2DVector aRet(m_aAxisStartScreenPosition2D); + aRet += (m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D) + *((fScaledLogicTickValue+m_fOffset_LogicToScreen)*m_fStrech_LogicToScreen); + return aRet; +} + +void TickmarkHelper_2D::addPointSequenceForTickLine( drawing::PointSequenceSequence& rPoints + , sal_Int32 nSequenceIndex + , double fScaledLogicTickValue, double fInnerDirectionSign + , const TickmarkProperties& rTickmarkProperties + , bool bPlaceAtLabels ) const +{ + if( fInnerDirectionSign==0.0 ) + fInnerDirectionSign = 1.0; + + B2DVector aTickScreenPosition = this->getTickScreenPosition2D(fScaledLogicTickValue); + if( bPlaceAtLabels ) + aTickScreenPosition += m_aAxisLineToLabelLineShift; + + B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D; + aMainDirection.normalize(); + B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX()); + aOrthoDirection *= fInnerDirectionSign; + aOrthoDirection.normalize(); + + B2DVector aStart = aTickScreenPosition + aOrthoDirection*rTickmarkProperties.RelativePos; + B2DVector aEnd = aStart - aOrthoDirection*rTickmarkProperties.Length; + + rPoints[nSequenceIndex].realloc(2); + rPoints[nSequenceIndex][0].X = static_cast<sal_Int32>(aStart.getX()); + rPoints[nSequenceIndex][0].Y = static_cast<sal_Int32>(aStart.getY()); + rPoints[nSequenceIndex][1].X = static_cast<sal_Int32>(aEnd.getX()); + rPoints[nSequenceIndex][1].Y = static_cast<sal_Int32>(aEnd.getY()); +} + +B2DVector TickmarkHelper_2D::getDistanceAxisTickToText( const AxisProperties& rAxisProperties, bool bIncludeFarAwayDistanceIfSo, bool bIncludeSpaceBetweenTickAndText ) const +{ + bool bFarAwayLabels = false; + if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_START == rAxisProperties.m_eLabelPos + || ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END == rAxisProperties.m_eLabelPos ) + bFarAwayLabels = true; + + double fInnerDirectionSign = rAxisProperties.m_fInnerDirectionSign; + if( fInnerDirectionSign==0.0 ) + fInnerDirectionSign = 1.0; + + B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D; + aMainDirection.normalize(); + B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX()); + aOrthoDirection *= fInnerDirectionSign; + aOrthoDirection.normalize(); + + B2DVector aStart(0,0), aEnd(0,0); + if( bFarAwayLabels ) + { + TickmarkProperties aProps( AxisProperties::getBiggestTickmarkProperties() ); + aStart = aOrthoDirection*aProps.RelativePos; + aEnd = aStart - aOrthoDirection*aProps.Length; + } + else + { + for( sal_Int32 nN=rAxisProperties.m_aTickmarkPropertiesList.size();nN--;) + { + const TickmarkProperties& rProps = rAxisProperties.m_aTickmarkPropertiesList[nN]; + B2DVector aNewStart = aOrthoDirection*rProps.RelativePos; + B2DVector aNewEnd = aNewStart - aOrthoDirection*rProps.Length; + if(aNewStart.getLength()>aStart.getLength()) + aStart=aNewStart; + if(aNewEnd.getLength()>aEnd.getLength()) + aEnd=aNewEnd; + } + } + + B2DVector aLabelDirection(aStart); + if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign ) + aLabelDirection = aEnd; + + B2DVector aOrthoLabelDirection(aOrthoDirection); + if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign ) + aOrthoLabelDirection*=-1.0; + aOrthoLabelDirection.normalize(); + if( bIncludeSpaceBetweenTickAndText ) + aLabelDirection += aOrthoLabelDirection*AXIS2D_TICKLABELSPACING; + if( bFarAwayLabels && bIncludeFarAwayDistanceIfSo ) + aLabelDirection += m_aAxisLineToLabelLineShift; + return aLabelDirection; +} + +void TickmarkHelper_2D::createPointSequenceForAxisMainLine( drawing::PointSequenceSequence& rPoints ) const +{ + rPoints[0].realloc(2); + rPoints[0][0].X = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getX()); + rPoints[0][0].Y = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getY()); + rPoints[0][1].X = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getX()); + rPoints[0][1].Y = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getY()); +} + +void TickmarkHelper_2D::updateScreenValues( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const +{ + //get the transformed screen values for all tickmarks in rAllTickInfos + ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter = rAllTickInfos.begin(); + const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd = rAllTickInfos.end(); + for( ; aDepthIter != aDepthEnd; aDepthIter++ ) + { + ::std::vector< TickInfo >::iterator aTickIter = (*aDepthIter).begin(); + const ::std::vector< TickInfo >::const_iterator aTickEnd = (*aDepthIter).end(); + for( ; aTickIter != aTickEnd; aTickIter++ ) + { + TickInfo& rTickInfo = (*aTickIter); + rTickInfo.aTickScreenPosition = + this->getTickScreenPosition2D( rTickInfo.fScaledTickValue ); + } + } +} + +//----------------------------------------------------------------------------- +// ___TickmarkHelper_3D___ +//----------------------------------------------------------------------------- +TickmarkHelper_3D::TickmarkHelper_3D( + const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement ) + : TickmarkHelper( rScale, rIncrement ) +{ +} + +TickmarkHelper* TickmarkHelper_3D::createShiftedTickmarkHelper() const +{ + ExplicitIncrementData aShiftedIncrement( m_rIncrement ); + aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0; + return new TickmarkHelper_3D( m_rScale, aShiftedIncrement ); +} + +TickmarkHelper_3D::~TickmarkHelper_3D() +{ +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/TickmarkProperties.hxx b/chart2/source/view/axes/TickmarkProperties.hxx new file mode 100644 index 000000000000..09c0179d3698 --- /dev/null +++ b/chart2/source/view/axes/TickmarkProperties.hxx @@ -0,0 +1,53 @@ +/************************************************************************* + * + * 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_VTICKMARKPROPERTIES_HXX +#define _CHART2_VTICKMARKPROPERTIES_HXX + +#include "VLineProperties.hxx" + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +struct TickmarkProperties +{ + sal_Int32 RelativePos;//Position in screen values relative to the axis where the tickmark line starts + sal_Int32 Length;//Length of the tickmark line in screen values + + VLineProperties aLineProperties; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/Tickmarks.cxx b/chart2/source/view/axes/Tickmarks.cxx new file mode 100644 index 000000000000..834fe66eb97b --- /dev/null +++ b/chart2/source/view/axes/Tickmarks.cxx @@ -0,0 +1,333 @@ +/************************************************************************* + * + * 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 "Tickmarks.hxx" +#include "Tickmarks_Equidistant.hxx" +#include "Tickmarks_Dates.hxx" +#include "ViewDefines.hxx" +#include <rtl/math.hxx> +#include <tools/debug.hxx> +#include <memory> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::rtl::math; +using ::basegfx::B2DVector; + +TickInfo::TickInfo( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XScaling >& xInverse ) +: fScaledTickValue( 0.0 ) +, xInverseScaling( xInverse ) +, aTickScreenPosition(0.0,0.0) +, bPaintIt( true ) +, xTextShape( NULL ) +, nFactorForLimitedTextWidth(1) +{ +} + +double TickInfo::getUnscaledTickValue() const +{ + if( xInverseScaling.is() ) + return xInverseScaling->doScaling( fScaledTickValue ); + else + return fScaledTickValue; +} + +sal_Int32 TickInfo::getScreenDistanceBetweenTicks( const TickInfo& rOherTickInfo ) const +{ + //return the positive distance between the two first tickmarks in screen values + + B2DVector aDistance = rOherTickInfo.aTickScreenPosition - aTickScreenPosition; + sal_Int32 nRet = static_cast<sal_Int32>(aDistance.getLength()); + if(nRet<0) + nRet *= -1; + return nRet; +} + +PureTickIter::PureTickIter( ::std::vector< TickInfo >& rTickInfoVector ) + : m_rTickVector(rTickInfoVector) + , m_aTickIter(m_rTickVector.begin()) +{ +} +PureTickIter::~PureTickIter() +{ +} +TickInfo* PureTickIter::firstInfo() +{ + m_aTickIter = m_rTickVector.begin(); + if(m_aTickIter!=m_rTickVector.end()) + return &*m_aTickIter; + return 0; +} +TickInfo* PureTickIter::nextInfo() +{ + if(m_aTickIter!=m_rTickVector.end()) + { + m_aTickIter++; + if(m_aTickIter!=m_rTickVector.end()) + return &*m_aTickIter; + } + return 0; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +TickFactory::TickFactory( + const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement ) + : m_rScale( rScale ) + , m_rIncrement( rIncrement ) + , m_xInverseScaling(NULL) +{ + //@todo: make sure that the scale is valid for the scaling + + if( m_rScale.Scaling.is() ) + { + m_xInverseScaling = m_rScale.Scaling->getInverseScaling(); + DBG_ASSERT( m_xInverseScaling.is(), "each Scaling needs to return a inverse Scaling" ); + } + + m_fScaledVisibleMin = m_rScale.Minimum; + if( m_xInverseScaling.is() ) + m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin); + + m_fScaledVisibleMax = m_rScale.Maximum; + if( m_xInverseScaling.is() ) + m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax); +} + +TickFactory::~TickFactory() +{ +} + +bool TickFactory::isDateAxis() const +{ + return m_rScale.AxisType == AxisType::DATE; +} + +void TickFactory::getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const +{ + if( isDateAxis() ) + DateTickFactory( m_rScale, m_rIncrement ).getAllTicks( rAllTickInfos ); + else + EquidistantTickFactory( m_rScale, m_rIncrement ).getAllTicks( rAllTickInfos ); +} + +void TickFactory::getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const +{ + if( isDateAxis() ) + DateTickFactory( m_rScale, m_rIncrement ).getAllTicksShifted( rAllTickInfos ); + else + EquidistantTickFactory( m_rScale, m_rIncrement ).getAllTicksShifted( rAllTickInfos ); +} + +//----------------------------------------------------------------------------- +// ___TickFactory_2D___ +//----------------------------------------------------------------------------- +TickFactory_2D::TickFactory_2D( + const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement + //, double fStrech_SceneToScreen, double fOffset_SceneToScreen ) + , const B2DVector& rStartScreenPos, const B2DVector& rEndScreenPos + , const B2DVector& rAxisLineToLabelLineShift ) + : TickFactory( rScale, rIncrement ) + , m_aAxisStartScreenPosition2D(rStartScreenPos) + , m_aAxisEndScreenPosition2D(rEndScreenPos) + , m_aAxisLineToLabelLineShift(rAxisLineToLabelLineShift) + , m_fStrech_LogicToScreen(1.0) + , m_fOffset_LogicToScreen(0.0) +{ + double fWidthY = m_fScaledVisibleMax - m_fScaledVisibleMin; + if( AxisOrientation_MATHEMATICAL==m_rScale.Orientation ) + { + m_fStrech_LogicToScreen = 1.0/fWidthY; + m_fOffset_LogicToScreen = -m_fScaledVisibleMin; + } + else + { + B2DVector aSwap(m_aAxisStartScreenPosition2D); + m_aAxisStartScreenPosition2D = m_aAxisEndScreenPosition2D; + m_aAxisEndScreenPosition2D = aSwap; + + m_fStrech_LogicToScreen = -1.0/fWidthY; + m_fOffset_LogicToScreen = -m_fScaledVisibleMax; + } +} + +TickFactory_2D::~TickFactory_2D() +{ +} + +bool TickFactory_2D::isHorizontalAxis() const +{ + return ( m_aAxisStartScreenPosition2D.getY() == m_aAxisEndScreenPosition2D.getY() ); +} +bool TickFactory_2D::isVerticalAxis() const +{ + return ( m_aAxisStartScreenPosition2D.getX() == m_aAxisEndScreenPosition2D.getX() ); +} + +//static +sal_Int32 TickFactory_2D::getTickScreenDistance( TickIter& rIter ) +{ + //return the positive distance between the two first tickmarks in screen values + //if there are less than two tickmarks -1 is returned + + const TickInfo* pFirstTickInfo = rIter.firstInfo(); + const TickInfo* pSecondTickInfo = rIter.nextInfo(); + if(!pSecondTickInfo || !pFirstTickInfo) + return -1; + + return pFirstTickInfo->getScreenDistanceBetweenTicks( *pSecondTickInfo ); +} + +B2DVector TickFactory_2D::getTickScreenPosition2D( double fScaledLogicTickValue ) const +{ + B2DVector aRet(m_aAxisStartScreenPosition2D); + aRet += (m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D) + *((fScaledLogicTickValue+m_fOffset_LogicToScreen)*m_fStrech_LogicToScreen); + return aRet; +} + +void TickFactory_2D::addPointSequenceForTickLine( drawing::PointSequenceSequence& rPoints + , sal_Int32 nSequenceIndex + , double fScaledLogicTickValue, double fInnerDirectionSign + , const TickmarkProperties& rTickmarkProperties + , bool bPlaceAtLabels ) const +{ + if( fInnerDirectionSign==0.0 ) + fInnerDirectionSign = 1.0; + + B2DVector aTickScreenPosition = this->getTickScreenPosition2D(fScaledLogicTickValue); + if( bPlaceAtLabels ) + aTickScreenPosition += m_aAxisLineToLabelLineShift; + + B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D; + aMainDirection.normalize(); + B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX()); + aOrthoDirection *= fInnerDirectionSign; + aOrthoDirection.normalize(); + + B2DVector aStart = aTickScreenPosition + aOrthoDirection*rTickmarkProperties.RelativePos; + B2DVector aEnd = aStart - aOrthoDirection*rTickmarkProperties.Length; + + rPoints[nSequenceIndex].realloc(2); + rPoints[nSequenceIndex][0].X = static_cast<sal_Int32>(aStart.getX()); + rPoints[nSequenceIndex][0].Y = static_cast<sal_Int32>(aStart.getY()); + rPoints[nSequenceIndex][1].X = static_cast<sal_Int32>(aEnd.getX()); + rPoints[nSequenceIndex][1].Y = static_cast<sal_Int32>(aEnd.getY()); +} + +B2DVector TickFactory_2D::getDistanceAxisTickToText( const AxisProperties& rAxisProperties, bool bIncludeFarAwayDistanceIfSo, bool bIncludeSpaceBetweenTickAndText ) const +{ + bool bFarAwayLabels = false; + if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_START == rAxisProperties.m_eLabelPos + || ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END == rAxisProperties.m_eLabelPos ) + bFarAwayLabels = true; + + double fInnerDirectionSign = rAxisProperties.m_fInnerDirectionSign; + if( fInnerDirectionSign==0.0 ) + fInnerDirectionSign = 1.0; + + B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D; + aMainDirection.normalize(); + B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX()); + aOrthoDirection *= fInnerDirectionSign; + aOrthoDirection.normalize(); + + B2DVector aStart(0,0), aEnd(0,0); + if( bFarAwayLabels ) + { + TickmarkProperties aProps( AxisProperties::getBiggestTickmarkProperties() ); + aStart = aOrthoDirection*aProps.RelativePos; + aEnd = aStart - aOrthoDirection*aProps.Length; + } + else + { + for( sal_Int32 nN=rAxisProperties.m_aTickmarkPropertiesList.size();nN--;) + { + const TickmarkProperties& rProps = rAxisProperties.m_aTickmarkPropertiesList[nN]; + B2DVector aNewStart = aOrthoDirection*rProps.RelativePos; + B2DVector aNewEnd = aNewStart - aOrthoDirection*rProps.Length; + if(aNewStart.getLength()>aStart.getLength()) + aStart=aNewStart; + if(aNewEnd.getLength()>aEnd.getLength()) + aEnd=aNewEnd; + } + } + + B2DVector aLabelDirection(aStart); + if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign ) + aLabelDirection = aEnd; + + B2DVector aOrthoLabelDirection(aOrthoDirection); + if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign ) + aOrthoLabelDirection*=-1.0; + aOrthoLabelDirection.normalize(); + if( bIncludeSpaceBetweenTickAndText ) + aLabelDirection += aOrthoLabelDirection*AXIS2D_TICKLABELSPACING; + if( bFarAwayLabels && bIncludeFarAwayDistanceIfSo ) + aLabelDirection += m_aAxisLineToLabelLineShift; + return aLabelDirection; +} + +void TickFactory_2D::createPointSequenceForAxisMainLine( drawing::PointSequenceSequence& rPoints ) const +{ + rPoints[0].realloc(2); + rPoints[0][0].X = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getX()); + rPoints[0][0].Y = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getY()); + rPoints[0][1].X = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getX()); + rPoints[0][1].Y = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getY()); +} + +void TickFactory_2D::updateScreenValues( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const +{ + //get the transformed screen values for all tickmarks in rAllTickInfos + ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter = rAllTickInfos.begin(); + const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd = rAllTickInfos.end(); + for( ; aDepthIter != aDepthEnd; aDepthIter++ ) + { + ::std::vector< TickInfo >::iterator aTickIter = (*aDepthIter).begin(); + const ::std::vector< TickInfo >::const_iterator aTickEnd = (*aDepthIter).end(); + for( ; aTickIter != aTickEnd; aTickIter++ ) + { + TickInfo& rTickInfo = (*aTickIter); + rTickInfo.aTickScreenPosition = + this->getTickScreenPosition2D( rTickInfo.fScaledTickValue ); + } + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/Tickmarks.hxx b/chart2/source/view/axes/Tickmarks.hxx new file mode 100644 index 000000000000..62fa5fef92d0 --- /dev/null +++ b/chart2/source/view/axes/Tickmarks.hxx @@ -0,0 +1,166 @@ +/************************************************************************* + * + * 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_TICKMARKS_HXX +#define _CHART2_TICKMARKS_HXX + +#include "TickmarkProperties.hxx" +#include "VAxisProperties.hxx" +#include "chartview/ExplicitScaleValues.hxx" +#include <basegfx/vector/b2dvector.hxx> +#include <com/sun/star/drawing/PointSequenceSequence.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/uno/Sequence.h> + +#include <vector> + +//............................................................................. +namespace chart +{ +//............................................................................. + +using ::basegfx::B2DVector; +//----------------------------------------------------------------------------- +/** +*/ + +struct TickInfo +{ + double fScaledTickValue; + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XScaling > xInverseScaling; + + ::basegfx::B2DVector aTickScreenPosition; + bool bPaintIt; + + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShape > xTextShape; + + rtl::OUString aText;//used only for complex categories so far + sal_Int32 nFactorForLimitedTextWidth;//categories in higher levels of complex categories can have more place than a single simple category + +//methods: + TickInfo( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XScaling >& xInverseScaling ); + + double getUnscaledTickValue() const; + sal_Int32 getScreenDistanceBetweenTicks( const TickInfo& rOherTickInfo ) const; +private: + TickInfo(); +}; +class TickIter +{ +public: + virtual ~TickIter(){}; + virtual TickInfo* firstInfo()=0; + virtual TickInfo* nextInfo()=0; +}; + +class PureTickIter : public TickIter +{ +public: + PureTickIter( ::std::vector< TickInfo >& rTickInfoVector ); + virtual ~PureTickIter(); + virtual TickInfo* firstInfo(); + virtual TickInfo* nextInfo(); + +private: + ::std::vector< TickInfo >& m_rTickVector; + ::std::vector< TickInfo >::iterator m_aTickIter; +}; + +class TickFactory +{ +public: + TickFactory( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ); + virtual ~TickFactory(); + + void getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const; + void getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const; + virtual void updateScreenValues( ::std::vector< ::std::vector< TickInfo > >& /*rAllTickInfos*/ ) const {} + +private: //methods + bool isDateAxis() const; + +protected: //member + ExplicitScaleData m_rScale; + ExplicitIncrementData m_rIncrement; + ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XScaling > + m_xInverseScaling; + + //minimum and maximum of the visible range after scaling + double m_fScaledVisibleMin; + double m_fScaledVisibleMax; +}; + +class TickFactory_2D : public TickFactory +{ +public: + TickFactory_2D( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement + , const ::basegfx::B2DVector& rStartScreenPos, const ::basegfx::B2DVector& rEndScreenPos + , const ::basegfx::B2DVector& rAxisLineToLabelLineShift ); + //, double fStrech_SceneToScreen, double fOffset_SceneToScreen ); + virtual ~TickFactory_2D(); + + static sal_Int32 getTickScreenDistance( TickIter& rIter ); + + void createPointSequenceForAxisMainLine( ::com::sun::star::drawing::PointSequenceSequence& rPoints ) const; + void addPointSequenceForTickLine( ::com::sun::star::drawing::PointSequenceSequence& rPoints + , sal_Int32 nSequenceIndex + , double fScaledLogicTickValue, double fInnerDirectionSign + , const TickmarkProperties& rTickmarkProperties, bool bPlaceAtLabels ) const; + ::basegfx::B2DVector getDistanceAxisTickToText( const AxisProperties& rAxisProperties + , bool bIncludeFarAwayDistanceIfSo = false + , bool bIncludeSpaceBetweenTickAndText = true ) const; + + virtual void updateScreenValues( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const; + + bool isHorizontalAxis() const; + bool isVerticalAxis() const; + +protected: //methods + ::basegfx::B2DVector getTickScreenPosition2D( double fScaledLogicTickValue ) const; + +private: //member + ::basegfx::B2DVector m_aAxisStartScreenPosition2D; + ::basegfx::B2DVector m_aAxisEndScreenPosition2D; + + //labels might be posioned high or low on the border of the diagram far away from the axis + //add this vector to go from the axis line to the label line (border of the diagram) + ::basegfx::B2DVector m_aAxisLineToLabelLineShift; + + double m_fStrech_LogicToScreen; + double m_fOffset_LogicToScreen; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/Tickmarks_Dates.cxx b/chart2/source/view/axes/Tickmarks_Dates.cxx new file mode 100644 index 000000000000..b5177fe307b8 --- /dev/null +++ b/chart2/source/view/axes/Tickmarks_Dates.cxx @@ -0,0 +1,171 @@ +/************************************************************************* + * + * 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 "Tickmarks_Dates.hxx" +#include "DateScaling.hxx" +#include <rtl/math.hxx> +#include <tools/debug.hxx> +#include "DateHelper.hxx" + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::rtl::math; +using ::basegfx::B2DVector; +using ::com::sun::star::chart::TimeUnit::DAY; +using ::com::sun::star::chart::TimeUnit::MONTH; +using ::com::sun::star::chart::TimeUnit::YEAR; + +DateTickFactory::DateTickFactory( + const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement ) + : m_aScale( rScale ) + , m_aIncrement( rIncrement ) + , m_xInverseScaling(NULL) +{ + //@todo: make sure that the scale is valid for the scaling + + if( m_aScale.Scaling.is() ) + { + m_xInverseScaling = m_aScale.Scaling->getInverseScaling(); + DBG_ASSERT( m_xInverseScaling.is(), "each Scaling needs to return a inverse Scaling" ); + } + + m_fScaledVisibleMin = m_aScale.Minimum; + if( m_xInverseScaling.is() ) + m_fScaledVisibleMin = m_aScale.Scaling->doScaling(m_fScaledVisibleMin); + + m_fScaledVisibleMax = m_aScale.Maximum; + if( m_xInverseScaling.is() ) + m_fScaledVisibleMax = m_aScale.Scaling->doScaling(m_fScaledVisibleMax); +} + +DateTickFactory::~DateTickFactory() +{ +} + +void DateTickFactory::getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos, bool bShifted ) const +{ + rAllTickInfos.resize(2); + ::std::vector< TickInfo >& rMajorTicks = rAllTickInfos[0]; + ::std::vector< TickInfo >& rMinorTicks = rAllTickInfos[1]; + rMajorTicks.clear(); + rMinorTicks.clear(); + + Date aNull(m_aScale.NullDate); + + Date aDate = aNull + ::rtl::math::approxFloor(m_aScale.Minimum); + Date aMaxDate = aNull + ::rtl::math::approxFloor(m_aScale.Maximum); + + uno::Reference< chart2::XScaling > xScaling(m_aScale.Scaling); + uno::Reference< chart2::XScaling > xInverseScaling(m_xInverseScaling); + if( bShifted ) + { + xScaling = new DateScaling(aNull,m_aScale.TimeResolution,true/*bShifted*/); + xInverseScaling = xScaling->getInverseScaling(); + } + + //create major date tickinfos + while( aDate<= aMaxDate ) + { + if( bShifted && aDate==aMaxDate ) + break; + + TickInfo aNewTick(xInverseScaling); aNewTick.fScaledTickValue = aDate - aNull; + + if( xInverseScaling.is() ) + aNewTick.fScaledTickValue = xScaling->doScaling(aNewTick.fScaledTickValue); + rMajorTicks.push_back( aNewTick ); + + if(m_aIncrement.MajorTimeInterval.Number<=0) + break; + + //find next major date + switch( m_aIncrement.MajorTimeInterval.TimeUnit ) + { + case DAY: + aDate += m_aIncrement.MajorTimeInterval.Number; + break; + case YEAR: + aDate = DateHelper::GetDateSomeYearsAway( aDate, m_aIncrement.MajorTimeInterval.Number ); + break; + case MONTH: + default: + aDate = DateHelper::GetDateSomeMonthsAway( aDate, m_aIncrement.MajorTimeInterval.Number ); + break; + } + } + + //create minor date tickinfos + aDate = aNull + ::rtl::math::approxFloor(m_aScale.Minimum); + while( aDate<= aMaxDate ) + { + if( bShifted && aDate==aMaxDate ) + break; + + TickInfo aNewTick(xInverseScaling); aNewTick.fScaledTickValue = aDate - aNull; + if( xInverseScaling.is() ) + aNewTick.fScaledTickValue = xScaling->doScaling(aNewTick.fScaledTickValue); + rMinorTicks.push_back( aNewTick ); + + if(m_aIncrement.MinorTimeInterval.Number<=0) + break; + + //find next minor date + switch( m_aIncrement.MinorTimeInterval.TimeUnit ) + { + case DAY: + aDate += m_aIncrement.MinorTimeInterval.Number; + break; + case YEAR: + aDate = DateHelper::GetDateSomeYearsAway( aDate, m_aIncrement.MinorTimeInterval.Number ); + break; + case MONTH: + default: + aDate = DateHelper::GetDateSomeMonthsAway( aDate, m_aIncrement.MinorTimeInterval.Number ); + break; + } + } +} + +void DateTickFactory::getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const +{ + getAllTicks( rAllTickInfos, false ); +} + +void DateTickFactory::getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const +{ + getAllTicks( rAllTickInfos, true ); +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/Tickmarks_Dates.hxx b/chart2/source/view/axes/Tickmarks_Dates.hxx new file mode 100644 index 000000000000..464e8b4ca24c --- /dev/null +++ b/chart2/source/view/axes/Tickmarks_Dates.hxx @@ -0,0 +1,65 @@ +/************************************************************************* + * + * 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_TICKMARKS_DATES_HXX +#define _CHART2_TICKMARKS_DATES_HXX + +#include "Tickmarks.hxx" + +//............................................................................. +namespace chart +{ +//............................................................................. + +class DateTickFactory +{ +public: + DateTickFactory( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ); + ~DateTickFactory(); + + void getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const; + void getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const; + +private: //methods + void getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos, bool bShifted ) const; + +private: //member + ExplicitScaleData m_aScale; + ExplicitIncrementData m_aIncrement; + ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XScaling > + m_xInverseScaling; + + //minimum and maximum of the visible range after scaling + double m_fScaledVisibleMin; + double m_fScaledVisibleMax; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/Tickmarks_Equidistant.cxx b/chart2/source/view/axes/Tickmarks_Equidistant.cxx new file mode 100644 index 000000000000..9344af1ffac9 --- /dev/null +++ b/chart2/source/view/axes/Tickmarks_Equidistant.cxx @@ -0,0 +1,671 @@ +/************************************************************************* + * + * 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 "Tickmarks_Equidistant.hxx" +#include "ViewDefines.hxx" +#include <rtl/math.hxx> +#include <tools/debug.hxx> +#include <memory> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::rtl::math; +using ::basegfx::B2DVector; + +//static +double EquidistantTickFactory::getMinimumAtIncrement( double fMin, const ExplicitIncrementData& rIncrement ) +{ + //the returned value will be <= fMin and on a Major Tick given by rIncrement + if(rIncrement.Distance<=0.0) + return fMin; + + double fRet = rIncrement.BaseValue + + floor( approxSub( fMin, rIncrement.BaseValue ) + / rIncrement.Distance) + *rIncrement.Distance; + + if( fRet > fMin ) + { + if( !approxEqual(fRet, fMin) ) + fRet -= rIncrement.Distance; + } + return fRet; +} +//static +double EquidistantTickFactory::getMaximumAtIncrement( double fMax, const ExplicitIncrementData& rIncrement ) +{ + //the returned value will be >= fMax and on a Major Tick given by rIncrement + if(rIncrement.Distance<=0.0) + return fMax; + + double fRet = rIncrement.BaseValue + + floor( approxSub( fMax, rIncrement.BaseValue ) + / rIncrement.Distance) + *rIncrement.Distance; + + if( fRet < fMax ) + { + if( !approxEqual(fRet, fMax) ) + fRet += rIncrement.Distance; + } + return fRet; +} + +EquidistantTickFactory::EquidistantTickFactory( + const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement ) + : m_rScale( rScale ) + , m_rIncrement( rIncrement ) + , m_xInverseScaling(NULL) + , m_pfCurrentValues(NULL) +{ + //@todo: make sure that the scale is valid for the scaling + + m_pfCurrentValues = new double[getTickDepth()]; + + if( m_rScale.Scaling.is() ) + { + m_xInverseScaling = m_rScale.Scaling->getInverseScaling(); + DBG_ASSERT( m_xInverseScaling.is(), "each Scaling needs to return a inverse Scaling" ); + } + + double fMin = m_fScaledVisibleMin = m_rScale.Minimum; + if( m_xInverseScaling.is() ) + { + m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin); + if(m_rIncrement.PostEquidistant ) + fMin = m_fScaledVisibleMin; + } + + double fMax = m_fScaledVisibleMax = m_rScale.Maximum; + if( m_xInverseScaling.is() ) + { + m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax); + if(m_rIncrement.PostEquidistant ) + fMax = m_fScaledVisibleMax; + } + + //-- + m_fOuterMajorTickBorderMin = EquidistantTickFactory::getMinimumAtIncrement( fMin, m_rIncrement ); + m_fOuterMajorTickBorderMax = EquidistantTickFactory::getMaximumAtIncrement( fMax, m_rIncrement ); + //-- + + m_fOuterMajorTickBorderMin_Scaled = m_fOuterMajorTickBorderMin; + m_fOuterMajorTickBorderMax_Scaled = m_fOuterMajorTickBorderMax; + if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() ) + { + m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin); + m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax); + + //check validity of new range: m_fOuterMajorTickBorderMin <-> m_fOuterMajorTickBorderMax + //it is assumed here, that the original range in the given Scale is valid + if( !rtl::math::isFinite(m_fOuterMajorTickBorderMin_Scaled) ) + { + m_fOuterMajorTickBorderMin += m_rIncrement.Distance; + m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin); + } + if( !rtl::math::isFinite(m_fOuterMajorTickBorderMax_Scaled) ) + { + m_fOuterMajorTickBorderMax -= m_rIncrement.Distance; + m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax); + } + } +} + +EquidistantTickFactory::~EquidistantTickFactory() +{ + delete[] m_pfCurrentValues; +} + +sal_Int32 EquidistantTickFactory::getTickDepth() const +{ + return static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) + 1; +} + +void EquidistantTickFactory::addSubTicks( sal_Int32 nDepth, uno::Sequence< uno::Sequence< double > >& rParentTicks ) const +{ + EquidistantTickIter aIter( rParentTicks, m_rIncrement, 0, nDepth-1 ); + double* pfNextParentTick = aIter.firstValue(); + if(!pfNextParentTick) + return; + double fLastParentTick = *pfNextParentTick; + pfNextParentTick = aIter.nextValue(); + if(!pfNextParentTick) + return; + + sal_Int32 nMaxSubTickCount = this->getMaxTickCount( nDepth ); + if(!nMaxSubTickCount) + return; + + uno::Sequence< double > aSubTicks(nMaxSubTickCount); + sal_Int32 nRealSubTickCount = 0; + sal_Int32 nIntervalCount = m_rIncrement.SubIncrements[nDepth-1].IntervalCount; + + double* pValue = NULL; + for(; pfNextParentTick; fLastParentTick=*pfNextParentTick, pfNextParentTick = aIter.nextValue()) + { + for( sal_Int32 nPartTick = 1; nPartTick<nIntervalCount; nPartTick++ ) + { + pValue = this->getMinorTick( nPartTick, nDepth + , fLastParentTick, *pfNextParentTick ); + if(!pValue) + continue; + + aSubTicks[nRealSubTickCount] = *pValue; + nRealSubTickCount++; + } + } + + aSubTicks.realloc(nRealSubTickCount); + rParentTicks[nDepth] = aSubTicks; + if(static_cast<sal_Int32>(m_rIncrement.SubIncrements.size())>nDepth) + addSubTicks( nDepth+1, rParentTicks ); +} + + +sal_Int32 EquidistantTickFactory::getMaxTickCount( sal_Int32 nDepth ) const +{ + //return the maximum amount of ticks + //possibly open intervals at the two ends of the region are handled as if they were completely visible + //(this is necessary for calculating the sub ticks at the borders correctly) + + if( nDepth >= getTickDepth() ) + return 0; + if( m_fOuterMajorTickBorderMax < m_fOuterMajorTickBorderMin ) + return 0; + if( m_rIncrement.Distance<=0.0) + return 0; + + double fSub; + if(m_rIncrement.PostEquidistant ) + fSub = approxSub( m_fScaledVisibleMax, m_fScaledVisibleMin ); + else + fSub = approxSub( m_rScale.Maximum, m_rScale.Minimum ); + + if (!isFinite(fSub)) + return 0; + + sal_Int32 nIntervalCount = static_cast<sal_Int32>( fSub / m_rIncrement.Distance ); + + nIntervalCount+=3; + for(sal_Int32 nN=0; nN<nDepth-1; nN++) + { + if( m_rIncrement.SubIncrements[nN].IntervalCount>1 ) + nIntervalCount *= m_rIncrement.SubIncrements[nN].IntervalCount; + } + + sal_Int32 nTickCount = nIntervalCount; + if(nDepth>0 && m_rIncrement.SubIncrements[nDepth-1].IntervalCount>1) + nTickCount = nIntervalCount * (m_rIncrement.SubIncrements[nDepth-1].IntervalCount-1); + + return nTickCount; +} + +double* EquidistantTickFactory::getMajorTick( sal_Int32 nTick ) const +{ + m_pfCurrentValues[0] = m_fOuterMajorTickBorderMin + nTick*m_rIncrement.Distance; + + if(m_pfCurrentValues[0]>m_fOuterMajorTickBorderMax) + { + if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMax) ) + return NULL; + } + if(m_pfCurrentValues[0]<m_fOuterMajorTickBorderMin) + { + if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMin) ) + return NULL; + } + + //return always the value after scaling + if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() ) + m_pfCurrentValues[0] = m_rScale.Scaling->doScaling( m_pfCurrentValues[0] ); + + return &m_pfCurrentValues[0]; +} + +double* EquidistantTickFactory::getMinorTick( sal_Int32 nTick, sal_Int32 nDepth + , double fStartParentTick, double fNextParentTick ) const +{ + //check validity of arguments + { + //DBG_ASSERT( fStartParentTick < fNextParentTick, "fStartParentTick >= fNextParentTick"); + if(fStartParentTick >= fNextParentTick) + return NULL; + if(nDepth>static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) || nDepth<=0) + return NULL; + + //subticks are only calculated if they are laying between parent ticks: + if(nTick<=0) + return NULL; + if(nTick>=m_rIncrement.SubIncrements[nDepth-1].IntervalCount) + return NULL; + } + + bool bPostEquidistant = m_rIncrement.SubIncrements[nDepth-1].PostEquidistant; + + double fAdaptedStartParent = fStartParentTick; + double fAdaptedNextParent = fNextParentTick; + + if( !bPostEquidistant && m_xInverseScaling.is() ) + { + fAdaptedStartParent = m_xInverseScaling->doScaling(fStartParentTick); + fAdaptedNextParent = m_xInverseScaling->doScaling(fNextParentTick); + } + + double fDistance = (fAdaptedNextParent - fAdaptedStartParent)/m_rIncrement.SubIncrements[nDepth-1].IntervalCount; + + m_pfCurrentValues[nDepth] = fAdaptedStartParent + nTick*fDistance; + + //return always the value after scaling + if(!bPostEquidistant && m_xInverseScaling.is() ) + m_pfCurrentValues[nDepth] = m_rScale.Scaling->doScaling( m_pfCurrentValues[nDepth] ); + + if( !isWithinOuterBorder( m_pfCurrentValues[nDepth] ) ) + return NULL; + + return &m_pfCurrentValues[nDepth]; +} + +bool EquidistantTickFactory::isWithinOuterBorder( double fScaledValue ) const +{ + if(fScaledValue>m_fOuterMajorTickBorderMax_Scaled) + return false; + if(fScaledValue<m_fOuterMajorTickBorderMin_Scaled) + return false; + + return true; +} + +bool EquidistantTickFactory::isVisible( double fScaledValue ) const +{ + if(fScaledValue>m_fScaledVisibleMax) + { + if( !approxEqual(fScaledValue,m_fScaledVisibleMax) ) + return false; + } + if(fScaledValue<m_fScaledVisibleMin) + { + if( !approxEqual(fScaledValue,m_fScaledVisibleMin) ) + return false; + } + return true; +} + +void EquidistantTickFactory::getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const +{ + uno::Sequence< uno::Sequence< double > > aAllTicks; + + //create point sequences for each tick depth + sal_Int32 nDepthCount = this->getTickDepth(); + sal_Int32 nMaxMajorTickCount = this->getMaxTickCount( 0 ); + + aAllTicks.realloc(nDepthCount); + aAllTicks[0].realloc(nMaxMajorTickCount); + + sal_Int32 nRealMajorTickCount = 0; + double* pValue = NULL; + for( sal_Int32 nMajorTick=0; nMajorTick<nMaxMajorTickCount; nMajorTick++ ) + { + pValue = this->getMajorTick( nMajorTick ); + if(!pValue) + continue; + aAllTicks[0][nRealMajorTickCount] = *pValue; + nRealMajorTickCount++; + } + if(!nRealMajorTickCount) + return; + aAllTicks[0].realloc(nRealMajorTickCount); + + if(nDepthCount>0) + this->addSubTicks( 1, aAllTicks ); + + //so far we have added all ticks between the outer major tick marks + //this was necessary to create sub ticks correctly + //now we reduce all ticks to the visible ones that lie between the real borders + sal_Int32 nDepth = 0; + sal_Int32 nTick = 0; + for( nDepth = 0; nDepth < nDepthCount; nDepth++) + { + sal_Int32 nInvisibleAtLowerBorder = 0; + sal_Int32 nInvisibleAtUpperBorder = 0; + //we need only to check all ticks within the first major interval at each border + sal_Int32 nCheckCount = 1; + for(sal_Int32 nN=0; nN<nDepth; nN++) + { + if( m_rIncrement.SubIncrements[nN].IntervalCount>1 ) + nCheckCount *= m_rIncrement.SubIncrements[nN].IntervalCount; + } + uno::Sequence< double >& rTicks = aAllTicks[nDepth]; + sal_Int32 nCount = rTicks.getLength(); + //check lower border + for( nTick=0; nTick<nCheckCount && nTick<nCount; nTick++) + { + if( !isVisible( rTicks[nTick] ) ) + nInvisibleAtLowerBorder++; + } + //check upper border + for( nTick=nCount-1; nTick>nCount-1-nCheckCount && nTick>=0; nTick--) + { + if( !isVisible( rTicks[nTick] ) ) + nInvisibleAtUpperBorder++; + } + //resize sequence + if( !nInvisibleAtLowerBorder && !nInvisibleAtUpperBorder) + continue; + if( !nInvisibleAtLowerBorder ) + rTicks.realloc(nCount-nInvisibleAtUpperBorder); + else + { + sal_Int32 nNewCount = nCount-nInvisibleAtUpperBorder-nInvisibleAtLowerBorder; + if(nNewCount<0) + nNewCount=0; + + uno::Sequence< double > aOldTicks(rTicks); + rTicks.realloc(nNewCount); + for(nTick = 0; nTick<nNewCount; nTick++) + rTicks[nTick] = aOldTicks[nInvisibleAtLowerBorder+nTick]; + } + } + + //fill return value + rAllTickInfos.resize(aAllTicks.getLength()); + for( nDepth=0 ;nDepth<aAllTicks.getLength(); nDepth++ ) + { + sal_Int32 nCount = aAllTicks[nDepth].getLength(); + + ::std::vector< TickInfo >& rTickInfoVector = rAllTickInfos[nDepth]; + rTickInfoVector.clear(); + rTickInfoVector.reserve( nCount ); + for(sal_Int32 nN = 0; nN<nCount; nN++) + { + TickInfo aTickInfo(m_xInverseScaling); + aTickInfo.fScaledTickValue = aAllTicks[nDepth][nN]; + rTickInfoVector.push_back(aTickInfo); + } + } +} + +void EquidistantTickFactory::getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const +{ + ExplicitIncrementData aShiftedIncrement( m_rIncrement ); + aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0; + EquidistantTickFactory( m_rScale, aShiftedIncrement ).getAllTicks(rAllTickInfos); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +EquidistantTickIter::EquidistantTickIter( const uno::Sequence< uno::Sequence< double > >& rTicks + , const ExplicitIncrementData& rIncrement + , sal_Int32 nMinDepth, sal_Int32 nMaxDepth ) + : m_pSimpleTicks(&rTicks) + , m_pInfoTicks(0) + , m_rIncrement(rIncrement) + , m_nMinDepth(0), m_nMaxDepth(0) + , m_nTickCount(0), m_pnPositions(NULL) + , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL) + , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 ) +{ + initIter( nMinDepth, nMaxDepth ); +} + +EquidistantTickIter::EquidistantTickIter( ::std::vector< ::std::vector< TickInfo > >& rTicks + , const ExplicitIncrementData& rIncrement + , sal_Int32 nMinDepth, sal_Int32 nMaxDepth ) + : m_pSimpleTicks(NULL) + , m_pInfoTicks(&rTicks) + , m_rIncrement(rIncrement) + , m_nMinDepth(0), m_nMaxDepth(0) + , m_nTickCount(0), m_pnPositions(NULL) + , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL) + , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 ) +{ + initIter( nMinDepth, nMaxDepth ); +} + +void EquidistantTickIter::initIter( sal_Int32 /*nMinDepth*/, sal_Int32 nMaxDepth ) +{ + m_nMaxDepth = nMaxDepth; + if(nMaxDepth<0 || m_nMaxDepth>getMaxDepth()) + m_nMaxDepth=getMaxDepth(); + + sal_Int32 nDepth = 0; + for( nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ ) + m_nTickCount += getTickCount(nDepth); + + if(!m_nTickCount) + return; + + m_pnPositions = new sal_Int32[m_nMaxDepth+1]; + + m_pnPreParentCount = new sal_Int32[m_nMaxDepth+1]; + m_pbIntervalFinished = new bool[m_nMaxDepth+1]; + m_pnPreParentCount[0] = 0; + m_pbIntervalFinished[0] = false; + double fParentValue = getTickValue(0,0); + for( nDepth = 1; nDepth<=m_nMaxDepth ;nDepth++ ) + { + m_pbIntervalFinished[nDepth] = false; + + sal_Int32 nPreParentCount = 0; + sal_Int32 nCount = getTickCount(nDepth); + for(sal_Int32 nN = 0; nN<nCount; nN++) + { + if(getTickValue(nDepth,nN) < fParentValue) + nPreParentCount++; + else + break; + } + m_pnPreParentCount[nDepth] = nPreParentCount; + if(nCount) + { + double fNextParentValue = getTickValue(nDepth,0); + if( fNextParentValue < fParentValue ) + fParentValue = fNextParentValue; + } + } +} + +EquidistantTickIter::~EquidistantTickIter() +{ + delete[] m_pnPositions; + delete[] m_pnPreParentCount; + delete[] m_pbIntervalFinished; +} + +sal_Int32 EquidistantTickIter::getStartDepth() const +{ + //find the depth of the first visible tickmark: + //it is the depth of the smallest value + sal_Int32 nReturnDepth=0; + double fMinValue = DBL_MAX; + for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ ) + { + sal_Int32 nCount = getTickCount(nDepth); + if( !nCount ) + continue; + double fThisValue = getTickValue(nDepth,0); + if(fThisValue<fMinValue) + { + nReturnDepth = nDepth; + fMinValue = fThisValue; + } + } + return nReturnDepth; +} + +double* EquidistantTickIter::firstValue() +{ + if( gotoFirst() ) + { + m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]); + return &m_fCurrentValue; + } + return NULL; +} + +TickInfo* EquidistantTickIter::firstInfo() +{ + if( m_pInfoTicks && gotoFirst() ) + return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]]; + return NULL; +} + +sal_Int32 EquidistantTickIter::getIntervalCount( sal_Int32 nDepth ) +{ + if(nDepth>static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) || nDepth<0) + return 0; + + if(!nDepth) + return m_nTickCount; + + return m_rIncrement.SubIncrements[nDepth-1].IntervalCount; +} + +bool EquidistantTickIter::isAtLastPartTick() +{ + if(!m_nCurrentDepth) + return false; + sal_Int32 nIntervalCount = getIntervalCount( m_nCurrentDepth ); + if(!nIntervalCount || nIntervalCount == 1) + return true; + if( m_pbIntervalFinished[m_nCurrentDepth] ) + return false; + sal_Int32 nPos = m_pnPositions[m_nCurrentDepth]+1; + if(m_pnPreParentCount[m_nCurrentDepth]) + nPos += nIntervalCount-1 - m_pnPreParentCount[m_nCurrentDepth]; + bool bRet = nPos && nPos % (nIntervalCount-1) == 0; + if(!nPos && !m_pnPreParentCount[m_nCurrentDepth] + && m_pnPositions[m_nCurrentDepth-1]==-1 ) + bRet = true; + return bRet; +} + +bool EquidistantTickIter::gotoFirst() +{ + if( m_nMaxDepth<0 ) + return false; + if( !m_nTickCount ) + return false; + + for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ ) + m_pnPositions[nDepth] = -1; + + m_nCurrentPos = 0; + m_nCurrentDepth = getStartDepth(); + m_pnPositions[m_nCurrentDepth] = 0; + return true; +} + +bool EquidistantTickIter::gotoNext() +{ + if( m_nCurrentPos < 0 ) + return false; + m_nCurrentPos++; + + if( m_nCurrentPos >= m_nTickCount ) + return false; + + if( m_nCurrentDepth==m_nMaxDepth && isAtLastPartTick() ) + { + do + { + m_pbIntervalFinished[m_nCurrentDepth] = true; + m_nCurrentDepth--; + } + while( m_nCurrentDepth && isAtLastPartTick() ); + } + else if( m_nCurrentDepth<m_nMaxDepth ) + { + do + { + m_nCurrentDepth++; + } + while( m_nCurrentDepth<m_nMaxDepth ); + } + m_pbIntervalFinished[m_nCurrentDepth] = false; + m_pnPositions[m_nCurrentDepth] = m_pnPositions[m_nCurrentDepth]+1; + return true; +} + +bool EquidistantTickIter::gotoIndex( sal_Int32 nTickIndex ) +{ + if( nTickIndex < 0 ) + return false; + if( nTickIndex >= m_nTickCount ) + return false; + + if( nTickIndex < m_nCurrentPos ) + if( !gotoFirst() ) + return false; + + while( nTickIndex > m_nCurrentPos ) + if( !gotoNext() ) + return false; + + return true; +} + +sal_Int32 EquidistantTickIter::getCurrentIndex() const +{ + return m_nCurrentPos; +} +sal_Int32 EquidistantTickIter::getMaxIndex() const +{ + return m_nTickCount-1; +} + +double* EquidistantTickIter::nextValue() +{ + if( gotoNext() ) + { + m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]); + return &m_fCurrentValue; + } + return NULL; +} + +TickInfo* EquidistantTickIter::nextInfo() +{ + if( m_pInfoTicks && gotoNext() && + static_cast< sal_Int32 >( + (*m_pInfoTicks)[m_nCurrentDepth].size()) > m_pnPositions[m_nCurrentDepth] ) + { + return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]]; + } + return NULL; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/Tickmarks_Equidistant.hxx b/chart2/source/view/axes/Tickmarks_Equidistant.hxx new file mode 100644 index 000000000000..836a93d28db2 --- /dev/null +++ b/chart2/source/view/axes/Tickmarks_Equidistant.hxx @@ -0,0 +1,166 @@ +/************************************************************************* + * + * 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_TICKMARKS_EQUIDISTANT_HXX +#define _CHART2_TICKMARKS_EQUIDISTANT_HXX + +#include "Tickmarks.hxx" + +//............................................................................. +namespace chart +{ +//............................................................................. + +using ::basegfx::B2DVector; +//----------------------------------------------------------------------------- +/** +*/ + +class EquidistantTickIter : public TickIter +{ +public: + EquidistantTickIter( const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Sequence< double > >& rTicks + , const ExplicitIncrementData& rIncrement + , sal_Int32 nMinDepth=0, sal_Int32 nMaxDepth=-1 ); + EquidistantTickIter( ::std::vector< ::std::vector< TickInfo > >& rTickInfos + , const ExplicitIncrementData& rIncrement + , sal_Int32 nMinDepth=0, sal_Int32 nMaxDepth=-1 ); + virtual ~EquidistantTickIter(); + + virtual double* firstValue(); + virtual double* nextValue(); + + virtual TickInfo* firstInfo(); + virtual TickInfo* nextInfo(); + + sal_Int32 getCurrentDepth() const { return m_nCurrentDepth; } + +protected: + bool gotoIndex( sal_Int32 nTickIndex ); + sal_Int32 getCurrentIndex() const; + sal_Int32 getMaxIndex() const; + +private: //methods + sal_Int32 getIntervalCount( sal_Int32 nDepth ); + bool isAtLastPartTick(); + + void initIter( sal_Int32 nMinDepth, sal_Int32 nMaxDepth ); + sal_Int32 getStartDepth() const; + + bool gotoFirst(); + bool gotoNext(); + + + double getTickValue(sal_Int32 nDepth, sal_Int32 nIndex) const + { + if(m_pSimpleTicks) + return (*m_pSimpleTicks)[nDepth][nIndex]; + else + return (((*m_pInfoTicks)[nDepth])[nIndex]).fScaledTickValue; + } + sal_Int32 getTickCount( sal_Int32 nDepth ) const + { + if(m_pSimpleTicks) + return (*m_pSimpleTicks)[nDepth].getLength(); + else + return (*m_pInfoTicks)[nDepth].size(); + } + sal_Int32 getMaxDepth() const + { + if(m_pSimpleTicks) + return (*m_pSimpleTicks).getLength()-1; + else + return (*m_pInfoTicks).size()-1; + } + +private: //member + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Sequence< double > >* m_pSimpleTicks; + ::std::vector< ::std::vector< TickInfo > >* m_pInfoTicks; + const ExplicitIncrementData& m_rIncrement; + //iteration from m_nMinDepth to m_nMaxDepth + sal_Int32 m_nMinDepth; + sal_Int32 m_nMaxDepth; + sal_Int32 m_nTickCount; + sal_Int32* m_pnPositions; //current positions in the different sequences + sal_Int32* m_pnPreParentCount; //the tickmarks do not start with a major tick always, + //the PreParentCount states for each depth how many subtickmarks are available in front of the first parent tickmark + bool* m_pbIntervalFinished; + sal_Int32 m_nCurrentDepth; + sal_Int32 m_nCurrentPos; + double m_fCurrentValue; +}; + +class EquidistantTickFactory +{ +public: + EquidistantTickFactory( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ); + ~EquidistantTickFactory(); + + void getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const; + void getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const; + + static double getMinimumAtIncrement( double fMin, const ExplicitIncrementData& rIncrement ); + static double getMaximumAtIncrement( double fMax, const ExplicitIncrementData& rIncrement ); + +private: //methods + void addSubTicks( sal_Int32 nDepth, + ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Sequence< double > >& rParentTicks ) const; + double* getMajorTick( sal_Int32 nTick ) const; + double* getMinorTick( sal_Int32 nTick, sal_Int32 nDepth + , double fStartParentTick, double fNextParentTick ) const; + sal_Int32 getMaxTickCount( sal_Int32 nDepth = 0 ) const; + sal_Int32 getTickDepth() const; + + bool isVisible( double fValue ) const; + bool isWithinOuterBorder( double fScaledValue ) const; //all within the outer major tick marks + +private: //member + ExplicitScaleData m_rScale; + ExplicitIncrementData m_rIncrement; + ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XScaling > + m_xInverseScaling; + + //minimum and maximum of the visible range after scaling + double m_fScaledVisibleMin; + double m_fScaledVisibleMax; + + double* m_pfCurrentValues; + //major-tick positions that may lay outside the visible range but complete partly visible intervals at the borders + double m_fOuterMajorTickBorderMin; + double m_fOuterMajorTickBorderMax; + double m_fOuterMajorTickBorderMin_Scaled; + double m_fOuterMajorTickBorderMax_Scaled; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/VAxisBase.cxx b/chart2/source/view/axes/VAxisBase.cxx new file mode 100644 index 000000000000..fb193ec93a95 --- /dev/null +++ b/chart2/source/view/axes/VAxisBase.cxx @@ -0,0 +1,265 @@ +/************************************************************************* + * + * 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 "VAxisBase.hxx" +#include "ShapeFactory.hxx" +#include "CommonConverters.hxx" +#include "Tickmarks.hxx" +#include "macros.hxx" + +// header for define DBG_ASSERT +#include <tools/debug.hxx> + +#include <memory> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +VAxisBase::VAxisBase( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , const AxisProperties& rAxisProperties + , const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier ) + : VAxisOrGridBase( nDimensionIndex, nDimensionCount ) + , m_xNumberFormatsSupplier( xNumberFormatsSupplier ) + , m_aAxisProperties( rAxisProperties ) + , m_bUseTextLabels( false ) + , m_bReCreateAllTickInfos( true ) + , m_bRecordMaximumTextSize(false) + , m_nMaximumTextWidthSoFar(0) + , m_nMaximumTextHeightSoFar(0) +{ +} + +VAxisBase::~VAxisBase() +{ +} + +sal_Int32 VAxisBase::getDimensionCount() +{ + return m_nDimension; +} + +void VAxisBase::initAxisLabelProperties( const ::com::sun::star::awt::Size& rFontReferenceSize + , const ::com::sun::star::awt::Rectangle& rMaximumSpaceForLabels ) +{ + m_aAxisLabelProperties.m_aFontReferenceSize = rFontReferenceSize; + m_aAxisLabelProperties.m_aMaximumSpaceForLabels = rMaximumSpaceForLabels; + + if( !m_aAxisProperties.m_bDisplayLabels ) + return; + + if( AxisType::SERIES==m_aAxisProperties.m_nAxisType ) + { + if( m_aAxisProperties.m_xAxisTextProvider.is() ) + m_aTextLabels = m_aAxisProperties.m_xAxisTextProvider->getTextualData(); + + m_bUseTextLabels = true; + if( m_aTextLabels.getLength() == 1 ) + { + //don't show a single series name + m_aAxisProperties.m_bDisplayLabels = false; + return; + } + } + else if( AxisType::CATEGORY==m_aAxisProperties.m_nAxisType ) + { + if( m_aAxisProperties.m_pExplicitCategoriesProvider ) + m_aTextLabels = m_aAxisProperties.m_pExplicitCategoriesProvider->getSimpleCategories(); + + m_bUseTextLabels = true; + } + + m_aAxisLabelProperties.nNumberFormatKey = m_aAxisProperties.m_nNumberFormatKey; + m_aAxisLabelProperties.init(m_aAxisProperties.m_xAxisModel); + if( m_aAxisProperties.m_bComplexCategories && AxisType::CATEGORY == m_aAxisProperties.m_nAxisType ) + m_aAxisLabelProperties.eStaggering = SIDE_BY_SIDE; +} + +bool VAxisBase::isDateAxis() const +{ + return AxisType::DATE == m_aScale.AxisType; +} +bool VAxisBase::isComplexCategoryAxis() const +{ + return m_aAxisProperties.m_bComplexCategories && m_bUseTextLabels; +} + +void VAxisBase::recordMaximumTextSize( const Reference< drawing::XShape >& xShape, double fRotationAngleDegree ) +{ + if( m_bRecordMaximumTextSize && xShape.is() ) + { + awt::Size aSize( ShapeFactory::getSizeAfterRotation( + xShape, fRotationAngleDegree ) ); + + m_nMaximumTextWidthSoFar = std::max( m_nMaximumTextWidthSoFar, aSize.Width ); + m_nMaximumTextHeightSoFar = std::max( m_nMaximumTextHeightSoFar, aSize.Height ); + } +} + +sal_Int32 VAxisBase::estimateMaximumAutoMainIncrementCount() +{ + return 10; +} + +void VAxisBase::setExrtaLinePositionAtOtherAxis( const double& fCrossingAt ) +{ + if( m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis ) + delete m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis; + m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis = new double(fCrossingAt); +} + +sal_Bool VAxisBase::isAnythingToDraw() +{ + if( !m_aAxisProperties.m_xAxisModel.is() ) + return false; + + DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"Axis is not proper initialized"); + if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is())) + return false; + + uno::Reference< beans::XPropertySet > xProps( m_aAxisProperties.m_xAxisModel, uno::UNO_QUERY ); + if( xProps.is() ) + { + sal_Bool bShow = sal_False; + xProps->getPropertyValue( C2U( "Show" ) ) >>= bShow; + if( !bShow ) + return false; + } + return true; +} + +void VAxisBase::setExplicitScaleAndIncrement( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ) + throw (uno::RuntimeException) +{ + m_bReCreateAllTickInfos = true; + m_aScale = rScale; + m_aIncrement = rIncrement; +} + +void VAxisBase::createAllTickInfos( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) +{ + std::auto_ptr< TickFactory > apTickFactory( this->createTickFactory() ); + if( m_aScale.ShiftedCategoryPosition ) + apTickFactory->getAllTicksShifted( rAllTickInfos ); + else + apTickFactory->getAllTicks( rAllTickInfos ); +} + +bool VAxisBase::prepareShapeCreation() +{ + //returns true if all is ready for further shape creation and any shapes need to be created + if( !isAnythingToDraw() ) + return false; + + if( m_bReCreateAllTickInfos ) + { + //----------------------------------------- + //create all scaled tickmark values + removeTextShapesFromTicks(); + + createAllTickInfos(m_aAllTickInfos); + m_bReCreateAllTickInfos = false; + } + + if( m_xGroupShape_Shapes.is() ) + return true; + + //----------------------------------------- + //create named group shape + m_xGroupShape_Shapes = this->createGroupShape( m_xLogicTarget, m_nDimension==2 ? m_aCID : C2U("")); + + if( m_aAxisProperties.m_bDisplayLabels ) + m_xTextTarget = m_pShapeFactory->createGroup2D( m_xFinalTarget, m_aCID ); + + return true; +} + +sal_Int32 VAxisBase::getIndexOfLongestLabel( const uno::Sequence< rtl::OUString >& rLabels ) +{ + sal_Int32 nRet = 0; + sal_Int32 nLength = 0; + sal_Int32 nN = 0; + for( nN=0; nN<rLabels.getLength(); nN++ ) + { + //todo: get real text width (without creating shape) instead of character count + if( rLabels[nN].getLength() > nLength ) + { + nLength = rLabels[nN].getLength(); + nRet = nN; + } + } + return nRet; +} + +void VAxisBase::removeTextShapesFromTicks() +{ + if( m_xTextTarget.is() ) + { + ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter = m_aAllTickInfos.begin(); + const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd = m_aAllTickInfos.end(); + for( ; aDepthIter != aDepthEnd; aDepthIter++ ) + { + ::std::vector< TickInfo >::iterator aTickIter = (*aDepthIter).begin(); + const ::std::vector< TickInfo >::const_iterator aTickEnd = (*aDepthIter).end(); + for( ; aTickIter != aTickEnd; aTickIter++ ) + { + TickInfo& rTickInfo = (*aTickIter); + if(rTickInfo.xTextShape.is()) + { + m_xTextTarget->remove(rTickInfo.xTextShape); + rTickInfo.xTextShape = NULL; + } + } + } + } +} + +void VAxisBase::updateUnscaledValuesAtTicks( TickIter& rIter ) +{ + Reference< XScaling > xInverseScaling( NULL ); + if( m_aScale.Scaling.is() ) + xInverseScaling = m_aScale.Scaling->getInverseScaling(); + + for( TickInfo* pTickInfo = rIter.firstInfo() + ; pTickInfo; pTickInfo = rIter.nextInfo() ) + { + //xxxxx pTickInfo->updateUnscaledValue( xInverseScaling ); + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/VAxisBase.hxx b/chart2/source/view/axes/VAxisBase.hxx new file mode 100644 index 000000000000..e51e2d8dbd9b --- /dev/null +++ b/chart2/source/view/axes/VAxisBase.hxx @@ -0,0 +1,110 @@ +/************************************************************************* + * + * 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_VAXISBASE_HXX +#define _CHART2_VAXISBASE_HXX + +#include "VAxisOrGridBase.hxx" +#include "VAxisProperties.hxx" +#include "Tickmarks.hxx" +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +class VAxisBase : public VAxisOrGridBase +{ +public: + VAxisBase( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , const AxisProperties& rAxisProperties + , const ::com::sun::star::uno::Reference< + ::com::sun::star::util::XNumberFormatsSupplier >& xNumberFormatsSupplier ); + virtual ~VAxisBase(); + + sal_Int32 getDimensionCount(); + + virtual void createMaximumLabels()=0; + virtual void createLabels()=0; + virtual void updatePositions()=0; + + virtual sal_Bool isAnythingToDraw(); + virtual void initAxisLabelProperties( + const ::com::sun::star::awt::Size& rFontReferenceSize + , const ::com::sun::star::awt::Rectangle& rMaximumSpaceForLabels ); + + virtual void setExplicitScaleAndIncrement( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ) + throw (::com::sun::star::uno::RuntimeException); + + virtual sal_Int32 estimateMaximumAutoMainIncrementCount(); + virtual void createAllTickInfos( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ); + + void setExrtaLinePositionAtOtherAxis( const double& fCrossingAt ); + + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- +protected: //methods + sal_Int32 getIndexOfLongestLabel( const ::com::sun::star::uno::Sequence< rtl::OUString >& rLabels ); + void removeTextShapesFromTicks(); + void updateUnscaledValuesAtTicks( TickIter& rIter ); + + virtual bool prepareShapeCreation(); + void recordMaximumTextSize( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShape >& xShape + , double fRotationAngleDegree ); + + bool isDateAxis() const; + bool isComplexCategoryAxis() const; + +protected: //member + ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier > m_xNumberFormatsSupplier; + AxisProperties m_aAxisProperties; + AxisLabelProperties m_aAxisLabelProperties; + ::com::sun::star::uno::Sequence< rtl::OUString > m_aTextLabels; + bool m_bUseTextLabels; + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > m_xGroupShape_Shapes; + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > m_xTextTarget; + + ::std::vector< ::std::vector< TickInfo > > m_aAllTickInfos; + bool m_bReCreateAllTickInfos; + + bool m_bRecordMaximumTextSize; + sal_Int32 m_nMaximumTextWidthSoFar; + sal_Int32 m_nMaximumTextHeightSoFar; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/VAxisOrGridBase.cxx b/chart2/source/view/axes/VAxisOrGridBase.cxx new file mode 100644 index 000000000000..715da4972390 --- /dev/null +++ b/chart2/source/view/axes/VAxisOrGridBase.cxx @@ -0,0 +1,89 @@ +/************************************************************************* + * + * 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 "VAxisOrGridBase.hxx" +#include "ShapeFactory.hxx" +#include "CommonConverters.hxx" +#include "Tickmarks.hxx" + +// header for define DBG_ASSERT +#include <tools/debug.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +VAxisOrGridBase::VAxisOrGridBase( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount ) + : PlotterBase( nDimensionCount ) + , m_nDimensionIndex( nDimensionIndex ) + , m_eLeftWallPos(CuboidPlanePosition_Left) + , m_eBackWallPos(CuboidPlanePosition_Back) + , m_eBottomPos(CuboidPlanePosition_Bottom) +{ +} + +VAxisOrGridBase::~VAxisOrGridBase() +{ +} + +void VAxisOrGridBase::setExplicitScaleAndIncrement( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ) + throw (uno::RuntimeException) +{ + m_aScale = rScale; + m_aIncrement = rIncrement; +} + +void VAxisOrGridBase::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix ) +{ + m_aMatrixScreenToScene = HomogenMatrixToB3DHomMatrix(rMatrix); + PlotterBase::setTransformationSceneToScreen( rMatrix); +} + +void VAxisOrGridBase::set3DWallPositions( CuboidPlanePosition eLeftWallPos, CuboidPlanePosition eBackWallPos, CuboidPlanePosition eBottomPos ) +{ + m_eLeftWallPos = eLeftWallPos; + m_eBackWallPos = eBackWallPos; + m_eBottomPos = eBottomPos; +} + +TickFactory* VAxisOrGridBase::createTickFactory() +{ + return new TickFactory( m_aScale, m_aIncrement ); +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/VAxisOrGridBase.hxx b/chart2/source/view/axes/VAxisOrGridBase.hxx new file mode 100644 index 000000000000..9091aabf0dc5 --- /dev/null +++ b/chart2/source/view/axes/VAxisOrGridBase.hxx @@ -0,0 +1,82 @@ +/************************************************************************* + * + * 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_VAXISORGRIDBASE_HXX +#define _CHART2_VAXISORGRIDBASE_HXX + +#include "PlotterBase.hxx" +#include "ThreeDHelper.hxx" +#include "chartview/ExplicitScaleValues.hxx" + +#include <com/sun/star/drawing/HomogenMatrix.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <basegfx/matrix/b3dhommatrix.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ +class ShapeFactory; +class TickFactory; + +class VAxisOrGridBase : public PlotterBase +{ +public: + VAxisOrGridBase( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount ); + virtual ~VAxisOrGridBase(); + + virtual void setTransformationSceneToScreen( const ::com::sun::star::drawing::HomogenMatrix& rMatrix ); + virtual void setExplicitScaleAndIncrement( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ) + throw (::com::sun::star::uno::RuntimeException); + void set3DWallPositions( CuboidPlanePosition eLeftWallPos, CuboidPlanePosition eBackWallPos, CuboidPlanePosition eBottomPos ); + + virtual TickFactory* createTickFactory(); + + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- +protected: //member + ExplicitScaleData m_aScale; + ExplicitIncrementData m_aIncrement; + sal_Int32 m_nDimensionIndex; + + ::basegfx::B3DHomMatrix m_aMatrixScreenToScene; + + CuboidPlanePosition m_eLeftWallPos; + CuboidPlanePosition m_eBackWallPos; + CuboidPlanePosition m_eBottomPos; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/VAxisProperties.cxx b/chart2/source/view/axes/VAxisProperties.cxx new file mode 100644 index 000000000000..9f710d926e0c --- /dev/null +++ b/chart2/source/view/axes/VAxisProperties.cxx @@ -0,0 +1,484 @@ +/************************************************************************* + * + * 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 "VAxisProperties.hxx" +#include "macros.hxx" +#include "ViewDefines.hxx" +#include "CommonConverters.hxx" +#include "AxisHelper.hxx" +#include "DiagramHelper.hxx" +#include "ChartModelHelper.hxx" + +#include <tools/color.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/chart/ChartAxisArrangeOrderType.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/text/WritingMode2.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +sal_Int32 lcl_calcTickLengthForDepth(sal_Int32 nDepth,sal_Int32 nTickmarkStyle) +{ + sal_Int32 nWidth = AXIS2D_TICKLENGTH; //@maybefuturetodo this length could be offered by the model + double fPercent = 1.0; + switch(nDepth) + { + case 0: + fPercent = 1.0; + break; + case 1: + fPercent = 0.75;//percentage like in the old chart + break; + case 2: + fPercent = 0.5; + break; + default: + fPercent = 0.3; + break; + } + if(nTickmarkStyle==3)//inner and outer tickmarks + fPercent*=2.0; + return static_cast<sal_Int32>(nWidth*fPercent); +} + +double lcl_getTickOffset(sal_Int32 nLength,sal_Int32 nTickmarkStyle) +{ + double fPercent = 0.0; //0<=fPercent<=1 + //0.0: completly inner + //1.0: completly outer + //0.5: half and half + + /* + nTickmarkStyle: + 1: inner tickmarks + 2: outer tickmarks + 3: inner and outer tickmarks + */ + switch(nTickmarkStyle) + { + case 1: + fPercent = 0.0; + break; + case 2: + fPercent = 1.0; + break; + default: + fPercent = 0.5; + break; + } + return fPercent*nLength; +} + +VLineProperties AxisProperties::makeLinePropertiesForDepth( sal_Int32 /* nDepth */ ) const +{ + //@todo get this from somewhere; maybe for each subincrement + //so far the model does not offer different settings for each tick depth + return m_aLineProperties; +} + +TickmarkProperties AxisProperties::makeTickmarkProperties( + sal_Int32 nDepth ) const +{ + /* + nTickmarkStyle: + 1: inner tickmarks + 2: outer tickmarks + 3: inner and outer tickmarks + */ + sal_Int32 nTickmarkStyle = 1; + if(nDepth==0) + { + nTickmarkStyle = m_nMajorTickmarks; + if(!nTickmarkStyle) + { + //create major tickmarks as if they were minor tickmarks + nDepth = 1; + nTickmarkStyle = m_nMinorTickmarks; + } + } + else if( nDepth==1) + { + nTickmarkStyle = m_nMinorTickmarks; + } + + if( m_fInnerDirectionSign == 0.0 ) + { + if( nTickmarkStyle != 0 ) + nTickmarkStyle = 3; //inner and outer tickmarks + } + + TickmarkProperties aTickmarkProperties; + aTickmarkProperties.Length = lcl_calcTickLengthForDepth(nDepth,nTickmarkStyle); + aTickmarkProperties.RelativePos = static_cast<sal_Int32>(lcl_getTickOffset(aTickmarkProperties.Length,nTickmarkStyle)); + aTickmarkProperties.aLineProperties = this->makeLinePropertiesForDepth( nDepth ); + return aTickmarkProperties; +} + +TickmarkProperties AxisProperties::makeTickmarkPropertiesForComplexCategories( + sal_Int32 nTickLength, sal_Int32 nTickStartDistanceToAxis, sal_Int32 /*nTextLevel*/ ) const +{ + sal_Int32 nTickmarkStyle = (m_fLabelDirectionSign==m_fInnerDirectionSign) ? 2/*outside*/ : 1/*inside*/; + + TickmarkProperties aTickmarkProperties; + aTickmarkProperties.Length = nTickLength;// + nTextLevel*( lcl_calcTickLengthForDepth(0,nTickmarkStyle) ); + aTickmarkProperties.RelativePos = static_cast<sal_Int32>(lcl_getTickOffset(aTickmarkProperties.Length+nTickStartDistanceToAxis,nTickmarkStyle)); + aTickmarkProperties.aLineProperties = this->makeLinePropertiesForDepth( 0 ); + return aTickmarkProperties; +} + +TickmarkProperties AxisProperties::getBiggestTickmarkProperties() +{ + TickmarkProperties aTickmarkProperties; + sal_Int32 nDepth = 0; + sal_Int32 nTickmarkStyle = 3;//inner and outer tickmarks + aTickmarkProperties.Length = lcl_calcTickLengthForDepth( nDepth,nTickmarkStyle ); + aTickmarkProperties.RelativePos = static_cast<sal_Int32>( lcl_getTickOffset( aTickmarkProperties.Length, nTickmarkStyle ) ); + return aTickmarkProperties; +} + +//-------------------------------------------------------------------------- + +AxisProperties::AxisProperties( const uno::Reference< XAxis >& xAxisModel + , ExplicitCategoriesProvider* pExplicitCategoriesProvider ) + : m_xAxisModel(xAxisModel) + , m_nDimensionIndex(0) + , m_bIsMainAxis(true) + , m_bSwapXAndY(false) + , m_eCrossoverType( ::com::sun::star::chart::ChartAxisPosition_ZERO ) + , m_eLabelPos( ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS ) + , m_eTickmarkPos( ::com::sun::star::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS ) + , m_pfMainLinePositionAtOtherAxis(NULL) + , m_pfExrtaLinePositionAtOtherAxis(NULL) + , m_bCrossingAxisHasReverseDirection(false) + , m_bCrossingAxisIsCategoryAxes(false) + , m_fLabelDirectionSign(1.0) + , m_fInnerDirectionSign(1.0) + , m_aLabelAlignment(LABEL_ALIGN_RIGHT_TOP) + , m_bDisplayLabels( true ) + , m_nNumberFormatKey(0) + , m_nMajorTickmarks(1) + , m_nMinorTickmarks(1) + , m_aTickmarkPropertiesList() + , m_aLineProperties() + //for category axes + , m_nAxisType(AxisType::REALNUMBER) + , m_bComplexCategories(false) + , m_pExplicitCategoriesProvider(pExplicitCategoriesProvider) + , m_xAxisTextProvider(0) +{ +} + +AxisProperties::AxisProperties( const AxisProperties& rAxisProperties ) + : m_xAxisModel( rAxisProperties.m_xAxisModel ) + , m_nDimensionIndex( m_nDimensionIndex ) + , m_bIsMainAxis( rAxisProperties.m_bIsMainAxis ) + , m_bSwapXAndY( rAxisProperties.m_bSwapXAndY ) + , m_eCrossoverType( rAxisProperties.m_eCrossoverType ) + , m_eLabelPos( rAxisProperties.m_eLabelPos ) + , m_eTickmarkPos( rAxisProperties.m_eTickmarkPos ) + , m_pfMainLinePositionAtOtherAxis( NULL ) + , m_pfExrtaLinePositionAtOtherAxis( NULL ) + , m_bCrossingAxisHasReverseDirection( rAxisProperties.m_bCrossingAxisHasReverseDirection ) + , m_bCrossingAxisIsCategoryAxes( rAxisProperties.m_bCrossingAxisIsCategoryAxes ) + , m_fLabelDirectionSign( rAxisProperties.m_fLabelDirectionSign ) + , m_fInnerDirectionSign( rAxisProperties.m_fInnerDirectionSign ) + , m_aLabelAlignment( rAxisProperties.m_aLabelAlignment ) + , m_bDisplayLabels( rAxisProperties.m_bDisplayLabels ) + , m_nNumberFormatKey( rAxisProperties.m_nNumberFormatKey ) + , m_nMajorTickmarks( rAxisProperties.m_nMajorTickmarks ) + , m_nMinorTickmarks( rAxisProperties.m_nMinorTickmarks ) + , m_aTickmarkPropertiesList( rAxisProperties.m_aTickmarkPropertiesList ) + , m_aLineProperties( rAxisProperties.m_aLineProperties ) + //for category axes + , m_nAxisType( rAxisProperties.m_nAxisType ) + , m_bComplexCategories( rAxisProperties.m_bComplexCategories ) + , m_pExplicitCategoriesProvider( rAxisProperties.m_pExplicitCategoriesProvider ) + , m_xAxisTextProvider( rAxisProperties.m_xAxisTextProvider ) +{ + if( rAxisProperties.m_pfMainLinePositionAtOtherAxis ) + m_pfMainLinePositionAtOtherAxis = new double(*rAxisProperties.m_pfMainLinePositionAtOtherAxis); + if( rAxisProperties.m_pfExrtaLinePositionAtOtherAxis ) + m_pfExrtaLinePositionAtOtherAxis = new double (*rAxisProperties.m_pfExrtaLinePositionAtOtherAxis); +} + +AxisProperties::~AxisProperties() +{ + delete m_pfMainLinePositionAtOtherAxis; + delete m_pfExrtaLinePositionAtOtherAxis; +} + +LabelAlignment lcl_getLabelAlignmentForZAxis( const AxisProperties& rAxisProperties ) +{ + LabelAlignment aRet( LABEL_ALIGN_RIGHT ); + if( rAxisProperties.m_fLabelDirectionSign<0 ) + aRet = LABEL_ALIGN_LEFT; + return aRet; +} + +LabelAlignment lcl_getLabelAlignmentForYAxis( const AxisProperties& rAxisProperties ) +{ + LabelAlignment aRet( LABEL_ALIGN_RIGHT ); + if( rAxisProperties.m_fLabelDirectionSign<0 ) + aRet = LABEL_ALIGN_LEFT; + return aRet; +} + +LabelAlignment lcl_getLabelAlignmentForXAxis( const AxisProperties& rAxisProperties ) +{ + LabelAlignment aRet( LABEL_ALIGN_BOTTOM ); + if( rAxisProperties.m_fLabelDirectionSign<0 ) + aRet = LABEL_ALIGN_TOP; + return aRet; +} + +void AxisProperties::initAxisPositioning( const uno::Reference< beans::XPropertySet >& xAxisProp ) +{ + if( !xAxisProp.is() ) + return; + try + { + if( AxisHelper::isAxisPositioningEnabled() ) + { + xAxisProp->getPropertyValue(C2U( "CrossoverPosition" )) >>= m_eCrossoverType; + if( ::com::sun::star::chart::ChartAxisPosition_VALUE == m_eCrossoverType ) + { + double fValue = 0.0; + xAxisProp->getPropertyValue(C2U( "CrossoverValue" )) >>= fValue; + + if( m_bCrossingAxisIsCategoryAxes ) + fValue = ::rtl::math::round(fValue); + m_pfMainLinePositionAtOtherAxis = new double(fValue); + } + else if( ::com::sun::star::chart::ChartAxisPosition_ZERO == m_eCrossoverType ) + m_pfMainLinePositionAtOtherAxis = new double(0.0); + + xAxisProp->getPropertyValue(C2U( "LabelPosition" )) >>= m_eLabelPos; + xAxisProp->getPropertyValue(C2U( "MarkPosition" )) >>= m_eTickmarkPos; + } + else + { + m_eCrossoverType = ::com::sun::star::chart::ChartAxisPosition_START; + if( m_bIsMainAxis == m_bCrossingAxisHasReverseDirection ) + m_eCrossoverType = ::com::sun::star::chart::ChartAxisPosition_END; + m_eLabelPos = ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS; + m_eTickmarkPos = ::com::sun::star::chart::ChartAxisMarkPosition_AT_LABELS; + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } +} + +void AxisProperties::init( bool bCartesian ) +{ + uno::Reference< beans::XPropertySet > xProp = + uno::Reference<beans::XPropertySet>::query( this->m_xAxisModel ); + if( !xProp.is() ) + return; + + if( m_nDimensionIndex<2 ) + initAxisPositioning( xProp ); + + ScaleData aScaleData = m_xAxisModel->getScaleData(); + if( m_nDimensionIndex==0 ) + AxisHelper::checkDateAxis( aScaleData, m_pExplicitCategoriesProvider, bCartesian ); + m_nAxisType = aScaleData.AxisType; + + if( bCartesian ) + { + if( m_nDimensionIndex == 0 && m_nAxisType == AxisType::CATEGORY + && m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->hasComplexCategories() ) + m_bComplexCategories = true; + + if( ::com::sun::star::chart::ChartAxisPosition_END == m_eCrossoverType ) + m_fInnerDirectionSign = m_bCrossingAxisHasReverseDirection ? 1 : -1; + else + m_fInnerDirectionSign = m_bCrossingAxisHasReverseDirection ? -1 : 1; + + if( ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS == m_eLabelPos ) + m_fLabelDirectionSign = m_fInnerDirectionSign; + else if( ::com::sun::star::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE == m_eLabelPos ) + m_fLabelDirectionSign = -m_fInnerDirectionSign; + else if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_START == m_eLabelPos ) + m_fLabelDirectionSign = m_bCrossingAxisHasReverseDirection ? -1 : 1; + else if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END == m_eLabelPos ) + m_fLabelDirectionSign = m_bCrossingAxisHasReverseDirection ? 1 : -1; + + if( m_nDimensionIndex==2 ) + m_aLabelAlignment = lcl_getLabelAlignmentForZAxis(*this); + else + { + bool bIsYAxisPosition = (m_nDimensionIndex==1 && !m_bSwapXAndY) + || (m_nDimensionIndex==0 && m_bSwapXAndY); + if( bIsYAxisPosition ) + { + m_fLabelDirectionSign*=-1; + m_fInnerDirectionSign*=-1; + } + + if( bIsYAxisPosition ) + m_aLabelAlignment = lcl_getLabelAlignmentForYAxis(*this); + else + m_aLabelAlignment = lcl_getLabelAlignmentForXAxis(*this); + } + } + + try + { + //init LineProperties + m_aLineProperties.initFromPropertySet( xProp ); + + //init display labels + xProp->getPropertyValue( C2U( "DisplayLabels" ) ) >>= m_bDisplayLabels; + + //init TickmarkProperties + xProp->getPropertyValue( C2U( "MajorTickmarks" ) ) >>= m_nMajorTickmarks; + xProp->getPropertyValue( C2U( "MinorTickmarks" ) ) >>= m_nMinorTickmarks; + + sal_Int32 nMaxDepth = 0; + if(m_nMinorTickmarks!=0) + nMaxDepth=2; + else if(m_nMajorTickmarks!=0) + nMaxDepth=1; + + this->m_aTickmarkPropertiesList.clear(); + for( sal_Int32 nDepth=0; nDepth<nMaxDepth; nDepth++ ) + { + TickmarkProperties aTickmarkProperties = this->makeTickmarkProperties( nDepth ); + this->m_aTickmarkPropertiesList.push_back( aTickmarkProperties ); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } +} + +//----------------------------------------------------------------------------- + +AxisLabelProperties::AxisLabelProperties() + : m_aFontReferenceSize( ChartModelHelper::getDefaultPageSize() ) + , m_aMaximumSpaceForLabels( 0 , 0, m_aFontReferenceSize.Width, m_aFontReferenceSize.Height ) + , nNumberFormatKey(0) + , eStaggering( SIDE_BY_SIDE ) + , bLineBreakAllowed( false ) + , bOverlapAllowed( false ) + , bStackCharacters( false ) + , fRotationAngleDegree( 0.0 ) + , nRhythm( 1 ) + , bRhythmIsFix(false) +{ + /* + aLocale.Language = C2U( "en" ); + aLocale.Country = C2U( "US" ); + + //aLocale.Language = C2U( "ar" ); + //aLocale.Country = C2U( "IR" ); + + //aLocale.Language = C2U( "ja" ); + //aLocale.Country = C2U( "JP" ); + */ +} + +void AxisLabelProperties::init( const uno::Reference< XAxis >& xAxisModel ) +{ + uno::Reference< beans::XPropertySet > xProp = + uno::Reference<beans::XPropertySet>::query( xAxisModel ); + if(xProp.is()) + { + try + { + xProp->getPropertyValue( C2U( "TextBreak" ) ) >>= this->bLineBreakAllowed; + xProp->getPropertyValue( C2U( "TextOverlap" ) ) >>= this->bOverlapAllowed; + xProp->getPropertyValue( C2U( "StackCharacters" ) ) >>= this->bStackCharacters; + xProp->getPropertyValue( C2U( "TextRotation" ) ) >>= this->fRotationAngleDegree; + + ::com::sun::star::chart::ChartAxisArrangeOrderType eArrangeOrder; + xProp->getPropertyValue( C2U( "ArrangeOrder" ) ) >>= eArrangeOrder; + switch(eArrangeOrder) + { + case ::com::sun::star::chart::ChartAxisArrangeOrderType_SIDE_BY_SIDE: + this->eStaggering = SIDE_BY_SIDE; + break; + case ::com::sun::star::chart::ChartAxisArrangeOrderType_STAGGER_EVEN: + this->eStaggering = STAGGER_EVEN; + break; + case ::com::sun::star::chart::ChartAxisArrangeOrderType_STAGGER_ODD: + this->eStaggering = STAGGER_ODD; + break; + default: + this->eStaggering = STAGGER_AUTO; + break; + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } +} + +/* +sal_Int16 getSwappedWritingMode( sal_Int16 nWritingMode ) +{ + //LR_TB == LT + //RL_TB == RT (Arabic, Hebrew) + //TB_RL == TR (Japanese, Chinese, Korean) + // ?? TL (Mongolian) see also text::WritingMode2 + + switch(nWritingMode) + { + case text::WritingMode2::RL_TB: + return text::WritingMode2::TB_RL; + case text::WritingMode2::TB_RL: + return text::WritingMode2::RL_TB; + case text::WritingMode2::LR_TB: + return text::WritingMode2::TB_LR; + default: + return text::WritingMode2::LR_TB; + } +} +*/ + +sal_Bool AxisLabelProperties::getIsStaggered() const +{ + if( STAGGER_ODD == eStaggering || STAGGER_EVEN == eStaggering ) + return sal_True; + return sal_False; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/VAxisProperties.hxx b/chart2/source/view/axes/VAxisProperties.hxx new file mode 100644 index 000000000000..69e0edb82730 --- /dev/null +++ b/chart2/source/view/axes/VAxisProperties.hxx @@ -0,0 +1,167 @@ +/************************************************************************* + * + * 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_VAXIS_PROPERTIES_HXX +#define _CHART2_VAXIS_PROPERTIES_HXX + +#include "TickmarkProperties.hxx" +#include "PlottingPositionHelper.hxx" +#include "LabelAlignment.hxx" +#include "ExplicitCategoriesProvider.hxx" + +#include <com/sun/star/chart/ChartAxisLabelPosition.hpp> +#include <com/sun/star/chart/ChartAxisMarkPosition.hpp> +#include <com/sun/star/chart/ChartAxisPosition.hpp> +#include <com/sun/star/chart2/XAxis.hpp> +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/chart2/data/XTextualDataSequence.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/drawing/TextVerticalAdjust.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> +#include <com/sun/star/lang/Locale.hpp> + +#include <vector> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +//These properties describe how a couple of labels are arranged one to another. +//The couple can contain all labels for all tickmark depth or just the labels for one single depth or +//the labels from an coherent range of tick depths (e.g. the major and first minor tickmarks should be handled together). +//... only allow side by side for different tick depth +enum AxisLabelStaggering +{ + SIDE_BY_SIDE + , STAGGER_EVEN + , STAGGER_ODD + , STAGGER_AUTO +}; + +struct AxisLabelProperties +{ + AxisLabelProperties(); + + ::com::sun::star::awt::Size m_aFontReferenceSize;//reference size to calculate the font height + ::com::sun::star::awt::Rectangle m_aMaximumSpaceForLabels;//Labels need to be clipped in order to fit into this rectangle + + sal_Int32 nNumberFormatKey; + + AxisLabelStaggering eStaggering; + + sal_Bool bLineBreakAllowed; + sal_Bool bOverlapAllowed; + + sal_Bool bStackCharacters; + double fRotationAngleDegree; + + sal_Int32 nRhythm; //show only each nth label with n==nRhythm + bool bRhythmIsFix; //states wether the given rhythm is fix or may be changed + + //methods: + void init( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XAxis >& xAxisModel ); + + sal_Bool getIsStaggered() const; +}; + +struct AxisProperties +{ + ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XAxis > m_xAxisModel; + + sal_Int32 m_nDimensionIndex; + bool m_bIsMainAxis;//not secondary axis + bool m_bSwapXAndY; + + ::com::sun::star::chart::ChartAxisPosition m_eCrossoverType; + ::com::sun::star::chart::ChartAxisLabelPosition m_eLabelPos; + ::com::sun::star::chart::ChartAxisMarkPosition m_eTickmarkPos; + + double* m_pfMainLinePositionAtOtherAxis; + double* m_pfExrtaLinePositionAtOtherAxis; + + bool m_bCrossingAxisHasReverseDirection; + bool m_bCrossingAxisIsCategoryAxes; + + //this direction is used to indicate in which direction the labels are to be drawn + double m_fLabelDirectionSign; + //this direction is used to indicate in which direction inner tickmarks are to be drawn + double m_fInnerDirectionSign; + LabelAlignment m_aLabelAlignment; + sal_Bool m_bDisplayLabels; + + sal_Int32 m_nNumberFormatKey; + + /* + 0: no tickmarks 1: inner tickmarks + 2: outer tickmarks 3: inner and outer tickmarks + */ + sal_Int32 m_nMajorTickmarks; + sal_Int32 m_nMinorTickmarks; + ::std::vector<TickmarkProperties> m_aTickmarkPropertiesList; + + VLineProperties m_aLineProperties; + + //for category axes -> + sal_Int32 m_nAxisType;//REALNUMBER, CATEGORY etc. type ::com::sun::star::chart2::AxisType + bool m_bComplexCategories; + ExplicitCategoriesProvider* m_pExplicitCategoriesProvider;/*no ownership here*/ + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::data::XTextualDataSequence > + m_xAxisTextProvider; //for categries or series names + //<- category axes + + //methods: + + AxisProperties( const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XAxis >& xAxisModel + , ExplicitCategoriesProvider* pExplicitCategoriesProvider ); + AxisProperties( const AxisProperties& rAxisProperties ); + virtual ~AxisProperties(); + virtual void init(bool bCartesian=false);//init from model data (m_xAxisModel) + + void initAxisPositioning( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xAxisProp ); + + static TickmarkProperties getBiggestTickmarkProperties(); + TickmarkProperties makeTickmarkPropertiesForComplexCategories( sal_Int32 nTickLength, sal_Int32 nTickStartDistanceToAxis, sal_Int32 nTextLevel ) const; + +private: + AxisProperties(); + +protected: + virtual TickmarkProperties makeTickmarkProperties( sal_Int32 nDepth ) const; + VLineProperties makeLinePropertiesForDepth( sal_Int32 nDepth ) const; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/VCartesianAxis.cxx b/chart2/source/view/axes/VCartesianAxis.cxx new file mode 100644 index 000000000000..23c36a8c5ed7 --- /dev/null +++ b/chart2/source/view/axes/VCartesianAxis.cxx @@ -0,0 +1,1672 @@ +/************************************************************************* + * + * 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 <basegfx/numeric/ftools.hxx> + +#include "VCartesianAxis.hxx" +#include "PlottingPositionHelper.hxx" +#include "ShapeFactory.hxx" +#include "CommonConverters.hxx" +#include "macros.hxx" +#include "ViewDefines.hxx" +#include "PropertyMapper.hxx" +#include "NumberFormatterWrapper.hxx" +#include "LabelPositionHelper.hxx" +#include "TrueGuard.hxx" +#include "BaseGFXHelper.hxx" +#include "AxisHelper.hxx" +#include "Tickmarks_Equidistant.hxx" + +#include <rtl/math.hxx> +#include <tools/color.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <editeng/unoprnms.hxx> +#include <svx/unoshape.hxx> +#include <svx/unoshtxt.hxx> + +#include <algorithm> +#include <memory> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::rtl::math; +using ::com::sun::star::uno::Reference; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +VCartesianAxis::VCartesianAxis( const AxisProperties& rAxisProperties + , const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , PlottingPositionHelper* pPosHelper )//takes ownership + : VAxisBase( nDimensionIndex, nDimensionCount, rAxisProperties, xNumberFormatsSupplier ) +{ + if( pPosHelper ) + m_pPosHelper = pPosHelper; + else + m_pPosHelper = new PlottingPositionHelper(); +} + +VCartesianAxis::~VCartesianAxis() +{ + delete m_pPosHelper; + m_pPosHelper = NULL; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +Reference< drawing::XShape > createSingleLabel( + const Reference< lang::XMultiServiceFactory>& xShapeFactory + , const Reference< drawing::XShapes >& xTarget + , const awt::Point& rAnchorScreenPosition2D + , const rtl::OUString& rLabel + , const AxisLabelProperties& rAxisLabelProperties + , const AxisProperties& rAxisProperties + , const tNameSequence& rPropNames + , const tAnySequence& rPropValues + ) +{ + if(!rLabel.getLength()) + return 0; + + // #i78696# use mathematically correct rotation now + const double fRotationAnglePi(rAxisLabelProperties.fRotationAngleDegree * (F_PI / -180.0)); + uno::Any aATransformation = ShapeFactory::makeTransformation( rAnchorScreenPosition2D, fRotationAnglePi ); + rtl::OUString aLabel = ShapeFactory::getStackedString( rLabel, rAxisLabelProperties.bStackCharacters ); + + Reference< drawing::XShape > xShape2DText = ShapeFactory(xShapeFactory) + .createText( xTarget, aLabel, rPropNames, rPropValues, aATransformation ); + + //correctPositionForRotation + LabelPositionHelper::correctPositionForRotation( xShape2DText + , rAxisProperties.m_aLabelAlignment, rAxisLabelProperties.fRotationAngleDegree, rAxisProperties.m_bComplexCategories ); + + return xShape2DText; +} + +bool lcl_doesShapeOverlapWithTickmark( const Reference< drawing::XShape >& xShape + , double fRotationAngleDegree + , const basegfx::B2DVector& rTickScreenPosition + , bool bIsHorizontalAxis, bool bIsVerticalAxis ) +{ + if(!xShape.is()) + return false; + + ::basegfx::B2IRectangle aShapeRect = BaseGFXHelper::makeRectangle(xShape->getPosition(),ShapeFactory::getSizeAfterRotation( xShape, fRotationAngleDegree )); + + if( bIsVerticalAxis ) + { + return ( (rTickScreenPosition.getY() >= aShapeRect.getMinY()) + && (rTickScreenPosition.getY() <= aShapeRect.getMaxY()) ); + } + if( bIsHorizontalAxis ) + { + return ( (rTickScreenPosition.getX() >= aShapeRect.getMinX()) + && (rTickScreenPosition.getX() <= aShapeRect.getMaxX()) ); + } + + basegfx::B2IVector aPosition( + static_cast<sal_Int32>( rTickScreenPosition.getX() ) + , static_cast<sal_Int32>( rTickScreenPosition.getY() ) ); + return aShapeRect.isInside(aPosition); +} + +bool doesOverlap( const Reference< drawing::XShape >& xShape1 + , const Reference< drawing::XShape >& xShape2 + , double fRotationAngleDegree ) +{ + if( !xShape1.is() || !xShape2.is() ) + return false; + + ::basegfx::B2IRectangle aRect1( BaseGFXHelper::makeRectangle(xShape1->getPosition(),ShapeFactory::getSizeAfterRotation( xShape1, fRotationAngleDegree ))); + ::basegfx::B2IRectangle aRect2( BaseGFXHelper::makeRectangle(xShape2->getPosition(),ShapeFactory::getSizeAfterRotation( xShape2, fRotationAngleDegree ))); + return aRect1.overlaps(aRect2); +} + +void removeShapesAtWrongRhythm( TickIter& rIter + , sal_Int32 nCorrectRhythm + , sal_Int32 nMaxTickToCheck + , const Reference< drawing::XShapes >& xTarget ) +{ + sal_Int32 nTick = 0; + for( TickInfo* pTickInfo = rIter.firstInfo() + ; pTickInfo && nTick <= nMaxTickToCheck + ; pTickInfo = rIter.nextInfo(), nTick++ ) + { + //remove labels which does not fit into the rhythm + if( nTick%nCorrectRhythm != 0) + { + if(pTickInfo->xTextShape.is()) + { + xTarget->remove(pTickInfo->xTextShape); + pTickInfo->xTextShape = NULL; + } + } + } +} + +class LabelIterator : public TickIter +{ + //this Iterator iterates over existing text labels + + //if the labels are staggered and bInnerLine is true + //we iterate only through the labels which are lying more inside the diagram + + //if the labels are staggered and bInnerLine is false + //we iterate only through the labels which are lying more outside the diagram + + //if the labels are not staggered + //we iterate through all labels + +public: + LabelIterator( ::std::vector< TickInfo >& rTickInfoVector + , const AxisLabelStaggering eAxisLabelStaggering + , bool bInnerLine ); + + virtual TickInfo* firstInfo(); + virtual TickInfo* nextInfo(); + +private: //methods + LabelIterator(); + +private: //member + PureTickIter m_aPureTickIter; + const AxisLabelStaggering m_eAxisLabelStaggering; + bool m_bInnerLine; +}; + +LabelIterator::LabelIterator( ::std::vector< TickInfo >& rTickInfoVector + , const AxisLabelStaggering eAxisLabelStaggering + , bool bInnerLine ) + : m_aPureTickIter( rTickInfoVector ) + , m_eAxisLabelStaggering(eAxisLabelStaggering) + , m_bInnerLine(bInnerLine) +{ +} + +TickInfo* LabelIterator::firstInfo() +{ + TickInfo* pTickInfo = m_aPureTickIter.firstInfo(); + while( pTickInfo && !pTickInfo->xTextShape.is() ) + pTickInfo = m_aPureTickIter.nextInfo(); + if(!pTickInfo) + return NULL; + if( (STAGGER_EVEN==m_eAxisLabelStaggering && m_bInnerLine) + || + (STAGGER_ODD==m_eAxisLabelStaggering && !m_bInnerLine) + ) + { + //skip first label + do + pTickInfo = m_aPureTickIter.nextInfo(); + while( pTickInfo && !pTickInfo->xTextShape.is() ); + } + if(!pTickInfo) + return NULL; + return pTickInfo; +} + +TickInfo* LabelIterator::nextInfo() +{ + TickInfo* pTickInfo = NULL; + //get next label + do + pTickInfo = m_aPureTickIter.nextInfo(); + while( pTickInfo && !pTickInfo->xTextShape.is() ); + + if( STAGGER_EVEN==m_eAxisLabelStaggering + || STAGGER_ODD==m_eAxisLabelStaggering ) + { + //skip one label + do + pTickInfo = m_aPureTickIter.nextInfo(); + while( pTickInfo && !pTickInfo->xTextShape.is() ); + } + return pTickInfo; +} + +B2DVector lcl_getLabelsDistance( TickIter& rIter, const B2DVector& rDistanceTickToText, double fRotationAngleDegree ) +{ + //calculates the height or width of a line of labels + //thus a following line of labels can be shifted for that distance + + B2DVector aRet(0,0); + + sal_Int32 nDistanceTickToText = static_cast<sal_Int32>( rDistanceTickToText.getLength() ); + if( nDistanceTickToText==0.0) + return aRet; + + B2DVector aStaggerDirection(rDistanceTickToText); + aStaggerDirection.normalize(); + + sal_Int32 nDistance=0; + Reference< drawing::XShape > xShape2DText(NULL); + for( TickInfo* pTickInfo = rIter.firstInfo() + ; pTickInfo + ; pTickInfo = rIter.nextInfo() ) + { + xShape2DText = pTickInfo->xTextShape; + if( xShape2DText.is() ) + { + awt::Size aSize = ShapeFactory::getSizeAfterRotation( xShape2DText, fRotationAngleDegree ); + if(fabs(aStaggerDirection.getX())>fabs(aStaggerDirection.getY())) + nDistance = ::std::max(nDistance,aSize.Width); + else + nDistance = ::std::max(nDistance,aSize.Height); + } + } + + aRet = aStaggerDirection*nDistance; + + //add extra distance for vertical distance + if(fabs(aStaggerDirection.getX())>fabs(aStaggerDirection.getY())) + aRet += rDistanceTickToText; + + return aRet; +} + +void lcl_shiftLables( TickIter& rIter, const B2DVector& rStaggerDistance ) +{ + if(rStaggerDistance.getLength()==0.0) + return; + Reference< drawing::XShape > xShape2DText(NULL); + for( TickInfo* pTickInfo = rIter.firstInfo() + ; pTickInfo + ; pTickInfo = rIter.nextInfo() ) + { + xShape2DText = pTickInfo->xTextShape; + if( xShape2DText.is() ) + { + awt::Point aPos = xShape2DText->getPosition(); + aPos.X += static_cast<sal_Int32>(rStaggerDistance.getX()); + aPos.Y += static_cast<sal_Int32>(rStaggerDistance.getY()); + xShape2DText->setPosition( aPos ); + } + } +} + +bool lcl_hasWordBreak( const Reference< drawing::XShape >& rxShape ) +{ + if ( rxShape.is() ) + { + SvxShape* pShape = SvxShape::getImplementation( rxShape ); + SvxShapeText* pShapeText = dynamic_cast< SvxShapeText* >( pShape ); + if ( pShapeText ) + { + SvxTextEditSource* pTextEditSource = dynamic_cast< SvxTextEditSource* >( pShapeText->GetEditSource() ); + if ( pTextEditSource ) + { + pTextEditSource->UpdateOutliner(); + SvxTextForwarder* pTextForwarder = pTextEditSource->GetTextForwarder(); + if ( pTextForwarder ) + { + sal_uInt16 nParaCount = pTextForwarder->GetParagraphCount(); + for ( sal_uInt16 nPara = 0; nPara < nParaCount; ++nPara ) + { + sal_uInt16 nLineCount = pTextForwarder->GetLineCount( nPara ); + for ( sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine ) + { + sal_uInt16 nLineStart = 0; + sal_uInt16 nLineEnd = 0; + pTextForwarder->GetLineBoundaries( nLineStart, nLineEnd, nPara, nLine ); + sal_uInt16 nWordStart = 0; + sal_uInt16 nWordEnd = 0; + if ( pTextForwarder->GetWordIndices( nPara, nLineStart, nWordStart, nWordEnd ) && + ( nWordStart != nLineStart ) ) + { + return true; + } + } + } + } + } + } + } + + return false; +} + +class MaxLabelTickIter : public TickIter +{ + //iterate over first two and last two labels and the longest label +public: + MaxLabelTickIter( ::std::vector< TickInfo >& rTickInfoVector + , sal_Int32 nLongestLabelIndex ); + virtual ~MaxLabelTickIter(); + + virtual TickInfo* firstInfo(); + virtual TickInfo* nextInfo(); + +private: + ::std::vector< TickInfo >& m_rTickInfoVector; + ::std::vector< sal_Int32 > m_aValidIndices; + sal_Int32 m_nCurrentIndex; +}; + +MaxLabelTickIter::MaxLabelTickIter( ::std::vector< TickInfo >& rTickInfoVector + , sal_Int32 nLongestLabelIndex ) + : m_rTickInfoVector(rTickInfoVector) + , m_nCurrentIndex(0) +{ + sal_Int32 nMaxIndex = m_rTickInfoVector.size()-1; + if( nLongestLabelIndex<0 || nLongestLabelIndex>=nMaxIndex-1 ) + nLongestLabelIndex = 0; + + if( nMaxIndex>=0 ) + m_aValidIndices.push_back(0); + if( nMaxIndex>=1 ) + m_aValidIndices.push_back(1); + if( nLongestLabelIndex>1 ) + m_aValidIndices.push_back(nLongestLabelIndex); + if( nMaxIndex > 2 ) + m_aValidIndices.push_back(nMaxIndex-1); + if( nMaxIndex > 1 ) + m_aValidIndices.push_back(nMaxIndex); +} +MaxLabelTickIter::~MaxLabelTickIter() +{ +} + +TickInfo* MaxLabelTickIter::firstInfo() +{ + m_nCurrentIndex = 0; + if( m_nCurrentIndex < static_cast<sal_Int32>(m_aValidIndices.size()) ) + return &m_rTickInfoVector[m_aValidIndices[m_nCurrentIndex]]; + return 0; +} + +TickInfo* MaxLabelTickIter::nextInfo() +{ + m_nCurrentIndex++; + if( m_nCurrentIndex>=0 && m_nCurrentIndex<static_cast<sal_Int32>(m_aValidIndices.size()) ) + return &m_rTickInfoVector[m_aValidIndices[m_nCurrentIndex]]; + return 0; +} + +bool VCartesianAxis::isBreakOfLabelsAllowed( const AxisLabelProperties& rAxisLabelProperties + , bool bIsHorizontalAxis ) +{ + if( m_aTextLabels.getLength() > 100 ) + return false; + if( !rAxisLabelProperties.bLineBreakAllowed ) + return false; + if( rAxisLabelProperties.bStackCharacters ) + return false; + //no break for value axis + if( !m_bUseTextLabels ) + return false; + if( !::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) ) + return false; + //break only for horizontal axis + return bIsHorizontalAxis; +} + +bool VCartesianAxis::isAutoStaggeringOfLabelsAllowed( const AxisLabelProperties& rAxisLabelProperties + , bool bIsHorizontalAxis, bool bIsVerticalAxis ) +{ + if( rAxisLabelProperties.eStaggering != STAGGER_AUTO ) + return false; + if( rAxisLabelProperties.bOverlapAllowed ) + return false; + if( rAxisLabelProperties.bLineBreakAllowed ) //auto line break or auto staggering, doing both automatisms they may conflict... + return false; + if( !::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) ) + return false; + //automatic staggering only for horizontal axis with horizontal text + //or vertical axis with vertical text + if( bIsHorizontalAxis ) + return !rAxisLabelProperties.bStackCharacters; + if( bIsVerticalAxis ) + return rAxisLabelProperties.bStackCharacters; + return false; +} + +struct ComplexCategoryPlacement +{ + rtl::OUString Text; + sal_Int32 Count; + double TickValue; + + ComplexCategoryPlacement( const rtl::OUString& rText, sal_Int32 nCount, double fTickValue ) + : Text(rText), Count(nCount), TickValue(fTickValue) + {} +}; + +void VCartesianAxis::createAllTickInfosFromComplexCategories( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos, bool bShiftedPosition ) +{ + //no minor tickmarks will be generated! + //order is: inner labels first , outer labels last (that is different to all other TickIter cases) + if(!bShiftedPosition) + { + rAllTickInfos.clear(); + sal_Int32 nLevel=0; + sal_Int32 nLevelCount = m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoryLevelCount(); + for( ; nLevel<nLevelCount; nLevel++ ) + { + ::std::vector< TickInfo > aTickInfoVector; + std::vector< ComplexCategory > aComplexCategories( m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoriesByLevel( nLevel ) ); + sal_Int32 nCatIndex = 0; + std::vector< ComplexCategory >::const_iterator aIt(aComplexCategories.begin()); + std::vector< ComplexCategory >::const_iterator aEnd(aComplexCategories.end()); + for(;aIt!=aEnd;++aIt) + { + TickInfo aTickInfo(0); + ComplexCategory aCat(*aIt); + sal_Int32 nCount = aCat.Count; + if( nCatIndex + 1.0 + nCount >= m_aScale.Maximum ) + { + nCount = static_cast<sal_Int32>(m_aScale.Maximum - 1.0 - nCatIndex); + if( nCount <= 0 ) + nCount = 1; + } + aTickInfo.fScaledTickValue = nCatIndex + 1.0 + nCount/2.0; + aTickInfo.nFactorForLimitedTextWidth = nCount; + aTickInfo.aText = aCat.Text; + aTickInfoVector.push_back(aTickInfo); + nCatIndex += nCount; + if( nCatIndex + 1.0 >= m_aScale.Maximum ) + break; + } + rAllTickInfos.push_back(aTickInfoVector); + } + } + else //bShiftedPosition==false + { + rAllTickInfos.clear(); + sal_Int32 nLevel=0; + sal_Int32 nLevelCount = m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoryLevelCount(); + for( ; nLevel<nLevelCount; nLevel++ ) + { + ::std::vector< TickInfo > aTickInfoVector; + std::vector< ComplexCategory > aComplexCategories( m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoriesByLevel( nLevel ) ); + sal_Int32 nCatIndex = 0; + std::vector< ComplexCategory >::const_iterator aIt(aComplexCategories.begin()); + std::vector< ComplexCategory >::const_iterator aEnd(aComplexCategories.end()); + for(;aIt!=aEnd;++aIt) + { + TickInfo aTickInfo(0); + ComplexCategory aCat(*aIt); + aTickInfo.fScaledTickValue = nCatIndex + 1.0; + aTickInfoVector.push_back(aTickInfo); + nCatIndex += aCat.Count; + if( nCatIndex + 1.0 > m_aScale.Maximum ) + break; + } + //fill up with single ticks until maximum scale + while( nCatIndex + 1.0 < m_aScale.Maximum ) + { + TickInfo aTickInfo(0); + aTickInfo.fScaledTickValue = nCatIndex + 1.0; + aTickInfoVector.push_back(aTickInfo); + nCatIndex ++; + if( nLevel>0 ) + break; + } + //add an additional tick at the end + { + TickInfo aTickInfo(0); + aTickInfo.fScaledTickValue = m_aScale.Maximum; + aTickInfoVector.push_back(aTickInfo); + } + rAllTickInfos.push_back(aTickInfoVector); + } + } +} + +void VCartesianAxis::createAllTickInfos( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) +{ + if( isComplexCategoryAxis() ) + createAllTickInfosFromComplexCategories( rAllTickInfos, false ); + else + VAxisBase::createAllTickInfos(rAllTickInfos); +} + +::std::auto_ptr< TickIter > VCartesianAxis::createLabelTickIterator( sal_Int32 nTextLevel ) +{ + if( nTextLevel>=0 && nTextLevel < static_cast< sal_Int32 >(m_aAllTickInfos.size()) ) + return ::std::auto_ptr< TickIter >( new PureTickIter( m_aAllTickInfos[nTextLevel] ) ); + return ::std::auto_ptr< TickIter >(); +} +::std::auto_ptr< TickIter > VCartesianAxis::createMaximumLabelTickIterator( sal_Int32 nTextLevel ) +{ + if( isComplexCategoryAxis() || isDateAxis() ) + { + return createLabelTickIterator( nTextLevel ); //mmmm maybe todo: create less than all texts here + } + else + { + if(nTextLevel==0) + { + if( !m_aAllTickInfos.empty() ) + { + sal_Int32 nLongestLabelIndex = m_bUseTextLabels ? this->getIndexOfLongestLabel( m_aTextLabels ) : 0; + return ::std::auto_ptr< TickIter >( new MaxLabelTickIter( m_aAllTickInfos[0], nLongestLabelIndex ) ); + } + } + } + return ::std::auto_ptr< TickIter >(); +} + +sal_Int32 VCartesianAxis::getTextLevelCount() const +{ + sal_Int32 nTextLevelCount = 1; + if( isComplexCategoryAxis() ) + nTextLevelCount = m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoryLevelCount(); + return nTextLevelCount; +} + +bool VCartesianAxis::createTextShapes( + const Reference< drawing::XShapes >& xTarget + , TickIter& rTickIter + , AxisLabelProperties& rAxisLabelProperties + , TickFactory_2D* pTickFactory + , sal_Int32 nScreenDistanceBetweenTicks ) +{ + //returns true if the text shapes have been created succesfully + //otherwise false - in this case the AxisLabelProperties have changed + //and contain new instructions for the next try for text shape creation + + Reference< XScaling > xInverseScaling( NULL ); + if( m_aScale.Scaling.is() ) + xInverseScaling = m_aScale.Scaling->getInverseScaling(); + + FixedNumberFormatter aFixedNumberFormatter( + m_xNumberFormatsSupplier, rAxisLabelProperties.nNumberFormatKey ); + + const bool bIsHorizontalAxis = pTickFactory->isHorizontalAxis(); + const bool bIsVerticalAxis = pTickFactory->isVerticalAxis(); + bool bIsStaggered = rAxisLabelProperties.getIsStaggered(); + B2DVector aTextToTickDistance( pTickFactory->getDistanceAxisTickToText( m_aAxisProperties, true ) ); + sal_Int32 nLimitedSpaceForText = -1; + if( isBreakOfLabelsAllowed( rAxisLabelProperties, bIsHorizontalAxis ) ) + { + nLimitedSpaceForText = nScreenDistanceBetweenTicks; + if( bIsStaggered ) + nLimitedSpaceForText *= 2; + + if( nLimitedSpaceForText > 0 ) + { //reduce space for a small amount to have a visible distance between the labels: + sal_Int32 nReduce = (nLimitedSpaceForText*5)/100; + if(!nReduce) + nReduce = 1; + nLimitedSpaceForText -= nReduce; + } + } + + std::vector< ComplexCategoryPlacement > aComplexCategoryPlacements; + uno::Sequence< rtl::OUString >* pCategories = 0; + if( m_bUseTextLabels && !m_aAxisProperties.m_bComplexCategories ) + pCategories = &m_aTextLabels; + + TickInfo* pPreviousVisibleTickInfo = NULL; + TickInfo* pPREPreviousVisibleTickInfo = NULL; + TickInfo* pLastVisibleNeighbourTickInfo = NULL; + + //------------------------------------------------ + //prepare properties for multipropertyset-interface of shape + tNameSequence aPropNames; + tAnySequence aPropValues; + + bool bLimitedHeight = fabs(aTextToTickDistance.getX()) > fabs(aTextToTickDistance.getY()); + Reference< beans::XPropertySet > xProps( m_aAxisProperties.m_xAxisModel, uno::UNO_QUERY ); + PropertyMapper::getTextLabelMultiPropertyLists( xProps, aPropNames, aPropValues, false + , nLimitedSpaceForText, bLimitedHeight ); + LabelPositionHelper::doDynamicFontResize( aPropValues, aPropNames, xProps + , m_aAxisLabelProperties.m_aFontReferenceSize ); + LabelPositionHelper::changeTextAdjustment( aPropValues, aPropNames, m_aAxisProperties.m_aLabelAlignment ); + + uno::Any* pColorAny = PropertyMapper::getValuePointer(aPropValues,aPropNames,C2U("CharColor")); + sal_Int32 nColor = Color( COL_AUTO ).GetColor(); + if(pColorAny) + *pColorAny >>= nColor; + + uno::Any* pLimitedSpaceAny = PropertyMapper::getValuePointerForLimitedSpace(aPropValues,aPropNames,bLimitedHeight); + //------------------------------------------------ + + sal_Int32 nTick = 0; + for( TickInfo* pTickInfo = rTickIter.firstInfo() + ; pTickInfo + ; pTickInfo = rTickIter.nextInfo(), nTick++ ) + { + pLastVisibleNeighbourTickInfo = bIsStaggered ? + pPREPreviousVisibleTickInfo : pPreviousVisibleTickInfo; + + //don't create labels which does not fit into the rhythm + if( nTick%rAxisLabelProperties.nRhythm != 0) + continue; + + //don't create labels for invisible ticks + if( !pTickInfo->bPaintIt ) + continue; + + //if NO OVERLAP -> don't create labels where the tick overlaps + //with the text of the last neighbour tickmark + if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.bOverlapAllowed ) + { + if( lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo->xTextShape + , rAxisLabelProperties.fRotationAngleDegree + , pTickInfo->aTickScreenPosition + , bIsHorizontalAxis, bIsVerticalAxis ) ) + { + bool bOverlapAlsoAfterSwitchingOnAutoStaggering = true; + if( !bIsStaggered && isAutoStaggeringOfLabelsAllowed( rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis ) ) + { + bIsStaggered = true; + rAxisLabelProperties.eStaggering = STAGGER_EVEN; + pLastVisibleNeighbourTickInfo = pPREPreviousVisibleTickInfo; + if( !pLastVisibleNeighbourTickInfo || + !lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo->xTextShape + , rAxisLabelProperties.fRotationAngleDegree + , pTickInfo->aTickScreenPosition + , bIsHorizontalAxis, bIsVerticalAxis ) ) + bOverlapAlsoAfterSwitchingOnAutoStaggering = false; + } + if( bOverlapAlsoAfterSwitchingOnAutoStaggering ) + { + if( rAxisLabelProperties.bRhythmIsFix ) + continue; + rAxisLabelProperties.nRhythm++; + removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.nRhythm, nTick, xTarget ); + return false; + } + } + } + + //xxxxx pTickInfo->updateUnscaledValue( xInverseScaling ); + + bool bHasExtraColor=false; + sal_Int32 nExtraColor=0; + + rtl::OUString aLabel; + if(pCategories) + { + sal_Int32 nIndex = static_cast< sal_Int32 >(pTickInfo->getUnscaledTickValue()) - 1; //first category (index 0) matches with real number 1.0 + if( nIndex>=0 && nIndex<pCategories->getLength() ) + aLabel = (*pCategories)[nIndex]; + } + else if( m_aAxisProperties.m_bComplexCategories ) + { + aLabel = pTickInfo->aText; + } + else + aLabel = aFixedNumberFormatter.getFormattedString( pTickInfo->getUnscaledTickValue(), nExtraColor, bHasExtraColor ); + + if(pColorAny) + *pColorAny = uno::makeAny(bHasExtraColor?nExtraColor:nColor); + if(pLimitedSpaceAny) + *pLimitedSpaceAny = uno::makeAny(sal_Int32(nLimitedSpaceForText*pTickInfo->nFactorForLimitedTextWidth)); + + B2DVector aTickScreenPos2D( pTickInfo->aTickScreenPosition ); + aTickScreenPos2D += aTextToTickDistance; + awt::Point aAnchorScreenPosition2D( + static_cast<sal_Int32>(aTickScreenPos2D.getX()) + ,static_cast<sal_Int32>(aTickScreenPos2D.getY())); + + //create single label + if(!pTickInfo->xTextShape.is()) + pTickInfo->xTextShape = createSingleLabel( m_xShapeFactory, xTarget + , aAnchorScreenPosition2D, aLabel + , rAxisLabelProperties, m_aAxisProperties + , aPropNames, aPropValues ); + if(!pTickInfo->xTextShape.is()) + continue; + + recordMaximumTextSize( pTickInfo->xTextShape, rAxisLabelProperties.fRotationAngleDegree ); + + //better rotate if single words are broken apart + if( nLimitedSpaceForText>0 && !rAxisLabelProperties.bOverlapAllowed + && ::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) + && m_aAxisProperties.m_bComplexCategories + && lcl_hasWordBreak( pTickInfo->xTextShape ) ) + { + rAxisLabelProperties.fRotationAngleDegree = 90; + rAxisLabelProperties.bLineBreakAllowed = false; + m_aAxisLabelProperties.fRotationAngleDegree = rAxisLabelProperties.fRotationAngleDegree; + removeTextShapesFromTicks(); + return false; + } + + //if NO OVERLAP -> remove overlapping shapes + if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.bOverlapAllowed ) + { + if( doesOverlap( pLastVisibleNeighbourTickInfo->xTextShape, pTickInfo->xTextShape, rAxisLabelProperties.fRotationAngleDegree ) ) + { + bool bOverlapAlsoAfterSwitchingOnAutoStaggering = true; + if( !bIsStaggered && isAutoStaggeringOfLabelsAllowed( rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis ) ) + { + bIsStaggered = true; + rAxisLabelProperties.eStaggering = STAGGER_EVEN; + pLastVisibleNeighbourTickInfo = pPREPreviousVisibleTickInfo; + if( !pLastVisibleNeighbourTickInfo || + !lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo->xTextShape + , rAxisLabelProperties.fRotationAngleDegree + , pTickInfo->aTickScreenPosition + , bIsHorizontalAxis, bIsVerticalAxis ) ) + bOverlapAlsoAfterSwitchingOnAutoStaggering = false; + } + if( bOverlapAlsoAfterSwitchingOnAutoStaggering ) + { + if( rAxisLabelProperties.bRhythmIsFix ) + { + xTarget->remove(pTickInfo->xTextShape); + pTickInfo->xTextShape = NULL; + continue; + } + rAxisLabelProperties.nRhythm++; + removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.nRhythm, nTick, xTarget ); + return false; + } + } + } + + pPREPreviousVisibleTickInfo = pPreviousVisibleTickInfo; + pPreviousVisibleTickInfo = pTickInfo; + } + return true; +} + +drawing::PointSequenceSequence lcl_makePointSequence( B2DVector& rStart, B2DVector& rEnd ) +{ + drawing::PointSequenceSequence aPoints(1); + aPoints[0].realloc(2); + aPoints[0][0].X = static_cast<sal_Int32>(rStart.getX()); + aPoints[0][0].Y = static_cast<sal_Int32>(rStart.getY()); + aPoints[0][1].X = static_cast<sal_Int32>(rEnd.getX()); + aPoints[0][1].Y = static_cast<sal_Int32>(rEnd.getY()); + return aPoints; +} + +double VCartesianAxis::getLogicValueWhereMainLineCrossesOtherAxis() const +{ + double fMin = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMinY(); + double fMax = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMaxY(); + + double fCrossesOtherAxis; + if(m_aAxisProperties.m_pfMainLinePositionAtOtherAxis) + fCrossesOtherAxis = *m_aAxisProperties.m_pfMainLinePositionAtOtherAxis; + else + { + if( ::com::sun::star::chart::ChartAxisPosition_END == m_aAxisProperties.m_eCrossoverType ) + fCrossesOtherAxis = fMax; + else + fCrossesOtherAxis = fMin; + } + return fCrossesOtherAxis; +} + +double VCartesianAxis::getLogicValueWhereLabelLineCrossesOtherAxis() const +{ + double fMin = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMinY(); + double fMax = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMaxY(); + + double fCrossesOtherAxis; + if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_START == m_aAxisProperties.m_eLabelPos ) + fCrossesOtherAxis = fMin; + else if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END == m_aAxisProperties.m_eLabelPos ) + fCrossesOtherAxis = fMax; + else + fCrossesOtherAxis = getLogicValueWhereMainLineCrossesOtherAxis(); + return fCrossesOtherAxis; +} + +bool VCartesianAxis::getLogicValueWhereExtraLineCrossesOtherAxis( double& fCrossesOtherAxis ) const +{ + if( !m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis ) + return false; + double fMin = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMinY(); + double fMax = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMaxY(); + if( *m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis <= fMin + || *m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis >= fMax ) + return false; + fCrossesOtherAxis = *m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis; + return true; +} + +B2DVector VCartesianAxis::getScreenPosition( double fLogicX, double fLogicY, double fLogicZ ) const +{ + B2DVector aRet(0,0); + + if( m_pPosHelper ) + { + drawing::Position3D aScenePos = m_pPosHelper->transformLogicToScene( fLogicX, fLogicY, fLogicZ, true ); + if(3==m_nDimension) + { + if( m_xLogicTarget.is() && m_pPosHelper && m_pShapeFactory ) + { + tPropertyNameMap aDummyPropertyNameMap; + Reference< drawing::XShape > xShape3DAnchor = m_pShapeFactory->createCube( m_xLogicTarget + , aScenePos,drawing::Direction3D(1,1,1), 0, 0, aDummyPropertyNameMap); + awt::Point a2DPos = xShape3DAnchor->getPosition(); //get 2D position from xShape3DAnchor + m_xLogicTarget->remove(xShape3DAnchor); + aRet.setX( a2DPos.X ); + aRet.setY( a2DPos.Y ); + } + else + { + DBG_ERROR("cannot calculate scrren position in VCartesianAxis::getScreenPosition"); + } + } + else + { + aRet.setX( aScenePos.PositionX ); + aRet.setY( aScenePos.PositionY ); + } + } + + return aRet; +} + +VCartesianAxis::ScreenPosAndLogicPos VCartesianAxis::getScreenPosAndLogicPos( double fLogicX_, double fLogicY_, double fLogicZ_ ) const +{ + ScreenPosAndLogicPos aRet; + aRet.fLogicX = fLogicX_; + aRet.fLogicY = fLogicY_; + aRet.fLogicZ = fLogicZ_; + aRet.aScreenPos = getScreenPosition( fLogicX_, fLogicY_, fLogicZ_ ); + return aRet; +} + +typedef ::std::vector< VCartesianAxis::ScreenPosAndLogicPos > tScreenPosAndLogicPosList; +struct lcl_LessXPos : ::std::binary_function< VCartesianAxis::ScreenPosAndLogicPos, VCartesianAxis::ScreenPosAndLogicPos, bool > +{ + inline bool operator() ( const VCartesianAxis::ScreenPosAndLogicPos& rPos1, const VCartesianAxis::ScreenPosAndLogicPos& rPos2 ) + { + return ( rPos1.aScreenPos.getX() < rPos2.aScreenPos.getX() ); + } +}; + +struct lcl_GreaterYPos : ::std::binary_function< VCartesianAxis::ScreenPosAndLogicPos, VCartesianAxis::ScreenPosAndLogicPos, bool > +{ + inline bool operator() ( const VCartesianAxis::ScreenPosAndLogicPos& rPos1, const VCartesianAxis::ScreenPosAndLogicPos& rPos2 ) + { + return ( rPos1.aScreenPos.getY() > rPos2.aScreenPos.getY() ); + } +}; + +void VCartesianAxis::get2DAxisMainLine( B2DVector& rStart, B2DVector& rEnd, double fCrossesOtherAxis ) +{ + //m_aAxisProperties might get updated and changed here because + // the label alignmant and inner direction sign depends exactly of the choice of the axis line position which is made here in this method + + double fMinX = m_pPosHelper->getLogicMinX(); + double fMinY = m_pPosHelper->getLogicMinY(); + double fMinZ = m_pPosHelper->getLogicMinZ(); + double fMaxX = m_pPosHelper->getLogicMaxX(); + double fMaxY = m_pPosHelper->getLogicMaxY(); + double fMaxZ = m_pPosHelper->getLogicMaxZ(); + + double fXStart = fMinX; + double fYStart = fMinY; + double fZStart = fMinZ; + double fXEnd = fXStart; + double fYEnd = fYStart; + double fZEnd = fZStart; + + double fXOnXPlane = fMinX; + double fXOther = fMaxX; + int nDifferentValue = !m_pPosHelper->isMathematicalOrientationX() ? -1 : 1; + if( !m_pPosHelper->isSwapXAndY() ) + nDifferentValue *= (CuboidPlanePosition_Left != m_eLeftWallPos) ? -1 : 1; + else + nDifferentValue *= (CuboidPlanePosition_Bottom != m_eBottomPos) ? -1 : 1; + if( nDifferentValue<0 ) + { + fXOnXPlane = fMaxX; + fXOther = fMinX; + } + + double fYOnYPlane = fMinY; + double fYOther = fMaxY; + nDifferentValue = !m_pPosHelper->isMathematicalOrientationY() ? -1 : 1; + if( !m_pPosHelper->isSwapXAndY() ) + nDifferentValue *= (CuboidPlanePosition_Bottom != m_eBottomPos) ? -1 : 1; + else + nDifferentValue *= (CuboidPlanePosition_Left != m_eLeftWallPos) ? -1 : 1; + if( nDifferentValue<0 ) + { + fYOnYPlane = fMaxY; + fYOther = fMinY; + } + + double fZOnZPlane = fMaxZ; + double fZOther = fMinZ; + nDifferentValue = !m_pPosHelper->isMathematicalOrientationZ() ? -1 : 1; + nDifferentValue *= (CuboidPlanePosition_Back != m_eBackWallPos) ? -1 : 1; + if( nDifferentValue<0 ) + { + fZOnZPlane = fMinZ; + fZOther = fMaxZ; + } + + if( 0==m_nDimensionIndex ) //x-axis + { + if( fCrossesOtherAxis < fMinY ) + fCrossesOtherAxis = fMinY; + else if( fCrossesOtherAxis > fMaxY ) + fCrossesOtherAxis = fMaxY; + + fYStart = fYEnd = fCrossesOtherAxis; + fXEnd=m_pPosHelper->getLogicMaxX(); + + if(3==m_nDimension) + { + if( AxisHelper::isAxisPositioningEnabled() ) + { + if( ::rtl::math::approxEqual( fYOther, fYStart) ) + fZStart = fZEnd = fZOnZPlane; + else + fZStart = fZEnd = fZOther; + } + else + { + rStart = getScreenPosition( fXStart, fYStart, fZStart ); + rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd ); + + double fDeltaX = rEnd.getX() - rStart.getX(); + double fDeltaY = rEnd.getY() - rStart.getY(); + + //only those points are candidates which are lying on exactly one wall as these are outer edges + tScreenPosAndLogicPosList aPosList; + aPosList.push_back( getScreenPosAndLogicPos( fMinX, fYOnYPlane, fZOther ) ); + aPosList.push_back( getScreenPosAndLogicPos( fMinX, fYOther, fZOnZPlane ) ); + + if( fabs(fDeltaY) > fabs(fDeltaX) ) + { + m_aAxisProperties.m_aLabelAlignment = LABEL_ALIGN_LEFT; + //choose most left positions + ::std::sort( aPosList.begin(), aPosList.end(), lcl_LessXPos() ); + m_aAxisProperties.m_fLabelDirectionSign = fDeltaY<0 ? -1 : 1; + } + else + { + m_aAxisProperties.m_aLabelAlignment = LABEL_ALIGN_BOTTOM; + //choose most bottom positions + ::std::sort( aPosList.begin(), aPosList.end(), lcl_GreaterYPos() ); + m_aAxisProperties.m_fLabelDirectionSign = fDeltaX<0 ? -1 : 1; + } + ScreenPosAndLogicPos aBestPos( aPosList[0] ); + fYStart = fYEnd = aBestPos.fLogicY; + fZStart = fZEnd = aBestPos.fLogicZ; + if( !m_pPosHelper->isMathematicalOrientationX() ) + m_aAxisProperties.m_fLabelDirectionSign *= -1; + } + }//end 3D x axis + } + else if( 1==m_nDimensionIndex ) //y-axis + { + if( fCrossesOtherAxis < fMinX ) + fCrossesOtherAxis = fMinX; + else if( fCrossesOtherAxis > fMaxX ) + fCrossesOtherAxis = fMaxX; + + fXStart = fXEnd = fCrossesOtherAxis; + fYEnd=m_pPosHelper->getLogicMaxY(); + + if(3==m_nDimension) + { + if( AxisHelper::isAxisPositioningEnabled() ) + { + if( ::rtl::math::approxEqual( fXOther, fXStart) ) + fZStart = fZEnd = fZOnZPlane; + else + fZStart = fZEnd = fZOther; + } + else + { + rStart = getScreenPosition( fXStart, fYStart, fZStart ); + rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd ); + + double fDeltaX = rEnd.getX() - rStart.getX(); + double fDeltaY = rEnd.getY() - rStart.getY(); + + //only those points are candidates which are lying on exactly one wall as these are outer edges + tScreenPosAndLogicPosList aPosList; + aPosList.push_back( getScreenPosAndLogicPos( fXOnXPlane, fMinY, fZOther ) ); + aPosList.push_back( getScreenPosAndLogicPos( fXOther, fMinY, fZOnZPlane ) ); + + if( fabs(fDeltaY) > fabs(fDeltaX) ) + { + m_aAxisProperties.m_aLabelAlignment = LABEL_ALIGN_LEFT; + //choose most left positions + ::std::sort( aPosList.begin(), aPosList.end(), lcl_LessXPos() ); + m_aAxisProperties.m_fLabelDirectionSign = fDeltaY<0 ? -1 : 1; + } + else + { + m_aAxisProperties.m_aLabelAlignment = LABEL_ALIGN_BOTTOM; + //choose most bottom positions + ::std::sort( aPosList.begin(), aPosList.end(), lcl_GreaterYPos() ); + m_aAxisProperties.m_fLabelDirectionSign = fDeltaX<0 ? -1 : 1; + } + ScreenPosAndLogicPos aBestPos( aPosList[0] ); + fXStart = fXEnd = aBestPos.fLogicX; + fZStart = fZEnd = aBestPos.fLogicZ; + if( !m_pPosHelper->isMathematicalOrientationY() ) + m_aAxisProperties.m_fLabelDirectionSign *= -1; + } + }//end 3D y axis + } + else //z-axis + { + fZEnd = m_pPosHelper->getLogicMaxZ(); + if( AxisHelper::isAxisPositioningEnabled() ) + { + if( !m_aAxisProperties.m_bSwapXAndY ) + { + if( fCrossesOtherAxis < fMinY ) + fCrossesOtherAxis = fMinY; + else if( fCrossesOtherAxis > fMaxY ) + fCrossesOtherAxis = fMaxY; + fYStart = fYEnd = fCrossesOtherAxis; + + if( ::rtl::math::approxEqual( fYOther, fYStart) ) + fXStart = fXEnd = fXOnXPlane; + else + fXStart = fXEnd = fXOther; + } + else + { + if( fCrossesOtherAxis < fMinX ) + fCrossesOtherAxis = fMinX; + else if( fCrossesOtherAxis > fMaxX ) + fCrossesOtherAxis = fMaxX; + fXStart = fXEnd = fCrossesOtherAxis; + + if( ::rtl::math::approxEqual( fXOther, fXStart) ) + fYStart = fYEnd = fYOnYPlane; + else + fYStart = fYEnd = fYOther; + } + } + else + { + if( !m_pPosHelper->isSwapXAndY() ) + { + fXStart = fXEnd = m_pPosHelper->isMathematicalOrientationX() ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMinX(); + fYStart = fYEnd = m_pPosHelper->isMathematicalOrientationY() ? m_pPosHelper->getLogicMinY() : m_pPosHelper->getLogicMaxY(); + } + else + { + fXStart = fXEnd = m_pPosHelper->isMathematicalOrientationX() ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMaxX(); + fYStart = fYEnd = m_pPosHelper->isMathematicalOrientationY() ? m_pPosHelper->getLogicMaxY() : m_pPosHelper->getLogicMinY(); + } + + if(3==m_nDimension) + { + rStart = getScreenPosition( fXStart, fYStart, fZStart ); + rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd ); + + double fDeltaX = rEnd.getX() - rStart.getX(); + + //only those points are candidates which are lying on exactly one wall as these are outer edges + tScreenPosAndLogicPosList aPosList; + aPosList.push_back( getScreenPosAndLogicPos( fXOther, fYOnYPlane, fMinZ ) ); + aPosList.push_back( getScreenPosAndLogicPos( fXOnXPlane, fYOther, fMinZ ) ); + + ::std::sort( aPosList.begin(), aPosList.end(), lcl_GreaterYPos() ); + ScreenPosAndLogicPos aBestPos( aPosList[0] ); + ScreenPosAndLogicPos aNotSoGoodPos( aPosList[1] ); + + //choose most bottom positions + if( !::rtl::math::approxEqual( fDeltaX, 0.0 ) ) // prefere left-right algnments + { + if( aBestPos.aScreenPos.getX() > aNotSoGoodPos.aScreenPos.getX() ) + m_aAxisProperties.m_aLabelAlignment = LABEL_ALIGN_RIGHT; + else + m_aAxisProperties.m_aLabelAlignment = LABEL_ALIGN_LEFT; + } + else + { + if( aBestPos.aScreenPos.getY() > aNotSoGoodPos.aScreenPos.getY() ) + m_aAxisProperties.m_aLabelAlignment = LABEL_ALIGN_BOTTOM; + else + m_aAxisProperties.m_aLabelAlignment = LABEL_ALIGN_TOP; + } + + m_aAxisProperties.m_fLabelDirectionSign = fDeltaX<0 ? -1 : 1; + if( !m_pPosHelper->isMathematicalOrientationZ() ) + m_aAxisProperties.m_fLabelDirectionSign *= -1; + + fXStart = fXEnd = aBestPos.fLogicX; + fYStart = fYEnd = aBestPos.fLogicY; + } + }//end 3D z axis + } + + rStart = getScreenPosition( fXStart, fYStart, fZStart ); + rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd ); + + if(3==m_nDimension && !AxisHelper::isAxisPositioningEnabled() ) + m_aAxisProperties.m_fInnerDirectionSign = m_aAxisProperties.m_fLabelDirectionSign;//to behave like before + + if(3==m_nDimension && AxisHelper::isAxisPositioningEnabled() ) + { + double fDeltaX = rEnd.getX() - rStart.getX(); + double fDeltaY = rEnd.getY() - rStart.getY(); + + if( 2==m_nDimensionIndex ) + { + if( m_eLeftWallPos != CuboidPlanePosition_Left ) + { + m_aAxisProperties.m_fLabelDirectionSign *= -1.0; + m_aAxisProperties.m_fInnerDirectionSign *= -1.0; + } + + m_aAxisProperties.m_aLabelAlignment = + ( m_aAxisProperties.m_fLabelDirectionSign<0 ) ? + LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT; + + if( ( fDeltaY<0 && m_aScale.Orientation == AxisOrientation_REVERSE ) || + ( fDeltaY>0 && m_aScale.Orientation == AxisOrientation_MATHEMATICAL ) ) + m_aAxisProperties.m_aLabelAlignment = + ( m_aAxisProperties.m_aLabelAlignment==LABEL_ALIGN_RIGHT ) ? + LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT; + } + else if( fabs(fDeltaY) > fabs(fDeltaX) ) + { + if( m_eBackWallPos != CuboidPlanePosition_Back ) + { + m_aAxisProperties.m_fLabelDirectionSign *= -1.0; + m_aAxisProperties.m_fInnerDirectionSign *= -1.0; + } + + m_aAxisProperties.m_aLabelAlignment = + ( m_aAxisProperties.m_fLabelDirectionSign<0 ) ? + LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT; + + if( ( fDeltaY<0 && m_aScale.Orientation == AxisOrientation_REVERSE ) || + ( fDeltaY>0 && m_aScale.Orientation == AxisOrientation_MATHEMATICAL ) ) + m_aAxisProperties.m_aLabelAlignment = + ( m_aAxisProperties.m_aLabelAlignment==LABEL_ALIGN_RIGHT ) ? + LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT; + } + else + { + if( m_eBackWallPos != CuboidPlanePosition_Back ) + { + m_aAxisProperties.m_fLabelDirectionSign *= -1.0; + m_aAxisProperties.m_fInnerDirectionSign *= -1.0; + } + + m_aAxisProperties.m_aLabelAlignment = + ( m_aAxisProperties.m_fLabelDirectionSign<0 ) ? + LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM; + + if( ( fDeltaX>0 && m_aScale.Orientation == AxisOrientation_REVERSE ) || + ( fDeltaX<0 && m_aScale.Orientation == AxisOrientation_MATHEMATICAL ) ) + m_aAxisProperties.m_aLabelAlignment = + ( m_aAxisProperties.m_aLabelAlignment==LABEL_ALIGN_TOP ) ? + LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP; + } + } +} + +TickFactory* VCartesianAxis::createTickFactory() +{ + return createTickFactory2D(); +} + +TickFactory_2D* VCartesianAxis::createTickFactory2D() +{ + B2DVector aStart, aEnd; + this->get2DAxisMainLine( aStart, aEnd, this->getLogicValueWhereMainLineCrossesOtherAxis() ); + + B2DVector aLabelLineStart, aLabelLineEnd; + this->get2DAxisMainLine( aLabelLineStart, aLabelLineEnd, this->getLogicValueWhereLabelLineCrossesOtherAxis() ); + + return new TickFactory_2D( m_aScale, m_aIncrement, aStart, aEnd, aLabelLineStart-aStart ); +} + +void lcl_hideIdenticalScreenValues( TickIter& rTickIter ) +{ + TickInfo* pPreviousTickInfo = rTickIter.firstInfo(); + if(!pPreviousTickInfo) + return; + pPreviousTickInfo->bPaintIt = true; + for( TickInfo* pTickInfo = rTickIter.nextInfo(); pTickInfo; pTickInfo = rTickIter.nextInfo()) + { + pTickInfo->bPaintIt = + ( static_cast<sal_Int32>(pTickInfo->aTickScreenPosition.getX()) + != static_cast<sal_Int32>(pPreviousTickInfo->aTickScreenPosition.getX()) ) + || + ( static_cast<sal_Int32>(pTickInfo->aTickScreenPosition.getY()) + != static_cast<sal_Int32>(pPreviousTickInfo->aTickScreenPosition.getY()) ); + pPreviousTickInfo = pTickInfo; + } +} + +//'hide' tickmarks with identical screen values in aAllTickInfos +void VCartesianAxis::hideIdenticalScreenValues( ::std::vector< ::std::vector< TickInfo > >& rTickInfos ) const +{ + if( isComplexCategoryAxis() || isDateAxis() ) + { + sal_Int32 nCount = rTickInfos.size(); + for( sal_Int32 nN=0; nN<nCount; nN++ ) + { + PureTickIter aTickIter( rTickInfos[nN] ); + lcl_hideIdenticalScreenValues( aTickIter ); + } + } + else + { + EquidistantTickIter aTickIter( rTickInfos, m_aIncrement, 0, -1 ); + lcl_hideIdenticalScreenValues( aTickIter ); + } +} + +sal_Int32 VCartesianAxis::estimateMaximumAutoMainIncrementCount() +{ + sal_Int32 nRet = 10; + + if( m_nMaximumTextWidthSoFar==0 && m_nMaximumTextHeightSoFar==0 ) + return nRet; + + B2DVector aStart, aEnd; + this->get2DAxisMainLine( aStart, aEnd, this->getLogicValueWhereMainLineCrossesOtherAxis() ); + + sal_Int32 nMaxHeight = static_cast<sal_Int32>(fabs(aEnd.getY()-aStart.getY())); + sal_Int32 nMaxWidth = static_cast<sal_Int32>(fabs(aEnd.getX()-aStart.getX())); + + sal_Int32 nTotalAvailable = nMaxHeight; + sal_Int32 nSingleNeeded = m_nMaximumTextHeightSoFar; + + //for horizontal axis: + if( (m_nDimensionIndex == 0 && !m_aAxisProperties.m_bSwapXAndY) + || (m_nDimensionIndex == 1 && m_aAxisProperties.m_bSwapXAndY) ) + { + nTotalAvailable = nMaxWidth; + nSingleNeeded = m_nMaximumTextWidthSoFar; + } + + if( nSingleNeeded>0 ) + nRet = nTotalAvailable/nSingleNeeded; + + return nRet; +} + +void VCartesianAxis::doStaggeringOfLabels( const AxisLabelProperties& rAxisLabelProperties, TickFactory_2D* pTickFactory2D ) +{ + if( !pTickFactory2D ) + return; + + if( isComplexCategoryAxis() ) + { + sal_Int32 nTextLevelCount = getTextLevelCount(); + B2DVector aCummulatedLabelsDistance(0,0); + for( sal_Int32 nTextLevel=0; nTextLevel<nTextLevelCount; nTextLevel++ ) + { + ::std::auto_ptr< TickIter > apTickIter = createLabelTickIterator( nTextLevel ); + if(apTickIter.get()) + { + double fRotationAngleDegree = m_aAxisLabelProperties.fRotationAngleDegree; + if( nTextLevel>0 ) + { + lcl_shiftLables( *apTickIter.get(), aCummulatedLabelsDistance ); + fRotationAngleDegree = 0.0; + } + aCummulatedLabelsDistance += lcl_getLabelsDistance( *apTickIter.get() + , pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties ) + , fRotationAngleDegree ); + } + } + } + else if( rAxisLabelProperties.getIsStaggered() ) + { + if( !m_aAllTickInfos.empty() ) + { + LabelIterator aInnerIter( m_aAllTickInfos[0], rAxisLabelProperties.eStaggering, true ); + LabelIterator aOuterIter( m_aAllTickInfos[0], rAxisLabelProperties.eStaggering, false ); + + lcl_shiftLables( aOuterIter + , lcl_getLabelsDistance( aInnerIter + , pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties ), 0.0 ) ); + } + } +} + +void VCartesianAxis::createLabels() +{ + if( !prepareShapeCreation() ) + return; + + //----------------------------------------- + //create labels + if( m_aAxisProperties.m_bDisplayLabels ) + { + std::auto_ptr< TickFactory_2D > apTickFactory2D( this->createTickFactory2D() ); + TickFactory_2D* pTickFactory2D = apTickFactory2D.get(); + if( !pTickFactory2D ) + return; + + //----------------------------------------- + //get the transformed screen values for all tickmarks in aAllTickInfos + pTickFactory2D->updateScreenValues( m_aAllTickInfos ); + //----------------------------------------- + //'hide' tickmarks with identical screen values in aAllTickInfos + hideIdenticalScreenValues( m_aAllTickInfos ); + + removeTextShapesFromTicks(); + + //create tick mark text shapes + sal_Int32 nTextLevelCount = getTextLevelCount(); + sal_Int32 nScreenDistanceBetweenTicks = -1; + for( sal_Int32 nTextLevel=0; nTextLevel<nTextLevelCount; nTextLevel++ ) + { + ::std::auto_ptr< TickIter > apTickIter = createLabelTickIterator( nTextLevel ); + if(apTickIter.get()) + { + if(nTextLevel==0) + { + nScreenDistanceBetweenTicks = TickFactory_2D::getTickScreenDistance( *apTickIter.get() ); + if( nTextLevelCount>1 ) + nScreenDistanceBetweenTicks*=2; //the above used tick iter does contain also the sub ticks -> thus the given distance is only the half + } + + AxisLabelProperties aComplexProps(m_aAxisLabelProperties); + if( m_aAxisProperties.m_bComplexCategories ) + { + if( nTextLevel==0 ) + { + aComplexProps.bLineBreakAllowed = true; + aComplexProps.bOverlapAllowed = !::rtl::math::approxEqual( aComplexProps.fRotationAngleDegree, 0.0 ); + } + else + { + aComplexProps.bOverlapAllowed = true; + aComplexProps.bRhythmIsFix = true; + aComplexProps.nRhythm = 1; + aComplexProps.fRotationAngleDegree = 0.0; + } + } + AxisLabelProperties& rAxisLabelProperties = m_aAxisProperties.m_bComplexCategories ? aComplexProps : m_aAxisLabelProperties; + while( !createTextShapes( m_xTextTarget, *apTickIter.get(), rAxisLabelProperties, pTickFactory2D, nScreenDistanceBetweenTicks ) ) + { + }; + } + } + doStaggeringOfLabels( m_aAxisLabelProperties, pTickFactory2D ); + } +} + +void VCartesianAxis::createMaximumLabels() +{ + TrueGuard aRecordMaximumTextSize(m_bRecordMaximumTextSize); + + if( !prepareShapeCreation() ) + return; + + //----------------------------------------- + //create labels + if( m_aAxisProperties.m_bDisplayLabels ) + { + std::auto_ptr< TickFactory_2D > apTickFactory2D( this->createTickFactory2D() ); + TickFactory_2D* pTickFactory2D = apTickFactory2D.get(); + if( !pTickFactory2D ) + return; + + //----------------------------------------- + //get the transformed screen values for all tickmarks in aAllTickInfos + pTickFactory2D->updateScreenValues( m_aAllTickInfos ); + + //create tick mark text shapes + //@todo: iterate through all tick depth wich should be labeled + + AxisLabelProperties aAxisLabelProperties( m_aAxisLabelProperties ); + if( isAutoStaggeringOfLabelsAllowed( aAxisLabelProperties, pTickFactory2D->isHorizontalAxis(), pTickFactory2D->isVerticalAxis() ) ) + aAxisLabelProperties.eStaggering = STAGGER_EVEN; + aAxisLabelProperties.bOverlapAllowed = true; + aAxisLabelProperties.bLineBreakAllowed = false; + sal_Int32 nTextLevelCount = getTextLevelCount(); + for( sal_Int32 nTextLevel=0; nTextLevel<nTextLevelCount; nTextLevel++ ) + { + ::std::auto_ptr< TickIter > apTickIter = createMaximumLabelTickIterator( nTextLevel ); + if(apTickIter.get()) + { + while( !createTextShapes( m_xTextTarget, *apTickIter.get(), aAxisLabelProperties, pTickFactory2D, -1 ) ) + { + }; + } + } + doStaggeringOfLabels( aAxisLabelProperties, pTickFactory2D ); + } +} + +void VCartesianAxis::updatePositions() +{ + //----------------------------------------- + //update positions of labels + if( m_aAxisProperties.m_bDisplayLabels ) + { + std::auto_ptr< TickFactory_2D > apTickFactory2D( this->createTickFactory2D() ); + TickFactory_2D* pTickFactory2D = apTickFactory2D.get(); + if( !pTickFactory2D ) + return; + + //----------------------------------------- + //update positions of all existing text shapes + pTickFactory2D->updateScreenValues( m_aAllTickInfos ); + + ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter = m_aAllTickInfos.begin(); + const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd = m_aAllTickInfos.end(); + for( sal_Int32 nDepth=0; aDepthIter != aDepthEnd; aDepthIter++, nDepth++ ) + { + ::std::vector< TickInfo >::iterator aTickIter = aDepthIter->begin(); + const ::std::vector< TickInfo >::const_iterator aTickEnd = aDepthIter->end(); + for( ; aTickIter != aTickEnd; aTickIter++ ) + { + TickInfo& rTickInfo = (*aTickIter); + Reference< drawing::XShape > xShape2DText( rTickInfo.xTextShape ); + if( xShape2DText.is() ) + { + B2DVector aTextToTickDistance( pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties, true ) ); + B2DVector aTickScreenPos2D( rTickInfo.aTickScreenPosition ); + aTickScreenPos2D += aTextToTickDistance; + awt::Point aAnchorScreenPosition2D( + static_cast<sal_Int32>(aTickScreenPos2D.getX()) + ,static_cast<sal_Int32>(aTickScreenPos2D.getY())); + + double fRotationAngleDegree = m_aAxisLabelProperties.fRotationAngleDegree; + if( nDepth>0 ) + fRotationAngleDegree = 0.0; + + // #i78696# use mathematically correct rotation now + const double fRotationAnglePi(fRotationAngleDegree * (F_PI / -180.0)); + uno::Any aATransformation = ShapeFactory::makeTransformation(aAnchorScreenPosition2D, fRotationAnglePi); + + //set new position + uno::Reference< beans::XPropertySet > xProp( xShape2DText, uno::UNO_QUERY ); + if( xProp.is() ) + { + try + { + xProp->setPropertyValue( C2U( "Transformation" ), aATransformation ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + + //correctPositionForRotation + LabelPositionHelper::correctPositionForRotation( xShape2DText + , m_aAxisProperties.m_aLabelAlignment, fRotationAngleDegree, m_aAxisProperties.m_bComplexCategories ); + } + } + } + + doStaggeringOfLabels( m_aAxisLabelProperties, pTickFactory2D ); + } +} + +void VCartesianAxis::createTickMarkLineShapes( ::std::vector< TickInfo >& rTickInfos, const TickmarkProperties& rTickmarkProperties, TickFactory_2D& rTickFactory2D, bool bOnlyAtLabels ) +{ + sal_Int32 nPointCount = rTickInfos.size(); + drawing::PointSequenceSequence aPoints(2*nPointCount); + + ::std::vector< TickInfo >::const_iterator aTickIter = rTickInfos.begin(); + const ::std::vector< TickInfo >::const_iterator aTickEnd = rTickInfos.end(); + sal_Int32 nN = 0; + for( ; aTickIter != aTickEnd; aTickIter++ ) + { + if( !(*aTickIter).bPaintIt ) + continue; + + bool bTicksAtLabels = ( m_aAxisProperties.m_eTickmarkPos != ::com::sun::star::chart::ChartAxisMarkPosition_AT_AXIS ); + double fInnerDirectionSign = m_aAxisProperties.m_fInnerDirectionSign; + if( bTicksAtLabels && m_aAxisProperties.m_eLabelPos == ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END ) + fInnerDirectionSign *= -1.0; + bTicksAtLabels = bTicksAtLabels || bOnlyAtLabels; + //add ticks at labels: + rTickFactory2D.addPointSequenceForTickLine( aPoints, nN++, (*aTickIter).fScaledTickValue + , fInnerDirectionSign , rTickmarkProperties, bTicksAtLabels ); + //add ticks at axis (without lables): + if( !bOnlyAtLabels && m_aAxisProperties.m_eTickmarkPos == ::com::sun::star::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS ) + rTickFactory2D.addPointSequenceForTickLine( aPoints, nN++, (*aTickIter).fScaledTickValue + , m_aAxisProperties.m_fInnerDirectionSign, rTickmarkProperties, !bTicksAtLabels ); + } + aPoints.realloc(nN); + m_pShapeFactory->createLine2D( m_xGroupShape_Shapes, aPoints + , &rTickmarkProperties.aLineProperties ); +} + +void VCartesianAxis::createShapes() +{ + if( !prepareShapeCreation() ) + return; + + std::auto_ptr< TickFactory_2D > apTickFactory2D( this->createTickFactory2D() ); + TickFactory_2D* pTickFactory2D = apTickFactory2D.get(); + if( !pTickFactory2D ) + return; + + //----------------------------------------- + //create line shapes + if(2==m_nDimension) + { + //----------------------------------------- + //create extra long ticks to separate complex categories (create them only there where the labels are) + if( isComplexCategoryAxis() ) + { + ::std::vector< ::std::vector< TickInfo > > aComplexTickInfos; + createAllTickInfosFromComplexCategories( aComplexTickInfos, true ); + pTickFactory2D->updateScreenValues( aComplexTickInfos ); + hideIdenticalScreenValues( aComplexTickInfos ); + + ::std::vector<TickmarkProperties> aTickmarkPropertiesList; + static bool bIncludeSpaceBetweenTickAndText = false; + sal_Int32 nOffset = static_cast<sal_Int32>(pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties, false, bIncludeSpaceBetweenTickAndText ).getLength()); + sal_Int32 nTextLevelCount = getTextLevelCount(); + for( sal_Int32 nTextLevel=0; nTextLevel<nTextLevelCount; nTextLevel++ ) + { + ::std::auto_ptr< TickIter > apTickIter = createLabelTickIterator( nTextLevel ); + if( apTickIter.get() ) + { + double fRotationAngleDegree = m_aAxisLabelProperties.fRotationAngleDegree; + if( nTextLevel>0 ) + fRotationAngleDegree = 0.0; + B2DVector aLabelsDistance( lcl_getLabelsDistance( *apTickIter.get(), pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties, false ), fRotationAngleDegree ) ); + sal_Int32 nCurrentLength = static_cast<sal_Int32>(aLabelsDistance.getLength()); + aTickmarkPropertiesList.push_back( m_aAxisProperties.makeTickmarkPropertiesForComplexCategories( nOffset + nCurrentLength, 0, nTextLevel ) ); + nOffset += nCurrentLength; + } + } + + sal_Int32 nTickmarkPropertiesCount = aTickmarkPropertiesList.size(); + ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter = aComplexTickInfos.begin(); + const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd = aComplexTickInfos.end(); + for( sal_Int32 nDepth=0; aDepthIter != aDepthEnd && nDepth < nTickmarkPropertiesCount; aDepthIter++, nDepth++ ) + { + if(nDepth==0 && !m_aAxisProperties.m_nMajorTickmarks) + continue; + createTickMarkLineShapes( *aDepthIter, aTickmarkPropertiesList[nDepth], *pTickFactory2D, true /*bOnlyAtLabels*/ ); + } + } + //----------------------------------------- + //create normal ticks for major and minor intervals + { + ::std::vector< ::std::vector< TickInfo > > aUnshiftedTickInfos; + if( m_aScale.ShiftedCategoryPosition )// if ShiftedCategoryPosition==true the tickmarks in m_aAllTickInfos are shifted + { + pTickFactory2D->getAllTicks( aUnshiftedTickInfos ); + pTickFactory2D->updateScreenValues( aUnshiftedTickInfos ); + hideIdenticalScreenValues( aUnshiftedTickInfos ); + } + ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos = m_aScale.ShiftedCategoryPosition ? aUnshiftedTickInfos : m_aAllTickInfos; + + ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter = rAllTickInfos.begin(); + const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd = rAllTickInfos.end(); + if(aDepthIter == aDepthEnd)//no tickmarks at all + return; + + sal_Int32 nTickmarkPropertiesCount = m_aAxisProperties.m_aTickmarkPropertiesList.size(); + for( sal_Int32 nDepth=0; aDepthIter != aDepthEnd && nDepth < nTickmarkPropertiesCount; aDepthIter++, nDepth++ ) + createTickMarkLineShapes( *aDepthIter, m_aAxisProperties.m_aTickmarkPropertiesList[nDepth], *pTickFactory2D, false /*bOnlyAtLabels*/ ); + } + //----------------------------------------- + //create axis main lines + //it serves also as the handle shape for the axis selection + { + drawing::PointSequenceSequence aPoints(1); + apTickFactory2D->createPointSequenceForAxisMainLine( aPoints ); + Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D( + m_xGroupShape_Shapes, aPoints + , &m_aAxisProperties.m_aLineProperties ); + //because of this name this line will be used for marking the axis + m_pShapeFactory->setShapeName( xShape, C2U("MarkHandles") ); + } + //----------------------------------------- + //create an additional line at NULL + if( !AxisHelper::isAxisPositioningEnabled() ) + { + double fExtraLineCrossesOtherAxis; + if( getLogicValueWhereExtraLineCrossesOtherAxis(fExtraLineCrossesOtherAxis) ) + { + B2DVector aStart, aEnd; + this->get2DAxisMainLine( aStart, aEnd, fExtraLineCrossesOtherAxis ); + drawing::PointSequenceSequence aPoints( lcl_makePointSequence(aStart,aEnd) ); + Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D( + m_xGroupShape_Shapes, aPoints, &m_aAxisProperties.m_aLineProperties ); + } + } + } + + //createLabels(); +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/VCartesianAxis.hxx b/chart2/source/view/axes/VCartesianAxis.hxx new file mode 100644 index 000000000000..d199a112bab1 --- /dev/null +++ b/chart2/source/view/axes/VCartesianAxis.hxx @@ -0,0 +1,137 @@ +/************************************************************************* + * + * 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_VCARTESIANAXIS_HXX +#define _CHART2_VCARTESIANAXIS_HXX + +#include "VAxisBase.hxx" +#include <basegfx/vector/b2dvector.hxx> + +#include <memory> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +class VCartesianAxis : public VAxisBase +{ + //------------------------------------------------------------------------- + // public methods + //------------------------------------------------------------------------- +public: + VCartesianAxis( const AxisProperties& rAxisProperties + , const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , PlottingPositionHelper* pPosHelper = NULL //takes ownership + ); + + virtual ~VCartesianAxis(); + + virtual void createMaximumLabels(); + virtual void createLabels(); + virtual void updatePositions(); + + virtual void createShapes(); + + virtual sal_Int32 estimateMaximumAutoMainIncrementCount(); + virtual void createAllTickInfos( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ); + void createAllTickInfosFromComplexCategories( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos, bool bShiftedPosition ); + + ::std::auto_ptr< TickIter > createLabelTickIterator( sal_Int32 nTextLevel ); + ::std::auto_ptr< TickIter > createMaximumLabelTickIterator( sal_Int32 nTextLevel ); + sal_Int32 getTextLevelCount() const; + + //------------------------------------------------------------------------- + virtual TickFactory* createTickFactory(); + + //------------------------------------------------------------------------- + double getLogicValueWhereMainLineCrossesOtherAxis() const; + double getLogicValueWhereLabelLineCrossesOtherAxis() const; + bool getLogicValueWhereExtraLineCrossesOtherAxis( double& fCrossesOtherAxis) const; + void get2DAxisMainLine( ::basegfx::B2DVector& rStart, ::basegfx::B2DVector& rEnd, double fCrossesOtherAxis ); + + //------------------------------------------------------------------------- + //Layout interface for cartesian axes: + + //the returned value describes the minimum size that is necessary + //for the text labels in the direction orthogonal to the axis + //(for an y-axis a width is returned; in case of an x-axis the value describes a height) + //the return value is measured in screen dimension + //As an example the MinimumOrthogonalSize of an x-axis equals the + //Font Height if the label properties allow for labels parallel to the axis. +// sal_Int32 calculateMinimumOrthogonalSize( /*... parallel...*/ ); + //Minimum->Preferred + + //returns true if the MinimumOrthogonalSize can be calculated + //with the creation of at most one text shape + //(this is e.g. true if the parameters allow for labels parallel to the axis.) +// sal_bool canQuicklyCalculateMinimumOrthogonalSize(); + + + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + + struct ScreenPosAndLogicPos + { + double fLogicX; + double fLogicY; + double fLogicZ; + + B2DVector aScreenPos; + }; + +protected: //methods + bool createTextShapes( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget + , TickIter& rTickIter + , AxisLabelProperties& rAxisLabelProperties + , TickFactory_2D* pTickFactory + , sal_Int32 nScreenDistanceBetweenTicks ); + + void createTickMarkLineShapes( ::std::vector< TickInfo >& rTickInfos, const TickmarkProperties& rTickmarkProperties, TickFactory_2D& rTickFactory2D, bool bOnlyAtLabels ); + + TickFactory_2D* createTickFactory2D(); + void hideIdenticalScreenValues( ::std::vector< ::std::vector< TickInfo > >& rTickInfos ) const; + + void doStaggeringOfLabels( const AxisLabelProperties& rAxisLabelProperties + , TickFactory_2D* pTickFactory2D ); + bool isAutoStaggeringOfLabelsAllowed( const AxisLabelProperties& rAxisLabelProperties + , bool bIsHorizontalAxis, bool bIsVerticalAxis ); + bool isBreakOfLabelsAllowed( const AxisLabelProperties& rAxisLabelProperties, bool bIsHorizontalAxis ); + + ::basegfx::B2DVector getScreenPosition( double fLogicX, double fLogicY, double fLogicZ ) const; + ScreenPosAndLogicPos getScreenPosAndLogicPos( double fLogicX, double fLogicY, double fLogicZ ) const; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/VCartesianCoordinateSystem.cxx b/chart2/source/view/axes/VCartesianCoordinateSystem.cxx new file mode 100644 index 000000000000..ca83850a88ff --- /dev/null +++ b/chart2/source/view/axes/VCartesianCoordinateSystem.cxx @@ -0,0 +1,233 @@ +/************************************************************************* + * + * 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 "VCartesianCoordinateSystem.hxx" +#include "VCartesianGrid.hxx" +#include "VCartesianAxis.hxx" +#include "macros.hxx" +#include "AxisIndexDefines.hxx" +#include "AxisHelper.hxx" +#include "ChartTypeHelper.hxx" + +//for auto_ptr +#include <memory> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +//............................................................................. + +class TextualDataProvider : public ::cppu::WeakImplHelper1< + ::com::sun::star::chart2::data::XTextualDataSequence + > +{ +public: + TextualDataProvider( const uno::Sequence< ::rtl::OUString >& rTextSequence ) + : m_aTextSequence( rTextSequence ) + { + } + virtual ~TextualDataProvider() + { + } + + //XTextualDataSequence + virtual uno::Sequence< ::rtl::OUString > SAL_CALL getTextualData() + throw ( uno::RuntimeException) + { + return m_aTextSequence; + } + +private: //member + uno::Sequence< ::rtl::OUString > m_aTextSequence; +}; + +//............................................................................. + +VCartesianCoordinateSystem::VCartesianCoordinateSystem( const Reference< XCoordinateSystem >& xCooSys ) + : VCoordinateSystem(xCooSys) +{ +} + +VCartesianCoordinateSystem::~VCartesianCoordinateSystem() +{ +} + +void VCartesianCoordinateSystem::createGridShapes() +{ + if(!m_xLogicTargetForGrids.is() || !m_xFinalTarget.is() ) + return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = this->getPropertySwapXAndYAxis(); + + for( sal_Int32 nDimensionIndex=0; nDimensionIndex<3; nDimensionIndex++) + { + sal_Int32 nAxisIndex = MAIN_AXIS_INDEX; + Reference< XAxis > xAxis( AxisHelper::getAxis( nDimensionIndex, nAxisIndex, m_xCooSysModel ) ); + if(!xAxis.is() || !AxisHelper::shouldAxisBeDisplayed( xAxis, m_xCooSysModel )) + continue; + + VCartesianGrid aGrid(nDimensionIndex,nDimensionCount,this->getGridListFromAxis( xAxis )); + aGrid.setExplicitScaleAndIncrement( this->getExplicitScale(nDimensionIndex,nAxisIndex) + , this->getExplicitIncrement(nDimensionIndex,nAxisIndex) ); + aGrid.set3DWallPositions( m_eLeftWallPos, m_eBackWallPos, m_eBottomPos ); + + aGrid.initPlotter(m_xLogicTargetForGrids,m_xFinalTarget,m_xShapeFactory + , this->createCIDForGrid( xAxis,nDimensionIndex,nAxisIndex ) ); + if(2==nDimensionCount) + aGrid.setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + aGrid.setScales( this->getExplicitScales(nDimensionIndex,nAxisIndex), bSwapXAndY ); + aGrid.createShapes(); + } +} + +void VCartesianCoordinateSystem::createVAxisList( + const uno::Reference< util::XNumberFormatsSupplier > & xNumberFormatsSupplier + , const awt::Size& rFontReferenceSize + , const awt::Rectangle& rMaximumSpaceForLabels + ) +{ + m_aAxisMap.clear(); + + //if(!m_xLogicTargetForAxes.is() || !m_xFinalTarget.is() || !m_xCooSysModel.is() ) + // return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = this->getPropertySwapXAndYAxis(); + + if(nDimensionCount<=0) + return; + + sal_Int32 nDimensionIndex = 0; + + for( nDimensionIndex = 0; nDimensionIndex < nDimensionCount; nDimensionIndex++ ) + { + sal_Int32 nMaxAxisIndex = m_xCooSysModel->getMaximumAxisIndexByDimension(nDimensionIndex); + for( sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; nAxisIndex++ ) + { + Reference< XAxis > xAxis = this->getAxisByDimension(nDimensionIndex,nAxisIndex); + if(!xAxis.is() || !AxisHelper::shouldAxisBeDisplayed( xAxis, m_xCooSysModel )) + continue; + + AxisProperties aAxisProperties(xAxis,this->getExplicitCategoriesProvider()); + aAxisProperties.m_nDimensionIndex = nDimensionIndex; + aAxisProperties.m_bSwapXAndY = bSwapXAndY; + aAxisProperties.m_bIsMainAxis = (nAxisIndex==0); + Reference< XAxis > xCrossingMainAxis( AxisHelper::getCrossingMainAxis( xAxis, m_xCooSysModel ) ); + if( xCrossingMainAxis.is() ) + { + ScaleData aCrossingScale( xCrossingMainAxis->getScaleData() ); + aAxisProperties.m_bCrossingAxisHasReverseDirection = (AxisOrientation_REVERSE==aCrossingScale.Orientation); + + if( aCrossingScale.AxisType == AxisType::CATEGORY ) + aAxisProperties.m_bCrossingAxisIsCategoryAxes = true; + } + + if( nDimensionIndex == 2 ) + { + aAxisProperties.m_xAxisTextProvider = new TextualDataProvider( m_aSeriesNamesForZAxis ); + + //for the z axis copy the positioning properties from the x axis (or from the y axis for swapped coordinate systems) + Reference< XAxis > xSisterAxis( AxisHelper::getCrossingMainAxis( xCrossingMainAxis, m_xCooSysModel ) ); + aAxisProperties.initAxisPositioning( Reference< beans::XPropertySet >( xSisterAxis, uno::UNO_QUERY) ); + } + aAxisProperties.init(true); + if(aAxisProperties.m_bDisplayLabels) + aAxisProperties.m_nNumberFormatKey = this->getNumberFormatKeyForAxis( xAxis, xNumberFormatsSupplier ); + //------------------- + ::boost::shared_ptr< VAxisBase > apVAxis( new VCartesianAxis(aAxisProperties,xNumberFormatsSupplier,nDimensionIndex,nDimensionCount) ); + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + m_aAxisMap[aFullAxisIndex] = apVAxis; + apVAxis->set3DWallPositions( m_eLeftWallPos, m_eBackWallPos, m_eBottomPos ); + + apVAxis->initAxisLabelProperties(rFontReferenceSize,rMaximumSpaceForLabels); + } + } +} + +void VCartesianCoordinateSystem::initVAxisInList() +{ + if(!m_xLogicTargetForAxes.is() || !m_xFinalTarget.is() || !m_xCooSysModel.is() ) + return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = this->getPropertySwapXAndYAxis(); + + tVAxisMap::iterator aIt( m_aAxisMap.begin() ); + tVAxisMap::const_iterator aEnd( m_aAxisMap.end() ); + for( ; aIt != aEnd; ++aIt ) + { + VAxisBase* pVAxis = aIt->second.get(); + if( pVAxis ) + { + sal_Int32 nDimensionIndex = aIt->first.first; + sal_Int32 nAxisIndex = aIt->first.second; + pVAxis->setExplicitScaleAndIncrement( this->getExplicitScale( nDimensionIndex, nAxisIndex ), this->getExplicitIncrement( nDimensionIndex, nAxisIndex ) ); + pVAxis->initPlotter(m_xLogicTargetForAxes,m_xFinalTarget,m_xShapeFactory + , this->createCIDForAxis( getAxisByDimension( nDimensionIndex, nAxisIndex ), nDimensionIndex, nAxisIndex ) ); + if(2==nDimensionCount) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + pVAxis->setScales( this->getExplicitScales(nDimensionIndex,nAxisIndex), bSwapXAndY ); + } + } +} + +void VCartesianCoordinateSystem::updateScalesAndIncrementsOnAxes() +{ + if(!m_xLogicTargetForAxes.is() || !m_xFinalTarget.is() || !m_xCooSysModel.is() ) + return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = this->getPropertySwapXAndYAxis(); + + tVAxisMap::iterator aIt( m_aAxisMap.begin() ); + tVAxisMap::const_iterator aEnd( m_aAxisMap.end() ); + for( ; aIt != aEnd; ++aIt ) + { + VAxisBase* pVAxis = aIt->second.get(); + if( pVAxis ) + { + sal_Int32 nDimensionIndex = aIt->first.first; + sal_Int32 nAxisIndex = aIt->first.second; + pVAxis->setExplicitScaleAndIncrement( this->getExplicitScale( nDimensionIndex, nAxisIndex ), this->getExplicitIncrement( nDimensionIndex, nAxisIndex ) ); + if(2==nDimensionCount) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + pVAxis->setScales( this->getExplicitScales(nDimensionIndex,nAxisIndex), bSwapXAndY ); + } + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/VCartesianCoordinateSystem.hxx b/chart2/source/view/axes/VCartesianCoordinateSystem.hxx new file mode 100644 index 000000000000..b28400c6f906 --- /dev/null +++ b/chart2/source/view/axes/VCartesianCoordinateSystem.hxx @@ -0,0 +1,64 @@ +/************************************************************************* + * + * 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_VCARTESIAN_COORDINATESYSTEM_HXX +#define _CHART2_VCARTESIAN_COORDINATESYSTEM_HXX + +#include "VCoordinateSystem.hxx" + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ +class VCartesianCoordinateSystem : public VCoordinateSystem +{ +public: + VCartesianCoordinateSystem( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XCoordinateSystem >& xCooSys ); + virtual ~VCartesianCoordinateSystem(); + + virtual void createVAxisList( + const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier > & xNumberFormatsSupplier + , const ::com::sun::star::awt::Size& rFontReferenceSize + , const ::com::sun::star::awt::Rectangle& rMaximumSpaceForLabels ); + + virtual void initVAxisInList(); + virtual void updateScalesAndIncrementsOnAxes(); + + virtual void createGridShapes(); + +private: + VCartesianCoordinateSystem(); +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/VCartesianGrid.cxx b/chart2/source/view/axes/VCartesianGrid.cxx new file mode 100644 index 000000000000..ff93feefa228 --- /dev/null +++ b/chart2/source/view/axes/VCartesianGrid.cxx @@ -0,0 +1,335 @@ +/************************************************************************* + * + * 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 "VCartesianGrid.hxx" +#include "Tickmarks.hxx" +#include "PlottingPositionHelper.hxx" +#include "ShapeFactory.hxx" +#include "ObjectIdentifier.hxx" +#include "macros.hxx" +#include "CommonConverters.hxx" +#include "AxisHelper.hxx" +#include <com/sun/star/drawing/PointSequenceSequence.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> + +#include <vector> +#include <memory> + +//............................................................................. +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; + +struct GridLinePoints +{ + Sequence< double > P0; + Sequence< double > P1; + Sequence< double > P2; + + GridLinePoints( const PlottingPositionHelper* pPosHelper, sal_Int32 nDimensionIndex + , CuboidPlanePosition eLeftWallPos=CuboidPlanePosition_Left + , CuboidPlanePosition eBackWallPos=CuboidPlanePosition_Back + , CuboidPlanePosition eBottomPos=CuboidPlanePosition_Bottom ); + void update( double fScaledTickValue ); + + sal_Int32 m_nDimensionIndex; +}; + +GridLinePoints::GridLinePoints( const PlottingPositionHelper* pPosHelper, sal_Int32 nDimensionIndex + , CuboidPlanePosition eLeftWallPos + , CuboidPlanePosition eBackWallPos + , CuboidPlanePosition eBottomPos ) + : m_nDimensionIndex(nDimensionIndex) +{ + double MinX = pPosHelper->getLogicMinX(); + double MinY = pPosHelper->getLogicMinY(); + double MinZ = pPosHelper->getLogicMinZ(); + double MaxX = pPosHelper->getLogicMaxX(); + double MaxY = pPosHelper->getLogicMaxY(); + double MaxZ = pPosHelper->getLogicMaxZ(); + + pPosHelper->doLogicScaling( &MinX,&MinY,&MinZ ); + pPosHelper->doLogicScaling( &MaxX,&MaxY,&MaxZ ); + + if(!pPosHelper->isMathematicalOrientationX()) + { + double fHelp = MinX; + MinX = MaxX; + MaxX = fHelp; + } + if(!pPosHelper->isMathematicalOrientationY()) + { + double fHelp = MinY; + MinY = MaxY; + MaxY = fHelp; + } + if(pPosHelper->isMathematicalOrientationZ())//z axis in draw is reverse to mathematical + { + double fHelp = MinZ; + MinZ = MaxZ; + MaxZ = fHelp; + } + bool bSwapXY = pPosHelper->isSwapXAndY(); + + P0.realloc(3); + P1.realloc(3); + P2.realloc(3); + + //P0: point on 'back' wall, not on 'left' wall + //P1: point on both walls + //P2: point on 'left' wall not on 'back' wall + + P0[0]=P1[0]=P2[0]= (CuboidPlanePosition_Left == eLeftWallPos || bSwapXY) ? MinX : MaxX; + P0[1]=P1[1]=P2[1]= (CuboidPlanePosition_Left == eLeftWallPos || !bSwapXY) ? MinY : MaxY; + P0[2]=P1[2]=P2[2]= (CuboidPlanePosition_Back == eBackWallPos) ? MinZ : MaxZ; + + if(m_nDimensionIndex==0) + { + P0[1]= (CuboidPlanePosition_Left == eLeftWallPos || !bSwapXY) ? MaxY : MinY; + P2[2]= (CuboidPlanePosition_Back == eBackWallPos) ? MaxZ : MinZ; + if( CuboidPlanePosition_Bottom != eBottomPos && !bSwapXY ) + P2=P1; + } + else if(m_nDimensionIndex==1) + { + P0[0]= (CuboidPlanePosition_Left == eLeftWallPos || bSwapXY) ? MaxX : MinX; + P2[2]= (CuboidPlanePosition_Back == eBackWallPos) ? MaxZ : MinZ; + if( CuboidPlanePosition_Bottom != eBottomPos && bSwapXY ) + P2=P1; + } + else if(m_nDimensionIndex==2) + { + P0[0]= (CuboidPlanePosition_Left == eLeftWallPos || bSwapXY) ? MaxX : MinX; + P2[1]= (CuboidPlanePosition_Left == eLeftWallPos || !bSwapXY) ? MaxY : MinY; + if( CuboidPlanePosition_Bottom != eBottomPos ) + { + if( !bSwapXY ) + P0=P1; + else + P2=P1; + } + } +} + +void GridLinePoints::update( double fScaledTickValue ) +{ + P0[m_nDimensionIndex] = P1[m_nDimensionIndex] = P2[m_nDimensionIndex] = fScaledTickValue; +} + +void addLine2D( drawing::PointSequenceSequence& rPoints, sal_Int32 nIndex + , const GridLinePoints& rScaledLogicPoints + , const Reference< XTransformation > & xTransformation + ) +{ + drawing::Position3D aPA = SequenceToPosition3D( xTransformation->transform( rScaledLogicPoints.P0 ) ); + drawing::Position3D aPB = SequenceToPosition3D( xTransformation->transform( rScaledLogicPoints.P1 ) ); + + rPoints[nIndex].realloc(2); + rPoints[nIndex][0].X = static_cast<sal_Int32>(aPA.PositionX); + rPoints[nIndex][0].Y = static_cast<sal_Int32>(aPA.PositionY); + rPoints[nIndex][1].X = static_cast<sal_Int32>(aPB.PositionX); + rPoints[nIndex][1].Y = static_cast<sal_Int32>(aPB.PositionY); +} + +void addLine3D( drawing::PolyPolygonShape3D& rPoints, sal_Int32 nIndex + , const GridLinePoints& rBasePoints + , const Reference< XTransformation > & xTransformation ) +{ + drawing::Position3D aPoint = SequenceToPosition3D( xTransformation->transform( rBasePoints.P0 ) ); + AddPointToPoly( rPoints, aPoint, nIndex ); + aPoint = SequenceToPosition3D( xTransformation->transform( rBasePoints.P1 ) ); + AddPointToPoly( rPoints, aPoint, nIndex ); + aPoint = SequenceToPosition3D( xTransformation->transform( rBasePoints.P2 ) ); + AddPointToPoly( rPoints, aPoint, nIndex ); +} + +//--------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------- + +VCartesianGrid::VCartesianGrid( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , const Sequence< Reference< beans::XPropertySet > > & rGridPropertiesList ) + : VAxisOrGridBase( nDimensionIndex, nDimensionCount ) + , m_aGridPropertiesList( rGridPropertiesList ) +{ + m_pPosHelper = new PlottingPositionHelper(); +} + +VCartesianGrid::~VCartesianGrid() +{ + delete m_pPosHelper; + m_pPosHelper = NULL; +} + +void VCartesianGrid::fillLinePropertiesFromGridModel( ::std::vector<VLineProperties>& rLinePropertiesList + , const Sequence< Reference< beans::XPropertySet > > & rGridPropertiesList ) +{ + rLinePropertiesList.clear(); + if( !rGridPropertiesList.getLength() ) + return; + + VLineProperties aLineProperties; + for( sal_Int32 nN=0; nN < rGridPropertiesList.getLength(); nN++ ) + { + if(!AxisHelper::isGridVisible( rGridPropertiesList[nN] )) + aLineProperties.LineStyle = uno::makeAny( drawing::LineStyle_NONE ); + else + aLineProperties.initFromPropertySet( rGridPropertiesList[nN] ); + rLinePropertiesList.push_back(aLineProperties); + } +}; + +void VCartesianGrid::createShapes() +{ + if(!m_aGridPropertiesList.getLength()) + return; + //somehow equal to axis tickmarks + + //----------------------------------------- + //create named group shape + Reference< drawing::XShapes > xGroupShape_Shapes( + this->createGroupShape( m_xLogicTarget, m_aCID ) ); + + if(!xGroupShape_Shapes.is()) + return; + //----------------------------------------- + + ::std::vector<VLineProperties> aLinePropertiesList; + fillLinePropertiesFromGridModel( aLinePropertiesList, m_aGridPropertiesList ); + + //----------------------------------------- + //create all scaled tickmark values + std::auto_ptr< TickFactory > apTickFactory( this->createTickFactory() ); + TickFactory& aTickFactory = *apTickFactory.get(); + ::std::vector< ::std::vector< TickInfo > > aAllTickInfos; + aTickFactory.getAllTicks( aAllTickInfos ); + + //----------------------------------------- + //create tick mark line shapes + ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter = aAllTickInfos.begin(); + const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd = aAllTickInfos.end(); + + if(aDepthIter == aDepthEnd)//no tickmarks at all + return; + + + sal_Int32 nLinePropertiesCount = aLinePropertiesList.size(); + for( sal_Int32 nDepth=0 + ; aDepthIter != aDepthEnd && nDepth < nLinePropertiesCount + ; aDepthIter++, nDepth++ ) + { + if( !aLinePropertiesList[nDepth].isLineVisible() ) + continue; + + Reference< drawing::XShapes > xTarget( xGroupShape_Shapes ); + if( nDepth > 0 ) + { + xTarget.set( this->createGroupShape( m_xLogicTarget + , ObjectIdentifier::addChildParticle( m_aCID, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_SUBGRID, nDepth-1 ) ) + ) ); + if(!xTarget.is()) + xTarget.set( xGroupShape_Shapes ); + } + + if(2==m_nDimension) + { + + GridLinePoints aGridLinePoints( m_pPosHelper, m_nDimensionIndex ); + + sal_Int32 nPointCount = (*aDepthIter).size(); + drawing::PointSequenceSequence aPoints(nPointCount); + + ::std::vector< TickInfo >::const_iterator aTickIter = (*aDepthIter).begin(); + const ::std::vector< TickInfo >::const_iterator aTickEnd = (*aDepthIter).end(); + sal_Int32 nRealPointCount = 0; + for( ; aTickIter != aTickEnd; aTickIter++ ) + { + if( !(*aTickIter).bPaintIt ) + continue; + aGridLinePoints.update( (*aTickIter).fScaledTickValue ); + addLine2D( aPoints, nRealPointCount, aGridLinePoints, m_pPosHelper->getTransformationScaledLogicToScene() ); + nRealPointCount++; + } + aPoints.realloc(nRealPointCount); + m_pShapeFactory->createLine2D( xTarget, aPoints, &aLinePropertiesList[nDepth] ); + + //prepare polygon for handle shape: + drawing::PointSequenceSequence aHandlesPoints(1); + sal_Int32 nOldHandleCount = aHandlesPoints[0].getLength(); + aHandlesPoints[0].realloc(nOldHandleCount+nRealPointCount); + for( sal_Int32 nN = 0; nN<nRealPointCount; nN++) + aHandlesPoints[0][nOldHandleCount+nN] = aPoints[nN][1]; + + //create handle shape: + VLineProperties aHandleLineProperties; + aHandleLineProperties.LineStyle = uno::makeAny( drawing::LineStyle_NONE ); + Reference< drawing::XShape > xHandleShape = + m_pShapeFactory->createLine2D( xTarget, aHandlesPoints, &aHandleLineProperties ); + m_pShapeFactory->setShapeName( xHandleShape, C2U("HandlesOnly") ); + } + //----------------------------------------- + else //if(2!=m_nDimension) + { + GridLinePoints aGridLinePoints( m_pPosHelper, m_nDimensionIndex, m_eLeftWallPos, m_eBackWallPos, m_eBottomPos ); + + sal_Int32 nPointCount = (*aDepthIter).size(); + drawing::PolyPolygonShape3D aPoints; + aPoints.SequenceX.realloc(nPointCount); + aPoints.SequenceY.realloc(nPointCount); + aPoints.SequenceZ.realloc(nPointCount); + + ::std::vector< TickInfo >::const_iterator aTickIter = (*aDepthIter).begin(); + const ::std::vector< TickInfo >::const_iterator aTickEnd = (*aDepthIter).end(); + sal_Int32 nRealPointCount = 0; + sal_Int32 nPolyIndex = 0; + for( ; aTickIter != aTickEnd; aTickIter++, nPolyIndex++ ) + { + if( !(*aTickIter).bPaintIt ) + continue; + + aGridLinePoints.update( (*aTickIter).fScaledTickValue ); + addLine3D( aPoints, nPolyIndex, aGridLinePoints, m_pPosHelper->getTransformationScaledLogicToScene() ); + nRealPointCount+=3; + } + aPoints.SequenceX.realloc(nRealPointCount); + aPoints.SequenceY.realloc(nRealPointCount); + aPoints.SequenceZ.realloc(nRealPointCount); + m_pShapeFactory->createLine3D( xTarget, aPoints, aLinePropertiesList[nDepth] ); + } + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/VCartesianGrid.hxx b/chart2/source/view/axes/VCartesianGrid.hxx new file mode 100644 index 000000000000..0a0f8b91716f --- /dev/null +++ b/chart2/source/view/axes/VCartesianGrid.hxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * 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_VCARTESIANGRID_HXX +#define _CHART2_VCARTESIANGRID_HXX + +#include "VAxisOrGridBase.hxx" +#include "VLineProperties.hxx" + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +class VCartesianGrid : public VAxisOrGridBase +{ +//------------------------------------------------------------------------- +// public methods +//------------------------------------------------------------------------- +public: + VCartesianGrid( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet > >& rGridPropertiesList //main grid, subgrid, subsubgrid etc + ); + virtual ~VCartesianGrid(); + + virtual void createShapes(); + + static void fillLinePropertiesFromGridModel( ::std::vector<VLineProperties>& rLinePropertiesList + , const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet > >& rGridPropertiesList ); + +private: + ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet > > m_aGridPropertiesList; //main grid, subgrid, subsubgrid etc +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/VCoordinateSystem.cxx b/chart2/source/view/axes/VCoordinateSystem.cxx new file mode 100644 index 000000000000..42e6042d7e70 --- /dev/null +++ b/chart2/source/view/axes/VCoordinateSystem.cxx @@ -0,0 +1,603 @@ +/************************************************************************* + * + * 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 "VCoordinateSystem.hxx" +#include "VCartesianCoordinateSystem.hxx" +#include "VPolarCoordinateSystem.hxx" +#include "ScaleAutomatism.hxx" +#include "VSeriesPlotter.hxx" +#include "ShapeFactory.hxx" +#include "servicenames_coosystems.hxx" +#include "macros.hxx" +#include "AxisIndexDefines.hxx" +#include "ObjectIdentifier.hxx" +#include "ExplicitCategoriesProvider.hxx" +#include "AxisHelper.hxx" +#include "ContainerHelper.hxx" +#include "VAxisBase.hxx" +#include "ViewDefines.hxx" +#include "DataSeriesHelper.hxx" +#include "chartview/ExplicitValueProvider.hxx" +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/chart2/XChartTypeContainer.hpp> +#include <com/sun/star/chart2/XDataSeriesContainer.hpp> + +// header for define DBG_ASSERT +#include <tools/debug.hxx> +#include <rtl/math.hxx> + +//............................................................................. +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; + +VCoordinateSystem* VCoordinateSystem::createCoordinateSystem( + const Reference< XCoordinateSystem >& xCooSysModel ) +{ + if( !xCooSysModel.is() ) + return 0; + + rtl::OUString aViewServiceName = xCooSysModel->getViewServiceName(); + + //@todo: in future the coordinatesystems should be instanciated via service factory + VCoordinateSystem* pRet=NULL; + if( aViewServiceName.equals( CHART2_COOSYSTEM_CARTESIAN_VIEW_SERVICE_NAME ) ) + pRet = new VCartesianCoordinateSystem(xCooSysModel); + else if( aViewServiceName.equals( CHART2_COOSYSTEM_POLAR_VIEW_SERVICE_NAME ) ) + pRet = new VPolarCoordinateSystem(xCooSysModel); + if(!pRet) + pRet = new VCoordinateSystem(xCooSysModel); + return pRet; +} + +VCoordinateSystem::VCoordinateSystem( const Reference< XCoordinateSystem >& xCooSys ) + : m_xCooSysModel(xCooSys) + , m_xLogicTargetForGrids(0) + , m_xLogicTargetForAxes(0) + , m_xFinalTarget(0) + , m_xShapeFactory(0) + , m_aMatrixSceneToScreen() + , m_eLeftWallPos(CuboidPlanePosition_Left) + , m_eBackWallPos(CuboidPlanePosition_Back) + , m_eBottomPos(CuboidPlanePosition_Bottom) + , m_aMergedMinimumAndMaximumSupplier() + , m_aExplicitScales(3) + , m_aExplicitIncrements(3) + , m_apExplicitCategoriesProvider(NULL) +{ + if( !m_xCooSysModel.is() || m_xCooSysModel->getDimension()<3 ) + { + m_aExplicitScales[2].Minimum = 1.0; + m_aExplicitScales[2].Maximum = 2.0; + m_aExplicitScales[2].Orientation = AxisOrientation_MATHEMATICAL; + } +} +VCoordinateSystem::~VCoordinateSystem() +{ +} + +void VCoordinateSystem::initPlottingTargets( const Reference< drawing::XShapes >& xLogicTarget + , const Reference< drawing::XShapes >& xFinalTarget + , const Reference< lang::XMultiServiceFactory >& xShapeFactory + , Reference< drawing::XShapes >& xLogicTargetForSeriesBehindAxis ) + throw (uno::RuntimeException) +{ + DBG_ASSERT(xLogicTarget.is()&&xFinalTarget.is()&&xShapeFactory.is(),"no proper initialization parameters"); + //is only allowed to be called once + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + //create group shape for grids first thus axes are always painted above grids + ShapeFactory aShapeFactory(xShapeFactory); + if(nDimensionCount==2) + { + //create and add to target + m_xLogicTargetForGrids = aShapeFactory.createGroup2D( xLogicTarget ); + xLogicTargetForSeriesBehindAxis = aShapeFactory.createGroup2D( xLogicTarget ); + m_xLogicTargetForAxes = aShapeFactory.createGroup2D( xLogicTarget ); + } + else + { + //create and added to target + m_xLogicTargetForGrids = aShapeFactory.createGroup3D( xLogicTarget ); + xLogicTargetForSeriesBehindAxis = aShapeFactory.createGroup3D( xLogicTarget ); + m_xLogicTargetForAxes = aShapeFactory.createGroup3D( xLogicTarget ); + } + m_xFinalTarget = xFinalTarget; + m_xShapeFactory = xShapeFactory; +} + +void VCoordinateSystem::setParticle( const rtl::OUString& rCooSysParticle ) +{ + m_aCooSysParticle = rCooSysParticle; +} + +void VCoordinateSystem::setTransformationSceneToScreen( + const drawing::HomogenMatrix& rMatrix ) +{ + m_aMatrixSceneToScreen = rMatrix; + + //correct transformation for axis + tVAxisMap::iterator aIt( m_aAxisMap.begin() ); + tVAxisMap::const_iterator aEnd( m_aAxisMap.end() ); + for( ; aIt != aEnd; ++aIt ) + { + VAxisBase* pVAxis = aIt->second.get(); + if( pVAxis ) + { + if(2==pVAxis->getDimensionCount()) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + } + } +} + +drawing::HomogenMatrix VCoordinateSystem::getTransformationSceneToScreen() +{ + return m_aMatrixSceneToScreen; +} + +//better performance for big data +uno::Sequence< sal_Int32 > VCoordinateSystem::getCoordinateSystemResolution( + const awt::Size& rPageSize, const awt::Size& rPageResolution ) +{ + uno::Sequence< sal_Int32 > aResolution(2); + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + if(nDimensionCount>2) + aResolution.realloc(nDimensionCount); + sal_Int32 nN = 0; + for( nN = 0 ;nN<aResolution.getLength(); nN++ ) + aResolution[nN]=1000; + + ::basegfx::B3DTuple aScale( BaseGFXHelper::GetScaleFromMatrix( + BaseGFXHelper::HomogenMatrixToB3DHomMatrix( + m_aMatrixSceneToScreen ) ) ); + + double fCoosysWidth = static_cast< double >( fabs(aScale.getX()*FIXED_SIZE_FOR_3D_CHART_VOLUME)); + double fCoosysHeight = static_cast< double >( fabs(aScale.getY()*FIXED_SIZE_FOR_3D_CHART_VOLUME)); + + double fPageWidth = rPageSize.Width; + double fPageHeight = rPageSize.Height; + + //factor 2 to avoid rounding problems + sal_Int32 nXResolution = static_cast<sal_Int32>(2.0*static_cast<double>(rPageResolution.Width)*fCoosysWidth/fPageWidth); + sal_Int32 nYResolution = static_cast<sal_Int32>(2.0*static_cast<double>(rPageResolution.Height)*fCoosysHeight/fPageHeight); + + if( nXResolution < 10 ) + nXResolution = 10; + if( nYResolution < 10 ) + nYResolution = 10; + + if( this->getPropertySwapXAndYAxis() ) + std::swap(nXResolution,nYResolution); + + //2D + if( 2 == aResolution.getLength() ) + { + aResolution[0]=nXResolution; + aResolution[1]=nYResolution; + } + else + { + //this maybe can be optimized further ... + sal_Int32 nMaxResolution = std::max( nXResolution, nYResolution ); + nMaxResolution*=2; + for( nN = 0 ;nN<aResolution.getLength(); nN++ ) + aResolution[nN]=nMaxResolution; + } + + return aResolution; +} + +Reference< XCoordinateSystem > VCoordinateSystem::getModel() const +{ + return m_xCooSysModel; +} + +Reference< XAxis > VCoordinateSystem::getAxisByDimension( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const +{ + if( m_xCooSysModel.is() ) + return m_xCooSysModel->getAxisByDimension( nDimensionIndex, nAxisIndex ); + return 0; +} + +Sequence< Reference< beans::XPropertySet > > VCoordinateSystem::getGridListFromAxis( const Reference< XAxis >& xAxis ) +{ + std::vector< Reference< beans::XPropertySet > > aRet; + + if( xAxis.is() ) + { + aRet.push_back( xAxis->getGridProperties() ); + std::vector< Reference< beans::XPropertySet > > aSubGrids( ContainerHelper::SequenceToVector( xAxis->getSubGridProperties() ) ); + aRet.insert( aRet.end(), aSubGrids.begin(), aSubGrids.end() ); + } + + return ContainerHelper::ContainerToSequence( aRet ); +} + +void VCoordinateSystem::impl_adjustDimension( sal_Int32& rDimensionIndex ) const +{ + if( rDimensionIndex<0 ) + rDimensionIndex=0; + if( rDimensionIndex>2 ) + rDimensionIndex=2; +} + +void VCoordinateSystem::impl_adjustDimensionAndIndex( sal_Int32& rDimensionIndex, sal_Int32& rAxisIndex ) const +{ + impl_adjustDimension( rDimensionIndex ); + + if( rAxisIndex < 0 || rAxisIndex > this->getMaximumAxisIndexByDimension(rDimensionIndex) ) + rAxisIndex = 0; +} + +void VCoordinateSystem::setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider /*takes ownership*/ ) +{ + m_apExplicitCategoriesProvider = ::std::auto_ptr< ExplicitCategoriesProvider >(pExplicitCategoriesProvider); +} + +ExplicitCategoriesProvider* VCoordinateSystem::getExplicitCategoriesProvider() +{ + return m_apExplicitCategoriesProvider.get(); +} + +std::vector< ExplicitScaleData > VCoordinateSystem::getExplicitScales( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const +{ + std::vector< ExplicitScaleData > aRet(m_aExplicitScales); + + impl_adjustDimensionAndIndex( nDimensionIndex, nAxisIndex ); + aRet[nDimensionIndex]=this->getExplicitScale( nDimensionIndex, nAxisIndex ); + + return aRet; +} + +std::vector< ExplicitIncrementData > VCoordinateSystem::getExplicitIncrements( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const +{ + std::vector< ExplicitIncrementData > aRet(m_aExplicitIncrements); + + impl_adjustDimensionAndIndex( nDimensionIndex, nAxisIndex ); + aRet[nDimensionIndex]=this->getExplicitIncrement( nDimensionIndex, nAxisIndex ); + + return aRet; +} + +ExplicitScaleData VCoordinateSystem::getExplicitScale( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const +{ + ExplicitScaleData aRet; + + impl_adjustDimensionAndIndex( nDimensionIndex, nAxisIndex ); + + if( nAxisIndex == 0) + { + aRet = m_aExplicitScales[nDimensionIndex]; + } + else + { + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + tFullExplicitScaleMap::const_iterator aIt = m_aSecondaryExplicitScales.find( aFullAxisIndex ); + if( aIt != m_aSecondaryExplicitScales.end() ) + aRet = aIt->second; + else + aRet = m_aExplicitScales[nDimensionIndex]; + } + + return aRet; +} + +ExplicitIncrementData VCoordinateSystem::getExplicitIncrement( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const +{ + ExplicitIncrementData aRet; + + impl_adjustDimensionAndIndex( nDimensionIndex, nAxisIndex ); + + if( nAxisIndex == 0) + { + aRet = m_aExplicitIncrements[nDimensionIndex]; + } + else + { + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + tFullExplicitIncrementMap::const_iterator aIt = m_aSecondaryExplicitIncrements.find( aFullAxisIndex ); + if( aIt != m_aSecondaryExplicitIncrements.end() ) + aRet = aIt->second; + else + aRet = m_aExplicitIncrements[nDimensionIndex]; + } + + return aRet; +} + +rtl::OUString VCoordinateSystem::createCIDForAxis( const Reference< chart2::XAxis >& /* xAxis */, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + rtl::OUString aAxisParticle( ObjectIdentifier::createParticleForAxis( nDimensionIndex, nAxisIndex ) ); + return ObjectIdentifier::createClassifiedIdentifierForParticles( m_aCooSysParticle, aAxisParticle ); +} +rtl::OUString VCoordinateSystem::createCIDForGrid( const Reference< chart2::XAxis >& /* xAxis */, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + rtl::OUString aGridParticle( ObjectIdentifier::createParticleForGrid( nDimensionIndex, nAxisIndex ) ); + return ObjectIdentifier::createClassifiedIdentifierForParticles( m_aCooSysParticle, aGridParticle ); +} + +sal_Int32 VCoordinateSystem::getMaximumAxisIndexByDimension( sal_Int32 nDimensionIndex ) const +{ + sal_Int32 nRet = 0; + tFullExplicitScaleMap::const_iterator aIt = m_aSecondaryExplicitScales.begin(); + tFullExplicitScaleMap::const_iterator aEnd = m_aSecondaryExplicitScales.end(); + for(; aIt!=aEnd; ++aIt) + { + if(aIt->first.first==nDimensionIndex) + { + sal_Int32 nLocalIdx = aIt->first.second; + if( nRet < nLocalIdx ) + nRet = nLocalIdx; + } + } + return nRet; +} + +void VCoordinateSystem::createVAxisList( + const uno::Reference< util::XNumberFormatsSupplier > & /* xNumberFormatsSupplier */ + , const awt::Size& /* rFontReferenceSize */ + , const awt::Rectangle& /* rMaximumSpaceForLabels */ + ) +{ +} + +void VCoordinateSystem::initVAxisInList() +{ +} +void VCoordinateSystem::updateScalesAndIncrementsOnAxes() +{ +} + +void VCoordinateSystem::prepareScaleAutomatismForDimensionAndIndex( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex ) +{ + if( rScaleAutomatism.getScale().AxisType==AxisType::DATE && nDimIndex==0 ) + { + sal_Int32 nTimeResolution = ::com::sun::star::chart::TimeUnit::MONTH; + if( !(rScaleAutomatism.getScale().TimeIncrement.TimeResolution >>= nTimeResolution) ) + { + nTimeResolution = m_aMergedMinimumAndMaximumSupplier.calculateTimeResolutionOnXAxis(); + rScaleAutomatism.setAutomaticTimeResolution( nTimeResolution ); + } + m_aMergedMinimumAndMaximumSupplier.setTimeResolutionOnXAxis( nTimeResolution, rScaleAutomatism.getNullDate() ); + } + + double fMin = 0.0; + double fMax = 0.0; + ::rtl::math::setInf(&fMin, false); + ::rtl::math::setInf(&fMax, true); + if( 0 == nDimIndex ) + { + fMin = m_aMergedMinimumAndMaximumSupplier.getMinimumX(); + fMax = m_aMergedMinimumAndMaximumSupplier.getMaximumX(); + } + else if( 1 == nDimIndex ) + { + ExplicitScaleData aScale = getExplicitScale( 0, 0 ); + fMin = m_aMergedMinimumAndMaximumSupplier.getMinimumYInRange(aScale.Minimum,aScale.Maximum, nAxisIndex); + fMax = m_aMergedMinimumAndMaximumSupplier.getMaximumYInRange(aScale.Minimum,aScale.Maximum, nAxisIndex); + } + else if( 2 == nDimIndex ) + { + fMin = m_aMergedMinimumAndMaximumSupplier.getMinimumZ(); + fMax = m_aMergedMinimumAndMaximumSupplier.getMaximumZ(); + } + + //merge our values with those already contained in rScaleAutomatism + rScaleAutomatism.expandValueRange( fMin, fMax ); + + rScaleAutomatism.setAutoScalingOptions( + m_aMergedMinimumAndMaximumSupplier.isExpandBorderToIncrementRhythm( nDimIndex ), + m_aMergedMinimumAndMaximumSupplier.isExpandIfValuesCloseToBorder( nDimIndex ), + m_aMergedMinimumAndMaximumSupplier.isExpandWideValuesToZero( nDimIndex ), + m_aMergedMinimumAndMaximumSupplier.isExpandNarrowValuesTowardZero( nDimIndex ) ); + + VAxisBase* pVAxis( this->getVAxis( nDimIndex, nAxisIndex ) ); + if( pVAxis ) + rScaleAutomatism.setMaximumAutoMainIncrementCount( pVAxis->estimateMaximumAutoMainIncrementCount() ); +} + +VAxisBase* VCoordinateSystem::getVAxis( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + VAxisBase* pRet = 0; + + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + + tVAxisMap::const_iterator aIt = m_aAxisMap.find( aFullAxisIndex ); + if( aIt != m_aAxisMap.end() ) + pRet = aIt->second.get(); + + return pRet; +} + +void VCoordinateSystem::setExplicitScaleAndIncrement( + sal_Int32 nDimensionIndex + , sal_Int32 nAxisIndex + , const ExplicitScaleData& rExplicitScale + , const ExplicitIncrementData& rExplicitIncrement ) +{ + impl_adjustDimension( nDimensionIndex ); + + if( nAxisIndex==0 ) + { + m_aExplicitScales[nDimensionIndex]=rExplicitScale; + m_aExplicitIncrements[nDimensionIndex]=rExplicitIncrement; + } + else + { + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + m_aSecondaryExplicitScales[aFullAxisIndex] = rExplicitScale; + m_aSecondaryExplicitIncrements[aFullAxisIndex] = rExplicitIncrement; + } +} + +void VCoordinateSystem::set3DWallPositions( CuboidPlanePosition eLeftWallPos, CuboidPlanePosition eBackWallPos, CuboidPlanePosition eBottomPos ) +{ + m_eLeftWallPos = eLeftWallPos; + m_eBackWallPos = eBackWallPos; + m_eBottomPos = eBottomPos; +} + +void VCoordinateSystem::createMaximumAxesLabels() +{ + tVAxisMap::iterator aIt( m_aAxisMap.begin() ); + tVAxisMap::const_iterator aEnd( m_aAxisMap.end() ); + for( ; aIt != aEnd; ++aIt ) + { + VAxisBase* pVAxis = aIt->second.get(); + if( pVAxis ) + { + if(2==pVAxis->getDimensionCount()) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + pVAxis->createMaximumLabels(); + } + } +} +void VCoordinateSystem::createAxesLabels() +{ + tVAxisMap::iterator aIt( m_aAxisMap.begin() ); + tVAxisMap::const_iterator aEnd( m_aAxisMap.end() ); + for( ; aIt != aEnd; ++aIt ) + { + VAxisBase* pVAxis = aIt->second.get(); + if( pVAxis ) + { + if(2==pVAxis->getDimensionCount()) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + pVAxis->createLabels(); + } + } +} + +void VCoordinateSystem::updatePositions() +{ + tVAxisMap::iterator aIt( m_aAxisMap.begin() ); + tVAxisMap::const_iterator aEnd( m_aAxisMap.end() ); + for( ; aIt != aEnd; ++aIt ) + { + VAxisBase* pVAxis = aIt->second.get(); + if( pVAxis ) + { + if(2==pVAxis->getDimensionCount()) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + pVAxis->updatePositions(); + } + } +} + +void VCoordinateSystem::createAxesShapes() +{ + tVAxisMap::iterator aIt( m_aAxisMap.begin() ); + tVAxisMap::const_iterator aEnd( m_aAxisMap.end() ); + for( ; aIt != aEnd; ++aIt ) + { + VAxisBase* pVAxis = aIt->second.get(); + if( pVAxis ) + { + if(2==pVAxis->getDimensionCount()) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + + tFullAxisIndex aFullAxisIndex = aIt->first; + if( aFullAxisIndex.second == 0 ) + { + if( aFullAxisIndex.first == 0 ) + { + if( AxisType::CATEGORY!=m_aExplicitScales[1].AxisType ) + pVAxis->setExrtaLinePositionAtOtherAxis( + m_aExplicitScales[1].Origin ); + } + else if( aFullAxisIndex.first == 1 ) + { + if( AxisType::CATEGORY!=m_aExplicitScales[0].AxisType ) + pVAxis->setExrtaLinePositionAtOtherAxis( + m_aExplicitScales[0].Origin ); + } + } + + pVAxis->createShapes(); + } + } +} +void VCoordinateSystem::createGridShapes() +{ +} +void VCoordinateSystem::addMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ) +{ + m_aMergedMinimumAndMaximumSupplier.addMinimumAndMaximumSupplier(pMinimumAndMaximumSupplier); +} + +bool VCoordinateSystem::hasMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ) +{ + return m_aMergedMinimumAndMaximumSupplier.hasMinimumAndMaximumSupplier(pMinimumAndMaximumSupplier); +} + +void VCoordinateSystem::clearMinimumAndMaximumSupplierList() +{ + m_aMergedMinimumAndMaximumSupplier.clearMinimumAndMaximumSupplierList(); +} + +bool VCoordinateSystem::getPropertySwapXAndYAxis() const +{ + Reference<beans::XPropertySet> xProp(m_xCooSysModel, uno::UNO_QUERY ); + sal_Bool bSwapXAndY = false; + if( xProp.is()) try + { + xProp->getPropertyValue( C2U( "SwapXAndYAxis" ) ) >>= bSwapXAndY; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + return bSwapXAndY; +} + +bool VCoordinateSystem::needSeriesNamesForAxis() const +{ + return ( m_xCooSysModel.is() && m_xCooSysModel->getDimension() == 3 ); +} +void VCoordinateSystem::setSeriesNamesForAxis( const Sequence< rtl::OUString >& rSeriesNames ) +{ + m_aSeriesNamesForZAxis = rSeriesNames; +} + +sal_Int32 VCoordinateSystem::getNumberFormatKeyForAxis( + const Reference< chart2::XAxis >& xAxis + , const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier ) +{ + return ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( + xAxis, m_xCooSysModel, xNumberFormatsSupplier ); +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/VPolarAngleAxis.cxx b/chart2/source/view/axes/VPolarAngleAxis.cxx new file mode 100644 index 000000000000..c23d6b95629d --- /dev/null +++ b/chart2/source/view/axes/VPolarAngleAxis.cxx @@ -0,0 +1,234 @@ +/************************************************************************* + * + * 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 <basegfx/numeric/ftools.hxx> + +#include "VPolarAngleAxis.hxx" +#include "VPolarGrid.hxx" +#include "ShapeFactory.hxx" +#include "macros.hxx" +#include "NumberFormatterWrapper.hxx" +#include "PolarLabelPositionHelper.hxx" +#include <tools/color.hxx> + +#include <memory> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::rtl::math; + +VPolarAngleAxis::VPolarAngleAxis( const AxisProperties& rAxisProperties + , const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionCount ) + : VPolarAxis( rAxisProperties, xNumberFormatsSupplier, 0/*nDimensionIndex*/, nDimensionCount ) +{ +} + +VPolarAngleAxis::~VPolarAngleAxis() +{ + delete m_pPosHelper; + m_pPosHelper = NULL; +} + +bool VPolarAngleAxis::createTextShapes_ForAngleAxis( + const uno::Reference< drawing::XShapes >& xTarget + , EquidistantTickIter& rTickIter + , AxisLabelProperties& rAxisLabelProperties + , double fLogicRadius + , double fLogicZ ) +{ + sal_Int32 nDimensionCount = 2; + ShapeFactory aShapeFactory(m_xShapeFactory); + + FixedNumberFormatter aFixedNumberFormatter( + m_xNumberFormatsSupplier, rAxisLabelProperties.nNumberFormatKey ); + + //------------------------------------------------ + //prepare text properties for multipropertyset-interface of shape + tNameSequence aPropNames; + tAnySequence aPropValues; + + uno::Reference< beans::XPropertySet > xProps( m_aAxisProperties.m_xAxisModel, uno::UNO_QUERY ); + PropertyMapper::getTextLabelMultiPropertyLists( xProps, aPropNames, aPropValues, false ); + LabelPositionHelper::doDynamicFontResize( aPropValues, aPropNames, xProps + , rAxisLabelProperties.m_aFontReferenceSize ); + + uno::Any* pColorAny = PropertyMapper::getValuePointer(aPropValues,aPropNames,C2U("CharColor")); + sal_Int32 nColor = Color( COL_AUTO ).GetColor(); + if(pColorAny) + *pColorAny >>= nColor; + + const uno::Sequence< rtl::OUString >* pLabels = m_bUseTextLabels? &m_aTextLabels : 0; + + //------------------------------------------------ + + //TickInfo* pLastVisibleNeighbourTickInfo = NULL; + sal_Int32 nTick = 0; + + for( TickInfo* pTickInfo = rTickIter.firstInfo() + ; pTickInfo + ; pTickInfo = rTickIter.nextInfo(), nTick++ ) + { + //don't create labels which does not fit into the rhythm + if( nTick%rAxisLabelProperties.nRhythm != 0) + continue; + + //don't create labels for invisible ticks + if( !pTickInfo->bPaintIt ) + continue; + + //if NO OVERLAP -> don't create labels where the + //anchor position is the same as for the last label + //@todo + + if(!pTickInfo->xTextShape.is()) + { + //create single label + bool bHasExtraColor=false; + sal_Int32 nExtraColor=0; + + rtl::OUString aLabel; + if(pLabels) + { + sal_Int32 nIndex = static_cast< sal_Int32 >(pTickInfo->getUnscaledTickValue()) - 1; //first category (index 0) matches with real number 1.0 + if( nIndex>=0 && nIndex<pLabels->getLength() ) + aLabel = (*pLabels)[nIndex]; + } + else + aLabel = aFixedNumberFormatter.getFormattedString( pTickInfo->getUnscaledTickValue(), nExtraColor, bHasExtraColor ); + + if(pColorAny) + *pColorAny = uno::makeAny(bHasExtraColor?nExtraColor:nColor); + + double fLogicAngle = pTickInfo->getUnscaledTickValue(); + + LabelAlignment eLabelAlignment(LABEL_ALIGN_CENTER); + PolarLabelPositionHelper aPolarLabelPositionHelper(m_pPosHelper,nDimensionCount,xTarget,&aShapeFactory); + sal_Int32 nScreenValueOffsetInRadiusDirection = m_aAxisLabelProperties.m_aMaximumSpaceForLabels.Height/15; + awt::Point aAnchorScreenPosition2D( aPolarLabelPositionHelper.getLabelScreenPositionAndAlignmentForLogicValues( + eLabelAlignment, fLogicAngle, fLogicRadius, fLogicZ, nScreenValueOffsetInRadiusDirection )); + LabelPositionHelper::changeTextAdjustment( aPropValues, aPropNames, eLabelAlignment ); + + // #i78696# use mathematically correct rotation now + const double fRotationAnglePi(rAxisLabelProperties.fRotationAngleDegree * (F_PI / -180.0)); + + uno::Any aATransformation = ShapeFactory::makeTransformation( aAnchorScreenPosition2D, fRotationAnglePi ); + rtl::OUString aStackedLabel = ShapeFactory::getStackedString( aLabel, rAxisLabelProperties.bStackCharacters ); + + pTickInfo->xTextShape = aShapeFactory.createText( xTarget, aStackedLabel, aPropNames, aPropValues, aATransformation ); + } + + //if NO OVERLAP -> remove overlapping shapes + //@todo + } + return true; +} + +void VPolarAngleAxis::createMaximumLabels() +{ + if( !prepareShapeCreation() ) + return; + + createLabels(); +} + +void VPolarAngleAxis::updatePositions() +{ + //todo: really only update the positions + + if( !prepareShapeCreation() ) + return; + + createLabels(); +} + +void VPolarAngleAxis::createLabels() +{ + if( !prepareShapeCreation() ) + return; + + double fLogicRadius = m_pPosHelper->getOuterLogicRadius(); + double fLogicZ = 1.0;//as defined + + if( m_aAxisProperties.m_bDisplayLabels ) + { + //----------------------------------------- + //get the transformed screen values for all tickmarks in aAllTickInfos + std::auto_ptr< TickFactory > apTickFactory( this->createTickFactory() ); + + //create tick mark text shapes + //@todo: iterate through all tick depth wich should be labeled + + EquidistantTickIter aTickIter( m_aAllTickInfos, m_aIncrement, 0, 0 ); + this->updateUnscaledValuesAtTicks( aTickIter ); + + removeTextShapesFromTicks(); + + AxisLabelProperties aAxisLabelProperties( m_aAxisLabelProperties ); + aAxisLabelProperties.bOverlapAllowed = true; + while( !createTextShapes_ForAngleAxis( m_xTextTarget, aTickIter + , aAxisLabelProperties + , fLogicRadius, fLogicZ + ) ) + { + }; + + //no staggering for polar angle axis + } +} + +void VPolarAngleAxis::createShapes() +{ + if( !prepareShapeCreation() ) + return; + + double fLogicRadius = m_pPosHelper->getOuterLogicRadius(); + double fLogicZ = 1.0;//as defined + + //----------------------------------------- + //create axis main lines + drawing::PointSequenceSequence aPoints(1); + VPolarGrid::createLinePointSequence_ForAngleAxis( aPoints, m_aAllTickInfos, m_aIncrement, m_aScale, m_pPosHelper, fLogicRadius, fLogicZ ); + uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D( + m_xGroupShape_Shapes, aPoints, &m_aAxisProperties.m_aLineProperties ); + //because of this name this line will be used for marking the axis + m_pShapeFactory->setShapeName( xShape, C2U("MarkHandles") ); + + //----------------------------------------- + //create labels + createLabels(); +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/VPolarAngleAxis.hxx b/chart2/source/view/axes/VPolarAngleAxis.hxx new file mode 100644 index 000000000000..011033faaefa --- /dev/null +++ b/chart2/source/view/axes/VPolarAngleAxis.hxx @@ -0,0 +1,67 @@ +/************************************************************************* + * + * 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_VPOLARANGLEAXIS_HXX +#define _CHART2_VPOLARANGLEAXIS_HXX + +#include "VPolarAxis.hxx" +#include "Tickmarks_Equidistant.hxx" + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +class VPolarAngleAxis : public VPolarAxis +{ +public: + VPolarAngleAxis( const AxisProperties& rAxisProperties + , const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionCount ); + virtual ~VPolarAngleAxis(); + + virtual void createMaximumLabels(); + virtual void createLabels(); + virtual void updatePositions(); + + virtual void createShapes(); + +private: //methods + bool createTextShapes_ForAngleAxis( + const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget + , EquidistantTickIter& rTickIter + , AxisLabelProperties& rAxisLabelProperties + , double fLogicRadius, double fLogicZ ); +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/VPolarAxis.cxx b/chart2/source/view/axes/VPolarAxis.cxx new file mode 100644 index 000000000000..5f818da6c959 --- /dev/null +++ b/chart2/source/view/axes/VPolarAxis.cxx @@ -0,0 +1,83 @@ +/************************************************************************* + * + * 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 "VPolarAxis.hxx" +#include "VPolarAngleAxis.hxx" +#include "VPolarRadiusAxis.hxx" +#include "macros.hxx" +#include "Tickmarks.hxx" +#include "ShapeFactory.hxx" + +#include <memory> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +VPolarAxis* VPolarAxis::createAxis( const AxisProperties& rAxisProperties + , const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount ) +{ + if( 0==nDimensionIndex ) + return new VPolarAngleAxis( rAxisProperties, xNumberFormatsSupplier, nDimensionCount ); + return new VPolarRadiusAxis( rAxisProperties, xNumberFormatsSupplier, nDimensionCount ); +} + +VPolarAxis::VPolarAxis( const AxisProperties& rAxisProperties + , const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount ) + : VAxisBase( nDimensionIndex, nDimensionCount, rAxisProperties, xNumberFormatsSupplier ) + , m_pPosHelper( new PolarPlottingPositionHelper() ) + , m_aIncrements() +{ + PlotterBase::m_pPosHelper = m_pPosHelper; +} + +VPolarAxis::~VPolarAxis() +{ + delete m_pPosHelper; + m_pPosHelper = NULL; +} + +void VPolarAxis::setIncrements( const std::vector< ExplicitIncrementData >& rIncrements ) +{ + m_aIncrements = rIncrements; +} + +sal_Bool VPolarAxis::isAnythingToDraw() +{ + return ( 2==m_nDimension && VAxisBase::isAnythingToDraw() ); +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/VPolarAxis.hxx b/chart2/source/view/axes/VPolarAxis.hxx new file mode 100644 index 000000000000..a72b338416e2 --- /dev/null +++ b/chart2/source/view/axes/VPolarAxis.hxx @@ -0,0 +1,69 @@ +/************************************************************************* + * + * 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_VPOLARAXIS_HXX +#define _CHART2_VPOLARAXIS_HXX + +#include "VAxisBase.hxx" + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +class PolarPlottingPositionHelper; + +class VPolarAxis : public VAxisBase +{ +public: + static VPolarAxis* createAxis( const AxisProperties& rAxisProperties + , const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount ); + + void setIncrements( const std::vector< ExplicitIncrementData >& rIncrements ); + + virtual sal_Bool isAnythingToDraw(); + + virtual ~VPolarAxis(); + +protected: + VPolarAxis( const AxisProperties& rAxisProperties + , const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount ); + +protected: //member + PolarPlottingPositionHelper* m_pPosHelper; + ::std::vector< ExplicitIncrementData > m_aIncrements; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/VPolarCoordinateSystem.cxx b/chart2/source/view/axes/VPolarCoordinateSystem.cxx new file mode 100644 index 000000000000..5d13f5c46f66 --- /dev/null +++ b/chart2/source/view/axes/VPolarCoordinateSystem.cxx @@ -0,0 +1,202 @@ +/************************************************************************* + * + * 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 "VPolarCoordinateSystem.hxx" +#include "VPolarGrid.hxx" +#include "VPolarAxis.hxx" +#include "AxisIndexDefines.hxx" +#include "AxisHelper.hxx" + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +VPolarCoordinateSystem::VPolarCoordinateSystem( const Reference< XCoordinateSystem >& xCooSys ) + : VCoordinateSystem(xCooSys) +{ +} + +VPolarCoordinateSystem::~VPolarCoordinateSystem() +{ +} + +//better performance for big data +uno::Sequence< sal_Int32 > VPolarCoordinateSystem::getCoordinateSystemResolution( + const awt::Size& rPageSize, const awt::Size& rPageResolution ) +{ + uno::Sequence< sal_Int32 > aResolution( VCoordinateSystem::getCoordinateSystemResolution( rPageSize, rPageResolution) ); + + if( aResolution.getLength() >= 2 ) + { + if( this->getPropertySwapXAndYAxis() ) + { + aResolution[0]/=2;//radius + aResolution[1]*=4;//outer circle resolution + } + else + { + aResolution[0]*=4;//outer circle resolution + aResolution[1]/=2;//radius + } + } + + return aResolution; +} + +void VPolarCoordinateSystem::createVAxisList( + const uno::Reference< util::XNumberFormatsSupplier > & xNumberFormatsSupplier + , const awt::Size& rFontReferenceSize + , const awt::Rectangle& rMaximumSpaceForLabels + ) +{ + m_aAxisMap.clear(); + + //if(!m_xLogicTargetForAxes.is() || !m_xFinalTarget.is() || !m_xCooSysModel.is() ) + // return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); +// bool bSwapXAndY = this->getPropertySwapXAndYAxis(); + + sal_Int32 nDimensionIndex = 0; + + //create angle axis (dimension index 0) + for( nDimensionIndex = 0; nDimensionIndex < nDimensionCount; nDimensionIndex++ ) + { + sal_Int32 nMaxAxisIndex = m_xCooSysModel->getMaximumAxisIndexByDimension(nDimensionIndex); + for( sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; nAxisIndex++ ) + { + Reference< XAxis > xAxis( this->getAxisByDimension(nDimensionIndex,nAxisIndex) ); + if(!xAxis.is() || !AxisHelper::shouldAxisBeDisplayed( xAxis, m_xCooSysModel )) + continue; + AxisProperties aAxisProperties(xAxis,this->getExplicitCategoriesProvider()); + aAxisProperties.init(); + if(aAxisProperties.m_bDisplayLabels) + aAxisProperties.m_nNumberFormatKey = this->getNumberFormatKeyForAxis( xAxis, xNumberFormatsSupplier ); + //------------------- + ::boost::shared_ptr< VAxisBase > apVAxis( VPolarAxis::createAxis( aAxisProperties,xNumberFormatsSupplier,nDimensionIndex,nDimensionCount) ); + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + m_aAxisMap[aFullAxisIndex] = apVAxis; + + apVAxis->initAxisLabelProperties(rFontReferenceSize,rMaximumSpaceForLabels); + } + } +} + +void VPolarCoordinateSystem::initVAxisInList() +{ + if(!m_xLogicTargetForAxes.is() || !m_xFinalTarget.is() || !m_xCooSysModel.is() ) + return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = this->getPropertySwapXAndYAxis(); + + tVAxisMap::iterator aIt( m_aAxisMap.begin() ); + tVAxisMap::const_iterator aEnd( m_aAxisMap.end() ); + for( ; aIt != aEnd; ++aIt ) + { + VAxisBase* pVAxis = aIt->second.get(); + if( pVAxis ) + { + sal_Int32 nDimensionIndex = aIt->first.first; + sal_Int32 nAxisIndex = aIt->first.second; + pVAxis->setExplicitScaleAndIncrement( this->getExplicitScale( nDimensionIndex, nAxisIndex ), this->getExplicitIncrement(nDimensionIndex, nAxisIndex) ); + pVAxis->initPlotter(m_xLogicTargetForAxes,m_xFinalTarget,m_xShapeFactory + , this->createCIDForAxis( getAxisByDimension( nDimensionIndex, nAxisIndex ), nDimensionIndex, nAxisIndex ) ); + VPolarAxis* pVPolarAxis = dynamic_cast< VPolarAxis* >( pVAxis ); + if( pVPolarAxis ) + pVPolarAxis->setIncrements( this->getExplicitIncrements( nDimensionIndex, nAxisIndex ) ); + if(2==nDimensionCount) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + pVAxis->setScales( this->getExplicitScales( nDimensionIndex, nAxisIndex ), bSwapXAndY ); + } + } +} + +void VPolarCoordinateSystem::updateScalesAndIncrementsOnAxes() +{ + if(!m_xLogicTargetForAxes.is() || !m_xFinalTarget.is() || !m_xCooSysModel.is() ) + return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = this->getPropertySwapXAndYAxis(); + + tVAxisMap::iterator aIt( m_aAxisMap.begin() ); + tVAxisMap::const_iterator aEnd( m_aAxisMap.end() ); + for( ; aIt != aEnd; ++aIt ) + { + VAxisBase* pVAxis = aIt->second.get(); + if( pVAxis ) + { + sal_Int32 nDimensionIndex = aIt->first.first; + sal_Int32 nAxisIndex = aIt->first.second; + pVAxis->setExplicitScaleAndIncrement( this->getExplicitScale( nDimensionIndex, nAxisIndex ), this->getExplicitIncrement(nDimensionIndex, nAxisIndex) ); + VPolarAxis* pVPolarAxis = dynamic_cast< VPolarAxis* >( pVAxis ); + if( pVPolarAxis ) + pVPolarAxis->setIncrements( this->getExplicitIncrements( nDimensionIndex, nAxisIndex ) ); + if(2==nDimensionCount) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + pVAxis->setScales( this->getExplicitScales( nDimensionIndex, nAxisIndex ), bSwapXAndY ); + } + } +} + +void VPolarCoordinateSystem::createGridShapes() +{ + if(!m_xLogicTargetForGrids.is() || !m_xFinalTarget.is() ) + return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = this->getPropertySwapXAndYAxis(); + + for( sal_Int32 nDimensionIndex=0; nDimensionIndex<3; nDimensionIndex++) + { + sal_Int32 nAxisIndex = MAIN_AXIS_INDEX; + + Reference< XAxis > xAxis( AxisHelper::getAxis( nDimensionIndex, nAxisIndex, m_xCooSysModel ) ); + if(!xAxis.is() || !AxisHelper::shouldAxisBeDisplayed( xAxis, m_xCooSysModel )) + continue; + + VPolarGrid aGrid(nDimensionIndex,nDimensionCount,this->getGridListFromAxis( xAxis )); + aGrid.setIncrements( this->getExplicitIncrements( nDimensionIndex, nAxisIndex ) ); + aGrid.initPlotter(m_xLogicTargetForGrids,m_xFinalTarget,m_xShapeFactory + , this->createCIDForGrid( xAxis, nDimensionIndex, nAxisIndex ) ); + if(2==nDimensionCount) + aGrid.setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + aGrid.setScales( this->getExplicitScales( nDimensionIndex, nAxisIndex), bSwapXAndY ); + aGrid.createShapes(); + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/VPolarCoordinateSystem.hxx b/chart2/source/view/axes/VPolarCoordinateSystem.hxx new file mode 100644 index 000000000000..f1ba84c5469e --- /dev/null +++ b/chart2/source/view/axes/VPolarCoordinateSystem.hxx @@ -0,0 +1,68 @@ +/************************************************************************* + * + * 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_VPOLAR_COORDINATESYSTEM_HXX +#define _CHART2_VPOLAR_COORDINATESYSTEM_HXX + +#include "VCoordinateSystem.hxx" + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ +class VPolarCoordinateSystem : public VCoordinateSystem +{ +public: + VPolarCoordinateSystem( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XCoordinateSystem >& xCooSys ); + virtual ~VPolarCoordinateSystem(); + + //better performance for big data + virtual ::com::sun::star::uno::Sequence< sal_Int32 > getCoordinateSystemResolution( const ::com::sun::star::awt::Size& rPageSize + , const ::com::sun::star::awt::Size& rPageResolution ); + + virtual void createVAxisList( + const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier > & xNumberFormatsSupplier + , const ::com::sun::star::awt::Size& rFontReferenceSize + , const ::com::sun::star::awt::Rectangle& rMaximumSpaceForLabels ); + + virtual void initVAxisInList(); + virtual void updateScalesAndIncrementsOnAxes(); + + virtual void createGridShapes(); + +private: + VPolarCoordinateSystem(); +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/VPolarGrid.cxx b/chart2/source/view/axes/VPolarGrid.cxx new file mode 100644 index 000000000000..30becdf4725d --- /dev/null +++ b/chart2/source/view/axes/VPolarGrid.cxx @@ -0,0 +1,273 @@ +/************************************************************************* + * + * 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 "VPolarGrid.hxx" +#include "VCartesianGrid.hxx" +#include "Tickmarks.hxx" +#include "PlottingPositionHelper.hxx" +#include "ShapeFactory.hxx" +#include "ObjectIdentifier.hxx" +#include "macros.hxx" +#include "CommonConverters.hxx" +#include "Tickmarks_Equidistant.hxx" +#include <com/sun/star/drawing/LineStyle.hpp> + +#include <vector> +#include <memory> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +VPolarGrid::VPolarGrid( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , const uno::Sequence< Reference< beans::XPropertySet > > & rGridPropertiesList ) + : VAxisOrGridBase( nDimensionIndex, nDimensionCount ) + , m_aGridPropertiesList( rGridPropertiesList ) + , m_pPosHelper( new PolarPlottingPositionHelper() ) + , m_aIncrements() +{ + PlotterBase::m_pPosHelper = m_pPosHelper; +} + +VPolarGrid::~VPolarGrid() +{ + delete m_pPosHelper; + m_pPosHelper = NULL; +} + +void VPolarGrid::setIncrements( const std::vector< ExplicitIncrementData >& rIncrements ) +{ + m_aIncrements = rIncrements; +} + +void VPolarGrid::getAllTickInfos( sal_Int32 nDimensionIndex, ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const +{ + TickFactory aTickFactory( + m_pPosHelper->getScales()[nDimensionIndex], m_aIncrements[nDimensionIndex] ); + aTickFactory.getAllTicks( rAllTickInfos ); +} + +void VPolarGrid::createLinePointSequence_ForAngleAxis( + drawing::PointSequenceSequence& rPoints + , ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos + , const ExplicitIncrementData& rIncrement + , const ExplicitScaleData& rScale + , PolarPlottingPositionHelper* pPosHelper + , double fLogicRadius, double fLogicZ ) +{ + Reference< XScaling > xInverseScaling( NULL ); + if( rScale.Scaling.is() ) + xInverseScaling = rScale.Scaling->getInverseScaling(); + + sal_Int32 nTick = 0; + EquidistantTickIter aIter( rAllTickInfos, rIncrement, 0, 0 ); + for( TickInfo* pTickInfo = aIter.firstInfo() + ; pTickInfo + ; pTickInfo = aIter.nextInfo(), nTick++ ) + { + if(nTick>=rPoints[0].getLength()) + rPoints[0].realloc(rPoints[0].getLength()+30); + + //xxxxx pTickInfo->updateUnscaledValue( xInverseScaling ); + double fLogicAngle = pTickInfo->getUnscaledTickValue(); + + drawing::Position3D aScenePosition3D( pPosHelper->transformAngleRadiusToScene( fLogicAngle, fLogicRadius, fLogicZ ) ); + rPoints[0][nTick].X = static_cast<sal_Int32>(aScenePosition3D.PositionX); + rPoints[0][nTick].Y = static_cast<sal_Int32>(aScenePosition3D.PositionY); + } + if(rPoints[0].getLength()>1) + { + rPoints[0].realloc(nTick+1); + rPoints[0][nTick].X = rPoints[0][0].X; + rPoints[0][nTick].Y = rPoints[0][0].Y; + } + else + rPoints[0].realloc(0); +} +#ifdef NOTYET +void VPolarGrid::create2DAngleGrid( const Reference< drawing::XShapes >& xLogicTarget + , ::std::vector< ::std::vector< TickInfo > >& /* rRadiusTickInfos */ + , ::std::vector< ::std::vector< TickInfo > >& rAngleTickInfos + , const ::std::vector<VLineProperties>& rLinePropertiesList ) +{ + Reference< drawing::XShapes > xMainTarget( + this->createGroupShape( xLogicTarget, m_aCID ) ); + + const ExplicitScaleData& rAngleScale = m_pPosHelper->getScales()[0]; + Reference< XScaling > xInverseScaling( NULL ); + if( rAngleScale.Scaling.is() ) + xInverseScaling = rAngleScale.Scaling->getInverseScaling(); + + double fLogicInnerRadius = m_pPosHelper->getInnerLogicRadius(); + double fLogicOuterRadius = m_pPosHelper->getOuterLogicRadius(); + double fLogicZ = 1.0;//as defined + + sal_Int32 nLinePropertiesCount = rLinePropertiesList.size(); + ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter = rAngleTickInfos.begin(); + sal_Int32 nDepth=0; + /* + //no subgrids so far for polar angle grid (need different radii) + const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd = rAngleTickInfos.end(); + for( ; aDepthIter != aDepthEnd && nDepth < nLinePropertiesCount + ; aDepthIter++, nDepth++ ) + */ + if(nLinePropertiesCount) + { + //create axis main lines + drawing::PointSequenceSequence aAllPoints; + ::std::vector< TickInfo >::iterator aTickIter = (*aDepthIter).begin(); + const ::std::vector< TickInfo >::const_iterator aTickEnd = (*aDepthIter).end(); + for( ; aTickIter != aTickEnd; aTickIter++ ) + { + TickInfo& rTickInfo = *aTickIter; + if( !rTickInfo.bPaintIt ) + continue; + + //xxxxx rTickInfo.updateUnscaledValue( xInverseScaling ); + double fLogicAngle = rTickInfo.getUnscaledTickValue(); + + drawing::PointSequenceSequence aPoints(1); + aPoints[0].realloc(2); + drawing::Position3D aScenePositionStart( m_pPosHelper->transformAngleRadiusToScene( fLogicAngle, fLogicInnerRadius, fLogicZ ) ); + drawing::Position3D aScenePositionEnd( m_pPosHelper->transformAngleRadiusToScene( fLogicAngle, fLogicOuterRadius, fLogicZ ) ); + aPoints[0][0].X = static_cast<sal_Int32>(aScenePositionStart.PositionX); + aPoints[0][0].Y = static_cast<sal_Int32>(aScenePositionStart.PositionY); + aPoints[0][1].X = static_cast<sal_Int32>(aScenePositionEnd.PositionX); + aPoints[0][1].Y = static_cast<sal_Int32>(aScenePositionEnd.PositionY); + appendPointSequence( aAllPoints, aPoints ); + } + + Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D( + xMainTarget, aAllPoints, &rLinePropertiesList[nDepth] ); + //because of this name this line will be used for marking + m_pShapeFactory->setShapeName( xShape, C2U("MarkHandles") ); + } +} +#endif + +void VPolarGrid::create2DRadiusGrid( const Reference< drawing::XShapes >& xLogicTarget + , ::std::vector< ::std::vector< TickInfo > >& rRadiusTickInfos + , ::std::vector< ::std::vector< TickInfo > >& rAngleTickInfos + , const ::std::vector<VLineProperties>& rLinePropertiesList ) +{ + Reference< drawing::XShapes > xMainTarget( + this->createGroupShape( xLogicTarget, m_aCID ) ); + + const ExplicitScaleData& rRadiusScale = m_pPosHelper->getScales()[1]; + const ExplicitScaleData& rAngleScale = m_pPosHelper->getScales()[0]; + const ExplicitIncrementData& rAngleIncrement = m_aIncrements[0]; + Reference< XScaling > xInverseRadiusScaling( NULL ); + if( rRadiusScale.Scaling.is() ) + xInverseRadiusScaling = rRadiusScale.Scaling->getInverseScaling(); + + sal_Int32 nLinePropertiesCount = rLinePropertiesList.size(); + ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter = rRadiusTickInfos.begin(); + const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd = rRadiusTickInfos.end(); + for( sal_Int32 nDepth=0 + ; aDepthIter != aDepthEnd && nDepth < nLinePropertiesCount + ; aDepthIter++, nDepth++ ) + { + if( !rLinePropertiesList[nDepth].isLineVisible() ) + continue; + + Reference< drawing::XShapes > xTarget( xMainTarget ); + if( nDepth > 0 ) + { + xTarget.set( this->createGroupShape( xLogicTarget + , ObjectIdentifier::addChildParticle( m_aCID, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_SUBGRID, nDepth-1 ) ) + ) ); + if(!xTarget.is()) + xTarget.set( xMainTarget ); + } + + //create axis main lines + drawing::PointSequenceSequence aAllPoints; + ::std::vector< TickInfo >::iterator aTickIter = (*aDepthIter).begin(); + const ::std::vector< TickInfo >::const_iterator aTickEnd = (*aDepthIter).end(); + for( ; aTickIter != aTickEnd; aTickIter++ ) + { + TickInfo& rTickInfo = *aTickIter; + if( !rTickInfo.bPaintIt ) + continue; + + //xxxxx rTickInfo.updateUnscaledValue( xInverseRadiusScaling ); + double fLogicRadius = rTickInfo.getUnscaledTickValue(); + double fLogicZ = 1.0;//as defined + + drawing::PointSequenceSequence aPoints(1); + VPolarGrid::createLinePointSequence_ForAngleAxis( aPoints, rAngleTickInfos + , rAngleIncrement, rAngleScale, m_pPosHelper, fLogicRadius, fLogicZ ); + if(aPoints[0].getLength()) + appendPointSequence( aAllPoints, aPoints ); + } + + Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D( + xTarget, aAllPoints, &rLinePropertiesList[nDepth] ); + //because of this name this line will be used for marking + m_pShapeFactory->setShapeName( xShape, C2U("MarkHandles") ); + } +} + +void VPolarGrid::createShapes() +{ + DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"Axis is not proper initialized"); + if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is())) + return; + if(!m_aGridPropertiesList.getLength()) + return; + + //----------------------------------------- + //create all scaled tickmark values + ::std::vector< ::std::vector< TickInfo > > aAngleTickInfos; + ::std::vector< ::std::vector< TickInfo > > aRadiusTickInfos; + getAllTickInfos( 0, aAngleTickInfos ); + getAllTickInfos( 1, aRadiusTickInfos ); + + //----------------------------------------- + ::std::vector<VLineProperties> aLinePropertiesList; + VCartesianGrid::fillLinePropertiesFromGridModel( aLinePropertiesList, m_aGridPropertiesList ); + + //----------------------------------------- + //create tick mark line shapes + if(2==m_nDimension) + { + if(m_nDimensionIndex==1) + this->create2DRadiusGrid( m_xLogicTarget, aRadiusTickInfos, aAngleTickInfos, aLinePropertiesList ); + //else //no Angle Grid so far as this equals exactly the y axis positions + // this->create2DAngleGrid( m_xLogicTarget, aRadiusTickInfos, aAngleTickInfos, aLinePropertiesList ); + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/VPolarGrid.hxx b/chart2/source/view/axes/VPolarGrid.hxx new file mode 100644 index 000000000000..1ea3bccc1f90 --- /dev/null +++ b/chart2/source/view/axes/VPolarGrid.hxx @@ -0,0 +1,94 @@ +/************************************************************************* + * + * 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_VPOLARGRID_HXX +#define _CHART2_VPOLARGRID_HXX + +#include "VAxisOrGridBase.hxx" +#include "Tickmarks.hxx" +#include "VLineProperties.hxx" +#include <com/sun/star/drawing/PointSequenceSequence.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ +class PolarPlottingPositionHelper; + +class VPolarGrid : public VAxisOrGridBase +{ +//------------------------------------------------------------------------- +// public methods +//------------------------------------------------------------------------- +public: + VPolarGrid( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet > > & rGridPropertiesList //main grid, subgrid, subsubgrid etc + ); + virtual ~VPolarGrid(); + + virtual void createShapes(); + + void setIncrements( const std::vector< ExplicitIncrementData >& rIncrements ); + + static void createLinePointSequence_ForAngleAxis( + ::com::sun::star::drawing::PointSequenceSequence& rPoints + , ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos + , const ExplicitIncrementData& rIncrement + , const ExplicitScaleData& rScale + , PolarPlottingPositionHelper* pPosHelper + , double fLogicRadius, double fLogicZ ); + +private: //member + ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet > > m_aGridPropertiesList;//main grid, subgrid, subsubgrid etc + PolarPlottingPositionHelper* m_pPosHelper; + ::std::vector< ExplicitIncrementData > m_aIncrements; + + void getAllTickInfos( sal_Int32 nDimensionIndex, ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const; + + void create2DRadiusGrid( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xLogicTarget + , ::std::vector< ::std::vector< TickInfo > >& rRadiusTickInfos + , ::std::vector< ::std::vector< TickInfo > >& rAngleTickInfos + , const ::std::vector<VLineProperties>& rLinePropertiesList ); +#if NOTYET + void create2DAngleGrid( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xLogicTarget + , ::std::vector< ::std::vector< TickInfo > >& rRadiusTickInfos + , ::std::vector< ::std::vector< TickInfo > >& rAngleTickInfos + , const ::std::vector<VLineProperties>& rLinePropertiesList ); +#endif +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/VPolarRadiusAxis.cxx b/chart2/source/view/axes/VPolarRadiusAxis.cxx new file mode 100644 index 000000000000..bc56b3824e6e --- /dev/null +++ b/chart2/source/view/axes/VPolarRadiusAxis.cxx @@ -0,0 +1,185 @@ +/************************************************************************* + * + * 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 "VPolarRadiusAxis.hxx" +#include "VCartesianAxis.hxx" +#include "PlottingPositionHelper.hxx" +#include "CommonConverters.hxx" +#include "Tickmarks_Equidistant.hxx" +#include <rtl/math.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::rtl::math; + +VPolarRadiusAxis::VPolarRadiusAxis( const AxisProperties& rAxisProperties + , const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionCount ) + : VPolarAxis( rAxisProperties, xNumberFormatsSupplier, 1/*nDimensionIndex*/, nDimensionCount ) +{ + m_aAxisProperties.m_fLabelDirectionSign=0.0; + m_aAxisProperties.m_fInnerDirectionSign=0.0; + m_aAxisProperties.m_bIsMainAxis=false; + m_aAxisProperties.m_aLabelAlignment=LABEL_ALIGN_RIGHT; + m_aAxisProperties.init(); + + m_apAxisWithLabels = std::auto_ptr<VCartesianAxis>( new VCartesianAxis( + m_aAxisProperties,xNumberFormatsSupplier,1/*nDimensionIndex*/,nDimensionCount + ,new PolarPlottingPositionHelper() ) ); +} + +VPolarRadiusAxis::~VPolarRadiusAxis() +{ + delete m_pPosHelper; + m_pPosHelper = NULL; +} + +void VPolarRadiusAxis::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix) +{ + VPolarAxis::setTransformationSceneToScreen( rMatrix ); + m_apAxisWithLabels->setTransformationSceneToScreen( rMatrix ); +} + +void VPolarRadiusAxis::setExplicitScaleAndIncrement( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ) + throw (uno::RuntimeException) +{ + VPolarAxis::setExplicitScaleAndIncrement( rScale, rIncrement ); + m_apAxisWithLabels->setExplicitScaleAndIncrement( rScale, rIncrement ); +} + +void VPolarRadiusAxis::initPlotter( const uno::Reference< drawing::XShapes >& xLogicTarget + , const uno::Reference< drawing::XShapes >& xFinalTarget + , const uno::Reference< lang::XMultiServiceFactory >& xShapeFactory + , const rtl::OUString& rCID ) + throw (uno::RuntimeException) +{ + VPolarAxis::initPlotter( xLogicTarget, xFinalTarget, xShapeFactory, rCID ); + m_apAxisWithLabels->initPlotter( xLogicTarget, xFinalTarget, xShapeFactory, rCID ); +} + +void VPolarRadiusAxis::setScales( const std::vector< ExplicitScaleData >& rScales, bool bSwapXAndYAxis ) +{ + VPolarAxis::setScales( rScales, bSwapXAndYAxis ); + m_apAxisWithLabels->setScales( rScales, bSwapXAndYAxis ); +} + +void VPolarRadiusAxis::initAxisLabelProperties( const ::com::sun::star::awt::Size& rFontReferenceSize + , const ::com::sun::star::awt::Rectangle& rMaximumSpaceForLabels ) +{ + VPolarAxis::initAxisLabelProperties( rFontReferenceSize, rMaximumSpaceForLabels ); + m_apAxisWithLabels->initAxisLabelProperties( rFontReferenceSize, rMaximumSpaceForLabels ); +} + +sal_Int32 VPolarRadiusAxis::estimateMaximumAutoMainIncrementCount() +{ + return 2; +} + +bool VPolarRadiusAxis::prepareShapeCreation() +{ + //returns true if all is ready for further shape creation and any shapes need to be created + if( !isAnythingToDraw() ) + return false; + + if( m_xGroupShape_Shapes.is() ) + return true; + + return true; +} + +void VPolarRadiusAxis::createMaximumLabels() +{ + m_apAxisWithLabels->createMaximumLabels(); +} + +void VPolarRadiusAxis::updatePositions() +{ + m_apAxisWithLabels->updatePositions(); +} + +void VPolarRadiusAxis::createLabels() +{ + m_apAxisWithLabels->createLabels(); +} + +void VPolarRadiusAxis::createShapes() +{ + if( !prepareShapeCreation() ) + return; + + const ExplicitScaleData& rAngleScale = m_pPosHelper->getScales()[0]; + const ExplicitIncrementData& rAngleIncrement = m_aIncrements[0]; + + ::std::vector< ::std::vector< TickInfo > > aAngleTickInfos; + TickFactory aAngleTickFactory( rAngleScale, rAngleIncrement ); + aAngleTickFactory.getAllTicks( aAngleTickInfos ); + + uno::Reference< XScaling > xInverseScaling( NULL ); + if( rAngleScale.Scaling.is() ) + xInverseScaling = rAngleScale.Scaling->getInverseScaling(); + + AxisProperties aAxisProperties(m_aAxisProperties); + + sal_Int32 nTick = 0; + EquidistantTickIter aIter( aAngleTickInfos, rAngleIncrement, 0, 0 ); + for( TickInfo* pTickInfo = aIter.firstInfo() + ; pTickInfo; pTickInfo = aIter.nextInfo(), nTick++ ) + { + if( nTick == 0 ) + { + m_apAxisWithLabels->createShapes(); + continue; + } + + //xxxxx pTickInfo->updateUnscaledValue( xInverseScaling ); + aAxisProperties.m_pfMainLinePositionAtOtherAxis = new double( pTickInfo->getUnscaledTickValue() ); + aAxisProperties.m_bDisplayLabels=false; + + //------------------- + VCartesianAxis aAxis(aAxisProperties,m_xNumberFormatsSupplier + ,1,2,new PolarPlottingPositionHelper()); + aAxis.setExplicitScaleAndIncrement( m_aScale, m_aIncrement ); + aAxis.initPlotter(m_xLogicTarget,m_xFinalTarget,m_xShapeFactory, m_aCID ); + aAxis.setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( m_aMatrixScreenToScene ) ); + aAxis.setScales( m_pPosHelper->getScales(), false ); + aAxis.initAxisLabelProperties(m_aAxisLabelProperties.m_aFontReferenceSize,m_aAxisLabelProperties.m_aMaximumSpaceForLabels); + aAxis.createShapes(); + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/axes/VPolarRadiusAxis.hxx b/chart2/source/view/axes/VPolarRadiusAxis.hxx new file mode 100644 index 000000000000..e1dbb8c1b1c0 --- /dev/null +++ b/chart2/source/view/axes/VPolarRadiusAxis.hxx @@ -0,0 +1,94 @@ +/************************************************************************* + * + * 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_VPOLARRADIUSAXIS_HXX +#define _CHART2_VPOLARRADIUSAXIS_HXX + +#include "VPolarAxis.hxx" + +#include <memory> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +class VCartesianAxis; + +class VPolarRadiusAxis : public VPolarAxis +{ +public: + VPolarRadiusAxis( const AxisProperties& rAxisProperties + , const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionCount ); + virtual ~VPolarRadiusAxis(); + + virtual void initPlotter( + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xLogicTarget + , const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xFinalTarget + , const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& xFactory + , const rtl::OUString& rCID + ) throw (::com::sun::star::uno::RuntimeException ); + + virtual void setTransformationSceneToScreen( const ::com::sun::star::drawing::HomogenMatrix& rMatrix ); + + virtual void setScales( const ::std::vector< ExplicitScaleData >& rScales, bool bSwapXAndYAxis ); + + virtual void setExplicitScaleAndIncrement( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ) + throw (::com::sun::star::uno::RuntimeException); + + virtual void initAxisLabelProperties( + const ::com::sun::star::awt::Size& rFontReferenceSize + , const ::com::sun::star::awt::Rectangle& rMaximumSpaceForLabels ); + + virtual sal_Int32 estimateMaximumAutoMainIncrementCount(); + + virtual void createMaximumLabels(); + virtual void createLabels(); + virtual void updatePositions(); + + virtual void createShapes(); + +protected: //methods + virtual bool prepareShapeCreation(); + +private: //member + std::auto_ptr<VCartesianAxis> m_apAxisWithLabels; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/axes/makefile.mk b/chart2/source/view/axes/makefile.mk new file mode 100644 index 000000000000..af88a61b6b37 --- /dev/null +++ b/chart2/source/view/axes/makefile.mk @@ -0,0 +1,70 @@ +#************************************************************************* +# +# 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= chvaxes + +ENABLE_EXCEPTIONS= TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE: settings.mk +.INCLUDE: $(PRJ)$/chartview.pmk + +#.IF "$(GUI)" == "WNT" +#CFLAGS+=-GR +#.ENDIF + +# --- export library ------------------------------------------------- + +#object files to build and link together to lib $(SLB)$/$(TARGET).lib +SLOFILES = \ + $(SLO)$/VAxisOrGridBase.obj \ + $(SLO)$/VAxisBase.obj \ + $(SLO)$/DateHelper.obj \ + $(SLO)$/DateScaling.obj \ + $(SLO)$/Tickmarks.obj \ + $(SLO)$/Tickmarks_Equidistant.obj \ + $(SLO)$/Tickmarks_Dates.obj \ + $(SLO)$/MinimumAndMaximumSupplier.obj \ + $(SLO)$/ScaleAutomatism.obj \ + $(SLO)$/VAxisProperties.obj \ + $(SLO)$/VCartesianAxis.obj \ + $(SLO)$/VCartesianGrid.obj \ + $(SLO)$/VCartesianCoordinateSystem.obj \ + $(SLO)$/VPolarAxis.obj \ + $(SLO)$/VPolarAngleAxis.obj \ + $(SLO)$/VPolarRadiusAxis.obj \ + $(SLO)$/VPolarGrid.obj \ + $(SLO)$/VPolarCoordinateSystem.obj \ + $(SLO)$/VCoordinateSystem.obj + +# --- Targets ----------------------------------------------------------------- + +.INCLUDE: target.mk diff --git a/chart2/source/view/charttypes/AreaChart.cxx b/chart2/source/view/charttypes/AreaChart.cxx new file mode 100644 index 000000000000..41bec1f9c331 --- /dev/null +++ b/chart2/source/view/charttypes/AreaChart.cxx @@ -0,0 +1,997 @@ +/************************************************************************* + * + * 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 "chartview/servicenames_charttypes.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 "DateHelper.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(); + if( m_pMainPosHelper ) + { + m_pMainPosHelper->AllowShiftXAxisPos(true); + m_pMainPosHelper->AllowShiftZAxisPos(true); + } + 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::getMaximumX() +{ + double fMax = VSeriesPlotter::getMaximumX(); + if( m_bCategoryXAxis && m_bIsPolarCooSys )//the angle axis in net charts needs a different autoscaling + fMax += 1.0; + return fMax; +} + +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 LegendSymbolStyle_BOX; + return LegendSymbolStyle_LINE; +} + +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; +} + +//----------------------------------------------------------------- +// lang::XServiceInfo +//----------------------------------------------------------------- +/* +APPHELPER_XSERVICEINFO_IMPL(AreaChart,CHART2_VIEW_AREACHART_SERVICE_IMPLEMENTATION_NAME) + + uno::Sequence< rtl::OUString > AreaChart +::getSupportedServiceNames_Static() +{ + uno::Sequence< rtl::OUString > aSNS( 1 ); + aSNS.getArray()[ 0 ] = CHART2_VIEW_AREACHART_SERVICE_NAME; + return aSNS; +} +*/ +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 = 1.0;//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); + if( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) + fLogicX = DateHelper::RasterizeDateValue( fLogicX, m_aNullDate, m_nTimeResolution ); + 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 +//............................................................................. diff --git a/chart2/source/view/charttypes/AreaChart.hxx b/chart2/source/view/charttypes/AreaChart.hxx new file mode 100644 index 000000000000..972d97fa75ac --- /dev/null +++ b/chart2/source/view/charttypes/AreaChart.hxx @@ -0,0 +1,123 @@ +/************************************************************************* + * + * 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(); + + virtual void 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; + virtual bool keepAspectRatio() const; + + //------------------------------------------------------------------------- + // MinimumAndMaximumSupplier + //------------------------------------------------------------------------- + virtual double getMaximumX(); + virtual bool isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex ); + virtual bool isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex ); + + //------------------------------------------------------------------------- + + virtual 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 diff --git a/chart2/source/view/charttypes/BarChart.cxx b/chart2/source/view/charttypes/BarChart.cxx new file mode 100644 index 000000000000..dbf01165bf79 --- /dev/null +++ b/chart2/source/view/charttypes/BarChart.cxx @@ -0,0 +1,978 @@ +/************************************************************************* + * + * 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 "chartview/servicenames_charttypes.hxx" +//#include "servicenames_coosystems.hxx" +#include "CommonConverters.hxx" +#include "ObjectIdentifier.hxx" +#include "LabelPositionHelper.hxx" +#include "BarPositionHelper.hxx" +#include "macros.hxx" +#include "AxisIndexDefines.hxx" +#include "Clipping.hxx" +#include "DateHelper.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->getScaledSlotWidth()); + } + 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; +} + +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 = 1.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; + // + + sal_Int32 nStartIndex = 0; + sal_Int32 nEndIndex = VSeriesPlotter::getPointCount(); +//============================================================================= + //iterate through all x values per indices + for( sal_Int32 nPointIndex = nStartIndex; nPointIndex < nEndIndex; nPointIndex++ ) + { + ::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( nPointIndex + , 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->getScaledSlotWidth(); + + ::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( nPointIndex + , 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(nPointIndex==nStartIndex)//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 fUnscaledLogicX = (*aSeriesIter)->getXValue( nPointIndex ); + fUnscaledLogicX = DateHelper::RasterizeDateValue( fUnscaledLogicX, m_aNullDate, m_nTimeResolution ); + if(fUnscaledLogicX<pPosHelper->getLogicMinX()) + continue;//point not visible + if(fUnscaledLogicX>pPosHelper->getLogicMaxX()) + continue;//point not visible + if(pPosHelper->isStrongLowerRequested(0) && fUnscaledLogicX==pPosHelper->getLogicMaxX()) + continue;//point not visible + double fLogicX = pPosHelper->getScaledSlotPos( fUnscaledLogicX, fSlotX ); + + double fLogicBarHeight = (*aSeriesIter)->getYValue( nPointIndex ); + 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+0.5; + + drawing::Position3D aUnscaledLogicPosition( fUnscaledLogicX, 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( nPointIndex ) ); + 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(nPointIndex) + && + 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 + { + //if( bCreateLineInsteadOfComplexGeometryDueToMissingSpace ) + //{ + // drawing::PolyPolygonShape3D aPoly; + // drawing::Position3D aUpperPoint( fLogicX,fUpperYValue,fLogicZ ); + // drawing::Position3D aLowerPoint( fLogicX,fLowerYValue,fLogicZ ); + + // AddPointToPoly( aPoly, aUpperPoint ); + // AddPointToPoly( aPoly, aLowerPoint ); + + // VLineProperties aLineProperties; + // aLineProperties.initFromPropertySet( xDataPointProperties, true /*bUseSeriesPropertyNames*/ ); + // if( !aLineProperties.isLineVisible() ) + // { + // //todo + // //aLineProperties.Color = + // } + + // xShape = m_pShapeFactory->createLine2D( xPointGroupShape_Shapes + // , PolyToPointSequence(aPoly), &aLineProperties ); + //} + + 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(),nPointIndex) ); + } + + //create error bar + createErrorBar_Y( aUnscaledLogicPosition, **aSeriesIter, nPointIndex, m_xLogicTarget, &fLogicX ); + + //------------ + //create data point label + if( (**aSeriesIter).getDataPointLabelIfLabel(nPointIndex) ) + { + double fLogicSum = aLogicYSumMap[nAttachedAxisIndex]; + + LabelAlignment eAlignment(LABEL_ALIGN_CENTER); + sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nPointIndex, 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, nPointIndex + , fLogicValueForLabeDisplay, fLogicSum, aScreenPosition2D, eAlignment, nOffset ); + } + + }//end iteration through partial points + + //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 +//============================================================================= +//============================================================================= +//============================================================================= + 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 +//............................................................................. diff --git a/chart2/source/view/charttypes/BarChart.hxx b/chart2/source/view/charttypes/BarChart.hxx new file mode 100644 index 000000000000..c20c85168b5d --- /dev/null +++ b/chart2/source/view/charttypes/BarChart.hxx @@ -0,0 +1,94 @@ +/************************************************************************* + * + * 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(); + + virtual void 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; + virtual bool keepAspectRatio() const; + + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + +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 diff --git a/chart2/source/view/charttypes/BarPositionHelper.cxx b/chart2/source/view/charttypes/BarPositionHelper.cxx new file mode 100644 index 000000000000..45dab527da11 --- /dev/null +++ b/chart2/source/view/charttypes/BarPositionHelper.cxx @@ -0,0 +1,91 @@ +/************************************************************************* + * + * 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" +#include "DateHelper.hxx" +#include <com/sun/star/chart/TimeUnit.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +BarPositionHelper::BarPositionHelper( bool /* bSwapXAndY */ ) + : CategoryPositionHelper( 1 ) +{ + AllowShiftXAxisPos(true); + AllowShiftZAxisPos(true); +} + +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; +} + +double BarPositionHelper::getScaledSlotPos( double fUnscaledLogicX, double fSeriesNumber ) const +{ + if( m_bDateAxis ) + fUnscaledLogicX = DateHelper::RasterizeDateValue( fUnscaledLogicX, m_aNullDate, m_nTimeResolution ); + double fScaledLogicX(fUnscaledLogicX); + doLogicScaling(&fScaledLogicX,NULL,NULL); + fScaledLogicX = CategoryPositionHelper::getScaledSlotPos( fScaledLogicX, fSeriesNumber ); + return fScaledLogicX; + +} + +void BarPositionHelper::setScaledCategoryWidth( double fScaledCategoryWidth ) +{ + m_fScaledCategoryWidth = fScaledCategoryWidth; + CategoryPositionHelper::setCategoryWidth( m_fScaledCategoryWidth ); +} +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/charttypes/BarPositionHelper.hxx b/chart2/source/view/charttypes/BarPositionHelper.hxx new file mode 100644 index 000000000000..3a905877bcb9 --- /dev/null +++ b/chart2/source/view/charttypes/BarPositionHelper.hxx @@ -0,0 +1,61 @@ +/************************************************************************* + * + * 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; + + void updateSeriesCount( double fSeriesCount ); /*only enter the size of x stacked series*/ + + virtual double getScaledSlotPos( double fCategoryX, double fSeriesNumber ) const; + virtual void setScaledCategoryWidth( double fScaledCategoryWidth ); +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/charttypes/BubbleChart.cxx b/chart2/source/view/charttypes/BubbleChart.cxx new file mode 100644 index 000000000000..3dbbc0eaf3e2 --- /dev/null +++ b/chart2/source/view/charttypes/BubbleChart.cxx @@ -0,0 +1,417 @@ +/************************************************************************* + * + * 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=1.0; + 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 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 = 1.0;//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..f94fe9e367e7 --- /dev/null +++ b/chart2/source/view/charttypes/BubbleChart.hxx @@ -0,0 +1,90 @@ +/************************************************************************* + * + * 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(); + + virtual void 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 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 new file mode 100644 index 000000000000..57d5a70e4080 --- /dev/null +++ b/chart2/source/view/charttypes/CandleStickChart.cxx @@ -0,0 +1,390 @@ +/************************************************************************* + * + * 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 "DateHelper.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 +//------------------------------------------------------------------------- + +bool CandleStickChart::isSeperateStackingForDifferentSigns( sal_Int32 /* nDimensionIndex */ ) +{ + return false; +} + +//----------------------------------------------------------------- +//----------------------------------------------------------------- +//----------------------------------------------------------------- + +LegendSymbolStyle CandleStickChart::getLegendSymbolStyle() +{ + return LegendSymbolStyle_LINE; +} + +//----------------------------------------------------------------- +// lang::XServiceInfo +//----------------------------------------------------------------- +/* +APPHELPER_XSERVICEINFO_IMPL(CandleStickChart,CHART2_VIEW_CANDLESTICKCHART_SERVICE_IMPLEMENTATION_NAME) + + uno::Sequence< rtl::OUString > CandleStickChart +::getSupportedServiceNames_Static() +{ + uno::Sequence< rtl::OUString > aSNS( 1 ); + aSNS.getArray()[ 0 ] = CHART2_VIEW_CANDLESTICKCHART_SERVICE_NAME; + return aSNS; +} +*/ + +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 nStartIndex = 0; + sal_Int32 nEndIndex = VSeriesPlotter::getPointCount(); + double fLogicZ = 1.5;//as defined +//============================================================================= + //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(); +//============================================================================= + 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 fUnscaledX = (*aSeriesIter)->getXValue( nIndex ); + if( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) + fUnscaledX = DateHelper::RasterizeDateValue( fUnscaledX, m_aNullDate, m_nTimeResolution ); + if(fUnscaledX<pPosHelper->getLogicMinX() || fUnscaledX>pPosHelper->getLogicMaxX()) + continue;//point not visible + double fScaledX = pPosHelper->getScaledSlotPos( fUnscaledX, fSlotX ); + + double fUnscaledY_First = (*aSeriesIter)->getY_First( nIndex ); + double fUnscaledY_Last = (*aSeriesIter)->getY_Last( nIndex ); + double fUnscaledY_Min = (*aSeriesIter)->getY_Min( nIndex ); + double fUnscaledY_Max = (*aSeriesIter)->getY_Max( nIndex ); + + bool bBlack=false; + if(fUnscaledY_Last<=fUnscaledY_First) + { + std::swap(fUnscaledY_First,fUnscaledY_Last); + bBlack=true; + } + if(fUnscaledY_Max<fUnscaledY_Min) + std::swap(fUnscaledY_Min,fUnscaledY_Max); + //transformation 3) -> 4) + double fHalfScaledWidth = pPosHelper->getScaledSlotWidth()/2.0; + + double fScaledY_First(fUnscaledY_First); + double fScaledY_Last(fUnscaledY_Last); + double fScaledY_Min(fUnscaledY_Min); + double fScaledY_Max(fUnscaledY_Max); + pPosHelper->clipLogicValues( 0,&fScaledY_First,0 ); + pPosHelper->clipLogicValues( 0,&fScaledY_Last,0 ); + pPosHelper->clipLogicValues( 0,&fScaledY_Min,0 ); + pPosHelper->clipLogicValues( 0,&fScaledY_Max,0 ); + pPosHelper->doLogicScaling( 0,&fScaledY_First,0 ); + pPosHelper->doLogicScaling( 0,&fScaledY_Last,0 ); + pPosHelper->doLogicScaling( 0,&fScaledY_Min,0 ); + pPosHelper->doLogicScaling( 0,&fScaledY_Max,0 ); + + drawing::Position3D aPosLeftFirst( pPosHelper->transformScaledLogicToScene( fScaledX-fHalfScaledWidth, fScaledY_First ,0 ,true ) ); + drawing::Position3D aPosRightLast( pPosHelper->transformScaledLogicToScene( fScaledX+fHalfScaledWidth, fScaledY_Last ,0 ,true ) ); + drawing::Position3D aPosMiddleFirst( pPosHelper->transformScaledLogicToScene( fScaledX, fScaledY_First ,0 ,true ) ); + drawing::Position3D aPosMiddleLast( pPosHelper->transformScaledLogicToScene( fScaledX, fScaledY_Last ,0 ,true ) ); + drawing::Position3D aPosMiddleMinimum( pPosHelper->transformScaledLogicToScene( fScaledX, fScaledY_Min ,0 ,true ) ); + drawing::Position3D aPosMiddleMaximum( pPosHelper->transformScaledLogicToScene( fScaledX, fScaledY_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( fUnscaledX, fUnscaledY_First ,fLogicZ ) + && isValidPosition(aPosLeftFirst) && isValidPosition(aPosMiddleFirst) ) + { + AddPointToPoly( aPoly, aPosLeftFirst, nLineIndex ); + AddPointToPoly( aPoly, aPosMiddleFirst, nLineIndex++ ); + } + if( pPosHelper->isLogicVisible( fUnscaledX, fUnscaledY_Last ,fLogicZ ) + && 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 + , fUnscaledY_First, 1.0, Position3DToAWTPoint(aPosMiddleFirst), LABEL_ALIGN_LEFT_BOTTOM ); + if(isValidPosition(aPosMiddleLast)) + this->createDataLabel( xTextTarget, **aSeriesIter, nIndex + , fUnscaledY_Last, 1.0, Position3DToAWTPoint(aPosMiddleLast), LABEL_ALIGN_RIGHT_TOP ); + if(isValidPosition(aPosMiddleMinimum)) + this->createDataLabel( xTextTarget, **aSeriesIter, nIndex + , fUnscaledY_Min, 1.0, Position3DToAWTPoint(aPosMiddleMinimum), LABEL_ALIGN_BOTTOM ); + if(isValidPosition(aPosMiddleMaximum)) + this->createDataLabel( xTextTarget, **aSeriesIter, nIndex + , fUnscaledY_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 +//............................................................................. diff --git a/chart2/source/view/charttypes/CandleStickChart.hxx b/chart2/source/view/charttypes/CandleStickChart.hxx new file mode 100644 index 000000000000..df9531ec71bf --- /dev/null +++ b/chart2/source/view/charttypes/CandleStickChart.hxx @@ -0,0 +1,78 @@ +/************************************************************************* + * + * 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(); + + virtual void 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 isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex ); + + //------------------------------------------------------------------------- + + virtual LegendSymbolStyle getLegendSymbolStyle(); + + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + +private: //methods + //no default constructor + CandleStickChart(); + +private: //member + BarPositionHelper* m_pMainPosHelper; +}; +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/charttypes/CategoryPositionHelper.cxx b/chart2/source/view/charttypes/CategoryPositionHelper.cxx new file mode 100644 index 000000000000..76f07168bdf2 --- /dev/null +++ b/chart2/source/view/charttypes/CategoryPositionHelper.cxx @@ -0,0 +1,105 @@ +/************************************************************************* + * + * 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::getScaledSlotWidth() const +{ + double fWidth = m_fCategoryWidth / + ( m_fSeriesCount + + m_fOuterDistance + + m_fInnerDistance*( m_fSeriesCount - 1.0) ); + return fWidth; +} + +double CategoryPositionHelper::getScaledSlotPos( double fScaledXPos, double fSeriesNumber ) const +{ + //the returned position is in the middle of the rect + //fSeriesNumber 0...n-1 + double fPos = fScaledXPos + - (m_fCategoryWidth/2.0) + + (m_fOuterDistance/2.0 + fSeriesNumber*(1.0+m_fInnerDistance)) * getScaledSlotWidth() + + getScaledSlotWidth()/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; +} + +void CategoryPositionHelper::setCategoryWidth( double fCategoryWidth ) +{ + m_fCategoryWidth = fCategoryWidth; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/charttypes/CategoryPositionHelper.hxx b/chart2/source/view/charttypes/CategoryPositionHelper.hxx new file mode 100644 index 000000000000..c12d17d40b03 --- /dev/null +++ b/chart2/source/view/charttypes/CategoryPositionHelper.hxx @@ -0,0 +1,69 @@ +/************************************************************************* + * + * 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 getScaledSlotWidth() const; + virtual double getScaledSlotPos( double fCategoryX, double fSeriesNumber ) const; + virtual void setCategoryWidth( double fCategoryWidth ); + + //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 diff --git a/chart2/source/view/charttypes/PieChart.cxx b/chart2/source/view/charttypes/PieChart.cxx new file mode 100644 index 000000000000..abb30c2a67a9 --- /dev/null +++ b/chart2/source/view/charttypes/PieChart.cxx @@ -0,0 +1,895 @@ +/************************************************************************* + * + * 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 "chartview/servicenames_charttypes.hxx" +//#include "servicenames_coosystems.hxx" +#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 PieChart::setScales( const std::vector< ExplicitScaleData >& rScales, bool /* bSwapXAndYAxis */ ) +{ + DBG_ASSERT(m_nDimension<=static_cast<sal_Int32>(rScales.size()),"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; +} + +//----------------------------------------------------------------- +// lang::XServiceInfo +//----------------------------------------------------------------- +/* +APPHELPER_XSERVICEINFO_IMPL(PieChart,CHART2_VIEW_PIECHART_SERVICE_IMPLEMENTATION_NAME) + + uno::Sequence< rtl::OUString > PieChart +::getSupportedServiceNames_Static() +{ + uno::Sequence< rtl::OUString > aSNS( 1 ); + aSNS.getArray()[ 0 ] = CHART2_VIEW_PIECHART_SERVICE_NAME; + return aSNS; +} +*/ + +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 = -1.0;//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, fLogicZ+0.5, 0 )); + + PieLabelInfo aPieLabelInfo; + aPieLabelInfo.aFirstPosition = basegfx::B2IVector( aScreenPosition2D.X, aScreenPosition2D.Y ); + awt::Point aOrigin( aPolarPosHelper.transformSceneToScreenPosition( m_pPosHelper->transformUnitCircleToScene( 0.0, 0.0, fLogicZ+1.0 ) ) ); + 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 +//............................................................................. diff --git a/chart2/source/view/charttypes/PieChart.hxx b/chart2/source/view/charttypes/PieChart.hxx new file mode 100644 index 000000000000..c306e2db256f --- /dev/null +++ b/chart2/source/view/charttypes/PieChart.hxx @@ -0,0 +1,131 @@ +/************************************************************************* + * + * 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(); + + virtual void createShapes(); + virtual void rearrangeLabelToAvoidOverlapIfRequested( const ::com::sun::star::awt::Size& rPageSize ); + + virtual void setScales( const ::std::vector< ExplicitScaleData >& rScales, bool bSwapXAndYAxis ); + 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 diff --git a/chart2/source/view/charttypes/Splines.cxx b/chart2/source/view/charttypes/Splines.cxx new file mode 100644 index 000000000000..67ecac93b64c --- /dev/null +++ b/chart2/source/view/charttypes/Splines.cxx @@ -0,0 +1,545 @@ +/************************************************************************* + * + * 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 +//............................................................................. + diff --git a/chart2/source/view/charttypes/Splines.hxx b/chart2/source/view/charttypes/Splines.hxx new file mode 100644 index 000000000000..642522f53ebe --- /dev/null +++ b/chart2/source/view/charttypes/Splines.hxx @@ -0,0 +1,61 @@ +/************************************************************************* + * + * 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 diff --git a/chart2/source/view/charttypes/VSeriesPlotter.cxx b/chart2/source/view/charttypes/VSeriesPlotter.cxx new file mode 100755 index 000000000000..1077591dfce8 --- /dev/null +++ b/chart2/source/view/charttypes/VSeriesPlotter.cxx @@ -0,0 +1,2259 @@ +/************************************************************************* + * + * 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 "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" +#include "DateHelper.hxx" +#include "DiagramHelper.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/chart/TimeUnit.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/drawing/LineStyle.hpp> +#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_nTimeResolution(::com::sun::star::chart::TimeUnit::DAY) + , m_aNullDate(30,12,1899) + , 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) + { + if( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) + pSeries->setXValues( m_pExplicitCategoriesProvider->getOriginalCategories() ); + else + pSeries->setCategoryXAxis(); + } + else + { + if( m_pExplicitCategoriesProvider ) + pSeries->setXValuesIfNone( m_pExplicitCategoriesProvider->getOriginalCategories() ); + } + + 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 = DiagramHelper::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 + + float fViewFontSize( 10.0 ); + { + uno::Reference< beans::XPropertySet > xProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) ); + if( xProps.is() ) + xProps->getPropertyValue( C2U( "CharHeight" )) >>= fViewFontSize; + // pt -> 1/100th mm + fViewFontSize *= (2540.0 / 72.0); + } + Reference< drawing::XShape > xSymbol; + if(pLabel->ShowLegendSymbol) + { + sal_Int32 nSymbolHeigth = static_cast< sal_Int32 >( fViewFontSize * 0.6 ); + awt::Size aCurrentRatio = this->getPreferredLegendKeyAspectRatio(); + sal_Int32 nSymbolWidth = aCurrentRatio.Width; + if( aCurrentRatio.Height > 0 ) + { + nSymbolWidth = nSymbolHeigth* aCurrentRatio.Width/aCurrentRatio.Height; + } + awt::Size aMaxSymbolExtent( nSymbolWidth, nSymbolHeigth ); + + if( rDataSeries.isVaryColorsByPoint() ) + xSymbol.set( VSeriesPlotter::createLegendSymbolForPoint( aMaxSymbolExtent, rDataSeries, nPointIndex, xTarget_, m_xShapeFactory ) ); + else + xSymbol.set( VSeriesPlotter::createLegendSymbolForSeries( aMaxSymbolExtent, 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::Point aSymbolPosition( aUnrotatedTextPos ); + awt::Size aSymbolSize( xSymbol->getSize() ); + awt::Size aTextSize( xTextShape->getSize() ); + + sal_Int32 nXDiff = aSymbolSize.Width + static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.22 ) );//minimum 1mm + if( !bMultiLineLabel || nLineCountForSymbolsize <= 0 ) + nLineCountForSymbolsize = 1; + aSymbolPosition.Y += ((aTextSize.Height/nLineCountForSymbolsize)/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->setPosition( aSymbolPosition ); + 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; +} + +drawing::Position3D lcl_transformMixedToScene( PlottingPositionHelper* pPosHelper + , double fX /*scaled*/, double fY /*unscaled*/, double fZ /*unscaled*/, bool bClip ) +{ + if(!pPosHelper) + return drawing::Position3D(0,0,0); + pPosHelper->doLogicScaling( 0,&fY,&fZ ); + if(bClip) + pPosHelper->clipScaledLogicValues( &fX,&fY,&fZ ); + return pPosHelper->transformScaledLogicToScene( fX, fY, fZ, false ); +} + +} // 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 */ + , double* pfScaledLogicX + ) +{ + 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; + double fScaledX = fX; + if( pfScaledLogicX ) + fScaledX = *pfScaledLogicX; + else + m_pPosHelper->doLogicScaling( &fScaledX, 0, 0 ); + + aMiddle = lcl_transformMixedToScene( m_pPosHelper, fScaledX, 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; + aPositive = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fLocalY, fZ, true ); + } + else + { + fLocalX+=fLength; + aPositive = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true ); + } + bCreatePositiveBorder = m_pPosHelper->isLogicVisible(fLocalX, fLocalY, fZ); + } + 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; + aNegative = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fLocalY, fZ, true ); + } + else + { + fLocalX-=fLength; + aNegative = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true ); + } + bCreateNegativeBorder = m_pPosHelper->isLogicVisible( fLocalX, fLocalY, fZ); + } + 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 + , double* pfScaledLogicX ) +{ + 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 */ + , pfScaledLogicX ); + } +} + +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; + + std::vector< ExplicitScaleData > aScales( m_pPosHelper->getScales()); + uno::Reference< chart2::XScaling > xScalingX; + uno::Reference< chart2::XScaling > xScalingY; + if( aScales.size() >= 2 ) + { + xScalingX.set( aScales[0].Scaling ); + xScalingY.set( aScales[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); +} + +void VSeriesPlotter::setTimeResolutionOnXAxis( long TimeResolution, const Date& rNullDate ) +{ + m_nTimeResolution = TimeResolution; + m_aNullDate = rNullDate; +} + +//------------------------------------------------------------------------- +// MinimumAndMaximumSupplier +//------------------------------------------------------------------------- +long VSeriesPlotter::calculateTimeResolutionOnXAxis() +{ + long nRet = ::com::sun::star::chart::TimeUnit::YEAR; + if( m_pExplicitCategoriesProvider ) + { + const std::vector< DatePlusIndex >& rDateCategories = m_pExplicitCategoriesProvider->getDateCategories(); + std::vector< DatePlusIndex >::const_iterator aIt = rDateCategories.begin(), aEnd = rDateCategories.end(); + Date aNullDate(30,12,1899); + if( m_apNumberFormatterWrapper.get() ) + aNullDate = m_apNumberFormatterWrapper->getNullDate(); + if( aIt!=aEnd ) + { + Date aPrevious(aNullDate); aPrevious+=rtl::math::approxFloor(aIt->fValue); + ++aIt; + for(;aIt!=aEnd;++aIt) + { + Date aCurrent(aNullDate); aCurrent+=rtl::math::approxFloor(aIt->fValue); + if( ::com::sun::star::chart::TimeUnit::YEAR == nRet ) + { + if( DateHelper::IsInSameYear( aPrevious, aCurrent ) ) + nRet = ::com::sun::star::chart::TimeUnit::MONTH; + } + if( ::com::sun::star::chart::TimeUnit::MONTH == nRet ) + { + if( DateHelper::IsInSameMonth( aPrevious, aCurrent ) ) + nRet = ::com::sun::star::chart::TimeUnit::DAY; + } + if( ::com::sun::star::chart::TimeUnit::DAY == nRet ) + break; + aPrevious=aCurrent; + } + } + } + return nRet; +} +double VSeriesPlotter::getMinimumX() +{ + double fMinimum, fMaximum; + this->getMinimumAndMaximiumX( fMinimum, fMaximum ); + return fMinimum; +} +double VSeriesPlotter::getMaximumX() +{ + double fMinimum, fMaximum; + this->getMinimumAndMaximiumX( fMinimum, fMaximum ); + return fMaximum; +} + +double VSeriesPlotter::getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) +{ + if( !m_bCategoryXAxis || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) ) + { + 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 || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) ) + { + 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 1.0; +} +double VSeriesPlotter::getMaximumZ() +{ + if( 3!=m_nDimension || !m_aZSlots.size() ) + return getMinimumZ()+1; + return m_aZSlots.size(); +} + +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 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; + if(pRet) + pRet->setTimeResolution( m_nTimeResolution, m_aNullDate ); + 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; +} + +std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntries( + const awt::Size& rEntryKeyAspectRatio + , ::com::sun::star::chart::ChartLegendExpansion eLegendExpansion + , 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( 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( rEntryKeyAspectRatio, + *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 != ::com::sun::star::chart::ChartLegendExpansion_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() ); + } + } + } + } + + return aResult; +} + +::std::vector< VDataSeries* > VSeriesPlotter::getAllSeries() +{ + ::std::vector< VDataSeries* > aAllSeries; + ::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* > aSeriesList = aXSlotIter->m_aSeriesVector; + aAllSeries.insert( aAllSeries.end(), aSeriesList.begin(), aSeriesList.end() ); + } + } + return aAllSeries; +} + +namespace +{ +bool lcl_HasVisibleLine( const uno::Reference< beans::XPropertySet >& xProps, bool& rbHasDashedLine ) +{ + bool bHasVisibleLine = false; + rbHasDashedLine = false; + drawing::LineStyle aLineStyle = drawing::LineStyle_NONE; + if( xProps.is() && ( xProps->getPropertyValue( C2U("LineStyle")) >>= aLineStyle ) ) + { + if( aLineStyle != drawing::LineStyle_NONE ) + bHasVisibleLine = true; + if( aLineStyle == drawing::LineStyle_DASH ) + rbHasDashedLine = true; + } + return bHasVisibleLine; +} + +bool lcl_HasRegressionCurves( const VDataSeries& rSeries, bool& rbHasDashedLine ) +{ + bool bHasRegressionCurves = false; + 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() ) + { + bHasRegressionCurves = true; + lcl_HasVisibleLine( uno::Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ), rbHasDashedLine ); + } + } + } + return bHasRegressionCurves; +} +} +LegendSymbolStyle VSeriesPlotter::getLegendSymbolStyle() +{ + return LegendSymbolStyle_BOX; +} + +awt::Size VSeriesPlotter::getPreferredLegendKeyAspectRatio() +{ + awt::Size aRet(1000,1000); + if( m_nDimension==3 ) + return aRet; + + bool bSeriesAllowsLines = (getLegendSymbolStyle() == LegendSymbolStyle_LINE); + bool bHasLines = false; + bool bHasDashedLines = false; + ::std::vector< VDataSeries* > aAllSeries( getAllSeries() ); + ::std::vector< VDataSeries* >::const_iterator aSeriesIter = aAllSeries.begin(); + const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = aAllSeries.end(); + //iterate through all series + for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ ) + { + if( bSeriesAllowsLines ) + { + bool bCurrentDashed = false; + if( lcl_HasVisibleLine( (*aSeriesIter)->getPropertiesOfSeries(), bCurrentDashed ) ) + { + bHasLines = true; + if( bCurrentDashed ) + { + bHasDashedLines = true; + break; + } + } + } + bool bRegressionHasDashedLines=false; + if( lcl_HasRegressionCurves( **aSeriesIter, bRegressionHasDashedLines ) ) + { + bHasLines = true; + if( bRegressionHasDashedLines ) + { + bHasDashedLines = true; + break; + } + } + } + if( bHasLines ) + { + if( bHasDashedLines ) + aRet = awt::Size(1600,-1); + else + aRet = awt::Size(800,-1); + } + return aRet; +} + +uno::Any VSeriesPlotter::getExplicitSymbol( const VDataSeries& /*rSeries*/, sal_Int32 /*nPointIndex*/ ) +{ + return uno::Any(); +} + +Reference< drawing::XShape > VSeriesPlotter::createLegendSymbolForSeries( + const awt::Size& rEntryKeyAspectRatio + , 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_LINE: + ePropType = VLegendSymbolFactory::PROP_TYPE_LINE_SERIES; + break; + default: + break; + }; + Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio, + xTarget, eLegendSymbolStyle, xShapeFactory + , rSeries.getPropertiesOfSeries(), ePropType, aExplicitSymbol )); + + return xShape; +} + +Reference< drawing::XShape > VSeriesPlotter::createLegendSymbolForPoint( + const awt::Size& rEntryKeyAspectRatio + , 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_LINE: + 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( rEntryKeyAspectRatio, + xTarget, eLegendSymbolStyle, xShapeFactory, xPointSet, ePropType, aExplicitSymbol )); + + return xShape; +} + +std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntriesForSeries( + const awt::Size& rEntryKeyAspectRatio + , 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( rEntryKeyAspectRatio, + 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( + rEntryKeyAspectRatio, 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() ) + { + //label + OUString aResStr( 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( rEntryKeyAspectRatio, + xSymbolGroup, LegendSymbolStyle_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 = RegressionCurveHelper::isMeanValueLine( aCurves[i] ); + 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; +} + +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 +//............................................................................. 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 diff --git a/chart2/source/view/chartview.component b/chart2/source/view/chartview.component new file mode 100644 index 000000000000..773666150651 --- /dev/null +++ b/chart2/source/view/chartview.component @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--********************************************************************** +* +* 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. +* +**********************************************************************--> + +<component loader="com.sun.star.loader.SharedLibrary" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.chart2.ChartView"> + <service name="com.sun.star.chart2.ChartView"/> + </implementation> +</component> diff --git a/chart2/source/view/diagram/VDiagram.cxx b/chart2/source/view/diagram/VDiagram.cxx new file mode 100644 index 000000000000..0aad597d2475 --- /dev/null +++ b/chart2/source/view/diagram/VDiagram.cxx @@ -0,0 +1,808 @@ +/************************************************************************* + * + * 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 "VDiagram.hxx" +#include "PropertyMapper.hxx" +#include "ViewDefines.hxx" +#include "Stripe.hxx" +#include "macros.hxx" +#include "ObjectIdentifier.hxx" +#include "DiagramHelper.hxx" +#include "BaseGFXHelper.hxx" +#include "CommonConverters.hxx" +#include "ChartTypeHelper.hxx" +#include "ThreeDHelper.hxx" +#include <editeng/unoprnms.hxx> +#include <tools/color.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/ProjectionMode.hpp> +#include <com/sun/star/drawing/ShadeMode.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/lang/XTypeProvider.hpp> +// header for class SvxShape +#include <svx/unoshape.hxx> +// header for class E3dScene +#include <svx/scene3d.hxx> +#include <svx/e3dsceneupdater.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +VDiagram::VDiagram( + const uno::Reference< XDiagram > & xDiagram + , const drawing::Direction3D& rPreferredAspectRatio + , sal_Int32 nDimension, sal_Bool bPolar ) + : m_xLogicTarget(NULL) + , m_xFinalTarget(NULL) + , m_xShapeFactory(NULL) + , m_pShapeFactory(NULL) + , m_xOuterGroupShape(NULL) + , m_xCoordinateRegionShape(NULL) + , m_xWall2D(NULL) + , m_nDimensionCount(nDimension) + , m_bPolar(bPolar) + , m_xDiagram(xDiagram) + , m_aPreferredAspectRatio(rPreferredAspectRatio) + , m_xAspectRatio3D() + , m_fXAnglePi(0) + , m_fYAnglePi(0) + , m_fZAnglePi(0) + , m_bRightAngledAxes(sal_False) +{ + if( m_nDimensionCount == 3) + { + uno::Reference< beans::XPropertySet > xSourceProp( m_xDiagram, uno::UNO_QUERY ); + ThreeDHelper::getRotationAngleFromDiagram( xSourceProp, m_fXAnglePi, m_fYAnglePi, m_fZAnglePi ); + if( ChartTypeHelper::isSupportingRightAngledAxes( + DiagramHelper::getChartTypeByIndex( m_xDiagram, 0 ) ) ) + { + if(xSourceProp.is()) + xSourceProp->getPropertyValue(C2U( "RightAngledAxes" )) >>= m_bRightAngledAxes; + if( m_bRightAngledAxes ) + { + ThreeDHelper::adaptRadAnglesForRightAngledAxes( m_fXAnglePi, m_fYAnglePi ); + m_fZAnglePi=0.0; + } + } + } +} + +VDiagram::~VDiagram() +{ + delete m_pShapeFactory; +} + +void VDiagram::init( + const uno::Reference< drawing::XShapes >& xLogicTarget + , const uno::Reference< drawing::XShapes >& xFinalTarget + , const uno::Reference< lang::XMultiServiceFactory >& xFactory ) +{ + DBG_ASSERT(xLogicTarget.is()&&xFinalTarget.is()&&xFactory.is(),"no proper initialization parameters"); + + m_xLogicTarget = xLogicTarget; + m_xFinalTarget = xFinalTarget; + m_xShapeFactory = xFactory; + m_pShapeFactory = new ShapeFactory(xFactory); +} + +void VDiagram::createShapes( const awt::Point& rPos, const awt::Size& rSize ) +{ + m_aAvailablePosIncludingAxes = rPos; + m_aAvailableSizeIncludingAxes = rSize; + + if( m_nDimensionCount == 3 ) + createShapes_3d(); + else + createShapes_2d(); +} + +::basegfx::B2IRectangle VDiagram::adjustPosAndSize( const awt::Point& rPos, const awt::Size& rSize ) +{ + ::basegfx::B2IRectangle aAllowedRect( BaseGFXHelper::makeRectangle(m_aAvailablePosIncludingAxes,m_aAvailableSizeIncludingAxes) ); + ::basegfx::B2IRectangle aNewInnerRect( BaseGFXHelper::makeRectangle(rPos,rSize) ); + aNewInnerRect.intersect( aAllowedRect ); + + if( m_nDimensionCount == 3 ) + aNewInnerRect = adjustPosAndSize_3d( BaseGFXHelper::B2IRectangleToAWTPoint(aNewInnerRect), BaseGFXHelper::B2IRectangleToAWTSize(aNewInnerRect) ); + else + aNewInnerRect = adjustPosAndSize_2d( BaseGFXHelper::B2IRectangleToAWTPoint(aNewInnerRect), BaseGFXHelper::B2IRectangleToAWTSize(aNewInnerRect) ); + + return aNewInnerRect; +} + +::basegfx::B2IRectangle VDiagram::adjustPosAndSize_2d( const awt::Point& rPos, const awt::Size& rAvailableSize ) +{ + m_aCurrentPosWithoutAxes = rPos; + m_aCurrentSizeWithoutAxes = rAvailableSize; + if( m_aPreferredAspectRatio.DirectionX > 0 && m_aPreferredAspectRatio.DirectionY > 0) + { + //do not change aspect ratio + awt::Size aAspectRatio( static_cast<sal_Int32>(m_aPreferredAspectRatio.DirectionX*FIXED_SIZE_FOR_3D_CHART_VOLUME), + static_cast<sal_Int32>(m_aPreferredAspectRatio.DirectionY*FIXED_SIZE_FOR_3D_CHART_VOLUME )); + m_aCurrentSizeWithoutAxes = awt::Size( ShapeFactory::calculateNewSizeRespectingAspectRatio( + rAvailableSize, aAspectRatio ) ); + //center diagram position + m_aCurrentPosWithoutAxes = awt::Point( ShapeFactory::calculateTopLeftPositionToCenterObject( + rPos, rAvailableSize, m_aCurrentSizeWithoutAxes ) ); + + } + + if( m_xWall2D.is() ) + { + m_xWall2D->setSize( m_aCurrentSizeWithoutAxes); + m_xWall2D->setPosition(m_aCurrentPosWithoutAxes); + } + + return ::basegfx::B2IRectangle( BaseGFXHelper::makeRectangle(m_aCurrentPosWithoutAxes,m_aCurrentSizeWithoutAxes) ); +} + +void VDiagram::createShapes_2d() +{ + DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()&&m_xShapeFactory.is(),"is not proper initialized"); + if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()&&m_xShapeFactory.is())) + return; + + //create group shape + uno::Reference< drawing::XShapes > xOuterGroup_Shapes = m_pShapeFactory->createGroup2D(m_xLogicTarget); + m_xOuterGroupShape = uno::Reference<drawing::XShape>( xOuterGroup_Shapes, uno::UNO_QUERY ); + + uno::Reference< drawing::XShapes > xGroupForWall( m_pShapeFactory->createGroup2D(xOuterGroup_Shapes,C2U("PlotAreaExcludingAxes")) ); + + //create independent group shape as container for datapoints and such things + { + uno::Reference< drawing::XShapes > xShapes = m_pShapeFactory->createGroup2D(xOuterGroup_Shapes,C2U("testonly;CooContainer=XXX_CID")); + m_xCoordinateRegionShape = uno::Reference<drawing::XShape>( xShapes, uno::UNO_QUERY ); + } + + //--------------------------- + bool bAddFloorAndWall = DiagramHelper::isSupportingFloorAndWall( m_xDiagram ); + + //add back wall + { + m_xWall2D = uno::Reference< drawing::XShape >( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.RectangleShape" ) ), uno::UNO_QUERY ); + //m_xWall2D->setPosition(m_aAvailablePosIncludingAxes); + //m_xWall2D->setSize(m_aAvailableSizeIncludingAxes); + xGroupForWall->add(m_xWall2D); + uno::Reference< beans::XPropertySet > xProp( m_xWall2D, uno::UNO_QUERY ); + if( xProp.is()) + { + try + { + DBG_ASSERT( m_xDiagram.is(), "Invalid Diagram model" ); + if( m_xDiagram.is() ) + { + uno::Reference< beans::XPropertySet > xWallProp( m_xDiagram->getWall()); + if( xWallProp.is()) + PropertyMapper::setMappedProperties( xProp, xWallProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties() ); + } + if( !bAddFloorAndWall ) + { + //we always need this object as dummy object for correct scene dimensions + //but it should not be visible in this case: + ShapeFactory::makeShapeInvisible( m_xWall2D ); + } + else + { + //CID for selection handling + rtl::OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, rtl::OUString() ) );//@todo read CID from model + xProp->setPropertyValue( C2U( UNO_NAME_MISC_OBJ_NAME ), uno::makeAny( aWallCID ) ); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + + } + + //--------------------------- + //position and size for diagram + adjustPosAndSize_2d( m_aAvailablePosIncludingAxes, m_aAvailableSizeIncludingAxes ); +} + +E3dScene* lcl_getE3dScene( const uno::Reference< drawing::XShape >& xShape ) +{ + E3dScene* pRet=NULL; + uno::Reference< lang::XUnoTunnel > xUnoTunnel( xShape, uno::UNO_QUERY ); + uno::Reference< lang::XTypeProvider > xTypeProvider( xShape, uno::UNO_QUERY ); + if(xUnoTunnel.is()&&xTypeProvider.is()) + { + SvxShape* pSvxShape = reinterpret_cast<SvxShape*>(xUnoTunnel->getSomething( SvxShape::getUnoTunnelId() )); + if(pSvxShape) + { + SdrObject* pObj = pSvxShape->GetSdrObject(); + if( pObj && pObj->ISA(E3dScene) ) + pRet = (E3dScene*)pObj; + } + } + return pRet; +} + +void lcl_setLightSources( + const uno::Reference< beans::XPropertySet > & xSource, + const uno::Reference< beans::XPropertySet > & xDest ) +{ + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_1 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_1 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_2 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_2 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_3 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_3 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_4 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_4 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_5 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_5 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_6 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_6 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_7 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_7 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_8 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_8 ))); + + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_1 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_1 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_3 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_3 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_4 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_4 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_5 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_5 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_6 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_6 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_7 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_7 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_8 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_8 ))); + + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_1 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_1 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_2 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_2 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_3 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_3 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_4 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_4 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_5 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_5 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_6 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_6 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_7 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_7 ))); + xDest->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_8 ), + xSource->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_8 ))); +} + +namespace +{ + +void lcl_ensureScaleValue( double& rfScale ) +{ + DBG_ASSERT(rfScale>0, "calculation error for automatic 3D height in chart"); + if( rfScale<0 ) + rfScale = 1.0; + else if( rfScale<0.2 ) + rfScale = 0.2; + else if( rfScale>5.0 ) + rfScale = 5.0; +} + +} + +void VDiagram::adjustAspectRatio3d( const awt::Size& rAvailableSize ) +{ + DBG_ASSERT(m_xAspectRatio3D.is(), "created shape offers no XPropertySet"); + if( m_xAspectRatio3D.is()) + { + try + { + double fScaleX = m_aPreferredAspectRatio.DirectionX; + double fScaleY = m_aPreferredAspectRatio.DirectionY; + double fScaleZ = m_aPreferredAspectRatio.DirectionZ; + + //normalize scale factors + { + double fMax = std::max( std::max( fScaleX, fScaleY) , fScaleZ ); + fScaleX/=fMax; + fScaleY/=fMax; + fScaleZ/=fMax; + } + + if( fScaleX<0 || fScaleY<0 || fScaleZ<0 ) + { + //calculate automatic 3D aspect ratio that fits good into the given 2D area + double fW = rAvailableSize.Width; + double fH = rAvailableSize.Height; + +// double cx = fabs(cos(m_fXAnglePi)); + double sx = fabs(sin(m_fXAnglePi)); +// double cy = fabs(cos(m_fYAnglePi)); + double sy = fabs(sin(m_fYAnglePi)); + double cz = fabs(cos(m_fZAnglePi)); + double sz = fabs(sin(m_fZAnglePi)); + + if(m_bRightAngledAxes) + { + //base equations: + //fH*zoomfactor == sx*fScaleZ + fScaleY; + //fW*zoomfactor == sy*fScaleZ + fScaleX; + + if( fScaleX>0 && fScaleZ>0 ) + { + //calculate fScaleY: + if( !::basegfx::fTools::equalZero(fW) ) + { + fScaleY = (fH/fW)*(sy*fScaleZ+fScaleX)-(sx*fScaleZ); + lcl_ensureScaleValue( fScaleY ); + } + else + fScaleY = 1.0;//looking from top or bottom the height is irrelevant + } + else if( fScaleY>0 && fScaleZ>0 ) + { + //calculate fScaleX: + if( !::basegfx::fTools::equalZero(fH) ) + { + fScaleX = (fW/fH)*(sx*fScaleZ+fScaleY)-(sy*fScaleZ); + lcl_ensureScaleValue(fScaleX); + } + else + fScaleX = 1.0;//looking from top or bottom hieght is irrelevant + } + else + { + //todo + DBG_ASSERT(false, "not implemented yet"); + + if( fScaleX<0 ) + fScaleX = 1.0; + if( fScaleY<0 ) + fScaleY = 1.0; + if( fScaleZ<0 ) + fScaleZ = 1.0; + } + } + else + { + //base equations: + //fH*zoomfactor == cz*fScaleY + sz*fScaleX; + //fW*zoomfactor == cz*fScaleX + sz*fScaleY; + //==> fScaleY*(fH*sz-fW*cz) == fScaleX*(fW*sz-fH*cz); + if( fScaleX>0 && fScaleZ>0 ) + { + //calculate fScaleY: + double fDivide = fH*sz-fW*cz; + if( !::basegfx::fTools::equalZero(fDivide) ) + { + fScaleY = fScaleX*(fW*sz-fH*cz) / fDivide; + lcl_ensureScaleValue(fScaleY); + } + else + fScaleY = 1.0;//looking from top or bottom the height is irrelevant + + /* + //fW*zoomfactor == fScaleX*cy*cz + fScaleY*sz*cy + fScaleZ*sy*cx; + //fH*zoomfactor == fScaleY*cx*cz + fScaleX*sz*cy + fScaleZ*sx*cz; + //==> fScaleY*(sz*cy*fH -cx*cz*fW) = fScaleX*(sz*cy*fW - cy*cz*fH) + fScaleZ*(sx*cz*fW - sy*cx*fH); + double fDivide = sz*cy*fH -cx*cz*fW; + if( !::basegfx::fTools::equalZero(fDivide) ) + { + fScaleY = ( fScaleX*(sz*cy*fW - cy*cz*fH) + + fScaleZ*(sx*cz*fW - sy*cx*fH) ) / fDivide; + lcl_ensureScaleValue(fScaleY); + } + else + fScaleY = 1.0;//looking from top or bottom hieght is irrelevant + */ + } + else if( fScaleY>0 && fScaleZ>0 ) + { + //calculate fScaleX: + double fDivide = fW*sz-fH*cz; + if( !::basegfx::fTools::equalZero(fDivide) ) + { + fScaleX = fScaleY*(fH*sz-fW*cz) / fDivide; + lcl_ensureScaleValue(fScaleX); + } + else + fScaleX = 1.0;//looking from top or bottom hieght is irrelevant + } + else + { + //todo + DBG_ASSERT(false, "not implemented yet"); + + if( fScaleX<0 ) + fScaleX = 1.0; + if( fScaleY<0 ) + fScaleY = 1.0; + if( fScaleZ<0 ) + fScaleZ = 1.0; + } + } + } + + //normalize scale factors + { + double fMax = std::max( std::max( fScaleX, fScaleY) , fScaleZ ); + fScaleX/=fMax; + fScaleY/=fMax; + fScaleZ/=fMax; + } + + // identity matrix + ::basegfx::B3DHomMatrix aResult; + aResult.translate( -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, + -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, + -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0 ); + aResult.scale( fScaleX, fScaleY, fScaleZ ); + aResult.translate( FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, + FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, + FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0 ); + + // To get the 3D aspect ratio's effect on the 2D scene size, the scene's 2D size needs to be adapted to + // 3D content changes here. The tooling class remembers the current 3D transformation stack + // and in it's destructor, calculates a new 2D SnapRect for the scene and it's modified 3D geometry. + E3DModifySceneSnapRectUpdater aUpdater(lcl_getE3dScene( m_xOuterGroupShape )); + + m_xAspectRatio3D->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aResult )) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } +} + +::basegfx::B2IRectangle VDiagram::adjustPosAndSize_3d( const awt::Point& rPos, const awt::Size& rAvailableSize ) +{ + adjustAspectRatio3d( rAvailableSize ); + + //do not change aspect ratio of 3D scene with 2D bound rect + m_aCurrentSizeWithoutAxes = ShapeFactory::calculateNewSizeRespectingAspectRatio( + rAvailableSize, m_xOuterGroupShape->getSize() ); + m_xOuterGroupShape->setSize( m_aCurrentSizeWithoutAxes ); + + //center diagram position + m_aCurrentPosWithoutAxes= ShapeFactory::calculateTopLeftPositionToCenterObject( + rPos, rAvailableSize, m_aCurrentSizeWithoutAxes ); + m_xOuterGroupShape->setPosition(m_aCurrentPosWithoutAxes); + + return ::basegfx::B2IRectangle( BaseGFXHelper::makeRectangle(m_aCurrentPosWithoutAxes,m_aCurrentSizeWithoutAxes) ); +} + +void VDiagram::createShapes_3d() +{ + DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()&&m_xShapeFactory.is(),"is not proper initialized"); + if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()&&m_xShapeFactory.is())) + return; + + //create shape + m_xOuterGroupShape = uno::Reference< drawing::XShape >( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DSceneObject" ) ), uno::UNO_QUERY ); + ShapeFactory::setShapeName( m_xOuterGroupShape, C2U("PlotAreaExcludingAxes") ); + m_xLogicTarget->add(m_xOuterGroupShape); + + uno::Reference< drawing::XShapes > xOuterGroup_Shapes = + uno::Reference<drawing::XShapes>( m_xOuterGroupShape, uno::UNO_QUERY ); + + + //------------------------------------------------------------------------- + //create additional group to manipulate the aspect ratio of the whole diagram: + xOuterGroup_Shapes = m_pShapeFactory->createGroup3D( xOuterGroup_Shapes, rtl::OUString() ); + + m_xAspectRatio3D = uno::Reference< beans::XPropertySet >( xOuterGroup_Shapes, uno::UNO_QUERY ); + + //--------------------------- + + bool bAddFloorAndWall = DiagramHelper::isSupportingFloorAndWall( m_xDiagram ); + + const bool bDoubleSided = false; + const bool bFlatNormals = true; + + //add walls + { + uno::Reference< beans::XPropertySet > xWallProp( NULL ); + if( m_xDiagram.is() ) + xWallProp=uno::Reference< beans::XPropertySet >( m_xDiagram->getWall()); + + rtl::OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, rtl::OUString() ) );//@todo read CID from model + if( !bAddFloorAndWall ) + aWallCID = rtl::OUString(); + uno::Reference< drawing::XShapes > xWallGroup_Shapes( m_pShapeFactory->createGroup3D( xOuterGroup_Shapes, aWallCID ) ); + + CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( uno::Reference< beans::XPropertySet >( m_xDiagram, uno::UNO_QUERY ) ) ); + CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( uno::Reference< beans::XPropertySet >( m_xDiagram, uno::UNO_QUERY ) ) ); + + //add left wall + { + short nRotatedTexture = ( CuboidPlanePosition_Front==eBackWallPos ) ? 3 : 1; + double xPos = 0.0; + if( CuboidPlanePosition_Right==eLeftWallPos ) + xPos = FIXED_SIZE_FOR_3D_CHART_VOLUME; + Stripe aStripe( drawing::Position3D(xPos,FIXED_SIZE_FOR_3D_CHART_VOLUME,0) + , drawing::Direction3D(0,0,FIXED_SIZE_FOR_3D_CHART_VOLUME) + , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) ); + if( CuboidPlanePosition_Right==eLeftWallPos ) + { + nRotatedTexture = ( CuboidPlanePosition_Front==eBackWallPos ) ? 2 : 0; + aStripe = Stripe( drawing::Position3D(xPos,FIXED_SIZE_FOR_3D_CHART_VOLUME,0) + , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) + , drawing::Direction3D(0,0,FIXED_SIZE_FOR_3D_CHART_VOLUME) ); + } + aStripe.InvertNormal(true); + + uno::Reference< drawing::XShape > xShape = + m_pShapeFactory->createStripe( xWallGroup_Shapes, aStripe + , xWallProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), bDoubleSided, nRotatedTexture, bFlatNormals ); + if( !bAddFloorAndWall ) + { + //we always need this object as dummy object for correct scene dimensions + //but it should not be visible in this case: + ShapeFactory::makeShapeInvisible( xShape ); + } + } + //add back wall + { + short nRotatedTexture = 0; + double zPos = 0.0; + if( CuboidPlanePosition_Front==eBackWallPos ) + zPos = FIXED_SIZE_FOR_3D_CHART_VOLUME; + Stripe aStripe( drawing::Position3D(0,FIXED_SIZE_FOR_3D_CHART_VOLUME,zPos) + , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) + , drawing::Direction3D(FIXED_SIZE_FOR_3D_CHART_VOLUME,0,0) ); + if( CuboidPlanePosition_Front==eBackWallPos ) + { + aStripe = Stripe( drawing::Position3D(0,FIXED_SIZE_FOR_3D_CHART_VOLUME,zPos) + , drawing::Direction3D(FIXED_SIZE_FOR_3D_CHART_VOLUME,0,0) + , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) ); + nRotatedTexture = 3; + } + aStripe.InvertNormal(true); + + uno::Reference< drawing::XShape > xShape = + m_pShapeFactory->createStripe(xWallGroup_Shapes, aStripe + , xWallProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), bDoubleSided, nRotatedTexture, bFlatNormals ); + if( !bAddFloorAndWall ) + { + //we always need this object as dummy object for correct scene dimensions + //but it should not be visible in this case: + ShapeFactory::makeShapeInvisible( xShape ); + } + } + } + + try + { + uno::Reference< beans::XPropertySet > xSourceProp( m_xDiagram, uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xDestProp( m_xOuterGroupShape, uno::UNO_QUERY_THROW ); + + //perspective + { + //ignore distance and focal length from file format and model comcpletely + //use vrp only to indicate the distance of the camera and thus influence the perspecitve + xDestProp->setPropertyValue( C2U( UNO_NAME_3D_SCENE_DISTANCE ), uno::makeAny( + static_cast<sal_Int32>(ThreeDHelper::getCameraDistance( xSourceProp )))); + xDestProp->setPropertyValue( C2U( UNO_NAME_3D_SCENE_PERSPECTIVE ), + xSourceProp->getPropertyValue( C2U( UNO_NAME_3D_SCENE_PERSPECTIVE ))); + } + + //light + { + xDestProp->setPropertyValue( C2U( UNO_NAME_3D_SCENE_SHADE_MODE ), + xSourceProp->getPropertyValue( C2U( UNO_NAME_3D_SCENE_SHADE_MODE ))); + xDestProp->setPropertyValue( C2U( UNO_NAME_3D_SCENE_AMBIENTCOLOR ), + xSourceProp->getPropertyValue( C2U( UNO_NAME_3D_SCENE_AMBIENTCOLOR ))); + xDestProp->setPropertyValue( C2U( UNO_NAME_3D_SCENE_TWO_SIDED_LIGHTING ), + xSourceProp->getPropertyValue( C2U( UNO_NAME_3D_SCENE_TWO_SIDED_LIGHTING ))); + lcl_setLightSources( xSourceProp, xDestProp ); + } + + //rotation + { + //set diagrams rotation is set exclusively vie the transformation matrix + //don't set a camera at all! + //the cameras rotation is incorporated into this matrix + + ::basegfx::B3DHomMatrix aEffectiveTranformation; + aEffectiveTranformation.translate(-FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0); + + if(!m_bRightAngledAxes) + aEffectiveTranformation.rotate(m_fXAnglePi,m_fYAnglePi,m_fZAnglePi); + else + aEffectiveTranformation.shearXY(m_fYAnglePi,-m_fXAnglePi); + + //#i98497# 3D charts are rendered with wrong size + E3DModifySceneSnapRectUpdater aUpdater(lcl_getE3dScene( m_xOuterGroupShape )); + xDestProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ), + uno::makeAny( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aEffectiveTranformation ) ) ); + } + } + catch( const uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + + //add floor plate + { + uno::Reference< beans::XPropertySet > xFloorProp( NULL ); + if( m_xDiagram.is() ) + xFloorProp=uno::Reference< beans::XPropertySet >( m_xDiagram->getFloor()); + + Stripe aStripe( drawing::Position3D(0,0,0) + , drawing::Direction3D(0,0,FIXED_SIZE_FOR_3D_CHART_VOLUME) + , drawing::Direction3D(FIXED_SIZE_FOR_3D_CHART_VOLUME,0,0) ); + aStripe.InvertNormal(true); + + uno::Reference< drawing::XShape > xShape = + m_pShapeFactory->createStripe(xOuterGroup_Shapes, aStripe + , xFloorProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), bDoubleSided, 0, bFlatNormals ); + + CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( uno::Reference< beans::XPropertySet >( m_xDiagram, uno::UNO_QUERY ) ) ); + if( !bAddFloorAndWall || (CuboidPlanePosition_Bottom!=eBottomPos) ) + { + //we always need this object as dummy object for correct scene dimensions + //but it should not be visible in this case: + ShapeFactory::makeShapeInvisible( xShape ); + } + else + { + rtl::OUString aFloorCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_FLOOR, rtl::OUString() ) );//@todo read CID from model + ShapeFactory::setShapeName( xShape, aFloorCID ); + } + } + //--------------------------- + + //create an additional scene for the smaller inner coordinate region: + { + uno::Reference< drawing::XShapes > xShapes = m_pShapeFactory->createGroup3D( xOuterGroup_Shapes,C2U("testonly;CooContainer=XXX_CID") ); + m_xCoordinateRegionShape = uno::Reference< drawing::XShape >( xShapes, uno::UNO_QUERY ); + + uno::Reference< beans::XPropertySet > xShapeProp( m_xCoordinateRegionShape, uno::UNO_QUERY ); + DBG_ASSERT(xShapeProp.is(), "created shape offers no XPropertySet"); + if( xShapeProp.is()) + { + try + { + double fXScale = (FIXED_SIZE_FOR_3D_CHART_VOLUME -GRID_TO_WALL_DISTANCE) /FIXED_SIZE_FOR_3D_CHART_VOLUME; + double fYScale = (FIXED_SIZE_FOR_3D_CHART_VOLUME -GRID_TO_WALL_DISTANCE) /FIXED_SIZE_FOR_3D_CHART_VOLUME; + double fZScale = (FIXED_SIZE_FOR_3D_CHART_VOLUME -GRID_TO_WALL_DISTANCE) /FIXED_SIZE_FOR_3D_CHART_VOLUME; + + ::basegfx::B3DHomMatrix aM; + aM.translate(GRID_TO_WALL_DISTANCE/fXScale, GRID_TO_WALL_DISTANCE/fYScale, GRID_TO_WALL_DISTANCE/fZScale); + aM.scale( fXScale, fYScale, fZScale ); + E3DModifySceneSnapRectUpdater aUpdater(lcl_getE3dScene( m_xOuterGroupShape )); + xShapeProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(BaseGFXHelper::B3DHomMatrixToHomogenMatrix(aM)) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + } + + m_aCurrentPosWithoutAxes = m_aAvailablePosIncludingAxes; + m_aCurrentSizeWithoutAxes = m_aAvailableSizeIncludingAxes; + adjustPosAndSize_3d( m_aAvailablePosIncludingAxes, m_aAvailableSizeIncludingAxes ); +} + +uno::Reference< drawing::XShapes > VDiagram::getCoordinateRegion() +{ + return uno::Reference<drawing::XShapes>( m_xCoordinateRegionShape, uno::UNO_QUERY ); +} + +::basegfx::B2IRectangle VDiagram::getCurrentRectangle() +{ + return BaseGFXHelper::makeRectangle(m_aCurrentPosWithoutAxes,m_aCurrentSizeWithoutAxes); +} + +void VDiagram::reduceToMimimumSize() +{ + if( m_xOuterGroupShape.is() ) + { + awt::Size aMaxSize( m_aAvailableSizeIncludingAxes ); + awt::Point aMaxPos( m_aAvailablePosIncludingAxes ); + + sal_Int32 nNewWidth = aMaxSize.Width/3; + sal_Int32 nNewHeight = aMaxSize.Height/3; + awt::Size aNewSize( nNewWidth, nNewHeight ); + awt::Point aNewPos( aMaxPos ); + aNewPos.X += nNewWidth; + aNewPos.Y += nNewHeight; + + adjustPosAndSize( aNewPos, aNewSize ); + } +} + +::basegfx::B2IRectangle VDiagram::adjustInnerSize( const ::basegfx::B2IRectangle& rConsumedOuterRect ) +{ + awt::Point aNewPos( m_aCurrentPosWithoutAxes ); + awt::Size aNewSize( m_aCurrentSizeWithoutAxes ); + + ::basegfx::B2IRectangle rAvailableOuterRect( + BaseGFXHelper::makeRectangle(m_aAvailablePosIncludingAxes,m_aAvailableSizeIncludingAxes) ); + + sal_Int32 nDeltaWidth = static_cast<sal_Int32>(rAvailableOuterRect.getWidth() - rConsumedOuterRect.getWidth()); + sal_Int32 nDeltaHeight = static_cast<sal_Int32>(rAvailableOuterRect.getHeight() - rConsumedOuterRect.getHeight()); + if( (aNewSize.Width + nDeltaWidth) < rAvailableOuterRect.getWidth()/3 ) + nDeltaWidth = static_cast<sal_Int32>(rAvailableOuterRect.getWidth()/3 - aNewSize.Width); + aNewSize.Width += nDeltaWidth; + + if( (aNewSize.Height + nDeltaHeight) < rAvailableOuterRect.getHeight()/3 ) + nDeltaHeight = static_cast<sal_Int32>(rAvailableOuterRect.getHeight()/3 - aNewSize.Height); + aNewSize.Height += nDeltaHeight; + + sal_Int32 nDiffLeft = rConsumedOuterRect.getMinX() - rAvailableOuterRect.getMinX(); + sal_Int32 nDiffRight = rAvailableOuterRect.getMaxX() - rConsumedOuterRect.getMaxX(); + if( nDiffLeft >= 0 ) + aNewPos.X -= nDiffLeft; + else if( nDiffRight >= 0 ) + { + if( nDiffRight > -nDiffLeft ) + aNewPos.X += abs(nDiffLeft); + else if( nDiffRight > abs(nDeltaWidth) ) + aNewPos.X += nDiffRight; + else + aNewPos.X += abs(nDeltaWidth); + } + + sal_Int32 nDiffUp = rConsumedOuterRect.getMinY() - rAvailableOuterRect.getMinY(); + sal_Int32 nDiffDown = rAvailableOuterRect.getMaxY() - rConsumedOuterRect.getMaxY(); + if( nDiffUp >= 0 ) + aNewPos.Y -= nDiffUp; + else if( nDiffDown >= 0 ) + { + if( nDiffDown > -nDiffUp ) + aNewPos.Y += abs(nDiffUp); + else if( nDiffDown > abs(nDeltaHeight) ) + aNewPos.Y += nDiffDown; + else + aNewPos.Y += abs(nDeltaHeight); + } + + return adjustPosAndSize( aNewPos, aNewSize ); +} + +//............................................................................. +} //namespace chart +//............................................................................. + diff --git a/chart2/source/view/diagram/makefile.mk b/chart2/source/view/diagram/makefile.mk new file mode 100644 index 000000000000..652f203b2267 --- /dev/null +++ b/chart2/source/view/diagram/makefile.mk @@ -0,0 +1,48 @@ +#************************************************************************* +# +# 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= chvdiagram + +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)$/VDiagram.obj + +# --- Targets ----------------------------------------------------------------- + +.INCLUDE: target.mk + diff --git a/chart2/source/view/exports.flt b/chart2/source/view/exports.flt new file mode 100644 index 000000000000..56fa90f75bb1 --- /dev/null +++ b/chart2/source/view/exports.flt @@ -0,0 +1,4 @@ +lcl_ +_real@ +_TI1 +_TI2 diff --git a/chart2/source/view/inc/Clipping.hxx b/chart2/source/view/inc/Clipping.hxx new file mode 100644 index 000000000000..d04a576737bf --- /dev/null +++ b/chart2/source/view/inc/Clipping.hxx @@ -0,0 +1,70 @@ +/************************************************************************* + * + * 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_CLIPPING_HXX +#define _CHART2_CLIPPING_HXX + +#include <basegfx/range/b2drectangle.hxx> +#include <com/sun/star/drawing/PolyPolygonShape3D.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +class Clipping +{ + /** This class uses the Liang-Biarsky parametric line-clipping algorithm as described in: + Computer Graphics: principles and practice, 2nd ed., + James D. Foley et al., + Section 3.12.4 on page 117. + */ + +public: + /** @descr The intersection between an open polygon and a rectangle is + calculated and the resulting lines are placed into the poly-polygon aResult. + @param rPolygon The polygon is required to be open, ie. it's start and end point + have different coordinates and that it is continuous, ie. has no holes. + @param rRectangle The clipping area. + @param aResult The resulting lines that are the parts of the given polygon lying inside + the clipping area are stored into aResult whose prior content is deleted first. + */ + static void clipPolygonAtRectangle( + const ::com::sun::star::drawing::PolyPolygonShape3D& rPolygon + , const ::basegfx::B2DRectangle& rRectangle + , ::com::sun::star::drawing::PolyPolygonShape3D& aResult + , bool bSplitPiecesToDifferentPolygons = true ); +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/DateHelper.hxx b/chart2/source/view/inc/DateHelper.hxx new file mode 100644 index 000000000000..c2352e246695 --- /dev/null +++ b/chart2/source/view/inc/DateHelper.hxx @@ -0,0 +1,60 @@ +/************************************************************************* + * + * 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_DATEHELPER_HXX +#define _CHART2_DATEHELPER_HXX + +#include <com/sun/star/chart2/XScaling.hpp> +#include <tools/date.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +class DateHelper +{ +public: + static bool IsInSameYear( const Date& rD1, const Date& rD2 ); + static bool IsInSameMonth( const Date& rD1, const Date& rD2 ); + + static long GetMonthsBetweenDates( Date aD1, Date aD2 ); + static Date GetDateSomeMonthsAway( const Date& rD, long nMonthDistance ); + static Date GetDateSomeYearsAway( const Date& rD, long nYearDistance ); + static bool IsLessThanOneMonthAway( const Date& rD1, const Date& rD2 ); + static bool IsLessThanOneYearAway( const Date& rD1, const Date& rD2 ); + + static double RasterizeDateValue( double fValue, const Date& rNullDate, long TimeResolution ); +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/LabelAlignment.hxx b/chart2/source/view/inc/LabelAlignment.hxx new file mode 100644 index 000000000000..26ec703db302 --- /dev/null +++ b/chart2/source/view/inc/LabelAlignment.hxx @@ -0,0 +1,41 @@ +/************************************************************************* + * + * 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_VIEW_LabelAlignment_HXX +#define _CHART2_VIEW_LabelAlignment_HXX + +//............................................................................. +namespace chart +{ +//............................................................................. + +enum LabelAlignment { LABEL_ALIGN_CENTER, LABEL_ALIGN_LEFT, LABEL_ALIGN_TOP, LABEL_ALIGN_RIGHT, LABEL_ALIGN_BOTTOM, LABEL_ALIGN_LEFT_TOP, LABEL_ALIGN_LEFT_BOTTOM, LABEL_ALIGN_RIGHT_TOP, LABEL_ALIGN_RIGHT_BOTTOM }; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/LabelPositionHelper.hxx b/chart2/source/view/inc/LabelPositionHelper.hxx new file mode 100644 index 000000000000..a240736018bc --- /dev/null +++ b/chart2/source/view/inc/LabelPositionHelper.hxx @@ -0,0 +1,86 @@ +/************************************************************************* + * + * 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_VIEW_LABELPOSITIONHELPER_HXX +#define _CHART2_VIEW_LABELPOSITIONHELPER_HXX + +#include "LabelAlignment.hxx" +#include "PropertyMapper.hxx" +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/drawing/Position3D.hpp> +#include <com/sun/star/drawing/XShapes.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ +class PlottingPositionHelper; +class ShapeFactory; + +class LabelPositionHelper +{ +public: + LabelPositionHelper( + PlottingPositionHelper* pPosHelper + , sal_Int32 nDimensionCount + , const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xLogicTarget + , ShapeFactory* pShapeFactory ); + virtual ~LabelPositionHelper(); + + ::com::sun::star::awt::Point transformSceneToScreenPosition( + const ::com::sun::star::drawing::Position3D& rScenePosition3D ) const; + + static void changeTextAdjustment( tAnySequence& rPropValues, const tNameSequence& rPropNames, LabelAlignment eAlignment); + static void doDynamicFontResize( tAnySequence& rPropValues, const tNameSequence& rPropNames + , const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xAxisModelProps + , const ::com::sun::star::awt::Size& rNewReferenceSize ); + + static void correctPositionForRotation( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xShape2DText + , LabelAlignment eLabelAlignment, const double fRotationAngle, bool bRotateAroundCenter ); + +private: + LabelPositionHelper(); + +protected: + PlottingPositionHelper* m_pPosHelper; + sal_Int32 m_nDimensionCount; + +private: + //these members are only necessary for transformation from 3D to 2D + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes > m_xLogicTarget; + ShapeFactory* m_pShapeFactory; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/LegendEntryProvider.hxx b/chart2/source/view/inc/LegendEntryProvider.hxx new file mode 100644 index 000000000000..1ecc78107d2b --- /dev/null +++ b/chart2/source/view/inc/LegendEntryProvider.hxx @@ -0,0 +1,96 @@ +/************************************************************************* + * + * 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_VIEW_LEGENDENTRYPROVIDER_HXX +#define CHART2_VIEW_LEGENDENTRYPROVIDER_HXX + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/chart/ChartLegendExpansion.hpp> +#include <com/sun/star/chart2/XFormattedString.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <vector> + +namespace chart +{ + +enum LegendSymbolStyle +{ + /** A square box with border. + */ + LegendSymbolStyle_BOX, + + /** A line like with a symbol. + */ + LegendSymbolStyle_LINE, + + /** A bordered circle which has the same bounding-box as the + <member>BOX</member>. + */ + LegendSymbolStyle_CIRCLE +}; + +struct ViewLegendEntry +{ + /** The legend symbol that represents a data series or other + information contained in the legend + */ + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShape > aSymbol; + + /** The descriptive text for a legend entry. + */ + ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XFormattedString > > aLabel; +}; + +class LegendEntryProvider +{ +public: + virtual ::com::sun::star::awt::Size getPreferredLegendKeyAspectRatio()=0; + + virtual std::vector< ViewLegendEntry > createLegendEntries( + const ::com::sun::star::awt::Size& rEntryKeyAspectRatio, + ::com::sun::star::chart::ChartLegendExpansion eLegendExpansion, + const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xTextProperties, + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget, + const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& xShapeFactory, + const ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext >& xContext + ) = 0; +}; + +} // namespace chart + +// CHART2_VIEW_LEGENDENTRYPROVIDER_HXX +#endif diff --git a/chart2/source/view/inc/Linear3DTransformation.hxx b/chart2/source/view/inc/Linear3DTransformation.hxx new file mode 100644 index 000000000000..71a728d2dc73 --- /dev/null +++ b/chart2/source/view/inc/Linear3DTransformation.hxx @@ -0,0 +1,67 @@ +/************************************************************************* + * + * 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 _CHART_LINEAR3DTRANSFORMATION_HXX +#define _CHART_LINEAR3DTRANSFORMATION_HXX + +#include <cppuhelper/implbase1.hxx> +#include <com/sun/star/chart2/XTransformation.hpp> +#include <com/sun/star/drawing/HomogenMatrix.hpp> + +namespace chart +{ + +class Linear3DTransformation : public ::cppu::WeakImplHelper1< + ::com::sun::star::chart2::XTransformation + > +{ +public: + Linear3DTransformation( const ::com::sun::star::drawing::HomogenMatrix& rHomMatrix, bool bSwapXAndY ); + virtual ~Linear3DTransformation(); + + // ____ XTransformation ____ + /// @see ::com::sun::star::chart2::XTransformation + virtual ::com::sun::star::uno::Sequence< double > SAL_CALL transform( + const ::com::sun::star::uno::Sequence< double >& rSourceValues ) + throw (::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + /// @see ::com::sun::star::chart2::XTransformation + virtual sal_Int32 SAL_CALL getSourceDimension() + throw (::com::sun::star::uno::RuntimeException); + /// @see ::com::sun::star::chart2::XTransformation + virtual sal_Int32 SAL_CALL getTargetDimension() + throw (::com::sun::star::uno::RuntimeException); + +private: + ::com::sun::star::drawing::HomogenMatrix m_Matrix; + bool m_bSwapXAndY; +}; + +} // namespace chart + +// _CHART_LINEAR3DTRANSFORMATION_HXX +#endif + diff --git a/chart2/source/view/inc/MinimumAndMaximumSupplier.hxx b/chart2/source/view/inc/MinimumAndMaximumSupplier.hxx new file mode 100644 index 000000000000..dee1fec8e67d --- /dev/null +++ b/chart2/source/view/inc/MinimumAndMaximumSupplier.hxx @@ -0,0 +1,107 @@ +/************************************************************************* + * + * 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_MINIMUMANDMAXIMUMSUPPLIER_HXX +#define _CHART2_MINIMUMANDMAXIMUMSUPPLIER_HXX + +#include <sal/types.h> +#include <tools/date.hxx> +#include <set> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +class MinimumAndMaximumSupplier +{ +public: + virtual double getMinimumX() = 0; + virtual double getMaximumX() = 0; + + //problem y maybe not is always the second border to ask for + virtual double getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) = 0; + virtual double getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) = 0; + + //problem: z maybe not independent in future + virtual double getMinimumZ() = 0; + virtual double getMaximumZ() = 0; + + virtual bool isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex ) = 0; + virtual bool isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex ) = 0; + virtual bool isExpandWideValuesToZero( sal_Int32 nDimensionIndex ) = 0; + virtual bool isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex ) = 0; + virtual bool isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) = 0; + + //return a constant out of ::com::sun::star::chart::TimeUnit that allows to display the smallest distance between occuring dates + virtual long calculateTimeResolutionOnXAxis() = 0; + virtual void setTimeResolutionOnXAxis( long nTimeResolution, const Date& rNullDate ) = 0; +}; + +class MergedMinimumAndMaximumSupplier : public MinimumAndMaximumSupplier +{ +public: + MergedMinimumAndMaximumSupplier(); + virtual ~MergedMinimumAndMaximumSupplier(); + + void addMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ); + bool hasMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ); + void clearMinimumAndMaximumSupplierList(); + + //--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 double getMinimumZ(); + virtual double getMaximumZ(); + + 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 ); + + virtual long calculateTimeResolutionOnXAxis(); + virtual void setTimeResolutionOnXAxis( long nTimeResolution, const Date& rNullDate ); + +private: + typedef ::std::set< MinimumAndMaximumSupplier* > MinimumAndMaximumSupplierSet; + MinimumAndMaximumSupplierSet m_aMinimumAndMaximumSupplierList; + + inline MinimumAndMaximumSupplierSet::iterator begin() { return m_aMinimumAndMaximumSupplierList.begin(); } + inline MinimumAndMaximumSupplierSet::iterator end() { return m_aMinimumAndMaximumSupplierList.end(); } +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/PlotterBase.hxx b/chart2/source/view/inc/PlotterBase.hxx new file mode 100644 index 000000000000..7920845248e4 --- /dev/null +++ b/chart2/source/view/inc/PlotterBase.hxx @@ -0,0 +1,107 @@ +/************************************************************************* + * + * 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_PLOTTERBASE_HXX +#define _CHART2_PLOTTERBASE_HXX + +#include "chartview/ExplicitScaleValues.hxx" + +#include <com/sun/star/drawing/HomogenMatrix.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/drawing/Position3D.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/chart2/XTransformation.hpp> + +#include <cppuhelper/implbase1.hxx> +#include <vector> + +//............................................................................. +namespace chart +{ +//............................................................................. + +class ShapeFactory; +class PlottingPositionHelper; + +class PlotterBase +{ +public: + PlotterBase( sal_Int32 nDimension ); + virtual ~PlotterBase(); + + virtual void initPlotter( + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xLogicTarget + , const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xFinalTarget + , const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& xFactory + , const rtl::OUString& rCID + ) throw (::com::sun::star::uno::RuntimeException ); + + virtual void setScales( const ::std::vector< ExplicitScaleData >& rScales, bool bSwapXAndYAxis ); + + virtual void setTransformationSceneToScreen( const ::com::sun::star::drawing::HomogenMatrix& rMatrix ); + + virtual void createShapes() = 0; + + static bool isValidPosition( const ::com::sun::star::drawing::Position3D& rPos ); + + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- +private: //methods + //no default constructor + PlotterBase(); + +protected: //methods + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > + createGroupShape( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget + , ::rtl::OUString rName=::rtl::OUString() ); + +protected: //member + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes > m_xLogicTarget; + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes > m_xFinalTarget; + ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory> m_xShapeFactory; + ShapeFactory* m_pShapeFactory; + //::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext> m_xCC; + + rtl::OUString m_aCID; + + sal_Int32 m_nDimension; + // needs to be created and deleted by the derived class + PlottingPositionHelper* m_pPosHelper; +}; +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/PlottingPositionHelper.hxx b/chart2/source/view/inc/PlottingPositionHelper.hxx new file mode 100644 index 000000000000..42c7a90a0116 --- /dev/null +++ b/chart2/source/view/inc/PlottingPositionHelper.hxx @@ -0,0 +1,450 @@ +/************************************************************************* + * + * 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_PLOTTINGPOSITIONHELPER_HXX +#define _CHART2_PLOTTINGPOSITIONHELPER_HXX + +#include "LabelAlignment.hxx" +#include "chartview/ExplicitScaleValues.hxx" + +#include <basegfx/range/b2drectangle.hxx> +#include <rtl/math.hxx> +#include <com/sun/star/chart2/XTransformation.hpp> +#include <com/sun/star/drawing/Direction3D.hpp> +#include <com/sun/star/drawing/HomogenMatrix.hpp> +#include <com/sun/star/drawing/PolyPolygonShape3D.hpp> +#include <com/sun/star/drawing/Position3D.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <basegfx/matrix/b3dhommatrix.hxx> + +/* +//for WeakImplHelper1 +#include <cppuhelper/implbase1.hxx> +*/ +//............................................................................. +namespace chart +{ +//............................................................................. + +class ShapeFactory; + +//----------------------------------------------------------------------------- +/** +*/ + +class PlottingPositionHelper +{ +public: + PlottingPositionHelper(); + PlottingPositionHelper( const PlottingPositionHelper& rSource ); + virtual ~PlottingPositionHelper(); + + virtual PlottingPositionHelper* clone() const; + virtual PlottingPositionHelper* createSecondaryPosHelper( const ExplicitScaleData& rSecondaryScale ); + + virtual void setTransformationSceneToScreen( const ::com::sun::star::drawing::HomogenMatrix& rMatrix); + + virtual void setScales( const ::std::vector< ExplicitScaleData >& rScales, bool bSwapXAndYAxis ); + const ::std::vector< ExplicitScaleData >& getScales() const; + + //better performance for big data + inline void setCoordinateSystemResolution( const ::com::sun::star::uno::Sequence< sal_Int32 >& rCoordinateSystemResolution ); + inline bool isSameForGivenResolution( double fX, double fY, double fZ + , double fX2, double fY2, double fZ2 ); + + inline bool isStrongLowerRequested( sal_Int32 nDimensionIndex ) const; + inline bool isLogicVisible( double fX, double fY, double fZ ) const; + inline void doLogicScaling( double* pX, double* pY, double* pZ, bool bClip=false ) const; + inline void doUnshiftedLogicScaling( double* pX, double* pY, double* pZ, bool bClip=false ) const; + inline void clipLogicValues( double* pX, double* pY, double* pZ ) const; + void clipScaledLogicValues( double* pX, double* pY, double* pZ ) const; + inline bool clipYRange( double& rMin, double& rMax ) const; + + inline void doLogicScaling( ::com::sun::star::drawing::Position3D& rPos, bool bClip=false ) const; + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTransformation > + getTransformationScaledLogicToScene() const; + + virtual ::com::sun::star::drawing::Position3D + transformLogicToScene( double fX, double fY, double fZ, bool bClip ) const; + + virtual ::com::sun::star::drawing::Position3D + transformScaledLogicToScene( double fX, double fY, double fZ, bool bClip ) const; + + void transformScaledLogicToScene( ::com::sun::star::drawing::PolyPolygonShape3D& rPoly ) const; + + static com::sun::star::awt::Point transformSceneToScreenPosition( + const com::sun::star::drawing::Position3D& rScenePosition3D + , const com::sun::star::uno::Reference< com::sun::star::drawing::XShapes >& xSceneTarget + , ShapeFactory* pShapeFactory, sal_Int32 nDimensionCount ); + + inline double getLogicMinX() const; + inline double getLogicMinY() const; + inline double getLogicMinZ() const; + inline double getLogicMaxX() const; + inline double getLogicMaxY() const; + inline double getLogicMaxZ() const; + + inline bool isMathematicalOrientationX() const; + inline bool isMathematicalOrientationY() const; + inline bool isMathematicalOrientationZ() const; + + ::basegfx::B2DRectangle getScaledLogicClipDoubleRect() const; + ::com::sun::star::drawing::Direction3D getScaledLogicWidth() const; + + inline bool isSwapXAndY() const; + + bool isPercentY() const; + + double getBaseValueY() const; + + inline bool maySkipPointsInRegressionCalculation() const; + + void setTimeResolution( long nTimeResolution, const Date& rNullDate ); + virtual void setScaledCategoryWidth( double fScaledCategoryWidth ); + void AllowShiftXAxisPos( bool bAllowShift ); + void AllowShiftZAxisPos( bool bAllowShift ); + +protected: //member + ::std::vector< ExplicitScaleData > m_aScales; + ::basegfx::B3DHomMatrix m_aMatrixScreenToScene; + + //this is calculated based on m_aScales and m_aMatrixScreenToScene + mutable ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XTransformation > m_xTransformationLogicToScene; + + bool m_bSwapXAndY;//e.g. true for bar chart and false for column chart + + sal_Int32 m_nXResolution; + sal_Int32 m_nYResolution; + sal_Int32 m_nZResolution; + + bool m_bMaySkipPointsInRegressionCalculation; + + bool m_bDateAxis; + long m_nTimeResolution; + Date m_aNullDate; + + double m_fScaledCategoryWidth; + bool m_bAllowShiftXAxisPos; + bool m_bAllowShiftZAxisPos; +}; + +//describes wich axis of the drawinglayer scene or sreen axis are the normal axis +enum NormalAxis +{ + NormalAxis_X + , NormalAxis_Y + , NormalAxis_Z +}; + +class PolarPlottingPositionHelper : public PlottingPositionHelper + /* + , public ::cppu::WeakImplHelper1< + ::com::sun::star::chart2::XTransformation > + */ +{ +public: + PolarPlottingPositionHelper( NormalAxis eNormalAxis=NormalAxis_Z ); + PolarPlottingPositionHelper( const PolarPlottingPositionHelper& rSource ); + virtual ~PolarPlottingPositionHelper(); + + virtual PlottingPositionHelper* clone() const; + + virtual void setTransformationSceneToScreen( const ::com::sun::star::drawing::HomogenMatrix& rMatrix); + virtual void setScales( const std::vector< ExplicitScaleData >& rScales, bool bSwapXAndYAxis ); + + ::basegfx::B3DHomMatrix getUnitCartesianToScene() const; + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTransformation > + getTransformationScaledLogicToScene() const; + + //the resulting values should be used for input to the transformation + //received with 'getTransformationScaledLogicToScene' + double transformToRadius( double fLogicValueOnRadiusAxis, bool bDoScaling=true ) const; + double transformToAngleDegree( double fLogicValueOnAngleAxis, bool bDoScaling=true ) const; + double getWidthAngleDegree( double& fStartLogicValueOnAngleAxis, double& fEndLogicValueOnAngleAxis ) const; + // + + virtual ::com::sun::star::drawing::Position3D + transformLogicToScene( double fX, double fY, double fZ, bool bClip ) const; + virtual ::com::sun::star::drawing::Position3D + transformScaledLogicToScene( double fX, double fY, double fZ, bool bClip ) const; + ::com::sun::star::drawing::Position3D + transformAngleRadiusToScene( double fLogicValueOnAngleAxis, double fLogicValueOnRadiusAxis, double fLogicZ, bool bDoScaling=true ) const; + ::com::sun::star::drawing::Position3D + transformUnitCircleToScene( double fUnitAngleDegree, double fUnitRadius, double fLogicZ, bool bDoScaling=true ) const; + + using PlottingPositionHelper::transformScaledLogicToScene; + +#ifdef NOTYET + double getInnerLogicRadius() const; +#endif + double getOuterLogicRadius() const; + + inline bool isMathematicalOrientationAngle() const; + inline bool isMathematicalOrientationRadius() const; + + /* + // ____ XTransformation ____ + /// @see ::com::sun::star::chart2::XTransformation + virtual ::com::sun::star::uno::Sequence< double > SAL_CALL transform( + const ::com::sun::star::uno::Sequence< double >& rSourceValues ) + throw (::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + /// @see ::com::sun::star::chart2::XTransformation + virtual sal_Int32 SAL_CALL getSourceDimension() + throw (::com::sun::star::uno::RuntimeException); + /// @see ::com::sun::star::chart2::XTransformation + virtual sal_Int32 SAL_CALL getTargetDimension() + throw (::com::sun::star::uno::RuntimeException); + */ +public: + //Offset for radius axis in absolute logic scaled values (1.0 == 1 category) + double m_fRadiusOffset; + //Offset for angle axis in real degree + double m_fAngleDegreeOffset; + +private: + ::basegfx::B3DHomMatrix m_aUnitCartesianToScene; + NormalAxis m_eNormalAxis; + + ::basegfx::B3DHomMatrix impl_calculateMatrixUnitCartesianToScene( const ::basegfx::B3DHomMatrix& rMatrixScreenToScene ) const; +}; + +bool PolarPlottingPositionHelper::isMathematicalOrientationAngle() const +{ + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[1] : m_aScales[2]; + if( ::com::sun::star::chart2::AxisOrientation_MATHEMATICAL==rScale.Orientation ) + return true; + return false; +} +bool PolarPlottingPositionHelper::isMathematicalOrientationRadius() const +{ + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[0] : m_aScales[1]; + if( ::com::sun::star::chart2::AxisOrientation_MATHEMATICAL==rScale.Orientation ) + return true; + return false; +} + +//better performance for big data +void PlottingPositionHelper::setCoordinateSystemResolution( const ::com::sun::star::uno::Sequence< sal_Int32 >& rCoordinateSystemResolution ) +{ + m_nXResolution = 1000; + m_nYResolution = 1000; + m_nZResolution = 1000; + if( rCoordinateSystemResolution.getLength() > 0 ) + m_nXResolution = rCoordinateSystemResolution[0]; + if( rCoordinateSystemResolution.getLength() > 1 ) + m_nYResolution = rCoordinateSystemResolution[1]; + if( rCoordinateSystemResolution.getLength() > 2 ) + m_nZResolution = rCoordinateSystemResolution[2]; +} + +bool PlottingPositionHelper::isSameForGivenResolution( double fX, double fY, double fZ + , double fX2, double fY2, double fZ2 /*these values are all expected tp be scaled already*/ ) +{ + if( !::rtl::math::isFinite(fX) || !::rtl::math::isFinite(fY) || !::rtl::math::isFinite(fZ) + || !::rtl::math::isFinite(fX2) || !::rtl::math::isFinite(fY2) || !::rtl::math::isFinite(fZ2) ) + return false; + + double fScaledMinX = getLogicMinX(); + double fScaledMinY = getLogicMinY(); + double fScaledMinZ = getLogicMinZ(); + double fScaledMaxX = getLogicMaxX(); + double fScaledMaxY = getLogicMaxY(); + double fScaledMaxZ = getLogicMaxZ(); + + doLogicScaling( &fScaledMinX, &fScaledMinY, &fScaledMinZ ); + doLogicScaling( &fScaledMaxX, &fScaledMaxY, &fScaledMaxZ); + + bool bSameX = ( static_cast<sal_Int32>(m_nXResolution*(fX - fScaledMinX)/(fScaledMaxX-fScaledMinX)) + == static_cast<sal_Int32>(m_nXResolution*(fX2 - fScaledMinX)/(fScaledMaxX-fScaledMinX)) ); + + bool bSameY = ( static_cast<sal_Int32>(m_nYResolution*(fY - fScaledMinY)/(fScaledMaxY-fScaledMinY)) + == static_cast<sal_Int32>(m_nYResolution*(fY2 - fScaledMinY)/(fScaledMaxY-fScaledMinY)) ); + + bool bSameZ = ( static_cast<sal_Int32>(m_nZResolution*(fZ - fScaledMinZ)/(fScaledMaxZ-fScaledMinZ)) + == static_cast<sal_Int32>(m_nZResolution*(fZ2 - fScaledMinZ)/(fScaledMaxZ-fScaledMinZ)) ); + + return (bSameX && bSameY && bSameZ); +} + +bool PlottingPositionHelper::isStrongLowerRequested( sal_Int32 nDimensionIndex ) const +{ + if( m_aScales.empty() ) + return false; + if( 0==nDimensionIndex ) + return m_bAllowShiftXAxisPos && m_aScales[nDimensionIndex].ShiftedCategoryPosition; + else if( 2==nDimensionIndex ) + return m_bAllowShiftZAxisPos && m_aScales[nDimensionIndex].ShiftedCategoryPosition; + return false; +} + +bool PlottingPositionHelper::isLogicVisible( + double fX, double fY, double fZ ) const +{ + return fX >= m_aScales[0].Minimum && ( isStrongLowerRequested(0) ? fX < m_aScales[0].Maximum : fX <= m_aScales[0].Maximum ) + && fY >= m_aScales[1].Minimum && fY <= m_aScales[1].Maximum + && fZ >= m_aScales[2].Minimum && ( isStrongLowerRequested(2) ? fZ < m_aScales[2].Maximum : fZ <= m_aScales[2].Maximum ); +} + +void PlottingPositionHelper::doLogicScaling( double* pX, double* pY, double* pZ, bool bClip ) const +{ + if(bClip) + this->clipLogicValues( pX,pY,pZ ); + + if(pX) + { + if( m_aScales[0].Scaling.is()) + *pX = m_aScales[0].Scaling->doScaling(*pX); + if( m_bAllowShiftXAxisPos && m_aScales[0].ShiftedCategoryPosition ) + (*pX) += m_fScaledCategoryWidth/2.0; + } + if(pY && m_aScales[1].Scaling.is()) + *pY = m_aScales[1].Scaling->doScaling(*pY); + if(pZ) + { + if( m_aScales[2].Scaling.is()) + *pZ = m_aScales[2].Scaling->doScaling(*pZ); + if( m_bAllowShiftZAxisPos && m_aScales[2].ShiftedCategoryPosition) + (*pZ) += 0.5; + } +} + +void PlottingPositionHelper::doUnshiftedLogicScaling( double* pX, double* pY, double* pZ, bool bClip ) const +{ + if(bClip) + this->clipLogicValues( pX,pY,pZ ); + + if(pX && m_aScales[0].Scaling.is()) + *pX = m_aScales[0].Scaling->doScaling(*pX); + if(pY && m_aScales[1].Scaling.is()) + *pY = m_aScales[1].Scaling->doScaling(*pY); + if(pZ && m_aScales[2].Scaling.is()) + *pZ = m_aScales[2].Scaling->doScaling(*pZ); +} + +void PlottingPositionHelper::doLogicScaling( ::com::sun::star::drawing::Position3D& rPos, bool bClip ) const +{ + doLogicScaling( &rPos.PositionX, &rPos.PositionY, &rPos.PositionZ, bClip ); +} + +void PlottingPositionHelper::clipLogicValues( double* pX, double* pY, double* pZ ) const +{ + if(pX) + { + if( *pX < m_aScales[0].Minimum ) + *pX = m_aScales[0].Minimum; + else if( *pX > m_aScales[0].Maximum ) + *pX = m_aScales[0].Maximum; + } + if(pY) + { + if( *pY < m_aScales[1].Minimum ) + *pY = m_aScales[1].Minimum; + else if( *pY > m_aScales[1].Maximum ) + *pY = m_aScales[1].Maximum; + } + if(pZ) + { + if( *pZ < m_aScales[2].Minimum ) + *pZ = m_aScales[2].Minimum; + else if( *pZ > m_aScales[2].Maximum ) + *pZ = m_aScales[2].Maximum; + } +} + +inline bool PlottingPositionHelper::clipYRange( double& rMin, double& rMax ) const +{ + //returns true if something remains + if( rMin > rMax ) + { + double fHelp = rMin; + rMin = rMax; + rMax = fHelp; + } + if( rMin > getLogicMaxY() ) + return false; + if( rMax < getLogicMinY() ) + return false; + if( rMin < getLogicMinY() ) + rMin = getLogicMinY(); + if( rMax > getLogicMaxY() ) + rMax = getLogicMaxY(); + return true; +} + +inline double PlottingPositionHelper::getLogicMinX() const +{ + return m_aScales[0].Minimum; +} +inline double PlottingPositionHelper::getLogicMinY() const +{ + return m_aScales[1].Minimum; +} +inline double PlottingPositionHelper::getLogicMinZ() const +{ + return m_aScales[2].Minimum; +} + +inline double PlottingPositionHelper::getLogicMaxX() const +{ + return m_aScales[0].Maximum; +} +inline double PlottingPositionHelper::getLogicMaxY() const +{ + return m_aScales[1].Maximum; +} +inline double PlottingPositionHelper::getLogicMaxZ() const +{ + return m_aScales[2].Maximum; +} +inline bool PlottingPositionHelper::isMathematicalOrientationX() const +{ + return ::com::sun::star::chart2::AxisOrientation_MATHEMATICAL == m_aScales[0].Orientation; +} +inline bool PlottingPositionHelper::isMathematicalOrientationY() const +{ + return ::com::sun::star::chart2::AxisOrientation_MATHEMATICAL == m_aScales[1].Orientation; +} +inline bool PlottingPositionHelper::isMathematicalOrientationZ() const +{ + return ::com::sun::star::chart2::AxisOrientation_MATHEMATICAL == m_aScales[2].Orientation; +} +inline bool PlottingPositionHelper::isSwapXAndY() const +{ + return m_bSwapXAndY; +} +inline bool PlottingPositionHelper::maySkipPointsInRegressionCalculation() const +{ + return m_bMaySkipPointsInRegressionCalculation; +} + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/PolarLabelPositionHelper.hxx b/chart2/source/view/inc/PolarLabelPositionHelper.hxx new file mode 100644 index 000000000000..b4fd1fdc8483 --- /dev/null +++ b/chart2/source/view/inc/PolarLabelPositionHelper.hxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * 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_VIEW_POLARLABELPOSITIONHELPER_HXX +#define _CHART2_VIEW_POLARLABELPOSITIONHELPER_HXX + +#include "LabelPositionHelper.hxx" +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/drawing/Position3D.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ +class PolarPlottingPositionHelper; + +class PolarLabelPositionHelper : public LabelPositionHelper +{ +public: + PolarLabelPositionHelper( + PolarPlottingPositionHelper* pPosHelper + , sal_Int32 nDimensionCount + , const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xLogicTarget + , ShapeFactory* pShapeFactory ); + virtual ~PolarLabelPositionHelper(); + + ::com::sun::star::awt::Point getLabelScreenPositionAndAlignmentForLogicValues( + LabelAlignment& rAlignment + , double fLogicValueOnAngleAxis + , double fLogicValueOnRadiusAxis + , double fLogicZ + , sal_Int32 nScreenValueOffsetInRadiusDirection=0 ) const; + + ::com::sun::star::awt::Point getLabelScreenPositionAndAlignmentForUnitCircleValues( + LabelAlignment& rAlignment, sal_Int32 nLabelPlacement /*see ::com::sun::star::chart::DataLabelPlacement*/ + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , double fLogicZ + , sal_Int32 nScreenValueOffsetInRadiusDirection=0 ) const; + +private: + PolarPlottingPositionHelper* m_pPosHelper; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/PropertyMapper.hxx b/chart2/source/view/inc/PropertyMapper.hxx new file mode 100644 index 000000000000..c0871b94f835 --- /dev/null +++ b/chart2/source/view/inc/PropertyMapper.hxx @@ -0,0 +1,133 @@ +/************************************************************************* + * + * 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_PROPERTYMAPPER_HXX +#define _CHART2_PROPERTYMAPPER_HXX + +#include <comphelper/InlineContainer.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/XShape.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +typedef ::std::map< ::rtl::OUString, ::rtl::OUString > tPropertyNameMap; +typedef ::comphelper::MakeMap< ::rtl::OUString, ::rtl::OUString > tMakePropertyNameMap; + +typedef ::std::map< ::rtl::OUString, ::com::sun::star::uno::Any > tPropertyNameValueMap; +typedef ::comphelper::MakeMap< ::rtl::OUString, ::com::sun::star::uno::Any > tMakePropertyNameValueMap; + +typedef ::com::sun::star::uno::Sequence< rtl::OUString > tNameSequence; +typedef ::comphelper::MakeSequence< rtl::OUString > tMakeNameSequence; + +typedef ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > tAnySequence; +typedef ::comphelper::MakeSequence< ::com::sun::star::uno::Any > tMakeAnySequence; + +class PropertyMapper +{ +public: + static void setMappedProperties( + const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xTarget + , const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xSource + , const tPropertyNameMap& rMap + , tPropertyNameValueMap* pOverwriteMap=0 ); + + static void getValueMap( + tPropertyNameValueMap& rValueMap + , const tPropertyNameMap& rNameMap + , const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xSourceProp + ); + + static void getMultiPropertyLists( + tNameSequence& rNames + , tAnySequence& rValues + , const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xProp + , const tPropertyNameMap& rMap + ); + + static void getMultiPropertyListsFromValueMap( + tNameSequence& rNames + , tAnySequence& rValues + , const tPropertyNameValueMap& rValueMap + ); + + static ::com::sun::star::uno::Any* + getValuePointer( tAnySequence& rPropValues + , const tNameSequence& rPropNames + , const rtl::OUString& rPropName ); + + static ::com::sun::star::uno::Any* + getValuePointerForLimitedSpace( tAnySequence& rPropValues + , const tNameSequence& rPropNames + , bool bLimitedHeight ); + + static void setMultiProperties( + const tNameSequence& rNames + , const tAnySequence& rValues + , const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xTarget ); + + static const tMakePropertyNameMap& getPropertyNameMapForCharacterProperties(); + static const tMakePropertyNameMap& getPropertyNameMapForParagraphProperties(); + static const tMakePropertyNameMap& getPropertyNameMapForFillProperties(); + static const tMakePropertyNameMap& getPropertyNameMapForLineProperties(); + static const tMakePropertyNameMap& getPropertyNameMapForFillAndLineProperties(); + static const tMakePropertyNameMap& getPropertyNameMapForTextShapeProperties(); + + static const tMakePropertyNameMap& getPropertyNameMapForFilledSeriesProperties(); + static const tMakePropertyNameMap& getPropertyNameMapForLineSeriesProperties(); + + static void getTextLabelMultiPropertyLists( + const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xSourceProp + , tNameSequence& rPropNames, tAnySequence& rPropValues + , bool bName=true + , sal_Int32 nLimitedSpace=-1 + , bool bLimitedHeight=false ); + + /** adds line-, fill- and character properties and sets some suitable + defaults for auto-grow properties + */ + static void getPreparedTextShapePropertyLists( + const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xSourceProp + , tNameSequence& rPropNames + , tAnySequence& rPropValues ); +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/ScaleAutomatism.hxx b/chart2/source/view/inc/ScaleAutomatism.hxx new file mode 100644 index 000000000000..327027efcf39 --- /dev/null +++ b/chart2/source/view/inc/ScaleAutomatism.hxx @@ -0,0 +1,134 @@ +/************************************************************************* + * + * 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_SCALEAUTOMATISM_HXX +#define _CHART2_SCALEAUTOMATISM_HXX + +#include "chartview/ExplicitScaleValues.hxx" +#include <com/sun/star/chart2/ScaleData.hpp> + +#include <tools/date.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- + +/** This class implements the calculation of automatic axis limits. +*/ +class ScaleAutomatism +{ +public: + explicit ScaleAutomatism( + const ::com::sun::star::chart2::ScaleData& rSourceScale, const Date& rNullDate ); + virtual ~ScaleAutomatism(); + + /** Expands own value range with the passed minimum and maximum. */ + void expandValueRange( double fMinimum, double fMaximum ); + + /** Sets additional auto scaling options. + @param bExpandBorderToIncrementRhythm If true, expands automatic + borders to the fixed or calculated increment rhythm. + @param bExpandIfValuesCloseToBorder If true, expands automatic borders + if values are too close (closer than 1/21 of visible area). + @param bExpandWideValuesToZero If true, expands automatic border to + zero, if source values are positive only or negative only, and if + the absolute values are wide spread (at least one value is less + than 5/6 of absolute maximum), or if all values are equal. + @param bExpandNarrowValuesTowardZero If true, expands automatic border + toward zero (50% of the visible range), if source values are + positive only or negative only, and if the absolute values are + close to the absolute maximum (no value is less than 5/6 of + absolute maximum). */ + void setAutoScalingOptions( + bool bExpandBorderToIncrementRhythm, + bool bExpandIfValuesCloseToBorder, + bool bExpandWideValuesToZero, + bool bExpandNarrowValuesTowardZero ); + + /** Sets the maximum allowed number of automatic main increments. + @descr The number of main increments may be limited e.g. by the length + of the axis and the font size of the axis caption text. */ + void setMaximumAutoMainIncrementCount( sal_Int32 nMaximumAutoMainIncrementCount ); + + /** Sets the time resolution to be used in case it is not set explicitly within the scale + */ + void setAutomaticTimeResolution( sal_Int32 nTimeResolution ); + + /** Fills the passed scale data and increment data according to the own settings. */ + void calculateExplicitScaleAndIncrement( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement ) const; + + ::com::sun::star::chart2::ScaleData getScale() const; + Date getNullDate() const; + +private: + /** Fills the passed scale data and increment data for category scaling. */ + void calculateExplicitIncrementAndScaleForCategory( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const; + + /** Fills the passed scale data and increment data for logarithmic scaling. */ + void calculateExplicitIncrementAndScaleForLogarithmic( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const; + + /** Fills the passed scale data and increment data for linear scaling. */ + void calculateExplicitIncrementAndScaleForLinear( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const; + + /** Fills the passed scale data and increment data for date-time axis. */ + void calculateExplicitIncrementAndScaleForDateTimeAxis( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const; + +private: + ::com::sun::star::chart2::ScaleData m_aSourceScale; + + double m_fValueMinimum; /// Minimum of all source values. + double m_fValueMaximum; /// Maximum of all source values. + sal_Int32 m_nMaximumAutoMainIncrementCount; /// Maximum number of automatic main increments. + bool m_bExpandBorderToIncrementRhythm; /// true = Expand to main increments. + bool m_bExpandIfValuesCloseToBorder; /// true = Expand if values are too close to the borders. + bool m_bExpandWideValuesToZero; /// true = Expand wide spread values to zero. + bool m_bExpandNarrowValuesTowardZero; /// true = Expand narrow range toward zero (add half of range). + sal_Int32 m_nTimeResolution;// a constant out of ::com::sun::star::chart::TimeUnit + + Date m_aNullDate; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/ShapeFactory.hxx b/chart2/source/view/inc/ShapeFactory.hxx new file mode 100644 index 000000000000..ef75f3a323af --- /dev/null +++ b/chart2/source/view/inc/ShapeFactory.hxx @@ -0,0 +1,254 @@ +/************************************************************************* + * + * 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_VIEW_SHAPEFACTORY_HXX +#define _CHART2_VIEW_SHAPEFACTORY_HXX + +#include "PropertyMapper.hxx" +#include "VLineProperties.hxx" +#include "BaseGFXHelper.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/Direction3D.hpp> +#include <com/sun/star/drawing/HomogenMatrix.hpp> +#include <com/sun/star/drawing/PointSequenceSequence.hpp> +#include <com/sun/star/drawing/PolyPolygonShape3D.hpp> +#include <com/sun/star/drawing/Position3D.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. + +class Stripe; +class ShapeFactory +{ +public: + ShapeFactory(::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory> xFactory) + {m_xShapeFactory = xFactory;} + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > + createGroup2D( + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget + , ::rtl::OUString aName = ::rtl::OUString() ); + + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > + createGroup3D( + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget + , ::rtl::OUString aName = ::rtl::OUString() ); + + //------ + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createCube( 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 + , sal_Int32 nRotateZAngleHundredthDegree + , const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap + , bool bRounded = false); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createCylinder( 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 + , sal_Int32 nRotateZAngleHundredthDegree ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createPyramid( 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 + , bool bRotateZ + , const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createCone( 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 ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createPieSegment2D( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , const ::com::sun::star::drawing::Direction3D& rOffset + , const ::com::sun::star::drawing::HomogenMatrix& rUnitCircleToScene ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createPieSegment( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , const ::com::sun::star::drawing::Direction3D& rOffset + , const ::com::sun::star::drawing::HomogenMatrix& rUnitCircleToScene + , double fDepth ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createStripe( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget + , const Stripe& rStripe + , const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap + , sal_Bool bDoubleSided = true + , short nRotatedTexture = 0 //0 to 7 are the different possibilities + , bool bFlatNormals=true ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createArea3D( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget + , const ::com::sun::star::drawing::PolyPolygonShape3D& rPolyPolygon + , double fDepth); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createArea2D( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget + , const ::com::sun::star::drawing::PolyPolygonShape3D& rPolyPolygon); + + static sal_Int32 getSymbolCount(); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createSymbol2D( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget + , const ::com::sun::star::drawing::Position3D& rPos + , const ::com::sun::star::drawing::Direction3D& rSize + , sal_Int32 nStandardSymbol + , sal_Int32 nBorderColor=0 + , sal_Int32 nFillColor=0 ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createGraphic2D( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget + , const ::com::sun::star::drawing::Position3D& rPos + , const ::com::sun::star::drawing::Direction3D& rSize + , const ::com::sun::star::uno::Reference< ::com::sun::star::graphic::XGraphic >& xGraphic ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createLine2D( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget + , const ::com::sun::star::drawing::PointSequenceSequence& rPoints + , const VLineProperties* pLineProperties = NULL ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createLine3D( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget + , const ::com::sun::star::drawing::PolyPolygonShape3D& rPoints + , const VLineProperties& rLineProperties ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createCircle2D( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget + , const ::com::sun::star::drawing::Position3D& rPos + , const ::com::sun::star::drawing::Direction3D& rSize ); + + //------------------- create 2D elements: + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createText( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget2D + , const ::rtl::OUString& rText + , const tNameSequence& rPropNames + , const tAnySequence& rPropValues + , const ::com::sun::star::uno::Any& rATransformation + ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createInvisibleRectangle( + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget + , const ::com::sun::star::awt::Size& rSize ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > + getOrCreateChartRootShape( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XDrawPage>& xPage ); + + static ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > + getChartRootShape( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XDrawPage>& xPage ); + + //------ + static void makeShapeInvisible( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShape >& xShape ); + + static void setShapeName( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShape >& xShape + , const rtl::OUString& rName ); + + static rtl::OUString getShapeName( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShape >& xShape ); + + static ::com::sun::star::uno::Any makeTransformation( const ::com::sun::star::awt::Point& rScreenPosition2D, double fRotationAnglePi=0.0 ); + + static rtl::OUString getStackedString( const rtl::OUString& rString, bool bStacked=true ); + + static bool hasPolygonAnyLines( ::com::sun::star::drawing::PolyPolygonShape3D& rPoly ); + static bool isPolygonEmptyOrSinglePoint( ::com::sun::star::drawing::PolyPolygonShape3D& rPoly ); + static void closePolygon( ::com::sun::star::drawing::PolyPolygonShape3D& rPoly ); + + static ::com::sun::star::awt::Size calculateNewSizeRespectingAspectRatio( + const ::com::sun::star::awt::Size& rTargetSize + , const ::com::sun::star::awt::Size& rSourceSizeWithCorrectAspectRatio ); + + static ::com::sun::star::awt::Point calculateTopLeftPositionToCenterObject( + const ::com::sun::star::awt::Point& rTargetAreaPosition + , const ::com::sun::star::awt::Size& rTargetAreaSize + , const ::com::sun::star::awt::Size& rObjectSize ); + + static ::basegfx::B2IRectangle getRectangleOfShape( + const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xShape ); + + static ::com::sun::star::awt::Size getSizeAfterRotation( + const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xShape, double fRotationAngleDegree ); + + static void removeSubShapes( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xShapes ); + +private: + ShapeFactory(); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + impl_createCube( 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, sal_Int32 nRotateZAngleHundredthDegree + , bool bRounded ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + impl_createConeOrCylinder( 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 + , bool bCylinder = false); + + //member: + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory> + m_xShapeFactory; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/Stripe.hxx b/chart2/source/view/inc/Stripe.hxx new file mode 100644 index 000000000000..ca1aaf155d1e --- /dev/null +++ b/chart2/source/view/inc/Stripe.hxx @@ -0,0 +1,89 @@ +/************************************************************************* + * + * 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 _CHART_STRIPE_HXX +#define _CHART_STRIPE_HXX + +#include <com/sun/star/drawing/Position3D.hpp> +#include <com/sun/star/drawing/Direction3D.hpp> +#include <com/sun/star/uno/Any.h> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** A Stripe represents a 2 dimensional foursquare plane in a 3 dimaensional room. + +@todo could: it is not necessary to have 4 point members here; it would be sufficient to have one point and 2 directions +*/ + +class Stripe +{ +public: + Stripe( const ::com::sun::star::drawing::Position3D& rPoint1 + , const ::com::sun::star::drawing::Direction3D& rDirectionToPoint2 + , const ::com::sun::star::drawing::Direction3D& rDirectionToPoint4 ); + + Stripe( const ::com::sun::star::drawing::Position3D& rPoint1 + , const ::com::sun::star::drawing::Position3D& rPoint2 + , double fDepth ); + + Stripe( const ::com::sun::star::drawing::Position3D& rPoint1 + , const ::com::sun::star::drawing::Position3D& rPoint2 + , const ::com::sun::star::drawing::Position3D& rPoint3 + , const ::com::sun::star::drawing::Position3D& rPoint4 ); + + void SetManualNormal( const ::com::sun::star::drawing::Direction3D& rNormal ); + ::com::sun::star::drawing::Direction3D getNormal() const; + + void InvertNormal( bool bInvertNormal ); + + ::com::sun::star::uno::Any getPolyPolygonShape3D() const; + ::com::sun::star::uno::Any getNormalsPolygon() const; + ::com::sun::star::uno::Any getTexturePolygon( short nRotatedTexture ) const; //0 to 7 are the different possibilities + + ::com::sun::star::drawing::Position3D GetPosition1() const { return m_aPoint1; } + ::com::sun::star::drawing::Position3D GetPosition2() const { return m_aPoint2; } + ::com::sun::star::drawing::Position3D GetPosition3() const { return m_aPoint3; } + ::com::sun::star::drawing::Position3D GetPosition4() const { return m_aPoint4; } + +private: + ::com::sun::star::drawing::Position3D m_aPoint1; + ::com::sun::star::drawing::Position3D m_aPoint2; + ::com::sun::star::drawing::Position3D m_aPoint3; + ::com::sun::star::drawing::Position3D m_aPoint4; + + bool m_bInvertNormal; + bool m_bManualNormalSet; + ::com::sun::star::drawing::Direction3D m_aManualNormal; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/VCoordinateSystem.hxx b/chart2/source/view/inc/VCoordinateSystem.hxx new file mode 100644 index 000000000000..f4fd12547118 --- /dev/null +++ b/chart2/source/view/inc/VCoordinateSystem.hxx @@ -0,0 +1,209 @@ +/************************************************************************* + * + * 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_VCOORDINATESYSTEM_HXX +#define _CHART2_VCOORDINATESYSTEM_HXX + +#include "MinimumAndMaximumSupplier.hxx" +#include "ScaleAutomatism.hxx" +#include "ThreeDHelper.hxx" +#include "ExplicitCategoriesProvider.hxx" +#include "chartview/ExplicitScaleValues.hxx" + +#include <com/sun/star/chart2/XCoordinateSystem.hpp> +#include "comphelper/implementationreference.hxx" +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/drawing/HomogenMatrix.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> + +#include<map> +#include <vector> +#include <boost/shared_ptr.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ +class VAxisBase; +class VCoordinateSystem +{ +public: + virtual ~VCoordinateSystem(); + + static VCoordinateSystem* createCoordinateSystem( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XCoordinateSystem >& xCooSysModel ); + + virtual void initPlottingTargets( + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xLogicTarget + , const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xFinalTarget + , const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& xFactory + , ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xLogicTargetForSeriesBehindAxis ) + throw (::com::sun::star::uno::RuntimeException); + + void setParticle( const rtl::OUString& rCooSysParticle ); + + virtual void setTransformationSceneToScreen( const ::com::sun::star::drawing::HomogenMatrix& rMatrix ); + ::com::sun::star::drawing::HomogenMatrix getTransformationSceneToScreen(); + + //better performance for big data + virtual ::com::sun::star::uno::Sequence< sal_Int32 > getCoordinateSystemResolution( const ::com::sun::star::awt::Size& rPageSize + , const ::com::sun::star::awt::Size& rPageResolution ); + + ExplicitScaleData getExplicitScale( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const; + ExplicitIncrementData getExplicitIncrement( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const; + + void setExplicitCategoriesProvider( ExplicitCategoriesProvider* /*takes ownership*/ ); + ExplicitCategoriesProvider* getExplicitCategoriesProvider(); + + // returns a coplete scale set for a given dimension and index; for example if nDimensionIndex==1 and nAxisIndex==2 you get returned the secondary x axis, main y axis and main z axis + ::std::vector< ExplicitScaleData > getExplicitScales( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const; + // returns a coplete increment set for a given dimension and index; for example if nDimensionIndex==1 and nAxisIndex==2 you get returned the secondary x axis, main y axis and main z axis + ::std::vector< ExplicitIncrementData > getExplicitIncrements( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const; + + void addMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ); + bool hasMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ); + void clearMinimumAndMaximumSupplierList(); + + void prepareScaleAutomatismForDimensionAndIndex( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex ); + + void setExplicitScaleAndIncrement( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex + , const ExplicitScaleData& rExplicitScale + , const ExplicitIncrementData& rExplicitIncrement ); + + void set3DWallPositions( CuboidPlanePosition eLeftWallPos, CuboidPlanePosition eBackWallPos, CuboidPlanePosition eBottomPos ); + + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XCoordinateSystem > + getModel() const; + + virtual void createVAxisList( + const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier > & xNumberFormatsSupplier + , const ::com::sun::star::awt::Size& rFontReferenceSize + , const ::com::sun::star::awt::Rectangle& rMaximumSpaceForLabels ); + + virtual void initVAxisInList(); + virtual void updateScalesAndIncrementsOnAxes(); + + virtual void createMaximumAxesLabels(); + virtual void createAxesLabels(); + virtual void updatePositions(); + virtual void createAxesShapes(); + + virtual void createGridShapes(); + + virtual bool getPropertySwapXAndYAxis() const; + + sal_Int32 getMaximumAxisIndexByDimension( sal_Int32 nDimensionIndex ) const; + + virtual bool needSeriesNamesForAxis() const; + void setSeriesNamesForAxis( const ::com::sun::star::uno::Sequence< rtl::OUString >& rSeriesNames ); + +protected: //methods + VCoordinateSystem( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XCoordinateSystem >& xCooSys ); + + ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XAxis > + getAxisByDimension( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const; + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > > + getGridListFromAxis( const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XAxis >& xAxis ); + + VAxisBase* getVAxis( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + + rtl::OUString createCIDForAxis( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XAxis >& xAxis + , sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + rtl::OUString createCIDForGrid( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XAxis >& xAxis + , sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + + sal_Int32 getNumberFormatKeyForAxis( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XAxis >& xAxis + , const ::com::sun::star::uno::Reference< + ::com::sun::star::util::XNumberFormatsSupplier >& xNumberFormatsSupplier ); + +private: //methods + void impl_adjustDimension( sal_Int32& rDimensionIndex ) const; + void impl_adjustDimensionAndIndex( sal_Int32& rDimensionIndex, sal_Int32& rAxisIndex ) const; + +protected: //member + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XCoordinateSystem > m_xCooSysModel; + + rtl::OUString m_aCooSysParticle; + + typedef std::pair< sal_Int32, sal_Int32 > tFullAxisIndex; //first index is the dimension, second index is the axis index that indicates wether this is a main or secondary axis + + // + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes > m_xLogicTargetForGrids; + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes > m_xLogicTargetForAxes; + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes > m_xFinalTarget; + ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory> m_xShapeFactory; + ::com::sun::star::drawing::HomogenMatrix m_aMatrixSceneToScreen; + + CuboidPlanePosition m_eLeftWallPos; + CuboidPlanePosition m_eBackWallPos; + CuboidPlanePosition m_eBottomPos; + + // + MergedMinimumAndMaximumSupplier m_aMergedMinimumAndMaximumSupplier; //this is used only for autoscaling purpose + + ::com::sun::star::uno::Sequence< rtl::OUString > m_aSeriesNamesForZAxis; + + typedef std::map< tFullAxisIndex, ::boost::shared_ptr< VAxisBase > > tVAxisMap; + + tVAxisMap m_aAxisMap; + +private: + std::vector< ExplicitScaleData > m_aExplicitScales; + std::vector< ExplicitIncrementData > m_aExplicitIncrements; + + typedef std::map< tFullAxisIndex, ExplicitScaleData > tFullExplicitScaleMap; + typedef std::map< tFullAxisIndex, ExplicitIncrementData > tFullExplicitIncrementMap; + + tFullExplicitScaleMap m_aSecondaryExplicitScales; + tFullExplicitIncrementMap m_aSecondaryExplicitIncrements; + + ::std::auto_ptr< ExplicitCategoriesProvider > m_apExplicitCategoriesProvider; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/VDataSeries.hxx b/chart2/source/view/inc/VDataSeries.hxx new file mode 100644 index 000000000000..62d61cb17269 --- /dev/null +++ b/chart2/source/view/inc/VDataSeries.hxx @@ -0,0 +1,268 @@ +/************************************************************************* + * + * 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_VIEW_DATASERIES_HXX +#define _CHART2_VIEW_DATASERIES_HXX + +#include "PropertyMapper.hxx" + +#include <vector> +//for auto_ptr +#include <memory> +#include <com/sun/star/chart2/DataPointLabel.hpp> +#include <com/sun/star/chart2/Symbol.hpp> +#include <com/sun/star/chart2/StackingDirection.hpp> +#include <com/sun/star/chart2/data/XLabeledDataSequence.hpp> +#include <com/sun/star/chart2/XChartType.hpp> +#include <com/sun/star/chart2/XDataSeries.hpp> +#include <com/sun/star/drawing/HomogenMatrix.hpp> +#include <com/sun/star/drawing/PolyPolygonShape3D.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <cppuhelper/weakref.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ +class VDataSequence +{ +public: + void init( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::data::XDataSequence >& xModel ); + bool is() const; + void clear(); + double getValue( sal_Int32 index ) const; + sal_Int32 detectNumberFormatKey( sal_Int32 index ) const; + sal_Int32 getLength() const; + + + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::data::XDataSequence > Model; + + mutable ::com::sun::star::uno::Sequence< double > Doubles; +}; + +class VDataSeries +{ +public: + VDataSeries( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XDataSeries >& xDataSeries ); + virtual ~VDataSeries(); + + ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XDataSeries > + getModel() const; + + void setCategoryXAxis(); + void setXValues( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::data::XDataSequence >& xValues ); + void setXValuesIfNone( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::data::XDataSequence >& xValues ); + void setParticle( const rtl::OUString& rSeriesParticle ); + void setGlobalSeriesIndex( sal_Int32 nGlobalSeriesIndex ); + void setPageReferenceSize( const ::com::sun::star::awt::Size & rPageRefSize ); + + sal_Int32 getTotalPointCount() const; + double getXValue( sal_Int32 index ) const; + double getYValue( sal_Int32 index ) const; + + double getY_Min( sal_Int32 index ) const; + double getY_Max( sal_Int32 index ) const; + double getY_First( sal_Int32 index ) const; + double getY_Last( sal_Int32 index ) const; + + double getBubble_Size( sal_Int32 index ) const; + + double getMinimumofAllDifferentYValues( sal_Int32 index ) const; + double getMaximumofAllDifferentYValues( sal_Int32 index ) const; + + ::com::sun::star::uno::Sequence< double > getAllX() const; + ::com::sun::star::uno::Sequence< double > getAllY() const; + + double getYMeanValue() const; + + bool hasExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const; + sal_Int32 getExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const; + sal_Int32 detectNumberFormatKey( sal_Int32 nPointIndex ) const; + bool shouldLabelNumberFormatKeyBeDetectedFromYAxis() const; + + sal_Int32 getLabelPlacement( sal_Int32 nPointIndex, const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XChartType >& xChartType + , sal_Int32 nDimensionCount, sal_Bool bSwapXAndY ) const; + + ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > + getPropertiesOfPoint( sal_Int32 index ) const; + + ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > + getPropertiesOfSeries() const; + + ::com::sun::star::chart2::Symbol* + getSymbolProperties( sal_Int32 index ) const; + + ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > + getYErrorBarProperties( sal_Int32 index ) const; + + bool hasPointOwnColor( sal_Int32 index ) const; + + ::com::sun::star::chart2::StackingDirection getStackingDirection() const; + sal_Int32 getAttachedAxisIndex() const; + void setAttachedAxisIndex( sal_Int32 nAttachedAxisIndex ); + + void doSortByXValues(); + + void setConnectBars( sal_Bool bConnectBars ); + sal_Bool getConnectBars() const; + + void setGroupBarsPerAxis( sal_Bool bGroupBarsPerAxis ); + sal_Bool getGroupBarsPerAxis() const; + + void setStartingAngle( sal_Int32 nStartingAngle ); + sal_Int32 getStartingAngle() const; + + void setRoleOfSequenceForDataLabelNumberFormatDetection( const rtl::OUString& rRole ); + + //this is only temporarily here for area chart: + ::com::sun::star::drawing::PolyPolygonShape3D m_aPolyPolygonShape3D; + sal_Int32 m_nPolygonIndex; + double m_fLogicMinX; + double m_fLogicMaxX; + // + //this is here for deep stacking: + double m_fLogicZPos;//from 0 to series count -1 + // + + rtl::OUString getCID() const; + rtl::OUString getSeriesParticle() const; + rtl::OUString getPointCID_Stub() const; + rtl::OUString getErrorBarsCID() const; + rtl::OUString getLabelsCID() const; + rtl::OUString getLabelCID_Stub() const; + rtl::OUString getDataCurveCID( sal_Int32 nCurveIndex, bool bAverageLine ) const; + + ::com::sun::star::chart2::DataPointLabel* + getDataPointLabelIfLabel( sal_Int32 index ) const; + bool getTextLabelMultiPropertyLists( sal_Int32 index, tNameSequence*& pPropNames, tAnySequence*& pPropValues ) const; + + rtl::OUString getDataCurveEquationCID( sal_Int32 nCurveIndex ) const; + bool isAttributedDataPoint( sal_Int32 index ) const; + + bool isVaryColorsByPoint() const; + + void releaseShapes(); + + void setMissingValueTreatment( sal_Int32 nMissingValueTreatment ); + sal_Int32 getMissingValueTreatment() const; + +private: //methods + ::com::sun::star::chart2::DataPointLabel* + getDataPointLabel( sal_Int32 index ) const; + void adaptPointCache( sal_Int32 nNewPointIndex ) const; + +public: //member + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > m_xGroupShape; + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > m_xLabelsGroupShape; + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > m_xErrorBarsGroupShape; + + //the following group shapes will be created as children of m_xGroupShape on demand + //they can be used to assure that some parts of a series shape are always in front of others (e.g. symbols in front of lines) + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > m_xFrontSubGroupShape; + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > m_xBackSubGroupShape; + +private: //member + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XDataSeries > m_xDataSeries; + ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::data::XLabeledDataSequence > > m_aDataSequences; + + //all points given by the model data (here are not only the visible points meant) + sal_Int32 m_nPointCount; + + VDataSequence m_aValues_X; + VDataSequence m_aValues_Y; + VDataSequence m_aValues_Z; + + VDataSequence m_aValues_Y_Min; + VDataSequence m_aValues_Y_Max; + VDataSequence m_aValues_Y_First; + VDataSequence m_aValues_Y_Last; + + VDataSequence m_aValues_Bubble_Size; + + VDataSequence* m_pValueSequenceForDataLabelNumberFormatDetection; + + mutable double m_fYMeanValue; + + ::com::sun::star::uno::Sequence< sal_Int32 > m_aAttributedDataPointIndexList; + + ::com::sun::star::chart2::StackingDirection m_eStackingDirection; + + sal_Int32 m_nAxisIndex;//indicates wether this is attached to a main or secondary axis + + sal_Bool m_bConnectBars; + + sal_Bool m_bGroupBarsPerAxis; + + sal_Int32 m_nStartingAngle; + + rtl::OUString m_aSeriesParticle; + rtl::OUString m_aCID; + rtl::OUString m_aPointCID_Stub; + rtl::OUString m_aLabelCID_Stub; + + sal_Int32 m_nGlobalSeriesIndex; + + //some cached values for data labels as they are very expensive + mutable ::std::auto_ptr< ::com::sun::star::chart2::DataPointLabel > + m_apLabel_Series; + mutable ::std::auto_ptr< tNameSequence > m_apLabelPropNames_Series; + mutable ::std::auto_ptr< tAnySequence > m_apLabelPropValues_Series; + mutable ::std::auto_ptr< ::com::sun::star::chart2::Symbol > + m_apSymbolProperties_Series; + + mutable ::std::auto_ptr< ::com::sun::star::chart2::DataPointLabel > + m_apLabel_AttributedPoint; + mutable ::std::auto_ptr< tNameSequence > m_apLabelPropNames_AttributedPoint; + mutable ::std::auto_ptr< tAnySequence > m_apLabelPropValues_AttributedPoint; + mutable ::std::auto_ptr< ::com::sun::star::chart2::Symbol > + m_apSymbolProperties_AttributedPoint; + mutable ::std::auto_ptr< ::com::sun::star::chart2::Symbol > + m_apSymbolProperties_InvisibleSymbolForSelection; + mutable sal_Int32 m_nCurrentAttributedPoint; + ::com::sun::star::awt::Size m_aReferenceSize; + // + + sal_Int32 m_nMissingValueTreatment; + bool m_bAllowPercentValueInDataLabel; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/VDiagram.hxx b/chart2/source/view/inc/VDiagram.hxx new file mode 100644 index 000000000000..6bcef92111ef --- /dev/null +++ b/chart2/source/view/inc/VDiagram.hxx @@ -0,0 +1,136 @@ +/************************************************************************* + * + * 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_VDIAGRAM_HXX +#define _CHART2_VDIAGRAM_HXX + +#include <com/sun/star/drawing/HomogenMatrix.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/chart2/XDiagram.hpp> +#include "ShapeFactory.hxx" +#include <basegfx/range/b2irectangle.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. + +class ShapeFactory; + +//----------------------------------------------------------------------------- +/** The VDiagram is responsible to generate the visible parts of the Diagram +that is wall, floor, axes and data series. +The axes and data series are subobjects which are created and managed by the +diagram. +*/ + +class VDiagram +{ +public: //methods + VDiagram( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XDiagram > & xDiagram + , const ::com::sun::star::drawing::Direction3D& rPreferredAspectRatio + , sal_Int32 nDimension=3, sal_Bool bPolar=sal_False ); + virtual ~VDiagram(); + + void init( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xLogicTarget + , const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xFinalTarget + , const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory); + + void createShapes( const ::com::sun::star::awt::Point& rPos + , const ::com::sun::star::awt::Size& rSize ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > + getCoordinateRegion(); + + ::basegfx::B2IRectangle getCurrentRectangle(); + + void reduceToMimimumSize(); + + ::basegfx::B2IRectangle adjustPosAndSize( const ::com::sun::star::awt::Point& rPos + , const ::com::sun::star::awt::Size& rAvailableSize ); + + ::basegfx::B2IRectangle adjustInnerSize( const ::basegfx::B2IRectangle& rConsumedOuterRect ); + + // updateShapes(..); + // const awt::Point& rPos, const awt::Size& rSize ); + +private: //methods + void createShapes_2d(); + void createShapes_3d(); + + ::basegfx::B2IRectangle adjustPosAndSize_2d( const ::com::sun::star::awt::Point& rPos + , const ::com::sun::star::awt::Size& rAvailableSize ); + ::basegfx::B2IRectangle adjustPosAndSize_3d( const ::com::sun::star::awt::Point& rPos + , const ::com::sun::star::awt::Size& rAvailableSize ); + + void adjustAspectRatio3d( const ::com::sun::star::awt::Size& rAvailableSize ); + +private: //members + VDiagram(const VDiagram& rD); + + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes > m_xLogicTarget; + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes > m_xFinalTarget; + ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory> m_xShapeFactory; + ShapeFactory* m_pShapeFactory; + + // this is the surrounding shape which contains floor, wall and coordinate + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > m_xOuterGroupShape; + // this is an additional inner shape that represents the coordinate region - that is - where to place data points + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > m_xCoordinateRegionShape; + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > m_xWall2D; + + sal_Int32 m_nDimensionCount; + sal_Bool m_bPolar; + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XDiagram > m_xDiagram; + + ::com::sun::star::drawing::Direction3D m_aPreferredAspectRatio; + ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > m_xAspectRatio3D; + + double m_fXAnglePi; + double m_fYAnglePi; + double m_fZAnglePi; + sal_Bool m_bRightAngledAxes; + + ::com::sun::star::awt::Point m_aAvailablePosIncludingAxes; + ::com::sun::star::awt::Size m_aAvailableSizeIncludingAxes; + + ::com::sun::star::awt::Point m_aCurrentPosWithoutAxes; + ::com::sun::star::awt::Size m_aCurrentSizeWithoutAxes; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif + + diff --git a/chart2/source/view/inc/VLegendSymbolFactory.hxx b/chart2/source/view/inc/VLegendSymbolFactory.hxx new file mode 100644 index 000000000000..4ea3c67d5ece --- /dev/null +++ b/chart2/source/view/inc/VLegendSymbolFactory.hxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * 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_VLEGENDSYMBOLFACTORY_HXX +#define CHART2_VLEGENDSYMBOLFACTORY_HXX + +#include "LegendEntryProvider.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/drawing/XShapes.hpp> + +namespace chart +{ + +class VLegendSymbolFactory +{ +public: + enum tPropertyType + { + PROP_TYPE_FILLED_SERIES, + PROP_TYPE_LINE_SERIES, + PROP_TYPE_FILL, + PROP_TYPE_LINE, + PROP_TYPE_FILL_AND_LINE + }; + + static ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShape > + createSymbol( + const ::com::sun::star::awt::Size& rEntryKeyAspectRatio, + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes > xSymbolContainer, + LegendSymbolStyle eStyle, + const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory > & xShapeFactory, + const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet > & xLegendEntryProperties, + tPropertyType ePropertyType, + const ::com::sun::star::uno::Any& rExplicitSymbol /*should contain a ::com::sun::star::chart2::Symbol without automatic symbol if the charttype does support symbols else empty*/); + +private: + VLegendSymbolFactory(); +}; + +} // namespace chart + +// CHART2_VLEGENDSYMBOLFACTORY_HXX +#endif diff --git a/chart2/source/view/inc/VLineProperties.hxx b/chart2/source/view/inc/VLineProperties.hxx new file mode 100644 index 000000000000..f6ec92d38cf8 --- /dev/null +++ b/chart2/source/view/inc/VLineProperties.hxx @@ -0,0 +1,61 @@ +/************************************************************************* + * + * 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_VLINEPROPERTIES_HXX +#define _CHART2_VLINEPROPERTIES_HXX + +#include <com/sun/star/beans/XPropertySet.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +struct VLineProperties +{ + com::sun::star::uno::Any Color; //type sal_Int32 UNO_NAME_LINECOLOR + com::sun::star::uno::Any LineStyle; //type drawing::LineStyle for property UNO_NAME_LINESTYLE + com::sun::star::uno::Any Transparence;//type sal_Int16 for property UNO_NAME_LINETRANSPARENCE + com::sun::star::uno::Any Width;//type sal_Int32 for property UNO_NAME_LINEWIDTH + com::sun::star::uno::Any DashName;//type OUString for property "LineDashName" + + VLineProperties(); + void initFromPropertySet( const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xProp + , bool bUseSeriesPropertyNames=false ); + + bool isLineVisible() const; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/VPolarTransformation.hxx b/chart2/source/view/inc/VPolarTransformation.hxx new file mode 100644 index 000000000000..f3da18ac92b6 --- /dev/null +++ b/chart2/source/view/inc/VPolarTransformation.hxx @@ -0,0 +1,67 @@ +/************************************************************************* + * + * 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 _CHART_VPOLARTRANSFORMATION_HXX +#define _CHART_VPOLARTRANSFORMATION_HXX + +#include "PlottingPositionHelper.hxx" +#include <cppuhelper/implbase1.hxx> +#include <com/sun/star/chart2/XTransformation.hpp> + +namespace chart +{ + +class VPolarTransformation : public ::cppu::WeakImplHelper1< + ::com::sun::star::chart2::XTransformation + > +{ +public: + VPolarTransformation( const PolarPlottingPositionHelper& rPositionHelper ); + virtual ~VPolarTransformation(); + + // ____ XTransformation ____ + /// @see ::com::sun::star::chart2::XTransformation + virtual ::com::sun::star::uno::Sequence< double > SAL_CALL transform( + const ::com::sun::star::uno::Sequence< double >& rSourceValues ) + throw (::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + /// @see ::com::sun::star::chart2::XTransformation + virtual sal_Int32 SAL_CALL getSourceDimension() + throw (::com::sun::star::uno::RuntimeException); + /// @see ::com::sun::star::chart2::XTransformation + virtual sal_Int32 SAL_CALL getTargetDimension() + throw (::com::sun::star::uno::RuntimeException); + +private: + PolarPlottingPositionHelper m_aPositionHelper; + ::basegfx::B3DHomMatrix m_aUnitCartesianToScene; +}; + +} // namespace chart + +// _CHART_VPOLARTRANSFORMATION_HXX +#endif + diff --git a/chart2/source/view/inc/VSeriesPlotter.hxx b/chart2/source/view/inc/VSeriesPlotter.hxx new file mode 100644 index 000000000000..9e427a5e2a81 --- /dev/null +++ b/chart2/source/view/inc/VSeriesPlotter.hxx @@ -0,0 +1,451 @@ +/************************************************************************* + * + * 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_VSERIESPLOTTER_HXX +#define _CHART2_VSERIESPLOTTER_HXX + +#include "PlotterBase.hxx" +#include "VDataSeries.hxx" +#include "LabelAlignment.hxx" +#include "MinimumAndMaximumSupplier.hxx" +#include "LegendEntryProvider.hxx" +#include "ExplicitCategoriesProvider.hxx" +#include <com/sun/star/chart2/XChartType.hpp> +#include <com/sun/star/drawing/Direction3D.hpp> + + +namespace com { namespace sun { namespace star { + namespace util { + class XNumberFormatsSupplier; + } + namespace chart2 { + class XColorScheme; + class XRegressionCurveCalculator; + } +}}} + +//............................................................................. +namespace chart +{ +//............................................................................. + +class NumberFormatterWrapper; + +class AxesNumberFormats +{ +public: + AxesNumberFormats() {}; + + void setFormat( sal_Int32 nFormatKey, sal_Int32 nDimIndex, sal_Int32 nAxisIndex ) + { + m_aNumberFormatMap[tFullAxisIndex(nDimIndex,nAxisIndex)] = nFormatKey; + } + sal_Int32 hasFormat( sal_Int32 nDimIndex, sal_Int32 nAxisIndex ) const + { + return (m_aNumberFormatMap.find(tFullAxisIndex(nDimIndex,nAxisIndex)) !=m_aNumberFormatMap.end()); + } + sal_Int32 getFormat( sal_Int32 nDimIndex, sal_Int32 nAxisIndex ) const + { + tNumberFormatMap::const_iterator aIt = m_aNumberFormatMap.find(tFullAxisIndex(nDimIndex,nAxisIndex)); + if( aIt !=m_aNumberFormatMap.end() ) + return aIt->second; + return 0; + } + +private: + typedef std::pair< sal_Int32, sal_Int32 > tFullAxisIndex; + typedef std::map< tFullAxisIndex, sal_Int32 > tNumberFormatMap; + tNumberFormatMap m_aNumberFormatMap; +}; + +//----------------------------------------------------------------------------- +/** +*/ + +//enum StackType { STACK_NORMAL, STACK_NONE, STACK_BESIDES, STACK_ONTOP, STACK_BEHIND }; + +class VDataSeriesGroup +{ + //a list of series that have the same CoordinateSystem + //they are used to be plotted maybe in a stacked manner by a plotter + +public: + VDataSeriesGroup(); + VDataSeriesGroup( VDataSeries* pSeries ); + virtual ~VDataSeriesGroup(); + + void addSeries( VDataSeries* pSeries );//takes ownership of pSeries + sal_Int32 getSeriesCount() const; + void deleteSeries(); + + sal_Int32 getPointCount() const; + sal_Int32 getAttachedAxisIndexForFirstSeries() const; + + void getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const; + void getMinimumAndMaximiumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const; + + void calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex + , bool bSeperateStackingForDifferentSigns + , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex ); + void calculateYMinAndMaxForCategoryRange( sal_Int32 nStartCategoryIndex, sal_Int32 nEndCategoryIndex + , bool bSeperateStackingForDifferentSigns + , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex ); + + ::std::vector< VDataSeries* > m_aSeriesVector; + +private: + //cached values + struct CachedYValues + { + CachedYValues(); + + bool m_bValuesDirty; + double m_fMinimumY; + double m_fMaximumY; + }; + + mutable bool m_bMaxPointCountDirty; + mutable sal_Int32 m_nMaxPointCount; + typedef std::map< sal_Int32, CachedYValues > tCachedYValuesPerAxisIndexMap; + mutable ::std::vector< tCachedYValuesPerAxisIndexMap > m_aListOfCachedYValues; +}; + +class VSeriesPlotter : public PlotterBase, public MinimumAndMaximumSupplier, public LegendEntryProvider +{ + //------------------------------------------------------------------------- + // public methods + //------------------------------------------------------------------------- +public: + virtual ~VSeriesPlotter(); + + /* + * A new series can be positioned relative to other series in a chart. + * This positioning has two dimensions. First a series can be placed + * next to each other on the category axis. This position is indicated by xSlot. + * Second a series can be stacked on top of another. This position is indicated by ySlot. + * The positions are counted from 0 on. + * xSlot < 0 : append the series to already existing x series + * xSlot > occupied : append the series to already existing x series + * + * If the xSlot is already occupied the given ySlot decides what should happen: + * ySlot < -1 : move all existing series in the xSlot to next slot + * ySlot == -1 : stack on top at given x position + * ySlot == already occupied : insert at given y and x position + * ySlot > occupied : stack on top at given x position + */ + virtual void addSeries( VDataSeries* pSeries, sal_Int32 zSlot = -1, sal_Int32 xSlot = -1,sal_Int32 ySlot = -1 ); + + /** a value <= 0 for a directions means that this direction can be stretched arbitrary + */ + virtual ::com::sun::star::drawing::Direction3D getPreferredDiagramAspectRatio() const; + virtual bool keepAspectRatio() const; + + /** this enables you to handle series on the same x axis with different y axis + the property AttachedAxisIndex at a dataseries indicates which value scale is to use + (0==AttachedAxisIndex or a not set AttachedAxisIndex property indicates that this series should be scaled at the main y-axis; + 1==AttachedAxisIndex indicates that the series should be scaled at the first secondary axis if there is any otherwise at the main y axis + and so on. + The parameter nAxisIndex matches this DataSereis property 'AttachedAxisIndex'. + nAxisIndex must be greater than 0. nAxisIndex==1 referres to the first secondary axis. + ) + */ + + virtual void addSecondaryValueScale( const ExplicitScaleData& rScale, sal_Int32 nAxisIndex ) + throw (::com::sun::star::uno::RuntimeException); + + //------------------------------------------------------------------------- + // 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 double getMinimumZ(); + virtual double getMaximumZ(); + + 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 ); + + virtual long calculateTimeResolutionOnXAxis(); + virtual void setTimeResolutionOnXAxis( long nTimeResolution, const Date& rNullDate ); + + //------ + + void getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const; + void getMinimumAndMaximiumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const; + + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + + virtual std::vector< ViewLegendEntry > createLegendEntries( + const ::com::sun::star::awt::Size& rEntryKeyAspectRatio, + ::com::sun::star::chart::ChartLegendExpansion eLegendExpansion, + const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xTextProperties, + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget, + const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& xShapeFactory, + const ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext >& xContext + ); + + + virtual LegendSymbolStyle getLegendSymbolStyle(); + virtual com::sun::star::awt::Size getPreferredLegendKeyAspectRatio(); + + virtual ::com::sun::star::uno::Any getExplicitSymbol( const VDataSeries& rSeries, sal_Int32 nPointIndex=-1/*-1 for series symbol*/ ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > createLegendSymbolForSeries( + const ::com::sun::star::awt::Size& rEntryKeyAspectRatio + , const VDataSeries& rSeries + , const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget + , const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xShapeFactory ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > createLegendSymbolForPoint( + const ::com::sun::star::awt::Size& rEntryKeyAspectRatio + , const VDataSeries& rSeries + , sal_Int32 nPointIndex + , const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes >& xTarget + , const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xShapeFactory ); + + virtual std::vector< ViewLegendEntry > createLegendEntriesForSeries( + const ::com::sun::star::awt::Size& rEntryKeyAspectRatio, + const VDataSeries& rSeries, + const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xTextProperties, + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget, + const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& xShapeFactory, + const ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext >& xContext + ); + + ::std::vector< VDataSeries* > getAllSeries(); + + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + + static VSeriesPlotter* createSeriesPlotter( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XChartType >& xChartTypeModel + , sal_Int32 nDimensionCount + , bool bExcludingPositioning = false /*for pie and donut charts labels and exploded segments are excluded from the given size*/); + + sal_Int32 getPointCount() const; + + void setNumberFormatsSupplier( const ::com::sun::star::uno::Reference< + ::com::sun::star::util::XNumberFormatsSupplier > & xNumFmtSupplier ); + void setAxesNumberFormats( const AxesNumberFormats& rAxesNumberFormats ) { m_aAxesNumberFormats = rAxesNumberFormats; }; + + void setColorScheme( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XColorScheme >& xColorScheme ); + + void setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider ); + + //get series names for the z axis labels + ::com::sun::star::uno::Sequence< rtl::OUString > getSeriesNames() const; + + void setPageReferenceSize( const ::com::sun::star::awt::Size & rPageRefSize ); + //better performance for big data + void setCoordinateSystemResolution( const ::com::sun::star::uno::Sequence< sal_Int32 >& rCoordinateSystemResolution ); + bool PointsWereSkipped() const; + + //return the depth for a logic 1 + double getTransformedDepth() const; + + void releaseShapes(); + + virtual void rearrangeLabelToAvoidOverlapIfRequested( const ::com::sun::star::awt::Size& rPageSize ); + + bool WantToPlotInFrontOfAxisLine(); + virtual bool shouldSnapRectToUsedArea(); + + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- + //------------------------------------------------------------------------- +private: //methods + //no default constructor + VSeriesPlotter(); + +protected: //methods + + VSeriesPlotter( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XChartType >& xChartTypeModel + , sal_Int32 nDimensionCount + , bool bCategoryXAxis=true ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > + getSeriesGroupShape( VDataSeries* pDataSeries + , const::com::sun::star:: uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget ); + + //the following group shapes will be created as children of SeriesGroupShape on demand + //they can be used to assure that some parts of a series shape are always in front of others (e.g. symbols in front of lines) + //parameter xTarget will be used as parent for the series group shape + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > + getSeriesGroupShapeFrontChild( VDataSeries* pDataSeries + , const::com::sun::star:: uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget ); + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > + getSeriesGroupShapeBackChild( VDataSeries* pDataSeries + , const::com::sun::star:: uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > + getLabelsGroupShape( VDataSeries& rDataSeries + , const::com::sun::star:: uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > + getErrorBarsGroupShape( VDataSeries& rDataSeries + , const::com::sun::star:: uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget ); + + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + createDataLabel( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget + , VDataSeries& rDataSeries + , sal_Int32 nPointIndex + , double fValue + , double fSumValue + , const ::com::sun::star::awt::Point& rScreenPosition2D + , LabelAlignment eAlignment=LABEL_ALIGN_CENTER + , sal_Int32 nOffset=0 ); + + ::rtl::OUString getLabelTextForValue( VDataSeries& rDataSeries + , sal_Int32 nPointIndex + , double fValue + , bool bAsPercentage ); + + /** creates two T-shaped error bars in both directions (up/down or + left/right depending on the bVertical parameter) + + @param rPos + logic coordinates + + @param xErrorBarProperties + the XPropertySet returned by the DataPoint-property "ErrorBarX" or + "ErrorBarY". + + @param nIndex + the index of the data point in rData for which the calculation is + done. + + @param bVertical + for y-error bars this is true, for x-error-bars it is false. + */ + virtual void createErrorBar( + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget + , const ::com::sun::star::drawing::Position3D & rPos + , const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet > & xErrorBarProperties + , const VDataSeries& rVDataSeries + , sal_Int32 nIndex + , bool bVertical + , double* pfScaledLogicX + ); + + virtual void createErrorBar_Y( const ::com::sun::star::drawing::Position3D& rUnscaledLogicPosition + , VDataSeries& rVDataSeries, sal_Int32 nPointIndex + , const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget + , double* pfScaledLogicX=0 ); + + virtual void createRegressionCurvesShapes( VDataSeries& rVDataSeries + , const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTarget + , const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xEquationTarget + , bool bMaySkipPointsInRegressionCalculation ); + + virtual void createRegressionCurveEquationShapes( const ::rtl::OUString & rEquationCID + , const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet > & xEquationProperties + , const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xEquationTarget + , const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XRegressionCurveCalculator > & xRegressionCurveCalculator + , ::com::sun::star::awt::Point aDefaultPos ); + + virtual void setMappedProperties( + const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShape >& xTarget + , const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xSource + , const tPropertyNameMap& rMap + , tPropertyNameValueMap* pOverwriteMap=0 ); + + virtual PlottingPositionHelper& getPlottingPositionHelper( sal_Int32 nAxisIndex ) const;//nAxisIndex indicates wether the position belongs to the main axis ( nAxisIndex==0 ) or secondary axis ( nAxisIndex==1 ) + + VDataSeries* getFirstSeries() const; + +protected: //member + PlottingPositionHelper* m_pMainPosHelper; + + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XChartType > m_xChartTypeModel; + ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet > m_xChartTypeModelProps; + + ::std::vector< ::std::vector< VDataSeriesGroup > > m_aZSlots; + + bool m_bCategoryXAxis;//true->xvalues are indices (this would not be necessary if series for category chart wouldn't have x-values) + long m_nTimeResolution; + Date m_aNullDate; + + ::std::auto_ptr< NumberFormatterWrapper > m_apNumberFormatterWrapper; + AxesNumberFormats m_aAxesNumberFormats;//direct numberformats on axes, if empty ask the data series instead + + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XColorScheme > m_xColorScheme; + + ExplicitCategoriesProvider* m_pExplicitCategoriesProvider; + + //better performance for big data + ::com::sun::star::uno::Sequence< sal_Int32 > m_aCoordinateSystemResolution; + bool m_bPointsWereSkipped; + +private: //member + typedef std::map< sal_Int32 , ExplicitScaleData > tSecondaryValueScales; + tSecondaryValueScales m_aSecondaryValueScales; + + typedef std::map< sal_Int32 , PlottingPositionHelper* > tSecondaryPosHelperMap; + mutable tSecondaryPosHelperMap m_aSecondaryPosHelperMap; + ::com::sun::star::awt::Size m_aPageReferenceSize; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif diff --git a/chart2/source/view/inc/ViewDefines.hxx b/chart2/source/view/inc/ViewDefines.hxx new file mode 100644 index 000000000000..623e46e64fb7 --- /dev/null +++ b/chart2/source/view/inc/ViewDefines.hxx @@ -0,0 +1,47 @@ +/************************************************************************* + * + * 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 _CHART_COMMONDEFINES_HXX +#define _CHART_COMMONDEFINES_HXX + +namespace chart +{ + +//========================================================================= +// +//========================================================================= +#define CHART_3DOBJECT_SEGMENTCOUNT ((sal_Int32)32) +#define FIXED_SIZE_FOR_3D_CHART_VOLUME (10000.0) +//There needs to be a little distance betweengrid lines and walls in 3D, otherwise the lines are partly hidden by the walls +#define GRID_TO_WALL_DISTANCE (1.0) + +const double ZDIRECTION = 1.0; +const sal_Int32 AXIS2D_TICKLENGTH = 150;//value like in old chart +const sal_Int32 AXIS2D_TICKLABELSPACING = 100;//value like in old chart + + +}//end namespace chart +#endif diff --git a/chart2/source/view/main/ChartItemPool.cxx b/chart2/source/view/main/ChartItemPool.cxx new file mode 100644 index 000000000000..c66044b9aa0d --- /dev/null +++ b/chart2/source/view/main/ChartItemPool.cxx @@ -0,0 +1,228 @@ +/************************************************************************* + * + * 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 "ChartItemPool.hxx" +#include "macros.hxx" + +#include "chartview/ChartSfxItemIds.hxx" +#include <svx/chrtitem.hxx> +#include <svl/intitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/sizeitem.hxx> +#include <svl/stritem.hxx> +#include <svl/rectitem.hxx> +#include <svl/ilstitem.hxx> +#define _SVSTDARR_ULONGS +#include <svl/svstdarr.hxx> +#include <editeng/editids.hrc> +#include <svx/svxids.hrc> + +#include <com/sun/star/chart2/LegendPosition.hpp> + +namespace chart +{ + +ChartItemPool::ChartItemPool(): + SfxItemPool( String( RTL_CONSTASCII_USTRINGPARAM( "ChartItemPool" )), SCHATTR_START, SCHATTR_END, NULL, NULL ) +{ +// OSL_TRACE( "SCH: CTOR: ChartItemPool" ); + /************************************************************************** + * PoolDefaults + **************************************************************************/ + ppPoolDefaults = new SfxPoolItem*[SCHATTR_END - SCHATTR_START + 1]; + + ppPoolDefaults[SCHATTR_DATADESCR_SHOW_NUMBER - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_SHOW_NUMBER); + ppPoolDefaults[SCHATTR_DATADESCR_SHOW_PERCENTAGE- SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_SHOW_PERCENTAGE); + ppPoolDefaults[SCHATTR_DATADESCR_SHOW_CATEGORY - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_SHOW_CATEGORY); + ppPoolDefaults[SCHATTR_DATADESCR_SHOW_SYMBOL - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_SHOW_SYMBOL); + ppPoolDefaults[SCHATTR_DATADESCR_SEPARATOR - SCHATTR_START] = new SfxStringItem(SCHATTR_DATADESCR_SEPARATOR,C2U(" ")); + ppPoolDefaults[SCHATTR_DATADESCR_PLACEMENT - SCHATTR_START] = new SfxInt32Item(SCHATTR_DATADESCR_PLACEMENT,0); + SvULongs aTmp; + ppPoolDefaults[SCHATTR_DATADESCR_AVAILABLE_PLACEMENTS - SCHATTR_START] = new SfxIntegerListItem(SCHATTR_DATADESCR_AVAILABLE_PLACEMENTS,aTmp); + ppPoolDefaults[SCHATTR_DATADESCR_NO_PERCENTVALUE - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_NO_PERCENTVALUE); + ppPoolDefaults[SCHATTR_PERCENT_NUMBERFORMAT_VALUE - SCHATTR_START] = new SfxUInt32Item(SCHATTR_PERCENT_NUMBERFORMAT_VALUE, 0); + ppPoolDefaults[SCHATTR_PERCENT_NUMBERFORMAT_SOURCE - SCHATTR_START] = new SfxBoolItem(SCHATTR_PERCENT_NUMBERFORMAT_SOURCE); + + //legend + ppPoolDefaults[SCHATTR_LEGEND_POS - SCHATTR_START] = new SfxInt32Item(SCHATTR_LEGEND_POS, ::com::sun::star::chart2::LegendPosition_LINE_END ); + ppPoolDefaults[SCHATTR_LEGEND_SHOW - SCHATTR_START] = new SfxBoolItem(SCHATTR_LEGEND_SHOW, sal_True); + + //text + ppPoolDefaults[SCHATTR_TEXT_DEGREES - SCHATTR_START] = new SfxInt32Item(SCHATTR_TEXT_DEGREES, 0); + ppPoolDefaults[SCHATTR_TEXT_STACKED - SCHATTR_START] = new SfxBoolItem(SCHATTR_TEXT_STACKED,sal_False); + + //statistic + ppPoolDefaults[SCHATTR_STAT_AVERAGE - SCHATTR_START] = new SfxBoolItem (SCHATTR_STAT_AVERAGE); + ppPoolDefaults[SCHATTR_STAT_KIND_ERROR - SCHATTR_START] = new SvxChartKindErrorItem (CHERROR_NONE, SCHATTR_STAT_KIND_ERROR); + ppPoolDefaults[SCHATTR_STAT_PERCENT - SCHATTR_START] = new SvxDoubleItem (0.0, SCHATTR_STAT_PERCENT); + ppPoolDefaults[SCHATTR_STAT_BIGERROR - SCHATTR_START] = new SvxDoubleItem (0.0, SCHATTR_STAT_BIGERROR); + ppPoolDefaults[SCHATTR_STAT_CONSTPLUS - SCHATTR_START] = new SvxDoubleItem (0.0, SCHATTR_STAT_CONSTPLUS); + ppPoolDefaults[SCHATTR_STAT_CONSTMINUS - SCHATTR_START] = new SvxDoubleItem (0.0, SCHATTR_STAT_CONSTMINUS); + ppPoolDefaults[SCHATTR_STAT_INDICATE - SCHATTR_START] = new SvxChartIndicateItem (CHINDICATE_NONE, SCHATTR_STAT_INDICATE); + ppPoolDefaults[SCHATTR_STAT_RANGE_POS - SCHATTR_START] = new SfxStringItem (SCHATTR_STAT_RANGE_POS, String()); + ppPoolDefaults[SCHATTR_STAT_RANGE_NEG - SCHATTR_START] = new SfxStringItem (SCHATTR_STAT_RANGE_NEG, String()); + + ppPoolDefaults[SCHATTR_STYLE_DEEP - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_DEEP, 0); + ppPoolDefaults[SCHATTR_STYLE_3D - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_3D, 0); + ppPoolDefaults[SCHATTR_STYLE_VERTICAL - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_VERTICAL, 0); + ppPoolDefaults[SCHATTR_STYLE_BASETYPE - SCHATTR_START] = new SfxInt32Item(SCHATTR_STYLE_BASETYPE, 0); + ppPoolDefaults[SCHATTR_STYLE_LINES - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_LINES, 0); + ppPoolDefaults[SCHATTR_STYLE_PERCENT - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_PERCENT, 0); + ppPoolDefaults[SCHATTR_STYLE_STACKED - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_STACKED, 0); + ppPoolDefaults[SCHATTR_STYLE_SPLINES - SCHATTR_START] = new SfxInt32Item (SCHATTR_STYLE_SPLINES, 0); //Bug: war Bool! ->Fileformat testen (betrifft nur 5er) + ppPoolDefaults[SCHATTR_STYLE_SYMBOL - SCHATTR_START] = new SfxInt32Item (SCHATTR_STYLE_SYMBOL, 0); + ppPoolDefaults[SCHATTR_STYLE_SHAPE - SCHATTR_START] = new SfxInt32Item (SCHATTR_STYLE_SHAPE, 0); + + ppPoolDefaults[SCHATTR_AXIS - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS,2); //2 = Y-Achse!!! + + //axis scale + ppPoolDefaults[SCHATTR_AXISTYPE - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXISTYPE, CHART_AXIS_REALNUMBER); + ppPoolDefaults[SCHATTR_AXIS_REVERSE - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_REVERSE,0); + ppPoolDefaults[SCHATTR_AXIS_AUTO_MIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_MIN); + ppPoolDefaults[SCHATTR_AXIS_MIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_MIN); + ppPoolDefaults[SCHATTR_AXIS_AUTO_MAX - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_MAX); + ppPoolDefaults[SCHATTR_AXIS_MAX - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_MAX); + ppPoolDefaults[SCHATTR_AXIS_AUTO_STEP_MAIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_STEP_MAIN); + ppPoolDefaults[SCHATTR_AXIS_STEP_MAIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_STEP_MAIN); + ppPoolDefaults[SCHATTR_AXIS_MAIN_TIME_UNIT - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_MAIN_TIME_UNIT,2); + ppPoolDefaults[SCHATTR_AXIS_AUTO_STEP_HELP - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_STEP_HELP); + ppPoolDefaults[SCHATTR_AXIS_STEP_HELP - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_STEP_HELP,0); + ppPoolDefaults[SCHATTR_AXIS_HELP_TIME_UNIT - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_HELP_TIME_UNIT,2); + ppPoolDefaults[SCHATTR_AXIS_AUTO_TIME_RESOLUTION - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_TIME_RESOLUTION); + ppPoolDefaults[SCHATTR_AXIS_TIME_RESOLUTION - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_TIME_RESOLUTION,2); + ppPoolDefaults[SCHATTR_AXIS_LOGARITHM - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_LOGARITHM); + ppPoolDefaults[SCHATTR_AXIS_AUTO_DATEAXIS - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_DATEAXIS); + ppPoolDefaults[SCHATTR_AXIS_ALLOW_DATEAXIS - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_ALLOW_DATEAXIS); + ppPoolDefaults[SCHATTR_AXIS_AUTO_ORIGIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_ORIGIN); + ppPoolDefaults[SCHATTR_AXIS_ORIGIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_ORIGIN); + + //axis position + ppPoolDefaults[SCHATTR_AXIS_TICKS - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_TICKS,CHAXIS_MARK_OUTER); + ppPoolDefaults[SCHATTR_AXIS_HELPTICKS - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_HELPTICKS,0); + ppPoolDefaults[SCHATTR_AXIS_POSITION - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_POSITION,0); + ppPoolDefaults[SCHATTR_AXIS_POSITION_VALUE - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_POSITION_VALUE); + ppPoolDefaults[SCHATTR_AXIS_CROSSING_MAIN_AXIS_NUMBERFORMAT - SCHATTR_START] = new SfxUInt32Item(SCHATTR_AXIS_CROSSING_MAIN_AXIS_NUMBERFORMAT,0); + ppPoolDefaults[SCHATTR_AXIS_LABEL_POSITION - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_LABEL_POSITION,0); + ppPoolDefaults[SCHATTR_AXIS_MARK_POSITION - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_MARK_POSITION,0); + + //axis label + ppPoolDefaults[SCHATTR_AXIS_SHOWDESCR - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_SHOWDESCR,0); + ppPoolDefaults[SCHATTR_AXIS_LABEL_ORDER - SCHATTR_START] = new SvxChartTextOrderItem(CHTXTORDER_SIDEBYSIDE, SCHATTR_AXIS_LABEL_ORDER); + ppPoolDefaults[SCHATTR_AXIS_LABEL_OVERLAP - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_LABEL_OVERLAP,sal_False); + ppPoolDefaults[SCHATTR_AXIS_LABEL_BREAK - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_LABEL_BREAK, sal_False ); + + //-- + ppPoolDefaults[SCHATTR_SYMBOL_BRUSH - SCHATTR_START] = new SvxBrushItem(SCHATTR_SYMBOL_BRUSH); + ppPoolDefaults[SCHATTR_STOCK_VOLUME - SCHATTR_START] = new SfxBoolItem(SCHATTR_STOCK_VOLUME,0); + ppPoolDefaults[SCHATTR_STOCK_UPDOWN - SCHATTR_START] = new SfxBoolItem(SCHATTR_STOCK_UPDOWN,0); + ppPoolDefaults[SCHATTR_SYMBOL_SIZE - SCHATTR_START] = new SvxSizeItem(SCHATTR_SYMBOL_SIZE,Size(0,0)); + + // new for New Chart + ppPoolDefaults[SCHATTR_BAR_OVERLAP - SCHATTR_START] = new SfxInt32Item(SCHATTR_BAR_OVERLAP,0); + ppPoolDefaults[SCHATTR_BAR_GAPWIDTH - SCHATTR_START] = new SfxInt32Item(SCHATTR_BAR_GAPWIDTH,0); + ppPoolDefaults[SCHATTR_BAR_CONNECT - SCHATTR_START] = new SfxBoolItem(SCHATTR_BAR_CONNECT, sal_False); + ppPoolDefaults[SCHATTR_NUM_OF_LINES_FOR_BAR - SCHATTR_START] = new SfxInt32Item( SCHATTR_NUM_OF_LINES_FOR_BAR, 0 ); + ppPoolDefaults[SCHATTR_SPLINE_ORDER - SCHATTR_START] = new SfxInt32Item( SCHATTR_SPLINE_ORDER, 3 ); + ppPoolDefaults[SCHATTR_SPLINE_RESOLUTION - SCHATTR_START] = new SfxInt32Item( SCHATTR_SPLINE_RESOLUTION, 20 ); + ppPoolDefaults[SCHATTR_DIAGRAM_STYLE - SCHATTR_START] = new SvxChartStyleItem( CHSTYLE_2D_COLUMN, SCHATTR_DIAGRAM_STYLE ); + ppPoolDefaults[SCHATTR_GROUP_BARS_PER_AXIS - SCHATTR_START] = new SfxBoolItem(SCHATTR_GROUP_BARS_PER_AXIS, sal_False); + ppPoolDefaults[SCHATTR_STARTING_ANGLE - SCHATTR_START] = new SfxInt32Item( SCHATTR_STARTING_ANGLE, 90 ); + ppPoolDefaults[SCHATTR_CLOCKWISE - SCHATTR_START] = new SfxBoolItem( SCHATTR_CLOCKWISE, sal_False ); + + ppPoolDefaults[SCHATTR_MISSING_VALUE_TREATMENT - SCHATTR_START] = new SfxInt32Item(SCHATTR_MISSING_VALUE_TREATMENT, 0); + ppPoolDefaults[SCHATTR_AVAILABLE_MISSING_VALUE_TREATMENTS - SCHATTR_START] = new SfxIntegerListItem(SCHATTR_AVAILABLE_MISSING_VALUE_TREATMENTS,aTmp); + ppPoolDefaults[SCHATTR_INCLUDE_HIDDEN_CELLS - SCHATTR_START] = new SfxBoolItem(SCHATTR_INCLUDE_HIDDEN_CELLS, sal_True); + + ppPoolDefaults[SCHATTR_AXIS_FOR_ALL_SERIES - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_FOR_ALL_SERIES, 0); + + ppPoolDefaults[SCHATTR_REGRESSION_TYPE - SCHATTR_START] = new SvxChartRegressItem (CHREGRESS_NONE, SCHATTR_REGRESSION_TYPE); + ppPoolDefaults[SCHATTR_REGRESSION_SHOW_EQUATION - SCHATTR_START] = new SfxBoolItem(SCHATTR_REGRESSION_SHOW_EQUATION, 0); + ppPoolDefaults[SCHATTR_REGRESSION_SHOW_COEFF - SCHATTR_START] = new SfxBoolItem(SCHATTR_REGRESSION_SHOW_COEFF, 0); + + /************************************************************************** + * ItemInfos + **************************************************************************/ + pItemInfos = new SfxItemInfo[SCHATTR_END - SCHATTR_START + 1]; + + sal_uInt16 i; + for( i = SCHATTR_START; i <= SCHATTR_END; i++ ) + { + pItemInfos[i - SCHATTR_START]._nSID = 0; + pItemInfos[i - SCHATTR_START]._nFlags = SFX_ITEM_POOLABLE; + } + + // slot ids differing from which ids + pItemInfos[SCHATTR_SYMBOL_BRUSH - SCHATTR_START]._nSID = SID_ATTR_BRUSH; + pItemInfos[SCHATTR_STYLE_SYMBOL - SCHATTR_START]._nSID = SID_ATTR_SYMBOLTYPE; + pItemInfos[SCHATTR_SYMBOL_SIZE - SCHATTR_START]._nSID = SID_ATTR_SYMBOLSIZE; + + SetDefaults(ppPoolDefaults); + SetItemInfos(pItemInfos); +} + +ChartItemPool::ChartItemPool(const ChartItemPool& rPool): + SfxItemPool(rPool) +{ +// OSL_TRACE( "SCH: CTOR: ChartItemPool" ); +} + +ChartItemPool::~ChartItemPool() +{ +// OSL_TRACE( "SCH: DTOR: ChartItemPool" ); + Delete(); + + delete[] pItemInfos; + + const sal_uInt16 nMax = SCHATTR_END - SCHATTR_START + 1; + for( sal_uInt16 i=0; i<nMax; ++i ) + { + SetRefCount(*ppPoolDefaults[i], 0); + delete ppPoolDefaults[i]; + } + + delete[] ppPoolDefaults; +} + +SfxItemPool* ChartItemPool::Clone() const +{ + return new ChartItemPool(*this); +} + +SfxMapUnit ChartItemPool::GetMetric(sal_uInt16 /* nWhich */) const +{ + return SFX_MAPUNIT_100TH_MM; +} + +SfxItemPool* ChartItemPool::CreateChartItemPool() +{ + return new ChartItemPool(); +} + +} // namespace chart diff --git a/chart2/source/view/main/ChartItemPool.hxx b/chart2/source/view/main/ChartItemPool.hxx new file mode 100644 index 000000000000..10d30e9d2cf4 --- /dev/null +++ b/chart2/source/view/main/ChartItemPool.hxx @@ -0,0 +1,58 @@ +/************************************************************************* + * + * 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_ITEMPOOL_HXX +#define _CHART2_ITEMPOOL_HXX + +#include <svl/poolitem.hxx> +#include <svl/itempool.hxx> + +namespace chart +{ +class ChartItemPool : public SfxItemPool +{ +private: + SfxPoolItem** ppPoolDefaults; + SfxItemInfo* pItemInfos; + +public: + ChartItemPool(); + ChartItemPool(const ChartItemPool& rPool); +protected: + virtual ~ChartItemPool(); +public: + + virtual SfxItemPool* Clone() const; + SfxMapUnit GetMetric( sal_uInt16 nWhich ) const; + + /// creates a pure chart item pool + static SfxItemPool* CreateChartItemPool(); +}; + +} // namespace chart + +#endif +// _CHART2_ITEMPOOL_HXX diff --git a/chart2/source/view/main/ChartView.cxx b/chart2/source/view/main/ChartView.cxx new file mode 100644 index 000000000000..ad20a557756c --- /dev/null +++ b/chart2/source/view/main/ChartView.cxx @@ -0,0 +1,3076 @@ +/************************************************************************* + * + * 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 "ChartView.hxx" +#include "chartview/DrawModelWrapper.hxx" +#include "NumberFormatterWrapper.hxx" +#include "ViewDefines.hxx" +#include "VDiagram.hxx" +#include "VTitle.hxx" +#include "ShapeFactory.hxx" +#include "VCoordinateSystem.hxx" +#include "VSeriesPlotter.hxx" +#include "CommonConverters.hxx" +#include "macros.hxx" +#include "TitleHelper.hxx" +#include "LegendHelper.hxx" +#include "VLegend.hxx" +#include "PropertyMapper.hxx" +#include "ChartModelHelper.hxx" +#include "ChartTypeHelper.hxx" +#include "ScaleAutomatism.hxx" +#include "MinimumAndMaximumSupplier.hxx" +#include "ObjectIdentifier.hxx" +#include "DiagramHelper.hxx" +#include "RelativePositionHelper.hxx" +#include "servicenames.hxx" +#include "AxisHelper.hxx" +#include "AxisIndexDefines.hxx" +#include "ControllerLockGuard.hxx" +#include "BaseGFXHelper.hxx" +#include "DataSeriesHelper.hxx" +#include "DateHelper.hxx" + +#include <comphelper/scopeguard.hxx> +#include <boost/bind.hpp> +#include <unotools/streamwrap.hxx> +// header for class LocaleDataWrapper +#include <unotools/localedatawrapper.hxx> +// header for class SdrPage +#include <svx/svdpage.hxx> +// header for class SvxDrawPage +#include <svx/unopage.hxx> +// header for class SvxShape +#include <svx/unoshape.hxx> +// header for class Application +#include <vcl/svapp.hxx> +#include <vos/mutex.hxx> +#include <svx/unofill.hxx> + +#include <time.h> + +#include <com/sun/star/chart/ChartAxisPosition.hpp> +#include <com/sun/star/chart/DataLabelPlacement.hpp> +#include <com/sun/star/chart/MissingValueTreatment.hpp> +#include <com/sun/star/chart2/StackingDirection.hpp> +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> +#include <com/sun/star/chart2/XChartTypeContainer.hpp> +#include <com/sun/star/chart2/XDataSeriesContainer.hpp> +#include <com/sun/star/chart2/XTitled.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <com/sun/star/chart2/RelativeSize.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/XShapeGroup.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/util/XRefreshable.hpp> +#include <com/sun/star/util/NumberFormat.hpp> + +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <svl/languageoptions.hxx> +#include <sot/clsids.hxx> + +//............................................................................. +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 ::com::sun::star::uno::Any; +using rtl::OUString; + +const uno::Sequence<sal_Int8>& ExplicitValueProvider::getUnoTunnelId() +{ + static uno::Sequence<sal_Int8> * pSeq = 0; + if( !pSeq ) + { + osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); + if( !pSeq ) + { + static uno::Sequence< sal_Int8 > aSeq( 16 ); + rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True ); + pSeq = &aSeq; + } + } + return *pSeq; +} + +ExplicitValueProvider* ExplicitValueProvider::getExplicitValueProvider( + const Reference< uno::XInterface >& xChartView ) +{ + ExplicitValueProvider* pExplicitValueProvider=0; + + Reference< lang::XUnoTunnel > xTunnel( xChartView, uno::UNO_QUERY ); + if( xTunnel.is() ) + { + pExplicitValueProvider = reinterpret_cast<ExplicitValueProvider*>(xTunnel->getSomething( + ExplicitValueProvider::getUnoTunnelId() )); + } + return pExplicitValueProvider; +} + +ChartView::ChartView( + uno::Reference<uno::XComponentContext> const & xContext) + : m_aMutex() + , m_xCC(xContext) + , m_xChartModel() + , m_xShapeFactory() + , m_xDrawPage() + , m_pDrawModelWrapper() + , m_aListenerContainer( m_aMutex ) + , m_bViewDirty(true) + , m_bInViewUpdate(false) + , m_bViewUpdatePending(false) + , m_bRefreshAddIn(true) + , m_aPageResolution(1000,1000) + , m_bPointsWereSkipped(false) + , m_nScaleXNumerator(1) + , m_nScaleXDenominator(1) + , m_nScaleYNumerator(1) + , m_nScaleYDenominator(1) + , m_bSdrViewIsInEditMode(sal_False) + , m_aResultingDiagramRectangleExcludingAxes(0,0,0,0) +{ +} + +void ChartView::impl_setChartModel( const uno::Reference< frame::XModel >& xChartModel ) +{ + if( m_xChartModel != xChartModel ) + { + m_xChartModel = xChartModel; + m_bViewDirty = true; + } +} + +void SAL_CALL ChartView::initialize( const uno::Sequence< uno::Any >& aArguments ) + throw ( uno::Exception, uno::RuntimeException) +{ + DBG_ASSERT(aArguments.getLength() >= 1,"need 1 argument to initialize the view: xModel"); + if( !(aArguments.getLength() >= 1) ) + return; + + uno::Reference< frame::XModel > xNewChartModel; + if( !(aArguments[0] >>= xNewChartModel) ) + { + DBG_ERROR( "need a Reference to frame::XModel as first parameter for view initialization" ); + } + impl_setChartModel( xNewChartModel ); + + if( !m_pDrawModelWrapper.get() ) + { + // /-- + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + m_pDrawModelWrapper = ::boost::shared_ptr< DrawModelWrapper >( new DrawModelWrapper( m_xCC ) ); + m_xShapeFactory = m_pDrawModelWrapper->getShapeFactory(); + m_xDrawPage = m_pDrawModelWrapper->getMainDrawPage(); + StartListening( m_pDrawModelWrapper->getSdrModel(), sal_False /*bPreventDups*/ ); + // \-- + } +} + +ChartView::~ChartView() +{ + if( m_pDrawModelWrapper.get() ) + { + EndListening( m_pDrawModelWrapper->getSdrModel(), sal_False /*bAllDups*/ ); + ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + m_pDrawModelWrapper.reset(); + } + m_xDrawPage = NULL; + impl_deleteCoordinateSystems(); +} + +void ChartView::impl_deleteCoordinateSystems() +{ + //delete all coordinate systems + ::std::vector< VCoordinateSystem* > aVectorToDeleteObjects; + ::std::swap( aVectorToDeleteObjects, m_aVCooSysList );//#i109770# + ::std::vector< VCoordinateSystem* >::const_iterator aIter = aVectorToDeleteObjects.begin(); + const ::std::vector< VCoordinateSystem* >::const_iterator aEnd = aVectorToDeleteObjects.end(); + for( ; aIter != aEnd; aIter++ ) + { + delete *aIter; + } + aVectorToDeleteObjects.clear(); +} + + +//----------------------------------------------------------------- +// datatransfer::XTransferable +namespace +{ +const rtl::OUString lcl_aGDIMetaFileMIMEType( + RTL_CONSTASCII_USTRINGPARAM("application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"")); +const rtl::OUString lcl_aGDIMetaFileMIMETypeHighContrast( + RTL_CONSTASCII_USTRINGPARAM("application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"")); +} // anonymous namespace + +void ChartView::getMetaFile( const uno::Reference< io::XOutputStream >& xOutStream + , bool bUseHighContrast ) +{ + if( !m_xDrawPage.is() ) + return; + + uno::Reference< lang::XMultiServiceFactory > xFactory( m_xCC->getServiceManager(), uno::UNO_QUERY ); + if( !xFactory.is() ) + return; + + // creating the graphic exporter + uno::Reference< document::XExporter > xExporter( xFactory->createInstance( + C2U("com.sun.star.drawing.GraphicExportFilter")), uno::UNO_QUERY); + uno::Reference< document::XFilter > xFilter( xExporter, uno::UNO_QUERY ); + + if( !xExporter.is() || !xFilter.is() ) + return; + + uno::Sequence< beans::PropertyValue > aProps(3); + aProps[0].Name = C2U("FilterName"); + aProps[0].Value <<= C2U("SVM"); + + aProps[1].Name = C2U("OutputStream"); + aProps[1].Value <<= xOutStream; + + uno::Sequence< beans::PropertyValue > aFilterData(4); + aFilterData[0].Name = C2U("ExportOnlyBackground"); + aFilterData[0].Value <<= sal_False; + aFilterData[1].Name = C2U("HighContrast"); + aFilterData[1].Value <<= bUseHighContrast; + + aFilterData[2].Name = C2U("Version"); + const sal_Int32 nVersion = SOFFICE_FILEFORMAT_50; + aFilterData[2].Value <<= nVersion; + + aFilterData[3].Name = C2U("CurrentPage"); + aFilterData[3].Value <<= uno::Reference< uno::XInterface >( m_xDrawPage, uno::UNO_QUERY ); + + //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% + { + aFilterData.realloc( aFilterData.getLength()+4 ); + aFilterData[4].Name = C2U("ScaleXNumerator"); + aFilterData[4].Value = uno::makeAny( m_nScaleXNumerator ); + aFilterData[5].Name = C2U("ScaleXDenominator"); + aFilterData[5].Value = uno::makeAny( m_nScaleXDenominator ); + aFilterData[6].Name = C2U("ScaleYNumerator"); + aFilterData[6].Value = uno::makeAny( m_nScaleYNumerator ); + aFilterData[7].Name = C2U("ScaleYDenominator"); + aFilterData[7].Value = uno::makeAny( m_nScaleYDenominator ); + } + + aProps[2].Name = C2U("FilterData"); + aProps[2].Value <<= aFilterData; + + xExporter->setSourceDocument( uno::Reference< lang::XComponent >( m_xDrawPage, uno::UNO_QUERY) ); + if( xFilter->filter( aProps ) ) + { + xOutStream->flush(); + xOutStream->closeOutput(); + uno::Reference< io::XSeekable > xSeekable( xOutStream, uno::UNO_QUERY ); + if( xSeekable.is() ) + xSeekable->seek(0); + } +} + +uno::Any SAL_CALL ChartView::getTransferData( const datatransfer::DataFlavor& aFlavor ) + throw (datatransfer::UnsupportedFlavorException, io::IOException, uno::RuntimeException) +{ + bool bHighContrastMetaFile( aFlavor.MimeType.equals(lcl_aGDIMetaFileMIMETypeHighContrast)); + uno::Any aRet; + if( ! (bHighContrastMetaFile || aFlavor.MimeType.equals(lcl_aGDIMetaFileMIMEType)) ) + return aRet; + + update(); + + SvMemoryStream aStream( 1024, 1024 ); + utl::OStreamWrapper* pStreamWrapper = new utl::OStreamWrapper( aStream ); + + uno::Reference< io::XOutputStream > xOutStream( pStreamWrapper ); + uno::Reference< io::XInputStream > xInStream( pStreamWrapper ); + uno::Reference< io::XSeekable > xSeekable( pStreamWrapper ); + + if( xOutStream.is() ) + { + this->getMetaFile( xOutStream, bHighContrastMetaFile ); + + if( xInStream.is() && xSeekable.is() ) + { + xSeekable->seek(0); + sal_Int32 nBytesToRead = xInStream->available(); + uno::Sequence< sal_Int8 > aSeq( nBytesToRead ); + xInStream->readBytes( aSeq, nBytesToRead); + aRet <<= aSeq; + xInStream->closeInput(); + } + } + + return aRet; +} +uno::Sequence< datatransfer::DataFlavor > SAL_CALL ChartView::getTransferDataFlavors() + throw (uno::RuntimeException) +{ + uno::Sequence< datatransfer::DataFlavor > aRet(2); + + aRet[0] = datatransfer::DataFlavor( lcl_aGDIMetaFileMIMEType, + C2U( "GDIMetaFile" ), + ::getCppuType( (const uno::Sequence< sal_Int8 >*) NULL ) ); + aRet[1] = datatransfer::DataFlavor( lcl_aGDIMetaFileMIMETypeHighContrast, + C2U( "GDIMetaFile" ), + ::getCppuType( (const uno::Sequence< sal_Int8 >*) NULL ) ); + + return aRet; +} +::sal_Bool SAL_CALL ChartView::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor ) + throw (uno::RuntimeException) +{ + return ( aFlavor.MimeType.equals(lcl_aGDIMetaFileMIMEType) || + aFlavor.MimeType.equals(lcl_aGDIMetaFileMIMETypeHighContrast) ); +} + +//----------------------------------------------------------------- +// ____ XUnoTunnel ___ +::sal_Int64 SAL_CALL ChartView::getSomething( const uno::Sequence< ::sal_Int8 >& aIdentifier ) + throw( uno::RuntimeException) +{ + if( aIdentifier.getLength() == 16 && 0 == rtl_compareMemory( ExplicitValueProvider::getUnoTunnelId().getConstArray(), + aIdentifier.getConstArray(), 16 ) ) + { + ExplicitValueProvider* pProvider = this; + return reinterpret_cast<sal_Int64>(pProvider); + } + return 0; +} + +//----------------------------------------------------------------- +// lang::XServiceInfo + +APPHELPER_XSERVICEINFO_IMPL(ChartView,CHART_VIEW_SERVICE_IMPLEMENTATION_NAME) + + uno::Sequence< rtl::OUString > ChartView +::getSupportedServiceNames_Static() +{ + uno::Sequence< rtl::OUString > aSNS( 1 ); + aSNS.getArray()[ 0 ] = CHART_VIEW_SERVICE_NAME; + return aSNS; +} + +//----------------------------------------------------------------- +//----------------------------------------------------------------- + +::basegfx::B3DHomMatrix createTransformationSceneToScreen( + const ::basegfx::B2IRectangle& rDiagramRectangleWithoutAxes ) +{ + ::basegfx::B3DHomMatrix aM; + aM.scale(double(rDiagramRectangleWithoutAxes.getWidth())/FIXED_SIZE_FOR_3D_CHART_VOLUME + , -double(rDiagramRectangleWithoutAxes.getHeight())/FIXED_SIZE_FOR_3D_CHART_VOLUME, 1.0 ); + aM.translate(double(rDiagramRectangleWithoutAxes.getMinX()) + , double(rDiagramRectangleWithoutAxes.getMinY()+rDiagramRectangleWithoutAxes.getHeight()-1), 0); + return aM; +} + +VCoordinateSystem* findInCooSysList( const std::vector< VCoordinateSystem* >& rVCooSysList + , const uno::Reference< XCoordinateSystem >& xCooSys ) +{ + for( size_t nC=0; nC < rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = rVCooSysList[nC]; + if(pVCooSys->getModel()==xCooSys) + return pVCooSys; + } + return NULL; +} + +VCoordinateSystem* addCooSysToList( std::vector< VCoordinateSystem* >& rVCooSysList + , const uno::Reference< XCoordinateSystem >& xCooSys + , const uno::Reference< frame::XModel >& xChartModel ) +{ + VCoordinateSystem* pVCooSys = findInCooSysList( rVCooSysList, xCooSys ); + if( !pVCooSys ) + { + pVCooSys = VCoordinateSystem::createCoordinateSystem(xCooSys ); + if(pVCooSys) + { + rtl::OUString aCooSysParticle( ObjectIdentifier::createParticleForCoordinateSystem( xCooSys, xChartModel ) ); + pVCooSys->setParticle(aCooSysParticle); + + pVCooSys->setExplicitCategoriesProvider( new ExplicitCategoriesProvider(xCooSys,xChartModel) ); + + rVCooSysList.push_back( pVCooSys ); + } + } + return pVCooSys; +} + +VCoordinateSystem* lcl_getCooSysForPlotter( const std::vector< VCoordinateSystem* >& rVCooSysList, MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ) +{ + if(!pMinimumAndMaximumSupplier) + return 0; + for( size_t nC=0; nC < rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = rVCooSysList[nC]; + if(pVCooSys->hasMinimumAndMaximumSupplier( pMinimumAndMaximumSupplier )) + return pVCooSys; + } + return 0; +} + +typedef std::pair< sal_Int32, sal_Int32 > tFullAxisIndex; //first index is the dimension, second index is the axis index that indicates wether this is a main or secondary axis +typedef std::pair< VCoordinateSystem* , tFullAxisIndex > tFullCoordinateSystem; +typedef std::map< VCoordinateSystem*, tFullAxisIndex > tCoordinateSystemMap; + +struct AxisUsage +{ + AxisUsage(); + ~AxisUsage(); + + void addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + ::std::vector< VCoordinateSystem* > getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + sal_Int32 getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex ); + //tFullAxisIndex getDimensionAndIndexForCooSys( VCoordinateSystem* pCooSys ); + + ScaleAutomatism aScaleAutomatism; + +private: + tCoordinateSystemMap aCoordinateSystems; + std::map< sal_Int32, sal_Int32 > aMaxIndexPerDimension; +}; + +AxisUsage::AxisUsage() + : aScaleAutomatism(AxisHelper::createDefaultScale(),Date()) +{ +} + +AxisUsage::~AxisUsage() +{ + aCoordinateSystems.clear(); +} + +/* +tFullScaleIndex AxisUsage::getDimensionAndIndexForCooSys( VCoordinateSystem* pCooSys ) +{ + tFullScaleIndex aRet(0,0); + + tCoordinateSystemMap::const_iterator aFound( aCoordinateSystems.find(pCooSys) ); + if(aFound!=aCoordinateSystems.end()) + aRet = aFound->second; + + return aRet; +} +*/ + +void AxisUsage::addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + if(!pCooSys) + return; + + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + tCoordinateSystemMap::const_iterator aFound( aCoordinateSystems.find(pCooSys) ); + + //use one scale only once for each coordinate system + //main axis are preferred over secondary axis + //value scales are preferred + if(aFound!=aCoordinateSystems.end()) + { + sal_Int32 nFoundAxisIndex = aFound->second.second; + if( nFoundAxisIndex < nAxisIndex ) + return; + sal_Int32 nFoundDimension = aFound->second.first; + if( nFoundDimension ==1 ) + return; + if( nFoundDimension < nDimensionIndex ) + return; + } + aCoordinateSystems[pCooSys] = aFullAxisIndex; + + //set maximum scale index + std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex); + if( aIter != aMaxIndexPerDimension.end() ) + { + sal_Int32 nCurrentMaxIndex = aIter->second; + if( nCurrentMaxIndex < nAxisIndex ) + aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex; + } + else + aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex; +} +::std::vector< VCoordinateSystem* > AxisUsage::getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + ::std::vector< VCoordinateSystem* > aRet; + + tCoordinateSystemMap::const_iterator aIter; + for( aIter = aCoordinateSystems.begin(); aIter!=aCoordinateSystems.end();++aIter ) + { + if( aIter->second.first != nDimensionIndex ) + continue; + if( aIter->second.second != nAxisIndex ) + continue; + aRet.push_back( aIter->first ); + } + + return aRet; +} +sal_Int32 AxisUsage::getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex ) +{ + sal_Int32 nRet = -1; + std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex); + if( aIter != aMaxIndexPerDimension.end() ) + nRet = aIter->second; + return nRet; +} + +//----------------------------------------------------- + +class SeriesPlotterContainer +{ +public: + SeriesPlotterContainer( std::vector< VCoordinateSystem* >& rVCooSysList ); + ~SeriesPlotterContainer(); + + void initializeCooSysAndSeriesPlotter( const uno::Reference< frame::XModel >& xChartModel ); + void initAxisUsageList(const Date& rNullDate); + void doAutoScaling( const uno::Reference< frame::XModel >& xChartModel ); + void updateScalesAndIncrementsOnAxes(); + void setScalesFromCooSysToPlotter(); + void setNumberFormatsFromAxes(); + drawing::Direction3D getPreferredAspectRatio(); + + std::vector< VSeriesPlotter* >& getSeriesPlotterList() { return m_aSeriesPlotterList; } + std::vector< VCoordinateSystem* >& getCooSysList() { return m_rVCooSysList; } + std::vector< LegendEntryProvider* > getLegendEntryProviderList(); + + void AdaptScaleOfYAxisWithoutAttachedSeries( const uno::Reference< frame::XModel >& xChartModel ); + +private: + std::vector< VSeriesPlotter* > m_aSeriesPlotterList; + std::vector< VCoordinateSystem* >& m_rVCooSysList; + ::std::map< uno::Reference< XAxis >, AxisUsage > m_aAxisUsageList; + sal_Int32 m_nMaxAxisIndex; + bool m_bChartTypeUsesShiftedCategoryPositionPerDefault; + sal_Int32 m_nDefaultDateNumberFormat; +}; + +SeriesPlotterContainer::SeriesPlotterContainer( std::vector< VCoordinateSystem* >& rVCooSysList ) + : m_rVCooSysList( rVCooSysList ) + , m_nMaxAxisIndex(0) + , m_bChartTypeUsesShiftedCategoryPositionPerDefault(false) + , m_nDefaultDateNumberFormat(0) +{ +} + +SeriesPlotterContainer::~SeriesPlotterContainer() +{ + // - remove plotter from coordinatesystems + for( size_t nC=0; nC < m_rVCooSysList.size(); nC++) + m_rVCooSysList[nC]->clearMinimumAndMaximumSupplierList(); + // - delete all plotter + ::std::vector< VSeriesPlotter* >::const_iterator aPlotterIter = m_aSeriesPlotterList.begin(); + const ::std::vector< VSeriesPlotter* >::const_iterator aPlotterEnd = m_aSeriesPlotterList.end(); + for( aPlotterIter = m_aSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + delete *aPlotterIter; + m_aSeriesPlotterList.clear(); +} + +std::vector< LegendEntryProvider* > SeriesPlotterContainer::getLegendEntryProviderList() +{ + std::vector< LegendEntryProvider* > aRet( m_aSeriesPlotterList.size() ); + ::std::vector< VSeriesPlotter* >::const_iterator aPlotterIter = m_aSeriesPlotterList.begin(); + const ::std::vector< VSeriesPlotter* >::const_iterator aPlotterEnd = m_aSeriesPlotterList.end(); + sal_Int32 nN = 0; + for( aPlotterIter = m_aSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; ++aPlotterIter, nN++ ) + aRet[nN] = *aPlotterIter; + return aRet; +} + +void SeriesPlotterContainer::initializeCooSysAndSeriesPlotter( + const uno::Reference< frame::XModel >& xChartModel ) +{ + //------------ get model series from model + sal_Int32 nDiagramIndex = 0;//todo if more than one diagam is supported + uno::Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + if( !xDiagram.is()) + return; + + uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( xChartModel, uno::UNO_QUERY ); + uno::Reference< chart2::XChartDocument > xChartDoc( xChartModel, uno::UNO_QUERY ); + if( xChartDoc.is() && xChartDoc->hasInternalDataProvider() + && DiagramHelper::isSupportingDateAxis( xDiagram ) ) + m_nDefaultDateNumberFormat=DiagramHelper::getDateNumberFormat( xNumberFormatsSupplier ); + + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + if(!nDimensionCount) + { + //@todo handle mixed dimension + nDimensionCount = 2; + } + + sal_Bool bSortByXValues = sal_False; + sal_Bool bConnectBars = sal_False; + sal_Bool bGroupBarsPerAxis = sal_True; + sal_Bool bIncludeHiddenCells = sal_True; + sal_Int32 nStartingAngle = 90; + try + { + uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY_THROW ); + xDiaProp->getPropertyValue( C2U( "SortByXValues" ) ) >>= bSortByXValues; + xDiaProp->getPropertyValue( C2U( "ConnectBars" ) ) >>= bConnectBars; + xDiaProp->getPropertyValue( C2U( "GroupBarsPerAxis" ) ) >>= bGroupBarsPerAxis; + xDiaProp->getPropertyValue( C2U( "IncludeHiddenCells" ) ) >>= bIncludeHiddenCells; + xDiaProp->getPropertyValue( C2U( "StartingAngle" ) ) >>= nStartingAngle; + } + catch( const uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + + //--------------------------------------------------------------------- + //prepare for autoscaling and shape creation + // - create plotter for charttypes (for each first scale group at each plotter, as they are independent) + // - add series to plotter (thus each charttype can provide minimum and maximum values for autoscaling) + // - add plotter to coordinate systems + + //iterate through all coordinate systems + uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY ); + OSL_ASSERT( xCooSysContainer.is()); + if( !xCooSysContainer.is()) + return; + uno::Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme()); + uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() ); + sal_Int32 nGlobalSeriesIndex = 0;//for automatic symbols + for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS ) + { + uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] ); + VCoordinateSystem* pVCooSys = addCooSysToList(m_rVCooSysList,xCooSys,xChartModel); + + //iterate through all chart types in the current coordinate system + uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY ); + OSL_ASSERT( xChartTypeContainer.is()); + if( !xChartTypeContainer.is() ) + continue; + uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() ); + for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT ) + { + uno::Reference< XChartType > xChartType( aChartTypeList[nT] ); + + if(nT==0) + m_bChartTypeUsesShiftedCategoryPositionPerDefault = ChartTypeHelper::shiftCategoryPosAtXAxisPerDefault( xChartType ); + + bool bExcludingPositioning = DiagramPositioningMode_EXCLUDING == DiagramHelper::getDiagramPositioningMode( xDiagram ); + VSeriesPlotter* pPlotter = VSeriesPlotter::createSeriesPlotter( xChartType, nDimensionCount, bExcludingPositioning ); + if( !pPlotter ) + continue; + m_aSeriesPlotterList.push_back( pPlotter ); + pPlotter->setNumberFormatsSupplier( xNumberFormatsSupplier ); + pPlotter->setColorScheme( xColorScheme ); + pPlotter->setExplicitCategoriesProvider( pVCooSys->getExplicitCategoriesProvider() ); + sal_Int32 nMissingValueTreatment = DiagramHelper::getCorrectedMissingValueTreatment( xDiagram, xChartType ); + + if(pVCooSys) + pVCooSys->addMinimumAndMaximumSupplier(pPlotter); + + //------------ add series to plotter and thus prepare him for providing minimum and maximum values + uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY ); + OSL_ASSERT( xDataSeriesContainer.is()); + if( !xDataSeriesContainer.is() ) + continue; + sal_Int32 zSlot=-1; + sal_Int32 xSlot=-1; + sal_Int32 ySlot=-1; + uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() ); + for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS ) + { + uno::Reference< XDataSeries > xDataSeries( aSeriesList[nS], uno::UNO_QUERY ); + if(!xDataSeries.is()) + continue; + if( !bIncludeHiddenCells && !DataSeriesHelper::hasUnhiddenData(xDataSeries) ) + continue; + + VDataSeries* pSeries = new VDataSeries( xDataSeries ); + + pSeries->setGlobalSeriesIndex(nGlobalSeriesIndex); + nGlobalSeriesIndex++; + + if( bSortByXValues ) + pSeries->doSortByXValues(); + + pSeries->setConnectBars( bConnectBars ); + pSeries->setGroupBarsPerAxis( bGroupBarsPerAxis ); + pSeries->setStartingAngle( nStartingAngle ); + + pSeries->setMissingValueTreatment( nMissingValueTreatment ); + + rtl::OUString aSeriesParticle( ObjectIdentifier::createParticleForSeries( nDiagramIndex, nCS, nT, nS ) ); + pSeries->setParticle(aSeriesParticle); + + OUString aRole( ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( xChartType ) ); + pSeries->setRoleOfSequenceForDataLabelNumberFormatDetection(aRole); + + //ignore secondary axis for charttypes that do not suppoert them + if( pSeries->getAttachedAxisIndex() != MAIN_AXIS_INDEX && + !ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount, 1 ) ) + { + pSeries->setAttachedAxisIndex(MAIN_AXIS_INDEX); + } + + StackingDirection eDirection = pSeries->getStackingDirection(); + switch(eDirection) + { + case StackingDirection_NO_STACKING: + xSlot++; ySlot=-1; + if(zSlot<0) + zSlot=0; + break; + case StackingDirection_Y_STACKING: + ySlot++; + if(xSlot<0) + xSlot=0; + if(zSlot<0) + zSlot=0; + break; + case StackingDirection_Z_STACKING: + zSlot++; xSlot=-1; ySlot=-1; + break; + default: + // UNO enums have one additional auto-generated case + break; + } + pPlotter->addSeries( pSeries, zSlot, xSlot, ySlot ); + } + } + } + + //transport seriesnames to the coordinatesystems if needed + if( m_aSeriesPlotterList.size() ) + { + uno::Sequence< rtl::OUString > aSeriesNames; + bool bSeriesNamesInitialized = false; + for( size_t nC=0; nC < m_rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = m_rVCooSysList[nC]; + if(!pVCooSys) + continue; + if( pVCooSys->needSeriesNamesForAxis() ) + { + if(!bSeriesNamesInitialized) + { + VSeriesPlotter* pSeriesPlotter = m_aSeriesPlotterList[0]; + if( pSeriesPlotter ) + aSeriesNames = pSeriesPlotter->getSeriesNames(); + bSeriesNamesInitialized = true; + } + pVCooSys->setSeriesNamesForAxis( aSeriesNames ); + } + } + } +} + +void SeriesPlotterContainer::initAxisUsageList(const Date& rNullDate) +{ + m_aAxisUsageList.clear(); + size_t nC; + for( nC=0; nC < m_rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = m_rVCooSysList[nC]; + for(sal_Int32 nDimensionIndex=0; nDimensionIndex<3; nDimensionIndex++) + { + uno::Reference< XCoordinateSystem > xCooSys = pVCooSys->getModel(); + sal_Int32 nDimensionCount = xCooSys->getDimension(); + if( nDimensionIndex >= nDimensionCount ) + continue; + bool bChartTypeAllowsDateAxis = ChartTypeHelper::isSupportingDateAxis( AxisHelper::getChartTypeByIndex( xCooSys, 0 ), nDimensionCount, nDimensionIndex ); + const sal_Int32 nMaximumAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex) + { + uno::Reference< XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ) ); + OSL_ASSERT( xAxis.is()); + if( xAxis.is()) + { + if(m_aAxisUsageList.find(xAxis)==m_aAxisUsageList.end()) + { + chart2::ScaleData aSourceScale = xAxis->getScaleData(); + ExplicitCategoriesProvider* pExplicitCategoriesProvider = pVCooSys->getExplicitCategoriesProvider(); + if( nDimensionIndex==0 ) + AxisHelper::checkDateAxis( aSourceScale, pExplicitCategoriesProvider, bChartTypeAllowsDateAxis ); + if( (aSourceScale.AxisType == AxisType::CATEGORY && m_bChartTypeUsesShiftedCategoryPositionPerDefault) + || (aSourceScale.AxisType==AxisType::CATEGORY && pExplicitCategoriesProvider && pExplicitCategoriesProvider->hasComplexCategories() ) + || aSourceScale.AxisType == AxisType::DATE + || aSourceScale.AxisType == AxisType::SERIES ) + aSourceScale.ShiftedCategoryPosition = true; + else + aSourceScale.ShiftedCategoryPosition = false; + m_aAxisUsageList[xAxis].aScaleAutomatism = ScaleAutomatism(aSourceScale,rNullDate); + } + AxisUsage& rAxisUsage = m_aAxisUsageList[xAxis]; + rAxisUsage.addCoordinateSystem(pVCooSys,nDimensionIndex,nAxisIndex); + } + } + } + } + + ::std::map< uno::Reference< XAxis >, AxisUsage >::iterator aAxisIter = m_aAxisUsageList.begin(); + const ::std::map< uno::Reference< XAxis >, AxisUsage >::const_iterator aAxisEndIter = m_aAxisUsageList.end(); + + //init m_nMaxAxisIndex + m_nMaxAxisIndex = 0; + for(sal_Int32 nDimensionIndex=0; nDimensionIndex<3; nDimensionIndex++) + { + for( aAxisIter = m_aAxisUsageList.begin(); aAxisIter != aAxisEndIter; aAxisIter++ ) + { + sal_Int32 nLocalMax = aAxisIter->second.getMaxAxisIndexForDimension( nDimensionIndex ); + if( m_nMaxAxisIndex < nLocalMax ) + m_nMaxAxisIndex = nLocalMax; + } + } +} + +void SeriesPlotterContainer::setScalesFromCooSysToPlotter() +{ + //set scales to plotter to enable them to provide the preferred scene AspectRatio + ::std::vector< VSeriesPlotter* >::const_iterator aPlotterIter = m_aSeriesPlotterList.begin(); + const ::std::vector< VSeriesPlotter* >::const_iterator aPlotterEnd = m_aSeriesPlotterList.end(); + for( aPlotterIter = m_aSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + { + VSeriesPlotter* pSeriesPlotter = *aPlotterIter; + VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter ); + if(pVCooSys) + { + pSeriesPlotter->setScales( pVCooSys->getExplicitScales(0,0), pVCooSys->getPropertySwapXAndYAxis() ); + sal_Int32 nMaxAxisIndex = pVCooSys->getMaximumAxisIndexByDimension(1);//only additional value axis are relevant for series plotter + for( sal_Int32 nI=1; nI<=nMaxAxisIndex; nI++ ) + pSeriesPlotter->addSecondaryValueScale( pVCooSys->getExplicitScale(1,nI), nI ); + } + } +} + +void SeriesPlotterContainer::setNumberFormatsFromAxes() +{ + //set numberfarmats to plotter to enable them to display the data labels in the numberfromat of teh axis + + ::std::vector< VSeriesPlotter* >::const_iterator aPlotterIter = m_aSeriesPlotterList.begin(); + const ::std::vector< VSeriesPlotter* >::const_iterator aPlotterEnd = m_aSeriesPlotterList.end(); + for( aPlotterIter = m_aSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + { + VSeriesPlotter* pSeriesPlotter = *aPlotterIter; + VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter ); + if(pVCooSys) + { + AxesNumberFormats aAxesNumberFormats; + uno::Reference< XCoordinateSystem > xCooSys = pVCooSys->getModel(); + sal_Int32 nDimensionCount = xCooSys->getDimension(); + for(sal_Int32 nDimensionIndex=0; nDimensionIndex<nDimensionCount; ++nDimensionIndex) + { + const sal_Int32 nMaximumAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex) + { + try + { + Reference< beans::XPropertySet > xAxisProp( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ), uno::UNO_QUERY ); + if( xAxisProp.is()) + { + sal_Int32 nNumberFormatKey(0); + if( xAxisProp->getPropertyValue( C2U( "NumberFormat" ) ) >>= nNumberFormatKey ) + { + aAxesNumberFormats.setFormat( nNumberFormatKey, nDimensionIndex, nAxisIndex ); + } + else if( nDimensionIndex==0 ) + { + //provide a default date format for date axis with own data + aAxesNumberFormats.setFormat( m_nDefaultDateNumberFormat, nDimensionIndex, nAxisIndex ); + } + } + } + catch( lang::IndexOutOfBoundsException& e ) + { + ASSERT_EXCEPTION( e ); + } + } + } + pSeriesPlotter->setAxesNumberFormats( aAxesNumberFormats ); + } + } +} + +void SeriesPlotterContainer::updateScalesAndIncrementsOnAxes() +{ + for( size_t nC=0; nC < m_rVCooSysList.size(); nC++) + m_rVCooSysList[nC]->updateScalesAndIncrementsOnAxes(); +} + +void SeriesPlotterContainer::doAutoScaling( const uno::Reference< frame::XModel >& xChartModel ) +{ + //precondition: need a initialized m_aSeriesPlotterList + //precondition: need a initialized m_aAxisUsageList + + ::std::map< uno::Reference< XAxis >, AxisUsage >::iterator aAxisIter = m_aAxisUsageList.begin(); + const ::std::map< uno::Reference< XAxis >, AxisUsage >::const_iterator aAxisEndIter = m_aAxisUsageList.end(); + + //iterate over the main scales first than secondary axis + size_t nC; + sal_Int32 nAxisIndex=0; + for( nAxisIndex=0; nAxisIndex<=m_nMaxAxisIndex; nAxisIndex++ ) + { + + // - first do autoscale for all x and z scales (because they are treated independent) + for( aAxisIter = m_aAxisUsageList.begin(); aAxisIter != aAxisEndIter; aAxisIter++ ) + { + AxisUsage& rAxisUsage = (*aAxisIter).second; + ::std::vector< VCoordinateSystem* > aVCooSysList_X = rAxisUsage.getCoordinateSystems(0,nAxisIndex); + ::std::vector< VCoordinateSystem* > aVCooSysList_Z = rAxisUsage.getCoordinateSystems(2,nAxisIndex); + + for( nC=0; nC < aVCooSysList_X.size(); nC++) + aVCooSysList_X[nC]->prepareScaleAutomatismForDimensionAndIndex(rAxisUsage.aScaleAutomatism,0,nAxisIndex); + for( nC=0; nC < aVCooSysList_Z.size(); nC++) + aVCooSysList_Z[nC]->prepareScaleAutomatismForDimensionAndIndex(rAxisUsage.aScaleAutomatism,2,nAxisIndex); + + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + rAxisUsage.aScaleAutomatism.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement ); + + for( nC=0; nC < aVCooSysList_X.size(); nC++) + aVCooSysList_X[nC]->setExplicitScaleAndIncrement( 0, nAxisIndex, aExplicitScale, aExplicitIncrement ); + for( nC=0; nC < aVCooSysList_Z.size(); nC++) + aVCooSysList_Z[nC]->setExplicitScaleAndIncrement( 2, nAxisIndex, aExplicitScale, aExplicitIncrement ); + } + + // - second do autoscale for the dependent y scales (the coordinate systems are prepared with x and z scales already ) + for( aAxisIter = m_aAxisUsageList.begin(); aAxisIter != aAxisEndIter; aAxisIter++ ) + { + AxisUsage& rAxisUsage = (*aAxisIter).second; + ::std::vector< VCoordinateSystem* > aVCooSysList_X = rAxisUsage.getCoordinateSystems(0,nAxisIndex); + ::std::vector< VCoordinateSystem* > aVCooSysList_Y = rAxisUsage.getCoordinateSystems(1,nAxisIndex); + ::std::vector< VCoordinateSystem* > aVCooSysList_Z = rAxisUsage.getCoordinateSystems(2,nAxisIndex); + + if(!aVCooSysList_Y.size()) + continue; + + for( nC=0; nC < aVCooSysList_Y.size(); nC++) + aVCooSysList_Y[nC]->prepareScaleAutomatismForDimensionAndIndex(rAxisUsage.aScaleAutomatism,1,nAxisIndex); + + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + rAxisUsage.aScaleAutomatism.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement ); + + for( nC=0; nC < aVCooSysList_X.size(); nC++) + aVCooSysList_X[nC]->setExplicitScaleAndIncrement( 0, nAxisIndex, aExplicitScale, aExplicitIncrement ); + for( nC=0; nC < aVCooSysList_Y.size(); nC++) + aVCooSysList_Y[nC]->setExplicitScaleAndIncrement( 1, nAxisIndex, aExplicitScale, aExplicitIncrement ); + for( nC=0; nC < aVCooSysList_Z.size(); nC++) + aVCooSysList_Z[nC]->setExplicitScaleAndIncrement( 2, nAxisIndex, aExplicitScale, aExplicitIncrement ); + } + } + AdaptScaleOfYAxisWithoutAttachedSeries( xChartModel ); +} + +void SeriesPlotterContainer::AdaptScaleOfYAxisWithoutAttachedSeries( const uno::Reference< frame::XModel >& xChartModel ) +{ + //issue #i80518# + + ::std::map< uno::Reference< XAxis >, AxisUsage >::iterator aAxisIter = m_aAxisUsageList.begin(); + const ::std::map< uno::Reference< XAxis >, AxisUsage >::const_iterator aAxisEndIter = m_aAxisUsageList.end(); + + for( sal_Int32 nAxisIndex=0; nAxisIndex<=m_nMaxAxisIndex; nAxisIndex++ ) + { + for( aAxisIter = m_aAxisUsageList.begin(); aAxisIter != aAxisEndIter; aAxisIter++ ) + { + AxisUsage& rAxisUsage = (*aAxisIter).second; + ::std::vector< VCoordinateSystem* > aVCooSysList_Y = rAxisUsage.getCoordinateSystems( 1, nAxisIndex ); + if( !aVCooSysList_Y.size() ) + continue; + + uno::Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + if( xDiagram.is() ) + { + bool bSeriesAttachedToThisAxis = false; + sal_Int32 nAttachedAxisIndex = -1; + { + ::std::vector< Reference< XDataSeries > > aSeriesVector( DiagramHelper::getDataSeriesFromDiagram( xDiagram ) ); + ::std::vector< Reference< XDataSeries > >::const_iterator aIter = aSeriesVector.begin(); + for( ; aIter != aSeriesVector.end(); aIter++ ) + { + sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex( *aIter ); + if( nAxisIndex == nCurrentIndex ) + { + bSeriesAttachedToThisAxis = true; + break; + } + else if( nAttachedAxisIndex<0 || nAttachedAxisIndex>nCurrentIndex ) + nAttachedAxisIndex=nCurrentIndex; + } + } + + if( !bSeriesAttachedToThisAxis && nAttachedAxisIndex >= 0 ) + { + for( size_t nC = 0; nC < aVCooSysList_Y.size(); ++nC ) + { + aVCooSysList_Y[nC]->prepareScaleAutomatismForDimensionAndIndex( rAxisUsage.aScaleAutomatism, 1, nAttachedAxisIndex ); + + ExplicitScaleData aExplicitScaleSource = aVCooSysList_Y[nC]->getExplicitScale( 1,nAttachedAxisIndex ); + ExplicitIncrementData aExplicitIncrementSource = aVCooSysList_Y[nC]->getExplicitIncrement( 1,nAttachedAxisIndex ); + + ExplicitScaleData aExplicitScaleDest = aVCooSysList_Y[nC]->getExplicitScale( 1,nAxisIndex );; + ExplicitIncrementData aExplicitIncrementDest = aVCooSysList_Y[nC]->getExplicitIncrement( 1,nAxisIndex );; + + aExplicitScaleDest.Orientation = aExplicitScaleSource.Orientation; + aExplicitScaleDest.Scaling = aExplicitScaleSource.Scaling; + aExplicitScaleDest.AxisType = aExplicitScaleSource.AxisType; + + aExplicitIncrementDest.BaseValue = aExplicitIncrementSource.BaseValue; + + ScaleData aScale( rAxisUsage.aScaleAutomatism.getScale() ); + if( !aScale.Minimum.hasValue() ) + { + bool bNewMinOK = true; + double fMax=0.0; + if( aScale.Maximum >>= fMax ) + bNewMinOK = (aExplicitScaleSource.Minimum <= fMax); + if( bNewMinOK ) + aExplicitScaleDest.Minimum = aExplicitScaleSource.Minimum; + } + else + aExplicitIncrementDest.BaseValue = aExplicitScaleDest.Minimum; + + if( !aScale.Maximum.hasValue() ) + { + bool bNewMaxOK = true; + double fMin=0.0; + if( aScale.Minimum >>= fMin ) + bNewMaxOK = (fMin <= aExplicitScaleSource.Maximum); + if( bNewMaxOK ) + aExplicitScaleDest.Maximum = aExplicitScaleSource.Maximum; + } + if( !aScale.Origin.hasValue() ) + aExplicitScaleDest.Origin = aExplicitScaleSource.Origin; + + if( !aScale.IncrementData.Distance.hasValue() ) + aExplicitIncrementDest.Distance = aExplicitIncrementSource.Distance; + + bool bAutoMinorInterval = true; + if( aScale.IncrementData.SubIncrements.getLength() ) + bAutoMinorInterval = !( aScale.IncrementData.SubIncrements[0].IntervalCount.hasValue() ); + if( bAutoMinorInterval ) + { + if( !aExplicitIncrementDest.SubIncrements.empty() && !aExplicitIncrementSource.SubIncrements.empty() ) + aExplicitIncrementDest.SubIncrements[0].IntervalCount = + aExplicitIncrementSource.SubIncrements[0].IntervalCount; + } + + aVCooSysList_Y[nC]->setExplicitScaleAndIncrement( 1, nAxisIndex, aExplicitScaleDest, aExplicitIncrementDest ); + } + } + } + } + } + + if( AxisHelper::isAxisPositioningEnabled() ) + { + //correct origin for y main axis (the origin is where the other main axis crosses) + sal_Int32 nAxisIndex=0; + sal_Int32 nDimensionIndex=1; + for( aAxisIter = m_aAxisUsageList.begin(); aAxisIter != aAxisEndIter; aAxisIter++ ) + { + AxisUsage& rAxisUsage = (*aAxisIter).second; + ::std::vector< VCoordinateSystem* > aVCooSysList = rAxisUsage.getCoordinateSystems(nDimensionIndex,nAxisIndex); + size_t nC; + for( nC=0; nC < aVCooSysList.size(); nC++) + { + ExplicitScaleData aExplicitScale( aVCooSysList[nC]->getExplicitScale( nDimensionIndex, nAxisIndex ) ); + ExplicitIncrementData aExplicitIncrement( aVCooSysList[nC]->getExplicitIncrement( nDimensionIndex, nAxisIndex ) ); + + Reference< chart2::XCoordinateSystem > xCooSys( aVCooSysList[nC]->getModel() ); + Reference< XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ) ); + Reference< beans::XPropertySet > xCrossingMainAxis( AxisHelper::getCrossingMainAxis( xAxis, xCooSys ), uno::UNO_QUERY ); + + ::com::sun::star::chart::ChartAxisPosition eCrossingMainAxisPos( ::com::sun::star::chart::ChartAxisPosition_ZERO ); + if( xCrossingMainAxis.is() ) + { + xCrossingMainAxis->getPropertyValue(C2U( "CrossoverPosition" )) >>= eCrossingMainAxisPos; + if( ::com::sun::star::chart::ChartAxisPosition_VALUE == eCrossingMainAxisPos ) + { + double fValue = 0.0; + xCrossingMainAxis->getPropertyValue(C2U( "CrossoverValue" )) >>= fValue; + aExplicitScale.Origin = fValue; + } + else if( ::com::sun::star::chart::ChartAxisPosition_ZERO == eCrossingMainAxisPos ) + aExplicitScale.Origin = 0.0; + else if( ::com::sun::star::chart::ChartAxisPosition_START == eCrossingMainAxisPos ) + aExplicitScale.Origin = aExplicitScale.Minimum; + else if( ::com::sun::star::chart::ChartAxisPosition_END == eCrossingMainAxisPos ) + aExplicitScale.Origin = aExplicitScale.Maximum; + } + + aVCooSysList[nC]->setExplicitScaleAndIncrement( nDimensionIndex, nAxisIndex, aExplicitScale, aExplicitIncrement ); + } + } + } +} + +drawing::Direction3D SeriesPlotterContainer::getPreferredAspectRatio() +{ + drawing::Direction3D aPreferredAspectRatio(1.0,1.0,1.0); + + sal_Int32 nPlotterCount=0; + //get a list of all preferred aspect ratios and combine them + //first with special demands wins (less or equal zero <-> arbitrary) + double fx, fy, fz; + fx = fy = fz = -1.0; + ::std::vector< VSeriesPlotter* >::const_iterator aPlotterIter = m_aSeriesPlotterList.begin(); + const ::std::vector< VSeriesPlotter* >::const_iterator aPlotterEnd = m_aSeriesPlotterList.end(); + for( aPlotterIter = m_aSeriesPlotterList.begin(), nPlotterCount=0 + ; aPlotterIter != aPlotterEnd; aPlotterIter++, nPlotterCount++ ) + { + drawing::Direction3D aSingleRatio( (*aPlotterIter)->getPreferredDiagramAspectRatio() ); + if( fx<0 && aSingleRatio.DirectionX>0 ) + fx = aSingleRatio.DirectionX; + + if( fy<0 && aSingleRatio.DirectionY>0 ) + { + if( fx>0 && aSingleRatio.DirectionX>0 ) + fy = fx*aSingleRatio.DirectionY/aSingleRatio.DirectionX; + else if( fz>0 && aSingleRatio.DirectionZ>0 ) + fy = fz*aSingleRatio.DirectionY/aSingleRatio.DirectionZ; + else + fy = aSingleRatio.DirectionY; + } + + if( fz<0 && aSingleRatio.DirectionZ>0 ) + { + if( fx>0 && aSingleRatio.DirectionX>0 ) + fz = fx*aSingleRatio.DirectionZ/aSingleRatio.DirectionX; + else if( fy>0 && aSingleRatio.DirectionY>0 ) + fz = fy*aSingleRatio.DirectionZ/aSingleRatio.DirectionY; + else + fz = aSingleRatio.DirectionZ; + } + + if( fx>0 && fy>0 && fz>0 ) + break; + } + aPreferredAspectRatio = drawing::Direction3D(fx, fy, fz); + return aPreferredAspectRatio; +} + +//----------------------------------------------------- + +namespace +{ + +bool lcl_IsPieOrDonut( const uno::Reference< XDiagram >& xDiagram ) +{ + //special treatment for pie charts + //the size is checked after complete creation to get the datalabels into the given space + + //todo: this is just a workaround at the moment for pie and donut labels + return DiagramHelper::isPieOrDonutChart( xDiagram ); +} + +void lcl_setDefaultWritingMode( ::boost::shared_ptr< DrawModelWrapper > pDrawModelWrapper, const Reference< frame::XModel >& xChartModel ) +{ + //get writing mode from parent document: + if( SvtLanguageOptions().IsCTLFontEnabled() ) + { + try + { + uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY ); + sal_Int16 nWritingMode=-1; + if ( xChild.is() ) + { + uno::Reference< beans::XPropertySet > xParentProps( xChild->getParent(), uno::UNO_QUERY ); + uno::Reference< style::XStyleFamiliesSupplier > xStyleFamiliesSupplier( xParentProps, uno::UNO_QUERY ); + if( xStyleFamiliesSupplier.is() ) + { + uno::Reference< container::XNameAccess > xStylesFamilies( xStyleFamiliesSupplier->getStyleFamilies() ); + if( xStylesFamilies.is() ) + { + if( !xStylesFamilies->hasByName( C2U("PageStyles") ) ) + { + //draw/impress is parent document + uno::Reference< lang::XMultiServiceFactory > xFatcory( xParentProps, uno::UNO_QUERY ); + if( xFatcory.is() ) + { + uno::Reference< beans::XPropertySet > xDrawDefaults( xFatcory->createInstance( C2U( "com.sun.star.drawing.Defaults" ) ), uno::UNO_QUERY ); + if( xDrawDefaults.is() ) + xDrawDefaults->getPropertyValue( C2U("WritingMode") ) >>= nWritingMode; + } + } + else + { + uno::Reference< container::XNameAccess > xPageStyles( xStylesFamilies->getByName( C2U("PageStyles") ), uno::UNO_QUERY ); + if( xPageStyles.is() ) + { + rtl::OUString aPageStyle; + + uno::Reference< text::XTextDocument > xTextDocument( xParentProps, uno::UNO_QUERY ); + if( xTextDocument.is() ) + { + //writer is parent document + //retrieve the current page style from the text cursor property PageStyleName + + uno::Reference< text::XTextEmbeddedObjectsSupplier > xTextEmbeddedObjectsSupplier( xTextDocument, uno::UNO_QUERY ); + if( xTextEmbeddedObjectsSupplier.is() ) + { + uno::Reference< container::XNameAccess > xEmbeddedObjects( xTextEmbeddedObjectsSupplier->getEmbeddedObjects() ); + if( xEmbeddedObjects.is() ) + { + uno::Sequence< rtl::OUString > aNames( xEmbeddedObjects->getElementNames() ); + + sal_Int32 nCount = aNames.getLength(); + for( sal_Int32 nN=0; nN<nCount; nN++ ) + { + uno::Reference< beans::XPropertySet > xEmbeddedProps( xEmbeddedObjects->getByName( aNames[nN] ), uno::UNO_QUERY ); + if( xEmbeddedProps.is() ) + { + static rtl::OUString aChartCLSID = rtl::OUString( SvGlobalName( SO3_SCH_CLASSID ).GetHexName()); + rtl::OUString aCLSID; + xEmbeddedProps->getPropertyValue( C2U("CLSID") ) >>= aCLSID; + if( aCLSID.equals(aChartCLSID) ) + { + uno::Reference< frame::XModel > xModel; + xEmbeddedProps->getPropertyValue( C2U("Model") ) >>= xModel; + if( xModel == xChartModel ) + { + uno::Reference< text::XTextContent > xEmbeddedObject( xEmbeddedProps, uno::UNO_QUERY ); + if( xEmbeddedObject.is() ) + { + uno::Reference< text::XTextRange > xAnchor( xEmbeddedObject->getAnchor() ); + if( xAnchor.is() ) + { + uno::Reference< beans::XPropertySet > xAnchorProps( xAnchor, uno::UNO_QUERY ); + if( xAnchorProps.is() ) + { + xAnchorProps->getPropertyValue( C2U("WritingMode") ) >>= nWritingMode; + } + uno::Reference< text::XText > xText( xAnchor->getText() ); + if( xText.is() ) + { + uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY ); + if( xTextCursorProps.is() ) + xTextCursorProps->getPropertyValue( C2U("PageStyleName") ) >>= aPageStyle; + } + } + } + break; + } + } + } + } + } + } + if( !aPageStyle.getLength() ) + { + uno::Reference< text::XText > xText( xTextDocument->getText() ); + if( xText.is() ) + { + uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY ); + if( xTextCursorProps.is() ) + xTextCursorProps->getPropertyValue( C2U("PageStyleName") ) >>= aPageStyle; + } + } + } + else + { + //Calc is parent document + xParentProps->getPropertyValue( C2U("PageStyle") ) >>= aPageStyle; + if(!aPageStyle.getLength()) + aPageStyle = C2U("Default"); + } + if( nWritingMode == -1 || nWritingMode == text::WritingMode2::PAGE ) + { + uno::Reference< beans::XPropertySet > xPageStyle( xPageStyles->getByName( aPageStyle ), uno::UNO_QUERY ); + if( xPageStyle.is() ) + xPageStyle->getPropertyValue( C2U("WritingMode") ) >>= nWritingMode; + } + } + } + } + } + } + if( nWritingMode != -1 && nWritingMode != text::WritingMode2::PAGE ) + { + if( pDrawModelWrapper.get() ) + pDrawModelWrapper->GetItemPool().SetPoolDefaultItem(SfxInt32Item(EE_PARA_WRITINGDIR, nWritingMode) ); + } + } + catch( uno::Exception& ex ) + { + ASSERT_EXCEPTION( ex ); + } + } +} + +sal_Int16 lcl_getDefaultWritingModeFromPool( ::boost::shared_ptr< DrawModelWrapper > pDrawModelWrapper ) +{ + sal_Int16 nWritingMode = text::WritingMode2::LR_TB; + if( pDrawModelWrapper.get() ) + { + const SfxPoolItem* pItem = &(pDrawModelWrapper->GetItemPool().GetDefaultItem( EE_PARA_WRITINGDIR )); + if( pItem ) + nWritingMode = static_cast< sal_Int16 >((static_cast< const SfxInt32Item * >( pItem ))->GetValue()); + } + return nWritingMode; +} + +} //end anonymous namespace + +//------------ create complete diagram shape (inclusive axis and series) + +awt::Rectangle ChartView::impl_createDiagramAndContent( SeriesPlotterContainer& rSeriesPlotterContainer + , const uno::Reference< drawing::XShapes>& xDiagramPlusAxes_Shapes + , const awt::Point& rAvailablePos + , const awt::Size& rAvailableSize + , const awt::Size& rPageSize + , bool bUseFixedInnerSize + , const uno::Reference< drawing::XShape>& xDiagram_MarkHandles /*needs to be resized to fit the result*/ + ) +{ + //return the used rectangle + awt::Rectangle aUsedOuterRect( rAvailablePos.X, rAvailablePos.Y, 0, 0 ); + +// sal_Int32 nDiagramIndex = 0;//todo if more than one diagam is supported + uno::Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( m_xChartModel ) ); + if( !xDiagram.is()) + return aUsedOuterRect; + + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + if(!nDimensionCount) + { + //@todo handle mixed dimension + nDimensionCount = 2; + } + + ::basegfx::B2IRectangle aAvailableOuterRect( BaseGFXHelper::makeRectangle(rAvailablePos,rAvailableSize) ); + + const std::vector< VCoordinateSystem* >& rVCooSysList( rSeriesPlotterContainer.getCooSysList() ); + const std::vector< VSeriesPlotter* >& rSeriesPlotterList( rSeriesPlotterContainer.getSeriesPlotterList() ); + + //create VAxis, so they can give necessary information for automatic scaling + uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( m_xChartModel, uno::UNO_QUERY ); + size_t nC = 0; + for( nC=0; nC < rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = rVCooSysList[nC]; + if(3==nDimensionCount) + { + uno::Reference<beans::XPropertySet> xSceneProperties( xDiagram, uno::UNO_QUERY ); + CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( xSceneProperties ) ); + CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( xSceneProperties ) ); + CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( xSceneProperties ) ); + pVCooSys->set3DWallPositions( eLeftWallPos, eBackWallPos, eBottomPos ); + } + pVCooSys->createVAxisList( xNumberFormatsSupplier + , rPageSize //font reference size + , BaseGFXHelper::B2IRectangleToAWTRectangle( aAvailableOuterRect ) //maximum space for labels + ); + } + + + // - prepare list of all axis and how they are used + Date aNullDate = NumberFormatterWrapper( uno::Reference< util::XNumberFormatsSupplier >( m_xChartModel, uno::UNO_QUERY ) ).getNullDate(); + rSeriesPlotterContainer.initAxisUsageList(aNullDate); + rSeriesPlotterContainer.doAutoScaling( m_xChartModel ); + rSeriesPlotterContainer.setScalesFromCooSysToPlotter(); + rSeriesPlotterContainer.setNumberFormatsFromAxes(); + + //--------------------------------------------------------------------- + //create shapes + + //------------ create diagram shapes + //aspect ratio + drawing::Direction3D aPreferredAspectRatio( + rSeriesPlotterContainer.getPreferredAspectRatio() ); + + uno::Reference< drawing::XShapes > xSeriesTargetInFrontOfAxis(0); + uno::Reference< drawing::XShapes > xSeriesTargetBehindAxis(0); + VDiagram aVDiagram(xDiagram, aPreferredAspectRatio, nDimensionCount); + {//create diagram + aVDiagram.init(xDiagramPlusAxes_Shapes,xDiagramPlusAxes_Shapes,m_xShapeFactory); + aVDiagram.createShapes(rAvailablePos,rAvailableSize); + xSeriesTargetInFrontOfAxis = aVDiagram.getCoordinateRegion(); + if( !bUseFixedInnerSize ) + aVDiagram.reduceToMimimumSize(); + } + + uno::Reference< drawing::XShapes > xTextTargetShapes( ShapeFactory(m_xShapeFactory).createGroup2D(xDiagramPlusAxes_Shapes) ); + + // - create axis and grids for all coordinate systems + + //init all coordinate systems + for( nC=0; nC < rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = rVCooSysList[nC]; + pVCooSys->initPlottingTargets(xSeriesTargetInFrontOfAxis,xTextTargetShapes,m_xShapeFactory,xSeriesTargetBehindAxis); + + pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); + + pVCooSys->initVAxisInList(); + } + + //calculate resulting size respecting axis label layout and fontscaling + + uno::Reference< drawing::XShape > xBoundingShape( xDiagramPlusAxes_Shapes, uno::UNO_QUERY ); + ::basegfx::B2IRectangle aConsumedOuterRect; + + //use first coosys only so far; todo: calculate for more than one coosys if we have more in future + //todo: this is just a workaround at the moment for pie and donut labels + bool bIsPieOrDonut = lcl_IsPieOrDonut(xDiagram); + if( !bIsPieOrDonut && rVCooSysList.size() > 0 ) + { + VCoordinateSystem* pVCooSys = rVCooSysList[0]; + pVCooSys->createMaximumAxesLabels(); + + aConsumedOuterRect = ::basegfx::B2IRectangle( ShapeFactory::getRectangleOfShape(xBoundingShape) ); + ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() ); + if( !bUseFixedInnerSize ) + aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect ); + + pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aNewInnerRect ) )); + + //redo autoscaling to get size and text dependent automatic main increment count + rSeriesPlotterContainer.doAutoScaling( m_xChartModel ); + rSeriesPlotterContainer.updateScalesAndIncrementsOnAxes(); + rSeriesPlotterContainer.setScalesFromCooSysToPlotter(); + + pVCooSys->createAxesLabels(); + + bool bLessSpaceConsumedThanExpected = false; + { + ::basegfx::B2IRectangle aOldRect( aConsumedOuterRect ); + aConsumedOuterRect = ShapeFactory::getRectangleOfShape(xBoundingShape); + if( aConsumedOuterRect.getMinX() > aAvailableOuterRect.getMinX() + || aConsumedOuterRect.getMaxX() < aAvailableOuterRect.getMaxX() + || aConsumedOuterRect.getMinY() > aAvailableOuterRect.getMinY() + || aConsumedOuterRect.getMinY() < aAvailableOuterRect.getMaxY() ) + bLessSpaceConsumedThanExpected = true; + } + + if( bLessSpaceConsumedThanExpected && !bUseFixedInnerSize ) + { + aVDiagram.adjustInnerSize( aConsumedOuterRect ); + pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); + } + pVCooSys->updatePositions();//todo: logically this belongs to the condition above, but it seems also to be neccessary to give the axes group shapes the right bounding rects for hit test - probably caused by bug i106183 -> check again if fixed + } + + //create axes and grids for the final size + for( nC=0; nC < rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = rVCooSysList[nC]; + + pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); + + pVCooSys->createAxesShapes(); + pVCooSys->createGridShapes(); + } + + // - create data series for all charttypes + m_bPointsWereSkipped = false; + ::std::vector< VSeriesPlotter* >::const_iterator aPlotterIter = rSeriesPlotterList.begin(); + const ::std::vector< VSeriesPlotter* >::const_iterator aPlotterEnd = rSeriesPlotterList.end(); + for( aPlotterIter = rSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + { + //------------ set transformation to plotter / create series + VSeriesPlotter* pSeriesPlotter = *aPlotterIter; + rtl::OUString aCID; //III + uno::Reference< drawing::XShapes > xSeriesTarget(0); + if( pSeriesPlotter->WantToPlotInFrontOfAxisLine() ) + xSeriesTarget = xSeriesTargetInFrontOfAxis; + else + { + xSeriesTarget = xSeriesTargetBehindAxis; + DBG_ASSERT( !bIsPieOrDonut, "not implemented yet! - during a complete recreation this shape is destroyed so no series can be created anymore" ); + } + pSeriesPlotter->initPlotter( xSeriesTarget,xTextTargetShapes,m_xShapeFactory,aCID ); + pSeriesPlotter->setPageReferenceSize( rPageSize ); + VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, pSeriesPlotter ); + if(2==nDimensionCount) + pSeriesPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() ); + //better performance for big data + awt::Size aCoordinateRegionResolution(1000,1000); + { + //calculate resolution for coordinate system + Sequence<sal_Int32> aCoordinateSystemResolution = pVCooSys->getCoordinateSystemResolution( rPageSize, m_aPageResolution ); + pSeriesPlotter->setCoordinateSystemResolution( aCoordinateSystemResolution ); + } + // + pSeriesPlotter->createShapes(); + m_bPointsWereSkipped = m_bPointsWereSkipped || pSeriesPlotter->PointsWereSkipped(); + } + + //recreate all with corrected sizes if requested + if( bIsPieOrDonut ) + { + m_bPointsWereSkipped = false; + + aConsumedOuterRect = ::basegfx::B2IRectangle( ShapeFactory::getRectangleOfShape(xBoundingShape) ); + ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() ); + if( !bUseFixedInnerSize ) + aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect ); + + for( aPlotterIter = rSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + { + VSeriesPlotter* pSeriesPlotter = *aPlotterIter; + pSeriesPlotter->releaseShapes(); + } + + //clear and recreate + ShapeFactory::removeSubShapes( xSeriesTargetInFrontOfAxis ); //xSeriesTargetBehindAxis is a sub shape of xSeriesTargetInFrontOfAxis and will be removed here + xSeriesTargetBehindAxis.clear(); + ShapeFactory::removeSubShapes( xTextTargetShapes ); + + //set new transformation + for( nC=0; nC < rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = rVCooSysList[nC]; + pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aNewInnerRect ) )); + } + + // - create data series for all charttypes + for( aPlotterIter = rSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + { + //------------ set transformation to plotter / create series + VSeriesPlotter* pSeriesPlotter = *aPlotterIter; + VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, pSeriesPlotter ); + if(2==nDimensionCount) + pSeriesPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() ); + pSeriesPlotter->createShapes(); + m_bPointsWereSkipped = m_bPointsWereSkipped || pSeriesPlotter->PointsWereSkipped(); + } + + /* + uno::Reference< drawing::XShape > xDiagramPlusAxes_KeepRatio( xDiagramPlusAxes_Shapes, uno::UNO_QUERY ); + + awt::Size aNewSize( rAvailableSize ); + awt::Point aNewPos( rAvailablePos ); + if( bKeepAspectRatio ) + { + awt::Size aCurrentSize( xDiagramPlusAxes_KeepRatio->getSize()); + + aNewSize = ShapeFactory::calculateNewSizeRespectingAspectRatio( + rAvailableSize, aCurrentSize ); + aNewPos = ShapeFactory::calculateTopLeftPositionToCenterObject( + rAvailablePos, rAvailableSize, aNewSize ); + } + + xDiagramPlusAxes_KeepRatio->setPosition( aNewPos ); + xDiagramPlusAxes_KeepRatio->setSize( aNewSize ); + */ + for( aPlotterIter = rSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + { + VSeriesPlotter* pSeriesPlotter = *aPlotterIter; + pSeriesPlotter->rearrangeLabelToAvoidOverlapIfRequested( rPageSize ); + } + } + + if( bUseFixedInnerSize ) + { + //if( !bIsPieOrDonut ) + // aConsumedOuterRect = ::basegfx::B2IRectangle( ShapeFactory::getRectangleOfShape(xBoundingShape) ); + aUsedOuterRect = awt::Rectangle( aConsumedOuterRect.getMinX(), aConsumedOuterRect.getMinY(), aConsumedOuterRect.getWidth(), aConsumedOuterRect.getHeight() ); + } + else + aUsedOuterRect = awt::Rectangle( rAvailablePos.X, rAvailablePos.Y, rAvailableSize.Width, rAvailableSize.Height ); + + bool bSnapRectToUsedArea = false; + for( aPlotterIter = rSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + { + VSeriesPlotter* pSeriesPlotter = *aPlotterIter; + bSnapRectToUsedArea = pSeriesPlotter->shouldSnapRectToUsedArea(); + if(bSnapRectToUsedArea) + break; + } + if(bSnapRectToUsedArea) + { + if( bUseFixedInnerSize ) + m_aResultingDiagramRectangleExcludingAxes = getRectangleOfObject( C2U("PlotAreaExcludingAxes") ); + else + { + ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle(); + m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle( aConsumedInnerRect.getMinX(), aConsumedInnerRect.getMinY(), aConsumedInnerRect.getWidth(), aConsumedInnerRect.getHeight() ); + } + } + else + { + if( bUseFixedInnerSize ) + m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle( rAvailablePos.X, rAvailablePos.Y, rAvailableSize.Width, rAvailableSize.Height ); + else + { + ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle(); + m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle( aConsumedInnerRect.getMinX(), aConsumedInnerRect.getMinY(), aConsumedInnerRect.getWidth(), aConsumedInnerRect.getHeight() ); + } + } + + if( xDiagram_MarkHandles.is() ) + { + awt::Point aPos(rAvailablePos); + awt::Size aSize(rAvailableSize); + bool bPosSizeExcludeAxesProperty = true; + uno::Reference< beans::XPropertySet > xDiaProps( xDiagram, uno::UNO_QUERY_THROW ); + if( xDiaProps.is() ) + xDiaProps->getPropertyValue(C2U("PosSizeExcludeAxes")) >>= bPosSizeExcludeAxesProperty; + if( bUseFixedInnerSize || bPosSizeExcludeAxesProperty ) + { + aPos = awt::Point( m_aResultingDiagramRectangleExcludingAxes.X, m_aResultingDiagramRectangleExcludingAxes.Y ); + aSize = awt::Size( m_aResultingDiagramRectangleExcludingAxes.Width, m_aResultingDiagramRectangleExcludingAxes.Height ); + } + xDiagram_MarkHandles->setPosition( aPos ); + xDiagram_MarkHandles->setSize( aSize ); + } + + return aUsedOuterRect; +} + +//------------------------------------------------------------- +//------------------------------------------------------------- +//------------------------------------------------------------- + +sal_Bool ChartView::getExplicitValuesForAxis( + uno::Reference< XAxis > xAxis + , ExplicitScaleData& rExplicitScale + , ExplicitIncrementData& rExplicitIncrement ) +{ + impl_updateView(); + + if(!xAxis.is()) + return sal_False; + + uno::Reference< XCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis(xAxis,ChartModelHelper::findDiagram( m_xChartModel ) ) ); + const VCoordinateSystem* pVCooSys = findInCooSysList(m_aVCooSysList,xCooSys); + if(!pVCooSys) + return sal_False; + + sal_Int32 nDimensionIndex=-1; + sal_Int32 nAxisIndex=-1; + if( AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ) ) + { + rExplicitScale = pVCooSys->getExplicitScale(nDimensionIndex,nAxisIndex); + rExplicitIncrement = pVCooSys->getExplicitIncrement(nDimensionIndex,nAxisIndex); + if( rExplicitScale.ShiftedCategoryPosition ) + { + //remove 'one' from max + if( rExplicitScale.AxisType == ::com::sun::star::chart2::AxisType::DATE ) + { + Date aMaxDate(rExplicitScale.NullDate); aMaxDate += static_cast<long>(::rtl::math::approxFloor(rExplicitScale.Maximum)); + //for explicit scales with shifted categories we need one interval more + switch( rExplicitScale.TimeResolution ) + { + case ::com::sun::star::chart::TimeUnit::DAY: + aMaxDate--;break; + case ::com::sun::star::chart::TimeUnit::MONTH: + aMaxDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,-1); + break; + case ::com::sun::star::chart::TimeUnit::YEAR: + aMaxDate = DateHelper::GetDateSomeYearsAway(aMaxDate,-1); + break; + } + rExplicitScale.Maximum = aMaxDate - rExplicitScale.NullDate; + } + else if( rExplicitScale.AxisType == ::com::sun::star::chart2::AxisType::CATEGORY ) + rExplicitScale.Maximum -= 1.0; + else if( rExplicitScale.AxisType == ::com::sun::star::chart2::AxisType::SERIES ) + rExplicitScale.Maximum -= 1.0; + } + return sal_True; + } + return sal_False; +} + +SdrPage* ChartView::getSdrPage() +{ + SdrPage* pPage=0; + Reference< lang::XUnoTunnel> xUnoTunnel(m_xDrawPage,uno::UNO_QUERY); + if(xUnoTunnel.is()) + { + SvxDrawPage* pSvxDrawPage = reinterpret_cast<SvxDrawPage*>(xUnoTunnel->getSomething( + SvxDrawPage::getUnoTunnelId() )); + if(pSvxDrawPage) + { + pPage = pSvxDrawPage->GetSdrPage(); + } + } + return pPage; +} + +uno::Reference< drawing::XShape > ChartView::getShapeForCID( const rtl::OUString& rObjectCID ) +{ + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + SdrObject* pObj = DrawModelWrapper::getNamedSdrObject( rObjectCID, this->getSdrPage() ); + if( pObj ) + return uno::Reference< drawing::XShape >( pObj->getUnoShape(), uno::UNO_QUERY); + return 0; +} + +awt::Rectangle ChartView::getDiagramRectangleExcludingAxes() +{ + impl_updateView(); + return m_aResultingDiagramRectangleExcludingAxes; +} + +awt::Rectangle ChartView::getRectangleOfObject( const rtl::OUString& rObjectCID, bool bSnapRect ) +{ + impl_updateView(); + + awt::Rectangle aRet; + uno::Reference< drawing::XShape > xShape( getShapeForCID(rObjectCID) ); + if(xShape.is()) + { + //special handling for axis for old api: + //same special handling for diagram + ObjectType eObjectType( ObjectIdentifier::getObjectType( rObjectCID ) ); + if( eObjectType == OBJECTTYPE_AXIS || eObjectType == OBJECTTYPE_DIAGRAM ) + { + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + SvxShape* pRoot = SvxShape::getImplementation( xShape ); + if( pRoot ) + { + SdrObject* pRootSdrObject = pRoot->GetSdrObject(); + if( pRootSdrObject ) + { + SdrObjList* pRootList = pRootSdrObject->GetSubList(); + if( pRootList ) + { + OUString aShapeName = C2U("MarkHandles"); + if( eObjectType == OBJECTTYPE_DIAGRAM ) + aShapeName = C2U("PlotAreaIncludingAxes"); + SdrObject* pShape = DrawModelWrapper::getNamedSdrObject( aShapeName, pRootList ); + if( pShape ) + xShape = uno::Reference< drawing::XShape >( pShape->getUnoShape(), uno::UNO_QUERY); + } + } + } + } + + awt::Size aSize( xShape->getSize() ); + awt::Point aPoint( xShape->getPosition() ); + aRet = awt::Rectangle( aPoint.X, aPoint.Y, aSize.Width, aSize.Height ); + if( bSnapRect ) + { + //for rotated objects the shape size and position differs from the visible rectangle + SvxShape* pShape = SvxShape::getImplementation( xShape ); + if( pShape ) + { + SdrObject* pSdrObject = pShape->GetSdrObject(); + if( pSdrObject ) + { + Rectangle aSnapRect( pSdrObject->GetSnapRect() ); + aRet = awt::Rectangle(aSnapRect.Left(),aSnapRect.Top(),aSnapRect.GetWidth(),aSnapRect.GetHeight()); + } + } + } + } + return aRet; +} + +::boost::shared_ptr< DrawModelWrapper > ChartView::getDrawModelWrapper() +{ + return m_pDrawModelWrapper; +} + +namespace +{ +sal_Int32 lcl_getDiagramTitleSpace() +{ + return 200; //=0,2 cm spacing +} +bool lcl_getPropertySwapXAndYAxis( const uno::Reference< XDiagram >& xDiagram ) +{ + bool bSwapXAndY = false; + + uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY ); + if( xCooSysContainer.is() ) + { + uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() ); + if( aCooSysList.getLength() ) + { + uno::Reference<beans::XPropertySet> xProp(aCooSysList[0], uno::UNO_QUERY ); + if( xProp.is()) try + { + xProp->getPropertyValue( C2U( "SwapXAndYAxis" ) ) >>= bSwapXAndY; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + } + return bSwapXAndY; +} + +} + +sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( + const Reference< chart2::XAxis >& xAxis + , const Reference< chart2::XCoordinateSystem > & xCorrespondingCoordinateSystem + , const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier ) +{ + return AxisHelper::getExplicitNumberFormatKeyForAxis( xAxis, xCorrespondingCoordinateSystem, xNumberFormatsSupplier + , true /*bSearchForParallelAxisIfNothingIsFound*/ ); +} + +sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( + const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, + const uno::Reference< XDataSeries >& xSeries, + sal_Int32 nPointIndex /*-1 for whole series*/, + const uno::Reference< XDiagram >& xDiagram + ) +{ + sal_Int32 nFormat=0; + if( !xSeriesOrPointProp.is() ) + return nFormat; + + rtl::OUString aPropName( C2U( "NumberFormat" ) ); + if( !(xSeriesOrPointProp->getPropertyValue(aPropName) >>= nFormat) ) + { + uno::Reference< chart2::XChartType > xChartType( DataSeriesHelper::getChartTypeOfSeries( xSeries, xDiagram ) ); + + bool bFormatFound = false; + if( ChartTypeHelper::shouldLabelNumberFormatKeyBeDetectedFromYAxis( xChartType ) ) + { + uno::Reference< beans::XPropertySet > xAttachedAxisProps( DiagramHelper::getAttachedAxis( xSeries, xDiagram ), uno::UNO_QUERY ); + if( xAttachedAxisProps.is() && ( xAttachedAxisProps->getPropertyValue( aPropName ) >>= nFormat ) ) + bFormatFound = true; + } + if( !bFormatFound ) + { + Reference< chart2::data::XDataSource > xSeriesSource( xSeries, uno::UNO_QUERY ); + OUString aRole( ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( xChartType ) ); + + Reference< data::XLabeledDataSequence > xLabeledSequence( + DataSeriesHelper::getDataSequenceByRole( xSeriesSource, aRole, false )); + if( xLabeledSequence.is() ) + { + Reference< data::XDataSequence > xValues( xLabeledSequence->getValues() ); + if( xValues.is() ) + nFormat = xValues->getNumberFormatKeyByIndex( nPointIndex ); + } + } + } + if(nFormat<0) + nFormat=0; + return nFormat; +} + +sal_Int32 ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel( + const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, + const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier ) +{ + sal_Int32 nFormat=0; + if( !xSeriesOrPointProp.is() ) + return nFormat; + if( !(xSeriesOrPointProp->getPropertyValue(C2U( "PercentageNumberFormat" )) >>= nFormat) ) + { + nFormat = DiagramHelper::getPercentNumberFormat( xNumberFormatsSupplier ); + } + if(nFormat<0) + nFormat=0; + return nFormat; +} + +awt::Rectangle ExplicitValueProvider::addAxisTitleSizes( + const Reference< frame::XModel >& xChartModel + , const Reference< uno::XInterface >& xChartView + , const awt::Rectangle& rExcludingPositionAndSize ) +{ + awt::Rectangle aRet(rExcludingPositionAndSize); + + //add axis title sizes to the diagram size + uno::Reference< chart2::XTitle > xTitle_Height( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, xChartModel ) ); + uno::Reference< chart2::XTitle > xTitle_Width( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, xChartModel ) ); + uno::Reference< chart2::XTitle > xSecondTitle_Height( TitleHelper::getTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, xChartModel ) ); + uno::Reference< chart2::XTitle > xSecondTitle_Width( TitleHelper::getTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, xChartModel ) ); + if( xTitle_Height.is() || xTitle_Width.is() || xSecondTitle_Height.is() || xSecondTitle_Width.is() ) + { + ExplicitValueProvider* pExplicitValueProvider = ExplicitValueProvider::getExplicitValueProvider(xChartView); + if( pExplicitValueProvider ) + { + //detect wether x axis points into x direction or not + if( lcl_getPropertySwapXAndYAxis( ChartModelHelper::findDiagram( xChartModel ) ) ) + { + std::swap( xTitle_Height, xTitle_Width ); + std::swap( xSecondTitle_Height, xSecondTitle_Width ); + } + + sal_Int32 nTitleSpaceWidth = 0; + sal_Int32 nTitleSpaceHeight = 0; + sal_Int32 nSecondTitleSpaceWidth = 0; + sal_Int32 nSecondTitleSpaceHeight = 0; + + if( xTitle_Height.is() ) + { + rtl::OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Height, xChartModel ) ); + nTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height; + if( nTitleSpaceHeight ) + nTitleSpaceHeight+=lcl_getDiagramTitleSpace(); + } + if( xTitle_Width.is() ) + { + rtl::OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Width, xChartModel ) ); + nTitleSpaceWidth = pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width; + if(nTitleSpaceWidth) + nTitleSpaceWidth+=lcl_getDiagramTitleSpace(); + } + if( xSecondTitle_Height.is() ) + { + rtl::OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Height, xChartModel ) ); + nSecondTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height; + if( nSecondTitleSpaceHeight ) + nSecondTitleSpaceHeight+=lcl_getDiagramTitleSpace(); + } + if( xSecondTitle_Width.is() ) + { + rtl::OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Width, xChartModel ) ); + nSecondTitleSpaceWidth += pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width; + if( nSecondTitleSpaceWidth ) + nSecondTitleSpaceWidth+=lcl_getDiagramTitleSpace(); + } + + aRet.X -= nTitleSpaceWidth; + aRet.Y -= nSecondTitleSpaceHeight; + aRet.Width += nTitleSpaceWidth + nSecondTitleSpaceWidth; + aRet.Height += nTitleSpaceHeight + nSecondTitleSpaceHeight; + } + } + return aRet; +} + +awt::Rectangle ExplicitValueProvider::substractAxisTitleSizes( + const Reference< frame::XModel >& xChartModel + , const Reference< uno::XInterface >& xChartView + , const awt::Rectangle& rPositionAndSizeIncludingTitles ) +{ + awt::Rectangle aRet(rPositionAndSizeIncludingTitles); + + //add axis title sizes to the diagram size + uno::Reference< chart2::XTitle > xTitle_Height( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, xChartModel ) ); + uno::Reference< chart2::XTitle > xTitle_Width( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, xChartModel ) ); + uno::Reference< chart2::XTitle > xSecondTitle_Height( TitleHelper::getTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, xChartModel ) ); + uno::Reference< chart2::XTitle > xSecondTitle_Width( TitleHelper::getTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, xChartModel ) ); + if( xTitle_Height.is() || xTitle_Width.is() || xSecondTitle_Height.is() || xSecondTitle_Width.is() ) + { + ExplicitValueProvider* pExplicitValueProvider = ExplicitValueProvider::getExplicitValueProvider(xChartView); + if( pExplicitValueProvider ) + { + //detect wether x axis points into x direction or not + if( lcl_getPropertySwapXAndYAxis( ChartModelHelper::findDiagram( xChartModel ) ) ) + { + std::swap( xTitle_Height, xTitle_Width ); + std::swap( xSecondTitle_Height, xSecondTitle_Width ); + } + + sal_Int32 nTitleSpaceWidth = 0; + sal_Int32 nTitleSpaceHeight = 0; + sal_Int32 nSecondTitleSpaceWidth = 0; + sal_Int32 nSecondTitleSpaceHeight = 0; + + if( xTitle_Height.is() ) + { + rtl::OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Height, xChartModel ) ); + nTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height; + if( nTitleSpaceHeight ) + nTitleSpaceHeight+=lcl_getDiagramTitleSpace(); + } + if( xTitle_Width.is() ) + { + rtl::OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Width, xChartModel ) ); + nTitleSpaceWidth = pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width; + if(nTitleSpaceWidth) + nTitleSpaceWidth+=lcl_getDiagramTitleSpace(); + } + if( xSecondTitle_Height.is() ) + { + rtl::OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Height, xChartModel ) ); + nSecondTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height; + if( nSecondTitleSpaceHeight ) + nSecondTitleSpaceHeight+=lcl_getDiagramTitleSpace(); + } + if( xSecondTitle_Width.is() ) + { + rtl::OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Width, xChartModel ) ); + nSecondTitleSpaceWidth += pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width; + if( nSecondTitleSpaceWidth ) + nSecondTitleSpaceWidth+=lcl_getDiagramTitleSpace(); + } + + aRet.X += nTitleSpaceWidth; + aRet.Y += nSecondTitleSpaceHeight; + aRet.Width -= (nTitleSpaceWidth + nSecondTitleSpaceWidth); + aRet.Height -= (nTitleSpaceHeight + nSecondTitleSpaceHeight); + } + } + return aRet; +} + +double lcl_getPageLayoutDistancePercentage() +{ + return 0.02; +} + +bool getAvailablePosAndSizeForDiagram( + awt::Point& rOutPos, awt::Size& rOutAvailableDiagramSize + , const awt::Rectangle& rSpaceLeft + , const awt::Size & rPageSize + , const uno::Reference< XDiagram > & xDiagram + , bool& bUseFixedInnerSize ) +{ + bUseFixedInnerSize = false; + + //@todo: we need a size dependent on the axis labels + awt::Rectangle aRemainingSpace(rSpaceLeft); + { + sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage()); + sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage()); + aRemainingSpace.X+=nXDistance; + aRemainingSpace.Width-=2*nXDistance; + aRemainingSpace.Y+=nYDistance; + aRemainingSpace.Height-=2*nYDistance; + } + if(aRemainingSpace.Width <= 0 || aRemainingSpace.Height <= 0 ) + return false; + + uno::Reference< beans::XPropertySet > xProp(xDiagram, uno::UNO_QUERY); + + bool bPosSizeExcludeAxes = false; + if( xProp.is() ) + xProp->getPropertyValue( C2U( "PosSizeExcludeAxes" ) ) >>= bPosSizeExcludeAxes; + + //size: + ::com::sun::star::chart2::RelativeSize aRelativeSize; + if( xProp.is() && (xProp->getPropertyValue( C2U( "RelativeSize" ) )>>=aRelativeSize) ) + { + rOutAvailableDiagramSize.Height = static_cast<sal_Int32>(aRelativeSize.Secondary*rPageSize.Height); + rOutAvailableDiagramSize.Width = static_cast<sal_Int32>(aRelativeSize.Primary*rPageSize.Width); + bUseFixedInnerSize = bPosSizeExcludeAxes; + } + else + rOutAvailableDiagramSize = awt::Size(aRemainingSpace.Width,aRemainingSpace.Height); + + //position: + chart2::RelativePosition aRelativePosition; + if( xProp.is() && (xProp->getPropertyValue( C2U( "RelativePosition" ) )>>=aRelativePosition) ) + { + //@todo decide wether x is primary or secondary + + //the coordinates re relative to the page + double fX = aRelativePosition.Primary*rPageSize.Width; + double fY = aRelativePosition.Secondary*rPageSize.Height; + + rOutPos = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( + awt::Point(static_cast<sal_Int32>(fX),static_cast<sal_Int32>(fY)) + , rOutAvailableDiagramSize, aRelativePosition.Anchor ); + bUseFixedInnerSize = bPosSizeExcludeAxes; + } + else + rOutPos = awt::Point(aRemainingSpace.X,aRemainingSpace.Y); + + //ensure that the diagram does not lap out right side or out of bottom + { + if( rOutPos.Y + rOutAvailableDiagramSize.Height > rPageSize.Height ) + rOutAvailableDiagramSize.Height = rPageSize.Height - rOutPos.Y; + if( rOutPos.X + rOutAvailableDiagramSize.Width > rPageSize.Width ) + rOutAvailableDiagramSize.Width = rPageSize.Width - rOutPos.X; + } + + return true; +} + +enum TitleAlignment { ALIGN_LEFT, ALIGN_TOP, ALIGN_RIGHT, ALIGN_BOTTOM, ALIGN_Z }; + +void changePositionOfAxisTitle( VTitle* pVTitle, TitleAlignment eAlignment + , awt::Rectangle& rDiagramPlusAxesRect, const awt::Size & rPageSize ) +{ + if(!pVTitle) + return; + + awt::Point aNewPosition(0,0); + awt::Size aTitleSize = pVTitle->getFinalSize(); + sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage()); + sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage()); + switch( eAlignment ) + { + case ALIGN_TOP: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2 + , rDiagramPlusAxesRect.Y - aTitleSize.Height/2 - nYDistance ); + break; + case ALIGN_BOTTOM: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2 + , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height + aTitleSize.Height/2 + nYDistance ); + break; + case ALIGN_LEFT: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X - aTitleSize.Width/2 - nXDistance + , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 ); + break; + case ALIGN_RIGHT: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance + , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 ); + break; + case ALIGN_Z: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance + , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height - aTitleSize.Height/2 ); + break; + default: + break; + } + + sal_Int32 nMaxY = rPageSize.Height - aTitleSize.Height/2; + sal_Int32 nMaxX = rPageSize.Width - aTitleSize.Width/2; + sal_Int32 nMinX = aTitleSize.Width/2; + sal_Int32 nMinY = aTitleSize.Height/2; + if( aNewPosition.Y > nMaxY ) + aNewPosition.Y = nMaxY; + if( aNewPosition.X > nMaxX ) + aNewPosition.X = nMaxX; + if( aNewPosition.Y < nMinY ) + aNewPosition.Y = nMinY; + if( aNewPosition.X < nMinX ) + aNewPosition.X = nMinX; + + pVTitle->changePosition( aNewPosition ); +} + +std::auto_ptr<VTitle> lcl_createTitle( TitleHelper::eTitleType eType + , const uno::Reference< drawing::XShapes>& xPageShapes + , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory + , const uno::Reference< frame::XModel >& xChartModel + , awt::Rectangle& rRemainingSpace + , const awt::Size & rPageSize + , TitleAlignment eAlignment + , bool& rbAutoPosition ) +{ + std::auto_ptr<VTitle> apVTitle; + + // #i109336# Improve auto positioning in chart + double fPercentage = lcl_getPageLayoutDistancePercentage(); + sal_Int32 nXDistance = static_cast< sal_Int32 >( rPageSize.Width * fPercentage ); + sal_Int32 nYDistance = static_cast< sal_Int32 >( rPageSize.Height * fPercentage ); + if ( eType == TitleHelper::MAIN_TITLE ) + { + sal_Int32 nYOffset = 135; // 1/100 mm + nYDistance += nYOffset; + } + else if ( eType == TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION ) + { + sal_Int32 nYOffset = 420; // 1/100 mm + nYDistance = nYOffset; + } + else if ( eType == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION ) + { + sal_Int32 nXOffset = 450; // 1/100 mm + nXDistance = nXOffset; + } + + uno::Reference< XTitle > xTitle( TitleHelper::getTitle( eType, xChartModel ) ); + if(xTitle.is()) + { + rtl::OUString aCompleteString( TitleHelper::getCompleteString( xTitle ) ); + if ( aCompleteString.getLength() == 0 ) + return apVTitle;//don't create empty titles as the resulting diagram position is wrong then + + //create title + apVTitle = std::auto_ptr<VTitle>(new VTitle(xTitle)); + rtl::OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle, xChartModel ) ); + apVTitle->init(xPageShapes,xShapeFactory,aCID); + apVTitle->createShapes( awt::Point(0,0), rPageSize ); + awt::Size aTitleUnrotatedSize = apVTitle->getUnrotatedSize(); + awt::Size aTitleSize = apVTitle->getFinalSize(); + + //position + rbAutoPosition=true; + awt::Point aNewPosition(0,0); + chart2::RelativePosition aRelativePosition; + uno::Reference< beans::XPropertySet > xProp(xTitle, uno::UNO_QUERY); + if( xProp.is() && (xProp->getPropertyValue( C2U( "RelativePosition" ) )>>=aRelativePosition) ) + { + rbAutoPosition = false; + + //@todo decide wether x is primary or secondary + double fX = aRelativePosition.Primary*rPageSize.Width; + double fY = aRelativePosition.Secondary*rPageSize.Height; + + double fAnglePi = apVTitle->getRotationAnglePi(); + aNewPosition = RelativePositionHelper::getCenterOfAnchoredObject( + awt::Point(static_cast<sal_Int32>(fX),static_cast<sal_Int32>(fY)) + , aTitleUnrotatedSize, aRelativePosition.Anchor, fAnglePi ); + } + else //auto position + { + switch( eAlignment ) + { + case ALIGN_TOP: + aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2 + , rRemainingSpace.Y + aTitleSize.Height/2 + nYDistance ); + break; + case ALIGN_BOTTOM: + aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2 + , rRemainingSpace.Y + rRemainingSpace.Height - aTitleSize.Height/2 - nYDistance ); + break; + case ALIGN_LEFT: + aNewPosition = awt::Point( rRemainingSpace.X + aTitleSize.Width/2 + nXDistance + , rRemainingSpace.Y + rRemainingSpace.Height/2 ); + break; + case ALIGN_RIGHT: + aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width - aTitleSize.Width/2 - nXDistance + , rRemainingSpace.Y + rRemainingSpace.Height/2 ); + break; + default: + break; + + } + } + apVTitle->changePosition( aNewPosition ); + + //remaining space + switch( eAlignment ) + { + case ALIGN_TOP: + rRemainingSpace.Y += ( aTitleSize.Height + nYDistance ); + rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance ); + break; + case ALIGN_BOTTOM: + rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance ); + break; + case ALIGN_LEFT: + rRemainingSpace.X += ( aTitleSize.Width + nXDistance ); + rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance ); + break; + case ALIGN_RIGHT: + rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance ); + break; + default: + break; + } + } + else + { + // #i109336# Improve auto positioning in chart + switch ( eAlignment ) + { + case ALIGN_TOP: + { + rRemainingSpace.Y += nYDistance; + rRemainingSpace.Height -= nYDistance; + } + break; + case ALIGN_BOTTOM: + { + rRemainingSpace.Height -= nYDistance; + } + break; + case ALIGN_LEFT: + { + rRemainingSpace.X += nXDistance; + rRemainingSpace.Width -= nXDistance; + } + break; + case ALIGN_RIGHT: + { + rRemainingSpace.Width -= nXDistance; + } + break; + default: + break; + } + } + return apVTitle; +} + +bool lcl_createLegend( const uno::Reference< XLegend > & xLegend + , const uno::Reference< drawing::XShapes>& xPageShapes + , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory + , const uno::Reference< uno::XComponentContext > & xContext + , awt::Rectangle & rRemainingSpace + , const awt::Size & rPageSize + , const uno::Reference< frame::XModel > & xModel + , const std::vector< LegendEntryProvider* >& rLegendEntryProviderList + , sal_Int16 nDefaultWritingMode ) +{ + if( VLegend::isVisible( xLegend )) + { + VLegend aVLegend( xLegend, xContext, rLegendEntryProviderList ); + aVLegend.init( xPageShapes, xShapeFactory, xModel ); + aVLegend.setDefaultWritingMode( nDefaultWritingMode ); + aVLegend.createShapes( awt::Size( rRemainingSpace.Width, rRemainingSpace.Height ), + rPageSize ); + aVLegend.changePosition( rRemainingSpace, rPageSize ); + return true; + } + return false; +} + +void formatPage( + const uno::Reference< frame::XModel > & xModel + , const awt::Size rPageSize + , const uno::Reference< drawing::XShapes >& xTarget + , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory + ) +{ + try + { + uno::Reference< XChartDocument > xChartDoc( xModel, uno::UNO_QUERY ); + OSL_ASSERT( xChartDoc.is()); + if( ! xChartDoc.is()) + return; + uno::Reference< beans::XPropertySet > xModelPage( xChartDoc->getPageBackground()); + if( ! xModelPage.is()) + return; + + + if( !xShapeFactory.is() ) + return; + + uno::Reference< beans::XPropertySet > xPageProp; + // create a shape for the background + { + uno::Reference< drawing::XShape > xShape( + xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY ); + if( xTarget.is() && + xShape.is()) + { + xTarget->add( xShape ); + xShape->setSize( rPageSize ); + xPageProp.set( xShape, uno::UNO_QUERY ); + if( xPageProp.is()) + { + xPageProp->setPropertyValue( C2U("LineStyle"), uno::makeAny( drawing::LineStyle_NONE )); + } + } + } + + //format page + if( xPageProp.is()) + { + tPropertyNameValueMap aNameValueMap; + PropertyMapper::getValueMap( aNameValueMap, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xModelPage ); + + rtl::OUString aCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, rtl::OUString() ) ); + aNameValueMap.insert( tPropertyNameValueMap::value_type( C2U("Name"), uno::makeAny( aCID ) ) ); //CID rtl::OUString + + tNameSequence aNames; + tAnySequence aValues; + PropertyMapper::getMultiPropertyListsFromValueMap( aNames, aValues, aNameValueMap ); + PropertyMapper::setMultiProperties( aNames, aValues, xPageProp ); + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } +} + +void lcl_removeEmptyGroupShapes( const Reference< drawing::XShapes>& xParent ) +{ + if(!xParent.is()) + return; + Reference< drawing::XShapeGroup > xParentGroup( xParent, uno::UNO_QUERY ); + if( !xParentGroup.is() ) + { + Reference< drawing::XDrawPage > xPage( xParent, uno::UNO_QUERY ); + if( !xPage.is() ) + return; + } + + //iterate from back! + for( sal_Int32 nN = xParent->getCount(); nN--; ) + { + uno::Any aAny = xParent->getByIndex( nN ); + Reference< drawing::XShapes> xShapes(0); + if( aAny >>= xShapes ) + lcl_removeEmptyGroupShapes( xShapes ); + if( xShapes.is() && xShapes->getCount()==0 ) + { + //remove empty group shape + Reference< drawing::XShapeGroup > xGroup( xShapes, uno::UNO_QUERY ); + Reference< drawing::XShape > xShape( xShapes, uno::UNO_QUERY ); + if( xGroup.is() ) + xParent->remove( xShape ); + } + } +} + +bool ChartView::impl_AddInDrawsAllByItself() +{ + bool bRet = false; + /* + uno::Reference< beans::XPropertySet > xProp( m_xChartModel, uno::UNO_QUERY ); + if( xProp.is()) try + { + uno::Reference< util::XRefreshable > xAddIn; + xProp->getPropertyValue( C2U( "AddIn" ) ) >>= xAddIn; + if( xAddIn.is() ) + { + rtl::OUString aBaseDiagram; + xProp->getPropertyValue( C2U( "BaseDiagram" ) ) >>= aBaseDiagram; + if(aBaseDiagram.getLength()) + bRet = true; + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + */ + return bRet; +} + +void ChartView::impl_refreshAddIn() +{ + if( !m_bRefreshAddIn ) + return; + + uno::Reference< beans::XPropertySet > xProp( m_xChartModel, uno::UNO_QUERY ); + if( xProp.is()) try + { + uno::Reference< util::XRefreshable > xAddIn; + xProp->getPropertyValue( C2U( "AddIn" ) ) >>= xAddIn; + if( xAddIn.is() ) + { + sal_Bool bRefreshAddInAllowed = sal_True; + xProp->getPropertyValue( C2U( "RefreshAddInAllowed" ) ) >>= bRefreshAddInAllowed; + if( bRefreshAddInAllowed ) + xAddIn->refresh(); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } +} + +void ChartView::createShapes() +{ +#if OSL_DEBUG_LEVEL > 0 + clock_t nStart = clock(); + OSL_TRACE( "\nPPPPPPPPP>>>>>>>>>>>> chart view :: createShapes()" ); +#endif + + //make sure add-in is refreshed after creating the shapes + const ::comphelper::ScopeGuard aGuard( boost::bind( &ChartView::impl_refreshAddIn, this ) ); + if( impl_AddInDrawsAllByItself() ) + return; + + m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle(0,0,0,0); + impl_deleteCoordinateSystems(); + if( m_pDrawModelWrapper ) + { + // /-- + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + // #i12587# support for shapes in chart + m_pDrawModelWrapper->getSdrModel().EnableUndo( sal_False ); + m_pDrawModelWrapper->clearMainDrawPage(); + // \-- + } + + lcl_setDefaultWritingMode( m_pDrawModelWrapper, m_xChartModel ); + + awt::Size aPageSize = ChartModelHelper::getPageSize( m_xChartModel ); + + uno::Reference<drawing::XShapes> xPageShapes( ShapeFactory(m_xShapeFactory) + .getOrCreateChartRootShape( m_xDrawPage ) ); + + SdrPage* pPage = ChartView::getSdrPage(); + if(pPage) //it is neccessary to use the implementation here as the uno page does not provide a propertyset + pPage->SetSize(Size(aPageSize.Width,aPageSize.Height)); + else + { + DBG_ERROR("could not set page size correctly"); + } + + { + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + + //------------ apply fill properties to page + // todo: it would be nicer to just pass the page m_xDrawPage and format it, + // but the draw page does not support XPropertySet + formatPage( m_xChartModel, aPageSize, xPageShapes, m_xShapeFactory ); + + //sal_Int32 nYDistance = static_cast<sal_Int32>(aPageSize.Height*lcl_getPageLayoutDistancePercentage()); + awt::Rectangle aRemainingSpace( 0, 0, aPageSize.Width, aPageSize.Height ); + + //create the group shape for diagram and axes first to have title and legends on top of it + uno::Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( m_xChartModel ) ); + rtl::OUString aDiagramCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, rtl::OUString::valueOf( sal_Int32(0) ) ) );//todo: other index if more than one diagram is possible + uno::Reference< drawing::XShapes > xDiagramPlusAxesPlusMarkHandlesGroup_Shapes( ShapeFactory(m_xShapeFactory).createGroup2D(xPageShapes,aDiagramCID) ); + + uno::Reference< drawing::XShape > xDiagram_MarkHandles( ShapeFactory(m_xShapeFactory).createInvisibleRectangle( + xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0,0) ) ); + ShapeFactory::setShapeName( xDiagram_MarkHandles, C2U("MarkHandles") ); + + uno::Reference< drawing::XShape > xDiagram_OuterRect( ShapeFactory(m_xShapeFactory).createInvisibleRectangle( + xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0,0) ) ); + ShapeFactory::setShapeName( xDiagram_OuterRect, C2U("PlotAreaIncludingAxes") ); + + uno::Reference< drawing::XShapes > xDiagramPlusAxes_Shapes( ShapeFactory(m_xShapeFactory).createGroup2D(xDiagramPlusAxesPlusMarkHandlesGroup_Shapes ) ); + + //------------ create some titles + std::auto_ptr<VTitle> apVTitle(0); + bool bAutoPositionDummy = true; + + //------------ create main title shape + lcl_createTitle( TitleHelper::MAIN_TITLE, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, ALIGN_TOP, bAutoPositionDummy ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + //------------ create sub title shape + lcl_createTitle( TitleHelper::SUB_TITLE, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, ALIGN_TOP, bAutoPositionDummy ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + + //------------ prepare series to give input to the legend (create categories and symbols etc.) + SeriesPlotterContainer aSeriesPlotterContainer( m_aVCooSysList ); + aSeriesPlotterContainer.initializeCooSysAndSeriesPlotter( m_xChartModel ); + + //------------ create legend + lcl_createLegend( LegendHelper::getLegend( m_xChartModel ), xPageShapes, m_xShapeFactory, m_xCC + , aRemainingSpace, aPageSize, m_xChartModel, aSeriesPlotterContainer.getLegendEntryProviderList() + , lcl_getDefaultWritingModeFromPool( m_pDrawModelWrapper ) ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + sal_Int32 nDimension = DiagramHelper::getDimension( xDiagram ); + + //------------ create x axis title + bool bAutoPosition_XTitle = true; + std::auto_ptr<VTitle> apVTitle_X; + if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 0 ) ) + apVTitle_X = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, ALIGN_BOTTOM, bAutoPosition_XTitle ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + //------------ create y axis title + bool bAutoPosition_YTitle = true; + std::auto_ptr<VTitle> apVTitle_Y; + if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 1 ) ) + apVTitle_Y = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, ALIGN_LEFT, bAutoPosition_YTitle ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + //------------ create z axis title + bool bAutoPosition_ZTitle = true; + std::auto_ptr<VTitle> apVTitle_Z; + if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 2 ) ) + apVTitle_Z = lcl_createTitle( TitleHelper::Z_AXIS_TITLE, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, ALIGN_RIGHT, bAutoPosition_ZTitle ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + bool bDummy = false; + bool bIsVertical = DiagramHelper::getVertical( xDiagram, bDummy, bDummy ); + + //------------ create secondary x axis title + bool bAutoPosition_SecondXTitle = true; + std::auto_ptr<VTitle> apVTitle_SecondX; + if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension, 0 ) ) + apVTitle_SecondX = lcl_createTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, bIsVertical? ALIGN_RIGHT : ALIGN_TOP, bAutoPosition_SecondXTitle ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + //------------ create secondary y axis title + bool bAutoPosition_SecondYTitle = true; + std::auto_ptr<VTitle> apVTitle_SecondY; + if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension, 1 ) ) + apVTitle_SecondY = lcl_createTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, bIsVertical? ALIGN_TOP : ALIGN_RIGHT, bAutoPosition_SecondYTitle ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + //------------ create complete diagram shape (inclusive axis and series) + awt::Point aAvailablePosDia; + awt::Size aAvailableSizeForDiagram; + bool bUseFixedInnerSize = false; + if( getAvailablePosAndSizeForDiagram( aAvailablePosDia, aAvailableSizeForDiagram, aRemainingSpace, aPageSize + , ChartModelHelper::findDiagram( m_xChartModel ), bUseFixedInnerSize ) ) + { + awt::Rectangle aUsedOuterRect = impl_createDiagramAndContent( aSeriesPlotterContainer + , xDiagramPlusAxes_Shapes + , aAvailablePosDia ,aAvailableSizeForDiagram, aPageSize, bUseFixedInnerSize, xDiagram_MarkHandles ); + + if( xDiagram_OuterRect.is() ) + { + xDiagram_OuterRect->setPosition( awt::Point( aUsedOuterRect.X, aUsedOuterRect.Y ) ); + xDiagram_OuterRect->setSize( awt::Size( aUsedOuterRect.Width, aUsedOuterRect.Height ) ); + } + + //correct axis title position + awt::Rectangle aDiagramPlusAxesRect( aUsedOuterRect ); + if(bAutoPosition_XTitle) + changePositionOfAxisTitle( apVTitle_X.get(), ALIGN_BOTTOM, aDiagramPlusAxesRect, aPageSize ); + if(bAutoPosition_YTitle) + changePositionOfAxisTitle( apVTitle_Y.get(), ALIGN_LEFT, aDiagramPlusAxesRect, aPageSize ); + if(bAutoPosition_ZTitle) + changePositionOfAxisTitle( apVTitle_Z.get(), ALIGN_Z, aDiagramPlusAxesRect, aPageSize ); + if(bAutoPosition_SecondXTitle) + changePositionOfAxisTitle( apVTitle_SecondX.get(), bIsVertical? ALIGN_RIGHT : ALIGN_TOP, aDiagramPlusAxesRect, aPageSize ); + if(bAutoPosition_SecondYTitle) + changePositionOfAxisTitle( apVTitle_SecondY.get(), bIsVertical? ALIGN_TOP : ALIGN_RIGHT, aDiagramPlusAxesRect, aPageSize ); + } + + //cleanup: remove all empty group shapes to avoid grey border lines: + lcl_removeEmptyGroupShapes( xPageShapes ); + } + + // #i12587# support for shapes in chart + if ( m_pDrawModelWrapper ) + { + ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + m_pDrawModelWrapper->getSdrModel().EnableUndo( sal_True ); + } + +#if OSL_DEBUG_LEVEL > 0 + clock_t nEnd = clock(); + double fDuration =(double(nEnd-nStart)*1000.0)/double(CLOCKS_PER_SEC); + + OSL_TRACE( "\nPPPPPPPPP<<<<<<<<<<<< chart view :: createShapes():: needed %f msec", fDuration ); +#endif +} + +//----------------------------------------------------------------- +// util::XEventListener (base of XCloseListener) +//----------------------------------------------------------------- +void SAL_CALL ChartView::disposing( const lang::EventObject& /* rSource */ ) + throw(uno::RuntimeException) +{ + impl_setChartModel( 0 ); +} + +void ChartView::impl_updateView() +{ + if( !m_xChartModel.is() || !m_pDrawModelWrapper ) + return; + + // #i12587# support for shapes in chart + if ( m_bSdrViewIsInEditMode ) + { + return; + } + + if( m_bViewDirty && !m_bInViewUpdate ) + { + m_bInViewUpdate = true; + //bool bOldRefreshAddIn = m_bRefreshAddIn; + //m_bRefreshAddIn = false; + try + { + impl_notifyModeChangeListener(C2U("invalid")); + + //prepare draw model + { + // /-- + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + m_pDrawModelWrapper->lockControllers(); + // \-- + } + + //create chart view + { + m_bViewDirty = false; + m_bViewUpdatePending = false; + createShapes(); + + if( m_bViewDirty ) + { + //avoid recursions due to add-in + m_bRefreshAddIn = false; + m_bViewDirty = false; + m_bViewUpdatePending = false; + //delete old chart view + createShapes(); + m_bRefreshAddIn = true; + } + } + + m_bViewDirty = m_bViewUpdatePending; + m_bViewUpdatePending = false; + m_bInViewUpdate = false; + } + catch( uno::Exception& ex) + { + m_bViewDirty = m_bViewUpdatePending; + m_bViewUpdatePending = false; + m_bInViewUpdate = false; + ASSERT_EXCEPTION( ex ); + } + + { + // /-- + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + m_pDrawModelWrapper->unlockControllers(); + // \-- + } + + impl_notifyModeChangeListener(C2U("valid")); + + //m_bRefreshAddIn = bOldRefreshAddIn; + } +} + +// ____ XModifyListener ____ +void SAL_CALL ChartView::modified( const lang::EventObject& /* aEvent */ ) + throw (uno::RuntimeException) +{ + m_bViewDirty = sal_True; + if( m_bInViewUpdate ) + m_bViewUpdatePending = true; + + impl_notifyModeChangeListener(C2U("dirty")); +} + +//SfxListener +void ChartView::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) +{ + //#i77362 change notification for changes on additional shapes are missing + if( m_bInViewUpdate ) + return; + + // #i12587# support for shapes in chart + if ( m_bSdrViewIsInEditMode && m_xChartModel.is() ) + { + uno::Reference< view::XSelectionSupplier > xSelectionSupplier( m_xChartModel->getCurrentController(), uno::UNO_QUERY ); + if ( xSelectionSupplier.is() ) + { + ::rtl::OUString aSelObjCID; + uno::Any aSelObj( xSelectionSupplier->getSelection() ); + aSelObj >>= aSelObjCID; + if ( aSelObjCID.getLength() > 0 ) + { + return; + } + } + } + + const SdrHint* pSdrHint = dynamic_cast< const SdrHint* >(&rHint); + if( !pSdrHint ) + return; + + bool bShapeChanged = false; + switch( pSdrHint->GetKind() ) + { + case HINT_OBJCHG: + bShapeChanged = true; + break; + case HINT_OBJINSERTED: + bShapeChanged = true; + break; + case HINT_OBJREMOVED: + bShapeChanged = true; + break; + case HINT_MODELCLEARED: + bShapeChanged = true; + break; + case HINT_ENDEDIT: + bShapeChanged = true; + break; + default: + break; + } + + if(bShapeChanged) + { + //#i76053# do not send view modified notifications for changes on the hidden page which contains e.g. the symbols for the dialogs + if( ChartView::getSdrPage() != pSdrHint->GetPage() ) + bShapeChanged=false; + } + + if(!bShapeChanged) + return; + + Reference< util::XModifiable > xModifiable( m_xChartModel, uno::UNO_QUERY ); + if( xModifiable.is() ) + xModifiable->setModified( sal_True ); +} + +void ChartView::impl_notifyModeChangeListener( const rtl::OUString& rNewMode ) +{ + try + { + ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer + .getContainer( ::getCppuType((const uno::Reference< util::XModeChangeListener >*)0) ); + if( pIC ) + { + util::ModeChangeEvent aEvent( static_cast< uno::XWeak* >( this ), rNewMode ); + ::cppu::OInterfaceIteratorHelper aIt( *pIC ); + while( aIt.hasMoreElements() ) + { + uno::Reference< util::XModeChangeListener > xListener( aIt.next(), uno::UNO_QUERY ); + if( xListener.is() ) + xListener->modeChanged( aEvent ); + } + } + } + catch( uno::Exception& ex) + { + ASSERT_EXCEPTION( ex ); + } +} + +// ____ XModeChangeBroadcaster ____ + +void SAL_CALL ChartView::addModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener ) + throw (uno::RuntimeException) +{ + m_aListenerContainer.addInterface( + ::getCppuType((const uno::Reference< util::XModeChangeListener >*)0), xListener ); +} +void SAL_CALL ChartView::removeModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener ) + throw (uno::RuntimeException) +{ + m_aListenerContainer.removeInterface( + ::getCppuType((const uno::Reference< util::XModeChangeListener >*)0), xListener ); +} +void SAL_CALL ChartView::addModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ ) + throw (lang::NoSupportException, uno::RuntimeException) +{ + +} +void SAL_CALL ChartView::removeModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ ) + throw (lang::NoSupportException, uno::RuntimeException) +{ + +} + +// ____ XUpdatable ____ +void SAL_CALL ChartView::update() throw (uno::RuntimeException) +{ + impl_updateView(); + + //#i100778# migrate all imported or old documents to a plot area sizing exclusive axes (in case the save settings allow for this): + //Although in general it is a bad idea to change the model from within the view this is exceptionally the best place to do this special conversion. + //When a view update is requested (what happens for creating the metafile or displaying + //the chart in edit mode or printing) it is most likely that all necessary informations are available - like the underlying spreadsheet data for example. + //Those data is important for the correct axis lable sizes which are needed during conversion. + if( DiagramHelper::switchDiagramPositioningToExcludingPositioning( m_xChartModel, true, false ) ) + impl_updateView(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL ChartView::getPropertySetInfo() + throw (uno::RuntimeException) +{ + OSL_ENSURE(false,"not implemented"); + return 0; +} + +void SAL_CALL ChartView::setPropertyValue( const ::rtl::OUString& rPropertyName + , const Any& rValue ) + throw (beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException + , lang::WrappedTargetException, uno::RuntimeException) +{ + if( rPropertyName.equals(C2U("Resolution")) ) + { + awt::Size aNewResolution; + if( ! (rValue >>= aNewResolution) ) + throw lang::IllegalArgumentException( C2U("Property 'Resolution' requires value of type awt::Size"), 0, 0 ); + + if( m_aPageResolution.Width!=aNewResolution.Width || m_aPageResolution.Height!=aNewResolution.Height ) + { + //set modified only when the new resolution is higher and points were skipped before + bool bSetModified = m_bPointsWereSkipped && (m_aPageResolution.Width<aNewResolution.Width || m_aPageResolution.Height<aNewResolution.Height); + + m_aPageResolution = aNewResolution; + + if( bSetModified ) + this->modified( lang::EventObject( static_cast< uno::XWeak* >( this ) ) ); + } + } + else if( rPropertyName.equals(C2U("ZoomFactors")) ) + { + //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% + uno::Sequence< beans::PropertyValue > aZoomFactors; + if( ! (rValue >>= aZoomFactors) ) + throw lang::IllegalArgumentException( C2U("Property 'ZoomFactors' requires value of type Sequence< PropertyValue >"), 0, 0 ); + + sal_Int32 nFilterArgs = aZoomFactors.getLength(); + beans::PropertyValue* pDataValues = aZoomFactors.getArray(); + while( nFilterArgs-- ) + { + if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleXNumerator" ) ) ) + pDataValues->Value >>= m_nScaleXNumerator; + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleXDenominator" ) ) ) + pDataValues->Value >>= m_nScaleXDenominator; + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleYNumerator" ) ) ) + pDataValues->Value >>= m_nScaleYNumerator; + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleYDenominator" ) ) ) + pDataValues->Value >>= m_nScaleYDenominator; + + pDataValues++; + } + } + else if( rPropertyName.equals(C2U("SdrViewIsInEditMode")) ) + { + //#i77362 change notification for changes on additional shapes are missing + if( ! (rValue >>= m_bSdrViewIsInEditMode) ) + throw lang::IllegalArgumentException( C2U("Property 'SdrViewIsInEditMode' requires value of type sal_Bool"), 0, 0 ); + } + else + throw beans::UnknownPropertyException( C2U("unknown property was tried to set to chart wizard"), 0 ); +} + +Any SAL_CALL ChartView::getPropertyValue( const ::rtl::OUString& rPropertyName ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + Any aRet; + if( rPropertyName.equals(C2U("Resolution")) ) + { + aRet = uno::makeAny( m_aPageResolution ); + } + else + throw beans::UnknownPropertyException( C2U("unknown property was tried to get from chart wizard"), 0 ); + return aRet; +} + +void SAL_CALL ChartView::addPropertyChangeListener( + const ::rtl::OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* xListener */ ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + OSL_ENSURE(false,"not implemented"); +} +void SAL_CALL ChartView::removePropertyChangeListener( + const ::rtl::OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* aListener */ ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + OSL_ENSURE(false,"not implemented"); +} + +void SAL_CALL ChartView::addVetoableChangeListener( const ::rtl::OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + OSL_ENSURE(false,"not implemented"); +} + +void SAL_CALL ChartView::removeVetoableChangeListener( const ::rtl::OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + OSL_ENSURE(false,"not implemented"); +} + +// ____ XMultiServiceFactory ____ + +Reference< uno::XInterface > ChartView::createInstance( const ::rtl::OUString& aServiceSpecifier ) + throw (uno::Exception, uno::RuntimeException) +{ + SdrModel* pModel = ( m_pDrawModelWrapper ? &m_pDrawModelWrapper->getSdrModel() : NULL ); + if ( pModel ) + { + if ( aServiceSpecifier.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.DashTable" ) ) == 0 ) + { + if ( !m_xDashTable.is() ) + { + m_xDashTable = SvxUnoDashTable_createInstance( pModel ); + } + return m_xDashTable; + } + else if ( aServiceSpecifier.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.GradientTable" ) ) == 0 ) + { + if ( !m_xGradientTable.is() ) + { + m_xGradientTable = SvxUnoGradientTable_createInstance( pModel ); + } + return m_xGradientTable; + } + else if ( aServiceSpecifier.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.HatchTable" ) ) == 0 ) + { + if ( !m_xHatchTable.is() ) + { + m_xHatchTable = SvxUnoHatchTable_createInstance( pModel ); + } + return m_xHatchTable; + } + else if ( aServiceSpecifier.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.BitmapTable" ) ) == 0 ) + { + if ( !m_xBitmapTable.is() ) + { + m_xBitmapTable = SvxUnoBitmapTable_createInstance( pModel ); + } + return m_xBitmapTable; + } + else if ( aServiceSpecifier.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.TransparencyGradientTable" ) ) == 0 ) + { + if ( !m_xTransGradientTable.is() ) + { + m_xTransGradientTable = SvxUnoTransGradientTable_createInstance( pModel ); + } + return m_xTransGradientTable; + } + else if ( aServiceSpecifier.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.MarkerTable" ) ) == 0 ) + { + if ( !m_xMarkerTable.is() ) + { + m_xMarkerTable = SvxUnoMarkerTable_createInstance( pModel ); + } + return m_xMarkerTable; + } + } + + return 0; +} + +Reference< uno::XInterface > ChartView::createInstanceWithArguments( const ::rtl::OUString& ServiceSpecifier, const uno::Sequence< uno::Any >& Arguments ) + throw (uno::Exception, uno::RuntimeException) +{ + OSL_ENSURE( Arguments.getLength(), "ChartView::createInstanceWithArguments: arguments are ignored" ); + (void) Arguments; // avoid warning + return createInstance( ServiceSpecifier ); +} + +uno::Sequence< ::rtl::OUString > ChartView::getAvailableServiceNames() throw (uno::RuntimeException) +{ + uno::Sequence< ::rtl::OUString > aServiceNames( 6 ); + + aServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.DashTable" ) ); + aServiceNames[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.GradientTable" ) ); + aServiceNames[2] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.HatchTable" ) ); + aServiceNames[3] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.BitmapTable" ) ); + aServiceNames[4] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.TransparencyGradientTable" ) ); + aServiceNames[5] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.MarkerTable" ) ); + + return aServiceNames; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/ChartView.hxx b/chart2/source/view/main/ChartView.hxx new file mode 100644 index 000000000000..76c1ce5c4858 --- /dev/null +++ b/chart2/source/view/main/ChartView.hxx @@ -0,0 +1,261 @@ +/************************************************************************* + * + * 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 _CHARTVIEWIMPL_HXX +#define _CHARTVIEWIMPL_HXX + +#include "chartview/ExplicitValueProvider.hxx" +#include "ServiceMacros.hxx" +#include <cppuhelper/implbase9.hxx> +#include <cppuhelper/interfacecontainer.hxx> + +// header for class SfxListener +#include <svl/lstner.hxx> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/util/XModifyListener.hpp> +#include <com/sun/star/util/XModeChangeBroadcaster.hpp> +#include <com/sun/star/util/XUpdatable.hpp> + +#include <vector> +#include <boost/shared_ptr.hpp> + +class SdrPage; + +//............................................................................. +namespace chart +{ +//............................................................................. + +class VCoordinateSystem; +class DrawModelWrapper; +class SeriesPlotterContainer; + +//----------------------------------------------------------------------------- +/** The ChartView is responsible to manage the generation of Drawing Objects +for visualization on a given OutputDevice. The ChartModel is responsible to notify changes to the view. +The view than changes to state dirty. The view can be updated with call 'update'. + +The View is not responsible to handle single user events (that is instead done by the ChartWindow). +*/ + +class ChartView : public ::cppu::WeakImplHelper9< + ::com::sun::star::lang::XInitialization + , ::com::sun::star::lang::XServiceInfo + , ::com::sun::star::datatransfer::XTransferable + ,::com::sun::star::lang::XUnoTunnel + //::com::sun::star::lang::XComponent ??? + //::com::sun::star::uno::XWeak // implemented by WeakImplHelper(optional interface) + //::com::sun::star::uno::XInterface // implemented by WeakImplHelper(optional interface) + //::com::sun::star::lang::XTypeProvider // implemented by WeakImplHelper + ,::com::sun::star::util::XModifyListener + ,::com::sun::star::util::XModeChangeBroadcaster + ,::com::sun::star::util::XUpdatable + ,::com::sun::star::beans::XPropertySet + ,::com::sun::star::lang::XMultiServiceFactory + > + , public ExplicitValueProvider + , private SfxListener +{ +public: + ChartView(::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext > const & xContext); + virtual ~ChartView(); + + // ___lang::XServiceInfo___ + APPHELPER_XSERVICEINFO_DECL() + APPHELPER_SERVICE_FACTORY_HELPER(ChartView) + + // ___lang::XInitialization___ + virtual void SAL_CALL initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) + throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + + // ___ExplicitValueProvider___ + virtual sal_Bool getExplicitValuesForAxis( + ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XAxis > xAxis + , ExplicitScaleData& rExplicitScale + , ExplicitIncrementData& rExplicitIncrement ); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + getShapeForCID( const rtl::OUString& rObjectCID ); + + virtual ::com::sun::star::awt::Rectangle getRectangleOfObject( const rtl::OUString& rObjectCID, bool bSnapRect=false ); + + virtual ::com::sun::star::awt::Rectangle getDiagramRectangleExcludingAxes(); + + ::boost::shared_ptr< DrawModelWrapper > getDrawModelWrapper(); + + // ___XTransferable___ + virtual ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) + throw (::com::sun::star::datatransfer::UnsupportedFlavorException + , ::com::sun::star::io::IOException + , ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) + throw (::com::sun::star::uno::RuntimeException); + + //------------------------------------------------------------------------------------- + // ::com::sun::star::util::XEventListener (base of XCloseListener and XModifyListener) + //------------------------------------------------------------------------------------- + virtual void SAL_CALL + disposing( const ::com::sun::star::lang::EventObject& Source ) + throw (::com::sun::star::uno::RuntimeException); + + //----------------------------------------------------------------- + // ::com::sun::star::util::XModifyListener + //----------------------------------------------------------------- + virtual void SAL_CALL modified( + const ::com::sun::star::lang::EventObject& aEvent ) + throw (::com::sun::star::uno::RuntimeException); + + //SfxListener + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); + + //----------------------------------------------------------------- + // ::com::sun::star::util::XModeChangeBroadcaster + //----------------------------------------------------------------- + + virtual void SAL_CALL addModeChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModeChangeListener >& _rxListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeModeChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModeChangeListener >& _rxListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addModeChangeApproveListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModeChangeApproveListener >& _rxListener ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeModeChangeApproveListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModeChangeApproveListener >& _rxListener ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + + //----------------------------------------------------------------- + // ::com::sun::star::util::XUpdatable + //----------------------------------------------------------------- + virtual void SAL_CALL update() throw (::com::sun::star::uno::RuntimeException); + + //----------------------------------------------------------------- + // ::com::sun::star::beans::XPropertySet + //----------------------------------------------------------------- + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + //----------------------------------------------------------------- + // ::com::sun::star::lang::XMultiServiceFactory + //----------------------------------------------------------------- + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstance( const ::rtl::OUString& aServiceSpecifier ) + throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstanceWithArguments( + const ::rtl::OUString& ServiceSpecifier, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Arguments ) + throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getAvailableServiceNames() throw (::com::sun::star::uno::RuntimeException); + + // for ExplicitValueProvider + // ____ XUnoTunnel ___ + virtual ::sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< ::sal_Int8 >& aIdentifier ) + throw (::com::sun::star::uno::RuntimeException); + +private: //methods + ChartView(); + + void createShapes(); + void getMetaFile( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream >& xOutStream + , bool bUseHighContrast ); + SdrPage* getSdrPage(); + + void impl_setChartModel( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel >& xChartModel ); + void impl_deleteCoordinateSystems(); + void impl_notifyModeChangeListener( const rtl::OUString& rNewMode ); + + void impl_refreshAddIn(); + bool impl_AddInDrawsAllByItself(); + + void impl_updateView(); + + ::com::sun::star::awt::Rectangle impl_createDiagramAndContent( SeriesPlotterContainer& rSeriesPlotterContainer + , const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes>& xDiagramPlusAxes_Shapes + , const ::com::sun::star::awt::Point& rAvailablePos + , const ::com::sun::star::awt::Size& rAvailableSize + , const ::com::sun::star::awt::Size& rPageSize + , bool bUseFixedInnerSize + , const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape>& xDiagram_MarkHandles ); + + +private: //member + ::osl::Mutex m_aMutex; + + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext> + m_xCC; + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel > + m_xChartModel; + + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory> + m_xShapeFactory; + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage> + m_xDrawPage; + + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xDashTable; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xGradientTable; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xHatchTable; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xBitmapTable; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xTransGradientTable; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xMarkerTable; + + ::boost::shared_ptr< DrawModelWrapper > m_pDrawModelWrapper; + + std::vector< VCoordinateSystem* > m_aVCooSysList; + + ::cppu::OMultiTypeInterfaceContainerHelper + m_aListenerContainer; + + bool volatile m_bViewDirty; //states wether the view needs to be rebuild + bool volatile m_bInViewUpdate; + bool volatile m_bViewUpdatePending; + bool volatile m_bRefreshAddIn; + + //better performance for big data + ::com::sun::star::awt::Size m_aPageResolution; + bool m_bPointsWereSkipped; + + //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% + sal_Int32 m_nScaleXNumerator; + sal_Int32 m_nScaleXDenominator; + sal_Int32 m_nScaleYNumerator; + sal_Int32 m_nScaleYDenominator; + + sal_Bool m_bSdrViewIsInEditMode; + + ::com::sun::star::awt::Rectangle m_aResultingDiagramRectangleExcludingAxes; +}; + +//............................................................................. +} //namespace chart +//............................................................................. + +#endif diff --git a/chart2/source/view/main/Clipping.cxx b/chart2/source/view/main/Clipping.cxx new file mode 100644 index 000000000000..7eced29eb271 --- /dev/null +++ b/chart2/source/view/main/Clipping.cxx @@ -0,0 +1,304 @@ +/************************************************************************* + * + * 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 "Clipping.hxx" +#include "CommonConverters.hxx" +#include "BaseGFXHelper.hxx" + +#include <com/sun/star/drawing/Position3D.hpp> +#include <com/sun/star/drawing/DoubleSequence.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using ::basegfx::B2DRectangle; +using ::basegfx::B2DTuple; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +namespace{ +/** @descr This is a supporting function for lcl_clip2d. It computes a new parametric + value for an entering (dTE) or leaving (dTL) intersection point with one + of the edges bounding the clipping area. + For explanation of the parameters please refer to : + + Liang-Biarsky parametric line-clipping algorithm as described in: + Computer Graphics: principles and practice, 2nd ed., + James D. Foley et al., + Section 3.12.4 on page 117. +*/ +bool lcl_CLIPt(double fDenom,double fNum, double & fTE, double & fTL) +{ + double fT; + + if (fDenom > 0) // Intersection enters: PE + { + fT = fNum / fDenom; // Parametric value at the intersection. + if (fT > fTL) // fTE and fTL crossover + return false; // therefore reject the line. + else if (fT > fTE) // A new fTE has been found. + fTE = fT; + } + else if (fDenom < 0) // Intersection leaves: PL + { + fT = fNum / fDenom; // Parametric Value at the intersection. + if (fT < fTE) // fTE and fTL crossover + return false; // therefore reject the line. + else if (fT < fTL) // A new fTL has been found. + fTL = fT; + } + else if (fNum > 0) + return false; // Line lies on the outside of the edge. + + return true; +} + +/** @descr The line given by it's two endpoints rP0 and rP1 is clipped at the rectangle + rRectangle. If there is at least a part of it visible then sal_True is returned and + the endpoints of that part are stored in rP0 and rP1. The points rP0 and rP1 + may have the same coordinates. + @param rP0 Start point of the line to clip. Modified to contain a start point inside + the clipping area if possible. + @param rP1 End point of the line to clip. Modified to contain an end point inside + the clipping area if possible. + @param rRectangle Clipping area. + @return If the line lies completely or partly inside the clipping area then TRUE + is returned. If the line lies completely outside then sal_False is returned and rP0 and + rP1 are left unmodified. +*/ +bool lcl_clip2d(B2DTuple& rPoint0, B2DTuple& rPoint1, const B2DRectangle& rRectangle) +{ + //Direction vector of the line. + B2DTuple aDirection = rPoint1 - rPoint0; + + if( aDirection.getX()==0 && aDirection.getY()==0 && rRectangle.isInside(rPoint0) ) + { + // Degenerate case of a zero length line. + return true; + } + else + { + // Values of the line parameter where the line enters resp. leaves the rectangle. + double fTE = 0, + fTL = 1; + + // Test wether at least a part lies in the four half-planes with respect to + // the rectangles four edges. + if( lcl_CLIPt(aDirection.getX(), rRectangle.getMinX() - rPoint0.getX(), fTE, fTL) ) + if( lcl_CLIPt(-aDirection.getX(), rPoint0.getX() - rRectangle.getMaxX(), fTE, fTL) ) + if( lcl_CLIPt(aDirection.getY(), rRectangle.getMinY() - rPoint0.getY(), fTE, fTL) ) + if( lcl_CLIPt(-aDirection.getY(), rPoint0.getY() - rRectangle.getMaxY(), fTE, fTL) ) + { + // At least a part is visible. + if (fTL < 1) + { + // Compute the new end point. + rPoint1.setX( rPoint0.getX() + fTL * aDirection.getX() ); + rPoint1.setY( rPoint0.getY() + fTL * aDirection.getY() ); + } + if (fTE > 0) + { + // Compute the new starting point. + rPoint0.setX( rPoint0.getX() + fTE * aDirection.getX() ); + rPoint0.setY( rPoint0.getY() + fTE * aDirection.getY() ); + } + return true; + } + + // Line is not visible. + return false; + } +} + +bool lcl_clip2d_(drawing::Position3D& rPoint0, drawing::Position3D& rPoint1, const B2DRectangle& rRectangle) +{ + B2DTuple aP0(rPoint0.PositionX,rPoint0.PositionY); + B2DTuple aP1(rPoint1.PositionX,rPoint1.PositionY); + bool bRet = lcl_clip2d( aP0, aP1, rRectangle ); + + rPoint0.PositionX = aP0.getX(); + rPoint0.PositionY = aP0.getY(); + rPoint1.PositionX = aP1.getX(); + rPoint1.PositionY = aP1.getY(); + + return bRet; +} + +void lcl_addPointToPoly( drawing::PolyPolygonShape3D& rPoly + , const drawing::Position3D& rPos + , sal_Int32 nPolygonIndex + , std::vector< sal_Int32 >& rResultPointCount + , sal_Int32 nReservePointCount ) +{ + if(nPolygonIndex<0) + { + OSL_ENSURE( false, "The polygon index needs to be > 0"); + nPolygonIndex=0; + } + + //make sure that we have enough polygons + if(nPolygonIndex >= rPoly.SequenceX.getLength() ) + { + rPoly.SequenceX.realloc(nPolygonIndex+1); + rPoly.SequenceY.realloc(nPolygonIndex+1); + rPoly.SequenceZ.realloc(nPolygonIndex+1); + rResultPointCount.resize(nPolygonIndex+1,0); + } + + drawing::DoubleSequence* pOuterSequenceX = &rPoly.SequenceX.getArray()[nPolygonIndex]; + drawing::DoubleSequence* pOuterSequenceY = &rPoly.SequenceY.getArray()[nPolygonIndex]; + drawing::DoubleSequence* pOuterSequenceZ = &rPoly.SequenceZ.getArray()[nPolygonIndex]; + + sal_Int32 nNewResultPointCount = rResultPointCount[nPolygonIndex]+1; + sal_Int32 nSeqLength = pOuterSequenceX->getLength(); + + if( nSeqLength <= nNewResultPointCount ) + { + sal_Int32 nReallocLength = nReservePointCount; + if( nNewResultPointCount > nReallocLength ) + { + nReallocLength = nNewResultPointCount; + DBG_ERROR("this should not be the case to avoid performance problems"); + } + pOuterSequenceX->realloc(nReallocLength); + pOuterSequenceY->realloc(nReallocLength); + pOuterSequenceZ->realloc(nReallocLength); + } + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + pInnerSequenceX[nNewResultPointCount-1] = rPos.PositionX; + pInnerSequenceY[nNewResultPointCount-1] = rPos.PositionY; + pInnerSequenceZ[nNewResultPointCount-1] = rPos.PositionZ; + rResultPointCount[nPolygonIndex]=nNewResultPointCount; +} + +}//end anonymous namespace + +void Clipping::clipPolygonAtRectangle( const drawing::PolyPolygonShape3D& rPolygon + , const B2DRectangle& rRectangle + , drawing::PolyPolygonShape3D& aResult + , bool bSplitPiecesToDifferentPolygons ) +{ + aResult.SequenceX.realloc(0); + aResult.SequenceY.realloc(0); + aResult.SequenceZ.realloc(0); + + if(!rPolygon.SequenceX.getLength()) + return; + + //need clipping?: + { + ::basegfx::B3DRange a3DRange( BaseGFXHelper::getBoundVolume( rPolygon ) ); + ::basegfx::B2DRange a2DRange( a3DRange.getMinX(), a3DRange.getMinY(), a3DRange.getMaxX(), a3DRange.getMaxY() ); + if( rRectangle.isInside( a2DRange ) ) + { + aResult = rPolygon; + return; + } + else + { + a2DRange.intersect( rRectangle ); + if( a2DRange.isEmpty() ) + return; + } + } + + // + std::vector< sal_Int32 > aResultPointCount;//per polygon index + + //apply clipping: + drawing::Position3D aFrom; + drawing::Position3D aTo; + + sal_Int32 nNewPolyIndex = 0; + sal_Int32 nOldPolyCount = rPolygon.SequenceX.getLength(); + for(sal_Int32 nOldPolyIndex=0; nOldPolyIndex<nOldPolyCount; nOldPolyIndex++, nNewPolyIndex++ ) + { + sal_Int32 nOldPointCount = rPolygon.SequenceX[nOldPolyIndex].getLength(); + + // set last point to a position outside the rectangle, such that the first + // time lcl_clip2d returns true, the comparison to last will always yield false + drawing::Position3D aLast(rRectangle.getMinX()-1.0,rRectangle.getMinY()-1.0, 0.0 ); + + for(sal_Int32 nOldPoint=1; nOldPoint<nOldPointCount; nOldPoint++) + { + aFrom = getPointFromPoly(rPolygon,nOldPoint-1,nOldPolyIndex); + aTo = getPointFromPoly(rPolygon,nOldPoint,nOldPolyIndex); + if( lcl_clip2d_(aFrom, aTo, rRectangle) ) + { + // compose an Polygon of as many consecutive points as possible + if(aFrom == aLast) + { + if( !(aTo==aFrom) ) + { + lcl_addPointToPoly( aResult, aTo, nNewPolyIndex, aResultPointCount, nOldPointCount ); + } + } + else + { + if( bSplitPiecesToDifferentPolygons && nOldPoint!=1 ) + { + if( nNewPolyIndex < aResult.SequenceX.getLength() + && aResultPointCount[nNewPolyIndex]>0 ) + nNewPolyIndex++; + } + lcl_addPointToPoly( aResult, aFrom, nNewPolyIndex, aResultPointCount, nOldPointCount ); + if( !(aTo==aFrom) ) + lcl_addPointToPoly( aResult, aTo, nNewPolyIndex, aResultPointCount, nOldPointCount ); + } + aLast = aTo; + } + } + } + //free unused space + for( sal_Int32 nPolygonIndex = aResultPointCount.size(); nPolygonIndex--; ) + { + drawing::DoubleSequence* pOuterSequenceX = &aResult.SequenceX.getArray()[nPolygonIndex]; + drawing::DoubleSequence* pOuterSequenceY = &aResult.SequenceY.getArray()[nPolygonIndex]; + drawing::DoubleSequence* pOuterSequenceZ = &aResult.SequenceZ.getArray()[nPolygonIndex]; + + sal_Int32 nUsedPointCount = aResultPointCount[nPolygonIndex]; + pOuterSequenceX->realloc(nUsedPointCount); + pOuterSequenceY->realloc(nUsedPointCount); + pOuterSequenceZ->realloc(nUsedPointCount); + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/DataPointSymbolSupplier.cxx b/chart2/source/view/main/DataPointSymbolSupplier.cxx new file mode 100644 index 000000000000..d59a011cd429 --- /dev/null +++ b/chart2/source/view/main/DataPointSymbolSupplier.cxx @@ -0,0 +1,66 @@ +/************************************************************************* + * + * 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 "chartview/DataPointSymbolSupplier.hxx" +#include "ShapeFactory.hxx" +#include "macros.hxx" + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +//using namespace ::com::sun::star::chart2; + +uno::Reference< drawing::XShapes > DataPointSymbolSupplier::create2DSymbolList( + uno::Reference< lang::XMultiServiceFactory > xShapeFactory + , const uno::Reference< drawing::XShapes >& xTarget + , const drawing::Direction3D& rSize ) +{ + uno::Reference< drawing::XShape > xGroup( + xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.GroupShape" ) ), uno::UNO_QUERY ); + if(xTarget.is()) + xTarget->add(xGroup); + uno::Reference< drawing::XShapes > xGroupShapes = + uno::Reference<drawing::XShapes>( xGroup, uno::UNO_QUERY ); + + ShapeFactory aShapeFactory(xShapeFactory); + drawing::Position3D aPos(0,0,0); + for(sal_Int32 nS=0;nS<ShapeFactory::getSymbolCount();nS++) + { + aShapeFactory.createSymbol2D( xGroupShapes, aPos, rSize, nS ); + } + return xGroupShapes; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/DrawModelWrapper.cxx b/chart2/source/view/main/DrawModelWrapper.cxx new file mode 100644 index 000000000000..a23041ada673 --- /dev/null +++ b/chart2/source/view/main/DrawModelWrapper.cxx @@ -0,0 +1,409 @@ +/************************************************************************* + * + * 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 "chartview/DrawModelWrapper.hxx" +#include "macros.hxx" +#include "ShapeFactory.hxx" +#include "ChartItemPool.hxx" +#include "ObjectIdentifier.hxx" +#include <svx/unomodel.hxx> +#include <svl/itempool.hxx> +// header for class SfxBoolItem +#include <svl/eitem.hxx> +// header for define EE_PARA_HYPHENATE +#include <editeng/eeitem.hxx> +// header for class Svx3DPercentDiagonalItem +#include <svx/svx3ditems.hxx> +// header for class SvtPathOptions +#include <unotools/pathoptions.hxx> +// header E3dObjFactory +#include <svx/objfac3d.hxx> +// header for class SdrObjList +#include <svx/svdpage.hxx> +// header for SvxUnoXDashTable_createInstance +#include <svx/XPropertyTable.hxx> +// header for class XDashList +#include <svx/xtable.hxx> +// header for class SdrOutliner +#include <svx/svdoutl.hxx> +// header for class LinguMgr +#include <editeng/unolingu.hxx> +// header for class Application +#include <vcl/svapp.hxx> +// header for class VirtualDevice +#include <vcl/virdev.hxx> + +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> + +#include <sfx2/objsh.hxx> +#include <com/sun/star/linguistic2/XHyphenator.hpp> +#include <com/sun/star/linguistic2/XSpellChecker1.hpp> + +using namespace ::com::sun::star; + +//............................................................................. +namespace +{ +// this code is copied from sfx2/source/doc/objembed.cxx +SfxObjectShell * lcl_GetParentObjectShell( const uno::Reference< frame::XModel > & xModel ) +{ + SfxObjectShell* pResult = NULL; + + try + { + uno::Reference< container::XChild > xChildModel( xModel, uno::UNO_QUERY ); + if ( xChildModel.is() ) + { + uno::Reference< lang::XUnoTunnel > xParentTunnel( xChildModel->getParent(), uno::UNO_QUERY ); + if ( xParentTunnel.is() ) + { + SvGlobalName aSfxIdent( SFX_GLOBAL_CLASSID ); + pResult = reinterpret_cast< SfxObjectShell * >( + xParentTunnel->getSomething( uno::Sequence< sal_Int8 >( aSfxIdent.GetByteSequence() ) ) ); + } + } + } + catch( uno::Exception& ) + { + // TODO: error handling + } + + return pResult; +} + +// this code is copied from sfx2/source/doc/objembed.cxx. It is a workaround to +// get the reference device (e.g. printer) fromthe parent document +OutputDevice * lcl_GetParentRefDevice( const uno::Reference< frame::XModel > & xModel ) +{ + SfxObjectShell * pParent = lcl_GetParentObjectShell( xModel ); + if ( pParent ) + return pParent->GetDocumentRefDev(); + return NULL; +} + +} // anonymous namespace + +//.. ........................................................................... +namespace chart +{ +//............................................................................. + +DrawModelWrapper::DrawModelWrapper( + uno::Reference<uno::XComponentContext> const & xContext ) + : SdrModel( SvtPathOptions().GetPalettePath() ) + , m_xMCF(0) + , m_pChartItemPool(0) + , m_xMainDrawPage(0) + , m_xHiddenDrawPage(0) + , m_apRefDevice(0) +{ + m_pChartItemPool = ChartItemPool::CreateChartItemPool(); + + m_xMCF = xContext->getServiceManager(); + + SetScaleUnit(MAP_100TH_MM); + SetScaleFraction(Fraction(1, 1)); + SetDefaultFontHeight(423); // 12pt + + SfxItemPool* pMasterPool = &GetItemPool(); + pMasterPool->SetDefaultMetric(SFX_MAPUNIT_100TH_MM); + pMasterPool->SetPoolDefaultItem(SfxBoolItem(EE_PARA_HYPHENATE, sal_True) ); + pMasterPool->SetPoolDefaultItem(Svx3DPercentDiagonalItem (5)); + + SfxItemPool* pPool = pMasterPool; + // append chart pool to end of pool chain + for (;;) + { + SfxItemPool* pSecondary = pPool->GetSecondaryPool(); + if (!pSecondary) + break; + + pPool = pSecondary; + } + pPool->SetSecondaryPool(m_pChartItemPool); + pMasterPool->FreezeIdRanges(); + + //this factory needs to be created before first use of 3D scenes once upon an office runtime + //@todo in future this should be done by drawing engine itself on demand + static bool b3dFactoryInitialized = false; + if(!b3dFactoryInitialized) + { + E3dObjFactory aObjFactory; + b3dFactoryInitialized = true; + } + + //Hyphenyation and spellchecking + SdrOutliner& rOutliner = GetDrawOutliner(); + try + { + uno::Reference< linguistic2::XHyphenator > xHyphenator( LinguMgr::GetHyphenator() ); + if( xHyphenator.is() ) + rOutliner.SetHyphenator( xHyphenator ); + + uno::Reference< linguistic2::XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() ); + if ( xSpellChecker.is() ) + rOutliner.SetSpeller( xSpellChecker ); + } + catch(...) + { + DBG_ERROR("Can't get Hyphenator or SpellChecker for chart"); + } + + //ref device for font rendering + OutputDevice* pDefaultDevice = rOutliner.GetRefDevice(); + if( !pDefaultDevice ) + pDefaultDevice = Application::GetDefaultDevice(); + m_apRefDevice = std::auto_ptr< OutputDevice >( new VirtualDevice( *pDefaultDevice ) ); + MapMode aMapMode = m_apRefDevice->GetMapMode(); + aMapMode.SetMapUnit(MAP_100TH_MM); + m_apRefDevice->SetMapMode(aMapMode); + SetRefDevice(m_apRefDevice.get()); + rOutliner.SetRefDevice(m_apRefDevice.get()); +} + +DrawModelWrapper::~DrawModelWrapper() +{ + //remove m_pChartItemPool from pool chain + if(m_pChartItemPool) + { + SfxItemPool* pPool = &GetItemPool(); + for (;;) + { + SfxItemPool* pSecondary = pPool->GetSecondaryPool(); + if(pSecondary == m_pChartItemPool) + { + pPool->SetSecondaryPool (NULL); + break; + } + pPool = pSecondary; + } + SfxItemPool::Free(m_pChartItemPool); + } +} + +uno::Reference< uno::XInterface > DrawModelWrapper +::createUnoModel() +{ + uno::Reference< lang::XComponent > xComponent = new SvxUnoDrawingModel( this ); //tell Andreas Schluens if SvxUnoDrawingModel is not needed anymore -> remove export from svx to avoid link problems in writer + return uno::Reference< uno::XInterface >::query( xComponent ); +} + +uno::Reference< frame::XModel > DrawModelWrapper::getUnoModel() +{ + uno::Reference< uno::XInterface > xI = this->SdrModel::getUnoModel(); + return uno::Reference<frame::XModel>::query( xI ); +} + +SdrModel& DrawModelWrapper::getSdrModel() +{ + return *this; +} + +uno::Reference< lang::XMultiServiceFactory > DrawModelWrapper::getShapeFactory() +{ + uno::Reference< lang::XMultiServiceFactory > xShapeFactory( this->getUnoModel(), uno::UNO_QUERY ); + return xShapeFactory; +} + +uno::Reference< drawing::XDrawPage > DrawModelWrapper::getMainDrawPage() +{ + //create draw page: + if( !m_xMainDrawPage.is() ) + { + uno::Reference< drawing::XDrawPagesSupplier > xDrawPagesSuplier( this->getUnoModel(), uno::UNO_QUERY ); + if( xDrawPagesSuplier.is() ) + { + uno::Reference< drawing::XDrawPages > xDrawPages( xDrawPagesSuplier->getDrawPages () ); + if( xDrawPages->getCount()>1 ) + { + uno::Any aPage = xDrawPages->getByIndex( 0 ) ; + aPage >>= m_xMainDrawPage; + } + if(!m_xMainDrawPage.is()) + { + m_xMainDrawPage = xDrawPages->insertNewByIndex( 0 ); + } + } + } + //ensure that additional shapes are in front of the chart objects so create the chart root before + ShapeFactory(this->getShapeFactory()).getOrCreateChartRootShape( m_xMainDrawPage ); + return m_xMainDrawPage; +} +uno::Reference< drawing::XDrawPage > DrawModelWrapper::getHiddenDrawPage() +{ + if( !m_xHiddenDrawPage.is() ) + { + uno::Reference< drawing::XDrawPagesSupplier > xDrawPagesSuplier( this->getUnoModel(), uno::UNO_QUERY ); + if( xDrawPagesSuplier.is() ) + { + uno::Reference< drawing::XDrawPages > xDrawPages( xDrawPagesSuplier->getDrawPages () ); + if( xDrawPages->getCount()>1 ) + { + uno::Any aPage = xDrawPages->getByIndex( 1 ) ; + aPage >>= m_xHiddenDrawPage; + } + + if(!m_xHiddenDrawPage.is()) + { + if( xDrawPages->getCount()==0 ) + m_xMainDrawPage = xDrawPages->insertNewByIndex( 0 ); + m_xHiddenDrawPage = xDrawPages->insertNewByIndex( 1 ); + } + } + } + return m_xHiddenDrawPage; +} +void DrawModelWrapper::clearMainDrawPage() +{ + //uno::Reference<drawing::XShapes> xChartRoot( m_xMainDrawPage, uno::UNO_QUERY ); + uno::Reference<drawing::XShapes> xChartRoot( ShapeFactory::getChartRootShape( m_xMainDrawPage ) ); + if( xChartRoot.is() ) + { + sal_Int32 nSubCount = xChartRoot->getCount(); + uno::Reference< drawing::XShape > xShape; + for( sal_Int32 nS = nSubCount; nS--; ) + { + if( xChartRoot->getByIndex( nS ) >>= xShape ) + xChartRoot->remove( xShape ); + } + } +} + +uno::Reference< drawing::XShapes > DrawModelWrapper::getChartRootShape( + const uno::Reference< drawing::XDrawPage>& xDrawPage ) +{ + return ShapeFactory::getChartRootShape( xDrawPage ); +} + +void DrawModelWrapper::lockControllers() +{ + uno::Reference< frame::XModel > xDrawModel( this->getUnoModel() ); + if( xDrawModel.is()) + xDrawModel->lockControllers(); +} +void DrawModelWrapper::unlockControllers() +{ + uno::Reference< frame::XModel > xDrawModel( this->getUnoModel() ); + if( xDrawModel.is()) + xDrawModel->unlockControllers(); +} + +void DrawModelWrapper::attachParentReferenceDevice( const uno::Reference< frame::XModel > & xChartModel ) +{ + OutputDevice * pParentRefDev( lcl_GetParentRefDevice( xChartModel )); + if( pParentRefDev ) + { + SetRefDevice( pParentRefDev ); + } +} + +OutputDevice* DrawModelWrapper::getReferenceDevice() const +{ + return SdrModel::GetRefDevice(); +} + +SfxItemPool& DrawModelWrapper::GetItemPool() +{ + return this->SdrModel::GetItemPool(); +} +const SfxItemPool& DrawModelWrapper::GetItemPool() const +{ + return this->SdrModel::GetItemPool(); +} +XColorTable* DrawModelWrapper::GetColorTable() const +{ + return this->SdrModel::GetColorTable(); +} +XDashList* DrawModelWrapper::GetDashList() const +{ + return this->SdrModel::GetDashList(); +} +XLineEndList* DrawModelWrapper::GetLineEndList() const +{ + return this->SdrModel::GetLineEndList(); +} +XGradientList* DrawModelWrapper::GetGradientList() const +{ + return this->SdrModel::GetGradientList(); +} +XHatchList* DrawModelWrapper::GetHatchList() const +{ + return this->SdrModel::GetHatchList(); +} +XBitmapList* DrawModelWrapper::GetBitmapList() const +{ + return this->SdrModel::GetBitmapList(); +} + +SdrObject* DrawModelWrapper::getNamedSdrObject( const rtl::OUString& rName ) +{ + if(rName.getLength()==0) + return 0; + return getNamedSdrObject( rName, GetPage(0) ); +} + +SdrObject* DrawModelWrapper::getNamedSdrObject( const String& rObjectCID, SdrObjList* pSearchList ) +{ + if(!pSearchList || rObjectCID.Len()==0) + return 0; + sal_uLong nCount = pSearchList->GetObjCount(); + for( sal_uLong nN=0; nN<nCount; nN++ ) + { + SdrObject* pObj = pSearchList->GetObj(nN); + if(!pObj) + continue; + if( ObjectIdentifier::areIdenticalObjects( rObjectCID, pObj->GetName() ) ) + return pObj; + pObj = DrawModelWrapper::getNamedSdrObject( rObjectCID, pObj->GetSubList() ); + if(pObj) + return pObj; + } + return 0; +} + +bool DrawModelWrapper::removeShape( const uno::Reference< drawing::XShape >& xShape ) +{ + uno::Reference< container::XChild > xChild( xShape, uno::UNO_QUERY ); + if( xChild.is() ) + { + uno::Reference<drawing::XShapes> xShapes( xChild->getParent(), uno::UNO_QUERY ); + if( xShapes.is() ) + { + xShapes->remove(xShape); + return true; + } + } + return false; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/LabelPositionHelper.cxx b/chart2/source/view/main/LabelPositionHelper.cxx new file mode 100644 index 000000000000..cd954f53b7ba --- /dev/null +++ b/chart2/source/view/main/LabelPositionHelper.cxx @@ -0,0 +1,485 @@ +/************************************************************************* + * + * 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 "LabelPositionHelper.hxx" +#include "PlottingPositionHelper.hxx" +#include "CommonConverters.hxx" +#include "PropertyMapper.hxx" +#include "ShapeFactory.hxx" +#include "macros.hxx" +#include "RelativeSizeHelper.hxx" +#include <com/sun/star/drawing/TextVerticalAdjust.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +LabelPositionHelper::LabelPositionHelper( + PlottingPositionHelper* pPosHelper + , sal_Int32 nDimensionCount + , const uno::Reference< drawing::XShapes >& xLogicTarget + , ShapeFactory* pShapeFactory ) + : m_pPosHelper(pPosHelper) + , m_nDimensionCount(nDimensionCount) + , m_xLogicTarget(xLogicTarget) + , m_pShapeFactory(pShapeFactory) +{ +} + +LabelPositionHelper::~LabelPositionHelper() +{ +} + +awt::Point LabelPositionHelper::transformSceneToScreenPosition( const drawing::Position3D& rScenePosition3D ) const +{ + return PlottingPositionHelper::transformSceneToScreenPosition( + rScenePosition3D, m_xLogicTarget, m_pShapeFactory, m_nDimensionCount ); +} + +void LabelPositionHelper::changeTextAdjustment( tAnySequence& rPropValues, const tNameSequence& rPropNames, LabelAlignment eAlignment) +{ + //HorizontalAdjustment + { + drawing::TextHorizontalAdjust eHorizontalAdjust = drawing::TextHorizontalAdjust_CENTER; + if( LABEL_ALIGN_RIGHT==eAlignment || LABEL_ALIGN_RIGHT_TOP==eAlignment || LABEL_ALIGN_RIGHT_BOTTOM==eAlignment ) + eHorizontalAdjust = drawing::TextHorizontalAdjust_LEFT; + else if( LABEL_ALIGN_LEFT==eAlignment || LABEL_ALIGN_LEFT_TOP==eAlignment || LABEL_ALIGN_LEFT_BOTTOM==eAlignment ) + eHorizontalAdjust = drawing::TextHorizontalAdjust_RIGHT; + uno::Any* pHorizontalAdjustAny = PropertyMapper::getValuePointer(rPropValues,rPropNames,C2U("TextHorizontalAdjust")); + if(pHorizontalAdjustAny) + *pHorizontalAdjustAny = uno::makeAny(eHorizontalAdjust); + } + + //VerticalAdjustment + { + drawing::TextVerticalAdjust eVerticalAdjust = drawing::TextVerticalAdjust_CENTER; + if( LABEL_ALIGN_TOP==eAlignment || LABEL_ALIGN_RIGHT_TOP==eAlignment || LABEL_ALIGN_LEFT_TOP==eAlignment ) + eVerticalAdjust = drawing::TextVerticalAdjust_BOTTOM; + else if( LABEL_ALIGN_BOTTOM==eAlignment || LABEL_ALIGN_RIGHT_BOTTOM==eAlignment || LABEL_ALIGN_LEFT_BOTTOM==eAlignment ) + eVerticalAdjust = drawing::TextVerticalAdjust_TOP; + uno::Any* pVerticalAdjustAny = PropertyMapper::getValuePointer(rPropValues,rPropNames,C2U("TextVerticalAdjust")); + if(pVerticalAdjustAny) + *pVerticalAdjustAny = uno::makeAny(eVerticalAdjust); + } +} + +void lcl_doDynamicFontResize( uno::Any* pAOldAndNewFontHeightAny + , const awt::Size& rOldReferenceSize + , const awt::Size& rNewReferenceSize ) +{ + double fOldFontHeight = 0, fNewFontHeight; + if( pAOldAndNewFontHeightAny && ( *pAOldAndNewFontHeightAny >>= fOldFontHeight ) ) + { + fNewFontHeight = RelativeSizeHelper::calculate( fOldFontHeight, rOldReferenceSize, rNewReferenceSize ); + *pAOldAndNewFontHeightAny = uno::makeAny(fNewFontHeight); + } +} + +void LabelPositionHelper::doDynamicFontResize( tAnySequence& rPropValues + , const tNameSequence& rPropNames + , const uno::Reference< beans::XPropertySet >& xAxisModelProps + , const awt::Size& rNewReferenceSize + ) +{ + //------------------------- + //handle dynamic font resize: + awt::Size aOldReferenceSize; + if( xAxisModelProps->getPropertyValue( C2U("ReferencePageSize")) >>= aOldReferenceSize ) + { + uno::Any* pAOldAndNewFontHeightAny = PropertyMapper::getValuePointer( rPropValues, rPropNames, C2U("CharHeight") ); + lcl_doDynamicFontResize( pAOldAndNewFontHeightAny, aOldReferenceSize, rNewReferenceSize ); + pAOldAndNewFontHeightAny = PropertyMapper::getValuePointer( rPropValues, rPropNames, C2U("CharHeightAsian") ); + lcl_doDynamicFontResize( pAOldAndNewFontHeightAny, aOldReferenceSize, rNewReferenceSize ); + pAOldAndNewFontHeightAny = PropertyMapper::getValuePointer( rPropValues, rPropNames, C2U("CharHeightComplex") ); + lcl_doDynamicFontResize( pAOldAndNewFontHeightAny, aOldReferenceSize, rNewReferenceSize ); + } +} + +namespace +{ + +void lcl_correctRotation_Left( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize, bool bRotateAroundCenter ) +{ + //correct label positions for labels on a left side of something with a right centered alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = -aSize.Height*rtl::math::sin( fAnglePi )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = -aSize.Width*rtl::math::sin( fAnglePi )/2.0; + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-F_PI/2.0; + rfXCorrection = -aSize.Width *rtl::math::sin( beta ) + -aSize.Height *rtl::math::cos( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = -aSize.Width *rtl::math::cos( beta )/2.0; + else + rfYCorrection = -aSize.Width *rtl::math::cos( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = fAnglePi - F_PI; + rfXCorrection = -aSize.Width *rtl::math::cos( beta ) + -aSize.Height*rtl::math::sin( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = aSize.Width *rtl::math::sin( beta )/2.0; + else + rfYCorrection = aSize.Width *rtl::math::sin( beta ); + } + else + { + double beta = 2*F_PI - fAnglePi; + rfXCorrection = -aSize.Height*rtl::math::sin( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = aSize.Width*rtl::math::sin( beta )/2.0; + } +} + +void lcl_correctRotation_Right( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize, bool bRotateAroundCenter ) +{ + //correct label positions for labels on a right side of something with a left centered alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree== 0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = aSize.Height*rtl::math::sin( fAnglePi )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = aSize.Width*rtl::math::sin( fAnglePi )/2.0; + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = F_PI - fAnglePi; + rfXCorrection = aSize.Width *rtl::math::cos( beta ) + + aSize.Height*rtl::math::sin( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = aSize.Width *rtl::math::sin( beta )/2.0; + else + rfYCorrection = aSize.Width *rtl::math::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*F_PI/2.0 - fAnglePi; + rfXCorrection = aSize.Width *rtl::math::sin( beta ) + +aSize.Height*rtl::math::cos( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = -aSize.Width *rtl::math::cos( beta )/2.0; + else + rfYCorrection = -aSize.Width *rtl::math::cos( beta ); + } + else + { + rfXCorrection = aSize.Height*rtl::math::sin( 2*F_PI - fAnglePi )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = -aSize.Width*rtl::math::sin( 2*F_PI - fAnglePi )/2.0; + } +} + +void lcl_correctRotation_Top( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize, bool bRotateAroundCenter ) +{ + //correct label positions for labels on top of something with a bottom centered alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree== 0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = aSize.Height*rtl::math::sin( fAnglePi )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection += aSize.Width*rtl::math::cos( fAnglePi )/2.0; + rfYCorrection = -aSize.Width*rtl::math::sin( fAnglePi )/2.0; + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi - F_PI/2.0; + rfXCorrection = aSize.Height*rtl::math::cos( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection -= aSize.Width*rtl::math::sin( beta )/2.0; + rfYCorrection = -aSize.Width*rtl::math::cos( beta )/2.0 + - aSize.Height*rtl::math::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = fAnglePi - F_PI; + rfXCorrection = -aSize.Height *rtl::math::sin( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection += aSize.Width *rtl::math::cos( beta )/2.0; + rfYCorrection = -aSize.Width *rtl::math::sin( beta )/2.0 + -aSize.Height *rtl::math::cos( beta ); + } + else + { + rfXCorrection = aSize.Height*rtl::math::sin( fAnglePi )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection -= aSize.Width*rtl::math::cos( fAnglePi )/2.0; + rfYCorrection = aSize.Width*rtl::math::sin( fAnglePi )/2.0; + } +} + +void lcl_correctRotation_Bottom( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize, bool bRotateAroundCenter ) +{ + //correct label positions for labels below something with a top centered alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = -aSize.Height*rtl::math::sin( fAnglePi )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection -= aSize.Width *rtl::math::cos( fAnglePi )/2.0; + rfYCorrection = aSize.Width*rtl::math::sin( fAnglePi )/2.0; + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-F_PI/2.0; + rfXCorrection = -aSize.Height*rtl::math::cos( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection += aSize.Width *rtl::math::sin( beta )/2.0; + rfYCorrection = aSize.Width *rtl::math::cos( beta )/2.0 + +aSize.Height*rtl::math::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*F_PI/2.0 - fAnglePi; + rfXCorrection = aSize.Height*rtl::math::cos( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection -= aSize.Width *rtl::math::sin( beta )/2.0; + rfYCorrection = aSize.Height*rtl::math::sin( beta ) + +aSize.Width*rtl::math::cos( beta )/2.0; + } + else + { + double beta = 2*F_PI - fAnglePi; + rfXCorrection = aSize.Height*rtl::math::sin( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection += aSize.Width*rtl::math::cos( beta )/2.0; + rfYCorrection = aSize.Width*rtl::math::sin( beta )/2.0; + } +} + +void lcl_correctRotation_Left_Top( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize ) +{ + //correct position for labels at the left top corner of something with a bottom right alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfYCorrection = -aSize.Width*rtl::math::sin( fAnglePi ); + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-F_PI/2.0; + rfXCorrection = -aSize.Width*rtl::math::sin( beta ); + rfYCorrection = -aSize.Height*rtl::math::sin( beta ) + -aSize.Width*rtl::math::cos( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*F_PI/2.0 - fAnglePi; + rfXCorrection = -aSize.Height*rtl::math::cos( beta ) + -aSize.Width*rtl::math::sin( beta ); + rfYCorrection = -aSize.Height*rtl::math::sin( beta ); + } + else + { + rfXCorrection = aSize.Height*rtl::math::sin( fAnglePi ); + } +} + +void lcl_correctRotation_Left_Bottom( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize ) +{ + //correct position for labels at the left bottom corner of something with a top right alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = -aSize.Height*rtl::math::sin( fAnglePi ); + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-F_PI/2.0; + rfXCorrection = -aSize.Width*rtl::math::sin( beta ) + -aSize.Height*rtl::math::cos( beta );; + rfYCorrection = aSize.Height*rtl::math::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*F_PI/2.0 - fAnglePi; + rfXCorrection = -aSize.Width*rtl::math::sin( beta ); + rfYCorrection = aSize.Width*rtl::math::cos( beta ) + +aSize.Height*rtl::math::sin( beta ); + } + else + { + rfYCorrection = -aSize.Width*rtl::math::sin( fAnglePi ); + } +} + +void lcl_correctRotation_Right_Top( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize ) +{ + //correct position for labels at the right top corner of something with a bottom left alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = aSize.Height*rtl::math::sin( fAnglePi ); + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-F_PI/2.0; + rfXCorrection = aSize.Width*rtl::math::sin( beta ) + +aSize.Height*rtl::math::cos( beta ); + rfYCorrection = -aSize.Height*rtl::math::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*F_PI/2.0 - fAnglePi; + rfXCorrection = aSize.Width*rtl::math::sin( beta ); + rfYCorrection = -aSize.Width*rtl::math::cos( beta ) + -aSize.Height*rtl::math::sin( beta ); + } + else + { + rfYCorrection = aSize.Width*rtl::math::sin( fAnglePi ); + } +} + +void lcl_correctRotation_Right_Bottom( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize ) +{ + //correct position for labels at the right bottom corner of something with a top left alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfYCorrection = aSize.Width*rtl::math::sin( fAnglePi ); + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-F_PI/2.0; + rfXCorrection = aSize.Width*rtl::math::sin( beta ); + rfYCorrection = aSize.Height*rtl::math::sin( beta ) + +aSize.Width*rtl::math::cos( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*F_PI/2.0 - fAnglePi; + rfXCorrection = aSize.Height*rtl::math::cos( beta ) + +aSize.Width*rtl::math::sin( beta ); + rfYCorrection = aSize.Height*rtl::math::sin( beta ); + } + else + { + rfXCorrection = -aSize.Height*rtl::math::sin( fAnglePi ); + } +} + +}//end anonymous namespace + +void LabelPositionHelper::correctPositionForRotation( const uno::Reference< drawing::XShape >& xShape2DText + , LabelAlignment eLabelAlignment, const double fRotationAngle, bool bRotateAroundCenter ) +{ + if( !xShape2DText.is() ) + return; + + awt::Point aOldPos = xShape2DText->getPosition(); + awt::Size aSize = xShape2DText->getSize(); + + double fYCorrection = 0.0; + double fXCorrection = 0.0; + + double fAnglePositiveDegree = fRotationAngle; + while(fAnglePositiveDegree<0.0) + fAnglePositiveDegree+=360.0; + + switch(eLabelAlignment) + { + case LABEL_ALIGN_LEFT: + lcl_correctRotation_Left( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize, bRotateAroundCenter ); + break; + case LABEL_ALIGN_RIGHT: + lcl_correctRotation_Right( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize, bRotateAroundCenter ); + break; + case LABEL_ALIGN_TOP: + lcl_correctRotation_Top( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize, bRotateAroundCenter ); + break; + case LABEL_ALIGN_BOTTOM: + lcl_correctRotation_Bottom( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize, bRotateAroundCenter ); + break; + case LABEL_ALIGN_LEFT_TOP: + lcl_correctRotation_Left_Top( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize ); + break; + case LABEL_ALIGN_LEFT_BOTTOM: + lcl_correctRotation_Left_Bottom( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize ); + break; + case LABEL_ALIGN_RIGHT_TOP: + lcl_correctRotation_Right_Top( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize ); + break; + case LABEL_ALIGN_RIGHT_BOTTOM: + lcl_correctRotation_Right_Bottom( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize ); + break; + default: //LABEL_ALIGN_CENTER + break; + } + + xShape2DText->setPosition( awt::Point( + static_cast<sal_Int32>(aOldPos.X + fXCorrection ) + , static_cast<sal_Int32>(aOldPos.Y + fYCorrection ) ) ); +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/Linear3DTransformation.cxx b/chart2/source/view/main/Linear3DTransformation.cxx new file mode 100644 index 000000000000..9292ee6eb757 --- /dev/null +++ b/chart2/source/view/main/Linear3DTransformation.cxx @@ -0,0 +1,107 @@ +/************************************************************************* + * + * 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 "Linear3DTransformation.hxx" +#include <algorithm> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::RuntimeException; + +namespace chart +{ + + Linear3DTransformation::Linear3DTransformation( const drawing::HomogenMatrix& rHomMatrix, bool bSwapXAndY ) + : m_Matrix(rHomMatrix) + , m_bSwapXAndY(bSwapXAndY) +{} + +Linear3DTransformation::~Linear3DTransformation() +{} + +// ____ XTransformation ____ +Sequence< double > SAL_CALL Linear3DTransformation::transform( + const Sequence< double >& rSourceValues ) + throw (RuntimeException, + lang::IllegalArgumentException) +{ + double fX = rSourceValues[0]; + double fY = rSourceValues[1]; + double fZ = rSourceValues[2]; + if(m_bSwapXAndY) + std::swap(fX,fY); + Sequence< double > aNewVec(3); + double fZwi; + + fZwi = m_Matrix.Line1.Column1 * fX + + m_Matrix.Line1.Column2 * fY + + m_Matrix.Line1.Column3 * fZ + + m_Matrix.Line1.Column4; + aNewVec[0] = fZwi; + + fZwi = m_Matrix.Line2.Column1 * fX + + m_Matrix.Line2.Column2 * fY + + m_Matrix.Line2.Column3 * fZ + + m_Matrix.Line2.Column4; + aNewVec[1] = fZwi; + + fZwi = m_Matrix.Line3.Column1 * fX + + m_Matrix.Line3.Column2 * fY + + m_Matrix.Line3.Column3 * fZ + + m_Matrix.Line3.Column4; + aNewVec[2] = fZwi; + + fZwi = m_Matrix.Line4.Column1 * fX + + m_Matrix.Line4.Column2 * fY + + m_Matrix.Line4.Column3 * fZ + + m_Matrix.Line4.Column4; + if(fZwi != 1.0 && fZwi != 0.0) + { + aNewVec[0] /= fZwi; + aNewVec[1] /= fZwi; + aNewVec[2] /= fZwi; + } + return aNewVec; +} + +sal_Int32 SAL_CALL Linear3DTransformation::getSourceDimension() + throw (RuntimeException) +{ + return 3; +} + +sal_Int32 SAL_CALL Linear3DTransformation::getTargetDimension() + throw (RuntimeException) +{ + return 3; +} + + +} // namespace chart diff --git a/chart2/source/view/main/PlotterBase.cxx b/chart2/source/view/main/PlotterBase.cxx new file mode 100644 index 000000000000..8a71f45b4dbb --- /dev/null +++ b/chart2/source/view/main/PlotterBase.cxx @@ -0,0 +1,132 @@ +/************************************************************************* + * + * 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 "PlotterBase.hxx" +#include "PlottingPositionHelper.hxx" +#include "ShapeFactory.hxx" +#include <rtl/math.hxx> +#include <com/sun/star/chart2/DataPointLabel.hpp> +#include <tools/debug.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +PlotterBase::PlotterBase( sal_Int32 nDimensionCount ) + : m_xLogicTarget(NULL) + , m_xFinalTarget(NULL) + , m_xShapeFactory(NULL) + , m_pShapeFactory(NULL) + , m_aCID() + , m_nDimension(nDimensionCount) + , m_pPosHelper(NULL) +{ +} + +void PlotterBase::initPlotter( const uno::Reference< drawing::XShapes >& xLogicTarget + , const uno::Reference< drawing::XShapes >& xFinalTarget + , const uno::Reference< lang::XMultiServiceFactory >& xShapeFactory + , const rtl::OUString& rCID ) + throw (uno::RuntimeException) +{ + DBG_ASSERT(xLogicTarget.is()&&xFinalTarget.is()&&xShapeFactory.is(),"no proper initialization parameters"); + //is only allowed to be called once + m_xLogicTarget = xLogicTarget; + m_xFinalTarget = xFinalTarget; + m_xShapeFactory = xShapeFactory; + m_pShapeFactory = new ShapeFactory(xShapeFactory); + m_aCID = rCID; +} + +PlotterBase::~PlotterBase() +{ + delete m_pShapeFactory; +} + +void PlotterBase::setScales( const std::vector< ExplicitScaleData >& rScales, bool bSwapXAndYAxis ) +{ + DBG_ASSERT(m_nDimension<=static_cast<sal_Int32>(rScales.size()),"Dimension of Plotter does not fit two dimension of given scale sequence"); + m_pPosHelper->setScales( rScales, bSwapXAndYAxis ); +} + + +void PlotterBase::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix) +{ + DBG_ASSERT(m_nDimension==2,"Set this transformation only in case of 2D"); + if(m_nDimension!=2) + return; + m_pPosHelper->setTransformationSceneToScreen( rMatrix ); +} + +uno::Reference< drawing::XShapes > PlotterBase::createGroupShape( + const uno::Reference< drawing::XShapes >& xTarget + , ::rtl::OUString rName ) +{ + if(!m_xShapeFactory.is()) + return NULL; + + if(m_nDimension==2) + { + //create and add to target + return m_pShapeFactory->createGroup2D( xTarget, rName ); + } + else + { + //create and added to target + return m_pShapeFactory->createGroup3D( xTarget, rName ); + } +} + +bool PlotterBase::isValidPosition( const drawing::Position3D& rPos ) +{ + if( ::rtl::math::isNan(rPos.PositionX) ) + return false; + if( ::rtl::math::isNan(rPos.PositionY) ) + return false; + if( ::rtl::math::isNan(rPos.PositionZ) ) + return false; + if( ::rtl::math::isInf(rPos.PositionX) ) + return false; + if( ::rtl::math::isInf(rPos.PositionY) ) + return false; + if( ::rtl::math::isInf(rPos.PositionZ) ) + return false; + return true; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/PlottingPositionHelper.cxx b/chart2/source/view/main/PlottingPositionHelper.cxx new file mode 100644 index 000000000000..e257581d664b --- /dev/null +++ b/chart2/source/view/main/PlottingPositionHelper.cxx @@ -0,0 +1,715 @@ +/************************************************************************* + * + * 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 "PlottingPositionHelper.hxx" +#include "CommonConverters.hxx" +#include "ViewDefines.hxx" +#include "Linear3DTransformation.hxx" +#include "VPolarTransformation.hxx" +#include "ShapeFactory.hxx" +#include "PropertyMapper.hxx" +#include "DateHelper.hxx" + +#include <com/sun/star/chart/TimeUnit.hpp> +#include <com/sun/star/chart2/AxisType.hpp> +#include <com/sun/star/drawing/DoubleSequence.hpp> +#include <com/sun/star/drawing/Position3D.hpp> + +#include <rtl/math.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +PlottingPositionHelper::PlottingPositionHelper() + : m_aScales() + , m_aMatrixScreenToScene() + , m_xTransformationLogicToScene(NULL) + , m_bSwapXAndY( false ) + , m_nXResolution( 1000 ) + , m_nYResolution( 1000 ) + , m_nZResolution( 1000 ) + , m_bMaySkipPointsInRegressionCalculation( true ) + , m_bDateAxis(false) + , m_nTimeResolution( ::com::sun::star::chart::TimeUnit::DAY ) + , m_aNullDate(30,12,1899) + , m_fScaledCategoryWidth(1.0) + , m_bAllowShiftXAxisPos(false) + , m_bAllowShiftZAxisPos(false) +{ +} +PlottingPositionHelper::PlottingPositionHelper( const PlottingPositionHelper& rSource ) + : m_aScales( rSource.m_aScales ) + , m_aMatrixScreenToScene( rSource.m_aMatrixScreenToScene ) + , m_xTransformationLogicToScene( NULL ) //should be recalculated + , m_bSwapXAndY( rSource.m_bSwapXAndY ) + , m_nXResolution( rSource.m_nXResolution ) + , m_nYResolution( rSource.m_nYResolution ) + , m_nZResolution( rSource.m_nZResolution ) + , m_bMaySkipPointsInRegressionCalculation( rSource.m_bMaySkipPointsInRegressionCalculation ) + , m_bDateAxis( rSource.m_bDateAxis ) + , m_nTimeResolution( rSource.m_nTimeResolution ) + , m_aNullDate( rSource.m_aNullDate ) + , m_fScaledCategoryWidth( rSource.m_fScaledCategoryWidth ) + , m_bAllowShiftXAxisPos( rSource.m_bAllowShiftXAxisPos ) + , m_bAllowShiftZAxisPos( rSource.m_bAllowShiftZAxisPos ) +{ +} + +PlottingPositionHelper::~PlottingPositionHelper() +{ + +} + +PlottingPositionHelper* PlottingPositionHelper::clone() const +{ + PlottingPositionHelper* pRet = new PlottingPositionHelper(*this); + return pRet; +} + +PlottingPositionHelper* PlottingPositionHelper::createSecondaryPosHelper( const ExplicitScaleData& rSecondaryScale ) +{ + PlottingPositionHelper* pRet = this->clone(); + pRet->m_aScales[1]=rSecondaryScale; + return pRet; +} + +void PlottingPositionHelper::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix) +{ + m_aMatrixScreenToScene = HomogenMatrixToB3DHomMatrix(rMatrix); + m_xTransformationLogicToScene = NULL; +} + +void PlottingPositionHelper::setScales( const std::vector< ExplicitScaleData >& rScales, bool bSwapXAndYAxis ) +{ + m_aScales = rScales; + m_bSwapXAndY = bSwapXAndYAxis; + m_xTransformationLogicToScene = NULL; +} +const std::vector< ExplicitScaleData >& PlottingPositionHelper::getScales() const +{ + return m_aScales; +} + +uno::Reference< XTransformation > PlottingPositionHelper::getTransformationScaledLogicToScene() const +{ + //this is a standard transformation for a cartesian coordinate system + + //transformation from 2) to 4) //@todo 2) and 4) need a ink 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 + doUnshiftedLogicScaling( &MinX, &MinY, &MinZ ); + doUnshiftedLogicScaling( &MaxX, &MaxY, &MaxZ); + + if(m_bSwapXAndY) + { + std::swap(MinX,MinY); + std::swap(MaxX,MaxY); + std::swap(nXAxisOrientation,nYAxisOrientation); + } + + 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; + + double fScaleX = fScaleDirectionX*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthX; + double fScaleY = fScaleDirectionY*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthY; + double fScaleZ = fScaleDirectionZ*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthZ; + + aMatrix.scale(fScaleX, fScaleY, fScaleZ); + + if( AxisOrientation_MATHEMATICAL==nXAxisOrientation ) + aMatrix.translate(-MinX*fScaleX, 0.0, 0.0); + else + aMatrix.translate(-MaxX*fScaleX, 0.0, 0.0); + if( AxisOrientation_MATHEMATICAL==nYAxisOrientation ) + aMatrix.translate(0.0, -MinY*fScaleY, 0.0); + else + aMatrix.translate(0.0, -MaxY*fScaleY, 0.0); + if( AxisOrientation_MATHEMATICAL==nZAxisOrientation ) + aMatrix.translate(0.0, 0.0, -MaxZ*fScaleZ);//z direction in draw is reverse mathematical direction + else + aMatrix.translate(0.0, 0.0, -MinZ*fScaleZ); + + aMatrix = m_aMatrixScreenToScene*aMatrix; + + m_xTransformationLogicToScene = new Linear3DTransformation(B3DHomMatrixToHomogenMatrix( aMatrix ),m_bSwapXAndY); + } + return m_xTransformationLogicToScene; +} + +drawing::Position3D PlottingPositionHelper::transformLogicToScene( + double fX, double fY, double fZ, bool bClip ) const +{ + this->doLogicScaling( &fX,&fY,&fZ ); + if(bClip) + this->clipScaledLogicValues( &fX,&fY,&fZ ); + + return this->transformScaledLogicToScene( fX, fY, fZ, false ); +} + +drawing::Position3D PlottingPositionHelper::transformScaledLogicToScene( + double fX, double fY, double fZ, bool bClip ) const +{ + if( bClip ) + this->clipScaledLogicValues( &fX,&fY,&fZ ); + + drawing::Position3D aPos( fX, fY, fZ); + + uno::Reference< XTransformation > xTransformation = + this->getTransformationScaledLogicToScene(); + uno::Sequence< double > aSeq = + xTransformation->transform( Position3DToSequence(aPos) ); + return SequenceToPosition3D(aSeq); +} + +awt::Point PlottingPositionHelper::transformSceneToScreenPosition( const drawing::Position3D& rScenePosition3D + , const uno::Reference< drawing::XShapes >& xSceneTarget + , ShapeFactory* pShapeFactory + , sal_Int32 nDimensionCount ) +{ + //@todo would like to have a cheaper method to do this transformation + awt::Point aScreenPoint( static_cast<sal_Int32>(rScenePosition3D.PositionX), static_cast<sal_Int32>(rScenePosition3D.PositionY) ); + + //transformation from scene to screen (only neccessary for 3D): + if(3==nDimensionCount) + { + //create 3D anchor shape + tPropertyNameMap aDummyPropertyNameMap; + uno::Reference< drawing::XShape > xShape3DAnchor = pShapeFactory->createCube( xSceneTarget + , rScenePosition3D,drawing::Direction3D(1,1,1) + , 0, 0, aDummyPropertyNameMap); + //get 2D position from xShape3DAnchor + aScreenPoint = xShape3DAnchor->getPosition(); + xSceneTarget->remove(xShape3DAnchor); + } + return aScreenPoint; +} + +void PlottingPositionHelper::transformScaledLogicToScene( drawing::PolyPolygonShape3D& rPolygon ) const +{ + drawing::Position3D aScenePosition; + for( sal_Int32 nS = rPolygon.SequenceX.getLength(); nS--;) + { + drawing::DoubleSequence& xValues = rPolygon.SequenceX[nS]; + drawing::DoubleSequence& yValues = rPolygon.SequenceY[nS]; + drawing::DoubleSequence& zValues = rPolygon.SequenceZ[nS]; + for( sal_Int32 nP = xValues.getLength(); nP--; ) + { + double& fX = xValues[nP]; + double& fY = yValues[nP]; + double& fZ = zValues[nP]; + aScenePosition = this->transformScaledLogicToScene( fX,fY,fZ,true ); + fX = aScenePosition.PositionX; + fY = aScenePosition.PositionY; + fZ = aScenePosition.PositionZ; + } + } +} + + +void PlottingPositionHelper::clipScaledLogicValues( double* pX, double* pY, double* pZ ) const +{ + //get logic clip values: + double MinX = getLogicMinX(); + double MinY = getLogicMinY(); + double MinZ = getLogicMinZ(); + double MaxX = getLogicMaxX(); + double MaxY = getLogicMaxY(); + double MaxZ = getLogicMaxZ(); + + //apply scaling + doUnshiftedLogicScaling( &MinX, &MinY, &MinZ ); + doUnshiftedLogicScaling( &MaxX, &MaxY, &MaxZ); + + if(pX) + { + if( *pX < MinX ) + *pX = MinX; + else if( *pX > MaxX ) + *pX = MaxX; + } + if(pY) + { + if( *pY < MinY ) + *pY = MinY; + else if( *pY > MaxY ) + *pY = MaxY; + } + if(pZ) + { + if( *pZ < MinZ ) + *pZ = MinZ; + else if( *pZ > MaxZ ) + *pZ = MaxZ; + } +} + +basegfx::B2DRectangle PlottingPositionHelper::getScaledLogicClipDoubleRect() const +{ + //get logic clip values: + double MinX = getLogicMinX(); + double MinY = getLogicMinY(); + double MinZ = getLogicMinZ(); + double MaxX = getLogicMaxX(); + double MaxY = getLogicMaxY(); + double MaxZ = getLogicMaxZ(); + + //apply scaling + doUnshiftedLogicScaling( &MinX, &MinY, &MinZ ); + doUnshiftedLogicScaling( &MaxX, &MaxY, &MaxZ); + + basegfx::B2DRectangle aRet( MinX, MaxY, MaxX, MinY ); + return aRet; +} + +drawing::Direction3D PlottingPositionHelper::getScaledLogicWidth() const +{ + drawing::Direction3D aRet; + + double MinX = getLogicMinX(); + double MinY = getLogicMinY(); + double MinZ = getLogicMinZ(); + double MaxX = getLogicMaxX(); + double MaxY = getLogicMaxY(); + double MaxZ = getLogicMaxZ(); + + doLogicScaling( &MinX, &MinY, &MinZ ); + doLogicScaling( &MaxX, &MaxY, &MaxZ); + + aRet.DirectionX = MaxX - MinX; + aRet.DirectionY = MaxY - MinY; + aRet.DirectionZ = MaxZ - MinZ; + return aRet; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +PolarPlottingPositionHelper::PolarPlottingPositionHelper( NormalAxis eNormalAxis ) + : m_fRadiusOffset(0.0) + , m_fAngleDegreeOffset(90.0) + , m_aUnitCartesianToScene() + , m_eNormalAxis(eNormalAxis) +{ + m_bMaySkipPointsInRegressionCalculation = false; +} + +PolarPlottingPositionHelper::PolarPlottingPositionHelper( const PolarPlottingPositionHelper& rSource ) + : PlottingPositionHelper(rSource) + , m_fRadiusOffset( rSource.m_fRadiusOffset ) + , m_fAngleDegreeOffset( rSource.m_fAngleDegreeOffset ) + , m_aUnitCartesianToScene( rSource.m_aUnitCartesianToScene ) + , m_eNormalAxis( rSource.m_eNormalAxis ) +{ +} + +PolarPlottingPositionHelper::~PolarPlottingPositionHelper() +{ +} + +PlottingPositionHelper* PolarPlottingPositionHelper::clone() const +{ + PolarPlottingPositionHelper* pRet = new PolarPlottingPositionHelper(*this); + return pRet; +} + +void PolarPlottingPositionHelper::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix) +{ + PlottingPositionHelper::setTransformationSceneToScreen( rMatrix); + m_aUnitCartesianToScene =impl_calculateMatrixUnitCartesianToScene( m_aMatrixScreenToScene ); +} +void PolarPlottingPositionHelper::setScales( const std::vector< ExplicitScaleData >& rScales, bool bSwapXAndYAxis ) +{ + PlottingPositionHelper::setScales( rScales, bSwapXAndYAxis ); + m_aUnitCartesianToScene =impl_calculateMatrixUnitCartesianToScene( m_aMatrixScreenToScene ); +} + +::basegfx::B3DHomMatrix PolarPlottingPositionHelper::impl_calculateMatrixUnitCartesianToScene( const ::basegfx::B3DHomMatrix& rMatrixScreenToScene ) const +{ + ::basegfx::B3DHomMatrix aRet; + + if( m_aScales.empty() ) + return aRet; + + double fTranslate =1.0; + double fScale =FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0; + + double fTranslateLogicZ =fTranslate; + double fScaleLogicZ =fScale; + { + double fScaleDirectionZ = AxisOrientation_MATHEMATICAL==m_aScales[2].Orientation ? 1.0 : -1.0; + double MinZ = getLogicMinZ(); + double MaxZ = getLogicMaxZ(); + doLogicScaling( 0, 0, &MinZ ); + doLogicScaling( 0, 0, &MaxZ ); + double fWidthZ = MaxZ - MinZ; + + if( AxisOrientation_MATHEMATICAL==m_aScales[2].Orientation ) + fTranslateLogicZ=MinZ; + else + fTranslateLogicZ=MaxZ; + fScaleLogicZ = fScaleDirectionZ*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthZ; + } + + double fTranslateX = fTranslate; + double fTranslateY = fTranslate; + double fTranslateZ = fTranslate; + + double fScaleX = fScale; + double fScaleY = fScale; + double fScaleZ = fScale; + + switch(m_eNormalAxis) + { + case NormalAxis_X: + { + fTranslateX = fTranslateLogicZ; + fScaleX = fScaleLogicZ; + } + break; + case NormalAxis_Y: + { + fTranslateY = fTranslateLogicZ; + fScaleY = fScaleLogicZ; + } + break; + default: //NormalAxis_Z: + { + fTranslateZ = fTranslateLogicZ; + fScaleZ = fScaleLogicZ; + } + break; + } + + aRet.translate(fTranslateX, fTranslateY, fTranslateZ);//x first + aRet.scale(fScaleX, fScaleY, fScaleZ);//x first + + aRet = rMatrixScreenToScene * aRet; + return aRet; +} + +::basegfx::B3DHomMatrix PolarPlottingPositionHelper::getUnitCartesianToScene() const +{ + return m_aUnitCartesianToScene; +} + +uno::Reference< XTransformation > PolarPlottingPositionHelper::getTransformationScaledLogicToScene() const +{ + if( !m_xTransformationLogicToScene.is() ) + m_xTransformationLogicToScene = new VPolarTransformation(*this); + return m_xTransformationLogicToScene; +} + +double PolarPlottingPositionHelper::getWidthAngleDegree( double& fStartLogicValueOnAngleAxis, double& fEndLogicValueOnAngleAxis ) const +{ + const ExplicitScaleData& rAngleScale = m_bSwapXAndY ? m_aScales[1] : m_aScales[0]; + if( AxisOrientation_MATHEMATICAL != rAngleScale.Orientation ) + { + double fHelp = fEndLogicValueOnAngleAxis; + fEndLogicValueOnAngleAxis = fStartLogicValueOnAngleAxis; + fStartLogicValueOnAngleAxis = fHelp; + } + + double fStartAngleDegree = this->transformToAngleDegree( fStartLogicValueOnAngleAxis ); + double fEndAngleDegree = this->transformToAngleDegree( fEndLogicValueOnAngleAxis ); + double fWidthAngleDegree = fEndAngleDegree - fStartAngleDegree; + + if( ::rtl::math::approxEqual( fStartAngleDegree, fEndAngleDegree ) + && !::rtl::math::approxEqual( fStartLogicValueOnAngleAxis, fEndLogicValueOnAngleAxis ) ) + fWidthAngleDegree = 360.0; + + while(fWidthAngleDegree<0.0) + fWidthAngleDegree+=360.0; + while(fWidthAngleDegree>360.0) + fWidthAngleDegree-=360.0; + + return fWidthAngleDegree; +} + +double PolarPlottingPositionHelper::transformToAngleDegree( double fLogicValueOnAngleAxis, bool bDoScaling ) const +{ + double fRet=0.0; + + double fAxisAngleScaleDirection = 1.0; + { + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[1] : m_aScales[0]; + if(AxisOrientation_MATHEMATICAL != rScale.Orientation) + fAxisAngleScaleDirection *= -1.0; + } + + double MinAngleValue = 0.0; + double MaxAngleValue = 0.0; + { + double MinX = getLogicMinX(); + double MinY = getLogicMinY(); + double MaxX = getLogicMaxX(); + double MaxY = getLogicMaxY(); + double MinZ = getLogicMinZ(); + double MaxZ = getLogicMaxZ(); + + doLogicScaling( &MinX, &MinY, &MinZ ); + doLogicScaling( &MaxX, &MaxY, &MaxZ); + + MinAngleValue = m_bSwapXAndY ? MinY : MinX; + MaxAngleValue = m_bSwapXAndY ? MaxY : MaxX; + } + + double fScaledLogicAngleValue = 0.0; + if(bDoScaling) + { + double fX = m_bSwapXAndY ? getLogicMaxX() : fLogicValueOnAngleAxis; + double fY = m_bSwapXAndY ? fLogicValueOnAngleAxis : getLogicMaxY(); + double fZ = getLogicMaxZ(); + clipLogicValues( &fX, &fY, &fZ ); + doLogicScaling( &fX, &fY, &fZ ); + fScaledLogicAngleValue = m_bSwapXAndY ? fY : fX; + } + else + fScaledLogicAngleValue = fLogicValueOnAngleAxis; + + fRet = m_fAngleDegreeOffset + + fAxisAngleScaleDirection*(fScaledLogicAngleValue-MinAngleValue)*360.0 + /fabs(MaxAngleValue-MinAngleValue); + while(fRet>360.0) + fRet-=360.0; + while(fRet<0) + fRet+=360.0; + return fRet; +} + +double PolarPlottingPositionHelper::transformToRadius( double fLogicValueOnRadiusAxis, bool bDoScaling ) const +{ + double fNormalRadius = 0.0; + { + double fScaledLogicRadiusValue = 0.0; + double fX = m_bSwapXAndY ? fLogicValueOnRadiusAxis: getLogicMaxX(); + double fY = m_bSwapXAndY ? getLogicMaxY() : fLogicValueOnRadiusAxis; + if(bDoScaling) + doLogicScaling( &fX, &fY, 0 ); + + fScaledLogicRadiusValue = m_bSwapXAndY ? fX : fY; + + bool bMinIsInnerRadius = true; + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[0] : m_aScales[1]; + if(AxisOrientation_MATHEMATICAL != rScale.Orientation) + bMinIsInnerRadius = false; + + double fInnerScaledLogicRadius=0.0; + double fOuterScaledLogicRadius=0.0; + { + double MinX = getLogicMinX(); + double MinY = getLogicMinY(); + doLogicScaling( &MinX, &MinY, 0 ); + double MaxX = getLogicMaxX(); + double MaxY = getLogicMaxY(); + doLogicScaling( &MaxX, &MaxY, 0 ); + + double fMin = m_bSwapXAndY ? MinX : MinY; + double fMax = m_bSwapXAndY ? MaxX : MaxY; + + fInnerScaledLogicRadius = bMinIsInnerRadius ? fMin : fMax; + fOuterScaledLogicRadius = bMinIsInnerRadius ? fMax : fMin; + } + + if( bMinIsInnerRadius ) + fInnerScaledLogicRadius -= fabs(m_fRadiusOffset); + else + fInnerScaledLogicRadius += fabs(m_fRadiusOffset); + fNormalRadius = (fScaledLogicRadiusValue-fInnerScaledLogicRadius)/(fOuterScaledLogicRadius-fInnerScaledLogicRadius); + } + return fNormalRadius; +} + +drawing::Position3D PolarPlottingPositionHelper::transformLogicToScene( double fX, double fY, double fZ, bool bClip ) const +{ + if(bClip) + this->clipLogicValues( &fX,&fY,&fZ ); + double fLogicValueOnAngleAxis = m_bSwapXAndY ? fY : fX; + double fLogicValueOnRadiusAxis = m_bSwapXAndY ? fX : fY; + return this->transformAngleRadiusToScene( fLogicValueOnAngleAxis, fLogicValueOnRadiusAxis, fZ, true ); +} + +drawing::Position3D PolarPlottingPositionHelper::transformScaledLogicToScene( double fX, double fY, double fZ, bool bClip ) const +{ + if(bClip) + this->clipScaledLogicValues( &fX,&fY,&fZ ); + double fLogicValueOnAngleAxis = m_bSwapXAndY ? fY : fX; + double fLogicValueOnRadiusAxis = m_bSwapXAndY ? fX : fY; + return this->transformAngleRadiusToScene( fLogicValueOnAngleAxis, fLogicValueOnRadiusAxis, fZ, false ); +} +drawing::Position3D PolarPlottingPositionHelper::transformUnitCircleToScene( double fUnitAngleDegree, double fUnitRadius + , double fLogicZ, bool /* bDoScaling */ ) const +{ + double fAnglePi = fUnitAngleDegree*F_PI/180.0; + + double fX=fUnitRadius*rtl::math::cos(fAnglePi); + double fY=fUnitRadius*rtl::math::sin(fAnglePi); + double fZ=fLogicZ; + + switch(m_eNormalAxis) + { + case NormalAxis_X: + std::swap(fX,fZ); + break; + case NormalAxis_Y: + std::swap(fY,fZ); + fZ*=-1; + break; + default: //NormalAxis_Z + break; + } + + //!! applying matrix to vector does ignore translation, so it is important to use a B3DPoint here instead of B3DVector + ::basegfx::B3DPoint aPoint(fX,fY,fZ); + ::basegfx::B3DPoint aRet = m_aUnitCartesianToScene * aPoint; + return B3DPointToPosition3D(aRet); +} + +drawing::Position3D PolarPlottingPositionHelper::transformAngleRadiusToScene( double fLogicValueOnAngleAxis, double fLogicValueOnRadiusAxis, double fLogicZ, bool bDoScaling ) const +{ + double fUnitAngleDegree = this->transformToAngleDegree(fLogicValueOnAngleAxis,bDoScaling); + double fUnitRadius = this->transformToRadius(fLogicValueOnRadiusAxis,bDoScaling); + + return transformUnitCircleToScene( fUnitAngleDegree, fUnitRadius, fLogicZ, bDoScaling ); +} + +#ifdef NOTYET +double PolarPlottingPositionHelper::getInnerLogicRadius() const +{ + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[0] : m_aScales[1]; + if( AxisOrientation_MATHEMATICAL==rScale.Orientation ) + return rScale.Minimum; + else + return rScale.Maximum; +} +#endif + +double PolarPlottingPositionHelper::getOuterLogicRadius() const +{ + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[0] : m_aScales[1]; + if( AxisOrientation_MATHEMATICAL==rScale.Orientation ) + return rScale.Maximum; + else + return rScale.Minimum; +} + +bool PlottingPositionHelper::isPercentY() const +{ + return m_aScales[1].AxisType==AxisType::PERCENT; +} + +double PlottingPositionHelper::getBaseValueY() const +{ + return m_aScales[1].Origin; +} + +void PlottingPositionHelper::setTimeResolution( long nTimeResolution, const Date& rNullDate ) +{ + m_nTimeResolution = nTimeResolution; + m_aNullDate = rNullDate; + + //adapt category width + double fCategoryWidth = 1.0; + if( !m_aScales.empty() ) + { + if( m_aScales[0].AxisType == ::com::sun::star::chart2::AxisType::DATE ) + { + m_bDateAxis = true; + if( nTimeResolution == ::com::sun::star::chart::TimeUnit::YEAR ) + { + const double fMonthCount = 12.0;//todo: this depends on the DateScaling and must be adjusted in case we use more generic calendars in future + fCategoryWidth = fMonthCount; + } + } + } + setScaledCategoryWidth(fCategoryWidth); +} + +void PlottingPositionHelper::setScaledCategoryWidth( double fScaledCategoryWidth ) +{ + m_fScaledCategoryWidth = fScaledCategoryWidth; +} +void PlottingPositionHelper::AllowShiftXAxisPos( bool bAllowShift ) +{ + m_bAllowShiftXAxisPos = bAllowShift; +} +void PlottingPositionHelper::AllowShiftZAxisPos( bool bAllowShift ) +{ + m_bAllowShiftZAxisPos = bAllowShift; +} + +/* +// ____ XTransformation ____ +uno::Sequence< double > SAL_CALL PolarPlottingPositionHelper::transform( + const uno::Sequence< double >& rSourceValues ) + throw (uno::RuntimeException, lang::IllegalArgumentException) +{ + uno::Sequence< double > aSourceValues(3); + return aSourceValues; +} + +sal_Int32 SAL_CALL PolarPlottingPositionHelper::getSourceDimension() throw (uno::RuntimeException) +{ + return 3; +} + +sal_Int32 SAL_CALL PolarPlottingPositionHelper::getTargetDimension() throw (uno::RuntimeException) +{ + return 3; +} +*/ + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/PolarLabelPositionHelper.cxx b/chart2/source/view/main/PolarLabelPositionHelper.cxx new file mode 100644 index 000000000000..8e5402b48d63 --- /dev/null +++ b/chart2/source/view/main/PolarLabelPositionHelper.cxx @@ -0,0 +1,188 @@ +/************************************************************************* + * + * 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 "PolarLabelPositionHelper.hxx" +#include "PlottingPositionHelper.hxx" +#include "CommonConverters.hxx" +#include <basegfx/vector/b2dvector.hxx> +#include <basegfx/vector/b2ivector.hxx> + +#include <com/sun/star/chart/DataLabelPlacement.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +PolarLabelPositionHelper::PolarLabelPositionHelper( + PolarPlottingPositionHelper* pPosHelper + , sal_Int32 nDimensionCount + , const uno::Reference< drawing::XShapes >& xLogicTarget + , ShapeFactory* pShapeFactory ) + : LabelPositionHelper( pPosHelper, nDimensionCount, xLogicTarget, pShapeFactory ) + , m_pPosHelper(pPosHelper) +{ +} + +PolarLabelPositionHelper::~PolarLabelPositionHelper() +{ +} + +awt::Point PolarLabelPositionHelper::getLabelScreenPositionAndAlignmentForLogicValues( + LabelAlignment& rAlignment + , double fLogicValueOnAngleAxis + , double fLogicValueOnRadiusAxis + , double fLogicZ + , sal_Int32 nScreenValueOffsetInRadiusDirection ) const +{ + double fUnitCircleAngleDegree = m_pPosHelper->transformToAngleDegree( fLogicValueOnAngleAxis ); + double fUnitCircleRadius = m_pPosHelper->transformToRadius( fLogicValueOnRadiusAxis ); + + return getLabelScreenPositionAndAlignmentForUnitCircleValues( + rAlignment, ::com::sun::star::chart::DataLabelPlacement::OUTSIDE + , fUnitCircleAngleDegree, 0.0 + , fUnitCircleRadius, fUnitCircleRadius, fLogicZ, nScreenValueOffsetInRadiusDirection ); +} + +awt::Point PolarLabelPositionHelper::getLabelScreenPositionAndAlignmentForUnitCircleValues( + LabelAlignment& rAlignment, sal_Int32 nLabelPlacement + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , double fLogicZ + , sal_Int32 nScreenValueOffsetInRadiusDirection ) const +{ + bool bCenter = (nLabelPlacement != ::com::sun::star::chart::DataLabelPlacement::OUTSIDE) + && (nLabelPlacement != ::com::sun::star::chart::DataLabelPlacement::INSIDE); + + double fAngleDegree = fUnitCircleStartAngleDegree + fUnitCircleWidthAngleDegree/2.0; + double fRadius = 0.0; + if( !bCenter ) //e.g. for pure pie chart(one ring only) or for angle axis of polyar coordinate system + fRadius = fUnitCircleOuterRadius; + else + fRadius = fUnitCircleInnerRadius + (fUnitCircleOuterRadius-fUnitCircleInnerRadius)/2.0 ; + + awt::Point aRet( this->transformSceneToScreenPosition( + m_pPosHelper->transformUnitCircleToScene( fAngleDegree, fRadius, fLogicZ+0.5 ) ) ); + + if(3==m_nDimensionCount && nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::OUTSIDE) + { + //check wether the upper or the downer edge is more distant from the center + //take the farest point to put the label to + + awt::Point aP0( this->transformSceneToScreenPosition( + m_pPosHelper->transformUnitCircleToScene( 0, 0, fLogicZ ) ) ); + awt::Point aP1(aRet); + awt::Point aP2( this->transformSceneToScreenPosition( + m_pPosHelper->transformUnitCircleToScene( fAngleDegree, fRadius, fLogicZ-0.5 ) ) ); + + ::basegfx::B2DVector aV0( aP0.X, aP0.Y ); + ::basegfx::B2DVector aV1( aP1.X, aP1.Y ); + ::basegfx::B2DVector aV2( aP2.X, aP2.Y ); + + double fL1 = ::basegfx::B2DVector(aV1-aV0).getLength(); + double fL2 = ::basegfx::B2DVector(aV2-aV0).getLength(); + + if(fL2>fL1) + aRet = aP2; + + //calculate new angle for alignment + double fDX = aRet.X-aP0.X; + double fDY = aRet.Y-aP0.Y; + fDY*=-1.0;//drawing layer has inverse y values + if( fDX != 0.0 ) + { + fAngleDegree = atan(fDY/fDX)*180.0/F_PI; + if(fDX<0.0) + fAngleDegree+=180.0; + } + else + { + if(fDY>0.0) + fAngleDegree = 90.0; + else + fAngleDegree = 270.0; + } + } + //------------------------------ + //set LabelAlignment + if( !bCenter ) + { + while(fAngleDegree>360.0) + fAngleDegree-=360.0; + while(fAngleDegree<0.0) + fAngleDegree+=360.0; + + bool bOutside = nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::OUTSIDE; + + if(fAngleDegree==0.0) + rAlignment = LABEL_ALIGN_CENTER; + else if(fAngleDegree<=22.5) + rAlignment = bOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT; + else if(fAngleDegree<67.5) + rAlignment = bOutside ? LABEL_ALIGN_RIGHT_TOP : LABEL_ALIGN_LEFT_BOTTOM; + else if(fAngleDegree<112.5) + rAlignment = bOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM; + else if(fAngleDegree<=157.5) + rAlignment = bOutside ? LABEL_ALIGN_LEFT_TOP : LABEL_ALIGN_RIGHT_BOTTOM; + else if(fAngleDegree<=202.5) + rAlignment = bOutside ? LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT; + else if(fAngleDegree<247.5) + rAlignment = bOutside ? LABEL_ALIGN_LEFT_BOTTOM : LABEL_ALIGN_RIGHT_TOP; + else if(fAngleDegree<292.5) + rAlignment = bOutside ? LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP; + else if(fAngleDegree<337.5) + rAlignment = bOutside ? LABEL_ALIGN_RIGHT_BOTTOM : LABEL_ALIGN_LEFT_TOP; + else + rAlignment = bOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT; + } + else + { + rAlignment = LABEL_ALIGN_CENTER; + } + + //add a scaling independent Offset if requested + if( nScreenValueOffsetInRadiusDirection != 0) + { + awt::Point aOrigin( this->transformSceneToScreenPosition( + m_pPosHelper->transformUnitCircleToScene( 0.0, 0.0, fLogicZ+0.5 ) ) ); + basegfx::B2IVector aDirection( aRet.X- aOrigin.X, aRet.Y- aOrigin.Y ); + aDirection.setLength(nScreenValueOffsetInRadiusDirection); + aRet.X += aDirection.getX(); + aRet.Y += aDirection.getY(); + } + + return aRet; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/PropertyMapper.cxx b/chart2/source/view/main/PropertyMapper.cxx new file mode 100644 index 000000000000..99b7c0bd2ae0 --- /dev/null +++ b/chart2/source/view/main/PropertyMapper.cxx @@ -0,0 +1,529 @@ +/************************************************************************* + * + * 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 "PropertyMapper.hxx" +#include "ContainerHelper.hxx" +#include "macros.hxx" + +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/TextVerticalAdjust.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> +#include <com/sun/star/drawing/LineJoint.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; + +namespace +{ + +void lcl_overwriteOrAppendValues( + tPropertyNameValueMap &rMap, const tPropertyNameValueMap& rOverwriteMap ) +{ + tPropertyNameValueMap::const_iterator aIt( rOverwriteMap.begin() ); + tPropertyNameValueMap::const_iterator aEnd( rOverwriteMap.end() ); + + for( ; aIt != aEnd; ++aIt ) + rMap[ aIt->first ] = aIt->second; +} + +} // anonymous namespace + +void PropertyMapper::setMappedProperties( + const uno::Reference< beans::XPropertySet >& xTarget + , const uno::Reference< beans::XPropertySet >& xSource + , const tPropertyNameMap& rMap + , tPropertyNameValueMap* pOverwriteMap ) +{ + if( !xTarget.is() || !xSource.is() ) + return; + + tNameSequence aNames; + tAnySequence aValues; + getMultiPropertyLists(aNames, aValues, xSource, rMap ); + if(pOverwriteMap && (aNames.getLength() == aValues.getLength())) + { + tPropertyNameValueMap aNewMap; + for( sal_Int32 nI=0; nI<aNames.getLength(); ++nI ) + aNewMap[ aNames[nI] ] = aValues[nI]; + lcl_overwriteOrAppendValues( aNewMap, *pOverwriteMap ); + aNames = ContainerHelper::MapKeysToSequence( aNewMap ); + aValues = ContainerHelper::MapValuesToSequence( aNewMap ); + } + + PropertyMapper::setMultiProperties( aNames, aValues, xTarget ); +} + +void PropertyMapper::getValueMap( + tPropertyNameValueMap& rValueMap + , const tPropertyNameMap& rNameMap + , const uno::Reference< beans::XPropertySet >& xSourceProp + ) +{ + tPropertyNameMap::const_iterator aIt( rNameMap.begin() ); + tPropertyNameMap::const_iterator aEnd( rNameMap.end() ); + + for( ; aIt != aEnd; ++aIt ) + { + rtl::OUString aTarget = aIt->first; + rtl::OUString aSource = aIt->second; + try + { + uno::Any aAny( xSourceProp->getPropertyValue(aSource) ); + if( aAny.hasValue() ) + rValueMap.insert( tPropertyNameValueMap::value_type( aTarget, aAny ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } +} + +void PropertyMapper::getMultiPropertyLists( + tNameSequence& rNames + , tAnySequence& rValues + , const uno::Reference< beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rNameMap + ) +{ + tPropertyNameValueMap aValueMap; + getValueMap( aValueMap, rNameMap, xSourceProp ); + getMultiPropertyListsFromValueMap( rNames, rValues, aValueMap ); +} + +void PropertyMapper::getMultiPropertyListsFromValueMap( + tNameSequence& rNames + , tAnySequence& rValues + , const tPropertyNameValueMap& rValueMap + ) +{ + sal_Int32 nPropertyCount = rValueMap.size(); + rNames.realloc(nPropertyCount); + rValues.realloc(nPropertyCount); + + //fill sequences + tPropertyNameValueMap::const_iterator aValueIt( rValueMap.begin() ); + tPropertyNameValueMap::const_iterator aValueEnd( rValueMap.end() ); + sal_Int32 nN=0; + for( ; aValueIt != aValueEnd; ++aValueIt ) + { + const uno::Any& rAny = aValueIt->second; + if( rAny.hasValue() ) + { + //do not set empty anys because of performance (otherwise SdrAttrObj::ItemChange will take much longer) + rNames[nN] = aValueIt->first; + rValues[nN] = rAny; + ++nN; + } + } + //reduce to real property count + rNames.realloc(nN); + rValues.realloc(nN); +} + +uno::Any* PropertyMapper::getValuePointer( tAnySequence& rPropValues + , const tNameSequence& rPropNames + , const rtl::OUString& rPropName ) +{ + sal_Int32 nCount = rPropNames.getLength(); + for( sal_Int32 nN = 0; nN < nCount; nN++ ) + { + if(rPropNames[nN].equals(rPropName)) + return &rPropValues[nN]; + } + return NULL; +} + +uno::Any* PropertyMapper::getValuePointerForLimitedSpace( tAnySequence& rPropValues + , const tNameSequence& rPropNames + , bool bLimitedHeight) +{ + return PropertyMapper::getValuePointer( rPropValues, rPropNames + , bLimitedHeight ? C2U("TextMaximumFrameHeight") : C2U("TextMaximumFrameWidth") ); +} + +/* +//set some properties from service style::CharacterProperties: +//-------- tabpage: Zeichen ----------- +//Schriftart z.B. Albany UNO_NAME_EDIT_CHAR_FONTNAME == UNO_NAME_EDIT_CHAR_FONTSTYLENAME //UNO_NAME_CHAR_FONT +//Schriftschnitt z.B. kursiv UNO_NAME_EDIT_CHAR_POSTURE UNO_NAME_CHAR_POSTURE awt::FontSlant NONE OBLIQUE ITALIC DONTKNOW REVERSE_OBLIQUE REVERSE_ITALIC +//Schriftgrad (Punktgrösse z.B. 12) UNO_NAME_EDIT_CHAR_HEIGHT == UNO_NAME_CHAR_HEIGHT + //? UNO_NAME_EDIT_CHAR_WEIGHT == UNO_NAME_CHAR_WEIGHT +//Sprache UNO_NAME_EDIT_CHAR_LOCALE lang::Locale + +//-------- tabpage: Schrifteffekt ----------- +//Unterstreichung UNO_NAME_CHAR_UNDERLINE sal_Int16 awt::FontUnderline_NONE _SINGLE _DOUBLE _DOTTED _DONTKNOW _DASH ... +//Unterstreichung-farbe ??? 'CharUnderlineColor' + CharUnderlineHasColor +//Durchstreichung z.B. doppelt "CharStrikeout" sal_Int16 awt::FontStrikeout_NONE _SINGLE _DOUBLE ... +//wortweise-Durchstreichung ja/nein "CharWordMode" bool +//Schriftfarbe UNO_NAME_EDIT_CHAR_COLOR sal_Int32 UNO_NAME_CHAR_COLOR +//ReliefArt ohne/erhaben/tief "CharRelief" sal_Int16 text::FontRelief_NONE FontRelief_EMBOSSED FontRelief_ENGRAVED +//Kontur "CharContoured" bool +//Schatten UNO_NAME_CHAR_SHADOWED bool +*/ + +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForCharacterProperties() +{ + //shape property -- chart model object property + static tMakePropertyNameMap m_aShapePropertyMapForCharacterProperties = + tMakePropertyNameMap +// ( C2U( "CharBackColor" ), C2U("TextBackgroundColor") ) +// ( C2U( "CharCaseMap" ), C2U("CaseMapping") ) + ( C2U( "CharColor" ), C2U("CharColor") ) + ( C2U( "CharContoured" ), C2U("CharContoured") ) +/////// ( C2U( "CharCrossedOut" ), C2U("CharCrossedOut") ) //setting this explicitly somehow conflicts with CharStrikeout + ( C2U( "CharEmphasis" ), C2U("CharEmphasis") )//the service style::CharacterProperties describes a property called 'CharEmphasize' wich is nowhere implemented +// ( C2U( "CharEscapement" ), C2U("CharEscapement") ) //#i98344# @future: add these to properties again, if the user interface offers the possibility to change them; then make sure that older wrong files are corrected on import +// ( C2U( "CharEscapementHeight" ), C2U("CharEscapementHeight") ) //#i98344# @future: add these to properties again, if the user interface offers the possibility to change them; then make sure that older wrong files are corrected on import +// ( C2U( "CharFlash" ), C2U("Flashing") ) + + ( C2U( "CharFontFamily" ), C2U("CharFontFamily") ) + ( C2U( "CharFontFamilyAsian" ), C2U("CharFontFamilyAsian") ) + ( C2U( "CharFontFamilyComplex" ), C2U("CharFontFamilyComplex") ) + ( C2U( "CharFontCharSet" ), C2U("CharFontCharSet") ) + ( C2U( "CharFontCharSetAsian" ), C2U("CharFontCharSetAsian") ) + ( C2U( "CharFontCharSetComplex" ), C2U("CharFontCharSetComplex") ) + ( C2U( "CharFontName" ), C2U("CharFontName") ) + ( C2U( "CharFontNameAsian" ), C2U("CharFontNameAsian") ) + ( C2U( "CharFontNameComplex" ), C2U("CharFontNameComplex") ) + ( C2U( "CharFontPitch" ), C2U("CharFontPitch") ) + ( C2U( "CharFontPitchAsian" ), C2U("CharFontPitchAsian") ) + ( C2U( "CharFontPitchComplex" ), C2U("CharFontPitchComplex") ) + ( C2U( "CharFontStyleName" ), C2U("CharFontStyleName") ) + ( C2U( "CharFontStyleNameAsian" ), C2U("CharFontStyleNameAsian") ) + ( C2U( "CharFontStyleNameComplex" ),C2U("CharFontStyleNameComplex") ) + + ( C2U( "CharHeight" ), C2U("CharHeight") ) + ( C2U( "CharHeightAsian" ), C2U("CharHeightAsian") ) + ( C2U( "CharHeightComplex" ), C2U("CharHeightComplex") ) + ( C2U( "CharKerning" ), C2U("CharKerning") ) + ( C2U( "CharLocale" ), C2U("CharLocale") ) + ( C2U( "CharLocaleAsian" ), C2U("CharLocaleAsian") ) + ( C2U( "CharLocaleComplex" ), C2U("CharLocaleComplex") ) +// ( C2U( "CharNoHyphenation" ), C2U("InhibitHyphenation") ) + ( C2U( "CharPosture" ), C2U("CharPosture") ) + ( C2U( "CharPostureAsian" ), C2U("CharPostureAsian") ) + ( C2U( "CharPostureComplex" ), C2U("CharPostureComplex") ) + ( C2U( "CharRelief" ), C2U("CharRelief") ) +// ( C2U( "CharRotation" ), C2U("Rotation") ) --> additional feature ... +// ( C2U( "CharScaleWidth" ), C2U("CharScaleWidth") ) + ( C2U( "CharShadowed" ), C2U("CharShadowed") ) + ( C2U( "CharStrikeout" ), C2U("CharStrikeout") ) + ( C2U( "CharUnderline" ), C2U("CharUnderline") ) + ( C2U( "CharUnderlineColor" ), C2U("CharUnderlineColor") ) + ( C2U( "CharUnderlineHasColor" ), C2U("CharUnderlineHasColor") ) + ( C2U( "CharWeight" ), C2U("CharWeight") ) + ( C2U( "CharWeightAsian" ), C2U("CharWeightAsian") ) + ( C2U( "CharWeightComplex" ), C2U("CharWeightComplex") ) + ( C2U( "CharWordMode" ), C2U("CharWordMode") ) + + ( C2U( "WritingMode" ), C2U("WritingMode") ) + +// ( C2U( "RubyText" ), C2U("RubyText") ) +// ( C2U( "RubyAdjust" ), C2U("RubyAdjust") ) +// ( C2U( "RubyCharStyleName" ), C2U("RubyStyleName") ) +// ( C2U( "RubyIsAbove" ), C2U("RubyIsAbove") ) + ( C2U( "ParaIsCharacterDistance" ), C2U("ParaIsCharacterDistance") ) + ; + return m_aShapePropertyMapForCharacterProperties; +} + +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForParagraphProperties() +{ + //shape property -- chart model object property + static tMakePropertyNameMap m_aShapePropertyMapForParagraphProperties = + tMakePropertyNameMap + ( C2U( "ParaAdjust" ), C2U("ParaAdjust") ) + ( C2U( "ParaBottomMargin" ), C2U("ParaBottomMargin") ) + ( C2U( "ParaIsHyphenation" ), C2U("ParaIsHyphenation") ) + ( C2U( "ParaLastLineAdjust" ), C2U("ParaLastLineAdjust") ) + ( C2U( "ParaLeftMargin" ), C2U("ParaLeftMargin") ) + ( C2U( "ParaRightMargin" ), C2U("ParaRightMargin") ) + ( C2U( "ParaTopMargin" ), C2U("ParaTopMargin") ) + ; + return m_aShapePropertyMapForParagraphProperties; +} + +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForFillProperties() +{ + //shape property -- chart model object property + static tMakePropertyNameMap m_aShapePropertyMapForFillProperties = + tMakePropertyNameMap + ( C2U( "FillBackground" ), C2U( "FillBackground" ) ) + ( C2U( "FillBitmapName" ), C2U( "FillBitmapName" ) ) + ( C2U( "FillColor" ), C2U( "FillColor" ) ) + ( C2U( "FillGradientName" ), C2U( "FillGradientName" ) ) + ( C2U( "FillGradientStepCount" ), C2U( "FillGradientStepCount" ) ) + ( C2U( "FillHatchName" ), C2U( "FillHatchName" ) ) + ( C2U( "FillStyle" ), C2U( "FillStyle" ) ) + ( C2U( "FillTransparence" ), C2U( "FillTransparence" ) ) + ( C2U( "FillTransparenceGradientName" ), C2U("FillTransparenceGradientName") ) + //bitmap properties + ( C2U( "FillBitmapMode" ), C2U( "FillBitmapMode" ) ) + ( C2U( "FillBitmapSizeX" ), C2U( "FillBitmapSizeX" ) ) + ( C2U( "FillBitmapSizeY" ), C2U( "FillBitmapSizeY" ) ) + ( C2U( "FillBitmapLogicalSize" ), C2U( "FillBitmapLogicalSize" ) ) + ( C2U( "FillBitmapOffsetX" ), C2U( "FillBitmapOffsetX" ) ) + ( C2U( "FillBitmapOffsetY" ), C2U( "FillBitmapOffsetY" ) ) + ( C2U( "FillBitmapRectanglePoint" ),C2U( "FillBitmapRectanglePoint" ) ) + ( C2U( "FillBitmapPositionOffsetX" ),C2U( "FillBitmapPositionOffsetX" ) ) + ( C2U( "FillBitmapPositionOffsetY" ),C2U( "FillBitmapPositionOffsetY" ) ) + ; + return m_aShapePropertyMapForFillProperties; +} + +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForLineProperties() +{ + //shape property -- chart model object property + static tMakePropertyNameMap m_aShapePropertyMapForLineProperties = + tMakePropertyNameMap + ( C2U( "LineColor" ), C2U( "LineColor" ) ) + ( C2U( "LineDashName" ), C2U( "LineDashName" ) ) + ( C2U( "LineJoint" ), C2U( "LineJoint" ) ) + ( C2U( "LineStyle" ), C2U( "LineStyle" ) ) + ( C2U( "LineTransparence" ), C2U( "LineTransparence" ) ) + ( C2U( "LineWidth" ), C2U( "LineWidth" ) ) + ; + return m_aShapePropertyMapForLineProperties; +} + +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForFillAndLineProperties() +{ + static tMakePropertyNameMap m_aShapePropertyMapForFillAndLineProperties = + tMakePropertyNameMap + ( PropertyMapper::getPropertyNameMapForFillProperties() ) + ( PropertyMapper::getPropertyNameMapForLineProperties() ) + ; + + return m_aShapePropertyMapForFillAndLineProperties; +} + +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForTextShapeProperties() +{ + static tMakePropertyNameMap m_aShapePropertyMapForTextShapeProperties = + tMakePropertyNameMap + ( PropertyMapper::getPropertyNameMapForCharacterProperties() ) + ( PropertyMapper::getPropertyNameMapForFillProperties() ) + ( PropertyMapper::getPropertyNameMapForLineProperties() ) +// ( PropertyMapper::getPropertyNameMapForParagraphProperties() ) + // some text properties +// ( C2U( "TextHorizontalAdjust" ), C2U( "TextHorizontalAdjust" ) ) +// ( C2U( "TextVerticalAdjust" ), C2U( "TextVerticalAdjust" ) ) +// ( C2U( "TextAutoGrowHeight" ), C2U( "TextAutoGrowHeight" ) ) +// ( C2U( "TextAutoGrowWidth" ), C2U( "TextAutoGrowWidth" ) ) +// ( C2U( "TextLeftDistance" ), C2U( "TextLeftDistance" ) ) +// ( C2U( "TextRightDistance" ), C2U( "TextRightDistance" ) ) +// ( C2U( "TextUpperDistance" ), C2U( "TextUpperDistance" ) ) +// ( C2U( "TextLowerDistance" ), C2U( "TextLowerDistance" ) ) + ; + + return m_aShapePropertyMapForTextShapeProperties; +} + +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForLineSeriesProperties() +{ + //shape property -- chart model object property + static tMakePropertyNameMap m_aShapePropertyMapForLineSeriesProperties = + tMakePropertyNameMap + ( C2U( "LineColor" ), C2U("Color") ) + ( C2U( "LineDashName" ), C2U("LineDashName") ) +// ( C2U( "LineJoint" ), C2U("LineJoint") ) + ( C2U( "LineStyle" ), C2U("LineStyle") ) + ( C2U( "LineTransparence" ), C2U("Transparency") ) + ( C2U( "LineWidth" ), C2U("LineWidth") ) + + ; + return m_aShapePropertyMapForLineSeriesProperties; +} + +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForFilledSeriesProperties() +{ + //shape property -- chart model object property + static tMakePropertyNameMap m_aShapePropertyMapForFilledSeriesProperties = + tMakePropertyNameMap + ( C2U( "FillBackground"), C2U("FillBackground") ) + ( C2U( "FillBitmapName" ), C2U("FillBitmapName") ) + ( C2U( "FillColor" ), C2U("Color") ) + ( C2U( "FillGradientName" ), C2U("GradientName") ) + ( C2U( "FillGradientStepCount" ), C2U( "GradientStepCount" ) ) + ( C2U( "FillHatchName" ), C2U("HatchName") ) + ( C2U( "FillStyle" ), C2U("FillStyle") ) + ( C2U( "FillTransparence" ), C2U("Transparency") ) + ( C2U( "FillTransparenceGradientName" ), C2U("TransparencyGradientName") ) + //bitmap properties + ( C2U( "FillBitmapMode" ), C2U( "FillBitmapMode" ) ) + ( C2U( "FillBitmapSizeX" ), C2U( "FillBitmapSizeX" ) ) + ( C2U( "FillBitmapSizeY" ), C2U( "FillBitmapSizeY" ) ) + ( C2U( "FillBitmapLogicalSize" ), C2U( "FillBitmapLogicalSize" ) ) + ( C2U( "FillBitmapOffsetX" ), C2U( "FillBitmapOffsetX" ) ) + ( C2U( "FillBitmapOffsetY" ), C2U( "FillBitmapOffsetY" ) ) + ( C2U( "FillBitmapRectanglePoint" ),C2U( "FillBitmapRectanglePoint" ) ) + ( C2U( "FillBitmapPositionOffsetX" ),C2U( "FillBitmapPositionOffsetX" ) ) + ( C2U( "FillBitmapPositionOffsetY" ),C2U( "FillBitmapPositionOffsetY" ) ) + //line properties + ( C2U( "LineColor" ), C2U("BorderColor") ) + ( C2U( "LineDashName" ), C2U("BorderDashName") ) +// ( C2U( "LineJoint" ), C2U("LineJoint") ) + ( C2U( "LineStyle" ), C2U("BorderStyle") ) + ( C2U( "LineTransparence" ), C2U("BorderTransparency") ) + ( C2U( "LineWidth" ), C2U("BorderWidth") ) + ; + return m_aShapePropertyMapForFilledSeriesProperties; +} + +void PropertyMapper::setMultiProperties( + const tNameSequence& rNames + , const tAnySequence& rValues + , const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xTarget ) +{ + bool bSuccess = false; + try + { + uno::Reference< beans::XMultiPropertySet > xShapeMultiProp( xTarget, uno::UNO_QUERY ); + if( xShapeMultiProp.is() ) + { + xShapeMultiProp->setPropertyValues( rNames, rValues ); + bSuccess = true; + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); //if this occurs more often think of removing the XMultiPropertySet completly for better performance + } + + if(!bSuccess) + try + { + sal_Int32 nCount = std::max( rNames.getLength(), rValues.getLength() ); + rtl::OUString aPropName; + uno::Any aValue; + for( sal_Int32 nN = 0; nN < nCount; nN++ ) + { + aPropName = rNames[nN]; + aValue = rValues[nN]; + + try + { + xTarget->setPropertyValue( aPropName, aValue ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } +} + +void PropertyMapper::getTextLabelMultiPropertyLists( + const uno::Reference< beans::XPropertySet >& xSourceProp + , tNameSequence& rPropNames, tAnySequence& rPropValues + , bool bName + , sal_Int32 nLimitedSpace + , bool bLimitedHeight ) +{ + //fill character properties into the ValueMap + tPropertyNameValueMap aValueMap; + PropertyMapper::getValueMap( aValueMap + , PropertyMapper::getPropertyNameMapForCharacterProperties() + , xSourceProp ); + + //some more shape properties apart from character properties, position-matrix and label string + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("LineStyle"), uno::makeAny(drawing::LineStyle_NONE) ) ); // drawing::LineStyle + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextHorizontalAdjust"), uno::makeAny(drawing::TextHorizontalAdjust_CENTER) ) ); // drawing::TextHorizontalAdjust - needs to be overwritten + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextVerticalAdjust"), uno::makeAny(drawing::TextVerticalAdjust_CENTER) ) ); //drawing::TextVerticalAdjust - needs to be overwritten + //aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextWritingMode"), uno::makeAny(eWritingMode) ) ); //text::WritingMode + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextAutoGrowHeight"), uno::makeAny(sal_True) ) ); // sal_Bool + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextAutoGrowWidth"), uno::makeAny(sal_True) ) ); // sal_Bool + if( bName ) + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("Name"), uno::makeAny( rtl::OUString() ) ) ); //CID rtl::OUString - needs to be overwritten for each point + + if( nLimitedSpace > 0 ) + { + if(bLimitedHeight) + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextMaximumFrameHeight"), uno::makeAny(nLimitedSpace) ) ); //sal_Int32 + else + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextMaximumFrameWidth"), uno::makeAny(nLimitedSpace) ) ); //sal_Int32 + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("ParaIsHyphenation"), uno::makeAny(sal_True) ) ); + } + + /* + //@todo ?: add paragraph properties: + //(uno::makeAny(eParaAdjust)) //ParaAdjust - style::ParagraphAdjust + //(uno::makeAny( (sal_Bool)rAxisLabelProperties.bLineBreakAllowed )) //ParaIsHyphenation - sal_Bool + style::ParagraphAdjust eParaAdjust( style::ParagraphAdjust_LEFT ); + if( eHorizontalAdjust == drawing::TextHorizontalAdjust_RIGHT ) + eParaAdjust = style::ParagraphAdjust_RIGHT; + */ + + PropertyMapper::getMultiPropertyListsFromValueMap( rPropNames, rPropValues, aValueMap ); +} + +void PropertyMapper::getPreparedTextShapePropertyLists( + const uno::Reference< beans::XPropertySet >& xSourceProp + , tNameSequence& rPropNames, tAnySequence& rPropValues ) +{ + //fill character, line and fill properties into the ValueMap + tPropertyNameValueMap aValueMap; + PropertyMapper::getValueMap( aValueMap + , PropertyMapper::getPropertyNameMapForTextShapeProperties() + , xSourceProp ); + + // auto-grow makes sure the shape has the correct size after setting text + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextHorizontalAdjust"), uno::makeAny( drawing::TextHorizontalAdjust_CENTER ))); + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextVerticalAdjust"), uno::makeAny( drawing::TextVerticalAdjust_CENTER ))); + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextAutoGrowHeight"), uno::makeAny( true ))); + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextAutoGrowWidth"), uno::makeAny( true ))); + + // set some distance to the border, in case it is shown + const sal_Int32 nWidthDist = 250; + const sal_Int32 nHeightDist = 125; + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextLeftDistance"), uno::makeAny( nWidthDist ))); + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextRightDistance"), uno::makeAny( nWidthDist ))); + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextUpperDistance"), uno::makeAny( nHeightDist ))); + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextLowerDistance"), uno::makeAny( nHeightDist ))); + + // use a line-joint showing the border of thick lines like two rectangles + // filled in between. + aValueMap[C2U("LineJoint")] <<= drawing::LineJoint_ROUND; + + PropertyMapper::getMultiPropertyListsFromValueMap( rPropNames, rPropValues, aValueMap ); +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/ShapeFactory.cxx b/chart2/source/view/main/ShapeFactory.cxx new file mode 100644 index 000000000000..311b5e076e9a --- /dev/null +++ b/chart2/source/view/main/ShapeFactory.cxx @@ -0,0 +1,2101 @@ +/************************************************************************* + * + * 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 "ShapeFactory.hxx" +#include "ViewDefines.hxx" +#include "Stripe.hxx" +#include "CommonConverters.hxx" +#include "macros.hxx" +#include "PropertyMapper.hxx" +#include <comphelper/InlineContainer.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/CircleKind.hpp> +#include <com/sun/star/drawing/DoubleSequence.hpp> +#include <com/sun/star/drawing/FlagSequence.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/NormalsKind.hpp> +#include <com/sun/star/drawing/PointSequence.hpp> +#include <com/sun/star/drawing/PolygonKind.hpp> +#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp> +#include <com/sun/star/drawing/ProjectionMode.hpp> +#include <com/sun/star/drawing/ShadeMode.hpp> +#include <com/sun/star/drawing/TextFitToSizeType.hpp> +#include <com/sun/star/drawing/TextureProjectionMode.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/uno/Any.hxx> + + +#include <editeng/unoprnms.hxx> +#include <tools/color.hxx> +#include <tools/debug.hxx> +#include <rtl/math.hxx> +#include <svx/svdocirc.hxx> +#include <svx/svdopath.hxx> + +#ifndef _BGFX_VECTOR_B2DPOINT_HXX +#include <basegfx/point/b2dpoint.hxx> +#endif +#include <basegfx/matrix/b3dhommatrix.hxx> + +#include <algorithm> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// set a name/CID at a shape (is used for selection handling) +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +void ShapeFactory::setShapeName( const uno::Reference< drawing::XShape >& xShape + , const rtl::OUString& rName ) +{ + if(!xShape.is()) + return; + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + xProp->setPropertyValue( C2U( UNO_NAME_MISC_OBJ_NAME ) + , uno::makeAny( rName ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } +} + +//----------------------------------------------------------------------------- + +rtl::OUString ShapeFactory::getShapeName( const uno::Reference< drawing::XShape >& xShape ) +{ + rtl::OUString aRet; + + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + xProp->getPropertyValue( C2U( UNO_NAME_MISC_OBJ_NAME ) ) >>= aRet; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + + return aRet; +} + +//----------------------------------------------------------------------------- + +uno::Reference< drawing::XShapes > ShapeFactory::getChartRootShape( + const uno::Reference< drawing::XDrawPage>& xDrawPage ) +{ + uno::Reference< drawing::XShapes > xRet; + uno::Reference< drawing::XShapes > xShapes( xDrawPage, uno::UNO_QUERY ); + if( xShapes.is() ) + { + sal_Int32 nCount = xShapes->getCount(); + uno::Reference< drawing::XShape > xShape; + for( sal_Int32 nN = nCount; nN--; ) + { + if( xShapes->getByIndex( nN ) >>= xShape ) + { + if( ShapeFactory::getShapeName( xShape ).equals(C2U("com.sun.star.chart2.shapes")) ) + { + xRet = uno::Reference< drawing::XShapes >( xShape, uno::UNO_QUERY ); + break; + } + } + } + } + return xRet; +} + +//----------------------------------------------------------------------------- + +uno::Reference< drawing::XShapes > ShapeFactory::getOrCreateChartRootShape( + const uno::Reference< drawing::XDrawPage>& xDrawPage ) +{ + uno::Reference< drawing::XShapes > xRet( ShapeFactory::getChartRootShape( xDrawPage ) ); + if( !xRet.is() ) + { + //create the root shape + xRet = this->createGroup2D( + uno::Reference<drawing::XShapes>( xDrawPage, uno::UNO_QUERY ) + , C2U("com.sun.star.chart2.shapes") ); + } + return xRet; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// diverse PolyPolygon create methods +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +uno::Any createPolyPolygon_Cube( + const drawing::Direction3D& rSize, double fRoundedEdge, bool bRounded = true ) +{ + DBG_ASSERT(fRoundedEdge>=0, "fRoundedEdge needs to be >= 0"); + + // always use extra points, so set percent diagonal to 0.4 which is 0% in the UI (old Chart comment) + if( fRoundedEdge == 0.0 && bRounded) + fRoundedEdge = 0.4 / 200.0; + else if(!bRounded) + fRoundedEdge = 0.0; + + //fWidthH stands for Half Width + const double fWidthH = rSize.DirectionX >=0.0? rSize.DirectionX/2.0 : -rSize.DirectionX/2.0; + const double fHeight = rSize.DirectionY; +// const double fDepth = rSize.DirectionZ >=0.0? rSize.DirectionZ : -rSize.DirectionZ ; + + const double fHeightSign = fHeight >= 0.0 ? 1.0 : -1.0; + + const double fOffset = (fWidthH * fRoundedEdge) * 1.05; // increase by 5% for safety + const bool bRoundEdges = fRoundedEdge && fOffset < fWidthH && 2.0 * fOffset < fHeightSign*fHeight; + const sal_Int32 nPointCount = bRoundEdges ? 13 : 5; + + //-------------------------------------- + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(1); + aPP.SequenceY.realloc(1); + aPP.SequenceZ.realloc(1); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(nPointCount); + pOuterSequenceY->realloc(nPointCount); + pOuterSequenceZ->realloc(nPointCount); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + for(sal_Int32 nN = nPointCount; nN--;) + *pInnerSequenceZ++ = 0.0; + //*pInnerSequenceZ++ = -fDepth/2.0; + + if(nPointCount == 5) + { + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = 0.0; + + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH; + } + else + { + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = fHeightSign*fOffset; + *pInnerSequenceY++ = fHeight - fHeightSign*fOffset; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight - fHeightSign*fOffset; + *pInnerSequenceY++ = fHeightSign*fOffset; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = 0.0; + + *pInnerSequenceX++ = -fWidthH + fOffset; + *pInnerSequenceX++ = fWidthH - fOffset; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH - fOffset; + *pInnerSequenceX++ = -fWidthH + fOffset; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH + fOffset; + } + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +uno::Any createPolyPolygon_Cylinder( + double fHeight + , double fRadius + , sal_Int32& nVerticalSegmentCount ) +{ + //fHeight may be negative + DBG_ASSERT(fRadius>0, "The radius of a cylinder needs to be > 0"); + + //-------------------------------------- + drawing::PolyPolygonShape3D aPP; + + nVerticalSegmentCount=1; + + aPP.SequenceX.realloc(3); + aPP.SequenceY.realloc(3); + aPP.SequenceZ.realloc(3); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + double fY1 = 0.0; + double fY2 = fHeight; + + if( fHeight<0.0 ) + ::std::swap(fY1,fY2); + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = fY1; + + *pInnerSequenceX++ = fRadius; + *pInnerSequenceY++ = fY1; + //---------------------------- + + pOuterSequenceX++;pOuterSequenceY++;pOuterSequenceZ++; + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + pInnerSequenceX = pOuterSequenceX->getArray(); + pInnerSequenceY = pOuterSequenceY->getArray(); + pInnerSequenceZ = pOuterSequenceZ->getArray(); + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = fRadius; + *pInnerSequenceY++ = fY1; + + *pInnerSequenceX++ = fRadius; + *pInnerSequenceY++ = fY2; + //---------------------------- + + pOuterSequenceX++;pOuterSequenceY++;pOuterSequenceZ++; + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + pInnerSequenceX = pOuterSequenceX->getArray(); + pInnerSequenceY = pOuterSequenceY->getArray(); + pInnerSequenceZ = pOuterSequenceZ->getArray(); + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = fRadius; + *pInnerSequenceY++ = fY2; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = fY2; + //---------------------------- + + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +uno::Any createPolyPolygon_Cone( double fHeight, double fRadius, double fTopHeight + , sal_Int32& nVerticalSegmentCount ) +{ + DBG_ASSERT(fRadius>0, "The radius of a cone needs to be > 0"); + + //for stacked charts we need cones without top -> fTopHeight != 0 resp. bTopless == true + //fTopHeight indicates the high of the cutted top only (not the full height) + bool bTopless = !::rtl::math::approxEqual( fHeight, fHeight + fTopHeight ); + + double r1= 0.0, r2 = fRadius; + if(bTopless) + // #i63212# fHeight may be negative, fTopHeight is always positive -> use fabs(fHeight) + r1 = fRadius * (fTopHeight)/(fabs(fHeight)+fTopHeight); + + nVerticalSegmentCount=1; + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(2); + aPP.SequenceY.realloc(2); + aPP.SequenceZ.realloc(2); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + double fX1 = 0.0; + double fX2 = r2; + double fX3 = r1; + + double fY1 = 0.0; + double fY2 = 0.0; + double fY3 = fHeight; + + if( fHeight<0.0 ) + { + ::std::swap(fX1,fX3); + ::std::swap(fY1,fY3); + } + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceY++ = fY1; + *pInnerSequenceX++ = fX1; + + *pInnerSequenceY++ = fY2; + *pInnerSequenceX++ = fX2; + //---------------------------- + + pOuterSequenceX++;pOuterSequenceY++;pOuterSequenceZ++; + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + pInnerSequenceX = pOuterSequenceX->getArray(); + pInnerSequenceY = pOuterSequenceY->getArray(); + pInnerSequenceZ = pOuterSequenceZ->getArray(); + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceY++ = fY2; + *pInnerSequenceX++ = fX2; + + *pInnerSequenceY++ = fY3; + *pInnerSequenceX++ = fX3; + //---------------------------- + + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// methods for 3D shape creation +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +uno::Reference<drawing::XShape> + ShapeFactory::createCube( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , sal_Int32 nRotateZAngleHundredthDegree + , const uno::Reference< beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap + , bool bRounded ) +{ + if( !xTarget.is() ) + return 0; + if( bRounded ) + { + try + { + if( xSourceProp.is() ) + { + drawing::LineStyle aLineStyle; + xSourceProp->getPropertyValue( C2U( "BorderStyle" ) ) >>= aLineStyle; + if( aLineStyle == drawing::LineStyle_SOLID ) + bRounded = false; + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + uno::Reference<drawing::XShape> xShape = impl_createCube( xTarget, rPosition, rSize, nRotateZAngleHundredthDegree, bRounded ); + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + if( xSourceProp.is()) + PropertyMapper::setMappedProperties( xProp, xSourceProp, rPropertyNameMap ); + return xShape; +} + +uno::Reference<drawing::XShape> + ShapeFactory::impl_createCube( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , sal_Int32 nRotateZAngleHundredthDegree + , bool bRounded ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DExtrudeObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //depth + double fDepth = rSize.DirectionZ; + if(fDepth<0) + fDepth*=-1.0; + xProp->setPropertyValue( C2U( UNO_NAME_3D_EXTRUDE_DEPTH ) + , uno::makeAny((sal_Int32)fDepth) ); + + //PercentDiagonal + sal_Int16 nPercentDiagonal = bRounded ? 3 : 0; + xProp->setPropertyValue( C2U( UNO_NAME_3D_PERCENT_DIAGONAL ) + , uno::makeAny( nPercentDiagonal ) ); + + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , createPolyPolygon_Cube( rSize, double(nPercentDiagonal)/200.0,bRounded) ); + + //Matrix for position + { + ::basegfx::B3DHomMatrix aM; + if(nRotateZAngleHundredthDegree!=0) + aM.rotate(0.0,0.0,-nRotateZAngleHundredthDegree/18000.00*F_PI); + aM.translate(rPosition.PositionX + , rPosition.PositionY + , rPosition.PositionZ - (fDepth/2.0)); + drawing::HomogenMatrix aHM = B3DHomMatrixToHomogenMatrix(aM); + xProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(aHM) ); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference<drawing::XShape> + ShapeFactory::createCylinder( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , sal_Int32 nRotateZAngleHundredthDegree ) +{ + return impl_createConeOrCylinder( + xTarget, rPosition, rSize, 0.0, nRotateZAngleHundredthDegree, true ); +} + +uno::Reference<drawing::XShape> + ShapeFactory::createPyramid( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , double fTopHeight, bool bRotateZ + , const uno::Reference< beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap ) +{ + if( !xTarget.is() ) + return 0; + + Reference< drawing::XShapes > xGroup( ShapeFactory::createGroup3D( xTarget, rtl::OUString() ) ); + + sal_Bool bDoubleSided = false; + short nRotatedTexture = 0; + + const double fWidth = rSize.DirectionX; + const double fDepth = rSize.DirectionZ; + const double fHeight = rSize.DirectionY; + + drawing::Position3D aBottomP1( rPosition.PositionX, rPosition.PositionY, rPosition.PositionZ - fDepth/2.0 ); + if(bRotateZ) + aBottomP1.PositionY -= fWidth/2.0; + else + aBottomP1.PositionX -= fWidth/2.0; + drawing::Position3D aBottomP2( aBottomP1 ); + if(bRotateZ) + aBottomP2.PositionY += fWidth; + else + aBottomP2.PositionX += fWidth; + drawing::Position3D aBottomP3( aBottomP2 ); + drawing::Position3D aBottomP4( aBottomP1 ); + aBottomP3.PositionZ += fDepth; + aBottomP4.PositionZ += fDepth; + + const double fTopFactor = (fTopHeight)/(fabs(fHeight)+fTopHeight); + drawing::Position3D aTopP1( rPosition.PositionX, rPosition.PositionY, rPosition.PositionZ - fDepth*fTopFactor/2.0 ); + if(bRotateZ) + { + aTopP1.PositionY -= fWidth*fTopFactor/2.0; + aTopP1.PositionX += fHeight; + } + else + { + aTopP1.PositionX -= fWidth*fTopFactor/2.0; + aTopP1.PositionY += fHeight; + } + drawing::Position3D aTopP2( aTopP1 ); + if(bRotateZ) + aTopP2.PositionY += fWidth*fTopFactor; + else + aTopP2.PositionX += fWidth*fTopFactor; + drawing::Position3D aTopP3( aTopP2 ); + drawing::Position3D aTopP4( aTopP1 ); + aTopP3.PositionZ += fDepth*fTopFactor; + aTopP4.PositionZ += fDepth*fTopFactor; + + Stripe aStripeBottom( aBottomP1, aBottomP4, aBottomP3, aBottomP2 ); + + drawing::Position3D aNormalsBottomP1( aBottomP1 ); + drawing::Position3D aNormalsBottomP2( aBottomP2 ); + drawing::Position3D aNormalsBottomP3( aBottomP3 ); + drawing::Position3D aNormalsBottomP4( aBottomP4 ); + drawing::Position3D aNormalsTopP1( aBottomP1 ); + drawing::Position3D aNormalsTopP2( aBottomP2 ); + drawing::Position3D aNormalsTopP3( aBottomP3 ); + drawing::Position3D aNormalsTopP4( aBottomP4 ); + if( bRotateZ ) + { + aNormalsTopP1.PositionX += fHeight; + aNormalsTopP2.PositionX += fHeight; + aNormalsTopP3.PositionX += fHeight; + aNormalsTopP4.PositionX += fHeight; + } + else + { + aNormalsTopP1.PositionY += fHeight; + aNormalsTopP2.PositionY += fHeight; + aNormalsTopP3.PositionY += fHeight; + aNormalsTopP4.PositionY += fHeight; + } + + bool bInvertPolygon = false; + bool bInvertNormals = false; + + if(bRotateZ) + { + //bars + if(fHeight>=0.0) + { + nRotatedTexture = 2; + bInvertNormals = true; + aStripeBottom = Stripe( aBottomP1, aBottomP4, aBottomP3, aBottomP2 ); + } + else + { + bInvertPolygon = true; + nRotatedTexture = 1; + aStripeBottom = Stripe( aBottomP2, aBottomP3, aBottomP4, aBottomP1 ); + } + } + else + { + //columns + if(fHeight>=0.0) + { + bInvertPolygon = true; + nRotatedTexture = 2; + aStripeBottom = Stripe( aBottomP2, aBottomP3, aBottomP4, aBottomP1 ); + } + else + { + nRotatedTexture = 3; + bInvertNormals = true; + aStripeBottom = Stripe( aBottomP4, aBottomP3, aBottomP2, aBottomP1 ); + } + } + aStripeBottom.InvertNormal(true); + + Stripe aStripe1( aTopP2, aTopP1, aBottomP1, aBottomP2 ); + Stripe aStripe2( aTopP3, aTopP2, aBottomP2, aBottomP3 ); + Stripe aStripe3( aTopP4, aTopP3, aBottomP3, aBottomP4 ); + Stripe aStripe4( aTopP1, aTopP4, aBottomP4, aBottomP1 ); + + if( bInvertPolygon ) + { + aStripe1 = Stripe( aBottomP1, aTopP1, aTopP2, aBottomP2 ); + aStripe2 = Stripe( aBottomP2, aTopP2, aTopP3, aBottomP3 ); + aStripe3 = Stripe( aBottomP3, aTopP3, aTopP4, aBottomP4 ); + aStripe4 = Stripe( aBottomP4, aTopP4, aTopP1, aBottomP1 ); + } + + Stripe aNormalsStripe1( aNormalsTopP1, aNormalsBottomP1, aNormalsBottomP2, aNormalsTopP2 ); + Stripe aNormalsStripe2( aNormalsTopP2, aNormalsBottomP2, aNormalsBottomP3, aNormalsTopP3 ); + Stripe aNormalsStripe3( aNormalsTopP3, aNormalsBottomP3, aNormalsBottomP4, aNormalsTopP4 ); + Stripe aNormalsStripe4( aNormalsTopP4, aNormalsBottomP4, aNormalsBottomP1, aNormalsTopP1 ); + + if( bInvertNormals ) + { + aNormalsStripe1 = Stripe( aNormalsTopP2, aNormalsBottomP2, aNormalsBottomP1, aNormalsTopP1 ); + aNormalsStripe2 = Stripe( aNormalsTopP3, aNormalsBottomP3, aNormalsBottomP2, aNormalsTopP2 ); + aNormalsStripe3 = Stripe( aNormalsTopP4, aNormalsBottomP4, aNormalsBottomP3, aNormalsTopP3 ); + aNormalsStripe4 = Stripe( aNormalsTopP1, aNormalsBottomP1, aNormalsBottomP4, aNormalsTopP4 ); + } + + aStripe1.SetManualNormal( aNormalsStripe1.getNormal() ); + aStripe2.SetManualNormal( aNormalsStripe2.getNormal() ); + aStripe3.SetManualNormal( aNormalsStripe3.getNormal() ); + aStripe4.SetManualNormal( aNormalsStripe4.getNormal() ); + + const bool bFlatNormals = false; + ShapeFactory::createStripe( xGroup, aStripe1, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + ShapeFactory::createStripe( xGroup, aStripe2, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + ShapeFactory::createStripe( xGroup, aStripe3, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + ShapeFactory::createStripe( xGroup, aStripe4, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + ShapeFactory::createStripe( xGroup, aStripeBottom, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + + return Reference< drawing::XShape >( xGroup, uno::UNO_QUERY ); +} + +uno::Reference<drawing::XShape> + ShapeFactory::createCone( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree ) +{ + return impl_createConeOrCylinder( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree ); +} + +uno::Reference<drawing::XShape> + ShapeFactory::impl_createConeOrCylinder( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree + , bool bCylinder ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DLatheObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + double fWidth = rSize.DirectionX/2.0; //The depth will be corrrected within Matrix + double fRadius = fWidth; //!!!!!!!! problem in drawing layer: rotation object calculates wrong needed size -> wrong camera (it's a problem with bounding boxes) + double fHeight = rSize.DirectionY; + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //PercentDiagonal + sal_Int16 nPercentDiagonal = 5; + xProp->setPropertyValue( C2U( UNO_NAME_3D_PERCENT_DIAGONAL ) + , uno::makeAny( nPercentDiagonal ) ); + + //Polygon + sal_Int32 nVerticalSegmentCount = 0; + uno::Any aPPolygon = bCylinder ? createPolyPolygon_Cylinder( + fHeight, fRadius, nVerticalSegmentCount) + : createPolyPolygon_Cone( + fHeight, fRadius, fTopHeight, nVerticalSegmentCount); + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ), aPPolygon ); + + //Matrix for position + { + ::basegfx::B3DHomMatrix aM; + if(nRotateZAngleHundredthDegree!=0) + aM.rotate(0.0,0.0,-nRotateZAngleHundredthDegree/18000.00*F_PI); + //stretch the symmetric objects to given depth + aM.scale(1.0,1.0,rSize.DirectionZ/rSize.DirectionX); + aM.translate(rPosition.PositionX, rPosition.PositionY, rPosition.PositionZ); + drawing::HomogenMatrix aHM = B3DHomMatrixToHomogenMatrix(aM); + xProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(aHM) ); + } + + //Segments + xProp->setPropertyValue( C2U( UNO_NAME_3D_HORZ_SEGS ) + , uno::makeAny(CHART_3DOBJECT_SEGMENTCOUNT) ); + xProp->setPropertyValue( C2U( UNO_NAME_3D_VERT_SEGS ) + , uno::makeAny((sal_Int32)nVerticalSegmentCount) );//depends on point count of the used polygon + + //Reduced lines + xProp->setPropertyValue( C2U( UNO_NAME_3D_REDUCED_LINE_GEOMETRY ) + , uno::makeAny((sal_Bool)sal_True) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +//------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------ + +void appendAndCloseBezierCoords( drawing::PolyPolygonBezierCoords& rReturn, const drawing::PolyPolygonBezierCoords& rAdd, sal_Bool bAppendInverse ) +{ + if(!rAdd.Coordinates.getLength()) + return; + sal_Int32 nAddCount = rAdd.Coordinates[0].getLength(); + if(!nAddCount) + return; + + sal_Int32 nOldCount = rReturn.Coordinates[0].getLength(); + + rReturn.Coordinates[0].realloc(nOldCount+nAddCount+1); + rReturn.Flags[0].realloc(nOldCount+nAddCount+1); + + for(sal_Int32 nN=0;nN<nAddCount; nN++ ) + { + sal_Int32 nAdd = bAppendInverse ? (nAddCount-1-nN) : nN; + rReturn.Coordinates[0][nOldCount+nN] = rAdd.Coordinates[0][nAdd]; + rReturn.Flags[0][nOldCount+nN] = rAdd.Flags[0][nAdd]; + } + + //close + rReturn.Coordinates[0][nOldCount+nAddCount] = rReturn.Coordinates[0][0]; + rReturn.Flags[0][nOldCount+nAddCount] = rReturn.Flags[0][0]; +} + +//------------------------------------------------------------------------------------------------------------ + +drawing::PolyPolygonBezierCoords getCircularArcBezierCoords( + double fStartAngleRadian, double fWidthAngleRadian, double fUnitRadius + , const ::basegfx::B2DHomMatrix& rTransformationFromUnitCircle + , const double fAngleSubdivisionRadian ) +{ + //at least one polygon is created using two normal and two control points + //if the angle is larger it is separated into multiple sub angles + + drawing::PolyPolygonBezierCoords aReturn = drawing::PolyPolygonBezierCoords(); + sal_Int32 nSegmentCount = static_cast< sal_Int32 >( fWidthAngleRadian/fAngleSubdivisionRadian ); + if( fWidthAngleRadian > fAngleSubdivisionRadian*nSegmentCount ) + nSegmentCount++; + + double fFirstSegmentAngle = fAngleSubdivisionRadian; + double fLastSegmentAngle = fAngleSubdivisionRadian; + if(nSegmentCount==1) + { + fFirstSegmentAngle = fWidthAngleRadian; + fLastSegmentAngle = 0.0; + } + else + { + double fFirstAngleOnSubDevision = (static_cast<sal_Int32>(fStartAngleRadian/fAngleSubdivisionRadian)+1)*fAngleSubdivisionRadian; + if( !::rtl::math::approxEqual( fStartAngleRadian, fFirstAngleOnSubDevision ) ) + fFirstSegmentAngle = fFirstAngleOnSubDevision-fStartAngleRadian; + + if(nSegmentCount>1) + { + fLastSegmentAngle = fWidthAngleRadian-fFirstSegmentAngle-fAngleSubdivisionRadian*(nSegmentCount-2); + if( fLastSegmentAngle<0 ) + nSegmentCount--; + if( fLastSegmentAngle>fAngleSubdivisionRadian ) + { + fLastSegmentAngle-=fAngleSubdivisionRadian; + nSegmentCount++; + } + } + } + + sal_Int32 nPointCount = 1 + 3*nSegmentCount; //first point of next segment equals last point of former segment + + aReturn.Coordinates = drawing::PointSequenceSequence(1); + aReturn.Flags = drawing::FlagSequenceSequence(1); + + drawing::PointSequence aPoints(nPointCount); + drawing::FlagSequence aFlags(nPointCount); + + // + + //!! applying matrix to vector does ignore translation, so it is important to use a B2DPoint here instead of B2DVector + ::basegfx::B2DPoint P0,P1,P2,P3; + ::basegfx::B2DPoint POrigin = rTransformationFromUnitCircle * ::basegfx::B2DPoint(0.0, 0.0); + + sal_Int32 nPoint=0; + double fCurrentRotateAngle = fStartAngleRadian; + for(sal_Int32 nSegment=0; nSegment<nSegmentCount; nSegment++) + { + double fCurrentSegmentAngle = fAngleSubdivisionRadian; + if(nSegment==0)//first segment gets only a smaller peace until the next subdevision + fCurrentSegmentAngle = fFirstSegmentAngle; + else if(nSegment==(nSegmentCount-1)) //the last segment gets the rest angle that does not fit into equal pieces + fCurrentSegmentAngle = fLastSegmentAngle; + + //first create untransformed points for a unit circle arc: + const double fCos = cos(fCurrentSegmentAngle/2.0); + const double fSin = sin(fCurrentSegmentAngle/2.0); + P0.setX(fCos); + P3.setX(fCos); + P0.setY(-fSin); + P3.setY(-P0.getY()); + + P1.setX((4.0-fCos)/3.0); + P2.setX(P1.getX()); + P1.setY((1.0-fCos)*(fCos-3.0)/(3.0*fSin)); + P2.setY(-P1.getY()); + //transform thus startangle equals NULL + ::basegfx::B2DHomMatrix aStart; + aStart.rotate(fCurrentSegmentAngle/2.0 + fCurrentRotateAngle ); + fCurrentRotateAngle+=fCurrentSegmentAngle; + + aStart.scale( fUnitRadius, fUnitRadius ); + + //apply given transformation to get final points + P0 = rTransformationFromUnitCircle*(aStart*P0); + P1 = rTransformationFromUnitCircle*(aStart*P1); + P2 = rTransformationFromUnitCircle*(aStart*P2); + P3 = rTransformationFromUnitCircle*(aStart*P3); + + aPoints[nPoint].X = static_cast< sal_Int32 >( P0.getX()); + aPoints[nPoint].Y = static_cast< sal_Int32 >( P0.getY()); + aFlags [nPoint++] = drawing::PolygonFlags_NORMAL; + + aPoints[nPoint].X = static_cast< sal_Int32 >( P1.getX()); + aPoints[nPoint].Y = static_cast< sal_Int32 >( P1.getY()); + aFlags[nPoint++] = drawing::PolygonFlags_CONTROL; + + aPoints[nPoint].X = static_cast< sal_Int32 >( P2.getX()); + aPoints[nPoint].Y = static_cast< sal_Int32 >( P2.getY()); + aFlags [nPoint++] = drawing::PolygonFlags_CONTROL; + + if(nSegment==(nSegmentCount-1)) + { + aPoints[nPoint].X = static_cast< sal_Int32 >( P3.getX()); + aPoints[nPoint].Y = static_cast< sal_Int32 >( P3.getY()); + aFlags [nPoint++] = drawing::PolygonFlags_NORMAL; + } + } + + aReturn.Coordinates[0] = aPoints; + aReturn.Flags[0] = aFlags; + + return aReturn; +} + +//------------------------------------------------------------------------------------------------------------ + +drawing::PolyPolygonBezierCoords getRingBezierCoords( + double fUnitCircleInnerRadius + , double fUnitCircleOuterRadius + , double fStartAngleRadian, double fWidthAngleRadian + , ::basegfx::B2DHomMatrix aTransformationFromUnitCircle + , const double fAngleSubdivisionRadian ) +{ + drawing::PolyPolygonBezierCoords aReturn = drawing::PolyPolygonBezierCoords(); + + aReturn.Coordinates = drawing::PointSequenceSequence(1); + aReturn.Flags = drawing::FlagSequenceSequence(1); + + drawing::PolyPolygonBezierCoords aOuterArc = getCircularArcBezierCoords( + fStartAngleRadian, fWidthAngleRadian, fUnitCircleOuterRadius, aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + aReturn.Coordinates[0] = aOuterArc.Coordinates[0]; + aReturn.Flags[0] = aOuterArc.Flags[0]; + + drawing::PolyPolygonBezierCoords aInnerArc = getCircularArcBezierCoords( + fStartAngleRadian, fWidthAngleRadian, fUnitCircleInnerRadius, aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + appendAndCloseBezierCoords( aReturn, aInnerArc, sal_True ); + + //fill rMarkHandlePoints + /* + { + rMarkHandlePoints.realloc(1); + rMarkHandlePoints[0].realloc(6); + sal_Int32 nHandleCount=0; + sal_Int32 nOuterArcCount = aOuterArc.Coordinates[0].getLength(); + if(nOuterArcCount>0) + rMarkHandlePoints[0][nHandleCount++]=aOuterArc.Coordinates[0][0]; + if(nOuterArcCount>1) + rMarkHandlePoints[0][nHandleCount++]=aOuterArc.Coordinates[0][nOuterArcCount-1]; + sal_Int32 nInnerArcCount = aInnerArc.Coordinates[0].getLength(); + if(nInnerArcCount>0) + rMarkHandlePoints[0][nHandleCount++]=aInnerArc.Coordinates[0][0]; + if(nInnerArcCount>1) + rMarkHandlePoints[0][nHandleCount++]=aInnerArc.Coordinates[0][nInnerArcCount-1]; + rMarkHandlePoints[0].realloc(nHandleCount); + } + */ + + return aReturn; +} + +//------------------------------------------------------------------------------------------------------------ + +uno::Reference< drawing::XShape > + ShapeFactory::createPieSegment2D( + const uno::Reference< drawing::XShapes >& xTarget + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , const drawing::Direction3D& rOffset + , const drawing::HomogenMatrix& rUnitCircleToScene ) +{ + if( !xTarget.is() ) + return 0; + + while(fUnitCircleWidthAngleDegree>360) + fUnitCircleWidthAngleDegree -= 360.0; + while(fUnitCircleWidthAngleDegree<0) + fUnitCircleWidthAngleDegree += 360.0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( + C2U("com.sun.star.drawing.ClosedBezierShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); //need to add the shape before setting of properties + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + ::basegfx::B2DHomMatrix aTransformationFromUnitCircle( IgnoreZ( HomogenMatrixToB3DHomMatrix(rUnitCircleToScene) ) ); + aTransformationFromUnitCircle.translate(rOffset.DirectionX,rOffset.DirectionY); + + const double fAngleSubdivisionRadian = F_PI/10.0; + + drawing::PolyPolygonBezierCoords aCoords = getRingBezierCoords( + fUnitCircleInnerRadius, fUnitCircleOuterRadius + , fUnitCircleStartAngleDegree*F_PI/180.0, fUnitCircleWidthAngleDegree*F_PI/180.0 + , aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + + xProp->setPropertyValue( C2U( "PolyPolygonBezier" ), uno::makeAny( aCoords ) ); + + //add shape for markhandles + /* + drawing::PointSequenceSequence aMarkHandlePoints(1); to be filled within getRingBezierCoords + if( xGroup.is() ) + { + VLineProperties aHandleLineProperties; + aHandleLineProperties.LineStyle = uno::makeAny( drawing::LineStyle_NONE ); + uno::Reference< drawing::XShape > xHandleShape = + this->createLine2D( xGroup, aMarkHandlePoints, &aHandleLineProperties ); + this->setShapeName( xHandleShape, C2U("HandlesOnly") ); + } + */ + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + + return xShape; +} + +//------------------------------------------------------------------------------------------------------------ + +uno::Reference< drawing::XShape > + ShapeFactory::createPieSegment( + const uno::Reference< drawing::XShapes >& xTarget + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , const drawing::Direction3D& rOffset + , const drawing::HomogenMatrix& rUnitCircleToScene + , double fDepth ) +{ + if( !xTarget.is() ) + return 0; + + while(fUnitCircleWidthAngleDegree>360) + fUnitCircleWidthAngleDegree -= 360.0; + while(fUnitCircleWidthAngleDegree<0) + fUnitCircleWidthAngleDegree += 360.0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DExtrudeObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); //need to add the shape before setting of properties + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + ::basegfx::B2DHomMatrix aTransformationFromUnitCircle( IgnoreZ( HomogenMatrixToB3DHomMatrix(rUnitCircleToScene) ) ); + aTransformationFromUnitCircle.translate(rOffset.DirectionX,rOffset.DirectionY); + + const double fAngleSubdivisionRadian = F_PI/32.0; + + drawing::PolyPolygonBezierCoords aCoords = getRingBezierCoords( + fUnitCircleInnerRadius, fUnitCircleOuterRadius + , fUnitCircleStartAngleDegree*F_PI/180.0, fUnitCircleWidthAngleDegree*F_PI/180.0 + , aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + + //depth + xProp->setPropertyValue( C2U( UNO_NAME_3D_EXTRUDE_DEPTH ) + , uno::makeAny((sal_Int32)fDepth) ); + + //PercentDiagonal + sal_Int16 nPercentDiagonal = 0; + xProp->setPropertyValue( C2U( UNO_NAME_3D_PERCENT_DIAGONAL ) + , uno::makeAny( nPercentDiagonal ) ); + + //Polygon + drawing::PolyPolygonShape3D aPoly( BezierToPoly(aCoords) ); + ShapeFactory::closePolygon( aPoly ); + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , uno::makeAny( aPoly ) ); + + //DoubleSided + xProp->setPropertyValue( C2U( UNO_NAME_3D_DOUBLE_SIDED ) + , uno::makeAny( (sal_Bool)true) ); + + //Reduced lines + xProp->setPropertyValue( C2U( UNO_NAME_3D_REDUCED_LINE_GEOMETRY ) + , uno::makeAny((sal_Bool)sal_True) ); + + //TextureProjectionMode + xProp->setPropertyValue( C2U( UNO_NAME_3D_TEXTURE_PROJ_Y ) + , uno::makeAny( drawing::TextureProjectionMode_OBJECTSPECIFIC ) ); + + //TextureProjectionMode + xProp->setPropertyValue( C2U( UNO_NAME_3D_TEXTURE_PROJ_X ) + , uno::makeAny( drawing::TextureProjectionMode_PARALLEL ) ); + xProp->setPropertyValue( C2U( UNO_NAME_3D_TEXTURE_PROJ_Y ) + , uno::makeAny( drawing::TextureProjectionMode_OBJECTSPECIFIC ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +//------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------ + +uno::Reference< drawing::XShape > + ShapeFactory::createStripe( const uno::Reference< drawing::XShapes >& xTarget + , const Stripe& rStripe + , const uno::Reference< beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap + , sal_Bool bDoubleSided + , short nRotatedTexture + , bool bFlatNormals ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DPolygonObject" ) ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , rStripe.getPolyPolygonShape3D() ); + + //TexturePolygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_TEXTUREPOLYGON3D ) + , rStripe.getTexturePolygon( nRotatedTexture ) ); + + //Normals Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_NORMALSPOLYGON3D ) + , rStripe.getNormalsPolygon() ); + //NormalsKind + if(bFlatNormals) + xProp->setPropertyValue( C2U( UNO_NAME_3D_NORMALS_KIND ) + , uno::makeAny( drawing::NormalsKind_FLAT ) ); + + //LineOnly + xProp->setPropertyValue( C2U( UNO_NAME_3D_LINEONLY ) + , uno::makeAny( (sal_Bool)false) ); + + //DoubleSided + xProp->setPropertyValue( C2U( UNO_NAME_3D_DOUBLE_SIDED ) + , uno::makeAny(bDoubleSided) ); + + if( xSourceProp.is()) + PropertyMapper::setMappedProperties( xProp, xSourceProp, rPropertyNameMap ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createArea3D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::PolyPolygonShape3D& rPolyPolygon + , double fDepth ) +{ + if( !xTarget.is() ) + return 0; + + if( !rPolyPolygon.SequenceX.getLength()) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DExtrudeObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //depth + xProp->setPropertyValue( C2U( UNO_NAME_3D_EXTRUDE_DEPTH ) + , uno::makeAny((sal_Int32)fDepth) ); + + //PercentDiagonal + sal_Int16 nPercentDiagonal = 0; + xProp->setPropertyValue( C2U( UNO_NAME_3D_PERCENT_DIAGONAL ) + , uno::makeAny( nPercentDiagonal ) ); + + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , uno::makeAny( rPolyPolygon ) ); + + //DoubleSided + xProp->setPropertyValue( C2U( UNO_NAME_3D_DOUBLE_SIDED ) + , uno::makeAny( (sal_Bool)true) ); + + //the z component of the polygon is now ignored by the drawing layer, + //so we nned to translate the object via transformation matrix + + //Matrix for position + if( rPolyPolygon.SequenceZ.getLength()&& rPolyPolygon.SequenceZ[0].getLength() ) + { + ::basegfx::B3DHomMatrix aM; + aM.translate( 0 + , 0 + , rPolyPolygon.SequenceZ[0][0] ); + drawing::HomogenMatrix aHM = B3DHomMatrixToHomogenMatrix(aM); + xProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(aHM) ); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createArea2D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::PolyPolygonShape3D& rPolyPolygon ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.PolyPolygonShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //UNO_NAME_POLYGON "Polygon" drawing::PointSequence* + drawing::PointSequenceSequence aPoints( PolyToPointSequence(rPolyPolygon) ); + + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_POLYPOLYGON ) + , uno::makeAny( aPoints ) ); + + //ZOrder + //an area should always be behind other shapes + xProp->setPropertyValue( C2U( UNO_NAME_MISC_OBJ_ZORDER ) + , uno::makeAny( sal_Int32(0) ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +enum SymbolType { SYMBOL_SQUARE=0 + , SYMBOL_DIAMOND + , SYMBOL_ARROW_DOWN + , SYMBOL_ARROW_UP + , SYMBOL_ARROW_RIGHT + , SYMBOL_ARROW_LEFT + , SYMBOL_BOWTIE + , SYMBOL_SANDGLASS + , SYMBOL_COUNT + }; + +sal_Int32 ShapeFactory::getSymbolCount() +{ + return SYMBOL_COUNT; +} + +drawing::PolyPolygonShape3D createPolyPolygon_Symbol( const drawing::Position3D& rPos + , const drawing::Direction3D& rSize + , sal_Int32 nStandardSymbol ) +{ + if(nStandardSymbol<0) + nStandardSymbol*=-1; + nStandardSymbol = nStandardSymbol%ShapeFactory::getSymbolCount(); + SymbolType eSymbolType=static_cast<SymbolType>(nStandardSymbol); + + const double& fX = rPos.PositionX; + const double& fY = rPos.PositionY; + + const double fWidthH = rSize.DirectionX/2.0; //fWidthH stands for Half Width + const double fHeightH = rSize.DirectionY/2.0; //fHeightH stands for Half Height + + sal_Int32 nPointCount = 4; //all arrow symbols only need 4 points + switch( eSymbolType ) + { + case SYMBOL_SQUARE: + case SYMBOL_DIAMOND: + case SYMBOL_BOWTIE: + case SYMBOL_SANDGLASS: + nPointCount = 5; + break; + default: + break; + } + + //-------------------------------------- + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(1); + aPP.SequenceY.realloc(1); + aPP.SequenceZ.realloc(1); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(nPointCount); + pOuterSequenceY->realloc(nPointCount); + pOuterSequenceZ->realloc(nPointCount); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + for(sal_Int32 nN = nPointCount; nN--;) + *pInnerSequenceZ++ = 0.0; + + switch(eSymbolType) + { + case SYMBOL_ARROW_UP: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + break; + } + case SYMBOL_ARROW_DOWN: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + break; + } + case SYMBOL_ARROW_RIGHT: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + break; + } + case SYMBOL_ARROW_LEFT: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY; + break; + } + case SYMBOL_BOWTIE: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + break; + } + case SYMBOL_SANDGLASS: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + break; + } + case SYMBOL_DIAMOND: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY; + + *pInnerSequenceX++ = fX; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY; + + *pInnerSequenceX++ = fX; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY; + break; + } + default: //case SYMBOL_SQUARE: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + break; + } + } + //return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); + return aPP; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createSymbol2D( + const uno::Reference< drawing::XShapes >& xTarget + , const drawing::Position3D& rPosition + , const drawing::Direction3D& rSize + , sal_Int32 nStandardSymbol + , sal_Int32 nBorderColor + , sal_Int32 nFillColor ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.PolyPolygonShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + drawing::PointSequenceSequence aPoints( PolyToPointSequence( + createPolyPolygon_Symbol( rPosition, rSize, nStandardSymbol ) )); + + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_POLYPOLYGON ) + , uno::makeAny( aPoints ) ); + + //LineColor + xProp->setPropertyValue( C2U( UNO_NAME_LINECOLOR ) + , uno::makeAny( nBorderColor ) ); + + //FillColor + xProp->setPropertyValue( C2U( UNO_NAME_FILLCOLOR ) + , uno::makeAny( nFillColor ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createGraphic2D( + const uno::Reference< drawing::XShapes >& xTarget + , const drawing::Position3D& rPosition + , const drawing::Direction3D& rSize + , const uno::Reference< graphic::XGraphic >& xGraphic ) +{ + if( !xTarget.is() || !xGraphic.is() ) + return 0; + + // @todo: change this to a rectangle shape with a fill bitmap for + // performance reasons (ask AW, said CL) + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.GraphicObjectShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + try + { + // assume position is upper left corner. Transform to center. + drawing::Position3D aCenterPosition( + rPosition.PositionX - (rSize.DirectionX / 2.0), + rPosition.PositionY - (rSize.DirectionY / 2.0), + rPosition.PositionZ ); + xShape->setPosition( Position3DToAWTPoint( aCenterPosition )); + xShape->setSize( Direction3DToAWTSize( rSize )); + } + catch( const uno::Exception & e ) + { + ASSERT_EXCEPTION( e ); + } + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + xProp->setPropertyValue( C2U("Graphic"), uno::makeAny( xGraphic )); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShapes > + ShapeFactory::createGroup2D( const uno::Reference< drawing::XShapes >& xTarget + , ::rtl::OUString aName ) +{ + if( !xTarget.is() ) + return 0; + try + { + //create and add to target + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.GroupShape" ) ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set name + if(aName.getLength()) + setShapeName( xShape , aName ); + + {//workaround + //need this null size as otherwise empty group shapes where painted with a gray border + xShape->setSize(awt::Size(0,0)); + } + + //return + uno::Reference< drawing::XShapes > xShapes = + uno::Reference<drawing::XShapes>( xShape, uno::UNO_QUERY ); + return xShapes; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + return 0; +} + +uno::Reference< drawing::XShapes > + ShapeFactory::createGroup3D( const uno::Reference< drawing::XShapes >& xTarget + , ::rtl::OUString aName ) +{ + if( !xTarget.is() ) + return 0; + try + { + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DSceneObject" ) ), uno::UNO_QUERY ); + + xTarget->add(xShape); + + //it is necessary to set the transform matrix to initialize the scene properly (bug #106316#) + //otherwise all objects which are placed into this Group will not be visible + //the following should be unnecessary after a the bug is fixed + { + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + ::basegfx::B3DHomMatrix aM; + xProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(B3DHomMatrixToHomogenMatrix(aM)) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + } + + //set name + if(aName.getLength()) + setShapeName( xShape , aName ); + + //return + uno::Reference< drawing::XShapes > xShapes = + uno::Reference<drawing::XShapes>( xShape, uno::UNO_QUERY ); + return xShapes; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + return 0; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createCircle2D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::Position3D& rPosition + , const drawing::Direction3D& rSize ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.EllipseShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + try + { + drawing::Position3D aCenterPosition( + rPosition.PositionX - (rSize.DirectionX / 2.0), + rPosition.PositionY - (rSize.DirectionY / 2.0), + rPosition.PositionZ ); + xShape->setPosition( Position3DToAWTPoint( aCenterPosition )); + xShape->setSize( Direction3DToAWTSize( rSize )); + } + catch( const uno::Exception & e ) + { + ASSERT_EXCEPTION( e ); + } + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + drawing::CircleKind eKind = drawing::CircleKind_FULL; + xProp->setPropertyValue( C2U( UNO_NAME_CIRCKIND ) + , uno::makeAny( eKind ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createLine3D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::PolyPolygonShape3D& rPoints + , const VLineProperties& rLineProperties ) +{ + if( !xTarget.is() ) + return 0; + + if(!rPoints.SequenceX.getLength()) + return NULL; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DPolygonObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , uno::makeAny( rPoints ) ); + + //LineOnly + xProp->setPropertyValue( C2U( UNO_NAME_3D_LINEONLY ) + , uno::makeAny( (sal_Bool)true ) ); + + //Transparency + if(rLineProperties.Transparence.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINETRANSPARENCE ) + , rLineProperties.Transparence ); + + //LineStyle + if(rLineProperties.LineStyle.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINESTYLE ) + , rLineProperties.LineStyle ); + + //LineWidth + if(rLineProperties.Width.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINEWIDTH ) + , rLineProperties.Width ); + + //LineColor + if(rLineProperties.Color.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINECOLOR ) + , rLineProperties.Color ); + //, uno::makeAny( sal_Int32( Color(COL_RED).GetColor()) ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createLine2D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::PointSequenceSequence& rPoints + , const VLineProperties* pLineProperties ) +{ + if( !xTarget.is() ) + return 0; + + if(!rPoints.getLength()) + return NULL; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + //"com.sun.star.drawing.LineShape") ), uno::UNO_QUERY ); + "com.sun.star.drawing.PolyLineShape") ), uno::UNO_QUERY ); + //"com.sun.star.drawing.PolyLinePathShape") ), uno::UNO_QUERY ); + //"com.sun.star.drawing.PolyPolygonPathShape") ), uno::UNO_QUERY ); + //"com.sun.star.drawing.PolyPolygonShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_POLYPOLYGON ) + , uno::makeAny( rPoints ) ); + + if(pLineProperties) + { + //Transparency + if(pLineProperties->Transparence.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINETRANSPARENCE ) + , pLineProperties->Transparence ); + + //LineStyle + if(pLineProperties->LineStyle.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINESTYLE ) + , pLineProperties->LineStyle ); + + //LineWidth + if(pLineProperties->Width.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINEWIDTH ) + , pLineProperties->Width ); + + //LineColor + if(pLineProperties->Color.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINECOLOR ) + , pLineProperties->Color ); + + //LineDashName + if(pLineProperties->DashName.hasValue()) + xProp->setPropertyValue( C2U( "LineDashName" ) + , pLineProperties->DashName ); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Any ShapeFactory::makeTransformation( const awt::Point& rScreenPosition2D, double fRotationAnglePi ) +{ + ::basegfx::B2DHomMatrix aM; + //As autogrow is active the rectangle is automatically expanded to that side + //to which the text is not adjusted. + // aM.scale( 1, 1 ); Oops? A scale with this parameters is neutral, line commented out + aM.rotate( fRotationAnglePi ); + aM.translate( rScreenPosition2D.X, rScreenPosition2D.Y ); + uno::Any aATransformation = uno::makeAny( B2DHomMatrixToHomogenMatrix3(aM) ); + return aATransformation; +} + +void ShapeFactory::makeShapeInvisible( const uno::Reference< drawing::XShape >& xShape ) +{ + uno::Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xShapeProp.is(), "created shape offers no XPropertySet"); + if( xShapeProp.is()) + { + try + { + xShapeProp->setPropertyValue( C2U("LineStyle"), uno::makeAny( drawing::LineStyle_NONE )); + xShapeProp->setPropertyValue( C2U("FillStyle"), uno::makeAny( drawing::FillStyle_NONE )); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } +} + +uno::Reference< drawing::XShape > ShapeFactory::createInvisibleRectangle( + const uno::Reference< drawing::XShapes >& xTarget + , const awt::Size& rSize ) +{ + try + { + if(!xTarget.is()) + return 0; + + uno::Reference< drawing::XShape > xShape( m_xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY ); + if( xTarget.is() && xShape.is()) + { + xTarget->add( xShape ); + ShapeFactory::makeShapeInvisible( xShape ); + xShape->setSize( rSize ); + } + return xShape; + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + return 0; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createText( const uno::Reference< drawing::XShapes >& xTarget + , const ::rtl::OUString& rText + , const tNameSequence& rPropNames + , const tAnySequence& rPropValues + , const uno::Any& rATransformation ) +{ + if( !xTarget.is() ) + return 0; + + if(!rText.getLength()) + return 0; + + //create shape and add to page + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.TextShape" ) ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set text + uno::Reference< text::XTextRange > xTextRange( xShape, uno::UNO_QUERY ); + if( xTextRange.is() ) + xTextRange->setString( rText ); + + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + if( xProp.is() ) + { + //set properties + PropertyMapper::setMultiProperties( rPropNames, rPropValues, xProp ); + + //set position matrix + //the matrix needs to be set at the end behind autogrow and such position influencing properties + try + { + xProp->setPropertyValue( C2U( "Transformation" ), rATransformation ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +rtl::OUString ShapeFactory::getStackedString( const rtl::OUString& rString, bool bStacked ) +{ + sal_Int32 nLen = rString.getLength(); + if(!bStacked || !nLen) + return rString; + + rtl::OUStringBuffer aStackStr; + rtl::OUStringBuffer aSource(rString); + + //add a newline after each letter + //as we do not no letters here add a newline after each char + for( sal_Int32 nPosSrc=0; nPosSrc < nLen; nPosSrc++ ) + { + if( nPosSrc ) + aStackStr.append( sal_Unicode('\r') ); + aStackStr.append( aSource.charAt( nPosSrc ) ); + } + return aStackStr.makeStringAndClear(); +} + +bool ShapeFactory::hasPolygonAnyLines( drawing::PolyPolygonShape3D& rPoly) +{ + // #i67757# check all contained polygons, if at least one polygon contains 2 or more points, return true + for( sal_Int32 nIdx = 0, nCount = rPoly.SequenceX.getLength(); nIdx < nCount; ++nIdx ) + if( rPoly.SequenceX[ nIdx ].getLength() > 1 ) + return true; + return false; +} + +bool ShapeFactory::isPolygonEmptyOrSinglePoint( drawing::PolyPolygonShape3D& rPoly) +{ + // true, if empty polypolygon or one polygon with one point + return (rPoly.SequenceX.getLength() == 0) || + ((rPoly.SequenceX.getLength() == 1) && (rPoly.SequenceX[0].getLength() <= 1)); +} + +void ShapeFactory::closePolygon( drawing::PolyPolygonShape3D& rPoly) +{ + DBG_ASSERT( rPoly.SequenceX.getLength() <= 1, "ShapeFactory::closePolygon - single polygon expected" ); + //add a last point == first point + if(isPolygonEmptyOrSinglePoint(rPoly)) + return; + drawing::Position3D aFirst(rPoly.SequenceX[0][0],rPoly.SequenceY[0][0],rPoly.SequenceZ[0][0]); + AddPointToPoly( rPoly, aFirst ); +} + +awt::Size ShapeFactory::calculateNewSizeRespectingAspectRatio( + const awt::Size& rTargetSize + , const awt::Size& rSourceSizeWithCorrectAspectRatio ) +{ + awt::Size aNewSize; + + double fFactorWidth = double(rTargetSize.Width)/double(rSourceSizeWithCorrectAspectRatio.Width); + double fFactorHeight = double(rTargetSize.Height)/double(rSourceSizeWithCorrectAspectRatio.Height); + double fFactor = std::min(fFactorWidth,fFactorHeight); + aNewSize.Width=static_cast<sal_Int32>(fFactor*rSourceSizeWithCorrectAspectRatio.Width); + aNewSize.Height=static_cast<sal_Int32>(fFactor*rSourceSizeWithCorrectAspectRatio.Height); + + return aNewSize; +} + +awt::Point ShapeFactory::calculateTopLeftPositionToCenterObject( + const awt::Point& rTargetAreaPosition + , const awt::Size& rTargetAreaSize + , const awt::Size& rObjectSize ) +{ + awt::Point aNewPosition(rTargetAreaPosition); + aNewPosition.X += static_cast<sal_Int32>(double(rTargetAreaSize.Width-rObjectSize.Width)/2.0); + aNewPosition.Y += static_cast<sal_Int32>(double(rTargetAreaSize.Height-rObjectSize.Height)/2.0); + return aNewPosition; +} + +::basegfx::B2IRectangle ShapeFactory::getRectangleOfShape( + const uno::Reference< drawing::XShape >& xShape ) +{ + ::basegfx::B2IRectangle aRet; + + if( xShape.is() ) + { + awt::Point aPos = xShape->getPosition(); + awt::Size aSize = xShape->getSize(); + aRet = BaseGFXHelper::makeRectangle(aPos,aSize); + } + return aRet; + +} + +awt::Size ShapeFactory::getSizeAfterRotation( + const uno::Reference< drawing::XShape >& xShape, double fRotationAngleDegree ) +{ + awt::Size aRet(0,0); + if(xShape.is()) + { + const awt::Size aSize( xShape->getSize() ); + + if( ::rtl::math::approxEqual( fRotationAngleDegree, 0.0 ) ) + aRet = aSize; + else + { + while(fRotationAngleDegree>=360.0) + fRotationAngleDegree-=360.0; + while(fRotationAngleDegree<0.0) + fRotationAngleDegree+=360.0; + if(fRotationAngleDegree>270.0) + fRotationAngleDegree=360.0-fRotationAngleDegree; + else if(fRotationAngleDegree>180.0) + fRotationAngleDegree=fRotationAngleDegree-180.0; + else if(fRotationAngleDegree>90.0) + fRotationAngleDegree=180.0-fRotationAngleDegree; + + const double fAnglePi = fRotationAngleDegree*F_PI/180.0; + + aRet.Height = static_cast<sal_Int32>( + aSize.Width*rtl::math::sin( fAnglePi ) + + aSize.Height*rtl::math::cos( fAnglePi )); + aRet.Width = static_cast<sal_Int32>( + aSize.Width*rtl::math::cos( fAnglePi ) + + aSize.Height*rtl::math::sin( fAnglePi )); + } + } + return aRet; +} + +void ShapeFactory::removeSubShapes( const uno::Reference< drawing::XShapes >& xShapes ) +{ + if( xShapes.is() ) + { + sal_Int32 nSubCount = xShapes->getCount(); + uno::Reference< drawing::XShape > xShape; + for( sal_Int32 nS = nSubCount; nS--; ) + { + if( xShapes->getByIndex( nS ) >>= xShape ) + xShapes->remove( xShape ); + } + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/Stripe.cxx b/chart2/source/view/main/Stripe.cxx new file mode 100644 index 000000000000..2df78e2a8e91 --- /dev/null +++ b/chart2/source/view/main/Stripe.cxx @@ -0,0 +1,360 @@ +/************************************************************************* + * + * 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 "Stripe.hxx" +#include "CommonConverters.hxx" +#include <com/sun/star/drawing/PolyPolygonShape3D.hpp> +#include <com/sun/star/drawing/DoubleSequence.hpp> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <basegfx/polygon/b3dpolygontools.hxx> + +using namespace ::com::sun::star; + +//............................................................................. +namespace chart +{ +//............................................................................. + +Stripe::Stripe( const drawing::Position3D& rPoint1 + , const drawing::Direction3D& rDirectionToPoint2 + , const drawing::Direction3D& rDirectionToPoint4 ) + : m_aPoint1(rPoint1) + , m_aPoint2(rPoint1+rDirectionToPoint2) + , m_aPoint3(m_aPoint2+rDirectionToPoint4) + , m_aPoint4(rPoint1+rDirectionToPoint4) + , m_bInvertNormal(false) + , m_bManualNormalSet(false) +{ +} + +Stripe::Stripe( const drawing::Position3D& rPoint1 + , const drawing::Position3D& rPoint2 + , double fDepth ) + : m_aPoint1(rPoint1) + , m_aPoint2(rPoint2) + , m_aPoint3(rPoint2) + , m_aPoint4(rPoint1) + , m_bInvertNormal(false) + , m_bManualNormalSet(false) +{ + m_aPoint3.PositionZ += fDepth; + m_aPoint4.PositionZ += fDepth; +} + +Stripe::Stripe( const drawing::Position3D& rPoint1 + , const drawing::Position3D& rPoint2 + , const drawing::Position3D& rPoint3 + , const drawing::Position3D& rPoint4 ) + : m_aPoint1(rPoint1) + , m_aPoint2(rPoint2) + , m_aPoint3(rPoint3) + , m_aPoint4(rPoint4) + , m_bInvertNormal(false) + , m_bManualNormalSet(false) +{ +} + +void Stripe::SetManualNormal( const drawing::Direction3D& rNormal ) +{ + m_aManualNormal = rNormal; + m_bManualNormalSet = true; +} + +void Stripe::InvertNormal( bool bInvertNormal ) +{ + m_bInvertNormal = bInvertNormal; +} + +uno::Any Stripe::getPolyPolygonShape3D() const +{ + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(1); + aPP.SequenceY.realloc(1); + aPP.SequenceZ.realloc(1); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(4); + pOuterSequenceY->realloc(4); + pOuterSequenceZ->realloc(4); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + *pInnerSequenceX++ = m_aPoint1.PositionX; + *pInnerSequenceY++ = m_aPoint1.PositionY; + *pInnerSequenceZ++ = m_aPoint1.PositionZ; + + *pInnerSequenceX++ = m_aPoint2.PositionX; + *pInnerSequenceY++ = m_aPoint2.PositionY; + *pInnerSequenceZ++ = m_aPoint2.PositionZ; + + *pInnerSequenceX++ = m_aPoint3.PositionX; + *pInnerSequenceY++ = m_aPoint3.PositionY; + *pInnerSequenceZ++ = m_aPoint3.PositionZ; + + *pInnerSequenceX++ = m_aPoint4.PositionX; + *pInnerSequenceY++ = m_aPoint4.PositionY; + *pInnerSequenceZ++ = m_aPoint4.PositionZ; + + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +drawing::Direction3D Stripe::getNormal() const +{ + drawing::Direction3D aRet(1.0,0.0,0.0); + + if( m_bManualNormalSet ) + aRet = m_aManualNormal; + else + { + ::basegfx::B3DPolygon aPolygon3D; + aPolygon3D.append(Position3DToB3DPoint( m_aPoint1 )); + aPolygon3D.append(Position3DToB3DPoint( m_aPoint2 )); + aPolygon3D.append(Position3DToB3DPoint( m_aPoint3 )); + aPolygon3D.append(Position3DToB3DPoint( m_aPoint4 )); + ::basegfx::B3DVector aNormal(::basegfx::tools::getNormal(aPolygon3D)); + aRet = B3DVectorToDirection3D(aNormal); + } + + if( m_bInvertNormal ) + { + aRet.DirectionX *= -1.0; + aRet.DirectionY *= -1.0; + aRet.DirectionZ *= -1.0; + } + return aRet; +} + +uno::Any Stripe::getNormalsPolygon() const +{ + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(1); + aPP.SequenceY.realloc(1); + aPP.SequenceZ.realloc(1); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(4); + pOuterSequenceY->realloc(4); + pOuterSequenceZ->realloc(4); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + drawing::Direction3D aNormal( getNormal() ); + + for(sal_Int32 nN=4; --nN; ) + { + *pInnerSequenceX++ = aNormal.DirectionX; + *pInnerSequenceY++ = aNormal.DirectionY; + *pInnerSequenceZ++ = aNormal.DirectionZ; + } + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +uno::Any Stripe::getTexturePolygon( short nRotatedTexture ) const +{ + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(1); + aPP.SequenceY.realloc(1); + aPP.SequenceZ.realloc(1); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(4); + pOuterSequenceY->realloc(4); + pOuterSequenceZ->realloc(4); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + if( nRotatedTexture==0 ) + { + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==1 ) + { + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==2 ) + { + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==3 ) + { + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==4 ) + { + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==5 ) + { + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==6 ) + { + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==7 ) + { + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + } + + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/VDataSeries.cxx b/chart2/source/view/main/VDataSeries.cxx new file mode 100644 index 000000000000..2b9512d4af2a --- /dev/null +++ b/chart2/source/view/main/VDataSeries.cxx @@ -0,0 +1,1002 @@ +/************************************************************************* + * + * 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 "VDataSeries.hxx" +#include "ObjectIdentifier.hxx" +#include "macros.hxx" +#include "CommonConverters.hxx" +#include "LabelPositionHelper.hxx" +#include "ChartTypeHelper.hxx" +#include "ContainerHelper.hxx" +#include "DataSeriesHelper.hxx" +#include "RegressionCurveHelper.hxx" + +#include <com/sun/star/chart/MissingValueTreatment.hpp> +#include <com/sun/star/chart2/Symbol.hpp> + +//#include "CommonConverters.hxx" +#include <rtl/math.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/TextVerticalAdjust.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> +#include <com/sun/star/text/WritingMode.hpp> +#include <com/sun/star/chart2/data/XDataSource.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +void VDataSequence::init( const uno::Reference< data::XDataSequence >& xModel ) +{ + Model = xModel; + Doubles = DataSequenceToDoubleSequence( xModel ); +} + +bool VDataSequence::is() const +{ + return Model.is(); +} +void VDataSequence::clear() +{ + Model = NULL; + Doubles.realloc(0); +} + +double VDataSequence::getValue( sal_Int32 index ) const +{ + if( 0<=index && index<Doubles.getLength() ) + return Doubles[index]; + else + { + double fNan; + ::rtl::math::setNan( & fNan ); + return fNan; + } +} + +sal_Int32 VDataSequence::detectNumberFormatKey( sal_Int32 index ) const +{ + sal_Int32 nNumberFormatKey = -1; + + // -1 is allowed and means a key for the whole sequence + if( -1<=index && index<Doubles.getLength() && + Model.is()) + { + nNumberFormatKey = Model->getNumberFormatKeyByIndex( index ); + } + + return nNumberFormatKey; +} + +sal_Int32 VDataSequence::getLength() const +{ + return Doubles.getLength(); +} + +namespace +{ +struct lcl_LessXOfPoint +{ + inline bool operator() ( const std::vector< double >& first, + const std::vector< double >& second ) + { + if( first.size() > 0 && second.size() > 0 ) + { + return first[0]<second[0]; + } + return false; + } +}; + +void lcl_clearIfNoValuesButTextIsContained( VDataSequence& rData, const uno::Reference<data::XDataSequence>& xDataSequence ) +{ + //#i71686#, #i101968#, #i102428# + sal_Int32 nCount = rData.Doubles.getLength(); + for( sal_Int32 i = 0; i < nCount; ++i ) + { + if( !::rtl::math::isNan( rData.Doubles[i] ) ) + return; + } + //no double value is countained + //is there any text? + uno::Sequence< rtl::OUString > aStrings( DataSequenceToStringSequence( xDataSequence ) ); + sal_Int32 nTextCount = aStrings.getLength(); + for( sal_Int32 j = 0; j < nTextCount; ++j ) + { + if( aStrings[j].getLength() ) + { + rData.clear(); + return; + } + } + //no content at all +} + +void lcl_maybeReplaceNanWithZero( double& rfValue, sal_Int32 nMissingValueTreatment ) +{ + if( nMissingValueTreatment == ::com::sun::star::chart::MissingValueTreatment::USE_ZERO + && (::rtl::math::isNan(rfValue) || ::rtl::math::isInf(rfValue)) ) + rfValue = 0.0; +} + +} + +VDataSeries::VDataSeries( const uno::Reference< XDataSeries >& xDataSeries ) + : m_nPolygonIndex(0) + , m_fLogicMinX(0.0) + , m_fLogicMaxX(0.0) + , m_fLogicZPos(0.0) + , m_xGroupShape(NULL) + , m_xLabelsGroupShape(NULL) + , m_xErrorBarsGroupShape(NULL) + , m_xFrontSubGroupShape(NULL) + , m_xBackSubGroupShape(NULL) + , m_xDataSeries(xDataSeries) + , m_aDataSequences() + , m_nPointCount(0) + + , m_aValues_X() + , m_aValues_Y() + , m_aValues_Z() + , m_aValues_Y_Min() + , m_aValues_Y_Max() + , m_aValues_Y_First() + , m_aValues_Y_Last() + , m_aValues_Bubble_Size() + , m_pValueSequenceForDataLabelNumberFormatDetection(&m_aValues_Y) + + , m_fYMeanValue(1.0) + + , m_aAttributedDataPointIndexList() + + , m_eStackingDirection(StackingDirection_NO_STACKING) + , m_nAxisIndex(0) + , m_bConnectBars(sal_False) + , m_bGroupBarsPerAxis(sal_True) + , m_nStartingAngle(90) + + , m_aSeriesParticle() + , m_aCID() + , m_aPointCID_Stub() + , m_aLabelCID_Stub() + + , m_nGlobalSeriesIndex(0) + + , m_apLabel_Series(NULL) + , m_apLabelPropNames_Series(NULL) + , m_apLabelPropValues_Series(NULL) + , m_apSymbolProperties_Series(NULL) + + , m_apLabel_AttributedPoint(NULL) + , m_apLabelPropNames_AttributedPoint(NULL) + , m_apLabelPropValues_AttributedPoint(NULL) + , m_apSymbolProperties_AttributedPoint(NULL) + , m_apSymbolProperties_InvisibleSymbolForSelection(NULL) + , m_nCurrentAttributedPoint(-1) + , m_nMissingValueTreatment(::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP) + , m_bAllowPercentValueInDataLabel(false) +{ + ::rtl::math::setNan( & m_fYMeanValue ); + + uno::Reference<data::XDataSource> xDataSource = + uno::Reference<data::XDataSource>( xDataSeries, uno::UNO_QUERY ); + + m_aDataSequences = xDataSource->getDataSequences(); + + for(sal_Int32 nN = m_aDataSequences.getLength();nN--;) + { + if(!m_aDataSequences[nN].is()) + continue; + uno::Reference<data::XDataSequence> xDataSequence( m_aDataSequences[nN]->getValues()); + uno::Reference<beans::XPropertySet> xProp(xDataSequence, uno::UNO_QUERY ); + if( xProp.is()) + { + try + { + uno::Any aARole = xProp->getPropertyValue( C2U( "Role" ) ); + rtl::OUString aRole; + aARole >>= aRole; + + if( aRole.equals(C2U("values-x")) ) + { + m_aValues_X.init( xDataSequence ); + lcl_clearIfNoValuesButTextIsContained( m_aValues_X, xDataSequence ); + } + else if( aRole.equals(C2U("values-y")) ) + m_aValues_Y.init( xDataSequence ); + else if( aRole.equals(C2U("values-min")) ) + m_aValues_Y_Min.init( xDataSequence ); + else if( aRole.equals(C2U("values-max")) ) + m_aValues_Y_Max.init( xDataSequence ); + else if( aRole.equals(C2U("values-first")) ) + m_aValues_Y_First.init( xDataSequence ); + else if( aRole.equals(C2U("values-last")) ) + m_aValues_Y_Last.init( xDataSequence ); + else if( aRole.equals(C2U("values-size")) ) + m_aValues_Bubble_Size.init( xDataSequence ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + } + + //determine the point count + m_nPointCount = m_aValues_Y.getLength(); + { + if( m_nPointCount < m_aValues_Bubble_Size.getLength() ) + m_nPointCount = m_aValues_Bubble_Size.getLength(); + if( m_nPointCount < m_aValues_Y_Min.getLength() ) + m_nPointCount = m_aValues_Y_Min.getLength(); + if( m_nPointCount < m_aValues_Y_Max.getLength() ) + m_nPointCount = m_aValues_Y_Max.getLength(); + if( m_nPointCount < m_aValues_Y_First.getLength() ) + m_nPointCount = m_aValues_Y_First.getLength(); + if( m_nPointCount < m_aValues_Y_Last.getLength() ) + m_nPointCount = m_aValues_Y_Last.getLength(); + } + + uno::Reference<beans::XPropertySet> xProp(xDataSeries, uno::UNO_QUERY ); + if( xProp.is()) + { + try + { + //get AttributedDataPoints + xProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= m_aAttributedDataPointIndexList; + + xProp->getPropertyValue( C2U( "StackingDirection" ) ) >>= m_eStackingDirection; + + xProp->getPropertyValue( C2U( "AttachedAxisIndex" ) ) >>= m_nAxisIndex; + if(m_nAxisIndex<0) + m_nAxisIndex=0; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } +} + +VDataSeries::~VDataSeries() +{ +} + +void VDataSeries::doSortByXValues() +{ + if( m_aValues_X.is() && m_aValues_X.Doubles.getLength() ) + { + //prepare a vector vor sorting + std::vector< ::std::vector< double > > aTmp;//outer vector are points, inner vector are the different values of athe point + double fNan; + ::rtl::math::setNan( & fNan ); + sal_Int32 nPointIndex = 0; + for( nPointIndex=0; nPointIndex < m_nPointCount; nPointIndex++ ) + { + std::vector< double > aSinglePoint; + aSinglePoint.push_back( (nPointIndex < m_aValues_X.Doubles.getLength()) ? m_aValues_X.Doubles[nPointIndex] : fNan ); + aSinglePoint.push_back( (nPointIndex < m_aValues_Y.Doubles.getLength()) ? m_aValues_Y.Doubles[nPointIndex] : fNan ); + aTmp.push_back( aSinglePoint ); + } + + //do sort + std::sort( aTmp.begin(), aTmp.end(), lcl_LessXOfPoint() ); + + //fill the sorted points back to the mambers + m_aValues_X.Doubles.realloc( m_nPointCount ); + m_aValues_Y.Doubles.realloc( m_nPointCount ); + + for( nPointIndex=0; nPointIndex < m_nPointCount; nPointIndex++ ) + { + m_aValues_X.Doubles[nPointIndex]=aTmp[nPointIndex][0]; + m_aValues_Y.Doubles[nPointIndex]=aTmp[nPointIndex][1]; + } + } +} + +uno::Reference< XDataSeries > VDataSeries::getModel() const +{ + return m_xDataSeries; +} + +void VDataSeries::releaseShapes() +{ + m_xGroupShape.set(0); + m_xLabelsGroupShape.set(0); + m_xErrorBarsGroupShape.set(0); + m_xFrontSubGroupShape.set(0); + m_xBackSubGroupShape.set(0); + + m_aPolyPolygonShape3D.SequenceX.realloc(0); + m_aPolyPolygonShape3D.SequenceY.realloc(0); + m_aPolyPolygonShape3D.SequenceZ.realloc(0); + m_nPolygonIndex = 0; +} + +void VDataSeries::setCategoryXAxis() +{ + m_aValues_X.clear(); + m_bAllowPercentValueInDataLabel = true; +} + +void VDataSeries::setXValues( const Reference< chart2::data::XDataSequence >& xValues ) +{ + m_aValues_X.clear(); + m_aValues_X.init( xValues ); + m_bAllowPercentValueInDataLabel = true; +} + +void VDataSeries::setXValuesIfNone( const Reference< chart2::data::XDataSequence >& xValues ) +{ + if( m_aValues_X.is() ) + return; + + m_aValues_X.init( xValues ); + lcl_clearIfNoValuesButTextIsContained( m_aValues_X, xValues ); +} + +void VDataSeries::setGlobalSeriesIndex( sal_Int32 nGlobalSeriesIndex ) +{ + m_nGlobalSeriesIndex = nGlobalSeriesIndex; +} + +void VDataSeries::setParticle( const rtl::OUString& rSeriesParticle ) +{ + m_aSeriesParticle = rSeriesParticle; + + //get CID + m_aCID = ObjectIdentifier::createClassifiedIdentifierForParticle( m_aSeriesParticle ); + m_aPointCID_Stub = ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT, m_aSeriesParticle ); + + m_aLabelCID_Stub = ObjectIdentifier::createClassifiedIdentifierWithParent( + OBJECTTYPE_DATA_LABEL, ::rtl::OUString(), getLabelsCID() ); +} +rtl::OUString VDataSeries::getSeriesParticle() const +{ + return m_aSeriesParticle; +} +rtl::OUString VDataSeries::getCID() const +{ + return m_aCID; +} +rtl::OUString VDataSeries::getPointCID_Stub() const +{ + return m_aPointCID_Stub; +} +rtl::OUString VDataSeries::getErrorBarsCID() const +{ + rtl::OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_ERRORS ) ); + aChildParticle+=(C2U("=")); + + return ObjectIdentifier::createClassifiedIdentifierForParticles( + m_aSeriesParticle, aChildParticle ); +} +rtl::OUString VDataSeries::getLabelsCID() const +{ + rtl::OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) ); + aChildParticle+=(C2U("=")); + + return ObjectIdentifier::createClassifiedIdentifierForParticles( + m_aSeriesParticle, aChildParticle ); +} +rtl::OUString VDataSeries::getLabelCID_Stub() const +{ + return m_aLabelCID_Stub; +} +rtl::OUString VDataSeries::getDataCurveCID( sal_Int32 nCurveIndex, bool bAverageLine ) const +{ + rtl::OUString aRet; + aRet = ObjectIdentifier::createDataCurveCID( m_aSeriesParticle, nCurveIndex, bAverageLine ); + return aRet; +} + +rtl::OUString VDataSeries::getDataCurveEquationCID( sal_Int32 nCurveIndex ) const +{ + rtl::OUString aRet; + aRet = ObjectIdentifier::createDataCurveEquationCID( m_aSeriesParticle, nCurveIndex ); + return aRet; +} +void VDataSeries::setPageReferenceSize( const awt::Size & rPageRefSize ) +{ + m_aReferenceSize = rPageRefSize; +} + +StackingDirection VDataSeries::getStackingDirection() const +{ + return m_eStackingDirection; +} +sal_Int32 VDataSeries::getAttachedAxisIndex() const +{ + return m_nAxisIndex; +} +void VDataSeries::setConnectBars( sal_Bool bConnectBars ) +{ + m_bConnectBars = bConnectBars; +} +sal_Bool VDataSeries::getConnectBars() const +{ + return m_bConnectBars; +} +void VDataSeries::setGroupBarsPerAxis( sal_Bool bGroupBarsPerAxis ) +{ + m_bGroupBarsPerAxis = bGroupBarsPerAxis; +} +sal_Bool VDataSeries::getGroupBarsPerAxis() const +{ + return m_bGroupBarsPerAxis; +} + +void VDataSeries::setStartingAngle( sal_Int32 nStartingAngle ) +{ + m_nStartingAngle = nStartingAngle; +} +sal_Int32 VDataSeries::getStartingAngle() const +{ + return m_nStartingAngle; +} + +void VDataSeries::setAttachedAxisIndex( sal_Int32 nAttachedAxisIndex ) +{ + if( nAttachedAxisIndex < 0 ) + nAttachedAxisIndex = 0; + m_nAxisIndex = nAttachedAxisIndex; +} + +sal_Int32 VDataSeries::getTotalPointCount() const +{ + return m_nPointCount; +} + +double VDataSeries::getXValue( sal_Int32 index ) const +{ + double fRet = 0.0; + if(m_aValues_X.is()) + { + if( 0<=index && index<m_aValues_X.getLength() ) + fRet = m_aValues_X.Doubles[index]; + else + ::rtl::math::setNan( &fRet ); + } + else + { + // #i70133# always return correct X position - needed for short data series + if( 0<=index /*&& index < m_nPointCount*/ ) + fRet = index+1;//first category (index 0) matches with real number 1.0 + else + ::rtl::math::setNan( &fRet ); + } + lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() ); + return fRet; +} + +double VDataSeries::getYValue( sal_Int32 index ) const +{ + double fRet = 0.0; + if(m_aValues_Y.is()) + { + if( 0<=index && index<m_aValues_Y.getLength() ) + fRet = m_aValues_Y.Doubles[index]; + else + ::rtl::math::setNan( &fRet ); + } + else + { + // #i70133# always return correct X position - needed for short data series + if( 0<=index /*&& index < m_nPointCount*/ ) + fRet = index+1;//first category (index 0) matches with real number 1.0 + else + ::rtl::math::setNan( &fRet ); + } + lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() ); + return fRet; +} + +double VDataSeries::getY_Min( sal_Int32 index ) const +{ + return m_aValues_Y_Min.getValue( index ); +} +double VDataSeries::getY_Max( sal_Int32 index ) const +{ + return m_aValues_Y_Max.getValue( index ); +} +double VDataSeries::getY_First( sal_Int32 index ) const +{ + return m_aValues_Y_First.getValue( index ); +} +double VDataSeries::getY_Last( sal_Int32 index ) const +{ + return m_aValues_Y_Last.getValue( index ); +} +double VDataSeries::getBubble_Size( sal_Int32 index ) const +{ + return m_aValues_Bubble_Size.getValue( index ); +} + +bool VDataSeries::hasExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const +{ + rtl::OUString aPropName( bForPercentage ? C2U( "PercentageNumberFormat" ) : C2U( "NumberFormat" ) ); + bool bHasNumberFormat = false; + uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( nPointIndex )); + sal_Int32 nNumberFormat = -1; + if( xPointProp.is() && (xPointProp->getPropertyValue(aPropName) >>= nNumberFormat) ) + bHasNumberFormat = true; + return bHasNumberFormat; +} +sal_Int32 VDataSeries::getExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const +{ + rtl::OUString aPropName( bForPercentage ? C2U( "PercentageNumberFormat" ) : C2U( "NumberFormat" ) ); + sal_Int32 nNumberFormat = -1; + uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( nPointIndex )); + if( xPointProp.is() ) + xPointProp->getPropertyValue(aPropName) >>= nNumberFormat; + return nNumberFormat; +} +void VDataSeries::setRoleOfSequenceForDataLabelNumberFormatDetection( const rtl::OUString& rRole ) +{ + if( rRole.equals(C2U("values-y")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y; + else if( rRole.equals(C2U("values-size")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Bubble_Size; + else if( rRole.equals(C2U("values-min")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Min; + else if( rRole.equals(C2U("values-max")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Max; + else if( rRole.equals(C2U("values-first")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_First; + else if( rRole.equals(C2U("values-last")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Last; + else if( rRole.equals(C2U("values-x")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_X; +} +bool VDataSeries::shouldLabelNumberFormatKeyBeDetectedFromYAxis() const +{ + if( m_pValueSequenceForDataLabelNumberFormatDetection == &m_aValues_Bubble_Size ) + return false; + else if( m_pValueSequenceForDataLabelNumberFormatDetection == &m_aValues_X ) + return false; + return true; +} +sal_Int32 VDataSeries::detectNumberFormatKey( sal_Int32 index ) const +{ + sal_Int32 nRet = 0; + if( m_pValueSequenceForDataLabelNumberFormatDetection ) + nRet = m_pValueSequenceForDataLabelNumberFormatDetection->detectNumberFormatKey( index ); + return nRet; +} + +sal_Int32 VDataSeries::getLabelPlacement( sal_Int32 nPointIndex, const uno::Reference< chart2::XChartType >& xChartType, sal_Int32 nDimensionCount, sal_Bool bSwapXAndY ) const +{ + sal_Int32 nLabelPlacement=0; + try + { + uno::Reference< beans::XPropertySet > xPointProps( this->getPropertiesOfPoint( nPointIndex ) ); + if( xPointProps.is() ) + xPointProps->getPropertyValue( C2U( "LabelPlacement" ) ) >>= nLabelPlacement; + + //ensure that the set label placement is supported by this charttype + + uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements( + xChartType, nDimensionCount, bSwapXAndY, m_xDataSeries ) ); + + for( sal_Int32 nN = 0; nN < aAvailablePlacements.getLength(); nN++ ) + if( aAvailablePlacements[nN] == nLabelPlacement ) + return nLabelPlacement; //ok + + //otherwise use the first supported one + if( aAvailablePlacements.getLength() ) + { + nLabelPlacement = aAvailablePlacements[0]; + return nLabelPlacement; + } + + DBG_ERROR("no label placement supported"); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + return nLabelPlacement; +} + +double VDataSeries::getMinimumofAllDifferentYValues( sal_Int32 index ) const +{ + double fMin=0.0; + ::rtl::math::setInf(&fMin, false); + + if( !m_aValues_Y.is() && + (m_aValues_Y_Min.is() || m_aValues_Y_Max.is() + || m_aValues_Y_First.is() || m_aValues_Y_Last.is() ) ) + { + double fY_Min = getY_Min( index ); + double fY_Max = getY_Max( index ); + double fY_First = getY_First( index ); + double fY_Last = getY_Last( index ); + + if(fMin>fY_First) + fMin=fY_First; + if(fMin>fY_Last) + fMin=fY_Last; + if(fMin>fY_Min) + fMin=fY_Min; + if(fMin>fY_Max) + fMin=fY_Max; + } + else + { + double fY = getYValue( index ); + if(fMin>fY) + fMin=fY; + } + + if( ::rtl::math::isInf(fMin) ) + ::rtl::math::setNan(&fMin); + + return fMin; +} + +double VDataSeries::getMaximumofAllDifferentYValues( sal_Int32 index ) const +{ + double fMax=0.0; + ::rtl::math::setInf(&fMax, true); + + if( !m_aValues_Y.is() && + (m_aValues_Y_Min.is() || m_aValues_Y_Max.is() + || m_aValues_Y_First.is() || m_aValues_Y_Last.is() ) ) + { + double fY_Min = getY_Min( index ); + double fY_Max = getY_Max( index ); + double fY_First = getY_First( index ); + double fY_Last = getY_Last( index ); + + if(fMax<fY_First) + fMax=fY_First; + if(fMax<fY_Last) + fMax=fY_Last; + if(fMax<fY_Min) + fMax=fY_Min; + if(fMax<fY_Max) + fMax=fY_Max; + } + else + { + double fY = getYValue( index ); + if(fMax<fY) + fMax=fY; + } + + if( ::rtl::math::isInf(fMax) ) + ::rtl::math::setNan(&fMax); + + return fMax; +} + +uno::Sequence< double > VDataSeries::getAllX() const +{ + if(!m_aValues_X.is() && !m_aValues_X.getLength() && m_nPointCount) + { + //init x values from category indexes + //first category (index 0) matches with real number 1.0 + m_aValues_X.Doubles.realloc( m_nPointCount ); + for(sal_Int32 nN=m_aValues_X.getLength();nN--;) + m_aValues_X.Doubles[nN] = nN+1; + } + return m_aValues_X.Doubles; +} + +uno::Sequence< double > VDataSeries::getAllY() const +{ + if(!m_aValues_Y.is() && !m_aValues_Y.getLength() && m_nPointCount) + { + //init y values from indexes + //first y-value (index 0) matches with real number 1.0 + m_aValues_Y.Doubles.realloc( m_nPointCount ); + for(sal_Int32 nN=m_aValues_Y.getLength();nN--;) + m_aValues_Y.Doubles[nN] = nN+1; + } + return m_aValues_Y.Doubles; +} + +double VDataSeries::getYMeanValue() const +{ + if( ::rtl::math::isNan( m_fYMeanValue ) ) + { + uno::Reference< XRegressionCurveCalculator > xCalculator( RegressionCurveHelper::createRegressionCurveCalculatorByServiceName( C2U("com.sun.star.chart2.MeanValueRegressionCurve") ) ); + uno::Sequence< double > aXValuesDummy; + xCalculator->recalculateRegression( aXValuesDummy, getAllY() ); + double fXDummy = 1.0; + m_fYMeanValue = xCalculator->getCurveValue( fXDummy ); + } + return m_fYMeanValue; +} + +::std::auto_ptr< Symbol > getSymbolPropertiesFromPropertySet( + const uno::Reference< beans::XPropertySet >& xProp ) +{ + ::std::auto_ptr< Symbol > apSymbolProps( new Symbol() ); + try + { + if( xProp->getPropertyValue( C2U( "Symbol" ) ) >>= *apSymbolProps ) + { + //use main color to fill symbols + xProp->getPropertyValue( C2U( "Color" ) ) >>= apSymbolProps->FillColor; + // border of symbols always same as fill color + apSymbolProps->BorderColor = apSymbolProps->FillColor; + } + else + apSymbolProps.reset(); + } + catch( uno::Exception &e) + { + ASSERT_EXCEPTION( e ); + } + return apSymbolProps; +} + +Symbol* VDataSeries::getSymbolProperties( sal_Int32 index ) const +{ + Symbol* pRet=NULL; + if( isAttributedDataPoint( index ) ) + { + adaptPointCache( index ); + if(!m_apSymbolProperties_AttributedPoint.get()) + m_apSymbolProperties_AttributedPoint = getSymbolPropertiesFromPropertySet( this->getPropertiesOfPoint( index ) ); + pRet = m_apSymbolProperties_AttributedPoint.get(); + //if a single data point does not have symbols but the dataseries itself has symbols + //we create an invisible symbol shape to enable selection of that point + if( !pRet || pRet->Style == SymbolStyle_NONE ) + { + if(!m_apSymbolProperties_Series.get()) + m_apSymbolProperties_Series = getSymbolPropertiesFromPropertySet( this->getPropertiesOfSeries() ); + if( m_apSymbolProperties_Series.get() && m_apSymbolProperties_Series->Style != SymbolStyle_NONE ) + { + if(!m_apSymbolProperties_InvisibleSymbolForSelection.get()) + { + m_apSymbolProperties_InvisibleSymbolForSelection = ::std::auto_ptr< Symbol >( new Symbol() ); + m_apSymbolProperties_InvisibleSymbolForSelection->Style = SymbolStyle_STANDARD; + m_apSymbolProperties_InvisibleSymbolForSelection->StandardSymbol = 0;//square + m_apSymbolProperties_InvisibleSymbolForSelection->Size = m_apSymbolProperties_Series->Size; + m_apSymbolProperties_InvisibleSymbolForSelection->BorderColor = 0xff000000;//invisible + m_apSymbolProperties_InvisibleSymbolForSelection->FillColor = 0xff000000;//invisible + } + pRet = m_apSymbolProperties_InvisibleSymbolForSelection.get(); + } + } + } + else + { + if(!m_apSymbolProperties_Series.get()) + m_apSymbolProperties_Series = getSymbolPropertiesFromPropertySet( this->getPropertiesOfSeries() ); + pRet = m_apSymbolProperties_Series.get(); + } + + if( pRet && pRet->Style == SymbolStyle_AUTO ) + { + pRet->Style = SymbolStyle_STANDARD; + + sal_Int32 nIndex = m_nGlobalSeriesIndex; + if(m_aValues_X.is()) + nIndex++; + pRet->StandardSymbol = nIndex; + } + + return pRet; +} + +uno::Reference< beans::XPropertySet > VDataSeries::getYErrorBarProperties( sal_Int32 index ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProp; + + uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( index )); + if( xPointProp.is() ) + xPointProp->getPropertyValue( C2U( "ErrorBarY" )) >>= xErrorBarProp; + return xErrorBarProp; +} + +bool VDataSeries::hasPointOwnColor( sal_Int32 index ) const +{ + if( !isAttributedDataPoint(index) ) + return false; + + try + { + uno::Reference< beans::XPropertyState > xPointState( this->getPropertiesOfPoint(index), uno::UNO_QUERY_THROW ); + return (xPointState->getPropertyState( C2U("Color")) != beans::PropertyState_DEFAULT_VALUE ); + } + catch( uno::Exception& e) + { + ASSERT_EXCEPTION( e ); + } + return false; +} + +bool VDataSeries::isAttributedDataPoint( sal_Int32 index ) const +{ + //returns true if the data point assigned by the given index has set it's own properties + if( index>=m_nPointCount || m_nPointCount==0) + return false; + for(sal_Int32 nN=m_aAttributedDataPointIndexList.getLength();nN--;) + { + if(index==m_aAttributedDataPointIndexList[nN]) + return true; + } + return false; +} + +bool VDataSeries::isVaryColorsByPoint() const +{ + bool bVaryColorsByPoint = false; + Reference< beans::XPropertySet > xSeriesProp( this->getPropertiesOfSeries() ); + if( xSeriesProp.is() ) + xSeriesProp->getPropertyValue( C2U("VaryColorsByPoint") ) >>= bVaryColorsByPoint; + return bVaryColorsByPoint; +} + +uno::Reference< beans::XPropertySet > VDataSeries::getPropertiesOfPoint( sal_Int32 index ) const +{ + if( isAttributedDataPoint( index ) ) + return m_xDataSeries->getDataPointByIndex(index); + return this->getPropertiesOfSeries(); +} + +uno::Reference< beans::XPropertySet > VDataSeries::getPropertiesOfSeries() const +{ + return uno::Reference<beans::XPropertySet>(m_xDataSeries, uno::UNO_QUERY ); +} + +::std::auto_ptr< DataPointLabel > getDataPointLabelFromPropertySet( + const uno::Reference< beans::XPropertySet >& xProp ) +{ + ::std::auto_ptr< DataPointLabel > apLabel( new DataPointLabel() ); + try + { + if( !(xProp->getPropertyValue( C2U( "Label" ) ) >>= *apLabel) ) + apLabel.reset(); + } + catch( uno::Exception &e) + { + ASSERT_EXCEPTION( e ); + } + return apLabel; +} + +void VDataSeries::adaptPointCache( sal_Int32 nNewPointIndex ) const +{ + if( m_nCurrentAttributedPoint != nNewPointIndex ) + { + m_apLabel_AttributedPoint.reset(); + m_apLabelPropNames_AttributedPoint.reset(); + m_apLabelPropValues_AttributedPoint.reset(); + m_apSymbolProperties_AttributedPoint.reset(); + m_nCurrentAttributedPoint = nNewPointIndex; + } +} + +DataPointLabel* VDataSeries::getDataPointLabel( sal_Int32 index ) const +{ + DataPointLabel* pRet = NULL; + if( isAttributedDataPoint( index ) ) + { + adaptPointCache( index ); + if( !m_apLabel_AttributedPoint.get() ) + m_apLabel_AttributedPoint = getDataPointLabelFromPropertySet( this->getPropertiesOfPoint( index ) ); + pRet = m_apLabel_AttributedPoint.get(); + } + else + { + if(!m_apLabel_Series.get()) + m_apLabel_Series = getDataPointLabelFromPropertySet( this->getPropertiesOfPoint( index ) ); + pRet = m_apLabel_Series.get(); + } + if( !m_bAllowPercentValueInDataLabel ) + { + if( pRet ) + pRet->ShowNumberInPercent = false; + } + return pRet; +} + +DataPointLabel* VDataSeries::getDataPointLabelIfLabel( sal_Int32 index ) const +{ + DataPointLabel* pLabel = this->getDataPointLabel( index ); + if( !pLabel || (!pLabel->ShowNumber && !pLabel->ShowNumberInPercent + && !pLabel->ShowCategoryName ) ) + return 0; + return pLabel; +} + +bool VDataSeries::getTextLabelMultiPropertyLists( sal_Int32 index + , tNameSequence*& pPropNames + , tAnySequence*& pPropValues ) const +{ + pPropNames = NULL; pPropValues = NULL; + uno::Reference< beans::XPropertySet > xTextProp; + bool bDoDynamicFontResize = false; + if( isAttributedDataPoint( index ) ) + { + adaptPointCache( index ); + if(!m_apLabelPropValues_AttributedPoint.get()) + { + pPropNames = new tNameSequence(); + pPropValues = new tAnySequence(); + xTextProp.set( this->getPropertiesOfPoint( index )); + PropertyMapper::getTextLabelMultiPropertyLists( xTextProp, *pPropNames, *pPropValues ); + m_apLabelPropNames_AttributedPoint = ::std::auto_ptr< tNameSequence >(pPropNames); + m_apLabelPropValues_AttributedPoint = ::std::auto_ptr< tAnySequence >(pPropValues); + bDoDynamicFontResize = true; + } + pPropNames = m_apLabelPropNames_AttributedPoint.get(); + pPropValues = m_apLabelPropValues_AttributedPoint.get(); + } + else + { + if(!m_apLabelPropValues_Series.get()) + { + pPropNames = new tNameSequence(); + pPropValues = new tAnySequence(); + xTextProp.set( this->getPropertiesOfPoint( index )); + PropertyMapper::getTextLabelMultiPropertyLists( xTextProp, *pPropNames, *pPropValues ); + m_apLabelPropNames_Series = ::std::auto_ptr< tNameSequence >(pPropNames); + m_apLabelPropValues_Series = ::std::auto_ptr< tAnySequence >(pPropValues); + bDoDynamicFontResize = true; + } + pPropNames = m_apLabelPropNames_Series.get(); + pPropValues = m_apLabelPropValues_Series.get(); + } + + if( bDoDynamicFontResize && + pPropNames && pPropValues && + xTextProp.is()) + { + LabelPositionHelper::doDynamicFontResize( *pPropValues, *pPropNames, xTextProp, m_aReferenceSize ); + } + if(pPropNames&&pPropValues) + return true; + return false; +} + +void VDataSeries::setMissingValueTreatment( sal_Int32 nMissingValueTreatment ) +{ + m_nMissingValueTreatment = nMissingValueTreatment; +} + +sal_Int32 VDataSeries::getMissingValueTreatment() const +{ + return m_nMissingValueTreatment; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/VLegend.cxx b/chart2/source/view/main/VLegend.cxx new file mode 100644 index 000000000000..33e1d1f26aa4 --- /dev/null +++ b/chart2/source/view/main/VLegend.cxx @@ -0,0 +1,1050 @@ +/************************************************************************* + * + * 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 "VLegend.hxx" +#include "macros.hxx" +#include "PropertyMapper.hxx" +#include "CommonConverters.hxx" +#include "ObjectIdentifier.hxx" +#include "RelativePositionHelper.hxx" +#include "ShapeFactory.hxx" +#include "RelativeSizeHelper.hxx" +#include "LegendEntryProvider.hxx" +#include "chartview/DrawModelWrapper.hxx" +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> +#include <com/sun/star/drawing/LineJoint.hpp> +#include <com/sun/star/chart/ChartLegendExpansion.hpp> +#include <com/sun/star/chart2/LegendPosition.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <rtl/ustrbuf.hxx> +#include <svl/languageoptions.hxx> + +#include <vector> +#include <algorithm> + +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; +using ::rtl::OUStringBuffer; + +//............................................................................. +namespace chart +{ +//............................................................................. + +namespace +{ + +typedef ::std::pair< ::chart::tNameSequence, ::chart::tAnySequence > tPropertyValues; + +typedef ::std::vector< ViewLegendEntry > tViewLegendEntryContainer; + +double lcl_CalcViewFontSize( + const Reference< beans::XPropertySet > & xProp, + const awt::Size & rReferenceSize ) +{ + double fResult = 10.0; + + awt::Size aPropRefSize; + float fFontHeight( 0.0 ); + if( xProp.is() && ( xProp->getPropertyValue( C2U( "CharHeight" )) >>= fFontHeight )) + { + fResult = fFontHeight; + try + { + if( (xProp->getPropertyValue( C2U( "ReferencePageSize" )) >>= aPropRefSize) && + (aPropRefSize.Height > 0)) + { + // todo: find out if asian text is really used +// Reference< beans::XPropertySetInfo >xInfo( xProp, uno::UNO_QUERY ); +// float fFontHeight2 = fFontHeight; +// if( xInfo.is() && +// xInfo->hasPropertyByName(C2U("CharHeightAsian")) && +// (xProp->getPropertyValue(C2U("CharHeightAsian")) >>= fFontHeight2) && +// fFontHeight2 > fFontHeight ) +// { +// fFontHeight = fFontHeight2; +// } + +// if( xInfo.is() && +// xInfo->hasPropertyByName(C2U("CharHeightComplex")) && +// (xProp->getPropertyValue(C2U("CharHeightComplex")) >>= fFontHeight2) && +// fFontHeight2 > fFontHeight ) +// { +// fFontHeight = fFontHeight2; +// } + + fResult = ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize ); + } + } + catch( const uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + } + + // pt -> 1/100th mm + return (fResult * (2540.0 / 72.0)); +} + +void lcl_getProperties( + const Reference< beans::XPropertySet > & xLegendProp, + tPropertyValues & rOutLineFillProperties, + tPropertyValues & rOutTextProperties, + const awt::Size & rReferenceSize ) +{ + // Get Line- and FillProperties from model legend + if( xLegendProp.is()) + { + // set rOutLineFillProperties + ::chart::tPropertyNameValueMap aLineFillValueMap; + ::chart::PropertyMapper::getValueMap( aLineFillValueMap, ::chart::PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xLegendProp ); + + aLineFillValueMap[ C2U("LineJoint") ] = uno::makeAny( drawing::LineJoint_ROUND ); + + ::chart::PropertyMapper::getMultiPropertyListsFromValueMap( + rOutLineFillProperties.first, rOutLineFillProperties.second, aLineFillValueMap ); + + // set rOutTextProperties + ::chart::tPropertyNameValueMap aTextValueMap; + ::chart::PropertyMapper::getValueMap( aTextValueMap, ::chart::PropertyMapper::getPropertyNameMapForCharacterProperties(), xLegendProp ); + + drawing::TextHorizontalAdjust eHorizAdjust( drawing::TextHorizontalAdjust_LEFT ); + aTextValueMap[ C2U("TextAutoGrowHeight") ] = uno::makeAny( sal_True ); + aTextValueMap[ C2U("TextAutoGrowWidth") ] = uno::makeAny( sal_True ); + aTextValueMap[ C2U("TextHorizontalAdjust") ] = uno::makeAny( eHorizAdjust ); + aTextValueMap[ C2U("TextMaximumFrameWidth") ] = uno::makeAny( rReferenceSize.Width ); //needs to be overwritten by actual available space in the legend + + // recalculate font size + awt::Size aPropRefSize; + float fFontHeight( 0.0 ); + if( (xLegendProp->getPropertyValue( C2U( "ReferencePageSize" )) >>= aPropRefSize) && + (aPropRefSize.Height > 0) && + (aTextValueMap[ C2U("CharHeight") ] >>= fFontHeight) ) + { + aTextValueMap[ C2U("CharHeight") ] = uno::makeAny( + static_cast< float >( + ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize ))); + + if( aTextValueMap[ C2U("CharHeightAsian") ] >>= fFontHeight ) + { + aTextValueMap[ C2U("CharHeightAsian") ] = uno::makeAny( + static_cast< float >( + ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize ))); + } + if( aTextValueMap[ C2U("CharHeightComplex") ] >>= fFontHeight ) + { + aTextValueMap[ C2U("CharHeightComplex") ] = uno::makeAny( + static_cast< float >( + ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize ))); + } + } + + ::chart::PropertyMapper::getMultiPropertyListsFromValueMap( + rOutTextProperties.first, rOutTextProperties.second, aTextValueMap ); + } +} + +awt::Size lcl_createTextShapes( + const tViewLegendEntryContainer & rEntries, + const Reference< lang::XMultiServiceFactory > & xShapeFactory, + const Reference< drawing::XShapes > & xTarget, + ::std::vector< Reference< drawing::XShape > > & rOutTextShapes, + const tPropertyValues & rTextProperties ) +{ + awt::Size aResult; + + for( tViewLegendEntryContainer::const_iterator aIt( rEntries.begin()); + aIt != rEntries.end(); ++aIt ) + { + try + { + // create label shape + Reference< drawing::XShape > xEntry( + xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.TextShape" )), uno::UNO_QUERY_THROW ); + xTarget->add( xEntry ); + + // set label text + Sequence< Reference< XFormattedString > > aLabelSeq = (*aIt).aLabel; + for( sal_Int32 i = 0; i < aLabelSeq.getLength(); ++i ) + { + // todo: support more than one text range + if( i == 1 ) + break; + + Reference< text::XTextRange > xRange( xEntry, uno::UNO_QUERY ); + OUString aLabelString( aLabelSeq[i]->getString()); + // workaround for Issue #i67540# + if( !aLabelString.getLength()) + aLabelString = C2U(" "); + if( xRange.is()) + xRange->setString( aLabelString ); + + PropertyMapper::setMultiProperties( + rTextProperties.first, rTextProperties.second, + Reference< beans::XPropertySet >( xRange, uno::UNO_QUERY )); + + // adapt max-extent + awt::Size aCurrSize( xEntry->getSize()); + aResult.Width = ::std::max( aResult.Width, aCurrSize.Width ); + aResult.Height = ::std::max( aResult.Height, aCurrSize.Height ); + } + + rOutTextShapes.push_back( xEntry ); + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + } + + return aResult; +} + +void lcl_collectColumnWidths( std::vector< sal_Int32 >& rColumnWidths, const sal_Int32 nNumberOfRows, const sal_Int32 nNumberOfColumns + , const ::std::vector< Reference< drawing::XShape > > aTextShapes, sal_Int32 nSymbolPlusDistanceWidth ) +{ + rColumnWidths.clear(); + sal_Int32 nRow = 0; + sal_Int32 nColumn = 0; + sal_Int32 nNumberOfEntries = aTextShapes.size(); + for( ; nRow < nNumberOfRows; ++nRow ) + { + for( nColumn = 0; nColumn < nNumberOfColumns; ++nColumn ) + { + sal_Int32 nEntry = (nColumn + nRow * nNumberOfColumns); + if( nEntry < nNumberOfEntries ) + { + awt::Size aTextSize( aTextShapes[ nEntry ]->getSize() ); + sal_Int32 nWidth = nSymbolPlusDistanceWidth + aTextSize.Width; + if( nRow==0 ) + rColumnWidths.push_back( nWidth ); + else + rColumnWidths[nColumn] = ::std::max( nWidth, rColumnWidths[nColumn] ); + } + } + } +} + +void lcl_collectRowHeighs( std::vector< sal_Int32 >& rRowHeights, const sal_Int32 nNumberOfRows, const sal_Int32 nNumberOfColumns + , const ::std::vector< Reference< drawing::XShape > > aTextShapes ) +{ + // calculate maximum height for each row + // and collect column widths + rRowHeights.clear(); + sal_Int32 nRow = 0; + sal_Int32 nColumn = 0; + sal_Int32 nNumberOfEntries = aTextShapes.size(); + for( ; nRow < nNumberOfRows; ++nRow ) + { + sal_Int32 nCurrentRowHeight = 0; + for( nColumn = 0; nColumn < nNumberOfColumns; ++nColumn ) + { + sal_Int32 nEntry = (nColumn + nRow * nNumberOfColumns); + if( nEntry < nNumberOfEntries ) + { + awt::Size aTextSize( aTextShapes[ nEntry ]->getSize() ); + nCurrentRowHeight = ::std::max( nCurrentRowHeight, aTextSize.Height ); + } + } + rRowHeights.push_back( nCurrentRowHeight ); + } +} + +sal_Int32 lcl_getTextLineHeight( const std::vector< sal_Int32 >& aRowHeights, const sal_Int32 nNumberOfRows, double fViewFontSize ) +{ + const sal_Int32 nFontHeight = static_cast< sal_Int32 >( fViewFontSize ); + sal_Int32 nTextLineHeight = nFontHeight; + for( sal_Int32 nR=0; nR<nNumberOfRows; nR++ ) + { + sal_Int32 nFullTextHeight = aRowHeights[ nR ]; + if( ( nFullTextHeight / nFontHeight ) <= 1 ) + { + nTextLineHeight = nFullTextHeight;//found an entry with one line-> have real text height + break; + } + } + return nTextLineHeight; +} + +//returns resulting legend size +awt::Size lcl_placeLegendEntries( + tViewLegendEntryContainer & rEntries, + ::com::sun::star::chart::ChartLegendExpansion eExpansion, + bool bSymbolsLeftSide, + double fViewFontSize, + const awt::Size& rMaxSymbolExtent, + tPropertyValues & rTextProperties, + const Reference< drawing::XShapes > & xTarget, + const Reference< lang::XMultiServiceFactory > & xShapeFactory, + const awt::Size & rAvailableSpace ) +{ + bool bIsCustomSize = (eExpansion == ::com::sun::star::chart::ChartLegendExpansion_CUSTOM); + awt::Size aResultingLegendSize(0,0); + if( bIsCustomSize ) + aResultingLegendSize = rAvailableSpace; + + // #i109336# Improve auto positioning in chart + sal_Int32 nXPadding = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.33 ) ); + //sal_Int32 nXPadding = static_cast< sal_Int32 >( std::max( 200.0, fViewFontSize * 0.33 ) ); + sal_Int32 nXOffset = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.66 ) ); + sal_Int32 nYPadding = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.2 ) ); + sal_Int32 nYOffset = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.2 ) ); + //sal_Int32 nYOffset = static_cast< sal_Int32 >( std::max( 230.0, fViewFontSize * 0.45 ) ); + + const sal_Int32 nSymbolToTextDistance = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.22 ) );//minimum 1mm + const sal_Int32 nSymbolPlusDistanceWidth = rMaxSymbolExtent.Width + nSymbolToTextDistance; + sal_Int32 nMaxTextWidth = rAvailableSpace.Width - (2 * nXPadding) - nSymbolPlusDistanceWidth; + rtl::OUString aPropNameTextMaximumFrameWidth( C2U("TextMaximumFrameWidth") ); + uno::Any* pFrameWidthAny = PropertyMapper::getValuePointer( rTextProperties.second, rTextProperties.first, aPropNameTextMaximumFrameWidth); + if(pFrameWidthAny) + { + if( eExpansion == ::com::sun::star::chart::ChartLegendExpansion_HIGH ) + { + // limit the width of texts to 30% of the total available width + // #i109336# Improve auto positioning in chart + nMaxTextWidth = rAvailableSpace.Width * 3 / 10; + } + *pFrameWidthAny = uno::makeAny(nMaxTextWidth); + } + + ::std::vector< Reference< drawing::XShape > > aTextShapes; + awt::Size aMaxEntryExtent = lcl_createTextShapes( rEntries, xShapeFactory, xTarget, aTextShapes, rTextProperties ); + OSL_ASSERT( aTextShapes.size() == rEntries.size()); + + sal_Int32 nMaxEntryWidth = nXOffset + nSymbolPlusDistanceWidth + aMaxEntryExtent.Width; + sal_Int32 nMaxEntryHeight = nYOffset + aMaxEntryExtent.Height; + sal_Int32 nNumberOfEntries = rEntries.size(); + + sal_Int32 nNumberOfColumns = 0, nNumberOfRows = 0; + std::vector< sal_Int32 > aColumnWidths; + std::vector< sal_Int32 > aRowHeights; + + sal_Int32 nTextLineHeight = static_cast< sal_Int32 >( fViewFontSize ); + + // determine layout depending on LegendExpansion + if( eExpansion == ::com::sun::star::chart::ChartLegendExpansion_CUSTOM ) + { + sal_Int32 nCurrentRow=0; + sal_Int32 nCurrentColumn=-1; + sal_Int32 nColumnCount=0; + sal_Int32 nMaxColumnCount=-1; + for( sal_Int32 nN=0; nN<static_cast<sal_Int32>(aTextShapes.size()); nN++ ) + { + Reference< drawing::XShape > xShape( aTextShapes[nN] ); + if( !xShape.is() ) + continue; + awt::Size aSize( xShape->getSize() ); + sal_Int32 nNewWidth = aSize.Width + nSymbolPlusDistanceWidth; + sal_Int32 nCurrentColumnCount = aColumnWidths.size(); + + //are we allowed to add a new column? + if( nMaxColumnCount==-1 || (nCurrentColumn+1) < nMaxColumnCount ) + { + //try add a new column + nCurrentColumn++; + if( nCurrentColumn < nCurrentColumnCount ) + { + //check wether the current column width is sufficient for the new entry + if( aColumnWidths[nCurrentColumn]>=nNewWidth ) + { + //all good proceed with next entry + continue; + } + } + if( nCurrentColumn < nCurrentColumnCount ) + aColumnWidths[nCurrentColumn] = std::max( nNewWidth, aColumnWidths[nCurrentColumn] ); + else + aColumnWidths.push_back(nNewWidth); + + //do the columns still fit into the given size? + nCurrentColumnCount = aColumnWidths.size();//update count + sal_Int32 nSumWidth = 0; + for( sal_Int32 nC=0; nC<nCurrentColumnCount; nC++ ) + nSumWidth += aColumnWidths[nC]; + + if( nSumWidth <= rAvailableSpace.Width || nCurrentColumnCount==1 ) + { + //all good proceed with next entry + continue; + } + else + { + //not enough space for the current amount of columns + //try again with less columns + nMaxColumnCount = nCurrentColumnCount-1; + nN=-1; + nCurrentRow=0; + nCurrentColumn=-1; + nColumnCount=0; + aColumnWidths.clear(); + } + } + else + { + //add a new row and try the same entry again + nCurrentRow++; + nCurrentColumn=-1; + nN--; + } + } + nNumberOfColumns = aColumnWidths.size(); + nNumberOfRows = nCurrentRow+1; + + //check if there is not enough space so that some entries must be removed + lcl_collectRowHeighs( aRowHeights, nNumberOfRows, nNumberOfColumns, aTextShapes ); + nTextLineHeight = lcl_getTextLineHeight( aRowHeights, nNumberOfRows, fViewFontSize ); + sal_Int32 nSumHeight = 0; + for( sal_Int32 nR=0; nR<nNumberOfRows; nR++ ) + nSumHeight += aRowHeights[nR]; + sal_Int32 nRemainingSpace = rAvailableSpace.Height - nSumHeight; + + if( nRemainingSpace<0 ) + { + //remove entries that are too big + for( sal_Int32 nR=nNumberOfRows; nR--; ) + { + for( sal_Int32 nC=nNumberOfColumns; nC--; ) + { + sal_Int32 nEntry = (nC + nR * nNumberOfColumns); + if( nEntry < static_cast<sal_Int32>(aTextShapes.size()) ) + { + DrawModelWrapper::removeShape( aTextShapes[nEntry] ); + aTextShapes.pop_back(); + } + if( nEntry < nNumberOfEntries ) + { + DrawModelWrapper::removeShape( rEntries[ nEntry ].aSymbol ); + rEntries.pop_back(); + nNumberOfEntries--; + } + } + nSumHeight -= aRowHeights[nR]; + aRowHeights.pop_back(); + nRemainingSpace = rAvailableSpace.Height - nSumHeight; + if( nRemainingSpace>=0 ) + break; + } + nNumberOfRows = static_cast<sal_Int32>(aRowHeights.size()); + } + if( nRemainingSpace > 0 ) + { + sal_Int32 nNormalSpacingHeight = 2*nYPadding+(nNumberOfRows-1)*nYOffset; + if( nRemainingSpace < nNormalSpacingHeight ) + { + //reduce spacing between the entries + nYPadding = nYOffset = nRemainingSpace/(nNumberOfRows+1); + } + else + { + //we have some space left that should be spread equally between all rows + sal_Int32 nRemainingSingleSpace = (nRemainingSpace-nNormalSpacingHeight)/(nNumberOfRows+1); + nYPadding += nRemainingSingleSpace; + nYOffset += nRemainingSingleSpace; + } + } + + //check spacing between columns + sal_Int32 nSumWidth = 0; + for( sal_Int32 nC=0; nC<nNumberOfColumns; nC++ ) + nSumWidth += aColumnWidths[nC]; + nRemainingSpace = rAvailableSpace.Width - nSumWidth; + if( nRemainingSpace>=0 ) + { + sal_Int32 nNormalSpacingWidth = 2*nXPadding+(nNumberOfColumns-1)*nXOffset; + if( nRemainingSpace < nNormalSpacingWidth ) + { + //reduce spacing between the entries + nXPadding = nXOffset = nRemainingSpace/(nNumberOfColumns+1); + } + else + { + //we have some space left that should be spread equally between all columns + sal_Int32 nRemainingSingleSpace = (nRemainingSpace-nNormalSpacingWidth)/(nNumberOfColumns+1); + nXPadding += nRemainingSingleSpace; + nXOffset += nRemainingSingleSpace; + } + } + } + else if( eExpansion == ::com::sun::star::chart::ChartLegendExpansion_HIGH ) + { + sal_Int32 nMaxNumberOfRows = nMaxEntryHeight + ? (rAvailableSpace.Height - 2*nYPadding ) / nMaxEntryHeight + : 0; + + nNumberOfColumns = nMaxNumberOfRows + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nMaxNumberOfRows ) )) + : 0; + nNumberOfRows = nNumberOfColumns + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nNumberOfColumns ) )) + : 0; + } + else if( eExpansion == ::com::sun::star::chart::ChartLegendExpansion_WIDE ) + { + sal_Int32 nMaxNumberOfColumns = nMaxEntryWidth + ? (rAvailableSpace.Width - 2*nXPadding ) / nMaxEntryWidth + : 0; + + nNumberOfRows = nMaxNumberOfColumns + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nMaxNumberOfColumns ) )) + : 0; + nNumberOfColumns = nNumberOfRows + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nNumberOfRows ) )) + : 0; + } + else // ::com::sun::star::chart::ChartLegendExpansion_BALANCED + { + double fAspect = nMaxEntryHeight + ? static_cast< double >( nMaxEntryWidth ) / static_cast< double >( nMaxEntryHeight ) + : 0.0; + + nNumberOfRows = static_cast< sal_Int32 >( + ceil( sqrt( static_cast< double >( nNumberOfEntries ) * fAspect ))); + nNumberOfColumns = nNumberOfRows + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nNumberOfRows ) )) + : 0; + } + + if(nNumberOfRows<=0) + return aResultingLegendSize; + + if( eExpansion != ::com::sun::star::chart::ChartLegendExpansion_CUSTOM ) + { + lcl_collectColumnWidths( aColumnWidths, nNumberOfRows, nNumberOfColumns, aTextShapes, nSymbolPlusDistanceWidth ); + lcl_collectRowHeighs( aRowHeights, nNumberOfRows, nNumberOfColumns, aTextShapes ); + nTextLineHeight = lcl_getTextLineHeight( aRowHeights, nNumberOfRows, fViewFontSize ); + } + + sal_Int32 nCurrentXPos = nXPadding; + sal_Int32 nCurrentYPos = nYPadding; + if( !bSymbolsLeftSide ) + nCurrentXPos = -nXPadding; + + // place entries into column and rows + sal_Int32 nMaxYPos = 0; + sal_Int32 nRow = 0; + sal_Int32 nColumn = 0; + for( nColumn = 0; nColumn < nNumberOfColumns; ++nColumn ) + { + nCurrentYPos = nYPadding; + for( nRow = 0; nRow < nNumberOfRows; ++nRow ) + { + sal_Int32 nEntry = (nColumn + nRow * nNumberOfColumns); + if( nEntry >= nNumberOfEntries ) + break; + + // text shape + Reference< drawing::XShape > xTextShape( aTextShapes[nEntry] ); + if( xTextShape.is() ) + { + awt::Size aTextSize( xTextShape->getSize() ); + sal_Int32 nTextXPos = nCurrentXPos + nSymbolPlusDistanceWidth; + if( !bSymbolsLeftSide ) + nTextXPos = nCurrentXPos - nSymbolPlusDistanceWidth - aTextSize.Width; + xTextShape->setPosition( awt::Point( nTextXPos, nCurrentYPos )); + } + + // symbol + Reference< drawing::XShape > xSymbol( rEntries[ nEntry ].aSymbol ); + if( xSymbol.is() ) + { + awt::Size aSymbolSize( rMaxSymbolExtent ); + sal_Int32 nSymbolXPos = nCurrentXPos; + if( !bSymbolsLeftSide ) + nSymbolXPos = nCurrentXPos - rMaxSymbolExtent.Width; + sal_Int32 nSymbolYPos = nCurrentYPos + ( ( nTextLineHeight - aSymbolSize.Height ) / 2 ); + xSymbol->setPosition( awt::Point( nSymbolXPos, nSymbolYPos ) ); + } + + nCurrentYPos += aRowHeights[ nRow ]; + if( nRow+1 < nNumberOfRows ) + nCurrentYPos += nYOffset; + nMaxYPos = ::std::max( nMaxYPos, nCurrentYPos ); + } + if( bSymbolsLeftSide ) + { + nCurrentXPos += aColumnWidths[nColumn]; + if( nColumn+1 < nNumberOfColumns ) + nCurrentXPos += nXOffset; + } + else + { + nCurrentXPos -= aColumnWidths[nColumn]; + if( nColumn+1 < nNumberOfColumns ) + nCurrentXPos -= nXOffset; + } + } + + if( !bIsCustomSize ) + { + if( bSymbolsLeftSide ) + aResultingLegendSize.Width = nCurrentXPos + nXPadding; + else + { + sal_Int32 nLegendWidth = -(nCurrentXPos-nXPadding); + aResultingLegendSize.Width = nLegendWidth; + } + aResultingLegendSize.Height = nMaxYPos + nYPadding; + } + + if( !bSymbolsLeftSide ) + { + sal_Int32 nLegendWidth = aResultingLegendSize.Width; + awt::Point aPos(0,0); + for( sal_Int32 nEntry=0; nEntry<nNumberOfEntries; nEntry++ ) + { + Reference< drawing::XShape > xSymbol( rEntries[ nEntry ].aSymbol ); + aPos = xSymbol->getPosition(); + aPos.X += nLegendWidth; + xSymbol->setPosition( aPos ); + Reference< drawing::XShape > xText( aTextShapes[ nEntry ] ); + aPos = xText->getPosition(); + aPos.X += nLegendWidth; + xText->setPosition( aPos ); + } + } + + return aResultingLegendSize; +} + +// #i109336# Improve auto positioning in chart +sal_Int32 lcl_getLegendLeftRightMargin() +{ + return 210; // 1/100 mm +} + +// #i109336# Improve auto positioning in chart +sal_Int32 lcl_getLegendTopBottomMargin() +{ + return 185; // 1/100 mm +} + +chart2::RelativePosition lcl_getDefaultPosition( LegendPosition ePos, const awt::Rectangle& rOutAvailableSpace, const awt::Size & rPageSize ) +{ + chart2::RelativePosition aResult; + + switch( ePos ) + { + case LegendPosition_LINE_START: + { + // #i109336# Improve auto positioning in chart + const double fDefaultDistance = ( static_cast< double >( lcl_getLegendLeftRightMargin() ) / + static_cast< double >( rPageSize.Width ) ); + aResult = chart2::RelativePosition( + fDefaultDistance, 0.5, drawing::Alignment_LEFT ); + } + break; + case LegendPosition_LINE_END: + { + // #i109336# Improve auto positioning in chart + const double fDefaultDistance = ( static_cast< double >( lcl_getLegendLeftRightMargin() ) / + static_cast< double >( rPageSize.Width ) ); + aResult = chart2::RelativePosition( + 1.0 - fDefaultDistance, 0.5, drawing::Alignment_RIGHT ); + } + break; + case LegendPosition_PAGE_START: + { + // #i109336# Improve auto positioning in chart + const double fDefaultDistance = ( static_cast< double >( lcl_getLegendTopBottomMargin() ) / + static_cast< double >( rPageSize.Height ) ); + double fDistance = (static_cast<double>(rOutAvailableSpace.Y)/static_cast<double>(rPageSize.Height)) + fDefaultDistance; + aResult = chart2::RelativePosition( + 0.5, fDistance, drawing::Alignment_TOP ); + } + break; + case LegendPosition_PAGE_END: + { + // #i109336# Improve auto positioning in chart + const double fDefaultDistance = ( static_cast< double >( lcl_getLegendTopBottomMargin() ) / + static_cast< double >( rPageSize.Height ) ); + aResult = chart2::RelativePosition( + 0.5, 1.0 - fDefaultDistance, drawing::Alignment_BOTTOM ); + } + break; + + case LegendPosition_CUSTOM: + // to avoid warning + case LegendPosition_MAKE_FIXED_SIZE: + // nothing to be set + break; + } + + return aResult; +} + +/** @return + a point relative to the upper left corner that can be used for + XShape::setPosition() +*/ +awt::Point lcl_calculatePositionAndRemainingSpace( + awt::Rectangle & rRemainingSpace, + const awt::Size & rPageSize, + chart2::RelativePosition aRelPos, + LegendPosition ePos, + const awt::Size& aLegendSize ) +{ + // calculate position + awt::Point aResult( + static_cast< sal_Int32 >( aRelPos.Primary * rPageSize.Width ), + static_cast< sal_Int32 >( aRelPos.Secondary * rPageSize.Height )); + + aResult = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( + aResult, aLegendSize, aRelPos.Anchor ); + + // adapt rRemainingSpace if LegendPosition is not CUSTOM + // #i109336# Improve auto positioning in chart + sal_Int32 nXDistance = lcl_getLegendLeftRightMargin(); + sal_Int32 nYDistance = lcl_getLegendTopBottomMargin(); + switch( ePos ) + { + case LegendPosition_LINE_START: + { + sal_Int32 nExtent = aLegendSize.Width; + rRemainingSpace.Width -= ( nExtent + nXDistance ); + rRemainingSpace.X += ( nExtent + nXDistance ); + } + break; + case LegendPosition_LINE_END: + { + rRemainingSpace.Width -= ( aLegendSize.Width + nXDistance ); + } + break; + case LegendPosition_PAGE_START: + { + sal_Int32 nExtent = aLegendSize.Height; + rRemainingSpace.Height -= ( nExtent + nYDistance ); + rRemainingSpace.Y += ( nExtent + nYDistance ); + } + break; + case LegendPosition_PAGE_END: + { + rRemainingSpace.Height -= ( aLegendSize.Height + nYDistance ); + } + break; + + default: + // nothing + break; + } + + // adjust the legend position. Esp. for old files that had slightly smaller legends + const sal_Int32 nEdgeDistance( 30 ); + if( aResult.X + aLegendSize.Width > rPageSize.Width ) + { + sal_Int32 nNewX( (rPageSize.Width - aLegendSize.Width) - nEdgeDistance ); + if( nNewX > rPageSize.Width / 4 ) + aResult.X = nNewX; + } + if( aResult.Y + aLegendSize.Height > rPageSize.Height ) + { + sal_Int32 nNewY( (rPageSize.Height - aLegendSize.Height) - nEdgeDistance ); + if( nNewY > rPageSize.Height / 4 ) + aResult.Y = nNewY; + } + + return aResult; +} + +bool lcl_shouldSymbolsBePlacedOnTheLeftSide( const Reference< beans::XPropertySet >& xLegendProp, sal_Int16 nDefaultWritingMode ) +{ + bool bSymbolsLeftSide = true; + try + { + if( SvtLanguageOptions().IsCTLFontEnabled() ) + { + if(xLegendProp.is()) + { + sal_Int16 nWritingMode=-1; + if( (xLegendProp->getPropertyValue( C2U("WritingMode") ) >>= nWritingMode) ) + { + if( nWritingMode == text::WritingMode2::PAGE ) + nWritingMode = nDefaultWritingMode; + if( nWritingMode == text::WritingMode2::RL_TB ) + bSymbolsLeftSide=false; + } + } + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + return bSymbolsLeftSide; +} + +} // anonymous namespace + +VLegend::VLegend( + const Reference< XLegend > & xLegend, + const Reference< uno::XComponentContext > & xContext, + const std::vector< LegendEntryProvider* >& rLegendEntryProviderList ) : + m_xLegend( xLegend ), + m_xContext( xContext ), + m_aLegendEntryProviderList( rLegendEntryProviderList ) +{ +} + +// ---------------------------------------- + +void VLegend::init( + const Reference< drawing::XShapes >& xTargetPage, + const Reference< lang::XMultiServiceFactory >& xFactory, + const Reference< frame::XModel >& xModel ) +{ + m_xTarget = xTargetPage; + m_xShapeFactory = xFactory; + m_xModel = xModel; +} + +// ---------------------------------------- + +void VLegend::setDefaultWritingMode( sal_Int16 nDefaultWritingMode ) +{ + m_nDefaultWritingMode = nDefaultWritingMode; +} + +// ---------------------------------------- + +bool VLegend::isVisible( const Reference< XLegend > & xLegend ) +{ + if( ! xLegend.is()) + return sal_False; + + sal_Bool bShow = sal_False; + try + { + Reference< beans::XPropertySet > xLegendProp( xLegend, uno::UNO_QUERY_THROW ); + xLegendProp->getPropertyValue( C2U( "Show" )) >>= bShow; + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + + return bShow; +} + +// ---------------------------------------- + +void VLegend::createShapes( + const awt::Size & rAvailableSpace, + const awt::Size & rPageSize ) +{ + if(! (m_xLegend.is() && + m_xShapeFactory.is() && + m_xTarget.is())) + return; + + try + { + //create shape and add to page + m_xShape.set( m_xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.GroupShape" )), uno::UNO_QUERY ); + m_xTarget->add( m_xShape ); + + // set name to enable selection + { + OUString aLegendParticle( ObjectIdentifier::createParticleForLegend( m_xLegend, m_xModel ) ); + ShapeFactory::setShapeName( m_xShape, ObjectIdentifier::createClassifiedIdentifierForParticle( aLegendParticle ) ); + } + + // create and insert sub-shapes + Reference< drawing::XShapes > xLegendContainer( m_xShape, uno::UNO_QUERY ); + if( xLegendContainer.is()) + { + Reference< drawing::XShape > xBorder( + m_xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY ); + + // for quickly setting properties + tPropertyValues aLineFillProperties; + tPropertyValues aTextProperties; + + Reference< beans::XPropertySet > xLegendProp( m_xLegend, uno::UNO_QUERY ); + ::com::sun::star::chart::ChartLegendExpansion eExpansion = ::com::sun::star::chart::ChartLegendExpansion_HIGH; + awt::Size aLegendSize( rAvailableSpace ); + + if( xLegendProp.is()) + { + // get Expansion property + xLegendProp->getPropertyValue( C2U( "Expansion" )) >>= eExpansion; + if( eExpansion == ::com::sun::star::chart::ChartLegendExpansion_CUSTOM ) + { + RelativeSize aRelativeSize; + if ((xLegendProp->getPropertyValue( C2U( "RelativeSize" )) >>= aRelativeSize)) + { + aLegendSize.Width = aRelativeSize.Primary * rPageSize.Width; + aLegendSize.Height = aRelativeSize.Secondary * rPageSize.Height; + } + else + eExpansion = ::com::sun::star::chart::ChartLegendExpansion_HIGH; + } + lcl_getProperties( xLegendProp, aLineFillProperties, aTextProperties, rPageSize ); + } + + if( xBorder.is()) + { + xLegendContainer->add( xBorder ); + + // apply legend properties + PropertyMapper::setMultiProperties( + aLineFillProperties.first, aLineFillProperties.second, + Reference< beans::XPropertySet >( xBorder, uno::UNO_QUERY )); + + //because of this name this border will be used for marking the legend + ShapeFactory(m_xShapeFactory).setShapeName( xBorder, C2U("MarkHandles") ); + } + + // create entries + double fViewFontSize = lcl_CalcViewFontSize( xLegendProp, rPageSize );//todo + // #i109336# Improve auto positioning in chart + sal_Int32 nSymbolHeigth = static_cast< sal_Int32 >( fViewFontSize * 0.6 ); + sal_Int32 nSymbolWidth = static_cast< sal_Int32 >( nSymbolHeigth ); + + ::std::vector< LegendEntryProvider* >::const_iterator aIter = m_aLegendEntryProviderList.begin(); + const ::std::vector< LegendEntryProvider* >::const_iterator aEnd = m_aLegendEntryProviderList.end(); + for( aIter = m_aLegendEntryProviderList.begin(); aIter != aEnd; aIter++ ) + { + LegendEntryProvider* pLegendEntryProvider( *aIter ); + if( pLegendEntryProvider ) + { + awt::Size aCurrentRatio = pLegendEntryProvider->getPreferredLegendKeyAspectRatio(); + sal_Int32 nCurrentWidth = aCurrentRatio.Width; + if( aCurrentRatio.Height > 0 ) + { + nCurrentWidth = nSymbolHeigth* aCurrentRatio.Width/aCurrentRatio.Height; + } + nSymbolWidth = std::max( nSymbolWidth, nCurrentWidth ); + } + } + awt::Size aMaxSymbolExtent( nSymbolWidth, nSymbolHeigth ); + + tViewLegendEntryContainer aViewEntries; + for( aIter = m_aLegendEntryProviderList.begin(); aIter != aEnd; aIter++ ) + { + LegendEntryProvider* pLegendEntryProvider( *aIter ); + if( pLegendEntryProvider ) + { + std::vector< ViewLegendEntry > aNewEntries = pLegendEntryProvider->createLegendEntries( aMaxSymbolExtent, eExpansion, xLegendProp, xLegendContainer, m_xShapeFactory, m_xContext ); + aViewEntries.insert( aViewEntries.end(), aNewEntries.begin(), aNewEntries.end() ); + } + } + + bool bSymbolsLeftSide = lcl_shouldSymbolsBePlacedOnTheLeftSide( xLegendProp, m_nDefaultWritingMode ); + + // place entries + aLegendSize = lcl_placeLegendEntries( aViewEntries, eExpansion, bSymbolsLeftSide, fViewFontSize, aMaxSymbolExtent + , aTextProperties, xLegendContainer, m_xShapeFactory, aLegendSize ); + + if( xBorder.is() ) + xBorder->setSize( aLegendSize ); + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } +} + +// ---------------------------------------- + +void VLegend::changePosition( + awt::Rectangle & rOutAvailableSpace, + const awt::Size & rPageSize ) +{ + if(! m_xShape.is()) + return; + + try + { + // determine position and alignment depending on default position + awt::Size aLegendSize = m_xShape->getSize(); + Reference< beans::XPropertySet > xLegendProp( m_xLegend, uno::UNO_QUERY_THROW ); + chart2::RelativePosition aRelativePosition; + + bool bAutoPosition = + ! (xLegendProp->getPropertyValue( C2U( "RelativePosition" )) >>= aRelativePosition); + + LegendPosition ePos = LegendPosition_CUSTOM; + xLegendProp->getPropertyValue( C2U( "AnchorPosition" )) >>= ePos; + + //calculate position + if( bAutoPosition ) + { + // auto position: relative to remaining space + aRelativePosition = lcl_getDefaultPosition( ePos, rOutAvailableSpace, rPageSize ); + awt::Point aPos = lcl_calculatePositionAndRemainingSpace( + rOutAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize ); + m_xShape->setPosition( aPos ); + } + else + { + // manual position: relative to whole page + awt::Rectangle aAvailableSpace( 0, 0, rPageSize.Width, rPageSize.Height ); + awt::Point aPos = lcl_calculatePositionAndRemainingSpace( + aAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize ); + m_xShape->setPosition( aPos ); + + if( ePos != LegendPosition_CUSTOM ) + { + // calculate remaining space as if having autoposition: + aRelativePosition = lcl_getDefaultPosition( ePos, rOutAvailableSpace, rPageSize ); + lcl_calculatePositionAndRemainingSpace( + rOutAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize ); + } + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/VLegend.hxx b/chart2/source/view/main/VLegend.hxx new file mode 100644 index 000000000000..4534a350f4f4 --- /dev/null +++ b/chart2/source/view/main/VLegend.hxx @@ -0,0 +1,111 @@ +/************************************************************************* + * + * 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 _VLEGEND_HXX +#define _VLEGEND_HXX + +#include <com/sun/star/chart2/XLegend.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/frame/XModel.hpp> + +#include <vector> + +//............................................................................. +namespace chart +{ +//............................................................................. + +class LegendEntryProvider; + +//----------------------------------------------------------------------------- +/** +*/ + +class VLegend +{ +public: + VLegend( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XLegend > & xLegend, + const ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext > & xContext, + const std::vector< LegendEntryProvider* >& rLegendEntryProviderList ); + + void init( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTargetPage, + const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& xFactory, + const ::com::sun::star::uno::Reference< + ::com::sun::star::frame::XModel > & xModel ); + + void setDefaultWritingMode( sal_Int16 nDefaultWritingMode ); + + void createShapes( const ::com::sun::star::awt::Size & rAvailableSpace, + const ::com::sun::star::awt::Size & rPageSize ); + + /** Sets the position according to its internal anchor. + + @param rOutAvailableSpace + is modified by the method, if the legend is in a standard position, + such that the space allocated by the legend is removed from it. + + @param rReferenceSize + is used to calculate the offset (default 2%) from the edge. + */ + void changePosition( + ::com::sun::star::awt::Rectangle & rOutAvailableSpace, + const ::com::sun::star::awt::Size & rReferenceSize ); + + static bool isVisible( + const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XLegend > & xLegend ); + +private: + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes > m_xTarget; + ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory> m_xShapeFactory; + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XLegend > m_xLegend; + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShape > m_xShape; + ::com::sun::star::uno::Reference< + ::com::sun::star::frame::XModel > m_xModel; + ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext > m_xContext; + + std::vector< LegendEntryProvider* > m_aLegendEntryProviderList; + + sal_Int16 m_nDefaultWritingMode;//to be used when writing mode is set to page +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif + diff --git a/chart2/source/view/main/VLegendSymbolFactory.cxx b/chart2/source/view/main/VLegendSymbolFactory.cxx new file mode 100644 index 000000000000..b7168bd7ee9f --- /dev/null +++ b/chart2/source/view/main/VLegendSymbolFactory.cxx @@ -0,0 +1,215 @@ +/************************************************************************* + * + * 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 "VLegendSymbolFactory.hxx" +#include "macros.hxx" +#include "PropertyMapper.hxx" +#include "ShapeFactory.hxx" +#include "ObjectIdentifier.hxx" +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/chart2/Symbol.hpp> + +// header for define DBG_ASSERT +#include <tools/debug.hxx> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::rtl::OUString; + +namespace +{ +void lcl_setPropetiesToShape( + const Reference< beans::XPropertySet > & xProp, + const Reference< drawing::XShape > & xShape, + ::chart::VLegendSymbolFactory::tPropertyType ePropertyType ) +{ + const ::chart::tPropertyNameMap & aFilledSeriesNameMap( ::chart::PropertyMapper::getPropertyNameMapForFilledSeriesProperties()); + const ::chart::tPropertyNameMap & aLineSeriesNameMap( ::chart::PropertyMapper::getPropertyNameMapForLineSeriesProperties()); + const ::chart::tPropertyNameMap & aLineNameMap( ::chart::PropertyMapper::getPropertyNameMapForLineProperties()); + const ::chart::tPropertyNameMap & aFillNameMap( ::chart::PropertyMapper::getPropertyNameMapForFillProperties()); + const ::chart::tPropertyNameMap & aFillLineNameMap( ::chart::PropertyMapper::getPropertyNameMapForFillAndLineProperties()); + + Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY ); + if( xProp.is() && xShapeProp.is() ) + { + ::chart::tPropertyNameValueMap aValueMap; + switch( ePropertyType ) + { + case ::chart::VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES: + ::chart::PropertyMapper::getValueMap( aValueMap, aFilledSeriesNameMap, xProp ); + break; + case ::chart::VLegendSymbolFactory::PROP_TYPE_LINE_SERIES: + ::chart::PropertyMapper::getValueMap( aValueMap, aLineSeriesNameMap, xProp ); + break; + case ::chart::VLegendSymbolFactory::PROP_TYPE_LINE: + ::chart::PropertyMapper::getValueMap( aValueMap, aLineNameMap, xProp ); + break; + case ::chart::VLegendSymbolFactory::PROP_TYPE_FILL: + ::chart::PropertyMapper::getValueMap( aValueMap, aFillNameMap, xProp ); + break; + case ::chart::VLegendSymbolFactory::PROP_TYPE_FILL_AND_LINE: + ::chart::PropertyMapper::getValueMap( aValueMap, aFillLineNameMap, xProp ); + break; + } + + ::chart::tNameSequence aPropNames; + ::chart::tAnySequence aPropValues; + ::chart::PropertyMapper::getMultiPropertyListsFromValueMap( aPropNames, aPropValues, aValueMap ); + + uno::Any* pLineWidthAny = ::chart::PropertyMapper::getValuePointer(aPropValues,aPropNames,C2U("LineWidth")); + sal_Int32 nLineWidth = 0; + if( pLineWidthAny && (*pLineWidthAny>>=nLineWidth) ) + { + const sal_Int32 nMaxLineWidthForLegend = 50;/*1/100 mm*///todo: make this dependent from legend entry height + if( nLineWidth>nMaxLineWidthForLegend ) + *pLineWidthAny = uno::makeAny( nMaxLineWidthForLegend ); + } + + ::chart::PropertyMapper::setMultiProperties( aPropNames, aPropValues, xShapeProp ); + } +} + +} // anonymous namespace + +namespace chart +{ + +Reference< drawing::XShape > VLegendSymbolFactory::createSymbol( + const awt::Size& rEntryKeyAspectRatio, + const Reference< drawing::XShapes > xSymbolContainer, + LegendSymbolStyle eStyle, + const Reference< lang::XMultiServiceFactory > & xShapeFactory, + const Reference< beans::XPropertySet > & xLegendEntryProperties, + tPropertyType ePropertyType, const uno::Any& rExplicitSymbol ) +{ + Reference< drawing::XShape > xResult; + + if( ! (xSymbolContainer.is() && xShapeFactory.is())) + return xResult; + + xResult.set( xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.GroupShape" )), uno::UNO_QUERY ); + xSymbolContainer->add( xResult ); + Reference< drawing::XShapes > xResultGroup( xResult, uno::UNO_QUERY ); + if( ! xResultGroup.is()) + return xResult; + + // add an invisible square box to maintain aspect ratio + Reference< drawing::XShape > xBound( ShapeFactory(xShapeFactory).createInvisibleRectangle( + xResultGroup, rEntryKeyAspectRatio )); + + // create symbol + try + { + if( eStyle == LegendSymbolStyle_LINE ) + { + Reference< drawing::XShape > xLine( xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.LineShape" )), uno::UNO_QUERY ); + if( xLine.is()) + { + xResultGroup->add( xLine ); + xLine->setSize( awt::Size( rEntryKeyAspectRatio.Width, 0 )); + xLine->setPosition( awt::Point( 0, rEntryKeyAspectRatio.Height/2 )); + + lcl_setPropetiesToShape( xLegendEntryProperties, xLine, ePropertyType ); + } + + Reference< drawing::XShape > xSymbol; + const sal_Int32 nSize = std::min(rEntryKeyAspectRatio.Width,rEntryKeyAspectRatio.Height); + chart2::Symbol aSymbol; + if( rExplicitSymbol >>= aSymbol ) + { + drawing::Direction3D aSymbolSize( nSize, nSize, 0 ); + drawing::Position3D aPos( rEntryKeyAspectRatio.Width/2, rEntryKeyAspectRatio.Height/2, 0 ); + ShapeFactory aFactory( xShapeFactory ); + if( aSymbol.Style == chart2::SymbolStyle_STANDARD ) + { + // take series color as fill color + xLegendEntryProperties->getPropertyValue( C2U("Color")) >>= aSymbol.FillColor; + // border of symbols always same as fill color + aSymbol.BorderColor = aSymbol.FillColor; + + xSymbol.set( aFactory.createSymbol2D( + xResultGroup, + aPos, + aSymbolSize, + aSymbol.StandardSymbol, + aSymbol.BorderColor, + aSymbol.FillColor )); + } + else if( aSymbol.Style == chart2::SymbolStyle_GRAPHIC ) + { + xSymbol.set( aFactory.createGraphic2D( + xResultGroup, + aPos, + aSymbolSize, + aSymbol.Graphic )); + } + else if( aSymbol.Style == chart2::SymbolStyle_AUTO ) + { + DBG_ERROR("the given parameter is not allowed to contain an automatic symbol style"); + } + } + } + else if( eStyle == LegendSymbolStyle_CIRCLE ) + { + Reference< drawing::XShape > xShape( xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.EllipseShape" )), uno::UNO_QUERY ); + if( xShape.is() ) + { + xResultGroup->add( xShape ); + sal_Int32 nSize = std::min( rEntryKeyAspectRatio.Width, rEntryKeyAspectRatio.Height ); + xShape->setSize( awt::Size( nSize, nSize ) ); + xShape->setPosition( awt::Point( rEntryKeyAspectRatio.Width/2-nSize/2, rEntryKeyAspectRatio.Height/2-nSize/2 ) ); + lcl_setPropetiesToShape( xLegendEntryProperties, xShape, ePropertyType ); // PROP_TYPE_FILLED_SERIES ); + } + } + else // eStyle == LegendSymbolStyle_BOX + { + Reference< drawing::XShape > xShape( xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY ); + if( xShape.is() ) + { + xResultGroup->add( xShape ); + xShape->setSize( rEntryKeyAspectRatio ); + xShape->setPosition( awt::Point( 0, 0 ) ); + lcl_setPropetiesToShape( xLegendEntryProperties, xShape, ePropertyType ); // PROP_TYPE_FILLED_SERIES ); + } + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + + return xResult; +} + +} // namespace chart diff --git a/chart2/source/view/main/VLineProperties.cxx b/chart2/source/view/main/VLineProperties.cxx new file mode 100644 index 000000000000..dc8409a6891d --- /dev/null +++ b/chart2/source/view/main/VLineProperties.cxx @@ -0,0 +1,109 @@ +/************************************************************************* + * + * 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 "VLineProperties.hxx" +#include "macros.hxx" +#include <com/sun/star/drawing/LineStyle.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// get line properties from a propertyset +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +VLineProperties::VLineProperties() +{ + this->Color = uno::makeAny( sal_Int32(0x000000) ); //type sal_Int32 UNO_NAME_LINECOLOR + this->LineStyle = uno::makeAny( drawing::LineStyle_SOLID ); //type drawing::LineStyle for property UNO_NAME_LINESTYLE + this->Transparence = uno::makeAny( sal_Int16(0) );//type sal_Int16 for property UNO_NAME_LINETRANSPARENCE + this->Width = uno::makeAny( sal_Int32(0) );//type sal_Int32 for property UNO_NAME_LINEWIDTH +} + +void VLineProperties::initFromPropertySet( const uno::Reference< beans::XPropertySet >& xProp, bool bUseSeriesPropertyNames ) +{ + if(xProp.is()) + { + if( bUseSeriesPropertyNames ) try + { + this->Color = xProp->getPropertyValue( C2U( "BorderColor" ) ); + this->LineStyle = xProp->getPropertyValue( C2U( "BorderStyle" ) ); + this->Transparence = xProp->getPropertyValue( C2U( "BorderTransparency" ) ); + this->Width = xProp->getPropertyValue( C2U( "BorderWidth" ) ); + this->DashName = xProp->getPropertyValue( C2U( "BorderDashName" ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + else try + { + this->Color = xProp->getPropertyValue( C2U( "LineColor" ) ); + this->LineStyle = xProp->getPropertyValue( C2U( "LineStyle" ) ); + this->Transparence = xProp->getPropertyValue( C2U( "LineTransparence" ) ); + this->Width = xProp->getPropertyValue( C2U( "LineWidth" ) ); + this->DashName = xProp->getPropertyValue( C2U( "LineDashName" ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + else + this->LineStyle = uno::makeAny( drawing::LineStyle_NONE ); +} + +bool VLineProperties::isLineVisible() const +{ + bool bRet = false; + + drawing::LineStyle aLineStyle(drawing::LineStyle_SOLID); + this->LineStyle >>= aLineStyle; + if( aLineStyle != drawing::LineStyle_NONE ) + { + sal_Int16 nLineTransparence=0; + this->Transparence >>= nLineTransparence; + if(100!=nLineTransparence) + { + bRet = true; + } + } + + return bRet; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/VPolarTransformation.cxx b/chart2/source/view/main/VPolarTransformation.cxx new file mode 100644 index 000000000000..fd3037316cc6 --- /dev/null +++ b/chart2/source/view/main/VPolarTransformation.cxx @@ -0,0 +1,94 @@ +/************************************************************************* + * + * 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 "VPolarTransformation.hxx" +#include "ViewDefines.hxx" +#include "CommonConverters.hxx" +#include <algorithm> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::RuntimeException; + +namespace chart +{ + + +VPolarTransformation::VPolarTransformation( const PolarPlottingPositionHelper& rPositionHelper ) + : m_aPositionHelper(rPositionHelper) + , m_aUnitCartesianToScene( rPositionHelper.getUnitCartesianToScene() ) +{ +} + +VPolarTransformation::~VPolarTransformation() +{ +} + +// ____ XTransformation ____ +Sequence< double > SAL_CALL VPolarTransformation::transform( + const Sequence< double >& rSourceValues ) + throw (RuntimeException, + lang::IllegalArgumentException) +{ + double fScaledLogicAngle = rSourceValues[0]; + double fScaledLogicRadius = rSourceValues[1]; + + if( m_aPositionHelper.isSwapXAndY() ) + std::swap(fScaledLogicAngle,fScaledLogicRadius); + + double fAngleDegree = m_aPositionHelper.transformToAngleDegree( fScaledLogicAngle, false ); + double fAnglePi = fAngleDegree*F_PI/180.0; + double fRadius = m_aPositionHelper.transformToRadius( fScaledLogicRadius, false); + + double fX=fRadius*cos(fAnglePi); + double fY=fRadius*sin(fAnglePi); + double fZ=rSourceValues[2]; + + //!! applying matrix to vector does ignore translation, so it is important to use a B3DPoint here instead of B3DVector + ::basegfx::B3DPoint aPoint(fX,fY,fZ); + ::basegfx::B3DPoint aRet = m_aUnitCartesianToScene * aPoint; + return B3DPointToSequence(aRet); +} + +sal_Int32 SAL_CALL VPolarTransformation::getSourceDimension() + throw (RuntimeException) +{ + return 3; +} + +sal_Int32 SAL_CALL VPolarTransformation::getTargetDimension() + throw (RuntimeException) +{ + return 3; +} + + +} // namespace chart diff --git a/chart2/source/view/main/VTitle.cxx b/chart2/source/view/main/VTitle.cxx new file mode 100644 index 000000000000..c2aa01163b17 --- /dev/null +++ b/chart2/source/view/main/VTitle.cxx @@ -0,0 +1,299 @@ +/************************************************************************* + * + * 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 "VTitle.hxx" +#include "CommonConverters.hxx" +#include "macros.hxx" +#include "PropertyMapper.hxx" +#include "ShapeFactory.hxx" +#include "RelativeSizeHelper.hxx" +#include <com/sun/star/chart2/XFormattedString.hpp> +#include <rtl/math.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/TextVerticalAdjust.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> +#include <com/sun/star/text/ControlCharacter.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/XTextCursor.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +VTitle::VTitle( const uno::Reference< XTitle > & xTitle ) + : m_xTarget(NULL) + , m_xShapeFactory(NULL) + , m_xTitle(xTitle) + , m_xShape(NULL) + , m_aCID() + , m_fRotationAngleDegree(0.0) + , m_nXPos(0) + , m_nYPos(0) +{ +} + +VTitle::~VTitle() +{ +} + +void VTitle::init( + const uno::Reference< drawing::XShapes >& xTargetPage + , const uno::Reference< lang::XMultiServiceFactory >& xFactory + , const rtl::OUString& rCID ) +{ + m_xTarget = xTargetPage; + m_xShapeFactory = xFactory; + m_aCID = rCID; +} + +double VTitle::getRotationAnglePi() const +{ + return m_fRotationAngleDegree*F_PI/180.0; +} + +awt::Size VTitle::getUnrotatedSize() const //size before rotation +{ + awt::Size aRet; + if(m_xShape.is()) + aRet = m_xShape->getSize(); + return aRet; +} + +awt::Size VTitle::getFinalSize() const //size after rotation +{ + return ShapeFactory::getSizeAfterRotation( + m_xShape, m_fRotationAngleDegree ); +} + +void VTitle::changePosition( const awt::Point& rPos ) +{ + if(!m_xShape.is()) + return; + uno::Reference< beans::XPropertySet > xShapeProp( m_xShape, uno::UNO_QUERY ); + if(!xShapeProp.is()) + return; + try + { + m_nXPos = rPos.X; + m_nYPos = rPos.Y; + + //set position matrix + //the matrix needs to be set at the end behind autogrow and such position influencing properties + ::basegfx::B2DHomMatrix aM; + aM.rotate( -m_fRotationAngleDegree*F_PI/180.0 );//#i78696#->#i80521# + aM.translate( m_nXPos, m_nYPos); + xShapeProp->setPropertyValue( C2U( "Transformation" ), uno::makeAny( B2DHomMatrixToHomogenMatrix3(aM) ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } +} + +void VTitle::createShapes( + const awt::Point& rPos + , const awt::Size& rReferenceSize ) +{ + try + { + if(!m_xTitle.is()) + return; + + uno::Sequence< uno::Reference< XFormattedString > > aStringList = m_xTitle->getText(); + if(aStringList.getLength()<=0) + return; + + //create shape and add to page + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.TextShape" ) ), uno::UNO_QUERY ); + m_xTarget->add(xShape); + m_xShape = xShape; + + //set text and text properties + uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY ); + uno::Reference< text::XTextCursor > xTextCursor( xText->createTextCursor() ); + uno::Reference< text::XTextRange > xTextRange( xTextCursor, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xTitleProperties( m_xTitle, uno::UNO_QUERY ); + if( !xText.is() || !xTextRange.is() || !xTextCursor.is() || !xShapeProp.is() || !xTitleProperties.is() ) + return; + + tPropertyNameValueMap aValueMap; + //fill line-, fill- and paragraph-properties into the ValueMap + { + tMakePropertyNameMap aNameMap = PropertyMapper::getPropertyNameMapForParagraphProperties(); + aNameMap( PropertyMapper::getPropertyNameMapForFillAndLineProperties() ); + + PropertyMapper::getValueMap( aValueMap, aNameMap, xTitleProperties ); + } + + //fill some more shape properties into the ValueMap + { + drawing::TextHorizontalAdjust eHorizontalAdjust = drawing::TextHorizontalAdjust_CENTER; + drawing::TextVerticalAdjust eVerticalAdjust = drawing::TextVerticalAdjust_CENTER; + //text::WritingMode eWritingMode = text::WritingMode_LR_TB;//@todo get correct one + + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextHorizontalAdjust"), uno::makeAny(eHorizontalAdjust) ) ); // drawing::TextHorizontalAdjust + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextVerticalAdjust"), uno::makeAny(eVerticalAdjust) ) ); //drawing::TextVerticalAdjust + //aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextWritingMode"), uno::makeAny(eWritingMode) ) ); //text::WritingMode + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextAutoGrowHeight"), uno::makeAny(sal_True) ) ); // sal_Bool + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextAutoGrowWidth"), uno::makeAny(sal_True) ) ); // sal_Bool + + ////aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextMaximumFrameWidth"), uno::makeAny(rSize.Width) ) ); //sal_Int32 + ////aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextMaximumFrameHeight"), uno::makeAny(rSize.Height) ) ); //sal_Int32 + + //set name/classified ObjectID (CID) + if( m_aCID.getLength() ) + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("Name"), uno::makeAny( m_aCID ) ) ); //CID rtl::OUString + } + + //set global title properties + { + tNameSequence aPropNames; + tAnySequence aPropValues; + PropertyMapper::getMultiPropertyListsFromValueMap( aPropNames, aPropValues, aValueMap ); + PropertyMapper::setMultiProperties( aPropNames, aPropValues, xShapeProp ); + } + + sal_Bool bStackCharacters(sal_False); + try + { + xTitleProperties->getPropertyValue( C2U( "StackCharacters" ) ) >>= bStackCharacters; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + if(bStackCharacters) + { + //if the characters should be stacked we use only the first character properties for code simplicity + if( aStringList.getLength()>0 ) + { + rtl::OUString aLabel; + for( sal_Int32 nN=0; nN<aStringList.getLength();nN++ ) + aLabel += aStringList[nN]->getString(); + aLabel = ShapeFactory::getStackedString( aLabel, bStackCharacters ); + + xTextCursor->gotoEnd(false); + xText->insertString( xTextRange, aLabel, false ); + xTextCursor->gotoEnd(true); + uno::Reference< beans::XPropertySet > xTargetProps( xShape, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xSourceProps( aStringList[0], uno::UNO_QUERY ); + + PropertyMapper::setMappedProperties( xTargetProps, xSourceProps + , PropertyMapper::getPropertyNameMapForCharacterProperties() ); + + // adapt font size according to page size + awt::Size aOldRefSize; + if( xTitleProperties->getPropertyValue( C2U("ReferencePageSize")) >>= aOldRefSize ) + { + RelativeSizeHelper::adaptFontSizes( xTargetProps, aOldRefSize, rReferenceSize ); + } + } + } + else + { + uno::Sequence< uno::Reference< text::XTextCursor > > aCursorList( aStringList.getLength() ); + sal_Int32 nN = 0; + for( nN=0; nN<aStringList.getLength();nN++ ) + { + xTextCursor->gotoEnd(false); + xText->insertString( xTextRange, aStringList[nN]->getString(), false ); + xTextCursor->gotoEnd(true); + aCursorList[nN] = xText->createTextCursorByRange( uno::Reference< text::XTextRange >(xTextCursor,uno::UNO_QUERY) ); + } + awt::Size aOldRefSize; + bool bHasRefPageSize = + ( xTitleProperties->getPropertyValue( C2U("ReferencePageSize")) >>= aOldRefSize ); + + //for( nN=0; nN<aStringList.getLength();nN++ ) //portion wise fromatting does not work still + if( aStringList.getLength()>0 ) + { + //uno::Reference< beans::XPropertySet > xTargetProps( aCursorList[nN], uno::UNO_QUERY ); + //uno::Reference< beans::XPropertySet > xSourceProps( aStringList[nN], uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xTargetProps( xShape, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xSourceProps( aStringList[0], uno::UNO_QUERY ); + PropertyMapper::setMappedProperties( xTargetProps, xSourceProps, PropertyMapper::getPropertyNameMapForCharacterProperties() ); + + // adapt font size according to page size + if( bHasRefPageSize ) + { + RelativeSizeHelper::adaptFontSizes( xTargetProps, aOldRefSize, rReferenceSize ); + } + } + } + + // #i109336# Improve auto positioning in chart + float fFontHeight = 0.0; + if ( xShapeProp.is() && ( xShapeProp->getPropertyValue( C2U( "CharHeight" ) ) >>= fFontHeight ) ) + { + fFontHeight *= ( 2540. / 72. ); // pt -> 1/100 mm + float fXFraction = 0.18; + sal_Int32 nXDistance = static_cast< sal_Int32 >( ::rtl::math::round( fFontHeight * fXFraction ) ); + float fYFraction = 0.30; + sal_Int32 nYDistance = static_cast< sal_Int32 >( ::rtl::math::round( fFontHeight * fYFraction ) ); + xShapeProp->setPropertyValue( C2U( "TextLeftDistance" ), uno::makeAny( nXDistance ) ); + xShapeProp->setPropertyValue( C2U( "TextRightDistance" ), uno::makeAny( nXDistance ) ); + xShapeProp->setPropertyValue( C2U( "TextUpperDistance" ), uno::makeAny( nYDistance ) ); + xShapeProp->setPropertyValue( C2U( "TextLowerDistance" ), uno::makeAny( nYDistance ) ); + } + + try + { + double fAngleDegree = 0; + xTitleProperties->getPropertyValue( C2U( "TextRotation" ) ) >>= fAngleDegree; + m_fRotationAngleDegree += fAngleDegree; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + m_nXPos = rPos.X; + m_nYPos = rPos.Y; + + //set position matrix + //the matrix needs to be set at the end behind autogrow and such position influencing properties + ::basegfx::B2DHomMatrix aM; + aM.rotate( -m_fRotationAngleDegree*F_PI/180.0 );//#i78696#->#i80521# + aM.translate( m_nXPos, m_nYPos ); + xShapeProp->setPropertyValue( C2U( "Transformation" ), uno::makeAny( B2DHomMatrixToHomogenMatrix3(aM) ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/VTitle.hxx b/chart2/source/view/main/VTitle.hxx new file mode 100644 index 000000000000..e097ecd3bbcc --- /dev/null +++ b/chart2/source/view/main/VTitle.hxx @@ -0,0 +1,83 @@ +/************************************************************************* + * + * 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_VTITLE_HXX +#define _CHART2_VTITLE_HXX + +#include <com/sun/star/chart2/XTitle.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +class VTitle +{ +public: + VTitle( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XTitle > & xTitle ); + virtual ~VTitle(); + + void init( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTargetPage + , const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory + , const rtl::OUString& rCID ); + + void createShapes( const ::com::sun::star::awt::Point& rPos + , const ::com::sun::star::awt::Size& rReferenceSize ); + + double getRotationAnglePi() const; + ::com::sun::star::awt::Size getUnrotatedSize() const; + ::com::sun::star::awt::Size getFinalSize() const; + void changePosition( const ::com::sun::star::awt::Point& rPos ); + +private: + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes > m_xTarget; + ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory> m_xShapeFactory; + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XTitle > m_xTitle; + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShape > m_xShape; + rtl::OUString m_aCID; + + double m_fRotationAngleDegree; + sal_Int32 m_nXPos; + sal_Int32 m_nYPos; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif + diff --git a/chart2/source/view/main/_serviceregistration_view.cxx b/chart2/source/view/main/_serviceregistration_view.cxx new file mode 100644 index 000000000000..2f7e3db441e1 --- /dev/null +++ b/chart2/source/view/main/_serviceregistration_view.cxx @@ -0,0 +1,64 @@ +/************************************************************************* + * + * 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 <cppuhelper/implementationentry.hxx> + +#include "ChartView.hxx" + +static struct ::cppu::ImplementationEntry g_entries_chart2_view[] = +{ + { + ::chart::ChartView::create + , ::chart::ChartView::getImplementationName_Static + , ::chart::ChartView::getSupportedServiceNames_Static + , ::cppu::createSingleComponentFactory + , 0 + , 0 + } + ,{ 0, 0, 0, 0, 0, 0 } +}; + +// component exports +extern "C" +{ +//================================================================================================== +SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** /* ppEnv */ ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} +//================================================================================================== +SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( + const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey ) +{ + return ::cppu::component_getFactoryHelper( + pImplName, pServiceManager, pRegistryKey , g_entries_chart2_view ); +} +} +//========================================================================= diff --git a/chart2/source/view/main/makefile.mk b/chart2/source/view/main/makefile.mk new file mode 100644 index 000000000000..8675930aa107 --- /dev/null +++ b/chart2/source/view/main/makefile.mk @@ -0,0 +1,67 @@ +#************************************************************************* +# +# 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= chview + +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)$/ChartItemPool.obj \ + $(SLO)$/DrawModelWrapper.obj \ + $(SLO)$/PropertyMapper.obj \ + $(SLO)$/Stripe.obj \ + $(SLO)$/VLineProperties.obj \ + $(SLO)$/ShapeFactory.obj \ + $(SLO)$/VLegendSymbolFactory.obj \ + $(SLO)$/DataPointSymbolSupplier.obj \ + $(SLO)$/Linear3DTransformation.obj \ + $(SLO)$/VPolarTransformation.obj \ + $(SLO)$/Clipping.obj \ + $(SLO)$/PlottingPositionHelper.obj \ + $(SLO)$/LabelPositionHelper.obj \ + $(SLO)$/PolarLabelPositionHelper.obj \ + $(SLO)$/PlotterBase.obj \ + $(SLO)$/VDataSeries.obj \ + $(SLO)$/VLegend.obj \ + $(SLO)$/VTitle.obj \ + $(SLO)$/ChartView.obj \ + $(SLO)$/_serviceregistration_view.obj + +# --- Targets ----------------------------------------------------------------- + +.INCLUDE: target.mk diff --git a/chart2/source/view/makefile.mk b/chart2/source/view/makefile.mk new file mode 100644 index 000000000000..0b54ac976ad2 --- /dev/null +++ b/chart2/source/view/makefile.mk @@ -0,0 +1,128 @@ +#************************************************************************* +# +# 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= ..$/.. +PRJNAME= chart2 +TARGET= chartview + +USE_DEFFILE= TRUE +ENABLE_EXCEPTIONS= TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE: $(PRJ)$/util$/makefile.pmk +.INCLUDE: $(PRJ)$/chartview.pmk + +# --- export library ------------------------------------------------- + +#You can use several library macros of this form to build libraries that +#do not consist of all object files in a directory or to merge different libraries. +LIB1TARGET= $(SLB)$/$(TARGET).lib + +LIB1FILES= \ + $(SLB)$/chvaxes.lib \ + $(SLB)$/chvtypes.lib \ + $(SLB)$/chvdiagram.lib \ + $(SLB)$/chview.lib + +#-------- + +#Indicates the filename of the shared library. +SHL1TARGET= $(TARGET)$(DLLPOSTFIX) + +#indicates dependencies: +.IF "$(COM)" == "MSC" +SHL1DEPN = \ + $(LB)$/icharttools.lib +.ELSE +SHL1DEPN = +.ENDIF + +#Specifies an import library to create. For Win32 only. +SHL1IMPLIB= i$(TARGET) + +#Specifies libraries from the same module to put into the shared library. +#was created above +SHL1LIBS= $(LIB1TARGET) + +#Links import libraries. + +SHL1STDLIBS= $(CHARTTOOLS) \ + $(CPPULIB) \ + $(EDITENGLIB) \ + $(CPPUHELPERLIB) \ + $(COMPHELPERLIB) \ + $(SALLIB) \ + $(SVLLIB) \ + $(SVTOOLLIB) \ + $(SVXCORELIB) \ + $(TOOLSLIB) \ + $(UNOTOOLSLIB) \ + $(BASEGFXLIB) \ + $(VCLLIB) \ + $(SFXLIB) \ + $(BASEGFXLIB) + +#--------exports + +#specifies the exported symbols for Windows only: +SHL1DEF= $(MISC)$/$(SHL1TARGET).def + +#Specifies the library name to parse for symbols. For Win32 only. +DEFLIB1NAME= $(TARGET) + +#A file of symbols to export. +#DEF1EXPORTFILE= $(PRJ)$/source$/inc$/exports.dxp + +#--------definition file + +#name of the definition file: +DEF1NAME= $(SHL1TARGET) + +# indicates definition file dependencies +DEF1DEPN= $(MISC)$/$(SHL1TARGET).flt + +#A comment on the definition file. +DEF1DES= Viewable Component Chart View + +# --- Targets ----------------------------------------------------------------- + +.INCLUDE: target.mk + +# --- Filter ----------------------------------------------------------- + +$(MISC)$/$(SHL1TARGET).flt: makefile.mk \ + exports.flt + $(TYPE) exports.flt > $@ + +ALLTAR : $(MISC)/chartview.component + +$(MISC)/chartview.component .ERRREMOVE : $(SOLARENV)/bin/createcomponent.xslt \ + chartview.component + $(XSLTPROC) --nonet --stringparam uri \ + '$(COMPONENTPREFIX_BASIS_NATIVE)$(SHL1TARGETN:f)' -o $@ \ + $(SOLARENV)/bin/createcomponent.xslt chartview.component |