/** @brief STL ファイル入出力用ライブラリ @file STL.cpp @author Fumi.Iseki (C) @note エンディアン無変換 */ #include "STL.h" using namespace jbxl; /** STLData* ReadSTLFile(char* fname, unsigned int* fno) STLファイルを読み込むラッパー関数.アスキー,バイナリを自動判別. 読み込んだファセットの数(fno)を返す. */ DllExport STLData* ReadSTLFile(char* fname, long int* fno) { FILE* fp; struct stat stbuf; STLData* stldata; unsigned int temp; fp = fopen(fname, "rb"); if (fp==NULL) return NULL; fseek(fp, 80, SEEK_SET); fread(&temp, 4, 1, fp); fclose(fp); *fno = (long int)temp; stat(fname, &stbuf); if (stbuf.st_size == (*fno)*50+84) { // ファイルサイズのチェック stldata = ReadSTLFileB(fname, fno); // バイナリファイル } else { stldata = ReadSTLFileA(fname, fno); // アスキーファイル } if (stldata==NULL) { if (*fno!=0) { DEBUG_MODE print_messageln("ReadSTLFile: メモリの確保に失敗."); } else { DEBUG_MODE print_messageln("ReadSTLFile: データの読み込みに失敗."); } } else { DEBUG_MODE print_messageln("ReadSTLFile: file name = %s", fname); DEBUG_MODE print_messageln("ReadSTLFile: read facet No. = %d", *fno); } return stldata; } /** DllExport int WriteSTLFile (char* fname, SOLID* solid, bool ascii) STLファイルを書き込むラッパー関数. アスキー,バイナリを指定する.デフォルトはバイナリ(ascii==false). 書き込んだファセットの数を返す. */ DllExport int WriteSTLFile (char* fname, SOLID* solid, bool ascii) { int nn; if (ascii) nn = WriteSTLFileA(fname, solid); else nn = WriteSTLFileB(fname, solid); if (nn<0) DEBUG_MODE print_messageln("WriteSTLFile: ファイルオープンエラー."); return nn; } /** DllExport STLData* ReadSTLFileA(char* fname, long int* fno) アスキー形式の STLファイルを読み込み,読み込んだファセットの数を返す.@n ファイル中の facet, vertex 以外は無視. */ DllExport STLData* ReadSTLFileA(char* fname, long int* fno) { FILE* fp; STLData* stldata = NULL; float vect[3]; char buffer[LBUF], dummy[LBUF], *pbuf; int vno=0; // ファイルをオープンしてデータ数を数える. *fno = 0; fp = fopen(fname, "r"); if (fp==NULL) return 0; fgets(buffer, LBUF, fp); while (!feof(fp)) { pbuf = buffer; while(*pbuf==' '||*pbuf==CHAR_TAB) pbuf++; if (!strncasecmp(pbuf, "facet ", 6)) (*fno)++; if (!strncasecmp(pbuf, "vertex ", 7)) vno++; fgets(buffer, LBUF, fp); } fclose(fp); // メモリの確保 if (vno!=0 && vno==(*fno)*3) { stldata = (STLData*)malloc(sizeof(STLData)*(*fno)); } if (stldata==NULL) { *fno = 0; return NULL; } // もう一度ファイルをオープンして,データを読み込む. int i=0, j=0; fp = fopen(fname, "r"); if (fp==NULL) return 0; fgets(buffer, LBUF, fp); while (!feof(fp)) { pbuf = buffer; while(*pbuf==' '||*pbuf==CHAR_TAB) pbuf++; if (!strncasecmp(pbuf, "facet ", 6)) { sscanf(buffer, "%s %s %f %f %f", dummy, dummy, &vect[0], &vect[1], &vect[2]); for (int k=0; k<3; k++) stldata[i].vect[k] = vect[k]; j = 3; } if (!strncasecmp(pbuf, "vertex ", 7) && j>=3 && j<12) { sscanf(buffer, "%s %f %f %f", dummy, &vect[0], &vect[1], &vect[2]); for (int k=0; k<3; k++) stldata[i].vect[j+k] = vect[k]; j += 3; if (j==12) i++; } fgets(buffer, LBUF, fp); } fclose(fp); return stldata; } /** DllExport STLData* ReadSTLFileB(char* fname, long int* fno) バイナリ形式の STLファイルを読み込み,読み込んだファセットの数を返す. */ DllExport STLData* ReadSTLFileB(char* fname, long int* fno) { FILE* fp; char message[81]; // STLのファイルメッセージ tmpSTLData* tmp_stldata; STLData* stldata; STLData* exdata; fp = fopen(fname, "rb"); if (fp==NULL) return 0; fread(message, 80, 1, fp); message[80] = '\0'; // STLのファイルメッセージ(message[])80Byteは未使用 fread(fno, 4, 1, fp); tmp_stldata = (tmpSTLData*)malloc(sizeof(tmpSTLData)*(*fno)); if (tmp_stldata==NULL) return NULL; fread(tmp_stldata, sizeof(tmpSTLData), *fno, fp); fclose(fp); stldata = (STLData*)malloc(sizeof(STLData)*(*fno)); if (stldata==NULL) { free(tmp_stldata); return NULL; } for (int i=0; i<(*fno); i++) { exdata = (STLData*)(&tmp_stldata[i]); // アドレスの読み替え(50Byteの構造体を作れないため) for (int j=0; j<12; j++) { stldata[i].vect[j] = exdata->vect[j]; // データの移動 } } free(tmp_stldata); return stldata; } /** DllExport int WriteSTLFileA(char* fname, SOLID* solid) SOLID のデータをアスキー形式の STLファイルとして書き込む */ DllExport int WriteSTLFileA(char* fname, SOLID* solid) { FILE* fp; int nn = 0; fp = fopen(fname, "wa"); if (fp==NULL) return -1; fprintf(fp, "solid %s\n", fname); BREP_CONTOUR_RING::iterator icon; for (icon=solid->contours.begin(); icon!=solid->contours.end(); icon++){ fprintf(fp, "facet normal %g %g %g\n", (*icon)->normal.x, (*icon)->normal.y, (*icon)->normal.z); fprintf(fp, " outer loop\n"); BREP_WING* wing = (*icon)->wing; for (int i=0; i<3; i++) { VECTOR vect = ((VERTEX*)(wing->vertex))->point; fprintf(fp, " vertex %g %g %g\n", vect.x, vect.y, vect.z); wing = wing->next; } fprintf(fp," endloop\n"); fprintf(fp,"endfacet\n"); nn++; } fprintf(fp, "endsolid %s\n", fname); fclose(fp); return nn; } /** DllExport int WriteSTLFileB(char* fname, SOLID* solid) SOLID のデータをバイナリ形式の STLファイルとして書き込む */ DllExport int WriteSTLFileB(char* fname, SOLID* solid) { FILE* fp; int fno; char message[80]="STL Binary Data Program by Fumi.Iseki"; STLData stldata; fp = fopen(fname, "wb"); if (fp==NULL) return -1; fno = (int)solid->contours.size(); fwrite(message, 80, 1, fp); fwrite(&fno, 4, 1, fp); BREP_CONTOUR_RING::iterator icon; for (icon=solid->contours.begin(); icon!=solid->contours.end(); icon++){ stldata.vect[0] = (float)(*icon)->normal.x; stldata.vect[1] = (float)(*icon)->normal.y; stldata.vect[2] = (float)(*icon)->normal.z; BREP_WING* wing = (*icon)->wing; for (int i=0; i<3; i++) { VECTOR vect = ((VERTEX*)(wing->vertex))->point; stldata.vect[3*i+3] = (float)vect.x; stldata.vect[3*i+4] = (float)vect.y; stldata.vect[3*i+5] = (float)vect.z; wing = wing->next; } fwrite(&stldata, 50, 1, fp); } fclose(fp); return fno; } /** DllExport void println_FacetAsciiSTL(CONTOUR* contour) contourの情報を STLのアスキー形式で表示する ReadSTLFileA()で読み込み可 */ DllExport void println_FacetAsciiSTL(CONTOUR* contour) { BREP_WING* wing = contour->wing; print_messageln("facet normal %g %g %g", contour->normal.x, contour->normal.y, contour->normal.z); print_messageln("outer loop"); for (int i=0; i<3; i++) { VECTOR vect = ((VERTEX*)(wing->vertex))->point; print_messageln("vertex %g %g %g", vect.x, vect.y, vect.z); wing = wing->next; } print_messageln("endloop"); print_messageln("endfacet"); } DllExport void freeSTL(STLData* stldata) { if (stldata!=NULL) free(stldata); }