43        fmt.Printf( 
"%%.0%df", nDigits );
 
 
   53static void getSISuffix( 
double x, 
const wxString& unit, 
int& power, wxString& suffix )
 
   55    const int n_powers = 11;
 
   83    for( 
int i = 0; i < n_powers - 1; i++ )
 
   85        double r_cur = pow( 10, powers[i].exponent );
 
   87        if( fabs( x ) >= r_cur && fabs( x ) < r_cur * 1000.0 )
 
   89            power = powers[i].exponent;
 
   91            if( powers[i].suffix )
 
   92                suffix = wxString( powers[i].suffix ) + unit;
 
 
  104    if( std::isnan( x ) )
 
  107    auto countSignificantDigits =
 
  110                while( k && ( k % 10LL ) == 0LL )
 
  124    int64_t k = (int)( ( x - floor( x ) ) * pow( 10.0, (
double) maxDigits ) );
 
  125    int     n = countSignificantDigits( k );
 
  128    n = std::min( n, countSignificantDigits( k + 1 ) );
 
 
  134template <
typename T_PARENT>
 
  139            T_PARENT( 
name, flags, false ),
 
 
  148        double        maxVis = T_PARENT::AbsVisibleMaxValue();
 
  153        int constexpr MAX_DIGITS = 3;
 
  154        int constexpr MAX_DISAMBIGUATION_DIGITS = 6;
 
  155        bool          duplicateLabels = 
false;
 
  159        double sf = pow( 10.0, power );
 
  166            for( 
size_t ii = 0; ii < T_PARENT::m_tickLabels.size(); ++ii )
 
  173                if( ii > 0 && l.
label == T_PARENT::m_tickLabels[ii-1].label )
 
  174                    duplicateLabels = 
true;
 
  177        while( duplicateLabels && ++digits <= MAX_DISAMBIGUATION_DIGITS );
 
 
 
  202        LIN_SCALE::ExtendDataRange( minV, maxV );
 
 
 
  232template <
typename T_PARENT>
 
  237            T_PARENT( 
name, flags, false ),
 
 
  248        int constexpr MAX_DIGITS = 3;
 
  253            double sf = pow( 10.0, power );
 
 
 
  290            && 
m_trace->GetSweepSize() != std::numeric_limits<size_t>::max() )
 
  294        double plotY = 
m_window->p2y( newY );
 
 
  311    int sweepCount = 
m_trace->GetSweepCount();
 
  312    size_t sweepSize = 
m_trace->GetSweepSize();
 
  314    if( sweepCount <= 1 )
 
  317    if( sweepSize == std::numeric_limits<size_t>::max() || sweepSize == 0 )
 
 
  338    const std::vector<double>& dataX = 
m_trace->GetDataX();
 
  339    const std::vector<double>& dataY = 
m_trace->GetDataY();
 
  341    if( dataX.size() <= 1 )
 
  349    size_t endIdx = dataX.size();
 
  350    int    sweepCount = 
m_trace->GetSweepCount();
 
  351    size_t sweepSize = 
m_trace->GetSweepSize();
 
  353    if( snapToNearest && 
m_trace->IsMultiRun() && sweepCount > 1
 
  354            && sweepSize != std::numeric_limits<size_t>::max() && sweepSize > 0
 
  355            && std::isfinite( snapTargetY ) )
 
  357        double bestDistance = std::numeric_limits<double>::infinity();
 
  361        for( 
int sweepIdx = 0; sweepIdx < sweepCount; ++sweepIdx )
 
  363            size_t candidateStart = 
