• 検索結果がありません。

ラムの学習環境は次のようなものがある. OS が Microsoft Windows の場合では Visual Studio が標準的な開発環境であり, コンパイラ, ライブラリ, デバッガ, エディタなどの開発に必要なツールが統合化されている. また複数の言語 (C, C++, C#, Pytho

N/A
N/A
Protected

Academic year: 2021

シェア "ラムの学習環境は次のようなものがある. OS が Microsoft Windows の場合では Visual Studio が標準的な開発環境であり, コンパイラ, ライブラリ, デバッガ, エディタなどの開発に必要なツールが統合化されている. また複数の言語 (C, C++, C#, Pytho"

Copied!
25
0
0

読み込み中.... (全文を見る)

全文

(1)

2.1 イベント駆動型プログラミング

2.1.1 フロー駆動型とイベント駆動型

プログラムは上から下へのフロー(流れ)に従って実行される.このようなプログラムを

フロー駆動型プログラムと呼ぶ.それに対し,イベント(出来事)に応じで対応する処理が

実行されるプログラムをイベント駆動型プログラムと呼ぶ.イベントの例はマウスのボタ

ンが押さる,マウスの座標位置が変わる,キーが押される,画面の表示が変わる,時間 1ms

経過したなどである.イベントが発生すると,OS 内にその情報を含むメッセージが生成さ

れる.イベント駆動型プログラムは常にメッセージを監視しており,対応すべきメッセージ

を受信するとその処理を行う.イベント駆動型プログラムに必要なことは,イベントの監視

をすること,そしてイベントに対応する処理を記述することである.

フロー駆動型プログラム イベント駆動型プログラム

OS

Fig.2.1.1. フロー駆動型プログラムとイベント駆動型プログラム.

X Window や Microsoft Windows で動作する殆どのプログラムはウィンドウにボタン,ラジ

オボタン,スライダ,スイッチなどの部品が備えられており,それらの状態の変化に応じて

様々な情報処理が行われる.このようなアプリケーションはイベント駆動型プログラムで

ある.

2.1.2 開発ツール

本授業の目的の 1 つは現在主流となっているイベント駆動型プログラミングの概念を理

解して,その基本的プログラムが作成できるようになることである.イベント駆動型プログ

イベントの監視

処理 B

処理 A

処理 C

処理 D

メッセージ

処理 A

処理 C

処理 B

(2)

ラムの学習環境は次のようなものがある.

OS が Microsoft Windows の場合では Visual Studio が標準的な開発環境であり,コンパイ

ラ,ライブラリ,デバッガ,エディタなどの開発に必要なツールが統合化されている.また

複数の言語(C, C++, C#, Python, Java Script, Visual Basic など)を使ってプログラミングがで

き,アプリケーションが動作するターゲットとなる OS についても選択肢(Windows,iOS,

Android や Linux)が広い.例えば Visual Studio Community 2013 は個人開発者や大学関係者

は無償で使用できる.

OS が UNIX 系(Ubuntu, Debian, Fedora など)の場合では GCC(GNU C Compiler)

,GNU

デバッガ,テキストエディタ,X Window 用ライブラリ(Xlib)が標準的にインストールさ

れており,それらが使用できる.プログラミングの作業の多くは端末上でのコマンド処理に

よって行われる.開発に必要なライブラリ,例えば X ツールキット(Motif,GTK+,Qt な

ど)は自らインストールすることになる.

また OS の種類に依存しない統合開発環境としては Eclipse が挙げられる.

本授業では Unix 上で Xlib を使用した X Window プログラミングをとおしてイベント駆動

型プログラミングの学習を行う.Xlib を学ぶ利点は次のとおりである.

(M1)フリーで,入手性がよく,開発に関する情報が多い.

(M2)1984 年,マサチューセッツ工科大学で X が開発されて以降,現在においてもその基盤

技術として標準的に使用されている実績があるため,今後も長く Xlib を利用できるこ

とが期待できる.

(M3) Xlib を学ぶことによって開発者レベルの学習経験が得られる.

2.2 Xlib

UNIX(あるいは Linux)では X Window システムが使用されている.これは画面,キーボ

ードやマウスなどの入出力装置を管理する役割の一面をもつ.X Window システム上のアプ

リケーションは様々なライブラリを使用して作られているが,その内最も基本的なライブ

ラリが Xlib である.Xlib はウィンドウの表示,線や円など簡単なグラフィックスを描く機

能を提供し,またキーボードやマウスの情報を扱うこともできる. Xlib についての情報源

を以下に記す.

Table of contents for Xlib Programming Manual:http://www.sbin.org/doc/Xlib/

Xlib programming manual: function index:

http://tronche.com/gui/x/xlib/function-index.html

2.3 クライアント・サーバモデル(client-server model)

(3)

側であり,サーバはそれを受け入れる側である.両者が通信によって接続したシステムを

(ソフトウェアモデルの観点から)クライアント・サーバモデルと呼ぶ.クライアントとサ

ーバの存在する場所はそれぞれ離れている場合もあるし同一の計算機上の場合もある.

X Window システムはクライアント・サーバモデルである.情報の流れの例を下の図に示

す.クライアントは C のプログラムである.例えばウィンドウを表示して線の描画をする

とき,C のプログラムは Xlib を介してそれを実行する.線の色や太さなど,図形の属性の

情報は Graphics Context(GC)にセットされる.

(CG は通信の効率化をはかる役割をもつ.)

クライアントの要求はサーバに伝えられ,サーバはディスプレイ上に表示を行う.次にサー

バは関連の情報(イベントのメッセージ)をクライアントへ送る.

クライアントとサーバではこのようなやり取りが頻繁に行われる.

Fig.2.3.1. クライアント・サーバモデル.

ここからは実際に X Window プログラムのリストを読み,コンパイル,実行,そしてプロ

グラムの動作確認を各自で行っていく.X Window で線や円などの簡単な図形を表示する方

法,マウスのポインタの位置やそのボタンの状態を検出する方法など学ぶ.幾つかのサンプ

ルプログラムの学習をとおして,基本的なイベント駆動型プログラムが作成できるようす

る.

ウィンドウの表示の要求

線の描画の要求

マウスポインタの移動の要求

etc.

GC

クライアント

(C のプログラム)

Xlib

サーバ

(X サーバ)

イベント情報 ウィンドウ情報の提供(再描画したなど) マウス情報の提供(ポインタの位置・ボタンの状態) キーボード情報の提供

etc.

(4)

3.0 プログラムの解析と,そのコンパイルおよび実行の手順

3.01 プログラムの解析

エディタでプログラムを開く.プログラムのコメント部分を参考にしてその動作を理

解する.不明な点,例えばステートメントの意味やそのオプションは man コマンドで調

べられる.例えばリスト中のステートメント,Display が不明であれば,端末で次の様に

して調べる.

man Display [Enter]

(man と Display の間にはスペースを入れる.[Enter]はエンターキーを押すことを意味する.)

(ただし,もしシステムにマニュアルがインストールされていない場合には何も表示さ

れない.

またブラウザでインターネットから情報を入手できる.

3.02 プログラムのコンパイルおよび実行

ソースコード上部のコメント行にコンパイルの処理内容が記されている.コンパイ

ルするときはその部分をコピーして,端末においてペーストしてコンパイルする.具体

的にはプログラムに次の様な記述があれば,

/* make(ubuntu): gcc 1_showwin.c -o 1_showwin -I/usr/include -L/usr/lib -lX11 */

黄色い部分がコピーの対象である.

コンパイル後,ls コマンドで,実行形式ファイル(例えば 1_showwin)があることを確

認後,それを次のように実行する.

>./1_showwin[Enter]

(5)

3.1 ウィンドウの表示

動作:画面に 1 つのウィンドウを表示する.終了するときには端末画面をマウスでクリック

して選択後,[Enter]キーを押す.

説明:1 つのウィンドウを画面に表示する方法を学ぶ.クライアントプログラムが最初に行

うことはサーバに接続することである.コードの中に次の行がある.

d = XOpenDisplay(NULL);

/* サーバとの接続を確立し,Display 型構造体のポインタを d へセットする */

この関数によってクライアントとサーバとの接続が確立される.引数には接続先サーバの

情報を渡すが,通常 NULL でよい.d には Display 構造体型のポインタがセットされる.以

後,クライアントとサーバ間において構造体 d を介してデータのやり取りが行われる.

Display 型構造体はディスプレイの属性に関するデータを扱う.

次にメモリ上にウィンドウを生成する.

w = XCreateSimpleWindow(d, RootWindow(d, 0), 100, 100, 320, 320, 2, black, white);

/* ウィンドウをメモリ上に生成し,Window 型構造体を w にセットする */

引数は順番に,通信に必要な Display 構造体,親ウィンドウの指定のための Window 型構造

体,座標データ x1, y1, x2, y2,ウィンドウの枠の太さ,枠の色,背景色である.上の例

では座標位置(100, 100)に 320×320 のウィンドウが生成される.Window 型構造体は Window

の属性のデータを扱うためのものである.座標は次のようになる.

(x1, y1)

(x2, y2)

ディスプレイの原点(0, 0)

(6)

次に,メモリ上に生成したウィンドウを画面に表示(マップ)する.

XMapWindow(d, w);

/* 生成したウィンドウを画面に表示(マップ)する */

引数は順番に,通信に必要な Display 構造体,親ウィンドウの指定のための Window 型構

造体である.これを実行しないと,ウィンドウは表示されない.

そして最後にバッファのフラッシュが行われる.

XFlush(d);

引数は通信に必要な Display 構造体である.サーバとクライアント間では常に通信が行われ

ており,命令はバッファに逐次蓄積される.データがある程度バッファに蓄積されると,デ

ータは一括してサーバへ送信される.この仕組みにより通信の効率化をはかっている.つま

りプログラムの最後に Xflush 命令を実行して,バッファに蓄えられている全てのデータを

サーバへ強制的に送信して,プログラムを完全に動作させる必要がある.

/* title: 1_showwin.c */ /* date: 2012/09/16 */

/* make: gcc 1_showwin.c -o 1_showwin -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 */ /* make(ubuntu): gcc 1_showwin.c -o 1_showwin -I/usr/include -L/usr/lib -lX11 */

#include<X11/Xlib.h> /* ライブラリのインクルード */ #include<X11/Xutil.h> /* ライブラリのインクルード */ main() { Display *d; /* display 型構造体 d の宣言 */ Window w; /* window 型構造体 w の宣言 */ int black, white;

d=XOpenDisplay(NULL); /* d とサーバを対応させる */

black=BlackPixel(d, 0); /* black に黒色コードを割り当てる */ white=WhitePixel(d, 0); /* white に白色コードを割り当てる */

w=XCreateSimpleWindow(d, RootWindow(d, 0), 100, 100, 320, 320, 2, black, white); /* ウィンドウを生 成し、w とウィンドウを対応させる */

XMapWindow(d, w); /* 生成したウィンドウを画面に表示する */ XFlush(d); /* バッファをフラッシュする */

getchar(); /* 画面がすぐ消えないようにするため、文字入力処理を入れる */ }

(7)

3.2 Line を引く

動作:1 つのウィンドウを表示し,ラインを 1 本引く.終了するときにはマウスでウィンド

ウをクリックする.

説明:ラインの描画とマウスのイベント処理を学ぶ.コードの中に次の行がある.

gc = XCreateGC(d, w, 0, 0);

/* グラフィックコンテキストを生成し,GC 型構造体を gc へセットする */

パラメータは順番に,通信に必要な Display 構造体,親ウィンドウの指定のための Window

型構造体,unsigned long 型の数値,XGCValues 型の数値である.最後の 2 つはともに 0 とす

ればデフォルト値が設定される.上は Graphics Context(GC)を生成するための命令であり,

生成された GC 型構造体が変数 gc にセットされる.GC は図形の属性,線の種類や太さなど

に関するデータを扱う目的で利用される.GC を使用する利点は「変更された属性の情報の

みを通信でやり取りすることにより通信の負荷を小さくすること」である.

コードの中に次の行がある.

XSelectInput(d, w, ExposureMask | ButtonPressMask);

/* 取り込むイベントの指定 */

これはチェックするイベント情報の指定を行っている.パラメータは順番に,通信に必要

な Display 構造体,親ウィンドウの指定のための Window 型構造体,そのあとは取り込む

イベント名のリストを「|」で区切って列挙する.

「|」は[Back Space]キーの左側のキー

に割り当てられている.ExposureMask はウィンドウが表示(マップ)されたときに発生す

るイベントを検出するために指定される.

(画面がマップされたとき,画面のクリアが実

行されるので,その後に図形描画の命令を実行することになる.つまりマップが実行され

たか否かを検出する必要がある.

) ButtonPressMask はマウスのボタンがクリックされた

ときに発生するイベントを検出するために指定される.OS 内では多量のメッセージがや

り取りされる.チェックすべきイベントをここで選択する.本プログラムではこれら 2 つ

のメッセージのみを監視してそれに対応する処理を行っている.

while(1)

引数は 1 である.偽:0,真:0 以外.つまり( )の中は常に真なので,無限ループを形成し

ている.while の中でイベントを拾い,イベントに応じた処理が行われる.

(8)

XNextEvent(d, &e);

/* サーバからのイベントの取り込み */

パラメータは順番に,通信に必要なDisplay構造体,XEvent構造体である.これによりサー

バから届くイベントをXEvent構造体であるeに格納する.

if

(e.type == Expose)

/* 画面が表示(マップ)されるイベントが発生したときの処理 */

if

(e.type == ButtonPress)

/* マウスのボタンが押されるイベントが発生したときの処理 */

上はXEvent構造体eのメンバ変数typeを調べ,イベントの種類に応じた処理の制御を行って

いる.

XDrawLine(d, w, gc, 10, 10, 310, 310);

上は線を引くための命令で,パラメータは順番に,通信に必要な Display 構造体,親ウィン

ドウの指定のための Window 型構造体,CG 構造体,x1, y1, x2, y2 となる.(x1, y1) - (x2,

y2)間の線が引かれる.

XCloseDisplay(d);

/* ウィンドウの使用の終了 */

上は安全にウィンドウを閉じるための処理を自動で行う命令である.パラメータは通信に

必要な Display 構造体である.上が実行されると,XFlash を実行したのと同じ効果,つま

りバッファにあるデータが全て送信される.

(9)

/* title: 1/* title: 2_drawline1.c */ /* date: 2012/09/16 */

/* make: gcc 2_drawline1.c -o 2_drawline1 -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 */ /* make(ubuntu): gcc 2_drawline1.c -o 2_drawline1 -I/usr/include -L/usr/lib -lX11 */

#include<X11/Xlib.h> /* ライブラリのインクルード */ #include<X11/Xutil.h> /* ライブラリのインクルード */ main() { Display *d; /* display 型構造体 d の宣言 */ Window w; /* window 型構造体 w の宣言 */ int black, white;

GC gc; /* GC 型構造体 gc の宣言 */

XEvent e; /* XEvent 型構造体 e の宣言 */

d=XOpenDisplay(NULL); /* d とサーバを対応させる */

black=BlackPixel(d, 0); /* black に黒色コードを割り当てる */ white=WhitePixel(d, 0); /* white に白色コードを割り当てる */

w=XCreateSimpleWindow(d, RootWindow(d, 0), 100, 100, 320, 320, 2, black, white); /* ウィンドウを生成し、w とウィンドウを対応させる */

gc=XCreateGC(d, w, 0, 0); /* グラフィックコンテキストを生成し、それと gc を対応させる */

XSelectInput(d, w, ExposureMask | ButtonPressMask); /* 取り込むイベントの指定 */

XMapWindow(d, w); /* 生成したウィンドウを画面に表示する */ while(1) { /* 無限ループ */ XNextEvent(d, &e); /* サーバからのイベントの取り込み */ if(e.type==Expose) /* 画面のイベントが発生したときの処理 */ { XDrawLine(d, w, gc, 10, 10, 310, 310); } /* 線の表示 */ if(e.type==ButtonPress) /* マウスのイベントが発生したときの処理 */ { break; } /* ループから抜ける */ } XCloseDisplay(d); /* ウィンドウの使用の終了 */ }

(10)

3.3 円弧を描く

動作:画面に 1 つのウィンドウを表示し,円弧を 1 つ描く.画面をマウスでクリックする

と処理が終了する.

説明:円(弧)の描画を学ぶ.プログラムの中に次の行がある.

XDrawArc(d, w, gc, 0, 0, 319, 319, 0, 300*64);

/* 円を描く */

上は円弧を描く命令で,パラメータは順番に,通信に必要な Display 構造体,親ウィンドウ

の指定のための Window 型構造体,CG 構造体,x, y, width, height, angle1, angle2 となる.x, y

は円弧を規定する長方形の左上の頂点の座標,続いて円弧の横幅,縦幅,angle1 は描画開始

角度,angle2 はその終了角度である.0 から 300deg の弧を描く.

(ただし角度の最小単位は

1/64 deg であり,300*64 の計算は 300 deg を意味する.

height

width

/* title: 3_circle1.c */ /* date: 2012/09/16 */

/* make: gcc 3_circle1.c -o 3_circle1 -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 */ /* make(ubuntu): gcc 3_circle1.c -o 3_circle1 -I/usr/include -L/usr/lib -lX11 */ #include<X11/Xlib.h> /* ライブラリのインクルード */

#include<X11/Xutil.h> /* ライブラリのインクルード */

int redraw(Display *d, Window w, GC gc) /* 描画部分を副関数で実現している */ { XDrawArc(d, w, gc, 0, 0, 319, 319, 0, 300*64); /* 円をかく */ } main() { Display *d; /* display 型構造体 d の宣言 */ Window w; /* window 型構造体 w の宣言 */ GC gc; /* GC 型構造体 gc の宣言 */ XEvent e; /* XEvent 型構造体 e の宣言 */ d=XOpenDisplay(NULL); /* d とサーバを対応させる */

w=XCreateSimpleWindow(d, RootWindow(d, 0), 100, 100, 320, 320, 2, BlackPixel(d, 0), WhitePixel(d, 0)); /* ウィンドウを生成し、w とウィンドウを対応させる */

gc=XCreateGC(d, w, 0, 0); /* グラフィックコンテキストを生成し、それと gc を対応させる */

XSelectInput(d, w, ExposureMask | ButtonPressMask); /* 取り込むイベントの指定 */ XMapWindow(d, w); /* 生成したウィンドウを画面に表示する */ while(1) { /* 無限ループ */ XNextEvent(d, &e); /* サーバからのイベントの取り込み */ if(e.type==Expose) /* 画面のイベントが発生したときの処理 */ { redraw(d, w, gc); } /* 図の表示 */ if(e.type==ButtonPress) /* マウスのイベントが発生したときの処理 */ { break; } /* ループから抜ける */ } XCloseDisplay(d); /* ウィンドウの使用の終了 */ }

(11)

3.4 太い円弧を描く

動作:画面に 1 つのウィンドウを表示し,太い円弧を 1 つ描く.終了するときにはマウスで

ウィンドウをクリックする.

説明:線の太さを変えることを学ぶ.コードの中に次の行がある.

XSetLineAttributes(d, gc, 50, LineSolid, CapButt, JoinMiter); /* アトリビュートの設定 */

上は線の属性(太さなど)を変える命令で,パラメータは順番に,通信に必要な Display 構

造体,CG 構造体,ラインの太さを指定する unsigned int 型の数値,ラインスタイルを指定す

る int 型の数値,線の端の形状を指定する int 型の数値,線分の結合様式を指定する int 型の

数値となる.ラインの属性を幾つか変えてその機能を確認する.

/* title: 4_circle2.c */ /* date: 2012/09/16 */

/* make: gcc 4_circle2.c -o 4_circle2 -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 */ /* make(ubuntu): gcc 4_circle2.c -o 4_circle2 -I/usr/include -L/usr/lib -lX11 */ #include<X11/Xlib.h> /* ライブラリのインクルード */

#include<X11/Xutil.h> /* ライブラリのインクルード */ int redraw(Display *d, Window w, GC gc)

{

XSetLineAttributes(d, gc, 50, LineSolid, CapButt, JoinMiter); /* アトリビュートの設定 */ XDrawArc(d, w, gc, 0, 0, 319, 319, 0, 300*64); /* 円をかく */ } main() { Display *d; /* display 型構造体 d の宣言 */ Window w; /* window 型構造体 w の宣言 */ GC gc; /* GC 型構造体 gc の宣言 */ XEvent e; /* XEvent 型構造体 e の宣言 */ d=XOpenDisplay(NULL); /* d とサーバを対応させる */

w=XCreateSimpleWindow(d, RootWindow(d, 0), 100, 100, 320, 320, 2, BlackPixel(d, 0), WhitePixel(d, 0)); /* ウィンドウを生成し、w とウィンドウを対応させる */

gc=XCreateGC(d, w, 0, 0); /* グラフィックコンテキストを生成し、それと gc を対応させる */

XSelectInput(d, w, ExposureMask | ButtonPressMask); /* 取り込むイベントの指定 */ XMapWindow(d, w); /* 生成したウィンドウを画面に表示する */ while(1) { /* 無限ループ */ XNextEvent(d, &e); /* サーバからのイベントの取り込み */ if(e.type==Expose) /* 画面のイベントが発生したときの処理 */ { redraw(d, w, gc); } /* 図の表示 */ if(e.type==ButtonPress) /* マウスのイベントが発生したときの処理 */ { break; } /* ループから抜ける */ } XCloseDisplay(d); /* ウィンドウの使用の終了 */ }

(12)

3.5 多角形を描く 1

動作:1 つのウィンドウを表示し,線によって多角形を 1 つ描く.ウィンドウのサイズを変

更してもそれに応じて描画された図形の大きさは変化しない.画面をマウスでクリックす

ると処理が終了する.なお実行する場合にはコマンドの後に角数を渡して実行する.

(例)5 角形を描く

>./6_showpol2 5[Enter]

説明:構造体配列へ複数の座標データを確保する方法を学ぶ.コードの中に次の行がある.

XPoint top[MAX_POS+1]; /* 座標データ */

上は XPonit 構造体型の変数 top を宣言している.その構造体は Xlib.h に次のように定義さ

れている.

typedef struct {

short x, y;

} XPoint;

上は X-Y 平面のある 1 点の座標データを格納できる.従ってその配列を使うと,多数の座

標データ x

i

, y

i

( i=1, 2, … )を扱うことができる.プログラムでは次のようにして多角形の頂

点の座標データを蓄積している.

for(i=0; i<=n; i++) {

/* 座標データを配列に代入する */

top[i].x=WIN_WIDTH /2+(WIN_WIDTH /2-10)*cos(th);

/* 座標の計算 */

top[i].y=WIN_HEIGHT/2-(WIN_HEIGHT/2-10)*sin(th);

/* 座標の計算 */

th+=dt;

}

WIN_WIDTH /2 と WIN_HEIGHT/2 はウィンドウの横幅あるいは高さの半分を意味する.ま

た WIN_WIDTH /2-10 は外枠から少し内側の位置を意味する.

上の配列 top は XDrawLines()で参照される.

XDrawLines(d, w, gc, top, n, CoordModeOrigin);

/* ラインの描画 */

配列 top を渡すことによって線による多角形を描画する.(for ループで Line 文を回すこと

なく便利である)

(13)

XSetLineAttributes(d, gc, 50, LineSolid, CapButt, JoinMiter); /* アトリビュートの設定 */

上は線の属性(太さなど)を変える命令で,パラメータは順番に,通信に必要な Display 構

造体,CG 構造体,ラインの太さを指定する unsigned int 型の数値,ラインスタイルを指定す

る int 型の数値,線の端の形状を指定する int 型の数値,線分の結合様式を指定する int 型の

数値となる.

/* title: 6_showpol2.c */ /* date: 2012/09/16 */

/* make: gcc 6_showpol2.c -o 6_showpol2 -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 -lm*/ /* make(ubuntu): gcc 6_showpol2.c -o 6_showpol2 -I/usr/include -L/usr/lib -lX11 -lm */

/* -lm は math.h をリンクするため */ #include<X11/Xlib.h> /* ライブラリのインクルード */ #include<X11/Xutil.h> /* ライブラリのインクルード */ #include<math.h> /* ライブラリのインクルード */ #include<stdio.h> /* ライブラリのインクルード */ #define MAX_POS 50 /* 頂点の数の上限.50 を超えると円と見分けがつかない */ #define WIN_WIDTH 320 /* ウィンドウの横幅 */ #define WIN_HEIGHT 320 /* ウィンドウの縦幅 */ int redraw(Display *d, Window w, GC gc, XPoint top[], int n)

{

XClearWindow(d, w);

/* ウィンドウをクリアする */

XDrawLines(d, w, gc, top, n, CoordModeOrigin); /* ラインの描画 */ }

main(int argc, char **argv) { Display *d; /* display 型構造体 d の宣言 */ Window w; /* window 型構造体 w の宣言 */ GC gc; /* GC 型構造体 gc の宣言 */ XEvent e; /* XEvent 型構造体 e の宣言 */ int i, n; double th=0, dt; XPoint top[MAX_POS+1]; /* 座標データ */ if(argc<=1) {

fprintf(stderr, "usage: %s <number of tops>¥n", argv[0]);

exit(1); /* パラメータが 1 以下の時はプログラムの終了 */ }

sscanf(argv[1], "%d", &n); /* プログラム実行時に与えたパラメータから n 角形の n を抽出する */ if(n>=MAX_POS) {

fprintf(stderr, "Sorry, parameter must be less than %d.¥n", MAX_POS);

exit(1); /* パラメータが 50 以上の時はプログラムの終了 */ }

dt=(2*M_PI)/n; /* 角度の刻み値を求める */

for(i=0; i<=n; i++) { /* 座標データを配列に代入する */

top[i].x=WIN_WIDTH /2+(WIN_WIDTH /2-10)*cos(th); /* 座標の計算 */ top[i].y=WIN_HEIGHT/2-(WIN_HEIGHT/2-10)*sin(th); /* 座標の計算 */ th+=dt;

}

d=XOpenDisplay(NULL); /* d とサーバを対応させる */

w=XCreateSimpleWindow(d, RootWindow(d, 0), 100, 100, WIN_WIDTH, WIN_HEIGHT, 2, BlackPixel(d, 0), WhitePixel(d, 0)); /* ウィンドウを生成し、w とウィンドウを対応させる */

gc=XCreateGC(d, w, 0, 0); /* グラフィックコンテキストを生成し、それと gc を対応させる */ XSelectInput(d, w, ExposureMask | ButtonPressMask); /* 取り込むイベントの指定 */

XMapWindow(d, w); /* 生成したウィンドウを画面に表示する */ while(1) { /* 無限ループ */ XNextEvent(d, &e); /* サーバからのイベントの取り込み */ if(e.type==Expose) /* 画面表示時のイベントが発生したときの処理 */ { redraw(d, w, gc, top, n+1); } /* 図の表示 */ if(e.type==ButtonPress) /* マウスのイベントが発生したときの処理 */ { break; } /* ループから抜ける */ } XCloseDisplay(d); /* ウィンドウの使用の終了 */ }

(14)

3.6 多角形を描く 2

動作:1 つのウィンドウを表示し,多角形を 1 つ描く.ウィンドウのサイズを変更すると,

それに応じて図形の大きさも調整されて表示される.画面をマウスでクリックすると処理

が終了する.なお実行する場合にはコマンドの後に角数を渡して実行する.

(例)5 角形を描く

>./7_showpol3 5[Enter]

説明:

「多角形を描く 1」では,ウィンドウの大きさを変更しても図形の大きさは変わらな

い.ここではウィンドウの大きさの情報を監視し,それに応じて図形の大きさも変化させる

ことを行う.ウィンドウサイズの変更が生じると,イベント:ConfigureNotify が生成される

ので,次のように新しく取り込むイベントについてマスクする.

XSelectInput(d, w, ExposureMask | ButtonPressMask | StructureNotifyMask); /* 取り込むイベントの指定 */

上でこの情報を監視する設定を行う.もしそのイベントが生じた際には次の処理がされる.

if

(e.type==ConfigureNotify) {

/* 画面の大きさの変化のイベントが発生したときの処理 */

xsiz=e.xconfigure.width;

/* ウィンドウの横の長さの情報を取得 */

ysiz=e.xconfigure.height;

/* ウィンドウの縦の長さの情報を取得 */

recalc(top, n, xsiz, ysiz);

/* 座標の再計算 */

redraw(d, w, gc, top, n+1);

/* 画面の再描画 */

}

イベント構造体のメンバ変数:.xconfigure.width, .xconfigure.height を調べてウィンドウの大

きさの情報が得られる.その後,図形座標の再計算,recalc()を行い,再描画, redraw()を行

う.

/* title: 7_showpol3.c */ /* date: 2012/09/17 */

/* make: gcc 7_showpol3.c -o 7_showpol3 -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 -lm*/ /* make(ubuntu): gcc 7_showpol3.c -o 7_showpol3 -I/usr/include -L/usr/lib -lX11 -lm */

/* -lm は math.h をリンクするため */ #include<X11/Xlib.h> /* ライブラリのインクルード */ #include<X11/Xutil.h> /* ライブラリのインクルード */ #include<math.h> /* ライブラリのインクルード */ #include<stdio.h> /* ライブラリのインクルード */ #define MAX_POS 50 /* 頂点の数の上限 */ #define WIN_WIDTH 320 /* ウィンドウの横幅 */ #define WIN_HEIGHT 320 /* ウィンドウの縦幅 */ int redraw(Display *d, Window w, GC gc, XPoint *top, int n) /* 画面の再描画 */ {

XClearWindow(d, w);

/* ウィンドウをクリアする */

XDrawLines(d, w, gc, top, n, CoordModeOrigin); /* ラインの描画 */ }

(15)

int recalc(XPoint *top, int n, int xsiz, int ysiz) /* 座標の再計算 */ {

int i;

double th=0, dt; dt=(2*M_PI)/n; for(i=0; i<=n; i++) {

th+=dt;

top[i].x=xsiz/2+(xsiz/2-10)*cos(th); /* ウィンドウのサイズに応じた座標の計算 */ top[i].y=ysiz/2+(ysiz/2-10)*sin(th); /* ウィンドウのサイズに応じた座標の計算 */ }

}

main(int argc, char **argv) { Display *d; /* display型構造体dの宣言 */ Window w; /* window型構造体wの宣言 */ GC gc; /* GC型構造体gcの宣言 */ XEvent e; /* XEvent型構造体eの宣言 */ int i, n; double th=0, dt; XPoint top[MAX_POS+1]; /* 座標データ */

int xsiz=WIN_WIDTH, ysiz=WIN_HEIGHT; /* ウィンドウサイズを保持する変数 */

if(argc<=1) {

fprintf(stderr, "usage: %s <number of tops>¥n", argv[0]); exit(1); /* プログラムの終了 */ }

sscanf(argv[1], "%d", &n); /* 配列からnを抽出する */ if(n>=MAX_POS) {

fprintf(stderr, "Sorry, parameter must be less than %d.¥n", MAX_POS); exit(1); /* プログラムの終了 */

}

recalc(top, n, xsiz, ysiz); /* 座標の再計算 */

d=XOpenDisplay(NULL); /* dとサーバを対応させる */

w=XCreateSimpleWindow(d, RootWindow(d, 0), 100, 100, WIN_WIDTH, WIN_HEIGHT, 2, BlackPixel(d, 0), WhitePixel(d, 0)); /* ウィンドウを生成し、wとウィンドウを対応させる */

gc=XCreateGC(d, w, 0, 0); /* グラフィックコンテキストを生成し、それとgcを対応させる */ XSelectInput(d, w, ExposureMask | ButtonPressMask | StructureNotifyMask); /* 取り込むイベントの指定 */ XMapWindow(d, w); /* 生成したウィンドウを画面に表示する */ while(1) { /* 無限ループ */ XNextEvent(d, &e); /* サーバからのイベントの取り込み */ if(e.type==ConfigureNotify) { /* 画面の大きさの変化のイベントが発生したときの処理 */ xsiz=e.xconfigure.width; /* ウィンドウの横の長さの情報を取得 */ ysiz=e.xconfigure.height; /* ウィンドウの縦の長さの情報を取得 */ recalc(top, n, xsiz, ysiz); /* 座標の再計算 */

redraw(d, w, gc, top, n+1); /* 画面の再描画 */ } if(e.type==Expose) /* 画面のイベントが発生したときの処理 */ { redraw(d, w, gc, top, n+1); } /* 図の表示 */ if(e.type==ButtonPress) /* マウスのイベントが発生したときの処理 */ { break; } /* ループから抜ける */ } XCloseDisplay(d); /* ウィンドウの使用の終了 */ }

(16)

3.7 弾性反射するボール

動作:1 つのウィンドウを表示し,1 つのボールが壁と床に反射しながら運動する様子を描

く.画面をマウスでクリックすると処理が終了する.実行する際にはコマンドの後にオプシ

ョンを渡すことができる.

(例) ./8_bounce[Enter] オプションを与えずに実行 ./8_bounce -h[Enter] ヘルプメニューでオプションの種類を表示 ./8_bounce –g 5[Enter] g(重力加速度)のオプションを与えて実行 /* title: 8_xbounce.c */ /* date: 2012/09/17 */

/* make: gcc 8_xbounce.c -o 8_xbounce -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 -lm*/ /* make(ubuntu): gcc 8_xbounce.c -o 8_xbounce -I/usr/include -L/usr/lib -lX11 -lm */

/* ‐lmはmath.hをリンクするため */ #include<X11/Xlib.h> /* ライブラリのインクルード */ #include<X11/Xutil.h> /* ライブラリのインクルード */ #include<math.h> /* ライブラリのインクルード */ #include<stdio.h> /* ライブラリのインクルード */ #define WIN_WIDTH 600 /* ウィンドウの横幅 */ #define WIN_HEIGHT 500 /* ウィンドウの縦幅 */ #define REAL_WIDTH 1.2 /* (m), 物理空間の大きさ(横)*/ #define REAL_HEIGHT 1.0 /* (m), 物理空間の大きさ(縦)*/ #define B_RADIUS 30 /* ボールの大きさ */ #define E 0.8 /* 床の弾性係数 */ #define V 2.0 /* 初速度(m/s) */ #define A 0.0 /* 投射角(degree) */ #define G 9.8 /* 加速度(m/s*s) */ #define Y0 0.9 /* 投射高度(m) */ #define DT 0.01 /* 数値積分の区間(時間の刻み値) */ struct Ball {

double x, y, vx, vy; /* x座標、y座標、xの速度成分、yの速度成分 */

};

