用Java保存二进制STL文件

用Java保存二进制STL文件,java,binary,save,bytearray,stl-format,Java,Binary,Save,Bytearray,Stl Format,我正在尝试将一些数据保存为STL文件,以便在3D打印机上使用。STL文件有两种形式:ASCII和二进制。ASCII格式相对容易理解和创建,但大多数3D打印服务要求其为二进制格式 有关STL二进制文件的信息在Wikipedia页面上解释如下: 我知道我会要求数据在字节数组中,但我不知道如何解释维基百科中的信息并创建字节数组。这就是我想要帮助的 到目前为止,我的代码只保存了一个空字节数组: byte[] bytes = null; FileOutputStream stream = new File

我正在尝试将一些数据保存为STL文件,以便在3D打印机上使用。STL文件有两种形式:ASCII和二进制。ASCII格式相对容易理解和创建,但大多数3D打印服务要求其为二进制格式

有关STL二进制文件的信息在Wikipedia页面上解释如下:

我知道我会要求数据在字节数组中,但我不知道如何解释维基百科中的信息并创建字节数组。这就是我想要帮助的

到目前为止,我的代码只保存了一个空字节数组:

byte[] bytes = null;
FileOutputStream stream = new FileOutputStream("test.stl");
    try {
        stream.write(bytes);
    } finally {
        stream.close();
}

您应该以ASCII生成此文件,并使用ASCII到二进制STL转换器

如果您自己无法回答这个问题,那么首先使用ascii可能更容易


如果您在最新的Java版本上启动一个新项目,您不应该与OutputStreams发生冲突。改用通道和字节缓冲区

try(FileChannel ch=new RandomAccessFile("test.stl", "rw").getChannel())
{
  ByteBuffer bb=ByteBuffer.allocate(10000).order(ByteOrder.LITTLE_ENDIAN);
  // ...
  // e.g. store a vertex:
  bb.putFloat(0.0f).putFloat(1.0f).putFloat(42);
  bb.flip();
  ch.write(bb);
  bb.clear();
  // ...
}
这是唯一一个根据需要为您提供little endian支持的API。然后匹配数据类型: UINT8表示无符号字节, UINT32表示无符号整数, REAL32表示浮动, UINT16表示无符号短符号, REAL32[3]表示三个浮点(即一个数组)


只要不超过相应有符号Java类型的最大值,就不必担心数据类型的无符号性质。

这不应该如此含糊不清。说明书上说:

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     
List all the geometric vertex coordinates as a "v", followed by x, y, z values, like:
    v 123.45 234.56 345.67

then List all the triangle as "f", followed by indices in a CCW order, like:
    f 1 2 3

Indices start with 1.
Use a # character to start a comment line. Don't append comments anywhere else in a line.
Blank lines are ok.
这意味着总文件大小为:80+4+三角形数*(4*3*4+2)

例如,100个三角形(84+100*50)生成一个5084字节的文件

您可以优化以下功能代码。 打开文件并写入标题:

        RandomAccessFile raf = new RandomAccessFile( fileName, "rw" );
        raf.setLength( 0L );
        FileChannel ch = raf.getChannel();

        ByteBuffer bb = ByteBuffer.allocate( 1024 ).order( ByteOrder.LITTLE_ENDIAN );

        byte titleByte[] = new byte[ 80 ];
        System.arraycopy( title.getBytes(), 0, titleByte, 0, title.length() );
        bb.put( titleByte );

        bb.putInt( nofTriangles );              // Number of triangles

        bb.flip();                              // prep for writing
        ch.write( bb );
在该代码中,点顶点和三角形索引位于如下数组中:

Vector3 vertices[ index ]
int indices[ index ][ triangle point number ]
写入点数据:

        for ( int i = 0; i < nofIndices; i++ )  // triangles
        {
            bb.clear();
            Vector3 normal = getNormal( indices[ i ][ 0 ], indices[ i ][ 1 ], indices[ i ][ 2 ] );
            bb.putFloat( normal[ k ].x );
            bb.putFloat( normal[ k ].y );
            bb.putFloat( normal[ k ].z );
                
            for ( int j = 0; j < 3; j++ )           // triangle indices
            {
                bb.putFloat( vertices[ indices[ i ][ j ] ].x );
                bb.putFloat( vertices[ indices[ i ][ j ] ].y );
                bb.putFloat( vertices[ indices[ i ][ j ] ].z );
            }
            bb.putShort( ( short ) 0 );             // number of attributes
            bb.flip();
            ch.write( bb );
        }
获取法线:

Vector3 getNormal( int ind1, int ind2, int ind3 )
{
    Vector3 p1 = vertices[ ind1 ];
    Vector3 p2 = vertices[ ind2 ];
    Vector3 p3 = vertices[ ind3 ];
    return p1.cpy().sub( p2 ).crs( p2.x - p3.x, p2.y - p3.y, p2.z - p3.z ) ).nor();
}
另见:

由于您的问题是基于编写一个文件发送到3D打印机,因此我建议您放弃STL格式文件,改用OBJ格式文件。它的编写要简单得多,并且生成的文件要小得多。OBJ没有二进制风格,但正如您将看到的,它仍然是一个非常紧凑的文件

(缩写)规范说明:

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     
List all the geometric vertex coordinates as a "v", followed by x, y, z values, like:
    v 123.45 234.56 345.67

then List all the triangle as "f", followed by indices in a CCW order, like:
    f 1 2 3

Indices start with 1.
Use a # character to start a comment line. Don't append comments anywhere else in a line.
Blank lines are ok.
它还支持很多其他东西,比如法线和纹理。但如果您只想将几何体写入文件以导入3D打印机,那么OBJ实际上是首选,并且这个简单的内容是有效和充分的

下面是一个组成1个单位立方体的完全有效文件的示例,该文件已成功导入Microsoft 3D Viewer(包含在Win/10中)、AutoDesk MeshMixer(免费下载)和PrusaSlicers(免费下载)中


如果在多个网格中有数据,则应合并顶点以消除重复点。但是因为文件是纯文本,所以可以使用PrintWriter()对象和println()方法来编写整个文件。

不过我想学习如何编写。我正在寻找一些关于这个主题的一般性建议和教程-我不仅仅是在寻找解决方案。谢谢。因此,如果我理解正确,这可能是标题和三角形计数:
String title=“testing”;bb.put(title.getBytes(“UTF-16”);//标题(80字节)bb.putInt(32);//三角形数(UINT32)
可用于每个三角形:
bb.putFloat(0)、putFloat(0)、putFloat(0);bb.putFloat(0)、putFloat(0)、putFloat(0);bb.putFloat(0)、putFloat(0)、putFloat(0);bb.putFloat(0)、putFloat(0)、putFloat(0);bb.putShort((short)12)我已经弄明白了。我忘了将标题设置为固定字节[80]数组。顺便说一句,如果要对多个字符串进行编码,最好让编码器直接将结果放入缓冲区,而不是创建临时数组。例如,
CharsetEncoder enc=StandardCharsets.UTF_16LE.newEncoder();enc.encode(CharBuffer.wrap(“测试”),bb,true)我刚刚意识到我实际上不需要设置头,它可以是一个空字节数组,这样就不会有问题了。你知道我该如何把颜色信息添加进去吗?wiki上提到的第一种方法说,它使用“属性字节计数”值来存储15位数据。我该怎么做呢?