1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <sal/config.h>
25 #include <chartview/ExplicitScaleValues.hxx>
27 #include <basegfx/range/b2drectangle.hxx>
28 #include <tools/long.hxx>
29 #include <com/sun/star/drawing/Direction3D.hpp>
30 #include <com/sun/star/drawing/Position3D.hpp>
31 #include <basegfx/matrix/b3dhommatrix.hxx>
32 #include <com/sun/star/awt/Point.hpp>
33 #include <com/sun/star/uno/Sequence.hxx>
34 #include <rtl/ref.hxx>
35 #include <svx/unoshape.hxx>
37 namespace com::sun::star::drawing
{ class XShapes
; }
38 namespace com::sun::star::drawing
{ struct HomogenMatrix
; }
39 namespace com::sun::star::drawing
{ struct PolyPolygonShape3D
; }
46 /** allows the transformation of numeric values from one
47 coordinate-system into another. Values may be transformed using
49 This is a non-UNO variant of the css::chart2::XTransformation interface,
50 but using more efficient calling and returning types.
52 class XTransformation2
55 virtual ~XTransformation2();
56 /** transforms the given input data tuple, given in the source
57 coordinate system, according to the internal transformation
58 rules, into a tuple of transformed coordinates in the
59 destination coordinate system.
61 <p>Note that both coordinate systems may have different
62 dimensions, e.g., if a transformation does simply a projection
63 into a lower-dimensional space.</p>
65 @param aValues a source tuple of data that is to be
66 transformed. The length of this sequence must be
67 equivalent to the dimension of the source coordinate
70 @return the transformed data tuple. The length of this
71 sequence is equal to the dimension of the output
74 @throws ::com::sun::star::lang::IllegalArgumentException
75 if the dimension of the input vector is not equal to the
76 dimension given in getSourceDimension().
78 virtual css::drawing::Position3D
transform(
79 const css::drawing::Position3D
& rSourceValues
) const = 0;
80 virtual css::drawing::Position3D
transform(
81 const css::uno::Sequence
< double >& rSourceValues
) const = 0;
85 class PlottingPositionHelper
88 PlottingPositionHelper();
89 PlottingPositionHelper( const PlottingPositionHelper
& rSource
);
90 virtual ~PlottingPositionHelper();
92 virtual std::unique_ptr
<PlottingPositionHelper
> clone() const;
93 std::unique_ptr
<PlottingPositionHelper
> createSecondaryPosHelper( const ExplicitScaleData
& rSecondaryScale
);
95 virtual void setTransformationSceneToScreen( const css::drawing::HomogenMatrix
& rMatrix
);
97 virtual void setScales( std::vector
< ExplicitScaleData
>&& rScales
, bool bSwapXAndYAxis
);
98 const std::vector
< ExplicitScaleData
>& getScales() const { return m_aScales
;}
100 //better performance for big data
101 inline void setCoordinateSystemResolution( const css::uno::Sequence
< sal_Int32
>& rCoordinateSystemResolution
);
102 inline bool isSameForGivenResolution( double fX
, double fY
, double fZ
103 , double fX2
, double fY2
, double fZ2
);
105 inline bool isStrongLowerRequested( sal_Int32 nDimensionIndex
) const;
106 inline bool isLogicVisible( double fX
, double fY
, double fZ
) const;
107 inline void doLogicScaling( double* pX
, double* pY
, double* pZ
) const;
108 inline void doUnshiftedLogicScaling( double* pX
, double* pY
, double* pZ
) const;
109 inline void clipLogicValues( double* pX
, double* pY
, double* pZ
) const;
110 void clipScaledLogicValues( double* pX
, double* pY
, double* pZ
) const;
111 inline bool clipYRange( double& rMin
, double& rMax
) const;
113 inline void doLogicScaling( css::drawing::Position3D
& rPos
) const;
115 virtual ::chart::XTransformation2
*
116 getTransformationScaledLogicToScene() const;
118 virtual css::drawing::Position3D
119 transformLogicToScene( double fX
, double fY
, double fZ
, bool bClip
) const;
121 virtual css::drawing::Position3D
122 transformScaledLogicToScene( double fX
, double fY
, double fZ
, bool bClip
) const;
124 void transformScaledLogicToScene( css::drawing::PolyPolygonShape3D
& rPoly
) const;
125 void transformScaledLogicToScene( std::vector
<std::vector
<css::drawing::Position3D
>>& rPoly
) const;
127 static css::awt::Point
transformSceneToScreenPosition(
128 const css::drawing::Position3D
& rScenePosition3D
129 , const rtl::Reference
<SvxShapeGroupAnyD
>& xSceneTarget
130 , sal_Int32 nDimensionCount
);
132 inline double getLogicMinX() const;
133 inline double getLogicMinY() const;
134 inline double getLogicMinZ() const;
135 inline double getLogicMaxX() const;
136 inline double getLogicMaxY() const;
137 inline double getLogicMaxZ() const;
139 inline bool isMathematicalOrientationX() const;
140 inline bool isMathematicalOrientationY() const;
141 inline bool isMathematicalOrientationZ() const;
143 ::basegfx::B2DRectangle
getScaledLogicClipDoubleRect() const;
144 css::drawing::Direction3D
getScaledLogicWidth() const;
146 inline bool isSwapXAndY() const;
148 bool isPercentY() const;
150 double getBaseValueY() const;
152 inline bool maySkipPointsInRegressionCalculation() const;
154 void setTimeResolution( tools::Long nTimeResolution
, const Date
& rNullDate
);
155 virtual void setScaledCategoryWidth( double fScaledCategoryWidth
);
156 void AllowShiftXAxisPos( bool bAllowShift
);
157 void AllowShiftZAxisPos( bool bAllowShift
);
160 std::vector
< ExplicitScaleData
> m_aScales
;
161 ::basegfx::B3DHomMatrix m_aMatrixScreenToScene
;
163 //this is calculated based on m_aScales and m_aMatrixScreenToScene
164 mutable std::unique_ptr
< ::chart::XTransformation2
> m_xTransformationLogicToScene
;
166 bool m_bSwapXAndY
;//e.g. true for bar chart and false for column chart
168 sal_Int32 m_nXResolution
;
169 sal_Int32 m_nYResolution
;
170 sal_Int32 m_nZResolution
;
172 bool m_bMaySkipPointsInRegressionCalculation
;
175 tools::Long m_nTimeResolution
;
178 double m_fScaledCategoryWidth
;
179 bool m_bAllowShiftXAxisPos
;
180 bool m_bAllowShiftZAxisPos
;
183 class PolarPlottingPositionHelper
: public PlottingPositionHelper
186 PolarPlottingPositionHelper();
187 PolarPlottingPositionHelper( const PolarPlottingPositionHelper
& rSource
);
188 virtual ~PolarPlottingPositionHelper() override
;
190 virtual std::unique_ptr
<PlottingPositionHelper
> clone() const override
;
192 virtual void setTransformationSceneToScreen( const css::drawing::HomogenMatrix
& rMatrix
) override
;
193 virtual void setScales( std::vector
< ExplicitScaleData
>&& rScales
, bool bSwapXAndYAxis
) override
;
195 const ::basegfx::B3DHomMatrix
& getUnitCartesianToScene() const { return m_aUnitCartesianToScene
;}
197 virtual ::chart::XTransformation2
*
198 getTransformationScaledLogicToScene() const override
;
200 //the resulting values provided by the following 3 methods should be used
201 //for input to the transformation received with
202 //'getTransformationScaledLogicToScene'
204 /** Given a value in the radius axis scale range, it returns the normalized
207 double transformToRadius( double fLogicValueOnRadiusAxis
, bool bDoScaling
=true ) const;
209 /** Given a value in the angle axis scale range (e.g. [0,1] for pie charts)
210 * this method returns the related angle in degree.
212 double transformToAngleDegree( double fLogicValueOnAngleAxis
, bool bDoScaling
=true ) const;
214 /** Given 2 values in the angle axis scale range (e.g. [0,1] for pie charts)
215 * this method returns the angle between the 2 values keeping into account
216 * the correct axis orientation; (for instance, this method is used for
217 * computing the angle width of a pie slice).
219 double getWidthAngleDegree( double& fStartLogicValueOnAngleAxis
, double& fEndLogicValueOnAngleAxis
) const;
221 virtual css::drawing::Position3D
222 transformLogicToScene( double fX
, double fY
, double fZ
, bool bClip
) const override
;
223 virtual css::drawing::Position3D
224 transformScaledLogicToScene( double fX
, double fY
, double fZ
, bool bClip
) const override
;
225 css::drawing::Position3D
226 transformAngleRadiusToScene( double fLogicValueOnAngleAxis
, double fLogicValueOnRadiusAxis
, double fLogicZ
, bool bDoScaling
=true ) const;
228 /** Return the scene coordinates of the passed point: this point is
229 * described through a normalized cylindrical coordinate system, with an
231 * (For a standard pie chart the origin of the coordinate system is the
232 * pie center; for an of-pie chart the components of the aOffset
233 * parameter are not all zero).
235 css::drawing::Position3D
236 transformUnitCircleToScene( double fUnitAngleDegree
237 , double fUnitRadius
, double fLogicZ
238 , const ::basegfx::B3DVector
& aOffset
= ::basegfx::B3DVector()) const;
240 using PlottingPositionHelper::transformScaledLogicToScene
;
242 double getOuterLogicRadius() const;
244 inline bool isMathematicalOrientationAngle() const;
245 inline bool isMathematicalOrientationRadius() const;
247 ///m_bSwapXAndY (inherited): by default the X axis (scale[0]) represents
248 ///the angle axis and the Y axis (scale[1]) represents the radius axis;
249 ///when this parameter is true, the opposite happens (this is the case for
252 ///Offset for radius axis in absolute logic scaled values (1.0 == 1 category)
253 ///For a donut, it represents the non-normalized inner radius (see notes for
254 ///transformToRadius)
255 double m_fRadiusOffset
;
256 ///Offset for angle axis in real degree.
257 ///For a pie it represents the angle offset at which the first slice have to
259 double m_fAngleDegreeOffset
;
262 ::basegfx::B3DHomMatrix m_aUnitCartesianToScene
;
264 ::basegfx::B3DHomMatrix
impl_calculateMatrixUnitCartesianToScene( const ::basegfx::B3DHomMatrix
& rMatrixScreenToScene
) const;
267 bool PolarPlottingPositionHelper::isMathematicalOrientationAngle() const
269 const ExplicitScaleData
& rScale
= m_bSwapXAndY
? m_aScales
[1] : m_aScales
[2];
270 if( css::chart2::AxisOrientation_MATHEMATICAL
==rScale
.Orientation
)
274 bool PolarPlottingPositionHelper::isMathematicalOrientationRadius() const
276 const ExplicitScaleData
& rScale
= m_bSwapXAndY
? m_aScales
[0] : m_aScales
[1];
277 if( css::chart2::AxisOrientation_MATHEMATICAL
==rScale
.Orientation
)
282 //better performance for big data
283 void PlottingPositionHelper::setCoordinateSystemResolution( const css::uno::Sequence
< sal_Int32
>& rCoordinateSystemResolution
)
285 m_nXResolution
= 1000;
286 m_nYResolution
= 1000;
287 m_nZResolution
= 1000;
288 if( rCoordinateSystemResolution
.getLength() > 0 )
289 m_nXResolution
= rCoordinateSystemResolution
[0];
290 if( rCoordinateSystemResolution
.getLength() > 1 )
291 m_nYResolution
= rCoordinateSystemResolution
[1];
292 if( rCoordinateSystemResolution
.getLength() > 2 )
293 m_nZResolution
= rCoordinateSystemResolution
[2];
296 bool PlottingPositionHelper::isSameForGivenResolution( double fX
, double fY
, double fZ
297 , double fX2
, double fY2
, double fZ2
/*these values are all expected tp be scaled already*/ )
299 if( !std::isfinite(fX
) || !std::isfinite(fY
) || !std::isfinite(fZ
)
300 || !std::isfinite(fX2
) || !std::isfinite(fY2
) || !std::isfinite(fZ2
) )
303 double fScaledMinX
= getLogicMinX();
304 double fScaledMinY
= getLogicMinY();
305 double fScaledMinZ
= getLogicMinZ();
306 double fScaledMaxX
= getLogicMaxX();
307 double fScaledMaxY
= getLogicMaxY();
308 double fScaledMaxZ
= getLogicMaxZ();
310 doLogicScaling( &fScaledMinX
, &fScaledMinY
, &fScaledMinZ
);
311 doLogicScaling( &fScaledMaxX
, &fScaledMaxY
, &fScaledMaxZ
);
313 bool bSameX
= ( static_cast<sal_Int32
>(m_nXResolution
*(fX
- fScaledMinX
)/(fScaledMaxX
-fScaledMinX
))
314 == static_cast<sal_Int32
>(m_nXResolution
*(fX2
- fScaledMinX
)/(fScaledMaxX
-fScaledMinX
)) );
316 bool bSameY
= ( static_cast<sal_Int32
>(m_nYResolution
*(fY
- fScaledMinY
)/(fScaledMaxY
-fScaledMinY
))
317 == static_cast<sal_Int32
>(m_nYResolution
*(fY2
- fScaledMinY
)/(fScaledMaxY
-fScaledMinY
)) );
319 bool bSameZ
= ( static_cast<sal_Int32
>(m_nZResolution
*(fZ
- fScaledMinZ
)/(fScaledMaxZ
-fScaledMinZ
))
320 == static_cast<sal_Int32
>(m_nZResolution
*(fZ2
- fScaledMinZ
)/(fScaledMaxZ
-fScaledMinZ
)) );
322 return (bSameX
&& bSameY
&& bSameZ
);
325 bool PlottingPositionHelper::isStrongLowerRequested( sal_Int32 nDimensionIndex
) const
327 if( m_aScales
.empty() )
329 if( 0==nDimensionIndex
)
330 return m_bAllowShiftXAxisPos
&& m_aScales
[nDimensionIndex
].m_bShiftedCategoryPosition
;
331 else if( 2==nDimensionIndex
)
332 return m_bAllowShiftZAxisPos
&& m_aScales
[nDimensionIndex
].m_bShiftedCategoryPosition
;
336 bool PlottingPositionHelper::isLogicVisible(
337 double fX
, double fY
, double fZ
) const
339 return fX
>= m_aScales
[0].Minimum
&& ( isStrongLowerRequested(0) ? fX
< m_aScales
[0].Maximum
: fX
<= m_aScales
[0].Maximum
)
340 && fY
>= m_aScales
[1].Minimum
&& fY
<= m_aScales
[1].Maximum
341 && fZ
>= m_aScales
[2].Minimum
&& ( isStrongLowerRequested(2) ? fZ
< m_aScales
[2].Maximum
: fZ
<= m_aScales
[2].Maximum
);
344 void PlottingPositionHelper::doLogicScaling( double* pX
, double* pY
, double* pZ
) const
348 if( m_aScales
[0].Scaling
.is())
349 *pX
= m_aScales
[0].Scaling
->doScaling(*pX
);
350 if( m_bAllowShiftXAxisPos
&& m_aScales
[0].m_bShiftedCategoryPosition
)
351 (*pX
) += m_fScaledCategoryWidth
/2.0;
353 if(pY
&& m_aScales
[1].Scaling
.is())
354 *pY
= m_aScales
[1].Scaling
->doScaling(*pY
);
357 if( m_aScales
[2].Scaling
.is())
358 *pZ
= m_aScales
[2].Scaling
->doScaling(*pZ
);
359 if( m_bAllowShiftZAxisPos
&& m_aScales
[2].m_bShiftedCategoryPosition
)
364 void PlottingPositionHelper::doUnshiftedLogicScaling( double* pX
, double* pY
, double* pZ
) const
366 if(pX
&& m_aScales
[0].Scaling
.is())
367 *pX
= m_aScales
[0].Scaling
->doScaling(*pX
);
368 if(pY
&& m_aScales
[1].Scaling
.is())
369 *pY
= m_aScales
[1].Scaling
->doScaling(*pY
);
370 if(pZ
&& m_aScales
[2].Scaling
.is())
371 *pZ
= m_aScales
[2].Scaling
->doScaling(*pZ
);
374 void PlottingPositionHelper::doLogicScaling( css::drawing::Position3D
& rPos
) const
376 doLogicScaling( &rPos
.PositionX
, &rPos
.PositionY
, &rPos
.PositionZ
);
379 void PlottingPositionHelper::clipLogicValues( double* pX
, double* pY
, double* pZ
) const
383 if( *pX
< m_aScales
[0].Minimum
)
384 *pX
= m_aScales
[0].Minimum
;
385 else if( *pX
> m_aScales
[0].Maximum
)
386 *pX
= m_aScales
[0].Maximum
;
390 if( *pY
< m_aScales
[1].Minimum
)
391 *pY
= m_aScales
[1].Minimum
;
392 else if( *pY
> m_aScales
[1].Maximum
)
393 *pY
= m_aScales
[1].Maximum
;
397 if( *pZ
< m_aScales
[2].Minimum
)
398 *pZ
= m_aScales
[2].Minimum
;
399 else if( *pZ
> m_aScales
[2].Maximum
)
400 *pZ
= m_aScales
[2].Maximum
;
404 inline bool PlottingPositionHelper::clipYRange( double& rMin
, double& rMax
) const
406 //returns true if something remains
408 std::swap( rMin
, rMax
);
409 if( rMin
> getLogicMaxY() )
411 if( rMax
< getLogicMinY() )
413 if( rMin
< getLogicMinY() )
414 rMin
= getLogicMinY();
415 if( rMax
> getLogicMaxY() )
416 rMax
= getLogicMaxY();
420 inline double PlottingPositionHelper::getLogicMinX() const
422 return m_aScales
[0].Minimum
;
424 inline double PlottingPositionHelper::getLogicMinY() const
426 return m_aScales
[1].Minimum
;
428 inline double PlottingPositionHelper::getLogicMinZ() const
430 return m_aScales
[2].Minimum
;
433 inline double PlottingPositionHelper::getLogicMaxX() const
435 return m_aScales
[0].Maximum
;
437 inline double PlottingPositionHelper::getLogicMaxY() const
439 return m_aScales
[1].Maximum
;
441 inline double PlottingPositionHelper::getLogicMaxZ() const
443 return m_aScales
[2].Maximum
;
445 inline bool PlottingPositionHelper::isMathematicalOrientationX() const
447 return css::chart2::AxisOrientation_MATHEMATICAL
== m_aScales
[0].Orientation
;
449 inline bool PlottingPositionHelper::isMathematicalOrientationY() const
451 return css::chart2::AxisOrientation_MATHEMATICAL
== m_aScales
[1].Orientation
;
453 inline bool PlottingPositionHelper::isMathematicalOrientationZ() const
455 return css::chart2::AxisOrientation_MATHEMATICAL
== m_aScales
[2].Orientation
;
457 inline bool PlottingPositionHelper::isSwapXAndY() const
461 inline bool PlottingPositionHelper::maySkipPointsInRegressionCalculation() const
463 return m_bMaySkipPointsInRegressionCalculation
;
468 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */