SICP §2.2.4(図形言語 その6 [フレームの概念のまとめとフレーム座標写像について])

今度は『フレーム』の概念の説明。

SICPによると、ペインタの実装方法と組み合わせ方法を考える前に『フレーム』を考えなきゃならんのだって。・・・知らんがな(´・ω・`)


フレームを構成するのに必要な要素は、次の3つ。


・原点ベクタ:平面の絶対原点からのフレームの原点の変位を指定する。
・辺1ベクタ:フレームを平行四辺形と見なし、頂点の原点からの一辺を指定する。
・辺2ベクタ:フレームを平行四辺形と見なし、頂点の原点からのもう一方の他辺を指定する。
(※辺1と辺2のベクタが直交していれば長方形となる。)

で、この『フレーム』を扱う為に、構成子と選択子が必要になるわけだが、要素が『ベクタ』なので、更にこの『ベクタ』を扱う構成子と選択子、その他の演算手続が必要になる。

んが、SICPの説明の流れだと、とりあえず『ベクタ』はあるものとして、そのままフレームの話が進んでいる。

フレームの実装の仕方としては、こんな感じ。


・構成子:原点ベクタ、辺1のベクタ、辺2のベクタの3つを引数として受け取り、フレームを返却する。
・選択子:フレームを引数として受け取り、それぞれの手続に従って、原点ベクタ、辺1のベクタ、辺2のベクタを返却する。
で、これらについての具体的な実装は、「問題 2.47」で行うことになる。
そこで実装する各種手続は次の通り。

・構成子 :make-frame
・選択子(原点):origin-frame
・選択子(辺1):edge1-frame
・選択子(辺2):edge2-frame
この図形言語における『フレーム』は、

ペインタが描く図形が、指定された領域(フレーム)の中にうまく収まるようにする
ために作られた概念で、例えば、次のような「frame1」

原点ベクタ: (1.4, 2.1)
辺1ベクタ: (3.4, 2.1)
辺2ベクタ: (0.2, 5.9)
に、とあるペインタが表現する線画なり画像なりがうまく収まるようにするには、ペインタが描く為の情報群が「単位方形(x座標もy座標も、0〜1の間の値で表現される正方形)」の中に表現されるようにする必要がある。
すなわち、上記のframe1に例えば「フレームの各辺の中点を結ぶ菱形ABCDを描画する」ペインタを使用して描画する場合、この菱形を描く為の情報として、各中点の座標は次のように表現される必要がある。

A点: (0.0, 0.5)
B点: (0.5, 1.0)
C点: (1.0, 0.5)
D点: (0.5, 0.0)
このように表現することによって、やはりまったく別の原点、辺1、辺2をもつ frame2、frame3、... 等があっても、やはりそれらのフレームに合うように菱形を描画することができるようになるわけだ。


さて、ここで、単位方形領域内の情報で基本となるペインタが表現されること、及びフレームを使用することによって、どのようなフレームに対しても描画ができるようになるという利点は理解できたけども、じゃあ実際にどうやるのよ?という疑問が沸いてくる。
これを解決するために、単位方形領域内の情報を、フレームに合うように変換するための手続が必要になる。

次に記載されている内容がまさにそれで、名前は「フレーム座標写像」だ。「指定されたフレームに従うような、ベクタの変換処理を行う手続」を返す手続ってとこか。
フレームを構成しているのは「ベクタ」そんで、上記の菱形のような図形(線画)を構成してるのもやはり「ベクタ」。(とりあえず画像にしては華麗なまでにスルー。)だからこそ、この「フレーム座標写像」が意味を持ってくるわけだ。
では早速記述してみよう。

;フレームを渡し、その「指定されたフレームに沿ったベクタ変換を行う手続」を返す手続
(define (frame-coord-map frame)
  (lambda (v)
    (add-vect
     (origin-frame frame)
     (add-vect (scale-vect (xcor-vect v)
			   (edge1-frame frame))
	       (scale-vect (ycor-vect v)
			   (edge2-frame frame))))))

;使い方
((frame-coord-map a-frame) (make-vect 0 0)) ;← (origin-frame a-frame) の評価結果と同じ

ベクタに関係する手続がいくつかでてきているが、それぞれこんな感じに対応していると思いねぇ。


・make-vect :ベクタの構成子
・xcor-vect :ベクタの x 要素を取得する選択子
・ycor-vect :ベクタの y 要素を取得する選択子
・add-vect :ベクタの加算演算
・sub-vect :ベクタの減算演算
・scale-vect:ベクタのスカラー乗算演算
で、こやつら+ベクタの演算処理の手続に関しては、「問題 2.46」で定義することになっている。


この箇所では特に疑問点はなかったな。。というか、SICPの内容をちゃんと追ってきたから理解できてるのかも。。

最初からやれよって感じ?