Created
September 24, 2017 20:08
-
-
Save JamesBremner/d7d2f19a1ac73ffa34e1acd44cfae878 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <nana/gui.hpp> | |
namespace nana | |
{ | |
namespace plot | |
{ | |
class plot; | |
class trace | |
{ | |
public: | |
/// set data | |
void add( const std::vector< double >& y ) | |
{ | |
myY = y; | |
} | |
/// set color | |
void color( const colors & clr ) | |
{ | |
myColor = clr; | |
} | |
int size() | |
{ | |
return (int) myY.size(); | |
} | |
void bounds( int& min, int& max ) | |
{ | |
min = myY[0]; | |
max = min; | |
for( auto y : myY ) | |
{ | |
if( y < min ) | |
min = y; | |
if( y > max ) | |
max = y; | |
} | |
} | |
/// draw | |
void update( window wd, plot* p ); | |
private: | |
std::vector< double > myY; | |
colors myColor; | |
}; | |
/** 2D plotting */ | |
class plot | |
{ | |
public: | |
/** CTOR | |
@param[in parent window where plot will be drawn | |
*/ | |
plot( window parent ) | |
: myParent( parent ) | |
{ | |
} | |
/** Add a data trace | |
@param[in] t the data trace to be added | |
*/ | |
void add( trace& t ) | |
{ | |
myTrace.push_back( t ); | |
} | |
int xinc() | |
{ | |
return myXinc; | |
} | |
int minY() | |
{ | |
return myMinY; | |
} | |
int ymax() | |
{ | |
return myMaxY; | |
} | |
double Scale() | |
{ | |
return myScale; | |
} | |
int YOffset() | |
{ | |
return myYOffset; | |
} | |
/** Draw the plot */ | |
void Update() | |
{ | |
CalcScale(); | |
for( auto& t : myTrace ) | |
t.update( myParent, this ); | |
} | |
private: | |
///window where plot will be drawn | |
window myParent; | |
/// plot traces | |
std::vector< trace > myTrace; | |
int myXinc; | |
int myMinY, myMaxY; | |
double myScale; | |
int myYOffset; | |
void CalcScale() | |
{ | |
int maxCount = 0; | |
myTrace[0].bounds( myMinY, myMaxY ); | |
for( auto& t : myTrace ) { | |
if( t.size() > maxCount ) | |
maxCount = t.size(); | |
int min, max; | |
t.bounds( min, max ); | |
if( min < myMinY ) | |
myMinY = min; | |
if( max > myMaxY ) | |
myMaxY = max; | |
} | |
myXinc = 300 / maxCount; | |
myScale = 200 / ( myMaxY - myMinY ); | |
myYOffset = 200 + myScale * myMinY; | |
} | |
}; | |
void trace::update( window wd, plot * p ) | |
{ | |
drawing drw( wd ); | |
drw.draw([this,p](paint::graphics& graph) | |
{ | |
bool first = true; | |
int x = 0; | |
int xinc = p->xinc(); | |
double s = p->Scale(); | |
int yOffset = p->YOffset(); | |
int prev; | |
for( auto y : myY ) | |
{ | |
if( first ) | |
{ | |
first = false; | |
prev = y; | |
continue; | |
} | |
graph.line( | |
point(x, yOffset - prev * s), | |
point(x+xinc, yOffset - y * s), | |
myColor); | |
x += xinc; | |
prev = y; | |
} | |
}); | |
drw.update(); | |
} | |
} | |
} | |
int main() | |
{ | |
using namespace nana; | |
try | |
{ | |
form fm; | |
// construct plot to be drawn on form | |
plot::plot thePlot( fm ); | |
// construct first plot trace | |
plot::trace t1; | |
// provide some data to trace | |
std::vector< double > d1 { 10, 15, 20, 25, 30, 25, 20, 15, 10 }; | |
t1.add( d1 ); | |
// plot in blue | |
t1.color( colors::blue ); | |
// add to plot | |
thePlot.add( t1 ); | |
// construct second trace | |
plot::trace t2; | |
// provide data | |
std::vector< double > d2 { 20, 30, 40, 50, 60, 50, 40, 30, 20 }; | |
t2.add( d2 ); | |
// plot in red | |
t2.color( colors::red ); | |
// add to plot | |
thePlot.add( t2 ); | |
// update the plot | |
thePlot.Update(); | |
fm.show(); | |
exec(); | |
} | |
catch( std::runtime_error& e ) | |
{ | |
msgbox mb( e.what() ); | |
mb(); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment