接線曲面(ヘリカル・コンボリュート面)
可展面は柱面、錐面、接線曲面の3種類に分類されます。
柱面と錐面は、容易に想像ができると思いますが、では接線曲面とはどんなものか? なかなか容易に想像できません。
ネットで検索しても、ほとんど情報がありません。そのようなわけで、少しここでまとめてみたいと思います。
可展面はガウス曲率がゼロで、直線エレメントを持ちます。
直線エレメントが平行なものが柱面、1点で交わるものが錐面です。
接線曲面は、直線エレメントが異なった点で交わるケースを言います。別の言い方をすると、空間曲線の接線の集合で作られる曲面である、とも言われます。
このような接線曲面の最も簡単な例として、常螺旋(つるまき線)の接線によって生成される、ヘリカル・コンボリュート面というものがあります。
(ヘリカル・コンボリュート面という名称も、ネット上ではほとんど情報が見つかりません。唯一、信頼のおける出展として「工学基礎 図学と製図(磯田 浩/鈴木賢次郎 共著、サイエンス社)」があります。)
このヘリカル・コンボリュート面とは、いったいどのような曲面なのか、近似多面体を生成するプログラムを作ってみました。
下の図はその結果。曲面だけだとわかりにくいので、閉じた立体になるよう、底面と円柱面も生成しています。
真上から見た時に、切断面がインボリュート曲線になっていることを確認できると思います。
ちなみに、こちらの「Geometric modeling with conical meshes and developable surfaces」の論文によると、平面四角形のStripによって、離散的に可展面を表現できることが書かれています。
以下、Javaによるプログラムコード。興味がありましたら、パラメータをいじって試してみてください。
import java.io.BufferedWriter; import java.io.FileWriter; import javax.vecmath.*; public class TangentDevelopableSurfaceGen { public static void main(String[] args) { int N = 64; // 円周の分割数 double r = 100; // 円周の半径 double u = 4; // 常螺旋の一周当たり対半径上昇率 double da = Math.PI * 2 / N; int pNum = N; Vector3d[] P = new Vector3d[pNum]; Vector3d[] P_z0 = new Vector3d[pNum]; for(int i = 0; i < pNum; i++) { double px = r * Math.cos(i*da); double py = r * Math.sin(i*da); double pz = i*u*r/N; P[i] = new Vector3d(px, py, pz); double lx = -r*da*Math.sin(i*da); double ly = r*da*Math.cos(i*da); double lz = u*r/N; Vector3d lv = new Vector3d(lx, ly, lz); lv.normalize(); double scale = pz / lv.z; P_z0[i] = new Vector3d(P[i]); P_z0[i].x -= scale*lv.x; P_z0[i].y -= scale*lv.y; P_z0[i].z -= scale*lv.z; } try { java.util.Date date = new java.util.Date(); String filename = "c:\\tds_" + date.getTime() + ".obj"; FileWriter fw = new FileWriter(filename); BufferedWriter bw = new BufferedWriter(fw); bw.write("# Created by TangentDevelopableSurfaceGen\n"); bw.write("\n"); for(int i = 0; i < pNum; i++) { bw.write("v " + P[i].x + " " + P[i].z + " " + P[i].y + " \n"); // 常螺旋 bw.write("v " + P_z0[i].x + " " + P_z0[i].z + " " + P_z0[i].y + " \n"); // 接線のz=0の点 bw.write("v " + P[i].x + " " + (0.0) + " " + P[i].y + " \n"); // 円柱のz=0の点 } for(int i = 1; i < pNum; i++) { int index = i*3+1; bw.write("f " + (index) + " " + (index-3) + " " + (index-2) + " " + (index+1) + "\n"); // 接線曲面 bw.write("f " + (index) + " " + (index+2) + " " + (index-1) + " " + (index-3) + "\n"); // 円柱面 bw.write("f " + (index+2) + " " + (index+1) + " " + (index-2) + " " + (index-1) + "\n"); // 底面 } bw.close(); } catch(Exception e) {} } }
上記プログラムによって生成されたOBJファイルはこちら。
時間があれば、実際に展開図を作って紙模型に組み立てて見て、「ほら、確かに平面に展開できる曲面だね」とやってみたいところ。どなかたやってみてください :-)