計算数理A演習第3回

第3回


今週は先週の続きを行います。

各自続きから始めるようにしてください。


直線の描画

g_move 関数g_plot 関数を用いると直線を描くことができます。
g_move 関数で直線の始点を指定し、g_plot 関数で直線の終点を指定します。
また、g_line_color 関数で、直線の色を指定でき、g_line_width 関数で直線の幅を指定できます(それぞれマニュアル参照)。(0418-0.c)

#include <glsc.h>
#include <stdio.h>

int main()
{
    g_init("GRAPH", 100.0, 100.0);
    g_device(G_DISP);

    g_def_scale(1, -1.0, 1.0, -1.0, 1.0, 10.0, 10.0, 80.0, 80.0);

    g_sel_scale(1);
    g_area_color(G_BLUE);
    g_line_color(G_BLUE);
    g_circle(0.0, 0.0, 0.5, G_YES, G_YES);

    g_line_color(G_YELLOW);
    g_line_width(3);
    g_move(-1.0, -1.0);
    g_plot(1.0, 1.0);

    g_line_color(G_BLACK);
    g_line_width(1);
    g_move(-1.0, 1.0);
    g_plot(1.0, -1.0);

    g_sleep(G_STOP);
    g_term();

    return 0;
}

g_plot を連続してプログラム中に書くと、連続した直線を描く事ができます。
直前のプログラムの2つめの g_move を消去した次のプログラムでは、次のような結果となります(実際に2つめの g_move 関数を消去して試してみよ)。

つまり、直前の g_plot 関数で指定された座標を始点とする直線が引かれます。


y = sin(x) のグラフの描画

これから、GLSCを使って$y=\sin(x)$ のグラフを描きます。
実際には$y=\sin(x)$ のグラフは滑らかな曲線ですが、コンピュータではそのような滑らかな曲線を直接は扱えませんので折れ線で近似します。
つまり、変数$x$ は、実際には連続的に変化するものですが、とびとびの値を使います。
後の例で見るように、とびとびとはいえ、十分に細かく取れば、折れ線で曲線をうまく近似することができます。

図のように$[0, L]$区間を$N-1$等分して、その等分した小区間の幅を$dx$とします。
$N-1$等分すると図のように$N$個の区切りが現れますが、それらに$0, 1, \cdots, i, \cdots, N-1$と番号をつけることにします。
また、 $N$分割数$dx$分割幅と呼びます。このとき、

    $$X_i=i*dx$$

の部分についてそれぞれ$y=\sin(X_i)$を計算し、それらを折れ線で結ぶことを考えます。
C言語風に書けば

X[i] = dx*i;
Y[i] = sin(X[i]);

をそれぞれ求め、(X[0], Y[0]), (X[1],Y[1]), …., (X[N-1], Y[N-1]) を結ぶ折れ線を描くことになります。
これをプログラムにすると次のようになります。(上記の説明にあわせるためにかなり無駄なことをしています。)
ファイル名を 0418-1.c として打ち込み、実行してみてください。

注意: 数学関数(sin, cos, tan 等)を使う場合には #include <math.h> が必要となります。

#include <glsc.h>
#include <stdio.h>
/* 次の文は数学関数を使う場合に必要 */
#include <math.h>

/* 定数の定義 */
#define N (5)
#define PI (3.1415926)
#define L (2*PI)

int main()
{
    int i;
    double X[N], Y[N], dx;

    /* dx を求める */
    dx = L/(N - 1);

    /* GLSCの初期化および仮想座標系の定義 */
    g_init("GRAPH", 200.0, 100.0);
    g_device(G_DISP);

    g_def_scale(1, 0.0, L, -1.0, 1.0, 10.0, 10.0, 180.0, 80.0);

    /* 外枠の描画 */
    g_sel_scale(1);
    g_area_color(G_WHITE);
    g_line_color(G_BLACK);
    g_line_width(2);
    g_box(0.0, L, -1.0, 1.0, G_YES, G_YES);
    g_move(0.0, 0.0);
    g_plot(L, 0.0);

    /* X[i] を求める */
    for(i = 0; i < N; i++)
    {
        X[i] = i*dx;
    }

    /* Y[i] を求める */
    for(i = 0; i < N; i++)
    {
        Y[i] = sin(X[i]);
    }

    /* 折れ線の種類を設定 */
    g_line_color(G_RED);
    g_line_type(G_LINE_SOLID);
    g_line_width(2);

    /* 折れ線を描く */
    g_move(X[0], Y[0]);
    for(i = 1; i < N; i++)
    {
        g_plot(X[i], Y[i]);
    }

    g_sleep(G_STOP);
    g_term();

    return 0;
}

上記プログラムに、グラフの左端右端等の情報を書き入れたプログラムの出力を使って、$N$とグラフの関係を見てみましょう。
青色の破線で書かれたグラフが描きたいグラフ ($y=\sin(x)$ )です(とはいっても、もちろんこれも$N=100$ の折れ線です)。赤色の実線が描こうとしている折れ線です。

$N=5$の場合は次のようになります(赤線)。これでは、まったく$y=\sin(x)$ のグラフには見えません。

 

つづいて、$N=10$の場合(赤線)。曲線っぽくみえてきました。

 

$N=50$の場合(赤線)。見た目はほぼ$y=\sin(x)$のグラフに見えます。

 


課題2

上のサンプルプログラム(0418-1.c)を表示例のように表示するプログラムに変更せよ。
(グラフの左端等の表示と$N=100$のグラフを重ねて表示するように変更)

ヒント: Y[N] とは別に Y0[100] という配列を作って、それぞれを異なる線種で描く。また、文字列の描画(その2)で説明した手法を用いてタイトル部分を書くと良い。(注意:g_text 関数の最初の2つの引数(座標は)標準座標系での値になります.)


課題3

$y=3\cos(0.5x)$のグラフを$[-2\pi, 4\pi]$の範囲で描け。滑らかに見えるように、適度に$N$を調整すること. また、適度な大きさの「丸」を使った点描画でのグラフも描け.


\Large{$y=\sin(x+t)$}のグラフのアニメーション

すでに、アニメーションの作り方を知っているので簡単です。ただし、いま$t$は時間として扱いますが、当然連続量として扱うことができないので、$x$同様とびとびの値として扱います。先ほどの$x$と同様に考え、$t$の範囲を$[0, T]$として、それを$k-1$等分します。その小区間の幅を$dt$として(つまり、$dt=T/(k-1)$)、

$T_k=k\cdot dt$

とすることにより、$T_k$を止めるごとに Y[i] = sin(Xi + Tk) のグラフを描くことを繰り返せば、アニメーションとなります。次のサンプルプログラムを 0418-2.c として打ち込み実行してみてください。これまでのアニメーションプログラムと仕組みが同じであることに気づくことが重要です。


課題4

上のアニメーションのプログラムで$N$を 5 にするとどうなるか?やってみよ。(好きな方法で構いません.)


課題5

課題3のプログラムにグラフの左端等の情報を表示する部分を追加せよ。


課題6

$0.5(\sin (x+t) + \sin (x-t))$ のアニメーションを作成せよ。


課題7

$\sin (x+t) + \sin (x-t)$のアニメーションを作成せよ。