1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_chart2.hxx" 30 #include "Tickmarks.hxx" 31 #include "Tickmarks_Equidistant.hxx" 32 #include "Tickmarks_Dates.hxx" 33 #include "ViewDefines.hxx" 34 #include <rtl/math.hxx> 35 #include <tools/debug.hxx> 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 using ::basegfx::B2DVector; 46 47 TickInfo::TickInfo( const ::com::sun::star::uno::Reference< 48 ::com::sun::star::chart2::XScaling >& xInverse ) 49 : fScaledTickValue( 0.0 ) 50 , xInverseScaling( xInverse ) 51 , aTickScreenPosition(0.0,0.0) 52 , bPaintIt( true ) 53 , xTextShape( NULL ) 54 , nFactorForLimitedTextWidth(1) 55 { 56 } 57 58 double TickInfo::getUnscaledTickValue() const 59 { 60 if( xInverseScaling.is() ) 61 return xInverseScaling->doScaling( fScaledTickValue ); 62 else 63 return fScaledTickValue; 64 } 65 66 sal_Int32 TickInfo::getScreenDistanceBetweenTicks( const TickInfo& rOherTickInfo ) const 67 { 68 //return the positive distance between the two first tickmarks in screen values 69 70 B2DVector aDistance = rOherTickInfo.aTickScreenPosition - aTickScreenPosition; 71 sal_Int32 nRet = static_cast<sal_Int32>(aDistance.getLength()); 72 if(nRet<0) 73 nRet *= -1; 74 return nRet; 75 } 76 77 PureTickIter::PureTickIter( ::std::vector< TickInfo >& rTickInfoVector ) 78 : m_rTickVector(rTickInfoVector) 79 , m_aTickIter(m_rTickVector.begin()) 80 { 81 } 82 PureTickIter::~PureTickIter() 83 { 84 } 85 TickInfo* PureTickIter::firstInfo() 86 { 87 m_aTickIter = m_rTickVector.begin(); 88 if(m_aTickIter!=m_rTickVector.end()) 89 return &*m_aTickIter; 90 return 0; 91 } 92 TickInfo* PureTickIter::nextInfo() 93 { 94 if(m_aTickIter!=m_rTickVector.end()) 95 { 96 m_aTickIter++; 97 if(m_aTickIter!=m_rTickVector.end()) 98 return &*m_aTickIter; 99 } 100 return 0; 101 } 102 103 //----------------------------------------------------------------------------- 104 //----------------------------------------------------------------------------- 105 //----------------------------------------------------------------------------- 106 107 TickFactory::TickFactory( 108 const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement ) 109 : m_rScale( rScale ) 110 , m_rIncrement( rIncrement ) 111 , m_xInverseScaling(NULL) 112 { 113 //@todo: make sure that the scale is valid for the scaling 114 115 if( m_rScale.Scaling.is() ) 116 { 117 m_xInverseScaling = m_rScale.Scaling->getInverseScaling(); 118 DBG_ASSERT( m_xInverseScaling.is(), "each Scaling needs to return a inverse Scaling" ); 119 } 120 121 m_fScaledVisibleMin = m_rScale.Minimum; 122 if( m_xInverseScaling.is() ) 123 m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin); 124 125 m_fScaledVisibleMax = m_rScale.Maximum; 126 if( m_xInverseScaling.is() ) 127 m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax); 128 } 129 130 TickFactory::~TickFactory() 131 { 132 } 133 134 bool TickFactory::isDateAxis() const 135 { 136 return m_rScale.AxisType == AxisType::DATE; 137 } 138 139 void TickFactory::getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const 140 { 141 if( isDateAxis() ) 142 DateTickFactory( m_rScale, m_rIncrement ).getAllTicks( rAllTickInfos ); 143 else 144 EquidistantTickFactory( m_rScale, m_rIncrement ).getAllTicks( rAllTickInfos ); 145 } 146 147 void TickFactory::getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const 148 { 149 if( isDateAxis() ) 150 DateTickFactory( m_rScale, m_rIncrement ).getAllTicksShifted( rAllTickInfos ); 151 else 152 EquidistantTickFactory( m_rScale, m_rIncrement ).getAllTicksShifted( rAllTickInfos ); 153 } 154 155 //----------------------------------------------------------------------------- 156 // ___TickFactory_2D___ 157 //----------------------------------------------------------------------------- 158 TickFactory_2D::TickFactory_2D( 159 const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement 160 //, double fStrech_SceneToScreen, double fOffset_SceneToScreen ) 161 , const B2DVector& rStartScreenPos, const B2DVector& rEndScreenPos 162 , const B2DVector& rAxisLineToLabelLineShift ) 163 : TickFactory( rScale, rIncrement ) 164 , m_aAxisStartScreenPosition2D(rStartScreenPos) 165 , m_aAxisEndScreenPosition2D(rEndScreenPos) 166 , m_aAxisLineToLabelLineShift(rAxisLineToLabelLineShift) 167 , m_fStrech_LogicToScreen(1.0) 168 , m_fOffset_LogicToScreen(0.0) 169 { 170 double fWidthY = m_fScaledVisibleMax - m_fScaledVisibleMin; 171 if( AxisOrientation_MATHEMATICAL==m_rScale.Orientation ) 172 { 173 m_fStrech_LogicToScreen = 1.0/fWidthY; 174 m_fOffset_LogicToScreen = -m_fScaledVisibleMin; 175 } 176 else 177 { 178 B2DVector aSwap(m_aAxisStartScreenPosition2D); 179 m_aAxisStartScreenPosition2D = m_aAxisEndScreenPosition2D; 180 m_aAxisEndScreenPosition2D = aSwap; 181 182 m_fStrech_LogicToScreen = -1.0/fWidthY; 183 m_fOffset_LogicToScreen = -m_fScaledVisibleMax; 184 } 185 } 186 187 TickFactory_2D::~TickFactory_2D() 188 { 189 } 190 191 bool TickFactory_2D::isHorizontalAxis() const 192 { 193 return ( m_aAxisStartScreenPosition2D.getY() == m_aAxisEndScreenPosition2D.getY() ); 194 } 195 bool TickFactory_2D::isVerticalAxis() const 196 { 197 return ( m_aAxisStartScreenPosition2D.getX() == m_aAxisEndScreenPosition2D.getX() ); 198 } 199 200 //static 201 sal_Int32 TickFactory_2D::getTickScreenDistance( TickIter& rIter ) 202 { 203 //return the positive distance between the two first tickmarks in screen values 204 //if there are less than two tickmarks -1 is returned 205 206 const TickInfo* pFirstTickInfo = rIter.firstInfo(); 207 const TickInfo* pSecondTickInfo = rIter.nextInfo(); 208 if(!pSecondTickInfo || !pFirstTickInfo) 209 return -1; 210 211 return pFirstTickInfo->getScreenDistanceBetweenTicks( *pSecondTickInfo ); 212 } 213 214 B2DVector TickFactory_2D::getTickScreenPosition2D( double fScaledLogicTickValue ) const 215 { 216 B2DVector aRet(m_aAxisStartScreenPosition2D); 217 aRet += (m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D) 218 *((fScaledLogicTickValue+m_fOffset_LogicToScreen)*m_fStrech_LogicToScreen); 219 return aRet; 220 } 221 222 void TickFactory_2D::addPointSequenceForTickLine( drawing::PointSequenceSequence& rPoints 223 , sal_Int32 nSequenceIndex 224 , double fScaledLogicTickValue, double fInnerDirectionSign 225 , const TickmarkProperties& rTickmarkProperties 226 , bool bPlaceAtLabels ) const 227 { 228 if( fInnerDirectionSign==0.0 ) 229 fInnerDirectionSign = 1.0; 230 231 B2DVector aTickScreenPosition = this->getTickScreenPosition2D(fScaledLogicTickValue); 232 if( bPlaceAtLabels ) 233 aTickScreenPosition += m_aAxisLineToLabelLineShift; 234 235 B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D; 236 aMainDirection.normalize(); 237 B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX()); 238 aOrthoDirection *= fInnerDirectionSign; 239 aOrthoDirection.normalize(); 240 241 B2DVector aStart = aTickScreenPosition + aOrthoDirection*rTickmarkProperties.RelativePos; 242 B2DVector aEnd = aStart - aOrthoDirection*rTickmarkProperties.Length; 243 244 rPoints[nSequenceIndex].realloc(2); 245 rPoints[nSequenceIndex][0].X = static_cast<sal_Int32>(aStart.getX()); 246 rPoints[nSequenceIndex][0].Y = static_cast<sal_Int32>(aStart.getY()); 247 rPoints[nSequenceIndex][1].X = static_cast<sal_Int32>(aEnd.getX()); 248 rPoints[nSequenceIndex][1].Y = static_cast<sal_Int32>(aEnd.getY()); 249 } 250 251 B2DVector TickFactory_2D::getDistanceAxisTickToText( const AxisProperties& rAxisProperties, bool bIncludeFarAwayDistanceIfSo, bool bIncludeSpaceBetweenTickAndText ) const 252 { 253 bool bFarAwayLabels = false; 254 if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_START == rAxisProperties.m_eLabelPos 255 || ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END == rAxisProperties.m_eLabelPos ) 256 bFarAwayLabels = true; 257 258 double fInnerDirectionSign = rAxisProperties.m_fInnerDirectionSign; 259 if( fInnerDirectionSign==0.0 ) 260 fInnerDirectionSign = 1.0; 261 262 B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D; 263 aMainDirection.normalize(); 264 B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX()); 265 aOrthoDirection *= fInnerDirectionSign; 266 aOrthoDirection.normalize(); 267 268 B2DVector aStart(0,0), aEnd(0,0); 269 if( bFarAwayLabels ) 270 { 271 TickmarkProperties aProps( AxisProperties::getBiggestTickmarkProperties() ); 272 aStart = aOrthoDirection*aProps.RelativePos; 273 aEnd = aStart - aOrthoDirection*aProps.Length; 274 } 275 else 276 { 277 for( sal_Int32 nN=rAxisProperties.m_aTickmarkPropertiesList.size();nN--;) 278 { 279 const TickmarkProperties& rProps = rAxisProperties.m_aTickmarkPropertiesList[nN]; 280 B2DVector aNewStart = aOrthoDirection*rProps.RelativePos; 281 B2DVector aNewEnd = aNewStart - aOrthoDirection*rProps.Length; 282 if(aNewStart.getLength()>aStart.getLength()) 283 aStart=aNewStart; 284 if(aNewEnd.getLength()>aEnd.getLength()) 285 aEnd=aNewEnd; 286 } 287 } 288 289 B2DVector aLabelDirection(aStart); 290 if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign ) 291 aLabelDirection = aEnd; 292 293 B2DVector aOrthoLabelDirection(aOrthoDirection); 294 if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign ) 295 aOrthoLabelDirection*=-1.0; 296 aOrthoLabelDirection.normalize(); 297 if( bIncludeSpaceBetweenTickAndText ) 298 aLabelDirection += aOrthoLabelDirection*AXIS2D_TICKLABELSPACING; 299 if( bFarAwayLabels && bIncludeFarAwayDistanceIfSo ) 300 aLabelDirection += m_aAxisLineToLabelLineShift; 301 return aLabelDirection; 302 } 303 304 void TickFactory_2D::createPointSequenceForAxisMainLine( drawing::PointSequenceSequence& rPoints ) const 305 { 306 rPoints[0].realloc(2); 307 rPoints[0][0].X = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getX()); 308 rPoints[0][0].Y = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getY()); 309 rPoints[0][1].X = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getX()); 310 rPoints[0][1].Y = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getY()); 311 } 312 313 void TickFactory_2D::updateScreenValues( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const 314 { 315 //get the transformed screen values for all tickmarks in rAllTickInfos 316 ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter = rAllTickInfos.begin(); 317 const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd = rAllTickInfos.end(); 318 for( ; aDepthIter != aDepthEnd; aDepthIter++ ) 319 { 320 ::std::vector< TickInfo >::iterator aTickIter = (*aDepthIter).begin(); 321 const ::std::vector< TickInfo >::const_iterator aTickEnd = (*aDepthIter).end(); 322 for( ; aTickIter != aTickEnd; aTickIter++ ) 323 { 324 TickInfo& rTickInfo = (*aTickIter); 325 rTickInfo.aTickScreenPosition = 326 this->getTickScreenPosition2D( rTickInfo.fScaledTickValue ); 327 } 328 } 329 } 330 331 //............................................................................. 332 } //namespace chart 333 //............................................................................. 334