Skip to main content

altium_format/records/sch/
wire.rs

1//! SchWire - Schematic wire (Record 27).
2
3use crate::error::Result;
4use crate::traits::{FromParams, ToParams};
5use crate::types::{Coord, CoordRect, ParameterCollection, UnknownFields};
6use altium_format_derive::AltiumRecord;
7
8use super::{LineStyle, LineWidth, SchGraphicalBase, SchPrimitive};
9
10/// Schematic wire primitive.
11/// Wires are the electrical connections in a schematic.
12#[derive(Debug, Clone, Default, AltiumRecord)]
13#[altium(record_id = 27, format = "params")]
14pub struct SchWire {
15    /// Graphical base (location, color).
16    #[altium(flatten)]
17    pub graphical: SchGraphicalBase,
18
19    /// Line width.
20    #[altium(param = "LINEWIDTH", default)]
21    pub line_width: LineWidth,
22
23    /// Line style.
24    #[altium(param = "LINESTYLE", default)]
25    pub line_style: LineStyle,
26
27    /// Wire points as (x, y) raw coord pairs.
28    #[altium(
29        indexed_coords,
30        prefix_x = "X",
31        prefix_y = "Y",
32        count = "LOCATIONCOUNT"
33    )]
34    pub vertices: Vec<(i32, i32)>,
35
36    /// Unknown parameters (preserved for non-destructive editing).
37    #[altium(unknown)]
38    pub unknown_params: UnknownFields,
39}
40
41// Provide polyline field for compatibility with existing code
42impl SchWire {
43    /// Get a polyline-like view for compatibility.
44    pub fn polyline(&self) -> WirePolylineView<'_> {
45        WirePolylineView { wire: self }
46    }
47}
48
49/// View into wire's polyline-like data.
50pub struct WirePolylineView<'a> {
51    wire: &'a SchWire,
52}
53
54impl<'a> WirePolylineView<'a> {
55    pub fn polygon(&self) -> WirePolygonView<'a> {
56        WirePolygonView { wire: self.wire }
57    }
58}
59
60/// View into wire's polygon-like data.
61pub struct WirePolygonView<'a> {
62    wire: &'a SchWire,
63}
64
65impl<'a> WirePolygonView<'a> {
66    pub fn vertices(&self) -> &[(i32, i32)] {
67        &self.wire.vertices
68    }
69
70    pub fn graphical(&self) -> &SchGraphicalBase {
71        &self.wire.graphical
72    }
73}
74
75impl SchPrimitive for SchWire {
76    const RECORD_ID: i32 = 27;
77
78    fn location(&self) -> Option<crate::types::CoordPoint> {
79        Some(crate::types::CoordPoint::from_raw(
80            self.graphical.location_x,
81            self.graphical.location_y,
82        ))
83    }
84
85    fn record_type_name(&self) -> &'static str {
86        "Wire"
87    }
88
89    fn import_from_params(params: &ParameterCollection) -> Result<Self> {
90        Self::from_params(params)
91    }
92
93    fn export_to_params(&self) -> ParameterCollection {
94        self.to_params()
95    }
96
97    fn owner_index(&self) -> i32 {
98        self.graphical.base.owner_index
99    }
100
101    fn calculate_bounds(&self) -> CoordRect {
102        let Some(&(first_x, first_y)) = self.vertices.first() else {
103            return CoordRect::empty();
104        };
105
106        let (min_x, max_x, min_y, max_y) = self.vertices.iter().skip(1).fold(
107            (first_x, first_x, first_y, first_y),
108            |(min_x, max_x, min_y, max_y), &(x, y)| {
109                (min_x.min(x), max_x.max(x), min_y.min(y), max_y.max(y))
110            },
111        );
112
113        CoordRect::from_points(
114            Coord::from_raw(min_x),
115            Coord::from_raw(min_y),
116            Coord::from_raw(max_x),
117            Coord::from_raw(max_y),
118        )
119    }
120}