1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: VCartesianAxis.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_chart2.hxx"
33 #include <basegfx/numeric/ftools.hxx>
35 #include "VCartesianAxis.hxx"
36 #include "PlottingPositionHelper.hxx"
37 #include "ShapeFactory.hxx"
38 #include "CommonConverters.hxx"
40 #include "ViewDefines.hxx"
41 #include "PropertyMapper.hxx"
42 #include "chartview/NumberFormatterWrapper.hxx"
43 #include "LabelPositionHelper.hxx"
44 #include "TrueGuard.hxx"
45 #include "BaseGFXHelper.hxx"
46 #include "AxisHelper.hxx"
48 #include <rtl/math.hxx>
49 #include <tools/color.hxx>
50 #include <tools/debug.hxx>
51 #include <com/sun/star/text/XText.hpp>
52 #include <com/sun/star/text/WritingMode2.hpp>
53 #include <svx/unoprnms.hxx>
58 //.............................................................................
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
;
67 //-----------------------------------------------------------------------------
68 //-----------------------------------------------------------------------------
69 //-----------------------------------------------------------------------------
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
)
78 m_pPosHelper
= pPosHelper
;
80 m_pPosHelper
= new PlottingPositionHelper();
83 VCartesianAxis::~VCartesianAxis()
89 //-----------------------------------------------------------------------------
90 //-----------------------------------------------------------------------------
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
103 if(!rLabel
.getLength())
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
);
111 Reference
< drawing::XShape
> xShape2DText
= ShapeFactory(xShapeFactory
)
112 .createText( xTarget
, aLabel
, rPropNames
, rPropValues
, aATransformation
);
114 //correctPositionForRotation
115 LabelPositionHelper::correctPositionForRotation( xShape2DText
116 , rAxisProperties
.m_aLabelAlignment
, rAxisLabelProperties
.fRotationAngleDegree
, false );
121 bool lcl_doesShapeOverlapWithTickmark( const Reference
< drawing::XShape
>& xShape
122 , double fRotationAngleDegree
123 , const basegfx::B2DVector
& rTickScreenPosition
124 , TickmarkHelper_2D
* pTickmarkHelper
)
129 ::basegfx::B2IRectangle aShapeRect
= BaseGFXHelper::makeRectangle(xShape
->getPosition(),ShapeFactory::getSizeAfterRotation( xShape
, fRotationAngleDegree
));
131 if( pTickmarkHelper
->isVerticalAxis() )
133 return ( (rTickScreenPosition
.getY() >= aShapeRect
.getMinY())
134 && (rTickScreenPosition
.getY() <= aShapeRect
.getMaxY()) );
136 if( pTickmarkHelper
->isHorizontalAxis() )
138 return ( (rTickScreenPosition
.getX() >= aShapeRect
.getMinX())
139 && (rTickScreenPosition
.getX() <= aShapeRect
.getMaxX()) );
142 basegfx::B2IVector
aPosition(
143 static_cast<sal_Int32
>( rTickScreenPosition
.getX() )
144 , static_cast<sal_Int32
>( rTickScreenPosition
.getY() ) );
145 return aShapeRect
.isInside(aPosition
);
148 bool doesOverlap( const Reference
< drawing::XShape
>& xShape1
149 , const Reference
< drawing::XShape
>& xShape2
150 , double fRotationAngleDegree
)
152 if( !xShape1
.is() || !xShape2
.is() )
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
);
160 void removeShapesAtWrongRythm( TickIter
& rIter
161 , sal_Int32 nCorrectRhythm
162 , sal_Int32 nMaxTickToCheck
163 , const Reference
< drawing::XShapes
>& xTarget
)
166 for( TickInfo
* pTickInfo
= rIter
.firstInfo()
167 ; pTickInfo
&& nTick
<= nMaxTickToCheck
168 ; pTickInfo
= rIter
.nextInfo(), nTick
++ )
170 //remove labels which does not fit into the rythm
171 if( nTick
%nCorrectRhythm
!= 0)
173 if(pTickInfo
->xTextShape
.is())
175 xTarget
->remove(pTickInfo
->xTextShape
);
176 pTickInfo
->xTextShape
= NULL
;
182 class LabelIterator
: private TickIter
184 //this Iterator iterates over existing text labels
186 //if the labels are staggered and bInnerLine is true
187 //we iterate only through the labels which are lying more inside the diagram
189 //if the labels are staggered and bInnerLine is false
190 //we iterate only through the labels which are lying more outside the diagram
192 //if the labels are not staggered
193 //we iterate through all labels
196 LabelIterator( ::std::vector
< ::std::vector
< TickInfo
> >& rTickInfos
197 , const ::com::sun::star::chart2::ExplicitIncrementData
& rIncrement
198 , const AxisLabelStaggering eAxisLabelStaggering
200 , sal_Int32 nMinDepth
=0, sal_Int32 nMaxDepth
=-1 );
202 virtual TickInfo
* firstInfo();
203 virtual TickInfo
* nextInfo();
209 const AxisLabelStaggering m_eAxisLabelStaggering
;
213 LabelIterator::LabelIterator( ::std::vector
< ::std::vector
< TickInfo
> >& rTickInfos
214 , const ::com::sun::star::chart2::ExplicitIncrementData
& rIncrement
215 , const AxisLabelStaggering eAxisLabelStaggering
217 , sal_Int32 nMinDepth
, sal_Int32 nMaxDepth
)
218 : TickIter( rTickInfos
, rIncrement
, nMinDepth
, nMaxDepth
)
219 , m_eAxisLabelStaggering(eAxisLabelStaggering
)
220 , m_bInnerLine(bInnerLine
)
224 TickInfo
* LabelIterator::firstInfo()
226 TickInfo
* pTickInfo
= TickIter::firstInfo();
227 while( pTickInfo
&& !pTickInfo
->xTextShape
.is() )
228 pTickInfo
= TickIter::nextInfo();
231 if( (STAGGER_EVEN
==m_eAxisLabelStaggering
&& m_bInnerLine
)
233 (STAGGER_ODD
==m_eAxisLabelStaggering
&& !m_bInnerLine
)
238 pTickInfo
= TickIter::nextInfo();
239 while( pTickInfo
&& !pTickInfo
->xTextShape
.is() );
246 TickInfo
* LabelIterator::nextInfo()
248 TickInfo
* pTickInfo
= NULL
;
251 pTickInfo
= TickIter::nextInfo();
252 while( pTickInfo
&& !pTickInfo
->xTextShape
.is() );
254 if( STAGGER_EVEN
==m_eAxisLabelStaggering
255 || STAGGER_ODD
==m_eAxisLabelStaggering
)
259 pTickInfo
= TickIter::nextInfo();
260 while( pTickInfo
&& !pTickInfo
->xTextShape
.is() );
265 B2DVector
lcl_getStaggerDistance( LabelIterator
& rIter
, const B2DVector
& rDistanceTickToText
)
267 //calculates the height or width of the first line of labels
268 //thus the second line of labels needs to be shifted for that distance
272 sal_Int32 nDistanceTickToText
= static_cast<sal_Int32
>( rDistanceTickToText
.getLength() );
273 if( nDistanceTickToText
==0.0)
276 B2DVector
aStaggerDirection(rDistanceTickToText
);
277 aStaggerDirection
.normalize();
279 sal_Int32 nDistance
=0;
280 Reference
< drawing::XShape
> xShape2DText(NULL
);
281 for( TickInfo
* pTickInfo
= rIter
.firstInfo()
283 ; pTickInfo
= rIter
.nextInfo() )
285 xShape2DText
= pTickInfo
->xTextShape
;
286 DBG_ASSERT(xShape2DText
.is(),"LabelIterator does not work correctly");
288 awt::Size aSize
= xShape2DText
->getSize();
289 if(fabs(aStaggerDirection
.getX())>fabs(aStaggerDirection
.getY()))
290 nDistance
= ::std::max(nDistance
,aSize
.Width
);
292 nDistance
= ::std::max(nDistance
,aSize
.Height
);
295 aRet
= aStaggerDirection
*nDistance
;
297 //add extra distance for vertical distance
298 if(fabs(aStaggerDirection
.getX())>fabs(aStaggerDirection
.getY()))
299 aRet
+= rDistanceTickToText
;
304 void lcl_correctPositionForStaggering( LabelIterator
& rIter
, const B2DVector
& rStaggerDistance
)
306 if(rStaggerDistance
.getLength()==0.0)
308 Reference
< drawing::XShape
> xShape2DText(NULL
);
309 for( TickInfo
* pTickInfo
= rIter
.firstInfo()
311 ; pTickInfo
= rIter
.nextInfo() )
313 xShape2DText
= pTickInfo
->xTextShape
;
314 DBG_ASSERT(xShape2DText
.is(),"LabelIterator does not work correctly");
316 awt::Point aPos
= xShape2DText
->getPosition();
317 aPos
.X
+= static_cast<sal_Int32
>(rStaggerDistance
.getX());
318 aPos
.Y
+= static_cast<sal_Int32
>(rStaggerDistance
.getY());
319 xShape2DText
->setPosition( aPos
);
323 class MaxLabelTickIter
: public TickIter
325 //iterate over first two and last two labels and the longest label
327 MaxLabelTickIter( ::std::vector
< ::std::vector
< TickInfo
> >& rTickInfos
328 , const ::com::sun::star::chart2::ExplicitIncrementData
& rIncrement
329 , sal_Int32 nLongestLabelIndex
);
330 virtual ~MaxLabelTickIter();
332 virtual TickInfo
* nextInfo();
335 sal_Int32 m_nLongestLabelIndex
;
338 MaxLabelTickIter::MaxLabelTickIter( ::std::vector
< ::std::vector
< TickInfo
> >& rTickInfos
339 , const ::com::sun::star::chart2::ExplicitIncrementData
& rIncrement
340 , sal_Int32 nLongestLabelIndex
)
341 : TickIter( rTickInfos
, rIncrement
, 0//nMinDepth
344 , m_nLongestLabelIndex( nLongestLabelIndex
)
346 sal_Int32 nMaxIndex
= getMaxIndex();
348 //ensure correct value:
349 if( m_nLongestLabelIndex
<0 || m_nLongestLabelIndex
>nMaxIndex
)
350 m_nLongestLabelIndex
= 0;
352 //last label is checked anyhow
353 if( m_nLongestLabelIndex
==nMaxIndex
)
354 m_nLongestLabelIndex
= 0;
355 //label before last is checked anyhow
356 if( m_nLongestLabelIndex
+1==nMaxIndex
)
357 m_nLongestLabelIndex
= 0;
359 MaxLabelTickIter::~MaxLabelTickIter()
363 TickInfo
* MaxLabelTickIter::nextInfo()
365 sal_Int32 nCurrentPos
= getCurrentIndex();
366 sal_Int32 nMaxIndex
= getMaxIndex();
369 if( m_nLongestLabelIndex
>1 && nCurrentPos
<m_nLongestLabelIndex
)
370 gotoIndex( m_nLongestLabelIndex
-1 ) ;
373 if( nMaxIndex
>3 && nCurrentPos
<nMaxIndex
-1 )
374 gotoIndex( nMaxIndex
-2 );
375 else if( nMaxIndex
>2 && nCurrentPos
<nMaxIndex
)
376 gotoIndex( nMaxIndex
-1 );
380 return TickIter::nextInfo();
383 bool VCartesianAxis::isBreakOfLabelsAllowed( const AxisLabelProperties
& rAxisLabelProperties
384 , TickmarkHelper_2D
* pTickmarkHelper
)
386 if( m_aTextLabels
.getLength() > 100 )
388 if( !rAxisLabelProperties
.bLineBreakAllowed
)
390 if( rAxisLabelProperties
.bStackCharacters
)
392 //no break for value axis
393 if( !m_bUseTextLabels
)
395 if( !::rtl::math::approxEqual( rAxisLabelProperties
.fRotationAngleDegree
, 0.0 ) )
397 //break only for horizontal axis
398 if( pTickmarkHelper
)
399 return pTickmarkHelper
->isHorizontalAxis();
403 bool VCartesianAxis::isAutoStaggeringOfLabelsAllowed( const AxisLabelProperties
& rAxisLabelProperties
404 , TickmarkHelper_2D
* pTickmarkHelper
)
406 if( rAxisLabelProperties
.eStaggering
!= STAGGER_AUTO
)
408 if( rAxisLabelProperties
.bOverlapAllowed
)
410 if( rAxisLabelProperties
.bLineBreakAllowed
) //auto line break or auto staggering, doing both automatisms they may conflict...
412 if( !::rtl::math::approxEqual( rAxisLabelProperties
.fRotationAngleDegree
, 0.0 ) )
414 //automatic staggering only for horizontal axis with horizontal text
415 //or vertical axis with vertical text
416 if( pTickmarkHelper
)
418 if( pTickmarkHelper
->isHorizontalAxis() )
419 return !rAxisLabelProperties
.bStackCharacters
;
420 if( pTickmarkHelper
->isVerticalAxis() )
421 return rAxisLabelProperties
.bStackCharacters
;
426 bool VCartesianAxis::createTextShapes(
427 const Reference
< drawing::XShapes
>& xTarget
428 , TickIter
& rTickIter
429 , AxisLabelProperties
& rAxisLabelProperties
430 , TickmarkHelper_2D
* pTickmarkHelper
)
432 //returns true if the text shapes have been created succesfully
433 //otherwise false - in this case the AxisLabelProperties have changed
434 //and contain new instructions for the next try for text shape creation
436 uno::Sequence
< rtl::OUString
>* pCategories
= m_bUseTextLabels
? &m_aTextLabels
: 0;
438 Reference
< XScaling
> xInverseScaling( NULL
);
439 if( m_aScale
.Scaling
.is() )
440 xInverseScaling
= m_aScale
.Scaling
->getInverseScaling();
442 FixedNumberFormatter
aFixedNumberFormatter(
443 m_xNumberFormatsSupplier
, rAxisLabelProperties
.nNumberFormatKey
);
445 B2DVector
aTextToTickDistance( pTickmarkHelper
->getDistanceAxisTickToText( m_aAxisProperties
) );
447 TickInfo
* pPreviousVisibleTickInfo
= NULL
;
448 TickInfo
* pPREPreviousVisibleTickInfo
= NULL
;
449 TickInfo
* pLastVisibleNeighbourTickInfo
= NULL
;
450 bool bIsStaggered
= rAxisLabelProperties
.getIsStaggered();
451 sal_Int32 nLimitedSpace
= -1;
452 if( isBreakOfLabelsAllowed( rAxisLabelProperties
, pTickmarkHelper
) )
454 nLimitedSpace
= TickmarkHelper_2D::getTickScreenDistance( rTickIter
);
458 if( nLimitedSpace
> 0 )
459 { //reduce space for a small amount to have a visible distance between the labels:
460 sal_Int32 nReduce
= (nLimitedSpace
*5)/100;
463 nLimitedSpace
-= nReduce
;
465 //maybe @todo in future:
466 //if the labeled tickmarks are not equidistant [this is not considered to be a relevant case so far]
467 //the limited space maybe needs to be calculated for each tickmark seperatly
468 //or the staggering could be ignored in that case
471 //------------------------------------------------
472 //prepare properties for multipropertyset-interface of shape
473 tNameSequence aPropNames
;
474 tAnySequence aPropValues
;
476 Reference
< beans::XPropertySet
> xProps( m_aAxisProperties
.m_xAxisModel
, uno::UNO_QUERY
);
477 PropertyMapper::getTextLabelMultiPropertyLists( xProps
, aPropNames
, aPropValues
, false
478 , nLimitedSpace
, fabs(aTextToTickDistance
.getX()) > fabs(aTextToTickDistance
.getY()) );
479 LabelPositionHelper::doDynamicFontResize( aPropValues
, aPropNames
, xProps
480 , m_aAxisLabelProperties
.m_aFontReferenceSize
);
481 LabelPositionHelper::changeTextAdjustment( aPropValues
, aPropNames
, m_aAxisProperties
.m_aLabelAlignment
);
483 uno::Any
* pColorAny
= PropertyMapper::getValuePointer(aPropValues
,aPropNames
,C2U("CharColor"));
484 sal_Int32 nColor
= Color( COL_AUTO
).GetColor();
486 *pColorAny
>>= nColor
;
487 //------------------------------------------------
490 for( TickInfo
* pTickInfo
= rTickIter
.firstInfo()
492 ; pTickInfo
= rTickIter
.nextInfo(), nTick
++ )
494 pLastVisibleNeighbourTickInfo
= bIsStaggered
?
495 pPREPreviousVisibleTickInfo
: pPreviousVisibleTickInfo
;
497 //don't create labels which does not fit into the rythm
498 if( nTick
%rAxisLabelProperties
.nRhythm
!= 0)
501 //don't create labels for invisible ticks
502 if( !pTickInfo
->bPaintIt
)
505 //if NO OVERLAP -> don't create labels where the tick overlaps
506 //with the text of the last neighbour tickmark
507 if( pLastVisibleNeighbourTickInfo
&& !rAxisLabelProperties
.bOverlapAllowed
)
509 if( lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo
->xTextShape
510 , rAxisLabelProperties
.fRotationAngleDegree
511 , pTickInfo
->aTickScreenPosition
, pTickmarkHelper
) )
513 bool bOverlapAlsoAfterSwitchingOnAutoStaggering
= true;
514 if( !bIsStaggered
&& isAutoStaggeringOfLabelsAllowed( rAxisLabelProperties
, pTickmarkHelper
) )
517 rAxisLabelProperties
.eStaggering
= STAGGER_EVEN
;
518 pLastVisibleNeighbourTickInfo
= pPREPreviousVisibleTickInfo
;
519 if( !pLastVisibleNeighbourTickInfo
||
520 !lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo
->xTextShape
521 , rAxisLabelProperties
.fRotationAngleDegree
522 , pTickInfo
->aTickScreenPosition
, pTickmarkHelper
) )
523 bOverlapAlsoAfterSwitchingOnAutoStaggering
= false;
525 if( bOverlapAlsoAfterSwitchingOnAutoStaggering
)
527 if( rAxisLabelProperties
.bRhythmIsFix
)
529 rAxisLabelProperties
.nRhythm
++;
530 TickIter
aRemoveIter( m_aAllTickInfos
, m_aIncrement
, 0, 0 );
531 removeShapesAtWrongRythm( aRemoveIter
, rAxisLabelProperties
.nRhythm
, nTick
, xTarget
);
537 pTickInfo
->updateUnscaledValue( xInverseScaling
);
539 bool bHasExtraColor
=false;
540 sal_Int32 nExtraColor
=0;
542 rtl::OUString aLabel
;
545 sal_Int32 nIndex
= static_cast< sal_Int32
>(pTickInfo
->fUnscaledTickValue
) - 1; //first category (index 0) matches with real number 1.0
546 if( nIndex
>=0 && nIndex
<pCategories
->getLength() )
547 aLabel
= (*pCategories
)[nIndex
];
550 aLabel
= aFixedNumberFormatter
.getFormattedString( pTickInfo
->fUnscaledTickValue
, nExtraColor
, bHasExtraColor
);
553 *pColorAny
= uno::makeAny(bHasExtraColor
?nExtraColor
:nColor
);
555 B2DVector
aTickScreenPos2D( pTickInfo
->aTickScreenPosition
);
556 aTickScreenPos2D
+= aTextToTickDistance
;
557 awt::Point
aAnchorScreenPosition2D(
558 static_cast<sal_Int32
>(aTickScreenPos2D
.getX())
559 ,static_cast<sal_Int32
>(aTickScreenPos2D
.getY()));
561 //create single label
562 if(!pTickInfo
->xTextShape
.is())
563 pTickInfo
->xTextShape
= createSingleLabel( m_xShapeFactory
, xTarget
564 , aAnchorScreenPosition2D
, aLabel
565 , rAxisLabelProperties
, m_aAxisProperties
566 , aPropNames
, aPropValues
);
567 if(!pTickInfo
->xTextShape
.is())
570 recordMaximumTextSize( pTickInfo
->xTextShape
, rAxisLabelProperties
.fRotationAngleDegree
);
572 //if NO OVERLAP -> remove overlapping shapes
573 if( pLastVisibleNeighbourTickInfo
&& !rAxisLabelProperties
.bOverlapAllowed
)
575 if( doesOverlap( pLastVisibleNeighbourTickInfo
->xTextShape
, pTickInfo
->xTextShape
, m_aAxisLabelProperties
.fRotationAngleDegree
) )
577 bool bOverlapAlsoAfterSwitchingOnAutoStaggering
= true;
578 if( !bIsStaggered
&& isAutoStaggeringOfLabelsAllowed( rAxisLabelProperties
, pTickmarkHelper
) )
581 rAxisLabelProperties
.eStaggering
= STAGGER_EVEN
;
582 pLastVisibleNeighbourTickInfo
= pPREPreviousVisibleTickInfo
;
583 if( !pLastVisibleNeighbourTickInfo
||
584 !lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo
->xTextShape
585 , rAxisLabelProperties
.fRotationAngleDegree
586 , pTickInfo
->aTickScreenPosition
, pTickmarkHelper
) )
587 bOverlapAlsoAfterSwitchingOnAutoStaggering
= false;
589 if( bOverlapAlsoAfterSwitchingOnAutoStaggering
)
591 if( rAxisLabelProperties
.bRhythmIsFix
)
593 xTarget
->remove(pTickInfo
->xTextShape
);
594 pTickInfo
->xTextShape
= NULL
;
597 rAxisLabelProperties
.nRhythm
++;
598 TickIter
aRemoveIter( m_aAllTickInfos
, m_aIncrement
, 0, 0 );
599 removeShapesAtWrongRythm( aRemoveIter
, rAxisLabelProperties
.nRhythm
, nTick
, xTarget
);
605 pPREPreviousVisibleTickInfo
= pPreviousVisibleTickInfo
;
606 pPreviousVisibleTickInfo
= pTickInfo
;
611 drawing::PointSequenceSequence
lcl_makePointSequence( B2DVector
& rStart
, B2DVector
& rEnd
)
613 drawing::PointSequenceSequence
aPoints(1);
614 aPoints
[0].realloc(2);
615 aPoints
[0][0].X
= static_cast<sal_Int32
>(rStart
.getX());
616 aPoints
[0][0].Y
= static_cast<sal_Int32
>(rStart
.getY());
617 aPoints
[0][1].X
= static_cast<sal_Int32
>(rEnd
.getX());
618 aPoints
[0][1].Y
= static_cast<sal_Int32
>(rEnd
.getY());
622 double VCartesianAxis::getLogicValueWhereMainLineCrossesOtherAxis() const
624 double fMin
= (m_nDimensionIndex
==1) ? m_pPosHelper
->getLogicMinX() : m_pPosHelper
->getLogicMinY();
625 double fMax
= (m_nDimensionIndex
==1) ? m_pPosHelper
->getLogicMaxX() : m_pPosHelper
->getLogicMaxY();
627 double fCrossesOtherAxis
;
628 if(m_aAxisProperties
.m_pfMainLinePositionAtOtherAxis
)
629 fCrossesOtherAxis
= *m_aAxisProperties
.m_pfMainLinePositionAtOtherAxis
;
632 if( ::com::sun::star::chart::ChartAxisPosition_END
== m_aAxisProperties
.m_eCrossoverType
)
633 fCrossesOtherAxis
= fMax
;
635 fCrossesOtherAxis
= fMin
;
637 return fCrossesOtherAxis
;
640 double VCartesianAxis::getLogicValueWhereLabelLineCrossesOtherAxis() const
642 double fMin
= (m_nDimensionIndex
==1) ? m_pPosHelper
->getLogicMinX() : m_pPosHelper
->getLogicMinY();
643 double fMax
= (m_nDimensionIndex
==1) ? m_pPosHelper
->getLogicMaxX() : m_pPosHelper
->getLogicMaxY();
645 double fCrossesOtherAxis
;
646 if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_START
== m_aAxisProperties
.m_eLabelPos
)
647 fCrossesOtherAxis
= fMin
;
648 else if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END
== m_aAxisProperties
.m_eLabelPos
)
649 fCrossesOtherAxis
= fMax
;
651 fCrossesOtherAxis
= getLogicValueWhereMainLineCrossesOtherAxis();
652 return fCrossesOtherAxis
;
655 bool VCartesianAxis::getLogicValueWhereExtraLineCrossesOtherAxis( double& fCrossesOtherAxis
) const
657 if( !m_aAxisProperties
.m_pfExrtaLinePositionAtOtherAxis
)
659 double fMin
= (m_nDimensionIndex
==1) ? m_pPosHelper
->getLogicMinX() : m_pPosHelper
->getLogicMinY();
660 double fMax
= (m_nDimensionIndex
==1) ? m_pPosHelper
->getLogicMaxX() : m_pPosHelper
->getLogicMaxY();
661 if( *m_aAxisProperties
.m_pfExrtaLinePositionAtOtherAxis
<= fMin
662 || *m_aAxisProperties
.m_pfExrtaLinePositionAtOtherAxis
>= fMax
)
664 fCrossesOtherAxis
= *m_aAxisProperties
.m_pfExrtaLinePositionAtOtherAxis
;
668 B2DVector
VCartesianAxis::getScreenPosition( double fLogicX
, double fLogicY
, double fLogicZ
) const
674 drawing::Position3D aScenePos
= m_pPosHelper
->transformLogicToScene( fLogicX
, fLogicY
, fLogicZ
, true );
677 if( m_xLogicTarget
.is() && m_pPosHelper
&& m_pShapeFactory
)
679 tPropertyNameMap aDummyPropertyNameMap
;
680 Reference
< drawing::XShape
> xShape3DAnchor
= m_pShapeFactory
->createCube( m_xLogicTarget
681 , aScenePos
,drawing::Direction3D(1,1,1), 0, 0, aDummyPropertyNameMap
);
682 awt::Point a2DPos
= xShape3DAnchor
->getPosition(); //get 2D position from xShape3DAnchor
683 m_xLogicTarget
->remove(xShape3DAnchor
);
684 aRet
.setX( a2DPos
.X
);
685 aRet
.setY( a2DPos
.Y
);
689 DBG_ERROR("cannot calculate scrren position in VCartesianAxis::getScreenPosition");
694 aRet
.setX( aScenePos
.PositionX
);
695 aRet
.setY( aScenePos
.PositionY
);
702 VCartesianAxis::ScreenPosAndLogicPos
VCartesianAxis::getScreenPosAndLogicPos( double fLogicX_
, double fLogicY_
, double fLogicZ_
) const
704 ScreenPosAndLogicPos aRet
;
705 aRet
.fLogicX
= fLogicX_
;
706 aRet
.fLogicY
= fLogicY_
;
707 aRet
.fLogicZ
= fLogicZ_
;
708 aRet
.aScreenPos
= getScreenPosition( fLogicX_
, fLogicY_
, fLogicZ_
);
712 typedef ::std::vector
< VCartesianAxis::ScreenPosAndLogicPos
> tScreenPosAndLogicPosList
;
713 struct lcl_LessXPos
: ::std::binary_function
< VCartesianAxis::ScreenPosAndLogicPos
, VCartesianAxis::ScreenPosAndLogicPos
, bool >
715 inline bool operator() ( const VCartesianAxis::ScreenPosAndLogicPos
& rPos1
, const VCartesianAxis::ScreenPosAndLogicPos
& rPos2
)
717 return ( rPos1
.aScreenPos
.getX() < rPos2
.aScreenPos
.getX() );
721 struct lcl_GreaterYPos
: ::std::binary_function
< VCartesianAxis::ScreenPosAndLogicPos
, VCartesianAxis::ScreenPosAndLogicPos
, bool >
723 inline bool operator() ( const VCartesianAxis::ScreenPosAndLogicPos
& rPos1
, const VCartesianAxis::ScreenPosAndLogicPos
& rPos2
)
725 return ( rPos1
.aScreenPos
.getY() > rPos2
.aScreenPos
.getY() );
729 void VCartesianAxis::get2DAxisMainLine( B2DVector
& rStart
, B2DVector
& rEnd
, double fCrossesOtherAxis
)
731 //m_aAxisProperties might get updated and changed here because
732 // the label alignmant and inner direction sign depends exactly of the choice of the axis line position which is made here in this method
734 double fMinX
= m_pPosHelper
->getLogicMinX();
735 double fMinY
= m_pPosHelper
->getLogicMinY();
736 double fMinZ
= m_pPosHelper
->getLogicMinZ();
737 double fMaxX
= m_pPosHelper
->getLogicMaxX();
738 double fMaxY
= m_pPosHelper
->getLogicMaxY();
739 double fMaxZ
= m_pPosHelper
->getLogicMaxZ();
741 double fXStart
= fMinX
;
742 double fYStart
= fMinY
;
743 double fZStart
= fMinZ
;
744 double fXEnd
= fXStart
;
745 double fYEnd
= fYStart
;
746 double fZEnd
= fZStart
;
748 double fXOnXPlane
= fMinX
;
749 double fXOther
= fMaxX
;
750 int nDifferentValue
= !m_pPosHelper
->isMathematicalOrientationX() ? -1 : 1;
751 if( !m_pPosHelper
->isSwapXAndY() )
752 nDifferentValue
*= (CuboidPlanePosition_Left
!= m_eLeftWallPos
) ? -1 : 1;
754 nDifferentValue
*= (CuboidPlanePosition_Bottom
!= m_eBottomPos
) ? -1 : 1;
755 if( nDifferentValue
<0 )
761 double fYOnYPlane
= fMinY
;
762 double fYOther
= fMaxY
;
763 nDifferentValue
= !m_pPosHelper
->isMathematicalOrientationY() ? -1 : 1;
764 if( !m_pPosHelper
->isSwapXAndY() )
765 nDifferentValue
*= (CuboidPlanePosition_Bottom
!= m_eBottomPos
) ? -1 : 1;
767 nDifferentValue
*= (CuboidPlanePosition_Left
!= m_eLeftWallPos
) ? -1 : 1;
768 if( nDifferentValue
<0 )
774 double fZOnZPlane
= fMaxZ
;
775 double fZOther
= fMinZ
;
776 nDifferentValue
= !m_pPosHelper
->isMathematicalOrientationZ() ? -1 : 1;
777 nDifferentValue
*= (CuboidPlanePosition_Back
!= m_eBackWallPos
) ? -1 : 1;
778 if( nDifferentValue
<0 )
784 if( 0==m_nDimensionIndex
) //x-axis
786 if( fCrossesOtherAxis
< fMinY
)
787 fCrossesOtherAxis
= fMinY
;
788 else if( fCrossesOtherAxis
> fMaxY
)
789 fCrossesOtherAxis
= fMaxY
;
791 fYStart
= fYEnd
= fCrossesOtherAxis
;
792 fXEnd
=m_pPosHelper
->getLogicMaxX();
796 if( AxisHelper::isAxisPositioningEnabled() )
798 if( ::rtl::math::approxEqual( fYOther
, fYStart
) )
799 fZStart
= fZEnd
= fZOnZPlane
;
801 fZStart
= fZEnd
= fZOther
;
805 rStart
= getScreenPosition( fXStart
, fYStart
, fZStart
);
806 rEnd
= getScreenPosition( fXEnd
, fYEnd
, fZEnd
);
808 double fDeltaX
= rEnd
.getX() - rStart
.getX();
809 double fDeltaY
= rEnd
.getY() - rStart
.getY();
811 //only those points are candidates which are lying on exactly one wall as these are outer edges
812 tScreenPosAndLogicPosList aPosList
;
813 aPosList
.push_back( getScreenPosAndLogicPos( fMinX
, fYOnYPlane
, fZOther
) );
814 aPosList
.push_back( getScreenPosAndLogicPos( fMinX
, fYOther
, fZOnZPlane
) );
816 if( fabs(fDeltaY
) > fabs(fDeltaX
) )
818 m_aAxisProperties
.m_aLabelAlignment
= LABEL_ALIGN_LEFT
;
819 //choose most left positions
820 ::std::sort( aPosList
.begin(), aPosList
.end(), lcl_LessXPos() );
821 m_aAxisProperties
.m_fLabelDirectionSign
= fDeltaY
<0 ? -1 : 1;
825 m_aAxisProperties
.m_aLabelAlignment
= LABEL_ALIGN_BOTTOM
;
826 //choose most bottom positions
827 ::std::sort( aPosList
.begin(), aPosList
.end(), lcl_GreaterYPos() );
828 m_aAxisProperties
.m_fLabelDirectionSign
= fDeltaX
<0 ? -1 : 1;
830 ScreenPosAndLogicPos
aBestPos( aPosList
[0] );
831 fYStart
= fYEnd
= aBestPos
.fLogicY
;
832 fZStart
= fZEnd
= aBestPos
.fLogicZ
;
833 if( !m_pPosHelper
->isMathematicalOrientationX() )
834 m_aAxisProperties
.m_fLabelDirectionSign
*= -1;
838 else if( 1==m_nDimensionIndex
) //y-axis
840 if( fCrossesOtherAxis
< fMinX
)
841 fCrossesOtherAxis
= fMinX
;
842 else if( fCrossesOtherAxis
> fMaxX
)
843 fCrossesOtherAxis
= fMaxX
;
845 fXStart
= fXEnd
= fCrossesOtherAxis
;
846 fYEnd
=m_pPosHelper
->getLogicMaxY();
850 if( AxisHelper::isAxisPositioningEnabled() )
852 if( ::rtl::math::approxEqual( fXOther
, fXStart
) )
853 fZStart
= fZEnd
= fZOnZPlane
;
855 fZStart
= fZEnd
= fZOther
;
859 rStart
= getScreenPosition( fXStart
, fYStart
, fZStart
);
860 rEnd
= getScreenPosition( fXEnd
, fYEnd
, fZEnd
);
862 double fDeltaX
= rEnd
.getX() - rStart
.getX();
863 double fDeltaY
= rEnd
.getY() - rStart
.getY();
865 //only those points are candidates which are lying on exactly one wall as these are outer edges
866 tScreenPosAndLogicPosList aPosList
;
867 aPosList
.push_back( getScreenPosAndLogicPos( fXOnXPlane
, fMinY
, fZOther
) );
868 aPosList
.push_back( getScreenPosAndLogicPos( fXOther
, fMinY
, fZOnZPlane
) );
870 if( fabs(fDeltaY
) > fabs(fDeltaX
) )
872 m_aAxisProperties
.m_aLabelAlignment
= LABEL_ALIGN_LEFT
;
873 //choose most left positions
874 ::std::sort( aPosList
.begin(), aPosList
.end(), lcl_LessXPos() );
875 m_aAxisProperties
.m_fLabelDirectionSign
= fDeltaY
<0 ? -1 : 1;
879 m_aAxisProperties
.m_aLabelAlignment
= LABEL_ALIGN_BOTTOM
;
880 //choose most bottom positions
881 ::std::sort( aPosList
.begin(), aPosList
.end(), lcl_GreaterYPos() );
882 m_aAxisProperties
.m_fLabelDirectionSign
= fDeltaX
<0 ? -1 : 1;
884 ScreenPosAndLogicPos
aBestPos( aPosList
[0] );
885 fXStart
= fXEnd
= aBestPos
.fLogicX
;
886 fZStart
= fZEnd
= aBestPos
.fLogicZ
;
887 if( !m_pPosHelper
->isMathematicalOrientationY() )
888 m_aAxisProperties
.m_fLabelDirectionSign
*= -1;
894 fZEnd
= m_pPosHelper
->getLogicMaxZ();
895 if( AxisHelper::isAxisPositioningEnabled() )
897 if( !m_aAxisProperties
.m_bSwapXAndY
)
899 if( fCrossesOtherAxis
< fMinY
)
900 fCrossesOtherAxis
= fMinY
;
901 else if( fCrossesOtherAxis
> fMaxY
)
902 fCrossesOtherAxis
= fMaxY
;
903 fYStart
= fYEnd
= fCrossesOtherAxis
;
905 if( ::rtl::math::approxEqual( fYOther
, fYStart
) )
906 fXStart
= fXEnd
= fXOnXPlane
;
908 fXStart
= fXEnd
= fXOther
;
912 if( fCrossesOtherAxis
< fMinX
)
913 fCrossesOtherAxis
= fMinX
;
914 else if( fCrossesOtherAxis
> fMaxX
)
915 fCrossesOtherAxis
= fMaxX
;
916 fXStart
= fXEnd
= fCrossesOtherAxis
;
918 if( ::rtl::math::approxEqual( fXOther
, fXStart
) )
919 fYStart
= fYEnd
= fYOnYPlane
;
921 fYStart
= fYEnd
= fYOther
;
926 if( !m_pPosHelper
->isSwapXAndY() )
928 fXStart
= fXEnd
= m_pPosHelper
->isMathematicalOrientationX() ? m_pPosHelper
->getLogicMaxX() : m_pPosHelper
->getLogicMinX();
929 fYStart
= fYEnd
= m_pPosHelper
->isMathematicalOrientationY() ? m_pPosHelper
->getLogicMinY() : m_pPosHelper
->getLogicMaxY();
933 fXStart
= fXEnd
= m_pPosHelper
->isMathematicalOrientationX() ? m_pPosHelper
->getLogicMinX() : m_pPosHelper
->getLogicMaxX();
934 fYStart
= fYEnd
= m_pPosHelper
->isMathematicalOrientationY() ? m_pPosHelper
->getLogicMaxY() : m_pPosHelper
->getLogicMinY();
939 rStart
= getScreenPosition( fXStart
, fYStart
, fZStart
);
940 rEnd
= getScreenPosition( fXEnd
, fYEnd
, fZEnd
);
942 double fDeltaX
= rEnd
.getX() - rStart
.getX();
944 //only those points are candidates which are lying on exactly one wall as these are outer edges
945 tScreenPosAndLogicPosList aPosList
;
946 aPosList
.push_back( getScreenPosAndLogicPos( fXOther
, fYOnYPlane
, fMinZ
) );
947 aPosList
.push_back( getScreenPosAndLogicPos( fXOnXPlane
, fYOther
, fMinZ
) );
949 ::std::sort( aPosList
.begin(), aPosList
.end(), lcl_GreaterYPos() );
950 ScreenPosAndLogicPos
aBestPos( aPosList
[0] );
951 ScreenPosAndLogicPos
aNotSoGoodPos( aPosList
[1] );
953 //choose most bottom positions
954 if( !::rtl::math::approxEqual( fDeltaX
, 0.0 ) ) // prefere left-right algnments
956 if( aBestPos
.aScreenPos
.getX() > aNotSoGoodPos
.aScreenPos
.getX() )
957 m_aAxisProperties
.m_aLabelAlignment
= LABEL_ALIGN_RIGHT
;
959 m_aAxisProperties
.m_aLabelAlignment
= LABEL_ALIGN_LEFT
;
963 if( aBestPos
.aScreenPos
.getY() > aNotSoGoodPos
.aScreenPos
.getY() )
964 m_aAxisProperties
.m_aLabelAlignment
= LABEL_ALIGN_BOTTOM
;
966 m_aAxisProperties
.m_aLabelAlignment
= LABEL_ALIGN_TOP
;
969 m_aAxisProperties
.m_fLabelDirectionSign
= fDeltaX
<0 ? -1 : 1;
970 if( !m_pPosHelper
->isMathematicalOrientationZ() )
971 m_aAxisProperties
.m_fLabelDirectionSign
*= -1;
973 fXStart
= fXEnd
= aBestPos
.fLogicX
;
974 fYStart
= fYEnd
= aBestPos
.fLogicY
;
979 rStart
= getScreenPosition( fXStart
, fYStart
, fZStart
);
980 rEnd
= getScreenPosition( fXEnd
, fYEnd
, fZEnd
);
982 if(3==m_nDimension
&& !AxisHelper::isAxisPositioningEnabled() )
983 m_aAxisProperties
.m_fInnerDirectionSign
= m_aAxisProperties
.m_fLabelDirectionSign
;//to behave like before
985 if(3==m_nDimension
&& AxisHelper::isAxisPositioningEnabled() )
987 double fDeltaX
= rEnd
.getX() - rStart
.getX();
988 double fDeltaY
= rEnd
.getY() - rStart
.getY();
990 if( 2==m_nDimensionIndex
)
992 if( m_eLeftWallPos
!= CuboidPlanePosition_Left
)
994 m_aAxisProperties
.m_fLabelDirectionSign
*= -1.0;
995 m_aAxisProperties
.m_fInnerDirectionSign
*= -1.0;
998 m_aAxisProperties
.m_aLabelAlignment
=
999 ( m_aAxisProperties
.m_fLabelDirectionSign
<0 ) ?
1000 LABEL_ALIGN_LEFT
: LABEL_ALIGN_RIGHT
;
1002 if( ( fDeltaY
<0 && m_aScale
.Orientation
== AxisOrientation_REVERSE
) ||
1003 ( fDeltaY
>0 && m_aScale
.Orientation
== AxisOrientation_MATHEMATICAL
) )
1004 m_aAxisProperties
.m_aLabelAlignment
=
1005 ( m_aAxisProperties
.m_aLabelAlignment
==LABEL_ALIGN_RIGHT
) ?
1006 LABEL_ALIGN_LEFT
: LABEL_ALIGN_RIGHT
;
1008 else if( fabs(fDeltaY
) > fabs(fDeltaX
) )
1010 if( m_eBackWallPos
!= CuboidPlanePosition_Back
)
1012 m_aAxisProperties
.m_fLabelDirectionSign
*= -1.0;
1013 m_aAxisProperties
.m_fInnerDirectionSign
*= -1.0;
1016 m_aAxisProperties
.m_aLabelAlignment
=
1017 ( m_aAxisProperties
.m_fLabelDirectionSign
<0 ) ?
1018 LABEL_ALIGN_LEFT
: LABEL_ALIGN_RIGHT
;
1020 if( ( fDeltaY
<0 && m_aScale
.Orientation
== AxisOrientation_REVERSE
) ||
1021 ( fDeltaY
>0 && m_aScale
.Orientation
== AxisOrientation_MATHEMATICAL
) )
1022 m_aAxisProperties
.m_aLabelAlignment
=
1023 ( m_aAxisProperties
.m_aLabelAlignment
==LABEL_ALIGN_RIGHT
) ?
1024 LABEL_ALIGN_LEFT
: LABEL_ALIGN_RIGHT
;
1028 if( m_eBackWallPos
!= CuboidPlanePosition_Back
)
1030 m_aAxisProperties
.m_fLabelDirectionSign
*= -1.0;
1031 m_aAxisProperties
.m_fInnerDirectionSign
*= -1.0;
1034 m_aAxisProperties
.m_aLabelAlignment
=
1035 ( m_aAxisProperties
.m_fLabelDirectionSign
<0 ) ?
1036 LABEL_ALIGN_TOP
: LABEL_ALIGN_BOTTOM
;
1038 if( ( fDeltaX
>0 && m_aScale
.Orientation
== AxisOrientation_REVERSE
) ||
1039 ( fDeltaX
<0 && m_aScale
.Orientation
== AxisOrientation_MATHEMATICAL
) )
1040 m_aAxisProperties
.m_aLabelAlignment
=
1041 ( m_aAxisProperties
.m_aLabelAlignment
==LABEL_ALIGN_TOP
) ?
1042 LABEL_ALIGN_BOTTOM
: LABEL_ALIGN_TOP
;
1047 TickmarkHelper
* VCartesianAxis::createTickmarkHelper()
1049 return createTickmarkHelper2D();
1052 TickmarkHelper_2D
* VCartesianAxis::createTickmarkHelper2D()
1054 B2DVector aStart
, aEnd
;
1055 this->get2DAxisMainLine( aStart
, aEnd
, this->getLogicValueWhereMainLineCrossesOtherAxis() );
1057 B2DVector aLabelLineStart
, aLabelLineEnd
;
1058 this->get2DAxisMainLine( aLabelLineStart
, aLabelLineEnd
, this->getLogicValueWhereLabelLineCrossesOtherAxis() );
1060 return new TickmarkHelper_2D( m_aScale
, m_aIncrement
, aStart
, aEnd
, aLabelLineStart
-aStart
);
1063 sal_Int32
VCartesianAxis::estimateMaximumAutoMainIncrementCount()
1065 sal_Int32 nRet
= 10;
1067 if( m_nMaximumTextWidthSoFar
==0 && m_nMaximumTextHeightSoFar
==0 )
1070 B2DVector aStart
, aEnd
;
1071 this->get2DAxisMainLine( aStart
, aEnd
, this->getLogicValueWhereMainLineCrossesOtherAxis() );
1073 sal_Int32 nMaxHeight
= static_cast<sal_Int32
>(fabs(aEnd
.getY()-aStart
.getY()));
1074 sal_Int32 nMaxWidth
= static_cast<sal_Int32
>(fabs(aEnd
.getX()-aStart
.getX()));
1076 sal_Int32 nTotalAvailable
= nMaxHeight
;
1077 sal_Int32 nSingleNeeded
= m_nMaximumTextHeightSoFar
;
1079 //for horizontal axis:
1080 if( (m_nDimensionIndex
== 0 && !m_aAxisProperties
.m_bSwapXAndY
)
1081 || (m_nDimensionIndex
== 1 && m_aAxisProperties
.m_bSwapXAndY
) )
1083 nTotalAvailable
= nMaxWidth
;
1084 nSingleNeeded
= m_nMaximumTextWidthSoFar
;
1087 if( nSingleNeeded
>0 )
1088 nRet
= nTotalAvailable
/nSingleNeeded
;
1093 void VCartesianAxis::doStaggeringOfLabels( const AxisLabelProperties
& rAxisLabelProperties
, TickmarkHelper_2D
* pTickmarkHelper2D
)
1095 if( !pTickmarkHelper2D
)
1098 if( rAxisLabelProperties
.getIsStaggered() )
1100 LabelIterator
aInnerIter( m_aAllTickInfos
, m_aIncrement
1101 , rAxisLabelProperties
.eStaggering
, true, 0, 0 );
1102 LabelIterator
aOuterIter( m_aAllTickInfos
, m_aIncrement
1103 , rAxisLabelProperties
.eStaggering
, false, 0, 0 );
1105 lcl_correctPositionForStaggering( aOuterIter
1106 , lcl_getStaggerDistance( aInnerIter
1107 , pTickmarkHelper2D
->getDistanceAxisTickToText( m_aAxisProperties
) ) );
1111 void SAL_CALL
VCartesianAxis::createLabels()
1113 if( !prepareShapeCreation() )
1116 //-----------------------------------------
1118 if( m_aAxisProperties
.m_bDisplayLabels
)
1120 std::auto_ptr
< TickmarkHelper_2D
> apTickmarkHelper2D( this->createTickmarkHelper2D() );
1121 TickmarkHelper_2D
* pTickmarkHelper2D
= apTickmarkHelper2D
.get();
1122 if( !pTickmarkHelper2D
)
1125 //-----------------------------------------
1126 //get the transformed screen values for all tickmarks in aAllTickInfos
1127 pTickmarkHelper2D
->updateScreenValues( m_aAllTickInfos
);
1128 //-----------------------------------------
1129 //'hide' tickmarks with identical screen values in aAllTickInfos
1130 pTickmarkHelper2D
->hideIdenticalScreenValues( m_aAllTickInfos
);
1132 TickIter
aRemoveIter( m_aAllTickInfos
, m_aIncrement
, 0, 0 );
1133 removeTextShapesFromTicks( aRemoveIter
, m_xTextTarget
);
1135 //create tick mark text shapes
1136 TickIter
aTickIter( m_aAllTickInfos
, m_aIncrement
, 0, 0 );
1137 while( !createTextShapes( m_xTextTarget
, aTickIter
1138 , m_aAxisLabelProperties
, pTickmarkHelper2D
) )
1142 doStaggeringOfLabels( m_aAxisLabelProperties
, pTickmarkHelper2D
);
1146 void SAL_CALL
VCartesianAxis::createMaximumLabels()
1148 TrueGuard
aRecordMaximumTextSize(m_bRecordMaximumTextSize
);
1150 if( !prepareShapeCreation() )
1153 //-----------------------------------------
1155 if( m_aAxisProperties
.m_bDisplayLabels
)
1157 std::auto_ptr
< TickmarkHelper_2D
> apTickmarkHelper2D( this->createTickmarkHelper2D() );
1158 TickmarkHelper_2D
* pTickmarkHelper2D
= apTickmarkHelper2D
.get();
1159 if( !pTickmarkHelper2D
)
1162 //-----------------------------------------
1163 //get the transformed screen values for all tickmarks in aAllTickInfos
1164 pTickmarkHelper2D
->updateScreenValues( m_aAllTickInfos
);
1166 //create tick mark text shapes
1167 //@todo: iterate through all tick depth wich should be labeled
1169 sal_Int32 nLongestLabelIndex
= m_bUseTextLabels
1170 ? this->getIndexOfLongestLabel( m_aTextLabels
) : 0;
1171 MaxLabelTickIter
aTickIter( m_aAllTickInfos
, m_aIncrement
, nLongestLabelIndex
);
1172 AxisLabelProperties
aAxisLabelProperties( m_aAxisLabelProperties
);
1173 if( isAutoStaggeringOfLabelsAllowed( aAxisLabelProperties
, pTickmarkHelper2D
) )
1174 aAxisLabelProperties
.eStaggering
= STAGGER_EVEN
;
1175 aAxisLabelProperties
.bOverlapAllowed
= true;
1176 aAxisLabelProperties
.bLineBreakAllowed
= false;
1177 while( !createTextShapes( m_xTextTarget
, aTickIter
1178 , aAxisLabelProperties
, pTickmarkHelper2D
) )
1182 doStaggeringOfLabels( aAxisLabelProperties
, pTickmarkHelper2D
);
1186 void SAL_CALL
VCartesianAxis::updatePositions()
1188 //-----------------------------------------
1189 //update positions of labels
1190 if( m_aAxisProperties
.m_bDisplayLabels
)
1192 std::auto_ptr
< TickmarkHelper_2D
> apTickmarkHelper2D( this->createTickmarkHelper2D() );
1193 TickmarkHelper_2D
* pTickmarkHelper2D
= apTickmarkHelper2D
.get();
1194 if( !pTickmarkHelper2D
)
1197 //-----------------------------------------
1198 //update positions of all existing text shapes
1199 pTickmarkHelper2D
->updateScreenValues( m_aAllTickInfos
);
1201 TickIter
aTickIter( m_aAllTickInfos
, m_aIncrement
, 0, 0 );
1203 Reference
< drawing::XShape
> xShape2DText
;
1204 for( TickInfo
* pTickInfo
= aTickIter
.firstInfo()
1205 ; pTickInfo
; pTickInfo
= aTickIter
.nextInfo() )
1210 xShape2DText
= pTickInfo
->xTextShape
;
1211 if( xShape2DText
.is() )
1213 B2DVector
aTextToTickDistance( pTickmarkHelper2D
->getDistanceAxisTickToText( m_aAxisProperties
) );
1214 B2DVector
aTickScreenPos2D( pTickInfo
->aTickScreenPosition
);
1215 aTickScreenPos2D
+= aTextToTickDistance
;
1216 awt::Point
aAnchorScreenPosition2D(
1217 static_cast<sal_Int32
>(aTickScreenPos2D
.getX())
1218 ,static_cast<sal_Int32
>(aTickScreenPos2D
.getY()));
1220 // #i78696# use mathematically correct rotation now
1221 const double fRotationAnglePi(m_aAxisLabelProperties
.fRotationAngleDegree
* (F_PI
/ -180.0));
1222 uno::Any aATransformation
= ShapeFactory::makeTransformation(aAnchorScreenPosition2D
, fRotationAnglePi
);
1225 uno::Reference
< beans::XPropertySet
> xProp( xShape2DText
, uno::UNO_QUERY
);
1230 xProp
->setPropertyValue( C2U( "Transformation" ), aATransformation
);
1232 catch( uno::Exception
& e
)
1234 ASSERT_EXCEPTION( e
);
1238 //correctPositionForRotation
1239 LabelPositionHelper::correctPositionForRotation( xShape2DText
1240 , m_aAxisProperties
.m_aLabelAlignment
, m_aAxisLabelProperties
.fRotationAngleDegree
, false );
1244 doStaggeringOfLabels( m_aAxisLabelProperties
, pTickmarkHelper2D
);
1248 void SAL_CALL
VCartesianAxis::createShapes()
1250 if( !prepareShapeCreation() )
1253 std::auto_ptr
< TickmarkHelper_2D
> apTickmarkHelper2D( this->createTickmarkHelper2D() );
1254 TickmarkHelper_2D
* pTickmarkHelper2D
= apTickmarkHelper2D
.get();
1255 if( !pTickmarkHelper2D
)
1258 //-----------------------------------------
1259 //create tick mark line shapes
1262 ::std::vector
< ::std::vector
< TickInfo
> > aAllShiftedTickInfos
;
1263 if( m_aIncrement
.ShiftedPosition
)
1265 pTickmarkHelper2D
->getAllTicksShifted( aAllShiftedTickInfos
);
1266 pTickmarkHelper2D
->updateScreenValues( aAllShiftedTickInfos
);
1267 pTickmarkHelper2D
->hideIdenticalScreenValues( aAllShiftedTickInfos
);
1269 ::std::vector
< ::std::vector
< TickInfo
> >& rAllTickInfos
= m_aIncrement
.ShiftedPosition
? aAllShiftedTickInfos
: m_aAllTickInfos
;
1271 ::std::vector
< ::std::vector
< TickInfo
> >::iterator aDepthIter
= rAllTickInfos
.begin();
1272 const ::std::vector
< ::std::vector
< TickInfo
> >::const_iterator aDepthEnd
= rAllTickInfos
.end();
1274 if(aDepthIter
== aDepthEnd
)//no tickmarks at all
1277 sal_Int32 nTickmarkPropertiesCount
= m_aAxisProperties
.m_aTickmarkPropertiesList
.size();
1278 for( sal_Int32 nDepth
=0
1279 ; aDepthIter
!= aDepthEnd
&& nDepth
< nTickmarkPropertiesCount
1280 ; aDepthIter
++, nDepth
++ )
1282 const TickmarkProperties
& rTickmarkProperties
= m_aAxisProperties
.m_aTickmarkPropertiesList
[nDepth
];
1284 sal_Int32 nPointCount
= (*aDepthIter
).size();
1285 drawing::PointSequenceSequence
aPoints(2*nPointCount
);
1287 ::std::vector
< TickInfo
>::const_iterator aTickIter
= (*aDepthIter
).begin();
1288 const ::std::vector
< TickInfo
>::const_iterator aTickEnd
= (*aDepthIter
).end();
1290 for( ; aTickIter
!= aTickEnd
; aTickIter
++ )
1292 if( !(*aTickIter
).bPaintIt
)
1295 bool bTicksAtLabels
= ( m_aAxisProperties
.m_eTickmarkPos
!= ::com::sun::star::chart::ChartAxisMarkPosition_AT_AXIS
);
1296 double fInnerDirectionSign
= m_aAxisProperties
.m_fInnerDirectionSign
;
1297 if( bTicksAtLabels
&& m_aAxisProperties
.m_eLabelPos
== ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END
)
1298 fInnerDirectionSign
*= -1.0;
1299 apTickmarkHelper2D
->addPointSequenceForTickLine( aPoints
, nN
++, (*aTickIter
).fScaledTickValue
1300 , fInnerDirectionSign
, rTickmarkProperties
, bTicksAtLabels
);
1301 if( m_aAxisProperties
.m_eTickmarkPos
== ::com::sun::star::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS
)
1302 apTickmarkHelper2D
->addPointSequenceForTickLine( aPoints
, nN
++, (*aTickIter
).fScaledTickValue
1303 , m_aAxisProperties
.m_fInnerDirectionSign
, rTickmarkProperties
, !bTicksAtLabels
);
1305 aPoints
.realloc(nN
);
1306 m_pShapeFactory
->createLine2D( m_xGroupShape_Shapes
, aPoints
1307 , &rTickmarkProperties
.aLineProperties
);
1309 //-----------------------------------------
1310 //create axis main lines
1311 //it serves also as the handle shape for the axis selection
1313 drawing::PointSequenceSequence
aPoints(1);
1314 apTickmarkHelper2D
->createPointSequenceForAxisMainLine( aPoints
);
1315 Reference
< drawing::XShape
> xShape
= m_pShapeFactory
->createLine2D(
1316 m_xGroupShape_Shapes
, aPoints
1317 , &m_aAxisProperties
.m_aLineProperties
);
1318 //because of this name this line will be used for marking the axis
1319 m_pShapeFactory
->setShapeName( xShape
, C2U("MarkHandles") );
1321 //-----------------------------------------
1322 //create an additional line at NULL
1323 if( !AxisHelper::isAxisPositioningEnabled() )
1325 double fExtraLineCrossesOtherAxis
;
1326 if( getLogicValueWhereExtraLineCrossesOtherAxis(fExtraLineCrossesOtherAxis
) )
1328 B2DVector aStart
, aEnd
;
1329 this->get2DAxisMainLine( aStart
, aEnd
, fExtraLineCrossesOtherAxis
);
1330 drawing::PointSequenceSequence
aPoints( lcl_makePointSequence(aStart
,aEnd
) );
1331 Reference
< drawing::XShape
> xShape
= m_pShapeFactory
->createLine2D(
1332 m_xGroupShape_Shapes
, aPoints
, &m_aAxisProperties
.m_aLineProperties
);
1340 //.............................................................................
1342 //.............................................................................