はじめに
これは POV-Rayによる数学お絵かき入門 Advent Calendar 2017 の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
この例では色の指定にもi
を入れ込めて球面の色が変わるようになっています.https://i.imgur.com/j3sTDBZ.png
if
条件分岐を記述するためには次のように書きます.
#if(条件)
処理1
#else
処理2
#end
第四回に書いたように, POV-Rayでは真偽値が1と0で表現されます.
if
やwhile
の条件で判断される際には, 0
に等しいか否かによって判断されます.
macro
マクロを書くには次のように書きます.
#macro(第1引数,...,第n引数)
処理
#end
つまらない例ですが, 鉛直方向を向いた円柱のマクロは次のように書けます.
#macro(r,l)
cylinder{<0,0,0>,<0,l,0>,r}
#end
第四回でも少し触れましたが, macro
内で変数を宣言する際にはローカル変数にはlocal
, グローバル変数にはdeclare
を使います.
基本的にはmacro
は関数と考えて差し支えありませんが, 厳密には異なります.
これに関しては連載後半で改めて記述する予定です.
多面体
立方体
while
とmacro
を使う
一番簡単な立方体から書きなおします.
対称性を考えれば, 頂点は次のように書けます.
#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
cylinder
を付け加えて辺を描きます.
#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
ここで次のマクロRotate
を定義します.
#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$回転します.
上と合わせれば次のように書けます.
#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
正八面体
同様に次のように描けます.
#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
正四面体
全列挙の方が早そうですが, 折角なので対称性を利用して描いてみましょう.
これまでと違って条件分岐if
も使います.
立方体の頂点を元に正四面体を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,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
2つの正四面体の内の1つだけ描画するために, sphere
とcylinder
をif
で囲みます.
#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
正十二面体
前回愚直に書こうとして諦めた正十二面体も, 次のように書けます.
#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
正二十面体
最後の例は正二十面体です.
これも各頂点座標が黄金比で書けます.
#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