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