double toRad(double deg) { return(deg/180*M_PI); } /* radへの変換 */

int draw_ball(Display *d, Window w, GC gc, double x, double y) /* 円を描く */

{

int i, j;

i=x/REAL_WIDTH*WIN_WIDTH; /* ウィンドウ上のX方向の位置 */ j=(REAL_HEIGHT-y)/REAL_HEIGHT*WIN_HEIGHT; /* ウィンドウ上のy方向の位置 */ XSetForeground(d, gc, BlackPixel(d, 0)); /* 図形を描く時の色を黒色にする */ XFillArc(d, w, gc, i, j, B_RADIUS, B_RADIUS, 0, 360*64); /* 黒塗り潰しの円 */ XSetForeground(d, gc, WhitePixel(d, 0)); /* 図形を描く時の色を白色にする */ XDrawArc(d, w, gc, i, j, B_RADIUS, B_RADIUS, 0, 360*64); /* 白色で縁取り */ XFlush(d); /* バッファのフラッシュ */

}

int main(int argc, char *argv[]) /* argc:コマンドラインオプションの数(コマンド自体も含む)*/

{ /* argv[]:それぞれの文字列へのポインタが格納されている*/ Display *d; /* display型構造体dの宣言 */

Window r, w; /* window型構造体r, wの宣言 */ GC gc; /* GC型構造体gcの宣言 */ XEvent evnt; /* XEvent型構造体evntの宣言 */

struct Ball ball; /* Ball型構造体ballの宣言 */

int idx;

(17)

idx=1; /* argv[0]=8_xbounce,argv[n]でn>=1にオプションがセットされる.ここではオプションの種類を */ /* 調べるためにargv[]の開始位置,つまりidx=1としている. */

while(idx<argc) { /* 引き渡されたオプションの数だけループを行う */

if(strcmp(argv[idx], "-h")==0) { /* オプションがhのときはhelp の表示 */ fprintf(stderr, "*** %s¥n", argv[0]);

fprintf(stderr, "options as follows:¥n"); fprintf(stderr, "-h <help>¥n");

fprintf(stderr, "-e <erastic coefficient for floor and wall>¥n"); fprintf(stderr, "-v <initial throw velocity>¥n");

fprintf(stderr, "-a <throw angle in degree : holizontal=0>¥n"); fprintf(stderr, "-g <gravitic constant>¥n");

fprintf(stderr, "see document for more informations.¥n"); exit(1);

} else

if(strcmp(argv[idx], "-e")==0) /* オプションがeのときは弾性率をセットする */ sscanf(argv[++idx], "%lf", &e); /* 弾性係数 */

else

if(strcmp(argv[idx], "-v")==0) /* オプションがvのときは初速度をセットする */ sscanf(argv[++idx], "%lf", &v); /* 投射初速度 */

else

if(strcmp(argv[idx], "-a")==0) /* オプションがaのときは加速度をセットする */ sscanf(argv[++idx], "%lf", &a); /* 投射角 */

else

if(strcmp(argv[idx], "-g")==0) /* オプションがgのときは重力加速度をセットする */ sscanf(argv[++idx], "%lf", &g); /* 重力加速度 */

else {

printf(stderr, "Unknown option : %s¥n", argv[idx]); exit(1);

}

idx++; /* 他のオプションについても調べる */ }

printf("erastic coefficient : %g¥n", e); printf("velocity : %g¥n", v); printf("throw angle : %g¥n", a); printf("gravity : %g¥n", g); ball.x=0; ball.y=Y0; ball.vx=v*cos(toRad(a)); ball.vy=v*sin(toRad(a)); d=XOpenDisplay(NULL); /* dとサーバを対応させる */ r=RootWindow(d, 0);

w=XCreateSimpleWindow(d, r, 25, 25, WIN_WIDTH+B_RADIUS, WIN_HEIGHT+B_RADIUS, 2, BlackPixel(d, 0), WhitePixel(d, 0)); /* ウィンドウを生成し、wとウィンドウを対応させる */

gc=XCreateGC(d, w, 0, 0); /* グラフィックコンテキストを生成し、それとgcを対応させる */ XSelectInput(d, w, ExposureMask | ButtonPressMask); /* 取り込むイベントの指定 */

XMapWindow(d, w); /* 生成したウィンドウを画面に表示する */ while(1) { /* 無限ループ、ウィンドウがマップされるまで待つ */ XNextEvent(d, &evnt); /* サーバからのイベントの取り込み */ if(evnt.type==Expose) { break; } /* 画面のイベントが発生したときの処理 */ } /* ウィンドウが表示されたらループを抜ける */ while(1) {

XCheckMaskEvent(d, ButtonPress, &evnt); /* マウスボタンのイベントの監視 */ if(evnt.type==ButtonPress) { break; } /* マウスボタンのイベントが発生したときの処理 */ draw_ball(d, w, gc, ball.x, ball.y); /* ボールの描画関数を呼び出す */

ball.x+=ball.vx*dt; /* ボールのx座標の計算:オイラー法による */ if(ball.x<0) { /* ボールの左端についての計算 */ ball.x=0; ball.vx=-e*ball.vx; /* ボールの反射 */ } else if(ball.x>=REAL_WIDTH) { /* ボールの右端についての計算 */ ball.x=REAL_WIDTH; ball.vx=-e*ball.vx; /* ボールの反射 */ }

(18)

<補足>main 関数の引数について

argc はコマンドラインのオプションの数(コマンド自体も含む)である.また argv[ ] には

それぞれの文字列へのポインタが格納される.以下に引数を与えてプログラムを実行する

例を示す.

>a.out test1 test2 test3[Enter]

argv[0]=a.out

argv[1]=test1

argv[2]= test2

argv[3]= test3

ball.y+=ball.vy*dt; if(ball.y<0) { /* ボールの床との反射についての計算 */ ball.y=0; ball.vy=-e*ball.vy; } ball.vx+=0; /* 速度の更新 */ ball.vy+=-g*dt; usleep(100000); /* スリープ処理: マイクロ秒単位で実効を延期する */ } XCloseDisplay(d); /* ウィンドウの使用の終了 */

}

