SICP §2.2.4(図形言語 その7 [ペインタのまとめ])

さ、やっと『ペインタ』のおでましだ。

ペインタはフレームを引数として受け取り、そのフレームに合うように描画しようとする手続だ。
ここで、やっとgauche-glとの融合がなされる・・・長かった。。


SICPで記述されているペインタの例は「線画のペインタ」だ。線画なので、ペインタが内部に保持する情報は全てベクタになる。(実際にはベクタのリスト)
早速定義を表記しておこう。

;線画ペインタを返す。有向線分のリストを引数として渡す。
(define (segments->painter segment-list)
  ;返すのはペインタなので、フレームを受け取る手続を返却する。
  (lambda (frame)
    ;有向線分毎に draw-line を実行する。
    ;draw-line が受け取る値はフレームと有向線分を使ってフレーム座標写像した「座標」。
    ;この draw-line を、gauche-gl を使って定義することになる!
    (for-each
     (lambda (segment)
       (draw-line
	((frame-coord-map frame) (start-segment segment))
	((frame-coord-map frame) (end-segment segment))))
     segment-list)))

渡される有向線分は、単位方形に対する座標を使って表現されていることに注意。
さぁ、やっと gauche-gl との連結点が見えてきた。。長かった。。

つーわけで、ここらへんで総括するぜ!
SICP §2.2.4(図形言語 その3 [何が理解できていないのか])」で記載していた、gauche-gl を使ったサンプルに必要な処理を全て記述してみよう!もうペインタを使った描画ができるはず!


以下をファイルに記述し、実行権限を付加して端末エミュレータから実行してみよう。

#!/usr/bin/gosh
(use gl)
(use gl.glut)

;;; ==============================
;;; ベクタ関連
;;; ==============================
;構成子・選択子
(define (make-vect x y)
  (cons x y))

(define (xcor-vect v)
  (car v))

(define (ycor-vect v)
  (cdr v))

;ベクタ演算
(define (op-vect op v_1 v_2)
  (let ((x_1 (xcor-vect v_1))
	(y_1 (ycor-vect v_1))
	(x_2 (xcor-vect v_2))
	(y_2 (ycor-vect v_2)))
    (make-vect (op x_1 x_2) (op y_1 y_2))))

(define (add-vect v_1 v_2)
  (op-vect + v_1 v_2))

(define (sub-vect v_1 v_2)
  (op-vect - v_1 v_2))

(define (scale-vect s v)
  (op-vect * (make-vect s s) v))

;;; ==============================
;;; フレーム関連
;;; ==============================
;構成子・選択子
(define (make-frame origin edge1 edge2)
  (list origin edge1 edge2))

(define (frame-origin frame)
  (car frame))

(define (frame-edge1 frame)
  (cadr frame))

(define (frame-edge2 frame)
  (caddr frame))

;フレーム座標写像
(define (frame-coord-map frame)
  (lambda (v)
    (add-vect
     (frame-origin frame)
     (add-vect (scale-vect (xcor-vect v)
			   (frame-edge1 frame))
	       (scale-vect (ycor-vect v)
			   (frame-edge2 frame))))))

;;; ==============================
;;; 有向線分関連
;;; ==============================
;構成子・選択子
(define (make-segment start end)
  (cons start end))

(define (start-segment segment)
  (car segment))

(define (end-segment segment)
  (cdr segment))

;;; ==============================
;;; 線画用ペインタ生成手続
;;; ==============================
(define (segments->painter segment-list)
  (lambda (frame)
    (for-each
     (lambda (segment)
       (draw-line
	((frame-coord-map frame) (start-segment segment))
	((frame-coord-map frame) (end-segment segment))))
     segment-list)))

;;; ==============================
;;; フレームを生成
;;; ==============================
(define frame (make-frame (make-vect 0 0)
			  (make-vect 1 0)
			  (make-vect 0 1)))

;;; ==============================
;;; 菱形ペインタを生成
;;; ==============================
(define diamond
  (segments->painter (list
		      (make-segment (make-vect 0.0 0.5)
				    (make-vect 0.5 1.0))
		      (make-segment (make-vect 0.5 1.0)
				    (make-vect 1.0 0.5))
		      (make-segment (make-vect 1.0 0.5)
				    (make-vect 0.5 0.0))
		      (make-segment (make-vect 0.5 0.0)
				    (make-vect 0.0 0.5)))))


;;; ==============================
;;; 線分描画手続!
;;; ==============================
(define (draw-line p1 p2)
  (define (t z)
    (- (* 2 z) 1))
  (gl-vertex (t (xcor-vect p1)) (t (ycor-vect p1)))
  (gl-vertex (t (xcor-vect p2)) (t (ycor-vect p2))))

;;; ==============================
;;; 図形言語テスト用定形ロジック
;;; ==============================
(define (init)
  (gl-clear-color 1.0 1.0 1.0 1.0))

(define (disp)
  (gl-clear GL_COLOR_BUFFER_BIT)
  (gl-color 0.0 0.0 0.0 0.0)
  (gl-begin GL_LINE_LOOP)

  ;線画を描画!
  (diamond frame)

  (gl-end)
  (gl-flush))

(define (main args)
  (glut-init args)
  (glut-create-window "Painter Line Test")
  (glut-display-func disp)
  (init)
  (glut-main-loop)
  0)

でたー!!!!!!