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)
}

性能提示

  1. 对于大型STL文件,考虑使用缓冲读取器:

    use std::io::BufReader;
    
    let file = File::open("large_model.stl")?;
    let mut reader = BufReader::new(file);
    let mesh = read_stl(&mut reader)?;
    
  2. 如果需要频繁处理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(())
}

代码说明

  1. 读取STL文件

    • 使用read_stl函数读取STL文件
    • 使用BufReader提高读取性能
  2. 处理法线

    • 检查模型是否包含法线信息
    • 使用calculate_normals计算缺失的法线
  3. 模型变换

    • 对模型进行缩放和平移变换
    • 直接修改顶点坐标数据
  4. 写入STL文件

    • 使用write_stl函数写入二进制STL文件
    • 使用BufWriter提高写入性能
  5. 创建简单模型

    • 定义立方体的顶点和面数据
    • 创建并保存新的STL文件

性能提示

  1. 对于大型STL文件,始终使用缓冲读写(BufReader/BufWriter
  2. 如果不需要法线信息,可以跳过计算以减少内存使用
  3. 二进制STL格式比ASCII格式更高效

错误处理

建议使用Rust的错误处理机制:

if let Err(e) = process_stl_file() {
    eprintln!("处理STL文件时出错: {}", e);
    std::process::exit(1);
}

这个库非常适合需要处理3D打印模型、CAD数据或任何其他STL格式数据的Rust应用程序。

回到顶部