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