Qt/C++ + opengl 解析stl文件(二进制和Ascii两种格式)

6 篇文章 2 订阅

前言:

在这里插入图片描述

3D 的stl 模型文件分为两种 二进制和Ascii

明码的Ascii 内容清晰可以打开看,但是文件比较大
二进制的文件 看不到内容 但是占用空间小

我是用 qt + opengl 加载 stl 模型

本章写 qt c++ 加载 ascii 格式 和 二进制格式的 stl 文件

ASCII 格式:

在这里插入图片描述

 /*          ASCII STL 格式
     *
     *
     * solid
     *      facet normal +0.0000000E+00 +1.0000000E+00 +0.0000000E+00
                outer loop
                    vertex   +8.0000000E+01 +1.0000000E+02 +6.0000000E+01
                    vertex   +8.0000000E+01 +1.0000000E+02 +0.0000000E+00
                    vertex   +0.0000000E+00 +1.0000000E+02 +0.0000000E+00
                endloop
            endfacet
          ......
        endsolid
*/

文件头 solid 后面跟着的是文件描述
下面的7行 是一个三角形的描述
有多少个三角形就有多少个7行

然后包含1行法向量信息
3行顶点信息

文件结尾 endsolid

读取ASCII 格式代码

void loadAsciiSTL(std::string path,std::vector<FACET> &facetVec);



void Widget::loadAsciiSTL(std::string path, std::vector<FACET> &facetVec)
{
    /*          ASCII STL 格式
     *
     *
     * solid
     *      facet normal +0.0000000E+00 +1.0000000E+00 +0.0000000E+00
                outer loop
                    vertex   +8.0000000E+01 +1.0000000E+02 +6.0000000E+01
                    vertex   +8.0000000E+01 +1.0000000E+02 +0.0000000E+00
                    vertex   +0.0000000E+00 +1.0000000E+02 +0.0000000E+00
                endloop
            endfacet
          ......
        endsolid

     * 共计7行
     *
     *
     *
     *
     *
     * */

    FILE* file = fopen(path.c_str(),"r");

    //把文件指针移动到文件末尾,并计算文件大小
    fseek(file,0L,SEEK_END);
    long fileSize = ftell(file);

    fclose(file);

    file = fopen(path.c_str(),"r");
    //计算文件有多少行
    int fileLines = 0;

    for(long i = 0;i<fileSize;i++)
       //一个字符一个字符的读取 当读到换行符说明读到了一行 直到结束
        if(getc(file) == '\n')
            fileLines++;

    //计算三角形的个数
    int triangleCount = 0;
    //一段三角形的描述是7行 stl文件格式决定的
    triangleCount = fileLines / 7;

    //文件指针移到文件头
    rewind(file);

    //跳过文件头 solid
    while(getc(file) != '\n');


    for(auto i = 0; i< triangleCount;i++)
    {
        FACET temp;

        //读法向量
        fscanf(file,"%*s %*s %f %f %f\n",&temp.normal[0],&temp.normal[1],&temp.normal[2]);
        //跳过 outer loop
        fscanf(file,"%*s %*s");
        //读顶点数据
        fscanf(file,"%*s %f %f %f\n",&temp.vertex[0][0],&temp.vertex[0][1],&temp.vertex[0][2]);
        fscanf(file,"%*s %f %f %f\n",&temp.vertex[1][0],&temp.vertex[1][1],&temp.vertex[1][2]);
        fscanf(file,"%*s %f %f %f\n",&temp.vertex[2][0],&temp.vertex[2][1],&temp.vertex[2][2]);
        //跳过 endloop
        fscanf(file,"%*s");
        //跳过 endfacet
        fscanf(file,"%*s");

        facetVec.push_back(temp);
    }
    //跳过文件尾部 endsolid
    while(getc(file) != '\n');

    fclose(file);

    delete file;

}


二进制文件的格式

在这里插入图片描述

起始是80个字节的 头
下面是 UINT32 三角形的个数 4字节

三角形信息部分

法向量 float3 4x3 12字节字节
顶点1 float
3 4x3 12字节
顶点2 float3 4x3 12字节
顶点3 float
3 4x3 12字节
uint16 三角形的属性信息没有用 2字节

共计 12*4 +2 = 50字节

读取二进制文件代码

void loadBinarySTL(std::string path,std::vector<FACET> &facetVec);



void Widget::loadBinarySTL(std::string path, std::vector<FACET> &facetVec)
{
    FILE* file = fopen(path.c_str(),"r");

    /*80字节文件头*/
    char header[80];
    fread(header,80,1,file);

    uint32_t triangleNum;
    fread(&triangleNum,sizeof(uint32_t),1,file);

    for(auto i = 0; i< triangleNum;i++)
    {
        /*12字节法向量*/
        FACET temp;

        fread(&temp.normal[0],sizeof(float),1,file);
        fread(&temp.normal[1],sizeof(float),1,file);
        fread(&temp.normal[2],sizeof(float),1,file);

        /*36字节顶点*/
        for(auto j = 0; j< 3;j++)
        {
            fread(&temp.vertex[j][0],sizeof(float),1,file);
            fread(&temp.vertex[j][1],sizeof(float),1,file);
            fread(&temp.vertex[j][2],sizeof(float),1,file);
        }
        /*2字节三角型面片的属性信息*/
        char c[2];
        fread(c,2,1,file);

        facetVec.push_back(temp);
    }

    fclose(file);
    delete file;

}

注意我们要先判断是Ascii还是二进制然后在确定调用哪个接口

我这里写了一个函数来判断是什么格式

bool isAsciiFileType(QString path);



bool Widget::isAsciiFileType(QString path)
{
 QFile file(path);

    char ch[80];

    if(file.open(QIODevice::ReadOnly))
    {
        file.read(ch,80);

        file.close();
        //读取80个字节 如果是ascii 就会换行了 如果是二进制的不会有换行
        for(auto i = 0; i< 80;i++)
        {
            if(ch[i] == '\n')
            {
                qDebug()<<"this is ascii";
                return true;
            }
        }
        return false;
    }
    qDebug()<<"Open File Failed!";

    return false;
}

因为2进制的 第一行是80字节 但是ascii 第一行没有80字节
所以我们读取80字节 如果包含换行符说明就是ASCII 因为它换行了

使用的话就这样


if(isAsciiFileType(""))
	loadAsciiSTL()
else
	loadBinarySTL()
	


后续我会写 解析 stl 模型并画出来
用的是 qt + opengl
谢谢您的点赞和关注 支持我
  • 10
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值