前回の宿題

今回も前回の宿題を軸に講義を進めます。第5回からは「不動直線」を扱いますが、そのためにまず第1章は一次変換による図形の変換を分かりやすく理解するためのアプリケーションを作っていきます。

さて、前回の宿題ですが、インターフェースについてでした。アプリケーションとユーザの間で情報をやり取りするための仕組みをUIと呼びます。特にWindowsはGUI[*1]アプリケーションが主流です。

引用元:[第4回の宿題]
今回扱ったプログラムでは変換行列が最初に固定されているが、いちいちソースを変更しなくても、実行しているプログラムの中だけで変換行列を変更できるようにしたい。できるだけ分かりやすく便利なインターフェースを考えて、変換行列を自由に変更できるようにプログラムを改良せよ。

では、便利なインターフェースとは一体どういったものなのでしょうか?この問いに明確な答えはありません。なぜなら、ユーザが便利だと考えさえすれば、ユーザインターフェースは便利だと言えるからです。そしてこの場合のユーザとは、この問題を問いかけられた皆さんに他なりません。もし自分で納得の行くような便利なインターフェースにできたのならば、それが正解に他なりません。

簡単な例:入力欄を設置

最も単純なインターフェースは、入力欄を設けることです。今の場合、2×2変換行列を自由に変更したいので、4つの入力欄を用意すれば良いことになります。しかし、4つの入力欄を用意するにしても、色々な方法があります。

エディタ部品

部品は位置を指定しないと、左の方に配置されます。左の方だと原点に近くて、一次変換による点の移動を調べるのには不便そうですよね。そこで、エディタ部品を右の方に配置してみます。

エディタ.nako
!『matrix.nako』を取り込む
Aとは行列

基本X=母艦の幅-200

A00とはエディタ
その変更した時は〜0,0をA00に成分変更
A01とはエディタ
その変更した時は〜0,1をA01に成分変更
A10とはエディタ
その変更した時は〜1,0をA10に成分変更
A11とはエディタ
その変更した時は〜1,1をA11に成分変更

●成分変更({整数}I,{整数}Jを{数値}Nに)
 Aの要素[I][J]=N
 

システム変数の基本X,基本Yを設定すると、生成されるGUI部品は自動的にその位置に配置されます。さらに、GUI部品が生成されるときに、基本Yの値がその部品の高さ+部品間隔[*2]の分だけ増えるようになっているので、続けて部品を作成すれば自動的に縦に並びます。

フォーム部品・スピンエディタ部品

しかし上の例だと、ちょうどエディタのある当たりに調べたい点が来た場合に見づらそうですね。それに、どこが何行何列の成分なのか非常に分かりにくいです。

そこで別のウィンドウに表示させてみましょう。なでしこで最初に表示されるウィンドウ(メインフォーム)のことを母艦を呼びますが、二つ以上のウィンドウを出したい場合はフォーム部品を使用します。また、数値を入力するのに適したGUI部品として、スピンエディタがあります。スピンエディタは、三角形状のボタンやキーボードの上下キーを押すことで、現在入力されている整数値を1ずつ増減させることができます[*3]。そして、何行何列の値を設定しているか分かりやすいように、スピンエディタ行列と同じように配置します。複数の部品を配置するには、部品の位置と、部品の右側下側を利用するのが便利です。

エディタ.nako
!『matrix.nako』を取り込む
Aとは行列
A=「1,0{~}0,1」

行列窓とはフォーム
これについて
 テキストは『変換行列』
 Wは265。Hは85

A00とはスピンエディタ
これについて
 変更した時は〜0,0をA00に成分変更
 親部品は行列窓。位置は『5,5』
A01とはスピンエディタ
これについて
 変更した時は〜0,1をA01に成分変更
 親部品は行列窓。位置はA00の右側
A10とはスピンエディタ
これについて
 変更した時は〜1,0をA10に成分変更
 親部品は行列窓。位置はA00の下側
