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