sim: hopefully final version of plot axis unit/suffix handling.
This commit is contained in:
parent
01d18bad97
commit
b20f941bd0
|
@ -818,39 +818,21 @@ void mpScaleX::recalculateTicks ( wxDC & dc, mpWindow & w )
|
|||
updateTickLabels( dc, w );
|
||||
}
|
||||
|
||||
int countDecimalDigits ( double x )
|
||||
{
|
||||
int k = (int) ( ( x - floor(x)) * 1000000000.0 );
|
||||
int n = 0;
|
||||
|
||||
while(k && ((k % 10) == 0 || (k % 10) == 9))
|
||||
{
|
||||
k /= 10;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
|
||||
while (k != 0)
|
||||
{
|
||||
n++;
|
||||
k /= 10;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
int mpScaleBase::getLabelDecimalDigits(int maxDigits)
|
||||
{
|
||||
int m = 0;
|
||||
|
||||
for( auto l: m_tickLabels )
|
||||
{
|
||||
m = std::max ( countDecimalDigits ( l.pos ), m );
|
||||
int k = countDecimalDigits ( l.pos );
|
||||
m = std::max ( k, m );
|
||||
}
|
||||
|
||||
return std::min(m, maxDigits);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void mpScaleBase::computeLabelExtents ( wxDC & dc, mpWindow & w )
|
||||
{
|
||||
|
@ -871,25 +853,14 @@ void mpScaleBase::computeLabelExtents ( wxDC & dc, mpWindow & w )
|
|||
|
||||
void mpScaleBase::updateTickLabels( wxDC & dc, mpWindow & w )
|
||||
{
|
||||
int sigDigits = 0;
|
||||
|
||||
for ( auto l : m_tickLabels )
|
||||
sigDigits = std::max( sigDigits, countDecimalDigits( l.pos ) );
|
||||
|
||||
//printf("sigDigits: %d\n",sigDigits);
|
||||
|
||||
for ( auto &l : m_tickLabels )
|
||||
{
|
||||
l.label = formatLabel ( l.pos, sigDigits );
|
||||
l.visible = true;
|
||||
}
|
||||
|
||||
formatLabels();
|
||||
computeLabelExtents(dc, w);
|
||||
|
||||
int gap = IsHorizontal() ? m_maxLabelWidth + 10 : m_maxLabelHeight + 5;
|
||||
// int gap = IsHorizontal() ? m_maxLabelWidth + 10 : m_maxLabelHeight + 5;
|
||||
|
||||
if ( m_tickLabels.size() <= 2)
|
||||
return;
|
||||
//if ( m_tickLabels.size() <= 2)
|
||||
// return;
|
||||
|
||||
/*
|
||||
fixme!
|
||||
|
@ -1006,11 +977,14 @@ void mpScaleY::computeSlaveTicks( mpWindow& w )
|
|||
|
||||
double m;
|
||||
|
||||
m_absVisibleMaxV = 0;
|
||||
|
||||
for (unsigned int i = 0; i < m_masterScale->m_tickValues.size(); i++)
|
||||
{
|
||||
m = TransformFromPlot ( m_masterScale->TransformToPlot(m_masterScale->m_tickValues[i]) );
|
||||
m_tickValues.push_back(m);
|
||||
m_tickLabels.push_back( TickLabel (m) );
|
||||
m_absVisibleMaxV = std::max(m_absVisibleMaxV, fabs(m));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1035,6 +1009,7 @@ void mpScaleY::recalculateTicks ( wxDC & dc, mpWindow & w )
|
|||
|
||||
m_absVisibleMaxV = std::max(std::abs(minVvis), std::abs(maxVvis));
|
||||
|
||||
|
||||
m_tickValues.clear();
|
||||
m_tickLabels.clear();
|
||||
|
||||
|
@ -1412,24 +1387,13 @@ void mpScaleY::Plot(wxDC & dc, mpWindow & w)
|
|||
// Draw line
|
||||
dc.DrawLine( orgx, minYpx, orgx, maxYpx);
|
||||
|
||||
// To cut the axis line when draw outside margin is false, use this code
|
||||
/* if (m_drawOutsideMargins == true)
|
||||
dc.DrawLine( orgx, 0, orgx, extend);
|
||||
else
|
||||
dc.DrawLine( orgx, w.GetMarginTop(), orgx, w.GetScrY() - w.GetMarginBottom()); */
|
||||
|
||||
const double dig = floor( log( 128.0 / w.GetScaleY() ) / mpLN10 );
|
||||
//const double step = exp( mpLN10 * dig);
|
||||
//const double end = w.GetPosY() + (double)extend / w.GetScaleY();
|
||||
|
||||
wxCoord tx, ty;
|
||||
wxString s;
|
||||
wxString fmt;
|
||||
int tmp = (int)dig;
|
||||
int n=0;
|
||||
|
||||
|
||||
tmp=65536;
|
||||
int labelW = 0;
|
||||
// Before staring cycle, calculate label height
|
||||
int labelHeigth = 0;
|
||||
|
@ -1724,6 +1688,7 @@ void mpWindow::OnMouseMove(wxMouseEvent &event)
|
|||
}
|
||||
UpdateAll();
|
||||
} else {
|
||||
#if 0
|
||||
wxLayerList::iterator li;
|
||||
for (li = m_layers.begin(); li != m_layers.end(); li++) {
|
||||
if ((*li)->IsInfo() && (*li)->IsVisible()) {
|
||||
|
@ -1733,6 +1698,7 @@ void mpWindow::OnMouseMove(wxMouseEvent &event)
|
|||
RefreshRect(tmpLyr->GetRectangle());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* if (m_coordTooltip) {
|
||||
wxString toolTipContent;
|
||||
toolTipContent.Printf(_("X = %f\nY = %f"), p2x(event.GetX()), p2y(event.GetY()));
|
||||
|
|
|
@ -45,10 +45,13 @@ static wxString formatFloat (double x, int nDigits)
|
|||
return rv;
|
||||
}
|
||||
|
||||
static wxString formatSI ( double x, const wxString& unit, int decimalDigits, double maxValue = 0.0, bool lockSuffix = false, char suffix = 0 )
|
||||
static void getSISuffix ( double x, const wxString& unit, int& power, wxString& suffix )
|
||||
{
|
||||
const int n_powers = 11;
|
||||
const struct { double exponent; char suffix; } powers[] = {
|
||||
const struct {
|
||||
double exponent;
|
||||
char suffix;
|
||||
} powers[] = {
|
||||
{-18,'a'},
|
||||
{-15,'f'},
|
||||
{-12,'p'},
|
||||
|
@ -63,62 +66,109 @@ static wxString formatSI ( double x, const wxString& unit, int decimalDigits, do
|
|||
{15, 'P'}
|
||||
};
|
||||
|
||||
if ( x== 0.0)
|
||||
{
|
||||
return wxT("0") + unit;
|
||||
}
|
||||
power = 0;
|
||||
suffix = unit;
|
||||
|
||||
if (x == 0.0)
|
||||
return;
|
||||
|
||||
for ( int i = 0; i <n_powers - 1;i++)
|
||||
{
|
||||
double r_cur = pow(10, powers[i].exponent);
|
||||
bool rangeHit;
|
||||
|
||||
if (maxValue != 0.0)
|
||||
rangeHit = fabs(maxValue) >= r_cur && fabs(maxValue) < r_cur * 1000.0 ;
|
||||
else
|
||||
rangeHit = fabs(x) >= r_cur && fabs(x) < r_cur * 1000.0 ;
|
||||
|
||||
if( (!lockSuffix && rangeHit) || (lockSuffix && suffix == powers[i].suffix ) )
|
||||
if( fabs(x) >= r_cur && fabs(x) < r_cur * 1000.0 )
|
||||
{
|
||||
double v = x / r_cur;
|
||||
wxString rv;
|
||||
|
||||
rv = formatFloat ( v, decimalDigits );
|
||||
|
||||
if(powers[i].suffix)
|
||||
rv += powers[i].suffix;
|
||||
rv += unit;
|
||||
|
||||
return rv;
|
||||
power = powers[i].exponent;
|
||||
if ( powers[i].suffix )
|
||||
suffix = wxString(powers[i].suffix) + unit;
|
||||
else
|
||||
suffix = unit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return wxT("?");
|
||||
}
|
||||
|
||||
static int countDecimalDigits ( double x, int maxDigits )
|
||||
{
|
||||
int64_t k = (int) ( ( x - floor(x)) * pow ( 10.0, (double) maxDigits ));
|
||||
int n = 0;
|
||||
|
||||
while(k && ((k % 10LL) == 0LL || (k % 10LL) == 9LL))
|
||||
{
|
||||
k /= 10LL;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
|
||||
while (k != 0LL)
|
||||
{
|
||||
n++;
|
||||
k /= 10LL;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
class FREQUENCY_LIN_SCALE : public mpScaleX
|
||||
static void formatSILabels( mpScaleBase *scale, const wxString& aUnit, int nDigits )
|
||||
{
|
||||
public:
|
||||
FREQUENCY_LIN_SCALE(wxString name, int flags, bool ticks = false, unsigned int type = 0) :
|
||||
mpScaleX( name, flags, ticks ,type ) {};
|
||||
double maxVis = scale->AbsVisibleMaxValue();
|
||||
|
||||
const wxString formatLabel( double value, int nDigits )
|
||||
wxString suffix;
|
||||
int power, digits = 0;
|
||||
|
||||
getSISuffix( maxVis, aUnit, power, suffix);
|
||||
|
||||
double sf = pow(10.0, power);
|
||||
|
||||
for ( auto &l : scale->TickLabels() )
|
||||
{
|
||||
return formatSI ( value, wxT("Hz"), std::min(nDigits, 2) );
|
||||
}
|
||||
};
|
||||
int k = countDecimalDigits( l.pos / sf, nDigits );
|
||||
|
||||
digits = std::max(digits, k);
|
||||
}
|
||||
|
||||
for ( auto &l : scale->TickLabels() )
|
||||
{
|
||||
l.label = formatFloat ( l.pos / sf, digits ) + suffix;
|
||||
l.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
class FREQUENCY_LOG_SCALE : public mpScaleXLog
|
||||
{
|
||||
public:
|
||||
FREQUENCY_LOG_SCALE(wxString name, int flags, bool ticks = false, unsigned int type = 0) :
|
||||
mpScaleXLog( name, flags, ticks ,type ) {};
|
||||
FREQUENCY_LOG_SCALE(wxString name, int flags) :
|
||||
mpScaleXLog( name, flags ) {};
|
||||
|
||||
const wxString formatLabel( double value, int nDigits )
|
||||
void formatLabels()
|
||||
{
|
||||
return formatSI ( value, wxT("Hz"), std::min(nDigits, 2) );
|
||||
const wxString unit = wxT("Hz");
|
||||
wxString suffix;
|
||||
int power;
|
||||
|
||||
for ( auto &l : TickLabels() )
|
||||
{
|
||||
getSISuffix( l.pos, unit, power, suffix);
|
||||
double sf = pow(10.0, power);
|
||||
int k = countDecimalDigits( l.pos / sf, 3 );
|
||||
|
||||
l.label = formatFloat ( l.pos / sf, k ) + suffix;
|
||||
l.visible = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class FREQUENCY_LIN_SCALE : public mpScaleX
|
||||
{
|
||||
public:
|
||||
FREQUENCY_LIN_SCALE(wxString name, int flags) :
|
||||
mpScaleX( name, flags, false , 0 ) {};
|
||||
|
||||
void formatLabels()
|
||||
{
|
||||
formatSILabels( this, wxT("Hz"), 3 );
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -126,72 +176,74 @@ public:
|
|||
class TIME_SCALE : public mpScaleX
|
||||
{
|
||||
public:
|
||||
TIME_SCALE(wxString name, int flags, bool ticks = false, unsigned int type = 0) :
|
||||
mpScaleX ( name, flags, ticks ,type ) {};
|
||||
TIME_SCALE(wxString name, int flags) :
|
||||
mpScaleX ( name, flags, false, 0) {};
|
||||
|
||||
const wxString formatLabel( double value, int nDigits )
|
||||
void formatLabels()
|
||||
{
|
||||
return formatSI ( value, wxT("s"), std::min(nDigits, 3), AbsVisibleMaxValue() );
|
||||
formatSILabels( this, wxT("s"), 3 );
|
||||
}
|
||||
};
|
||||
|
||||
class VOLTAGE_SCALE_X : public mpScaleX
|
||||
{
|
||||
public:
|
||||
VOLTAGE_SCALE_X(wxString name, int flags, bool ticks = false, unsigned int type = 0) :
|
||||
mpScaleX ( name, flags, ticks, type ) {};
|
||||
VOLTAGE_SCALE_X(wxString name, int flags) :
|
||||
mpScaleX ( name, flags, false, 0 ) {};
|
||||
|
||||
const wxString formatLabel( double value, int nDigits )
|
||||
void formatLabels()
|
||||
{
|
||||
return formatSI ( value, wxT("V"), std::min(nDigits, 3), AbsVisibleMaxValue() );
|
||||
formatSILabels( this, wxT("V"), 3 );
|
||||
}
|
||||
};
|
||||
|
||||
class GAIN_SCALE : public mpScaleY
|
||||
{
|
||||
public:
|
||||
GAIN_SCALE(wxString name, int flags, bool ticks = false, unsigned int type = 0) :
|
||||
mpScaleY ( name, flags, ticks ) {};
|
||||
GAIN_SCALE( wxString name, int flags ) :
|
||||
mpScaleY ( name, flags, false) {};
|
||||
|
||||
const wxString formatLabel( double value, int nDigits )
|
||||
void formatLabels()
|
||||
{
|
||||
return formatSI ( value, wxT("dB"), std::min(nDigits, 1), AbsVisibleMaxValue(), true, 0 );
|
||||
formatSILabels( this, wxT("dB"), 3 );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class PHASE_SCALE : public mpScaleY
|
||||
{
|
||||
public:
|
||||
PHASE_SCALE(wxString name, int flags, bool ticks = false, unsigned int type = 0) :
|
||||
mpScaleY ( name, flags, ticks ) {};
|
||||
PHASE_SCALE(wxString name, int flags) :
|
||||
mpScaleY ( name, flags, false ) {};
|
||||
|
||||
const wxString formatLabel( double value, int nDigits )
|
||||
void formatLabels()
|
||||
{
|
||||
return formatSI ( value, wxT("\u00B0"), std::min(nDigits, 1), AbsVisibleMaxValue(), true, 0 );
|
||||
formatSILabels( this, wxT("\u00B0"), 3 );
|
||||
}
|
||||
};
|
||||
|
||||
class VOLTAGE_SCALE_Y : public mpScaleY
|
||||
{
|
||||
public:
|
||||
VOLTAGE_SCALE_Y(wxString name, int flags, bool ticks = false, unsigned int type = 0) :
|
||||
mpScaleY ( name, flags, ticks ) {};
|
||||
VOLTAGE_SCALE_Y(wxString name, int flags) :
|
||||
mpScaleY ( name, flags, false ) {};
|
||||
|
||||
const wxString formatLabel( double value, int nDigits )
|
||||
void formatLabels()
|
||||
{
|
||||
return formatSI ( value, wxT("V"), std::min(nDigits, 3), AbsVisibleMaxValue() );
|
||||
formatSILabels( this, wxT("V"), 3 );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class CURRENT_SCALE : public mpScaleY
|
||||
{
|
||||
public:
|
||||
CURRENT_SCALE(wxString name, int flags, bool ticks = false, unsigned int type = 0) :
|
||||
mpScaleY ( name, flags, ticks ) {};
|
||||
CURRENT_SCALE(wxString name, int flags ) :
|
||||
mpScaleY ( name, flags, false ) {};
|
||||
|
||||
const wxString formatLabel( double value, int nDigits )
|
||||
void formatLabels()
|
||||
{
|
||||
return formatSI ( value, wxT("A"), std::min(nDigits, 3), AbsVisibleMaxValue() );
|
||||
formatSILabels( this, wxT("A"), 3 );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -764,6 +764,18 @@ public:
|
|||
virtual double TransformToPlot ( double x ) { return 0.0; };
|
||||
virtual double TransformFromPlot (double xplot ){ return 0.0; };
|
||||
|
||||
struct TickLabel {
|
||||
TickLabel( double pos_=0.0, const wxString& label_ = wxT("") ) :
|
||||
pos ( pos_ ),
|
||||
label ( label_ ) {};
|
||||
double pos;
|
||||
wxString label;
|
||||
int pixelPos;
|
||||
bool visible;
|
||||
};
|
||||
|
||||
std::vector<TickLabel>& TickLabels() { return m_tickLabels; };
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
@ -771,7 +783,7 @@ protected:
|
|||
void updateTickLabels( wxDC & dc, mpWindow & w );
|
||||
void computeLabelExtents ( wxDC & dc, mpWindow & w );
|
||||
|
||||
virtual int getLabelDecimalDigits(int maxDigits);
|
||||
//virtual int getLabelDecimalDigits(int maxDigits);
|
||||
virtual void getVisibleDataRange ( mpWindow& w, double &minV, double& maxV) {};
|
||||
virtual void recalculateTicks ( wxDC & dc, mpWindow & w ) {};
|
||||
|
||||
|
@ -786,6 +798,7 @@ protected:
|
|||
}
|
||||
|
||||
virtual const wxString formatLabel( double value, int nDigits ) { return wxT(""); }
|
||||
virtual void formatLabels( ) { };
|
||||
|
||||
virtual double getTickPos( int n )
|
||||
{
|
||||
|
@ -803,16 +816,6 @@ protected:
|
|||
}
|
||||
|
||||
|
||||
struct TickLabel {
|
||||
TickLabel( double pos_=0.0, const wxString& label_ = wxT("") ) :
|
||||
pos ( pos_ ),
|
||||
label ( label_ ) {};
|
||||
double pos;
|
||||
wxString label;
|
||||
int pixelPos;
|
||||
bool visible;
|
||||
};
|
||||
|
||||
|
||||
std::vector<double> m_tickValues;
|
||||
std::vector<TickLabel> m_tickLabels;
|
||||
|
|
Loading…
Reference in New Issue