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