A11とはスピンエディタ
これについて
 変更した時は〜1,1をA11に成分変更
 親部品は行列窓。位置はA10の右側

行列窓を表示

●成分変更({整数}I,{整数}Jを{数値}Nに)
 Aの要素[I][J]=N
 

インタラクティブなUI

インタラクティブとは

インターフェースインタラクティブであるというのは、そのインターフェースでは相互的双方向的な情報のやり取りがなされるという意味です。

このように説明すると難しいですが、何も難しいことはなくて、単にユーザが入力するというステップさえあればそのUIインタラクティブだと言えます。上で見てきた例でも、ユーザが入力したときに、その値を行列の成分としてセットするよう処理するものでした。このように、ユーザとプログラムの間で情報を相互にやり取りし、処理することをインタラクティブと呼ぶのです。

しかし、上で見てきたプログラム例では少しインタラクティブ性が薄いですね。プログラム側がデータをどのように処理しているかが分かりにくいからです。つまり、データがユーザからプログラムへの一方通行気味なのです[*4]。では、どのようにすれば行列(ベクトル)をもっと図的に分かりやすく知ることができるのでしょうか。

プログラム

行列による一次変換を考えるときに、基底ベクトル2本を考えると分かりやすいことを3章で解説しました。そこで、行列を変更するために、その行列の2本の列ベクトルを図示し、フォーム上でドラッグすることでそのベクトルを変更できるようにしてみましょう。

行列エディタ.nako
!『matrix.nako』を取り込む

!中心X =125
!中心Y =200
!単位長=80

行列窓とはフォーム
これについて
 テキストは『変換行列』
 クライアントW=265
 クライアントH=310
 タグ=-1。#1
 マウス押した時は
  押されたボタンで条件分岐
   『左』ならばタグ= 0
   『右』ならばタグ= 1
   違えば、  タグ=-1
 マウス移動した時は
  もしタグ≧0ならば
   タグをマウスX,マウスYでベクトル設定。#3へ
   ベクトル図示。#4へ
 マウス離した時は
  タグ=-1

A00とはスピンエディタ
これについて
 変更した時は〜0,0をA00に成分変更
 親部品は行列窓。位置は『5,5』
A01とはスピンエディタ
これについて
 変更した時は〜0,1をA01に成分変更
 親部品は行列窓。位置はA00の右側
A10とはスピンエディタ
これについて
 変更した時は〜1,0をA10に成分変更
 親部品は行列窓。位置はA00の下側
A11とはスピンエディタ
これについて
 変更した時は〜1,1をA11に成分変更
 親部品は行列窓。位置はA10の右側

#2
Aとは行列。
A00=1;A01=0;
A10=0;A11=1;

行列窓を表示

#3
●ベクトル設定({整数}COLを{整数}X,{整数}Yで)
 X=(X-中心X)/単位長
 Y=(Y-中心Y)/単位長
 もしCOLが0ならば
  A00=X。A10=Y
 違えば、もしCOLが1ならば
  A01=X。A11=Y

#4
●ベクトル図示
 座標軸クリア
 ARRとは配列=Aのデータ
 線太さは4
 線色は青色
 行列窓の中心X,中心Yから中心X+ARR[0][0]*単位長,中心Y+ARR[1][0]*単位長へ線
 線色は緑色
 行列窓の中心X,中心Yから中心X+ARR[0][1]*単位長,中心Y+ARR[1][1]*単位長へ線
 行列窓の描画処理反映

#5
●座標軸クリア
 行列窓を画面クリア
 線色は黒色。線太さは1
 行列窓の中心X-単位長,中心Yから中心X+単位長,中心Yへ線
 行列窓の中心X,中心Y-単位長から中心X,中心Y+単位長へ線
 行列窓の中心X+5,中心Y+単位長へ『1』を文字表示
 行列窓の中心X+単位長,中心Y+5へ『1』を文字表示

