【问题标题】:Are .STL files missing triangles? This STL parsing code is consistently missing triangles.STL 文件是否缺少三角形?此 STL 解析代码始终缺少三角形
【发布时间】:2022-10-12 21:24:15
【问题描述】:

这是我的第二个解析二进制 STL 文件的项目。我遇到了几年前遇到的同样问题,我的 STL 文件的表示最终丢失了几个三角形。我已经尝试读取超过 STL 标题中指示的三角形数量,以查看是否有比指示更多的三角形,但我最终得到相同的缺失三角形。

我相信这是 STL 或我阅读它的方式的问题,而不是我的可视化问题,因为我之前在一个项目中遇到过相同的问题,该项目基本上只是使用与 C 几乎相同的代码读取 STL下面的代码。

Gomboc STL missing triangles after being run through my slicing project code

Low-poly Cat STL missing triangles after being run through my slicing project. Seen from the inside for clarity

//RETURNED POINTER MUST BE FREE'D
struct tri* readSTL(char* filename, int* numTriangles) {
    FILE* fp;
    char wordIn = '\0'; 

    fp = fopen(filename, "r");

    //READ 80 BYTE HEADER
    for (int i = 0; i < 80; i++) {
        fread(&wordIn, sizeof(char), 1, fp);
    }

    //READ 4 BYTE NUMBER OF TRIANGLES
    fread(numTriangles, sizeof(char), 4, fp);

    //READ ALL TRIANGLES
    struct tri* triangles = calloc(*numTriangles, sizeof(struct tri));

    for (int i = 0; i < *numTriangles; i++) {

       //READ NORMAL VECTOR
      fread(&(triangles[i].normal.X), sizeof(char), 4, fp);
      fread(&(triangles[i].normal.Y), sizeof(char), 4, fp);
      fread(&(triangles[i].normal.Z), sizeof(char), 4, fp);

      //READ X
      fread(&(triangles[i].p1.X), sizeof(char), 4, fp);
      fread(&(triangles[i].p1.Y), sizeof(char), 4, fp);
      fread(&(triangles[i].p1.Z), sizeof(char), 4, fp);

      //READ Y
      fread(&(triangles[i].p2.X), sizeof(char), 4, fp);
      fread(&(triangles[i].p2.Y), sizeof(char), 4, fp);
      fread(&(triangles[i].p2.Z), sizeof(char), 4, fp);

      //READ Z
      fread(&(triangles[i].p3.X), sizeof(char), 4, fp);
      fread(&(triangles[i].p3.Y), sizeof(char), 4, fp);
      fread(&(triangles[i].p3.Z), sizeof(char), 4, fp);

      //READ THROW-AWAY
      int throwaway;
      fread(&throwaway, sizeof(char), 2, fp);
      
      printf("FILE NORMAL: %f, %f, %f\n", triangles[i].normal.X,
              triangles[i].normal.Y, triangles[i].normal.Z);

      struct point Normal = computeNormal(triangles[i]);
      printf("Computed NORMAL: %f, %f, %f\n\n", Normal.X, Normal.Y, Normal.Z);
    }

    fclose(fp);

    return triangles;
}

关于 STL 数据结构,我是否遗漏了一些可以解释这一点的东西?这个问题似乎出现在我阅读的超过 100 个三角形的任何 STL 中。解析由 12 个三角形组成的 6 面立方体看起来很完美。

编辑 1此代码目前仅设置为读取 BINARY STL 文件,这就是它要读取的全部内容。

编辑 2我现在的主要理论是,在大多数导出到 STL 的软件中,缺少三角形是标准的,如果三角形是由它周围的三角形定义的,那么它就不会被添加。奇怪的是,这些未指定的三角形是如何确定的,因为它们在物体上没有视觉或对称图案,也没有丢失的三角形出现在可以从周围三角形合理推断的每个位置。

