Branch data 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 "PieChart.hxx"
21 : : #include "PlottingPositionHelper.hxx"
22 : : #include "ShapeFactory.hxx"
23 : : #include "PolarLabelPositionHelper.hxx"
24 : : #include "macros.hxx"
25 : : #include "CommonConverters.hxx"
26 : : #include "ViewDefines.hxx"
27 : : #include "ObjectIdentifier.hxx"
28 : :
29 : : #include <com/sun/star/chart/DataLabelPlacement.hpp>
30 : : #include <com/sun/star/chart2/XColorScheme.hpp>
31 : :
32 : : #include <com/sun/star/container/XChild.hpp>
33 : : #include <rtl/math.hxx>
34 : :
35 : : #include <boost/scoped_ptr.hpp>
36 : :
37 : : //.............................................................................
38 : : namespace chart
39 : : {
40 : : //.............................................................................
41 : : using namespace ::com::sun::star;
42 : : using namespace ::com::sun::star::chart2;
43 : :
44 : : class PiePositionHelper : public PolarPlottingPositionHelper
45 : : {
46 : : public:
47 : : PiePositionHelper( NormalAxis eNormalAxis, double fAngleDegreeOffset );
48 : : virtual ~PiePositionHelper();
49 : :
50 : : bool getInnerAndOuterRadius( double fCategoryX, double& fLogicInnerRadius, double& fLogicOuterRadius, bool bUseRings, double fMaxOffset ) const;
51 : :
52 : : public:
53 : : //Distance between different category rings, seen relative to width of a ring:
54 : : double m_fRingDistance; //>=0 m_fRingDistance=1 --> distance == width
55 : : };
56 : :
57 : 19 : PiePositionHelper::PiePositionHelper( NormalAxis eNormalAxis, double fAngleDegreeOffset )
58 : : : PolarPlottingPositionHelper(eNormalAxis)
59 : 19 : , m_fRingDistance(0.0)
60 : : {
61 : 19 : m_fRadiusOffset = 0.0;
62 : 19 : m_fAngleDegreeOffset = fAngleDegreeOffset;
63 : 19 : }
64 : :
65 : 19 : PiePositionHelper::~PiePositionHelper()
66 : : {
67 [ - + ]: 38 : }
68 : :
69 : 152 : bool PiePositionHelper::getInnerAndOuterRadius( double fCategoryX
70 : : , double& fLogicInnerRadius, double& fLogicOuterRadius
71 : : , bool bUseRings, double fMaxOffset ) const
72 : : {
73 [ + - ]: 152 : if( !bUseRings )
74 : 152 : fCategoryX = 1.0;
75 : :
76 : 152 : bool bIsVisible = true;
77 : 152 : double fLogicInner = fCategoryX -0.5+m_fRingDistance/2.0;
78 : 152 : double fLogicOuter = fCategoryX +0.5-m_fRingDistance/2.0;
79 : :
80 [ + - ]: 152 : if( !isMathematicalOrientationRadius() )
81 : : {
82 : : //in this case the given getMaximumX() was not corrcect instead the minimum should have been smaller by fMaxOffset
83 : : //but during getMaximumX and getMimumX we do not know the axis orientation
84 : 152 : fLogicInner += fMaxOffset;
85 : 152 : fLogicOuter += fMaxOffset;
86 : : }
87 : :
88 [ - + ]: 152 : if( fLogicInner >= getLogicMaxX() )
89 : 0 : return false;
90 [ - + ]: 152 : if( fLogicOuter <= getLogicMinX() )
91 : 0 : return false;
92 : :
93 [ - + ]: 152 : if( fLogicInner < getLogicMinX() )
94 : 0 : fLogicInner = getLogicMinX();
95 [ - + ]: 152 : if( fLogicOuter > getLogicMaxX() )
96 : 0 : fLogicOuter = getLogicMaxX();
97 : :
98 : 152 : fLogicInnerRadius = fLogicInner;
99 : 152 : fLogicOuterRadius = fLogicOuter;
100 [ + - ]: 152 : if( !isMathematicalOrientationRadius() )
101 : 152 : std::swap(fLogicInnerRadius,fLogicOuterRadius);
102 : 152 : return bIsVisible;
103 : : }
104 : :
105 : : //-----------------------------------------------------------------------------
106 : : //-----------------------------------------------------------------------------
107 : : //-----------------------------------------------------------------------------
108 : :
109 : 19 : PieChart::PieChart( const uno::Reference<XChartType>& xChartTypeModel
110 : : , sal_Int32 nDimensionCount
111 : : , bool bExcludingPositioning )
112 : : : VSeriesPlotter( xChartTypeModel, nDimensionCount )
113 [ - + ][ + - ]: 19 : , m_pPosHelper( new PiePositionHelper( NormalAxis_Z, (m_nDimension==3)?0.0:90.0 ) )
114 : : , m_bUseRings(false)
115 [ + - ][ + - ]: 38 : , m_bSizeExcludesLabelsAndExplodedSegments(bExcludingPositioning)
116 : : {
117 : 19 : ::rtl::math::setNan(&m_fMaxOffset);
118 : :
119 : 19 : PlotterBase::m_pPosHelper = m_pPosHelper;
120 : 19 : VSeriesPlotter::m_pMainPosHelper = m_pPosHelper;
121 : 19 : m_pPosHelper->m_fRadiusOffset = 0.0;
122 : 19 : m_pPosHelper->m_fRingDistance = 0.0;
123 : :
124 [ + - ]: 19 : uno::Reference< beans::XPropertySet > xChartTypeProps( xChartTypeModel, uno::UNO_QUERY );
125 [ + - ]: 19 : if( xChartTypeProps.is() ) try
126 : : {
127 [ + - ][ + - ]: 19 : xChartTypeProps->getPropertyValue( C2U( "UseRings" )) >>= m_bUseRings;
[ + - ][ # # ]
128 [ - + ]: 19 : if( m_bUseRings )
129 : : {
130 : 0 : m_pPosHelper->m_fRadiusOffset = 1.0;
131 [ # # ]: 0 : if( nDimensionCount==3 )
132 : 0 : m_pPosHelper->m_fRingDistance = 0.1;
133 : : }
134 : : }
135 [ # # ]: 0 : catch( const uno::Exception& e )
136 : : {
137 : : ASSERT_EXCEPTION( e );
138 : 19 : }
139 : 19 : }
140 : :
141 : 19 : PieChart::~PieChart()
142 : : {
143 [ + - ][ + - ]: 19 : delete m_pPosHelper;
144 [ - + ]: 38 : }
145 : :
146 : : //-----------------------------------------------------------------
147 : :
148 : 19 : void PieChart::setScales( const std::vector< ExplicitScaleData >& rScales, bool /* bSwapXAndYAxis */ )
149 : : {
150 : : OSL_ENSURE(m_nDimension<=static_cast<sal_Int32>(rScales.size()),"Dimension of Plotter does not fit two dimension of given scale sequence");
151 : 19 : m_pPosHelper->setScales( rScales, true );
152 : 19 : }
153 : :
154 : : //-----------------------------------------------------------------
155 : :
156 : 19 : drawing::Direction3D PieChart::getPreferredDiagramAspectRatio() const
157 : : {
158 [ - + ]: 19 : if( m_nDimension == 3 )
159 : 0 : return drawing::Direction3D(1,1,0.25);
160 : 19 : return drawing::Direction3D(1,1,1);
161 : : }
162 : :
163 : 0 : bool PieChart::keepAspectRatio() const
164 : : {
165 [ # # ]: 0 : if( m_nDimension == 3 )
166 : 0 : return false;
167 : 0 : return true;
168 : : }
169 : :
170 : 19 : bool PieChart::shouldSnapRectToUsedArea()
171 : : {
172 : 19 : return true;
173 : : }
174 : :
175 : 152 : uno::Reference< drawing::XShape > PieChart::createDataPoint(
176 : : const uno::Reference< drawing::XShapes >& xTarget
177 : : , const uno::Reference< beans::XPropertySet >& xObjectProperties
178 : : , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree
179 : : , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius
180 : : , double fLogicZ, double fDepth, double fExplodePercentage
181 : : , tPropertyNameValueMap* pOverwritePropertiesMap )
182 : : {
183 : : //---------------------------
184 : : //transform position:
185 : 152 : drawing::Direction3D aOffset;
186 [ - + ]: 152 : if( !::rtl::math::approxEqual( fExplodePercentage, 0.0 ) )
187 : : {
188 : 0 : double fAngle = fUnitCircleStartAngleDegree + fUnitCircleWidthAngleDegree/2.0;
189 : 0 : double fRadius = (fUnitCircleOuterRadius-fUnitCircleInnerRadius)*fExplodePercentage;
190 [ # # ]: 0 : drawing::Position3D aOrigin = m_pPosHelper->transformUnitCircleToScene( 0, 0, fLogicZ );
191 [ # # ]: 0 : drawing::Position3D aNewOrigin = m_pPosHelper->transformUnitCircleToScene( fAngle, fRadius, fLogicZ );
192 [ # # ]: 0 : aOffset = aNewOrigin - aOrigin;
193 : : }
194 : :
195 : : //---------------------------
196 : : //create point
197 [ + - ]: 152 : uno::Reference< drawing::XShape > xShape(0);
198 [ - + ]: 152 : if(m_nDimension==3)
199 : : {
200 : : xShape = m_pShapeFactory->createPieSegment( xTarget
201 : : , fUnitCircleStartAngleDegree, fUnitCircleWidthAngleDegree
202 : : , fUnitCircleInnerRadius, fUnitCircleOuterRadius
203 [ # # # # ]: 0 : , aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() )
204 [ # # ][ # # ]: 0 : , fDepth );
[ # # ]
205 : : }
206 : : else
207 : : {
208 : : xShape = m_pShapeFactory->createPieSegment2D( xTarget
209 : : , fUnitCircleStartAngleDegree, fUnitCircleWidthAngleDegree
210 : : , fUnitCircleInnerRadius, fUnitCircleOuterRadius
211 [ + - ][ + - ]: 152 : , aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() ) );
[ + - ][ + - ]
[ + - ]
212 : : }
213 [ + - ][ + - ]: 152 : this->setMappedProperties( xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), pOverwritePropertiesMap );
214 : 152 : return xShape;
215 : : }
216 : :
217 : 57 : void PieChart::addSeries( VDataSeries* pSeries, sal_Int32 /* zSlot */, sal_Int32 /* xSlot */, sal_Int32 /* ySlot */ )
218 : : {
219 : 57 : VSeriesPlotter::addSeries( pSeries, 0, -1, 0 );
220 : 57 : }
221 : :
222 : 19 : double PieChart::getMinimumX()
223 : : {
224 : 19 : return 0.5;
225 : : }
226 : 171 : double PieChart::getMaxOffset()
227 : : {
228 [ + + ]: 171 : if (!::rtl::math::isNan(m_fMaxOffset))
229 : : // Value already cached. Use it.
230 : 114 : return m_fMaxOffset;
231 : :
232 : 57 : m_fMaxOffset = 0.0;
233 [ - + ]: 57 : if( m_aZSlots.size()<=0 )
234 : 0 : return m_fMaxOffset;
235 [ - + ]: 57 : if( m_aZSlots[0].size()<=0 )
236 : 0 : return m_fMaxOffset;
237 : :
238 : 57 : const ::std::vector< VDataSeries* >& rSeriesList( m_aZSlots[0][0].m_aSeriesVector );
239 [ - + ]: 57 : if( rSeriesList.size()<=0 )
240 : 0 : return m_fMaxOffset;
241 : :
242 : 57 : VDataSeries* pSeries = rSeriesList[0];
243 [ + - ]: 57 : uno::Reference< beans::XPropertySet > xSeriesProp( pSeries->getPropertiesOfSeries() );
244 [ - + ]: 57 : if( !xSeriesProp.is() )
245 : 0 : return m_fMaxOffset;
246 : :
247 : 57 : double fExplodePercentage=0.0;
248 [ + - ][ + - ]: 57 : xSeriesProp->getPropertyValue( C2U( "Offset" )) >>= fExplodePercentage;
[ + - ]
249 [ - + ]: 57 : if(fExplodePercentage>m_fMaxOffset)
250 : 0 : m_fMaxOffset=fExplodePercentage;
251 : :
252 [ + - ]: 57 : if(!m_bSizeExcludesLabelsAndExplodedSegments)
253 : : {
254 [ + - ]: 57 : uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
255 [ + - ][ + - ]: 57 : if( xSeriesProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList )
[ + - ][ + - ]
[ + - ]
256 : : {
257 [ - + ]: 57 : for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;)
258 : : {
259 [ # # ][ # # ]: 0 : uno::Reference< beans::XPropertySet > xPointProp( pSeries->getPropertiesOfPoint(aAttributedDataPointIndexList[nN]) );
260 [ # # ]: 0 : if(xPointProp.is())
261 : : {
262 : 0 : fExplodePercentage=0.0;
263 [ # # ][ # # ]: 0 : xPointProp->getPropertyValue( C2U( "Offset" )) >>= fExplodePercentage;
[ # # ]
264 [ # # ]: 0 : if(fExplodePercentage>m_fMaxOffset)
265 : 0 : m_fMaxOffset=fExplodePercentage;
266 : : }
267 : 0 : }
268 [ + - ]: 57 : }
269 : : }
270 : 171 : return m_fMaxOffset;
271 : : }
272 : 19 : double PieChart::getMaximumX()
273 : : {
274 : 19 : double fMaxOffset = getMaxOffset();
275 [ - + ][ - + ]: 19 : if( m_aZSlots.size()>0 && m_bUseRings)
[ + - ]
276 : 0 : return m_aZSlots[0].size()+0.5+fMaxOffset;
277 : 19 : return 1.5+fMaxOffset;
278 : : }
279 : 19 : double PieChart::getMinimumYInRange( double /* fMinimumX */, double /* fMaximumX */, sal_Int32 /* nAxisIndex */ )
280 : : {
281 : 19 : return 0.0;
282 : : }
283 : :
284 : 19 : double PieChart::getMaximumYInRange( double /* fMinimumX */, double /* fMaximumX */, sal_Int32 /* nAxisIndex */ )
285 : : {
286 : 19 : return 1.0;
287 : : }
288 : :
289 : 38 : bool PieChart::isExpandBorderToIncrementRhythm( sal_Int32 /* nDimensionIndex */ )
290 : : {
291 : 38 : return false;
292 : : }
293 : :
294 : 38 : bool PieChart::isExpandIfValuesCloseToBorder( sal_Int32 /* nDimensionIndex */ )
295 : : {
296 : 38 : return false;
297 : : }
298 : :
299 : 38 : bool PieChart::isExpandWideValuesToZero( sal_Int32 /* nDimensionIndex */ )
300 : : {
301 : 38 : return false;
302 : : }
303 : :
304 : 38 : bool PieChart::isExpandNarrowValuesTowardZero( sal_Int32 /* nDimensionIndex */ )
305 : : {
306 : 38 : return false;
307 : : }
308 : :
309 : 0 : bool PieChart::isSeperateStackingForDifferentSigns( sal_Int32 /* nDimensionIndex */ )
310 : : {
311 : 0 : return false;
312 : : }
313 : :
314 : 38 : void PieChart::createShapes()
315 : : {
316 [ + - ][ + - ]: 38 : if( m_aZSlots.begin() == m_aZSlots.end() ) //no series
317 : : return;
318 : :
319 : : OSL_ENSURE(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"PieChart is not proper initialized");
320 [ + - ][ + - ]: 38 : if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()))
[ - + ][ + - ]
321 : : return;
322 : :
323 : : //the text labels should be always on top of the other series shapes
324 : : //therefore create an own group for the texts to move them to front
325 : : //(because the text group is created after the series group the texts are displayed on top)
326 : : uno::Reference< drawing::XShapes > xSeriesTarget(
327 [ + - ]: 38 : createGroupShape( m_xLogicTarget,rtl::OUString() ));
328 : : uno::Reference< drawing::XShapes > xTextTarget(
329 [ + - ]: 38 : m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() ));
330 : : //---------------------------------------------
331 : : //check necessary here that different Y axis can not be stacked in the same group? ... hm?
332 : :
333 : : //=============================================================================
334 : 38 : ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = m_aZSlots[0].begin();
335 [ + - ]: 38 : const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = m_aZSlots[0].end();
336 : :
337 : 38 : ::std::vector< VDataSeriesGroup >::size_type nExplodeableSlot = 0;
338 [ + - ][ - + ]: 38 : if( m_pPosHelper->isMathematicalOrientationRadius() && m_bUseRings )
[ # # ][ - + ]
339 : 0 : nExplodeableSlot = m_aZSlots[0].size()-1;
340 : :
341 : 38 : m_aLabelInfoList.clear();
342 : 38 : ::rtl::math::setNan(&m_fMaxOffset);
343 : :
344 : : //=============================================================================
345 [ + - ][ + - ]: 76 : for( double fSlotX=0; aXSlotIter != aXSlotEnd && (m_bUseRings||fSlotX<0.5 ); ++aXSlotIter, fSlotX+=1.0 )
[ + - ][ + + ]
[ + + ]
346 : : {
347 : 38 : ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
348 [ - + ]: 38 : if( pSeriesList->size()<=0 )//there should be only one series in each x slot
349 : 0 : continue;
350 : 38 : VDataSeries* pSeries = (*pSeriesList)[0];
351 [ - + ]: 38 : if(!pSeries)
352 : 0 : continue;
353 : :
354 [ + - ]: 38 : m_pPosHelper->m_fAngleDegreeOffset = pSeries->getStartingAngle();
355 : :
356 : 38 : double fLogicYSum = 0.0;
357 : : //iterate through all points to get the sum
358 : 38 : sal_Int32 nPointIndex=0;
359 [ + - ]: 38 : sal_Int32 nPointCount=pSeries->getTotalPointCount();
360 [ + + ]: 190 : for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
361 : : {
362 [ + - ]: 152 : double fY = pSeries->getYValue( nPointIndex );
363 : : if(fY<0.0)
364 : : {
365 : : //@todo warn somehow that negative values are treated as positive
366 : : }
367 [ - + ]: 152 : if( ::rtl::math::isNan(fY) )
368 : 0 : continue;
369 : 152 : fLogicYSum += fabs(fY);
370 : : }
371 [ - + ]: 38 : if(fLogicYSum==0.0)
372 : 0 : continue;
373 : 38 : double fLogicYForNextPoint = 0.0;
374 : : //iterate through all points to create shapes
375 [ + + ]: 190 : for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
376 : : {
377 : : double fLogicInnerRadius, fLogicOuterRadius;
378 [ + - ]: 152 : double fOffset = getMaxOffset();
379 [ + - ]: 152 : bool bIsVisible = m_pPosHelper->getInnerAndOuterRadius( fSlotX+1.0, fLogicInnerRadius, fLogicOuterRadius, m_bUseRings, fOffset );
380 [ - + ]: 152 : if( !bIsVisible )
381 : 0 : continue;
382 : :
383 [ + - ]: 152 : double fDepth = this->getTransformedDepth();
384 : :
385 [ + - ]: 152 : uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShape(pSeries, xSeriesTarget);
386 : : //collect data point information (logic coordinates, style ):
387 [ + - ]: 152 : double fLogicYValue = fabs(pSeries->getYValue( nPointIndex ));
388 [ - + ]: 152 : if( ::rtl::math::isNan(fLogicYValue) )
389 : 0 : continue;
390 [ - + ]: 152 : if(fLogicYValue==0.0)//@todo: continue also if the resolution to small
391 : 0 : continue;
392 : 152 : double fLogicYPos = fLogicYForNextPoint;
393 : 152 : fLogicYForNextPoint += fLogicYValue;
394 : :
395 [ + - ]: 152 : uno::Reference< beans::XPropertySet > xPointProperties = pSeries->getPropertiesOfPoint( nPointIndex );
396 : :
397 : : //iterate through all subsystems to create partial points
398 : : {
399 : : //logic values on angle axis:
400 : 152 : double fLogicStartAngleValue = fLogicYPos/fLogicYSum;
401 : 152 : double fLogicEndAngleValue = (fLogicYPos+fLogicYValue)/fLogicYSum;
402 : :
403 : 152 : double fExplodePercentage=0.0;
404 : 152 : bool bDoExplode = ( nExplodeableSlot == static_cast< ::std::vector< VDataSeriesGroup >::size_type >(fSlotX) );
405 [ + - ]: 152 : if(bDoExplode) try
406 : : {
407 [ + - ][ + - ]: 152 : xPointProperties->getPropertyValue( C2U( "Offset" )) >>= fExplodePercentage;
[ + - ][ # # ]
408 : : }
409 [ # # ]: 0 : catch( const uno::Exception& e )
410 : : {
411 : : ASSERT_EXCEPTION( e );
412 : : }
413 : :
414 : : //---------------------------
415 : : //transforme to unit circle:
416 [ + - ]: 152 : double fUnitCircleWidthAngleDegree = m_pPosHelper->getWidthAngleDegree( fLogicStartAngleValue, fLogicEndAngleValue );
417 [ + - ]: 152 : double fUnitCircleStartAngleDegree = m_pPosHelper->transformToAngleDegree( fLogicStartAngleValue );
418 [ + - ]: 152 : double fUnitCircleInnerRadius = m_pPosHelper->transformToRadius( fLogicInnerRadius );
419 [ + - ]: 152 : double fUnitCircleOuterRadius = m_pPosHelper->transformToRadius( fLogicOuterRadius );
420 : :
421 : : //---------------------------
422 : : //point color:
423 : 152 : boost::scoped_ptr< tPropertyNameValueMap > apOverwritePropertiesMap(NULL);
424 : : {
425 [ + - ][ + - ]: 152 : if(!pSeries->hasPointOwnColor(nPointIndex) && m_xColorScheme.is())
[ + - ][ + - ]
426 : : {
427 [ + - ][ + - ]: 152 : apOverwritePropertiesMap.reset( new tPropertyNameValueMap() );
[ + - ]
428 [ + - ][ + - ]: 304 : (*apOverwritePropertiesMap)[C2U("FillColor")] = uno::makeAny(
429 [ + - ][ + - ]: 456 : m_xColorScheme->getColorByIndex( nPointIndex ));
[ + - ]
430 : : }
431 : : }
432 : :
433 : : //create data point
434 : 152 : double fLogicZ = -0.5;//as defined
435 : : uno::Reference<drawing::XShape> xPointShape(
436 : : createDataPoint( xSeriesGroupShape_Shapes, xPointProperties
437 : : , fUnitCircleStartAngleDegree, fUnitCircleWidthAngleDegree
438 : : , fUnitCircleInnerRadius, fUnitCircleOuterRadius
439 [ + - ]: 152 : , fLogicZ, fDepth, fExplodePercentage, apOverwritePropertiesMap.get() ) );
440 : :
441 : : //create label
442 [ + - ][ - + ]: 152 : if( pSeries->getDataPointLabelIfLabel(nPointIndex) )
443 : : {
444 [ # # ]: 0 : if( !::rtl::math::approxEqual( fExplodePercentage, 0.0 ) )
445 : : {
446 : 0 : double fExplodeOffset = (fUnitCircleOuterRadius-fUnitCircleInnerRadius)*fExplodePercentage;
447 : 0 : fUnitCircleInnerRadius += fExplodeOffset;
448 : 0 : fUnitCircleOuterRadius += fExplodeOffset;
449 : : }
450 : :
451 [ # # ]: 0 : sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nPointIndex, m_xChartTypeModel, m_nDimension, m_pPosHelper->isSwapXAndY() );
452 : 0 : bool bMovementAllowed = ( nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::AVOID_OVERLAP );
453 [ # # ]: 0 : if( bMovementAllowed )
454 : 0 : nLabelPlacement = ::com::sun::star::chart::DataLabelPlacement::OUTSIDE;
455 : :
456 : 0 : LabelAlignment eAlignment(LABEL_ALIGN_CENTER);
457 : 0 : sal_Int32 nScreenValueOffsetInRadiusDirection = 0 ;
458 [ # # ]: 0 : if( nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::OUTSIDE )
459 [ # # ]: 0 : nScreenValueOffsetInRadiusDirection = (3!=m_nDimension) ? 150 : 0;//todo maybe calculate this font height dependent
460 [ # # ]: 0 : else if( nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::INSIDE )
461 [ # # ]: 0 : nScreenValueOffsetInRadiusDirection = (3!=m_nDimension) ? -150 : 0;//todo maybe calculate this font height dependent
462 [ # # ]: 0 : PolarLabelPositionHelper aPolarPosHelper(m_pPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory);
463 : : awt::Point aScreenPosition2D(
464 : : aPolarPosHelper.getLabelScreenPositionAndAlignmentForUnitCircleValues(eAlignment, nLabelPlacement
465 : : , fUnitCircleStartAngleDegree, fUnitCircleWidthAngleDegree
466 [ # # ]: 0 : , fUnitCircleInnerRadius, fUnitCircleOuterRadius, fLogicZ+0.5, 0 ));
467 : :
468 [ # # ]: 0 : PieLabelInfo aPieLabelInfo;
469 [ # # ]: 0 : aPieLabelInfo.aFirstPosition = basegfx::B2IVector( aScreenPosition2D.X, aScreenPosition2D.Y );
470 [ # # ][ # # ]: 0 : awt::Point aOrigin( aPolarPosHelper.transformSceneToScreenPosition( m_pPosHelper->transformUnitCircleToScene( 0.0, 0.0, fLogicZ+1.0 ) ) );
471 [ # # ]: 0 : aPieLabelInfo.aOrigin = basegfx::B2IVector( aOrigin.X, aOrigin.Y );
472 : :
473 : : //add a scaling independent Offset if requested
474 [ # # ]: 0 : if( nScreenValueOffsetInRadiusDirection != 0)
475 : : {
476 : 0 : basegfx::B2IVector aDirection( aScreenPosition2D.X- aOrigin.X, aScreenPosition2D.Y- aOrigin.Y );
477 [ # # ]: 0 : aDirection.setLength(nScreenValueOffsetInRadiusDirection);
478 : 0 : aScreenPosition2D.X += aDirection.getX();
479 : 0 : aScreenPosition2D.Y += aDirection.getY();
480 : : }
481 : :
482 : : aPieLabelInfo.xTextShape = this->createDataLabel( xTextTarget, *pSeries, nPointIndex
483 [ # # ][ # # ]: 0 : , fLogicYValue, fLogicYSum, aScreenPosition2D, eAlignment );
484 : :
485 [ # # ]: 0 : uno::Reference< container::XChild > xChild( aPieLabelInfo.xTextShape, uno::UNO_QUERY );
486 [ # # ]: 0 : if( xChild.is() )
487 [ # # ][ # # ]: 0 : aPieLabelInfo.xLabelGroupShape = uno::Reference<drawing::XShape>( xChild->getParent(), uno::UNO_QUERY );
[ # # ][ # # ]
488 : 0 : aPieLabelInfo.fValue = fLogicYValue;
489 : 0 : aPieLabelInfo.bMovementAllowed = bMovementAllowed;
490 : 0 : aPieLabelInfo.bMoved= false;
491 [ # # ]: 0 : aPieLabelInfo.xTextTarget = xTextTarget;
492 [ # # ][ # # ]: 0 : m_aLabelInfoList.push_back(aPieLabelInfo);
[ # # ]
493 : : }
494 : :
495 [ - + ]: 152 : if(!bDoExplode)
496 : : {
497 : : ShapeFactory::setShapeName( xPointShape
498 [ # # ][ # # ]: 0 : , ObjectIdentifier::createPointCID( pSeries->getPointCID_Stub(), nPointIndex ) );
[ # # ]
499 : : }
500 : : else try
501 : : {
502 : : //enable dragging of outer segments
503 : :
504 : 152 : double fAngle = fUnitCircleStartAngleDegree + fUnitCircleWidthAngleDegree/2.0;
505 : 152 : double fMaxDeltaRadius = fUnitCircleOuterRadius-fUnitCircleInnerRadius;
506 [ + - ]: 152 : drawing::Position3D aOrigin = m_pPosHelper->transformUnitCircleToScene( fAngle, fUnitCircleOuterRadius, fLogicZ );
507 [ + - ]: 152 : drawing::Position3D aNewOrigin = m_pPosHelper->transformUnitCircleToScene( fAngle, fUnitCircleOuterRadius + fMaxDeltaRadius, fLogicZ );
508 : :
509 : 152 : sal_Int32 nOffsetPercent( static_cast<sal_Int32>(fExplodePercentage * 100.0) );
510 : :
511 : : awt::Point aMinimumPosition( PlottingPositionHelper::transformSceneToScreenPosition(
512 [ + - ]: 152 : aOrigin, m_xLogicTarget, m_pShapeFactory, m_nDimension ) );
513 : : awt::Point aMaximumPosition( PlottingPositionHelper::transformSceneToScreenPosition(
514 [ + - ]: 152 : aNewOrigin, m_xLogicTarget, m_pShapeFactory, m_nDimension ) );
515 : :
516 : : //enable draging of piesegments
517 : : rtl::OUString aPointCIDStub( ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT
518 : : , pSeries->getSeriesParticle()
519 [ + - ]: 152 : , ObjectIdentifier::getPieSegmentDragMethodServiceName()
520 : : , ObjectIdentifier::createPieSegmentDragParameterString(
521 : : nOffsetPercent, aMinimumPosition, aMaximumPosition )
522 [ + - ][ + - ]: 304 : ) );
[ + - ]
523 : :
524 : : ShapeFactory::setShapeName( xPointShape
525 [ + - ][ # # ]: 152 : , ObjectIdentifier::createPointCID( aPointCIDStub, nPointIndex ) );
[ + - ]
526 : : }
527 [ # # ]: 0 : catch( const uno::Exception& e )
528 : : {
529 : : ASSERT_EXCEPTION( e );
530 [ + - ]: 152 : }
531 : : }//next series in x slot (next y slot)
532 [ + - ]: 152 : }//next category
533 : 38 : }//next x slot
534 : : //=============================================================================
535 : : //=============================================================================
536 : : //=============================================================================
537 : : /* @todo remove series shapes if empty
538 : : //remove and delete point-group-shape if empty
539 : : if(!xSeriesGroupShape_Shapes->getCount())
540 : : {
541 : : (*aSeriesIter)->m_xShape.set(NULL);
542 : : m_xLogicTarget->remove(xSeriesGroupShape_Shape);
543 : : }
544 : : */
545 : :
546 : : //remove and delete series-group-shape if empty
547 : :
548 : : //... todo
549 : : }
550 : :
551 : : namespace
552 : : {
553 : :
554 : 0 : ::basegfx::B2IRectangle lcl_getRect( const uno::Reference< drawing::XShape >& xShape )
555 : : {
556 : 0 : ::basegfx::B2IRectangle aRect;
557 [ # # ]: 0 : if( xShape.is() )
558 [ # # ][ # # ]: 0 : aRect = BaseGFXHelper::makeRectangle(xShape->getPosition(),xShape->getSize() );
[ # # ]
559 : 0 : return aRect;
560 : : }
561 : :
562 : 0 : bool lcl_isInsidePage( const awt::Point& rPos, const awt::Size& rSize, const awt::Size& rPageSize )
563 : : {
564 [ # # ][ # # ]: 0 : if( rPos.X < 0 || rPos.Y < 0 )
565 : 0 : return false;
566 [ # # ]: 0 : if( (rPos.X + rSize.Width) > rPageSize.Width )
567 : 0 : return false;
568 [ # # ]: 0 : if( (rPos.Y + rSize.Height) > rPageSize.Height )
569 : 0 : return false;
570 : 0 : return true;
571 : : }
572 : :
573 : : }//end anonymous namespace
574 : :
575 : 0 : PieChart::PieLabelInfo::PieLabelInfo()
576 : : : xTextShape(0), xLabelGroupShape(0), aFirstPosition(), aOrigin(), fValue(0.0)
577 [ # # ][ # # ]: 0 : , bMovementAllowed(false), bMoved(false), xTextTarget(0), pPrevious(0),pNext(0)
578 : : {
579 : 0 : }
580 : :
581 : 0 : bool PieChart::PieLabelInfo::moveAwayFrom( const PieChart::PieLabelInfo* pFix, const awt::Size& rPageSize, bool bMoveHalfWay, bool bMoveClockwise, bool bAlternativeMoveDirection )
582 : : {
583 : : //return true if the move was successful
584 [ # # ]: 0 : if(!this->bMovementAllowed)
585 : 0 : return false;
586 : :
587 : 0 : const sal_Int32 nLabelDistanceX = rPageSize.Width/50;
588 : 0 : const sal_Int32 nLabelDistanceY = rPageSize.Height/50;
589 : :
590 [ # # ]: 0 : ::basegfx::B2IRectangle aOverlap( lcl_getRect( this->xLabelGroupShape ) );
591 [ # # ][ # # ]: 0 : aOverlap.intersect( lcl_getRect( pFix->xLabelGroupShape ) );
592 [ # # ][ # # ]: 0 : if( !aOverlap.isEmpty() )
593 : : {
594 : : (void)bAlternativeMoveDirection;//todo
595 : :
596 [ # # ]: 0 : basegfx::B2IVector aRadiusDirection = this->aFirstPosition - this->aOrigin;
597 [ # # ]: 0 : aRadiusDirection.setLength(1.0);
598 : 0 : basegfx::B2IVector aTangentialDirection( -aRadiusDirection.getY(), aRadiusDirection.getX() );
599 : 0 : bool bShiftHorizontal = abs(aTangentialDirection.getX()) > abs(aTangentialDirection.getY());
600 : :
601 [ # # ][ # # ]: 0 : sal_Int32 nShift = bShiftHorizontal ? static_cast<sal_Int32>(aOverlap.getWidth()) : static_cast<sal_Int32>(aOverlap.getHeight());
[ # # ]
602 [ # # ]: 0 : nShift += (bShiftHorizontal ? nLabelDistanceX : nLabelDistanceY);
603 [ # # ]: 0 : if( bMoveHalfWay )
604 : 0 : nShift/=2;
605 [ # # ]: 0 : if(!bMoveClockwise)
606 : 0 : nShift*=-1;
607 [ # # ][ # # ]: 0 : awt::Point aOldPos( this->xLabelGroupShape->getPosition() );
608 [ # # ][ # # ]: 0 : basegfx::B2IVector aNewPos = basegfx::B2IVector( aOldPos.X, aOldPos.Y ) + nShift*aTangentialDirection;
609 : :
610 : : //check whether the new position is ok
611 : 0 : awt::Point aNewAWTPos( aNewPos.getX(), aNewPos.getY() );
612 [ # # ][ # # ]: 0 : if( !lcl_isInsidePage( aNewAWTPos, this->xLabelGroupShape->getSize(), rPageSize ) )
[ # # ]
613 : 0 : return false;
614 : :
615 [ # # ][ # # ]: 0 : this->xLabelGroupShape->setPosition( aNewAWTPos );
616 [ # # ][ # # ]: 0 : this->bMoved = true;
[ # # ]
617 : : }
618 : 0 : return true;
619 : : }
620 : :
621 : 0 : void PieChart::resetLabelPositionsToPreviousState()
622 : : {
623 : 0 : std::vector< PieLabelInfo >::iterator aIt = m_aLabelInfoList.begin();
624 [ # # ]: 0 : std::vector< PieLabelInfo >::const_iterator aEnd = m_aLabelInfoList.end();
625 [ # # ][ # # ]: 0 : for( ;aIt!=aEnd; ++aIt )
626 [ # # ][ # # ]: 0 : aIt->xLabelGroupShape->setPosition(aIt->aPreviousPosition);
627 : 0 : }
628 : :
629 : 0 : bool PieChart::detectLabelOverlapsAndMove( const awt::Size& rPageSize )
630 : : {
631 : : //returns true when there might be more to do
632 : :
633 : : //find borders of a group of overlapping labels
634 : 0 : bool bOverlapFound = false;
635 [ # # ]: 0 : PieLabelInfo* pStart = &(*(m_aLabelInfoList.rbegin()));
636 : 0 : PieLabelInfo* pFirstBorder = 0;
637 : 0 : PieLabelInfo* pSecondBorder = 0;
638 : 0 : PieLabelInfo* pCurrent = pStart;
639 [ # # ]: 0 : do
640 : : {
641 [ # # ]: 0 : ::basegfx::B2IRectangle aPreviousOverlap( lcl_getRect( pCurrent->xLabelGroupShape ) );
642 : 0 : ::basegfx::B2IRectangle aNextOverlap( aPreviousOverlap );
643 [ # # ][ # # ]: 0 : aPreviousOverlap.intersect( lcl_getRect( pCurrent->pPrevious->xLabelGroupShape ) );
644 [ # # ][ # # ]: 0 : aNextOverlap.intersect( lcl_getRect( pCurrent->pNext->xLabelGroupShape ) );
645 : :
646 [ # # ]: 0 : bool bPreviousOverlap = !aPreviousOverlap.isEmpty();
647 [ # # ]: 0 : bool bNextOverlap = !aNextOverlap.isEmpty();
648 [ # # ][ # # ]: 0 : if( bPreviousOverlap || bNextOverlap )
649 : 0 : bOverlapFound = true;
650 [ # # ][ # # ]: 0 : if( !bPreviousOverlap && bNextOverlap )
651 : : {
652 : 0 : pFirstBorder = pCurrent;
653 : : break;
654 : : }
655 : 0 : pCurrent = pCurrent->pNext;
656 : : }
657 : : while( pCurrent != pStart );
658 : :
659 [ # # ]: 0 : if( !bOverlapFound )
660 : 0 : return false;
661 : :
662 [ # # ]: 0 : if( pFirstBorder )
663 : : {
664 : 0 : pCurrent = pFirstBorder;
665 [ # # ]: 0 : do
666 : : {
667 [ # # ]: 0 : ::basegfx::B2IRectangle aPreviousOverlap( lcl_getRect( pCurrent->xLabelGroupShape ) );
668 : 0 : ::basegfx::B2IRectangle aNextOverlap( aPreviousOverlap );
669 [ # # ][ # # ]: 0 : aPreviousOverlap.intersect( lcl_getRect( pCurrent->pPrevious->xLabelGroupShape ) );
670 [ # # ][ # # ]: 0 : aNextOverlap.intersect( lcl_getRect( pCurrent->pNext->xLabelGroupShape ) );
671 : :
672 [ # # ][ # # ]: 0 : if( !aPreviousOverlap.isEmpty() && aNextOverlap.isEmpty() )
[ # # ][ # # ]
[ # # ]
673 : : {
674 : 0 : pSecondBorder = pCurrent;
675 : : break;
676 : : }
677 : 0 : pCurrent = pCurrent->pNext;
678 : : }
679 : : while( pCurrent != pFirstBorder );
680 : : }
681 : :
682 [ # # ][ # # ]: 0 : if( !pFirstBorder || !pSecondBorder )
683 : : {
684 [ # # ]: 0 : pFirstBorder = &(*(m_aLabelInfoList.rbegin()));
685 : 0 : pSecondBorder = &(*(m_aLabelInfoList.begin()));
686 : : }
687 : :
688 : : //find center
689 : 0 : PieLabelInfo* pCenter = pFirstBorder;
690 : 0 : sal_Int32 nOverlapGroupCount = 1;
691 [ # # ]: 0 : for( pCurrent = pFirstBorder ;pCurrent != pSecondBorder; pCurrent = pCurrent->pNext )
692 : 0 : nOverlapGroupCount++;
693 : 0 : sal_Int32 nCenterPos = nOverlapGroupCount/2;
694 : 0 : bool bSingleCenter = nOverlapGroupCount%2 != 0;
695 [ # # ]: 0 : if( bSingleCenter )
696 : 0 : nCenterPos++;
697 [ # # ]: 0 : if(nCenterPos>1)
698 : : {
699 : 0 : pCurrent = pFirstBorder;
700 [ # # ]: 0 : while( --nCenterPos )
701 : 0 : pCurrent = pCurrent->pNext;
702 : 0 : pCenter = pCurrent;
703 : : }
704 : :
705 : : //remind current positions
706 : 0 : pCurrent = pStart;
707 [ # # ]: 0 : do
708 : : {
709 [ # # ][ # # ]: 0 : pCurrent->aPreviousPosition = pCurrent->xLabelGroupShape->getPosition();
710 : 0 : pCurrent = pCurrent->pNext;
711 : : }
712 : : while( pCurrent != pStart );
713 : :
714 : : //
715 : 0 : bool bAlternativeMoveDirection = false;
716 [ # # ][ # # ]: 0 : if( !tryMoveLabels( pFirstBorder, pSecondBorder, pCenter, bSingleCenter, bAlternativeMoveDirection, rPageSize ) )
717 [ # # ]: 0 : tryMoveLabels( pFirstBorder, pSecondBorder, pCenter, bSingleCenter, bAlternativeMoveDirection, rPageSize );
718 : 0 : return true;
719 : : }
720 : :
721 : 0 : bool PieChart::tryMoveLabels( PieLabelInfo* pFirstBorder, PieLabelInfo* pSecondBorder
722 : : , PieLabelInfo* pCenter
723 : : , bool bSingleCenter, bool& rbAlternativeMoveDirection, const awt::Size& rPageSize )
724 : : {
725 [ # # ]: 0 : PieLabelInfo* p1 = bSingleCenter ? pCenter->pPrevious : pCenter;
726 : 0 : PieLabelInfo* p2 = pCenter->pNext;
727 : : //return true when successful
728 : :
729 : 0 : bool bLabelOrderIsAntiClockWise = m_pPosHelper->isMathematicalOrientationAngle();
730 : :
731 : 0 : PieLabelInfo* pCurrent = 0;
732 [ # # ]: 0 : for( pCurrent = p2 ;pCurrent->pPrevious != pSecondBorder; pCurrent = pCurrent->pNext )
733 : : {
734 : 0 : PieLabelInfo* pFix = 0;
735 [ # # ]: 0 : for( pFix = p2->pPrevious ;pFix != pCurrent; pFix = pFix->pNext )
736 : : {
737 [ # # ][ # # ]: 0 : if( !pCurrent->moveAwayFrom( pFix, rPageSize, !bSingleCenter && pCurrent == p2, !bLabelOrderIsAntiClockWise, rbAlternativeMoveDirection ) )
[ # # ]
738 : : {
739 [ # # ]: 0 : if( !rbAlternativeMoveDirection )
740 : : {
741 : 0 : rbAlternativeMoveDirection = true;
742 : 0 : resetLabelPositionsToPreviousState();
743 : 0 : return false;
744 : : }
745 : : }
746 : : }
747 : : }
748 [ # # ]: 0 : for( pCurrent = p1 ;pCurrent->pNext != pFirstBorder; pCurrent = pCurrent->pPrevious )
749 : : {
750 : 0 : PieLabelInfo* pFix = 0;
751 [ # # ]: 0 : for( pFix = p2->pNext ;pFix != pCurrent; pFix = pFix->pPrevious )
752 : : {
753 [ # # ]: 0 : if( !pCurrent->moveAwayFrom( pFix, rPageSize, false, bLabelOrderIsAntiClockWise, rbAlternativeMoveDirection ) )
754 : : {
755 [ # # ]: 0 : if( !rbAlternativeMoveDirection )
756 : : {
757 : 0 : rbAlternativeMoveDirection = true;
758 : 0 : resetLabelPositionsToPreviousState();
759 : 0 : return false;
760 : : }
761 : : }
762 : : }
763 : : }
764 : 0 : return true;
765 : : }
766 : :
767 : 19 : void PieChart::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& rPageSize )
768 : : {
769 : : //------------------------------------------------------------------
770 : : //check whether there are any labels that should be moved
771 : 19 : std::vector< PieLabelInfo >::iterator aIt1 = m_aLabelInfoList.begin();
772 [ + - ]: 19 : std::vector< PieLabelInfo >::const_iterator aEnd = m_aLabelInfoList.end();
773 : 19 : bool bMoveableFound = false;
774 [ + - ][ - + ]: 19 : for( ;aIt1!=aEnd; ++aIt1 )
775 : : {
776 [ # # ]: 0 : if(aIt1->bMovementAllowed)
777 : : {
778 : 0 : bMoveableFound = true;
779 : 0 : break;
780 : : }
781 : : }
782 [ - + ]: 19 : if(!bMoveableFound)
783 : : return;
784 : :
785 : 0 : double fPageDiagonaleLength = sqrt( double( rPageSize.Width*rPageSize.Width + rPageSize.Height*rPageSize.Height) );
786 [ # # ]: 0 : if( ::rtl::math::approxEqual( fPageDiagonaleLength, 0.0 ) )
787 : : return;
788 : :
789 : : //------------------------------------------------------------------
790 : : //init next and previous
791 : 0 : aIt1 = m_aLabelInfoList.begin();
792 : 0 : std::vector< PieLabelInfo >::iterator aIt2 = aIt1;
793 [ # # ][ # # ]: 0 : if( aIt1==aEnd )//no need to do anything when we only have one label
794 : : return;
795 [ # # ]: 0 : aIt1->pPrevious = &(*(m_aLabelInfoList.rbegin()));
796 : 0 : ++aIt2;
797 [ # # ][ # # ]: 0 : for( ;aIt2!=aEnd; ++aIt1, ++aIt2 )
798 : : {
799 : 0 : PieLabelInfo& rInfo1( *aIt1 );
800 : 0 : PieLabelInfo& rInfo2( *aIt2 );
801 : 0 : rInfo1.pNext = &rInfo2;
802 : 0 : rInfo2.pPrevious = &rInfo1;
803 : : }
804 : 0 : aIt1->pNext = &(*(m_aLabelInfoList.begin()));
805 : :
806 : :
807 : : //------------------------------------------------------------------
808 : : //detect overlaps and move
809 : 0 : sal_Int32 nMaxIterations = 50;
810 [ # # ][ # # ]: 0 : while( detectLabelOverlapsAndMove( rPageSize ) && nMaxIterations > 0 )
[ # # ][ # # ]
811 : 0 : nMaxIterations--;
812 : :
813 : : //------------------------------------------------------------------
814 : : //create connection lines for the moved labels
815 [ # # ]: 0 : aEnd = m_aLabelInfoList.end();
816 [ # # ]: 0 : VLineProperties aVLineProperties;
817 [ # # ][ # # ]: 0 : for( aIt1 = m_aLabelInfoList.begin(); aIt1!=aEnd; ++aIt1 )
818 : : {
819 : 0 : PieLabelInfo& rInfo( *aIt1 );
820 [ # # ]: 0 : if( rInfo.bMoved )
821 : : {
822 : 0 : sal_Int32 nX1 = rInfo.aFirstPosition.getX();
823 : 0 : sal_Int32 nY1 = rInfo.aFirstPosition.getY();
824 : 0 : sal_Int32 nX2 = nX1;
825 : 0 : sal_Int32 nY2 = nY1;
826 [ # # ]: 0 : ::basegfx::B2IRectangle aRect( lcl_getRect( rInfo.xLabelGroupShape ) );
827 [ # # ][ # # ]: 0 : if( nX1 < aRect.getMinX() )
828 [ # # ]: 0 : nX2 = aRect.getMinX();
829 [ # # ][ # # ]: 0 : else if( nX1 > aRect.getMaxX() )
830 [ # # ]: 0 : nX2 = aRect.getMaxX();
831 : :
832 [ # # ][ # # ]: 0 : if( nY1 < aRect.getMinY() )
833 [ # # ]: 0 : nY2 = aRect.getMinY();
834 [ # # ][ # # ]: 0 : else if( nY1 > aRect.getMaxY() )
835 [ # # ]: 0 : nY2 = aRect.getMaxY();
836 : :
837 : :
838 : : //when the line is very short compared to the page size don't create one
839 : 0 : ::basegfx::B2DVector aLength(nX1-nX2, nY1-nY2);
840 [ # # ][ # # ]: 0 : if( (aLength.getLength()/fPageDiagonaleLength) < 0.01 )
841 : 0 : continue;
842 : :
843 [ # # ]: 0 : drawing::PointSequenceSequence aPoints(1);
844 [ # # ][ # # ]: 0 : aPoints[0].realloc(2);
845 [ # # ][ # # ]: 0 : aPoints[0][0].X = nX1;
846 [ # # ][ # # ]: 0 : aPoints[0][0].Y = nY1;
847 [ # # ][ # # ]: 0 : aPoints[0][1].X = nX2;
848 [ # # ][ # # ]: 0 : aPoints[0][1].Y = nY2;
849 : :
850 [ # # ]: 0 : uno::Reference< beans::XPropertySet > xProp( rInfo.xTextShape, uno::UNO_QUERY);
851 [ # # ]: 0 : if( xProp.is() )
852 : : {
853 : 0 : sal_Int32 nColor = 0;
854 [ # # ][ # # ]: 0 : xProp->getPropertyValue(C2U("CharColor")) >>= nColor;
[ # # ]
855 [ # # ]: 0 : if( nColor != -1 )//automatic font color does not work for lines -> fallback to black
856 [ # # ]: 0 : aVLineProperties.Color = uno::makeAny(nColor);
857 : : }
858 [ # # ][ # # ]: 0 : m_pShapeFactory->createLine2D( rInfo.xTextTarget, aPoints, &aVLineProperties );
[ # # ]
859 : : }
860 : 19 : }
861 : : }
862 : :
863 : : //.............................................................................
864 : : } //namespace chart
865 : : //.............................................................................
866 : :
867 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|