Rust STL文件处理库stl_io的使用:高效读写和解析3D建模STL格式数据
Rust STL文件处理库stl_io的使用:高效读写和解析3D建模STL格式数据
stl_io是一个用于处理STL(立体光刻)文件的Rust库,支持高效读写和解析3D建模数据。
安装
在项目目录中运行以下Cargo命令:
cargo add stl_io
或者在Cargo.toml中添加:
stl_io = "0.8.5"
基本用法
读取STL文件
use stl_io::{read_stl, IndexedMesh};
fn main() -> std::io::Result<()> {
// 读取STL文件
let mut file = std::fs::File::open("model.stl")?;
let mesh = read_stl(&mut file)?;
// 访问顶点和面
println!("顶点数: {}", mesh.vertices.len());
println!("面数: {}", mesh.faces.len());
Ok(())
}
写入STL文件
use stl_io::{write_stl, IndexedMesh, Vector, Vertex};
fn main() -> std::io::Result<()> {
// 创建一个简单的立方体模型
let vertices = vec![
Vertex::new([0.0, 0.0, 0.0]),
Vertex::new([1.0, 0.0, 0.0]),
Vertex::new([1.0, 1.0, 0.0]),
Vertex::new([0.0, 1.0, 0.0]),
Vertex::new([0.0, 0.0, 1.0]),
Vertex::new([1.0, 0.0, 1.0]),
Vertex::new([1.0, 1.0, 1.0]),
Vertex::new([0.0, 1.0, 1.0]),
];
let faces = vec![
[0, 1, 2], [0, 2, 3], // 底面
[4, 5, 6], [4, 6, 7], // 顶面
[0, 1, 5], [0, 5, 4], // 前面
[1, 2, 6], [1, 6, 5], // 右面
[2, 3, 7], [2, 7, 6], // 后面
[3, 0, 4], [3, 4, 7], // 左面
];
let mesh = IndexedMesh {
vertices,
faces,
};
// 写入STL文件
let mut file = std::fs::File::create("cube.stl")?;
write_stl(&mut file, &mesh)?;
Ok(())
}
解析ASCII和二进制STL
stl_io可以自动检测并解析ASCII和二进制格式的STL文件:
use stl_io::{read_stl, IndexedMesh};
fn analyze_stl(file_path: &str) -> std::io::Result<()> {
let mut file = std::fs::File::open(file_path)?;
let mesh = read_stl(&mut file)?;
println!("文件: {}", file_path);
println!("顶点数: {}", mesh.vertices.len());
println!("面数: {}", mesh.faces.len());
// 计算边界框
let (min, max) = mesh.vertices.iter().fold(
(
[f32::INFINITY; 3],
[f32::NEG_INFINITY; 3],
),
|(min, max), v| {
(
[min[0].min(v[0]), min[1].min(v[1]), min[2].min(v[2])],
[max[0].max(v[0]), max[1].max(v[1]), max[2].max(v[2])],
)
},
);
println!("边界框:");
println!(" 最小: {:?}", min);
println!(" 最大: {:?}", max);
Ok(())
}
高级功能
计算法线
use stl_io::{read_stl, IndexedMesh};
use nalgebra::Vector3;
fn calculate_normals(mesh: &IndexedMesh) -> Vec<Vector3<f32>> {
mesh.faces.iter().map(|&[a, b, c]| {
let va = Vector3::from(mesh.vertices[a]);
let vb = Vector3::from(mesh.vertices[b]);
let vc = Vector3::from(mesh.vertices[c]);
let ab = vb - va;
let ac = vc - va;
ab.cross(&ac).normalize()
}).collect()
}
合并顶点
use stl_io::{IndexedMesh, Vertex};
use std::collections::HashMap;
fn merge_duplicate_vertices(mesh: IndexedMesh) -> IndexedMesh {
let mut unique_vertices = Vec::new();
let mut vertex_map = HashMap::new();
let mut new_faces = Vec::with_capacity(mesh.faces.len());
for face in mesh.faces {
let mut new_face = [0; 3];
for (i, &vi) in face.iter().enumerate() {
let vertex = mesh.vertices[vi];
let entry = vertex_map.entry(vertex).or_insert_with(|| {
let idx = unique_vertices.len();
unique_vertices.push(vertex);
idx
});
new_face[i] = *entry;
}
new_faces.push(new_face);
}
IndexedMesh {
vertices: unique_vertices,
faces: new_faces,
}
}
完整示例
下面是一个完整的示例,演示如何读取STL文件、处理数据并保存结果:
use stl_io::{read_stl, write_stl, IndexedMesh};
use std::path::Path;
fn process_stl(input_path: &Path, output_path: &Path) -> std::io::Result<()> {
// 1. 读取STL文件
println!("正在读取文件: {:?}", input_path);
let mut input_file = std::fs::File::open(input_path)?;
let mesh = read_stl(&mut input_file)?;
println!("原始模型:");
println!(" 顶点数: {}", mesh.vertices.len());
println!(" 面数: {}", mesh.faces.len());
// 2. 处理网格数据 (这里只是示例,可以添加实际的处理逻辑)
let processed_mesh = mesh; // 在实际应用中这里会有网格处理步骤
// 3. 写入处理后的STL文件
println!("正在写入文件: {:?}", output_path);
let mut output_file = std::fs::File::create(output_path)?;
write_stl(&mut output_file, &processed_mesh)?;
println!("处理完成!");
Ok(())
}
fn main() -> std::io::Result<()> {
let input_path = Path::new("input.stl");
let output_path = Path::new("output.stl");
process_stl(&input_path, &output_path)
}
性能提示
-
对于大型STL文件,考虑使用缓冲读取器:
use std::io::BufReader; let file = File::open("large_model.stl")?; let mut reader = BufReader::new(file); let mesh = read_stl(&mut reader)?;
-
如果需要频繁处理STL文件,可以重用缓冲区:
let mut buffer = Vec::new(); let mut file = File::open("model.stl")?; file.read_to_end(&mut buffer)?; let cursor = std::io::Cursor::new(buffer); let mesh = read_stl(&mut cursor)?;
stl_io库提供了简单而强大的接口来处理STL文件,非常适合3D打印、CAD和计算机图形学应用。
1 回复
Rust STL文件处理库stl_io的使用:高效读写和解析3D建模STL格式数据
stl_io
是一个用于处理STL(立体光刻)格式文件的Rust库,它可以高效地读取和写入3D建模中常用的STL文件格式。
功能特性
- 支持ASCII和二进制STL格式
- 高效的内存处理
- 提供对顶点和面的直接访问
- 支持写入STL文件
- 轻量级且无额外依赖
安装方法
在Cargo.toml中添加依赖:
[dependencies]
stl_io = "0.6"
完整示例代码
下面是一个完整的示例,展示如何使用stl_io
库读取、修改和写入STL文件:
use stl_io::{read_stl, write_stl, IndexedMesh, Vertex, calculate_normals};
use std::fs::File;
use std::io::BufReader;
use nalgebra::Vector3;
fn main() -> std::io::Result<()> {
// 1. 读取STL文件
let input_file = File::open("input.stl")?;
let mut mesh = read_stl(&mut BufReader::new(input_file))?;
println!("原始模型 - 顶点数: {}, 面数: {}",
mesh.vertices.len(),
mesh.faces.len());
// 2. 计算法线(如果不存在)
if mesh.normals.is_none() {
mesh.normals = Some(calculate_normals(&mesh.vertices, &mesh.faces));
println!("已计算法线");
}
// 3. 缩放并平移模型
let scale = 2.0;
let translation = Vector3::new(10.0, 5.0, 0.0);
for vertex in &mut mesh.vertices {
vertex.x = vertex.x * scale + translation.x;
vertex.y = vertex.y * scale + translation.y;
vertex.z = vertex.z * scale + translation.z;
}
println!("模型已缩放 {} 倍并平移 {:?}", scale, translation);
// 4. 写入修改后的STL文件
let output_file = File::create("output.stl")?;
write_stl(&mut BufWriter::new(output_file), &mesh)?;
println!("已保存修改后的模型到 output.stl");
// 5. 创建并保存一个简单的立方体
create_and_save_cube()?;
Ok(())
}
fn create_and_save_cube() -> std::io::Result<()> {
// 定义立方体的8个顶点
let vertices = vec![
Vertex::new([0.0, 0.0, 0.0]), // 0
Vertex::new([1.0, 0.0, 0.0]), // 1
Vertex::new([1.0, 1.0, 0.0]), // 2
Vertex::new([0.0, 1.0, 0.0]), // 3
Vertex::new([0.0, 0.0, 1.0]), // 4
Vertex::new([1.0, 0.0, 1.0]), // 5
Vertex::new([1.0, 1.0, 1.0]), // 6
Vertex::new([0.0, 1.0, 1.0]), // 7
];
// 定义立方体的12个三角形面(每个面2个三角形)
let faces = vec![
[0, 1, 2], [0, 2, 3], // 底面
[4, 5, 6], [4, 6, 7], // 顶面
[0, 1, 5], [0, 5, 4], // 前面
[1, 2, 6], [1, 6, 5], // 右面
[2, 3, 7], [2, 7, 6], // 后面
[3, 0, 4], [3, 4, 7], // 左面
];
let cube = IndexedMesh {
vertices,
faces,
normals: None,
};
let cube_file = File::create("cube.stl")?;
write_stl(&mut BufWriter::new(cube_file), &cube)?;
println!("已创建并保存立方体模型到 cube.stl");
Ok(())
}
代码说明
-
读取STL文件:
- 使用
read_stl
函数读取STL文件 - 使用
BufReader
提高读取性能
- 使用
-
处理法线:
- 检查模型是否包含法线信息
- 使用
calculate_normals
计算缺失的法线
-
模型变换:
- 对模型进行缩放和平移变换
- 直接修改顶点坐标数据
-
写入STL文件:
- 使用
write_stl
函数写入二进制STL文件 - 使用
BufWriter
提高写入性能
- 使用
-
创建简单模型:
- 定义立方体的顶点和面数据
- 创建并保存新的STL文件
性能提示
- 对于大型STL文件,始终使用缓冲读写(
BufReader
/BufWriter
) - 如果不需要法线信息,可以跳过计算以减少内存使用
- 二进制STL格式比ASCII格式更高效
错误处理
建议使用Rust的错误处理机制:
if let Err(e) = process_stl_file() {
eprintln!("处理STL文件时出错: {}", e);
std::process::exit(1);
}
这个库非常适合需要处理3D打印模型、CAD数据或任何其他STL格式数据的Rust应用程序。