Skip to main content

altium_format/records/sch/
mod.rs

1//! Schematic record types.
2//!
3//! Contains all schematic primitive record types like pins, wires, rectangles, etc.
4
5mod arc;
6mod bezier;
7mod bus;
8mod bus_entry;
9mod common;
10mod component;
11mod designator;
12mod ellipse;
13mod image;
14mod implementation;
15mod junction;
16mod label;
17mod line;
18mod netlabel;
19mod no_erc;
20mod parameter;
21mod pie;
22mod pin;
23mod pin_new; // Test derive macro implementation
24mod polygon;
25mod polyline;
26mod port;
27mod power;
28mod primitive;
29mod rectangle;
30mod sheet;
31mod symbol;
32mod text_frame;
33mod warning_sign;
34mod wire;
35
36pub use arc::{SchArc, SchEllipticalArc};
37pub use bezier::*;
38pub use bus::*;
39pub use bus_entry::*;
40pub use common::*;
41pub use component::*;
42pub use designator::*;
43pub use ellipse::*;
44pub use image::*;
45pub use implementation::*;
46pub use junction::*;
47pub use label::*;
48pub use line::*;
49pub use netlabel::*;
50pub use no_erc::*;
51pub use parameter::*;
52pub use pie::*;
53pub use pin::*;
54pub use polygon::*;
55pub use polyline::*;
56pub use port::*;
57pub use power::*;
58pub use primitive::*;
59pub use rectangle::*;
60pub use sheet::*;
61pub use symbol::*;
62pub use text_frame::*;
63pub use warning_sign::*;
64pub use wire::*;
65
66#[cfg(test)]
67mod tests;
68
69// DumpTree implementations
70use crate::dump::{DumpTree, TreeBuilder, fmt_angle, fmt_bool, fmt_coord, fmt_point};
71
72impl DumpTree for SchComponent {
73    fn dump(&self, tree: &mut TreeBuilder) {
74        let mut props = vec![("lib_reference", self.lib_reference.clone())];
75        if !self.component_description.is_empty() {
76            props.push(("description", self.component_description.clone()));
77        }
78        props.push((
79            "location",
80            fmt_point(self.graphical.location_x, self.graphical.location_y),
81        ));
82        props.push(("parts", format!("{}", self.part_count)));
83        tree.add_leaf("Component", &props);
84    }
85}
86
87impl DumpTree for SchPin {
88    fn dump(&self, tree: &mut TreeBuilder) {
89        let mut props = vec![];
90        if !self.designator.is_empty() {
91            props.push(("designator", self.designator.clone()));
92        }
93        if !self.name.is_empty() {
94            props.push(("name", self.name.clone()));
95        }
96        props.push((
97            "location",
98            fmt_point(self.graphical.location_x, self.graphical.location_y),
99        ));
100        props.push(("length", fmt_coord(self.pin_length)));
101        props.push(("electrical", format!("{:?}", self.electrical)));
102        if self.is_hidden() {
103            props.push(("hidden", "yes".to_string()));
104        }
105        tree.add_leaf("Pin", &props);
106    }
107}
108
109impl DumpTree for SchSymbol {
110    fn dump(&self, tree: &mut TreeBuilder) {
111        let mut props = vec![(
112            "location",
113            fmt_point(self.graphical.location_x, self.graphical.location_y),
114        )];
115        if self.scale_factor != 1.0 {
116            props.push(("scale", format!("{:.2}", self.scale_factor)));
117        }
118        if self.is_mirrored {
119            props.push(("mirrored", "yes".to_string()));
120        }
121        tree.add_leaf("Symbol", &props);
122    }
123}
124
125impl DumpTree for SchLabel {
126    fn dump(&self, tree: &mut TreeBuilder) {
127        let mut props = vec![
128            ("text", format!("\"{}\"", self.text)),
129            (
130                "location",
131                fmt_point(self.graphical.location_x, self.graphical.location_y),
132            ),
133        ];
134        if self.is_hidden {
135            props.push(("hidden", "yes".to_string()));
136        }
137        tree.add_leaf("Label", &props);
138    }
139}
140
141impl DumpTree for SchBezier {
142    fn dump(&self, tree: &mut TreeBuilder) {
143        tree.add_leaf(
144            "Bezier",
145            &[("control_points", format!("{}", self.vertices.len()))],
146        );
147    }
148}
149
150impl DumpTree for SchPolyline {
151    fn dump(&self, tree: &mut TreeBuilder) {
152        tree.add_leaf(
153            "Polyline",
154            &[
155                ("vertices", format!("{}", self.vertices.len())),
156                ("style", format!("{:?}", self.line_style)),
157            ],
158        );
159    }
160}
161
162impl DumpTree for SchPolygon {
163    fn dump(&self, tree: &mut TreeBuilder) {
164        let mut props = vec![("vertices", format!("{}", self.vertices.len()))];
165        if self.is_solid {
166            props.push(("filled", "yes".to_string()));
167        }
168        tree.add_leaf("Polygon", &props);
169    }
170}
171
172impl DumpTree for SchEllipse {
173    fn dump(&self, tree: &mut TreeBuilder) {
174        let mut props = vec![
175            (
176                "center",
177                fmt_point(self.graphical.location_x, self.graphical.location_y),
178            ),
179            (
180                "radius",
181                format!(
182                    "{} × {}",
183                    fmt_coord(self.radius_x),
184                    fmt_coord(self.radius_y)
185                ),
186            ),
187        ];
188        if self.is_solid {
189            props.push(("filled", "yes".to_string()));
190        }
191        tree.add_leaf("Ellipse", &props);
192    }
193}
194
195impl DumpTree for SchPie {
196    fn dump(&self, tree: &mut TreeBuilder) {
197        let mut props = vec![
198            (
199                "center",
200                fmt_point(self.graphical.location_x, self.graphical.location_y),
201            ),
202            (
203                "radii",
204                format!(
205                    "{} × {}",
206                    fmt_coord(self.radius),
207                    fmt_coord(if self.secondary_radius == 0 {
208                        self.radius
209                    } else {
210                        self.secondary_radius
211                    })
212                ),
213            ),
214            (
215                "angles",
216                format!(
217                    "{} → {}",
218                    fmt_angle(self.start_angle),
219                    fmt_angle(self.end_angle)
220                ),
221            ),
222        ];
223        if self.is_solid {
224            props.push(("filled", "yes".to_string()));
225        }
226        tree.add_leaf("Pie", &props);
227    }
228}
229
230impl DumpTree for SchEllipticalArc {
231    fn dump(&self, tree: &mut TreeBuilder) {
232        tree.add_leaf(
233            "EllipticalArc",
234            &[
235                (
236                    "center",
237                    fmt_point(self.graphical.location_x, self.graphical.location_y),
238                ),
239                (
240                    "radii",
241                    format!(
242                        "{} × {}",
243                        fmt_coord(self.radius),
244                        fmt_coord(self.secondary_radius)
245                    ),
246                ),
247                (
248                    "angles",
249                    format!(
250                        "{} → {}",
251                        fmt_angle(self.start_angle),
252                        fmt_angle(self.end_angle)
253                    ),
254                ),
255            ],
256        );
257    }
258}
259
260impl DumpTree for SchArc {
261    fn dump(&self, tree: &mut TreeBuilder) {
262        tree.add_leaf(
263            "Arc",
264            &[
265                (
266                    "center",
267                    fmt_point(self.graphical.location_x, self.graphical.location_y),
268                ),
269                ("radius", fmt_coord(self.radius)),
270                (
271                    "angles",
272                    format!(
273                        "{} → {}",
274                        fmt_angle(self.start_angle),
275                        fmt_angle(self.end_angle)
276                    ),
277                ),
278            ],
279        );
280    }
281}
282
283impl DumpTree for SchLine {
284    fn dump(&self, tree: &mut TreeBuilder) {
285        tree.add_leaf(
286            "Line",
287            &[
288                (
289                    "start",
290                    fmt_point(self.graphical.location_x, self.graphical.location_y),
291                ),
292                ("end", fmt_point(self.corner_x, self.corner_y)),
293            ],
294        );
295    }
296}
297
298impl DumpTree for SchRectangle {
299    fn dump(&self, tree: &mut TreeBuilder) {
300        let mut props = vec![
301            (
302                "corner1",
303                fmt_point(self.graphical.location_x, self.graphical.location_y),
304            ),
305            ("corner2", fmt_point(self.corner_x, self.corner_y)),
306        ];
307        if self.is_solid {
308            props.push(("filled", "yes".to_string()));
309        }
310        tree.add_leaf("Rectangle", &props);
311    }
312}
313
314impl DumpTree for SchPowerObject {
315    fn dump(&self, tree: &mut TreeBuilder) {
316        tree.add_leaf(
317            "PowerObject",
318            &[
319                ("net", format!("\"{}\"", self.text)),
320                ("style", format!("{:?}", self.style)),
321                (
322                    "location",
323                    fmt_point(self.graphical.location_x, self.graphical.location_y),
324                ),
325            ],
326        );
327    }
328}
329
330impl DumpTree for SchPort {
331    fn dump(&self, tree: &mut TreeBuilder) {
332        let mut props = vec![
333            ("name", format!("\"{}\"", self.name)),
334            (
335                "location",
336                fmt_point(self.graphical.location_x, self.graphical.location_y),
337            ),
338        ];
339        props.push(("io_type", format!("{:?}", self.io_type)));
340        props.push(("style", format!("{:?}", self.style)));
341        if self.width > 0 || self.height > 0 {
342            props.push(("size", format!("{}x{}", self.width, self.height)));
343        }
344        if !self.harness_type.is_empty() {
345            props.push(("harness", self.harness_type.clone()));
346        }
347        tree.add_leaf("Port", &props);
348    }
349}
350
351impl DumpTree for SchNetLabel {
352    fn dump(&self, tree: &mut TreeBuilder) {
353        tree.add_leaf(
354            "NetLabel",
355            &[
356                ("net", format!("\"{}\"", self.label.text)),
357                (
358                    "location",
359                    fmt_point(
360                        self.label.graphical.location_x,
361                        self.label.graphical.location_y,
362                    ),
363                ),
364            ],
365        );
366    }
367}
368
369impl DumpTree for SchWire {
370    fn dump(&self, tree: &mut TreeBuilder) {
371        let vertices = &self.vertices;
372        if vertices.len() == 2 {
373            tree.add_leaf(
374                "Wire",
375                &[
376                    ("start", fmt_point(vertices[0].0, vertices[0].1)),
377                    ("end", fmt_point(vertices[1].0, vertices[1].1)),
378                ],
379            );
380        } else {
381            tree.add_leaf(
382                "Wire",
383                &[("segments", format!("{}", vertices.len().saturating_sub(1)))],
384            );
385        }
386    }
387}
388
389impl DumpTree for SchTextFrame {
390    fn dump(&self, tree: &mut TreeBuilder) {
391        tree.add_leaf(
392            "TextFrame",
393            &[
394                ("text", format!("\"{}\"", self.text)),
395                (
396                    "corner1",
397                    fmt_point(self.graphical.location_x, self.graphical.location_y),
398                ),
399                ("corner2", fmt_point(self.corner_x, self.corner_y)),
400            ],
401        );
402    }
403}
404
405impl DumpTree for SchTextFrameVariant {
406    fn dump(&self, tree: &mut TreeBuilder) {
407        tree.add_leaf(
408            "TextFrameVariant",
409            &[
410                ("text", format!("\"{}\"", self.text)),
411                (
412                    "corner1",
413                    fmt_point(self.graphical.location_x, self.graphical.location_y),
414                ),
415                ("corner2", fmt_point(self.corner_x, self.corner_y)),
416            ],
417        );
418    }
419}
420
421impl DumpTree for SchJunction {
422    fn dump(&self, tree: &mut TreeBuilder) {
423        tree.add_leaf(
424            "Junction",
425            &[(
426                "location",
427                fmt_point(self.graphical.location_x, self.graphical.location_y),
428            )],
429        );
430    }
431}
432
433impl DumpTree for SchImage {
434    fn dump(&self, tree: &mut TreeBuilder) {
435        let mut props = vec![
436            (
437                "corner1",
438                fmt_point(self.graphical.location_x, self.graphical.location_y),
439            ),
440            ("corner2", fmt_point(self.corner_x, self.corner_y)),
441        ];
442        if !self.filename.is_empty() {
443            props.push(("file", self.filename.clone()));
444        }
445        props.push(("embedded", fmt_bool(self.embed_image)));
446        tree.add_leaf("Image", &props);
447    }
448}
449
450impl DumpTree for SchSheetHeader {
451    fn dump(&self, tree: &mut TreeBuilder) {
452        tree.add_leaf(
453            "SheetHeader",
454            &[
455                ("fonts", format!("{}", self.font_id_count)),
456                ("sheet_size", format!("{}", self.sheet_size)),
457            ],
458        );
459    }
460}
461
462impl DumpTree for SchParameter {
463    fn dump(&self, tree: &mut TreeBuilder) {
464        tree.add_leaf(
465            "Parameter",
466            &[
467                ("name", self.name.clone()),
468                ("value", format!("\"{}\"", self.label.text)),
469                (
470                    "location",
471                    fmt_point(
472                        self.label.graphical.location_x,
473                        self.label.graphical.location_y,
474                    ),
475                ),
476            ],
477        );
478    }
479}
480
481impl DumpTree for SchWarningSign {
482    fn dump(&self, tree: &mut TreeBuilder) {
483        let mut props = vec![(
484            "location",
485            fmt_point(self.graphical.location_x, self.graphical.location_y),
486        )];
487        if !self.name.is_empty() {
488            props.push(("name", self.name.clone()));
489        }
490        tree.add_leaf("WarningSign", &props);
491    }
492}
493
494impl DumpTree for SchDesignator {
495    fn dump(&self, tree: &mut TreeBuilder) {
496        tree.add_leaf(
497            "Designator",
498            &[
499                ("name", self.param.name.clone()),
500                ("value", format!("\"{}\"", self.param.label.text)),
501                (
502                    "location",
503                    fmt_point(
504                        self.param.label.graphical.location_x,
505                        self.param.label.graphical.location_y,
506                    ),
507                ),
508            ],
509        );
510    }
511}
512
513impl DumpTree for SchImplementationList {
514    fn dump(&self, tree: &mut TreeBuilder) {
515        tree.add_leaf(
516            "ImplementationList",
517            &[("owner_index", format!("{}", self.base.owner_index))],
518        );
519    }
520}
521
522impl DumpTree for SchImplementation {
523    fn dump(&self, tree: &mut TreeBuilder) {
524        let mut props = vec![
525            ("model_name", self.model_name.clone()),
526            ("model_type", self.model_type.clone()),
527        ];
528        if self.is_current {
529            props.push(("current", "yes".to_string()));
530        }
531        tree.add_leaf("Implementation", &props);
532    }
533}
534
535impl DumpTree for SchMapDefinerList {
536    fn dump(&self, tree: &mut TreeBuilder) {
537        tree.add_leaf(
538            "MapDefinerList",
539            &[("owner_index", format!("{}", self.base.owner_index))],
540        );
541    }
542}
543
544impl DumpTree for SchMapDefiner {
545    fn dump(&self, tree: &mut TreeBuilder) {
546        tree.add_leaf(
547            "MapDefiner",
548            &[
549                ("interface", self.designator_interface.clone()),
550                (
551                    "impl_count",
552                    format!("{}", self.designator_implementation.len()),
553                ),
554            ],
555        );
556    }
557}
558
559impl DumpTree for SchImplementationParameters {
560    fn dump(&self, tree: &mut TreeBuilder) {
561        tree.add_leaf(
562            "ImplementationParameters",
563            &[("owner_index", format!("{}", self.base.owner_index))],
564        );
565    }
566}
567
568impl DumpTree for SchBus {
569    fn dump(&self, tree: &mut TreeBuilder) {
570        let vertices = &self.vertices;
571        if vertices.len() == 2 {
572            tree.add_leaf(
573                "Bus",
574                &[
575                    ("start", fmt_point(vertices[0].0, vertices[0].1)),
576                    ("end", fmt_point(vertices[1].0, vertices[1].1)),
577                ],
578            );
579        } else {
580            tree.add_leaf(
581                "Bus",
582                &[("segments", format!("{}", vertices.len().saturating_sub(1)))],
583            );
584        }
585    }
586}
587
588impl DumpTree for SchBusEntry {
589    fn dump(&self, tree: &mut TreeBuilder) {
590        let (bus_x, bus_y) = self.bus_point();
591        let (wire_x, wire_y) = self.wire_point();
592        tree.add_leaf(
593            "BusEntry",
594            &[
595                ("bus_point", fmt_point(bus_x, bus_y)),
596                ("wire_point", fmt_point(wire_x, wire_y)),
597            ],
598        );
599    }
600}
601
602impl DumpTree for SchNoErc {
603    fn dump(&self, tree: &mut TreeBuilder) {
604        let mut props = vec![(
605            "location",
606            fmt_point(self.graphical.location_x, self.graphical.location_y),
607        )];
608        if self.is_active {
609            props.push(("active", "yes".to_string()));
610        }
611        tree.add_leaf("NoERC", &props);
612    }
613}
614
615impl DumpTree for SchRecord {
616    fn dump(&self, tree: &mut TreeBuilder) {
617        match self {
618            SchRecord::Component(r) => r.dump(tree),
619            SchRecord::Pin(r) => r.dump(tree),
620            SchRecord::Symbol(r) => r.dump(tree),
621            SchRecord::Label(r) => r.dump(tree),
622            SchRecord::Bezier(r) => r.dump(tree),
623            SchRecord::Polyline(r) => r.dump(tree),
624            SchRecord::Polygon(r) => r.dump(tree),
625            SchRecord::Ellipse(r) => r.dump(tree),
626            SchRecord::Pie(r) => r.dump(tree),
627            SchRecord::EllipticalArc(r) => r.dump(tree),
628            SchRecord::Arc(r) => r.dump(tree),
629            SchRecord::Line(r) => r.dump(tree),
630            SchRecord::Rectangle(r) => r.dump(tree),
631            SchRecord::PowerObject(r) => r.dump(tree),
632            SchRecord::Port(r) => r.dump(tree),
633            SchRecord::NoErc(r) => r.dump(tree),
634            SchRecord::NetLabel(r) => r.dump(tree),
635            SchRecord::Bus(r) => r.dump(tree),
636            SchRecord::Wire(r) => r.dump(tree),
637            SchRecord::TextFrame(r) => r.dump(tree),
638            SchRecord::TextFrameVariant(r) => r.dump(tree),
639            SchRecord::Junction(r) => r.dump(tree),
640            SchRecord::Image(r) => r.dump(tree),
641            SchRecord::SheetHeader(r) => r.dump(tree),
642            SchRecord::Designator(r) => r.dump(tree),
643            SchRecord::BusEntry(r) => r.dump(tree),
644            SchRecord::Parameter(r) => r.dump(tree),
645            SchRecord::WarningSign(r) => r.dump(tree),
646            SchRecord::ImplementationList(r) => r.dump(tree),
647            SchRecord::Implementation(r) => r.dump(tree),
648            SchRecord::MapDefinerList(r) => r.dump(tree),
649            SchRecord::MapDefiner(r) => r.dump(tree),
650            SchRecord::ImplementationParameters(r) => r.dump(tree),
651            SchRecord::Unknown { record_id, params } => {
652                tree.add_leaf(
653                    "Unknown",
654                    &[
655                        ("record_id", format!("{}", record_id)),
656                        ("params", format!("{} fields", params.len())),
657                    ],
658                );
659            }
660        }
661    }
662}