(19)

3.8 マウスの軌跡を表示する

動作:画面の左上に 1 つの小さなウィンドウが表示される.マウスを適当に動かすと,小さ

なウィンドウ上にマウスの軌跡が描かれる.マウスをクリックすると,小さな円が描かれる.

修了する時は「端末」で[Ctrl]キーを押しながら [c]キーを押す.

&rx,&ry:マウスポインタの位置をルートウィンドウの座標として得る.

&mask:マウスボタンの状態を通知するときに使用される.

ルートウィンドウ

/* title: 9_xtrace.c */ /* date: 2012/09/18 */

/* make: gcc 9_xtrace.c -o 9_xtrace -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 */ /* make(ubuntu): gcc 9_xtrace.c -o 9_xtrace -I/usr/include -L/usr/lib -lX11 */

#include<X11/Xlib.h> /* ライブラリのインクルード */ #include<X11/Xutil.h> /* ライブラリのインクルード */ #include<stdio.h> /* ライブラリのインクルード */ #define WIN_DIV 8 /* スクリーンとウィンドウの大きさの比率.マウスのポインタの移動量の */ /* 1/8の移動量で線が描かれる. */ int main() { Display *d; /* display型構造体dの宣言 */ Window root, w, child; /* window型構造体r, wの宣言 */ GC gc; /* GC型構造体gcの宣言 */ XEvent e; /* XEvent型構造体evntの宣言 */

