コッホ曲線とか雪片を SliP と JavaScript で描く



![KochSliP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73493/f3437394-c0e1-654b-f537-94008bb0e342.png)

[コッホ曲線を Wikipedia で引く](https://ja.wikipedia.org/wiki/コッホ曲線)とコンピューターによる生成の部分でアフィン変換を使用する方法が紹介されています。ちょっと大変ですね。
HTML の Canvas エレメントを使うと、API がアフィン変換をやってくれちゃうので自分でアフィン変換しなくてもコッホ曲線を描くことができます。Canvas API を使えちゃうプログラミング電卓 SliP でコッホ曲線を描いちゃいましょう！

SliP については以下をご覧ください。

https://qiita.com/Satachito/items/a962c0f2aa436e82b9fb

## コッホ曲線

詳しい説明は Wikipedia に譲るとして、ここでは次のように考えます。
```
L のコッホ曲線を描くには：
　L が３以下なら長さ L の直線を描く
　そうでなければ
　　L/3のコッホ曲線を描いて60度左に曲がる
　　L/3の長さのコッホ曲線を描いて120度右に曲がる
　　L/3の長さのコッホ曲線を描いて60度左に曲がる
　　L/3の長さのコッホ曲線を描く
```

## プログラミング


https://slip.828.tokyo


早速プログラミングしてみましょう。上のアドレスの[SliP](https://slip.828.tokyo)に以下のプログラムを入力して`CALCULATE`ボタンを押してみましょう。この時必ず右のオプションエリアの Programming チェックボックスにチェックを入れておいてください。


```
( 'WH = 300 )
( 'c2d = { WH WH }:canvas:beginPath:translate{ 0 ( WH ÷ 2 ) }:moveTo[ 0 0 ] )
(	'Koch = '(
		(	@ < 3 ?
			[	( c2d:lineTo{ @ 0 }:translate{ @ 0 } )
				(	{	( ( @ ÷ 3 ):Koch:rotate( π ÷ 3 ) )
						( ( @ ÷ 3 ):Koch:rotate( -π × 2 ÷ 3 ) )
						( ( @ ÷ 3 ):Koch:rotate( π ÷ 3 ) )
						( ( @ ÷ 3 ):Koch )
					}:$
				)
			]
		)
	)
)
( WH:Koch:stroke )
```
`canvas`は SliP 上にフローティングの canvas 要素を生成してそのコンテキストを返します。
返されたコンテキストは`c2d`という名前にアサインされます。
この`canvas`を含めこの２行目にある全ての命令は生成されたコンテキストを返します。
`beginPath`でパスを作る準備をします。
`translate`で canvas の左端の上下中央に原点を移動して
`moveTo`で原点からパスの始点を置きます。
３行目は`Koch`という関数を定義しています。
`@`は SliP では引数という意味を持ちます。
`?`は左辺がNilでなければ(@が３未満)、右辺の最初の式を評価します。
右辺の最初の式は`c2d`にアサインされたコンテキストに@の長さの線を描画して、原点をその終点に移します。
左辺がNilであれば（@が３以上）右辺の２番目の式を評価します。２番目の式は上の考え方の以下の部分です。
```
　　L/3のコッホ曲線を描いて60度左に曲がる
　　L/3の長さのコッホ曲線を描いて120度右に曲がる
　　L/3の長さのコッホ曲線を描いて60度左に曲がる
　　L/3の長さのコッホ曲線を描く
```
`{ 文1 文2 文3 文4 }`は評価されると`文1 文2 文3 文4`の順で評価されそれぞれの値`[ 値1 値2 値3 値4 ]`を返します。ここでは`[ コンテキスト コンテキスト コンテキスト コンテキスト ]`と返ってくるので、`:$`で最後の一つだけ取り出します。

`( WH:Koch:stroke )`はいよいよ`Koch`の実行です。WHには300という値が入っています。`stroke`は実際に線を描きます。

![スクリーンショット 2022-08-19 21.34.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73493/ff4685e4-1d20-1fc8-48d8-ac5385ce55c5.png)


## コッホ雪片

同一の長さのコッホ曲線を３つ描くとコッホ雪片という図形になります。
```
( 'L = WH ÷ 2 × sqrt( 3 ) )	//	Length of the side of an equilateral triangle inscribed in a circle
( 'c2d = { WH WH }:canvas:beginPath:translate{ ( WH ÷ 2 ) 0 }:moveTo[ 0 0 ]:rotate( π × 2 ÷ 3 ) )
{	( L:Koch:rotate( -π × 2 ÷ 3 ) )
	( L:Koch:rotate( -π × 2 ÷ 3 ) )
	( L:Koch:stroke )
}
```
canvas を作って、上端の左右中央に原点を移動して始点を移し右に120度曲がり
コッホ曲線を引いて左に120度曲がり、
コッホ曲線を引いて左に120度曲がり、
コッホ曲線を引いて線を描画です。

![スクリーンショット 2022-08-19 21.35.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73493/cd09ce2b-79fd-ddfa-46ba-a6d1d9117843.png)

## JavaScript で

HTML + JavaScript も用意してみました。


https://slip.828.tokyo/Koch.html

ここにアクセスしていただいてもいいですし、下のソースを拡張子htmlのファイルにしてブラウザに読ませればいけると思います。

```
<canvas id=CANVAS width=300 height=300 style="border: 1px solid green"></canvas><br>
<br>
<input type=button id=CURVE		value="Koch Curve"		>
<input type=button id=SNOWFLAKE	value="Koch Snowflake"	>

<script type=module>

const
c2d = CANVAS.getContext( '2d' )

const
Koch = _ => _ < 3
?	(	c2d.lineTo( _, 0 )
	,	c2d.translate( _, 0 )
	)
:	(	Koch( _ / 3 )
	,	c2d.rotate( Math.PI / 3 )
	,	Koch( _ / 3 )
	,	c2d.rotate( - Math.PI * 2 / 3 )
	,	Koch( _ / 3 )
	,	c2d.rotate( Math.PI / 3 )
	,	Koch( _ / 3 )
	)

CURVE.onclick = ev => (
	c2d.clearRect( 0, 0, CANVAS.width, CANVAS.height )
,	c2d.save()
,	c2d.beginPath()
,	c2d.translate( 0, CANVAS.height / 2 )
,	c2d.moveTo( 0, 0 )
,	Koch( CANVAS.width )
,	c2d.stroke()
,	c2d.restore()
)

SNOWFLAKE.onclick = ev => {
	c2d.clearRect( 0, 0, CANVAS.width, CANVAS.height )
	c2d.save()
	const _ = CANVAS.width / 2 * Math.sqrt( 3 )	//	Length of the side of an equilateral triangle inscribed in a circle
	c2d.beginPath()
	c2d.translate( CANVAS.width / 2, 0 )
	c2d.moveTo( 0, 0 )
	c2d.rotate(  Math.PI * 2 / 3 )
	Koch( _ )
	c2d.rotate( -Math.PI * 2 / 3 )
	Koch( _ )
	c2d.rotate( -Math.PI * 2 / 3 )
	Koch( _ )
	c2d.stroke()
	c2d.restore()
}
</script>
```

![スクリーンショット 2022-08-19 21.43.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73493/4ec353a6-fa81-fb7b-cc2e-0032c8370d4e.png)

## 最後に

ここまでお読みいただきありがとうございました！