Skip to main content

lib3mf_core/parser/
mesh_parser.rs

1use crate::error::{Lib3mfError, Result};
2use crate::model::{ClippingMode, Mesh, Triangle, Vertex};
3use crate::parser::beamlattice_parser::parse_beam_lattice_content;
4use crate::parser::xml_parser::{XmlParser, get_attribute, get_attribute_f32, get_attribute_u32};
5use quick_xml::events::Event;
6use std::io::BufRead;
7
8/// Parses a `<mesh>` element (vertices and triangles) into a `Mesh`.
9pub fn parse_mesh<R: BufRead>(parser: &mut XmlParser<R>) -> Result<Mesh> {
10    let mut mesh = Mesh::default();
11
12    loop {
13        match parser.read_next_event()? {
14            Event::Start(e) => match e.local_name().as_ref() {
15                b"vertices" => parse_vertices(parser, &mut mesh)?,
16                b"triangles" => parse_triangles(parser, &mut mesh)?,
17                b"beamlattice" => {
18                    let radius = get_attribute_f32(&e, b"radius").ok();
19                    let min_length = get_attribute_f32(&e, b"minlength").unwrap_or(0.0);
20                    let precision = get_attribute_f32(&e, b"precision").unwrap_or(0.0);
21                    // Handle both "clippingmode" (spec) and "clipping" (some implementations)
22                    let clipping_str = get_attribute(&e, b"clippingmode")
23                        .or_else(|| get_attribute(&e, b"clipping"));
24                    let clipping_mode = if let Some(s) = clipping_str {
25                        match s.as_ref() {
26                            "inside" => ClippingMode::Inside,
27                            "outside" => ClippingMode::Outside,
28                            _ => ClippingMode::None,
29                        }
30                    } else {
31                        ClippingMode::None
32                    };
33
34                    let lattice = parse_beam_lattice_content(
35                        parser,
36                        radius,
37                        min_length,
38                        precision,
39                        clipping_mode,
40                    )?;
41                    mesh.beam_lattice = Some(lattice);
42                }
43                _ => {} // Ignore headers/metadata inside mesh for now
44            },
45            Event::End(e) if e.local_name().as_ref() == b"mesh" => break,
46            Event::Eof => {
47                return Err(Lib3mfError::Validation(
48                    "Unexpected EOF in mesh".to_string(),
49                ));
50            }
51            _ => {}
52        }
53    }
54
55    Ok(mesh)
56}
57
58fn parse_vertices<R: BufRead>(parser: &mut XmlParser<R>, mesh: &mut Mesh) -> Result<()> {
59    loop {
60        match parser.read_next_event()? {
61            Event::Start(e) | Event::Empty(e) if e.name().as_ref() == b"vertex" => {
62                let x = get_attribute_f32(&e, b"x")?;
63                let y = get_attribute_f32(&e, b"y")?;
64                let z = get_attribute_f32(&e, b"z")?;
65                mesh.vertices.push(Vertex { x, y, z });
66            }
67            Event::End(e) if e.name().as_ref() == b"vertices" => break,
68            Event::Eof => {
69                return Err(Lib3mfError::Validation(
70                    "Unexpected EOF in vertices".to_string(),
71                ));
72            }
73            _ => {}
74        }
75    }
76    Ok(())
77}
78
79fn parse_triangles<R: BufRead>(parser: &mut XmlParser<R>, mesh: &mut Mesh) -> Result<()> {
80    loop {
81        match parser.read_next_event()? {
82            Event::Start(e) | Event::Empty(e) if e.name().as_ref() == b"triangle" => {
83                let v1 = get_attribute_u32(&e, b"v1")?;
84                let v2 = get_attribute_u32(&e, b"v2")?;
85                let v3 = get_attribute_u32(&e, b"v3")?;
86                let p1 = get_attribute_u32(&e, b"p1").ok();
87                let p2 = get_attribute_u32(&e, b"p2").ok();
88                let p3 = get_attribute_u32(&e, b"p3").ok();
89                let pid = get_attribute_u32(&e, b"pid").ok();
90
91                mesh.triangles.push(Triangle {
92                    v1,
93                    v2,
94                    v3,
95                    p1,
96                    p2,
97                    p3,
98                    pid,
99                });
100            }
101            Event::End(e) if e.name().as_ref() == b"triangles" => break,
102            Event::Eof => {
103                return Err(Lib3mfError::Validation(
104                    "Unexpected EOF in triangles".to_string(),
105                ));
106            }
107            _ => {}
108        }
109    }
110    Ok(())
111}