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