Another module for drawing graphs

Fifteen years ago, it took me to display a graph in my diploma program. There would be a program in Builder or Delphi, everything would be fine, but I only wrote for Windows in MFC, and there it is somehow not very good with graph classes. And then I wrote my own plotting module. Three five years have passed, but the module remained, was redesigned and I sometimes use it in my crafts in QNX, Linux and Windows. Perhaps it will be useful to you in some way.



The presented graph drawing module allows you to display an arbitrary number of colored graphs with a legend. The number of points in the graphs can be tens of millions or more (if only there is enough memory) without a significant decrease in the speed of redrawing, since each time the scale is changed, a set of points is built, displayed on the screen, taking into account the scale. Thus, the number of points only affects the recalculation time of these displayed points when changing the scale.



Rasterization functions have been moved to plug-in classes. In total, three options are currently possible: drawing with standard Windows-GUI functions from MFC (CVideo_Windows class), drawing with standard Qt functions (CVideo_Qt class) and software rasterization (CVideo_Software class - with revision this module can be used on microcontrollers). Transcoding of characters into the format required for rasterization classes is performed by the CTranslator class.



Separate classes include line types (if the type is supported by the rasterization class), colors, points, rectangles.



By holding down the left mouse button, you can move around the chart field. With the right button you can set the selected area, by clicking on which with the right mouse button you will return to the specified initial scale, and after clicking with the left button, the enlargement operation will be performed.



Drawn graphs look like this:







Creating a graph class, for example, for Windows in MFC, is done as follows:



 CWnd_Graphics cWnd_Graphics;// 
 CGrData *cGrData_SinPtr;//    
 CGrData *cGrData_CosPtr;//    

// 
CRect cRect_Client;
((CStatic*)GetDlgItem(IDC_STATIC_MAIN_MAP))->GetClientRect(&cRect_Client);
cWnd_Graphics.Create(WS_VISIBLE,cRect_Client,(CStatic*)GetDlgItem(IDC_STATIC_MAIN_MAP));
 	
 // 
 cWnd_Graphics.GetIGraphicsPtr()->SetBackGroundColor(CGrColor(192,192,192));
 cWnd_Graphics.GetIGraphicsPtr()->SetLegendBackGroundColor(CGrColor(230,230,230));
 cWnd_Graphics.GetIGraphicsPtr()->SetAxisColor(CGrColor(0,0,0),CGrColor(0,0,0));
 cWnd_Graphics.GetIGraphicsPtr()->SetTextValueColor(CGrColor(0,0,0),CGrColor(0,0,0),CGrColor(0,0,0));
 cWnd_Graphics.GetIGraphicsPtr()->SetSelectRectangleColor(CGrColor(0,0,255)); 
 cWnd_Graphics.GetIGraphicsPtr()->SetName(" ");
 // 
 cGrData_SinPtr=cWnd_Graphics.GetIGraphicsPtr()->AddNewGraphic();
 cGrData_SinPtr->SetEnable(true);
 cGrData_SinPtr->SetGrColor(CGrColor(255,0,0));
 cGrData_SinPtr->SetGrLineStyle(CGrLineStyle(IVideo::LINE_TYPE_SOLID,1,false,false));
 cGrData_SinPtr->SetName(" ");
 
 for(size_t n=0;n<1024;n++)
 {
  double x=n;
  double y=sin(x*0.01);
  cGrData_SinPtr->AddPoint(x,y);
 }

 cGrData_CosPtr=cWnd_Graphics.GetIGraphicsPtr()->AddNewGraphic();
 cGrData_CosPtr->SetEnable(true);
 cGrData_CosPtr->SetGrColor(CGrColor(0,0,255));
 cGrData_CosPtr->SetGrLineStyle(CGrLineStyle(IVideo::LINE_TYPE_SOLID,3,false,false));
 cGrData_CosPtr->SetName(" ");

 for(size_t n=0;n<1024;n++)
 {
  double x=n;
  double y=cos(x*0.01);
  cGrData_CosPtr->AddPoint(x,y);
 }

 // ,    
 CGrRect cGrRect;
 cWnd_Graphics.GetIGraphicsPtr()->FindViewRectangle(cGrRect);
 cWnd_Graphics.GetIGraphicsPtr()->SetRectangle(cGrRect);
 cWnd_Graphics.GetIGraphicsPtr()->OnMagnify();
 cWnd_Graphics.GetIGraphicsPtr()->GetRectangle(cGrRect);
 cWnd_Graphics.GetIGraphicsPtr()->SetOriginalScale(cGrRect);

      
      





