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