1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "Tickmarks.hxx"
21 #include "Tickmarks_Equidistant.hxx"
22 #include "Tickmarks_Dates.hxx"
23 #include <ViewDefines.hxx>
24 #include "VAxisProperties.hxx"
25 #include <osl/diagnose.h>
26 #include <com/sun/star/chart2/AxisType.hpp>
28 using namespace ::com::sun::star
;
29 using ::basegfx::B2DVector
;
33 TickInfo::TickInfo( const uno::Reference
<chart2::XScaling
>& xInverse
)
34 : fScaledTickValue( 0.0 )
35 , xInverseScaling( xInverse
)
36 , aTickScreenPosition(0.0,0.0)
38 , nFactorForLimitedTextWidth(1)
42 double TickInfo::getUnscaledTickValue() const
44 if( xInverseScaling
.is() )
45 return xInverseScaling
->doScaling( fScaledTickValue
);
47 return fScaledTickValue
;
50 sal_Int32
TickInfo::getScreenDistanceBetweenTicks( const TickInfo
& rOherTickInfo
) const
52 //return the positive distance between the two first tickmarks in screen values
54 B2DVector aDistance
= rOherTickInfo
.aTickScreenPosition
- aTickScreenPosition
;
55 sal_Int32 nRet
= static_cast<sal_Int32
>(aDistance
.getLength());
61 PureTickIter::PureTickIter( TickInfoArrayType
& rTickInfoVector
)
62 : m_rTickVector(rTickInfoVector
)
63 , m_aTickIter(m_rTickVector
.begin())
66 PureTickIter::~PureTickIter()
69 TickInfo
* PureTickIter::firstInfo()
71 m_aTickIter
= m_rTickVector
.begin();
72 if(m_aTickIter
!=m_rTickVector
.end())
76 TickInfo
* PureTickIter::nextInfo()
78 if(m_aTickIter
!=m_rTickVector
.end())
81 if(m_aTickIter
!=m_rTickVector
.end())
87 TickFactory::TickFactory(
88 const ExplicitScaleData
& rScale
, const ExplicitIncrementData
& rIncrement
)
90 , m_rIncrement( rIncrement
)
92 //@todo: make sure that the scale is valid for the scaling
94 if( m_rScale
.Scaling
.is() )
96 m_xInverseScaling
= m_rScale
.Scaling
->getInverseScaling();
97 OSL_ENSURE( m_xInverseScaling
.is(), "each Scaling needs to return an inverse Scaling" );
100 m_fScaledVisibleMin
= m_rScale
.Minimum
;
101 if( m_xInverseScaling
.is() )
102 m_fScaledVisibleMin
= m_rScale
.Scaling
->doScaling(m_fScaledVisibleMin
);
104 m_fScaledVisibleMax
= m_rScale
.Maximum
;
105 if( m_xInverseScaling
.is() )
106 m_fScaledVisibleMax
= m_rScale
.Scaling
->doScaling(m_fScaledVisibleMax
);
109 TickFactory::~TickFactory()
113 bool TickFactory::isDateAxis() const
115 return m_rScale
.AxisType
== chart2::AxisType::DATE
;
118 void TickFactory::getAllTicks( TickInfoArraysType
& rAllTickInfos
) const
121 DateTickFactory( m_rScale
, m_rIncrement
).getAllTicks( rAllTickInfos
);
123 EquidistantTickFactory( m_rScale
, m_rIncrement
).getAllTicks( rAllTickInfos
);
126 void TickFactory::getAllTicksShifted( TickInfoArraysType
& rAllTickInfos
) const
129 DateTickFactory( m_rScale
, m_rIncrement
).getAllTicksShifted( rAllTickInfos
);
131 EquidistantTickFactory( m_rScale
, m_rIncrement
).getAllTicksShifted( rAllTickInfos
);
134 // ___TickFactory_2D___
135 TickFactory2D::TickFactory2D(
136 const ExplicitScaleData
& rScale
, const ExplicitIncrementData
& rIncrement
137 //, double fStretch_SceneToScreen, double fOffset_SceneToScreen )
138 , const B2DVector
& rStartScreenPos
, const B2DVector
& rEndScreenPos
139 , const B2DVector
& rAxisLineToLabelLineShift
)
140 : TickFactory( rScale
, rIncrement
)
141 , m_aAxisStartScreenPosition2D(rStartScreenPos
)
142 , m_aAxisEndScreenPosition2D(rEndScreenPos
)
143 , m_aAxisLineToLabelLineShift(rAxisLineToLabelLineShift
)
144 , m_fStretch_LogicToScreen(1.0)
145 , m_fOffset_LogicToScreen(0.0)
147 double fWidthY
= m_fScaledVisibleMax
- m_fScaledVisibleMin
;
148 if (m_rScale
.Orientation
== chart2::AxisOrientation_MATHEMATICAL
)
150 m_fStretch_LogicToScreen
= 1.0/fWidthY
;
151 m_fOffset_LogicToScreen
= -m_fScaledVisibleMin
;
155 B2DVector
aSwap(m_aAxisStartScreenPosition2D
);
156 m_aAxisStartScreenPosition2D
= m_aAxisEndScreenPosition2D
;
157 m_aAxisEndScreenPosition2D
= aSwap
;
159 m_fStretch_LogicToScreen
= -1.0/fWidthY
;
160 m_fOffset_LogicToScreen
= -m_fScaledVisibleMax
;
164 TickFactory2D::~TickFactory2D()
168 bool TickFactory2D::isHorizontalAxis() const
170 // check trivial cases:
171 if ( m_aAxisStartScreenPosition2D
.getY() == m_aAxisEndScreenPosition2D
.getY() )
173 if ( m_aAxisStartScreenPosition2D
.getX() == m_aAxisEndScreenPosition2D
.getX() )
176 // for skew axes compare angle with horizontal vector
177 double fInclination
= std::abs(B2DVector(m_aAxisEndScreenPosition2D
-m_aAxisStartScreenPosition2D
).angle(B2DVector(1.0, 0.0)));
178 return fInclination
< F_PI4
|| fInclination
> (F_PI
-F_PI4
);
180 bool TickFactory2D::isVerticalAxis() const
182 // check trivial cases:
183 if ( m_aAxisStartScreenPosition2D
.getX() == m_aAxisEndScreenPosition2D
.getX() )
185 if ( m_aAxisStartScreenPosition2D
.getY() == m_aAxisEndScreenPosition2D
.getY() )
188 // for skew axes compare angle with vertical vector
189 double fInclination
= std::abs(B2DVector(m_aAxisEndScreenPosition2D
-m_aAxisStartScreenPosition2D
).angle(B2DVector(0.0, -1.0)));
190 return fInclination
< F_PI4
|| fInclination
> (F_PI
-F_PI4
);
193 sal_Int32
TickFactory2D::getTickScreenDistance( TickIter
& rIter
)
195 //return the positive distance between the two first tickmarks in screen values
196 //if there are less than two tickmarks -1 is returned
198 const TickInfo
* pFirstTickInfo
= rIter
.firstInfo();
199 const TickInfo
* pSecondTickInfo
= rIter
.nextInfo();
200 if(!pSecondTickInfo
|| !pFirstTickInfo
)
203 return pFirstTickInfo
->getScreenDistanceBetweenTicks( *pSecondTickInfo
);
206 B2DVector
TickFactory2D::getXaxisStartPos() const
208 return m_aAxisStartScreenPosition2D
;
211 B2DVector
TickFactory2D::getTickScreenPosition2D( double fScaledLogicTickValue
) const
213 B2DVector
aRet(m_aAxisStartScreenPosition2D
);
214 aRet
+= (m_aAxisEndScreenPosition2D
-m_aAxisStartScreenPosition2D
)
215 *((fScaledLogicTickValue
+m_fOffset_LogicToScreen
)*m_fStretch_LogicToScreen
);
219 void TickFactory2D::addPointSequenceForTickLine( drawing::PointSequenceSequence
& rPoints
220 , sal_Int32 nSequenceIndex
221 , double fScaledLogicTickValue
, double fInnerDirectionSign
222 , const TickmarkProperties
& rTickmarkProperties
223 , bool bPlaceAtLabels
) const
225 if( fInnerDirectionSign
==0.0 )
226 fInnerDirectionSign
= 1.0;
228 B2DVector aTickScreenPosition
= getTickScreenPosition2D(fScaledLogicTickValue
);
230 aTickScreenPosition
+= m_aAxisLineToLabelLineShift
;
232 B2DVector aMainDirection
= m_aAxisEndScreenPosition2D
-m_aAxisStartScreenPosition2D
;
233 aMainDirection
.normalize();
234 B2DVector
aOrthoDirection(-aMainDirection
.getY(),aMainDirection
.getX());
235 aOrthoDirection
*= fInnerDirectionSign
;
236 aOrthoDirection
.normalize();
238 B2DVector aStart
= aTickScreenPosition
+ aOrthoDirection
*rTickmarkProperties
.RelativePos
;
239 B2DVector aEnd
= aStart
- aOrthoDirection
*rTickmarkProperties
.Length
;
241 rPoints
[nSequenceIndex
].realloc(2);
242 rPoints
[nSequenceIndex
][0].X
= static_cast<sal_Int32
>(aStart
.getX());
243 rPoints
[nSequenceIndex
][0].Y
= static_cast<sal_Int32
>(aStart
.getY());
244 rPoints
[nSequenceIndex
][1].X
= static_cast<sal_Int32
>(aEnd
.getX());
245 rPoints
[nSequenceIndex
][1].Y
= static_cast<sal_Int32
>(aEnd
.getY());
248 B2DVector
TickFactory2D::getDistanceAxisTickToText( const AxisProperties
& rAxisProperties
, bool bIncludeFarAwayDistanceIfSo
, bool bIncludeSpaceBetweenTickAndText
) const
250 bool bFarAwayLabels
= false;
251 if( rAxisProperties
.m_eLabelPos
== css::chart::ChartAxisLabelPosition_OUTSIDE_START
252 || rAxisProperties
.m_eLabelPos
== css::chart::ChartAxisLabelPosition_OUTSIDE_END
)
253 bFarAwayLabels
= true;
255 double fInnerDirectionSign
= rAxisProperties
.maLabelAlignment
.mfInnerTickDirection
;
256 if( fInnerDirectionSign
==0.0 )
257 fInnerDirectionSign
= 1.0;
259 B2DVector aMainDirection
= m_aAxisEndScreenPosition2D
-m_aAxisStartScreenPosition2D
;
260 aMainDirection
.normalize();
261 B2DVector
aOrthoDirection(-aMainDirection
.getY(),aMainDirection
.getX());
262 aOrthoDirection
*= fInnerDirectionSign
;
263 aOrthoDirection
.normalize();
265 B2DVector
aStart(0,0), aEnd(0,0);
268 TickmarkProperties
aProps( AxisProperties::getBiggestTickmarkProperties() );
269 aStart
= aOrthoDirection
*aProps
.RelativePos
;
270 aEnd
= aStart
- aOrthoDirection
*aProps
.Length
;
274 for( sal_Int32 nN
=rAxisProperties
.m_aTickmarkPropertiesList
.size();nN
--;)
276 const TickmarkProperties
& rProps
= rAxisProperties
.m_aTickmarkPropertiesList
[nN
];
277 B2DVector aNewStart
= aOrthoDirection
*rProps
.RelativePos
;
278 B2DVector aNewEnd
= aNewStart
- aOrthoDirection
*rProps
.Length
;
279 if(aNewStart
.getLength()>aStart
.getLength())
281 if(aNewEnd
.getLength()>aEnd
.getLength())
286 B2DVector
aLabelDirection(aStart
);
287 if (rAxisProperties
.maLabelAlignment
.mfInnerTickDirection
!= rAxisProperties
.maLabelAlignment
.mfLabelDirection
)
288 aLabelDirection
= aEnd
;
290 B2DVector
aOrthoLabelDirection(aOrthoDirection
);
291 if (rAxisProperties
.maLabelAlignment
.mfInnerTickDirection
!= rAxisProperties
.maLabelAlignment
.mfLabelDirection
)
292 aOrthoLabelDirection
*=-1.0;
293 aOrthoLabelDirection
.normalize();
294 if( bIncludeSpaceBetweenTickAndText
)
295 aLabelDirection
+= aOrthoLabelDirection
*AXIS2D_TICKLABELSPACING
;
296 if( bFarAwayLabels
&& bIncludeFarAwayDistanceIfSo
)
297 aLabelDirection
+= m_aAxisLineToLabelLineShift
;
298 return aLabelDirection
;
301 void TickFactory2D::createPointSequenceForAxisMainLine( drawing::PointSequenceSequence
& rPoints
) const
303 rPoints
[0].realloc(2);
304 rPoints
[0][0].X
= static_cast<sal_Int32
>(m_aAxisStartScreenPosition2D
.getX());
305 rPoints
[0][0].Y
= static_cast<sal_Int32
>(m_aAxisStartScreenPosition2D
.getY());
306 rPoints
[0][1].X
= static_cast<sal_Int32
>(m_aAxisEndScreenPosition2D
.getX());
307 rPoints
[0][1].Y
= static_cast<sal_Int32
>(m_aAxisEndScreenPosition2D
.getY());
310 void TickFactory2D::updateScreenValues( TickInfoArraysType
& rAllTickInfos
) const
312 //get the transformed screen values for all tickmarks in rAllTickInfos
313 for (auto & tickInfos
: rAllTickInfos
)
315 for (auto & tickInfo
: tickInfos
)
317 tickInfo
.aTickScreenPosition
=
318 getTickScreenPosition2D(tickInfo
.fScaledTickValue
);
325 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */