/* exercise08.c : 教科書 2-19 参照 */ /* compile: cc -o exercise08 exercise08.c -g -O2 -Wall -lglfw -lGLU -lGL -lX11 -lXrandr -lm */ #include #include #include #include typedef struct Ball{ double x, y; /* ボールの中心位置 */ double vx, vy; /* ボールの移動速度 */ double r; /* ボールの半径 */ double mass; }ball; /* 円を描画する */ void circle(double x, double y, double r) { int const N = 24; /* 円周を 24分割して線分で描画することにする */ int i; glBegin(GL_LINE_LOOP); for (i = 0; i < N; i++) glVertex2d(x + cos(2 * M_PI * i / N) * r, y + sin(2 * M_PI * i / N) * r); glEnd(); } double dist(ball b1, ball b2, double* rx, double* ry){ *rx = (b2.x - b1.x); *ry = (b2.y - b1.y); return sqrt( (*rx)*(*rx) + (*ry)*(*ry) ); } double dist2(ball b1, ball b2){ return (b1.x-b2.x)*(b1.x-b2.x) + (b1.y-b2.y)*(b1.y-b2.y) ; } double calc_f(ball b1, ball b2, double* fx, double* fy){ double r, rx, ry; double G=10; r = dist(b1, b2, &rx, &ry); *fx = (G*b1.mass*b2.mass / (r*r)) * (rx/r); *fy = (G*b1.mass*b2.mass / (r*r)) * (ry/r); return sqrt( (*fx)*(*fx) + (*fy)*(*fy) ); } int main(void) { ball Ball[5]; int i, j; //double restitution = 0.99; /* はねかえり係数 */ int width = 640, height = 400; /* ウィンドウのサイズ */ Ball[0].x = 0; Ball[0].y = 0; Ball[0].vx = 0.0; Ball[0].vy = 0.0; Ball[0].r = 10.0; Ball[0].mass = 100.0; Ball[1].x = 70; Ball[1].y = 0; Ball[1].vx = 0.0; Ball[1].vy = 5.0; Ball[1].r = 2.0; Ball[1].mass = 1.0; Ball[2].x = 100; Ball[2].y = 0; Ball[2].vx = 0.0; Ball[2].vy = 3.5; Ball[2].r = 4.0; Ball[2].mass = 2.0; Ball[3].x = 0; Ball[3].y = 80; Ball[3].vx = -3.5; Ball[3].vy = 0.0; Ball[3].r = 2.0; Ball[3].mass = 1.0; Ball[4].x = 0; Ball[4].y = 120; Ball[4].vx = 2.0; Ball[4].vy = 0.0; Ball[4].r = 4.0; Ball[4].mass = 2.0; /* グラフィック環境を初期化して、ウィンドウを開く */ glfwInit(); glfwOpenWindow(width, height, 0, 0, 0, 0, 0, 0, GLFW_WINDOW); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* 投影以外の座標変換は行わない */ glScaled(2,2,2); glRotated(60,1,0,0); glRotated(60,0,0,1); for (;;) { /* Esc が押されるかウィンドウが閉じられたらおしまい */ if (glfwGetKey(GLFW_KEY_ESC) || !glfwGetWindowParam(GLFW_OPENED)) break; glfwGetWindowSize(&width, &height); /* 現在のウィンドウサイズを取得する */ glViewport(0, 0, width, height); /* ウィンドウ全面をビューポートにする */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-200, 200, -200, 200, -200.0, 200.0); /* この範囲の空間をビューポートに投影する */ glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); /* バックバッファを黒で塗り潰す */ //X-axis glColor3d(1, 0, 0); glBegin(GL_LINES); glVertex3d(-100,0,0); glVertex3d(100,0,0); glEnd(); //Y-axis glColor3d(0, 1, 0); glBegin(GL_LINES); glVertex3d(0,-100,0); glVertex3d(0,100,0); glEnd(); //Z-axis glColor3d(0, 0, 1); glBegin(GL_LINES); glVertex3d(0,0, -100); glVertex3d(0,0, 100); glEnd(); for(i=0; i<5; i++){ /* ウィンドウのサイズが変更されても、ボールがウィンドウ外に出ていかないようにする */ Ball[i].x = fminl(Ball[i].x, width - Ball[i].r); Ball[i].y = fminl(Ball[i].y, height - Ball[i].r); for(j=i+1; j<5; j++){ double fx, fy; calc_f(Ball[i], Ball[j], &fx, &fy); //printf("%d %d %lf %lf\n", i, j, fx, fy); Ball[i].vx += fx/Ball[i].mass; Ball[i].vy += fy/Ball[i].mass; Ball[j].vx -= fx/Ball[j].mass; Ball[j].vy -= fy/Ball[j].mass; } } for(i=0; i<5; i++){ /* ボールを移動 */ Ball[i].x += Ball[i].vx; Ball[i].y += Ball[i].vy; /* ウィンドウの上下左右の端にぶつかったらバウンド */ /* if (Ball[i].x <= Ball[i].r || Ball[i].x >= width - Ball[i].r) Ball[i].vx = -restitution*Ball[i].vx; if (Ball[i].y <= Ball[i].r || Ball[i].y >= height - Ball[i].r) Ball[i].vy = -restitution*Ball[i].vy; */ glColor3d(1.0, 1.0, 1.0); circle(Ball[i].x, Ball[i].y, Ball[i].r); /* ボールを描く */ } // printf("%lf %lf %lf %lf\n",Ball[0].x, Ball[0].y, Ball[0].vx, Ball[0].vy); glfwSwapBuffers(); /* フロントバッファとバックバッファを入れ替える */ usleep(10 * 1000); /* 40ミリ秒くらい時間待ち */ } glfwTerminate(); /* ウィンドウを閉じる */ return 0; }