Here is a toy program, in which some balls are bouncing in a box and repulsing each other with the electrostatic force, or by the Coulomb potential.
I do not know if the program is reasonably well written or very bad, but surely the line 10 in MyArea.cpp is ugly.
/* main.cpp */ #include <gtkmm/application.h> #include <gtkmm/window.h> #include "MyArea.h" #include "MyBall.h" int main(int argc, char** argv) { Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.example"); Gtk::Window window; window.set_title("Animation Test"); window.set_default_size(400, 400); MyArea area; window.add(area); area.show(); return app->run(window); }
/* MyArea.h */ #ifndef MYAREA_H_ #define MYAREA_H_ #include <gtkmm/drawingarea.h> class MyArea : public Gtk::DrawingArea { public: MyArea(); virtual ~MyArea(); protected: virtual bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr); bool on_timeout(); }; #endif /* MYAREA_H_ */
/* MyArea.cpp */ #include <vector> #include <cmath> #include <cairomm/context.h> #include <glibmm/main.h> #include "MyArea.h" #include "MyBall.h" using namespace std; vector<MyBall> particle(4); MyArea::MyArea() { Glib::signal_timeout().connect( sigc::mem_fun(*this, &MyArea::on_timeout), 10 ); for(unsigned int i=0;i<particle.size();i++) { double center = (0 + particle.size() - 1) / 2.0; double f = (i-center) / particle.size(); particle[i].Set(0.04, 1.0, f+0.5, 0.8*f, -0.4, 0.0, 0.001*f); } } MyArea::~MyArea() { } void Force(MyBall& b1, MyBall& b2) { double x1 = b1.Getx(); double y1 = b1.Gety(); double x2 = b2.Getx(); double y2 = b2.Gety(); double dist_sq = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); double dist = sqrt(dist_sq); double force = 0.000001 / dist_sq; double force_x = -force * (x2 - x1) / dist; double force_y = -force * (y2 - y1) / dist; b1.Changevx( force_x); b2.Changevx(-force_x); b1.Changevy( force_y); b2.Changevy(-force_y); } bool MyArea::on_timeout() { static int count = 0; if(count++ % 5 == 0) { get_window()->invalidate(true); } for(unsigned int i=0;i<particle.size();i++) { for(unsigned int j=0;j<particle.size();j++) { if(i != j) Force(particle[i], particle[j]); } } for(unsigned int i=0;i<particle.size();i++) { particle[i].Move(); } return true; } bool MyArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) { Gtk::Allocation allocation = get_allocation(); const int width = allocation.get_width(); const int height = allocation.get_height(); cr->scale(width, height); cr->translate(0.5, 0.5); cr->set_source_rgba(0.9, 0.9, 0.8, 1.0); cr->paint(); for(unsigned int i=0;i<particle.size();i++) { particle[i].Display(cr); } return true; }
/* MyBall.h */ #ifndef MYBALL_H_ #define MYBALL_H_ #include <cairomm/context.h> class MyBall { public: MyBall (); MyBall (double, double, double, double, double, double); virtual ~MyBall (); void Set (double, double, double, double, double, double); void Display(const Cairo::RefPtr<Cairo::Context>&); double Getx() const; double Gety() const; double Getw() const; void Changevx(double); void Changevy(double); void Move(); private: double m_r; double m_c; double m_x; double m_y; double m_vx; double m_vy; }; #endif /* MYBALL_H_ */
/* MyBall.cpp */ #include <cairomm/context.h> #include "MyBall.h" MyBall::MyBall() : m_r {0.1}, m_c {0.5}, m_x {0.0}, m_y {0.0}, m_vx {0.0}, m_vy {0.0} { } MyBall::~MyBall() { } double MyBall::Getx() const { return m_x; } double MyBall::Gety() const { return m_y; } void MyBall::Changevx(double v) { m_vx += v; } void MyBall::Changevy(double v) { m_vy += v; } void MyBall::Display(const Cairo::RefPtr<Cairo::Context>& cr) { cr->arc(m_x, m_y, m_r, 0.0, 2.0*M_PI); cr->set_source_rgba(0.0, m_c, 1.0-m_c, 1.0); cr->fill_preserve(); cr->set_source_rgba(0.0, 0.0, 0.0, 1.0); cr->set_line_width(0.01); cr->stroke(); } void MyBall::Move() { if(m_x>0.5 || m_x<-0.5) { m_vx = -m_vx; } if(m_y>0.5 || m_y<-0.5) { m_vy = -m_vy; } m_x += m_vx; m_y += m_vy; } void MyBall::Set(double r, double c, double x, double y, double vx, double vy) { m_r = r; m_c = c; m_x = x; m_y = y; m_vx = vx; m_vy = vy; }