球の切断

球を平面で切った図を作ります。

まずは完成図から。

左は半球を傾けたもの,右は中心から半径の2分の1で切ったものです。

この図は、平面図形と考えれば、円の一部と楕円を組み合わせれば描けそうです。しかし,インタラクティブに視点を変えていくとなると,3Dで描くほうがよいでしょう。

すこしずつ実験をしながら進めます。

球と切断面を描く

まず、球を描きますが、KeTCindyの Sfbdparadata できちんと描こうとすると,描画に時間がかかってインタラクティブに視点を変えるにはあまり現実的ではありません。球面は「面」としての図はいらないので,法線ベクトルが常に視点方向を向いている円を描くことで球に見せることにします。これをSpacekcではquasisphere (疑似球面)と呼んでいます。

まず疑似球面と断面の円を描きます。

pd1=quasisphere("1",[0,0,0],2);

pd2=circle3d("1",[0,0,0],[0,1,sqrt(3)],2);

この図で、球を表す円の下側の部分だけ表示すればいいのです。

切断面との交点を求めて、一方の交点から他方の交点までの範囲で描けばよいのですが、空間座標のままではこれを行う関数がありません。そこで2次元の画面に投影したプロットデータで処理をします。quasisphere と circle3d は"nodisp" オプションをつけて非表示にしておいて,それぞれのプロットデータを取得します。(この時点では空間座標です)

それぞれの要素を平面に射影して、Listplot() で描きます。

pd1=quasisphere("1",[0,0,0],2,["nodisp"]);

pd2=circle3d("1",[0,0,0],[0,1,sqrt(3)],2,["nodisp"]);

sp=apply(pd1,map2d(#));

su1=apply(pd2,map2d(#));

Listplot("1",sp);

Listplot("2",su1);

できる図は先ほどと同じです。

次のスクリプトを追加して交点を求めます。

int1=Intersectcrvs("sg1","sg2");

println(int1);

コンソールに次のように表示されます。(視点(座標軸の角度)によって違います)

[[1.73,-0.99],[1.76,-0.94],[-1.73,0.99],[-1.76,0.94]]

4つの値が出ているのは,円が実際には多角形であることによります。視点を変えると2つになることもあります。画面上ではほとんど区別できません。

上の場合は,1番目と3番目をとればよいでしょう。

Listplot()で描いていた円(疑似球面)は非表示にして,Partcrv() で円の下半分を描きます。

Listplot("1",sp,["nodisp"]);

Listplot("2",su1);

int1=Intersectcrvs("sg1","sg2");

println(int1);

p1=int1_1;

p2=int1_3;

Partcrv("1",p2,p1,"sg1");

これで,座標軸を非表示にすれば,冒頭の図ができます。

pd2=circle3d("1",[0,0,1],[0,0,1],sqrt(3),["nodisp"]);

として,交点を確認して取り直せば右の図になります。

応用

積分の問題としてよくある図。半球に水を満たし、30度傾けて水を流す。残った水の量を求める問題の図です。

球の切断面を追加します。

pd3=circle3d("2",[0,0,-1],[0,0,1],sqrt(3),["nodisp"]);

su2=apply(pd3,map2d(#));

Listplot("3",su2,["Color=blue"]);

水の入っている部分を色塗りするには,やはり平面に投影して,水面の円の上半分と球面の下方をとりだし,Joincrvs() でつないで閉曲線を作ってShade() で色塗りをします。

pd1=quasisphere("1",[0,0,0],2,["nodisp"]);

pd2=circle3d("1",[0,0,0],[0,1,sqrt(3)],2,["nodisp"]);

pd3=circle3d("2",[0,0,-1],[0,0,1],sqrt(3),["nodisp"]);

sp=apply(pd1,map2d(#));

su1=apply(pd2,map2d(#));

su2=apply(pd3,map2d(#));

Listplot("1",sp,["nodisp"]);

Listplot("2",su1);

Listplot("3",su2,["Color=blue"]);

int1=Intersectcrvs("sg1","sg2");

int2=Intersectcrvs("sg1","sg3");

println(int1);

println(int2);

p1=int1_1;

p2=int1_3;

p3=int2_1;

p4=int2_2;

Partcrv("1", p2, p1, "sg1");

Partcrv("2", p3, p4, "sg3",["nodisp"]);

Partcrv("3", p4, p3, "sg1",["nodisp"]);

Joincrvs("1",["part2","part3"],["nodisp"]);

Shade(["join1"],["Color=[0.2,0,0,0]"]);

傾ける前の図は,pd2の法線ベクトルを変え,交点の座標を見て調整します。

pd2=circle3d("1",[0,0,0],[0,0,1],2,["nodisp"]);

p1=int1_1;

p2=int1_2;

< 戻る >