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