HandyGraphicを用いたグラフィックス表示

関数と返値

printf関数やscanf関数は,画面メッセージ出力やキーボードからのデータ読み取りを実行するものとして説明されてきた.しかし,厳密に言えば,C言語における「関数」には2つの使い方がある.

後者の使い方の典型例として,例えば,平方根や三角関数などの数学関数の計算などがある.例えば,三角関数であれば,

/*        */
/* Eitetsu Oomoto, 07/04/2006 */

#include  <stdio.h>
#include  <stdlib.h>
#include  <math.h>  // 数学関数を使うときは,math.hを必ずインクルードする

#define PI 3.14159265

main()
{
    double result;
    double x;

    x = PI/2; /* π/2 (90度) */
    result = sin(x); // 正弦関数の値を計算した結果(返値)を代入
    printf("sin(PI/2) = %lf¥n", result); 

    exit(0);
}

といったようにsin関数の計算値を求めた結果を利用できる.この場合,変数xに代入している.このように関数を実行(計算)した結果として得られる値を,関数の「返値(かえりち)」或いは「戻り値」と呼ぶ.

一方,printf関数やscanf関数も「関数」であるので,実際には返値がある.しかし,その値は,printfやscanfが正常に実行できた場合には整数0(ゼロ), 何らかの原因により正常に実行できなかった場合には0以外の整数となっている.printf関数の実行に異常が生じるような事態は,通常の場合には殆ど有り得ないので,この返値には実質的に使い道が無い.

printf関数のように,関数の返値には意味が無く,関数によって何かの「機能」をコンピュータに実行させることだけに意味がある場合には,その関数をそのままプログラム中に文として書くだけでよく,その場合,関数の返値は自動的に破棄(無視)される.

つまり,「画面にメッセージを表示」という「機能が使いたいだけ」であれば,

    y = printf("Please input a number: "); 

と書くのではなく,

    printf("Please input a number: "); 

という具合に関数のみを文として書けば良いということである.尚,printf関数は,このような使い方がほぼ100%であると考えて良い.

以下の説明では,簡単なグラフィックス機能を実現するHandyGraphicライブラリについて説明するが,HandyGraphicでは各図形を描くなどの機能が関数として実現されている.また,一部の関数は,その返値をプログラム中で利用する.

関数の作成

自分の作成したプログラムの一部として,何か一定の処理を行う部分を考えやすくするために,その部分を取り出して「自作の関数」を作成する事も出来る.関数の作成については,教科書第13章に記載があり,詳細は秋学期に学習する予定である.

HandyGraphic

HandyGraphicは,本学コンピュータ理工学部の荻原剛志教授によって作成されたMacOS X上で動作する簡易グラフィック環境であり,NetBoot環境では標準で利用できる.ユーザーガイドはこちらを参照のこと.

尚,HandyGraphicを自宅環境など自分のMacBookをローカルブートした際に利用したい場合は,こちらのページを参照して,CSEフォルダ中においてある hg.dmg ディスクイメージを持ち帰って,各自インストールすること.このHandyGraphicの配布におけるソフトウェア・ライセンスはBSDライセンスとします.

グラフィック座標系

HandyGraphicライブラリを用いて画面上にグラフィックスを描く場合,まず描画領域(油絵のカンバスや画用紙を思い浮かべれば良い)となる描画用ウィンドウを予め開き,そのウィンドウ内で適当なグラフィックスを描画することになる.このウィンドウを表示処理を行っているのはHgDisplayerというアプリケーションでありHandyGraphicライブラリを用いたプログラムが起動すると自動的に起動するようになっている.尚,HandyGraphicライブラリを用いた自作プログラムが動作している途中で,HgDisplayerを終了させてしまうと自作プログラムが異常終了してしまうから,ちょっと注意しよう.

コンピュ−タの画面全体は小さな点(画素,ピクセル)の集りとして捉えることができ,画面左下を原点として右側へ水平に伸びるX軸と上へ伸びるY軸からなる2次元座標平面と考えることが出来る.この画面全体を表す座標軸を「スクリ−ン座標」と呼ぶ.これに対し,グラフィックスを描画する作図用ウィンドウ内部にも,ウィンドウ左下を原点とし,水平方向をx軸,垂直方向をy軸とする座標系があり,これを「ウィンドウ座標」と呼ぶ.各座標の値は倍精度実数値(double型)で表されるが,実際に画面描画される際には整数値に調整される.

グラフィックスを描く際は,必要とあれば描画用ウィンドウを指定した上で,そのウィンドウにおける「ウィンドウ座標」をつかって,その「描画用ウィンドウの内部のどこにどのような図形を描くか?」を指定することになる.HandyGraphicに用意されているグラフィック図形には,「直線」「円」「円弧と扇形」「長方形」「多角形」「文字列」などがあり,それぞれ対応する関数を実行することで画面描画される.以下の図は,幅600,高さ400の作図用ウィンドウを作成し、その中にウィンドウ座標で(x,y) = (300, 150)を中心として半径120の円を描く場合の座標の関係を表わす.

このグラフィックスを描画するプログラム handy.c は以下のようになる.

/*         */

#include <stdio.h>
#include <stdlib.h>
#include <handy.h>
		
main()
{
    HgOpen(600, 400); /* 描画用ウィンドウを開く*/
    HgCircle(300, 150, 120); /* 中心(300, 150)、半径120 の円を描く*/

    getchar(); /* プログラムを一時停止して待たせる*/

    exit(0); /* 何かキーをタイプすると終了する。*/
}

尚,描画ウィンドウはプログラムが終了すると画面から消えてしまうので,上記の例ではgetchar()関数を使って,キ−ボ−ドから何かキ−がタイプされるまで,実行を一時停止させている.getchar()関数とは,キーボードから1文字読み取る関数である.その詳細は教科書pp.152を参照のこと.

描画のための各種設定を行う関数

HandyGraphicでは,グラフィック図形を描く際の線の太さや色,及び,文字コードとフォントを指定することができる.

線の太さの指定

描画図形の線の太さは標準で1画素分であるが,HgSetWidth()関数を用いて変更できる.

int HgSetWidth( t )
    double t: 線の太さの値

一旦,変更すると別の指定がされるまで,その太さのままとなる.

注意: 上記の記述でHgSetWidth( t )の前に置かれた int は,この関数の返値がint型であることを示している.つまり,関数をプログラム中で使う場合,返値を必要としないのであれば,printf関数やscanf関数などと同じように使えば良い.また,上記の記述では,このHgSetWidth関数の引数はdouble型で与える事を意味しているので誤解無いようにして欲しい.以下の各関数の説明でも同様である.

引数に「整数型」の値(変数や定数)を与えるように記述した場合,C言語コンパイラにより「暗黙の自動型変換処理」が自動的に組み込まれて,整数型 -> 倍精度実数型というデータ型変換が起きるが,現時点では単純な場合しかプログラムコードに出てこないはずなので,あまり神経質に気にする必要はない.
詳細は教科書「第7章 実数型の計算と標準数学関数」の節で学ぶが,それは秋学期に取り上げられるだろう.

色指定

マクロによる固定的な色指定

