1mod arc;
6mod board;
7mod class;
8mod component;
9mod component_body;
10mod connection;
11mod differential_pair;
12mod fill;
13mod fromto;
14mod net;
15mod options;
16mod outline;
17mod pad;
18mod polygon;
19mod primitive;
20mod region;
21mod rule;
22mod text;
23mod track;
24mod via;
25
26pub use arc::*;
27pub use board::*;
28pub use class::*;
29pub use component::*;
30pub use component_body::*;
31pub use connection::*;
32pub use differential_pair::*;
33pub use fill::*;
34pub use fromto::*;
35pub use net::*;
36pub use options::*;
37pub use pad::*;
38pub use polygon::*;
39pub use primitive::*;
40pub use region::*;
41pub use rule::*;
42pub use text::*;
43pub use track::*;
44pub use via::*;
45
46pub(crate) use outline::PcbOutline;
47
48use crate::dump::{
50 DumpTree, TreeBuilder, fmt_angle, fmt_bool, fmt_coord_point, fmt_coord_val, fmt_layer,
51};
52
53impl DumpTree for PcbArc {
54 fn dump(&self, tree: &mut TreeBuilder) {
55 tree.add_leaf(
56 "Arc",
57 &[
58 ("layer", fmt_layer(&self.common.layer)),
59 ("center", fmt_coord_point(&self.location)),
60 ("radius", fmt_coord_val(&self.radius)),
61 (
62 "angles",
63 format!(
64 "{} → {}",
65 fmt_angle(self.start_angle),
66 fmt_angle(self.end_angle)
67 ),
68 ),
69 ("width", fmt_coord_val(&self.width)),
70 ],
71 );
72 }
73}
74
75impl DumpTree for PcbTrack {
76 fn dump(&self, tree: &mut TreeBuilder) {
77 tree.add_leaf(
78 "Track",
79 &[
80 ("layer", fmt_layer(&self.common.layer)),
81 ("start", fmt_coord_point(&self.start)),
82 ("end", fmt_coord_point(&self.end)),
83 ("width", fmt_coord_val(&self.width)),
84 ],
85 );
86 }
87}
88
89impl DumpTree for PcbPad {
90 fn dump(&self, tree: &mut TreeBuilder) {
91 let mut props = vec![
92 ("designator", self.designator.clone()),
93 ("layer", fmt_layer(&self.common.layer)),
94 ("location", fmt_coord_point(&self.location)),
95 ("size (top)", fmt_coord_point(&self.size_top())),
96 ("shape (top)", format!("{:?}", self.shape_top())),
97 ("hole", fmt_coord_val(&self.hole_size)),
98 ];
99 if self.rotation != 0.0 {
100 props.push(("rotation", fmt_angle(self.rotation)));
101 }
102 props.push(("plated", fmt_bool(self.is_plated)));
103 tree.add_leaf("Pad", &props);
104 }
105}
106
107impl DumpTree for PcbVia {
108 fn dump(&self, tree: &mut TreeBuilder) {
109 tree.add_leaf(
110 "Via",
111 &[
112 ("location", fmt_coord_point(&self.location)),
113 (
114 "layers",
115 format!(
116 "{} → {}",
117 fmt_layer(&self.from_layer),
118 fmt_layer(&self.to_layer)
119 ),
120 ),
121 ("diameter", fmt_coord_val(&self.diameter())),
122 ("hole", fmt_coord_val(&self.hole_size)),
123 ],
124 );
125 }
126}
127
128impl DumpTree for PcbText {
129 fn dump(&self, tree: &mut TreeBuilder) {
130 let mut props = vec![
131 ("text", format!("\"{}\"", self.text)),
132 ("layer", fmt_layer(&self.base.common.layer)),
133 ("position", fmt_coord_point(&self.base.corner1)),
134 ("height", fmt_coord_val(&self.height())),
135 ];
136 if self.base.rotation != 0.0 {
137 props.push(("rotation", fmt_angle(self.base.rotation)));
138 }
139 if self.mirrored {
140 props.push(("mirrored", "yes".to_string()));
141 }
142 if !self.font_name.is_empty() {
143 props.push(("font", self.font_name.clone()));
144 }
145 tree.add_leaf("Text", &props);
146 }
147}
148
149impl DumpTree for PcbFill {
150 fn dump(&self, tree: &mut TreeBuilder) {
151 let mut props = vec![
152 ("layer", fmt_layer(&self.base.common.layer)),
153 ("corner1", fmt_coord_point(&self.base.corner1)),
154 ("corner2", fmt_coord_point(&self.base.corner2)),
155 ];
156 if self.base.rotation != 0.0 {
157 props.push(("rotation", fmt_angle(self.base.rotation)));
158 }
159 tree.add_leaf("Fill", &props);
160 }
161}
162
163impl DumpTree for PcbRegion {
164 fn dump(&self, tree: &mut TreeBuilder) {
165 tree.add_leaf(
166 "Region",
167 &[
168 ("layer", fmt_layer(&self.common.layer)),
169 ("vertices", format!("{} points", self.outline.len())),
170 ],
171 );
172 }
173}
174
175impl DumpTree for PcbComponentBody {
176 fn dump(&self, tree: &mut TreeBuilder) {
177 let mut props = vec![("layer", fmt_layer(&self.common.layer))];
178 if !self.unique_id.is_empty() {
179 props.push(("unique_id", self.unique_id.clone()));
180 }
181 if !self.model_id.is_empty() {
182 props.push(("3D model", self.model_id.clone()));
183 }
184 props.push(("height", fmt_coord_val(&self.overall_height)));
185 props.push(("vertices", format!("{} points", self.outline.len())));
186 tree.add_leaf("ComponentBody", &props);
187 }
188}
189
190impl DumpTree for PcbRecord {
191 fn dump(&self, tree: &mut TreeBuilder) {
192 match self {
193 PcbRecord::Arc(r) => r.dump(tree),
194 PcbRecord::Pad(r) => r.dump(tree),
195 PcbRecord::Via(r) => r.dump(tree),
196 PcbRecord::Track(r) => r.dump(tree),
197 PcbRecord::Text(r) => r.dump(tree),
198 PcbRecord::Fill(r) => r.dump(tree),
199 PcbRecord::Region(r) => r.dump(tree),
200 PcbRecord::ComponentBody(r) => r.dump(tree),
201 PcbRecord::Polygon(r) => r.dump(tree),
202 PcbRecord::Unknown {
203 object_id,
204 raw_data,
205 } => {
206 tree.add_leaf(
207 "Unknown",
208 &[
209 ("object_id", format!("{:?}", object_id)),
210 ("size", format!("{} bytes", raw_data.len())),
211 ],
212 );
213 }
214 }
215 }
216}
217
218impl DumpTree for PcbComponent {
219 fn dump(&self, tree: &mut TreeBuilder) {
220 tree.begin_node(&format!("Footprint: {}", self.pattern));
221 tree.push(true);
222
223 tree.push(!self.primitives.is_empty());
225 let mut meta_props = vec![];
226 if !self.description.is_empty() {
227 meta_props.push(("description", self.description.clone()));
228 }
229 if self.height.to_raw() != 0 {
230 meta_props.push(("height", fmt_coord_val(&self.height)));
231 }
232 meta_props.push(("pads", format!("{}", self.pad_count())));
233 meta_props.push(("primitives", format!("{}", self.primitive_count())));
234 tree.add_leaf("Info", &meta_props);
235 tree.pop();
236
237 if !self.primitives.is_empty() {
239 tree.push(false);
240 tree.begin_node(&format!("Primitives ({})", self.primitives.len()));
241 for (i, prim) in self.primitives.iter().enumerate() {
242 tree.push(i < self.primitives.len() - 1);
243 prim.dump(tree);
244 tree.pop();
245 }
246 tree.pop();
247 }
248
249 tree.pop();
250 }
251}
252
253impl DumpTree for PcbRule {
254 fn dump(&self, tree: &mut TreeBuilder) {
255 let mut props = vec![
256 ("kind", format!("{}", self.kind)),
257 ("enabled", fmt_bool(self.enabled)),
258 ("priority", format!("{}", self.priority)),
259 ];
260
261 if !self.scope1_expression.is_empty() && self.scope1_expression != "All" {
262 props.push(("scope1", self.scope1_expression.clone()));
263 }
264 if !self.scope2_expression.is_empty() && self.scope2_expression != "All" {
265 props.push(("scope2", self.scope2_expression.clone()));
266 }
267 if !self.comment.is_empty() {
268 props.push(("comment", self.comment.clone()));
269 }
270
271 tree.add_leaf(&format!("Rule: {}", self.name), &props);
272 }
273}
274
275impl DumpTree for PcbPolygon {
276 fn dump(&self, tree: &mut TreeBuilder) {
277 let mut props = vec![
278 ("layer", fmt_layer(&self.layer)),
279 ("type", self.polygon_type.as_str().to_string()),
280 ("vertices", format!("{} points", self.vertices.len())),
281 ];
282 if !self.net_name.is_empty() {
283 props.push(("net", self.net_name.clone()));
284 }
285 props.push(("hatch", self.hatch_style.as_str().to_string()));
286 tree.add_leaf("Polygon", &props);
287 }
288}
289
290impl DumpTree for PcbNet {
291 fn dump(&self, tree: &mut TreeBuilder) {
292 let mut props = vec![("name", self.name.clone())];
293 if !self.layer_widths.is_empty() {
294 props.push((
295 "layer widths",
296 format!("{} layers", self.layer_widths.len()),
297 ));
298 }
299 tree.add_leaf("Net", &props);
300 }
301}
302
303impl DumpTree for PcbDifferentialPair {
304 fn dump(&self, tree: &mut TreeBuilder) {
305 tree.add_leaf(
306 "DifferentialPair",
307 &[
308 ("name", self.name.clone()),
309 ("positive", self.positive_net_name.clone()),
310 ("negative", self.negative_net_name.clone()),
311 ],
312 );
313 }
314}
315
316impl DumpTree for PcbFromTo {
317 fn dump(&self, tree: &mut TreeBuilder) {
318 tree.add_leaf(
319 "FromTo",
320 &[
321 ("from", self.from.clone()),
322 ("to", self.to.clone()),
323 ("net", self.net.clone()),
324 ],
325 );
326 }
327}
328
329impl DumpTree for PcbConnection {
330 fn dump(&self, tree: &mut TreeBuilder) {
331 tree.add_leaf(
332 "Connection",
333 &[
334 ("net_index", format!("{}", self.net_index)),
335 (
336 "from",
337 format!(
338 "({}, {})",
339 fmt_coord_val(&self.from_x),
340 fmt_coord_val(&self.from_y)
341 ),
342 ),
343 (
344 "to",
345 format!(
346 "({}, {})",
347 fmt_coord_val(&self.to_x),
348 fmt_coord_val(&self.to_y)
349 ),
350 ),
351 ],
352 );
353 }
354}
355
356impl DumpTree for PcbBoard {
357 fn dump(&self, tree: &mut TreeBuilder) {
358 let mut props = vec![
359 ("version", self.version.clone()),
360 (
361 "display_unit",
362 if self.is_metric() { "mm" } else { "mil" }.to_string(),
363 ),
364 ("outline", format!("{} vertices", self.outline.len())),
365 ];
366 if !self.date.is_empty() {
367 props.push(("date", self.date.clone()));
368 }
369 tree.add_leaf("Board", &props);
370 }
371}