金子邦彦研究室研究道具箱と教材オープンデータPly 形式のファイルを STL 形式に変換

Ply 形式のファイルを STL 形式に変換

変換したいだけならば、meshlab を利用するのが楽. Color STL 形式を作りたいと思い、プログラムを作成.

STL ファイルの情報: https://orion.math.iastate.edu/burkardt/data/stl/stl.html

コンパイル手順

gcc -o a.out a.cc -lm 

[image]

使用法

  1. Ply ファイルの準備

    60 Excellent Free 3D Model Websites http://www.hongkiat.com/blog/60-excellent-free-3d-model-websites/

  2. meshlab を用いて前処理
    1. meshlab を起動.
    2. Import Mesh でファイルを読み込む
    3. Export Mesh As で ply 形式を選ぶ.normal にチェックする.binary のチェックを外す.

    次のような形式に変換

    [image]

  3. その後、下のプログラムを利用.

    [image]

    ソースコード

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    
    static void Error(char* msg)
    {
    	fputs(msg,stderr); fputc('\n',stderr); exit(1);
    }
    
    #define STR_LEN	256
    
    static char	line[STR_LEN];
    
    static void	Scan(FILE* file)
    {
    	char	str[STR_LEN];
    
    	for (;;) {
    	    if (fgets(line,STR_LEN,file)==NULL)
    		Error("unexpected end of file.");
    
    	    if (line[strlen(line)-1]!='\n') Error("missing end of line.");
    
    	    if (sscanf(line,"%s",str)==1 && strcmp(str,"comment")) return;
    	}
    }
    
    static int	CheckElement(FILE* file, char* element)
    {
    	char	str[3][STR_LEN];
    	int	number;
    
    	Scan(file);
    	fprintf(stderr, "%s\n", line); 
    	if (sscanf(line,"%s %s %s",str[0],str[1],str[2])!=3 ||
    	    strcmp(str[0],"element") ||
    	    strcmp(str[1],element) ||
    	    sscanf(str[2],"%d",&number)!=1 ||
    	    number<=0) {
    	  fprintf(stderr,"bad element specification for %s (number = %d) \n",element, number);
    	    exit(1);
    	}
    	return number;
    }
    
    static void	CheckProperty(FILE* file, char* type, char* name, char* element)
    {
    	char	str[3][STR_LEN];
    
    	Scan(file);
    	if (sscanf(line,"%s %s %s",str[0],str[1],str[2])!=3 ||
    	    strcmp(str[0],"property") ||
    	    strcmp(str[1],type) ||
    	    strcmp(str[2],name)) {
    	  fprintf(stderr,"bad property specification for %s, (line = %s)\n",element, line);
    	    exit(1);
    	}
    }
    
    #define MA(noe,ptr)	malloc((noe)*sizeof(*(ptr)))
    
    typedef struct _vertex {
      double x;  
      double y;  
      double z;  
      double nx;
      double ny;
      double nz;
      int r;
      int g; 
      int b;
      int alpha;
    } vertex; 
    
    typedef struct _face {
      int v0; 
      int v1; 
      int v2; 
    } face; 
    
    int	main(int argc, char** argv)
    {
    	FILE	*zcp,*stl;
    	char	str[10][STR_LEN];
    	int vertices, faces;
    	//	int	vertices,faces,face,vertex,idx,R,G,B;
    	//	double	x10,x20,y10,y20,z10,z20,nx,ny,nz,n;
    	//	short	flag;
    
    	if (argc!=3) Error("usage : zcp_stl ZCP STL");
    
    	if (argv[1][0]=='-')
    	    zcp=stdin;
    	else
    	    if ((zcp=fopen(argv[1],"rb"))==NULL) Error("file not found.");
    
    	if (fgetc(zcp)!='p' ||
    	    fgetc(zcp)!='l' ||
    	    fgetc(zcp)!='y') Error("bad magic number.");
    
    	Scan(zcp);
    	if (sscanf(line,"%s %s %s",str[0],str[1],str[2])!=3 ||
    	    strcmp(str[0],"format") ||
    	    //	    strcmp(str[1],"binary_little_endian") ||
    	    strcmp(str[1],"ascii") ||
    	    strcmp(str[2],"1.0"))
    	    Error("bad format specification.");
    
    	vertices=CheckElement(zcp,"vertex");
    
    	CheckProperty(zcp,"float","x","vertex");
    	CheckProperty(zcp,"float","y","vertex");
    	CheckProperty(zcp,"float","z","vertex");
    
    	CheckProperty(zcp,"float","nx","vertex");
    	CheckProperty(zcp,"float","ny","vertex");
    	CheckProperty(zcp,"float","nz","vertex");
    
    	faces=CheckElement(zcp,"face");
    
    	Scan(zcp);
    	if (sscanf(line,"%s %s %s %s %s",
    			str[0],str[1],str[2],str[3],str[4])!=5 ||
    	    strcmp(str[0],"property") ||
    	    strcmp(str[1],"list") ||
    	    strcmp(str[2],"uchar") ||
    	    strcmp(str[3],"int") ||
    	    strcmp(str[4],"vertex_indices"))
    	    Error("bad vertex index specification for face.");
    
    	CheckProperty(zcp,"uchar","red","vertex");
    	CheckProperty(zcp,"uchar","green","vertex");
    	CheckProperty(zcp,"uchar","blue","vertex");
    	CheckProperty(zcp,"uchar","alpha","vertex");
    
    	Scan(zcp);
    	if (sscanf(line,"%s",str[0])!=1 ||
    	    strcmp(str[0],"end_header")) Error("missing end of header.");
    
    	vertex *XYZ = (vertex *)malloc(sizeof(vertex) * vertices); 
    
    	int i;
    	for (i=0; i<vertices; i++) {
    	  Scan(zcp);
    	  sscanf(line,"%s %s %s %s %s", str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7], str[8], str[9] );   
    	  XYZ[i].x = atof(str[0]);
    	  XYZ[i].y = atof(str[1]);
    	  XYZ[i].z = atof(str[2]);
    
    	  XYZ[i].nx = atof(str[3]);
    	  XYZ[i].ny = atof(str[4]);
    	  XYZ[i].nz = atof(str[5]);
    
    	  XYZ[i].r = atoi(str[6]);
    	  XYZ[i].g = atoi(str[7]);
    	  XYZ[i].b = atoi(str[8]);
    	  XYZ[i].alpha = atoi(str[9]);
    
    	}
    
    	face *F = (face *)malloc(sizeof(face) * faces); 
    
    	for (i=0; i<faces; i++) {
    	  Scan(zcp);
    	  sscanf(line,"%s %s %s %s", str[0], str[1], str[2], str[3]);
    	  F[i].v0 = atoi(str[1]);
    	  F[i].v1 = atoi(str[2]);
    	  F[i].v2 = atoi(str[3]);
    	}
    	// for debug
    	// printf("%f %f %f\n", XYZ[0].x, XYZ[0].y, XYZ[0].z );
    	// printf("%d %d %d\n", F[0].v0, F[0].v1, F[0].v2 );
    
    	if (argv[2][0]=='-')
    	    stl=stdout;
    	else
    	    if ((stl=fopen(argv[2],"w"))==NULL) Error("file not stored.");
    
    	// header
    	fputs("solid \n", stl);
    
    	for (i=0; i<faces; i++) {
    	  double x10 = XYZ[F[i].v1].x  -  XYZ[F[i].v0].x;
    	  double x20 = XYZ[F[i].v2].x  -  XYZ[F[i].v0].x;
    	  double y10 = XYZ[F[i].v1].y  -  XYZ[F[i].v0].y;
    	  double y20 = XYZ[F[i].v2].y  -  XYZ[F[i].v0].y;
    	  double z10 = XYZ[F[i].v1].z  -  XYZ[F[i].v0].z;
    	  double z20 = XYZ[F[i].v2].z  -  XYZ[F[i].v0].z;
    	  double nx=y10*z20-z10*y20;
    	  double ny=z10*x20-x10*z20;
    	  double nz=x10*y20-y10*x20; 
    	  double n=sqrt(nx*nx+ny*ny+nz*nz);
    	  fprintf(stl, "facet normal %f %f %f\n", nx/n, ny/n, nz/n );
    
    	  fprintf(stl, "outer loop\n");
    
    	  fprintf(stl, "vertex %f %f %f %d %d %d\n", XYZ[F[i].v0].x, XYZ[F[i].v0].y, XYZ[F[i].v0].z,  XYZ[F[i].v0].r, XYZ[F[i].v0].g, XYZ[F[i].v0].b );
    	  fprintf(stl, "vertex %f %f %f %d %d %d\n", XYZ[F[i].v1].x, XYZ[F[i].v1].y, XYZ[F[i].v1].z,  XYZ[F[i].v1].r, XYZ[F[i].v1].g, XYZ[F[i].v1].b );
    	  fprintf(stl, "vertex %f %f %f %d %d %d\n", XYZ[F[i].v2].x, XYZ[F[i].v2].y, XYZ[F[i].v2].z,  XYZ[F[i].v2].r, XYZ[F[i].v2].g, XYZ[F[i].v2].b );
    
    	  fprintf(stl, "endloop\n");
    
    	  fprintf(stl, "endfacet\n");
    	}
    
    	// end
    	fputs("endsolid \n", stl);
    	fclose(stl);
    	
    	//
    	if ( XYZ != NULL ) {
    	  free(XYZ);
    	}
    	if ( F != NULL ) {
    	  free(F);
    	}
    
    	return 0;
    }