Replaced sim plotting widget with wxMathPlot
This commit is contained in:
parent
951d16c655
commit
51906625ee
|
@ -169,6 +169,7 @@ set( COMMON_DLG_SRCS
|
|||
)
|
||||
|
||||
set( COMMON_WIDGET_SRCS
|
||||
widgets/mathplot.cpp
|
||||
widgets/widget_hotkey_list.cpp
|
||||
)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -249,18 +249,12 @@ set_source_files_properties( ../common/single_top.cpp PROPERTIES
|
|||
COMPILE_DEFINITIONS "TOP_FRAME=FRAME_SCH;PGM_DATA_FILE_EXT=\"sch\";BUILD_KIWAY_DLL"
|
||||
)
|
||||
|
||||
#if (KICAD_SPICE)
|
||||
set ( EESCHEMA_LINK_LIBS ${wxWidgets_LIBRARIES} mgl2 mgl2-wx)
|
||||
#else()
|
||||
# set ( EESCHEMA_LINK_LIBS ${wxWidgets_LIBRARIES} )
|
||||
#endif()
|
||||
|
||||
target_link_libraries( eeschema
|
||||
#singletop # replaces common, giving us restrictive control and link warnings.
|
||||
# There's way too much crap coming in from common yet.
|
||||
common
|
||||
bitmaps
|
||||
${EESCHEMA_LINK_LIBS}
|
||||
${wxWidgets_LIBRARIES}
|
||||
)
|
||||
|
||||
# the DSO (KIFACE) housing the main eeschema code:
|
||||
|
@ -273,7 +267,7 @@ target_link_libraries( eeschema_kiface
|
|||
bitmaps
|
||||
polygon
|
||||
gal
|
||||
${EESCHEMA_LINK_LIBS}
|
||||
${wxWidgets_LIBRARIES}
|
||||
${GDI_PLUS_LIBRARIES}
|
||||
)
|
||||
set_target_properties( eeschema_kiface PROPERTIES
|
||||
|
|
|
@ -140,11 +140,15 @@ void SIM_PLOT_FRAME::AddVoltagePlot( const wxString& aNetName )
|
|||
|
||||
if( nodeNumber >= -1 )
|
||||
{
|
||||
updatePlot( wxString::Format( "V(%d)", nodeNumber ), aNetName,
|
||||
static_cast<SIM_PLOT_PANEL*>( m_plotNotebook->GetCurrentPage() ) );
|
||||
updatePlot( wxString::Format( "V(%d)", nodeNumber ), aNetName, currentPlot() );
|
||||
}
|
||||
}
|
||||
|
||||
SIM_PLOT_PANEL* SIM_PLOT_FRAME::currentPlot() const
|
||||
{
|
||||
return static_cast<SIM_PLOT_PANEL*>( m_plotNotebook->GetCurrentPage() );
|
||||
}
|
||||
|
||||
|
||||
bool SIM_PLOT_FRAME::isSimulationRunning()
|
||||
{
|
||||
|
@ -184,7 +188,10 @@ void SIM_PLOT_FRAME::onSignalDblClick( wxCommandEvent& event )
|
|||
int idx = m_signals->GetSelection();
|
||||
|
||||
if( idx != wxNOT_FOUND )
|
||||
{
|
||||
AddVoltagePlot( m_signals->GetString( idx ) );
|
||||
currentPlot()->Fit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -241,10 +248,9 @@ void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
|
|||
for( unsigned int i = 0; i < m_plotNotebook->GetPageCount(); ++i )
|
||||
{
|
||||
SIM_PLOT_PANEL* plotPanel = static_cast<SIM_PLOT_PANEL*>( m_plotNotebook->GetPage( i ) );
|
||||
plotPanel->ResetAxisRanges();
|
||||
|
||||
for( const auto& trace : plotPanel->GetTraces() )
|
||||
updatePlot( trace.spiceName, trace.title, plotPanel );
|
||||
updatePlot( trace->GetSpiceName(), trace->GetName(), plotPanel );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,8 @@ class SIM_PLOT_FRAME : public SIM_PLOT_FRAME_BASE
|
|||
void AddVoltagePlot( const wxString& aNetName );
|
||||
|
||||
private:
|
||||
SIM_PLOT_PANEL* currentPlot() const;
|
||||
|
||||
bool isSimulationRunning();
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2016 CERN
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -29,188 +30,93 @@
|
|||
|
||||
SIM_PLOT_PANEL::SIM_PLOT_PANEL( wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
||||
const wxSize& size, long style, const wxString& name )
|
||||
: wxMathGL( parent, id, pos, size, style, name ), m_painter( this )
|
||||
: mpWindow( parent, id, pos, size, style ), m_colorIdx( 0 )
|
||||
{
|
||||
AutoResize = true;
|
||||
ResetAxisRanges();
|
||||
SetDraw( &m_painter );
|
||||
//SetMargins( 10, 10, 10, 10 );
|
||||
LockAspect();
|
||||
|
||||
m_axis_x = new mpScaleX( wxT( "T [s]" ) );
|
||||
m_axis_x->SetTicks( false );
|
||||
AddLayer( m_axis_x );
|
||||
|
||||
m_axis_y = new mpScaleY( wxT( "U [V]" ) );
|
||||
m_axis_y->SetTicks( false );
|
||||
AddLayer( m_axis_y );
|
||||
|
||||
m_legend = new mpInfoLegend( wxRect( 0, 0, 40, 40 ), wxWHITE_BRUSH );
|
||||
AddLayer( m_legend );
|
||||
|
||||
//m_coords = new mpInfoCoords( wxRect( 80, 20, 10, 10 ), wxWHITE_BRUSH );
|
||||
//AddLayer( m_coords );
|
||||
}
|
||||
|
||||
|
||||
SIM_PLOT_PANEL::~SIM_PLOT_PANEL()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
static std::pair<T, T> find_minmax( const T* aArray, unsigned int aSize )
|
||||
{
|
||||
std::pair<T, T> result( std::numeric_limits<T>::max(), std::numeric_limits<T>::min() );
|
||||
const T* ptr = aArray;
|
||||
|
||||
for( unsigned int i = 0; i < aSize; ++i )
|
||||
{
|
||||
if( *ptr < result.first )
|
||||
result.first = *ptr;
|
||||
|
||||
if( *ptr > result.second )
|
||||
result.second = *ptr;
|
||||
|
||||
++ptr;
|
||||
}
|
||||
|
||||
return result;
|
||||
// ~mpWindow destroys all the added layers, so there is no need to destroy m_traces contents
|
||||
}
|
||||
|
||||
|
||||
void SIM_PLOT_PANEL::AddTrace( const wxString& aSpiceName, const wxString& aTitle, int aPoints,
|
||||
double* aT, double* aY, int aFlags )
|
||||
const double* aT, const double* aY, int aFlags )
|
||||
{
|
||||
TRACE* t = NULL;
|
||||
|
||||
// Find previous entry, if there is one
|
||||
auto it = std::find_if( m_traces.begin(), m_traces.end(),
|
||||
[&](const TRACE& t) { return t.title == aTitle; });
|
||||
[&](const TRACE* t) { return t->GetName() == aTitle; });
|
||||
|
||||
if( it == m_traces.end() )
|
||||
{
|
||||
// New entry
|
||||
TRACE trace;
|
||||
trace.spiceName = aSpiceName;
|
||||
trace.title = aTitle;
|
||||
trace.style = wxString( '-' ) + m_painter.GenerateColor( SIM_PLOT_PAINTER::DARK );
|
||||
trace.x.Set( aT, aPoints );
|
||||
trace.y.Set( aY, aPoints );
|
||||
m_traces.push_back( trace );
|
||||
t = new TRACE( aTitle, aSpiceName );
|
||||
t->SetPen( wxPen( generateColor(), 1, wxSOLID ) );
|
||||
m_traces.push_back( t );
|
||||
|
||||
// It is a trick to keep legend always on the top
|
||||
DelLayer( m_legend );
|
||||
AddLayer( t );
|
||||
AddLayer( m_legend );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update
|
||||
TRACE& trace = *it;
|
||||
trace.x.Set( aT, aPoints );
|
||||
trace.y.Set( aY, aPoints );
|
||||
t = *it;
|
||||
}
|
||||
|
||||
// Update axis ranges
|
||||
std::pair<double, double> traceRangeT = find_minmax( aT, aPoints );
|
||||
m_axisRangeX.first = std::min( traceRangeT.first, m_axisRangeX.first );
|
||||
m_axisRangeX.second = std::max( traceRangeT.second, m_axisRangeX.second );
|
||||
|
||||
std::pair<double, double> traceRangeY = find_minmax( aY, aPoints );
|
||||
m_axisRangeY.first = std::min( traceRangeY.first, m_axisRangeY.first );
|
||||
m_axisRangeY.second = std::max( traceRangeY.second, m_axisRangeY.second );
|
||||
|
||||
Update();
|
||||
t->SetData( std::vector<double>( aT, aT + aPoints ), std::vector<double>( aY, aY + aPoints ) );
|
||||
UpdateAll();
|
||||
}
|
||||
|
||||
|
||||
void SIM_PLOT_PANEL::DeleteTraces()
|
||||
{
|
||||
for( TRACE* t : m_traces )
|
||||
{
|
||||
DelLayer( t, true );
|
||||
}
|
||||
|
||||
m_traces.clear();
|
||||
ResetAxisRanges();
|
||||
Update();
|
||||
}
|
||||
|
||||
|
||||
void SIM_PLOT_PANEL::ResetAxisRanges()
|
||||
wxColour SIM_PLOT_PANEL::generateColor()
|
||||
{
|
||||
// Set ranges to inverted values, so when there is a new plot added, it will
|
||||
// overridden with correct values
|
||||
m_axisRangeX.first = std::numeric_limits<double>::max();
|
||||
m_axisRangeX.second = std::numeric_limits<double>::min();
|
||||
m_axisRangeY.first = std::numeric_limits<double>::max();
|
||||
m_axisRangeY.second = std::numeric_limits<double>::min();
|
||||
}
|
||||
|
||||
|
||||
int SIM_PLOT_PAINTER::Draw( mglGraph* aGraph )
|
||||
{
|
||||
const std::vector<SIM_PLOT_PANEL::TRACE>& traces = m_parent->m_traces;
|
||||
const std::pair<double, double>& axisRangeX = m_parent->m_axisRangeX;
|
||||
const std::pair<double, double>& axisRangeY = m_parent->m_axisRangeY;
|
||||
|
||||
aGraph->Clf();
|
||||
//aGraph->SetPlotFactor( 1.5 );
|
||||
//aGraph->LoadFont( "termes" );
|
||||
aGraph->SetFontSize( 1.5 );
|
||||
|
||||
// Axis settings
|
||||
// Use autorange values if possible
|
||||
if( axisRangeX.first < axisRangeX.second )
|
||||
aGraph->SetRange( 'x', axisRangeX.first, axisRangeX.second );
|
||||
else
|
||||
aGraph->SetRange( 'x', 0, 1 );
|
||||
|
||||
if( axisRangeY.first < axisRangeY.second )
|
||||
{
|
||||
// Increase the Y axis range, so it is easy to read the extreme values
|
||||
double range = axisRangeY.second - axisRangeY.first;
|
||||
aGraph->SetRange( 'y', axisRangeY.first - 0.1 * range, axisRangeY.second + 0.1 * range );
|
||||
}
|
||||
else
|
||||
{
|
||||
aGraph->SetRange( 'y', 0, 1 );
|
||||
}
|
||||
|
||||
aGraph->Axis( "xy" );
|
||||
aGraph->Label( 'x', "Time [s]", 0 );
|
||||
aGraph->Label( 'y', "Voltage [V]", 0 );
|
||||
|
||||
aGraph->Box();
|
||||
aGraph->Grid();
|
||||
|
||||
// Draw traces
|
||||
for( auto t : traces )
|
||||
{
|
||||
aGraph->AddLegend( (const char*) t.title.c_str(), t.style );
|
||||
aGraph->Plot( t.y, t.style );
|
||||
}
|
||||
|
||||
if( traces.size() )
|
||||
{
|
||||
aGraph->SetFontSize( 2.5 );
|
||||
aGraph->Legend( 1, "-#" ); // legend entries horizontally + draw a box around legend
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
wxString SIM_PLOT_PAINTER::GenerateColor( COLOR_TYPE aType )
|
||||
{
|
||||
const char colors[] = "rgbcmylenupq";
|
||||
const unsigned int colorsNumber = sizeof( colors ) - 1;
|
||||
|
||||
// Safe defaults
|
||||
char color = 'k'; // black
|
||||
int shade = 5;
|
||||
|
||||
switch( aType )
|
||||
{
|
||||
case LIGHT:
|
||||
color = colors[m_lightColorIdx % colorsNumber];
|
||||
shade = 5 + m_lightColorIdx / colorsNumber;
|
||||
++m_lightColorIdx;
|
||||
|
||||
if( shade == 10 )
|
||||
{
|
||||
// Reached the color limit
|
||||
shade = 5;
|
||||
m_lightColorIdx = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case DARK:
|
||||
color = toupper( colors[m_darkColorIdx % colorsNumber] );
|
||||
shade = 5 - m_darkColorIdx / colorsNumber;
|
||||
++m_darkColorIdx;
|
||||
|
||||
if( shade == 0 )
|
||||
{
|
||||
// Reached the color limit
|
||||
shade = 5;
|
||||
m_darkColorIdx = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return wxString::Format( "{%c%d}", color, shade );
|
||||
/// @todo have a look at:
|
||||
/// http://stanford.edu/~mwaskom/software/seaborn/tutorial/color_palettes.html
|
||||
/// https://github.com/Gnuplotting/gnuplot-palettes
|
||||
|
||||
const unsigned long colors[] = { 0x000080, 0x008000, 0x800000, 0x008080, 0x800080, 0x808000, 0x808080 };
|
||||
|
||||
//const unsigned long colors[] = { 0xe3cea6, 0xb4781f, 0x8adfb2, 0x2ca033, 0x999afb, 0x1c1ae3, 0x6fbffd, 0x007fff, 0xd6b2ca, 0x9a3d6a };
|
||||
|
||||
// hls
|
||||
//const unsigned long colors[] = { 0x0f1689, 0x0f7289, 0x35890f, 0x0f8945, 0x89260f, 0x890f53, 0x89820f, 0x630f89 };
|
||||
|
||||
// pastels, good for dark background
|
||||
//const unsigned long colors[] = { 0x2fd8fe, 0x628dfa, 0x53d8a6, 0xa5c266, 0xb3b3b3, 0x94c3e4, 0xca9f8d, 0xac680e };
|
||||
|
||||
const unsigned int colorCount = sizeof(colors) / sizeof(unsigned long);
|
||||
|
||||
/// @todo generate shades to avoid repeating colors
|
||||
return wxColour( colors[m_colorIdx++ % colorCount] );
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2016 CERN
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -25,38 +26,9 @@
|
|||
#ifndef __SIM_PLOT_PANEL_H
|
||||
#define __SIM_PLOT_PANEL_H
|
||||
|
||||
#include "mgl2/wx.h"
|
||||
#include <widgets/mathplot.h>
|
||||
|
||||
class SIM_PLOT_PANEL;
|
||||
|
||||
class SIM_PLOT_PAINTER : public mglDraw
|
||||
{
|
||||
public:
|
||||
SIM_PLOT_PAINTER( const SIM_PLOT_PANEL* aParent )
|
||||
: m_parent( aParent ), m_lightColorIdx( 0 ), m_darkColorIdx( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
~SIM_PLOT_PAINTER()
|
||||
{
|
||||
}
|
||||
|
||||
//void Click() override;
|
||||
|
||||
int Draw( mglGraph* aGraph ) override;
|
||||
|
||||
enum COLOR_TYPE { LIGHT, DARK };
|
||||
|
||||
///> Generates a new, unique color for plotting curves
|
||||
wxString GenerateColor( COLOR_TYPE aType );
|
||||
|
||||
private:
|
||||
const SIM_PLOT_PANEL* m_parent;
|
||||
int m_lightColorIdx, m_darkColorIdx;
|
||||
};
|
||||
|
||||
|
||||
class SIM_PLOT_PANEL : public wxMathGL
|
||||
class SIM_PLOT_PANEL : public mpWindow
|
||||
{
|
||||
public:
|
||||
SIM_PLOT_PANEL( wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition,
|
||||
|
@ -64,33 +36,47 @@ public:
|
|||
|
||||
~SIM_PLOT_PANEL();
|
||||
|
||||
struct TRACE
|
||||
{
|
||||
wxString spiceName, title, style;
|
||||
mglData x, y;
|
||||
};
|
||||
|
||||
void AddTrace( const wxString& aSpiceName, const wxString& aTitle, int aPoints,
|
||||
double* aT, double* aY, int aFlags );
|
||||
const double* aT, const double* aY, int aFlags );
|
||||
|
||||
void DeleteTraces();
|
||||
|
||||
const std::vector<TRACE>& GetTraces() const
|
||||
class TRACE : public mpFXYVector
|
||||
{
|
||||
public:
|
||||
TRACE( const wxString& aTitle, const wxString& aSpiceName )
|
||||
: mpFXYVector( aTitle ), m_spiceName( aSpiceName )
|
||||
{
|
||||
SetContinuity( true );
|
||||
ShowName( false );
|
||||
}
|
||||
|
||||
const wxString& GetSpiceName() const
|
||||
{
|
||||
return m_spiceName;
|
||||
}
|
||||
|
||||
private:
|
||||
wxString m_spiceName;
|
||||
};
|
||||
|
||||
const std::vector<TRACE*>& GetTraces() const
|
||||
{
|
||||
return m_traces;
|
||||
}
|
||||
|
||||
void ResetAxisRanges();
|
||||
|
||||
private:
|
||||
SIM_PLOT_PAINTER m_painter;
|
||||
wxColour generateColor();
|
||||
|
||||
unsigned int m_colorIdx;
|
||||
|
||||
// Traces to be plotted
|
||||
std::vector<TRACE> m_traces;
|
||||
std::vector<TRACE*> m_traces;
|
||||
|
||||
// Axis ranges determined by the added traces data
|
||||
std::pair<double, double> m_axisRangeX, m_axisRangeY;
|
||||
|
||||
friend class SIM_PLOT_PAINTER;
|
||||
mpScaleX* m_axis_x;
|
||||
mpScaleY* m_axis_y;
|
||||
mpInfoLegend* m_legend;
|
||||
//mpInfoCoords* m_coords;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue