lib3mf_core/parser/
material_parser.rs

1use crate::error::{Lib3mfError, Result};
2use crate::model::{
3    BaseMaterial, BaseMaterialsGroup, BlendMethod, Color, ColorGroup, Composite,
4    CompositeMaterials, Multi, MultiProperties, ResourceId, Texture2DCoord, Texture2DGroup,
5};
6use crate::parser::xml_parser::{XmlParser, get_attribute};
7use quick_xml::events::Event;
8use std::io::BufRead;
9
10// ... existing code ...
11
12pub fn parse_texture_2d_group<R: BufRead>(
13    parser: &mut XmlParser<R>,
14    id: ResourceId,
15    texture_id: ResourceId,
16) -> Result<Texture2DGroup> {
17    let mut coords = Vec::new();
18
19    loop {
20        match parser.read_next_event()? {
21            Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"tex2coord" => {
22                let u = get_attribute(&e, b"u")
23                    .ok_or_else(|| Lib3mfError::Validation("tex2coord missing u".to_string()))?
24                    .parse::<f32>()
25                    .map_err(|_| Lib3mfError::Validation("Invalid u value".to_string()))?;
26                let v = get_attribute(&e, b"v")
27                    .ok_or_else(|| Lib3mfError::Validation("tex2coord missing v".to_string()))?
28                    .parse::<f32>()
29                    .map_err(|_| Lib3mfError::Validation("Invalid v value".to_string()))?;
30                coords.push(Texture2DCoord { u, v });
31            }
32            Event::End(e) if e.local_name().as_ref() == b"texture2dgroup" => break,
33            Event::Eof => {
34                return Err(Lib3mfError::Validation(
35                    "Unexpected EOF in texture2dgroup".to_string(),
36                ));
37            }
38            _ => {}
39        }
40    }
41
42    Ok(Texture2DGroup {
43        id,
44        texture_id,
45        coords,
46    })
47}
48
49pub fn parse_composite_materials<R: BufRead>(
50    parser: &mut XmlParser<R>,
51    id: ResourceId,
52    base_material_id: ResourceId,
53    indices: Vec<u32>,
54) -> Result<CompositeMaterials> {
55    let mut composites = Vec::new();
56
57    loop {
58        match parser.read_next_event()? {
59            Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"composite" => {
60                let values_str = get_attribute(&e, b"values").ok_or_else(|| {
61                    Lib3mfError::Validation("composite missing values".to_string())
62                })?;
63                let values = values_str
64                    .split_whitespace()
65                    .map(|s| {
66                        s.parse::<f32>().map_err(|_| {
67                            Lib3mfError::Validation("Invalid composite value".to_string())
68                        })
69                    })
70                    .collect::<Result<Vec<f32>>>()?;
71                composites.push(Composite { values });
72            }
73            Event::End(e) if e.local_name().as_ref() == b"compositematerials" => break,
74            Event::Eof => {
75                return Err(Lib3mfError::Validation(
76                    "Unexpected EOF in compositematerials".to_string(),
77                ));
78            }
79            _ => {}
80        }
81    }
82
83    Ok(CompositeMaterials {
84        id,
85        base_material_id,
86        indices,
87        composites,
88    })
89}
90
91pub fn parse_multi_properties<R: BufRead>(
92    parser: &mut XmlParser<R>,
93    id: ResourceId,
94    pids: Vec<ResourceId>,
95    blend_methods: Vec<BlendMethod>,
96) -> Result<MultiProperties> {
97    let mut multis = Vec::new();
98
99    loop {
100        match parser.read_next_event()? {
101            Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"multi" => {
102                let pindices_str = get_attribute(&e, b"pindices")
103                    .ok_or_else(|| Lib3mfError::Validation("multi missing pindices".to_string()))?;
104                let pindices = pindices_str
105                    .split_whitespace()
106                    .map(|s| {
107                        s.parse::<u32>().map_err(|_| {
108                            Lib3mfError::Validation("Invalid pindex value".to_string())
109                        })
110                    })
111                    .collect::<Result<Vec<u32>>>()?;
112                multis.push(Multi { pindices });
113            }
114            Event::End(e) if e.local_name().as_ref() == b"multiproperties" => break,
115            Event::Eof => {
116                return Err(Lib3mfError::Validation(
117                    "Unexpected EOF in multiproperties".to_string(),
118                ));
119            }
120            _ => {}
121        }
122    }
123
124    Ok(MultiProperties {
125        id,
126        pids,
127        blend_methods,
128        multis,
129    })
130}
131
132pub fn parse_base_materials<R: BufRead>(
133    parser: &mut XmlParser<R>,
134    id: ResourceId,
135) -> Result<BaseMaterialsGroup> {
136    let mut materials = Vec::new();
137
138    loop {
139        match parser.read_next_event()? {
140            Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"base" => {
141                let name = get_attribute(&e, b"name").ok_or_else(|| {
142                    Lib3mfError::Validation("base element missing 'name' attribute".to_string())
143                })?;
144                let color_hex = get_attribute(&e, b"displaycolor").ok_or_else(|| {
145                    Lib3mfError::Validation(
146                        "base element missing 'displaycolor' attribute".to_string(),
147                    )
148                })?;
149                let display_color = Color::from_hex(&color_hex).ok_or_else(|| {
150                    Lib3mfError::Validation(format!("Invalid color format: {}", color_hex))
151                })?;
152
153                materials.push(BaseMaterial {
154                    name: name.into_owned(),
155                    display_color,
156                });
157            }
158            Event::End(e) if e.local_name().as_ref() == b"basematerials" => break,
159            Event::Eof => {
160                return Err(Lib3mfError::Validation(
161                    "Unexpected EOF in basematerials".to_string(),
162                ));
163            }
164            _ => {}
165        }
166    }
167
168    Ok(BaseMaterialsGroup { id, materials })
169}
170
171pub fn parse_color_group<R: BufRead>(
172    parser: &mut XmlParser<R>,
173    id: ResourceId,
174) -> Result<ColorGroup> {
175    let mut colors = Vec::new();
176
177    loop {
178        match parser.read_next_event()? {
179            Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"color" => {
180                let color_hex = get_attribute(&e, b"color").ok_or_else(|| {
181                    Lib3mfError::Validation("color element missing 'color' attribute".to_string())
182                })?;
183                let color = Color::from_hex(&color_hex).ok_or_else(|| {
184                    Lib3mfError::Validation(format!("Invalid color format: {}", color_hex))
185                })?;
186                colors.push(color);
187            }
188            Event::End(e) if e.local_name().as_ref() == b"colorgroup" => break,
189            Event::Eof => {
190                return Err(Lib3mfError::Validation(
191                    "Unexpected EOF in colorgroup".to_string(),
192                ));
193            }
194            _ => {}
195        }
196    }
197
198    Ok(ColorGroup { id, colors })
199}