use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PcbDesign {
pub uuid: String,
pub filename: String,
pub version: Option<String>,
pub general: PcbGeneral,
pub layers: Vec<PcbLayer>,
pub setup: PcbSetup,
pub nets: Vec<PcbNet>,
pub footprints: Vec<Footprint>,
pub traces: Vec<Trace>,
pub vias: Vec<Via>,
pub zones: Vec<Zone>,
pub graphics: Vec<GraphicItem>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PcbGeneral {
pub thickness: f64, pub drawings: u32,
pub tracks: u32,
pub zones: u32,
pub modules: u32,
pub nets: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PcbLayer {
pub ordinal: u32, pub canonical_name: String, pub layer_type: LayerType,
pub user_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum LayerType {
Signal, Power, Mixed, Jumper, User, Unknown,
}
impl Default for LayerType {
fn default() -> Self {
LayerType::Signal
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PcbSetup {
pub trace_min: f64, pub via_size: f64, pub via_drill: f64, pub via_min_size: f64, pub via_min_drill: f64, pub copper_thickness: CopperThickness,
pub clearance: f64, pub track_width: f64, }
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct CopperThickness {
pub outer: f64, pub inner: f64, }
impl CopperThickness {
pub fn outer_mm(&self) -> f64 {
self.outer * 0.035
}
pub fn inner_mm(&self) -> f64 {
self.inner * 0.035
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PcbNet {
pub id: u32,
pub name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Footprint {
pub uuid: String,
pub reference: String,
pub value: String,
pub footprint_lib: String,
pub layer: String,
pub position: Position3D,
pub rotation: f64,
pub pads: Vec<Pad>,
pub properties: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
pub struct Position3D {
pub x: f64,
pub y: f64,
pub z: f64,
}
impl Position3D {
pub fn new(x: f64, y: f64) -> Self {
Self { x, y, z: 0.0 }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Pad {
pub number: String,
pub pad_type: PadType,
pub shape: PadShape,
pub position: Position3D,
pub size: Size2D,
pub drill: Option<DrillInfo>,
pub layers: Vec<String>,
pub net: Option<u32>,
pub net_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum PadType {
ThruHole,
SMD,
Connect,
NPThruHole, }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum PadShape {
Circle,
Rect,
Oval,
Trapezoid,
RoundRect,
Custom,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Size2D {
pub width: f64,
pub height: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DrillInfo {
pub diameter: f64,
pub offset: Option<Position3D>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Trace {
pub uuid: String,
pub start: Position3D,
pub end: Position3D,
pub width: f64, pub layer: String, pub net: u32, pub net_name: Option<String>, pub locked: bool,
}
impl Trace {
pub fn length(&self) -> f64 {
let dx = self.end.x - self.start.x;
let dy = self.end.y - self.start.y;
(dx * dx + dy * dy).sqrt()
}
pub fn cross_section_area(&self, copper_thickness_mm: f64) -> f64 {
self.width * copper_thickness_mm
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Via {
pub uuid: String,
pub position: Position3D,
pub size: f64, pub drill: f64, pub layers: (String, String), pub net: u32,
pub net_name: Option<String>,
pub via_type: ViaType,
pub locked: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ViaType {
Through,
Blind,
Buried,
Micro,
}
impl Default for ViaType {
fn default() -> Self {
ViaType::Through
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Zone {
pub uuid: String,
pub net: u32,
pub net_name: String,
pub layer: String,
pub priority: u32,
pub connect_pads: ZoneConnectType,
pub min_thickness: f64,
pub filled: bool,
pub outline: Vec<Position3D>, pub filled_polygons: Vec<FilledPolygon>,
pub keepout: Option<ZoneKeepout>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum ZoneConnectType {
Solid,
ThermalRelief,
None,
}
impl Default for ZoneConnectType {
fn default() -> Self {
ZoneConnectType::ThermalRelief
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FilledPolygon {
pub layer: String,
pub points: Vec<Position3D>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ZoneKeepout {
pub tracks: bool,
pub vias: bool,
pub pads: bool,
pub copperpour: bool,
pub footprints: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphicItem {
pub item_type: GraphicType,
pub layer: String,
pub start: Position3D,
pub end: Option<Position3D>,
pub width: f64,
pub fill: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum GraphicType {
Line,
Arc,
Circle,
Rect,
Polygon,
Text,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TraceSegmentAnalysis {
pub trace: Trace,
pub copper_thickness_mm: f64,
pub is_outer_layer: bool,
pub length_mm: f64,
pub cross_section_mm2: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum NetClassification {
HighSpeed, Clock, Power, Ground, Analog, Digital, Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LayerStack {
pub layers: Vec<LayerStackEntry>,
pub total_thickness_mm: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LayerStackEntry {
pub name: String,
pub layer_type: LayerType,
pub thickness_mm: f64,
pub material: String,
}
impl Default for PcbDesign {
fn default() -> Self {
Self {
uuid: String::new(),
filename: String::new(),
version: None,
general: PcbGeneral::default(),
layers: Vec::new(),
setup: PcbSetup::default(),
nets: Vec::new(),
footprints: Vec::new(),
traces: Vec::new(),
vias: Vec::new(),
zones: Vec::new(),
graphics: Vec::new(),
}
}
}