MoonBit 实现的 STL/OBJ/3MF/PLY 网格工具链:解析、打印前复核、修复、分析与流式扫描
///|
test "minimal library quick start" {
let mesh = @stlkit.parse_obj("v 0 0 0\nv 1 0 0\nv 0 1 0\nf 1 2 3\n").unwrap()
assert_eq(mesh.triangle_count(), 1)
assert_eq(mesh.surface_area(), 0.5)
let report = @stlkit.validate_checked(mesh, 0.0).unwrap()
assert_eq(report.boundary_edge_count, 3)
let bytes = @stlkit.write_stl_binary_checked(mesh).unwrap()
assert_eq(@stlkit.parse_mesh(bytes).unwrap().triangle_count(), 1)
}| 接口 | 用途 |
|---|---|
| parse_mesh(data) | 按内容检测 STL / OBJ / 3MF / PLY,返回 Result[Mesh, String] |
| parse_stl_ascii(text) / parse_stl_binary(data) | STL 读取 |
| parse_obj(text) | OBJ 顶点、法线、vt 声明和索引验证、负索引及多边形面;支持空格、制表符、CRLF、行内注释 |
| parse_3mf(data, compatibility=false) | 默认严格 OPC 关系/内容类型及 Core 几何读取;显式兼容只放宽旧包定位 |
| parse_ply(data, lenient_ascii=false) | ASCII / 小端 / 大端 PLY;默认连续按声明消费正文,不丢弃行尾 token |
| write_stl_ascii(mesh) / write_stl_binary(mesh) | STL 导出 |
| write_obj(mesh) | OBJ 导出 |
| write_ply_ascii(mesh) / write_ply_binary(mesh) | PLY 导出,统一容差去重 |
| write_mesh(mesh, filename) | 按输出后缀选择格式 |
// mesh 是已解析的网格。0.5 是调用方选择的参考壁厚,单位毫米。
let review = @stlkit.check_printability(mesh, 0.5)
println(review.verdict())
println(review.inward_component_count()) // 确定的负体积闭合分量数
if review.needs_review() {
println("请按报告检查模型和加工条件")
}moon update
moon check --target all --deny-warn
moon build
moon test --target wasm
moon test --target wasm-gc
moon test --target js
moon test --target native
node cmd/main/smoke.cjs
moon run scripts/build-web.mbtx
node web/smoke.cjspub struct IndexedMesh {
// private fields
}fn IndexedMesh::new(vertices : Array[Vec3], faces : Array[Face3], normals? : Array[Vec3]) -> Result[IndexedMesh, String]let mesh = @stlkit.IndexedMesh::new(
[@stlkit.Vec3::zero(), @stlkit.Vec3::new(1, 0, 0), @stlkit.Vec3::new(0, 1, 0)],
[{ a: 0, b: 1, c: 2, }],
)[0] [1] [2] Ixx Ixy Ixz
[3] [4] [5] = Iyx Iyy Iyz
[6] [7] [8] Izx Izy Izzpub(all) enum MeshFormat {
Ascii
Binary
Obj
ThreeMF
Ply
Unknown
}pub(all) enum ParseError {
InvalidLimits(String)
ResourceLimitExceeded(String)
UnknownFormat(String)
InvalidData(MeshFormat, String)
}pub(all) struct ParseLimits {
max_input_bytes : Int
max_vertices : Int
max_triangles : Int
max_list_items : Int
max_polygon_vertices : Int
max_uncompressed_bytes : Int
max_zip_entries : Int
max_component_depth : Int
max_component_instances : Int
max_records : Int
max_line_bytes : Int
max_xml_depth : Int
}let limits = { ..@stlkit.ParseLimits::default(), max_triangles: 100000, }
let result = @stlkit.parse_mesh(data, limits~)pub(all) struct PreviewOptions {
width : Int
height : Int
yaw : Double
pitch : Double
stroke : String
stroke_width : Double
}pub(all) struct PrintabilityReport {
validation : ValidationReport
winding : WindingReport
thickness : ThicknessReport?
min_thickness : Double
}pub(all) struct RepairLimits {
max_faces : Int
max_boundary_edges : Int
max_hole_vertices : Int
max_holes : Int
}pub(all) struct RepairOptions {
tolerance : Double
drop_degenerate : Bool
drop_duplicates : Bool
fill_holes : Bool
recompute_normals : Bool
unify_winding : Bool
}pub(all) struct RepairResult {
mesh : Mesh
removed_degenerate : Int
removed_duplicates : Int
filled_holes : Int
added_triangles : Int
recomputed_normals : Int
flipped_faces : Int
reoriented_components : Int
}pub(all) struct ScanStorage {
unique_vertices : Int
edge_records : Int
pending_bytes : Int
peak_buffered_bytes : Int
}pub(all) struct StlScanner {
// private fields
}pub(all) struct StreamReport {
triangle_count : Int
raw_vertex_count : Int
unique_vertex_count : Int
boundary_edge_count : Int
non_manifold_edge_count : Int
volume : Double
surface_area : Double
bbox : Aabb?
}pub(all) struct ThicknessReport {
samples : Int
hits : Int
min_thickness : Double
min_at : Vec3?
mean_thickness : Double
}pub(all) struct ValidationReport {
triangle_count : Int
raw_vertex_count : Int
unique_vertex_count : Int
boundary_edge_count : Int
non_manifold_edge_count : Int
degenerate_count : Int
wrong_normal_count : Int
unique_edge_count : Int
}pub(all) struct Vec3 {
x : Double
y : Double
z : Double
}pub(all) struct WindingComponent {
index : Int
faces : Array[Int]
flipped_faces : Int
closed : Bool
consistent : Bool
signed_volume : Double
orientation : WindingOrientation
bounds : Aabb
potentially_nested : Bool
}pub(all) struct WindingReport {
flipped_faces : Int
consistent : Bool
signed_volume : Double
components : Array[WindingComponent]
}fn default_weld_tolerance() -> Doublefn inspection_json(mesh : Mesh, format? : MeshFormat, min_thickness? : Double, samples? : Int) -> Result[Json, String]let report = @stlkit.inspection_json(mesh, format=@stlkit.Obj, samples=32)fn is_3mf(data : Bytes) -> Boolfn is_ply(data : Bytes) -> Boolmatch @stlkit.parse_mesh_checked(data) {
Ok(mesh) => println(mesh.triangle_count())
Err(error) => println(error.code())
}fn render_svg_checked(mesh : Mesh, options : PreviewOptions, max_faces? : Int, max_output_bytes? : Int) -> Result[String, String]fn repair_checked(mesh : Mesh, options : RepairOptions, limits? : RepairLimits) -> Result[RepairResult, String]fn symmetric_eigenvalues(m : FixedArray[Double]) -> FixedArray[Double]Install
Download zipMoonBit 实现的 STL/OBJ/3MF/PLY 网格工具链:解析、打印前复核、修复、分析与流式扫描