static_cast<size_t>( sweepIdx ) * sweepSize;
 
  364            size_t candidateEnd = std::min( dataX.size(), candidateStart + sweepSize );
 
  366            if( candidateStart >= candidateEnd )
 
  369            auto candidateBegin = dataX.begin() + candidateStart;
 
  370            auto candidateEndIt = dataX.begin() + candidateEnd;
 
  371            auto candidateMaxIt = std::upper_bound( candidateBegin, candidateEndIt, 
m_coords.x );
 
  372            int  candidateMaxIdx = candidateMaxIt - dataX.begin();
 
  373            int  candidateMinIdx = candidateMaxIdx - 1;
 
  375            if( candidateMinIdx < (
int) candidateStart
 
  376                    || candidateMaxIdx >= (
int) candidateEnd
 
  377                    || candidateMaxIdx >= (
int) dataX.size() )
 
  382            double leftX = dataX[candidateMinIdx];
 
  383            double rightX = dataX[candidateMaxIdx];
 
  385            if( leftX == rightX )
 
  388            double leftY = dataY[candidateMinIdx];
 
  389            double rightY = dataY[candidateMaxIdx];
 
  390            double value = leftY + ( rightY - leftY ) / ( rightX - leftX ) * ( 
m_coords.x - leftX );
 
  391            double distance = std::fabs( value - snapTargetY );
 
  396                bestSweep = sweepIdx;
 
  405    if( 
m_trace->IsMultiRun() && sweepCount > 1
 
  406            && sweepSize != std::numeric_limits<size_t>::max() && sweepSize > 0 )
 
  408        size_t available = 
static_cast<size_t>( sweepCount ) * sweepSize;
 
  410        if( available <= dataX.size() )
 
  415            startIdx = 
static_cast<size_t>( 
m_sweepIndex ) * sweepSize;
 
  416            endIdx = std::min( dataX.size(), startIdx + sweepSize );
 
  428    if( startIdx >= endIdx )
 
  434    auto beginIt = dataX.begin() + startIdx;
 
  435    auto endIt = dataX.begin() + endIdx;
 
  438    auto maxXIt = std::upper_bound( beginIt, endIt, 
m_coords.x );
 
  439    int maxIdx = maxXIt - dataX.begin();
 
  440    int minIdx = maxIdx - 1;
 
  443    if( minIdx < (
int) startIdx || maxIdx >= (
int) endIdx || maxIdx >= (
int) dataX.size() )
 
  452    const double leftX = dataX[minIdx];
 
  453    const double rightX = dataX[maxIdx];
 
  454    const double leftY = dataY[minIdx];
 
  455    const double rightY = dataY[maxIdx];
 
  458    m_coords.y = leftY + ( rightY - leftY ) / ( rightX - leftX ) * ( 
m_coords.x - leftX );
 
 
  467            return wxString::Format( 
_( 
"%d" ), 
id );
 
  470    return wxEmptyString;
 
 
  488        wxQueueEvent( aWindow.GetParent(), 
new wxCommandEvent( EVT_SIM_CURSOR_UPDATE ) );
 
  511    wxColour fg = aWindow.GetForegroundColour();
 
  515    if( cursorColor.
Distance( textColor ) < 0.66 )
 
  518    pen.SetColour( cursorColor.
ToColour() );
 
  519    pen.SetStyle( 
m_continuous ? wxPENSTYLE_SOLID : wxPENSTYLE_LONG_DASH );
 
  522    if( topPx < cursorPos.y && cursorPos.y < bottomPx )
 
  523        aDC.DrawLine( leftPx, cursorPos.y, rightPx, cursorPos.y );
 
  525    if( leftPx < cursorPos.x && cursorPos.x < rightPx )
 
  527        aDC.DrawLine( cursorPos.x, topPx, cursorPos.x, bottomPx );
 
  529        wxString 
id = 
getID();
 
  530        wxSize   size = aDC.GetTextExtent( wxS( 
"M" ) );
 
  531        wxRect   textRect( wxPoint( cursorPos.x + 1 - size.x / 2, topPx - 4 - size.y ), size );
 
  542        size.y = ( size.y / 2 ) * 2;
 
  543        poly[0] = { cursorPos.x - 1 - size.y / 2, topPx - size.y };
 
  544        poly[1] = { cursorPos.x + 1 + size.y / 2, topPx - size.y };
 
  545        poly[2] = { cursorPos.x, topPx };
 
  547        brush.SetStyle( wxBRUSHSTYLE_SOLID );
 
  548        brush.SetColour( 
m_trace->GetTraceColour() );
 
  549        aDC.SetBrush( brush );
 
  550        aDC.DrawPolygon( 3, poly );
 
  552        aDC.SetTextForeground( textColor.
ToColour() );
 
  553        aDC.DrawLabel( 
id, textRect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL );
 
  556                && 