Here, the cWnd_Graphics class provides a binding of the CGraphics graphics class with Windows, forwarding events that occur on Windows to the CGraphics class and providing the display of the graph in the ON_WM_PAINT redraw event. For other OSes, this bundle will need to be rewritten, taking into account the OS used. In this example, through cWnd_Graphics.GetIGraphicsPtr (), you can directly access the CGraphics chart class and configure the chart display parameters, as well as ask the chart class to create a new chart and return the AddNewGraphic pointer to it (a pointer to the CGrData class will be obtained). You cannot delete this pointer yourself - the chart can be deleted only through the DeleteGraphic function. In the future, work with the schedule is performed through the resulting pointer.



In total, the following chart management functions are available:



CGrData* AddNewGraphic(void);//       
  void DeleteAllGraphics(void);//    
  void DeleteGraphic(CGrData *cGrDataPtr);//   
  void FindRectangle(CGrRect &cGrRect) const;//     
  void FindRectangleOfEndPoints(CGrRect &cGrRect,size_t points) const;//        points 
  void FindRectangleOfEndTime(CGrRect &cGrRect,long double time) const;//        time 
  void FindViewRectangle(CGrRect &cGrRect) const;//         
  void FindViewRectangleOfEndPoints(CGrRect &cGrRect,size_t points) const;//            points 
  void FindViewRectangleOfEndTime(CGrRect &cGrRect,long double time) const;//            time 
  void SetTimeDivider(double value);//  
  double GetTimeDivider(void) const;//  
  // 
  void CancelSelect(void);// 
  void Redraw(void);// 
  void RedrawAll(void);// 
  void OnOriginalScale(void);//    
  //  
  void SetBackGroundColor(const CGrColor &cGrColor);//  
  void SetLegendBackGroundColor(const CGrColor &cGrColor);//   
  void SetAxisColor(const CGrColor &cGrColor_AxisX,const CGrColor &cGrColor_AxisY);//  
  void SetGridColor(const CGrColor &cGrColor_GridX,const CGrColor &cGrColor_GridY);//  
  void SetSelectRectangleColor(const CGrColor &cGrColor);//   
  void SetTextValueColor(const CGrColor &cGrColor_TextX,const CGrColor &cGrColor_TextY,const CGrColor &cGrColor_TextLegend);//  
  //   
  void SetAxisLineStyle(const CGrLineStyle &cGrLineStyle_AxisX,const CGrLineStyle &cGrLineStyle_AxisY);//  
  void SetGridLineStyle(const CGrLineStyle &cGrLineStyle_GridX,const CGrLineStyle &cGrLineStyle_GridY);//  
  //   
  void SetRectangle(const CGrRect &cGrRect);//   
  void SetGridStep(long double step_x,long double step_y);//  
  void GetRectangle(CGrRect &cGrRect) const;//   
  void GetGridSize(long double &step_x,long double &step_y) const;//   
  //  
  void SetEnableMagnify(bool enable);// 
  void SetEnableValue(bool x_value,bool y_value);//  
  void SetOriginalScale(const CGrRect &cGrRect);//  
  void SetMoveMode(bool inversion);//   
  bool GetSelectedRectangle(CGrRect &cGrRect) const;//  
  void GetClientRectangle(CGrRect &cGrRect) const;//  
  void SetName(const std::string &name);//  
  bool GetUserMode(void) const;//   
  void SetUserMode(bool state);//   

      
      





In principle, you can customize the display quite flexibly.



The user control mode specified in the last two functions is used when outputting data with updates (say, the instrument adds points at some frequency). In this case, when you try to move / enlarge the graph, the user control mode is enabled, and when you return to the original scale, this mode is disabled. This allows you to stop changing the scale while adding data (if the mode is enabled, then you simply do not need to call the recalculation of the scale, as in the example above).



An example of a program using this module (there are sources of the module).

There are 4 files from the project - main.cpp, cdialog_main.h, cdialog_main.cpp and stdafx.h. These four files contain an example of connecting the plotting module. All other source files are parts of the plotting module.



Well, that's actually all that can be said about this primitive craft.

PS I was prompted here that I had an unfortunate name for the functions (Graph - graph, and Graphic - graphics). Sorry, I learned German and thought that in English it would be like this. :)



All Articles