みたにっき@はてな

三谷純のブログ

接線曲面(ヘリカル・コンボリュート面)

可展面は柱面、錐面、接線曲面の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ファイルはこちら
時間があれば、実際に展開図を作って紙模型に組み立てて見て、「ほら、確かに平面に展開できる曲面だね」とやってみたいところ。どなかたやってみてください :-)