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