int width, height, rx, ry, wx, wy, xx, yy; /* rx,ry:ルートウィンドウの座標,その他は指定したウィンドウの 座標*/

unsigned int mask; /* mask:マウスボタンの情報 */

d=XOpenDisplay(NULL); /* dとサーバを対応させる */

w=XCreateSimpleWindow(d, RootWindow(d, 0), 25, 25, DisplayWidth(d, 0)/WIN_DIV, DisplayHeight(d, 0)/WIN_DIV, 2, BlackPixel(d, 0), WhitePixel(d, 0));/* ウィンドウを生成し、wとウィンドウを対応させる */

XStoreName(d, w, "XTrace"); /* ウィンドウのタイトルの設定 */

gc=XCreateGC(d, w, 0, 0); /* グラフィックコンテキストを生成し、それとgcを対応させる */ XMapWindow(d, w); /* 生成したウィンドウを画面に表示する */

XQueryPointer(d, w, &root, &child, &xx, &yy, &wx, &wy, &mask);

while(1) { /* 無限ループ、ウィンドウがマップされるまで待つ

*/

XQueryPointer(d, w, &root, &child, &rx, &ry, &wx, &wy, &mask); /*マウスポインタの情報取得 */ XDrawLine(d, w, gc, rx/WIN_DIV, ry/WIN_DIV, xx/WIN_DIV, yy/WIN_DIV); /*線を引く */ xx=rx; /* X方向の座標データについて,新旧を入れ替える. */

yy=ry; /* Y方向の座標データについて,新旧を入れ替える. */

if(mask & (Button1Mask | Button2Mask | Button3Mask)) /* サーバからのイベントの取り込み */ XDrawArc(d, w, gc, rx/WIN_DIV, ry/WIN_DIV, 2, 2, 0, 360*64); /*マウスボタンを押した時円を描く*/

/*rx/WIN_DIV:マウスのポインタの移動量の1/8の移動量で線が描かれる. */ usleep(100000); /* スリープ処理: マイクロ秒単位で実効を延期する */ } /* OSに負担をかけないため0.1s毎にマウスの位置のデータを取得する */ XCloseDisplay(d); /* ウィンドウの使用の終了 */

