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