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 "Tickmarks.hxx"
27 #include "Tickmarks_Equidistant.hxx"
28 #include "Tickmarks_Dates.hxx"
29 #include "ViewDefines.hxx"
30 #include <rtl/math.hxx>
31 #include <tools/debug.hxx>
32 #include <memory>
33 
34 //.............................................................................
35 namespace chart
36 {
37 //.............................................................................
38 using namespace ::com::sun::star;
39 using namespace ::com::sun::star::chart2;
40 using namespace ::rtl::math;
41 using ::basegfx::B2DVector;
42 
TickInfo(const::com::sun::star::uno::Reference<::com::sun::star::chart2::XScaling> & xInverse)43 TickInfo::TickInfo( const ::com::sun::star::uno::Reference<
44                     ::com::sun::star::chart2::XScaling >& xInverse )
45 : fScaledTickValue( 0.0 )
46 , xInverseScaling( xInverse )
47 , aTickScreenPosition(0.0,0.0)
48 , bPaintIt( true )
49 , xTextShape( NULL )
50 , nFactorForLimitedTextWidth(1)
51 {
52 }
53 
getUnscaledTickValue() const54 double TickInfo::getUnscaledTickValue() const
55 {
56     if( xInverseScaling.is() )
57         return xInverseScaling->doScaling( fScaledTickValue );
58     else
59         return fScaledTickValue;
60 }
61 
getScreenDistanceBetweenTicks(const TickInfo & rOherTickInfo) const62 sal_Int32 TickInfo::getScreenDistanceBetweenTicks( const TickInfo& rOherTickInfo ) const
63 {
64     //return the positive distance between the two first tickmarks in screen values
65 
66     B2DVector aDistance = rOherTickInfo.aTickScreenPosition - aTickScreenPosition;
67     sal_Int32 nRet = static_cast<sal_Int32>(aDistance.getLength());
68     if(nRet<0)
69         nRet *= -1;
70     return nRet;
71 }
72 
PureTickIter(::std::vector<TickInfo> & rTickInfoVector)73 PureTickIter::PureTickIter( ::std::vector< TickInfo >& rTickInfoVector )
74             : m_rTickVector(rTickInfoVector)
75             , m_aTickIter(m_rTickVector.begin())
76 {
77 }
~PureTickIter()78 PureTickIter::~PureTickIter()
79 {
80 }
firstInfo()81 TickInfo* PureTickIter::firstInfo()
82 {
83     m_aTickIter = m_rTickVector.begin();
84     if(m_aTickIter!=m_rTickVector.end())
85         return &*m_aTickIter;
86     return 0;
87 }
nextInfo()88 TickInfo* PureTickIter::nextInfo()
89 {
90     if(m_aTickIter!=m_rTickVector.end())
91     {
92         m_aTickIter++;
93         if(m_aTickIter!=m_rTickVector.end())
94             return &*m_aTickIter;
95     }
96     return 0;
97 }
98 
99 //-----------------------------------------------------------------------------
100 //-----------------------------------------------------------------------------
101 //-----------------------------------------------------------------------------
102 
TickFactory(const ExplicitScaleData & rScale,const ExplicitIncrementData & rIncrement)103 TickFactory::TickFactory(
104           const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement )
105             : m_rScale( rScale )
106             , m_rIncrement( rIncrement )
107             , m_xInverseScaling(NULL)
108 {
109     //@todo: make sure that the scale is valid for the scaling
110 
111     if( m_rScale.Scaling.is() )
112     {
113         m_xInverseScaling = m_rScale.Scaling->getInverseScaling();
114         DBG_ASSERT( m_xInverseScaling.is(), "each Scaling needs to return a inverse Scaling" );
115     }
116 
117     m_fScaledVisibleMin = m_rScale.Minimum;
118     if( m_xInverseScaling.is() )
119         m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin);
120 
121     m_fScaledVisibleMax = m_rScale.Maximum;
122     if( m_xInverseScaling.is() )
123         m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax);
124 }
125 
~TickFactory()126 TickFactory::~TickFactory()
127 {
128 }
129 
isDateAxis() const130 bool TickFactory::isDateAxis() const
131 {
132     return m_rScale.AxisType == AxisType::DATE;
133 }
134 
getAllTicks(::std::vector<::std::vector<TickInfo>> & rAllTickInfos) const135 void TickFactory::getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
136 {
137     if( isDateAxis() )
138         DateTickFactory( m_rScale, m_rIncrement ).getAllTicks( rAllTickInfos );
139     else
140         EquidistantTickFactory( m_rScale, m_rIncrement ).getAllTicks( rAllTickInfos );
141 }
142 
getAllTicksShifted(::std::vector<::std::vector<TickInfo>> & rAllTickInfos) const143 void TickFactory::getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
144 {
145     if( isDateAxis() )
146         DateTickFactory( m_rScale, m_rIncrement ).getAllTicksShifted( rAllTickInfos );
147     else
148         EquidistantTickFactory( m_rScale, m_rIncrement ).getAllTicksShifted( rAllTickInfos );
149 }
150 
151 //-----------------------------------------------------------------------------
152 // ___TickFactory_2D___
153 //-----------------------------------------------------------------------------
TickFactory_2D(const ExplicitScaleData & rScale,const ExplicitIncrementData & rIncrement,const B2DVector & rStartScreenPos,const B2DVector & rEndScreenPos,const B2DVector & rAxisLineToLabelLineShift)154 TickFactory_2D::TickFactory_2D(
155           const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement
156           //, double fStrech_SceneToScreen, double fOffset_SceneToScreen )
157           , const B2DVector& rStartScreenPos, const B2DVector& rEndScreenPos
158           , const B2DVector& rAxisLineToLabelLineShift )
159           : TickFactory( rScale, rIncrement )
160           , m_aAxisStartScreenPosition2D(rStartScreenPos)
161           , m_aAxisEndScreenPosition2D(rEndScreenPos)
162           , m_aAxisLineToLabelLineShift(rAxisLineToLabelLineShift)
163           , m_fStrech_LogicToScreen(1.0)
164           , m_fOffset_LogicToScreen(0.0)
165 {
166     double fWidthY = m_fScaledVisibleMax - m_fScaledVisibleMin;
167     if( AxisOrientation_MATHEMATICAL==m_rScale.Orientation )
168     {
169         m_fStrech_LogicToScreen = 1.0/fWidthY;
170         m_fOffset_LogicToScreen = -m_fScaledVisibleMin;
171     }
172     else
173     {
174         B2DVector aSwap(m_aAxisStartScreenPosition2D);
175         m_aAxisStartScreenPosition2D = m_aAxisEndScreenPosition2D;
176         m_aAxisEndScreenPosition2D = aSwap;
177 
178         m_fStrech_LogicToScreen = -1.0/fWidthY;
179         m_fOffset_LogicToScreen = -m_fScaledVisibleMax;
180     }
181 }
182 
~TickFactory_2D()183 TickFactory_2D::~TickFactory_2D()
184 {
185 }
186 
isHorizontalAxis() const187 bool TickFactory_2D::isHorizontalAxis() const
188 {
189     return ( m_aAxisStartScreenPosition2D.getY() == m_aAxisEndScreenPosition2D.getY() );
190 }
isVerticalAxis() const191 bool TickFactory_2D::isVerticalAxis() const
192 {
193     return ( m_aAxisStartScreenPosition2D.getX() == m_aAxisEndScreenPosition2D.getX() );
194 }
195 
196 //static
getTickScreenDistance(TickIter & rIter)197 sal_Int32 TickFactory_2D::getTickScreenDistance( TickIter& rIter )
198 {
199     //return the positive distance between the two first tickmarks in screen values
200     //if there are less than two tickmarks -1 is returned
201 
202     const TickInfo* pFirstTickInfo = rIter.firstInfo();
203     const TickInfo* pSecondTickInfo = rIter.nextInfo();
204     if(!pSecondTickInfo  || !pFirstTickInfo)
205         return -1;
206 
207     return pFirstTickInfo->getScreenDistanceBetweenTicks( *pSecondTickInfo );
208 }
209 
getTickScreenPosition2D(double fScaledLogicTickValue) const210 B2DVector TickFactory_2D::getTickScreenPosition2D( double fScaledLogicTickValue ) const
211 {
212     B2DVector aRet(m_aAxisStartScreenPosition2D);
213     aRet += (m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D)
214                 *((fScaledLogicTickValue+m_fOffset_LogicToScreen)*m_fStrech_LogicToScreen);
215     return aRet;
216 }
217 
addPointSequenceForTickLine(drawing::PointSequenceSequence & rPoints,sal_Int32 nSequenceIndex,double fScaledLogicTickValue,double fInnerDirectionSign,const TickmarkProperties & rTickmarkProperties,bool bPlaceAtLabels) const218 void TickFactory_2D::addPointSequenceForTickLine( drawing::PointSequenceSequence& rPoints
219                                 , sal_Int32 nSequenceIndex
220                                 , double fScaledLogicTickValue, double fInnerDirectionSign
221                                 , const TickmarkProperties& rTickmarkProperties
222                                 , bool bPlaceAtLabels ) const
223 {
224     if( fInnerDirectionSign==0.0 )
225         fInnerDirectionSign = 1.0;
226 
227     B2DVector aTickScreenPosition = this->getTickScreenPosition2D(fScaledLogicTickValue);
228     if( bPlaceAtLabels )
229         aTickScreenPosition += m_aAxisLineToLabelLineShift;
230 
231     B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D;
232     aMainDirection.normalize();
233     B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
234     aOrthoDirection *= fInnerDirectionSign;
235     aOrthoDirection.normalize();
236 
237     B2DVector aStart = aTickScreenPosition + aOrthoDirection*rTickmarkProperties.RelativePos;
238     B2DVector aEnd = aStart - aOrthoDirection*rTickmarkProperties.Length;
239 
240     rPoints[nSequenceIndex].realloc(2);
241     rPoints[nSequenceIndex][0].X = static_cast<sal_Int32>(aStart.getX());
242     rPoints[nSequenceIndex][0].Y = static_cast<sal_Int32>(aStart.getY());
243     rPoints[nSequenceIndex][1].X = static_cast<sal_Int32>(aEnd.getX());
244     rPoints[nSequenceIndex][1].Y = static_cast<sal_Int32>(aEnd.getY());
245 }
246 
getDistanceAxisTickToText(const AxisProperties & rAxisProperties,bool bIncludeFarAwayDistanceIfSo,bool bIncludeSpaceBetweenTickAndText) const247 B2DVector TickFactory_2D::getDistanceAxisTickToText( const AxisProperties& rAxisProperties, bool bIncludeFarAwayDistanceIfSo, bool bIncludeSpaceBetweenTickAndText ) const
248 {
249     bool bFarAwayLabels = false;
250     if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_START == rAxisProperties.m_eLabelPos
251         || ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END == rAxisProperties.m_eLabelPos )
252         bFarAwayLabels = true;
253 
254     double fInnerDirectionSign = rAxisProperties.m_fInnerDirectionSign;
255     if( fInnerDirectionSign==0.0 )
256         fInnerDirectionSign = 1.0;
257 
258     B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D;
259     aMainDirection.normalize();
260     B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
261     aOrthoDirection *= fInnerDirectionSign;
262     aOrthoDirection.normalize();
263 
264     B2DVector aStart(0,0), aEnd(0,0);
265     if( bFarAwayLabels )
266     {
267         TickmarkProperties aProps( AxisProperties::getBiggestTickmarkProperties() );
268         aStart = aOrthoDirection*aProps.RelativePos;
269         aEnd = aStart - aOrthoDirection*aProps.Length;
270     }
271     else
272     {
273         for( sal_Int32 nN=rAxisProperties.m_aTickmarkPropertiesList.size();nN--;)
274         {
275             const TickmarkProperties& rProps = rAxisProperties.m_aTickmarkPropertiesList[nN];
276             B2DVector aNewStart = aOrthoDirection*rProps.RelativePos;
277             B2DVector aNewEnd = aNewStart - aOrthoDirection*rProps.Length;
278             if(aNewStart.getLength()>aStart.getLength())
279                 aStart=aNewStart;
280             if(aNewEnd.getLength()>aEnd.getLength())
281                 aEnd=aNewEnd;
282         }
283     }
284 
285     B2DVector aLabelDirection(aStart);
286     if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign )
287         aLabelDirection = aEnd;
288 
289     B2DVector aOrthoLabelDirection(aOrthoDirection);
290     if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign )
291         aOrthoLabelDirection*=-1.0;
292     aOrthoLabelDirection.normalize();
293     if( bIncludeSpaceBetweenTickAndText )
294         aLabelDirection += aOrthoLabelDirection*AXIS2D_TICKLABELSPACING;
295     if( bFarAwayLabels && bIncludeFarAwayDistanceIfSo )
296         aLabelDirection += m_aAxisLineToLabelLineShift;
297     return aLabelDirection;
298 }
299 
createPointSequenceForAxisMainLine(drawing::PointSequenceSequence & rPoints) const300 void TickFactory_2D::createPointSequenceForAxisMainLine( drawing::PointSequenceSequence& rPoints ) const
301 {
302     rPoints[0].realloc(2);
303     rPoints[0][0].X = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getX());
304     rPoints[0][0].Y = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getY());
305     rPoints[0][1].X = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getX());
306     rPoints[0][1].Y = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getY());
307 }
308 
updateScreenValues(::std::vector<::std::vector<TickInfo>> & rAllTickInfos) const309 void TickFactory_2D::updateScreenValues( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
310 {
311     //get the transformed screen values for all tickmarks in rAllTickInfos
312     ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter       = rAllTickInfos.begin();
313     const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd  = rAllTickInfos.end();
314     for( ; aDepthIter != aDepthEnd; aDepthIter++ )
315     {
316         ::std::vector< TickInfo >::iterator       aTickIter = (*aDepthIter).begin();
317         const ::std::vector< TickInfo >::const_iterator aTickEnd  = (*aDepthIter).end();
318         for( ; aTickIter != aTickEnd; aTickIter++ )
319         {
320             TickInfo& rTickInfo = (*aTickIter);
321             rTickInfo.aTickScreenPosition =
322                 this->getTickScreenPosition2D( rTickInfo.fScaledTickValue );
323         }
324     }
325 }
326 
327 //.............................................................................
328 } //namespace chart
329 //.............................................................................
330