现在的位置: 首页 > 综合 > 正文

三维图形数据格式 STL的 读取

2013年02月18日 ⁄ 综合 ⁄ 共 2052字 ⁄ 字号 评论关闭

在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;

用于存放点坐标数据和法向量数据,这里将点坐标和法向量都读到一个数组中。

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;
}

抱歉!评论已关闭.