回転体

SpaceCindyRay を使って回転体を描きます。たとえば球面は,yz平面に描いた円をz軸の周りに回転してできる回転体です。円筒や円錐もそうです。トーラスも,z軸から離れたところにある円をz軸の周りに回転すればできますので回転体であるといえます。この節では,いろいろな回転体を効率よく描くスクリプトを作り,さらにちょっとした応用も考えていきます。使うのはSpaceCindyRayです。

z軸周りの回転体

空間内の曲線を,z軸周りに回転させます。 下図左は,曲線上のある点をz軸周りに回転して緑の円ができている様子を示します。これを,曲線上のすべての点について行えば,右図のようになります。


 

青の曲線はyz平面上で,媒介変数表示にして z=fz(u),y=fy(u) で表します。y=f(z) の形の式でも,z=fz(u)=u,y=fy(u)=f(u) とすればよいのです。すると,緑の円の半径は y=fy(u)ですので,円周上の点は x=fy(u)cosv , y=fy(u)sinv, z=fz(u) で表せます。2変数の媒介変数表示ですので,この曲面は surface3() で描けます。

スクリプトは次のようにすればよいでしょう。

setview3d(0,15,30);

fz(u):=u;

fy(u):=1+sin(2*u)/2;

pfx(u,v):=fy(u)*cos(v);

pfy(u,v):=fy(u)*sin(v);

pfz(u,v):=fz(u);

begin3d();

surface3(["pfx(u,v)","pfy(u,v)","pfz(u,v)"],[[-pi/2,pi/2],

[0,2*pi]],[limegreen,"Alpha=[1,0.3]","mesh=[100,100]"]);

end3d();

実行結果は次の図です。

surface3() のオプションのうち, " mesh=[100,100] " は,デフォルトよりこの方がきれいに描画されますのでつけました。

さて,このスクリプトを使いやすくなるように変更しましょう。たとえば,表示色と透明度は変数にしてはじめの方で定義すれば,書き換える場所を探す必要がなく使いやすくなります。一方,pfx(),pfy(),pfz() は変更の必要はありません。また,fz(), fy() で表される曲線は別途表示されるとよいでしょう。

y軸周りもできるようにする

さらに,z軸周りだけでなく,y軸周りもできるようにしましょう。

type=1; // 1 のときz軸周り 1以外のときy軸周り

fx(u):=u;

fy(u):=1.7*sin(u+pi/4);

range=[0,3*pi/4];

col=yellow;

alpha="Alpha=[1,1]";

//--------------------

setview3d(0,15,30);

pfx(u,v):=fy(u)*cos(v);

pfy(u,v):=fy(u)*sin(v);

pfz(u,v):=fx(u);

begin3d();

if(type==1,

plot([fy(t),fx(t)],start->range_1,stop->range_2);

surface3(["pfx(u,v)","pfy(u,v)","pfz(u,v)"],[range,[0,2*pi]],

[col,"mesh=[100,100]",alpha]);

,

plot([fx(t),fy(t)],start->range_1,stop->range_2);

surface3(["pfx(u,v)","pfz(u,v)","pfy(u,v)"],[range,[0,2*pi]],

[col,"mesh=[100,100]",alpha]);

);

end3d();

式や表示色など,変更するのは //------ から前の部分です。fx(u),fy(u) が曲線の式。z軸周りでも fz()にする必要はありません。rangeは定義域。colは表示色,alphaは透明度です。begin3d() のあとですが,plot(・・)は,Cinderellaの描画面の方に曲線を表示するためのものです。この例は正弦曲線の一部を回転したもので,色が yellow で宝珠のような形ですが,色と透明度を変えると栗のように見えます。

type=2 とするとy軸周りになります。次の図は,天使のラッパと呼ばれているものです。 双曲線 y=1/x の x ≧1 の部分を回転してできる図形です。スクリプトの前半だけ変えます。全体を左の方に平行移動しています。

type=2; // 1 のときz軸周り

fx(u):=u-3;

fy(u):=1/(u+1);

range=[0,7];

col=[0.95,0.9,0.2];

alpha="Alpha=[1,0.3]";

次の曲面は,先ほどの宝珠と似ていますが,三角関数ではなく無理関数を使います。y=u√(1-u)を基本形として,係数を変えたり,平行移動したりしています。注意すべきは定義域です。

type=1; // 1 のときz軸周り

fx(u):=2-u;

