第2回、第3回、第4回(2011年4月20日、4月27日、5月11日)


今週および来週の演習

 今日はGLSCグラフィックライブラリの使い方について紹介します。

 第2回、第3回(、第4回)で、GLSCの使い方をマスターしてもらいます。進み方としては、

を予定しています。早く進みたい人は、どんどん先に進んでかまいません。


4月20日分


GLSCとは

 GLSCは(Graphic Library for Scientific Computing)の略で、C言語でかかれたグラフィックライブラリです。GLSCを用いれば、科学技術計算の結果をディスプレイに表示したり、プリンターに出力したりすることができます。通常、コンピュータに絵を描かせる場合、その予備知識としてかなり多くのことを学ぶ必要があります。GLSCは機能が限定されている分、使い方が簡単で、覚えることも最小限ですみます。より高度なグラフィックスを表示させたい人は、他のライブラリを用いることになるでしょうが、基本をGLSCで学んでおけば、すんなりと習得できるでしょう。

注意: GLSCという言語があるわけではありません。この演習では cglsc コマンドを用いてコンパイルするため、あたかもGLSCという言語があるかのように錯覚する人もいるようですが、この演習で扱うものは全てC言語のプログラムです。後の「GLSCを使ったプログラムのコンパイルの仕方」にあるように、cglsc コマンドは実際には cc コマンドをオプション付きでよびだしているにすぎません。


もっとも簡単なGLSCプログラム

 次のプログラムは、画面上に白いウィンドウを表示するだけのプログラムです。GLSCでは、このウィンドウ内に絵を描くので、ウィンドウの表示は絶対に必要です。表示されたウィンドウは、ウィンドウ内をマウスで左クリックすると消えます。以下のサンプルプログラムをエディターで打ち込み、ファイル名を 0420-1.c として保存してください。コンパイルの方法がこれまでと異なるので、コンパイル、実行はまだしないで下さい(後ほど説明します)。

--------------------

 1: #include <glsc.h>
 2: #include <stdio.h>
 3: 
 4: main()
 5: {
 6:     g_init("GRAPH", 100.0, 100.0);
 7:     g_device(G_DISP);
 8:     g_sleep(G_STOP);
 9:     g_term();
10: }

--------------------

1行目: GLSCを使う場合にはこの #include 文が必要です

6行目: g_init 関数を用いて、絵を描くウィンドウの初期化を行います。第一引数である "GRAPH" は、画面に表示した絵をファイルとして保存する場合に使いますが、当面はこのように "GRAPH" としてください。その後に続く2つの引数は、実数型で、ウィンドウのサイズを指定します。

7行目: g_device 関数で、何に対して表示するかを指定します。画面に表示したいので、このように G_DISP を引数に指定します。

8行目: g_sleep 関数でプログラムの一時停止を行っています。引数として正の実数値またはG_STOPを受けます。引数が正の実数値である場合、その秒数停止します(例えば g_sleep(1.2); であれば1.2秒停止します)。引数が G_STOP である場合、ウィンドウの内部がマウスで左クリックされるまで停止します。

9行目: g_term 関数にてGLSCの処理を終わります。GLSCプログラムの最後に呼ばれます。


GLSCを使ったプログラムのコンパイル方法

 GLSCでは画面上に線を表示したりする必要がある為、様々な非標準ライブラリ(標準関数以外の関数の集まり)を使うようコンパイル時に指定する必要があります。その為には、例えば先のプログラムをコンパイルする場合、次のようなコマンドを打ち込む必要があります。

cc -I/usr/X11/include -I/home2/awa/SUURI_GLSC/include 0420-1.c -o 0420-1 -L/home2/awa/SUURI_GLSC/lib -lglscd -L/usr/X11R6/lib -lX11 -lm

しかし、これをいちいち打ち込むのは面倒なので、GLSCプログラムを簡単にコンパイルするためのコマンドをこちらで用意しました。そのコマンドを利用すると、上記の長いコマンドを打ち込んだ結果と同様の結果が、次の短いコマンドで得られます(先ほど行ってもらったGLSC利用の為の準備は、このコマンドを利用できるようにする為のものでした)。

cglsc  0420-1.c

