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