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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_chart2.hxx"
26 
27 #include "PolarLabelPositionHelper.hxx"
28 #include "PlottingPositionHelper.hxx"
29 #include "CommonConverters.hxx"
30 #include <basegfx/vector/b2dvector.hxx>
31 #include <basegfx/vector/b2ivector.hxx>
32 
33 #include <com/sun/star/chart/DataLabelPlacement.hpp>
34 
35 //.............................................................................
36 namespace chart
37 {
38 //.............................................................................
39 using namespace ::com::sun::star;
40 using namespace ::com::sun::star::chart2;
41 
PolarLabelPositionHelper(PolarPlottingPositionHelper * pPosHelper,sal_Int32 nDimensionCount,const uno::Reference<drawing::XShapes> & xLogicTarget,ShapeFactory * pShapeFactory)42 PolarLabelPositionHelper::PolarLabelPositionHelper(
43                     PolarPlottingPositionHelper* pPosHelper
44                     , sal_Int32 nDimensionCount
45                     , const uno::Reference< drawing::XShapes >& xLogicTarget
46                     , ShapeFactory* pShapeFactory )
47                     : LabelPositionHelper( pPosHelper, nDimensionCount, xLogicTarget, pShapeFactory )
48                     , m_pPosHelper(pPosHelper)
49 {
50 }
51 
~PolarLabelPositionHelper()52 PolarLabelPositionHelper::~PolarLabelPositionHelper()
53 {
54 }
55 
getLabelScreenPositionAndAlignmentForLogicValues(LabelAlignment & rAlignment,double fLogicValueOnAngleAxis,double fLogicValueOnRadiusAxis,double fLogicZ,sal_Int32 nScreenValueOffsetInRadiusDirection) const56 awt::Point PolarLabelPositionHelper::getLabelScreenPositionAndAlignmentForLogicValues(
57         LabelAlignment& rAlignment
58         , double fLogicValueOnAngleAxis
59         , double fLogicValueOnRadiusAxis
60         , double fLogicZ
61         , sal_Int32 nScreenValueOffsetInRadiusDirection ) const
62 {
63     double fUnitCircleAngleDegree = m_pPosHelper->transformToAngleDegree( fLogicValueOnAngleAxis );
64     double fUnitCircleRadius = m_pPosHelper->transformToRadius( fLogicValueOnRadiusAxis );
65 
66     return getLabelScreenPositionAndAlignmentForUnitCircleValues(
67            rAlignment, ::com::sun::star::chart::DataLabelPlacement::OUTSIDE
68            , fUnitCircleAngleDegree, 0.0
69            , fUnitCircleRadius, fUnitCircleRadius, fLogicZ, nScreenValueOffsetInRadiusDirection );
70 }
71 
getLabelScreenPositionAndAlignmentForUnitCircleValues(LabelAlignment & rAlignment,sal_Int32 nLabelPlacement,double fUnitCircleStartAngleDegree,double fUnitCircleWidthAngleDegree,double fUnitCircleInnerRadius,double fUnitCircleOuterRadius,double fLogicZ,sal_Int32 nScreenValueOffsetInRadiusDirection) const72 awt::Point PolarLabelPositionHelper::getLabelScreenPositionAndAlignmentForUnitCircleValues(
73         LabelAlignment& rAlignment, sal_Int32 nLabelPlacement
74         , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree
75         , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius
76         , double fLogicZ
77         , sal_Int32 nScreenValueOffsetInRadiusDirection ) const
78 {
79     bool bCenter = (nLabelPlacement != ::com::sun::star::chart::DataLabelPlacement::OUTSIDE)
80                 && (nLabelPlacement != ::com::sun::star::chart::DataLabelPlacement::INSIDE);
81 
82     double fAngleDegree = fUnitCircleStartAngleDegree + fUnitCircleWidthAngleDegree/2.0;
83     double fRadius = 0.0;
84     if( !bCenter ) //e.g. for pure pie chart(one ring only) or for angle axis of polyar coordinate system
85         fRadius = fUnitCircleOuterRadius;
86     else
87         fRadius = fUnitCircleInnerRadius + (fUnitCircleOuterRadius-fUnitCircleInnerRadius)/2.0 ;
88 
89     awt::Point aRet( this->transformSceneToScreenPosition(
90         m_pPosHelper->transformUnitCircleToScene( fAngleDegree, fRadius, fLogicZ+0.5 ) ) );
91 
92     if(3==m_nDimensionCount && nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::OUTSIDE)
93     {
94         //check whether the upper or the downer edge is more distant from the center
95         //take the farest point to put the label to
96 
97         awt::Point aP0( this->transformSceneToScreenPosition(
98             m_pPosHelper->transformUnitCircleToScene( 0, 0, fLogicZ ) ) );
99         awt::Point aP1(aRet);
100         awt::Point aP2( this->transformSceneToScreenPosition(
101             m_pPosHelper->transformUnitCircleToScene( fAngleDegree, fRadius, fLogicZ-0.5 ) ) );
102 
103         ::basegfx::B2DVector aV0( aP0.X, aP0.Y );
104         ::basegfx::B2DVector aV1( aP1.X, aP1.Y );
105         ::basegfx::B2DVector aV2( aP2.X, aP2.Y );
106 
107         double fL1 = ::basegfx::B2DVector(aV1-aV0).getLength();
108         double fL2 = ::basegfx::B2DVector(aV2-aV0).getLength();
109 
110         if(fL2>fL1)
111             aRet = aP2;
112 
113         //calculate new angle for alignment
114         double fDX = aRet.X-aP0.X;
115         double fDY = aRet.Y-aP0.Y;
116         fDY*=-1.0;//drawing layer has inverse y values
117         if( fDX != 0.0 )
118         {
119             fAngleDegree = atan(fDY/fDX)*180.0/F_PI;
120             if(fDX<0.0)
121                 fAngleDegree+=180.0;
122         }
123         else
124         {
125             if(fDY>0.0)
126                 fAngleDegree = 90.0;
127             else
128                 fAngleDegree = 270.0;
129         }
130     }
131     //------------------------------
132     //set LabelAlignment
133     if( !bCenter )
134     {
135         while(fAngleDegree>360.0)
136             fAngleDegree-=360.0;
137         while(fAngleDegree<0.0)
138             fAngleDegree+=360.0;
139 
140         bool bOutside = nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::OUTSIDE;
141 
142         if(fAngleDegree==0.0)
143             rAlignment = LABEL_ALIGN_CENTER;
144         else if(fAngleDegree<=22.5)
145             rAlignment = bOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT;
146         else if(fAngleDegree<67.5)
147             rAlignment = bOutside ? LABEL_ALIGN_RIGHT_TOP : LABEL_ALIGN_LEFT_BOTTOM;
148         else if(fAngleDegree<112.5)
149             rAlignment = bOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM;
150         else if(fAngleDegree<=157.5)
151             rAlignment = bOutside ? LABEL_ALIGN_LEFT_TOP : LABEL_ALIGN_RIGHT_BOTTOM;
152         else if(fAngleDegree<=202.5)
153             rAlignment = bOutside ? LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT;
154         else if(fAngleDegree<247.5)
155             rAlignment = bOutside ? LABEL_ALIGN_LEFT_BOTTOM : LABEL_ALIGN_RIGHT_TOP;
156         else if(fAngleDegree<292.5)
157             rAlignment = bOutside ? LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP;
158         else if(fAngleDegree<337.5)
159             rAlignment = bOutside ? LABEL_ALIGN_RIGHT_BOTTOM : LABEL_ALIGN_LEFT_TOP;
160         else
161             rAlignment = bOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT;
162     }
163     else
164     {
165         rAlignment = LABEL_ALIGN_CENTER;
166     }
167 
168     //add a scaling independent Offset if requested
169     if( nScreenValueOffsetInRadiusDirection != 0)
170     {
171         awt::Point aOrigin( this->transformSceneToScreenPosition(
172             m_pPosHelper->transformUnitCircleToScene( 0.0, 0.0, fLogicZ+0.5 ) ) );
173         basegfx::B2IVector aDirection( aRet.X- aOrigin.X, aRet.Y- aOrigin.Y );
174         aDirection.setLength(nScreenValueOffsetInRadiusDirection);
175         aRet.X += aDirection.getX();
176         aRet.Y += aDirection.getY();
177     }
178 
179     return aRet;
180 }
181 
182 //.............................................................................
183 } //namespace chart
184 //.............................................................................
185