(20)

3.9 立方体のワイヤーフレーム表示

動作:xcube1.c:は 1 つのウィンドウを表示し,立方体がワイヤーフレームで 2 次元表示さ

れる.修了する時は「端末」で[Ctrl]キーを押しながら[c]キーを押す.なお実行する場合に

はコマンドの後にオプション 2 つ(角度 θ,角度 φ)を渡して実行する.

(例)

>./xcube 30 45[Enter]

xcube2.c は動画表示である.実行する場合にはコマンドの後にオプション 1 つ(角度 φ)を

渡して実行する.

(例)

>./xcube2 30[Enter]

直交座標系(rectangular coordination system)と極座標系(polar coordination system)の変換

原点(0, 0, 0)と座標(x

1

, y

1

, z

1

)を結ぶベクトル r

1

がある.ベクトルが指し示す位置を極座標

で表すことを考える.今,x 軸と y 軸の間の角度を θ,xy 平面と r

1

との間の角度を

φ とする

と,

座標変換式は次のとおり.

(理論については 3 次元現象の 2 次元表示の章を参照のこと.)

x’ = x cos(θ) + y sin(θ) , y’= - x sin(θ) + y cos (θ)

:1 回目の変換

x’’ = x’ cos (φ) + z sin(φ) , z’ = - x’ sin(φ) + z cos(φ)

