//円(電荷)を任意で追加し、それらをクーロンの法則に基づいて動かす
#include <FL/Fl.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Window.H>
#include "../../../std_lib_facilities.h"
#include "../../../Point.h"
#include "../../../Graph.h"
#include "../../../GUI.h"
#include "../../../Simple_window.h"
#include "../../../Window.h"
using namespace Graph_lib;
struct dx_dy {
double dx;
double dy;
dx_dy(double xx, double yy) : dx(xx) ,dy(yy) {}
dx_dy() : dx(0), dy(0) {}
};
struct Coulomb_window :Window{
Coulomb_window(Point xy, int w, int h, const string& title );
int i;
double k,dx,dy; //k=定数,dx=x軸方向の移動距離の合計
char c;
private:
Graph_lib::Rectangle rect;
vector<int> vec; //正負(大きさ)
Vector_ref<Circle> vcircle; //円
vector<dx_dy> vdx_dy; //移動距離x,y
Button add_button; //円を追加
Button start_button; //円を動かし始める
Button quit_button; //終了
Button reset_button; //ヴェクタなどのリセット
In_box add_x; //追加する円の中心のx座標
In_box add_y;
In_box ec; //正負(大きさ)
static void cb_add(Address,Address);
void add();
static void cb_start(Address,Address);
void start();
static void cb_quit(Address,Address);
void quit();
static void cb_reset(Address,Address);
void reset();
void Calculation_of_power();
};
Coulomb_window::Coulomb_window(Point xy, int w, int h, const string& title )
:Window(xy,w,h,title),
rect(Point(0,30),600,400), //背景を白く
add_button(Point(x_max()-100,5),40,20,"add",cb_add),
start_button(Point(x_max()-150,5),40,20,"start",cb_start),
quit_button(Point(x_max()-50,5),40,20,"quit",cb_quit),
reset_button(Point(x_max()-200,5),40,20,"reset",cb_reset),
add_x(Point(x_max()-360,5),50,20,"add x:"),
add_y(Point(x_max()-260,5),50,20,"add y:"),
ec(Point(x_max()-460,5),50,20,"ec:")
{
k = 1;
rect.set_fill_color(Color::white);
rect.set_color(Color::invisible);
attach(rect);
attach(add_button);
attach(start_button);
attach(quit_button);
attach(reset_button);
attach(add_x);
attach(add_y);
attach(ec);
}
//dx_dyクラス同士の足し算
dx_dy operator+(const dx_dy& dd1, const dx_dy& dd2)
{
dx_dy dxdy = dx_dy(dd1.dx + dd2.dx, dd1.dy + dd2.dy);
return dxdy;
}
//移動距離の計算
void Coulomb_window::Calculation_of_power()
{
int n,l;
for(n = 0; n < vec.size(); ++n){
dx,dy = 0;
for(l = 0; l < vec.size(); ++l){
double f, xx, yy, s_x, s_y = 0; // f=力, s_x=2点間のx軸方向の相対距離, xx=x軸方向の移動距離, k=定数
s_x = vcircle[n].center().x - vcircle[l].center().x; //2つの円の中心を読み取り、s_x,x_yを求める
s_y = vcircle[n].center().y - vcircle[l].center().y;
f = (vec[n] * vec[l] * k)/(pow(s_x,2) + pow(s_y,2));
xx = f * k * sqrt(pow(s_x,2) / (pow(s_x,2) + pow(s_y,2)));
yy = sqrt(pow(f,2) - pow(xx,2));
if(vec[n] * vec[l] > 0){ //正の場合と負の場合の動きの違い
if(s_x<0){
xx = (-1) * xx;
}else if(s_y<0){
yy = (-1) * yy;
}
}else if(vec[n] * vec[l] < 0){
if(s_x>0){
xx = (-1) * xx;
}else if(s_y>0){
yy = (-1) * yy;
}
}
dx = xx + dx;
dy = yy + dy;
}
dx_dy dxy(dx,dy);
vdx_dy[n] = dxy + vdx_dy[n];
}
};
//ボタンが押され、add()の呼び出し
void Coulomb_window::cb_add(Address,Address pw)
{
reference_to<Coulomb_window>(pw).add();
};
//円を追加する
void Coulomb_window::add()
{
int ax = add_x.get_int();
int ay = add_y.get_int();
int cec = ec.get_int(); //正負(大きさ)
vec.push_back(cec);
vcircle.push_back(new Circle(Point(ax,ay),10));
int m;
for(m=0; m < vcircle.size(); ++m)
{
if(vec[m]>0){ //正であれば赤い円、負であれば青い円を描く
vcircle[m].set_fill_color(Color::red); //塗りつぶす
vcircle[m].set_color(Color::invisible); //輪郭線を消す
attach(vcircle[m]);
}else if(vec[m]<0){
vcircle[m].set_fill_color(Color::blue);
vcircle[m].set_color(Color::invisible);
attach(vcircle[m]);
}
}
redraw();
};
void Coulomb_window::cb_start(Address,Address pw)
{
reference_to<Coulomb_window>(pw).start();
};
//円を動かす
void Coulomb_window::start()
{
char c;
while(1){ //qキーが押されるまで円を動かし続ける
c = cin.peek();
if(c=='q') {
c = '0';
break; //ループを抜けて再び円を追加できる状態へ戻す
}
Calculation_of_power();
for (int h = 0; h < vdx_dy.size(); ++h)
{
int a,b = 0;
a = (int)(vdx_dy[h].dx + 0.5); //小数点以下は切り上げ、doubleからintへ
a = (vdx_dy[h].dx - (double)a) ? a+1 : a;
b = (int)(vdx_dy[h].dy + 0.5);
b = (vdx_dy[h].dy - (double)b) ? b+1 : b;
vcircle[h].move(a,b);
}
}
}
void Coulomb_window::cb_quit(Address,Address pw)
{
reference_to<Coulomb_window>(pw).quit();
};
//終了する
void Coulomb_window::quit()
{
hide();
};
void Coulomb_window::cb_reset(Address,Address pw)
{
reference_to<Coulomb_window>(pw).reset();
};
//ヴェクタを消去し、初期状態にする
void Coulomb_window::reset()
{
for(int q = 0; q < vec.size(); ++q)
{
detach((vcircle)[q]);
}
delete &vcircle;
vec.clear();
vdx_dy.clear();
};
int main()
try{
Coulomb_window win(Point(100,100),600,400,"Coulomb's_law");
return gui_main();
}
catch(exception& e) {
cerr << "exception: " << e.what() << '\n';
return 1;
}
catch (...) {
cerr << "some exception\n";
return 2;
}