我正在尝试将一些数据保存为STL文件,以便在3D打印机上使用。 STL文件有两种形式:ASCII和二进制。 ASCII格式相对易于理解和创建,但大多数3D打印服务要求它采用二进制格式。
有关STL Binary的信息在维基百科页面上有解释:http://en.wikipedia.org/wiki/STL_(file_format)
我知道我将要求数据位于字节数组中,但我不知道如何解释维基百科中的信息并创建字节数组。这就是我想要帮助的。
到目前为止我的代码只保存了一个空字节数组:
byte[] bytes = null;
FileOutputStream stream = new FileOutputStream("test.stl");
try {
stream.write(bytes);
} finally {
stream.close();
}
答案 0 :(得分:1)
如果你在最新的Java版本上开始一个新项目,你不应该对OutputStreams感到麻烦。请改用Channels和ByteBuffers。
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表示unsigned int, REAL32表示浮动, UINT16表示无符号短, REAL32 [3]表示三个浮点数(即数组)
只要不超过相应签名Java类型的最大值,就不必担心数据类型的无符号性质。
答案 1 :(得分:1)
这不应太含糊。规范说:
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
这意味着文件总大小为: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 );
}
关闭文件:
ch.close();
获取法线:
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();
}
答案 2 :(得分:0)
您应该使用ASCII生成此文件并使用ASCII到二进制STL转换器。
如果您自己无法回答这个问题,那么首先在ascii中执行此操作可能会更容易。
答案 3 :(得分:0)
由于您的问题基于编写要发送到3D打印机的文件,因此我建议您放弃STL格式文件,而改用OBJ格式文件。编写起来要简单得多,并且它产生的文件要小得多。没有OBJ的二进制风格,但是您仍然会看到它是一个非常紧凑的文件。
(缩写)规范说:
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(免费下载)
# vertices
v 0 0 0
v 0 1 0
v 1 1 0
v 1 0 0
v 0 0 1
v 0 1 1
v 1 1 1
v 1 0 1
# triangle indices
f 1 3 4
f 1 2 3
f 1 6 2
f 1 5 6
f 1 8 5
f 1 4 8
f 3 7 8
f 3 8 4
f 3 6 7
f 2 6 3
f 5 8 7
f 5 7 6
如果您有多个网格中的数据,则应合并顶点以消除重复的点。但是因为文件是纯文本,所以可以使用PrintWriter()对象和println()方法编写整个内容。