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