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 "VSeriesPlotter.hxx"
21 : : #include "ShapeFactory.hxx"
22 : : #include "chartview/ExplicitValueProvider.hxx"
23 : :
24 : : #include "CommonConverters.hxx"
25 : : #include "macros.hxx"
26 : : #include "ViewDefines.hxx"
27 : : #include "ObjectIdentifier.hxx"
28 : : #include "StatisticsHelper.hxx"
29 : : #include "PlottingPositionHelper.hxx"
30 : : #include "LabelPositionHelper.hxx"
31 : : #include "ChartTypeHelper.hxx"
32 : : #include "Clipping.hxx"
33 : : #include "servicenames_charttypes.hxx"
34 : : #include "NumberFormatterWrapper.hxx"
35 : : #include "ContainerHelper.hxx"
36 : : #include "DataSeriesHelper.hxx"
37 : : #include "RegressionCurveHelper.hxx"
38 : : #include "VLegendSymbolFactory.hxx"
39 : : #include "FormattedStringHelper.hxx"
40 : : #include "ResId.hxx"
41 : : #include "Strings.hrc"
42 : : #include "RelativePositionHelper.hxx"
43 : : #include "DateHelper.hxx"
44 : : #include "DiagramHelper.hxx"
45 : :
46 : : //only for creation: @todo remove if all plotter are uno components and instanciated via servicefactory
47 : : #include "BarChart.hxx"
48 : : #include "PieChart.hxx"
49 : : #include "AreaChart.hxx"
50 : : #include "CandleStickChart.hxx"
51 : : #include "BubbleChart.hxx"
52 : : //
53 : :
54 : : #include <com/sun/star/chart/ErrorBarStyle.hpp>
55 : : #include <com/sun/star/chart/TimeUnit.hpp>
56 : : #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
57 : : #include <com/sun/star/container/XChild.hpp>
58 : : #include <com/sun/star/chart2/RelativePosition.hpp>
59 : : #include <editeng/unoprnms.hxx>
60 : : #include <tools/color.hxx>
61 : : // header for class OUStringBuffer
62 : : #include <rtl/ustrbuf.hxx>
63 : : #include <rtl/math.hxx>
64 : : #include <basegfx/vector/b2dvector.hxx>
65 : : #include <com/sun/star/drawing/LineStyle.hpp>
66 : : #include <com/sun/star/util/XCloneable.hpp>
67 : :
68 : : #include <svx/unoshape.hxx>
69 : :
70 : : #include <functional>
71 : : #include <map>
72 : :
73 : : #include <boost/ptr_container/ptr_map.hpp>
74 : :
75 : : namespace chart {
76 : :
77 : : using namespace ::com::sun::star;
78 : : using namespace ::com::sun::star::chart2;
79 : : using ::com::sun::star::uno::Reference;
80 : : using ::com::sun::star::uno::Sequence;
81 : : using rtl::OUString;
82 : :
83 : : //-----------------------------------------------------------------------------
84 : :
85 : 13820 : VDataSeriesGroup::CachedYValues::CachedYValues()
86 : : : m_bValuesDirty(true)
87 : : , m_fMinimumY(0.0)
88 : 13820 : , m_fMaximumY(0.0)
89 : : {
90 : 13820 : }
91 : :
92 : 0 : VDataSeriesGroup::VDataSeriesGroup()
93 : : : m_aSeriesVector()
94 : : , m_bMaxPointCountDirty(true)
95 : : , m_nMaxPointCount(0)
96 [ # # ]: 0 : , m_aListOfCachedYValues()
97 : : {
98 : 0 : }
99 : :
100 : 3194 : VDataSeriesGroup::VDataSeriesGroup( VDataSeries* pSeries )
101 : : : m_aSeriesVector(1,pSeries)
102 : : , m_bMaxPointCountDirty(true)
103 : : , m_nMaxPointCount(0)
104 [ + - ][ + - ]: 3194 : , m_aListOfCachedYValues()
105 : : {
106 : 3194 : }
107 : :
108 : 17077 : VDataSeriesGroup::~VDataSeriesGroup()
109 : : {
110 [ - + ]: 17077 : }
111 : :
112 : 3194 : void VDataSeriesGroup::deleteSeries()
113 : : {
114 : : //delete all data series help objects:
115 [ + - ]: 3194 : ::std::vector< VDataSeries* >::const_iterator aIter = m_aSeriesVector.begin();
116 [ + - ]: 3194 : const ::std::vector< VDataSeries* >::const_iterator aEnd = m_aSeriesVector.end();
117 [ + - ][ + + ]: 6400 : for( ; aIter != aEnd; ++aIter )
118 : : {
119 [ + - ][ + - ]: 3206 : delete *aIter;
120 : : }
121 : 3194 : m_aSeriesVector.clear();
122 : 3194 : }
123 : :
124 : 12 : void VDataSeriesGroup::addSeries( VDataSeries* pSeries )
125 : : {
126 : 12 : m_aSeriesVector.push_back(pSeries);
127 : 12 : m_bMaxPointCountDirty=true;
128 : 12 : }
129 : :
130 : 12 : sal_Int32 VDataSeriesGroup::getSeriesCount() const
131 : : {
132 : 12 : return m_aSeriesVector.size();
133 : : }
134 : :
135 : : //-----------------------------------------------------------------------------
136 : :
137 : 981 : VSeriesPlotter::VSeriesPlotter( const uno::Reference<XChartType>& xChartTypeModel
138 : : , sal_Int32 nDimensionCount, bool bCategoryXAxis )
139 : : : PlotterBase( nDimensionCount )
140 : : , m_pMainPosHelper( 0 )
141 : : , m_xChartTypeModel(xChartTypeModel)
142 : : , m_xChartTypeModelProps( uno::Reference< beans::XPropertySet >::query( xChartTypeModel ))
143 : : , m_aZSlots()
144 : : , m_bCategoryXAxis(bCategoryXAxis)
145 : : , m_nTimeResolution(::com::sun::star::chart::TimeUnit::DAY)
146 : : , m_aNullDate(30,12,1899)
147 : : , m_xColorScheme()
148 : : , m_pExplicitCategoriesProvider(0)
149 [ + - ][ + - ]: 981 : , m_bPointsWereSkipped(false)
[ + - ][ + - ]
[ + - ][ + - ]
150 : : {
151 : : OSL_POSTCOND(m_xChartTypeModel.is(),"no XChartType available in view, fallback to default values may be wrong");
152 : 981 : }
153 : :
154 [ + - ][ + - ]: 981 : VSeriesPlotter::~VSeriesPlotter()
155 : : {
156 : : //delete all data series help objects:
157 : 981 : ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
158 [ + - ]: 981 : const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
159 [ + - ][ + + ]: 1980 : for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
160 : : {
161 : 999 : ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
162 [ + - ]: 999 : const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
163 [ + - ][ + + ]: 4193 : for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
164 : : {
165 [ + - ]: 3194 : aXSlotIter->deleteSeries();
166 : : }
167 : 999 : aZSlotIter->clear();
168 : : }
169 : 981 : m_aZSlots.clear();
170 : :
171 : 981 : tSecondaryPosHelperMap::iterator aPosIt = m_aSecondaryPosHelperMap.begin();
172 [ - + ]: 981 : while( aPosIt != m_aSecondaryPosHelperMap.end() )
173 : : {
174 : 0 : PlottingPositionHelper* pPosHelper = aPosIt->second;
175 [ # # ]: 0 : if( pPosHelper )
176 [ # # ][ # # ]: 0 : delete pPosHelper;
177 : 0 : ++aPosIt;
178 : : }
179 : 981 : m_aSecondaryPosHelperMap.clear();
180 : :
181 : 981 : m_aSecondaryValueScales.clear();
182 [ - + ]: 981 : }
183 : :
184 : 3206 : void VSeriesPlotter::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot )
185 : : {
186 : : //take ownership of pSeries
187 : :
188 : : OSL_PRECOND( pSeries, "series to add is NULL" );
189 [ - + ]: 3206 : if(!pSeries)
190 : 3206 : return;
191 : :
192 [ + - ]: 3206 : if(m_bCategoryXAxis)
193 : : {
194 [ + - ][ - + ]: 3206 : if( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() )
[ - + ]
195 [ # # ]: 0 : pSeries->setXValues( m_pExplicitCategoriesProvider->getOriginalCategories() );
196 : : else
197 : 3206 : pSeries->setCategoryXAxis();
198 : : }
199 : : else
200 : : {
201 [ # # ]: 0 : if( m_pExplicitCategoriesProvider )
202 [ # # ]: 0 : pSeries->setXValuesIfNone( m_pExplicitCategoriesProvider->getOriginalCategories() );
203 : : }
204 : :
205 [ + - ][ + + ]: 3206 : if(zSlot<0 || zSlot>=static_cast<sal_Int32>(m_aZSlots.size()))
[ + + ]
206 : : {
207 : : //new z slot
208 [ + - ]: 116 : ::std::vector< VDataSeriesGroup > aZSlot;
209 [ + - ][ + - ]: 116 : aZSlot.push_back( VDataSeriesGroup(pSeries) );
210 [ + - ]: 116 : m_aZSlots.push_back( aZSlot );
211 : : }
212 : : else
213 : : {
214 : : //existing zslot
215 : 3090 : ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[zSlot];
216 : :
217 [ + + ][ + + ]: 3090 : if(xSlot<0 || xSlot>=static_cast<sal_Int32>(rXSlots.size()))
[ + + ]
218 : : {
219 : : //append the series to already existing x series
220 [ + - ]: 3078 : rXSlots.push_back( VDataSeriesGroup(pSeries) );
221 : : }
222 : : else
223 : : {
224 : : //x slot is already occupied
225 : : //y slot decides what to do:
226 : :
227 : 12 : VDataSeriesGroup& rYSlots = rXSlots[xSlot];
228 : 12 : sal_Int32 nYSlotCount = rYSlots.getSeriesCount();
229 : :
230 [ + - ]: 12 : if( ySlot < -1 )
231 : : {
232 : : //move all existing series in the xSlot to next slot
233 : : //@todo
234 : : OSL_FAIL( "Not implemented yet");
235 : : }
236 [ + - ][ + - ]: 12 : else if( ySlot == -1 || ySlot >= nYSlotCount)
237 : : {
238 : : //append the series to already existing y series
239 : 12 : rYSlots.addSeries(pSeries);
240 : : }
241 : : else
242 : : {
243 : : //y slot is already occupied
244 : : //insert at given y and x position
245 : :
246 : : //@todo
247 : : OSL_FAIL( "Not implemented yet");
248 : : }
249 : : }
250 : : }
251 : : }
252 : :
253 : 0 : drawing::Direction3D VSeriesPlotter::getPreferredDiagramAspectRatio() const
254 : : {
255 : 0 : drawing::Direction3D aRet(1.0,1.0,1.0);
256 [ # # ]: 0 : drawing::Direction3D aScale( m_pPosHelper->getScaledLogicWidth() );
257 : 0 : aRet.DirectionZ = aScale.DirectionZ*0.2;
258 [ # # ]: 0 : if(aRet.DirectionZ>1.0)
259 : 0 : aRet.DirectionZ=1.0;
260 [ # # ]: 0 : if(aRet.DirectionZ>10)
261 : 0 : aRet.DirectionZ=10;
262 : 0 : return aRet;
263 : : }
264 : :
265 : 0 : bool VSeriesPlotter::keepAspectRatio() const
266 : : {
267 : 0 : return true;
268 : : }
269 : :
270 : 19 : void VSeriesPlotter::releaseShapes()
271 : : {
272 : 19 : ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
273 [ + - ]: 19 : const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
274 [ + - ][ + + ]: 38 : for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
275 : : {
276 : 19 : ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
277 [ + - ]: 19 : const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
278 [ + - ][ + + ]: 76 : for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
279 : : {
280 : 57 : ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
281 : :
282 : 57 : ::std::vector< VDataSeries* >::iterator aSeriesIter = pSeriesList->begin();
283 [ + - ]: 57 : const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
284 : :
285 : : //iterate through all series in this x slot
286 [ + - ][ + + ]: 114 : for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
287 : : {
288 : 57 : VDataSeries* pSeries( *aSeriesIter );
289 [ + - ]: 57 : pSeries->releaseShapes();
290 : : }
291 : : }
292 : : }
293 : 19 : }
294 : :
295 : 11909 : uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShape( VDataSeries* pDataSeries
296 : : , const uno::Reference< drawing::XShapes >& xTarget )
297 : : {
298 : 11909 : uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xGroupShape );
299 [ + + ]: 11909 : if( !xShapes.is() )
300 : : {
301 : : //create a group shape for this series and add to logic target:
302 [ + - ][ + - ]: 3187 : xShapes = createGroupShape( xTarget,pDataSeries->getCID() );
[ + - ]
303 [ + - ]: 3187 : pDataSeries->m_xGroupShape = xShapes;
304 : : }
305 : 11909 : return xShapes;
306 : : }
307 : :
308 : 2538 : uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShapeFrontChild( VDataSeries* pDataSeries
309 : : , const uno::Reference< drawing::XShapes >& xTarget )
310 : : {
311 : 2538 : uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xFrontSubGroupShape );
312 [ + + ]: 2538 : if(!xShapes.is())
313 : : {
314 : : //ensure that the series group shape is already created
315 [ + - ]: 296 : uno::Reference< drawing::XShapes > xSeriesShapes( this->getSeriesGroupShape( pDataSeries, xTarget ) );
316 : : //ensure that the back child is created first
317 [ + - ]: 296 : this->getSeriesGroupShapeBackChild( pDataSeries, xTarget );
318 : : //use series group shape as parent for the new created front group shape
319 [ + - ][ + - ]: 296 : xShapes = createGroupShape( xSeriesShapes );
320 [ + - ]: 296 : pDataSeries->m_xFrontSubGroupShape = xShapes;
321 : : }
322 : 2538 : return xShapes;
323 : : }
324 : :
325 : 592 : uno::Reference< drawing::XShapes > VSeriesPlotter::getSeriesGroupShapeBackChild( VDataSeries* pDataSeries
326 : : , const uno::Reference< drawing::XShapes >& xTarget )
327 : : {
328 : 592 : uno::Reference< drawing::XShapes > xShapes( pDataSeries->m_xBackSubGroupShape );
329 [ + + ]: 592 : if(!xShapes.is())
330 : : {
331 : : //ensure that the series group shape is already created
332 [ + - ]: 296 : uno::Reference< drawing::XShapes > xSeriesShapes( this->getSeriesGroupShape( pDataSeries, xTarget ) );
333 : : //use series group shape as parent for the new created back group shape
334 [ + - ][ + - ]: 296 : xShapes = createGroupShape( xSeriesShapes );
335 [ + - ]: 296 : pDataSeries->m_xBackSubGroupShape = xShapes;
336 : : }
337 : 592 : return xShapes;
338 : : }
339 : :
340 : 2272 : uno::Reference< drawing::XShapes > VSeriesPlotter::getLabelsGroupShape( VDataSeries& rDataSeries
341 : : , const uno::Reference< drawing::XShapes >& xTextTarget )
342 : : {
343 : : //xTextTarget needs to be a 2D shape container always!
344 : :
345 : 2272 : uno::Reference< drawing::XShapes > xShapes( rDataSeries.m_xLabelsGroupShape );
346 [ + + ]: 2272 : if(!xShapes.is())
347 : : {
348 : : //create a 2D group shape for texts of this series and add to text target:
349 [ + - ][ + - ]: 400 : xShapes = m_pShapeFactory->createGroup2D( xTextTarget, rDataSeries.getLabelsCID() );
[ + - ]
350 [ + - ]: 400 : rDataSeries.m_xLabelsGroupShape = xShapes;
351 : : }
352 : 2272 : return xShapes;
353 : : }
354 : :
355 : 4671 : uno::Reference< drawing::XShapes > VSeriesPlotter::getErrorBarsGroupShape( VDataSeries& rDataSeries
356 : : , const uno::Reference< drawing::XShapes >& xTarget
357 : : , bool bYError )
358 : : {
359 : : uno::Reference< ::com::sun::star::drawing::XShapes > &rShapeGroup =
360 [ + - ]: 4671 : bYError ? rDataSeries.m_xErrorYBarsGroupShape : rDataSeries.m_xErrorXBarsGroupShape;
361 : :
362 : 4671 : uno::Reference< drawing::XShapes > xShapes( rShapeGroup );
363 [ + + ]: 4671 : if(!xShapes.is())
364 : : {
365 : : //create a group shape for this series and add to logic target:
366 [ + - ][ + - ]: 1080 : xShapes = this->createGroupShape( xTarget,rDataSeries.getErrorBarsCID(bYError) );
[ + - ]
367 [ + - ]: 1080 : rShapeGroup = xShapes;
368 : : }
369 : 4671 : return xShapes;
370 : :
371 : : }
372 : :
373 : 2282 : OUString VSeriesPlotter::getLabelTextForValue( VDataSeries& rDataSeries
374 : : , sal_Int32 nPointIndex
375 : : , double fValue
376 : : , bool bAsPercentage )
377 : : {
378 : 2282 : OUString aNumber;
379 : :
380 [ + - ]: 2282 : if( m_apNumberFormatterWrapper.get())
381 : : {
382 : 2282 : sal_Int32 nNumberFormatKey = 0;
383 [ + - ][ - + ]: 2282 : if( rDataSeries.hasExplicitNumberFormat(nPointIndex,bAsPercentage) )
384 [ # # ]: 0 : nNumberFormatKey = rDataSeries.getExplicitNumberFormat(nPointIndex,bAsPercentage);
385 [ + + ]: 2282 : else if( bAsPercentage )
386 : : {
387 [ + - ][ + - ]: 91 : sal_Int32 nPercentFormat = DiagramHelper::getPercentNumberFormat( m_apNumberFormatterWrapper->getNumberFormatsSupplier() );
388 [ + - ]: 91 : if( nPercentFormat != -1 )
389 : 91 : nNumberFormatKey = nPercentFormat;
390 : : }
391 : : else
392 : : {
393 [ + - ][ + - ]: 2191 : if( rDataSeries.shouldLabelNumberFormatKeyBeDetectedFromYAxis() && m_aAxesNumberFormats.hasFormat(1,rDataSeries.getAttachedAxisIndex()) ) //y-axis
[ + - ][ + - ]
[ - + ][ - + ]
394 [ # # ][ # # ]: 0 : nNumberFormatKey = m_aAxesNumberFormats.getFormat(1,rDataSeries.getAttachedAxisIndex());
395 : : else
396 [ + - ]: 2191 : nNumberFormatKey = rDataSeries.detectNumberFormatKey( nPointIndex );
397 : : }
398 [ - + ]: 2282 : if(nNumberFormatKey<0)
399 : 0 : nNumberFormatKey=0;
400 : :
401 : 2282 : sal_Int32 nLabelCol = 0;
402 : : bool bColChanged;
403 : : aNumber = m_apNumberFormatterWrapper->getFormattedString(
404 [ + - ]: 2282 : nNumberFormatKey, fValue, nLabelCol, bColChanged );
405 : : //@todo: change color of label if bColChanged is true
406 : : }
407 : : else
408 : : {
409 : 0 : sal_Unicode cDecSeparator = '.';//@todo get this locale dependent
410 : : aNumber = ::rtl::math::doubleToUString( fValue, rtl_math_StringFormat_G /*rtl_math_StringFormat*/
411 : 0 : , 3/*DecPlaces*/ , cDecSeparator, false /*bEraseTrailingDecZeros*/ );
412 : : }
413 : 2282 : return aNumber;
414 : : }
415 : :
416 : 2272 : uno::Reference< drawing::XShape > VSeriesPlotter::createDataLabel( const uno::Reference< drawing::XShapes >& xTarget
417 : : , VDataSeries& rDataSeries
418 : : , sal_Int32 nPointIndex
419 : : , double fValue
420 : : , double fSumValue
421 : : , const awt::Point& rScreenPosition2D
422 : : , LabelAlignment eAlignment
423 : : , sal_Int32 nOffset )
424 : : {
425 : 2272 : uno::Reference< drawing::XShape > xTextShape;
426 : :
427 : : try
428 : : {
429 : 2272 : awt::Point aScreenPosition2D(rScreenPosition2D);
430 [ - + ]: 2272 : if(LABEL_ALIGN_LEFT==eAlignment)
431 : 0 : aScreenPosition2D.X -= nOffset;
432 [ - + ]: 2272 : else if(LABEL_ALIGN_RIGHT==eAlignment)
433 : 0 : aScreenPosition2D.X += nOffset;
434 [ + - ]: 2272 : else if(LABEL_ALIGN_TOP==eAlignment)
435 : 2272 : aScreenPosition2D.Y -= nOffset;
436 [ # # ]: 0 : else if(LABEL_ALIGN_BOTTOM==eAlignment)
437 : 0 : aScreenPosition2D.Y += nOffset;
438 : :
439 : : uno::Reference< drawing::XShapes > xTarget_(
440 : : m_pShapeFactory->createGroup2D( this->getLabelsGroupShape(rDataSeries, xTarget)
441 [ + - ][ + - ]: 2272 : , ObjectIdentifier::createPointCID( rDataSeries.getLabelCID_Stub(),nPointIndex ) ) );
[ + - ][ + - ]
442 : :
443 : : //check whether the label needs to be created and how:
444 [ + - ]: 2272 : DataPointLabel* pLabel = rDataSeries.getDataPointLabelIfLabel( nPointIndex );
445 : :
446 [ - + ]: 2272 : if( !pLabel )
447 : : return xTextShape;
448 : :
449 : : //------------------------------------------------
450 : : //prepare legend symbol
451 : :
452 : 2272 : float fViewFontSize( 10.0 );
453 : : {
454 [ + - ]: 2272 : uno::Reference< beans::XPropertySet > xProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) );
455 [ + - ]: 2272 : if( xProps.is() )
456 [ + - ][ + - ]: 2272 : xProps->getPropertyValue( C2U( "CharHeight" )) >>= fViewFontSize;
[ + - ]
457 : : // pt -> 1/100th mm
458 : 2272 : fViewFontSize *= (2540.0f / 72.0f);
459 : : }
460 : 2272 : Reference< drawing::XShape > xSymbol;
461 [ - + ]: 2272 : if(pLabel->ShowLegendSymbol)
462 : : {
463 : 0 : sal_Int32 nSymbolHeigth = static_cast< sal_Int32 >( fViewFontSize * 0.6 );
464 [ # # ]: 0 : awt::Size aCurrentRatio = this->getPreferredLegendKeyAspectRatio();
465 : 0 : sal_Int32 nSymbolWidth = aCurrentRatio.Width;
466 [ # # ]: 0 : if( aCurrentRatio.Height > 0 )
467 : : {
468 : 0 : nSymbolWidth = nSymbolHeigth* aCurrentRatio.Width/aCurrentRatio.Height;
469 : : }
470 : 0 : awt::Size aMaxSymbolExtent( nSymbolWidth, nSymbolHeigth );
471 : :
472 [ # # ][ # # ]: 0 : if( rDataSeries.isVaryColorsByPoint() )
473 [ # # ][ # # ]: 0 : xSymbol.set( VSeriesPlotter::createLegendSymbolForPoint( aMaxSymbolExtent, rDataSeries, nPointIndex, xTarget_, m_xShapeFactory ) );
474 : : else
475 [ # # ][ # # ]: 0 : xSymbol.set( VSeriesPlotter::createLegendSymbolForSeries( aMaxSymbolExtent, rDataSeries, xTarget_, m_xShapeFactory ) );
476 : :
477 : : }
478 : : //prepare text
479 : 2272 : ::rtl::OUStringBuffer aText;
480 : 2272 : ::rtl::OUString aSeparator(sal_Unicode(' '));
481 : 2272 : double fRotationDegrees = 0.0;
482 : : try
483 : : {
484 [ + - ]: 2272 : uno::Reference< beans::XPropertySet > xPointProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) );
485 [ + - ]: 2272 : if(xPointProps.is())
486 : : {
487 [ + - ][ + - ]: 2272 : xPointProps->getPropertyValue( C2U( "LabelSeparator" ) ) >>= aSeparator;
[ + - ]
488 [ + - ][ + - ]: 2272 : xPointProps->getPropertyValue( C2U( "TextRotation" ) ) >>= fRotationDegrees;
[ + - ]
489 [ # # ]: 2272 : }
490 : : }
491 [ # # ]: 0 : catch( const uno::Exception& e )
492 : : {
493 : : ASSERT_EXCEPTION( e );
494 : : }
495 [ + - ]: 2272 : bool bMultiLineLabel = aSeparator.equals(C2U("\n"));;
496 : 2272 : sal_Int32 nLineCountForSymbolsize = 0;
497 : : {
498 [ + + ]: 2272 : if(pLabel->ShowCategoryName)
499 : : {
500 [ + - ]: 2218 : if( m_pExplicitCategoriesProvider )
501 : : {
502 [ + - ]: 2218 : Sequence< OUString > aCategories( m_pExplicitCategoriesProvider->getSimpleCategories() );
503 [ + - ][ + - ]: 2218 : if( nPointIndex >= 0 && nPointIndex < aCategories.getLength() )
[ + - ]
504 : : {
505 [ + - ][ + - ]: 2218 : aText.append( aCategories[nPointIndex] );
506 : 2218 : ++nLineCountForSymbolsize;
507 [ + - ]: 2218 : }
508 : : }
509 : : }
510 : :
511 [ + + ]: 2272 : if(pLabel->ShowNumber)
512 : : {
513 : : OUString aNumber( this->getLabelTextForValue( rDataSeries
514 [ + - ]: 2191 : , nPointIndex, fValue, false /*bAsPercentage*/ ) );
515 [ + - ]: 2191 : if( !aNumber.isEmpty() )
516 : : {
517 [ + + ]: 2191 : if(aText.getLength())
518 [ + - ]: 2177 : aText.append(aSeparator);
519 [ + - ]: 2191 : aText.append(aNumber);
520 : 2191 : ++nLineCountForSymbolsize;
521 : 2191 : }
522 : : }
523 : :
524 [ + + ]: 2272 : if(pLabel->ShowNumberInPercent)
525 : : {
526 [ - + ]: 91 : if(fSumValue==0.0)
527 : 0 : fSumValue=1.0;
528 : 91 : fValue /= fSumValue;
529 [ - + ]: 91 : if( fValue < 0 )
530 : 0 : fValue*=-1.0;
531 : :
532 : : OUString aPercentage( this->getLabelTextForValue( rDataSeries
533 [ + - ]: 91 : , nPointIndex, fValue, true /*bAsPercentage*/ ) );
534 [ + - ]: 91 : if( !aPercentage.isEmpty() )
535 : : {
536 [ + + ]: 91 : if(aText.getLength())
537 [ + - ]: 51 : aText.append(aSeparator);
538 [ + - ]: 91 : aText.append(aPercentage);
539 : 91 : ++nLineCountForSymbolsize;
540 : 91 : }
541 : : }
542 : : }
543 : : //------------------------------------------------
544 : : //prepare properties for multipropertyset-interface of shape
545 : : tNameSequence* pPropNames;
546 : : tAnySequence* pPropValues;
547 [ + - ][ - + ]: 2272 : if( !rDataSeries.getTextLabelMultiPropertyLists( nPointIndex, pPropNames, pPropValues ) )
548 : : return xTextShape;
549 [ + - ]: 2272 : LabelPositionHelper::changeTextAdjustment( *pPropValues, *pPropNames, eAlignment );
550 : :
551 : : //------------------------------------------------
552 : : //create text shape
553 : : xTextShape = ShapeFactory(m_xShapeFactory).
554 : : createText( xTarget_, aText.makeStringAndClear()
555 [ + - ][ + - ]: 2272 : , *pPropNames, *pPropValues, ShapeFactory::makeTransformation( aScreenPosition2D ) );
[ + - ][ + - ]
[ + - ][ + - ]
556 : :
557 [ - + ]: 2272 : if( !xTextShape.is() )
558 : : return xTextShape;
559 : :
560 [ + - ][ + - ]: 2272 : const awt::Point aUnrotatedTextPos( xTextShape->getPosition() );
561 [ + + ]: 2272 : if( fRotationDegrees != 0.0 )
562 : : {
563 : 138 : const double fDegreesPi( fRotationDegrees * ( F_PI / -180.0 ) );
564 [ + - ]: 138 : uno::Reference< beans::XPropertySet > xProp( xTextShape, uno::UNO_QUERY );
565 [ + - ]: 138 : if( xProp.is() )
566 [ + - ][ + - ]: 138 : xProp->setPropertyValue( C2U( "Transformation" ), ShapeFactory::makeTransformation( aScreenPosition2D, fDegreesPi ) );
[ + - ][ + - ]
567 [ + - ]: 138 : LabelPositionHelper::correctPositionForRotation( xTextShape, eAlignment, fRotationDegrees, true /*bRotateAroundCenter*/ );
568 : : }
569 : :
570 [ - + ]: 2272 : if( xSymbol.is() )
571 : : {
572 [ # # ][ # # ]: 0 : const awt::Point aOldTextPos( xTextShape->getPosition() );
573 : 0 : awt::Point aNewTextPos( aOldTextPos );
574 : :
575 : 0 : awt::Point aSymbolPosition( aUnrotatedTextPos );
576 [ # # ][ # # ]: 0 : awt::Size aSymbolSize( xSymbol->getSize() );
577 [ # # ][ # # ]: 0 : awt::Size aTextSize( xTextShape->getSize() );
578 : :
579 [ # # ]: 0 : sal_Int32 nXDiff = aSymbolSize.Width + static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.22 ) );//minimum 1mm
580 [ # # ][ # # ]: 0 : if( !bMultiLineLabel || nLineCountForSymbolsize <= 0 )
581 : 0 : nLineCountForSymbolsize = 1;
582 : 0 : aSymbolPosition.Y += ((aTextSize.Height/nLineCountForSymbolsize)/4);
583 : :
584 [ # # ][ # # ]: 0 : if(LABEL_ALIGN_LEFT==eAlignment
[ # # ]
585 : : || LABEL_ALIGN_LEFT_TOP==eAlignment
586 : : || LABEL_ALIGN_LEFT_BOTTOM==eAlignment)
587 : : {
588 : 0 : aSymbolPosition.X -= nXDiff;
589 : : }
590 [ # # ][ # # ]: 0 : else if(LABEL_ALIGN_RIGHT==eAlignment
[ # # ]
591 : : || LABEL_ALIGN_RIGHT_TOP==eAlignment
592 : : || LABEL_ALIGN_RIGHT_BOTTOM==eAlignment )
593 : : {
594 : 0 : aNewTextPos.X += nXDiff;
595 : : }
596 [ # # ][ # # ]: 0 : else if(LABEL_ALIGN_TOP==eAlignment
[ # # ]
597 : : || LABEL_ALIGN_BOTTOM==eAlignment
598 : : || LABEL_ALIGN_CENTER==eAlignment )
599 : : {
600 : 0 : aSymbolPosition.X -= nXDiff/2;
601 : 0 : aNewTextPos.X += nXDiff/2;
602 : : }
603 : :
604 [ # # ][ # # ]: 0 : xSymbol->setPosition( aSymbolPosition );
605 [ # # ][ # # ]: 2272 : xTextShape->setPosition( aNewTextPos );
606 [ - + ][ - + ]: 2272 : }
[ - + ][ + - ]
[ # # ]
607 : : }
608 [ # # ]: 0 : catch( const uno::Exception& e )
609 : : {
610 : : ASSERT_EXCEPTION( e );
611 : : }
612 : :
613 : 2272 : return xTextShape;
614 : : }
615 : :
616 : : namespace
617 : : {
618 : 975 : double lcl_getErrorBarLogicLength(
619 : : const uno::Sequence< double > & rData,
620 : : uno::Reference< beans::XPropertySet > xProp,
621 : : sal_Int32 nErrorBarStyle,
622 : : sal_Int32 nIndex,
623 : : bool bPositive,
624 : : bool bYError )
625 : : {
626 : : double fResult;
627 : 975 : ::rtl::math::setNan( & fResult );
628 : : try
629 : : {
630 [ - - - + : 975 : switch( nErrorBarStyle )
- - - -
- ]
631 : : {
632 : : case ::com::sun::star::chart::ErrorBarStyle::NONE:
633 : 0 : break;
634 : : case ::com::sun::star::chart::ErrorBarStyle::VARIANCE:
635 [ # # ]: 0 : fResult = StatisticsHelper::getVariance( rData );
636 : 0 : break;
637 : : case ::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION:
638 [ # # ]: 0 : fResult = StatisticsHelper::getStandardDeviation( rData );
639 : 0 : break;
640 : : case ::com::sun::star::chart::ErrorBarStyle::RELATIVE:
641 : : {
642 : 975 : double fPercent = 0;
643 [ + - + - ]: 1950 : if( xProp->getPropertyValue( bPositive
644 : : ? C2U("PositiveError")
645 [ + + ][ + - ]: 975 : : C2U("NegativeError")) >>= fPercent )
[ + - ][ + - ]
646 : : {
647 [ + - ][ + - : 2925 : if( nIndex >=0 && nIndex < rData.getLength() &&
+ - + - ]
[ + - ]
648 : 975 : ! ::rtl::math::isNan( rData[nIndex] ) &&
649 : 975 : ! ::rtl::math::isNan( fPercent ))
650 : : {
651 : 975 : fResult = rData[nIndex] * fPercent / 100.0;
652 : : }
653 : : }
654 : : }
655 : 975 : break;
656 : : case ::com::sun::star::chart::ErrorBarStyle::ABSOLUTE:
657 [ # # ]: 0 : xProp->getPropertyValue( bPositive
658 : : ? C2U("PositiveError")
659 [ # # ][ # # ]: 0 : : C2U("NegativeError")) >>= fResult;
[ # # ][ # # ]
660 : 0 : break;
661 : : case ::com::sun::star::chart::ErrorBarStyle::ERROR_MARGIN:
662 : : {
663 : : // todo: check if this is really what's called error-margin
664 : 0 : double fPercent = 0;
665 [ # # # # ]: 0 : if( xProp->getPropertyValue( bPositive
666 : : ? C2U("PositiveError")
667 [ # # ][ # # ]: 0 : : C2U("NegativeError")) >>= fPercent )
[ # # ][ # # ]
668 : : {
669 : : double fMaxValue;
670 : 0 : ::rtl::math::setInf(&fMaxValue, true);
671 : 0 : const double* pValues = rData.getConstArray();
672 [ # # ]: 0 : for(sal_Int32 i=0; i<rData.getLength(); ++i, ++pValues)
673 : : {
674 [ # # ]: 0 : if(fMaxValue<*pValues)
675 : 0 : fMaxValue=*pValues;
676 : : }
677 [ # # # # ]: 0 : if( ::rtl::math::isFinite( fMaxValue ) &&
[ # # ]
678 : 0 : ::rtl::math::isFinite( fPercent ))
679 : : {
680 : 0 : fResult = fMaxValue * fPercent / 100.0;
681 : : }
682 : : }
683 : : }
684 : 0 : break;
685 : : case ::com::sun::star::chart::ErrorBarStyle::STANDARD_ERROR:
686 [ # # ]: 0 : fResult = StatisticsHelper::getStandardError( rData );
687 : 0 : break;
688 : : case ::com::sun::star::chart::ErrorBarStyle::FROM_DATA:
689 : : {
690 [ # # ]: 0 : uno::Reference< chart2::data::XDataSource > xErrorBarData( xProp, uno::UNO_QUERY );
691 [ # # ]: 0 : if( xErrorBarData.is())
692 : : fResult = StatisticsHelper::getErrorFromDataSource(
693 [ # # ][ # # ]: 0 : xErrorBarData, nIndex, bPositive, bYError);
694 : : }
695 : 0 : break;
696 : : }
697 : : }
698 [ # # ]: 0 : catch( const uno::Exception & e )
699 : : {
700 : : ASSERT_EXCEPTION( e );
701 : : }
702 : :
703 : 975 : return fResult;
704 : : }
705 : :
706 : 659 : void lcl_AddErrorBottomLine( const drawing::Position3D& rPosition, ::basegfx::B2DVector aMainDirection
707 : : , drawing::PolyPolygonShape3D& rPoly, sal_Int32 nSequenceIndex )
708 : : {
709 : 659 : double fFixedWidth = 200.0;
710 : :
711 [ + - ]: 659 : aMainDirection.normalize();
712 : 659 : ::basegfx::B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
713 [ + - ]: 659 : aOrthoDirection.normalize();
714 : :
715 : 659 : ::basegfx::B2DVector aAnchor( rPosition.PositionX, rPosition.PositionY );
716 : 659 : ::basegfx::B2DVector aStart = aAnchor + aOrthoDirection*fFixedWidth/2.0;
717 : 659 : ::basegfx::B2DVector aEnd = aAnchor - aOrthoDirection*fFixedWidth/2.0;
718 : :
719 [ + - ]: 659 : AddPointToPoly( rPoly, drawing::Position3D( aStart.getX(), aStart.getY(), rPosition.PositionZ), nSequenceIndex );
720 [ + - ]: 659 : AddPointToPoly( rPoly, drawing::Position3D( aEnd.getX(), aEnd.getY(), rPosition.PositionZ), nSequenceIndex );
721 : 659 : }
722 : :
723 : 659 : ::basegfx::B2DVector lcl_getErrorBarMainDirection(
724 : : const drawing::Position3D& rStart
725 : : , const drawing::Position3D& rBottomEnd
726 : : , PlottingPositionHelper* pPosHelper
727 : : , const drawing::Position3D& rUnscaledLogicPosition
728 : : , bool bYError )
729 : : {
730 : : ::basegfx::B2DVector aMainDirection = ::basegfx::B2DVector( rStart.PositionX - rBottomEnd.PositionX
731 : 659 : , rStart.PositionY - rBottomEnd.PositionY );
732 [ - + ][ + - ]: 659 : if( !aMainDirection.getLength() )
733 : : {
734 : : //get logic clip values:
735 [ # # ]: 0 : double MinX = pPosHelper->getLogicMinX();
736 [ # # ]: 0 : double MinY = pPosHelper->getLogicMinY();
737 [ # # ]: 0 : double MaxX = pPosHelper->getLogicMaxX();
738 [ # # ]: 0 : double MaxY = pPosHelper->getLogicMaxY();
739 [ # # ]: 0 : double fZ = pPosHelper->getLogicMinZ();
740 : :
741 : :
742 [ # # ]: 0 : if( bYError )
743 : : {
744 : : //main direction has constant x value
745 : 0 : MinX = rUnscaledLogicPosition.PositionX;
746 : 0 : MaxX = rUnscaledLogicPosition.PositionX;
747 : : }
748 : : else
749 : : {
750 : : //main direction has constant y value
751 : 0 : MinY = rUnscaledLogicPosition.PositionY;
752 : 0 : MaxY = rUnscaledLogicPosition.PositionY;
753 : : }
754 : :
755 [ # # ]: 0 : drawing::Position3D aStart = pPosHelper->transformLogicToScene( MinX, MinY, fZ, false );
756 [ # # ]: 0 : drawing::Position3D aEnd = pPosHelper->transformLogicToScene( MaxX, MaxY, fZ, false );
757 : :
758 : : aMainDirection = ::basegfx::B2DVector( aStart.PositionX - aEnd.PositionX
759 [ # # ]: 0 : , aStart.PositionY - aEnd.PositionY );
760 : : }
761 [ + - ]: 659 : if( !aMainDirection.getLength() )
762 : : {
763 : : //@todo
764 : : }
765 : 659 : return aMainDirection;
766 : : }
767 : :
768 : 1482 : drawing::Position3D lcl_transformMixedToScene( PlottingPositionHelper* pPosHelper
769 : : , double fX /*scaled*/, double fY /*unscaled*/, double fZ /*unscaled*/, bool bClip )
770 : : {
771 [ - + ]: 1482 : if(!pPosHelper)
772 : 0 : return drawing::Position3D(0,0,0);
773 : 1482 : pPosHelper->doLogicScaling( 0,&fY,&fZ );
774 [ + - ]: 1482 : if(bClip)
775 : 1482 : pPosHelper->clipScaledLogicValues( &fX,&fY,&fZ );
776 : 1482 : return pPosHelper->transformScaledLogicToScene( fX, fY, fZ, false );
777 : : }
778 : :
779 : : } // anonymous namespace
780 : :
781 : 4671 : void VSeriesPlotter::createErrorBar(
782 : : const uno::Reference< drawing::XShapes >& xTarget
783 : : , const drawing::Position3D& rUnscaledLogicPosition
784 : : , const uno::Reference< beans::XPropertySet > & xErrorBarProperties
785 : : , const VDataSeries& rVDataSeries
786 : : , sal_Int32 nIndex
787 : : , bool bYError /* = true */
788 : : , double* pfScaledLogicX
789 : : )
790 : : {
791 [ - + ]: 4671 : if( !ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ) )
792 : 0 : return;
793 : :
794 [ - + ]: 4671 : if( ! xErrorBarProperties.is())
795 : 0 : return;
796 : :
797 : : try
798 : : {
799 : 4671 : sal_Bool bShowPositive = sal_False;
800 : 4671 : sal_Bool bShowNegative = sal_False;
801 : 4671 : sal_Int32 nErrorBarStyle = ::com::sun::star::chart::ErrorBarStyle::VARIANCE;
802 : :
803 [ + - ][ + - ]: 4671 : xErrorBarProperties->getPropertyValue( C2U( "ShowPositiveError" )) >>= bShowPositive;
[ + - ]
804 [ + - ][ + - ]: 4671 : xErrorBarProperties->getPropertyValue( C2U( "ShowNegativeError" )) >>= bShowNegative;
[ + - ]
805 [ + - ][ + - ]: 4671 : xErrorBarProperties->getPropertyValue( C2U( "ErrorBarStyle" )) >>= nErrorBarStyle;
[ + - ]
806 : :
807 [ - + ][ + + ]: 4671 : if(!bShowPositive && !bShowNegative)
808 : : return;
809 : :
810 [ + - ]: 507 : if(nErrorBarStyle==::com::sun::star::chart::ErrorBarStyle::NONE)
811 : : return;
812 : :
813 : 507 : drawing::Position3D aUnscaledLogicPosition(rUnscaledLogicPosition);
814 [ - + ]: 507 : if(nErrorBarStyle==::com::sun::star::chart::ErrorBarStyle::STANDARD_DEVIATION)
815 : : {
816 [ # # ]: 0 : if (bYError)
817 [ # # ]: 0 : aUnscaledLogicPosition.PositionY = rVDataSeries.getYMeanValue();
818 : : else
819 [ # # ]: 0 : aUnscaledLogicPosition.PositionX = rVDataSeries.getXMeanValue();
820 : : }
821 : :
822 : 507 : bool bCreateNegativeBorder = false;//make a vertical line at the negative end of the error bar
823 : 507 : bool bCreatePositiveBorder = false;//make a vertical line at the positive end of the error bar
824 : 507 : drawing::Position3D aMiddle(aUnscaledLogicPosition);
825 : 507 : const double fX = aUnscaledLogicPosition.PositionX;
826 : 507 : const double fY = aUnscaledLogicPosition.PositionY;
827 : 507 : const double fZ = aUnscaledLogicPosition.PositionZ;
828 : 507 : double fScaledX = fX;
829 [ - + ]: 507 : if( pfScaledLogicX )
830 : 0 : fScaledX = *pfScaledLogicX;
831 : : else
832 [ + - ]: 507 : m_pPosHelper->doLogicScaling( &fScaledX, 0, 0 );
833 : :
834 [ + - ]: 507 : aMiddle = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fY, fZ, true );
835 : :
836 : 507 : drawing::Position3D aNegative(aMiddle);
837 : 507 : drawing::Position3D aPositive(aMiddle);
838 : :
839 [ + - ][ + - ]: 507 : uno::Sequence< double > aData( bYError ? rVDataSeries.getAllY() : rVDataSeries.getAllX() );
[ # # ]
840 : :
841 [ + - ]: 507 : if( bShowPositive )
842 : : {
843 [ + - ]: 507 : double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, true, bYError );
844 [ + - ]: 507 : if( ::rtl::math::isFinite( fLength ) )
845 : : {
846 : 507 : double fLocalX = fX;
847 : 507 : double fLocalY = fY;
848 [ + - ]: 507 : if( bYError )
849 : : {
850 : 507 : fLocalY+=fLength;
851 [ + - ]: 507 : aPositive = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fLocalY, fZ, true );
852 : : }
853 : : else
854 : : {
855 : 0 : fLocalX+=fLength;
856 [ # # ]: 0 : aPositive = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true );
857 : : }
858 [ + - ]: 507 : bCreatePositiveBorder = m_pPosHelper->isLogicVisible(fLocalX, fLocalY, fZ);
859 : : }
860 : : else
861 : 0 : bShowPositive = false;
862 : : }
863 : :
864 [ + + ]: 507 : if( bShowNegative )
865 : : {
866 [ + - ]: 468 : double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, false, bYError );
867 [ + - ]: 468 : if( ::rtl::math::isFinite( fLength ) )
868 : : {
869 : 468 : double fLocalX = fX;
870 : 468 : double fLocalY = fY;
871 [ + - ]: 468 : if( bYError )
872 : : {
873 : 468 : fLocalY-=fLength;
874 [ + - ]: 468 : aNegative = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fLocalY, fZ, true );
875 : : }
876 : : else
877 : : {
878 : 0 : fLocalX-=fLength;
879 [ # # ]: 0 : aNegative = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true );
880 : : }
881 [ + - ]: 468 : bCreateNegativeBorder = m_pPosHelper->isLogicVisible( fLocalX, fLocalY, fZ);
882 : : }
883 : : else
884 : 0 : bShowNegative = false;
885 : : }
886 : :
887 [ - + ][ # # ]: 507 : if(!bShowPositive && !bShowNegative)
888 : : return;
889 : :
890 [ + - ]: 507 : drawing::PolyPolygonShape3D aPoly;
891 : :
892 : 507 : sal_Int32 nSequenceIndex=0;
893 [ + + ]: 507 : if( bShowNegative )
894 [ + - ]: 468 : AddPointToPoly( aPoly, aNegative, nSequenceIndex );
895 [ + - ]: 507 : AddPointToPoly( aPoly, aMiddle, nSequenceIndex );
896 [ + - ]: 507 : if( bShowPositive )
897 [ + - ]: 507 : AddPointToPoly( aPoly, aPositive, nSequenceIndex );
898 : :
899 [ + + ][ + + ]: 507 : if( bShowNegative && bCreateNegativeBorder )
900 : : {
901 [ + - ]: 312 : ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aNegative, m_pPosHelper, aUnscaledLogicPosition, bYError );
902 : 312 : nSequenceIndex++;
903 [ + - ]: 312 : lcl_AddErrorBottomLine( aNegative, aMainDirection, aPoly, nSequenceIndex );
904 : : }
905 [ + - ][ + + ]: 507 : if( bShowPositive && bCreatePositiveBorder )
906 : : {
907 [ + - ]: 347 : ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aPositive, m_pPosHelper, aUnscaledLogicPosition, bYError );
908 : 347 : nSequenceIndex++;
909 [ + - ]: 347 : lcl_AddErrorBottomLine( aPositive, aMainDirection, aPoly, nSequenceIndex );
910 : : }
911 : :
912 [ + - ][ + - ]: 507 : uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D( xTarget, PolyToPointSequence( aPoly) );
[ + - ]
913 [ + - ][ + - ]: 4671 : this->setMappedProperties( xShape, xErrorBarProperties, PropertyMapper::getPropertyNameMapForLineProperties() );
[ + - ][ + - ]
[ + - ][ # # ]
914 : : }
915 : 0 : catch( const uno::Exception & e )
916 : : {
917 : : ASSERT_EXCEPTION( e );
918 : : }
919 : :
920 : : }
921 : :
922 : 0 : void VSeriesPlotter::createErrorBar_X( const drawing::Position3D& rUnscaledLogicPosition
923 : : , VDataSeries& rVDataSeries, sal_Int32 nPointIndex
924 : : , const uno::Reference< drawing::XShapes >& xTarget
925 : : , double* pfScaledLogicX )
926 : : {
927 [ # # ]: 0 : if(m_nDimension!=2)
928 : 0 : return;
929 : : // error bars
930 [ # # ]: 0 : uno::Reference< beans::XPropertySet > xErrorBarProp(rVDataSeries.getXErrorBarProperties(nPointIndex));
931 [ # # ]: 0 : if( xErrorBarProp.is())
932 : : {
933 : : uno::Reference< drawing::XShapes > xErrorBarsGroup_Shapes(
934 [ # # ]: 0 : this->getErrorBarsGroupShape(rVDataSeries, xTarget, false) );
935 : :
936 : : createErrorBar( xErrorBarsGroup_Shapes
937 : : , rUnscaledLogicPosition, xErrorBarProp
938 : : , rVDataSeries, nPointIndex
939 : : , false /* bYError */
940 [ # # ]: 0 : , pfScaledLogicX );
941 : 0 : }
942 : : }
943 : :
944 : 11476 : void VSeriesPlotter::createErrorBar_Y( const drawing::Position3D& rUnscaledLogicPosition
945 : : , VDataSeries& rVDataSeries, sal_Int32 nPointIndex
946 : : , const uno::Reference< drawing::XShapes >& xTarget
947 : : , double* pfScaledLogicX )
948 : : {
949 [ + + ]: 11476 : if(m_nDimension!=2)
950 : 11476 : return;
951 : : // error bars
952 [ + - ]: 11440 : uno::Reference< beans::XPropertySet > xErrorBarProp(rVDataSeries.getYErrorBarProperties(nPointIndex));
953 [ + + ]: 11440 : if( xErrorBarProp.is())
954 : : {
955 : : uno::Reference< drawing::XShapes > xErrorBarsGroup_Shapes(
956 [ + - ]: 4671 : this->getErrorBarsGroupShape(rVDataSeries, xTarget, true) );
957 : :
958 : : createErrorBar( xErrorBarsGroup_Shapes
959 : : , rUnscaledLogicPosition, xErrorBarProp
960 : : , rVDataSeries, nPointIndex
961 : : , true /* bYError */
962 [ + - ]: 4671 : , pfScaledLogicX );
963 : 11476 : }
964 : : }
965 : :
966 : 3129 : void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries& rVDataSeries
967 : : , const uno::Reference< drawing::XShapes >& xTarget
968 : : , const uno::Reference< drawing::XShapes >& xEquationTarget
969 : : , bool bMaySkipPointsInRegressionCalculation )
970 : : {
971 [ + + ]: 3129 : if(m_nDimension!=2)
972 : : return;
973 : : uno::Reference< XRegressionCurveContainer > xRegressionContainer(
974 [ + - ][ + - ]: 3087 : rVDataSeries.getModel(), uno::UNO_QUERY );
975 [ - + ]: 3087 : if(!xRegressionContainer.is())
976 : : return;
977 [ + - ]: 3087 : double fMinX = m_pPosHelper->getLogicMinX();
978 [ + - ]: 3087 : double fMaxX = m_pPosHelper->getLogicMaxX();
979 : :
980 : : uno::Sequence< uno::Reference< XRegressionCurve > > aCurveList =
981 [ + - ][ + - ]: 3087 : xRegressionContainer->getRegressionCurves();
982 [ + + ]: 3195 : for(sal_Int32 nN=0; nN<aCurveList.getLength(); nN++)
983 : : {
984 : : uno::Reference< XRegressionCurveCalculator > xRegressionCurveCalculator(
985 [ + - ][ + - ]: 108 : aCurveList[nN]->getCalculator() );
[ + - ]
986 [ - + ]: 108 : if( ! xRegressionCurveCalculator.is())
987 : 0 : continue;
988 [ + - ][ + - ]: 108 : xRegressionCurveCalculator->recalculateRegression( rVDataSeries.getAllX(), rVDataSeries.getAllY() );
[ + - ][ + - ]
[ + - ][ + - ]
989 : :
990 : 108 : sal_Int32 nRegressionPointCount = 50;//@todo find a more optimal solution if more complicated curve types are introduced
991 [ + - ]: 108 : drawing::PolyPolygonShape3D aRegressionPoly;
992 [ + - ]: 108 : aRegressionPoly.SequenceX.realloc(1);
993 [ + - ]: 108 : aRegressionPoly.SequenceY.realloc(1);
994 [ + - ]: 108 : aRegressionPoly.SequenceZ.realloc(1);
995 [ + - ][ + - ]: 108 : aRegressionPoly.SequenceX[0].realloc(nRegressionPointCount);
996 [ + - ][ + - ]: 108 : aRegressionPoly.SequenceY[0].realloc(nRegressionPointCount);
997 [ + - ][ + - ]: 108 : aRegressionPoly.SequenceZ[0].realloc(nRegressionPointCount);
998 : 108 : sal_Int32 nRealPointCount=0;
999 : :
1000 [ + - ][ + - ]: 108 : std::vector< ExplicitScaleData > aScales( m_pPosHelper->getScales());
1001 : 108 : uno::Reference< chart2::XScaling > xScalingX;
1002 : 108 : uno::Reference< chart2::XScaling > xScalingY;
1003 [ + - ]: 108 : if( aScales.size() >= 2 )
1004 : : {
1005 [ + - ][ + - ]: 108 : xScalingX.set( aScales[0].Scaling );
1006 [ + - ][ + - ]: 108 : xScalingY.set( aScales[1].Scaling );
1007 : : }
1008 : :
1009 : : uno::Sequence< geometry::RealPoint2D > aCalculatedPoints(
1010 [ + - ]: 108 : xRegressionCurveCalculator->getCurveValues(
1011 [ + - ]: 108 : fMinX, fMaxX, nRegressionPointCount, xScalingX, xScalingY, bMaySkipPointsInRegressionCalculation ));
1012 : 108 : nRegressionPointCount = aCalculatedPoints.getLength();
1013 [ + + ]: 1860 : for(sal_Int32 nP=0; nP<nRegressionPointCount; nP++)
1014 : : {
1015 [ + - ]: 1752 : double fLogicX = aCalculatedPoints[nP].X;
1016 [ + - ]: 1752 : double fLogicY = aCalculatedPoints[nP].Y;
1017 : 1752 : double fLogicZ = 0.0;//dummy
1018 : :
1019 [ + - ]: 1752 : m_pPosHelper->doLogicScaling( &fLogicX, &fLogicY, &fLogicZ );
1020 : :
1021 [ + - ][ + - : 8760 : if( !::rtl::math::isNan(fLogicX) && !::rtl::math::isInf(fLogicX)
+ - + - +
- + - ]
[ + - ]
1022 : 3504 : && !::rtl::math::isNan(fLogicY) && !::rtl::math::isInf(fLogicY)
1023 : 3504 : && !::rtl::math::isNan(fLogicZ) && !::rtl::math::isInf(fLogicZ) )
1024 : : {
1025 [ + - ][ + - ]: 1752 : aRegressionPoly.SequenceX[0][nRealPointCount] = fLogicX;
1026 [ + - ][ + - ]: 1752 : aRegressionPoly.SequenceY[0][nRealPointCount] = fLogicY;
1027 : 1752 : nRealPointCount++;
1028 : : }
1029 : : }
1030 [ + - ][ + - ]: 108 : aRegressionPoly.SequenceX[0].realloc(nRealPointCount);
1031 [ + - ][ + - ]: 108 : aRegressionPoly.SequenceY[0].realloc(nRealPointCount);
1032 [ + - ][ + - ]: 108 : aRegressionPoly.SequenceZ[0].realloc(nRealPointCount);
1033 : :
1034 [ + - ]: 108 : drawing::PolyPolygonShape3D aClippedPoly;
1035 [ + - ][ + - ]: 108 : Clipping::clipPolygonAtRectangle( aRegressionPoly, m_pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly );
1036 [ + - ]: 108 : aRegressionPoly = aClippedPoly;
1037 [ + - ]: 108 : m_pPosHelper->transformScaledLogicToScene( aRegressionPoly );
1038 : :
1039 : 108 : awt::Point aDefaultPos;
1040 [ + - ][ + - ]: 108 : if( aRegressionPoly.SequenceX.getLength() && aRegressionPoly.SequenceX[0].getLength() )
[ + + ][ + + ]
1041 : : {
1042 [ + - ][ + - ]: 84 : uno::Reference< beans::XPropertySet > xCurveModelProp( aCurveList[nN], uno::UNO_QUERY );
1043 [ + - ]: 84 : VLineProperties aVLineProperties;
1044 [ + - ]: 84 : aVLineProperties.initFromPropertySet( xCurveModelProp );
1045 : :
1046 : : //create an extra group shape for each curve for selection handling
1047 [ + - ][ + - ]: 84 : bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurveList[nN] );
1048 : : uno::Reference< drawing::XShapes > xRegressionGroupShapes =
1049 [ + - ][ + - ]: 84 : createGroupShape( xTarget, rVDataSeries.getDataCurveCID( nN, bAverageLine ) );
1050 : : uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D(
1051 [ + - ][ + - ]: 84 : xRegressionGroupShapes, PolyToPointSequence( aRegressionPoly ), &aVLineProperties );
[ + - ]
1052 [ + - ][ + - ]: 84 : m_pShapeFactory->setShapeName( xShape, C2U("MarkHandles") );
1053 [ + - ][ + - ]: 84 : aDefaultPos = xShape->getPosition();
1054 : : }
1055 : :
1056 : : // curve equation and correlation coefficient
1057 [ + - ][ + - ]: 108 : uno::Reference< beans::XPropertySet > xEqProp( aCurveList[nN]->getEquationProperties());
[ + - ]
1058 [ + - ]: 108 : if( xEqProp.is())
1059 : : {
1060 : : createRegressionCurveEquationShapes(
1061 : : rVDataSeries.getDataCurveEquationCID( nN ),
1062 : : xEqProp, xEquationTarget, xRegressionCurveCalculator,
1063 [ + - ][ + - ]: 108 : aDefaultPos );
1064 : : }
1065 [ + - ][ + - ]: 3237 : }
[ + - ][ + - ]
[ + - ][ + - ]
1066 : : }
1067 : :
1068 : 108 : void VSeriesPlotter::createRegressionCurveEquationShapes(
1069 : : const OUString & rEquationCID,
1070 : : const uno::Reference< beans::XPropertySet > & xEquationProperties,
1071 : : const uno::Reference< drawing::XShapes >& xEquationTarget,
1072 : : const uno::Reference< chart2::XRegressionCurveCalculator > & xRegressionCurveCalculator,
1073 : : awt::Point aDefaultPos )
1074 : : {
1075 : : OSL_ASSERT( xEquationProperties.is());
1076 [ + - ]: 108 : if( !xEquationProperties.is())
1077 : : return;
1078 : :
1079 : 108 : bool bShowEquation = false;
1080 : 108 : bool bShowCorrCoeff = false;
1081 : 108 : OUString aSep( sal_Unicode('\n'));
1082 [ + - ][ + - ]: 324 : if(( xEquationProperties->getPropertyValue( C2U("ShowEquation")) >>= bShowEquation ) &&
[ + - + - ]
[ + - ][ + - ]
[ + - # #
# # ][ + - ]
1083 [ + - ][ + - ]: 216 : ( xEquationProperties->getPropertyValue( C2U("ShowCorrelationCoefficient")) >>= bShowCorrCoeff ))
[ + - ][ + - ]
[ + - ]
[ # # # # ]
1084 : : {
1085 [ + - ][ - + ]: 108 : if( ! (bShowEquation || bShowCorrCoeff))
1086 : : return;
1087 : :
1088 : 0 : ::rtl::OUStringBuffer aFormula;
1089 : 0 : sal_Int32 nNumberFormatKey = 0;
1090 [ # # ][ # # ]: 0 : xEquationProperties->getPropertyValue( C2U("NumberFormat")) >>= nNumberFormatKey;
[ # # ]
1091 : :
1092 [ # # ]: 0 : if( bShowEquation )
1093 : : {
1094 [ # # ]: 0 : if( m_apNumberFormatterWrapper.get())
1095 : : {
1096 [ # # ]: 0 : aFormula = xRegressionCurveCalculator->getFormattedRepresentation(
1097 : : m_apNumberFormatterWrapper->getNumberFormatsSupplier(),
1098 [ # # ][ # # ]: 0 : nNumberFormatKey );
[ # # ][ # # ]
1099 : : }
1100 : : else
1101 : : {
1102 [ # # ][ # # ]: 0 : aFormula = xRegressionCurveCalculator->getRepresentation();
[ # # ][ # # ]
1103 : : }
1104 : :
1105 [ # # ]: 0 : if( bShowCorrCoeff )
1106 : : {
1107 [ # # ]: 0 : aFormula.append( aSep );
1108 : : }
1109 : : }
1110 [ # # ]: 0 : if( bShowCorrCoeff )
1111 : : {
1112 [ # # ]: 0 : aFormula.append( sal_Unicode( 'R' ));
1113 [ # # ]: 0 : aFormula.append( sal_Unicode( 0x00b2 ));
1114 [ # # ][ # # ]: 0 : aFormula.append( C2U( " = " ));
1115 [ # # ][ # # ]: 0 : double fR( xRegressionCurveCalculator->getCorrelationCoefficient());
1116 [ # # ]: 0 : if( m_apNumberFormatterWrapper.get())
1117 : : {
1118 : 0 : sal_Int32 nLabelCol = 0;
1119 : : bool bColChanged;
1120 : : aFormula.append(
1121 : : m_apNumberFormatterWrapper->getFormattedString(
1122 [ # # ][ # # ]: 0 : nNumberFormatKey, fR*fR, nLabelCol, bColChanged ));
1123 : : //@todo: change color of label if bColChanged is true
1124 : : }
1125 : : else
1126 : : {
1127 : 0 : sal_Unicode aDecimalSep( '.' );//@todo get this locale dependent
1128 : : aFormula.append( ::rtl::math::doubleToUString(
1129 [ # # ]: 0 : fR*fR, rtl_math_StringFormat_G, 4, aDecimalSep, true ));
1130 : : }
1131 : : }
1132 : :
1133 : 0 : awt::Point aScreenPosition2D;
1134 : 0 : chart2::RelativePosition aRelativePosition;
1135 [ # # ][ # # ]: 0 : if( xEquationProperties->getPropertyValue( C2U("RelativePosition")) >>= aRelativePosition )
[ # # ][ # # ]
[ # # ]
1136 : : {
1137 : : //@todo decide whether x is primary or secondary
1138 : 0 : double fX = aRelativePosition.Primary*m_aPageReferenceSize.Width;
1139 : 0 : double fY = aRelativePosition.Secondary*m_aPageReferenceSize.Height;
1140 : 0 : aScreenPosition2D.X = static_cast< sal_Int32 >( ::rtl::math::round( fX ));
1141 : 0 : aScreenPosition2D.Y = static_cast< sal_Int32 >( ::rtl::math::round( fY ));
1142 : : }
1143 : : else
1144 : 0 : aScreenPosition2D = aDefaultPos;
1145 : :
1146 [ # # ]: 0 : if( aFormula.getLength())
1147 : : {
1148 : : // set fill and line properties on creation
1149 [ # # ]: 0 : tNameSequence aNames;
1150 [ # # ]: 0 : tAnySequence aValues;
1151 [ # # ]: 0 : PropertyMapper::getPreparedTextShapePropertyLists( xEquationProperties, aNames, aValues );
1152 : :
1153 : : uno::Reference< drawing::XShape > xTextShape = m_pShapeFactory->createText(
1154 : : xEquationTarget, aFormula.makeStringAndClear(),
1155 [ # # ][ # # ]: 0 : aNames, aValues, ShapeFactory::makeTransformation( aScreenPosition2D ));
[ # # ]
1156 : :
1157 : : OSL_ASSERT( xTextShape.is());
1158 [ # # ]: 0 : if( xTextShape.is())
1159 : : {
1160 [ # # ]: 0 : ShapeFactory::setShapeName( xTextShape, rEquationCID );
1161 [ # # ][ # # ]: 0 : awt::Size aSize( xTextShape->getSize() );
1162 : : awt::Point aPos( RelativePositionHelper::getUpperLeftCornerOfAnchoredObject(
1163 [ # # ]: 0 : aScreenPosition2D, aSize, aRelativePosition.Anchor ) );
1164 : : //ensure that the equation is fully placed within the page (if possible)
1165 [ # # ]: 0 : if( (aPos.X + aSize.Width) > m_aPageReferenceSize.Width )
1166 : 0 : aPos.X = m_aPageReferenceSize.Width - aSize.Width;
1167 [ # # ]: 0 : if( aPos.X < 0 )
1168 : 0 : aPos.X = 0;
1169 [ # # ]: 0 : if( (aPos.Y + aSize.Height) > m_aPageReferenceSize.Height )
1170 : 0 : aPos.Y = m_aPageReferenceSize.Height - aSize.Height;
1171 [ # # ]: 0 : if( aPos.Y < 0 )
1172 : 0 : aPos.Y = 0;
1173 [ # # ][ # # ]: 0 : xTextShape->setPosition(aPos);
1174 [ # # ][ # # ]: 0 : }
1175 : 108 : }
1176 [ - + ]: 108 : }
1177 : : }
1178 : :
1179 : :
1180 : 11933 : void VSeriesPlotter::setMappedProperties(
1181 : : const uno::Reference< drawing::XShape >& xTargetShape
1182 : : , const uno::Reference< beans::XPropertySet >& xSource
1183 : : , const tPropertyNameMap& rMap
1184 : : , tPropertyNameValueMap* pOverwriteMap )
1185 : : {
1186 [ + - ]: 11933 : uno::Reference< beans::XPropertySet > xTargetProp( xTargetShape, uno::UNO_QUERY );
1187 [ + - ]: 11933 : PropertyMapper::setMappedProperties(xTargetProp,xSource,rMap,pOverwriteMap);
1188 : 11933 : }
1189 : :
1190 : 0 : void VSeriesPlotter::setTimeResolutionOnXAxis( long TimeResolution, const Date& rNullDate )
1191 : : {
1192 : 0 : m_nTimeResolution = TimeResolution;
1193 : 0 : m_aNullDate = rNullDate;
1194 : 0 : }
1195 : :
1196 : : //-------------------------------------------------------------------------
1197 : : // MinimumAndMaximumSupplier
1198 : : //-------------------------------------------------------------------------
1199 : 0 : long VSeriesPlotter::calculateTimeResolutionOnXAxis()
1200 : : {
1201 : 0 : long nRet = ::com::sun::star::chart::TimeUnit::YEAR;
1202 [ # # ]: 0 : if( m_pExplicitCategoriesProvider )
1203 : : {
1204 [ # # ]: 0 : const std::vector< DatePlusIndex >& rDateCategories = m_pExplicitCategoriesProvider->getDateCategories();
1205 : 0 : std::vector< DatePlusIndex >::const_iterator aIt = rDateCategories.begin(), aEnd = rDateCategories.end();
1206 : 0 : Date aNullDate(30,12,1899);
1207 [ # # ]: 0 : if( m_apNumberFormatterWrapper.get() )
1208 [ # # ]: 0 : aNullDate = m_apNumberFormatterWrapper->getNullDate();
1209 [ # # ][ # # ]: 0 : if( aIt!=aEnd )
1210 : : {
1211 [ # # ]: 0 : Date aPrevious(aNullDate); aPrevious+=static_cast<long>(rtl::math::approxFloor(aIt->fValue));
1212 : 0 : ++aIt;
1213 [ # # ][ # # ]: 0 : for(;aIt!=aEnd;++aIt)
1214 : : {
1215 [ # # ]: 0 : Date aCurrent(aNullDate); aCurrent+=static_cast<long>(rtl::math::approxFloor(aIt->fValue));
1216 [ # # ]: 0 : if( ::com::sun::star::chart::TimeUnit::YEAR == nRet )
1217 : : {
1218 [ # # ][ # # ]: 0 : if( DateHelper::IsInSameYear( aPrevious, aCurrent ) )
1219 : 0 : nRet = ::com::sun::star::chart::TimeUnit::MONTH;
1220 : : }
1221 [ # # ]: 0 : if( ::com::sun::star::chart::TimeUnit::MONTH == nRet )
1222 : : {
1223 [ # # ][ # # ]: 0 : if( DateHelper::IsInSameMonth( aPrevious, aCurrent ) )
1224 : 0 : nRet = ::com::sun::star::chart::TimeUnit::DAY;
1225 : : }
1226 [ # # ]: 0 : if( ::com::sun::star::chart::TimeUnit::DAY == nRet )
1227 : : break;
1228 : 0 : aPrevious=aCurrent;
1229 : : }
1230 : : }
1231 : : }
1232 : 0 : return nRet;
1233 : : }
1234 : 1938 : double VSeriesPlotter::getMinimumX()
1235 : : {
1236 : : double fMinimum, fMaximum;
1237 [ + - ]: 1938 : this->getMinimumAndMaximiumX( fMinimum, fMaximum );
1238 : 1938 : return fMinimum;
1239 : : }
1240 : 1938 : double VSeriesPlotter::getMaximumX()
1241 : : {
1242 : : double fMinimum, fMaximum;
1243 [ + - ]: 1938 : this->getMinimumAndMaximiumX( fMinimum, fMaximum );
1244 : 1938 : return fMaximum;
1245 : : }
1246 : :
1247 : 1952 : double VSeriesPlotter::getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex )
1248 : : {
1249 [ + - ][ + - ]: 1952 : if( !m_bCategoryXAxis || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) )
[ + - ][ - + ]
[ - + ]
1250 : : {
1251 : : double fMinY, fMaxY;
1252 [ # # ]: 0 : this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
1253 : 0 : return fMinY;
1254 : : }
1255 : :
1256 : : double fMinimum, fMaximum;
1257 : 1952 : ::rtl::math::setInf(&fMinimum, false);
1258 : 1952 : ::rtl::math::setInf(&fMaximum, true);
1259 [ + + ]: 3996 : for(size_t nZ =0; nZ<m_aZSlots.size();nZ++ )
1260 : : {
1261 : 2044 : ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[nZ];
1262 [ + + ]: 8402 : for(size_t nN =0; nN<rXSlots.size();nN++ )
1263 : : {
1264 : : double fLocalMinimum, fLocalMaximum;
1265 : 6358 : rXSlots[nN].calculateYMinAndMaxForCategoryRange(
1266 : : static_cast<sal_Int32>(fMinimumX-1.0) //first category (index 0) matches with real number 1.0
1267 : : , static_cast<sal_Int32>(fMaximumX-1.0) //first category (index 0) matches with real number 1.0
1268 [ + - ]: 6358 : , isSeperateStackingForDifferentSigns( 1 )
1269 [ + - ]: 6358 : , fLocalMinimum, fLocalMaximum, nAxisIndex );
1270 [ + + ]: 6358 : if(fMaximum<fLocalMaximum)
1271 : 3974 : fMaximum=fLocalMaximum;
1272 [ + + ]: 6358 : if(fMinimum>fLocalMinimum)
1273 : 3956 : fMinimum=fLocalMinimum;
1274 : : }
1275 : : }
1276 [ + + ]: 1952 : if(::rtl::math::isInf(fMinimum))
1277 : 14 : ::rtl::math::setNan(&fMinimum);
1278 : 1952 : return fMinimum;
1279 : : }
1280 : :
1281 : 1952 : double VSeriesPlotter::getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex )
1282 : : {
1283 [ + - ][ + - ]: 1952 : if( !m_bCategoryXAxis || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) )
[ + - ][ - + ]
[ - + ]
1284 : : {
1285 : : double fMinY, fMaxY;
1286 [ # # ]: 0 : this->getMinimumAndMaximiumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex );
1287 : 0 : return fMaxY;
1288 : : }
1289 : :
1290 : : double fMinimum, fMaximum;
1291 : 1952 : ::rtl::math::setInf(&fMinimum, false);
1292 : 1952 : ::rtl::math::setInf(&fMaximum, true);
1293 [ + + ]: 3996 : for(size_t nZ =0; nZ<m_aZSlots.size();nZ++ )
1294 : : {
1295 : 2044 : ::std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[nZ];
1296 [ + + ]: 8402 : for(size_t nN =0; nN<rXSlots.size();nN++ )
1297 : : {
1298 : : double fLocalMinimum, fLocalMaximum;
1299 : 6358 : rXSlots[nN].calculateYMinAndMaxForCategoryRange(
1300 : : static_cast<sal_Int32>(fMinimumX-1.0) //first category (index 0) matches with real number 1.0
1301 : : , static_cast<sal_Int32>(fMaximumX-1.0) //first category (index 0) matches with real number 1.0
1302 [ + - ]: 6358 : , isSeperateStackingForDifferentSigns( 1 )
1303 [ + - ]: 6358 : , fLocalMinimum, fLocalMaximum, nAxisIndex );
1304 [ + + ]: 6358 : if(fMaximum<fLocalMaximum)
1305 : 3974 : fMaximum=fLocalMaximum;
1306 [ + + ]: 6358 : if(fMinimum>fLocalMinimum)
1307 : 3956 : fMinimum=fLocalMinimum;
1308 : : }
1309 : : }
1310 [ + + ]: 1952 : if(::rtl::math::isInf(fMaximum))
1311 : 14 : ::rtl::math::setNan(&fMaximum);
1312 : 1952 : return fMaximum;
1313 : : }
1314 : :
1315 : 28 : double VSeriesPlotter::getMinimumZ()
1316 : : {
1317 : : //this is the default for all charts without a meaningfull z axis
1318 : 28 : return 1.0;
1319 : : }
1320 : 28 : double VSeriesPlotter::getMaximumZ()
1321 : : {
1322 [ + - ][ - + ]: 28 : if( 3!=m_nDimension || !m_aZSlots.size() )
[ - + ]
1323 : 0 : return getMinimumZ()+1;
1324 : 28 : return m_aZSlots.size();
1325 : : }
1326 : :
1327 : : namespace
1328 : : {
1329 : 7710 : bool lcl_isValueAxis( sal_Int32 nDimensionIndex, bool bCategoryXAxis )
1330 : : {
1331 : : // default implementation: true for Y axes, and for value X axis
1332 [ + + ]: 7710 : if( nDimensionIndex == 0 )
1333 : 3834 : return !bCategoryXAxis;
1334 [ + + ]: 3876 : if( nDimensionIndex == 1 )
1335 : 3848 : return true;
1336 : 7710 : return false;
1337 : : }
1338 : : }
1339 : :
1340 : 3918 : bool VSeriesPlotter::isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex )
1341 : : {
1342 : 3918 : return lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis );
1343 : : }
1344 : :
1345 : 3918 : bool VSeriesPlotter::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex )
1346 : : {
1347 : : // do not expand axes in 3D charts
1348 [ + + ][ + + ]: 3918 : return (m_nDimension < 3) && lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis );
1349 : : }
1350 : :
1351 : 3918 : bool VSeriesPlotter::isExpandWideValuesToZero( sal_Int32 nDimensionIndex )
1352 : : {
1353 : : // default implementation: only for Y axis
1354 : 3918 : return nDimensionIndex == 1;
1355 : : }
1356 : :
1357 : 3918 : bool VSeriesPlotter::isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex )
1358 : : {
1359 : : // default implementation: only for Y axis
1360 : 3918 : return nDimensionIndex == 1;
1361 : : }
1362 : :
1363 : 33542 : bool VSeriesPlotter::isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex )
1364 : : {
1365 : : // default implementation: only for Y axis
1366 : 33542 : return nDimensionIndex == 1;
1367 : : }
1368 : :
1369 : 3876 : void VSeriesPlotter::getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const
1370 : : {
1371 : 3876 : ::rtl::math::setInf(&rfMinimum, false);
1372 : 3876 : ::rtl::math::setInf(&rfMaximum, true);
1373 : :
1374 : 3876 : ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter = m_aZSlots.begin();
1375 : 3876 : const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
1376 [ + - ][ + + ]: 7880 : for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
1377 : : {
1378 : 4004 : ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
1379 : 4004 : const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
1380 [ + - ][ + + ]: 16636 : for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
1381 : : {
1382 : : double fLocalMinimum, fLocalMaximum;
1383 [ + - ]: 12632 : aXSlotIter->getMinimumAndMaximiumX( fLocalMinimum, fLocalMaximum );
1384 [ + - ][ + + ]: 12632 : if( !::rtl::math::isNan(fLocalMinimum) && fLocalMinimum< rfMinimum )
[ + + ]
1385 : 3876 : rfMinimum = fLocalMinimum;
1386 [ + - ][ + + ]: 12632 : if( !::rtl::math::isNan(fLocalMaximum) && fLocalMaximum> rfMaximum )
[ + + ]
1387 : 3876 : rfMaximum = fLocalMaximum;
1388 : : }
1389 : : }
1390 [ - + ]: 3876 : if(::rtl::math::isInf(rfMinimum))
1391 : 0 : ::rtl::math::setNan(&rfMinimum);
1392 [ - + ]: 3876 : if(::rtl::math::isInf(rfMaximum))
1393 : 0 : ::rtl::math::setNan(&rfMaximum);
1394 : 3876 : }
1395 : :
1396 : 0 : void VSeriesPlotter::getMinimumAndMaximiumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const
1397 : : {
1398 : 0 : ::rtl::math::setInf(&rfMinY, false);
1399 : 0 : ::rtl::math::setInf(&rfMaxY, true);
1400 : :
1401 : 0 : ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter = m_aZSlots.begin();
1402 : 0 : const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
1403 [ # # ][ # # ]: 0 : for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
1404 : : {
1405 : 0 : ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
1406 : 0 : const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
1407 [ # # ][ # # ]: 0 : for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
1408 : : {
1409 : : double fLocalMinimum, fLocalMaximum;
1410 [ # # ]: 0 : aXSlotIter->getMinimumAndMaximiumYInContinuousXRange( fLocalMinimum, fLocalMaximum, fMinX, fMaxX, nAxisIndex );
1411 [ # # ][ # # ]: 0 : if( !::rtl::math::isNan(fLocalMinimum) && fLocalMinimum< rfMinY )
[ # # ]
1412 : 0 : rfMinY = fLocalMinimum;
1413 [ # # ][ # # ]: 0 : if( !::rtl::math::isNan(fLocalMaximum) && fLocalMaximum> rfMaxY )
[ # # ]
1414 : 0 : rfMaxY = fLocalMaximum;
1415 : : }
1416 : : }
1417 [ # # ]: 0 : if(::rtl::math::isInf(rfMinY))
1418 : 0 : ::rtl::math::setNan(&rfMinY);
1419 [ # # ]: 0 : if(::rtl::math::isInf(rfMaxY))
1420 : 0 : ::rtl::math::setNan(&rfMaxY);
1421 : 0 : }
1422 : :
1423 : 962 : sal_Int32 VSeriesPlotter::getPointCount() const
1424 : : {
1425 : 962 : sal_Int32 nRet = 0;
1426 : :
1427 : 962 : ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter = m_aZSlots.begin();
1428 : 962 : const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
1429 : :
1430 [ + - ][ + + ]: 1942 : for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
1431 : : {
1432 : 980 : ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
1433 : 980 : const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
1434 : :
1435 [ + - ][ + + ]: 4117 : for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
1436 : : {
1437 [ + - ]: 3137 : sal_Int32 nPointCount = aXSlotIter->getPointCount();
1438 [ + + ]: 3137 : if( nPointCount>nRet )
1439 : 962 : nRet = nPointCount;
1440 : : }
1441 : : }
1442 : 962 : return nRet;
1443 : : }
1444 : :
1445 : 981 : void VSeriesPlotter::setNumberFormatsSupplier(
1446 : : const uno::Reference< util::XNumberFormatsSupplier > & xNumFmtSupplier )
1447 : : {
1448 [ + - ]: 981 : m_apNumberFormatterWrapper.reset( new NumberFormatterWrapper( xNumFmtSupplier ));
1449 : 981 : }
1450 : :
1451 : 981 : void VSeriesPlotter::setColorScheme( const uno::Reference< XColorScheme >& xColorScheme )
1452 : : {
1453 : 981 : m_xColorScheme = xColorScheme;
1454 : 981 : }
1455 : :
1456 : 981 : void VSeriesPlotter::setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider )
1457 : : {
1458 : 981 : m_pExplicitCategoriesProvider = pExplicitCategoriesProvider;
1459 : 981 : }
1460 : :
1461 : 93131 : sal_Int32 VDataSeriesGroup::getPointCount() const
1462 : : {
1463 [ + + ]: 93131 : if(!m_bMaxPointCountDirty)
1464 : 89994 : return m_nMaxPointCount;
1465 : :
1466 : 3137 : sal_Int32 nRet = 0;
1467 : 3137 : ::std::vector< VDataSeries* >::const_iterator aSeriesIter = m_aSeriesVector.begin();
1468 : 3137 : const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
1469 : :
1470 [ + - ][ + + ]: 6286 : for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter)
1471 : : {
1472 [ + - ]: 3149 : sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount();
1473 [ + + ]: 3149 : if( nPointCount>nRet )
1474 : 3137 : nRet = nPointCount;
1475 : : }
1476 : 3137 : m_nMaxPointCount=nRet;
1477 : 3137 : m_aListOfCachedYValues.clear();
1478 [ + - ]: 3137 : m_aListOfCachedYValues.resize(m_nMaxPointCount);
1479 : 3137 : m_bMaxPointCountDirty=false;
1480 : 93131 : return nRet;
1481 : : }
1482 : :
1483 : 22222 : sal_Int32 VDataSeriesGroup::getAttachedAxisIndexForFirstSeries() const
1484 : : {
1485 : 22222 : sal_Int32 nRet = 0;
1486 : 22222 : ::std::vector< VDataSeries* >::const_iterator aSeriesIter = m_aSeriesVector.begin();
1487 : 22222 : const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
1488 : :
1489 [ + - ][ + - ]: 22222 : if( aSeriesIter != aSeriesEnd )
1490 [ + - ]: 22222 : nRet = (*aSeriesIter)->getAttachedAxisIndex();
1491 : :
1492 : 22222 : return nRet;
1493 : : }
1494 : :
1495 : 12632 : void VDataSeriesGroup::getMinimumAndMaximiumX( double& rfMinimum, double& rfMaximum ) const
1496 : : {
1497 : 12632 : const ::std::vector< VDataSeries* >* pSeriesList = &this->m_aSeriesVector;
1498 : :
1499 : 12632 : ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
1500 : 12632 : const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
1501 : :
1502 : 12632 : ::rtl::math::setInf(&rfMinimum, false);
1503 : 12632 : ::rtl::math::setInf(&rfMaximum, true);
1504 : :
1505 [ + - ][ + + ]: 25312 : for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
1506 : : {
1507 [ + - ]: 12680 : sal_Int32 nPointCount = (*aSeriesIter)->getTotalPointCount();
1508 [ + + ]: 68584 : for(sal_Int32 nN=0;nN<nPointCount;nN++)
1509 : : {
1510 [ + - ]: 55904 : double fX = (*aSeriesIter)->getXValue( nN );
1511 [ - + ]: 55904 : if( ::rtl::math::isNan(fX) )
1512 : 0 : continue;
1513 [ + + ]: 55904 : if(rfMaximum<fX)
1514 : 55280 : rfMaximum=fX;
1515 [ + + ]: 55904 : if(rfMinimum>fX)
1516 : 12632 : rfMinimum=fX;
1517 : : }
1518 : : }
1519 [ - + ]: 12632 : if(::rtl::math::isInf(rfMinimum))
1520 : 0 : ::rtl::math::setNan(&rfMinimum);
1521 [ - + ]: 12632 : if(::rtl::math::isInf(rfMaximum))
1522 : 0 : ::rtl::math::setNan(&rfMaximum);
1523 : 12632 : }
1524 : :
1525 : : namespace {
1526 : :
1527 : : /**
1528 : : * Keep track of minimum and maximum Y values for one or more data series.
1529 : : * When multiple data series exist, that indicates that the data series are
1530 : : * stacked.
1531 : : *
1532 : : * <p>For each X value, we calculate separate Y value ranges for each data
1533 : : * series in the first pass. In the second pass, we calculate the minimum Y
1534 : : * value by taking the absolute minimum value of all data series, whereas
1535 : : * the maxium Y value is the sum of all the series maximum Y values.</p>
1536 : : *
1537 : : * <p>Once that's done for all X values, the final min / max Y values get
1538 : : * calculated by taking the absolute min / max Y values across all the X
1539 : : * values.</p>
1540 : : */
1541 : 0 : class PerXMinMaxCalculator
1542 : : {
1543 : : typedef std::pair<double, double> MinMaxType;
1544 : : typedef std::map<size_t, MinMaxType> SeriesMinMaxType;
1545 : : typedef boost::ptr_map<double, SeriesMinMaxType> GroupMinMaxType;
1546 : : typedef boost::unordered_map<double, MinMaxType> TotalStoreType;
1547 : : GroupMinMaxType maSeriesGroup;
1548 : : size_t mnCurSeries;
1549 : :
1550 : : public:
1551 : 0 : PerXMinMaxCalculator() : mnCurSeries(0) {}
1552 : :
1553 : 0 : void nextSeries() { ++mnCurSeries; }
1554 : :
1555 : 0 : void setValue(double fX, double fY)
1556 : : {
1557 [ # # ]: 0 : SeriesMinMaxType* pStore = getByXValue(fX); // get storage for given X value.
1558 [ # # ]: 0 : if (!pStore)
1559 : : // This shouldn't happen!
1560 : 0 : return;
1561 : :
1562 [ # # ]: 0 : SeriesMinMaxType::iterator it = pStore->lower_bound(mnCurSeries);
1563 [ # # ][ # # ]: 0 : if (it != pStore->end() && !pStore->key_comp()(mnCurSeries, it->first))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # # #
# # ]
1564 : : {
1565 [ # # ]: 0 : MinMaxType& r = it->second;
1566 : : // A min-max pair already exists for this series. Update it.
1567 [ # # ]: 0 : if (fY < r.first)
1568 : 0 : r.first = fY;
1569 [ # # ]: 0 : if (r.second < fY)
1570 : 0 : r.second = fY;
1571 : : }
1572 : : else
1573 : : {
1574 : : // No existing pair. Insert a new one.
1575 : : pStore->insert(
1576 : : it, SeriesMinMaxType::value_type(
1577 [ # # ][ # # ]: 0 : mnCurSeries, MinMaxType(fY,fY)));
[ # # ][ # # ]
1578 : : }
1579 : : }
1580 : :
1581 : 0 : void getTotalRange(double& rfMin, double& rfMax) const
1582 : : {
1583 : 0 : rtl::math::setNan(&rfMin);
1584 : 0 : rtl::math::setNan(&rfMax);
1585 : :
1586 [ # # ]: 0 : TotalStoreType aStore;
1587 [ # # ]: 0 : getTotalStore(aStore);
1588 : :
1589 [ # # ]: 0 : if (aStore.empty())
1590 : 0 : return;
1591 : :
1592 [ # # ][ # # ]: 0 : TotalStoreType::const_iterator it = aStore.begin(), itEnd = aStore.end();
1593 [ # # ]: 0 : rfMin = it->second.first;
1594 [ # # ]: 0 : rfMax = it->second.second;
1595 [ # # ]: 0 : for (++it; it != itEnd; ++it)
1596 : : {
1597 [ # # ][ # # ]: 0 : if (rfMin > it->second.first)
1598 [ # # ]: 0 : rfMin = it->second.first;
1599 [ # # ][ # # ]: 0 : if (rfMax < it->second.second)
1600 [ # # ]: 0 : rfMax = it->second.second;
1601 [ # # ][ # # ]: 0 : }
1602 : : }
1603 : :
1604 : : private:
1605 : : /**
1606 : : * Parse all data and reduce them into a set of global Y value ranges per
1607 : : * X value.
1608 : : */
1609 : 0 : void getTotalStore(TotalStoreType& rStore) const
1610 : : {
1611 [ # # ]: 0 : TotalStoreType aStore;
1612 [ # # ][ # # ]: 0 : GroupMinMaxType::const_iterator it = maSeriesGroup.begin(), itEnd = maSeriesGroup.end();
1613 [ # # ][ # # ]: 0 : for (; it != itEnd; ++it)
[ # # ]
1614 : : {
1615 [ # # ]: 0 : double fX = it->first;
1616 : :
1617 [ # # ]: 0 : const SeriesMinMaxType& rSeries = *it->second;
1618 : 0 : SeriesMinMaxType::const_iterator itSeries = rSeries.begin(), itSeriesEnd = rSeries.end();
1619 [ # # ][ # # ]: 0 : for (; itSeries != itSeriesEnd; ++itSeries)
[ # # ]
1620 : : {
1621 [ # # ][ # # ]: 0 : double fYMin = itSeries->second.first, fYMax = itSeries->second.second;
1622 [ # # ]: 0 : TotalStoreType::iterator itr = aStore.find(fX);
1623 [ # # ][ # # ]: 0 : if (itr == aStore.end())
1624 : : // New min-max pair for give X value.
1625 : : aStore.insert(
1626 [ # # ][ # # ]: 0 : TotalStoreType::value_type(fX, std::pair<double,double>(fYMin,fYMax)));
[ # # ]
1627 : : else
1628 : : {
1629 [ # # ]: 0 : MinMaxType& r = itr->second;
1630 [ # # ]: 0 : if (fYMin < r.first)
1631 : 0 : r.first = fYMin; // min y-value
1632 : :
1633 : 0 : r.second += fYMax; // accumulative max y-value.
1634 : : }
1635 : : }
1636 : : }
1637 [ # # ][ # # ]: 0 : rStore.swap(aStore);
1638 : 0 : }
1639 : :
1640 : 0 : SeriesMinMaxType* getByXValue(double fX)
1641 : : {
1642 [ # # ]: 0 : GroupMinMaxType::iterator it = maSeriesGroup.find(fX);
1643 [ # # ][ # # ]: 0 : if (it == maSeriesGroup.end())
[ # # ]
1644 : : {
1645 : : std::pair<GroupMinMaxType::iterator,bool> r =
1646 [ # # ][ # # ]: 0 : maSeriesGroup.insert(fX, new SeriesMinMaxType);
[ # # ]
1647 : :
1648 [ # # ]: 0 : if (!r.second)
1649 : : // insertion failed.
1650 : 0 : return NULL;
1651 : :
1652 : 0 : it = r.first;
1653 : : }
1654 : :
1655 [ # # ]: 0 : return it->second;
1656 : : }
1657 : : };
1658 : :
1659 : : }
1660 : :
1661 : 0 : void VDataSeriesGroup::getMinimumAndMaximiumYInContinuousXRange(
1662 : : double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const
1663 : : {
1664 : 0 : ::rtl::math::setNan(&rfMinY);
1665 : 0 : ::rtl::math::setNan(&rfMaxY);
1666 : :
1667 [ # # ]: 0 : if (m_aSeriesVector.empty())
1668 : : // No data series. Bail out.
1669 : 0 : return;
1670 : :
1671 [ # # ]: 0 : PerXMinMaxCalculator aRangeCalc;
1672 : 0 : std::vector<VDataSeries*>::const_iterator it = m_aSeriesVector.begin(), itEnd = m_aSeriesVector.end();
1673 [ # # ][ # # ]: 0 : for (; it != itEnd; ++it)
1674 : : {
1675 : 0 : const VDataSeries* pSeries = *it;
1676 [ # # ]: 0 : if (!pSeries)
1677 : 0 : continue;
1678 : :
1679 [ # # ][ # # ]: 0 : for (sal_Int32 i = 0, n = pSeries->getTotalPointCount(); i < n; ++i)
1680 : : {
1681 [ # # ][ # # ]: 0 : if (nAxisIndex != pSeries->getAttachedAxisIndex())
1682 : 0 : continue;
1683 : :
1684 [ # # ]: 0 : double fX = pSeries->getXValue(i);
1685 [ # # ]: 0 : if (rtl::math::isNan(fX))
1686 : 0 : continue;
1687 : :
1688 [ # # ][ # # ]: 0 : if (fX < fMinX || fX > fMaxX)
1689 : : // Outside specified X range. Skip it.
1690 : 0 : continue;
1691 : :
1692 [ # # ]: 0 : double fY = pSeries->getYValue(i);
1693 [ # # ]: 0 : if (::rtl::math::isNan(fY))
1694 : 0 : continue;
1695 : :
1696 [ # # ]: 0 : aRangeCalc.setValue(fX, fY);
1697 : : }
1698 : 0 : aRangeCalc.nextSeries();
1699 : : }
1700 : :
1701 [ # # ][ # # ]: 0 : aRangeCalc.getTotalRange(rfMinY, rfMaxY);
1702 : : }
1703 : :
1704 : 89994 : void VDataSeriesGroup::calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
1705 : : , bool bSeperateStackingForDifferentSigns
1706 : : , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex )
1707 : : {
1708 : 89994 : ::rtl::math::setInf(&rfMinimumY, false);
1709 : 89994 : ::rtl::math::setInf(&rfMaximumY, true);
1710 : :
1711 [ + - ]: 89994 : sal_Int32 nPointCount = getPointCount();//necessary to create m_aListOfCachedYValues
1712 [ + - ][ + + ]: 89994 : if(nCategoryIndex<0 || nCategoryIndex>=nPointCount || m_aSeriesVector.empty())
[ - + ][ + + ]
1713 : : return;
1714 : :
1715 [ + - ]: 78582 : CachedYValues aCachedYValues = m_aListOfCachedYValues[nCategoryIndex][nAxisIndex];
1716 [ + + ]: 78582 : if( !aCachedYValues.m_bValuesDirty )
1717 : : {
1718 : : //return cached values
1719 : 64762 : rfMinimumY = aCachedYValues.m_fMinimumY;
1720 : 64762 : rfMaximumY = aCachedYValues.m_fMaximumY;
1721 : : return;
1722 : : }
1723 : :
1724 : : double fTotalSum, fPositiveSum, fNegativeSum, fFirstPositiveY, fFirstNegativeY;
1725 : 13820 : ::rtl::math::setNan( &fTotalSum );
1726 : 13820 : ::rtl::math::setNan( &fPositiveSum );
1727 : 13820 : ::rtl::math::setNan( &fNegativeSum );
1728 : 13820 : ::rtl::math::setNan( &fFirstPositiveY );
1729 : 13820 : ::rtl::math::setNan( &fFirstNegativeY );
1730 : :
1731 [ + - ]: 13820 : ::std::vector< VDataSeries* >::const_iterator aSeriesIter = m_aSeriesVector.begin();
1732 [ + - ]: 13820 : ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = m_aSeriesVector.end();
1733 : :
1734 [ + + ]: 13820 : if( bSeperateStackingForDifferentSigns )
1735 : : {
1736 [ + - ][ + + ]: 22210 : for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
1737 : : {
1738 [ + - ][ - + ]: 11105 : if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
1739 : 0 : continue;
1740 : :
1741 [ + - ]: 11105 : double fValueMinY = (*aSeriesIter)->getMinimumofAllDifferentYValues( nCategoryIndex );
1742 [ + - ]: 11105 : double fValueMaxY = (*aSeriesIter)->getMaximumofAllDifferentYValues( nCategoryIndex );
1743 : :
1744 [ + + ]: 11105 : if( fValueMaxY >= 0 )
1745 : : {
1746 [ + - ]: 10899 : if( ::rtl::math::isNan( fPositiveSum ) )
1747 : 10899 : fPositiveSum = fFirstPositiveY = fValueMaxY;
1748 : : else
1749 : 0 : fPositiveSum += fValueMaxY;
1750 : : }
1751 [ + + ]: 11105 : if( fValueMinY < 0 )
1752 : : {
1753 [ + - ]: 190 : if(::rtl::math::isNan( fNegativeSum ))
1754 : 190 : fNegativeSum = fFirstNegativeY = fValueMinY;
1755 : : else
1756 : 0 : fNegativeSum += fValueMinY;
1757 : : }
1758 : : }
1759 [ + + ]: 11105 : rfMinimumY = ::rtl::math::isNan( fNegativeSum ) ? fFirstPositiveY : fNegativeSum;
1760 [ + + ]: 11105 : rfMaximumY = ::rtl::math::isNan( fPositiveSum ) ? fFirstNegativeY : fPositiveSum;
1761 : : }
1762 : : else
1763 : : {
1764 [ + - ][ + + ]: 5586 : for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
1765 : : {
1766 [ + - ][ + + ]: 2871 : if( nAxisIndex != (*aSeriesIter)->getAttachedAxisIndex() )
1767 : 273 : continue;
1768 : :
1769 [ + - ]: 2598 : double fValueMinY = (*aSeriesIter)->getMinimumofAllDifferentYValues( nCategoryIndex );
1770 [ + - ]: 2598 : double fValueMaxY = (*aSeriesIter)->getMaximumofAllDifferentYValues( nCategoryIndex );
1771 : :
1772 [ + + ]: 2598 : if( ::rtl::math::isNan( fTotalSum ) )
1773 : : {
1774 : 2442 : rfMinimumY = fValueMinY;
1775 : 2442 : rfMaximumY = fTotalSum = fValueMaxY;
1776 : : }
1777 : : else
1778 : : {
1779 : 156 : fTotalSum += fValueMaxY;
1780 [ + + ]: 156 : if( rfMinimumY > fTotalSum )
1781 : 36 : rfMinimumY = fTotalSum;
1782 [ + + ]: 156 : if( rfMaximumY < fTotalSum )
1783 : 102 : rfMaximumY = fTotalSum;
1784 : : }
1785 : : }
1786 : : }
1787 : :
1788 : 13820 : aCachedYValues.m_fMinimumY = rfMinimumY;
1789 : 13820 : aCachedYValues.m_fMaximumY = rfMaximumY;
1790 : 13820 : aCachedYValues.m_bValuesDirty = false;
1791 [ + - ]: 89994 : m_aListOfCachedYValues[nCategoryIndex][nAxisIndex]=aCachedYValues;
1792 : : }
1793 : :
1794 : 12716 : void VDataSeriesGroup::calculateYMinAndMaxForCategoryRange(
1795 : : sal_Int32 nStartCategoryIndex, sal_Int32 nEndCategoryIndex
1796 : : , bool bSeperateStackingForDifferentSigns
1797 : : , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex )
1798 : : {
1799 : : //@todo maybe cache these values
1800 : 12716 : ::rtl::math::setInf(&rfMinimumY, false);
1801 : 12716 : ::rtl::math::setInf(&rfMaximumY, true);
1802 : :
1803 : : //iterate through the given categories
1804 [ - + ]: 12716 : if(nStartCategoryIndex<0)
1805 : 0 : nStartCategoryIndex=0;
1806 [ - + ]: 12716 : if(nEndCategoryIndex<0)
1807 : 0 : nEndCategoryIndex=0;
1808 [ + + ]: 80500 : for( sal_Int32 nCatIndex = nStartCategoryIndex; nCatIndex <= nEndCategoryIndex; nCatIndex++ )
1809 : : {
1810 : 67784 : double fMinimumY; ::rtl::math::setNan(&fMinimumY);
1811 : 67784 : double fMaximumY; ::rtl::math::setNan(&fMaximumY);
1812 : :
1813 : : this->calculateYMinAndMaxForCategory( nCatIndex
1814 [ + - ]: 67784 : , bSeperateStackingForDifferentSigns, fMinimumY, fMaximumY, nAxisIndex );
1815 : :
1816 [ + + ]: 67784 : if(rfMinimumY > fMinimumY)
1817 : 25760 : rfMinimumY = fMinimumY;
1818 [ + + ]: 67784 : if(rfMaximumY < fMaximumY)
1819 : 25904 : rfMaximumY = fMaximumY;
1820 : : }
1821 : 12716 : }
1822 : :
1823 : 2213 : double VSeriesPlotter::getTransformedDepth() const
1824 : : {
1825 [ + - ]: 2213 : double MinZ = m_pMainPosHelper->getLogicMinZ();
1826 [ + - ]: 2213 : double MaxZ = m_pMainPosHelper->getLogicMaxZ();
1827 [ + - ]: 2213 : m_pMainPosHelper->doLogicScaling( 0, 0, &MinZ );
1828 [ + - ]: 2213 : m_pMainPosHelper->doLogicScaling( 0, 0, &MaxZ );
1829 : 2213 : return FIXED_SIZE_FOR_3D_CHART_VOLUME/(MaxZ-MinZ);
1830 : : }
1831 : :
1832 : 14 : void VSeriesPlotter::addSecondaryValueScale( const ExplicitScaleData& rScale, sal_Int32 nAxisIndex )
1833 : : throw (uno::RuntimeException)
1834 : : {
1835 [ - + ]: 14 : if( nAxisIndex<1 )
1836 : 14 : return;
1837 : :
1838 : 14 : m_aSecondaryValueScales[nAxisIndex]=rScale;
1839 : : }
1840 : :
1841 : 16492 : PlottingPositionHelper& VSeriesPlotter::getPlottingPositionHelper( sal_Int32 nAxisIndex ) const
1842 : : {
1843 : 16492 : PlottingPositionHelper* pRet = 0;
1844 [ - + ]: 16492 : if(nAxisIndex>0)
1845 : : {
1846 [ # # ]: 0 : tSecondaryPosHelperMap::const_iterator aPosIt = m_aSecondaryPosHelperMap.find( nAxisIndex );
1847 [ # # ]: 0 : if( aPosIt != m_aSecondaryPosHelperMap.end() )
1848 : : {
1849 : 0 : pRet = aPosIt->second;
1850 : : }
1851 : : else
1852 : : {
1853 [ # # ]: 0 : tSecondaryValueScales::const_iterator aScaleIt = m_aSecondaryValueScales.find( nAxisIndex );
1854 [ # # ][ # # ]: 0 : if( aScaleIt != m_aSecondaryValueScales.end() )
1855 : : {
1856 [ # # ][ # # ]: 0 : pRet = m_pPosHelper->createSecondaryPosHelper( aScaleIt->second );
1857 [ # # ]: 0 : m_aSecondaryPosHelperMap[nAxisIndex] = pRet;
1858 : : }
1859 : : }
1860 : : }
1861 [ + - ]: 16492 : if( !pRet )
1862 : 16492 : pRet = m_pMainPosHelper;
1863 [ + - ]: 16492 : if(pRet)
1864 : 16492 : pRet->setTimeResolution( m_nTimeResolution, m_aNullDate );
1865 : 16492 : return *pRet;
1866 : : }
1867 : :
1868 : 0 : void VSeriesPlotter::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& /*rPageSize*/ )
1869 : : {
1870 : 0 : }
1871 : :
1872 : 886 : VDataSeries* VSeriesPlotter::getFirstSeries() const
1873 : : {
1874 : 886 : ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter( m_aZSlots.begin() );
1875 : 886 : ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd( m_aZSlots.end() );
1876 [ + - ][ + - ]: 886 : for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
1877 : : {
1878 : 886 : ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
1879 : 886 : const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
1880 : :
1881 [ + - ][ + - ]: 886 : if( aXSlotIter != aXSlotEnd )
1882 : : {
1883 [ + - ]: 886 : VDataSeriesGroup aSeriesGroup( *aXSlotIter );
1884 [ + - ]: 886 : if( aSeriesGroup.m_aSeriesVector.size() )
1885 : : {
1886 : 886 : VDataSeries* pSeries = aSeriesGroup.m_aSeriesVector[0];
1887 [ + - ]: 886 : if(pSeries)
1888 : 886 : return pSeries;
1889 [ - + ]: 886 : }
1890 : : }
1891 : : }
1892 : 886 : return 0;
1893 : : }
1894 : :
1895 : 14 : uno::Sequence< rtl::OUString > VSeriesPlotter::getSeriesNames() const
1896 : : {
1897 [ + - ]: 14 : ::std::vector< rtl::OUString > aRetVector;
1898 : :
1899 : 14 : rtl::OUString aRole;
1900 [ + - ]: 14 : if( m_xChartTypeModel.is() )
1901 [ + - ][ + - ]: 14 : aRole = m_xChartTypeModel->getRoleOfSequenceForSeriesLabel();
1902 : :
1903 : 14 : ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotIter( m_aZSlots.begin() );
1904 : 14 : ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd( m_aZSlots.end() );
1905 [ + - ][ + + ]: 46 : for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
1906 : : {
1907 : 32 : ::std::vector< VDataSeriesGroup >::const_iterator aXSlotIter = aZSlotIter->begin();
1908 : 32 : const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
1909 : :
1910 [ + - ][ + - ]: 32 : if( aXSlotIter != aXSlotEnd )
1911 : : {
1912 [ + - ]: 32 : VDataSeriesGroup aSeriesGroup( *aXSlotIter );
1913 [ + - ]: 32 : if( aSeriesGroup.m_aSeriesVector.size() )
1914 : : {
1915 : 32 : VDataSeries* pSeries = aSeriesGroup.m_aSeriesVector[0];
1916 [ + - ][ # # ]: 32 : uno::Reference< XDataSeries > xSeries( pSeries ? pSeries->getModel() : 0 );
[ + - ]
1917 [ + - ]: 32 : if( xSeries.is() )
1918 : : {
1919 [ + - ]: 32 : rtl::OUString aSeriesName( DataSeriesHelper::getDataSeriesLabel( xSeries, aRole ) );
1920 [ + - ]: 32 : aRetVector.push_back( aSeriesName );
1921 : 32 : }
1922 : 32 : }
1923 : : }
1924 : : }
1925 [ + - ]: 14 : return ContainerHelper::ContainerToSequence( aRetVector );
1926 : : }
1927 : :
1928 : : namespace
1929 : : {
1930 : : struct lcl_setRefSizeAtSeriesGroup : public ::std::unary_function< VDataSeriesGroup, void >
1931 : : {
1932 : 981 : lcl_setRefSizeAtSeriesGroup( awt::Size aRefSize ) : m_aRefSize( aRefSize ) {}
1933 : 3194 : void operator()( VDataSeriesGroup & rGroup )
1934 : : {
1935 : 3194 : ::std::vector< VDataSeries* >::iterator aIt( rGroup.m_aSeriesVector.begin());
1936 : 3194 : const ::std::vector< VDataSeries* >::iterator aEndIt( rGroup.m_aSeriesVector.end());
1937 [ + - ][ + + ]: 6400 : for( ; aIt != aEndIt; ++aIt )
1938 [ + - ]: 3206 : (*aIt)->setPageReferenceSize( m_aRefSize );
1939 : 3194 : }
1940 : :
1941 : : private:
1942 : : awt::Size m_aRefSize;
1943 : : };
1944 : : } // anonymous namespace
1945 : :
1946 : 981 : void VSeriesPlotter::setPageReferenceSize( const ::com::sun::star::awt::Size & rPageRefSize )
1947 : : {
1948 : 981 : m_aPageReferenceSize = rPageRefSize;
1949 : :
1950 : : // set reference size also at all data series
1951 : :
1952 [ + - ]: 981 : ::std::vector< VDataSeriesGroup > aSeriesGroups( FlattenVector( m_aZSlots ));
1953 : : ::std::for_each( aSeriesGroups.begin(), aSeriesGroups.end(),
1954 [ + - ]: 981 : lcl_setRefSizeAtSeriesGroup( m_aPageReferenceSize ));
1955 : 981 : }
1956 : :
1957 : : //better performance for big data
1958 : 981 : void VSeriesPlotter::setCoordinateSystemResolution( const Sequence< sal_Int32 >& rCoordinateSystemResolution )
1959 : : {
1960 : 981 : m_aCoordinateSystemResolution = rCoordinateSystemResolution;
1961 : 981 : }
1962 : :
1963 : 1000 : bool VSeriesPlotter::PointsWereSkipped() const
1964 : : {
1965 : 1000 : return m_bPointsWereSkipped;
1966 : : }
1967 : :
1968 : 981 : bool VSeriesPlotter::WantToPlotInFrontOfAxisLine()
1969 : : {
1970 : 981 : return ChartTypeHelper::isSeriesInFrontOfAxisLine( m_xChartTypeModel );
1971 : : }
1972 : :
1973 : 962 : bool VSeriesPlotter::shouldSnapRectToUsedArea()
1974 : : {
1975 [ + + ]: 962 : if( m_nDimension == 3 )
1976 : 14 : return false;
1977 : 962 : return true;
1978 : : }
1979 : :
1980 : 944 : std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntries(
1981 : : const awt::Size& rEntryKeyAspectRatio
1982 : : , ::com::sun::star::chart::ChartLegendExpansion eLegendExpansion
1983 : : , const Reference< beans::XPropertySet >& xTextProperties
1984 : : , const Reference< drawing::XShapes >& xTarget
1985 : : , const Reference< lang::XMultiServiceFactory >& xShapeFactory
1986 : : , const Reference< uno::XComponentContext >& xContext
1987 : : )
1988 : : {
1989 : 944 : std::vector< ViewLegendEntry > aResult;
1990 : :
1991 [ + - ]: 944 : if( xTarget.is() )
1992 : : {
1993 : : //iterate through all series
1994 : 944 : bool bBreak = false;
1995 : 944 : bool bFirstSeries = true;
1996 : 944 : ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
1997 [ + - ]: 944 : const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
1998 [ + - ][ + + ]: 1906 : for( ; aZSlotIter!=aZSlotEnd && !bBreak; ++aZSlotIter )
[ + - ][ + + ]
1999 : : {
2000 : 962 : ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
2001 [ + - ]: 962 : const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
2002 [ + - ][ + + ]: 4023 : for( ; aXSlotIter!=aXSlotEnd && !bBreak; ++aXSlotIter )
[ + + ][ + + ]
2003 : : {
2004 : 3061 : ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
2005 [ + - ]: 3061 : ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin();
2006 [ + - ]: 3061 : const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end();
2007 : : //iterate through all series in this x slot
2008 [ + - ][ + + ]: 6134 : for( ; aSeriesIter!=aSeriesEnd && !bBreak; ++aSeriesIter )
[ + - ][ + + ]
2009 : : {
2010 : 3073 : VDataSeries* pSeries( *aSeriesIter );
2011 [ - + ]: 3073 : if(!pSeries)
2012 : 0 : continue;
2013 : :
2014 : : std::vector< ViewLegendEntry > aSeriesEntries( this->createLegendEntriesForSeries( rEntryKeyAspectRatio,
2015 [ + - ]: 3073 : *pSeries, xTextProperties, xTarget, xShapeFactory, xContext ) );
2016 : :
2017 : : //add series entries to the result now
2018 : :
2019 : : // use only the first series if VaryColorsByPoint is set for the first series
2020 [ + + ][ + - ]: 3073 : if( bFirstSeries && pSeries->isVaryColorsByPoint() )
[ + + ][ + + ]
2021 : 11 : bBreak = true;
2022 : 3073 : bFirstSeries = false;
2023 : :
2024 : : // add entries reverse if chart is stacked in y-direction and the legend is not wide.
2025 : : // If the legend is wide and we have a stacked bar-chart the normal order
2026 : : // is the correct one
2027 : 3073 : bool bReverse = false;
2028 [ + - ]: 3073 : if( eLegendExpansion != ::com::sun::star::chart::ChartLegendExpansion_WIDE )
2029 : : {
2030 [ + - ]: 3073 : StackingDirection eStackingDirection( pSeries->getStackingDirection() );
2031 : 3073 : bReverse = ( eStackingDirection == StackingDirection_Y_STACKING );
2032 : :
2033 : : //todo: respect direction of axis in future
2034 : : }
2035 : :
2036 [ + + ]: 3073 : if(bReverse)
2037 [ + - ]: 18 : aResult.insert( aResult.begin(), aSeriesEntries.begin(), aSeriesEntries.end() );
2038 : : else
2039 [ + - ]: 3055 : aResult.insert( aResult.end(), aSeriesEntries.begin(), aSeriesEntries.end() );
2040 : 3073 : }
2041 : : }
2042 : : }
2043 : : }
2044 : :
2045 : 944 : return aResult;
2046 : : }
2047 : :
2048 : 930 : ::std::vector< VDataSeries* > VSeriesPlotter::getAllSeries()
2049 : : {
2050 [ + - ]: 930 : ::std::vector< VDataSeries* > aAllSeries;
2051 : 930 : ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin();
2052 [ + - ]: 930 : const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end();
2053 [ + - ][ + + ]: 1860 : for( ; aZSlotIter != aZSlotEnd; ++aZSlotIter )
2054 : : {
2055 : 930 : ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin();
2056 [ + - ]: 930 : const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end();
2057 [ + - ][ + + ]: 3971 : for( ; aXSlotIter != aXSlotEnd; ++aXSlotIter )
2058 : : {
2059 [ + - ]: 3041 : ::std::vector< VDataSeries* > aSeriesList = aXSlotIter->m_aSeriesVector;
2060 [ + - ]: 3041 : aAllSeries.insert( aAllSeries.end(), aSeriesList.begin(), aSeriesList.end() );
2061 : 3041 : }
2062 : : }
2063 : 930 : return aAllSeries;
2064 : : }
2065 : :
2066 : : namespace
2067 : : {
2068 : 391 : bool lcl_HasVisibleLine( const uno::Reference< beans::XPropertySet >& xProps, bool& rbHasDashedLine )
2069 : : {
2070 : 391 : bool bHasVisibleLine = false;
2071 : 391 : rbHasDashedLine = false;
2072 : 391 : drawing::LineStyle aLineStyle = drawing::LineStyle_NONE;
2073 [ + - ][ + - ]: 391 : if( xProps.is() && ( xProps->getPropertyValue( C2U("LineStyle")) >>= aLineStyle ) )
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - # #
# # ]
2074 : : {
2075 [ + + ]: 391 : if( aLineStyle != drawing::LineStyle_NONE )
2076 : 381 : bHasVisibleLine = true;
2077 [ - + ]: 391 : if( aLineStyle == drawing::LineStyle_DASH )
2078 : 0 : rbHasDashedLine = true;
2079 : : }
2080 : 391 : return bHasVisibleLine;
2081 : : }
2082 : :
2083 : 3053 : bool lcl_HasRegressionCurves( const VDataSeries& rSeries, bool& rbHasDashedLine )
2084 : : {
2085 : 3053 : bool bHasRegressionCurves = false;
2086 [ + - ][ + - ]: 3053 : Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
2087 [ + - ]: 3053 : if( xRegrCont.is())
2088 : : {
2089 [ + - ][ + - ]: 3053 : Sequence< Reference< XRegressionCurve > > aCurves( xRegrCont->getRegressionCurves() );
2090 : 3053 : sal_Int32 i = 0, nCount = aCurves.getLength();
2091 [ + + ]: 3161 : for( i=0; i<nCount; ++i )
2092 : : {
2093 [ + - ][ + - ]: 108 : if( aCurves[i].is() )
2094 : : {
2095 : 108 : bHasRegressionCurves = true;
2096 [ + - ][ + - ]: 108 : lcl_HasVisibleLine( uno::Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ), rbHasDashedLine );
[ + - ]
2097 : : }
2098 [ + - ]: 3053 : }
2099 : : }
2100 : 3053 : return bHasRegressionCurves;
2101 : : }
2102 : : }
2103 : 3646 : LegendSymbolStyle VSeriesPlotter::getLegendSymbolStyle()
2104 : : {
2105 : 3646 : return LegendSymbolStyle_BOX;
2106 : : }
2107 : :
2108 : 944 : awt::Size VSeriesPlotter::getPreferredLegendKeyAspectRatio()
2109 : : {
2110 : 944 : awt::Size aRet(1000,1000);
2111 [ + + ]: 944 : if( m_nDimension==3 )
2112 : : return aRet;
2113 : :
2114 [ + - ]: 930 : bool bSeriesAllowsLines = (getLegendSymbolStyle() == LegendSymbolStyle_LINE);
2115 : 930 : bool bHasLines = false;
2116 : 930 : bool bHasDashedLines = false;
2117 [ + - ]: 930 : ::std::vector< VDataSeries* > aAllSeries( getAllSeries() );
2118 [ + - ]: 930 : ::std::vector< VDataSeries* >::const_iterator aSeriesIter = aAllSeries.begin();
2119 [ + - ]: 930 : const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = aAllSeries.end();
2120 : : //iterate through all series
2121 [ + - ][ + + ]: 3983 : for( ; aSeriesIter != aSeriesEnd; ++aSeriesIter )
2122 : : {
2123 [ + + ]: 3053 : if( bSeriesAllowsLines )
2124 : : {
2125 : 283 : bool bCurrentDashed = false;
2126 [ + - ][ + - ]: 283 : if( lcl_HasVisibleLine( (*aSeriesIter)->getPropertiesOfSeries(), bCurrentDashed ) )
[ + - ]
2127 : : {
2128 : 283 : bHasLines = true;
2129 [ - + ]: 283 : if( bCurrentDashed )
2130 : : {
2131 : 283 : bHasDashedLines = true;
2132 : : break;
2133 : : }
2134 : : }
2135 : : }
2136 : 3053 : bool bRegressionHasDashedLines=false;
2137 [ + - ][ + + ]: 3053 : if( lcl_HasRegressionCurves( **aSeriesIter, bRegressionHasDashedLines ) )
2138 : : {
2139 : 76 : bHasLines = true;
2140 [ - + ]: 76 : if( bRegressionHasDashedLines )
2141 : : {
2142 : 0 : bHasDashedLines = true;
2143 : : break;
2144 : : }
2145 : : }
2146 : : }
2147 [ + + ]: 930 : if( bHasLines )
2148 : : {
2149 [ - + ]: 65 : if( bHasDashedLines )
2150 : 0 : aRet = awt::Size(1600,-1);
2151 : : else
2152 : 65 : aRet = awt::Size(800,-1);
2153 : : }
2154 : 944 : return aRet;
2155 : : }
2156 : :
2157 : 2801 : uno::Any VSeriesPlotter::getExplicitSymbol( const VDataSeries& /*rSeries*/, sal_Int32 /*nPointIndex*/ )
2158 : : {
2159 : 2801 : return uno::Any();
2160 : : }
2161 : :
2162 : 3062 : Reference< drawing::XShape > VSeriesPlotter::createLegendSymbolForSeries(
2163 : : const awt::Size& rEntryKeyAspectRatio
2164 : : , const VDataSeries& rSeries
2165 : : , const Reference< drawing::XShapes >& xTarget
2166 : : , const Reference< lang::XMultiServiceFactory >& xShapeFactory )
2167 : : {
2168 : :
2169 [ + - ]: 3062 : LegendSymbolStyle eLegendSymbolStyle = this->getLegendSymbolStyle();
2170 [ + - ]: 3062 : uno::Any aExplicitSymbol( this->getExplicitSymbol( rSeries ) );
2171 : :
2172 : : VLegendSymbolFactory::tPropertyType ePropType =
2173 : 3062 : VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES;
2174 : :
2175 : : // todo: maybe the property-style does not solely depend on the
2176 : : // legend-symbol type
2177 [ + + ]: 3062 : switch( eLegendSymbolStyle )
2178 : : {
2179 : : case LegendSymbolStyle_LINE:
2180 : 283 : ePropType = VLegendSymbolFactory::PROP_TYPE_LINE_SERIES;
2181 : 283 : break;
2182 : : default:
2183 : 2779 : break;
2184 : : };
2185 : : Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
2186 : : xTarget, eLegendSymbolStyle, xShapeFactory
2187 [ + - ][ + - ]: 3062 : , rSeries.getPropertiesOfSeries(), ePropType, aExplicitSymbol ));
2188 : :
2189 : 3062 : return xShape;
2190 : : }
2191 : :
2192 : 35 : Reference< drawing::XShape > VSeriesPlotter::createLegendSymbolForPoint(
2193 : : const awt::Size& rEntryKeyAspectRatio
2194 : : , const VDataSeries& rSeries
2195 : : , sal_Int32 nPointIndex
2196 : : , const Reference< drawing::XShapes >& xTarget
2197 : : , const Reference< lang::XMultiServiceFactory >& xShapeFactory )
2198 : : {
2199 : :
2200 [ + - ]: 35 : LegendSymbolStyle eLegendSymbolStyle = this->getLegendSymbolStyle();
2201 [ + - ]: 35 : uno::Any aExplicitSymbol( this->getExplicitSymbol(rSeries,nPointIndex) );
2202 : :
2203 : : VLegendSymbolFactory::tPropertyType ePropType =
2204 : 35 : VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES;
2205 : :
2206 : : // todo: maybe the property-style does not solely depend on the
2207 : : // legend-symbol type
2208 [ - + ]: 35 : switch( eLegendSymbolStyle )
2209 : : {
2210 : : case LegendSymbolStyle_LINE:
2211 : 0 : ePropType = VLegendSymbolFactory::PROP_TYPE_LINE_SERIES;
2212 : 0 : break;
2213 : : default:
2214 : 35 : break;
2215 : : };
2216 : :
2217 : : // the default properties for the data point are the data series properties.
2218 : : // If a data point has own attributes overwrite them
2219 [ + - ]: 35 : Reference< beans::XPropertySet > xSeriesProps( rSeries.getPropertiesOfSeries() );
2220 : 35 : Reference< beans::XPropertySet > xPointSet( xSeriesProps );
2221 [ - + ][ + - ]: 35 : if( rSeries.isAttributedDataPoint( nPointIndex ) )
2222 [ # # ][ # # ]: 0 : xPointSet.set( rSeries.getPropertiesOfPoint( nPointIndex ));
2223 : :
2224 : : // if a data point has no own color use a color fom the diagram's color scheme
2225 [ + - ][ + - ]: 35 : if( ! rSeries.hasPointOwnColor( nPointIndex ))
2226 : : {
2227 [ + - ]: 35 : Reference< util::XCloneable > xCloneable( xPointSet,uno::UNO_QUERY );
2228 [ + - ][ + - ]: 35 : if( xCloneable.is() && m_xColorScheme.is() )
[ + - ]
2229 : : {
2230 [ + - ][ + - ]: 35 : xPointSet.set( xCloneable->createClone(), uno::UNO_QUERY );
[ + - ]
2231 [ + - ]: 35 : Reference< container::XChild > xChild( xPointSet, uno::UNO_QUERY );
2232 [ - + ]: 35 : if( xChild.is())
2233 [ # # ][ # # ]: 0 : xChild->setParent( xSeriesProps );
2234 : :
2235 : : OSL_ASSERT( xPointSet.is());
2236 [ + - ]: 35 : xPointSet->setPropertyValue(
2237 [ + - ][ + - ]: 35 : C2U("Color"), uno::makeAny( m_xColorScheme->getColorByIndex( nPointIndex )));
[ + - ][ + - ]
[ + - ]
2238 : 35 : }
2239 : : }
2240 : :
2241 : : Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
2242 [ + - ]: 35 : xTarget, eLegendSymbolStyle, xShapeFactory, xPointSet, ePropType, aExplicitSymbol ));
2243 : :
2244 : 35 : return xShape;
2245 : : }
2246 : :
2247 : 3073 : std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntriesForSeries(
2248 : : const awt::Size& rEntryKeyAspectRatio
2249 : : , const VDataSeries& rSeries
2250 : : , const Reference< beans::XPropertySet >& xTextProperties
2251 : : , const Reference< drawing::XShapes >& xTarget
2252 : : , const Reference< lang::XMultiServiceFactory >& xShapeFactory
2253 : : , const Reference< uno::XComponentContext >& xContext
2254 : : )
2255 : : {
2256 : 3073 : std::vector< ViewLegendEntry > aResult;
2257 : :
2258 [ + - ][ - + ]: 3073 : if( ! ( xShapeFactory.is() && xTarget.is() && xContext.is() ) )
[ - + ][ + - ]
2259 : 0 : return aResult;
2260 : :
2261 : : try
2262 : : {
2263 [ + - ]: 3073 : ViewLegendEntry aEntry;
2264 : 3073 : OUString aLabelText;
2265 [ + - ]: 3073 : bool bVaryColorsByPoint = rSeries.isVaryColorsByPoint();
2266 [ + + ]: 3073 : if( bVaryColorsByPoint )
2267 : : {
2268 [ + - ]: 11 : Sequence< OUString > aCategoryNames;
2269 [ + - ]: 11 : if( m_pExplicitCategoriesProvider )
2270 [ + - ][ + - ]: 11 : aCategoryNames = m_pExplicitCategoriesProvider->getSimpleCategories();
[ + - ]
2271 : :
2272 [ + + ]: 46 : for( sal_Int32 nIdx=0; nIdx<aCategoryNames.getLength(); ++nIdx )
2273 : : {
2274 : : // symbol
2275 [ + - ][ + - ]: 35 : uno::Reference< drawing::XShapes > xSymbolGroup( ShapeFactory(xShapeFactory).createGroup2D( xTarget ));
[ + - ]
2276 : :
2277 : : // create the symbol
2278 : : Reference< drawing::XShape > xShape( this->createLegendSymbolForPoint( rEntryKeyAspectRatio,
2279 [ + - ]: 35 : rSeries, nIdx, xSymbolGroup, xShapeFactory ) );
2280 : :
2281 : : // set CID to symbol for selection
2282 [ + - ]: 35 : if( xShape.is() )
2283 : : {
2284 [ + - ][ + - ]: 35 : aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
2285 : :
2286 [ + - ]: 35 : OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_DATA_POINT, nIdx ) );
2287 [ + - ][ + - ]: 35 : aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
2288 [ + - ][ + - ]: 35 : OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
2289 [ + - ]: 35 : ShapeFactory::setShapeName( xShape, aCID );
2290 : : }
2291 : :
2292 : : // label
2293 [ + - ]: 35 : aLabelText = aCategoryNames[nIdx];
2294 [ # # ][ + - ]: 35 : if( xShape.is() || !aLabelText.isEmpty() )
[ - + ]
2295 : : {
2296 [ + - ][ + - ]: 35 : aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
2297 [ + - ]: 35 : aResult.push_back(aEntry);
2298 : : }
2299 [ + - ]: 46 : }
2300 : : }
2301 : : else
2302 : : {
2303 : : // symbol
2304 [ + - ][ + - ]: 3062 : uno::Reference< drawing::XShapes > xSymbolGroup( ShapeFactory(xShapeFactory).createGroup2D( xTarget ));
[ + - ]
2305 : :
2306 : : // create the symbol
2307 : : Reference< drawing::XShape > xShape( this->createLegendSymbolForSeries(
2308 [ + - ]: 3062 : rEntryKeyAspectRatio, rSeries, xSymbolGroup, xShapeFactory ) );
2309 : :
2310 : : // set CID to symbol for selection
2311 [ + - ]: 3062 : if( xShape.is())
2312 : : {
2313 [ + - ][ + - ]: 3062 : aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
2314 : :
2315 [ + - ]: 3062 : OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
2316 [ + - ][ + - ]: 3062 : OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
2317 [ + - ]: 3062 : ShapeFactory::setShapeName( xShape, aCID );
2318 : : }
2319 : :
2320 : : // label
2321 [ + - ][ + - ]: 3062 : aLabelText = ( DataSeriesHelper::getDataSeriesLabel( rSeries.getModel(), m_xChartTypeModel.is() ? m_xChartTypeModel->getRoleOfSequenceForSeriesLabel() : C2U("values-y")) );
[ + - ][ # # ]
[ + - ][ + - ]
2322 [ + - ][ + - ]: 3062 : aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
2323 : :
2324 [ + - ]: 3062 : aResult.push_back(aEntry);
2325 : : }
2326 : :
2327 : : // don't show legend entry of regression curve & friends if this type of chart
2328 : : // doesn't support statistics #i63016#, fdo#37197
2329 [ + - ][ + + ]: 3073 : if (!ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ))
2330 : : return aResult;
2331 : :
2332 [ + - ][ + - ]: 3000 : Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
2333 [ + - ]: 3000 : if( xRegrCont.is())
2334 : : {
2335 [ + - ][ + - ]: 3000 : Sequence< Reference< XRegressionCurve > > aCurves( xRegrCont->getRegressionCurves());
2336 : 3000 : sal_Int32 i = 0, nCount = aCurves.getLength();
2337 [ + + ]: 3108 : for( i=0; i<nCount; ++i )
2338 : : {
2339 [ + - ][ + - ]: 108 : if( aCurves[i].is() )
2340 : : {
2341 : : //label
2342 [ + - ][ + - ]: 108 : OUString aResStr( RegressionCurveHelper::getUINameForRegressionCurve( aCurves[i] ) );
2343 [ + - ][ + - ]: 108 : replaceParamterInString( aResStr, C2U("%SERIESNAME"), aLabelText );
2344 [ + - ][ + - ]: 108 : aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aResStr, xTextProperties );
2345 : :
2346 : : // symbol
2347 [ + - ][ + - ]: 108 : uno::Reference< drawing::XShapes > xSymbolGroup( ShapeFactory(xShapeFactory).createGroup2D( xTarget ));
[ + - ]
2348 : :
2349 : : // create the symbol
2350 : : Reference< drawing::XShape > xShape( VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
2351 : : xSymbolGroup, LegendSymbolStyle_LINE, xShapeFactory,
2352 [ + - ]: 108 : Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ),
2353 [ + - ][ + - ]: 216 : VLegendSymbolFactory::PROP_TYPE_LINE, uno::Any() ));
2354 : :
2355 : : // set CID to symbol for selection
2356 [ + - ]: 108 : if( xShape.is())
2357 : : {
2358 [ + - ][ + - ]: 108 : aEntry.aSymbol = uno::Reference< drawing::XShape >( xSymbolGroup, uno::UNO_QUERY );
2359 : :
2360 [ + - ][ + - ]: 108 : bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurves[i] );
2361 [ + + ]: 108 : ObjectType eObjectType = bAverageLine ? OBJECTTYPE_DATA_AVERAGE_LINE : OBJECTTYPE_DATA_CURVE;
2362 [ + - ]: 108 : OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( eObjectType, i ) );
2363 [ + - ][ + - ]: 108 : aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
2364 [ + - ][ + - ]: 108 : OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
2365 [ + - ]: 108 : ShapeFactory::setShapeName( xShape, aCID );
2366 : : }
2367 : :
2368 [ + - ]: 108 : aResult.push_back(aEntry);
2369 : : }
2370 [ + - ]: 3000 : }
2371 [ + + ][ + - ]: 3073 : }
[ + + ][ # # ]
2372 : : }
2373 [ # # ]: 0 : catch( const uno::Exception & ex )
2374 : : {
2375 : : ASSERT_EXCEPTION( ex );
2376 : : }
2377 : 3073 : return aResult;
2378 : : }
2379 : :
2380 : 981 : VSeriesPlotter* VSeriesPlotter::createSeriesPlotter(
2381 : : const uno::Reference<XChartType>& xChartTypeModel
2382 : : , sal_Int32 nDimensionCount
2383 : : , bool bExcludingPositioning )
2384 : : {
2385 [ + - ][ + - ]: 981 : rtl::OUString aChartType = xChartTypeModel->getChartType();
2386 : :
2387 : : //@todo: in future the plotter should be instanciated via service factory
2388 : 981 : VSeriesPlotter* pRet=NULL;
2389 [ + - ][ + + ]: 981 : if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_COLUMN ) )
2390 [ + - ][ + - ]: 886 : pRet = new BarChart(xChartTypeModel,nDimensionCount);
2391 [ + - ][ - + ]: 95 : else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_BAR ) )
2392 [ # # ][ # # ]: 0 : pRet = new BarChart(xChartTypeModel,nDimensionCount);
2393 [ + - ][ - + ]: 95 : else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_AREA ) )
2394 [ # # ][ # # ]: 0 : pRet = new AreaChart(xChartTypeModel,nDimensionCount,true);
2395 [ + - ][ + + ]: 95 : else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_LINE ) )
2396 [ + - ][ + - ]: 72 : pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,true);
2397 [ + - ][ - + ]: 23 : else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) )
2398 [ # # ][ # # ]: 0 : pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true);
2399 [ + - ][ - + ]: 23 : else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE) )
2400 [ # # ][ # # ]: 0 : pRet = new BubbleChart(xChartTypeModel,nDimensionCount);
2401 [ + - ][ + + ]: 23 : else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
2402 [ + - ][ + - ]: 19 : pRet = new PieChart(xChartTypeModel,nDimensionCount, bExcludingPositioning );
2403 [ + - ][ - + ]: 4 : else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_NET) )
2404 [ # # ][ # # ]: 0 : pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,true,new PolarPlottingPositionHelper(),true,false,1,drawing::Direction3D(1,1,1) );
[ # # ][ # # ]
2405 [ + - ][ - + ]: 4 : else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) )
2406 [ # # ][ # # ]: 0 : pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,false,new PolarPlottingPositionHelper(),true,false,1,drawing::Direction3D(1,1,1) );
[ # # ][ # # ]
2407 [ + - ][ + - ]: 4 : else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) )
2408 [ + - ][ + - ]: 4 : pRet = new CandleStickChart(xChartTypeModel,nDimensionCount);
2409 : : else
2410 [ # # ][ # # ]: 0 : pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true);
2411 : 981 : return pRet;
2412 : : }
2413 : :
2414 : : //.............................................................................
2415 : : } //namespace chart
2416 : : //.............................................................................
2417 : :
2418 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|