SICP 読み (32) 2.2.4 例: 図形言語
最初、frame と painter の関係についての理解が微妙だった。単位方形 (unit square) についても同様。で、こいつらの理解ができんと駄目なのが分かってたので、図形を表示させる前になんとか理解しやすい試験がしたいな、と試行錯誤。
まず、gaunit で何とかならぬのか、と色々検討するも、元の for-each 使った実装では、どーにもならない事が分かる。図形描画なので副作用なソレ中心がデフォルトだよね、と言いつつペインタを試験用な stub にしてしまう。
(define (segments->painter segment-list) (lambda (frame) (map (lambda (segment) (draw-line ((frame-coord-map frame) (start-segment segment)) ((frame-coord-map frame) (end-segment segment)))) segment-list)))
for-each じゃなくって map にしちまえばリストが返される。しかも draw-line は以下。
(define (draw-line s e) (list s e))
これで draw-line に渡る値がチェックできる、とゆー事で試験を書いた。以下のような感じ。
(define-test-case "2.49-a (1)" ("2.49-a (1)" (let ((l1 (make-segment (make-vect 0.0 0.0) (make-vect 0.0 1.0))) (l2 (make-segment (make-vect 0.0 0.0) (make-vect 1.0 0.0))) (l3 (make-segment (make-vect 1.0 0.0) (make-vect 1.0 1.0))) (l4 (make-segment (make-vect 0.0 1.0) (make-vect 1.0 1.0)))) (let ((p (segments->painter (list l1 l2 l3 l4)))) (let ((f (make-frame (make-vect 2.0 2.0) (make-vect 2.0 0.0) (make-vect 0.0 2.0)))) (assert-equal 2.0 (xcor-vect (start-segment (car (p f))))) (assert-equal 2.0 (ycor-vect (start-segment (car (p f))))) (assert-equal 2.0 (xcor-vect (end-segment (car (p f))))) (assert-equal 4.0 (ycor-vect (end-segment (car (p f))))) )))))
ちなみに上記の試験は l1 の試験。(car (p f)) に l1、(cadr (p f)) に l2、(caddr (p f)) に l3 で (cadddr (p f)) が l4 という事で試験をしています。
frame の考え方の誤解
最初はこう考えていました。
(make-frame (make-vect 2.0 2.0) ;; origin (make-vect 4.0 2.0) ;; edge1 (make-vect 2.0 4.0)) ;; edge2
_表示スクリーン上の点 (0, 0)_ からの、と思ってたら「フレームの頂点の原点からの変位を指定_とあった。
上記の実装で問題 2.49 の a を試験したらどでかいヒシ型が出てきて (とは言え、図形が描画された訳ではないのですが)、びっくり仰天。実装を見てもそうなるのは当たり前に読めてしまって困りました。きちんと文章を読みましょう、な典型です。(恥
でも、コード見て意味が類推できなかったあたり、微妙スギかも、と。(とほほ
ペインタに渡す線分に関する誤解
ペインタの実装を見るに、線分はどうやって指定するんだ、とアタマがこんがらがっていました。コード直下に「線分は単位方形に対する座標を使って与えられている。」とあり、やっぱりか、と。
ここまで分かればあとはざくざくヤレそう。ただし、描画の実装はカンニングが必要かも。(GLUTによる「手抜き」OpenGL入門??)