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 #include <basegfx/numeric/ftools.hxx>
27 
28 #include "VPolarAngleAxis.hxx"
29 #include "VPolarGrid.hxx"
30 #include "ShapeFactory.hxx"
31 #include "macros.hxx"
32 #include "NumberFormatterWrapper.hxx"
33 #include "PolarLabelPositionHelper.hxx"
34 #include <tools/color.hxx>
35 
36 #include <memory>
37 
38 //.............................................................................
39 namespace chart
40 {
41 //.............................................................................
42 using namespace ::com::sun::star;
43 using namespace ::com::sun::star::chart2;
44 using namespace ::rtl::math;
45 
46 VPolarAngleAxis::VPolarAngleAxis( const AxisProperties& rAxisProperties
47             , const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier
48             , sal_Int32 nDimensionCount )
49             : VPolarAxis( rAxisProperties, xNumberFormatsSupplier, 0/*nDimensionIndex*/, nDimensionCount )
50 {
51 }
52 
53 VPolarAngleAxis::~VPolarAngleAxis()
54 {
55     delete m_pPosHelper;
56     m_pPosHelper = NULL;
57 }
58 
59 bool VPolarAngleAxis::createTextShapes_ForAngleAxis(
60                        const uno::Reference< drawing::XShapes >& xTarget
61                      , EquidistantTickIter& rTickIter
62                      , AxisLabelProperties& rAxisLabelProperties
63                      , double fLogicRadius
64                      , double fLogicZ )
65 {
66     sal_Int32 nDimensionCount = 2;
67     ShapeFactory aShapeFactory(m_xShapeFactory);
68 
69     FixedNumberFormatter aFixedNumberFormatter(
70         m_xNumberFormatsSupplier, rAxisLabelProperties.nNumberFormatKey );
71 
72     //------------------------------------------------
73     //prepare text properties for multipropertyset-interface of shape
74     tNameSequence aPropNames;
75     tAnySequence aPropValues;
76 
77     uno::Reference< beans::XPropertySet > xProps( m_aAxisProperties.m_xAxisModel, uno::UNO_QUERY );
78     PropertyMapper::getTextLabelMultiPropertyLists( xProps, aPropNames, aPropValues, false );
79     LabelPositionHelper::doDynamicFontResize( aPropValues, aPropNames, xProps
80         , rAxisLabelProperties.m_aFontReferenceSize );
81 
82     uno::Any* pColorAny = PropertyMapper::getValuePointer(aPropValues,aPropNames,C2U("CharColor"));
83     sal_Int32 nColor = Color( COL_AUTO ).GetColor();
84     if(pColorAny)
85         *pColorAny >>= nColor;
86 
87     const uno::Sequence< rtl::OUString >* pLabels = m_bUseTextLabels? &m_aTextLabels : 0;
88 
89     //------------------------------------------------
90 
91     //TickInfo* pLastVisibleNeighbourTickInfo = NULL;
92     sal_Int32 nTick = 0;
93 
94     for( TickInfo* pTickInfo = rTickIter.firstInfo()
95         ; pTickInfo
96         ; pTickInfo = rTickIter.nextInfo(), nTick++ )
97     {
98         //don't create labels which does not fit into the rhythm
99         if( nTick%rAxisLabelProperties.nRhythm != 0)
100             continue;
101 
102         //don't create labels for invisible ticks
103         if( !pTickInfo->bPaintIt )
104             continue;
105 
106         //if NO OVERLAP -> don't create labels where the
107         //anchor position is the same as for the last label
108         //@todo
109 
110         if(!pTickInfo->xTextShape.is())
111         {
112             //create single label
113             bool bHasExtraColor=false;
114             sal_Int32 nExtraColor=0;
115 
116             rtl::OUString aLabel;
117             if(pLabels)
118             {
119                 sal_Int32 nIndex = static_cast< sal_Int32 >(pTickInfo->getUnscaledTickValue()) - 1; //first category (index 0) matches with real number 1.0
120                 if( nIndex>=0 && nIndex<pLabels->getLength() )
121                     aLabel = (*pLabels)[nIndex];
122             }
123             else
124                 aLabel = aFixedNumberFormatter.getFormattedString( pTickInfo->getUnscaledTickValue(), nExtraColor, bHasExtraColor );
125 
126             if(pColorAny)
127                 *pColorAny = uno::makeAny(bHasExtraColor?nExtraColor:nColor);
128 
129             double fLogicAngle = pTickInfo->getUnscaledTickValue();
130 
131             LabelAlignment eLabelAlignment(LABEL_ALIGN_CENTER);
132             PolarLabelPositionHelper aPolarLabelPositionHelper(m_pPosHelper,nDimensionCount,xTarget,&aShapeFactory);
133             sal_Int32 nScreenValueOffsetInRadiusDirection = m_aAxisLabelProperties.m_aMaximumSpaceForLabels.Height/15;
134             awt::Point aAnchorScreenPosition2D( aPolarLabelPositionHelper.getLabelScreenPositionAndAlignmentForLogicValues(
135                     eLabelAlignment, fLogicAngle, fLogicRadius, fLogicZ, nScreenValueOffsetInRadiusDirection ));
136             LabelPositionHelper::changeTextAdjustment( aPropValues, aPropNames, eLabelAlignment );
137 
138             // #i78696# use mathematically correct rotation now
139             const double fRotationAnglePi(rAxisLabelProperties.fRotationAngleDegree * (F_PI / -180.0));
140 
141             uno::Any aATransformation = ShapeFactory::makeTransformation( aAnchorScreenPosition2D, fRotationAnglePi );
142             rtl::OUString aStackedLabel = ShapeFactory::getStackedString( aLabel, rAxisLabelProperties.bStackCharacters );
143 
144             pTickInfo->xTextShape = aShapeFactory.createText( xTarget, aStackedLabel, aPropNames, aPropValues, aATransformation );
145         }
146 
147         //if NO OVERLAP -> remove overlapping shapes
148         //@todo
149     }
150     return true;
151 }
152 
153 void VPolarAngleAxis::createMaximumLabels()
154 {
155     if( !prepareShapeCreation() )
156         return;
157 
158     createLabels();
159 }
160 
161 void VPolarAngleAxis::updatePositions()
162 {
163     //todo: really only update the positions
164 
165     if( !prepareShapeCreation() )
166         return;
167 
168     createLabels();
169 }
170 
171 void VPolarAngleAxis::createLabels()
172 {
173     if( !prepareShapeCreation() )
174         return;
175 
176     double fLogicRadius = m_pPosHelper->getOuterLogicRadius();
177     double fLogicZ      = 1.0;//as defined
178 
179     if( m_aAxisProperties.m_bDisplayLabels )
180     {
181         //-----------------------------------------
182         //get the transformed screen values for all tickmarks in aAllTickInfos
183         std::auto_ptr< TickFactory > apTickFactory( this->createTickFactory() );
184 
185         //create tick mark text shapes
186         //@todo: iterate through all tick depth wich should be labeled
187 
188         EquidistantTickIter aTickIter( m_aAllTickInfos, m_aIncrement, 0, 0 );
189         this->updateUnscaledValuesAtTicks( aTickIter );
190 
191         removeTextShapesFromTicks();
192 
193         AxisLabelProperties aAxisLabelProperties( m_aAxisLabelProperties );
194         aAxisLabelProperties.bOverlapAllowed = true;
195         while( !createTextShapes_ForAngleAxis( m_xTextTarget, aTickIter
196                         , aAxisLabelProperties
197                         , fLogicRadius, fLogicZ
198                         ) )
199         {
200         };
201 
202         //no staggering for polar angle axis
203     }
204 }
205 
206 void VPolarAngleAxis::createShapes()
207 {
208     if( !prepareShapeCreation() )
209         return;
210 
211     double fLogicRadius = m_pPosHelper->getOuterLogicRadius();
212     double fLogicZ      = 1.0;//as defined
213 
214     //-----------------------------------------
215     //create axis main lines
216     drawing::PointSequenceSequence aPoints(1);
217     VPolarGrid::createLinePointSequence_ForAngleAxis( aPoints, m_aAllTickInfos, m_aIncrement, m_aScale, m_pPosHelper, fLogicRadius, fLogicZ );
218     uno::Reference< drawing::XShape > xShape = m_pShapeFactory->createLine2D(
219             m_xGroupShape_Shapes, aPoints, &m_aAxisProperties.m_aLineProperties );
220     //because of this name this line will be used for marking the axis
221     m_pShapeFactory->setShapeName( xShape, C2U("MarkHandles") );
222 
223     //-----------------------------------------
224     //create labels
225     createLabels();
226 }
227 
228 //.............................................................................
229 } //namespace chart
230 //.............................................................................
231