LCOV - code coverage report
Current view: top level - chart2/source/view/axes - VCartesianAxis.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 579 893 64.8 %
Date: 2014-11-03 Functions: 43 51 84.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "VCartesianAxis.hxx"
      21             : #include "PlottingPositionHelper.hxx"
      22             : #include "AbstractShapeFactory.hxx"
      23             : #include "CommonConverters.hxx"
      24             : #include "macros.hxx"
      25             : #include "ViewDefines.hxx"
      26             : #include "PropertyMapper.hxx"
      27             : #include "NumberFormatterWrapper.hxx"
      28             : #include "LabelPositionHelper.hxx"
      29             : #include "TrueGuard.hxx"
      30             : #include "BaseGFXHelper.hxx"
      31             : #include "AxisHelper.hxx"
      32             : #include "Tickmarks_Equidistant.hxx"
      33             : 
      34             : #include <rtl/math.hxx>
      35             : #include <tools/color.hxx>
      36             : #include <com/sun/star/text/XText.hpp>
      37             : #include <com/sun/star/text/WritingMode2.hpp>
      38             : #include <editeng/unoprnms.hxx>
      39             : #include <svx/unoshape.hxx>
      40             : #include <svx/unoshtxt.hxx>
      41             : 
      42             : #include <basegfx/polygon/b2dpolygon.hxx>
      43             : #include <basegfx/polygon/b2dpolypolygon.hxx>
      44             : #include <basegfx/polygon/b2dpolygontools.hxx>
      45             : #include <basegfx/polygon/b2dpolygonclipper.hxx>
      46             : #include <basegfx/matrix/b2dhommatrix.hxx>
      47             : #include <basegfx/numeric/ftools.hxx>
      48             : 
      49             : #include <algorithm>
      50             : #include <boost/scoped_ptr.hpp>
      51             : 
      52             : using namespace ::com::sun::star;
      53             : using ::com::sun::star::uno::Reference;
      54             : using ::basegfx::B2DVector;
      55             : using ::basegfx::B2DPolygon;
      56             : using ::basegfx::B2DPolyPolygon;
      57             : 
      58             : namespace chart {
      59             : 
      60        1095 : VCartesianAxis::VCartesianAxis( const AxisProperties& rAxisProperties
      61             :             , const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier
      62             :             , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount
      63             :             , PlottingPositionHelper* pPosHelper )//takes ownership
      64        1095 :             : VAxisBase( nDimensionIndex, nDimensionCount, rAxisProperties, xNumberFormatsSupplier )
      65             : {
      66        1095 :     if( pPosHelper )
      67           0 :         m_pPosHelper = pPosHelper;
      68             :     else
      69        1095 :         m_pPosHelper = new PlottingPositionHelper();
      70        1095 : }
      71             : 
      72        3141 : VCartesianAxis::~VCartesianAxis()
      73             : {
      74        1047 :     delete m_pPosHelper;
      75        1047 :     m_pPosHelper = NULL;
      76        2094 : }
      77             : 
      78       10202 : Reference< drawing::XShape > createSingleLabel(
      79             :             const Reference< lang::XMultiServiceFactory>& xShapeFactory
      80             :           , const Reference< drawing::XShapes >& xTarget
      81             :           , const awt::Point& rAnchorScreenPosition2D
      82             :           , const OUString& rLabel
      83             :           , const AxisLabelProperties& rAxisLabelProperties
      84             :           , const AxisProperties& rAxisProperties
      85             :           , const tNameSequence& rPropNames
      86             :           , const tAnySequence& rPropValues
      87             :           )
      88             : {
      89       10202 :     if(rLabel.isEmpty())
      90          34 :         return 0;
      91             : 
      92             :     // #i78696# use mathematically correct rotation now
      93       10168 :     const double fRotationAnglePi(rAxisLabelProperties.fRotationAngleDegree * (F_PI / -180.0));
      94       10168 :     uno::Any aATransformation = AbstractShapeFactory::makeTransformation( rAnchorScreenPosition2D, fRotationAnglePi );
      95       20336 :     OUString aLabel = AbstractShapeFactory::getStackedString( rLabel, rAxisLabelProperties.bStackCharacters );
      96             : 
      97       20336 :     Reference< drawing::XShape > xShape2DText = AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory)
      98       20336 :                     ->createText( xTarget, aLabel, rPropNames, rPropValues, aATransformation );
      99             : 
     100             :     LabelPositionHelper::correctPositionForRotation( xShape2DText
     101       10168 :         , rAxisProperties.maLabelAlignment.meAlignment, rAxisLabelProperties.fRotationAngleDegree, rAxisProperties.m_bComplexCategories );
     102             : 
     103       20336 :     return xShape2DText;
     104             : }
     105             : 
     106        5122 : bool lcl_doesShapeOverlapWithTickmark( const Reference< drawing::XShape >& xShape
     107             :                        , double fRotationAngleDegree
     108             :                        , const basegfx::B2DVector& rTickScreenPosition
     109             :                        , bool bIsHorizontalAxis, bool bIsVerticalAxis )
     110             : {
     111        5122 :     if(!xShape.is())
     112           0 :         return false;
     113             : 
     114        5122 :     ::basegfx::B2IRectangle aShapeRect = BaseGFXHelper::makeRectangle(xShape->getPosition(),AbstractShapeFactory::getSizeAfterRotation( xShape, fRotationAngleDegree ));
     115             : 
     116        5122 :     if( bIsVerticalAxis )
     117             :     {
     118        2815 :         return ( (rTickScreenPosition.getY() >= aShapeRect.getMinY())
     119        2815 :             && (rTickScreenPosition.getY() <= aShapeRect.getMaxY()) );
     120             :     }
     121        2307 :     if( bIsHorizontalAxis )
     122             :     {
     123        1896 :         return ( (rTickScreenPosition.getX() >= aShapeRect.getMinX())
     124        1896 :             && (rTickScreenPosition.getX() <= aShapeRect.getMaxX()) );
     125             :     }
     126             : 
     127             :     basegfx::B2IVector aPosition(
     128         411 :         static_cast<sal_Int32>( rTickScreenPosition.getX() )
     129         822 :         , static_cast<sal_Int32>( rTickScreenPosition.getY() ) );
     130         411 :     return aShapeRect.isInside(aPosition);
     131             : }
     132             : 
     133       10220 : void lcl_getRotatedPolygon( B2DPolygon &aPoly, const ::basegfx::B2DRectangle &aRect, const awt::Point &aPos, const double fRotationAngleDegree )
     134             : {
     135       10220 :     ::basegfx::B2DHomMatrix aMatrix;
     136             : 
     137       10220 :     aPoly = basegfx::tools::createPolygonFromRect( aRect );
     138       10220 :     aMatrix.translate( -aRect.getWidth()/2, -aRect.getHeight()/2);
     139       10220 :     aMatrix.rotate( fRotationAngleDegree*M_PI/180.0 );
     140       10220 :     aPoly.transform( aMatrix );
     141       10220 :     aMatrix = ::basegfx::B2DHomMatrix();
     142       10220 :     aMatrix.translate( aRect.getWidth()/2+aPos.X, aRect.getHeight()/2+aPos.Y);
     143       10220 :     aPoly.transform( aMatrix );
     144       10220 : }
     145             : 
     146        5110 : bool doesOverlap( const Reference< drawing::XShape >& xShape1
     147             :                 , const Reference< drawing::XShape >& xShape2
     148             :                 , double fRotationAngleDegree )
     149             : {
     150        5110 :     if( !xShape1.is() || !xShape2.is() )
     151           0 :         return false;
     152             : 
     153        5110 :     ::basegfx::B2DRectangle aRect1( BaseGFXHelper::makeRectangle( awt::Point(0,0), xShape1->getSize()));
     154        5110 :     ::basegfx::B2DRectangle aRect2( BaseGFXHelper::makeRectangle( awt::Point(0,0), xShape2->getSize()));
     155             : 
     156        5110 :     B2DPolygon aPoly1;
     157       10220 :     B2DPolygon aPoly2;
     158        5110 :     lcl_getRotatedPolygon( aPoly1, aRect1, xShape1->getPosition(), fRotationAngleDegree );
     159        5110 :     lcl_getRotatedPolygon( aPoly2, aRect2, xShape2->getPosition(), fRotationAngleDegree );
     160             : 
     161       10220 :     B2DPolyPolygon aPolyPoly1, aPolyPoly2;
     162        5110 :     aPolyPoly1.append( aPoly1 );
     163        5110 :     aPolyPoly2.append( aPoly2 );
     164       10220 :     B2DPolyPolygon overlapPoly = ::basegfx::tools::clipPolyPolygonOnPolyPolygon( aPolyPoly1, aPolyPoly2, true, false );
     165             : 
     166       10220 :     return (overlapPoly.count() > 0);
     167             : }
     168             : 
     169          25 : void removeShapesAtWrongRhythm( TickIter& rIter
     170             :                               , sal_Int32 nCorrectRhythm
     171             :                               , sal_Int32 nMaxTickToCheck
     172             :                               , const Reference< drawing::XShapes >& xTarget )
     173             : {
     174          25 :     sal_Int32 nTick = 0;
     175         114 :     for( TickInfo* pTickInfo = rIter.firstInfo()
     176         106 :         ; pTickInfo && nTick <= nMaxTickToCheck
     177          89 :         ; pTickInfo = rIter.nextInfo(), nTick++ )
     178             :     {
     179             :         //remove labels which does not fit into the rhythm
     180          89 :         if( nTick%nCorrectRhythm != 0)
     181             :         {
     182          56 :             if(pTickInfo->xTextShape.is())
     183             :             {
     184          21 :                 xTarget->remove(pTickInfo->xTextShape);
     185          21 :                 pTickInfo->xTextShape = NULL;
     186             :             }
     187             :         }
     188             :     }
     189          25 : }
     190             : 
     191         862 : class LabelIterator : public TickIter
     192             : {
     193             :     //this Iterator iterates over existing text labels
     194             : 
     195             :     //if the labels are staggered and bInnerLine is true
     196             :     //we iterate only through the labels which are lying more inside the diagram
     197             : 
     198             :     //if the labels are staggered and bInnerLine is false
     199             :     //we iterate only through the labels which are lying more outside the diagram
     200             : 
     201             :     //if the labels are not staggered
     202             :     //we iterate through all labels
     203             : 
     204             : public:
     205             :     LabelIterator( TickInfoArrayType& rTickInfoVector
     206             :             , const AxisLabelStaggering eAxisLabelStaggering
     207             :             , bool bInnerLine );
     208             : 
     209             :     virtual TickInfo*   firstInfo() SAL_OVERRIDE;
     210             :     virtual TickInfo*   nextInfo() SAL_OVERRIDE;
     211             : 
     212             : private: //member
     213             :     PureTickIter m_aPureTickIter;
     214             :     const AxisLabelStaggering   m_eAxisLabelStaggering;
     215             :     bool m_bInnerLine;
     216             : };
     217             : 
     218         862 : LabelIterator::LabelIterator( TickInfoArrayType& rTickInfoVector
     219             :             , const AxisLabelStaggering eAxisLabelStaggering
     220             :             , bool bInnerLine )
     221             :             : m_aPureTickIter( rTickInfoVector )
     222             :             , m_eAxisLabelStaggering(eAxisLabelStaggering)
     223         862 :             , m_bInnerLine(bInnerLine)
     224             : {
     225         862 : }
     226             : 
     227         856 : TickInfo* LabelIterator::firstInfo()
     228             : {
     229         856 :     TickInfo* pTickInfo = m_aPureTickIter.firstInfo();
     230        1738 :     while( pTickInfo && !pTickInfo->xTextShape.is() )
     231          26 :         pTickInfo = m_aPureTickIter.nextInfo();
     232         856 :     if(!pTickInfo)
     233           2 :         return NULL;
     234         854 :     if( (STAGGER_EVEN==m_eAxisLabelStaggering && m_bInnerLine)
     235         425 :         ||
     236         425 :         (STAGGER_ODD==m_eAxisLabelStaggering && !m_bInnerLine)
     237             :         )
     238             :     {
     239             :         //skip first label
     240         445 :         do
     241         445 :             pTickInfo = m_aPureTickIter.nextInfo();
     242         445 :         while( pTickInfo && !pTickInfo->xTextShape.is() );
     243             :     }
     244         854 :     if(!pTickInfo)
     245           4 :         return NULL;
     246         850 :     return pTickInfo;
     247             : }
     248             : 
     249        1641 : TickInfo* LabelIterator::nextInfo()
     250             : {
     251        1641 :     TickInfo* pTickInfo = NULL;
     252             :     //get next label
     253        2275 :     do
     254        2275 :         pTickInfo = m_aPureTickIter.nextInfo();
     255        2275 :     while( pTickInfo && !pTickInfo->xTextShape.is() );
     256             : 
     257        1641 :     if(  STAGGER_EVEN==m_eAxisLabelStaggering
     258           0 :       || STAGGER_ODD==m_eAxisLabelStaggering )
     259             :     {
     260             :         //skip one label
     261        2259 :         do
     262        2259 :             pTickInfo = m_aPureTickIter.nextInfo();
     263        2259 :         while( pTickInfo && !pTickInfo->xTextShape.is() );
     264             :     }
     265        1641 :     return pTickInfo;
     266             : }
     267             : 
     268         431 : B2DVector lcl_getLabelsDistance( TickIter& rIter, const B2DVector& rDistanceTickToText, double fRotationAngleDegree )
     269             : {
     270             :     //calculates the height or width of a line of labels
     271             :     //thus a following line of labels can be shifted for that distance
     272             : 
     273         431 :     B2DVector aRet(0,0);
     274             : 
     275         431 :     sal_Int32 nDistanceTickToText = static_cast<sal_Int32>( rDistanceTickToText.getLength() );
     276         431 :     if( nDistanceTickToText==0.0)
     277           0 :         return aRet;
     278             : 
     279         862 :     B2DVector aStaggerDirection(rDistanceTickToText);
     280         431 :     aStaggerDirection.normalize();
     281             : 
     282         431 :     sal_Int32 nDistance=0;
     283         862 :     Reference< drawing::XShape >  xShape2DText(NULL);
     284        1234 :     for( TickInfo* pTickInfo = rIter.firstInfo()
     285             :         ; pTickInfo
     286         803 :         ; pTickInfo = rIter.nextInfo() )
     287             :     {
     288         803 :         xShape2DText = pTickInfo->xTextShape;
     289         803 :         if( xShape2DText.is() )
     290             :         {
     291         803 :             awt::Size aSize = AbstractShapeFactory::getSizeAfterRotation( xShape2DText, fRotationAngleDegree );
     292         803 :             if(fabs(aStaggerDirection.getX())>fabs(aStaggerDirection.getY()))
     293          32 :                 nDistance = ::std::max(nDistance,aSize.Width);
     294             :             else
     295         771 :                 nDistance = ::std::max(nDistance,aSize.Height);
     296             :         }
     297             :     }
     298             : 
     299         431 :     aRet = aStaggerDirection*nDistance;
     300             : 
     301             :     //add extra distance for vertical distance
     302         431 :     if(fabs(aStaggerDirection.getX())>fabs(aStaggerDirection.getY()))
     303          21 :         aRet += rDistanceTickToText;
     304             : 
     305         431 :     return aRet;
     306             : }
     307             : 
     308         431 : void lcl_shiftLabels( TickIter& rIter, const B2DVector& rStaggerDistance )
     309             : {
     310         431 :     if(rStaggerDistance.getLength()==0.0)
     311         437 :         return;
     312         425 :     Reference< drawing::XShape >  xShape2DText(NULL);
     313        1263 :     for( TickInfo* pTickInfo = rIter.firstInfo()
     314             :         ; pTickInfo
     315         838 :         ; pTickInfo = rIter.nextInfo() )
     316             :     {
     317         838 :         xShape2DText = pTickInfo->xTextShape;
     318         838 :         if( xShape2DText.is() )
     319             :         {
     320         838 :             awt::Point aPos  = xShape2DText->getPosition();
     321         838 :             aPos.X += static_cast<sal_Int32>(rStaggerDistance.getX());
     322         838 :             aPos.Y += static_cast<sal_Int32>(rStaggerDistance.getY());
     323         838 :             xShape2DText->setPosition( aPos );
     324             :         }
     325         425 :     }
     326             : }
     327             : 
     328           0 : bool lcl_hasWordBreak( const Reference< drawing::XShape >& rxShape )
     329             : {
     330           0 :     if ( rxShape.is() )
     331             :     {
     332           0 :         SvxShape* pShape = SvxShape::getImplementation( rxShape );
     333           0 :         SvxShapeText* pShapeText = dynamic_cast< SvxShapeText* >( pShape );
     334           0 :         if ( pShapeText )
     335             :         {
     336           0 :             SvxTextEditSource* pTextEditSource = dynamic_cast< SvxTextEditSource* >( pShapeText->GetEditSource() );
     337           0 :             if ( pTextEditSource )
     338             :             {
     339           0 :                 pTextEditSource->UpdateOutliner();
     340           0 :                 SvxTextForwarder* pTextForwarder = pTextEditSource->GetTextForwarder();
     341           0 :                 if ( pTextForwarder )
     342             :                 {
     343           0 :                     sal_Int32 nParaCount = pTextForwarder->GetParagraphCount();
     344           0 :                     for ( sal_Int32 nPara = 0; nPara < nParaCount; ++nPara )
     345             :                     {
     346           0 :                         sal_Int32 nLineCount = pTextForwarder->GetLineCount( nPara );
     347           0 :                         for ( sal_Int32 nLine = 0; nLine < nLineCount; ++nLine )
     348             :                         {
     349           0 :                             sal_Int32 nLineStart = 0;
     350           0 :                             sal_Int32 nLineEnd = 0;
     351           0 :                             pTextForwarder->GetLineBoundaries( nLineStart, nLineEnd, nPara, nLine );
     352             :                             assert(nLineStart >= 0);
     353           0 :                             sal_Int32 nWordStart = 0;
     354           0 :                             sal_Int32 nWordEnd = 0;
     355           0 :                             if ( pTextForwarder->GetWordIndices( nPara, nLineStart, nWordStart, nWordEnd ) &&
     356           0 :                                  ( nWordStart != nLineStart ) )
     357             :                             {
     358           0 :                                 return true;
     359             :                             }
     360             :                         }
     361             :                     }
     362             :                 }
     363             :             }
     364             :         }
     365             :     }
     366             : 
     367           0 :     return false;
     368             : }
     369             : 
     370             : /**
     371             :  * Iterate through only the first 2 and last 2 tick info items, and the tick
     372             :  * that has the longest text (in terms of character length) in case it's not
     373             :  * in the first or last 2 items.
     374             :  */
     375             : class MaxLabelTickIter : public TickIter
     376             : {
     377             : public:
     378             :     MaxLabelTickIter( TickInfoArrayType& rTickInfoVector
     379             :             , sal_Int32 nLongestLabelIndex );
     380             :     virtual ~MaxLabelTickIter();
     381             : 
     382             :     virtual TickInfo* firstInfo() SAL_OVERRIDE;
     383             :     virtual TickInfo* nextInfo() SAL_OVERRIDE;
     384             : 
     385             : private:
     386             :     TickInfoArrayType& m_rTickInfoVector;
     387             :     ::std::vector< sal_Int32 > m_aValidIndices;
     388             :     sal_Int32 m_nCurrentIndex;
     389             : };
     390             : 
     391         986 : MaxLabelTickIter::MaxLabelTickIter( TickInfoArrayType& rTickInfoVector
     392             :             , sal_Int32 nLongestLabelIndex )
     393             :             : m_rTickInfoVector(rTickInfoVector)
     394         986 :             , m_nCurrentIndex(0)
     395             : {
     396         986 :     sal_Int32 nMaxIndex = m_rTickInfoVector.size()-1;
     397         986 :     if( nLongestLabelIndex<0 || nLongestLabelIndex>=nMaxIndex-1 )
     398          18 :         nLongestLabelIndex = 0;
     399             : 
     400         986 :     if( nMaxIndex>=0 )
     401         986 :         m_aValidIndices.push_back(0);
     402         986 :     if( nMaxIndex>=1 )
     403         982 :         m_aValidIndices.push_back(1);
     404         986 :     if( nLongestLabelIndex>1 )
     405           0 :         m_aValidIndices.push_back(nLongestLabelIndex);
     406         986 :     if( nMaxIndex > 2 )
     407         917 :         m_aValidIndices.push_back(nMaxIndex-1);
     408         986 :     if( nMaxIndex > 1 )
     409         970 :         m_aValidIndices.push_back(nMaxIndex);
     410         986 : }
     411        1972 : MaxLabelTickIter::~MaxLabelTickIter()
     412             : {
     413        1972 : }
     414             : 
     415         986 : TickInfo* MaxLabelTickIter::firstInfo()
     416             : {
     417         986 :     m_nCurrentIndex = 0;
     418         986 :     if( m_nCurrentIndex < static_cast<sal_Int32>(m_aValidIndices.size()) )
     419         986 :         return &m_rTickInfoVector[m_aValidIndices[m_nCurrentIndex]];
     420           0 :     return 0;
     421             : }
     422             : 
     423        3855 : TickInfo* MaxLabelTickIter::nextInfo()
     424             : {
     425        3855 :     m_nCurrentIndex++;
     426        3855 :     if( m_nCurrentIndex>=0 && m_nCurrentIndex<static_cast<sal_Int32>(m_aValidIndices.size()) )
     427        2869 :         return &m_rTickInfoVector[m_aValidIndices[m_nCurrentIndex]];
     428         986 :     return 0;
     429             : }
     430             : 
     431        2006 : bool VCartesianAxis::isBreakOfLabelsAllowed( const AxisLabelProperties& rAxisLabelProperties
     432             :                                                      , bool bIsHorizontalAxis )
     433             : {
     434        2006 :     if( m_aTextLabels.getLength() > 100 )
     435           0 :         return false;
     436        2006 :     if( !rAxisLabelProperties.bLineBreakAllowed )
     437        1957 :         return false;
     438          49 :     if( rAxisLabelProperties.bStackCharacters )
     439           1 :         return false;
     440             :     //no break for value axis
     441          48 :     if( !m_bUseTextLabels )
     442           5 :         return false;
     443          43 :     if( !::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) )
     444           0 :         return false;
     445             :     //break only for horizontal axis
     446          43 :     return bIsHorizontalAxis;
     447             : }
     448             : 
     449        1012 : bool VCartesianAxis::isAutoStaggeringOfLabelsAllowed( const AxisLabelProperties& rAxisLabelProperties
     450             :                                                      , bool bIsHorizontalAxis, bool bIsVerticalAxis )
     451             : {
     452        1012 :     if( rAxisLabelProperties.eStaggering != STAGGER_AUTO )
     453         169 :         return false;
     454         843 :     if( rAxisLabelProperties.bOverlapAllowed )
     455           1 :         return false;
     456         842 :     if( rAxisLabelProperties.bLineBreakAllowed ) //auto line break or auto staggering, doing both automatisms they may conflict...
     457           0 :         return false;
     458         842 :     if( !::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) )
     459           2 :         return false;
     460             :     //automatic staggering only for horizontal axis with horizontal text
     461             :     //or vertical axis with vertical text
     462         840 :     if( bIsHorizontalAxis )
     463         410 :         return !rAxisLabelProperties.bStackCharacters;
     464         430 :     if( bIsVerticalAxis )
     465         378 :         return rAxisLabelProperties.bStackCharacters;
     466          52 :     return false;
     467             : }
     468             : 
     469           0 : void VCartesianAxis::createAllTickInfosFromComplexCategories( TickInfoArraysType& rAllTickInfos, bool bShiftedPosition )
     470             : {
     471             :     //no minor tickmarks will be generated!
     472             :     //order is: inner labels first , outer labels last (that is different to all other TickIter cases)
     473           0 :     if(!bShiftedPosition)
     474             :     {
     475           0 :         rAllTickInfos.clear();
     476           0 :         sal_Int32 nLevel=0;
     477           0 :         sal_Int32 nLevelCount = m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoryLevelCount();
     478           0 :         for( ; nLevel<nLevelCount; nLevel++ )
     479             :         {
     480           0 :             TickInfoArrayType aTickInfoVector;
     481             :             const std::vector<ComplexCategory>* pComplexCategories =
     482           0 :                 m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoriesByLevel(nLevel);
     483             : 
     484           0 :             if (!pComplexCategories)
     485           0 :                 continue;
     486             : 
     487           0 :             sal_Int32 nCatIndex = 0;
     488           0 :             std::vector<ComplexCategory>::const_iterator aIt = pComplexCategories->begin();
     489           0 :             std::vector<ComplexCategory>::const_iterator aEnd = pComplexCategories->end();
     490             : 
     491           0 :             for(;aIt!=aEnd;++aIt)
     492             :             {
     493           0 :                 TickInfo aTickInfo(0);
     494           0 :                 ComplexCategory aCat(*aIt);
     495           0 :                 sal_Int32 nCount = aCat.Count;
     496           0 :                 if( nCatIndex + 1.0 + nCount >= m_aScale.Maximum )
     497             :                 {
     498           0 :                     nCount = static_cast<sal_Int32>(m_aScale.Maximum - 1.0 - nCatIndex);
     499           0 :                     if( nCount <= 0 )
     500           0 :                         nCount = 1;
     501             :                 }
     502           0 :                 aTickInfo.fScaledTickValue = nCatIndex + 1.0 + nCount/2.0;
     503           0 :                 aTickInfo.nFactorForLimitedTextWidth = nCount;
     504           0 :                 aTickInfo.aText = aCat.Text;
     505           0 :                 aTickInfoVector.push_back(aTickInfo);
     506           0 :                 nCatIndex += nCount;
     507           0 :                 if( nCatIndex + 1.0 >= m_aScale.Maximum )
     508           0 :                     break;
     509           0 :             }
     510           0 :             rAllTickInfos.push_back(aTickInfoVector);
     511           0 :         }
     512             :     }
     513             :     else //bShiftedPosition==false
     514             :     {
     515           0 :         rAllTickInfos.clear();
     516           0 :         sal_Int32 nLevel=0;
     517           0 :         sal_Int32 nLevelCount = m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoryLevelCount();
     518           0 :         for( ; nLevel<nLevelCount; nLevel++ )
     519             :         {
     520           0 :             TickInfoArrayType aTickInfoVector;
     521             :             const std::vector<ComplexCategory>* pComplexCategories =
     522           0 :                 m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoriesByLevel(nLevel);
     523           0 :             sal_Int32 nCatIndex = 0;
     524           0 :             if (pComplexCategories)
     525             :             {
     526           0 :                 std::vector<ComplexCategory>::const_iterator aIt = pComplexCategories->begin();
     527           0 :                 std::vector<ComplexCategory>::const_iterator aEnd = pComplexCategories->end();
     528           0 :                 for(;aIt!=aEnd;++aIt)
     529             :                 {
     530           0 :                     TickInfo aTickInfo(0);
     531           0 :                     ComplexCategory aCat(*aIt);
     532           0 :                     aTickInfo.fScaledTickValue = nCatIndex + 1.0;
     533           0 :                     aTickInfoVector.push_back(aTickInfo);
     534           0 :                     nCatIndex += aCat.Count;
     535           0 :                     if( nCatIndex + 1.0 > m_aScale.Maximum )
     536           0 :                         break;
     537           0 :                 }
     538             :             }
     539             : 
     540             :             //fill up with single ticks until maximum scale
     541           0 :             while( nCatIndex + 1.0 < m_aScale.Maximum )
     542             :             {
     543           0 :                 TickInfo aTickInfo(0);
     544           0 :                 aTickInfo.fScaledTickValue = nCatIndex + 1.0;
     545           0 :                 aTickInfoVector.push_back(aTickInfo);
     546           0 :                 nCatIndex ++;
     547           0 :                 if( nLevel>0 )
     548           0 :                     break;
     549           0 :             }
     550             :             //add an additional tick at the end
     551             :             {
     552           0 :                 TickInfo aTickInfo(0);
     553           0 :                 aTickInfo.fScaledTickValue = m_aScale.Maximum;
     554           0 :                 aTickInfoVector.push_back(aTickInfo);
     555             :             }
     556           0 :             rAllTickInfos.push_back(aTickInfoVector);
     557           0 :         }
     558             :     }
     559           0 : }
     560             : 
     561        2132 : void VCartesianAxis::createAllTickInfos( TickInfoArraysType& rAllTickInfos )
     562             : {
     563        2132 :     if( isComplexCategoryAxis() )
     564           0 :         createAllTickInfosFromComplexCategories( rAllTickInfos, false );
     565             :     else
     566        2132 :         VAxisBase::createAllTickInfos(rAllTickInfos);
     567        2132 : }
     568             : 
     569         986 : TickIter* VCartesianAxis::createLabelTickIterator( sal_Int32 nTextLevel )
     570             : {
     571         986 :     if( nTextLevel>=0 && nTextLevel < static_cast< sal_Int32 >(m_aAllTickInfos.size()) )
     572         986 :         return new PureTickIter( m_aAllTickInfos[nTextLevel] );
     573           0 :     return NULL;
     574             : }
     575             : 
     576         986 : TickIter* VCartesianAxis::createMaximumLabelTickIterator( sal_Int32 nTextLevel )
     577             : {
     578         986 :     if( isComplexCategoryAxis() || isDateAxis() )
     579             :     {
     580           0 :         return createLabelTickIterator( nTextLevel ); //mmmm maybe todo: create less than all texts here
     581             :     }
     582             :     else
     583             :     {
     584         986 :         if(nTextLevel==0)
     585             :         {
     586         986 :             if( !m_aAllTickInfos.empty() )
     587             :             {
     588         986 :                 sal_Int32 nLongestLabelIndex = m_bUseTextLabels ? this->getIndexOfLongestLabel( m_aTextLabels ) : 0;
     589         986 :                 return new MaxLabelTickIter( m_aAllTickInfos[0], nLongestLabelIndex );
     590             :             }
     591             :         }
     592             :     }
     593           0 :     return NULL;
     594             : }
     595             : 
     596        1972 : sal_Int32 VCartesianAxis::getTextLevelCount() const
     597             : {
     598        1972 :     sal_Int32 nTextLevelCount = 1;
     599        1972 :     if( isComplexCategoryAxis() )
     600           0 :         nTextLevelCount = m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoryLevelCount();
     601        1972 :     return nTextLevelCount;
     602             : }
     603             : 
     604        2006 : bool VCartesianAxis::createTextShapes(
     605             :                        const Reference< drawing::XShapes >& xTarget
     606             :                      , TickIter& rTickIter
     607             :                      , AxisLabelProperties& rAxisLabelProperties
     608             :                      , TickFactory2D* pTickFactory
     609             :                      , sal_Int32 nScreenDistanceBetweenTicks )
     610             : {
     611             :     FixedNumberFormatter aFixedNumberFormatter(
     612        2006 :                 m_xNumberFormatsSupplier, rAxisLabelProperties.nNumberFormatKey );
     613             : 
     614        2006 :     const bool bIsHorizontalAxis = pTickFactory->isHorizontalAxis();
     615        2006 :     const bool bIsVerticalAxis = pTickFactory->isVerticalAxis();
     616        2006 :     bool bIsStaggered = rAxisLabelProperties.getIsStaggered();
     617        4012 :     B2DVector aTextToTickDistance( pTickFactory->getDistanceAxisTickToText( m_aAxisProperties, true ) );
     618        2006 :     sal_Int32 nLimitedSpaceForText = -1;
     619        2006 :     if( isBreakOfLabelsAllowed( rAxisLabelProperties, bIsHorizontalAxis ) )
     620             :     {
     621          43 :         nLimitedSpaceForText = nScreenDistanceBetweenTicks;
     622          43 :         if( bIsStaggered )
     623           0 :             nLimitedSpaceForText *= 2;
     624             : 
     625          43 :         if( nLimitedSpaceForText > 0 )
     626             :         { //reduce space for a small amount to have a visible distance between the labels:
     627          43 :             sal_Int32 nReduce = (nLimitedSpaceForText*5)/100;
     628          43 :             if(!nReduce)
     629           0 :                 nReduce = 1;
     630          43 :             nLimitedSpaceForText -= nReduce;
     631             :         }
     632             :     }
     633             : 
     634        2006 :     uno::Sequence< OUString >* pCategories = 0;
     635        2006 :     if( m_bUseTextLabels && !m_aAxisProperties.m_bComplexCategories )
     636         976 :         pCategories = &m_aTextLabels;
     637             : 
     638        2006 :     TickInfo* pPreviousVisibleTickInfo = NULL;
     639        2006 :     TickInfo* pPREPreviousVisibleTickInfo = NULL;
     640        2006 :     TickInfo* pLastVisibleNeighbourTickInfo = NULL;
     641             : 
     642             :     //prepare properties for multipropertyset-interface of shape
     643        4012 :     tNameSequence aPropNames;
     644        4012 :     tAnySequence aPropValues;
     645             : 
     646        2006 :     bool bLimitedHeight = fabs(aTextToTickDistance.getX()) > fabs(aTextToTickDistance.getY());
     647        4012 :     Reference< beans::XPropertySet > xProps( m_aAxisProperties.m_xAxisModel, uno::UNO_QUERY );
     648             :     PropertyMapper::getTextLabelMultiPropertyLists( xProps, aPropNames, aPropValues, false
     649        2006 :         , nLimitedSpaceForText, bLimitedHeight );
     650             :     LabelPositionHelper::doDynamicFontResize( aPropValues, aPropNames, xProps
     651        2006 :         , m_aAxisLabelProperties.m_aFontReferenceSize );
     652        2006 :     LabelPositionHelper::changeTextAdjustment( aPropValues, aPropNames, m_aAxisProperties.maLabelAlignment.meAlignment );
     653             : 
     654        2006 :     uno::Any* pColorAny = PropertyMapper::getValuePointer(aPropValues,aPropNames,"CharColor");
     655        2006 :     sal_Int32 nColor = Color( COL_AUTO ).GetColor();
     656        2006 :     if(pColorAny)
     657        2006 :         *pColorAny >>= nColor;
     658             : 
     659        2006 :     uno::Any* pLimitedSpaceAny = PropertyMapper::getValuePointerForLimitedSpace(aPropValues,aPropNames,bLimitedHeight);
     660             : 
     661        2006 :     sal_Int32 nTick = 0;
     662       12289 :     for( TickInfo* pTickInfo = rTickIter.firstInfo()
     663             :         ; pTickInfo
     664       10283 :         ; pTickInfo = rTickIter.nextInfo(), nTick++ )
     665             :     {
     666             :         pLastVisibleNeighbourTickInfo = bIsStaggered ?
     667       10317 :                     pPREPreviousVisibleTickInfo : pPreviousVisibleTickInfo;
     668             : 
     669             :         //don't create labels which does not fit into the rhythm
     670       10317 :         if( nTick%rAxisLabelProperties.nRhythm != 0 )
     671         190 :             continue;
     672             : 
     673             :         //don't create labels for invisible ticks
     674       10239 :         if( !pTickInfo->bPaintIt )
     675           0 :             continue;
     676             : 
     677             :         //if NO OVERLAP -> don't create labels where the tick overlaps
     678             :         //with the text of the last neighbour tickmark
     679       10239 :         if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.bOverlapAllowed )
     680             :         {
     681        5122 :             if( lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo->xTextShape
     682             :                        , rAxisLabelProperties.fRotationAngleDegree
     683             :                        , pTickInfo->aTickScreenPosition
     684        5122 :                        , bIsHorizontalAxis, bIsVerticalAxis ) )
     685             :             {
     686          12 :                 bool bOverlapAlsoAfterSwitchingOnAutoStaggering = true;
     687          12 :                 if( !bIsStaggered && isAutoStaggeringOfLabelsAllowed( rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis ) )
     688             :                 {
     689           0 :                     bIsStaggered = true;
     690           0 :                     rAxisLabelProperties.eStaggering = STAGGER_EVEN;
     691           0 :                     pLastVisibleNeighbourTickInfo = pPREPreviousVisibleTickInfo;
     692           0 :                     if( !pLastVisibleNeighbourTickInfo ||
     693             :                         !lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo->xTextShape
     694             :                                 , rAxisLabelProperties.fRotationAngleDegree
     695             :                                 , pTickInfo->aTickScreenPosition
     696           0 :                                 , bIsHorizontalAxis, bIsVerticalAxis ) )
     697           0 :                         bOverlapAlsoAfterSwitchingOnAutoStaggering = false;
     698             :                 }
     699          12 :                 if( bOverlapAlsoAfterSwitchingOnAutoStaggering )
     700             :                 {
     701          12 :                     if( rAxisLabelProperties.bRhythmIsFix )
     702           0 :                         continue;
     703          12 :                     rAxisLabelProperties.nRhythm++;
     704          12 :                     removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.nRhythm, nTick, xTarget );
     705          46 :                     return false;
     706             :                 }
     707             :             }
     708             :         }
     709             : 
     710             :         //xxxxx pTickInfo->updateUnscaledValue( xInverseScaling );
     711             : 
     712       10227 :         bool bHasExtraColor=false;
     713       10227 :         sal_Int32 nExtraColor=0;
     714             : 
     715       10227 :         OUString aLabel;
     716       10227 :         if(pCategories)
     717             :         {
     718        4249 :             sal_Int32 nIndex = static_cast< sal_Int32 >(pTickInfo->getUnscaledTickValue()) - 1; //first category (index 0) matches with real number 1.0
     719        4249 :             if( nIndex>=0 && nIndex<pCategories->getLength() )
     720        4219 :                 aLabel = (*pCategories)[nIndex];
     721             :         }
     722        5978 :         else if( m_aAxisProperties.m_bComplexCategories )
     723             :         {
     724           0 :             aLabel = pTickInfo->aText;
     725             :         }
     726             :         else
     727        5978 :             aLabel = aFixedNumberFormatter.getFormattedString( pTickInfo->getUnscaledTickValue(), nExtraColor, bHasExtraColor );
     728             : 
     729       10227 :         if(pColorAny)
     730       10227 :             *pColorAny = uno::makeAny(bHasExtraColor?nExtraColor:nColor);
     731       10227 :         if(pLimitedSpaceAny)
     732         170 :             *pLimitedSpaceAny = uno::makeAny(sal_Int32(nLimitedSpaceForText*pTickInfo->nFactorForLimitedTextWidth));
     733             : 
     734       20398 :         B2DVector aTickScreenPos2D( pTickInfo->aTickScreenPosition );
     735       10227 :         aTickScreenPos2D += aTextToTickDistance;
     736             :         awt::Point aAnchorScreenPosition2D(
     737       10227 :             static_cast<sal_Int32>(aTickScreenPos2D.getX())
     738       20454 :             ,static_cast<sal_Int32>(aTickScreenPos2D.getY()));
     739             : 
     740             :         //create single label
     741       10227 :         if(!pTickInfo->xTextShape.is())
     742       20404 :             pTickInfo->xTextShape = createSingleLabel( m_xShapeFactory, xTarget
     743             :                                     , aAnchorScreenPosition2D, aLabel
     744             :                                     , rAxisLabelProperties, m_aAxisProperties
     745       10202 :                                     , aPropNames, aPropValues );
     746       10227 :         if(!pTickInfo->xTextShape.is())
     747          34 :             continue;
     748             : 
     749       10193 :         recordMaximumTextSize( pTickInfo->xTextShape, rAxisLabelProperties.fRotationAngleDegree );
     750             : 
     751             :          //better rotate if single words are broken apart
     752       10363 :         if( nLimitedSpaceForText>0 && !rAxisLabelProperties.bOverlapAllowed
     753         164 :                 && ::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 )
     754         164 :                 && m_aAxisProperties.m_bComplexCategories
     755       10193 :                 && lcl_hasWordBreak( pTickInfo->xTextShape ) )
     756             :         {
     757           0 :             rAxisLabelProperties.fRotationAngleDegree = 90;
     758           0 :             rAxisLabelProperties.bLineBreakAllowed = false;
     759           0 :             m_aAxisLabelProperties.fRotationAngleDegree = rAxisLabelProperties.fRotationAngleDegree;
     760           0 :             removeTextShapesFromTicks();
     761           0 :             return false;
     762             :         }
     763             : 
     764             :         //if NO OVERLAP -> remove overlapping shapes
     765       10193 :         if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.bOverlapAllowed )
     766             :         {
     767        5110 :             if( doesOverlap( pLastVisibleNeighbourTickInfo->xTextShape, pTickInfo->xTextShape, rAxisLabelProperties.fRotationAngleDegree ) )
     768             :             {
     769          22 :                 bool bOverlapAlsoAfterSwitchingOnAutoStaggering = true;
     770          22 :                 if( !bIsStaggered && isAutoStaggeringOfLabelsAllowed( rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis ) )
     771             :                 {
     772           0 :                     bIsStaggered = true;
     773           0 :                     rAxisLabelProperties.eStaggering = STAGGER_EVEN;
     774           0 :                     pLastVisibleNeighbourTickInfo = pPREPreviousVisibleTickInfo;
     775           0 :                     if( !pLastVisibleNeighbourTickInfo ||
     776             :                         !lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo->xTextShape
     777             :                             , rAxisLabelProperties.fRotationAngleDegree
     778             :                             , pTickInfo->aTickScreenPosition
     779           0 :                             , bIsHorizontalAxis, bIsVerticalAxis ) )
     780           0 :                         bOverlapAlsoAfterSwitchingOnAutoStaggering = false;
     781             :                 }
     782          22 :                 if( bOverlapAlsoAfterSwitchingOnAutoStaggering )
     783             :                 {
     784             :                     /* Try auto-rotating to 45 degrees */
     785          22 :                     if( !rAxisLabelProperties.bOverlapAllowed && ::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) )
     786             :                     {
     787           9 :                         rAxisLabelProperties.fRotationAngleDegree = 45;
     788           9 :                         rAxisLabelProperties.bLineBreakAllowed = false;
     789           9 :                         rAxisLabelProperties.eStaggering = SIDE_BY_SIDE;
     790           9 :                         m_aAxisLabelProperties.fRotationAngleDegree = rAxisLabelProperties.fRotationAngleDegree;
     791           9 :                         removeTextShapesFromTicks();
     792           9 :                         return false;
     793             :                     }
     794          13 :                     if( rAxisLabelProperties.bRhythmIsFix )
     795             :                     {
     796           0 :                         xTarget->remove(pTickInfo->xTextShape);
     797           0 :                         pTickInfo->xTextShape = NULL;
     798           0 :                         continue;
     799             :                     }
     800          13 :                     rAxisLabelProperties.nRhythm++;
     801          13 :                     removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.nRhythm, nTick, xTarget );
     802          13 :                     return false;
     803             :                 }
     804             :             }
     805             :         }
     806             : 
     807       10171 :         pPREPreviousVisibleTickInfo = pPreviousVisibleTickInfo;
     808       10171 :         pPreviousVisibleTickInfo = pTickInfo;
     809       10171 :     }
     810        3978 :     return true;
     811             : }
     812             : 
     813           0 : drawing::PointSequenceSequence lcl_makePointSequence( B2DVector& rStart, B2DVector& rEnd )
     814             : {
     815           0 :     drawing::PointSequenceSequence aPoints(1);
     816           0 :     aPoints[0].realloc(2);
     817           0 :     aPoints[0][0].X = static_cast<sal_Int32>(rStart.getX());
     818           0 :     aPoints[0][0].Y = static_cast<sal_Int32>(rStart.getY());
     819           0 :     aPoints[0][1].X = static_cast<sal_Int32>(rEnd.getX());
     820           0 :     aPoints[0][1].Y = static_cast<sal_Int32>(rEnd.getY());
     821           0 :     return aPoints;
     822             : }
     823             : 
     824       13098 : double VCartesianAxis::getAxisIntersectionValue() const
     825             : {
     826       13098 :     if (m_aAxisProperties.m_pfMainLinePositionAtOtherAxis)
     827       12378 :         return *m_aAxisProperties.m_pfMainLinePositionAtOtherAxis;
     828             : 
     829         720 :     double fMin = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMinY();
     830         720 :     double fMax = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMaxY();
     831             : 
     832         720 :     return (css::chart::ChartAxisPosition_END == m_aAxisProperties.m_eCrossoverType) ? fMax : fMin;
     833             : }
     834             : 
     835        6178 : double VCartesianAxis::getLabelLineIntersectionValue() const
     836             : {
     837        6178 :     if (css::chart::ChartAxisLabelPosition_OUTSIDE_START == m_aAxisProperties.m_eLabelPos)
     838         246 :         return (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMinY();
     839             : 
     840        5932 :     if (css::chart::ChartAxisLabelPosition_OUTSIDE_END == m_aAxisProperties.m_eLabelPos)
     841           0 :         return (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMaxY();
     842             : 
     843        5932 :     return getAxisIntersectionValue();
     844             : }
     845             : 
     846           0 : double VCartesianAxis::getExtraLineIntersectionValue() const
     847             : {
     848             :     double fNan;
     849           0 :     rtl::math::setNan(&fNan);
     850             : 
     851           0 :     if( !m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis )
     852           0 :         return fNan;
     853             : 
     854           0 :     double fMin = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMinY();
     855           0 :     double fMax = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMaxY();
     856             : 
     857           0 :     if( *m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis <= fMin
     858           0 :         || *m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis >= fMax )
     859           0 :         return fNan;
     860             : 
     861           0 :     return *m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis;
     862             : }
     863             : 
     864       26688 : B2DVector VCartesianAxis::getScreenPosition( double fLogicX, double fLogicY, double fLogicZ ) const
     865             : {
     866       26688 :     B2DVector aRet(0,0);
     867             : 
     868       26688 :     if( m_pPosHelper )
     869             :     {
     870       26688 :         drawing::Position3D aScenePos = m_pPosHelper->transformLogicToScene( fLogicX, fLogicY, fLogicZ, true );
     871       26688 :         if(3==m_nDimension)
     872             :         {
     873        2416 :             if( m_xLogicTarget.is() && m_pPosHelper && m_pShapeFactory )
     874             :             {
     875        2416 :                 tPropertyNameMap aDummyPropertyNameMap;
     876             :                 Reference< drawing::XShape > xShape3DAnchor = m_pShapeFactory->createCube( m_xLogicTarget
     877        4832 :                         , aScenePos,drawing::Direction3D(1,1,1), 0, 0, aDummyPropertyNameMap);
     878        2416 :                 awt::Point a2DPos = xShape3DAnchor->getPosition(); //get 2D position from xShape3DAnchor
     879        2416 :                 m_xLogicTarget->remove(xShape3DAnchor);
     880        2416 :                 aRet.setX( a2DPos.X );
     881        4832 :                 aRet.setY( a2DPos.Y );
     882             :             }
     883             :             else
     884             :             {
     885             :                 OSL_FAIL("cannot calculate scrren position in VCartesianAxis::getScreenPosition");
     886             :             }
     887             :         }
     888             :         else
     889             :         {
     890       24272 :             aRet.setX( aScenePos.PositionX );
     891       24272 :             aRet.setY( aScenePos.PositionY );
     892             :         }
     893             :     }
     894             : 
     895       26688 :     return aRet;
     896             : }
     897             : 
     898           0 : VCartesianAxis::ScreenPosAndLogicPos VCartesianAxis::getScreenPosAndLogicPos( double fLogicX_, double fLogicY_, double fLogicZ_ ) const
     899             : {
     900           0 :     ScreenPosAndLogicPos aRet;
     901           0 :     aRet.fLogicX = fLogicX_;
     902           0 :     aRet.fLogicY = fLogicY_;
     903           0 :     aRet.fLogicZ = fLogicZ_;
     904           0 :     aRet.aScreenPos = getScreenPosition( fLogicX_, fLogicY_, fLogicZ_ );
     905           0 :     return aRet;
     906             : }
     907             : 
     908             : typedef ::std::vector< VCartesianAxis::ScreenPosAndLogicPos > tScreenPosAndLogicPosList;
     909             : struct lcl_LessXPos : ::std::binary_function< VCartesianAxis::ScreenPosAndLogicPos, VCartesianAxis::ScreenPosAndLogicPos, bool >
     910             : {
     911           0 :     inline bool operator() ( const VCartesianAxis::ScreenPosAndLogicPos& rPos1, const VCartesianAxis::ScreenPosAndLogicPos& rPos2 )
     912             :     {
     913           0 :         return ( rPos1.aScreenPos.getX() < rPos2.aScreenPos.getX() );
     914             :     }
     915             : };
     916             : 
     917             : struct lcl_GreaterYPos : ::std::binary_function< VCartesianAxis::ScreenPosAndLogicPos, VCartesianAxis::ScreenPosAndLogicPos, bool >
     918             : {
     919           0 :     inline bool operator() ( const VCartesianAxis::ScreenPosAndLogicPos& rPos1, const VCartesianAxis::ScreenPosAndLogicPos& rPos2 )
     920             :     {
     921           0 :         return ( rPos1.aScreenPos.getY() > rPos2.aScreenPos.getY() );
     922             :     }
     923             : };
     924             : 
     925       13344 : void VCartesianAxis::get2DAxisMainLine(
     926             :     B2DVector& rStart, B2DVector& rEnd, AxisLabelAlignment& rAlignment, double fCrossesOtherAxis ) const
     927             : {
     928             :     //m_aAxisProperties might get updated and changed here because
     929             :     //    the label alignmant and inner direction sign depends exactly of the choice of the axis line position which is made here in this method
     930             : 
     931       13344 :     double fMinX = m_pPosHelper->getLogicMinX();
     932       13344 :     double fMinY = m_pPosHelper->getLogicMinY();
     933       13344 :     double fMinZ = m_pPosHelper->getLogicMinZ();
     934       13344 :     double fMaxX = m_pPosHelper->getLogicMaxX();
     935       13344 :     double fMaxY = m_pPosHelper->getLogicMaxY();
     936       13344 :     double fMaxZ = m_pPosHelper->getLogicMaxZ();
     937             : 
     938       13344 :     double fXStart = fMinX;
     939       13344 :     double fYStart = fMinY;
     940       13344 :     double fZStart = fMinZ;
     941       13344 :     double fXEnd = fXStart;
     942       13344 :     double fYEnd = fYStart;
     943       13344 :     double fZEnd = fZStart;
     944             : 
     945       13344 :     double fXOnXPlane = fMinX;
     946       13344 :     double fXOther = fMaxX;
     947       13344 :     int nDifferentValue = !m_pPosHelper->isMathematicalOrientationX() ? -1 : 1;
     948       13344 :     if( !m_pPosHelper->isSwapXAndY() )
     949       12756 :         nDifferentValue *= (CuboidPlanePosition_Left != m_eLeftWallPos) ? -1 : 1;
     950             :     else
     951         588 :         nDifferentValue *= (CuboidPlanePosition_Bottom != m_eBottomPos) ? -1 : 1;
     952       13344 :     if( nDifferentValue<0 )
     953             :     {
     954           0 :         fXOnXPlane = fMaxX;
     955           0 :         fXOther = fMinX;
     956             :     }
     957             : 
     958       13344 :     double fYOnYPlane = fMinY;
     959       13344 :     double fYOther = fMaxY;
     960       13344 :     nDifferentValue = !m_pPosHelper->isMathematicalOrientationY() ? -1 : 1;
     961       13344 :     if( !m_pPosHelper->isSwapXAndY() )
     962       12756 :         nDifferentValue *= (CuboidPlanePosition_Bottom != m_eBottomPos) ? -1 : 1;
     963             :     else
     964         588 :         nDifferentValue *= (CuboidPlanePosition_Left != m_eLeftWallPos) ? -1 : 1;
     965       13344 :     if( nDifferentValue<0 )
     966             :     {
     967         239 :         fYOnYPlane = fMaxY;
     968         239 :         fYOther = fMinY;
     969             :     }
     970             : 
     971       13344 :     double fZOnZPlane = fMaxZ;
     972       13344 :     double fZOther = fMinZ;
     973       13344 :     nDifferentValue = !m_pPosHelper->isMathematicalOrientationZ() ? -1 : 1;
     974       13344 :     nDifferentValue *= (CuboidPlanePosition_Back != m_eBackWallPos) ? -1 : 1;
     975       13344 :     if( nDifferentValue<0 )
     976             :     {
     977           0 :         fZOnZPlane = fMinZ;
     978           0 :         fZOther = fMaxZ;
     979             :     }
     980             : 
     981       13344 :     if( 0==m_nDimensionIndex ) //x-axis
     982             :     {
     983        6804 :         if( fCrossesOtherAxis < fMinY )
     984        1157 :             fCrossesOtherAxis = fMinY;
     985        5647 :         else if( fCrossesOtherAxis > fMaxY )
     986           0 :             fCrossesOtherAxis = fMaxY;
     987             : 
     988        6804 :         fYStart = fYEnd = fCrossesOtherAxis;
     989        6804 :         fXEnd=m_pPosHelper->getLogicMaxX();
     990             : 
     991        6804 :         if(3==m_nDimension)
     992             :         {
     993         441 :             if( AxisHelper::isAxisPositioningEnabled() )
     994             :             {
     995         441 :                 if( ::rtl::math::approxEqual( fYOther, fYStart) )
     996           0 :                     fZStart = fZEnd = fZOnZPlane;
     997             :                 else
     998         441 :                     fZStart = fZEnd = fZOther;
     999             :             }
    1000             :             else
    1001             :             {
    1002           0 :                 rStart = getScreenPosition( fXStart, fYStart, fZStart );
    1003           0 :                 rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd );
    1004             : 
    1005           0 :                 double fDeltaX = rEnd.getX() - rStart.getX();
    1006           0 :                 double fDeltaY = rEnd.getY() - rStart.getY();
    1007             : 
    1008             :                 //only those points are candidates which are lying on exactly one wall as these are outer edges
    1009           0 :                 tScreenPosAndLogicPosList aPosList;
    1010           0 :                 aPosList.push_back( getScreenPosAndLogicPos( fMinX, fYOnYPlane, fZOther ) );
    1011           0 :                 aPosList.push_back( getScreenPosAndLogicPos( fMinX, fYOther, fZOnZPlane ) );
    1012             : 
    1013           0 :                 if( fabs(fDeltaY) > fabs(fDeltaX)  )
    1014             :                 {
    1015           0 :                     rAlignment.meAlignment = LABEL_ALIGN_LEFT;
    1016             :                     //choose most left positions
    1017           0 :                     ::std::sort( aPosList.begin(), aPosList.end(), lcl_LessXPos() );
    1018           0 :                     rAlignment.mfLabelDirection = (fDeltaY < 0) ? -1.0 : 1.0;
    1019             :                 }
    1020             :                 else
    1021             :                 {
    1022           0 :                     rAlignment.meAlignment = LABEL_ALIGN_BOTTOM;
    1023             :                     //choose most bottom positions
    1024           0 :                     ::std::sort( aPosList.begin(), aPosList.end(), lcl_GreaterYPos() );
    1025           0 :                     rAlignment.mfLabelDirection = (fDeltaX < 0) ? -1.0 : 1.0;
    1026             :                 }
    1027           0 :                 ScreenPosAndLogicPos aBestPos( aPosList[0] );
    1028           0 :                 fYStart = fYEnd = aBestPos.fLogicY;
    1029           0 :                 fZStart = fZEnd = aBestPos.fLogicZ;
    1030           0 :                 if( !m_pPosHelper->isMathematicalOrientationX() )
    1031           0 :                     rAlignment.mfLabelDirection *= -1.0;
    1032             :             }
    1033             :         }//end 3D x axis
    1034             :     }
    1035        6540 :     else if( 1==m_nDimensionIndex ) //y-axis
    1036             :     {
    1037        6232 :         if( fCrossesOtherAxis < fMinX )
    1038        5252 :             fCrossesOtherAxis = fMinX;
    1039         980 :         else if( fCrossesOtherAxis > fMaxX )
    1040           0 :             fCrossesOtherAxis = fMaxX;
    1041             : 
    1042        6232 :         fXStart = fXEnd = fCrossesOtherAxis;
    1043        6232 :         fYEnd=m_pPosHelper->getLogicMaxY();
    1044             : 
    1045        6232 :         if(3==m_nDimension)
    1046             :         {
    1047         459 :             if( AxisHelper::isAxisPositioningEnabled() )
    1048             :             {
    1049         459 :                 if( ::rtl::math::approxEqual( fXOther, fXStart) )
    1050           0 :                     fZStart = fZEnd = fZOnZPlane;
    1051             :                 else
    1052         459 :                     fZStart = fZEnd = fZOther;
    1053             :             }
    1054             :             else
    1055             :             {
    1056           0 :                 rStart = getScreenPosition( fXStart, fYStart, fZStart );
    1057           0 :                 rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd );
    1058             : 
    1059           0 :                 double fDeltaX = rEnd.getX() - rStart.getX();
    1060           0 :                 double fDeltaY = rEnd.getY() - rStart.getY();
    1061             : 
    1062             :                 //only those points are candidates which are lying on exactly one wall as these are outer edges
    1063           0 :                 tScreenPosAndLogicPosList aPosList;
    1064           0 :                 aPosList.push_back( getScreenPosAndLogicPos( fXOnXPlane, fMinY, fZOther ) );
    1065           0 :                 aPosList.push_back( getScreenPosAndLogicPos( fXOther, fMinY, fZOnZPlane ) );
    1066             : 
    1067           0 :                 if( fabs(fDeltaY) > fabs(fDeltaX)  )
    1068             :                 {
    1069           0 :                     rAlignment.meAlignment = LABEL_ALIGN_LEFT;
    1070             :                     //choose most left positions
    1071           0 :                     ::std::sort( aPosList.begin(), aPosList.end(), lcl_LessXPos() );
    1072           0 :                     rAlignment.mfLabelDirection = (fDeltaY < 0) ? -1.0 : 1.0;
    1073             :                 }
    1074             :                 else
    1075             :                 {
    1076           0 :                     rAlignment.meAlignment = LABEL_ALIGN_BOTTOM;
    1077             :                     //choose most bottom positions
    1078           0 :                     ::std::sort( aPosList.begin(), aPosList.end(), lcl_GreaterYPos() );
    1079           0 :                     rAlignment.mfLabelDirection = (fDeltaX < 0) ? -1.0 : 1.0;
    1080             :                 }
    1081           0 :                 ScreenPosAndLogicPos aBestPos( aPosList[0] );
    1082           0 :                 fXStart = fXEnd = aBestPos.fLogicX;
    1083           0 :                 fZStart = fZEnd = aBestPos.fLogicZ;
    1084           0 :                 if( !m_pPosHelper->isMathematicalOrientationY() )
    1085           0 :                     rAlignment.mfLabelDirection *= -1.0;
    1086             :             }
    1087             :         }//end 3D y axis
    1088             :     }
    1089             :     else //z-axis
    1090             :     {
    1091         308 :         fZEnd = m_pPosHelper->getLogicMaxZ();
    1092         308 :         if( AxisHelper::isAxisPositioningEnabled() )
    1093             :         {
    1094         308 :             if( !m_aAxisProperties.m_bSwapXAndY )
    1095             :             {
    1096         214 :                 if( fCrossesOtherAxis < fMinY )
    1097          12 :                     fCrossesOtherAxis = fMinY;
    1098         202 :                 else if( fCrossesOtherAxis > fMaxY )
    1099           0 :                     fCrossesOtherAxis = fMaxY;
    1100         214 :                 fYStart = fYEnd = fCrossesOtherAxis;
    1101             : 
    1102         214 :                 if( ::rtl::math::approxEqual( fYOther, fYStart) )
    1103           0 :                     fXStart = fXEnd = fXOnXPlane;
    1104             :                 else
    1105         214 :                     fXStart = fXEnd = fXOther;
    1106             :             }
    1107             :             else
    1108             :             {
    1109          94 :                 if( fCrossesOtherAxis < fMinX )
    1110          94 :                     fCrossesOtherAxis = fMinX;
    1111           0 :                 else if( fCrossesOtherAxis > fMaxX )
    1112           0 :                     fCrossesOtherAxis = fMaxX;
    1113          94 :                 fXStart = fXEnd = fCrossesOtherAxis;
    1114             : 
    1115          94 :                 if( ::rtl::math::approxEqual( fXOther, fXStart) )
    1116           0 :                     fYStart = fYEnd = fYOnYPlane;
    1117             :                 else
    1118          94 :                     fYStart = fYEnd = fYOther;
    1119             :             }
    1120             :         }
    1121             :         else
    1122             :         {
    1123           0 :             if( !m_pPosHelper->isSwapXAndY() )
    1124             :             {
    1125           0 :                 fXStart = fXEnd = m_pPosHelper->isMathematicalOrientationX() ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMinX();
    1126           0 :                 fYStart = fYEnd = m_pPosHelper->isMathematicalOrientationY() ? m_pPosHelper->getLogicMinY() : m_pPosHelper->getLogicMaxY();
    1127             :             }
    1128             :             else
    1129             :             {
    1130           0 :                 fXStart = fXEnd = m_pPosHelper->isMathematicalOrientationX() ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMaxX();
    1131           0 :                 fYStart = fYEnd = m_pPosHelper->isMathematicalOrientationY() ? m_pPosHelper->getLogicMaxY() : m_pPosHelper->getLogicMinY();
    1132             :             }
    1133             : 
    1134           0 :             if(3==m_nDimension)
    1135             :             {
    1136           0 :                 rStart = getScreenPosition( fXStart, fYStart, fZStart );
    1137           0 :                 rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd );
    1138             : 
    1139           0 :                 double fDeltaX = rEnd.getX() - rStart.getX();
    1140             : 
    1141             :                 //only those points are candidates which are lying on exactly one wall as these are outer edges
    1142           0 :                 tScreenPosAndLogicPosList aPosList;
    1143           0 :                 aPosList.push_back( getScreenPosAndLogicPos( fXOther, fYOnYPlane, fMinZ ) );
    1144           0 :                 aPosList.push_back( getScreenPosAndLogicPos( fXOnXPlane, fYOther, fMinZ ) );
    1145             : 
    1146           0 :                 ::std::sort( aPosList.begin(), aPosList.end(), lcl_GreaterYPos() );
    1147           0 :                 ScreenPosAndLogicPos aBestPos( aPosList[0] );
    1148           0 :                 ScreenPosAndLogicPos aNotSoGoodPos( aPosList[1] );
    1149             : 
    1150             :                 //choose most bottom positions
    1151           0 :                 if( !::rtl::math::approxEqual( fDeltaX, 0.0 ) ) // prefer left-right alignments
    1152             :                 {
    1153           0 :                     if( aBestPos.aScreenPos.getX() > aNotSoGoodPos.aScreenPos.getX() )
    1154           0 :                         rAlignment.meAlignment = LABEL_ALIGN_RIGHT;
    1155             :                     else
    1156           0 :                          rAlignment.meAlignment = LABEL_ALIGN_LEFT;
    1157             :                 }
    1158             :                 else
    1159             :                 {
    1160           0 :                     if( aBestPos.aScreenPos.getY() > aNotSoGoodPos.aScreenPos.getY() )
    1161           0 :                         rAlignment.meAlignment = LABEL_ALIGN_BOTTOM;
    1162             :                     else
    1163           0 :                         rAlignment.meAlignment = LABEL_ALIGN_TOP;
    1164             :                 }
    1165             : 
    1166           0 :                 rAlignment.mfLabelDirection = (fDeltaX < 0) ? -1.0 : 1.0;
    1167           0 :                 if( !m_pPosHelper->isMathematicalOrientationZ() )
    1168           0 :                     rAlignment.mfLabelDirection *= -1.0;
    1169             : 
    1170           0 :                 fXStart = fXEnd = aBestPos.fLogicX;
    1171           0 :                 fYStart = fYEnd = aBestPos.fLogicY;
    1172             :             }
    1173             :         }//end 3D z axis
    1174             :     }
    1175             : 
    1176       13344 :     rStart = getScreenPosition( fXStart, fYStart, fZStart );
    1177       13344 :     rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd );
    1178             : 
    1179       13344 :     if(3==m_nDimension && !AxisHelper::isAxisPositioningEnabled() )
    1180           0 :         rAlignment.mfInnerTickDirection = rAlignment.mfLabelDirection;//to behave like before
    1181             : 
    1182       13344 :     if(3==m_nDimension && AxisHelper::isAxisPositioningEnabled() )
    1183             :     {
    1184        1208 :         double fDeltaX = rEnd.getX() - rStart.getX();
    1185        1208 :         double fDeltaY = rEnd.getY() - rStart.getY();
    1186             : 
    1187        1208 :         if( 2==m_nDimensionIndex )
    1188             :         {
    1189         308 :             if( m_eLeftWallPos != CuboidPlanePosition_Left )
    1190             :             {
    1191           0 :                 rAlignment.mfLabelDirection *= -1.0;
    1192           0 :                 rAlignment.mfInnerTickDirection *= -1.0;
    1193             :             }
    1194             : 
    1195             :             rAlignment.meAlignment =
    1196         308 :                 (rAlignment.mfLabelDirection < 0) ?
    1197         308 :                     LABEL_ALIGN_LEFT :  LABEL_ALIGN_RIGHT;
    1198             : 
    1199         308 :             if( ( fDeltaY<0 && m_aScale.Orientation == chart2::AxisOrientation_REVERSE ) ||
    1200           0 :                 ( fDeltaY>0 && m_aScale.Orientation == chart2::AxisOrientation_MATHEMATICAL ) )
    1201             :                 rAlignment.meAlignment =
    1202           0 :                     (rAlignment.meAlignment == LABEL_ALIGN_RIGHT) ?
    1203           0 :                         LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT;
    1204             :         }
    1205         900 :         else if( fabs(fDeltaY) > fabs(fDeltaX) )
    1206             :         {
    1207         459 :             if( m_eBackWallPos != CuboidPlanePosition_Back )
    1208             :             {
    1209           0 :                 rAlignment.mfLabelDirection *= -1.0;
    1210           0 :                 rAlignment.mfInnerTickDirection *= -1.0;
    1211             :             }
    1212             : 
    1213             :             rAlignment.meAlignment =
    1214         459 :                 (rAlignment.mfLabelDirection < 0) ?
    1215         459 :                     LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT;
    1216             : 
    1217         459 :             if( ( fDeltaY<0 && m_aScale.Orientation == chart2::AxisOrientation_REVERSE ) ||
    1218           0 :                 ( fDeltaY>0 && m_aScale.Orientation == chart2::AxisOrientation_MATHEMATICAL ) )
    1219             :                 rAlignment.meAlignment =
    1220           0 :                     (rAlignment.meAlignment == LABEL_ALIGN_RIGHT) ?
    1221           0 :                         LABEL_ALIGN_LEFT :  LABEL_ALIGN_RIGHT;
    1222             :         }
    1223             :         else
    1224             :         {
    1225         441 :             if( m_eBackWallPos != CuboidPlanePosition_Back )
    1226             :             {
    1227           0 :                 rAlignment.mfLabelDirection *= -1.0;
    1228           0 :                 rAlignment.mfInnerTickDirection *= -1.0;
    1229             :             }
    1230             : 
    1231             :             rAlignment.meAlignment =
    1232         441 :                 (rAlignment.mfLabelDirection < 0) ?
    1233         441 :                     LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM;
    1234             : 
    1235         441 :             if( ( fDeltaX>0 && m_aScale.Orientation == chart2::AxisOrientation_REVERSE ) ||
    1236           0 :                 ( fDeltaX<0 && m_aScale.Orientation == chart2::AxisOrientation_MATHEMATICAL ) )
    1237             :                 rAlignment.meAlignment =
    1238           0 :                     (rAlignment.meAlignment == LABEL_ALIGN_TOP) ?
    1239           0 :                         LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP;
    1240             :         }
    1241             :     }
    1242       13344 : }
    1243             : 
    1244        2132 : TickFactory* VCartesianAxis::createTickFactory()
    1245             : {
    1246        2132 :     return createTickFactory2D();
    1247             : }
    1248             : 
    1249        6178 : TickFactory2D* VCartesianAxis::createTickFactory2D()
    1250             : {
    1251        6178 :     AxisLabelAlignment aLabelAlign = m_aAxisProperties.maLabelAlignment;
    1252       12356 :     B2DVector aStart, aEnd;
    1253        6178 :     get2DAxisMainLine(aStart, aEnd, aLabelAlign, getAxisIntersectionValue());
    1254             : 
    1255       12356 :     B2DVector aLabelLineStart, aLabelLineEnd;
    1256        6178 :     get2DAxisMainLine(aLabelLineStart, aLabelLineEnd, aLabelAlign, getLabelLineIntersectionValue());
    1257        6178 :     m_aAxisProperties.maLabelAlignment = aLabelAlign;
    1258             : 
    1259       12356 :     return new TickFactory2D( m_aScale, m_aIncrement, aStart, aEnd, aLabelLineStart-aStart );
    1260             : }
    1261             : 
    1262        1371 : void lcl_hideIdenticalScreenValues( TickIter& rTickIter )
    1263             : {
    1264        1371 :     TickInfo* pPrevTickInfo = rTickIter.firstInfo();
    1265        1371 :     if (!pPrevTickInfo)
    1266        1371 :         return;
    1267             : 
    1268        1371 :     pPrevTickInfo->bPaintIt = true;
    1269       16258 :     for( TickInfo* pTickInfo = rTickIter.nextInfo(); pTickInfo; pTickInfo = rTickIter.nextInfo())
    1270             :     {
    1271       14887 :         pTickInfo->bPaintIt = (pTickInfo->aTickScreenPosition != pPrevTickInfo->aTickScreenPosition);
    1272       14887 :         pPrevTickInfo = pTickInfo;
    1273             :     }
    1274             : }
    1275             : 
    1276             : //'hide' tickmarks with identical screen values in aAllTickInfos
    1277        1371 : void VCartesianAxis::hideIdenticalScreenValues( TickInfoArraysType& rTickInfos ) const
    1278             : {
    1279        1371 :     if( isComplexCategoryAxis() || isDateAxis() )
    1280             :     {
    1281           0 :         sal_Int32 nCount = rTickInfos.size();
    1282           0 :         for( sal_Int32 nN=0; nN<nCount; nN++ )
    1283             :         {
    1284           0 :             PureTickIter aTickIter( rTickInfos[nN] );
    1285           0 :             lcl_hideIdenticalScreenValues( aTickIter );
    1286           0 :         }
    1287             :     }
    1288             :     else
    1289             :     {
    1290        1371 :         EquidistantTickIter aTickIter( rTickInfos, m_aIncrement, 0, -1 );
    1291        1371 :         lcl_hideIdenticalScreenValues( aTickIter );
    1292             :     }
    1293        1371 : }
    1294             : 
    1295        2198 : sal_Int32 VCartesianAxis::estimateMaximumAutoMainIncrementCount()
    1296             : {
    1297        2198 :     sal_Int32 nRet = 10;
    1298             : 
    1299        2198 :     if( m_nMaximumTextWidthSoFar==0 && m_nMaximumTextHeightSoFar==0 )
    1300        1210 :         return nRet;
    1301             : 
    1302        1976 :     B2DVector aStart, aEnd;
    1303         988 :     AxisLabelAlignment aLabelAlign = m_aAxisProperties.maLabelAlignment;
    1304         988 :     get2DAxisMainLine(aStart, aEnd, aLabelAlign, getAxisIntersectionValue());
    1305         988 :     m_aAxisProperties.maLabelAlignment = aLabelAlign;
    1306             : 
    1307         988 :     sal_Int32 nMaxHeight = static_cast<sal_Int32>(fabs(aEnd.getY()-aStart.getY()));
    1308         988 :     sal_Int32 nMaxWidth = static_cast<sal_Int32>(fabs(aEnd.getX()-aStart.getX()));
    1309             : 
    1310         988 :     sal_Int32 nTotalAvailable = nMaxHeight;
    1311         988 :     sal_Int32 nSingleNeeded = m_nMaximumTextHeightSoFar;
    1312             : 
    1313             :     //for horizontal axis:
    1314         988 :     if( (m_nDimensionIndex == 0 && !m_aAxisProperties.m_bSwapXAndY)
    1315         487 :         || (m_nDimensionIndex == 1 && m_aAxisProperties.m_bSwapXAndY) )
    1316             :     {
    1317         520 :         nTotalAvailable = nMaxWidth;
    1318         520 :         nSingleNeeded = m_nMaximumTextWidthSoFar;
    1319             :     }
    1320             : 
    1321         988 :     if( nSingleNeeded>0 )
    1322         988 :         nRet = nTotalAvailable/nSingleNeeded;
    1323             : 
    1324        1976 :     return nRet;
    1325             : }
    1326             : 
    1327        2980 : void VCartesianAxis::doStaggeringOfLabels( const AxisLabelProperties& rAxisLabelProperties, TickFactory2D* pTickFactory2D )
    1328             : {
    1329        2980 :     if( !pTickFactory2D )
    1330        2980 :         return;
    1331             : 
    1332        2980 :     if( isComplexCategoryAxis() )
    1333             :     {
    1334           0 :         sal_Int32 nTextLevelCount = getTextLevelCount();
    1335           0 :         B2DVector aCummulatedLabelsDistance(0,0);
    1336           0 :         for( sal_Int32 nTextLevel=0; nTextLevel<nTextLevelCount; nTextLevel++ )
    1337             :         {
    1338           0 :             boost::scoped_ptr<TickIter> apTickIter(createLabelTickIterator(nTextLevel));
    1339           0 :             if (apTickIter)
    1340             :             {
    1341           0 :                 double fRotationAngleDegree = m_aAxisLabelProperties.fRotationAngleDegree;
    1342           0 :                 if( nTextLevel>0 )
    1343             :                 {
    1344           0 :                     lcl_shiftLabels( *apTickIter.get(), aCummulatedLabelsDistance );
    1345           0 :                     fRotationAngleDegree = 0.0;
    1346             :                 }
    1347           0 :                 aCummulatedLabelsDistance += lcl_getLabelsDistance( *apTickIter.get()
    1348             :                     , pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties )
    1349           0 :                     , fRotationAngleDegree );
    1350             :             }
    1351           0 :         }
    1352             :     }
    1353        2980 :     else if( rAxisLabelProperties.getIsStaggered() )
    1354             :     {
    1355         440 :         if( !m_aAllTickInfos.empty() )
    1356             :         {
    1357         431 :             LabelIterator aInnerIter( m_aAllTickInfos[0], rAxisLabelProperties.eStaggering, true );
    1358         862 :             LabelIterator aOuterIter( m_aAllTickInfos[0], rAxisLabelProperties.eStaggering, false );
    1359             : 
    1360             :             lcl_shiftLabels( aOuterIter
    1361             :                 , lcl_getLabelsDistance( aInnerIter
    1362         862 :                     , pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties ), 0.0 ) );
    1363             :         }
    1364             :     }
    1365             : }
    1366             : 
    1367        1095 : void VCartesianAxis::createLabels()
    1368             : {
    1369        1095 :     if( !prepareShapeCreation() )
    1370         138 :         return;
    1371             : 
    1372             :     //create labels
    1373        1066 :     if (!m_aAxisProperties.m_bDisplayLabels)
    1374          80 :         return;
    1375             : 
    1376         986 :     boost::scoped_ptr< TickFactory2D > apTickFactory2D( this->createTickFactory2D() );
    1377         986 :     TickFactory2D* pTickFactory2D = apTickFactory2D.get();
    1378         986 :     if( !pTickFactory2D )
    1379           0 :         return;
    1380             : 
    1381             :     //get the transformed screen values for all tickmarks in aAllTickInfos
    1382         986 :     pTickFactory2D->updateScreenValues( m_aAllTickInfos );
    1383             :     //'hide' tickmarks with identical screen values in aAllTickInfos
    1384         986 :     hideIdenticalScreenValues( m_aAllTickInfos );
    1385             : 
    1386         986 :     removeTextShapesFromTicks();
    1387             : 
    1388             :     //create tick mark text shapes
    1389         986 :     sal_Int32 nTextLevelCount = getTextLevelCount();
    1390         986 :     sal_Int32 nScreenDistanceBetweenTicks = -1;
    1391        1972 :     for( sal_Int32 nTextLevel=0; nTextLevel<nTextLevelCount; nTextLevel++ )
    1392             :     {
    1393         986 :         boost::scoped_ptr< TickIter > apTickIter(createLabelTickIterator( nTextLevel ));
    1394         986 :         if(apTickIter)
    1395             :         {
    1396         986 :             if(nTextLevel==0)
    1397             :             {
    1398         986 :                 nScreenDistanceBetweenTicks = TickFactory2D::getTickScreenDistance( *apTickIter.get() );
    1399         986 :                 if( nTextLevelCount>1 )
    1400           0 :                     nScreenDistanceBetweenTicks*=2; //the above used tick iter does contain also the sub ticks -> thus the given distance is only the half
    1401             :             }
    1402             : 
    1403         986 :             AxisLabelProperties aComplexProps(m_aAxisLabelProperties);
    1404         986 :             if( m_aAxisProperties.m_bComplexCategories )
    1405             :             {
    1406           0 :                 aComplexProps.bLineBreakAllowed = true;
    1407           0 :                 aComplexProps.bOverlapAllowed = !::rtl::math::approxEqual( aComplexProps.fRotationAngleDegree, 0.0 );
    1408             : 
    1409             :             }
    1410         986 :             AxisLabelProperties& rAxisLabelProperties =  m_aAxisProperties.m_bComplexCategories ? aComplexProps : m_aAxisLabelProperties;
    1411         986 :             while( !createTextShapes( m_xTextTarget, *apTickIter.get(), rAxisLabelProperties, pTickFactory2D, nScreenDistanceBetweenTicks ) )
    1412             :             {
    1413             :             };
    1414             :         }
    1415         986 :     }
    1416         986 :     doStaggeringOfLabels( m_aAxisLabelProperties, pTickFactory2D );
    1417             : }
    1418             : 
    1419        1095 : void VCartesianAxis::createMaximumLabels()
    1420             : {
    1421        1095 :     TrueGuard aRecordMaximumTextSize(m_bRecordMaximumTextSize);
    1422             : 
    1423        1095 :     if( !prepareShapeCreation() )
    1424          29 :         return;
    1425             : 
    1426             :     //create labels
    1427        1066 :     if (!m_aAxisProperties.m_bDisplayLabels)
    1428          80 :         return;
    1429             : 
    1430        1972 :     boost::scoped_ptr< TickFactory2D > apTickFactory2D( this->createTickFactory2D() );
    1431         986 :     TickFactory2D* pTickFactory2D = apTickFactory2D.get();
    1432         986 :     if( !pTickFactory2D )
    1433           0 :         return;
    1434             : 
    1435             :     //get the transformed screen values for all tickmarks in aAllTickInfos
    1436         986 :     pTickFactory2D->updateScreenValues( m_aAllTickInfos );
    1437             : 
    1438             :     //create tick mark text shapes
    1439             :     //@todo: iterate through all tick depth which should be labeled
    1440             : 
    1441         986 :     AxisLabelProperties aAxisLabelProperties( m_aAxisLabelProperties );
    1442         986 :     if( isAutoStaggeringOfLabelsAllowed( aAxisLabelProperties, pTickFactory2D->isHorizontalAxis(), pTickFactory2D->isVerticalAxis() ) )
    1443         410 :         aAxisLabelProperties.eStaggering = STAGGER_EVEN;
    1444             : 
    1445         986 :     aAxisLabelProperties.bOverlapAllowed = true;
    1446         986 :     aAxisLabelProperties.bLineBreakAllowed = false;
    1447         986 :     sal_Int32 nTextLevelCount = getTextLevelCount();
    1448        1972 :     for( sal_Int32 nTextLevel=0; nTextLevel<nTextLevelCount; nTextLevel++ )
    1449             :     {
    1450         986 :         boost::scoped_ptr< TickIter > apTickIter(createMaximumLabelTickIterator( nTextLevel ));
    1451         986 :         if(apTickIter)
    1452             :         {
    1453         986 :             while( !createTextShapes( m_xTextTarget, *apTickIter.get(), aAxisLabelProperties, pTickFactory2D, -1 ) )
    1454             :             {
    1455             :             };
    1456             :         }
    1457         986 :     }
    1458        1972 :     doStaggeringOfLabels( aAxisLabelProperties, pTickFactory2D );
    1459             : }
    1460             : 
    1461        1095 : void VCartesianAxis::updatePositions()
    1462             : {
    1463             :     //update positions of labels
    1464        1095 :     if (!m_aAxisProperties.m_bDisplayLabels)
    1465         174 :         return;
    1466             : 
    1467        1008 :     boost::scoped_ptr< TickFactory2D > apTickFactory2D( this->createTickFactory2D() );
    1468        1008 :     TickFactory2D* pTickFactory2D = apTickFactory2D.get();
    1469        1008 :     if( !pTickFactory2D )
    1470           0 :         return;
    1471             : 
    1472             :     //update positions of all existing text shapes
    1473        1008 :     pTickFactory2D->updateScreenValues( m_aAllTickInfos );
    1474             : 
    1475        1008 :     TickInfoArraysType::iterator aDepthIter = m_aAllTickInfos.begin();
    1476        1008 :     const TickInfoArraysType::const_iterator aDepthEnd  = m_aAllTickInfos.end();
    1477        2980 :     for( sal_Int32 nDepth=0; aDepthIter != aDepthEnd; ++aDepthIter, nDepth++ )
    1478             :     {
    1479        1972 :         TickInfoArrayType::iterator aTickIter = aDepthIter->begin();
    1480        1972 :         const TickInfoArrayType::const_iterator aTickEnd  = aDepthIter->end();
    1481       14757 :         for( ; aTickIter != aTickEnd; ++aTickIter )
    1482             :         {
    1483       12785 :             TickInfo& rTickInfo = (*aTickIter);
    1484       12785 :             Reference< drawing::XShape > xShape2DText( rTickInfo.xTextShape );
    1485       12785 :             if( xShape2DText.is() )
    1486             :             {
    1487        6284 :                 B2DVector aTextToTickDistance( pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties, true ) );
    1488       12568 :                 B2DVector aTickScreenPos2D( rTickInfo.aTickScreenPosition );
    1489        6284 :                 aTickScreenPos2D += aTextToTickDistance;
    1490             :                 awt::Point aAnchorScreenPosition2D(
    1491        6284 :                     static_cast<sal_Int32>(aTickScreenPos2D.getX())
    1492       12568 :                     ,static_cast<sal_Int32>(aTickScreenPos2D.getY()));
    1493             : 
    1494        6284 :                 double fRotationAngleDegree = m_aAxisLabelProperties.fRotationAngleDegree;
    1495        6284 :                 if( nDepth > 0 )
    1496             :                 {
    1497             :                     /* Multi-level Labels: default to 0 or 90 */
    1498           0 :                     if( pTickFactory2D->isHorizontalAxis() )
    1499           0 :                         fRotationAngleDegree = 0.0;
    1500             :                     else
    1501           0 :                         fRotationAngleDegree = 90;
    1502             :                 }
    1503             : 
    1504             :                 // #i78696# use mathematically correct rotation now
    1505        6284 :                 const double fRotationAnglePi(fRotationAngleDegree * (F_PI / -180.0));
    1506       12568 :                 uno::Any aATransformation = AbstractShapeFactory::makeTransformation(aAnchorScreenPosition2D, fRotationAnglePi);
    1507             : 
    1508             :                 //set new position
    1509       12568 :                 uno::Reference< beans::XPropertySet > xProp( xShape2DText, uno::UNO_QUERY );
    1510        6284 :                 if( xProp.is() )
    1511             :                 {
    1512             :                     try
    1513             :                     {
    1514        6284 :                         xProp->setPropertyValue( "Transformation", aATransformation );
    1515             :                     }
    1516           0 :                     catch( const uno::Exception& e )
    1517             :                     {
    1518             :                         ASSERT_EXCEPTION( e );
    1519             :                     }
    1520             :                 }
    1521             : 
    1522             :                 //correctPositionForRotation
    1523             :                 LabelPositionHelper::correctPositionForRotation( xShape2DText
    1524       12568 :                     , m_aAxisProperties.maLabelAlignment.meAlignment, fRotationAngleDegree, m_aAxisProperties.m_bComplexCategories );
    1525             :             }
    1526       12785 :         }
    1527             :     }
    1528             : 
    1529        1008 :     doStaggeringOfLabels( m_aAxisLabelProperties, pTickFactory2D );
    1530             : }
    1531             : 
    1532         993 : void VCartesianAxis::createTickMarkLineShapes( TickInfoArrayType& rTickInfos, const TickmarkProperties& rTickmarkProperties, TickFactory2D& rTickFactory2D, bool bOnlyAtLabels )
    1533             : {
    1534         993 :     sal_Int32 nPointCount = rTickInfos.size();
    1535         993 :     drawing::PointSequenceSequence aPoints(2*nPointCount);
    1536             : 
    1537         993 :     TickInfoArrayType::const_iterator       aTickIter = rTickInfos.begin();
    1538         993 :     const TickInfoArrayType::const_iterator aTickEnd  = rTickInfos.end();
    1539         993 :     sal_Int32 nN = 0;
    1540        7632 :     for( ; aTickIter != aTickEnd; ++aTickIter )
    1541             :     {
    1542        6639 :         if( !(*aTickIter).bPaintIt )
    1543           0 :             continue;
    1544             : 
    1545        6639 :         bool bTicksAtLabels = ( m_aAxisProperties.m_eTickmarkPos != ::com::sun::star::chart::ChartAxisMarkPosition_AT_AXIS );
    1546        6639 :         double fInnerDirectionSign = m_aAxisProperties.maLabelAlignment.mfInnerTickDirection;
    1547        6639 :         if( bTicksAtLabels && m_aAxisProperties.m_eLabelPos == ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END )
    1548           0 :             fInnerDirectionSign *= -1.0;
    1549        6639 :         bTicksAtLabels = bTicksAtLabels || bOnlyAtLabels;
    1550             :         //add ticks at labels:
    1551        6639 :         rTickFactory2D.addPointSequenceForTickLine( aPoints, nN++, (*aTickIter).fScaledTickValue
    1552       13278 :             , fInnerDirectionSign , rTickmarkProperties, bTicksAtLabels );
    1553             :         //add ticks at axis (without lables):
    1554        6639 :         if( !bOnlyAtLabels && m_aAxisProperties.m_eTickmarkPos == ::com::sun::star::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS )
    1555        5332 :             rTickFactory2D.addPointSequenceForTickLine( aPoints, nN++, (*aTickIter).fScaledTickValue
    1556       10664 :                 , m_aAxisProperties.maLabelAlignment.mfInnerTickDirection, rTickmarkProperties, !bTicksAtLabels );
    1557             :     }
    1558         993 :     aPoints.realloc(nN);
    1559             :     m_pShapeFactory->createLine2D( m_xGroupShape_Shapes, aPoints
    1560         993 :                                 , &rTickmarkProperties.aLineProperties );
    1561         993 : }
    1562             : 
    1563        1095 : void VCartesianAxis::createShapes()
    1564             : {
    1565        1095 :     if( !prepareShapeCreation() )
    1566          58 :         return;
    1567             : 
    1568        1066 :     boost::scoped_ptr< TickFactory2D > apTickFactory2D( this->createTickFactory2D() );
    1569        1066 :     TickFactory2D* pTickFactory2D = apTickFactory2D.get();
    1570        1066 :     if( !pTickFactory2D )
    1571           0 :         return;
    1572             : 
    1573             :     //create line shapes
    1574        1066 :     if(2==m_nDimension)
    1575             :     {
    1576             :         //create extra long ticks to separate complex categories (create them only there where the labels are)
    1577         961 :         if( isComplexCategoryAxis() )
    1578             :         {
    1579           0 :             TickInfoArraysType aComplexTickInfos;
    1580           0 :             createAllTickInfosFromComplexCategories( aComplexTickInfos, true );
    1581           0 :             pTickFactory2D->updateScreenValues( aComplexTickInfos );
    1582           0 :             hideIdenticalScreenValues( aComplexTickInfos );
    1583             : 
    1584           0 :             ::std::vector<TickmarkProperties> aTickmarkPropertiesList;
    1585             :             static bool bIncludeSpaceBetweenTickAndText = false;
    1586           0 :             sal_Int32 nOffset = static_cast<sal_Int32>(pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties, false, bIncludeSpaceBetweenTickAndText ).getLength());
    1587           0 :             sal_Int32 nTextLevelCount = getTextLevelCount();
    1588           0 :             for( sal_Int32 nTextLevel=0; nTextLevel<nTextLevelCount; nTextLevel++ )
    1589             :             {
    1590           0 :                 boost::scoped_ptr< TickIter > apTickIter(createLabelTickIterator( nTextLevel ));
    1591           0 :                 if( apTickIter )
    1592             :                 {
    1593           0 :                     double fRotationAngleDegree = m_aAxisLabelProperties.fRotationAngleDegree;
    1594           0 :                     B2DVector aLabelsDistance( lcl_getLabelsDistance( *apTickIter.get(), pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties, false ), fRotationAngleDegree ) );
    1595           0 :                     sal_Int32 nCurrentLength = static_cast<sal_Int32>(aLabelsDistance.getLength());
    1596           0 :                     aTickmarkPropertiesList.push_back( m_aAxisProperties.makeTickmarkPropertiesForComplexCategories( nOffset + nCurrentLength, 0, nTextLevel ) );
    1597           0 :                     nOffset += nCurrentLength;
    1598             :                 }
    1599           0 :             }
    1600             : 
    1601           0 :             sal_Int32 nTickmarkPropertiesCount = aTickmarkPropertiesList.size();
    1602           0 :             TickInfoArraysType::iterator aDepthIter             = aComplexTickInfos.begin();
    1603           0 :             const TickInfoArraysType::const_iterator aDepthEnd  = aComplexTickInfos.end();
    1604           0 :             for( sal_Int32 nDepth=0; aDepthIter != aDepthEnd && nDepth < nTickmarkPropertiesCount; ++aDepthIter, nDepth++ )
    1605             :             {
    1606           0 :                 if(nDepth==0 && !m_aAxisProperties.m_nMajorTickmarks)
    1607           0 :                     continue;
    1608           0 :                 createTickMarkLineShapes( *aDepthIter, aTickmarkPropertiesList[nDepth], *pTickFactory2D, true /*bOnlyAtLabels*/ );
    1609           0 :             }
    1610             :         }
    1611             :         //create normal ticks for major and minor intervals
    1612             :         {
    1613         961 :             TickInfoArraysType aUnshiftedTickInfos;
    1614         961 :             if( m_aScale.ShiftedCategoryPosition )// if ShiftedCategoryPosition==true the tickmarks in m_aAllTickInfos are shifted
    1615             :             {
    1616         385 :                 pTickFactory2D->getAllTicks( aUnshiftedTickInfos );
    1617         385 :                 pTickFactory2D->updateScreenValues( aUnshiftedTickInfos );
    1618         385 :                 hideIdenticalScreenValues( aUnshiftedTickInfos );
    1619             :             }
    1620         961 :             TickInfoArraysType& rAllTickInfos = m_aScale.ShiftedCategoryPosition ? aUnshiftedTickInfos : m_aAllTickInfos;
    1621             : 
    1622         961 :             TickInfoArraysType::iterator aDepthIter             = rAllTickInfos.begin();
    1623         961 :             const TickInfoArraysType::const_iterator aDepthEnd  = rAllTickInfos.end();
    1624         961 :             if(aDepthIter == aDepthEnd)//no tickmarks at all
    1625           0 :                 return;
    1626             : 
    1627         961 :             sal_Int32 nTickmarkPropertiesCount = m_aAxisProperties.m_aTickmarkPropertiesList.size();
    1628        1954 :             for( sal_Int32 nDepth=0; aDepthIter != aDepthEnd && nDepth < nTickmarkPropertiesCount; ++aDepthIter, nDepth++ )
    1629        1954 :                 createTickMarkLineShapes( *aDepthIter, m_aAxisProperties.m_aTickmarkPropertiesList[nDepth], *pTickFactory2D, false /*bOnlyAtLabels*/ );
    1630             :         }
    1631             :         //create axis main lines
    1632             :         //it serves also as the handle shape for the axis selection
    1633             :         {
    1634         961 :             drawing::PointSequenceSequence aPoints(1);
    1635         961 :             apTickFactory2D->createPointSequenceForAxisMainLine( aPoints );
    1636             :             Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D(
    1637             :                     m_xGroupShape_Shapes, aPoints
    1638        1922 :                     , &m_aAxisProperties.m_aLineProperties );
    1639             :             //because of this name this line will be used for marking the axis
    1640        1922 :             ::chart::AbstractShapeFactory::setShapeName( xShape, "MarkHandles" );
    1641             :         }
    1642             :         //create an additional line at NULL
    1643         961 :         if( !AxisHelper::isAxisPositioningEnabled() )
    1644             :         {
    1645           0 :             double fExtraLineCrossesOtherAxis = getExtraLineIntersectionValue();
    1646           0 :             if (!rtl::math::isNan(fExtraLineCrossesOtherAxis))
    1647             :             {
    1648           0 :                 B2DVector aStart, aEnd;
    1649           0 :                 AxisLabelAlignment aLabelAlign = m_aAxisProperties.maLabelAlignment;
    1650           0 :                 get2DAxisMainLine(aStart, aEnd, aLabelAlign, fExtraLineCrossesOtherAxis);
    1651           0 :                 m_aAxisProperties.maLabelAlignment = aLabelAlign;
    1652           0 :                 drawing::PointSequenceSequence aPoints( lcl_makePointSequence(aStart,aEnd) );
    1653             :                 Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D(
    1654           0 :                         m_xGroupShape_Shapes, aPoints, &m_aAxisProperties.m_aLineProperties );
    1655             :             }
    1656             :         }
    1657        1066 :     }
    1658             : 
    1659             :     //createLabels();
    1660             : }
    1661             : 
    1662         108 : } //namespace chart
    1663             : 
    1664             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10