#6
●成分変更({整数}I,{整数}Jを{数値}Nに)
 Aの要素[I][J]=N
 ベクトル図示
 

プログラム解説

このようにすれば、変更している行列がどのような基底ベクトルへの変換を表すのか一目瞭然ですね。さらに最初の2つの例と比べて、小数点以下の値の指定が直観的であることも大きな利点です。ユーザとプログラムの間で上手くベクトルという情報がやり取りされていることが分かりますね。

#1
左クリックか右クリックかで、行列の何列目のベクトルを扱っているかを切り替え、タグに記憶する。[*5]
#2
変換行列を単位行列Eで初期化している。Aijという名前の部品は変更時にAのデータを更新し再描画するので、これで行列A・スピンエディタ・図の全てを一度に初期化できる。
#3
「行列窓」部品の左上を原点(0,0)とする座標系におけるX,Yを、原点(中心X,中心Y)で縮尺が違う座標系(編集図)におけるX,Yへ変換してCOL列ベクトルとして設定する。
#4
行列Aの第0列ベクトルを青色で、第1列ベクトルを緑色で図示する。線を描画するために、#3の座標変換の逆変換をしていることに注意。
#5
編集図の座標系が分かりやすいよう、軸と単位長を図示する。
#6
Aの(I,J)成分をNに変更し、変更を図に反映させる。

今回は長いだけで割と単純なプログラムを扱っているので、講座全体的に解説は少し控え目です。まぁ、また宿題でこのプログラムを題材にするのであまり解説できないという本音もありますf(^^;)

まとめ

今回は宿題の解答例をいくつか見てきましたが、最初に述べたように正解というものが存在しません。しかし、より多くの部品手段仕組みを知ることで、より豊かで便利なインターフェースを作ることができるようになるでしょう。

次回は、今回扱ったプログラムを改良して汎用化し、今回のような長ったらしくて分かりづらいプログラムをいかに「部品化」「構造化」して分かりやすくするかに焦点を当てていきます。その部品の一つとして、少し数学的なメスも入れてアフィン変換というものを紹介します。ただしアフィン変換そのものは五の巻の主題「不動直線」とは直接の関係はなく、そう難しくないので紹介する程度に留めます。

ところで、2009年度の名古屋大学や京都大学の理系数学の入試問題を見たところ、予想通り行列の一次変換を絡めた問題が出ていました。五の巻「不動直線」は大きく3段構想にしてしまったので、第6章はまだまだ先になりますが、大学の入試問題を題材にするのも面白いかな〜と思っています。まだ分かりませんが…(汗

今回扱ったプログラム「行列エディタ.nako」について、改良できる点がないか探せ。また、プログラムをより分かりやすくできないか考察せよ。

また「考察せよ」という抽象的なお題にしてしまいましたf(^^;)。具体的に答えが出る宿題よりも、唸りながら考えてもらった方が実際身につくから敢えてそういう問題を好んで出しているので、無理に答えを出す必要はありません。頑張って考えてみてください。

注釈

*1
GUIと対を成すUIとして、CUIがあります。なでしこでは、GUIアプリケーションもCUIアプリケーションも作ることができます。
*2
後述の「右側」「下側」でも、部品間隔だけ間を取るように座標が算出される。
*3
スピンエディタ部品に小数値を入力した状態で上下キーを押すなどの増減操作を行うと、数値が0に戻されてしまいます。そのためスピンエディタ部品は本来このような小数値を扱う場合には不向きです。今回は図と連動させましたが、他には例えばバー部品と連動させるといった使い方も考えられます。
*4
GUI部品はそれ自体インタラクティブな性質を持っています。もちろんこのサンプルでも、自然とユーザは自分自身が入力した数値を見ることができます。しかし要件と特徴があまり一致していないのです。GUI部品を使いこなすには適材適所を知る必要があるのですね。
*5
全てのGUI部品は、タグポケットという記憶専用のメンバ変数を持っていて、必要に応じて自由にデータを入れて使うことができる。