【问题讨论】:

  • 如果“STL 文件”是二进制文件(而不是文本文件),那么您需要在binary 模式。如果它是一个文本文件,那么您不能使用fread,因为它会将内容作为原始二进制数据读取。
  • @Someprogrammerdude 我目前只阅读二进制 STL。我将更新问题以指定这一点。以现在的代码方式读取二进制 STL 会有任何潜在问题吗?
  • 那么你打开文件文本模式,这意味着在某些系统上可能会自动翻译某些“字符”(字节)。最值得注意的是,在 Windows 上,序列 0x0d 0x0a 将仅被转换为 0x0a\r\n 被转换为 \n)。
  • 顺便说一句,拥有一个合适的minimal reproducible example 会很不错。请花一些时间阅读the help pages,阅读SO tour,阅读How to Ask,以及this question checklist。还学习如何edit您的问题以改进它们。
  • @SteveSummit 是的,但它读取时不解释字节(除了可能的翻译)。将“文本”读入int 通常没有意义,以及将int 值的二进制数据读入字符数组(尽管这可能有时有点道理,尽管它仍然不是“字符串”)。

标签: c slicers stl-format triangle 3d-printing


【解决方案1】:

二进制 STL 是一种非常简单的格式。你可以找到它的文档on Wikipediaelsewhere。它由一个 80 字节的标头(没有普遍接受的解释)、一个三角形计数和一个指定数量的三角形列表组成,其中

  • 三角形计数表示为无符号、小端、32 位整数。

  • 每个三角形表示为

    • 12 little-endian,32 位 IEEE-754 二进制浮点数,表示面法线和三个顶点的坐标,加上
    • 一个无符号、小端序、16 位整数,描述为“属性字节数”。

    (共 50 个字节)

显然,STL 编写者在使用标头和属性字节数方面存在一些差异,但由于您忽略了这些,因此不会影响您的程序。 STL 编写者之间在法线字段方面也存在一些差异。鉴于顶点排序规则,法线与顶点是冗余的,显然有些软件用不同的数据填充法线。但是,您的代码似乎正在检查法线,因此我假设您对使用的法线正常感到满意。

由于您已验证其他软件正确呈现您的 STL 文件的内容,因此假设它们没有格式错误或损坏似乎是合理的。

你说...

我现在的主要理论是,在大多数导出到 STL 的软件中,缺少三角形是标准的,如果三角形是由它周围的三角形定义的,那么它就不会被添加。

……但这似乎不可信。全部没有任何孔的封闭曲面的三角形由它们周围的三角形定义。另外,我不确定您的示例表面应该是什么样子,但它看起来与这个解释不一致。特别是,这些间隙看起来并不都是三角形的,那些看起来并不像它们可以对应于满足 STL 顶点到顶点规则的单个三角形。当然,没有任何文件表明这种做法。

我相信这是 STL 或我阅读它的方式而不是我的可视化的问题

我不会的。

因为我之前在一个项目中遇到过相同的问题,该项目基本上只是使用与下面的 C 代码几乎相同的代码读取 STL。

显然,您为之前的项目编写了几乎相同的文件读取代码,那么在该项目的其他地方犯了错误,然后您在当前项目中重复了类似的错误,这会令人惊讶吗?

总体而言,您的代码看起来或多或少还可以。我注意到的问题包括:

  • 使用 STL 规范指定无符号整数的有符号整数,特别是对于三角形计数。但是,只有当您的三角形数量超过有符号整数(有符号 32 位整数约为 24 亿)时,这才会对您不利。

  • 假设 int 类型的大小是 32 位。尽管这在今天很常见,但 C 不需要它。结合上一点,最好包含stdint.h 并使用类型uint32_t 来表示三角形计数。

  • 该代码假定为小端机器。这可能就是您运行它的原因,但如果您对此有任何不确定性,那么您应该确认。

  • 您不检查函数调用的返回值。通过成功延续您的计划,其中一些在实践中被证实是成功的,而另一些则不是。尤其是您的fread() 呼叫应检查以确保它们成功完成,读取预期的全部项目数。如果您的问题确实体现在您提供的功能中,那么很可能其中一种可观察到的症状是读取失败。

最后,回到问题中唯一的实际问题:

关于 STL 数据结构,我是否遗漏了一些可以解释这一点的东西?

除了整数符号和可能的整数大小之外,不,它看起来不是这样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-30
    • 1970-01-01
    • 2021-08-02
    • 1970-01-01
    • 2020-05-08
    相关资源
    最近更新 更多