1use crate::point::{Point, point};
2use crate::primitives::{quote_string, ws};
3use crate::{parse_section, ws_separated};
4use nom::IResult;
5use nom::Parser;
6use nom::branch::alt;
7use nom::bytes::complete::{is_not, tag};
8use nom::multi::many0;
9use nom::number::complete::float;
10use nom::sequence::delimited;
11use std::collections::HashMap;
12
13fn electrical_properties(input: &str) -> IResult<&str, ElectricalProperties> {
29 let (remaining, properties) = many0(electrical_property).parse(input)?;
30 Ok((remaining, properties.into_iter().collect()))
31}
32
33fn electrical_property(input: &str) -> IResult<&str, (String, f32)> {
35 let (remaining, (_prop_tag, prop_name, value)) =
36 ws_separated!((tag("PROP"), is_not(" "), float)).parse(input)?;
37 Ok((remaining, (prop_name.to_string(), value)))
38}
39
40type ElectricalProperties = HashMap<String, f32>;
42
43#[derive(Debug, PartialEq, Clone, Default)]
46pub struct ElectricalComponent {
47 pub geometry_name: String,
48 pub part_number: String,
49 pub units: String,
50 pub height: f32,
51 pub outline: Vec<Point>,
52 pub properties: ElectricalProperties,
53}
54
55#[derive(Debug, PartialEq, Clone, Default, PartialOrd)]
58pub struct MechanicalComponent {
59 pub geometry_name: String,
60 pub part_number: String,
61 pub units: String,
62 pub height: f32,
63 pub outline: Vec<Point>,
64}
65
66pub fn electrical_component(input: &str) -> IResult<&str, ElectricalComponent> {
83 let (remaining, (geometry_name, part_number, units, height, outline, properties)) =
84 parse_section!(
85 "ELECTRICAL",
86 ws_separated!((
87 is_not(" "), alt((
89 quote_string, is_not(" "), )),
92 is_not(" "), float, many0(ws(point)), electrical_properties ))
97 )
98 .parse(input)?;
99
100 let electrical_component = ElectricalComponent {
101 geometry_name: geometry_name.to_string(),
102 part_number: part_number.to_string(),
103 units: units.to_string(),
104 height,
105 outline,
106 properties,
107 };
108
109 Ok((remaining, electrical_component))
110}
111
112pub fn mechanical_component(input: &str) -> IResult<&str, MechanicalComponent> {
129 let (remaining, (geometry_name, part_number, units, height, outline)) = parse_section!(
130 "MECHANICAL",
131 ws_separated!((
132 is_not(" "), is_not(" "), is_not(" "), float, many0(ws(point)) ))
138 )
139 .parse(input)?;
140
141 let mechanical_component = MechanicalComponent {
142 geometry_name: geometry_name.to_string(),
143 part_number: part_number.to_string(),
144 units: units.to_string(),
145 height,
146 outline,
147 };
148
149 Ok((remaining, mechanical_component))
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155 #[test]
156 fn test_electrical_component() {
157 let input = ".ELECTRICAL
158cs13_a pn-cap THOU 150.0
1590 -55.0 55.0 0.0
1600 -55.0 -55.0 0.0
1610 135.0 -55.0 0.0
1620 135.0 -80.0 0.0
1630 565.0 -80.0 0.0
1640 565.0 -55.0 0.0
1650 755.0 -55.0 0.0
1660 755.0 55.0 0.0
1670 565.0 55.0 0.0
1680 565.0 80.0 0.0
1690 135.0 80.0 0.0
1700 135.0 55.0 0.0
1710 -55.0 55.0 0.0
172PROP CAPACITANCE 100.0
173PROP TOLERANCE 5.0
174PROP RESISTANCE 122.0
175PROP POWER_OPR 2.5
176PROP POWER_MAX 9.12
177PROP THERM_COND 0.0
178PROP THETA_JB 0.2
179PROP THETA_JC 5.1
180.END_ELECTRICAL";
181 let (remaining, component) = electrical_component(input).unwrap();
182 assert_eq!(remaining, "");
183 assert_eq!(component.geometry_name, "cs13_a");
184 assert_eq!(component.part_number, "pn-cap");
185 assert_eq!(component.units, "THOU");
186 assert_eq!(component.height, 150.0);
187 assert_eq!(component.outline.len(), 13);
188 assert_eq!(component.properties["CAPACITANCE"], 100.0);
189 assert_eq!(component.properties["TOLERANCE"], 5.0);
190 assert_eq!(component.properties["RESISTANCE"], 122.0);
191 assert_eq!(component.properties["POWER_OPR"], 2.5);
192 assert_eq!(component.properties["POWER_MAX"], 9.12);
193 assert_eq!(component.properties["THERM_COND"], 0.0);
194 assert_eq!(component.properties["THETA_JB"], 0.2);
195 assert_eq!(component.properties["THETA_JC"], 5.1);
196 }
197
198 #[test]
199 fn test_electrical_component_2() {
200 let input = ".ELECTRICAL\r\nGLOB_FID_60R140 \"GLOB_FID_GLOB_FID_60R140_GLOB F\" THOU 2.0\r\n0 0.0 0.0 0.000\r\n0 70.0 0.0 360.000\r\n.END_ELECTRICAL\r\n";
201
202 let (remaining, component) = electrical_component(input).unwrap();
203
204 let expected = ElectricalComponent {
205 geometry_name: "GLOB_FID_60R140".to_string(),
206 part_number: "GLOB_FID_GLOB_FID_60R140_GLOB F".to_string(),
207 units: "THOU".to_string(),
208 height: 2.0,
209 outline: vec![
210 Point {
211 loop_label: 0,
212 x: 0.0,
213 y: 0.0,
214 angle: 0.0,
215 },
216 Point {
217 loop_label: 0,
218 x: 70.0,
219 y: 0.0,
220 angle: 360.0,
221 },
222 ],
223 properties: HashMap::new(),
224 };
225 assert_eq!(remaining, "");
226 assert_eq!(component.geometry_name, expected.geometry_name);
227 }
228 #[test]
229 fn test_mechanical_component() {
230 let input = ".MECHANICAL
231cs13_a pn-cap THOU 150.0
2320 -55.0 55.0 0.0
2330 -55.0 -55.0 0.0
2340 135.0 -55.0 0.0
2350 135.0 -80.0 0.0
2360 565.0 -80.0 0.0
2370 565.0 -55.0 0.0
238.END_MECHANICAL";
239 let (remaining, component) = mechanical_component(input).unwrap();
240 assert_eq!(remaining, "");
241 assert_eq!(component.geometry_name, "cs13_a");
242 assert_eq!(component.part_number, "pn-cap");
243 assert_eq!(component.units, "THOU");
244 assert_eq!(component.height, 150.0);
245 assert_eq!(component.outline.len(), 6);
246 assert_eq!(
247 component.outline[0],
248 Point {
249 loop_label: 0,
250 x: -55.0,
251 y: 55.0,
252 angle: 0.0
253 }
254 );
255 assert_eq!(
256 component.outline[4],
257 Point {
258 loop_label: 0,
259 x: 565.0,
260 y: -80.0,
261 angle: 0.0
262 }
263 );
264 }
265}