これにより、実行可能なファイル 0420-1 が生成されます。プログラムはこれまで同様、

./0420-1

で実行され、この場合、次のような真っ白な正方形ウィンドウが画面に表示されます。

ウィンドウ内をマウスで左クリックすることで、ウィンドウが消えます。


GLSCのマニュアル

 GLSCのマニュアルは、この演習のホームページのトップページからリンクされています。関数の使い方が良く分からない場合は、マニュアルを参照してください。


g_init 関数

 先のプログラム例の6行目で呼ばれている g_init 関数では、第2、第3引数でウィンドウの大きさを指定することができると説明しました。実際に、その数値を変更してウィンドウのサイズがどうかわるか見てみましょう。

次の各場合についてコンパイル実行してみてください。

g_init("GRAPH", 100.0, 200.0);

g_init("GRAPH", 300.0, 200.0);


標準座標系

 GLSCには、標準座標系と仮想座標系という二つの座標系が存在します。ここではまず、標準座標系について説明します。

 標準座標系は、例えば g_init("GRAPH", 200.0, 100.0) と初期化されたウィンドウでは次の図のようになります。

 

 

つまり、左上が座標 (0.0, 0.0) であり、右下が (200.0, 100.0) となるような座標系です。


GLSCによる文字列の描画

 GLSCでは g_text 関数にて文字をウィンドウ内に表示することができます(残念ながら漢字は表示できません)。例えば、次のプログラムでは、画面ウィンドウ内に Hello! と表示します。(0420-2.c)

--------------------

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

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

   /* 文字を描画 (横の座標, 縦の座標, 文字)*/
   g_text(0.0, 10.0, "Hello!");

    g_sleep(G_STOP);
    g_term();
}

--------------------

g_text 関数の第一、第二引数はウィンドウ上の標準座標系での座標です。コンパイルし実行すると、次のようになります。

実行結果

次のプログラムでは Hello! と GLSC という文字列をそれぞれ異なる場所に表示します。

--------------------

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

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

   /* 文字を描画 (横の座標, 縦の座標, 文字)*/
   g_text(0.0, 10.0, "Hello!");
   g_text(10.0, 20.0, "GLSC");

    g_sleep(G_STOP);
    g_term();
}

--------------------

実行結果

g_text_color 関数を使って、文字に色をつけることもできます。

--------------------

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

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

   /* 文字の色を指定してから描画 */
   g_text_color(G_RED);
   g_text(0.0, 10.0, "Hello!");
   g_text(10.0, 20.0, "GLSC");

    g_sleep(G_STOP);
    g_term();
}

--------------------

実行結果

g_text_color 関数を使って、文字の色を変えると、その後 g_text 関数で表示する文字全てに適用されます。例えば GLSC は黒で表示したい場合は次のよう改めて黒と指定する必要があります。

--------------------

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

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

   /* 文字の色を指定してから描画 */
   g_text_color(G_RED);
   g_text(0.0, 10.0, "Hello!");

   /* 文字の色を指定してから描画 */
   g_text_color(G_BLACK);
   g_text(10.0, 20.0, "GLSC");

    g_sleep(G_STOP);
    g_term();
}

--------------------

実行結果

 

g_text_color の引数には色を指定しますが、GLSCでは以下の8色を使うことができます。

 
color カラーディスプレイ
番号 マクロ
0 G_BLACK
1 G_RED
2 G_GREEN
3 G_BLUE
4 G_MAGENTA マゼンタ
5 G_YELLOW
6 G_CYAN シアン
7 G_WHITE

 

例えば、黄色で文字列を描画したい場合は、

g_text_color(G_YELLOW);

または

g_text_color(5);

とします(どちらの指定方法でもよい)。後者の指定方法は、例えば次のようなプログラムでは大変有用です。

--------------------

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

main()
{
   int i;

    g_init("GRAPH", 100.0, 100.0);
    g_device(G_DISP);

   for(i = 0; i < 8; i++)
   {
     /* 文字の色を数値で指定 */
      g_text_color(i);
      g_text(0.0 + i*10, 10.0 + i*10 ,"Hello!");
   }

    g_sleep(G_STOP);
    g_term();
}

--------------------

実行結果

白色で描画された最後の Hello! は背景色と同じである為見えません。


