なんだか難しくてよくわからない図形言語を解析してゆくページ
オブジェクト
- Frameオブジェクト
- 並行でない二つのベクトルで構成されており、そのベクトルを湧くとした座標平面を作る。
- Painterオブジェクト
- frameオブジェクトを受け取りそのframeオブジェクトで指定されている領域内で指定されている絵を描写する。
- Segmentオブジェクト
- 描かれる線分情報を保持するオブジェクト。
関数名と動作
実際やってみる
nagaさん(
naga:gnuplotを使った図形言語)の方法を用いて体感しながらやってみる。
とりあえず、draw-lineを用いて実際に線を引いてみるnagaさんのページからコピーしてこのようなファイル(ファイル名draw.scmとでもしておく)を用意する
#!/usr/bin/env gosh
(define (make-vect x y)
(cons x y))
(define (xcor-vect v)
(car v))
(define (ycor-vect v)
(cdr v))
(define (draw-line s-seg e-seg)
(display "set arrow from ")
(display (xcor-vect s-seg))
(display ",")
(display (ycor-vect s-seg))
(display " to ")
(display (xcor-vect e-seg))
(display ",")
(display (ycor-vect e-seg))
(display " nohead")
(newline))
(draw-line (make-vect 0.3 0.5) (make-vect 0.1 0.5))
(draw-line (make-vect 0.9 0.6) (make-vect 0.6 0.4))
これを元に描写してみる
> ./draw.scm > segment.gp
> gnuplot plot.gp
すると、
このように実際に線が描写されることがわかる。
ここで重要なのは、
線を描くだけならSICPで書かれている関数はそれほどいらない。
ということである。まず、単純に絵を描くということと、図形言語として絵を描くということを分けて考えないと混乱する。
まず、draw-lineでいろいろ遊んでみよう。
より手軽に遊ぶ為上のプログラムを多少変更した以下のプログラムを用いる
#!/usr/bin/env gosh
(define (make-vect x y)
(cons x y))
(define (xcor-vect v)
(car v))
(define (ycor-vect v)
(cdr v))
(define (make-frame origin edge1 edge2)
(list origin edge1 edge2))
(define (put-x-y-coord seg)
(let ((xcor (xcor-vect seg))
(ycor (ycor-vect seg)))
(for-each display (list xcor " " ycor "\n"))))
(define (draw-line s-seg e-seg)
(put-x-y-coord s-seg)
(put-x-y-coord e-seg)
(newline))
(define (print str)
(display str)
(newline))
(define init-commands (list
"set multiplot" ; 複数グラフを表示可能にする
"set xrange [0:1]" ; 表示領域 0≦x,y≦1
"set yrange [0:1]"
"set size 0.721,1.0" ; 縦横を同じ長さに
"unset border" ; 枠を表示しない
"unset tics" ; 刻みを表示しない
"unset key" ; keyを表示しない
"plot [0:1] 0 with dot" ; y=0の線を0≦x≦1に目立たないように表示する
"set style data line"
"plot '-'"))
(for-each print init-commands) ;必要な設定
;;以下の部分に描写する手続きを記述。
(draw-line (make-vect 0.3 0.5) (make-vect 0.1 0.5))
(draw-line (make-vect 0.9 0.6) (make-vect 0.6 0.4))
使い方としてはファイル名をdrawline.scmとし、
> ./drawline.scm | gnuplot -persist
でOK
segment->painterを使ってみる
(define idframe (make-frame (make-vect 0.0 0.0) (make-vect 1.0 0.0) (make-vect 0.0 1.0)))
(define seglist (list (make-segment (make-vect 0.0 0.0) (make-vect 1.0 1.0))
(make-segment (make-vect 1.0 0.5) (make-vect 1.0 0.0))
(make-segment (make-vect 0.0 0.0) (make-vect 1.0 0.5))))
((segments->painter seglist) idframe)
というようなものを実行してみる。(セグメントリストは適当なもの)
ここで用いたframeは正規ベクトルで構成されたありきたりなものであったので少し変更してみる。
(define idframe (make-frame (make-vect 0.0 0.0) (make-vect 1.0 0.0) (make-vect 0.0 1.0)))
↓
(define nextframe (make-frame (make-vect 0.0 0.0) (make-vect 0.8 0.1) (make-vect 0.5 0.3)))
結果
まずmake-pathを使ってフレームを表示させてみる。
(define idframe (make-frame (make-vect 0.0 0.0) (make-vect 1.0 0.0) (make-vect 0.0 1.0)))
(define exp-frame
(make-path (make-vect 0.0 0.0)
(make-vect 1.0 0.0)
(make-vect 1.0 1.0)
(make-vect 0.0 1.0)
(make-vect 0.0 0.0)))
として、
((segments->painter exp-frame) idframe)
を実行
これをフレームを変えることで変形させる。
(define transframe (make-frame (make-vect 0.0 0.0) (make-vect 0.8 0.2) (make-vect 0.2 0.8)))
((segments->painter exp-frame) transframe)
結果
さらにSICPに出てくるwaveの例を試してみる。
実行コマンド
((segments->painter exp-idframe) idframe)
(wave idframe)
実行コマンド
((segments->painter exp-idframe) transframe)
(wave transframe)
最終更新:2008年03月21日 00:35