1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 #ifndef _CHART2_PLOTTINGPOSITIONHELPER_HXX
28 #define _CHART2_PLOTTINGPOSITIONHELPER_HXX
29 
30 #include "LabelAlignment.hxx"
31 #include "chartview/ExplicitScaleValues.hxx"
32 
33 #include <basegfx/range/b2drectangle.hxx>
34 #include <rtl/math.hxx>
35 #include <com/sun/star/chart2/XTransformation.hpp>
36 #include <com/sun/star/drawing/Direction3D.hpp>
37 #include <com/sun/star/drawing/HomogenMatrix.hpp>
38 #include <com/sun/star/drawing/PolyPolygonShape3D.hpp>
39 #include <com/sun/star/drawing/Position3D.hpp>
40 #include <com/sun/star/drawing/XShapes.hpp>
41 #include <basegfx/matrix/b3dhommatrix.hxx>
42 
43 /*
44 //for WeakImplHelper1
45 #include <cppuhelper/implbase1.hxx>
46 */
47 //.............................................................................
48 namespace chart
49 {
50 //.............................................................................
51 
52 class ShapeFactory;
53 
54 //-----------------------------------------------------------------------------
55 /**
56 */
57 
58 class PlottingPositionHelper
59 {
60 public:
61     PlottingPositionHelper();
62     PlottingPositionHelper( const PlottingPositionHelper& rSource );
63     virtual ~PlottingPositionHelper();
64 
65     virtual PlottingPositionHelper* clone() const;
66     virtual PlottingPositionHelper* createSecondaryPosHelper( const ExplicitScaleData& rSecondaryScale );
67 
68     virtual void setTransformationSceneToScreen( const ::com::sun::star::drawing::HomogenMatrix& rMatrix);
69 
70     virtual void setScales( const ::std::vector< ExplicitScaleData >& rScales, bool bSwapXAndYAxis );
71     const ::std::vector< ExplicitScaleData >& getScales() const;
72 
73     //better performance for big data
74     inline void   setCoordinateSystemResolution( const ::com::sun::star::uno::Sequence< sal_Int32 >& rCoordinateSystemResolution );
75     inline bool   isSameForGivenResolution( double fX, double fY, double fZ
76                                 , double fX2, double fY2, double fZ2 );
77 
78     inline bool   isStrongLowerRequested( sal_Int32 nDimensionIndex ) const;
79     inline bool   isLogicVisible( double fX, double fY, double fZ ) const;
80     inline void   doLogicScaling( double* pX, double* pY, double* pZ, bool bClip=false ) const;
81     inline void   doUnshiftedLogicScaling( double* pX, double* pY, double* pZ, bool bClip=false ) const;
82     inline void   clipLogicValues( double* pX, double* pY, double* pZ ) const;
83            void   clipScaledLogicValues( double* pX, double* pY, double* pZ ) const;
84     inline bool   clipYRange( double& rMin, double& rMax ) const;
85 
86     inline void   doLogicScaling( ::com::sun::star::drawing::Position3D& rPos, bool bClip=false ) const;
87 
88     virtual ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTransformation >
89                   getTransformationScaledLogicToScene() const;
90 
91     virtual ::com::sun::star::drawing::Position3D
92             transformLogicToScene( double fX, double fY, double fZ, bool bClip ) const;
93 
94     virtual ::com::sun::star::drawing::Position3D
95             transformScaledLogicToScene( double fX, double fY, double fZ, bool bClip ) const;
96 
97     void    transformScaledLogicToScene( ::com::sun::star::drawing::PolyPolygonShape3D& rPoly ) const;
98 
99     static com::sun::star::awt::Point transformSceneToScreenPosition(
100                   const com::sun::star::drawing::Position3D& rScenePosition3D
101                 , const com::sun::star::uno::Reference< com::sun::star::drawing::XShapes >& xSceneTarget
102                 , ShapeFactory* pShapeFactory, sal_Int32 nDimensionCount );
103 
104     inline double getLogicMinX() const;
105     inline double getLogicMinY() const;
106     inline double getLogicMinZ() const;
107     inline double getLogicMaxX() const;
108     inline double getLogicMaxY() const;
109     inline double getLogicMaxZ() const;
110 
111     inline bool isMathematicalOrientationX() const;
112     inline bool isMathematicalOrientationY() const;
113     inline bool isMathematicalOrientationZ() const;
114 
115     ::basegfx::B2DRectangle     getScaledLogicClipDoubleRect() const;
116     ::com::sun::star::drawing::Direction3D getScaledLogicWidth() const;
117 
118     inline bool isSwapXAndY() const;
119 
120     bool isPercentY() const;
121 
122     double getBaseValueY() const;
123 
124     inline bool maySkipPointsInRegressionCalculation() const;
125 
126     void setTimeResolution( long nTimeResolution, const Date& rNullDate );
127     virtual void setScaledCategoryWidth( double fScaledCategoryWidth );
128     void AllowShiftXAxisPos( bool bAllowShift );
129     void AllowShiftZAxisPos( bool bAllowShift );
130 
131 protected: //member
132     ::std::vector< ExplicitScaleData >  m_aScales;
133     ::basegfx::B3DHomMatrix             m_aMatrixScreenToScene;
134 
135     //this is calculated based on m_aScales and m_aMatrixScreenToScene
136     mutable ::com::sun::star::uno::Reference<
137         ::com::sun::star::chart2::XTransformation >     m_xTransformationLogicToScene;
138 
139     bool    m_bSwapXAndY;//e.g. true for bar chart and false for column chart
140 
141     sal_Int32 m_nXResolution;
142     sal_Int32 m_nYResolution;
143     sal_Int32 m_nZResolution;
144 
145     bool m_bMaySkipPointsInRegressionCalculation;
146 
147     bool m_bDateAxis;
148     long m_nTimeResolution;
149     Date m_aNullDate;
150 
151     double m_fScaledCategoryWidth;
152     bool   m_bAllowShiftXAxisPos;
153     bool   m_bAllowShiftZAxisPos;
154 };
155 
156 //describes wich axis of the drawinglayer scene or sreen axis are the normal axis
157 enum NormalAxis
158 {
159       NormalAxis_X
160     , NormalAxis_Y
161     , NormalAxis_Z
162 };
163 
164 class PolarPlottingPositionHelper : public PlottingPositionHelper
165     /*
166                                   , public ::cppu::WeakImplHelper1<
167                                 ::com::sun::star::chart2::XTransformation >
168                                 */
169 {
170 public:
171     PolarPlottingPositionHelper( NormalAxis eNormalAxis=NormalAxis_Z );
172     PolarPlottingPositionHelper( const PolarPlottingPositionHelper& rSource );
173     virtual ~PolarPlottingPositionHelper();
174 
175     virtual PlottingPositionHelper* clone() const;
176 
177     virtual void setTransformationSceneToScreen( const ::com::sun::star::drawing::HomogenMatrix& rMatrix);
178     virtual void setScales( const std::vector< ExplicitScaleData >& rScales, bool bSwapXAndYAxis );
179 
180     ::basegfx::B3DHomMatrix getUnitCartesianToScene() const;
181 
182     virtual ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XTransformation >
183                   getTransformationScaledLogicToScene() const;
184 
185     //the resulting values should be used for input to the transformation
186     //received with 'getTransformationScaledLogicToScene'
187     double  transformToRadius( double fLogicValueOnRadiusAxis, bool bDoScaling=true ) const;
188     double  transformToAngleDegree( double fLogicValueOnAngleAxis, bool bDoScaling=true ) const;
189     double  getWidthAngleDegree( double& fStartLogicValueOnAngleAxis, double& fEndLogicValueOnAngleAxis ) const;
190     //
191 
192     virtual ::com::sun::star::drawing::Position3D
193             transformLogicToScene( double fX, double fY, double fZ, bool bClip ) const;
194     virtual ::com::sun::star::drawing::Position3D
195             transformScaledLogicToScene( double fX, double fY, double fZ, bool bClip ) const;
196     ::com::sun::star::drawing::Position3D
197             transformAngleRadiusToScene( double fLogicValueOnAngleAxis, double fLogicValueOnRadiusAxis, double fLogicZ, bool bDoScaling=true ) const;
198     ::com::sun::star::drawing::Position3D
199             transformUnitCircleToScene( double fUnitAngleDegree, double fUnitRadius, double fLogicZ, bool bDoScaling=true ) const;
200 
201     using PlottingPositionHelper::transformScaledLogicToScene;
202 
203 #ifdef NOTYET
204     double  getInnerLogicRadius() const;
205 #endif
206     double  getOuterLogicRadius() const;
207 
208     inline bool isMathematicalOrientationAngle() const;
209     inline bool isMathematicalOrientationRadius() const;
210 
211     /*
212     // ____ XTransformation ____
213     /// @see ::com::sun::star::chart2::XTransformation
214     virtual ::com::sun::star::uno::Sequence< double > SAL_CALL transform(
215         const ::com::sun::star::uno::Sequence< double >& rSourceValues )
216         throw (::com::sun::star::lang::IllegalArgumentException,
217                ::com::sun::star::uno::RuntimeException);
218     /// @see ::com::sun::star::chart2::XTransformation
219     virtual sal_Int32 SAL_CALL getSourceDimension()
220         throw (::com::sun::star::uno::RuntimeException);
221     /// @see ::com::sun::star::chart2::XTransformation
222     virtual sal_Int32 SAL_CALL getTargetDimension()
223         throw (::com::sun::star::uno::RuntimeException);
224         */
225 public:
226     //Offset for radius axis in absolute logic scaled values (1.0 == 1 category)
227     double      m_fRadiusOffset;
228     //Offset for angle axis in real degree
229     double      m_fAngleDegreeOffset;
230 
231 private:
232     ::basegfx::B3DHomMatrix m_aUnitCartesianToScene;
233     NormalAxis  m_eNormalAxis;
234 
235     ::basegfx::B3DHomMatrix impl_calculateMatrixUnitCartesianToScene( const ::basegfx::B3DHomMatrix& rMatrixScreenToScene ) const;
236 };
237 
238 bool PolarPlottingPositionHelper::isMathematicalOrientationAngle() const
239 {
240     const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[1] : m_aScales[2];
241     if( ::com::sun::star::chart2::AxisOrientation_MATHEMATICAL==rScale.Orientation )
242         return true;
243     return false;
244 }
245 bool PolarPlottingPositionHelper::isMathematicalOrientationRadius() const
246 {
247     const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[0] : m_aScales[1];
248     if( ::com::sun::star::chart2::AxisOrientation_MATHEMATICAL==rScale.Orientation )
249         return true;
250     return false;
251 }
252 
253 //better performance for big data
254 void PlottingPositionHelper::setCoordinateSystemResolution( const ::com::sun::star::uno::Sequence< sal_Int32 >& rCoordinateSystemResolution )
255 {
256     m_nXResolution = 1000;
257     m_nYResolution = 1000;
258     m_nZResolution = 1000;
259     if( rCoordinateSystemResolution.getLength() > 0 )
260         m_nXResolution = rCoordinateSystemResolution[0];
261     if( rCoordinateSystemResolution.getLength() > 1 )
262         m_nYResolution = rCoordinateSystemResolution[1];
263     if( rCoordinateSystemResolution.getLength() > 2 )
264         m_nZResolution = rCoordinateSystemResolution[2];
265 }
266 
267 bool PlottingPositionHelper::isSameForGivenResolution( double fX, double fY, double fZ
268                                 , double fX2, double fY2, double fZ2 /*these values are all expected tp be scaled already*/ )
269 {
270     if( !::rtl::math::isFinite(fX) || !::rtl::math::isFinite(fY) || !::rtl::math::isFinite(fZ)
271         || !::rtl::math::isFinite(fX2) || !::rtl::math::isFinite(fY2) || !::rtl::math::isFinite(fZ2) )
272         return false;
273 
274     double fScaledMinX = getLogicMinX();
275     double fScaledMinY = getLogicMinY();
276     double fScaledMinZ = getLogicMinZ();
277     double fScaledMaxX = getLogicMaxX();
278     double fScaledMaxY = getLogicMaxY();
279     double fScaledMaxZ = getLogicMaxZ();
280 
281     doLogicScaling( &fScaledMinX, &fScaledMinY, &fScaledMinZ );
282     doLogicScaling( &fScaledMaxX, &fScaledMaxY, &fScaledMaxZ);
283 
284     bool bSameX = ( static_cast<sal_Int32>(m_nXResolution*(fX - fScaledMinX)/(fScaledMaxX-fScaledMinX))
285                 == static_cast<sal_Int32>(m_nXResolution*(fX2 - fScaledMinX)/(fScaledMaxX-fScaledMinX)) );
286 
287     bool bSameY = ( static_cast<sal_Int32>(m_nYResolution*(fY - fScaledMinY)/(fScaledMaxY-fScaledMinY))
288                 == static_cast<sal_Int32>(m_nYResolution*(fY2 - fScaledMinY)/(fScaledMaxY-fScaledMinY)) );
289 
290     bool bSameZ = ( static_cast<sal_Int32>(m_nZResolution*(fZ - fScaledMinZ)/(fScaledMaxZ-fScaledMinZ))
291                 == static_cast<sal_Int32>(m_nZResolution*(fZ2 - fScaledMinZ)/(fScaledMaxZ-fScaledMinZ)) );
292 
293     return (bSameX && bSameY && bSameZ);
294 }
295 
296 bool PlottingPositionHelper::isStrongLowerRequested( sal_Int32 nDimensionIndex ) const
297 {
298     if( m_aScales.empty() )
299         return false;
300     if( 0==nDimensionIndex )
301         return m_bAllowShiftXAxisPos && m_aScales[nDimensionIndex].ShiftedCategoryPosition;
302     else if( 2==nDimensionIndex )
303         return m_bAllowShiftZAxisPos && m_aScales[nDimensionIndex].ShiftedCategoryPosition;
304     return false;
305 }
306 
307 bool PlottingPositionHelper::isLogicVisible(
308     double fX, double fY, double fZ ) const
309 {
310     return fX >= m_aScales[0].Minimum && ( isStrongLowerRequested(0) ? fX < m_aScales[0].Maximum : fX <= m_aScales[0].Maximum )
311         && fY >= m_aScales[1].Minimum && fY <= m_aScales[1].Maximum
312         && fZ >= m_aScales[2].Minimum && ( isStrongLowerRequested(2) ? fZ < m_aScales[2].Maximum : fZ <= m_aScales[2].Maximum );
313 }
314 
315 void PlottingPositionHelper::doLogicScaling( double* pX, double* pY, double* pZ, bool bClip ) const
316 {
317     if(bClip)
318         this->clipLogicValues( pX,pY,pZ );
319 
320     if(pX)
321     {
322         if( m_aScales[0].Scaling.is())
323             *pX = m_aScales[0].Scaling->doScaling(*pX);
324         if( m_bAllowShiftXAxisPos && m_aScales[0].ShiftedCategoryPosition )
325             (*pX) += m_fScaledCategoryWidth/2.0;
326     }
327     if(pY && m_aScales[1].Scaling.is())
328         *pY = m_aScales[1].Scaling->doScaling(*pY);
329     if(pZ)
330     {
331         if( m_aScales[2].Scaling.is())
332             *pZ = m_aScales[2].Scaling->doScaling(*pZ);
333         if( m_bAllowShiftZAxisPos && m_aScales[2].ShiftedCategoryPosition)
334             (*pZ) += 0.5;
335     }
336 }
337 
338 void PlottingPositionHelper::doUnshiftedLogicScaling( double* pX, double* pY, double* pZ, bool bClip ) const
339 {
340     if(bClip)
341         this->clipLogicValues( pX,pY,pZ );
342 
343     if(pX && m_aScales[0].Scaling.is())
344         *pX = m_aScales[0].Scaling->doScaling(*pX);
345     if(pY && m_aScales[1].Scaling.is())
346         *pY = m_aScales[1].Scaling->doScaling(*pY);
347     if(pZ && m_aScales[2].Scaling.is())
348         *pZ = m_aScales[2].Scaling->doScaling(*pZ);
349 }
350 
351 void PlottingPositionHelper::doLogicScaling( ::com::sun::star::drawing::Position3D& rPos, bool bClip ) const
352 {
353     doLogicScaling( &rPos.PositionX, &rPos.PositionY, &rPos.PositionZ, bClip );
354 }
355 
356 void PlottingPositionHelper::clipLogicValues( double* pX, double* pY, double* pZ ) const
357 {
358     if(pX)
359     {
360         if( *pX < m_aScales[0].Minimum )
361             *pX = m_aScales[0].Minimum;
362         else if( *pX > m_aScales[0].Maximum )
363             *pX = m_aScales[0].Maximum;
364     }
365     if(pY)
366     {
367         if( *pY < m_aScales[1].Minimum )
368             *pY = m_aScales[1].Minimum;
369         else if( *pY > m_aScales[1].Maximum )
370             *pY = m_aScales[1].Maximum;
371     }
372     if(pZ)
373     {
374         if( *pZ < m_aScales[2].Minimum )
375             *pZ = m_aScales[2].Minimum;
376         else if( *pZ > m_aScales[2].Maximum )
377             *pZ = m_aScales[2].Maximum;
378     }
379 }
380 
381 inline bool PlottingPositionHelper::clipYRange( double& rMin, double& rMax ) const
382 {
383     //returns true if something remains
384     if( rMin > rMax )
385     {
386         double fHelp = rMin;
387         rMin = rMax;
388         rMax = fHelp;
389     }
390     if( rMin > getLogicMaxY() )
391         return false;
392     if( rMax < getLogicMinY() )
393         return false;
394     if( rMin < getLogicMinY() )
395         rMin = getLogicMinY();
396     if( rMax > getLogicMaxY() )
397         rMax = getLogicMaxY();
398     return true;
399 }
400 
401 inline double PlottingPositionHelper::getLogicMinX() const
402 {
403     return m_aScales[0].Minimum;
404 }
405 inline double PlottingPositionHelper::getLogicMinY() const
406 {
407     return m_aScales[1].Minimum;
408 }
409 inline double PlottingPositionHelper::getLogicMinZ() const
410 {
411     return m_aScales[2].Minimum;
412 }
413 
414 inline double PlottingPositionHelper::getLogicMaxX() const
415 {
416     return m_aScales[0].Maximum;
417 }
418 inline double PlottingPositionHelper::getLogicMaxY() const
419 {
420     return m_aScales[1].Maximum;
421 }
422 inline double PlottingPositionHelper::getLogicMaxZ() const
423 {
424     return m_aScales[2].Maximum;
425 }
426 inline bool PlottingPositionHelper::isMathematicalOrientationX() const
427 {
428     return ::com::sun::star::chart2::AxisOrientation_MATHEMATICAL == m_aScales[0].Orientation;
429 }
430 inline bool PlottingPositionHelper::isMathematicalOrientationY() const
431 {
432     return ::com::sun::star::chart2::AxisOrientation_MATHEMATICAL == m_aScales[1].Orientation;
433 }
434 inline bool PlottingPositionHelper::isMathematicalOrientationZ() const
435 {
436     return ::com::sun::star::chart2::AxisOrientation_MATHEMATICAL == m_aScales[2].Orientation;
437 }
438 inline bool PlottingPositionHelper::isSwapXAndY() const
439 {
440     return m_bSwapXAndY;
441 }
442 inline bool PlottingPositionHelper::maySkipPointsInRegressionCalculation() const
443 {
444     return m_bMaySkipPointsInRegressionCalculation;
445 }
446 
447 //.............................................................................
448 } //namespace chart
449 //.............................................................................
450 #endif
451