Skip to main content

lib3mf_core/parser/
slice_parser.rs

1use crate::error::{Lib3mfError, Result};
2use crate::model::{Polygon, Segment, Slice, SliceRef, SliceStack, Vertex2D};
3use crate::parser::xml_parser::{XmlParser, get_attribute, get_attribute_f32, get_attribute_u32};
4use quick_xml::events::Event;
5use std::borrow::Cow;
6use std::io::BufRead;
7
8// parse_slice_stack removed (used content version directly)
9
10/// Parses the content of a `<slicestack>` element (after attributes are read) into a `SliceStack`.
11pub fn parse_slice_stack_content<R: BufRead>(
12    parser: &mut XmlParser<R>,
13    id: crate::model::ResourceId,
14    z_bottom: f32,
15) -> Result<SliceStack> {
16    let mut slices = Vec::new();
17    let mut refs = Vec::new();
18
19    loop {
20        match parser.read_next_event()? {
21            Event::Start(e) => match e.local_name().as_ref() {
22                b"slice" => {
23                    let z_top = get_attribute_f32(&e, b"ztop")?;
24                    let slice = parse_slice(parser, z_top)?;
25                    slices.push(slice);
26                }
27                b"sliceref" => {
28                    // Usually empty element <sliceref ... />?
29                    // Start or Empty.
30                    let stack_id =
31                        crate::model::ResourceId(get_attribute_u32(&e, b"slicestackid")?);
32                    let path = get_attribute(&e, b"slicepath")
33                        .map(|s: Cow<str>| s.into_owned())
34                        .unwrap_or_default();
35                    refs.push(SliceRef {
36                        slice_stack_id: stack_id,
37                        slice_path: path,
38                    });
39                }
40                _ => {}
41            },
42            Event::Empty(e) => {
43                if e.local_name().as_ref() == b"sliceref" {
44                    let stack_id =
45                        crate::model::ResourceId(get_attribute_u32(&e, b"slicestackid")?);
46                    let path = get_attribute(&e, b"slicepath")
47                        .map(|s: Cow<str>| s.into_owned())
48                        .unwrap_or_default();
49                    refs.push(SliceRef {
50                        slice_stack_id: stack_id,
51                        slice_path: path,
52                    });
53                }
54            }
55            Event::End(e) if e.local_name().as_ref() == b"slicestack" => break,
56            Event::Eof => {
57                return Err(Lib3mfError::Validation(
58                    "Unexpected EOF in slicestack".to_string(),
59                ));
60            }
61            _ => {}
62        }
63    }
64
65    Ok(SliceStack {
66        id,
67        z_bottom,
68        slices,
69        refs,
70    })
71}
72
73fn parse_slice<R: BufRead>(parser: &mut XmlParser<R>, z_top: f32) -> Result<Slice> {
74    let mut vertices = Vec::new();
75    let mut polygons = Vec::new();
76
77    loop {
78        match parser.read_next_event()? {
79            Event::Start(e) => match e.local_name().as_ref() {
80                b"vertices" => {
81                    vertices = parse_slice_vertices(parser)?;
82                }
83                b"polygon" => {
84                    // Polygon has attributes? "start"
85                    // Wait, polygon has `start` attribute indicating start vertex index?
86                    // "startsegment" is my field name. Spec says "start".
87                    let start = get_attribute_u32(&e, b"start").unwrap_or(0);
88                    let segments = parse_polygon_segments(parser)?;
89                    polygons.push(Polygon {
90                        start_segment: start,
91                        segments,
92                    });
93                }
94                _ => {}
95            },
96            Event::End(e) if e.local_name().as_ref() == b"slice" => break,
97            Event::Eof => {
98                return Err(Lib3mfError::Validation(
99                    "Unexpected EOF in slice".to_string(),
100                ));
101            }
102            _ => {}
103        }
104    }
105
106    Ok(Slice {
107        z_top,
108        vertices,
109        polygons,
110    })
111}
112
113fn parse_slice_vertices<R: BufRead>(parser: &mut XmlParser<R>) -> Result<Vec<Vertex2D>> {
114    let mut vertices = Vec::new();
115    loop {
116        match parser.read_next_event()? {
117            Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"vertex" => {
118                let x = get_attribute_f32(&e, b"x")?;
119                let y = get_attribute_f32(&e, b"y")?;
120                vertices.push(Vertex2D { x, y });
121            }
122            Event::End(e) if e.local_name().as_ref() == b"vertices" => break,
123            Event::Eof => {
124                return Err(Lib3mfError::Validation(
125                    "Unexpected EOF in slice vertices".to_string(),
126                ));
127            }
128            _ => {}
129        }
130    }
131    Ok(vertices)
132}
133
134fn parse_polygon_segments<R: BufRead>(parser: &mut XmlParser<R>) -> Result<Vec<Segment>> {
135    let mut segments = Vec::new();
136    loop {
137        match parser.read_next_event()? {
138            Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"segment" => {
139                let v2 = get_attribute_u32(&e, b"v2")?;
140                let p1 = get_attribute_u32(&e, b"p1").ok();
141                let p2 = get_attribute_u32(&e, b"p2").ok();
142                let pid = get_attribute_u32(&e, b"pid")
143                    .map(crate::model::ResourceId)
144                    .ok();
145
146                segments.push(Segment { v2, p1, p2, pid });
147            }
148            Event::End(e) if e.local_name().as_ref() == b"polygon" => break,
149            Event::Eof => {
150                return Err(Lib3mfError::Validation(
151                    "Unexpected EOF in polygon segments".to_string(),
152                ));
153            }
154            _ => {}
155        }
156    }
157    Ok(segments)
158}