在wiki上有对STL图形文件格式的详细描述。
http://en.wikipedia.org/wiki/STL_(file_format)
STL文件格式分为两种:ASCII字符格式,及二进制格式。
ASCII字符格式的格式如下:
开头一行:
solid name // 文件名是可选的字符串接下来,是三角片的数据格式:
facet normal ni nj nk outer loop vertex v1xv1yv1z vertex v2xv2yv2z vertex v3xv3yv3z 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;
用于存放点坐标数据和法向量数据,这里将点坐标和法向量都读到一个数组中。
- boolReadSTLFile(constchar*cfilename)
- {
- if(cfilename==NULL)
- {
- returnfalse;
- }
- ifstreamin(cfilename,ios::in);
- if(!in)
- {
- returnfalse;
- }
- stringheadStr;
- getline(in,headStr,'');
- in.close();
- if(headStr.empty())
- {
- returnfalse;
- }
- if(headStr[0]=='s')
- {
- ReadASCII(cfilename);
- }
- else
- {
- ReadBinary(cfilename);
- }
- returntrue;
- }
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;
}
- boolReadASCII(constchar*cfilename)
- {
- inti=0,j=0,cnt=0,pCnt=4;
- chara[100];
- charstr[100];
- doublex=0,y=0,z=0;
- Vec3ftPoint;
- Vector<Vec3f>pointList;//todo:可以预先计算出pointList的大小,节省空间
- ifstreamin;
- in.open(cfilename,ios::in);
- if(!in)
- {
- returnfalse;
- }
- 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());
- returntrue;
- }
- boolReadBinary(constchar*cfilename)
- {
- charstr[80];
- ifstreamin;
- //三角形数目
- intunTriangles(0);
- in.open(cfilename,ios::in);
- if(!in)
- {
- returnfalse;
- }
- in.read(str,80);
- in>>unTriangles;
- if(unTriangles==0)
- {
- returnfalse;
- }
- Vec3ftPoint;
- vector<Vec3f>pointList(unTriangles);//预留足够的空间
- floatx(0.f),y(0.f),z(0.f);
- charunusedByte;
- //Binary
- for(inti=0;i<(int)unTriangles;i++)
- {
- for(intpointIdx=0;pointIdx<4;pointIdx++)
- {
- in>>x>>y>>z;
- tPoint.SetParam(x,y,z);
- pointList.push_back(tPoint);
- }
- in>>unusedByte>>unusedByte;
- }
- in.close();
- returntrue;
- }
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;
}
在wiki上有对STL图形文件格式的详细描述。
http://en.wikipedia.org/wiki/STL_(file_format)
STL文件格式分为两种:ASCII字符格式,及二进制格式。
ASCII字符格式的格式如下:
开头一行:
solid name // 文件名是可选的字符串接下来,是三角片的数据格式:
facet normal ni nj nk outer loop vertex v1xv1yv1z vertex v2xv2yv2z vertex v3xv3yv3z 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;
用于存放点坐标数据和法向量数据,这里将点坐标和法向量都读到一个数组中。
- boolReadSTLFile(constchar*cfilename)
- {
- if(cfilename==NULL)
- {
- returnfalse;
- }
- ifstreamin(cfilename,ios::in);
- if(!in)
- {
- returnfalse;
- }
- stringheadStr;
- getline(in,headStr,'');
- in.close();
- if(headStr.empty())
- {
- returnfalse;
- }
- if(headStr[0]=='s')
- {
- ReadASCII(cfilename);
- }
- else
- {
- ReadBinary(cfilename);
- }
- returntrue;
- }
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;
}
- boolReadASCII(constchar*cfilename)
- {
- inti=0,j=0,cnt=0,pCnt=4;
- chara[100];
- charstr[100];
- doublex=0,y=0,z=0;
- Vec3ftPoint;
- Vector<Vec3f>pointList;//todo:可以预先计算出pointList的大小,节省空间
- ifstreamin;
- in.open(cfilename,ios::in);
- if(!in)
- {
- returnfalse;
- }
- 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());
- returntrue;
- }
- boolReadBinary(constchar*cfilename)
- {
- charstr[80];
- ifstreamin;
- //三角形数目
- intunTriangles(0);
- in.open(cfilename,ios::in);
- if(!in)
- {
- returnfalse;
- }
- in.read(str,80);
- in>>unTriangles;
- if(unTriangles==0)
- {
- returnfalse;
- }
- Vec3ftPoint;
- vector<Vec3f>pointList(unTriangles);//预留足够的空间
- floatx(0.f),y(0.f),z(0.f);
- charunusedByte;
- //Binary
- for(inti=0;i<(int)unTriangles;i++)
- {
- for(intpointIdx=0;pointIdx<4;pointIdx++)
- {
- in>>x>>y>>z;
- tPoint.SetParam(x,y,z);
- pointList.push_back(tPoint);
- }
- in>>unusedByte>>unusedByte;
- }
- in.close();
- returntrue;
- }
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;
}