191 lines
4.8 KiB
C++
191 lines
4.8 KiB
C++
|
/*
|
|||
|
*
|
|||
|
* ChartLogarithmicAxis.cpp
|
|||
|
*
|
|||
|
* Written by C<EFBFBD>dric Moonen (cedric_moonen@hotmail.com)
|
|||
|
*
|
|||
|
*
|
|||
|
*
|
|||
|
* This code may be used for any non-commercial and commercial purposes in a compiled form.
|
|||
|
* The code may be redistributed as long as it remains unmodified and providing that the
|
|||
|
* author name and this disclaimer remain intact. The sources can be modified WITH the author
|
|||
|
* consent only.
|
|||
|
*
|
|||
|
* This code is provided without any garanties. I cannot be held responsible for the damage or
|
|||
|
* the loss of time it causes. Use it at your own risks
|
|||
|
*
|
|||
|
* An e-mail to notify me that you are using this code is appreciated also.
|
|||
|
*
|
|||
|
*/
|
|||
|
|
|||
|
#include "stdafx.h"
|
|||
|
#include "ChartLogarithmicAxis.h"
|
|||
|
#include "ChartCtrl.h"
|
|||
|
#include <sstream>
|
|||
|
#include <iostream>
|
|||
|
#include <iomanip>
|
|||
|
#include <math.h>
|
|||
|
|
|||
|
using namespace std;
|
|||
|
|
|||
|
CChartLogarithmicAxis::CChartLogarithmicAxis()
|
|||
|
: CChartAxis(), m_dFirstTickValue(1)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
CChartLogarithmicAxis::~CChartLogarithmicAxis()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
double CChartLogarithmicAxis::GetFirstTickValue() const
|
|||
|
{
|
|||
|
double dRetVal = m_dFirstTickValue;
|
|||
|
if (m_bDiscrete)
|
|||
|
dRetVal = m_dFirstTickValue/10;
|
|||
|
return dRetVal;
|
|||
|
}
|
|||
|
|
|||
|
bool CChartLogarithmicAxis::GetNextTickValue(double dCurrentTick,
|
|||
|
double& dNextTick) const
|
|||
|
{
|
|||
|
dNextTick = dCurrentTick * 10;
|
|||
|
if (dNextTick <= m_MaxValue)
|
|||
|
return true;
|
|||
|
else
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
TChartString CChartLogarithmicAxis::GetTickLabel(double TickValue) const
|
|||
|
{
|
|||
|
double fLogDecCount;
|
|||
|
int nLogDecCount;
|
|||
|
|
|||
|
fLogDecCount = log10(TickValue);
|
|||
|
|
|||
|
if (fLogDecCount < 0.0)
|
|||
|
nLogDecCount = (int)(fabs(fLogDecCount) + 0.1);
|
|||
|
else
|
|||
|
nLogDecCount = 0;
|
|||
|
|
|||
|
TChartStringStream ssLabel;
|
|||
|
ssLabel << fixed << setprecision(nLogDecCount) << TickValue;
|
|||
|
return ssLabel.str();
|
|||
|
}
|
|||
|
|
|||
|
long CChartLogarithmicAxis::ValueToScreenStandard(double Value) const
|
|||
|
{
|
|||
|
long Offset = 0;
|
|||
|
long retVal = 0;
|
|||
|
|
|||
|
Offset = (int)floor((log10(Value)-log10(m_MinValue)) * GetAxisLenght()/(log10(m_MaxValue)-log10(m_MinValue)) );
|
|||
|
if (m_bIsHorizontal)
|
|||
|
{
|
|||
|
if (!m_bIsInverted)
|
|||
|
retVal = (m_StartPos + Offset);
|
|||
|
else
|
|||
|
retVal = (m_EndPos - Offset);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!m_bIsInverted)
|
|||
|
retVal = (m_StartPos - Offset);
|
|||
|
else
|
|||
|
retVal = (m_EndPos + Offset);
|
|||
|
}
|
|||
|
return retVal;
|
|||
|
}
|
|||
|
|
|||
|
long CChartLogarithmicAxis::ValueToScreenDiscrete(double Value) const
|
|||
|
{
|
|||
|
// In discrete mode, al values between two ticks are "directed"
|
|||
|
// to the middle of the interval.
|
|||
|
double lowTick = pow(10,floor(log10(Value)));
|
|||
|
double highTick = pow(10,floor(log10(Value*10)));
|
|||
|
|
|||
|
long lowTickPos = ValueToScreenStandard(lowTick);
|
|||
|
long highTickPos = ValueToScreenStandard(highTick);
|
|||
|
return (lowTickPos + (highTickPos-lowTickPos)/2);
|
|||
|
}
|
|||
|
|
|||
|
double CChartLogarithmicAxis::ScreenToValue(long ScreenVal) const
|
|||
|
{
|
|||
|
if (m_MaxValue==m_MinValue)
|
|||
|
return m_MinValue;
|
|||
|
|
|||
|
int AxisOffset = 0;
|
|||
|
if (!m_bIsHorizontal)
|
|||
|
{
|
|||
|
if (m_bIsInverted)
|
|||
|
AxisOffset = ScreenVal - m_EndPos;
|
|||
|
else
|
|||
|
AxisOffset = m_StartPos - ScreenVal;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!m_bIsInverted)
|
|||
|
AxisOffset = ScreenVal - m_StartPos;
|
|||
|
else
|
|||
|
AxisOffset = m_EndPos - ScreenVal;
|
|||
|
}
|
|||
|
|
|||
|
return (pow(10.0,(AxisOffset *1.0 / GetAxisLenght()*(log10(m_MaxValue)-log10(m_MinValue)) ) + log10(m_MinValue)) );
|
|||
|
}
|
|||
|
|
|||
|
void CChartLogarithmicAxis::PanAxis(long PanStart, long PanEnd)
|
|||
|
{
|
|||
|
double StartVal = ScreenToValue(PanStart);
|
|||
|
double EndVal = ScreenToValue(PanEnd);
|
|||
|
|
|||
|
double Factor = StartVal/EndVal;
|
|||
|
SetZoomMinMax(m_MinValue*Factor,m_MaxValue*Factor);
|
|||
|
}
|
|||
|
|
|||
|
long CChartLogarithmicAxis::GetTickPos(double TickVal) const
|
|||
|
{
|
|||
|
// The tick is always at the same position,
|
|||
|
// even if the axis is discrete.
|
|||
|
return ValueToScreenStandard(TickVal);
|
|||
|
}
|
|||
|
|
|||
|
void CChartLogarithmicAxis::RefreshTickIncrement()
|
|||
|
{
|
|||
|
// Do nothing. This is done by the user.
|
|||
|
}
|
|||
|
|
|||
|
void CChartLogarithmicAxis::RefreshFirstTick()
|
|||
|
{
|
|||
|
int LogBase = (int)log10(m_MinValue);
|
|||
|
m_dFirstTickValue = pow(10.0,LogBase);
|
|||
|
}
|
|||
|
|
|||
|
void CChartLogarithmicAxis::GetScrollbarSteps(int& iTotalSteps, int& iCurrentStep)
|
|||
|
{
|
|||
|
double SeriesMin=0, SeriesMax=0;
|
|||
|
GetSeriesMinMax(SeriesMin,SeriesMax);
|
|||
|
|
|||
|
if ((m_MaxValue-m_MinValue) == 0 || (SeriesMax-SeriesMin)==0 ||
|
|||
|
(SeriesMin<=0) )
|
|||
|
{
|
|||
|
iTotalSteps = 1;
|
|||
|
iCurrentStep = 1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
double dStep = pow(m_MaxValue/m_MinValue,0.1);
|
|||
|
iTotalSteps = (int)ceil(log(SeriesMax/SeriesMin)/log10(dStep));
|
|||
|
iCurrentStep = (int)(log(m_MinValue/SeriesMin)/log10(dStep));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void CChartLogarithmicAxis::SetAxisToScrollStep(int iPreviousStep,
|
|||
|
int iCurrentStep,
|
|||
|
bool bScrollInverted)
|
|||
|
{
|
|||
|
double dStep = pow(m_MaxValue/m_MinValue,0.1);
|
|||
|
double dFactor = pow(dStep,(iCurrentStep - iPreviousStep));
|
|||
|
if (bScrollInverted)
|
|||
|
SetZoomMinMax(m_MinValue/dFactor,m_MaxValue/dFactor);
|
|||
|
else
|
|||
|
SetZoomMinMax(m_MinValue*dFactor,m_MaxValue*dFactor);
|
|||
|
}
|