LCOV - code coverage report
Current view: top level - chart2/source/view/axes - VCartesianAxis.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 646 972 66.5 %
Date: 2015-06-13 12:38:46 Functions: 46 54 85.2 %
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        2131 : VCartesianAxis::VCartesianAxis( const AxisProperties& rAxisProperties
      61             :             , const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier
      62             :             , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount
      63             :             , PlottingPositionHelper* pPosHelper )//takes ownership
      64        2131 :             : VAxisBase( nDimensionIndex, nDimensionCount, rAxisProperties, xNumberFormatsSupplier )
      65             : {
      66        2131 :     if( pPosHelper )
      67          12 :         m_pPosHelper = pPosHelper;
      68             :     else
      69        2119 :         m_pPosHelper = new PlottingPositionHelper();
      70        2131 : }
      71             : 
      72        6299 : VCartesianAxis::~VCartesianAxis()
      73             : {
      74        2103 :     delete m_pPosHelper;
      75        2103 :     m_pPosHelper = NULL;
      76        4196 : }
      77             : 
      78       16259 : 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       16259 :     if(rLabel.isEmpty())
      90          44 :         return 0;
      91             : 
      92             :     // #i78696# use mathematically correct rotation now
      93       16215 :     const double fRotationAnglePi(rAxisLabelProperties.fRotationAngleDegree * (F_PI / -180.0));
      94       16215 :     uno::Any aATransformation = AbstractShapeFactory::makeTransformation( rAnchorScreenPosition2D, fRotationAnglePi );
      95       32430 :     OUString aLabel = AbstractShapeFactory::getStackedString( rLabel, rAxisLabelProperties.bStackCharacters );
      96             : 
      97       32430 :     Reference< drawing::XShape > xShape2DText = AbstractShapeFactory::getOrCreateShapeFactory(xShapeFactory)
      98       32430 :                     ->createText( xTarget, aLabel, rPropNames, rPropValues, aATransformation );
      99             : 
     100             :     LabelPositionHelper::correctPositionForRotation( xShape2DText
     101       16215 :         , rAxisProperties.maLabelAlignment.meAlignment, rAxisLabelProperties.fRotationAngleDegree, rAxisProperties.m_bComplexCategories );
     102             : 
     103       32430 :     return xShape2DText;
     104             : }
     105             : 
     106        8779 : bool lcl_doesShapeOverlapWithTickmark( const Reference< drawing::XShape >& xShape
     107             :                        , double fRotationAngleDegree
     108             :                        , const basegfx::B2DVector& rTickScreenPosition
     109             :                        , bool bIsHorizontalAxis, bool bIsVerticalAxis )
     110             : {
     111        8779 :     if(!xShape.is())
     112           0 :         return false;
     113             : 
     114        8779 :     ::basegfx::B2IRectangle aShapeRect = BaseGFXHelper::makeRectangle(xShape->getPosition(),AbstractShapeFactory::getSizeAfterRotation( xShape, fRotationAngleDegree ));
     115             : 
     116        8779 :     if( bIsVerticalAxis )
     117             :     {
     118        4982 :         return ( (rTickScreenPosition.getY() >= aShapeRect.getMinY())
     119        4982 :             && (rTickScreenPosition.getY() <= aShapeRect.getMaxY()) );
     120             :     }
     121        3797 :     if( bIsHorizontalAxis )
     122             :     {
     123        3566 :         return ( (rTickScreenPosition.getX() >= aShapeRect.getMinX())
     124        3566 :             && (rTickScreenPosition.getX() <= aShapeRect.getMaxX()) );
     125             :     }
     126             : 
     127             :     basegfx::B2IVector aPosition(
     128         231 :         static_cast<sal_Int32>( rTickScreenPosition.getX() )
     129         462 :         , static_cast<sal_Int32>( rTickScreenPosition.getY() ) );
     130         231 :     return aShapeRect.isInside(aPosition);
     131             : }
     132             : 
     133       17526 : void lcl_getRotatedPolygon( B2DPolygon &aPoly, const ::basegfx::B2DRectangle &aRect, const awt::Point &aPos, const double fRotationAngleDegree )
     134             : {
     135       17526 :     aPoly = basegfx::tools::createPolygonFromRect( aRect );
     136             : 
     137             :     // For rotating the rectangle we use the opposite angle,
     138             :     // since `B2DHomMatrix` class used for
     139             :     // representing the transformation, performs rotations in the positive
     140             :     // direction (from the X axis to the Y axis). However since the coordinate
     141             :     // system used by the chart has the Y-axis pointing downward, a rotation in
     142             :     // the positive direction means a clockwise rotation. On the contrary text
     143             :     // labels are rotated counterclockwise.
     144             :     // The rotation is performed around the top-left vertex of the rectangle
     145             :     // which is then moved to its final position by using the top-left
     146             :     // vertex of the text label bounding box (aPos) as the translation vector.
     147       17526 :     ::basegfx::B2DHomMatrix aMatrix;
     148       17526 :     aMatrix.rotate( -fRotationAngleDegree*M_PI/180.0 );
     149       17526 :     aMatrix.translate( aPos.X, aPos.Y);
     150       17526 :     aPoly.transform( aMatrix );
     151       17526 : }
     152             : 
     153        8763 : bool doesOverlap( const Reference< drawing::XShape >& xShape1
     154             :                 , const Reference< drawing::XShape >& xShape2
     155             :                 , double fRotationAngleDegree )
     156             : {
     157        8763 :     if( !xShape1.is() || !xShape2.is() )
     158           0 :         return false;
     159             : 
     160        8763 :     ::basegfx::B2DRectangle aRect1( BaseGFXHelper::makeRectangle( awt::Point(0,0), xShape1->getSize()));
     161        8763 :     ::basegfx::B2DRectangle aRect2( BaseGFXHelper::makeRectangle( awt::Point(0,0), xShape2->getSize()));
     162             : 
     163        8763 :     B2DPolygon aPoly1;
     164       17526 :     B2DPolygon aPoly2;
     165        8763 :     lcl_getRotatedPolygon( aPoly1, aRect1, xShape1->getPosition(), fRotationAngleDegree );
     166        8763 :     lcl_getRotatedPolygon( aPoly2, aRect2, xShape2->getPosition(), fRotationAngleDegree );
     167             : 
     168       17526 :     B2DPolyPolygon aPolyPoly1, aPolyPoly2;
     169        8763 :     aPolyPoly1.append( aPoly1 );
     170        8763 :     aPolyPoly2.append( aPoly2 );
     171       17526 :     B2DPolyPolygon overlapPoly = ::basegfx::tools::clipPolyPolygonOnPolyPolygon( aPolyPoly1, aPolyPoly2, true, false );
     172             : 
     173       17526 :     return (overlapPoly.count() > 0);
     174             : }
     175             : 
     176          62 : void removeShapesAtWrongRhythm( TickIter& rIter
     177             :                               , sal_Int32 nCorrectRhythm
     178             :                               , sal_Int32 nMaxTickToCheck
     179             :                               , const Reference< drawing::XShapes >& xTarget )
     180             : {
     181          62 :     sal_Int32 nTick = 0;
     182         257 :     for( TickInfo* pTickInfo = rIter.firstInfo()
     183         232 :         ; pTickInfo && nTick <= nMaxTickToCheck
     184         195 :         ; pTickInfo = rIter.nextInfo(), nTick++ )
     185             :     {
     186             :         //remove labels which does not fit into the rhythm
     187         195 :         if( nTick%nCorrectRhythm != 0)
     188             :         {
     189         123 :             if(pTickInfo->xTextShape.is())
     190             :             {
     191          56 :                 xTarget->remove(pTickInfo->xTextShape);
     192          56 :                 pTickInfo->xTextShape = NULL;
     193             :             }
     194             :         }
     195             :     }
     196          62 : }
     197             : 
     198             : /**
     199             :  * If the labels are staggered and bInnerLine is true we iterate through
     200             :  * only those labels that are closer to the diagram.
     201             :  *
     202             :  * If the labels are staggered and bInnerLine is false we iterate through
     203             :  * only those that are farther from the diagram.
     204             :  *
     205             :  * If the labels are not staggered we iterate through all labels.
     206             :  */
     207        1738 : class LabelIterator : public TickIter
     208             : {
     209             : public:
     210             :     LabelIterator( TickInfoArrayType& rTickInfoVector
     211             :             , const AxisLabelStaggering eAxisLabelStaggering
     212             :             , bool bInnerLine );
     213             : 
     214             :     virtual TickInfo*   firstInfo() SAL_OVERRIDE;
     215             :     virtual TickInfo*   nextInfo() SAL_OVERRIDE;
     216             : 
     217             : private: //member
     218             :     PureTickIter m_aPureTickIter;
     219             :     const AxisLabelStaggering   m_eAxisLabelStaggering;
     220             :     bool m_bInnerLine;
     221             : };
     222             : 
     223        1738 : LabelIterator::LabelIterator( TickInfoArrayType& rTickInfoVector
     224             :             , const AxisLabelStaggering eAxisLabelStaggering
     225             :             , bool bInnerLine )
     226             :             : m_aPureTickIter( rTickInfoVector )
     227             :             , m_eAxisLabelStaggering(eAxisLabelStaggering)
     228        1738 :             , m_bInnerLine(bInnerLine)
     229             : {
     230        1738 : }
     231             : 
     232        1733 : TickInfo* LabelIterator::firstInfo()
     233             : {
     234        1733 :     TickInfo* pTickInfo = m_aPureTickIter.firstInfo();
     235        3519 :     while( pTickInfo && !pTickInfo->xTextShape.is() )
     236          53 :         pTickInfo = m_aPureTickIter.nextInfo();
     237        1733 :     if(!pTickInfo)
     238           3 :         return NULL;
     239        1730 :     if( (STAGGER_EVEN==m_eAxisLabelStaggering && m_bInnerLine)
     240         864 :         ||
     241         864 :         (STAGGER_ODD==m_eAxisLabelStaggering && !m_bInnerLine)
     242             :         )
     243             :     {
     244             :         //skip first label
     245         886 :         do
     246         886 :             pTickInfo = m_aPureTickIter.nextInfo();
     247         886 :         while( pTickInfo && !pTickInfo->xTextShape.is() );
     248             :     }
     249        1730 :     if(!pTickInfo)
     250           2 :         return NULL;
     251        1728 :     return pTickInfo;
     252             : }
     253             : 
     254        2709 : TickInfo* LabelIterator::nextInfo()
     255             : {
     256        2709 :     TickInfo* pTickInfo = NULL;
     257             :     //get next label
     258        4167 :     do
     259        4167 :         pTickInfo = m_aPureTickIter.nextInfo();
     260        4167 :     while( pTickInfo && !pTickInfo->xTextShape.is() );
     261             : 
     262        2709 :     if(  STAGGER_EVEN==m_eAxisLabelStaggering
     263           0 :       || STAGGER_ODD==m_eAxisLabelStaggering )
     264             :     {
     265             :         //skip one label
     266        4147 :         do
     267        4147 :             pTickInfo = m_aPureTickIter.nextInfo();
     268        4147 :         while( pTickInfo && !pTickInfo->xTextShape.is() );
     269             :     }
     270        2709 :     return pTickInfo;
     271             : }
     272             : 
     273         869 : B2DVector lcl_getLabelsDistance( TickIter& rIter, const B2DVector& rDistanceTickToText, double fRotationAngleDegree )
     274             : {
     275             :     //calculates the height or width of a line of labels
     276             :     //thus a following line of labels can be shifted for that distance
     277             : 
     278         869 :     B2DVector aRet(0,0);
     279             : 
     280         869 :     sal_Int32 nDistanceTickToText = static_cast<sal_Int32>( rDistanceTickToText.getLength() );
     281         869 :     if( nDistanceTickToText==0.0)
     282           0 :         return aRet;
     283             : 
     284        1738 :     B2DVector aStaggerDirection(rDistanceTickToText);
     285         869 :     aStaggerDirection.normalize();
     286             : 
     287         869 :     sal_Int32 nDistance=0;
     288        1738 :     Reference< drawing::XShape >  xShape2DText(NULL);
     289        1805 :     for( TickInfo* pTickInfo = rIter.firstInfo()
     290             :         ; pTickInfo
     291         936 :         ; pTickInfo = rIter.nextInfo() )
     292             :     {
     293         936 :         xShape2DText = pTickInfo->xTextShape;
     294         936 :         if( xShape2DText.is() )
     295             :         {
     296         936 :             awt::Size aSize = AbstractShapeFactory::getSizeAfterRotation( xShape2DText, fRotationAngleDegree );
     297         936 :             if(fabs(aStaggerDirection.getX())>fabs(aStaggerDirection.getY()))
     298         126 :                 nDistance = ::std::max(nDistance,aSize.Width);
     299             :             else
     300         810 :                 nDistance = ::std::max(nDistance,aSize.Height);
     301             :         }
     302             :     }
     303             : 
     304         869 :     aRet = aStaggerDirection*nDistance;
     305             : 
     306             :     //add extra distance for vertical distance
     307         869 :     if(fabs(aStaggerDirection.getX())>fabs(aStaggerDirection.getY()))
     308          54 :         aRet += rDistanceTickToText;
     309             : 
     310         869 :     return aRet;
     311             : }
     312             : 
     313         869 : void lcl_shiftLabels( TickIter& rIter, const B2DVector& rStaggerDistance )
     314             : {
     315         869 :     if(rStaggerDistance.getLength()==0.0)
     316         874 :         return;
     317         864 :     Reference< drawing::XShape >  xShape2DText(NULL);
     318        2637 :     for( TickInfo* pTickInfo = rIter.firstInfo()
     319             :         ; pTickInfo
     320        1773 :         ; pTickInfo = rIter.nextInfo() )
     321             :     {
     322        1773 :         xShape2DText = pTickInfo->xTextShape;
     323        1773 :         if( xShape2DText.is() )
     324             :         {
     325        1773 :             awt::Point aPos  = xShape2DText->getPosition();
     326        1773 :             aPos.X += static_cast<sal_Int32>(rStaggerDistance.getX());
     327        1773 :             aPos.Y += static_cast<sal_Int32>(rStaggerDistance.getY());
     328        1773 :             xShape2DText->setPosition( aPos );
     329             :         }
     330         864 :     }
     331             : }
     332             : 
     333           0 : bool lcl_hasWordBreak( const Reference<drawing::XShape>& xShape )
     334             : {
     335           0 :     if (!xShape.is())
     336           0 :         return false;
     337             : 
     338           0 :     SvxShape* pShape = SvxShape::getImplementation(xShape);
     339           0 :     SvxShapeText* pShapeText = dynamic_cast<SvxShapeText*>(pShape);
     340           0 :     if (!pShapeText)
     341           0 :         return false;
     342             : 
     343           0 :     SvxTextEditSource* pTextEditSource = dynamic_cast<SvxTextEditSource*>(pShapeText->GetEditSource());
     344           0 :     if (!pTextEditSource)
     345           0 :         return false;
     346             : 
     347           0 :     pTextEditSource->UpdateOutliner();
     348           0 :     SvxTextForwarder* pTextForwarder = pTextEditSource->GetTextForwarder();
     349           0 :     if (!pTextForwarder)
     350           0 :         return false;
     351             : 
     352           0 :     sal_Int32 nParaCount = pTextForwarder->GetParagraphCount();
     353           0 :     for ( sal_Int32 nPara = 0; nPara < nParaCount; ++nPara )
     354             :     {
     355           0 :         sal_Int32 nLineCount = pTextForwarder->GetLineCount( nPara );
     356           0 :         for ( sal_Int32 nLine = 0; nLine < nLineCount; ++nLine )
     357             :         {
     358           0 :             sal_Int32 nLineStart = 0;
     359           0 :             sal_Int32 nLineEnd = 0;
     360           0 :             pTextForwarder->GetLineBoundaries( nLineStart, nLineEnd, nPara, nLine );
     361             :             assert(nLineStart >= 0);
     362           0 :             sal_Int32 nWordStart = 0;
     363           0 :             sal_Int32 nWordEnd = 0;
     364           0 :             if ( pTextForwarder->GetWordIndices( nPara, nLineStart, nWordStart, nWordEnd ) &&
     365           0 :                  ( nWordStart != nLineStart ) )
     366             :             {
     367           0 :                 return true;
     368             :             }
     369             :         }
     370             :     }
     371             : 
     372           0 :     return false;
     373             : }
     374             : 
     375       16321 : OUString getTextLabelString(
     376             :     const FixedNumberFormatter& rFixedNumberFormatter, const uno::Sequence<OUString>* pCategories,
     377             :     const TickInfo* pTickInfo, bool bComplexCat, sal_Int32& rExtraColor, bool& rHasExtraColor )
     378             : {
     379       16321 :     if (pCategories)
     380             :     {
     381             :         // This is a normal category axis.  Get the label string from the
     382             :         // label string array.
     383        7047 :         sal_Int32 nIndex = static_cast<sal_Int32>(pTickInfo->getUnscaledTickValue()) - 1; //first category (index 0) matches with real number 1.0
     384        7047 :         if( nIndex>=0 && nIndex<pCategories->getLength() )
     385        7013 :             return (*pCategories)[nIndex];
     386             : 
     387          34 :         return OUString();
     388             :     }
     389        9274 :     else if (bComplexCat)
     390             :     {
     391             :         // This is a complex category axis.  The label is stored in the tick.
     392           0 :         return pTickInfo->aText;
     393             :     }
     394             : 
     395             :     // This is a numeric axis.  Format the original tick value per number format.
     396        9274 :     return rFixedNumberFormatter.getFormattedString(pTickInfo->getUnscaledTickValue(), rExtraColor, rHasExtraColor);
     397             : }
     398             : 
     399        3766 : void getAxisLabelProperties(
     400             :     tNameSequence& rPropNames, tAnySequence& rPropValues, const AxisProperties& rAxisProp,
     401             :     const AxisLabelProperties& rAxisLabelProp,
     402             :     sal_Int32 nLimitedSpaceForText, bool bLimitedHeight )
     403             : {
     404        3766 :     Reference<beans::XPropertySet> xProps(rAxisProp.m_xAxisModel, uno::UNO_QUERY);
     405             : 
     406             :     PropertyMapper::getTextLabelMultiPropertyLists(
     407        3766 :         xProps, rPropNames, rPropValues, false, nLimitedSpaceForText, bLimitedHeight);
     408             : 
     409             :     LabelPositionHelper::doDynamicFontResize(
     410        3766 :         rPropValues, rPropNames, xProps, rAxisLabelProp.m_aFontReferenceSize);
     411             : 
     412             :     LabelPositionHelper::changeTextAdjustment(
     413        3766 :         rPropValues, rPropNames, rAxisProp.maLabelAlignment.meAlignment);
     414        3766 : }
     415             : 
     416             : /**
     417             :  * Iterate through only 3 ticks including the one that has the longest text
     418             :  * length.  When the first tick has the longest text, it iterates through
     419             :  * the first 3 ticks.  Otherwise it iterates through 3 ticks such that the
     420             :  * 2nd tick is the one with the longest text.
     421             :  */
     422             : class MaxLabelTickIter : public TickIter
     423             : {
     424             : public:
     425             :     MaxLabelTickIter( TickInfoArrayType& rTickInfoVector, size_t nLongestLabelIndex );
     426             :     virtual ~MaxLabelTickIter();
     427             : 
     428             :     virtual TickInfo* firstInfo() SAL_OVERRIDE;
     429             :     virtual TickInfo* nextInfo() SAL_OVERRIDE;
     430             : 
     431             : private:
     432             :     TickInfoArrayType& m_rTickInfoVector;
     433             :     std::vector<size_t> m_aValidIndices;
     434             :     size_t m_nCurrentIndex;
     435             : };
     436             : 
     437        1839 : MaxLabelTickIter::MaxLabelTickIter(
     438             :     TickInfoArrayType& rTickInfoVector, size_t nLongestLabelIndex ) :
     439        1839 :     m_rTickInfoVector(rTickInfoVector), m_nCurrentIndex(0)
     440             : {
     441             :     assert(!rTickInfoVector.empty()); // should be checked by the caller.
     442             :     assert(nLongestLabelIndex < rTickInfoVector.size());
     443             : 
     444        1839 :     size_t nMaxIndex = m_rTickInfoVector.size()-1;
     445        1839 :     if (nLongestLabelIndex >= nMaxIndex-1)
     446          38 :         nLongestLabelIndex = 0;
     447             : 
     448        1839 :     if (nLongestLabelIndex > 0)
     449           3 :         m_aValidIndices.push_back(nLongestLabelIndex-1);
     450             : 
     451        1839 :     m_aValidIndices.push_back(nLongestLabelIndex);
     452             : 
     453        7323 :     while (m_aValidIndices.size() < 3)
     454             :     {
     455        3673 :         ++nLongestLabelIndex;
     456        3673 :         if (nLongestLabelIndex > nMaxIndex)
     457          28 :             break;
     458             : 
     459        3645 :         m_aValidIndices.push_back(nLongestLabelIndex);
     460             :     }
     461        1839 : }
     462             : 
     463        3678 : MaxLabelTickIter::~MaxLabelTickIter()
     464             : {
     465        3678 : }
     466             : 
     467        1839 : TickInfo* MaxLabelTickIter::firstInfo()
     468             : {
     469        1839 :     m_nCurrentIndex = 0;
     470        1839 :     if (m_nCurrentIndex < m_aValidIndices.size())
     471        1839 :         return &m_rTickInfoVector[m_aValidIndices[m_nCurrentIndex]];
     472           0 :     return 0;
     473             : }
     474             : 
     475        5487 : TickInfo* MaxLabelTickIter::nextInfo()
     476             : {
     477        5487 :     m_nCurrentIndex++;
     478        5487 :     if (m_nCurrentIndex < m_aValidIndices.size())
     479        3648 :         return &m_rTickInfoVector[m_aValidIndices[m_nCurrentIndex]];
     480        1839 :     return 0;
     481             : }
     482             : 
     483        5507 : bool VCartesianAxis::isBreakOfLabelsAllowed(
     484             :     const AxisLabelProperties& rAxisLabelProperties, bool bIsHorizontalAxis ) const
     485             : {
     486        5507 :     if( m_aTextLabels.getLength() > 100 )
     487           0 :         return false;
     488        5507 :     if( !rAxisLabelProperties.bLineBreakAllowed )
     489        5337 :         return false;
     490         170 :     if( rAxisLabelProperties.bStackCharacters )
     491           3 :         return false;
     492             :     //no break for value axis
     493         167 :     if( !m_bUseTextLabels )
     494          37 :         return false;
     495         130 :     if( !::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) )
     496           0 :         return false;
     497             :     //break only for horizontal axis
     498         130 :     return bIsHorizontalAxis;
     499             : }
     500             : 
     501        5540 : bool VCartesianAxis::isAutoStaggeringOfLabelsAllowed(
     502             :     const AxisLabelProperties& rAxisLabelProperties, bool bIsHorizontalAxis, bool bIsVerticalAxis )
     503             : {
     504        5540 :     if( rAxisLabelProperties.eStaggering != STAGGER_AUTO )
     505        1700 :         return false;
     506        3840 :     if( rAxisLabelProperties.bOverlapAllowed )
     507         755 :         return false;
     508        3085 :     if( rAxisLabelProperties.bLineBreakAllowed ) //auto line break or auto staggering, doing both automatisms they may conflict...
     509           0 :         return false;
     510        3085 :     if( !::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) )
     511           6 :         return false;
     512             :     //automatic staggering only for horizontal axis with horizontal text
     513             :     //or vertical axis with vertical text
     514        3079 :     if( bIsHorizontalAxis )
     515        1630 :         return !rAxisLabelProperties.bStackCharacters;
     516        1449 :     if( bIsVerticalAxis )
     517        1385 :         return rAxisLabelProperties.bStackCharacters;
     518          64 :     return false;
     519             : }
     520             : 
     521           0 : void VCartesianAxis::createAllTickInfosFromComplexCategories( TickInfoArraysType& rAllTickInfos, bool bShiftedPosition )
     522             : {
     523             :     //no minor tickmarks will be generated!
     524             :     //order is: inner labels first , outer labels last (that is different to all other TickIter cases)
     525           0 :     if(!bShiftedPosition)
     526             :     {
     527           0 :         rAllTickInfos.clear();
     528           0 :         sal_Int32 nLevel=0;
     529           0 :         sal_Int32 nLevelCount = m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoryLevelCount();
     530           0 :         for( ; nLevel<nLevelCount; nLevel++ )
     531             :         {
     532           0 :             TickInfoArrayType aTickInfoVector;
     533             :             const std::vector<ComplexCategory>* pComplexCategories =
     534           0 :                 m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoriesByLevel(nLevel);
     535             : 
     536           0 :             if (!pComplexCategories)
     537           0 :                 continue;
     538             : 
     539           0 :             sal_Int32 nCatIndex = 0;
     540           0 :             std::vector<ComplexCategory>::const_iterator aIt = pComplexCategories->begin();
     541           0 :             std::vector<ComplexCategory>::const_iterator aEnd = pComplexCategories->end();
     542             : 
     543           0 :             for(;aIt!=aEnd;++aIt)
     544             :             {
     545           0 :                 TickInfo aTickInfo(0);
     546           0 :                 ComplexCategory aCat(*aIt);
     547           0 :                 sal_Int32 nCount = aCat.Count;
     548           0 :                 if( nCatIndex + 1.0 + nCount >= m_aScale.Maximum )
     549             :                 {
     550           0 :                     nCount = static_cast<sal_Int32>(m_aScale.Maximum - 1.0 - nCatIndex);
     551           0 :                     if( nCount <= 0 )
     552           0 :                         nCount = 1;
     553             :                 }
     554           0 :                 aTickInfo.fScaledTickValue = nCatIndex + 1.0 + nCount/2.0;
     555           0 :                 aTickInfo.nFactorForLimitedTextWidth = nCount;
     556           0 :                 aTickInfo.aText = aCat.Text;
     557           0 :                 aTickInfoVector.push_back(aTickInfo);
     558           0 :                 nCatIndex += nCount;
     559           0 :                 if( nCatIndex + 1.0 >= m_aScale.Maximum )
     560           0 :                     break;
     561           0 :             }
     562           0 :             rAllTickInfos.push_back(aTickInfoVector);
     563           0 :         }
     564             :     }
     565             :     else //bShiftedPosition==false
     566             :     {
     567           0 :         rAllTickInfos.clear();
     568           0 :         sal_Int32 nLevel=0;
     569           0 :         sal_Int32 nLevelCount = m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoryLevelCount();
     570           0 :         for( ; nLevel<nLevelCount; nLevel++ )
     571             :         {
     572           0 :             TickInfoArrayType aTickInfoVector;
     573             :             const std::vector<ComplexCategory>* pComplexCategories =
     574           0 :                 m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoriesByLevel(nLevel);
     575           0 :             sal_Int32 nCatIndex = 0;
     576           0 :             if (pComplexCategories)
     577             :             {
     578           0 :                 std::vector<ComplexCategory>::const_iterator aIt = pComplexCategories->begin();
     579           0 :                 std::vector<ComplexCategory>::const_iterator aEnd = pComplexCategories->end();
     580           0 :                 for(;aIt!=aEnd;++aIt)
     581             :                 {
     582           0 :                     TickInfo aTickInfo(0);
     583           0 :                     ComplexCategory aCat(*aIt);
     584           0 :                     aTickInfo.fScaledTickValue = nCatIndex + 1.0;
     585           0 :                     aTickInfoVector.push_back(aTickInfo);
     586           0 :                     nCatIndex += aCat.Count;
     587           0 :                     if( nCatIndex + 1.0 > m_aScale.Maximum )
     588           0 :                         break;
     589           0 :                 }
     590             :             }
     591             : 
     592             :             //fill up with single ticks until maximum scale
     593           0 :             while( nCatIndex + 1.0 < m_aScale.Maximum )
     594             :             {
     595           0 :                 TickInfo aTickInfo(0);
     596           0 :                 aTickInfo.fScaledTickValue = nCatIndex + 1.0;
     597           0 :                 aTickInfoVector.push_back(aTickInfo);
     598           0 :                 nCatIndex ++;
     599           0 :                 if( nLevel>0 )
     600           0 :                     break;
     601           0 :             }
     602             :             //add an additional tick at the end
     603             :             {
     604           0 :                 TickInfo aTickInfo(0);
     605           0 :                 aTickInfo.fScaledTickValue = m_aScale.Maximum;
     606           0 :                 aTickInfoVector.push_back(aTickInfo);
     607             :             }
     608           0 :             rAllTickInfos.push_back(aTickInfoVector);
     609           0 :         }
     610             :     }
     611           0 : }
     612             : 
     613        4002 : void VCartesianAxis::createAllTickInfos( TickInfoArraysType& rAllTickInfos )
     614             : {
     615        4002 :     if( isComplexCategoryAxis() )
     616           0 :         createAllTickInfosFromComplexCategories( rAllTickInfos, false );
     617             :     else
     618        4002 :         VAxisBase::createAllTickInfos(rAllTickInfos);
     619        4002 : }
     620             : 
     621        1839 : TickIter* VCartesianAxis::createLabelTickIterator( sal_Int32 nTextLevel )
     622             : {
     623        1839 :     if( nTextLevel>=0 && nTextLevel < static_cast< sal_Int32 >(m_aAllTickInfos.size()) )
     624        1839 :         return new PureTickIter( m_aAllTickInfos[nTextLevel] );
     625           0 :     return NULL;
     626             : }
     627             : 
     628        1839 : TickIter* VCartesianAxis::createMaximumLabelTickIterator( sal_Int32 nTextLevel )
     629             : {
     630        1839 :     if( isComplexCategoryAxis() || isDateAxis() )
     631             :     {
     632           0 :         return createLabelTickIterator( nTextLevel ); //mmmm maybe todo: create less than all texts here
     633             :     }
     634             :     else
     635             :     {
     636        1839 :         if(nTextLevel==0)
     637             :         {
     638        1839 :             if( !m_aAllTickInfos.empty() )
     639             :             {
     640        1839 :                 size_t nLongestLabelIndex = m_bUseTextLabels ? getIndexOfLongestLabel(m_aTextLabels) : 0;
     641        1839 :                 if (nLongestLabelIndex >= m_aAllTickInfos[0].size())
     642           0 :                     return NULL;
     643             : 
     644        1839 :                 return new MaxLabelTickIter( m_aAllTickInfos[0], nLongestLabelIndex );
     645             :             }
     646             :         }
     647             :     }
     648           0 :     return NULL;
     649             : }
     650             : 
     651        3678 : sal_Int32 VCartesianAxis::getTextLevelCount() const
     652             : {
     653        3678 :     sal_Int32 nTextLevelCount = 1;
     654        3678 :     if( isComplexCategoryAxis() )
     655           0 :         nTextLevelCount = m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoryLevelCount();
     656        3678 :     return nTextLevelCount;
     657             : }
     658             : 
     659        3766 : bool VCartesianAxis::createTextShapes(
     660             :     const Reference<drawing::XShapes>& xTarget, TickIter& rTickIter,
     661             :     AxisLabelProperties& rAxisLabelProperties, TickFactory2D* pTickFactory,
     662             :     sal_Int32 nScreenDistanceBetweenTicks )
     663             : {
     664        3766 :     const bool bIsHorizontalAxis = pTickFactory->isHorizontalAxis();
     665        3766 :     const bool bIsVerticalAxis = pTickFactory->isVerticalAxis();
     666             : 
     667       11233 :     if (!isBreakOfLabelsAllowed(rAxisLabelProperties, bIsHorizontalAxis) &&
     668        6652 :         !isAutoStaggeringOfLabelsAllowed(rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis) &&
     669        2886 :         !rAxisLabelProperties.isStaggered())
     670        2025 :         return createTextShapesSimple(xTarget, rTickIter, rAxisLabelProperties, pTickFactory);
     671             : 
     672             :     FixedNumberFormatter aFixedNumberFormatter(
     673        1741 :                 m_xNumberFormatsSupplier, rAxisLabelProperties.nNumberFormatKey );
     674             : 
     675        1741 :     bool bIsStaggered = rAxisLabelProperties.isStaggered();
     676        3482 :     B2DVector aTextToTickDistance = pTickFactory->getDistanceAxisTickToText(m_aAxisProperties, true);
     677        1741 :     sal_Int32 nLimitedSpaceForText = -1;
     678             : 
     679        1741 :     if( isBreakOfLabelsAllowed( rAxisLabelProperties, bIsHorizontalAxis ) )
     680             :     {
     681          65 :         nLimitedSpaceForText = nScreenDistanceBetweenTicks;
     682          65 :         if( bIsStaggered )
     683           0 :             nLimitedSpaceForText *= 2;
     684             : 
     685          65 :         if( nLimitedSpaceForText > 0 )
     686             :         { //reduce space for a small amount to have a visible distance between the labels:
     687          65 :             sal_Int32 nReduce = (nLimitedSpaceForText*5)/100;
     688          65 :             if(!nReduce)
     689           0 :                 nReduce = 1;
     690          65 :             nLimitedSpaceForText -= nReduce;
     691             :         }
     692             :     }
     693             : 
     694             :      // Stores an array of text label strings in case of a normal
     695             :      // (non-complex) category axis.
     696        1741 :     const uno::Sequence<OUString>* pCategories = NULL;
     697        1741 :     if( m_bUseTextLabels && !m_aAxisProperties.m_bComplexCategories )
     698        1539 :         pCategories = &m_aTextLabels;
     699             : 
     700        1741 :     bool bLimitedHeight = fabs(aTextToTickDistance.getX()) > fabs(aTextToTickDistance.getY());
     701             : 
     702             :     //prepare properties for multipropertyset-interface of shape
     703        3482 :     tNameSequence aPropNames;
     704        3482 :     tAnySequence aPropValues;
     705        1741 :     getAxisLabelProperties(aPropNames, aPropValues, m_aAxisProperties, rAxisLabelProperties, nLimitedSpaceForText, bLimitedHeight);
     706             : 
     707        1741 :     uno::Any* pColorAny = PropertyMapper::getValuePointer(aPropValues,aPropNames,"CharColor");
     708        1741 :     sal_Int32 nColor = Color( COL_AUTO ).GetColor();
     709        1741 :     if(pColorAny)
     710        1741 :         *pColorAny >>= nColor;
     711             : 
     712        1741 :     uno::Any* pLimitedSpaceAny = PropertyMapper::getValuePointerForLimitedSpace(aPropValues,aPropNames,bLimitedHeight);
     713             : 
     714        1741 :     const TickInfo* pPreviousVisibleTickInfo = NULL;
     715        1741 :     const TickInfo* pPREPreviousVisibleTickInfo = NULL;
     716        1741 :     sal_Int32 nTick = 0;
     717        8482 :     for( TickInfo* pTickInfo = rTickIter.firstInfo()
     718             :         ; pTickInfo
     719        6741 :         ; pTickInfo = rTickIter.nextInfo(), nTick++ )
     720             :     {
     721             :         const TickInfo* pLastVisibleNeighbourTickInfo = bIsStaggered ?
     722        6751 :                     pPREPreviousVisibleTickInfo : pPreviousVisibleTickInfo;
     723             : 
     724             :         //don't create labels which does not fit into the rhythm
     725        6751 :         if( nTick%rAxisLabelProperties.nRhythm != 0 )
     726         146 :             continue;
     727             : 
     728             :         //don't create labels for invisible ticks
     729        6693 :         if( !pTickInfo->bPaintIt )
     730           0 :             continue;
     731             : 
     732        6693 :         if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.bOverlapAllowed )
     733             :         {
     734             :             // Overlapping is not allowed.  If the label overlaps with its
     735             :             // neighbering label, try increasing the tick interval (or rhythm
     736             :             // as it's called) and start over.
     737             : 
     738        3170 :             if( lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo->xTextShape
     739             :                        , rAxisLabelProperties.fRotationAngleDegree
     740             :                        , pTickInfo->aTickScreenPosition
     741        3170 :                        , bIsHorizontalAxis, bIsVerticalAxis ) )
     742             :             {
     743             :                 // This tick overlaps with its neighbor.  Try to stagger (if
     744             :                 // auto staggering is allowed) to avoid overlapping.
     745             : 
     746           6 :                 bool bOverlapsAfterAutoStagger = true;
     747           6 :                 if( !bIsStaggered && isAutoStaggeringOfLabelsAllowed( rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis ) )
     748             :                 {
     749           0 :                     bIsStaggered = true;
     750           0 :                     rAxisLabelProperties.eStaggering = STAGGER_EVEN;
     751           0 :                     pLastVisibleNeighbourTickInfo = pPREPreviousVisibleTickInfo;
     752           0 :                     if( !pLastVisibleNeighbourTickInfo ||
     753             :                         !lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo->xTextShape
     754             :                                 , rAxisLabelProperties.fRotationAngleDegree
     755             :                                 , pTickInfo->aTickScreenPosition
     756           0 :                             , bIsHorizontalAxis, bIsVerticalAxis ) )
     757           0 :                         bOverlapsAfterAutoStagger = false;
     758             :                 }
     759             : 
     760           6 :                 if (bOverlapsAfterAutoStagger)
     761             :                 {
     762             :                     // Still overlaps with its neighbor even after staggering.
     763             :                     // Increment the visible tick intervals (if that's
     764             :                     // allowed) and start over.
     765             : 
     766           6 :                     if( rAxisLabelProperties.bRhythmIsFix )
     767           0 :                         continue;
     768           6 :                     rAxisLabelProperties.nRhythm++;
     769           6 :                     removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.nRhythm, nTick, xTarget );
     770          16 :                     return false;
     771             :                 }
     772             :             }
     773             :         }
     774             : 
     775        6687 :         bool bHasExtraColor=false;
     776        6687 :         sal_Int32 nExtraColor=0;
     777             : 
     778             :         OUString aLabel = getTextLabelString(
     779        6687 :             aFixedNumberFormatter, pCategories, pTickInfo, isComplexCategoryAxis(),
     780        6687 :             nExtraColor, bHasExtraColor);
     781             : 
     782        6687 :         if(pColorAny)
     783        6687 :             *pColorAny = uno::makeAny(bHasExtraColor?nExtraColor:nColor);
     784        6687 :         if(pLimitedSpaceAny)
     785         259 :             *pLimitedSpaceAny = uno::makeAny(sal_Int32(nLimitedSpaceForText*pTickInfo->nFactorForLimitedTextWidth));
     786             : 
     787       13340 :         B2DVector aTickScreenPos2D = pTickInfo->aTickScreenPosition;
     788        6687 :         aTickScreenPos2D += aTextToTickDistance;
     789             :         awt::Point aAnchorScreenPosition2D(
     790        6687 :             static_cast<sal_Int32>(aTickScreenPos2D.getX())
     791       13374 :             ,static_cast<sal_Int32>(aTickScreenPos2D.getY()));
     792             : 
     793             :         //create single label
     794        6687 :         if(!pTickInfo->xTextShape.is())
     795       13354 :             pTickInfo->xTextShape = createSingleLabel( m_xShapeFactory, xTarget
     796             :                                     , aAnchorScreenPosition2D, aLabel
     797             :                                     , rAxisLabelProperties, m_aAxisProperties
     798        6677 :                                     , aPropNames, aPropValues );
     799        6687 :         if(!pTickInfo->xTextShape.is())
     800          30 :             continue;
     801             : 
     802        6657 :         recordMaximumTextSize( pTickInfo->xTextShape, rAxisLabelProperties.fRotationAngleDegree );
     803             : 
     804        6916 :         if( nLimitedSpaceForText>0 && !rAxisLabelProperties.bOverlapAllowed
     805         256 :                 && ::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 )
     806         256 :                 && m_aAxisProperties.m_bComplexCategories
     807        6657 :                 && lcl_hasWordBreak( pTickInfo->xTextShape ) )
     808             :         {
     809             :             // Label has multiple lines and belongs to a complex category
     810             :             // axis. Rotate 90 degrees to try to avoid overlaps.
     811           0 :             rAxisLabelProperties.fRotationAngleDegree = 90;
     812           0 :             rAxisLabelProperties.bLineBreakAllowed = false;
     813           0 :             m_aAxisLabelProperties.fRotationAngleDegree = rAxisLabelProperties.fRotationAngleDegree;
     814           0 :             removeTextShapesFromTicks();
     815           0 :             return false;
     816             :         }
     817             : 
     818             :         //if NO OVERLAP -> remove overlapping shapes
     819        6657 :         if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.bOverlapAllowed )
     820             :         {
     821             :             // Check if the label still overlaps with its neighber.
     822        3164 :             if( doesOverlap( pLastVisibleNeighbourTickInfo->xTextShape, pTickInfo->xTextShape, rAxisLabelProperties.fRotationAngleDegree ) )
     823             :             {
     824             :                 // It overlaps.  Check if staggering helps.
     825           4 :                 bool bOverlapsAfterAutoStagger = true;
     826           4 :                 if( !bIsStaggered && isAutoStaggeringOfLabelsAllowed( rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis ) )
     827             :                 {
     828           0 :                     bIsStaggered = true;
     829           0 :                     rAxisLabelProperties.eStaggering = STAGGER_EVEN;
     830           0 :                     pLastVisibleNeighbourTickInfo = pPREPreviousVisibleTickInfo;
     831           0 :                     if( !pLastVisibleNeighbourTickInfo ||
     832             :                         !lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo->xTextShape
     833             :                             , rAxisLabelProperties.fRotationAngleDegree
     834             :                             , pTickInfo->aTickScreenPosition
     835           0 :                             , bIsHorizontalAxis, bIsVerticalAxis ) )
     836           0 :                         bOverlapsAfterAutoStagger = false;
     837             :                 }
     838             : 
     839           4 :                 if (bOverlapsAfterAutoStagger)
     840             :                 {
     841             :                     // Staggering didn't solve the overlap.
     842           4 :                     if( !rAxisLabelProperties.bOverlapAllowed && ::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) )
     843             :                     {
     844             :                         // Try auto-rotating the labels at 45 degrees and
     845             :                         // start over.  This rotation angle will be stored for
     846             :                         // all future text shape creation runs.
     847             :                         // The nRhythm parameter is reset to 1 since the layout
     848             :                         // used for text labels is changed.
     849           0 :                         rAxisLabelProperties.autoRotate45();
     850           0 :                         m_aAxisLabelProperties.fRotationAngleDegree = rAxisLabelProperties.fRotationAngleDegree; // Store it for future runs.
     851           0 :                         removeTextShapesFromTicks();
     852           0 :                         rAxisLabelProperties.nRhythm = 1;
     853           0 :                         return false;
     854             :                     }
     855             : 
     856           4 :                     if( rAxisLabelProperties.bRhythmIsFix )
     857             :                     {
     858             :                         // Tick interval is fixed.  We have no choice but to
     859             :                         // remove this label.
     860           0 :                         xTarget->remove(pTickInfo->xTextShape);
     861           0 :                         pTickInfo->xTextShape = NULL;
     862           0 :                         continue;
     863             :                     }
     864             : 
     865             :                     // Try incrementing the tick interval and start over.
     866           4 :                     rAxisLabelProperties.nRhythm++;
     867           4 :                     removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.nRhythm, nTick, xTarget );
     868           4 :                     return false;
     869             :                 }
     870             :             }
     871             :         }
     872             : 
     873        6653 :         pPREPreviousVisibleTickInfo = pPreviousVisibleTickInfo;
     874        6653 :         pPreviousVisibleTickInfo = pTickInfo;
     875        6653 :     }
     876        3472 :     return true;
     877             : }
     878             : 
     879        2025 : bool VCartesianAxis::createTextShapesSimple(
     880             :     const Reference<drawing::XShapes>& xTarget, TickIter& rTickIter,
     881             :     AxisLabelProperties& rAxisLabelProperties, TickFactory2D* pTickFactory )
     882             : {
     883             :     FixedNumberFormatter aFixedNumberFormatter(
     884        2025 :                 m_xNumberFormatsSupplier, rAxisLabelProperties.nNumberFormatKey );
     885             : 
     886        2025 :     const bool bIsHorizontalAxis = pTickFactory->isHorizontalAxis();
     887        2025 :     const bool bIsVerticalAxis = pTickFactory->isVerticalAxis();
     888        4050 :     B2DVector aTextToTickDistance = pTickFactory->getDistanceAxisTickToText(m_aAxisProperties, true);
     889             : 
     890             :      // Stores an array of text label strings in case of a normal
     891             :      // (non-complex) category axis.
     892        2025 :     const uno::Sequence<OUString>* pCategories = NULL;
     893        2025 :     if( m_bUseTextLabels && !m_aAxisProperties.m_bComplexCategories )
     894         393 :         pCategories = &m_aTextLabels;
     895             : 
     896        2025 :     bool bLimitedHeight = fabs(aTextToTickDistance.getX()) > fabs(aTextToTickDistance.getY());
     897             : 
     898             :     //prepare properties for multipropertyset-interface of shape
     899        4050 :     tNameSequence aPropNames;
     900        4050 :     tAnySequence aPropValues;
     901        2025 :     getAxisLabelProperties(aPropNames, aPropValues, m_aAxisProperties, rAxisLabelProperties, -1, bLimitedHeight);
     902             : 
     903        2025 :     uno::Any* pColorAny = PropertyMapper::getValuePointer(aPropValues,aPropNames,"CharColor");
     904        2025 :     sal_Int32 nColor = Color( COL_AUTO ).GetColor();
     905        2025 :     if(pColorAny)
     906        2025 :         *pColorAny >>= nColor;
     907             : 
     908        2025 :     uno::Any* pLimitedSpaceAny = PropertyMapper::getValuePointerForLimitedSpace(aPropValues,aPropNames,bLimitedHeight);
     909             : 
     910        2025 :     const TickInfo* pPreviousVisibleTickInfo = NULL;
     911        2025 :     sal_Int32 nTick = 0;
     912       11664 :     for( TickInfo* pTickInfo = rTickIter.firstInfo()
     913             :         ; pTickInfo
     914        9639 :         ; pTickInfo = rTickIter.nextInfo(), nTick++ )
     915             :     {
     916        9717 :         const TickInfo* pLastVisibleNeighbourTickInfo = pPreviousVisibleTickInfo;
     917             : 
     918             :         //don't create labels which does not fit into the rhythm
     919        9717 :         if( nTick%rAxisLabelProperties.nRhythm != 0 )
     920         160 :             continue;
     921             : 
     922             :         //don't create labels for invisible ticks
     923        9644 :         if( !pTickInfo->bPaintIt )
     924           0 :             continue;
     925             : 
     926        9644 :         if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.bOverlapAllowed )
     927             :         {
     928             :             // Overlapping is not allowed.  If the label overlaps with its
     929             :             // neighbering label, try increasing the tick interval (or rhythm
     930             :             // as it's called) and start over.
     931             : 
     932        5609 :             if( lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo->xTextShape
     933             :                        , rAxisLabelProperties.fRotationAngleDegree
     934             :                        , pTickInfo->aTickScreenPosition
     935        5609 :                        , bIsHorizontalAxis, bIsVerticalAxis ) )
     936             :             {
     937             :                 // This tick overlaps with its neighbor. Increment the visible
     938             :                 // tick intervals (if that's allowed) and start over.
     939             : 
     940          10 :                 if( rAxisLabelProperties.bRhythmIsFix )
     941           0 :                     continue;
     942          10 :                 rAxisLabelProperties.nRhythm++;
     943          10 :                 removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.nRhythm, nTick, xTarget );
     944          88 :                 return false;
     945             :             }
     946             :         }
     947             : 
     948        9634 :         bool bHasExtraColor=false;
     949        9634 :         sal_Int32 nExtraColor=0;
     950             : 
     951             :         OUString aLabel = getTextLabelString(
     952        9634 :             aFixedNumberFormatter, pCategories, pTickInfo, isComplexCategoryAxis(),
     953        9634 :             nExtraColor, bHasExtraColor);
     954             : 
     955        9634 :         if(pColorAny)
     956        9634 :             *pColorAny = uno::makeAny(bHasExtraColor?nExtraColor:nColor);
     957        9634 :         if(pLimitedSpaceAny)
     958           0 :             *pLimitedSpaceAny = uno::makeAny(sal_Int32(-1*pTickInfo->nFactorForLimitedTextWidth));
     959             : 
     960       19186 :         B2DVector aTickScreenPos2D = pTickInfo->aTickScreenPosition;
     961        9634 :         aTickScreenPos2D += aTextToTickDistance;
     962             :         awt::Point aAnchorScreenPosition2D(
     963        9634 :             static_cast<sal_Int32>(aTickScreenPos2D.getX())
     964       19268 :             ,static_cast<sal_Int32>(aTickScreenPos2D.getY()));
     965             : 
     966             :         //create single label
     967        9634 :         if(!pTickInfo->xTextShape.is())
     968       19164 :             pTickInfo->xTextShape = createSingleLabel( m_xShapeFactory, xTarget
     969             :                                     , aAnchorScreenPosition2D, aLabel
     970             :                                     , rAxisLabelProperties, m_aAxisProperties
     971        9582 :                                     , aPropNames, aPropValues );
     972        9634 :         if(!pTickInfo->xTextShape.is())
     973          14 :             continue;
     974             : 
     975        9620 :         recordMaximumTextSize( pTickInfo->xTextShape, rAxisLabelProperties.fRotationAngleDegree );
     976             : 
     977             :         //if NO OVERLAP -> remove overlapping shapes
     978        9620 :         if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.bOverlapAllowed )
     979             :         {
     980             :             // Check if the label still overlaps with its neighber.
     981        5599 :             if( doesOverlap( pLastVisibleNeighbourTickInfo->xTextShape, pTickInfo->xTextShape, rAxisLabelProperties.fRotationAngleDegree ) )
     982             :             {
     983             :                 // It overlaps.
     984          68 :                 if( !rAxisLabelProperties.bOverlapAllowed && ::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) )
     985             :                 {
     986             :                     // Try auto-rotating the labels at 45 degrees and
     987             :                     // start over.  This rotation angle will be stored for
     988             :                     // all future text shape creation runs.
     989             :                     // The nRhythm parameter is reset to 1 since the layout
     990             :                     // used for text labels is changed.
     991          26 :                     rAxisLabelProperties.autoRotate45();
     992          26 :                     m_aAxisLabelProperties.fRotationAngleDegree = rAxisLabelProperties.fRotationAngleDegree; // Store it for future runs.
     993          26 :                     removeTextShapesFromTicks();
     994          26 :                     rAxisLabelProperties.nRhythm = 1;
     995          26 :                     return false;
     996             :                 }
     997             : 
     998          42 :                 if( rAxisLabelProperties.bRhythmIsFix )
     999             :                 {
    1000             :                     // Tick interval is fixed.  We have no choice but to
    1001             :                     // remove this label.
    1002           0 :                     xTarget->remove(pTickInfo->xTextShape);
    1003           0 :                     pTickInfo->xTextShape = NULL;
    1004           0 :                     continue;
    1005             :                 }
    1006             : 
    1007             :                 // Try incrementing the tick interval and start over.
    1008          42 :                 rAxisLabelProperties.nRhythm++;
    1009          42 :                 removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.nRhythm, nTick, xTarget );
    1010          42 :                 return false;
    1011             :             }
    1012             :         }
    1013             : 
    1014        9552 :         pPreviousVisibleTickInfo = pTickInfo;
    1015        9552 :     }
    1016        3972 :     return true;
    1017             : }
    1018             : 
    1019           0 : drawing::PointSequenceSequence lcl_makePointSequence( B2DVector& rStart, B2DVector& rEnd )
    1020             : {
    1021           0 :     drawing::PointSequenceSequence aPoints(1);
    1022           0 :     aPoints[0].realloc(2);
    1023           0 :     aPoints[0][0].X = static_cast<sal_Int32>(rStart.getX());
    1024           0 :     aPoints[0][0].Y = static_cast<sal_Int32>(rStart.getY());
    1025           0 :     aPoints[0][1].X = static_cast<sal_Int32>(rEnd.getX());
    1026           0 :     aPoints[0][1].Y = static_cast<sal_Int32>(rEnd.getY());
    1027           0 :     return aPoints;
    1028             : }
    1029             : 
    1030       24684 : double VCartesianAxis::getAxisIntersectionValue() const
    1031             : {
    1032       24684 :     if (m_aAxisProperties.m_pfMainLinePositionAtOtherAxis)
    1033       23267 :         return *m_aAxisProperties.m_pfMainLinePositionAtOtherAxis;
    1034             : 
    1035        1417 :     double fMin = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMinY();
    1036        1417 :     double fMax = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMaxY();
    1037             : 
    1038        1417 :     return (css::chart::ChartAxisPosition_END == m_aAxisProperties.m_eCrossoverType) ? fMax : fMin;
    1039             : }
    1040             : 
    1041       11620 : double VCartesianAxis::getLabelLineIntersectionValue() const
    1042             : {
    1043       11620 :     if (css::chart::ChartAxisLabelPosition_OUTSIDE_START == m_aAxisProperties.m_eLabelPos)
    1044         390 :         return (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMinY();
    1045             : 
    1046       11230 :     if (css::chart::ChartAxisLabelPosition_OUTSIDE_END == m_aAxisProperties.m_eLabelPos)
    1047           0 :         return (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMaxY();
    1048             : 
    1049       11230 :     return getAxisIntersectionValue();
    1050             : }
    1051             : 
    1052           0 : double VCartesianAxis::getExtraLineIntersectionValue() const
    1053             : {
    1054             :     double fNan;
    1055           0 :     rtl::math::setNan(&fNan);
    1056             : 
    1057           0 :     if( !m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis )
    1058           0 :         return fNan;
    1059             : 
    1060           0 :     double fMin = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMinY();
    1061           0 :     double fMax = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMaxY();
    1062             : 
    1063           0 :     if( *m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis <= fMin
    1064           0 :         || *m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis >= fMax )
    1065           0 :         return fNan;
    1066             : 
    1067           0 :     return *m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis;
    1068             : }
    1069             : 
    1070       50148 : B2DVector VCartesianAxis::getScreenPosition( double fLogicX, double fLogicY, double fLogicZ ) const
    1071             : {
    1072       50148 :     B2DVector aRet(0,0);
    1073             : 
    1074       50148 :     if( m_pPosHelper )
    1075             :     {
    1076       50148 :         drawing::Position3D aScenePos = m_pPosHelper->transformLogicToScene( fLogicX, fLogicY, fLogicZ, true );
    1077       50148 :         if(3==m_nDimension)
    1078             :         {
    1079        3178 :             if( m_xLogicTarget.is() && m_pPosHelper && m_pShapeFactory )
    1080             :             {
    1081        3178 :                 tPropertyNameMap aDummyPropertyNameMap;
    1082             :                 Reference< drawing::XShape > xShape3DAnchor = m_pShapeFactory->createCube( m_xLogicTarget
    1083        6356 :                         , aScenePos,drawing::Direction3D(1,1,1), 0, 0, aDummyPropertyNameMap);
    1084        3178 :                 awt::Point a2DPos = xShape3DAnchor->getPosition(); //get 2D position from xShape3DAnchor
    1085        3178 :                 m_xLogicTarget->remove(xShape3DAnchor);
    1086        3178 :                 aRet.setX( a2DPos.X );
    1087        6356 :                 aRet.setY( a2DPos.Y );
    1088             :             }
    1089             :             else
    1090             :             {
    1091             :                 OSL_FAIL("cannot calculate scrren position in VCartesianAxis::getScreenPosition");
    1092             :             }
    1093             :         }
    1094             :         else
    1095             :         {
    1096       46970 :             aRet.setX( aScenePos.PositionX );
    1097       46970 :             aRet.setY( aScenePos.PositionY );
    1098             :         }
    1099             :     }
    1100             : 
    1101       50148 :     return aRet;
    1102             : }
    1103             : 
    1104           0 : VCartesianAxis::ScreenPosAndLogicPos VCartesianAxis::getScreenPosAndLogicPos( double fLogicX_, double fLogicY_, double fLogicZ_ ) const
    1105             : {
    1106           0 :     ScreenPosAndLogicPos aRet;
    1107           0 :     aRet.fLogicX = fLogicX_;
    1108           0 :     aRet.fLogicY = fLogicY_;
    1109           0 :     aRet.fLogicZ = fLogicZ_;
    1110           0 :     aRet.aScreenPos = getScreenPosition( fLogicX_, fLogicY_, fLogicZ_ );
    1111           0 :     return aRet;
    1112             : }
    1113             : 
    1114             : typedef ::std::vector< VCartesianAxis::ScreenPosAndLogicPos > tScreenPosAndLogicPosList;
    1115             : struct lcl_LessXPos : ::std::binary_function< VCartesianAxis::ScreenPosAndLogicPos, VCartesianAxis::ScreenPosAndLogicPos, bool >
    1116             : {
    1117           0 :     inline bool operator() ( const VCartesianAxis::ScreenPosAndLogicPos& rPos1, const VCartesianAxis::ScreenPosAndLogicPos& rPos2 )
    1118             :     {
    1119           0 :         return ( rPos1.aScreenPos.getX() < rPos2.aScreenPos.getX() );
    1120             :     }
    1121             : };
    1122             : 
    1123             : struct lcl_GreaterYPos : ::std::binary_function< VCartesianAxis::ScreenPosAndLogicPos, VCartesianAxis::ScreenPosAndLogicPos, bool >
    1124             : {
    1125           0 :     inline bool operator() ( const VCartesianAxis::ScreenPosAndLogicPos& rPos1, const VCartesianAxis::ScreenPosAndLogicPos& rPos2 )
    1126             :     {
    1127           0 :         return ( rPos1.aScreenPos.getY() > rPos2.aScreenPos.getY() );
    1128             :     }
    1129             : };
    1130             : 
    1131       25074 : void VCartesianAxis::get2DAxisMainLine(
    1132             :     B2DVector& rStart, B2DVector& rEnd, AxisLabelAlignment& rAlignment, double fCrossesOtherAxis ) const
    1133             : {
    1134             :     //m_aAxisProperties might get updated and changed here because
    1135             :     //    the label alignmant and inner direction sign depends exactly of the choice of the axis line position which is made here in this method
    1136             : 
    1137       25074 :     double fMinX = m_pPosHelper->getLogicMinX();
    1138       25074 :     double fMinY = m_pPosHelper->getLogicMinY();
    1139       25074 :     double fMinZ = m_pPosHelper->getLogicMinZ();
    1140       25074 :     double fMaxX = m_pPosHelper->getLogicMaxX();
    1141       25074 :     double fMaxY = m_pPosHelper->getLogicMaxY();
    1142       25074 :     double fMaxZ = m_pPosHelper->getLogicMaxZ();
    1143             : 
    1144       25074 :     double fXStart = fMinX;
    1145       25074 :     double fYStart = fMinY;
    1146       25074 :     double fZStart = fMinZ;
    1147       25074 :     double fXEnd = fXStart;
    1148       25074 :     double fYEnd = fYStart;
    1149       25074 :     double fZEnd = fZStart;
    1150             : 
    1151       25074 :     double fXOnXPlane = fMinX;
    1152       25074 :     double fXOther = fMaxX;
    1153       25074 :     int nDifferentValue = !m_pPosHelper->isMathematicalOrientationX() ? -1 : 1;
    1154       25074 :     if( !m_pPosHelper->isSwapXAndY() )
    1155       24248 :         nDifferentValue *= (CuboidPlanePosition_Left != m_eLeftWallPos) ? -1 : 1;
    1156             :     else
    1157         826 :         nDifferentValue *= (CuboidPlanePosition_Bottom != m_eBottomPos) ? -1 : 1;
    1158       25074 :     if( nDifferentValue<0 )
    1159             :     {
    1160          32 :         fXOnXPlane = fMaxX;
    1161          32 :         fXOther = fMinX;
    1162             :     }
    1163             : 
    1164       25074 :     double fYOnYPlane = fMinY;
    1165       25074 :     double fYOther = fMaxY;
    1166       25074 :     nDifferentValue = !m_pPosHelper->isMathematicalOrientationY() ? -1 : 1;
    1167       25074 :     if( !m_pPosHelper->isSwapXAndY() )
    1168       24248 :         nDifferentValue *= (CuboidPlanePosition_Bottom != m_eBottomPos) ? -1 : 1;
    1169             :     else
    1170         826 :         nDifferentValue *= (CuboidPlanePosition_Left != m_eLeftWallPos) ? -1 : 1;
    1171       25074 :     if( nDifferentValue<0 )
    1172             :     {
    1173         886 :         fYOnYPlane = fMaxY;
    1174         886 :         fYOther = fMinY;
    1175             :     }
    1176             : 
    1177       25074 :     double fZOnZPlane = fMaxZ;
    1178       25074 :     double fZOther = fMinZ;
    1179       25074 :     nDifferentValue = !m_pPosHelper->isMathematicalOrientationZ() ? -1 : 1;
    1180       25074 :     nDifferentValue *= (CuboidPlanePosition_Back != m_eBackWallPos) ? -1 : 1;
    1181       25074 :     if( nDifferentValue<0 )
    1182             :     {
    1183           0 :         fZOnZPlane = fMinZ;
    1184           0 :         fZOther = fMaxZ;
    1185             :     }
    1186             : 
    1187       25074 :     if( 0==m_nDimensionIndex ) //x-axis
    1188             :     {
    1189       13168 :         if( fCrossesOtherAxis < fMinY )
    1190        2522 :             fCrossesOtherAxis = fMinY;
    1191       10646 :         else if( fCrossesOtherAxis > fMaxY )
    1192           0 :             fCrossesOtherAxis = fMaxY;
    1193             : 
    1194       13168 :         fYStart = fYEnd = fCrossesOtherAxis;
    1195       13168 :         fXEnd=m_pPosHelper->getLogicMaxX();
    1196             : 
    1197       13168 :         if(3==m_nDimension)
    1198             :         {
    1199         614 :             if( AxisHelper::isAxisPositioningEnabled() )
    1200             :             {
    1201         614 :                 if( ::rtl::math::approxEqual( fYOther, fYStart) )
    1202           0 :                     fZStart = fZEnd = fZOnZPlane;
    1203             :                 else
    1204         614 :                     fZStart = fZEnd = fZOther;
    1205             :             }
    1206             :             else
    1207             :             {
    1208           0 :                 rStart = getScreenPosition( fXStart, fYStart, fZStart );
    1209           0 :                 rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd );
    1210             : 
    1211           0 :                 double fDeltaX = rEnd.getX() - rStart.getX();
    1212           0 :                 double fDeltaY = rEnd.getY() - rStart.getY();
    1213             : 
    1214             :                 //only those points are candidates which are lying on exactly one wall as these are outer edges
    1215           0 :                 tScreenPosAndLogicPosList aPosList;
    1216           0 :                 aPosList.push_back( getScreenPosAndLogicPos( fMinX, fYOnYPlane, fZOther ) );
    1217           0 :                 aPosList.push_back( getScreenPosAndLogicPos( fMinX, fYOther, fZOnZPlane ) );
    1218             : 
    1219           0 :                 if( fabs(fDeltaY) > fabs(fDeltaX)  )
    1220             :                 {
    1221           0 :                     rAlignment.meAlignment = LABEL_ALIGN_LEFT;
    1222             :                     //choose most left positions
    1223           0 :                     ::std::sort( aPosList.begin(), aPosList.end(), lcl_LessXPos() );
    1224           0 :                     rAlignment.mfLabelDirection = (fDeltaY < 0) ? -1.0 : 1.0;
    1225             :                 }
    1226             :                 else
    1227             :                 {
    1228           0 :                     rAlignment.meAlignment = LABEL_ALIGN_BOTTOM;
    1229             :                     //choose most bottom positions
    1230           0 :                     ::std::sort( aPosList.begin(), aPosList.end(), lcl_GreaterYPos() );
    1231           0 :                     rAlignment.mfLabelDirection = (fDeltaX < 0) ? -1.0 : 1.0;
    1232             :                 }
    1233           0 :                 ScreenPosAndLogicPos aBestPos( aPosList[0] );
    1234           0 :                 fYStart = fYEnd = aBestPos.fLogicY;
    1235           0 :                 fZStart = fZEnd = aBestPos.fLogicZ;
    1236           0 :                 if( !m_pPosHelper->isMathematicalOrientationX() )
    1237           0 :                     rAlignment.mfLabelDirection *= -1.0;
    1238             :             }
    1239             :         }//end 3D x axis
    1240             :     }
    1241       11906 :     else if( 1==m_nDimensionIndex ) //y-axis
    1242             :     {
    1243       11570 :         if( fCrossesOtherAxis < fMinX )
    1244        9918 :             fCrossesOtherAxis = fMinX;
    1245        1652 :         else if( fCrossesOtherAxis > fMaxX )
    1246           0 :             fCrossesOtherAxis = fMaxX;
    1247             : 
    1248       11570 :         fXStart = fXEnd = fCrossesOtherAxis;
    1249       11570 :         fYEnd=m_pPosHelper->getLogicMaxY();
    1250             : 
    1251       11570 :         if(3==m_nDimension)
    1252             :         {
    1253         639 :             if( AxisHelper::isAxisPositioningEnabled() )
    1254             :             {
    1255         639 :                 if( ::rtl::math::approxEqual( fXOther, fXStart) )
    1256           0 :                     fZStart = fZEnd = fZOnZPlane;
    1257             :                 else
    1258         639 :                     fZStart = fZEnd = fZOther;
    1259             :             }
    1260             :             else
    1261             :             {
    1262           0 :                 rStart = getScreenPosition( fXStart, fYStart, fZStart );
    1263           0 :                 rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd );
    1264             : 
    1265           0 :                 double fDeltaX = rEnd.getX() - rStart.getX();
    1266           0 :                 double fDeltaY = rEnd.getY() - rStart.getY();
    1267             : 
    1268             :                 //only those points are candidates which are lying on exactly one wall as these are outer edges
    1269           0 :                 tScreenPosAndLogicPosList aPosList;
    1270           0 :                 aPosList.push_back( getScreenPosAndLogicPos( fXOnXPlane, fMinY, fZOther ) );
    1271           0 :                 aPosList.push_back( getScreenPosAndLogicPos( fXOther, fMinY, fZOnZPlane ) );
    1272             : 
    1273           0 :                 if( fabs(fDeltaY) > fabs(fDeltaX)  )
    1274             :                 {
    1275           0 :                     rAlignment.meAlignment = LABEL_ALIGN_LEFT;
    1276             :                     //choose most left positions
    1277           0 :                     ::std::sort( aPosList.begin(), aPosList.end(), lcl_LessXPos() );
    1278           0 :                     rAlignment.mfLabelDirection = (fDeltaY < 0) ? -1.0 : 1.0;
    1279             :                 }
    1280             :                 else
    1281             :                 {
    1282           0 :                     rAlignment.meAlignment = LABEL_ALIGN_BOTTOM;
    1283             :                     //choose most bottom positions
    1284           0 :                     ::std::sort( aPosList.begin(), aPosList.end(), lcl_GreaterYPos() );
    1285           0 :                     rAlignment.mfLabelDirection = (fDeltaX < 0) ? -1.0 : 1.0;
    1286             :                 }
    1287           0 :                 ScreenPosAndLogicPos aBestPos( aPosList[0] );
    1288           0 :                 fXStart = fXEnd = aBestPos.fLogicX;
    1289           0 :                 fZStart = fZEnd = aBestPos.fLogicZ;
    1290           0 :                 if( !m_pPosHelper->isMathematicalOrientationY() )
    1291           0 :                     rAlignment.mfLabelDirection *= -1.0;
    1292             :             }
    1293             :         }//end 3D y axis
    1294             :     }
    1295             :     else //z-axis
    1296             :     {
    1297         336 :         fZEnd = m_pPosHelper->getLogicMaxZ();
    1298         336 :         if( AxisHelper::isAxisPositioningEnabled() )
    1299             :         {
    1300         336 :             if( !m_aAxisProperties.m_bSwapXAndY )
    1301             :             {
    1302         238 :                 if( fCrossesOtherAxis < fMinY )
    1303          18 :                     fCrossesOtherAxis = fMinY;
    1304         220 :                 else if( fCrossesOtherAxis > fMaxY )
    1305           0 :                     fCrossesOtherAxis = fMaxY;
    1306         238 :                 fYStart = fYEnd = fCrossesOtherAxis;
    1307             : 
    1308         238 :                 if( ::rtl::math::approxEqual( fYOther, fYStart) )
    1309           0 :                     fXStart = fXEnd = fXOnXPlane;
    1310             :                 else
    1311         238 :                     fXStart = fXEnd = fXOther;
    1312             :             }
    1313             :             else
    1314             :             {
    1315          98 :                 if( fCrossesOtherAxis < fMinX )
    1316          98 :                     fCrossesOtherAxis = fMinX;
    1317           0 :                 else if( fCrossesOtherAxis > fMaxX )
    1318           0 :                     fCrossesOtherAxis = fMaxX;
    1319          98 :                 fXStart = fXEnd = fCrossesOtherAxis;
    1320             : 
    1321          98 :                 if( ::rtl::math::approxEqual( fXOther, fXStart) )
    1322           0 :                     fYStart = fYEnd = fYOnYPlane;
    1323             :                 else
    1324          98 :                     fYStart = fYEnd = fYOther;
    1325             :             }
    1326             :         }
    1327             :         else
    1328             :         {
    1329           0 :             if( !m_pPosHelper->isSwapXAndY() )
    1330             :             {
    1331           0 :                 fXStart = fXEnd = m_pPosHelper->isMathematicalOrientationX() ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMinX();
    1332           0 :                 fYStart = fYEnd = m_pPosHelper->isMathematicalOrientationY() ? m_pPosHelper->getLogicMinY() : m_pPosHelper->getLogicMaxY();
    1333             :             }
    1334             :             else
    1335             :             {
    1336           0 :                 fXStart = fXEnd = m_pPosHelper->isMathematicalOrientationX() ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMaxX();
    1337           0 :                 fYStart = fYEnd = m_pPosHelper->isMathematicalOrientationY() ? m_pPosHelper->getLogicMaxY() : m_pPosHelper->getLogicMinY();
    1338             :             }
    1339             : 
    1340           0 :             if(3==m_nDimension)
    1341             :             {
    1342           0 :                 rStart = getScreenPosition( fXStart, fYStart, fZStart );
    1343           0 :                 rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd );
    1344             : 
    1345           0 :                 double fDeltaX = rEnd.getX() - rStart.getX();
    1346             : 
    1347             :                 //only those points are candidates which are lying on exactly one wall as these are outer edges
    1348           0 :                 tScreenPosAndLogicPosList aPosList;
    1349           0 :                 aPosList.push_back( getScreenPosAndLogicPos( fXOther, fYOnYPlane, fMinZ ) );
    1350           0 :                 aPosList.push_back( getScreenPosAndLogicPos( fXOnXPlane, fYOther, fMinZ ) );
    1351             : 
    1352           0 :                 ::std::sort( aPosList.begin(), aPosList.end(), lcl_GreaterYPos() );
    1353           0 :                 ScreenPosAndLogicPos aBestPos( aPosList[0] );
    1354           0 :                 ScreenPosAndLogicPos aNotSoGoodPos( aPosList[1] );
    1355             : 
    1356             :                 //choose most bottom positions
    1357           0 :                 if( !::rtl::math::approxEqual( fDeltaX, 0.0 ) ) // prefer left-right alignments
    1358             :                 {
    1359           0 :                     if( aBestPos.aScreenPos.getX() > aNotSoGoodPos.aScreenPos.getX() )
    1360           0 :                         rAlignment.meAlignment = LABEL_ALIGN_RIGHT;
    1361             :                     else
    1362           0 :                          rAlignment.meAlignment = LABEL_ALIGN_LEFT;
    1363             :                 }
    1364             :                 else
    1365             :                 {
    1366           0 :                     if( aBestPos.aScreenPos.getY() > aNotSoGoodPos.aScreenPos.getY() )
    1367           0 :                         rAlignment.meAlignment = LABEL_ALIGN_BOTTOM;
    1368             :                     else
    1369           0 :                         rAlignment.meAlignment = LABEL_ALIGN_TOP;
    1370             :                 }
    1371             : 
    1372           0 :                 rAlignment.mfLabelDirection = (fDeltaX < 0) ? -1.0 : 1.0;
    1373           0 :                 if( !m_pPosHelper->isMathematicalOrientationZ() )
    1374           0 :                     rAlignment.mfLabelDirection *= -1.0;
    1375             : 
    1376           0 :                 fXStart = fXEnd = aBestPos.fLogicX;
    1377           0 :                 fYStart = fYEnd = aBestPos.fLogicY;
    1378             :             }
    1379             :         }//end 3D z axis
    1380             :     }
    1381             : 
    1382       25074 :     rStart = getScreenPosition( fXStart, fYStart, fZStart );
    1383       25074 :     rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd );
    1384             : 
    1385       25074 :     if(3==m_nDimension && !AxisHelper::isAxisPositioningEnabled() )
    1386           0 :         rAlignment.mfInnerTickDirection = rAlignment.mfLabelDirection;//to behave like before
    1387             : 
    1388       25074 :     if(3==m_nDimension && AxisHelper::isAxisPositioningEnabled() )
    1389             :     {
    1390        1589 :         double fDeltaX = rEnd.getX() - rStart.getX();
    1391        1589 :         double fDeltaY = rEnd.getY() - rStart.getY();
    1392             : 
    1393        1589 :         if( 2==m_nDimensionIndex )
    1394             :         {
    1395         336 :             if( m_eLeftWallPos != CuboidPlanePosition_Left )
    1396             :             {
    1397           0 :                 rAlignment.mfLabelDirection *= -1.0;
    1398           0 :                 rAlignment.mfInnerTickDirection *= -1.0;
    1399             :             }
    1400             : 
    1401             :             rAlignment.meAlignment =
    1402         336 :                 (rAlignment.mfLabelDirection < 0) ?
    1403         336 :                     LABEL_ALIGN_LEFT :  LABEL_ALIGN_RIGHT;
    1404             : 
    1405         336 :             if( ( fDeltaY<0 && m_aScale.Orientation == chart2::AxisOrientation_REVERSE ) ||
    1406           0 :                 ( fDeltaY>0 && m_aScale.Orientation == chart2::AxisOrientation_MATHEMATICAL ) )
    1407             :                 rAlignment.meAlignment =
    1408           0 :                     (rAlignment.meAlignment == LABEL_ALIGN_RIGHT) ?
    1409           0 :                         LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT;
    1410             :         }
    1411        1253 :         else if( fabs(fDeltaY) > fabs(fDeltaX) )
    1412             :         {
    1413         639 :             if( m_eBackWallPos != CuboidPlanePosition_Back )
    1414             :             {
    1415           0 :                 rAlignment.mfLabelDirection *= -1.0;
    1416           0 :                 rAlignment.mfInnerTickDirection *= -1.0;
    1417             :             }
    1418             : 
    1419             :             rAlignment.meAlignment =
    1420         639 :                 (rAlignment.mfLabelDirection < 0) ?
    1421         639 :                     LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT;
    1422             : 
    1423         639 :             if( ( fDeltaY<0 && m_aScale.Orientation == chart2::AxisOrientation_REVERSE ) ||
    1424           0 :                 ( fDeltaY>0 && m_aScale.Orientation == chart2::AxisOrientation_MATHEMATICAL ) )
    1425             :                 rAlignment.meAlignment =
    1426           0 :                     (rAlignment.meAlignment == LABEL_ALIGN_RIGHT) ?
    1427           0 :                         LABEL_ALIGN_LEFT :  LABEL_ALIGN_RIGHT;
    1428             :         }
    1429             :         else
    1430             :         {
    1431         614 :             if( m_eBackWallPos != CuboidPlanePosition_Back )
    1432             :             {
    1433           0 :                 rAlignment.mfLabelDirection *= -1.0;
    1434           0 :                 rAlignment.mfInnerTickDirection *= -1.0;
    1435             :             }
    1436             : 
    1437             :             rAlignment.meAlignment =
    1438         614 :                 (rAlignment.mfLabelDirection < 0) ?
    1439         614 :                     LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM;
    1440             : 
    1441         614 :             if( ( fDeltaX>0 && m_aScale.Orientation == chart2::AxisOrientation_REVERSE ) ||
    1442           0 :                 ( fDeltaX<0 && m_aScale.Orientation == chart2::AxisOrientation_MATHEMATICAL ) )
    1443             :                 rAlignment.meAlignment =
    1444           0 :                     (rAlignment.meAlignment == LABEL_ALIGN_TOP) ?
    1445           0 :                         LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP;
    1446             :         }
    1447             :     }
    1448       25074 : }
    1449             : 
    1450        4002 : TickFactory* VCartesianAxis::createTickFactory()
    1451             : {
    1452        4002 :     return createTickFactory2D();
    1453             : }
    1454             : 
    1455       11620 : TickFactory2D* VCartesianAxis::createTickFactory2D()
    1456             : {
    1457       11620 :     AxisLabelAlignment aLabelAlign = m_aAxisProperties.maLabelAlignment;
    1458       23240 :     B2DVector aStart, aEnd;
    1459       11620 :     get2DAxisMainLine(aStart, aEnd, aLabelAlign, getAxisIntersectionValue());
    1460             : 
    1461       23240 :     B2DVector aLabelLineStart, aLabelLineEnd;
    1462       11620 :     get2DAxisMainLine(aLabelLineStart, aLabelLineEnd, aLabelAlign, getLabelLineIntersectionValue());
    1463       11620 :     m_aAxisProperties.maLabelAlignment = aLabelAlign;
    1464             : 
    1465       23240 :     return new TickFactory2D( m_aScale, m_aIncrement, aStart, aEnd, aLabelLineStart-aStart );
    1466             : }
    1467             : 
    1468        2681 : void lcl_hideIdenticalScreenValues( TickIter& rTickIter )
    1469             : {
    1470        2681 :     TickInfo* pPrevTickInfo = rTickIter.firstInfo();
    1471        2681 :     if (!pPrevTickInfo)
    1472        2681 :         return;
    1473             : 
    1474        2681 :     pPrevTickInfo->bPaintIt = true;
    1475       29964 :     for( TickInfo* pTickInfo = rTickIter.nextInfo(); pTickInfo; pTickInfo = rTickIter.nextInfo())
    1476             :     {
    1477       27283 :         pTickInfo->bPaintIt = (pTickInfo->aTickScreenPosition != pPrevTickInfo->aTickScreenPosition);
    1478       27283 :         pPrevTickInfo = pTickInfo;
    1479             :     }
    1480             : }
    1481             : 
    1482             : //'hide' tickmarks with identical screen values in aAllTickInfos
    1483        2681 : void VCartesianAxis::hideIdenticalScreenValues( TickInfoArraysType& rTickInfos ) const
    1484             : {
    1485        2681 :     if( isComplexCategoryAxis() || isDateAxis() )
    1486             :     {
    1487           0 :         sal_Int32 nCount = rTickInfos.size();
    1488           0 :         for( sal_Int32 nN=0; nN<nCount; nN++ )
    1489             :         {
    1490           0 :             PureTickIter aTickIter( rTickInfos[nN] );
    1491           0 :             lcl_hideIdenticalScreenValues( aTickIter );
    1492           0 :         }
    1493             :     }
    1494             :     else
    1495             :     {
    1496        2681 :         EquidistantTickIter aTickIter( rTickInfos, m_aIncrement, 0, -1 );
    1497        2681 :         lcl_hideIdenticalScreenValues( aTickIter );
    1498             :     }
    1499        2681 : }
    1500             : 
    1501        4242 : sal_Int32 VCartesianAxis::estimateMaximumAutoMainIncrementCount()
    1502             : {
    1503        4242 :     sal_Int32 nRet = 10;
    1504             : 
    1505        4242 :     if( m_nMaximumTextWidthSoFar==0 && m_nMaximumTextHeightSoFar==0 )
    1506        2408 :         return nRet;
    1507             : 
    1508        3668 :     B2DVector aStart, aEnd;
    1509        1834 :     AxisLabelAlignment aLabelAlign = m_aAxisProperties.maLabelAlignment;
    1510        1834 :     get2DAxisMainLine(aStart, aEnd, aLabelAlign, getAxisIntersectionValue());
    1511        1834 :     m_aAxisProperties.maLabelAlignment = aLabelAlign;
    1512             : 
    1513        1834 :     sal_Int32 nMaxHeight = static_cast<sal_Int32>(fabs(aEnd.getY()-aStart.getY()));
    1514        1834 :     sal_Int32 nMaxWidth = static_cast<sal_Int32>(fabs(aEnd.getX()-aStart.getX()));
    1515             : 
    1516        1834 :     sal_Int32 nTotalAvailable = nMaxHeight;
    1517        1834 :     sal_Int32 nSingleNeeded = m_nMaximumTextHeightSoFar;
    1518             : 
    1519             :     //for horizontal axis:
    1520        1834 :     if( (m_nDimensionIndex == 0 && !m_aAxisProperties.m_bSwapXAndY)
    1521         858 :         || (m_nDimensionIndex == 1 && m_aAxisProperties.m_bSwapXAndY) )
    1522             :     {
    1523        1004 :         nTotalAvailable = nMaxWidth;
    1524        1004 :         nSingleNeeded = m_nMaximumTextWidthSoFar;
    1525             :     }
    1526             : 
    1527        1834 :     if( nSingleNeeded>0 )
    1528        1834 :         nRet = nTotalAvailable/nSingleNeeded;
    1529             : 
    1530        3668 :     return nRet;
    1531             : }
    1532             : 
    1533        5612 : void VCartesianAxis::doStaggeringOfLabels( const AxisLabelProperties& rAxisLabelProperties, TickFactory2D* pTickFactory2D )
    1534             : {
    1535        5612 :     if( !pTickFactory2D )
    1536        5612 :         return;
    1537             : 
    1538        5612 :     if( isComplexCategoryAxis() )
    1539             :     {
    1540           0 :         sal_Int32 nTextLevelCount = getTextLevelCount();
    1541           0 :         B2DVector aCummulatedLabelsDistance(0,0);
    1542           0 :         for( sal_Int32 nTextLevel=0; nTextLevel<nTextLevelCount; nTextLevel++ )
    1543             :         {
    1544           0 :             boost::scoped_ptr<TickIter> apTickIter(createLabelTickIterator(nTextLevel));
    1545           0 :             if (apTickIter)
    1546             :             {
    1547           0 :                 double fRotationAngleDegree = m_aAxisLabelProperties.fRotationAngleDegree;
    1548           0 :                 if( nTextLevel>0 )
    1549             :                 {
    1550           0 :                     lcl_shiftLabels( *apTickIter.get(), aCummulatedLabelsDistance );
    1551           0 :                     fRotationAngleDegree = 0.0;
    1552             :                 }
    1553           0 :                 aCummulatedLabelsDistance += lcl_getLabelsDistance( *apTickIter.get()
    1554             :                     , pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties )
    1555           0 :                     , fRotationAngleDegree );
    1556             :             }
    1557           0 :         }
    1558             :     }
    1559        5612 :     else if (rAxisLabelProperties.isStaggered())
    1560             :     {
    1561         909 :         if( !m_aAllTickInfos.empty() )
    1562             :         {
    1563         869 :             LabelIterator aInnerIter( m_aAllTickInfos[0], rAxisLabelProperties.eStaggering, true );
    1564        1738 :             LabelIterator aOuterIter( m_aAllTickInfos[0], rAxisLabelProperties.eStaggering, false );
    1565             : 
    1566             :             lcl_shiftLabels( aOuterIter
    1567             :                 , lcl_getLabelsDistance( aInnerIter
    1568        1738 :                     , pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties ), 0.0 ) );
    1569             :         }
    1570             :     }
    1571             : }
    1572             : 
    1573        2121 : void VCartesianAxis::createLabels()
    1574             : {
    1575        2121 :     if( !prepareShapeCreation() )
    1576         407 :         return;
    1577             : 
    1578             :     //create labels
    1579        1996 :     if (!m_aAxisProperties.m_bDisplayLabels)
    1580         157 :         return;
    1581             : 
    1582        1839 :     boost::scoped_ptr< TickFactory2D > apTickFactory2D( this->createTickFactory2D() );
    1583        1839 :     TickFactory2D* pTickFactory2D = apTickFactory2D.get();
    1584        1839 :     if( !pTickFactory2D )
    1585           0 :         return;
    1586             : 
    1587             :     //get the transformed screen values for all tickmarks in aAllTickInfos
    1588        1839 :     pTickFactory2D->updateScreenValues( m_aAllTickInfos );
    1589             :     //'hide' tickmarks with identical screen values in aAllTickInfos
    1590        1839 :     hideIdenticalScreenValues( m_aAllTickInfos );
    1591             : 
    1592        1839 :     removeTextShapesFromTicks();
    1593             : 
    1594             :     //create tick mark text shapes
    1595        1839 :     sal_Int32 nTextLevelCount = getTextLevelCount();
    1596        1839 :     sal_Int32 nScreenDistanceBetweenTicks = -1;
    1597        3678 :     for( sal_Int32 nTextLevel=0; nTextLevel<nTextLevelCount; nTextLevel++ )
    1598             :     {
    1599        1839 :         boost::scoped_ptr< TickIter > apTickIter(createLabelTickIterator( nTextLevel ));
    1600        1839 :         if(apTickIter)
    1601             :         {
    1602        1839 :             if(nTextLevel==0)
    1603             :             {
    1604        1839 :                 nScreenDistanceBetweenTicks = TickFactory2D::getTickScreenDistance( *apTickIter.get() );
    1605        1839 :                 if( nTextLevelCount>1 )
    1606           0 :                     nScreenDistanceBetweenTicks*=2; //the above used tick iter does contain also the sub ticks -> thus the given distance is only the half
    1607             :             }
    1608             : 
    1609        1839 :             AxisLabelProperties aComplexProps(m_aAxisLabelProperties);
    1610        1839 :             if( m_aAxisProperties.m_bComplexCategories )
    1611             :             {
    1612           0 :                 aComplexProps.bLineBreakAllowed = true;
    1613           0 :                 aComplexProps.bOverlapAllowed = !::rtl::math::approxEqual( aComplexProps.fRotationAngleDegree, 0.0 );
    1614             : 
    1615             :             }
    1616        1839 :             AxisLabelProperties& rAxisLabelProperties =  m_aAxisProperties.m_bComplexCategories ? aComplexProps : m_aAxisLabelProperties;
    1617        1839 :             while( !createTextShapes( m_xTextTarget, *apTickIter.get(), rAxisLabelProperties, pTickFactory2D, nScreenDistanceBetweenTicks ) )
    1618             :             {
    1619             :             };
    1620             :         }
    1621        1839 :     }
    1622        1839 :     doStaggeringOfLabels( m_aAxisLabelProperties, pTickFactory2D );
    1623             : }
    1624             : 
    1625        2121 : void VCartesianAxis::createMaximumLabels()
    1626             : {
    1627        2121 :     TrueGuard aRecordMaximumTextSize(m_bRecordMaximumTextSize);
    1628             : 
    1629        2121 :     if( !prepareShapeCreation() )
    1630         125 :         return;
    1631             : 
    1632             :     //create labels
    1633        1996 :     if (!m_aAxisProperties.m_bDisplayLabels)
    1634         157 :         return;
    1635             : 
    1636        3678 :     boost::scoped_ptr< TickFactory2D > apTickFactory2D( this->createTickFactory2D() );
    1637        1839 :     TickFactory2D* pTickFactory2D = apTickFactory2D.get();
    1638        1839 :     if( !pTickFactory2D )
    1639           0 :         return;
    1640             : 
    1641             :     //get the transformed screen values for all tickmarks in aAllTickInfos
    1642        1839 :     pTickFactory2D->updateScreenValues( m_aAllTickInfos );
    1643             : 
    1644             :     //create tick mark text shapes
    1645             :     //@todo: iterate through all tick depth which should be labeled
    1646             : 
    1647        1839 :     AxisLabelProperties aAxisLabelProperties( m_aAxisLabelProperties );
    1648        1839 :     if( isAutoStaggeringOfLabelsAllowed( aAxisLabelProperties, pTickFactory2D->isHorizontalAxis(), pTickFactory2D->isVerticalAxis() ) )
    1649         815 :         aAxisLabelProperties.eStaggering = STAGGER_EVEN;
    1650             : 
    1651        1839 :     aAxisLabelProperties.bOverlapAllowed = true;
    1652        1839 :     aAxisLabelProperties.bLineBreakAllowed = false;
    1653        1839 :     sal_Int32 nTextLevelCount = getTextLevelCount();
    1654        3678 :     for( sal_Int32 nTextLevel=0; nTextLevel<nTextLevelCount; nTextLevel++ )
    1655             :     {
    1656        1839 :         boost::scoped_ptr< TickIter > apTickIter(createMaximumLabelTickIterator( nTextLevel ));
    1657        1839 :         if(apTickIter)
    1658             :         {
    1659        1839 :             while( !createTextShapes( m_xTextTarget, *apTickIter.get(), aAxisLabelProperties, pTickFactory2D, -1 ) )
    1660             :             {
    1661             :             };
    1662             :         }
    1663        1839 :     }
    1664        3678 :     doStaggeringOfLabels( aAxisLabelProperties, pTickFactory2D );
    1665             : }
    1666             : 
    1667        2121 : void VCartesianAxis::updatePositions()
    1668             : {
    1669             :     //update positions of labels
    1670        2121 :     if (!m_aAxisProperties.m_bDisplayLabels)
    1671         374 :         return;
    1672             : 
    1673        1934 :     boost::scoped_ptr< TickFactory2D > apTickFactory2D( this->createTickFactory2D() );
    1674        1934 :     TickFactory2D* pTickFactory2D = apTickFactory2D.get();
    1675        1934 :     if( !pTickFactory2D )
    1676           0 :         return;
    1677             : 
    1678             :     //update positions of all existing text shapes
    1679        1934 :     pTickFactory2D->updateScreenValues( m_aAllTickInfos );
    1680             : 
    1681        1934 :     TickInfoArraysType::iterator aDepthIter = m_aAllTickInfos.begin();
    1682        1934 :     const TickInfoArraysType::const_iterator aDepthEnd  = m_aAllTickInfos.end();
    1683        5612 :     for( sal_Int32 nDepth=0; aDepthIter != aDepthEnd; ++aDepthIter, nDepth++ )
    1684             :     {
    1685        3678 :         TickInfoArrayType::iterator aTickIter = aDepthIter->begin();
    1686        3678 :         const TickInfoArrayType::const_iterator aTickEnd  = aDepthIter->end();
    1687       25974 :         for( ; aTickIter != aTickEnd; ++aTickIter )
    1688             :         {
    1689       22296 :             TickInfo& rTickInfo = (*aTickIter);
    1690       22296 :             Reference< drawing::XShape > xShape2DText( rTickInfo.xTextShape );
    1691       22296 :             if( xShape2DText.is() )
    1692             :             {
    1693       10636 :                 B2DVector aTextToTickDistance( pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties, true ) );
    1694       21272 :                 B2DVector aTickScreenPos2D( rTickInfo.aTickScreenPosition );
    1695       10636 :                 aTickScreenPos2D += aTextToTickDistance;
    1696             :                 awt::Point aAnchorScreenPosition2D(
    1697       10636 :                     static_cast<sal_Int32>(aTickScreenPos2D.getX())
    1698       21272 :                     ,static_cast<sal_Int32>(aTickScreenPos2D.getY()));
    1699             : 
    1700       10636 :                 double fRotationAngleDegree = m_aAxisLabelProperties.fRotationAngleDegree;
    1701       10636 :                 if( nDepth > 0 )
    1702             :                 {
    1703             :                     /* Multi-level Labels: default to 0 or 90 */
    1704           0 :                     if( pTickFactory2D->isHorizontalAxis() )
    1705           0 :                         fRotationAngleDegree = 0.0;
    1706             :                     else
    1707           0 :                         fRotationAngleDegree = 90;
    1708             :                 }
    1709             : 
    1710             :                 // #i78696# use mathematically correct rotation now
    1711       10636 :                 const double fRotationAnglePi(fRotationAngleDegree * (F_PI / -180.0));
    1712       21272 :                 uno::Any aATransformation = AbstractShapeFactory::makeTransformation(aAnchorScreenPosition2D, fRotationAnglePi);
    1713             : 
    1714             :                 //set new position
    1715       21272 :                 uno::Reference< beans::XPropertySet > xProp( xShape2DText, uno::UNO_QUERY );
    1716       10636 :                 if( xProp.is() )
    1717             :                 {
    1718             :                     try
    1719             :                     {
    1720       10636 :                         xProp->setPropertyValue( "Transformation", aATransformation );
    1721             :                     }
    1722           0 :                     catch( const uno::Exception& e )
    1723             :                     {
    1724             :                         ASSERT_EXCEPTION( e );
    1725             :                     }
    1726             :                 }
    1727             : 
    1728             :                 //correctPositionForRotation
    1729             :                 LabelPositionHelper::correctPositionForRotation( xShape2DText
    1730       21272 :                     , m_aAxisProperties.maLabelAlignment.meAlignment, fRotationAngleDegree, m_aAxisProperties.m_bComplexCategories );
    1731             :             }
    1732       22296 :         }
    1733             :     }
    1734             : 
    1735        1934 :     doStaggeringOfLabels( m_aAxisLabelProperties, pTickFactory2D );
    1736             : }
    1737             : 
    1738        1887 : void VCartesianAxis::createTickMarkLineShapes( TickInfoArrayType& rTickInfos, const TickmarkProperties& rTickmarkProperties, TickFactory2D& rTickFactory2D, bool bOnlyAtLabels )
    1739             : {
    1740        1887 :     sal_Int32 nPointCount = rTickInfos.size();
    1741        1887 :     drawing::PointSequenceSequence aPoints(2*nPointCount);
    1742             : 
    1743        1887 :     TickInfoArrayType::const_iterator       aTickIter = rTickInfos.begin();
    1744        1887 :     const TickInfoArrayType::const_iterator aTickEnd  = rTickInfos.end();
    1745        1887 :     sal_Int32 nN = 0;
    1746       14058 :     for( ; aTickIter != aTickEnd; ++aTickIter )
    1747             :     {
    1748       12171 :         if( !(*aTickIter).bPaintIt )
    1749           0 :             continue;
    1750             : 
    1751       12171 :         bool bTicksAtLabels = ( m_aAxisProperties.m_eTickmarkPos != ::com::sun::star::chart::ChartAxisMarkPosition_AT_AXIS );
    1752       12171 :         double fInnerDirectionSign = m_aAxisProperties.maLabelAlignment.mfInnerTickDirection;
    1753       12171 :         if( bTicksAtLabels && m_aAxisProperties.m_eLabelPos == ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END )
    1754           0 :             fInnerDirectionSign *= -1.0;
    1755       12171 :         bTicksAtLabels = bTicksAtLabels || bOnlyAtLabels;
    1756             :         //add ticks at labels:
    1757       12171 :         rTickFactory2D.addPointSequenceForTickLine( aPoints, nN++, (*aTickIter).fScaledTickValue
    1758       24342 :             , fInnerDirectionSign , rTickmarkProperties, bTicksAtLabels );
    1759             :         //add ticks at axis (without labels):
    1760       12171 :         if( !bOnlyAtLabels && m_aAxisProperties.m_eTickmarkPos == ::com::sun::star::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS )
    1761        9014 :             rTickFactory2D.addPointSequenceForTickLine( aPoints, nN++, (*aTickIter).fScaledTickValue
    1762       18028 :                 , m_aAxisProperties.maLabelAlignment.mfInnerTickDirection, rTickmarkProperties, !bTicksAtLabels );
    1763             :     }
    1764        1887 :     aPoints.realloc(nN);
    1765             :     m_pShapeFactory->createLine2D( m_xGroupShape_Shapes, aPoints
    1766        1887 :                                 , &rTickmarkProperties.aLineProperties );
    1767        1887 : }
    1768             : 
    1769        2131 : void VCartesianAxis::createShapes()
    1770             : {
    1771        2131 :     if( !prepareShapeCreation() )
    1772         250 :         return;
    1773             : 
    1774        2006 :     boost::scoped_ptr< TickFactory2D > apTickFactory2D( this->createTickFactory2D() );
    1775        2006 :     TickFactory2D* pTickFactory2D = apTickFactory2D.get();
    1776        2006 :     if( !pTickFactory2D )
    1777           0 :         return;
    1778             : 
    1779             :     //create line shapes
    1780        2006 :     if(2==m_nDimension)
    1781             :     {
    1782             :         //create extra long ticks to separate complex categories (create them only there where the labels are)
    1783        1859 :         if( isComplexCategoryAxis() )
    1784             :         {
    1785           0 :             TickInfoArraysType aComplexTickInfos;
    1786           0 :             createAllTickInfosFromComplexCategories( aComplexTickInfos, true );
    1787           0 :             pTickFactory2D->updateScreenValues( aComplexTickInfos );
    1788           0 :             hideIdenticalScreenValues( aComplexTickInfos );
    1789             : 
    1790           0 :             ::std::vector<TickmarkProperties> aTickmarkPropertiesList;
    1791             :             static bool bIncludeSpaceBetweenTickAndText = false;
    1792           0 :             sal_Int32 nOffset = static_cast<sal_Int32>(pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties, false, bIncludeSpaceBetweenTickAndText ).getLength());
    1793           0 :             sal_Int32 nTextLevelCount = getTextLevelCount();
    1794           0 :             for( sal_Int32 nTextLevel=0; nTextLevel<nTextLevelCount; nTextLevel++ )
    1795             :             {
    1796           0 :                 boost::scoped_ptr< TickIter > apTickIter(createLabelTickIterator( nTextLevel ));
    1797           0 :                 if( apTickIter )
    1798             :                 {
    1799           0 :                     double fRotationAngleDegree = m_aAxisLabelProperties.fRotationAngleDegree;
    1800           0 :                     B2DVector aLabelsDistance( lcl_getLabelsDistance( *apTickIter.get(), pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties, false ), fRotationAngleDegree ) );
    1801           0 :                     sal_Int32 nCurrentLength = static_cast<sal_Int32>(aLabelsDistance.getLength());
    1802           0 :                     aTickmarkPropertiesList.push_back( m_aAxisProperties.makeTickmarkPropertiesForComplexCategories( nOffset + nCurrentLength, 0, nTextLevel ) );
    1803           0 :                     nOffset += nCurrentLength;
    1804             :                 }
    1805           0 :             }
    1806             : 
    1807           0 :             sal_Int32 nTickmarkPropertiesCount = aTickmarkPropertiesList.size();
    1808           0 :             TickInfoArraysType::iterator aDepthIter             = aComplexTickInfos.begin();
    1809           0 :             const TickInfoArraysType::const_iterator aDepthEnd  = aComplexTickInfos.end();
    1810           0 :             for( sal_Int32 nDepth=0; aDepthIter != aDepthEnd && nDepth < nTickmarkPropertiesCount; ++aDepthIter, nDepth++ )
    1811             :             {
    1812           0 :                 if(nDepth==0 && !m_aAxisProperties.m_nMajorTickmarks)
    1813           0 :                     continue;
    1814           0 :                 createTickMarkLineShapes( *aDepthIter, aTickmarkPropertiesList[nDepth], *pTickFactory2D, true /*bOnlyAtLabels*/ );
    1815           0 :             }
    1816             :         }
    1817             :         //create normal ticks for major and minor intervals
    1818             :         {
    1819        1859 :             TickInfoArraysType aUnshiftedTickInfos;
    1820        1859 :             if( m_aScale.ShiftedCategoryPosition )// if ShiftedCategoryPosition==true the tickmarks in m_aAllTickInfos are shifted
    1821             :             {
    1822         842 :                 pTickFactory2D->getAllTicks( aUnshiftedTickInfos );
    1823         842 :                 pTickFactory2D->updateScreenValues( aUnshiftedTickInfos );
    1824         842 :                 hideIdenticalScreenValues( aUnshiftedTickInfos );
    1825             :             }
    1826        1859 :             TickInfoArraysType& rAllTickInfos = m_aScale.ShiftedCategoryPosition ? aUnshiftedTickInfos : m_aAllTickInfos;
    1827             : 
    1828        1859 :             TickInfoArraysType::iterator aDepthIter             = rAllTickInfos.begin();
    1829        1859 :             const TickInfoArraysType::const_iterator aDepthEnd  = rAllTickInfos.end();
    1830        1859 :             if(aDepthIter == aDepthEnd)//no tickmarks at all
    1831           0 :                 return;
    1832             : 
    1833        1859 :             sal_Int32 nTickmarkPropertiesCount = m_aAxisProperties.m_aTickmarkPropertiesList.size();
    1834        3746 :             for( sal_Int32 nDepth=0; aDepthIter != aDepthEnd && nDepth < nTickmarkPropertiesCount; ++aDepthIter, nDepth++ )
    1835        3746 :                 createTickMarkLineShapes( *aDepthIter, m_aAxisProperties.m_aTickmarkPropertiesList[nDepth], *pTickFactory2D, false /*bOnlyAtLabels*/ );
    1836             :         }
    1837             :         //create axis main lines
    1838             :         //it serves also as the handle shape for the axis selection
    1839             :         {
    1840        1859 :             drawing::PointSequenceSequence aPoints(1);
    1841        1859 :             apTickFactory2D->createPointSequenceForAxisMainLine( aPoints );
    1842             :             Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D(
    1843             :                     m_xGroupShape_Shapes, aPoints
    1844        3718 :                     , &m_aAxisProperties.m_aLineProperties );
    1845             :             //because of this name this line will be used for marking the axis
    1846        3718 :             ::chart::AbstractShapeFactory::setShapeName( xShape, "MarkHandles" );
    1847             :         }
    1848             :         //create an additional line at NULL
    1849        1859 :         if( !AxisHelper::isAxisPositioningEnabled() )
    1850             :         {
    1851           0 :             double fExtraLineCrossesOtherAxis = getExtraLineIntersectionValue();
    1852           0 :             if (!rtl::math::isNan(fExtraLineCrossesOtherAxis))
    1853             :             {
    1854           0 :                 B2DVector aStart, aEnd;
    1855           0 :                 AxisLabelAlignment aLabelAlign = m_aAxisProperties.maLabelAlignment;
    1856           0 :                 get2DAxisMainLine(aStart, aEnd, aLabelAlign, fExtraLineCrossesOtherAxis);
    1857           0 :                 m_aAxisProperties.maLabelAlignment = aLabelAlign;
    1858           0 :                 drawing::PointSequenceSequence aPoints( lcl_makePointSequence(aStart,aEnd) );
    1859             :                 Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D(
    1860           0 :                         m_xGroupShape_Shapes, aPoints, &m_aAxisProperties.m_aLineProperties );
    1861             :             }
    1862             :         }
    1863        2006 :     }
    1864             : 
    1865             :     //createLabels();
    1866             : }
    1867             : 
    1868          57 : } //namespace chart
    1869             : 
    1870             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11