g_cls 関数

g_cls 関数を用いると、ウィンドウ内を消去することができます。次のプログラムでは、カラフルに Hello! を表示した後とまります(一つ目の g_sleep(G_STOP))。マウスのクリックをすることで g_cls 関数が実行され、画面が消去され、再びとまります(二つ目の g_sleep(G_STOP))。動作を確かめてください。(0420-7.c)

--------------------

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

main()
{
   int i;

    g_init("GRAPH", 100.0, 100.0);
    g_device(G_DISP);

   for(i = 0; i < 8; i++)
   {
      g_text_color(i);
      g_text(0.0 + i*10, 10.0 + i*10, "Hello!");
   }

    g_sleep(G_STOP);

   /* ウィンドウ内を消去 */
   g_cls();

   g_sleep(G_STOP);

    g_term();
}

--------------------


簡単なアニメーション

文字列をある位置に表示し、しばらくとまった後、画面を消去し、先ほどとは少し違った場所に再び文字列を表示するという一連の作業を繰り返すと、アニメーション効果を得ることができます。(0420-8.c)

--------------------

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

main()
{
   int i;

    g_init("GRAPH", 100.0, 100.0);
    g_device(G_DISP);

   for(i = 0; i < 100; i = i + 2)
   {
      /* 描写 */
      g_text_color(i%8);
      g_text(0.0 + i, 10.0 + i, "Hello!");

      /* 少々停止 */
      g_sleep(0.05);
      /* 消去 */
      g_cls();
   }

    g_sleep(G_STOP);

    g_term();
}

--------------------

途中の繰り返し文の中で、表示、停止、消去を繰り返しています。

g_text_color の引数は 0〜7 の整数であったので、 % 演算子を用いて、その範囲になるようにしてあります。

途中にある g_sleep(0.05); で約 0.05 秒間停止します。これが無いと早すぎてアニメーションに見えません。


文字列の描画(その2)

 例えば、変数の内容(や計算結果)を GLSC ウィンドウに表示したい場合は次のように文字列型(文字型の配列)を用いる必要があります。(0420-9.c)

--------------------

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

main()
{
   float a;
   char text[256]; // 256文字までの文字列の宣言

   a = 3.14;

    g_init("GRAPH", 100.0, 100.0);
    g_device(G_DISP);

   sprintf(text, "a = %f", a); 
   g_text(0.0, 10.0, text);


    g_sleep(G_STOP);
    g_term();
}

--------------------

イメージとしては 
char text[256]; で、「text」という名前の256文字まで文が書ける原稿用紙を用意し、
sprintf(text, "a = %f", a); で「text」に文章(256文字以内)を書き、
その内容を g_text(0.0, 10.0, text);で表示、という感じ。

sprintf 関数は、第一引数に文字型配列の名前(この例では text)を書く以外は、printf 関数と同様です(同じ変換文字列が使える)。

文字型の配列、および sprintf 関数と g_text 関数を組み合わせて使うことで、色々な文字列を表示することができます。

先のアニメーションの方法と組み合わせてカウントダウンとかさせられます。(0420-10.c) 
これを見ると「変数」を表示する事の有り難みがわかるかと思います。


4月27日分


仮想座標系

 GLSCでは、先程でてきた標準座標系の他に仮想座標系を定義し利用することができます。以下で述べるように、実際にGLSCで図形やグラフの描写を行う場合、仮想座標系は非常に強い力を発揮します。仮想座標系を定義するには g_def_scale という関数を使います。(仮想座標系はいくつでも(もちろん限界はありますが)定義することができます。)

 これまでにあつかった標準座標系は、例えば g_init("GRAPH", 200.0, 100.0) と初期化されたウィンドウでは次の図のようになりました。

 

 

つまり、左上が座標 (0.0, 0.0) であり、右下が (200.0, 100.0) となるような座標系です。例えば、 y = sin(x) のグラフを 0 < x < 4 の範囲で描きたい場合、標準座標系にそのようなグラフを描くには、座標変換の手続きが必要となります( そのまま描くとこうなります。。。)。それでは、いちいち紛らわしいので、この場合次のような座標系となっていれば便利です。

 

