[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
2.1.3 Animation
Widget classes (mglWindow
, mglGLUT
) support a delayed drawing, when all plotting functions are called once at the beginning of writing to memory lists. Further program displays the saved lists faster. Resulting redrawing will be faster but it requires sufficient memory. Several lists (frames) can be displayed one after another (by pressing ‘,’, ‘.’) or run as cinema. To switch these feature on one needs to modify function sample
:
int sample(mglGraph *gr) { gr->NewFrame(); // the first frame gr->Rotate(60,40); gr->Box(); gr->EndFrame(); // end of the first frame gr->NewFrame(); // the second frame gr->Box(); gr->Axis("xy"); gr->EndFrame(); // end of the second frame return gr->GetNumFrame(); // returns the frame number }
First, the function creates a frame by calling NewFrame()
for rotated axes and draws the bounding box. The function EndFrame()
must be called after the frame drawing! The second frame contains the bounding box and axes Axis("xy")
in the initial (unrotated) coordinates. Function sample
returns the number of created frames GetNumFrame()
.
Note, that such kind of animation is rather slow and not well suitable for visualization of running calculations. For the last case one can use Update()
function. The most simple case for doing this is running yours calculations firstly in separate thread and later start MathGL window (QT or FLTK) creation.
#include <mgl2/window.h> mglWindow *gr=NULL; void *calc(void *) { mglPoint pnt; for(int i=0;i<10;i++) // do calculation { sleep(2); // which can be very long pnt = mglPoint(2*mgl_rnd()-1,2*mgl_rnd()-1); if(gr) // be sure that window is ready { gr->Clf(); // make new drawing gr->Line(mglPoint(),pnt,"Ar2"); char str[10] = "i=0"; str[2] = '0'+i; gr->Puts(mglPoint(),str); gr->Update(); // update window } } exit(0); } int main(int argc,char **argv) { static pthread_t thr; // first run yours routine in separate thread pthread_create(&thr,0,calc,0); pthread_detach(thr); gr = new mglWindow; gr->Run(); return 0; }
Note, that such method looks as not working for GLUT windows due to limitation of glutMainLoop()
function.
Another ways use built-in MathGL feature to run a member function mglDraw::Calc()
separate thread, which work only if pthread support is enabled. For this, you just need to use mglDraw
class and reimplement its Calc()
method.
#include <mgl2/window.h> class Foo : public mglDraw { mglPoint pnt; // some result of calculation public: mglWindow *Gr; // graphics to be updated int Draw(mglGraph *gr); void Calc(); } foo; //----------------------------------------------------- void Foo::Calc() { for(int i=0;i<30;i++) // do calculation { sleep(2); // which can be very long pnt = mglPoint(2*mgl_rnd()-1,2*mgl_rnd()-1); Gr->Update(); // update window } } //----------------------------------------------------- int Foo::Draw(mglGraph *gr) { gr->Line(mglPoint(),pnt,"Ar2"); gr->Box(); return 0; } //----------------------------------------------------- int main(int argc,char **argv) { mglWindow gr(&foo,"MathGL examples"); foo.Gr = &gr; foo.Run(); return gr.Run(); }
Finally, you can put the event-handling loop in separate instead of yours code by using RunThr()
function instead of Run()
one. Unfortunately, such method work well only for FLTK windows and only if pthread support was enabled. Such limitation come from the Qt requirement to be run in the primary thread only. The sample code will be:
#include <mgl2/fltk.h> int main(int argc,char **argv) { mglFLTK gr("test"); // create window gr.RunThr(); // run event loop in separate thread for(int i=0;i<10;i++) // do calculation { sleep(1); // which can be very long pnt = mglPoint(2*mgl_rnd()-1,2*mgl_rnd()-1); gr.Clf(); // make new drawing gr.Line(mglPoint(),pnt,"Ar2"); char str[10] = "i=0"; str[2] = '0'+i; gr.Puts(mglPoint(),str); gr.Update(); // update window when you need it } return 0; // finish calculations and close the window }
Pictures with animation can be saved in file(s) as well. You can: export in animated GIF, or save each frame in separate file (usually JPEG) and convert these files into the movie (for example, by help of ImageMagic). Let me show both methods.
The simplest methods is making animated GIF. There are 3 steps: (1) open GIF file by StartGIF()
function; (2) create the frames by calling NewFrame()
before and EndFrame()
after plotting; (3) close GIF by CloseGIF()
function. So the simplest code for “running” sinusoid will look like this:
#include <mgl2/mgl.h> int main(int ,char **) { mglGraph gr; mglData dat(100); char str[32]; gr.StartGIF("sample.gif"); for(int i=0;i<40;i++) { gr.NewFrame(); // start frame gr.Box(); // some plotting for(int j=0;j<dat.nx;j++) dat.a[j]=sin(M_PI*j/dat.nx+M_PI*0.05*i); gr.Plot(dat,"b"); gr.EndFrame(); // end frame } gr.CloseGIF(); return 0; }
The second way is saving each frame in separate file (usually JPEG) and later make the movie from them. MathGL have special function for saving frames – it is WriteFrame()
. This function save each frame with automatic name ‘frame0001.jpg, frame0002.jpg’ and so on. Here prefix ‘frame’ is defined by PlotId variable of mglGraph
class. So the similar code will look like this:
#include <mgl2/mgl.h> int main(int ,char **) { mglGraph gr; mglData dat(100); char str[32]; for(int i=0;i<40;i++) { gr.NewFrame(); // start frame gr.Box(); // some plotting for(int j=0;j<dat.nx;j++) dat.a[j]=sin(M_PI*j/dat.nx+M_PI*0.05*i); gr.Plot(dat,"b"); gr.EndFrame(); // end frame gr.WriteFrame(); // save frame } return 0; }
Created files can be converted to movie by help of a lot of programs. For example, you can use ImageMagic (command ‘convert frame*.jpg movie.mpg’), MPEG library, GIMP and so on.
Finally, you can use mglconv
tool for doing the same with MGL scripts (see section Utilities for parsing MGL).
[ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated on March 21, 2014 using texi2html 5.0.