:2 回目の変換

Z

視点 Y

φ θ

(21)

/* title: xcube.c */ /* date: 2012/09/23 */

/* make: gcc xcube.c -o xcube -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 -lm*/ /* make(ubuntu): gcc xcube.c -o xcube -I/usr/include -L/usr/lib -lX11 -lm */ #include<X11/Xlib.h> /* ライブラリのインクルード */ #include<X11/Xutil.h> /* ライブラリのインクルード */ #include<stdio.h> /* ライブラリのインクルード */ #include<math.h> /* ライブラリのインクルード */ #define WIN_WIDTH 640 /* ウィンドウの横幅 */ #define WIN_HEIGHT 480 /* ウィンドウの縦幅 */ #define V_SCALE 60 /* 立方体の辺の長さ60ピクセル */ #define H_SCALE 60 /* 立方体の辺の長さ60ピクセル */ #define NP 8 /* 座標点の数,立方体を扱うので頂点の数は8 */ #define NL 12 /* 線の数,立方体を扱うので線の本数は12 */ struct COORD { /* 頂点の座標を扱うための構造体を宣言している */ double x; double y; double z; }; struct CONNECT { /* 線の視点と終点を扱うための構造体を宣言している */ int bgn; int end; };

struct COORD coord[NP]; /* 立方体の頂点を扱うので8つの構造体を確保する */