座標系がこのようになっていれば、y = sin(x) のグラフを描くのが簡単です( このように描けます)。実は、GLSCでは、このような座標系を、先の GLSC ウィンドウ内にいくつでも作ることができます。そして、実際に GLSC で絵を描く場合、この座標系(仮想座標系と呼びます)を用います。先の標準座標系は、文字列の描画時と仮想座標系の定義時にのみ使います。(仮想座標系を GLSC ウィンドウ内に定義する場合には何らかの座標系が必要です。標準座標系はその為にあるものだと考えてください。)

 例えば、先の標準座標系の中に、1つの仮想座標系を定義した場合のイメージを次に示します。

青色が、GLSCウィンドウ全体をあらわしています。その中に赤色の仮想座標系が定義されている様子を示しています。このような仮想座標系は次の g_def_scale 関数を用いて定義することができます。

(こちらの補足もご参考ください)

仮想座標系の定義(g_def_scale 関数)

 GLSC ウィンドウ内に長方形領域を定義して、その長方形内の座標系を定義する関数が g_def_scale 関数です。GLSC ウィンドウ内に長方形を定義するには長方形の位置大きさを指定する必要があります。また、新たに作成する仮想座標系の左端、右端、下端、上端の値を指定する必要があります。つまり、長方形の位置と大きさを指定するために4つの値が必要であり、新座標系を指定するために4つの値が必要(計8つ!)となるということを理解すれば、g_def_scale 関数に多くの引数の意味がおのずとわかります。また、仮想座標系はいくつでも定義できるので、どの仮想座標系の定義であるかを示す通し番号も必要となります。つまり、g_def_scale 関数には、全部で9つの引数があります。

  GLSCマニュアルの g_def_scale 関数の説明部分は次のように記載されています。このように、GLSC の関数は引数が多いので、関数利用の際には各人マニュアルを参照してください。

(こちらの補足もご参考ください)

g_def_scale 標準面上に仮想座標系を定義する


 はじめの引数は、これから定義する仮想座標系につける通し番号です。2,3,4,5番目の引数は、仮想座標系の左端、右端、下端、上端の値であり、6,7,8,9番目の引数は、仮想座標系の位置と大きさを標準座標系で与えます。長方形の位置と大きさ(6,7,8,9番目の引数)は、4頂点の座標を与えるのではなく、長方形の左上の標準座標系での座標と、長方形の幅と高さを与えるというところに注意してください。

 では、実際に g_def_scale 関数をつかったサンプルプログラムを見てみましょう。

--------------------

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

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

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

  g_sleep(G_STOP);
  g_term();
}

--------------------

このプログラムでは、次のような仮想座標系を定義しています。

 


円の描画

 GLSC では g_circle 関数で円を描画することができます。g_circle には5つの引数があり、はじめの2つで、円の中心位置を仮想座標系にて指定します。3つめの引数は、描く円の半径。4つめの引数は円のふちを描くかどうかの指定(G_YES または G_NO)で、5つめの引数は、円の内部を塗りつぶすかどうかの指定(G_YES または G_NO)を行います。(0427-1.c) (こちらの補足の下の方もご参考ください)

--------------------

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

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);

 /* 仮想座標系「1」を選択 */
  g_sel_scale(1);
  /* 円の描写 (横座標, 縦座標, 半径, ふち描く?, 塗りつぶす?) */
  g_circle(0.0, 0.0, 0.5, G_YES, G_NO);


  g_sleep(G_STOP);
  g_term();
}

--------------------

上のプログラムでは、次のような仮想座標系(赤色で示した)を1番(g_def_scale の第一引数)として定義しています。その仮想座標系に絵を描きたいので、それを選ぶために g_sel_scale 関数で1番の仮想座標系を選びます。その後、g_circle 関数で円を描きます。このように、仮想座標系がたった一つであっても、g_sel_scale で一度選ぶ必要があります。g_def_scale 関数と g_sel_scale 関数は GLSC プログラムには必ず出てくると思ってください。

 

 プログラムの実行結果は次のようになります。

 

例えば g_def_scale 関数の2つ目以降の引数を変えてみたり, 以下のように g_def_scale 関数と g_sel_scale 関数をコメントアウトしたものと比べてみると、どういうことか分かりやすいと思います.

