アニメーションGIF2

  • 使用したフリーアプリについては、こちらをどうぞ。
  • 3次元グラフ様のスケルトンオブジェクトをアニメーションGIFで動かしてみる。
  • 対象
    • ケルトンオブジェクトは、見えない部分のことなどを気にする必要がないので、面倒がない
    • 点を直線で結んだものがスケルトンオブジェクト
    • 点と直線の座標は3次元で与えられる
  • 手順
    • ケルトンオブジェクトをjava で作る
      • グラフとしてデータを格納する
        • 頂点(ノード)を登録し、それに3次元座標を与える
        • 頂点間を結ぶ辺を登録する
      • 視点を変えて眺める
        • 3次元に対応する3本の正規直行座標の単位ベクトルの射影ベクトルをオイラー角にて与える
	public static double[][] GetCoord(double[][] c,double[] a){
		double[][] ret = new double[c.length][2];
		double[] cos = {Math.cos(a[0]*Math.PI),Math.cos(a[1]*Math.PI),Math.cos(a[2]*Math.PI)};
		double[] sin = {Math.sin(a[0]*Math.PI),Math.sin(a[1]*Math.PI),Math.sin(a[2]*Math.PI)};
		
		for(int i=0;i<ret.length;i++){
			ret[i][0]=c[i][0]*(cos[0]*cos[1]*cos[2]-sin[0]*sin[2])+
			          c[i][1]*(sin[0]*cos[1]*cos[2]+cos[0]*sin[2])+
			          c[i][2]*(-sin[1]*cos[2]);
				
			ret[i][1]=c[i][0]*(-sin[0]*cos[2]-cos[0]*cos[1]*sin[2])+
	          c[i][1]*(cos[0]*cos[2]-sin[0]*cos[1]*sin[2])+
	          c[i][2]*(sin[1]*sin[2]);
		}
		return ret;
	}
        • yz軸についてのみの回転をさせたい、などの特別な用途には
	public static double[][] GetCoordYZrotation(double[][] c, double a){
		double[][] ret = new double[c.length][2];
		double cos = Math.cos(a*Math.PI);
		double sin = Math.sin(a*Math.PI);
		
		for(int i=0;i<ret.length;i++){
			ret[i][0]=c[i][0];
				
			ret[i][1]=c[i][1]*cos+c[i][2]*sin;
			}
		return ret;
	}
        • svgファイルにオブジェクトとして出力させる
          • 頂点は円で
	public static String Circle(double[] c,double f){
		String ret="";
		ret+="<circle cx=\"";
		ret+=c[0];
		ret+="\" cy=\"";
		ret+=c[1];
		ret+="\" r=\"";
		double scale=50;
		scale*=f;
		ret+=scale;
		ret+="\" fill=\"gray\"/>\n";

		return ret;
	}
          • 辺は直線で
	public static String Line(double[] c1, double[] c2,double width,int colorType){
		
		String ret="<line x1=\"";
		ret+=c1[0];
		ret+="\" y1=\"";
		ret+=c1[1];
		ret+="\" x2=\"";
		ret+=c2[0];
		ret+="\" y2=\"";
		ret+=c2[1];
		
		ret+="\" stroke-width=\"5\" stroke=\"";
		String[] color={"yellow","red","blue"};
		ret+=color[colorType];
		ret+="\"/>\n";
		
		return ret;
	}
        • svgファイルのヘッダ・フッタつきで、ファイルに出力させる(少し、色やら大きさやらについて、カスタマイズした部分があるので、シンプルなスケルトンにするには、それを取り除いて作ればよい)
          • この後、gifファイル形式に変換するが、そのとき、svgのキャンパスサイズなどが小さ過ぎると、まったく実用にならないgifファイルができてしまうので、適当に調整すること(ヘッダの、width, height, viewBox)。
	public void PrintSVG(double[] a,String outfile)throws IOException{
			String header="<?xml version=\"1.0\" standalone=\"no\"?>\n"+"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"+
	"<svg width=\"500pt\" height=\"500pt\" viewBox=\"-1000 -1000 2000 2000\" xmlns=\"http://www.w3.org/2000/svg\">";
			
			
			String footer="</svg>";
			BufferedWriter[] bw = new BufferedWriter[1];
			bw[0] = new BufferedWriter(new FileWriter(outfile));
			double[][] prevcoord=new double[3][2];
			double[][] postcoord=new double[3][2];
			try{
				bw[0].write(header);
				for(int i=0;i<edgeWidth.length;i++){
					prevcoord=GetCoord(coord[i],a);
					postcoord=GetCoord(coord[i+1],a);
					for(int j=0;j<prevcoord.length;j++){
						String tmpCircle=Circle(prevcoord[j],freq[i][j]);
						bw[0].write(tmpCircle);
						
					}
					for(int j=0;j<prevcoord.length;j++){
						for(int k=0;k<postcoord.length;k++){
							int colorType=0;
							if(j==k){
								colorType=2;
								if(j==1 && k==1){
									colorType=1;
								}
							}
							
							String tmpLine=Line(prevcoord[j],postcoord[k],edgeWidth[i][j][k],colorType);
							bw[0].write(tmpLine);
						}
					}
				}
				
				bw[0].write(footer);
				bw[0].close();
			}catch(Exception e){
				
				System.out.println(e);
				
			}
		}
	public void PrintSVGrotationYZ(double a,String outfile)throws IOException{
		String header="<?xml version=\"1.0\" standalone=\"no\"?>\n"+"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"+
"<svg width=\"500pt\" height=\"500pt\" viewBox=\"-1000 -1000 2000 2000\" xmlns=\"http://www.w3.org/2000/svg\">";
		
		
		String footer="</svg>";
		BufferedWriter[] bw = new BufferedWriter[1];
		bw[0] = new BufferedWriter(new FileWriter(outfile));
		double[][] prevcoord=new double[3][2];
		double[][] postcoord=new double[3][2];
		try{
			bw[0].write(header);
			for(int i=0;i<edgeWidth.length;i++){
				prevcoord=GetCoordYZrotation(coord[i],a);
				postcoord=GetCoordYZrotation(coord[i+1],a);
				for(int j=0;j<prevcoord.length;j++){
					String tmpCircle=Circle(prevcoord[j],freq[i][j]);
					bw[0].write(tmpCircle);
					
				}
				for(int j=0;j<prevcoord.length;j++){
					for(int k=0;k<postcoord.length;k++){
						int colorType=0;
						if(j==k){
							colorType=2;
							if(j==1 && k==1){
								colorType=1;
							}
						}
						
						String tmpLine=Line(prevcoord[j],postcoord[k],edgeWidth[i][j][k],colorType);
						bw[0].write(tmpLine);
					}
				}
			}
			
			bw[0].write(footer);
			bw[0].close();
		}catch(Exception e){
			
			System.out.println(e);
			
		}
	}
          • アニメーションのために、視点を変化させた複数ファイルを作成する
            • 下記の例は、グラフオブジェクトを作ったうえで、YZ軸について、0から2\piラジアンまで、0.1\pi刻みで視点を変えて、それにcounter番号つきで出力させたもの
Plot3DforSNP t=new Plot3DforSNP(freq,coord,edge);
		String outfile="test6";
		double kizami=0.1;
		int counter=0;
		for(double a=0;a<2;a+=kizami){
			String outfile2=outfile+"for"+counter+".svg";
			t.PrintSVGrotationYZ(a, outfile2);
			counter++;
		}
          • svgファイルをgif形式に一括して置換する
            • ImageMagickをインストールし、以下のようにして、gif形式ファイルを作る
mogrify -format gif *.svg
          • アニメーションgifにまとめる
            • Animation GIF Maker に出力ファイルを渡して、「まとめる」
            • 出来上がり!