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