--------------------

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

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_circle(0.0, 0.0, 0.5, G_YES, G_NO);


  g_sleep(G_STOP);
  g_term();
}

--------------------


2つの仮想座標系を定義して、使ってみましょう。次の例では、標準座標系上の全く同じ位置に同じ大きさの仮想座標系を作っています。ただし、座標のスケールが異なります。(0427-2.c)

--------------------

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

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_def_scale(2, -2.0, 2.0, -2.0, 2.0, 10.0, 10.0, 80.0, 80.0);

  g_sel_scale(1);
  g_circle(0.0, 0.0, 0.5, G_YES, G_NO);

 
g_sel_scale(2);
  g_circle(0.0, 0.0, 0.5, G_YES, G_NO);


  g_sleep(G_STOP);
  g_term();
}

--------------------

実行結果は次のようになります。2つの g_circle は全く同じなのに(位置、半径が同じ)、2つの見た目違う半径の円が描かれました。異なる仮想座標系を用いて描いているからですが、その意味をよく理解してください。 (こちらの補足の下の方もご参考ください)


円に色をつけることもできます。g_area_color 関数で、円内部の塗りつぶし色を指定し、 g_line_color 関数でふちの線色を指定します。2つめの g_circle では、内部塗りつぶしをしない(5つめの引数が G_NO である)ので先に描かれた赤色が残っています(5つめの引数を G_YES に変更してみよ)。

--------------------

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

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_def_scale(2, -2.0, 2.0, -2.0, 2.0, 10.0, 10.0, 80.0, 80.0);

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

  g_sel_scale(2);
  g_area_color(G_GREEN);
  g_line_color(G_GREEN);
  g_circle(0.0, 0.0, 0.5, G_YES, G_NO);

  
  g_sleep(G_STOP);
  g_term();
}

--------------------


四角形の描画

 g_box 関数により、四角形を描くことができます。

 g_box(横座標(左), 横座標(右), 縦座標(下), 縦座標(上), ふち描く?, 塗りつぶす?) 
 例)g_box(0.0, 1.0, -0.5, 0.5, G_YES, G_NO); 等

課題1

 上記プログラムの g_def_scale(2, -2.0, 2.0, -2.0, 2.0, 10.0, 10.0, 80.0, 80.0)で2〜9番目の変数をいろいろ変えて比較する事で, 仮想座標系の性質に慣れてください。


課題2

 円が時間と共に移動するアニメーションプログラムを作成せよ。


直線の描画

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

--------------------

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

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();
}

--------------------

 

 

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

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


課題3

 円や長方形等を組み合わせて、「串に刺さったおでん(四角いはんぺん、丸い大根、三角こんにゃく)」のような絵を描け。



5月11日分


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

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

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

Xi = i*dx

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

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

をそれぞれ求め、(X[0], Y[0]), (X[1],Y[1]), ...., (X[N-1], Y[N-1]) を結ぶ折れ線を描くことになります。これをプログラムにすると次のようになります。(上記の説明にあわせるためにかなり無駄なことをしています。)ファイル名を 0511-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)

main()
{
  int i;
  float 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();
}

--------------------

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

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

 

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

 

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

 


課題4

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

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


課題5

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


y = sin(x + t) のグラフのアニメーション

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

Tk = dt*k

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


課題6

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


課題7

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


課題8

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


課題9

 -1 ≦ x ≦ 1, 1 ≦ t, で (2πt)-1/2exp(-x2/2t) のアニメーションを作成せよ。
 (水面にインクを落とすと、この関数のように広がっていきます。) 


課題10

 -π ≦ x ≦ π で cos(x+t) + [cos(3x+t)]/9 + [cos(5x+t)]/25+ ... + [cos((2n-1)x+t)]/(2n-1)2 のアニメーションを作成せよ。(幾つかの n について試せ) 


課題11

 -π ≦ x ≦ π で cos(x-t) + [cos(3x+t)]/9 + [cos(5x-t)]/25+ ... + [cos((2n-1)x+(-1)nt)]/(2n-1)2 のアニメーションを作成せよ。(幾つかの n について試せ) 


課題12

 秒針、短針、長針のある、実時間の60倍で動く時計のアニメーションを作成せよ. 


戻る