fy(u):=u*sqrt(3-u)/2;

range=[0,2.99];

col=[0.9,0.95,0.9];

alpha="Alpha=[1,0.3]";

定義域は理論的には[0,3]でよいはずなのですが,そうすると表示がされません。値を細かく区切ってプロットしていくときの誤差のためと思われます。このような場合は,上のように定義域をわずかに狭くするか,関数の式でルートの中を絶対値にします。

fy(u):=u*sqrt(abs(3-u))/2;

range=[0,3];

とすれば同じように表示されます。メタリックな雫です。

なお,右の曲線の表示では下の線が軸まで届いていませんが,これもプロット時の誤差です。媒介変数のときの解像度に関する plot() の修飾子 steps->100 をつければ解消できますが,こちらの図は概要と思えばそのままでもよいでしょう。

次の図は,リマソン(カージオイド)を回転したものです。りんごのような形です。

fx(u):=-(1+1*cos(u))*cos(u);

fy(u):=(1+1*cos(u))*sin(u);

range=[0,pi];

col=brickred;

alpha="Alpha=[1,0.17]";

segment3d([[0,0,0.2],[-0.1,0.1,0.4]],[sepia,"size=1.5"]);

で枝をつけるとりんごらしくなります。

定義域を分ける

定義域を分けて曲線を組み合わせることもできます。次の例は,直線と指数関数のグラフを組み合わせて,カクテルグラスを描いたものです。

fx(u):=u;

fy(u):=if(u<-7/4,-3*u-5-1/8,

if(u<0,0.125,(3/2)^u-7/8);

);

range=[-2,2];

col=white;

alpha="Alpha=[1,0.3]";

描画色を白にしていますが,影ができるのでどうしてもメタリックな質感になってしまします。そこで,点光源を1つ作ります。

pointlight3d(1,position->[0,0,10]);

入れる場所は begin3d() の前でもあとでもよいです。

透明感は出ましたが,上下の輪郭が曖昧になってしまったので,円を描きましょう。グラスを描いた(回転体を描いた)あとに追加すればよいでしょう。

circle3d([0,0,2],[0,0,1],(3/2)^2-7/8,[[0.5,0.5,0.5],"size=0.2"]);

circle3d([0,0,-2],[0,0,1],7/8,[[0.5,0.5,0.5],"size=0.2"]);

回転体の描画を関数化する

カクテルグラスだけではなくて,中にカクテルも入れたいですね。カクテルも回転体で作って重ね書きすればよいでしょう。そのために,描画部分を関数化して,何度でも使えるようにしましょう。引数を type にすれば縦横自在になるので便利です。

// 回転体を描く 引数 typeは1のときz軸周り それ以外はy軸周り

revolution(type):=(

pfx(u,v):=fy(u)*cos(v);

pfy(u,v):=fy(u)*sin(v);

pfz(u,v):=fx(u);

if(type==1,

plot([fy(t),fx(t)],start->range_1,stop->range_2);

surface3(["pfx(u,v)","pfy(u,v)","pfz(u,v)"],[range,[0,2*pi]],

[col,"mesh=[100,100]",alpha]);

,

plot([fx(t),fy(t)],start->range_1,stop->range_2);

surface3(["pfx(u,v)","pfz(u,v)","pfy(u,v)"],[range,[0,2*pi]],

[col,"mesh=[100,100]",alpha]);

);

);

関数定義は一度だけ実行すればよいので,Initialization スロットに新しいページを作ってそちらに移動します。

Draw スロットの方はつぎのようにします。

setview3d(0,15,30);

begin3d();

pointlight3d(1,position->[0,0,10]);

fx(u):=u;

fy(u):=if(u<-7/4,-3*u-5-1/8,

if(u<0,0.125,(3/2)^u-7/8);

);

range=[-2,2];

col=white;

alpha="Alpha=[1,0.3]";

revolution(1);

fx(u):=u;

fy(u):=(3/2)^u-7/8-1/16;

range=[1/4,1.5];

col=orange;

alpha="Alpha=[1,1]";

revolution(1);

circle3d([0,0,2],[0,0,1],(3/2)^2-7/8,[[0.5,0.5,0.5],"size=0.2"]);

circle3d([0,0,-2],[0,0,1],7/8,[[0.5,0.5,0.5],"size=0.2"]);

end3d();

fx() と fy() を定義し直し,色の設定も変えて revolution(1) を呼び出しています。後の方が中身のカクテルです。