POV-Rayでよく使う制御文

# はじめに
これは [POV-Rayによる数学お絵かき入門 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/povray4math) の6日目の記事です.

POV-Rayでは幾つかの制御文が用意されていますが, その中でも今日は

* `while`
* `if`
* `macro`

について書きます.

公式ドキュメントでは以下が近いです.
http://www.povray.org/documentation/3.7.0/r3_3.html#r3_3_2_6
http://www.povray.org/documentation/3.7.0/r3_3.html#r3_3_2_8

# while
POV-Rayで繰り返しの処理を書くには次のようにします.

```
#while(条件)
	処理
#end
```

POV-Rayにはfor文が用意されていないため, 球面を複数並べる処理は次のように書きます.

```
#declare i=0;
#while(i<5)
	sphere{<i,0,0>,0.2 pigment{rgb<i/4,1-i/4,0>}}
	#declare i=i+1;
#end
```

![](https://i.imgur.com/j3sTDBZ.png)

この例では色の指定にも`i`を入れ込めて球面の色が変わるようになっています.https://i.imgur.com/j3sTDBZ.png

# if
条件分岐を記述するためには次のように書きます.

```
#if(条件)
	処理1
#else
	処理2
#end
```

[第四回](https://qiita.com/Hyrodium/items/7fb5d257e292eb81b64e)に書いたように, POV-Rayでは真偽値が1と0で表現されます.
`if`や`while`の条件で判断される際には, `0`に等しいか否かによって判断されます.

# macro
マクロを書くには次のように書きます.

```
#macro(第1引数,...,第n引数)
	処理
#end
```

つまらない例ですが, 鉛直方向を向いた円柱のマクロは次のように書けます.

```
#macro(r,l)
	cylinder{<0,0,0>,<0,l,0>,r}
#end
```

[第四回](https://qiita.com/Hyrodium/items/7fb5d257e292eb81b64e)でも少し触れましたが, `macro`内で変数を宣言する際にはローカル変数には`local`, グローバル変数には`declare`を使います.

基本的には`macro`は関数と考えて差し支えありませんが, 厳密には異なります.
これに関しては連載後半で改めて記述する予定です.

# 多面体
## 立方体
`while`と`macro`を使う
一番簡単な立方体から書きなおします.

対称性を考えれば, 頂点は次のように書けます.

```Povray
#declare i=-1;
#while(i<2)
	#declare j=-1;
	#while(j<2)
		#declare k=-1;
		#while(k<2)
			sphere{<i,j,k>,0.05 pigment{rgb<1,0,1>}}
			#declare k=k+2;
		#end
		#declare j=j+2;
	#end
	#declare i=i+2;
#end
```

![](https://i.imgur.com/xEf7hZC.png)

`cylinder`を付け加えて辺を描きます.

```Povray
#declare i=-1;
#while(i<2)
	#declare j=-1;
	#while(j<2)
		#declare k=-1;
		#while(k<2)
			sphere{<i,j,k>,0.05 pigment{rgb<1,0,1>}}
			#declare k=k+2;
		#end
		cylinder{<i,j,1>,<i,j,-1>,0.05 pigment{rgb<1,0,1>}}
		#declare j=j+2;
	#end
	#declare i=i+2;
#end
```

![](https://i.imgur.com/bSeHFid.png)

ここで次のマクロ`Rotate`を定義します.

```Povray
#macro Rotate(w,i)
	#local j=i;
	#local wj=w;
	#while(j)
		#local wj=<wj.z,wj.x,wj.y>;
		#local j=j-1;
	#end
	wj
#end
```

このマクロによって, ベクトル$(1,1,1)$を回転軸として引数のベクトルが$120^\circ$回転します.

上と合わせれば次のように書けます.

```Povray
#declare i=-1;
#while(i<2)
	#declare j=-1;
	#while(j<2)
		#declare k=-1;
		#while(k<2)
			sphere{<i,j,k>,0.05 pigment{rgb<1,0,1>}}
			#declare k=k+2;
		#end
		#declare l=0;
		#while (l<3)
			cylinder{Rotate(<i,j,1>,l),Rotate(<i,j,-1>,l),0.05 pigment{rgb<1,0,1>}}
			#declare l=l+1;
		#end
		#declare j=j+2;
	#end
	#declare i=i+2;
#end
```

![](https://i.imgur.com/7odoQv5.png)

## 正八面体
同様に次のように描けます.

```Povray
#declare i=-1;
#while(i<2)
	#declare l=0;
	#while(l<3)
        sphere{Rotate(<i,0,0>,l),0.05 pigment{rgb<0,1,1>}}
		#declare j=-1;
		#while (j<2)
			cylinder{Rotate(<i,0,0>,l),Rotate(<0,j,0>,l),0.05 pigment{rgb<0,1,1>}}
			#declare j=j+2;
		#end
		#declare l=l+1;
	#end
	#declare i=i+2;
#end
```

![](https://i.imgur.com/RhJEJYg.png)


## 正四面体
全列挙の方が早そうですが, 折角なので対称性を利用して描いてみましょう.
これまでと違って条件分岐`if`も使います.
立方体の頂点を元に正四面体を2つ作ります.

```Povray
#declare i=-1;
#while(i<2)
	#declare j=-1;
	#while(j<2)
		#declare k=-1;
		#while(k<2)
			sphere{<i,j,k>,0.05 pigment{rgb<1,1,0>}}
			#declare k=k+2;
		#end
        #declare l=0;
		#while (l<3)
            cylinder{Rotate(<i,j,1>,l),Rotate(<i,-j,-1>,l),0.05 pigment{rgb<1,0,1>}}
			#declare l=l+1;
		#end
		#declare j=j+2;
	#end
	#declare i=i+2;
#end
```

![](https://i.imgur.com/hHMed6s.png)

2つの正四面体の内の1つだけ描画するために, `sphere`と`cylinder`を`if`で囲みます.

```Povray
#declare i=-1;
#while(i<2)
	#declare j=-1;
	#while(j<2)
		#declare k=-1;
		#while(k<2)
			#if(mod(i*j*k,2)=1) sphere{<i,j,k>,0.05 pigment{rgb<1,1,0>}} #end
			#declare k=k+2;
		#end
        #declare l=0;
		#while (l<3)
            #if(mod(i*j,2)=1) cylinder{Rotate(<i,j,1>,l),Rotate(<i,-j,-1>,l),0.05 pigment{rgb<1,1,0>}} #end
			#declare l=l+1;
		#end
		#declare j=j+2;
	#end
	#declare i=i+2;
#end
```

![](https://i.imgur.com/9PLBVCJ.png)

## 正十二面体
前回愚直に書こうとして諦めた正十二面体も, 次のように書けます.

```Povray
#declare phi=(1+sqrt(5))/2;

#declare i=-1;
#while(i<2)
	#declare j=-1;
	#while(j<2)
		#declare k=-1;
		#while(k<2)
			sphere{<i,j,k>,0.05 pigment{rgb<1,0,0>}}
			#declare k=k+2;
		#end
        #declare l=0;
		#while (l<3)
            sphere{Rotate(<i*phi,j/phi,0>,l),0.05 pigment{rgb<1,0,0>}}
            cylinder{Rotate(<i*phi,0,0>,l),Rotate(<i*phi,j/phi,0>,l),0.05 pigment{rgb<1,0,0>}}
            cylinder{Rotate(<i,j,1>,l),Rotate(<i*phi,j/phi,0>,l),0.05 pigment{rgb<1,0,0>}}
            cylinder{Rotate(<i,j,-1>,l),Rotate(<i*phi,j/phi,0>,l),0.05 pigment{rgb<1,0,0>}}
            #declare l=l+1;
		#end
		#declare j=j+2;
	#end
	#declare i=i+2;
#end
```

![](https://i.imgur.com/o93UFPh.png)

## 正二十面体
最後の例は正二十面体です.
これも各頂点座標が黄金比で書けます.

```Povray
#declare i=-1;
#while(i<2)
	#declare j=-1;
	#while(j<2)
        #declare l=0;
		#while (l<3)
            sphere{Rotate(<i,j*phi,0>,l),0.05 pigment{rgb<0,0,1>}}
            cylinder{Rotate(<0,j*phi,0>,l),Rotate(<i,j*phi,0>,l),0.05 pigment{rgb<0,0,1>}}
            #declare k=-1;
            #while(k<2)
                cylinder{Rotate(<1,1*phi,0>,l)*<i,j,k>,Rotate(<1,1*phi,0>,l+1)*<i,j,k>,0.05 pigment{rgb<0,0,1>}}
    			#declare k=k+2;
    		#end
            #declare l=l+1;
		#end
		#declare j=j+2;
	#end
	#declare i=i+2;
#end
```

![](https://i.imgur.com/SDVOGoE.png)