altium_format/ops/
util.rs1use crate::io::SchDoc;
7use crate::records::sch::SchRecord;
8use crate::tree::{RecordId, RecordTree};
9use std::collections::HashMap;
10
11pub fn alphanumeric_sort(a: &str, b: &str) -> std::cmp::Ordering {
16 let extract_num = |s: &str| -> (String, i32) {
17 let mut prefix = String::new();
18 let mut num_str = String::new();
19
20 for c in s.chars() {
21 if c.is_ascii_digit() {
22 num_str.push(c);
23 } else if num_str.is_empty() {
24 prefix.push(c);
25 }
26 }
27
28 let num = num_str.parse().unwrap_or(0);
29 (prefix, num)
30 };
31
32 let (prefix_a, num_a) = extract_num(a);
33 let (prefix_b, num_b) = extract_num(b);
34
35 match prefix_a.cmp(&prefix_b) {
36 std::cmp::Ordering::Equal => num_a.cmp(&num_b),
37 other => other,
38 }
39}
40
41pub fn record_type_name(record: &SchRecord) -> &'static str {
43 match record {
44 SchRecord::Component(_) => "Component",
45 SchRecord::Pin(_) => "Pin",
46 SchRecord::Symbol(_) => "Symbol",
47 SchRecord::Label(_) => "Label",
48 SchRecord::Bezier(_) => "Bezier",
49 SchRecord::Polyline(_) => "Polyline",
50 SchRecord::Polygon(_) => "Polygon",
51 SchRecord::Ellipse(_) => "Ellipse",
52 SchRecord::Pie(_) => "Pie",
53 SchRecord::EllipticalArc(_) => "EllipticalArc",
54 SchRecord::Arc(_) => "Arc",
55 SchRecord::Line(_) => "Line",
56 SchRecord::Rectangle(_) => "Rectangle",
57 SchRecord::PowerObject(_) => "PowerObject",
58 SchRecord::Port(_) => "Port",
59 SchRecord::NoErc(_) => "NoERC",
60 SchRecord::NetLabel(_) => "NetLabel",
61 SchRecord::Bus(_) => "Bus",
62 SchRecord::Wire(_) => "Wire",
63 SchRecord::TextFrame(_) => "TextFrame",
64 SchRecord::TextFrameVariant(_) => "TextFrameVariant",
65 SchRecord::Junction(_) => "Junction",
66 SchRecord::Image(_) => "Image",
67 SchRecord::SheetHeader(_) => "SheetHeader",
68 SchRecord::Designator(_) => "Designator",
69 SchRecord::BusEntry(_) => "BusEntry",
70 SchRecord::Parameter(_) => "Parameter",
71 SchRecord::WarningSign(_) => "WarningSign",
72 SchRecord::ImplementationList(_) => "ImplementationList",
73 SchRecord::Implementation(_) => "Implementation",
74 SchRecord::MapDefinerList(_) => "MapDefinerList",
75 SchRecord::MapDefiner(_) => "MapDefiner",
76 SchRecord::ImplementationParameters(_) => "ImplementationParameters",
77 SchRecord::Unknown { .. } => "Unknown",
78 }
79}
80
81pub fn count_record_types(doc: &SchDoc) -> HashMap<&'static str, usize> {
83 let mut counts: HashMap<&'static str, usize> = HashMap::new();
84 for record in &doc.primitives {
85 let name = record_type_name(record);
86 *counts.entry(name).or_insert(0) += 1;
87 }
88 counts
89}
90
91pub fn sheet_size_name(style: i32) -> &'static str {
93 match style {
94 0 => "A4",
95 1 => "A3",
96 2 => "A2",
97 3 => "A1",
98 4 => "A0",
99 5 => "A",
100 6 => "B",
101 7 => "C",
102 8 => "D",
103 9 => "E",
104 10 => "Letter",
105 11 => "Legal",
106 12 => "Tabloid",
107 13 => "OrCAD A",
108 14 => "OrCAD B",
109 15 => "OrCAD C",
110 16 => "OrCAD D",
111 17 => "OrCAD E",
112 _ => "Custom",
113 }
114}
115
116pub fn get_component_designator(
118 tree: &RecordTree<SchRecord>,
119 component_id: RecordId,
120) -> Option<String> {
121 for (_child_id, child) in tree.children(component_id) {
122 if let SchRecord::Designator(d) = child {
123 return Some(d.param.label.text.clone());
124 }
125 }
126 None
127}
128
129pub fn get_component_pins(
131 tree: &RecordTree<SchRecord>,
132 comp_id: RecordId,
133) -> Vec<(String, String, i32, i32)> {
134 let mut pins = Vec::new();
135 for (_, child) in tree.children(comp_id) {
136 if let SchRecord::Pin(p) = child {
137 let (corner_x, corner_y) = p.get_corner();
138 pins.push((p.designator.clone(), p.name.clone(), corner_x, corner_y));
139 }
140 }
141 pins
142}