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