色の指定は,hgcolorというHandyGraphic固有のデータ型で指定するが,良く使われる色は,以下のようなマクロ定義(#define文を用いた定義)となっている.

マクロ名 マクロ名 マクロ名
HG_WHITE HG_RED シアン HG_CYAN
HG_BLACK HG_GREEN オレンジ HG_ORANGE
灰色 HG_GRAY HG_BLUE ピンク HG_PINK
淡灰色 HG_LGRAY HG_YELLOW マゼンタ HG_MAGENTA
濃灰色 HG_DGRAY HG_PURPLE HG_BROWN

このマクロ定義はヘッダファイル /usr/local/include/handy.h 中に定義されており,ソースプログラム中の #include <handy.h> 宣言に対してC言語コンパイラのプリプロセッサにより置き換えられることにより,ソースプログラム中でマクロ定義が有効になる.

描かれる図形の輪郭線(縁取り)の色は,HgSetColor()関数を用いる.尚,標準では黒で描画され,一旦,色指定されると次に色指定されるまで同じ色で描画し続ける.

int HgSetColor( color )
    hgcolor color: 色の指定

尚,図形を塗りつぶす色は輪郭線の色とは別にHgSetPaintColor()関数で指定する

int HgSetPaintColor( color )
    hgcolor color: 色の指定
中間的色合いの指定

自分の好きな色合いを指定したい場合,hgcolor型の値をHgGray()関数(グレーの指定),或いは,HgRGB()関数(カラーの指定)を用いて生成する

hgcolor HgGray( g )
    double g: 色の指定 (0.0 ≦ g ≦ 1.0)
    返値: 色を表す値
    
hgcolor HgRGB( r, g, b )
    	double r: 色の指定 (0.0 ≦ r ≦ 1.0)
    	double g: 色の指定 (0.0 ≦ g ≦ 1.0)
    	double b: 色の指定 (0.0 ≦ b ≦ 1.0)
    返値: 色を表す値

HgGray()関数では0から1までの実数値でグレーの度合いを表現する. 0.0が真っ黒, 1.0が真っ白となる.

HgRGB()関数では,光の三原色である,赤(Red), 緑(Green), 青(Blue)の混合で色合いを表す.0.0が最低輝度,1.0が最高輝度である.例えば,HgRGB(1.0, 0.0, 0.0)で赤,HgRGB(1.0, 1.0, 0.0)で黄色,HgRGB(1.0, 0.0, 1.0)で紫を表現できる.

上記の関数の返り値であるhgcolor型の値をHgSetColor()やHgPaintColor()の引数に用いることで,その色を描画色に設定する.

文字コードとフォントの指定

日本語を含む文字列を描画するには,ソースプログラムの日本語文字がどのような文字コードを用いているのかHgDisplayerに伝える必要がある.

int HgEncoding( coding )
    int coding: 文字コードを指定する整数値

尚,この文字コードを指定するにあたっては,以下のマクロ定義を使う.尚,文字コードが指定されなかった場合,標準では文字コードはUTF-8が想定される.

マクロ名 文字コード
HG_UTF8_CODE UTF-8
HG_JIS_CODE ISO-2022-JP
HG_SJIS_CODE Shift JIS
HG_EUCJP_CODE 日本語EUC

また,文字列を描画する書体(フォント)はHgSetFont()関数を用いて指定する.

int HgSetFont( font, size )
    hgfont font: フォントを指定する定数名(マクロ)
    double size: 文字サイズ

尚,フォント指定のマクロ定義は以下の通りである..

フォント 定数名
Courier HG_C
HG_CB
細斜体 HG_CI
太斜体 HG_CBI
Helvetica HG_H
HG_HB
細斜体 HG_HI
太斜体 HG_HBI
Times HG_T
HG_TB
細斜体 HG_TI
太斜体 HG_TBI
明朝 HG_M
HG_MB
ゴシック HG_G
HG_GB

グラフィックス描画のための関数

描画用ウィンドウの作成と表示

HgOpen()は描画用ウィンドウを作成して,画面に表示する.

int HgOpen( w, h )
    double w: ウィンドウの幅
    double h: ウィンドウの高さ

作成されるウィンドウの背景色は白である.また,このHgOpen関数で開かれたウィンドウを「標準ウィンドウ」と呼ぶ.尚,プログラムが終了したとき(あるいは強制終了したとき),描画ウィンドウは自動的に閉じられる.また,HgClose()関数を利用すれば,プログラム中で閉じることができる.

複数のウィンドウを開きたい場合は,HgWOpen()を用いる.

int HgWOpen( x, y, w, h )
    double x: ウィンドウ左下隅のスクリーンx座標
    double y: ウィンドウ左下隅のスクリーンy座標
    double w: ウィンドウの幅
    double h: ウィンドウの高さ

この関数の戻り値はウィンドウidと呼ばれる整数で,開いたウィンドウ毎に異なる.これを利用して複数のウィンドウを使い分けて図形を描画する事が出来る.また,標準ウィンドウのウィンドウidは常に0と定められており,ウィンドウが何も表示されていない状態でHgWOpen()で新しいウィンドウを一枚開くと,そのウィンドウidは0となり,すなわち「標準ウィンドウ」となる.

また,標準ウィンドウのウィンドウidは常に0と定められており,ウィンドウが何も表示されていない状態でHgWOpen()で新しいウィンドウを一枚開くと,そのウィンドウidは0となり,すなわち「標準ウィンドウ」となる.

本基礎プログラミング演習Iでは,学習レベルの都合上,複数ウィンドウを用いたプログラミングは原則として行わないが,そのようなプログラミングに興味ある場合は荻原先生のユーザーガイドを参照して欲しい.

描画ウィンドウのクローズ(閉じ)

HgClose()は標準ウィンドウを閉じる.

int HgClose( )

この関数の戻り値は通常0だが,万が一のエラー時には-1を返す.

また,HgWClose()は指定したidを持つ描画ウィンドウを閉じる.

int HgWClose ( wid )
    int wid: ウィンドウid

引数としてクローズさせたいウィンドウidを指定する.関数の戻り値は通常0だが,エラー時には-1を返す.

HgCloseAll()は全てのウィンドウを閉じる.返り値は無い.(この関数はvoid型と呼ばれるが,void型関数とは返値を返さない関数という意味である.)

void HgCloseAll( )

例えばスクリーン座標で(x,y) = (200, 150)の点を左下隅とする幅300,高さ300の描画ウィンドウAと,(x,y) = (600, 150)の点を左下隅とする幅200,高さ200の描画ウィンドウBの両方を表示して一旦停止し,キ−ボ−ドから何かのキ−がタイプされるとAウィンドウを閉じて,再度停止し,再びキ−ボ−ドがタイプされると終了するプログラムは以下のようになる.

/*    */

#include <stdio.h>
#include <stdlib.h>
#include <handy.h>

int main()
{
    int w_a;
    int w_b;

    w_a = HgWOpen(200, 150, 300, 300); 
    w_b = HgWOpen(600, 150, 200, 200); 
    getchar(); 
    
    HgWClose(w_a); 
    getchar(); 
    
    exit(0);
}

直線の描画


		

HgLine()は直線を描画する関数である.


		
int HgLine ( x1, y1, x2, y2 )
    double x1,y1: 始点のx,y座標
    double x2,y2: 終点のx,y座標

始点・終点の座標はウィンドウ座標系で与えるが,ウィンドウの外側にはみ出るような座標を指定しても構わない.関数の戻り値は通常0だが,エラー時には-1を返す.

例えば,int型変数widで示されるウィンドウ内に(10, 10)から(100, 200)まで直線を引く場合を考える.灰色の直線を引きたい場合は以下のようにすればよい.


		
HgSetColor(HgGray(0.5)); 
HgLine(10, 10, 100, 200);

また,同じ直線を少々くすんだ紫色で引きたい場合は次のようにする.


		
hgcolor c;
......
......
c = HgRGB(0.8, 0.0, 0.8); /* ちょっとくすんだ紫色 */
HgSetColor(c);
HgLine(10, 10, 100, 200);	

円の描画

HgCircle()は円周を描画し,HgCircleFill()は内部を塗りつぶした円を描画する.


		
int HgCircle ( x, y, r ) 
int HgCircleFill ( x, y, r, stroke ) 
    double x,y: 中心のx,y座標
    double r: 半径 (r ≧ 0) 
    int stroke: 円周(縁取り)を描くかどうか(0の場合は円周を描かず,0以外の値を指定すると他の図形と同じ太さ,同じ色で円周を描く.)

中心の座標はウィンドウ座標系で与えるがウィンドウの外側となるような座標を指定しても構わない.但し,半径は0以上の値でなければならない.関数の戻り値は通常0だが,エラー時には-1を返す.

円弧と扇形

HgArc()は円弧を描画する関数である.HgFan()は扇形を描画する.HgFanFill()は内部を塗りつぶした扇形を描画する.


		
int HgArc ( x, y, r, a0, a1 )
int HgFan ( x, y, r, a0, a1 )
int HgFanFill ( x, y, r, a0, a1, stroke )
    double x,y: 中心のx,y座標
    double r: 半径 (r ≧ 0)
    double a0: 始点方向とx軸のなす角度 (0 ≦ a0 ≦ 2π)
    double a1: 終点方向とx軸のなす角度 (0 ≦ a1 ≦ 2π)
    int stroke: 周囲を描くかどうか(0以外なら周囲を描画)

中心の座標はウィンドウ座標系で与えるが,ウィンドウの外側にはみ出るような座標を指定しても構わない.尚,半径は0以上の値でなければならない.また,角度には弧度法(ラジアン単位)を用いる.

関数の戻り値は,正常終了の場合0だが異常時には-1を返す.

長方形

HgBox()は長方形を描画し,HgBoxFill()は内部を塗りつぶした長方形を描画する.

int HgBox ( x, y, w, h )
int HgBoxFill ( x, y, w, h, stroke ) 
    double x,y: 左下隅のx,y座標
    double w: 幅 (w ≧ 0)
    double h: 高さ (h ≧ 0) 
    int stroke: 周囲を描くかどうか(0以外なら周囲を描画)

左下隅の座標はウィンドウ座標系で与えるが,ウィンドウの外側にはみ出る座標を指定しても構わない.尚,幅・高さは0以上の値でなければならない.関数の戻り値は,正常終了の場合0だが異常時には-1を返す.

折れ線

複数の点を結んだ折れ線を描くには,複数の点の座標値を配列に用意しておいて,HgLines()を用いて描画出来る.

int HgLines ( n, x, y )
    int n: 頂点数 (n ≧ 0) 
    double *x: 頂点のx座標を格納した配列へのポインタ
    double *y: 頂点のy座標を格納した配列へのポインタ

各頂点の座標はウィンドウ座標系で与えるが,ウィンドウの外側にはみ出る座標を指定してもかまわない.関数の戻り値は,正常終了の場合0だが異常時には-1を返す.

多角形

複数の点を折れ線と同様に指定して,HgPolygon()は多角形を描画し,HgPolygonFill()は内部が塗り潰した多角形を描画する.始点と終点は自動的に結ばれる.

int HgPolygon ( n, x, y )
int HgPolygonFill ( n, x, y, stroke )
    int n: 頂点数 (n ≧ 0) 
    double *x: 頂点のx座標を格納した配列へのポインタ
    double *y: 頂点のy座標を格納した配列へのポインタ
    int stroke: 周囲を描くかどうか(0以外なら周囲を描画)

各頂点の座標はウィンドウ座標系で与えるが,ウィンドウの外側にはみ出る座標を指定してもかまわない.関数の戻り値は,正常終了の場合0だが異常時には-1を返す.

尚,ポインタの考え方については,教科書第11章に記載がある.詳細は秋学期に学ぶだろう.

文字列

HgText()は文字列を描画する関数である.表示位置の指定以外については,C言語の標準関数であるprintf関数と同じように用いる.変数の値などを表示させたければ,書式指定文字列に続けて,引数で与えれば良い.

int HgText ( x, y, char *str, ... )
    double x,y: 文字列左下隅のx,y座標
    char *str: 書式指定文字列(例えば "x_value = %d" など)

左下隅の座標はウィンドウ座標系で与えるが,ウィンドウの外側にはみ出る座標を指定しても構わない.数の戻り値は,正常終了の場合0だが異常時には-1を返す.

例えば,幅500,高さ400の作図用ウィンドウを作成し、その中に、ウィンドウ座標で(x,y) = (50, 200)を文字列の左端として"Hello World 初めてのグラフィック"という文字をゴシック書体・サイズ14 pointで紫色表示する場合,以下のようなプログラムとなる.

/*        */

#include <stdio.h>
#include <stdlib.h>
#include <handy.h>

int main()
{
    int size;
    hgcolor color;
    
    HgEncoding(HG_UTF8_CODE); /* 文字コードはUTF-8(Mac OS Xの標準文字コード) */
    HgOpen(500, 400);
    
    size = 14; 
    HgSetFont(HG_G, size); /* ゴシック体, 14ポイント */
    color = HgRGB(1, 0, 1); /* 紫色 */
    HgSetColor(color); 
    HgText(50, 200, "Hello World 初めてのグラフィック: 文字の大きさは %d ポイントです.", size);
    
    getchar(); 

    exit(0);
}

複数ウィンドウを使い分けた図形描画

HandyGraphicでは,複数の描画ウィンドウを開いて,それぞれのウィンドウを使い分けながら図形描画させることが出来る.そのような描画を行うには,引数にウィンドウidを指定した描画用関数を用いる.

標準ウィンドウに描く関数の名前がHg...()となっているのに対し,ウィンドウを指定して描く関数ではHgW...()というようにHgに続いてWが追加された関数名となる.例えば標準ウィンドウへ直線を引く場合は,

int HgLine( x0, y0, x1, y1 ); 
    double x0: 始点のx座標
    double y0: 始点のy座標
    double x1: 終点のx座標
    double y1: 終点のy座標

を用いるが,ウィンドウを指定して直線を描画する場合は,HgWLine()関数を用いる.

int HgWLine( wid, x0, y0, x1, y1 ); 
    int wid: 描画させるウィンドウのid
    double x0: 始点のx座標
    double y0: 始点のy座標
    double x1: 終点のx座標
    double y1: 終点のy座標

例えばスクリーン座標で(x,y) = (200, 150)の点を左下隅とする幅300,高さ300の描画ウィンドウAと,(x,y) = (600, 150)の点を左下隅とする幅200,高さ200の描画ウィンドウBの両方を表示して,ウィンドウAには(100, 100)から(200, 200)までの赤い直線を引き,ウィンドウBには(100, 100)を中心として半径50の黄色輪郭で青く塗りつぶた円を描いて一旦停止した後,キ−ボ−ドから何かのキ−がタイプされると終了するプログラム window,c は以下のようになる.

/*        */

#include  <stdio.h>
#include  <stdlib.h>
#include  <handy.h>

int main()
{
  int w_a;
  int w_b;

  w_a = HgWOpen(200, 150, 300, 300);
  printf("DEBUG: w_a = %d¥n", w_a); // 変数w_aの値の確認
  w_b = HgWOpen(600, 150, 200, 200);
  printf("DEBUG: w_b = %d¥n", w_b); // 変数w_bの値の確認

  HgWSetColor(w_a, HG_RED); /* 赤色で描画 */
  HgWLine(w_a, 100, 100, 200, 200); 

  HgWSetColor(w_b, HG_YELLOW); /* 黄色で描画 */
  HgWSetPaintColor(w_b, HG_BLUE); /* 青色で塗り潰し */
  HgWSetWidth(w_b, 5); /* 太さを5に設定 */
  HgWCircleFill(w_b, 100, 100, 50, 1); /* 輪郭線有りの塗りつぶし円 */

  getchar(); 

  exit(0);

}

その他

図形を PDFファイルへ保存

HgDisplayerのメニューから「描画」→「画像を保存」と選択するとPDF形式のファイルとして保存する事が出来る,また,関数HgSave()を用いて,ウィンドウ内の図形をPDFファイルへ保存するように指示できる.

int HgSave ( name )
    char *name: 保存先のファイル名

nameには、EPS形式のデータを保存するファイル名を指定する.正常終了時の戻り値は0である.

ウィンドウの図形消去

HgClear()は全ての描画ウィンドウ内を消去する関数である.

int HgClear( )

尚,正常終了時の返値は0である.

キーイベントの取得

簡単なゲームプログラムなどを作りたい場合,キーボードからの入力が取り扱えると便利である.Unixの標準では,getchar()関数はリターンキーをタイプしないとキー入力を読み込んでくれないため,ゲーム開発などには不向きである.HandyGraphicには,キー入力イベントを簡単に取り扱うための関数HgGetChar()が用意されている.

int HgGetChar( )

この関数の返り値は,押されたキーの文字に対応する文字コード(ASCIIコード)の数値であり,例えば,aキーを押すと,'a'の文字コード値97が返される.

但し,このHgGetChar()関数は簡易的なキー入力処理だけを目的としているので,ごく簡単なゲームプログラムなどでの利用に留めたほうが良く,本格的なイベント処理にはHgEvent()関数を用いる事が推奨される.詳細は,HandyGraphicユーザーズガイドを参照のこと.

HandyGraphicライブラリを用いたプログラムの作成とコンパイル

HandyGraphicライブラリを自分のC言語プログラムで使用する場合,2つの約束事に従う必要がある.

その1 HandyGraphic用関数宣言ヘッダファイルをインクル−ド

プログラムの先頭部分に,

#include <handy.h>

という行を忘れずに加えておくこと.

その2 コンパイルにはHandyGraphic専用コマンド hgcc を使用

HandyGraphicライブラリの関数を呼び出しているプログラムをコンパイルするには,hgccというコマンドをgccコマンドの代りに使う事が必要である.

無事コンパイル出来れば,実行する方法は普通のC言語プログラムの場合と基本的に変わらない.

Mac OS X Mountain Lion環境での注意

Mac OS X Mountain Lion環境にてHandyGraphicライブラリを用いたCソースプログラムをコンパイルすると,プログラムが完全に正しくても以下のようなウォーニング(警告)が出てしまう.

mkbka046(549)$ hgcc anim.c
anim.c:12:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
main() ^‾‾‾ 1 warning generated.

これは,hgccコマンドが内部で呼び出して使っているC言語コンパイラがgccではなくLLVMコンパイラを使っているためである.LLVMでは警告チェックが厳しくなっておりmain関数の記述が最新のC言語規格に合致しないために,このような警告が発せられている.そのため,この警告だけは実害が無いので無視して構わないが,やはり少し気持ち悪い.

そこでmain関数の始まり箇所を最新のC言語規格に準拠させるべく

int main()
{

という具合に少し修正すれば警告は出なくなる.今後はmain関数の記載を上記のスタイルで書くようにしておこう.

ちなみに,最新のC言語規格からすれば,このようにmain関数の返値はintであると記述する方が規格的には正しい.教科書の記載は少し古いのだ.
また,HandyGraphicを使わない普通のC言語プログラムであっても同様に修正してもgccコマンドで全く問題なくコンパイル出来る.

図形描画の色や線幅の変更の考え方

HandyGraphicでのグラフィック図形での色指定や線幅などは,美術の時間に画用紙に絵筆で絵を描いているようなイメージで考えてください.

太い線を描きたければ,まず太い筆に持ち替えてから描くでしょう? もし赤い色を塗りたければ,まず赤い絵の具を筆に付けてから描きますよね?また,太い筆を持っている間は太い線しか描けなくて,細かいところを描きたければ,細い筆に持ち替えてから描くと思います.

HandyGraphicでは次のように色や線幅を取り扱います.

  1. プログラムが起動した直後は, となっている.(つまり,画用紙に絵を描き始める時は,細い筆で黒い絵の具を付けた状態)
  2. 線幅や色を変えた図形を描く場合には,
    1. HgSetColor関数などを使って,色や線幅を「予め」指定する.
    2. 続いて,図形を描く関数(HgCircle関数など)を実行して,先に指定しておいた幅や色で図形を描画する.
    という順番で各関数を実行する.(つまり,太さが違う筆に持ち替えた,或いは,違う色の絵の具を筆に付けた状態)
  3. プログラムで線幅や描画色を変更すると,再度変更するまでは,その変更した状態が維持されて,同じ線幅や同じ色で各図形は描画され続ける.(つまり,別の筆に持ち替える,又は,違う絵の具を付けるまでは,同じ幅・色で描画し続ける)

練習問題

適当な作業用ディレクトリを作り,以下のプログラムを作成してコンパイル・実行してみよ.

練習1

上記の説明に出てきたプログラム例handy.cが

として置いてあるので,これを手元にコピーしてEmacsで開いてプログラムコードを確認せよ.

コードを確認したらコンパイル・実行してみて,どのように動作するプログラムなのか自分なりに理解せよ.

練習2

上記の説明に出てきたプログラム例window.cが

として置いてあるので,これを手元にコピーしEmacsで開いてプログラムコードを確認せよ.

コードを確認したらコンパイル・実行してみて,どのように動作するプログラムなのか自分なりに理解せよ.

補足:window.cには,プログラムの実行にはあまり関係ないが,変数の値を画面表示して確認するためのprintf関数を実行している個所がある.このように,プログラムが動作している途中の要所々々でプログラムが自分の思った通りに動作しているかどうか変数の値などをメッセージとして表示させてみると,間違いの発見の手助けになる.このようなメッセージ表示を「デバッグメッセージ」と呼ぶ.

練習3

以下の練習問題では,描画ウィンドウとして幅300,高さ300の標準ウィンドウを想定し,各図形の座標値はウィンドウ座標にて表されているとする.

(150,150), (250,150), (250,250), (150, 250)を頂点とする正方形を線の太さ1の黒線にて描くプログラムsimple_square.cを作成してみよ.

練習4

(150, 200)を中心とする赤い円, (200, 200)を中心とする緑の円, (250, 200)を中心とする青い円をそれぞれ接するよう描くプログラムtriple_circle.cを作成せよ.但し,円の半径は全て同じとする.

提出課題

その1

(150,150), (250,150), (250,250), (150, 250)を頂点とする青く塗りつぶした正方形とそれに内接する黄色く塗りつぶした円を下図のように描くプログラムsquare.cを作成せよ.

提出はmoodle学習支援システムを利用して,ソースプログラムを提出すること.コンパイルして作成された実行可能形式プログラムを提出しても,基本的に評価対象外です.

課題名:  program/square

締切り期限:教員の指示による

その2

scanf関数を用いて,中心のX座標,Y座標,半径の3つを入力させ,下図のようなそれらの数値に応じた円とそれに内接する菱形,外接する正方形を描画するプログラムscanf.cを作成せよ.但し,全ての図形は塗りつぶし無し,線の太さは1とし,色指定は,円は黒,ひし形はオレンジ色,正方形は紫色とせよ.(ヒント: ひし形は直線を4本引くことを考えよ.)

提出はmoodle学習支援システムを利用して提出すること.

課題名: program/scanf

締切り期限:教員の指示による

注: scanf関数の後で,getchar関数を実行すると,少し奇妙な事(getchar関数のところで一旦停止してくれない.)が起こります.その例を として置いているので,参考にしてください.

その3

高さ600,幅600の描画用ウィンドウを開き,この描画ウィンドウ内にウィンドウ座標(300, 300)を中心とする半径100, 半径150, 半径200, 半径250, 半径300となる五個の同心円を描くプログラム forcircle.c をfor文を利用して作成せよ.ウィンドウ背景色は白色,描画色は緑色とする.提出はmoodle学習支援システムを用いること.

ヒント: 教科書pp.84の図5.4が参考になる.半径rについて50, 100, 150, 200, 250, 300というように,rを50づつ変化させながら円を描画することを考えてみよ.

課題名:program/forcircle

提出期限:教員の指示による

forcircle

基礎プログラミング演習Iの表紙ページへ戻る