struct CONNECT cnct[NL]; /* 立方体の頂点を結ぶ線を扱うので12の構造体を確保する */

double torad(double t) { return(t/180*M_PI); } /* degをradへ変換する関数 */

int mulmat(double *x, double *y, double th) /* 直交座標系から極座標系への変換についての計算 */

{ double xt, yt, si, co; si=sin(th); co=cos(th); xt= (*x)*co+(*y)*si; yt=-(*x)*si+(*y)*co; *x=xt; *y=yt;

}

int trans(double x, double y, double z, int *px, int *py, double th, double ph) { mulmat(&x, &y, th);

mulmat(&x, &z, ph);

*px=WIN_WIDTH /2+(int)(y*H_SCALE); /* 1回目の変換 */

*py=WIN_HEIGHT/2-(int)(z*V_SCALE); /* 2回目の変換 */

}

int redraw(Display *d, Window w, GC gc, double theta, double phy) { int x1, y1, x2, y2, i;

trans(0, 0, 0, &x1, &y1, theta, phy); /* X座標軸,長さ3,原点Oについて */

trans(3, 0, 0, &x2, &y2, theta, phy); /* (3,0,0)について */

XDrawLine(d, w, gc, x1, y1, x2, y2);

trans(0, 3, 0, &x2, &y2, theta, phy); /* Y座標軸,長さ3 */

XDrawLine(d, w, gc, x1, y1, x2, y2);

trans(0, 0, 3, &x2, &y2, theta, phy); /* Z座標軸,長さ3 */

XDrawLine(d, w, gc, x1, y1, x2, y2);

for(i=0; i<NL; i++) { /* NL=12,12本の線について描画処理をする */

trans( coord[cnct[i].bgn].x, /* 始点の計算 */

coord[cnct[i].bgn].y, coord[cnct[i].bgn].z, &x1, &y1, theta, phy);

trans( coord[cnct[i].end].x, /* 終点の計算 */

coord[cnct[i].end].y, coord[cnct[i].end].z, &x2, &y2, theta, phy);

XDrawLine(d, w, gc, x1, y1, x2, y2); /* 12本の全ての線を引く */

} XFlush(d); }

(22)