m_trace->GetSweepSize() != std::numeric_limits<size_t>::max() )
 
  559            const std::vector<wxString>& labels = 
m_trace->GetMultiRunLabels();
 
  567                runLabel = wxString::Format( 
_( 
"Run %d" ), 
m_sweepIndex + 1 );
 
  570            wxSize   runSize = aDC.GetTextExtent( runLabel );
 
  571            int      runX = textRect.GetRight() + 6;
 
  572            wxRect   runRect( wxPoint( runX, textRect.y ), runSize );
 
  574            runRect.Inflate( 3, 1 );
 
  576            wxBrush labelBrush( aWindow.GetBackgroundColour() );
 
  577            wxPen   labelPen( cursorColor.
ToColour() );
 
  579            aDC.SetPen( labelPen );
 
  580            aDC.SetBrush( labelBrush );
 
  581            aDC.DrawRectangle( runRect );
 
  582            aDC.SetTextForeground( cursorColor.
ToColour() );
 
  583            aDC.DrawLabel( runLabel, runRect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL );
 
 
  594    return ( 
std::abs( (
double) aPoint.x -
 
 
  612        SIM_TAB( aSimCommand, parent ),
 
  619    m_sizer   = 
new wxBoxSizer( wxVERTICAL );
 
 
  651    m_axis_y1->SetAxisMinMax( aLock, aMin, aMax );
 
 
  658    m_axis_y2->SetAxisMinMax( aLock, aMin, aMax );
 
 
  665    m_axis_y3->SetAxisMinMax( aLock, aMin, aMax );
 
 
  679        return wxEmptyString;
 
 
  690        return wxEmptyString;
 
 
  701        return wxEmptyString;
 
 
  712        return wxEmptyString;
 
 
  853            m_plotWin->SetMargins( 30, 160, 45, 70 );
 
 
  891    if( sim_cmd.StartsWith( 
".dc", &rem ) )
 
  899            ch = rem.GetChar( 0 );
 
  918            m_axis_x->SetName( 
_( 
"Voltage (swept)" ) );
 
  929            m_axis_x->SetName( 
_( 
"Current (swept)" ) );
 
  940            m_axis_x->SetName( 
_( 
"Resistance (swept)" ) );
 
  951            m_axis_x->SetName( 
_( 
"Temperature (swept)" ) );
 
  969        m_axis_y1->SetName( 
_( 
"Voltage (measured)" ) );
 
 
  985        m_plotWin->SetMargins( 30, 160, 45, 70 );
 
 
 1024    wxPenStyle penStyle;
 
 1027        penStyle = wxPENSTYLE_SOLID;
 
 1029        penStyle = 
m_dotted_cp ? wxPENSTYLE_DOT : wxPENSTYLE_SOLID;
 
 1031        penStyle = 
m_dotted_cp ? wxPENSTYLE_DOT : wxPENSTYLE_SOLID;
 
 1033        penStyle = wxPENSTYLE_SOLID;
 
 
 1050            bool hasVoltageTraces = 
false;
 
 1052            for( 
const auto& [ 
id, candidate ] : 
m_traces )
 
 1056                    hasVoltageTraces = 
true;
 
 1061            if( !hasVoltageTraces )
 
 
 1089                                 int aSweepCount, 
size_t aSweepSize, 
bool aIsMultiRun,
 
 1090                                 const std::vector<wxString>& aMultiRunLabels )
 
 1095        if( aX.size() > 0 && aX[0] == 0 )
 
 1097            aX.erase( aX.begin() );
 
 1098            aY.erase( aY.begin() );
 
 1106            for( 
double& pt : aY )
 
 1107                pt = pt * 180.0 / 
M_PI;                     
 
 1111            for( 
double& pt : aY )
 
 1115                    pt = 20 * log( pt ) / log( 10.0 );      
 
 
 1153    bool hasY1Traces = 
false;
 
 1154    bool hasY2Traces = 
false;
 
 1155    bool hasY3Traces = 
false;
 
 1177    bool visibilityChanged = 
false;
 
 1182        visibilityChanged = 
true;
 
 1188        visibilityChanged = 
true;
 
 1194        visibilityChanged = 
true;
 
 1197    if( visibilityChanged )
 
 
 1206        if( trace == aTrace )
 
 1219    m_plotWin->DelLayer( aTrace, 
true, 
true );
 
 
 1244    cursor->SetName( aSignalName );
 
 1251    wxQueueEvent( 
this, 
new wxCommandEvent( EVT_SIM_CURSOR_UPDATE ) );
 
 
 1259        aTrace->
SetCursor( aCursorId, 
nullptr );
 
 1263        wxQueueEvent( 
this, 
new wxCommandEvent( EVT_SIM_CURSOR_UPDATE ) );
 
 
 1276            wxStringTokenizer tokenizer( 
GetSimCommand(), 
" \t\r\n", wxTOKEN_STRTOK );
 
 1277            wxString          cmd = tokenizer.GetNextToken().Lower();
 
 1279            wxASSERT( cmd == wxS( 
".tran" ) );
 
 1285            if( tokenizer.HasMoreTokens() )
 
 1288            if( tokenizer.HasMoreTokens() )
 
 1291            if( tokenizer.HasMoreTokens() )
 
 1308        trace->UpdateScales();
 
 
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
 
The SIMULATOR_FRAME holds the main user-interface for running simulations.
 
void Move(wxPoint aDelta) override
Moves the layer rectangle of given pixel deltas.
 
static constexpr int DRAG_MARGIN
 
bool Inside(const wxPoint &aPoint) const override
Checks whether a point is inside the info box rectangle.
 
void doSetCoordX(double aValue)
 
bool OnDoubleClick(const wxPoint &aPoint, mpWindow &aWindow) override
 
void SetCoordX(double aValue)
 
void UpdateReference() override
Updates the rectangle reference point.
 
void Plot(wxDC &aDC, mpWindow &aWindow) override
Plot method.
 
A color representation with 4 components: red, green, blue, alpha.
 
COLOR4D & Invert()
Makes the color inverted, alpha remains the same.
 
wxColour ToColour() const
 
double Distance(const COLOR4D &other) const
Returns the distance (in RGB space) between two colors.
 
COLOR4D Mix(const COLOR4D &aColor, double aFactor) const
Return a color that is mixed with the input by a factor.
 
void formatLabels() override
 
wxString GetUnits() const
 
LIN_SCALE(const wxString &name, const wxString &unit, int flags)
 
wxString m_base_axis_label
 
wxString GetUnits() const
 
LOG_SCALE(const wxString &name, const wxString &unit, int flags)
 
void formatLabels() override
 
bool DeleteTrace(const wxString &aVectorName, int aTraceType)
 
mpWindow * GetPlotWin() const
 
void prepareDCAxes(int aNewTraceType)
Create/Ensure axes are available for plotting.
 
void SetTraceData(TRACE *aTrace, std::vector< double > &aX, std::vector< double > &aY, int aSweepCount, size_t aSweepSize, bool aIsMultiRun=false, const std::vector< wxString > &aMultiRunLabels={})
 
wxString GetUnitsY2() const
 
void SetY2Scale(bool aLock, double aMin, double aMax)
 
TRACE * GetTrace(const wxString &aVecName, int aType) const
 
void SetY1Scale(bool aLock, double aMin, double aMax)
 
void UpdateAxisVisibility()
 
void SetY3Scale(bool aLock, double aMin, double aMax)
 
std::map< wxString, TRACE * > m_traces
 
void UpdateTraceStyle(TRACE *trace)
Update plot colors.
 
void ResetScales(bool aIncludeX)
Update trace line style.
 
SIM_PLOT_TAB(const wxString &aSimCommand, wxWindow *parent)
 
void EnableCursor(TRACE *aTrace, int aCursorId, const wxString &aSignalName)
 
wxString GetUnitsX() const
 
void OnLanguageChanged() override
Getter for math plot window.
 
void EnsureThirdYAxisExists()
 
wxString getTraceId(const wxString &aVectorName, int aType) const
Construct the plot axes for DC simulation plot.
 
TRACE * GetOrAddTrace(const wxString &aVectorName, int aType)
 
wxPoint m_LastLegendPosition
 
wxString GetUnitsY1() const
 
std::map< wxString, wxColour > m_sessionTraceColors
 
void DisableCursor(TRACE *aTrace, int aCursorId)
Reset scale ranges to fit the current traces.
 
void updateAxes(int aNewTraceType=SIM_TRACE_TYPE::SPT_UNKNOWN)
 
wxString GetUnitsY3() const
 
SIM_TYPE GetSimType() const
 
const wxString & GetSimCommand() const
 
Helper class to recognize Spice formatted values.
 
void ResetDataRange() override
 
void ExtendDataRange(double minV, double maxV) override
 
void SetStartAndEnd(double aStartTime, double aEndTime)
 
TIME_SCALE(const wxString &name, const wxString &unit, int flags)
 
void SetIsMultiRun(bool aIsMultiRun)
 
void SetTraceColour(const wxColour &aColour)
 
void SetMultiRunLabels(const std::vector< wxString > &aLabels)
 
std::map< int, CURSOR * > & GetCursors()
 
SIM_TRACE_TYPE GetType() const
 
void SetData(const std::vector< double > &aX, const std::vector< double > &aY) override
Assigns new data set for the trace.
 
void SetCursor(int aCursorId, CURSOR *aCursor)
 
wxColour GetTraceColour() const
 
CURSOR * GetCursor(int aCursorId)
 
void SetSweepSize(size_t aSweepSize)
 
void SetSweepCount(int aSweepCount)
 
virtual void SetScale(mpScaleBase *scaleX, mpScaleBase *scaleY)
 
virtual void Move(wxPoint delta)
Moves the layer rectangle of given pixel deltas.
 
Implements the legend to be added to the plot This layer allows you to add a legend to describe the p...
 
const wxString & GetName() const
Get layer name.
 
const wxPen & GetPen() const
Get pen set for this layer.
 
void SetPen(const wxPen &pen)
Set layer pen.
 
Canvas for plotting mpLayer implementations.
 
int GetMarginLeft() const
 
int GetScrX() const
Get current view's X dimension in device context units.
 
int GetScrY() const
Get current view's Y dimension in device context units.
 
double p2x(wxCoord pixelCoordX)
Converts mpWindow (screen) pixel coordinates into graph (floating point) coordinates,...
 
wxCoord x2p(double x)
Converts graph (floating point) coordinates into mpWindow (screen) pixel coordinates,...
 
bool DelLayer(mpLayer *layer, bool alsoDeleteObject=false, bool refreshDisplay=true)
Remove a plot layer from the canvas.
 
wxCoord y2p(double y)
Converts graph (floating point) coordinates into mpWindow (screen) pixel coordinates,...
 
int GetMarginRight() const
 
int GetMarginBottom() const
 
#define mpALIGN_BORDER_RIGHT
Aligns Y axis to right border.
 
class WXDLLIMPEXP_MATHPLOT mpWindow
 
#define mpALIGN_RIGHT
Aligns label to the right.
 
#define mpALIGN_LEFT
Aligns label to the left.
 
#define mpALIGN_BOTTOM
Aligns label to the bottom.
 
KICOMMON_API wxFont GetStatusFont(wxWindow *aWindow)
 
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
 
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
 
Class is responsible for providing colors for traces on simulation plot.
 
wxDEFINE_EVENT(EVT_SIM_CURSOR_UPDATE, wxCommandEvent)
 
static void getSISuffix(double x, const wxString &unit, int &power, wxString &suffix)
 
static int countDecimalDigits(double x, int maxDigits)
 
static wxString formatFloat(double x, int nDigits)