stl文件处理

stl文件介绍

  1. 概述
    • stl文件用三维网格表现实体模型,stl文件有两种:一种是ASCII明码格式,另一种是二进制格式。(以下摘自百度百科stl展示.png
  2. ASCII格式
    • 在STL文件中的三角面片的信息单元 facet 是一个带矢量方向的三角面片,STL三维模型就是由一系列这样的三角面片构成。
      整个STL文件的首行给出了文件路径及文件名。
      在一个 STL文件中,每一个facet由7 行数据组成,
      facet normal 是三角面片指向实体外部的法矢量坐标,
      outer loop 说明随后的3行数据分别是三角面片的3个顶点坐标,3顶点沿指向实体外部的法矢量方向逆时针排列。
      solidfilenamestl//文件路径及文件名
      facetnormalxyz//三角面片法向量的3个分量值
      outerloop
      vertexxyz//三角面片第一个顶点坐标
      vertexxyz//三角面片第二个顶点坐标
      vertexxyz//三角面片第三个顶点坐标
      endloop
      endfacet//完成一个三角面片定义
      
      ......//其他facet
      
      endsolidfilenamestl//整个STL文件定义结束
      
  3. 二进制格式 二进制STL文件用固定的字节数来给出三角面片的几何信息。
    文件起始的80个字节是文件头,用于存贮文件名;
    紧接着用 4 个字节的整数来描述模型的三角面片个数,
    后面逐个给出每个三角面片的几何信息。每个三角面片占用固定的50个字节,依次是:
    3个4字节浮点数(角面片的法矢量)
    3个4字节浮点数(1个顶点的坐标)
    3个4字节浮点数(2个顶点的坐标)
    3个4字节浮点数(3个顶点的坐标)
    三角面片的最后2个字节用来描述三角面片的属性信息。
    一个完整二进制STL文件的大小为三角形面片数乘以 50再加上84个字节。
    UINT8//Header//文件头
    UINT32//Numberoftriangles//三角面片数量
    //foreachtriangle(每个三角面片中)
    REAL32[3]//Normalvector//法线矢量
    REAL32[3]//Vertex1//顶点1坐标
    REAL32[3]//Vertex2//顶点2坐标
    REAL32[3]//Vertex3//顶点3坐标
    UINT16//Attributebytecountend//文件属性统计
    

处理过程

  • 当开始processFiles时,会将files中命名的stl文件存贮到model的meshs中。model是一个PrintObject* 
    首先,loadModelSTL根据stl的类型选择调用loadModelSTL_binary或者loadModelSTL_ascii,得到meshs。然后用processModel对Meshs处理,将结果存入storage。 流程图.png

源码解析

bool processFiles(const std::vector<std::string> &files)//位于fffProcessor.h的line74

中:

FMatrix3x3 matrix;  //变换用的矩阵,没什么用
       if (!loadMeshFromFile(model, filename.c_str(), matrix))
       {
           logError("Failed to load model: %s\n", filename.c_str());
           return false;
       }

调用loadMeshFromFile.

  bool loadMeshFromFile(PrintObject* object, const char* filename, FMatrix3x3& matrix)
{
        const char* ext = strrchr(filename, '.');
    if (ext && (strcmp(ext, ".stl") == 0 || strcmp(ext, ".STL") == 0))
    {
        object->meshes.emplace_back(object);
        return loadModelSTL(&object->meshes[object->meshes.size()-1], filename, matrix);
    }
    return false;
}

而loadModelSTL首先读5个字节到buffer中,根据buffer是否为"solid"判断stl文件类型,分别调用
loadModelSTL_ascii和loadModelSTL_binary函数。

  bool loadModelSTL_ascii(Mesh* mesh, const  char* filename, FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "rt");
    char buffer[1024];
    FPoint3 vertex;
    int n = 0;
    Point3 v0(0,0,0), v1(0,0,0), v2(0,0,0);
    while(fgets_(buffer, sizeof(buffer), f))
    {
        if (sscanf(buffer, " vertex %f %f %f", &vertex.x, &vertex.y, &vertex.z) == 3)
        {
            n++;
            switch(n)
            {
            case 1:
                v0 = matrix.apply(vertex);  //矩阵转换vertex到(v0 v1 v2)
                                break;
            case 2:
                v1 = matrix.apply(vertex);
                break;
            case 3:
                v2 = matrix.apply(vertex);
                mesh->addFace(v0, v1, v2);           //到这里,将stl转换成了mesh
                n = 0;
                break;
            }
        }
    }
……
  • 提取出了三维点的信息,存到vertex中,再通过与矩阵matrix(其实是单位矩阵,结果一样)相乘进行坐标变换,得到三个点后组成三维面片,
    使用addFace添加到mesh中。
  bool loadModelSTL_binary(Mesh* mesh, const char* filename, FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "rb");
    char buffer[80];
    uint faceCount;
    //Skip the header
    if (fread(buffer, 80, 1, f) != 1) //前80字节是文件头
    {
        fclose(f);
        return false;
    }
    //Read the face count
    if (fread(&faceCount, sizeof(uint), 1, f) != 1)
    {
        fclose(f);
        return false;
    }
    //For each face read:
    //float(x,y,z) = normal, float(X,Y,Z)*3 = vertexes, uint16_t = flags
    for(unsigned int i=0;i<faceCount;i++)
    {
        if (fread(buffer, sizeof(float) * 3, 1, f) != 1) //角面片的法矢量
        {
            fclose(f);
            return false;
        }
        float v[9];
        if (fread(v, sizeof(float) * 9, 1, f) != 1) //三个顶点坐标 
        {
            fclose(f);
            return false;
        }
        Point3 v0 = matrix.apply(FPoint3(v[0], v[1], v[2]));
        Point3 v1 = matrix.apply(FPoint3(v[3], v[4], v[5]));
        Point3 v2 = matrix.apply(FPoint3(v[6], v[7], v[8]));
        mesh->addFace(v0, v1, v2);
        if (fread(buffer, sizeof(uint16_t), 1, f) != 1) //三角形面片数属性信息,或许可以用来表示材质??
        {
            fclose(f);
            return false;
        }
    }
……
  • 这样,stl中得数据完全转移到model.meshs中了。

底层类和函数介绍

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值