在wiki上有对STL图形文件格式的详细描述。
http://en.wikipedia.org/wiki/STL_(file_format)
STL文件格式分为两种:ASCII字符格式,及二进制格式。
ASCII字符格式的格式如下:
开头一行:
solid name // 文件名是可选的字符串接下来,是三角片的数据格式:
facet normal ni nj nk outer loop vertex v1x v1y v1z vertex v2x v2y v2z vertex v3x v3y v3z endloop endfacet结束行标志:
endsolid name
二进制格式数据:
因为字符格式的STL文件比较大,占空间,因为有了二进制格式,且二进制的存储格式与ASCII的格式不同。二进制有80个字节作为文件头,一般都忽略掉,但开头不能使solid,不然就不能与ASCII格式相区分了。 另外,接下来4个字节是存放的三角片的个数,这个是ASCII格式所没有 的。
UINT8[80] – Header UINT32 – Number of triangles foreach triangle REAL32[3] – Normal vector REAL32[3] – Vertex 1 REAL32[3] – Vertex 2 REAL32[3] – Vertex 3 UINT16 – Attribute byte count end
读取STL文件,首先,程序要区别读取的是那种格式的STL。然后根据格式,来读取数据。
先定义如下数据类型:
template <int D, class T = float>
class Vec {
private:
T v[D];
public:
...
};
typedef Vec<3,float> Vec3f;
用于存放点坐标数据和法向量数据,这里将点坐标和法向量都读到一个数组中。
bool ReadSTLFile(const char *cfilename) { if (cfilename == NULL) { return false; } ifstream in(cfilename, ios::in); if (!in) { return false; } string headStr; getline(in, headStr, ' '); in.close(); if (headStr.empty()) { return false; } if (headStr[0] == 's') { ReadASCII(cfilename); } else { ReadBinary(cfilename); } return true; }
bool ReadASCII(const char *cfilename) { int i=0,j=0,cnt=0 ,pCnt=4; char a[100]; char str[100]; double x=0,y=0,z=0; Vec3f tPoint; Vector<Vec3f> pointList; // todo: 可以预先计算出pointList的大小,节省空间 ifstream in; in.open(cfilename, ios::in); if (!in) { return false; } do { i=0; cnt=0; in.getline(a,100, '\n'); while(a[i]!='\0') { if (!islower((int)a[i]) && !isupper((int)a[i]) && a[i]!=' ') break; cnt++; i++; } while(a[cnt]!='\0') { str[j]=a[cnt]; cnt++; j++; } str[j]='\0'; j=0; if (sscanf(str,"%lf%lf%lf",&x,&y,&z)==3) { tPoint.SetParam(x,y,z); pointList.push_back(tPoint); } pCnt++; }while(!in.eof()); return true; } bool ReadBinary(const char *cfilename) { char str[80]; ifstream in; //三角形数目 int unTriangles(0); in.open(cfilename, ios::in); if (!in) { return false; } in.read(str, 80); in >> unTriangles; if(unTriangles==0) { return false; } Vec3f tPoint; vector<Vec3f> pointList(unTriangles); // 预留足够的空间 float x(0.f), y(0.f), z(0.f); char unusedByte; //Binary for(int i=0;i<(int)unTriangles;i++) { for (int pointIdx=0; pointIdx<4; pointIdx++) { in >> x >> y >> z; tPoint.SetParam(x, y, z); pointList.push_back(tPoint); } in >> unusedByte >> unusedByte; } in.close(); return true; }