main(int argc, char *argv[]) {

Display *d; /* display型構造体dの宣言 */ Window root, w; /* window型構造体r, wの宣言 */ GC gc; /* GC型構造体gcの宣言 */ XEvent e; /* XEvent型構造体evntの宣言 */ unsigned int black, white;

int i;

int x1, y1, x2, y2; double theta, phy;

coord[0].x=0; coord[0].y=0; coord[0].z=1; /* 座標のデータ */

coord[1].x=1; coord[1].y=0; coord[1].z=1; /* coord[i],i:頂点の番号(0,1,…7) */

coord[2].x=1; coord[2].y=1; coord[2].z=1; coord[3].x=0; coord[3].y=1; coord[3].z=1; coord[4].x=0; coord[4].y=0; coord[4].z=0; coord[5].x=1; coord[5].y=0; coord[5].z=0; coord[6].x=1; coord[6].y=1; coord[6].z=0; coord[7].x=0; coord[7].y=1; coord[7].z=0;

cnct[ 0].bgn=0; cnct[ 0].end=1; /* 線分のデータ,始点と終点を結ぶ線分のデータ */ cnct[ 1].bgn=1; cnct[ 1].end=2; /* cnct[j],j:線の番号(0,1,…11) */ cnct[ 2].bgn=2; cnct[ 2].end=3; /* cnct[j].bgn:j番目の線の始点(頂点の1つ) */ cnct[ 3].bgn=3; cnct[ 3].end=0; /* cnct[j].end:j番目の線の終点(頂点の1つ) */ cnct[ 4].bgn=0; cnct[ 4].end=4; cnct[ 5].bgn=1; cnct[ 5].end=5; cnct[ 6].bgn=2; cnct[ 6].end=6; cnct[ 7].bgn=3; cnct[ 7].end=7; cnct[ 8].bgn=4; cnct[ 8].end=5; cnct[ 9].bgn=5; cnct[ 9].end=6; cnct[10].bgn=6; cnct[10].end=7; cnct[11].bgn=7; cnct[11].end=4; sscanf(argv[1], "%lf", &theta); sscanf(argv[2], "%lf", &phy); theta=torad(theta); /* degをradへ変換 */ phy=torad(phy); /* degをradへ変換 */ d=XOpenDisplay(NULL); /* dとサーバを対応させる */ // root=RootWindow(d, 0);

w=XCreateSimpleWindow(d, RootWindow(d, 0), 25, 25, WIN_WIDTH, WIN_HEIGHT, 2, BlackPixel(d, 0), WhitePixel(d, 0)); /* ウィンドウを生成し、wとウィンドウを対応させる */ XSelectInput(d, w, ExposureMask); /* 取り込むイベントの指定 */ gc=XCreateGC(d, w, 0, 0); /* グラフィックコンテキストを生成し、それとgcを対応させる */ XMapWindow(d, w); /* 生成したウィンドウを画面に表示する */ while(1) { XNextEvent(d, &e); /* サーバからのイベントの取り込み */ if(e.type==Expose) /* 画面がマップされたら描画処理へ進む */

redraw(d, w, gc, theta, phy); }

(23)

/* title: xcube2.c */ /* date: 2012/09/23 */

/* make: gcc xcube2.c -o xcube2 -I/usr/X11R6/include -L/usr/X11R6/lib -lX11 -lm*/ /* make(ubuntu): gcc xcube2.c -o xcube2 -I/usr/include -L/usr/lib -lX11 -lm */ #include<X11/Xlib.h> /* ライブラリのインクルード */ #include<X11/Xutil.h> /* ライブラリのインクルード */ #include<stdio.h> /* ライブラリのインクルード */ #include<math.h> /* ライブラリのインクルード */ #define WIN_WIDTH 640 /* ウィンドウの横幅 */ #define WIN_HEIGHT 480 /* ウィンドウの縦幅 */ #define V_SCALE 60 /* */ #define H_SCALE 60 /* */ #define NP 8 #define NL 12 struct COORD { double x; double y; double z; }; struct CONNECT { int bgn; int end; };

struct COORD coord[NP];

struct CONNECT cnct[NL];

double torad(double t) { return(t/180*M_PI); } int mulmat(double *x, double *y, double th) {

double xt, yt, si, co; si=sin(th); co=cos(th); xt= (*x)*co+(*y)*si; yt=-(*x)*si+(*y)*co; *x=xt; *y=yt; }

int trans(double x, double y, double z, int *px, int *py, double th, double ph) { mulmat(&x, &y, th); mulmat(&x, &z, ph); *px=WIN_WIDTH /2+(int)(y*H_SCALE); *py=WIN_HEIGHT/2-(int)(z*V_SCALE); }

int redraw(Display *d, Window w, GC gc, double theta, double phy) {

int x1, y1, x2, y2, i;

trans(0, 0, 0, &x1, &y1, theta, phy); trans(3, 0, 0, &x2, &y2, theta, phy); XDrawLine(d, w, gc, x1, y1, x2, y2); trans(0, 3, 0, &x2, &y2, theta, phy); XDrawLine(d, w, gc, x1, y1, x2, y2); trans(0, 0, 3, &x2, &y2, theta, phy); XDrawLine(d, w, gc, x1, y1, x2, y2); for(i=0; i<NL; i++) {

trans(

coord[cnct[i].bgn].x, coord[cnct[i].bgn].y, coord[cnct[i].bgn].z, &x1, &y1, theta, phy);

(24)

trans(

coord[cnct[i].end].x, coord[cnct[i].end].y, coord[cnct[i].end].z, &x2, &y2, theta, phy);

XDrawLine(d, w, gc, x1, y1, x2, y2); }

XFlush(d); }

main(int argc, char *argv[]) {

Display *d; /* display型構造体dの宣言 */ Window root, w; /* window型構造体r, wの宣言 */ GC gc; /* GC型構造体gcの宣言 */ XEvent e; /* XEvent型構造体evntの宣言 */ unsigned int black, white;

int i;

int x1, y1, x2, y2; double theta, phy;

coord[0].x=0; coord[0].y=0; coord[0].z=1; coord[1].x=1; coord[1].y=0; coord[1].z=1; coord[2].x=1; coord[2].y=1; coord[2].z=1; coord[3].x=0; coord[3].y=1; coord[3].z=1; coord[4].x=0; coord[4].y=0; coord[4].z=0; coord[5].x=1; coord[5].y=0; coord[5].z=0; coord[6].x=1; coord[6].y=1; coord[6].z=0; coord[7].x=0; coord[7].y=1; coord[7].z=0; cnct[ 0].bgn=0; cnct[ 0].end=1; cnct[ 1].bgn=1; cnct[ 1].end=2; cnct[ 2].bgn=2; cnct[ 2].end=3; cnct[ 3].bgn=3; cnct[ 3].end=0; cnct[ 4].bgn=0; cnct[ 4].end=4; cnct[ 5].bgn=1; cnct[ 5].end=5; cnct[ 6].bgn=2; cnct[ 6].end=6; cnct[ 7].bgn=3; cnct[ 7].end=7; cnct[ 8].bgn=4; cnct[ 8].end=5; cnct[ 9].bgn=5; cnct[ 9].end=6; cnct[10].bgn=6; cnct[10].end=7; cnct[11].bgn=7; cnct[11].end=4; sscanf(argv[1], "%lf", &phy); phy=torad(phy); d=XOpenDisplay(NULL); /* dとサーバを対応させる */

w=XCreateSimpleWindow(d, RootWindow(d, 0), 25, 25, WIN_WIDTH, WIN_HEIGHT, 2, BlackPixel(d, 0), WhitePixel(d, 0)); /* ウィンドウを生成し、wとウィンドウを対応させる */ XSelectInput(d, w, ExposureMask); /* 取り込むイベントの指定 */ gc=XCreateGC(d, w, 0, 0); /* グラフィックコンテキストを生成し、それとgcを対応させる */ XMapWindow(d, w); /* 生成したウィンドウを画面に表示する */ for(i=0;i<360;i++) { // XNextEvent(d, &e); /* サーバからのイベントの取り込み */ // if(e.type==Expose) {

redraw(d, w, gc, theta, phy);

usleep(10000); /* 描画と描画の時間間隔:10ms */ XClearWindow(d, w); theta+=torad(1); /* θを1radずつ増加する,動画 */ // } } }

(25)

3.10 ミサイルゲーム(10_xmissile.c)

動作: 1 つのウィンドウを表示し,ドットで描かれたミサイルが点でできた線を描きなが

らマウスのポインタ位置に迫ってくる.もし追いつかれると,ゲームオーバーとなり,

逃げた時間に対応する数値を端末に表示して終了する.

本プログラムは,書籍

1)

によるものであり,それらにコメントを追記し,不具合を修正したもの

である.

4. レポート(レポート区分 C,10 点.

これまでの内容によって得た知識からアプリケーションを作成する.アプリケーション

は,例えばグラフィック関数電卓(sin 関数など幾つかの数式をグラフで表示する),シミュ

レーション(専門科目で出てきた式を適切なパラメータで計算して,結果をグラフで表示す

る)やゲーム(オリジナルでもよいし,前述のミサイルゲームを改造してもよい.改造の例

としてはミサイルの数を増やす.ミサイルがある距離に近づいた時に爆発し,衝撃波(円)

の範囲にいるとゲームオーバーになる.ある頻度でミサイルがワープするようにするなど.

アプリケーションを作るときはこれまで出てきた例題のプログラム,例えば項目 3.2 を基

もと

に改造するとよい.

条件:2 ページ以上の量のコードとする.

レポートはガイダンスのときに説明した書式でまとめること.追加点要素は次のとおり.

(1)

4 ページ以上の量のコード(+5 点)

(2)内容が特に優れているもの(+5 点)

引用文献

1) 大村正道,XWindow 練習帳,工学社,ISBN4-7775-1247-9.

参照

関連したドキュメント

7IEC で定義されていない出力で 575V 、 50Hz

スキルに国境がないIT系の職種にお いては、英語力のある人材とない人 材の差が大きいので、一定レベル以

これはつまり十進法ではなく、一進法を用いて自然数を表記するということである。とは いえ数が大きくなると見にくくなるので、.. 0, 1,

つの表が報告されているが︑その表題を示すと次のとおりである︒ 森秀雄 ︵北海道大学 ・当時︶によって発表されている ︒そこでは ︑五

また、 NO 2 の環境基準は、 「1時間値の1 日平均値が 0.04ppm から 0.06ppm までの ゾーン内又はそれ以下であること。」です

の変化は空間的に滑らかである」という仮定に基づいて おり,任意の画素と隣接する画素のフローの差分が小さ くなるまで推定を何回も繰り返す必要がある

はある程度個人差はあっても、その対象l笑いの発生源にはそれ

市場を拡大していくことを求めているはずであ るので、1だけではなく、2、3、4の戦略も