第2章(1)

2.2.4節では図形言語の例と問題がある。しかしScheme自身は画面への描画機能は持っていないため、本でも具体的な描画の方法は書かれていない。もちろん本に載っている関数や問題を実装しても実際に描画できるわけではない。もちろんそれではつまらないため、多くの人がこの図形言語の実際の描画の方法を示してくれている(素人くさいSICP読書会のページ奈良先端大のページなど)。その他「SICP 図形言語」で検索すれば多くの情報が出てくる。

でもGaucheで図形言語を扱う手軽な方法が見つからなかった。いくつか試してみたが、

  • Gauche-gtk ビルドに失敗。
  • Gauche-gl 一応成功。でもglの使い方を覚えるのが面倒。
  • PSを出力 試してない。

PS出力はまだ試していないが、Scheme処理系以外にブラックボックスができてしまうのがなんかいやだ。PSのフォーマットも当然知らないし。

ということで色々考えた結果SVGを使うことにしてみた。SVGはテキスト形式なので出力は簡単。さらに最近のFirefoxOperaは標準でSVGを表示できる。図形言語を試すにはなかなかよい。

SVGにはさまざまな機能があるが、今回の図形言語を扱う分には直線を引く方法を知るだけで十分だ。SVGで直線を引くにはline要素を使う。

<line x1="始点のx座標" y1="始点のy座標" x2="終点のx座標" y2="終点のy座標" stroke="線の色"/>

また、SVGのルート要素はsvgで、名前空間URIは"http://www.w3.org/2000/svg"だ。試しに以下のようなファイルを作ってhoge.svgなどの名前で保存し、FirefoxOperaに読ませてみる。

<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg">
  <line x1="100" x2="150" y1="200" y2="250" stroke="black"/>
</svg>

これで(100, 100)から(200, 250)に黒い直線が引かれた絵が表示されればOK。

では実際にSICPの図形言語に挑戦してみる。本にも書いてあるとおり、図形の描画は最終的にdraw-line関数に任されている。draw-lineは引数を2つ取り、それぞれ始点と終点を表している。点のx座標およびy座標はそれぞれxcor-vect関数、ycor-vect関数で取り出すことができる。取り出された座標の値を使ってline要素を書けば図形をSVGとして出力することができる。ただし図形は縦横ともに1の単位方形で描かれているため、そのまま出力して表示すると点にしかならない。座標値に適当な値をかけて大きくしよう。ここでは500倍にしてみる。出力はformat関数を使うとC言語のprintfっぽく書けて便利だ。

また、最初にXML宣言とsvg要素の開始タグを書き、最後にsvg要素の終了タグを書く必要がある。ここではdraw-initとdraw-finという関数を作ってごまかすことにした。描画する前にdraw-init、後にdraw-finを呼び出そう。

ということでできたのが以下の関数。

(define (draw-init)
  (print "<?xml version='1.0'?>")
  (print "<svg xmlns='http://www.w3.org/2000/svg'")
  (print "     xmlns:xlink='http://www.w3.org/1999/xlink'>"))

(define (draw-fin)
  (print "</svg>"))

(define (draw-line p1 p2)
  (print (format "<line x1='~a' y1='~a' x2='~a' y2='~a' stroke='black'/>"
		 (* (xcor-vect p1) 500)
		 (* (ycor-vect p1) 500)
		 (* (xcor-vect p2) 500)
		 (* (ycor-vect p2) 500)
		 )))

あとは本に載っている関数と問題ができれば表示できるはずだ。