1pub mod board;
2pub mod error;
3pub mod excellon_format;
4pub mod gerber;
5pub mod gerber_ascii;
6pub mod layer;
7pub mod unit_able;
8
9pub use gerber_parser;
10pub use gerber_parser::gerber_types;
11
12use crate::layer::{LayerData, LayerType};
13use derive_more::Display;
14
15#[cfg(feature = "serde")]
16use serde::{Deserialize, Serialize};
17
18pub type Result<T> = std::result::Result<T, error::Error>;
19
20pub trait LayerCorners {
21
22 fn get_size(&self) -> Size {
24 let (min, max) = self.get_corners();
25 let width = max.x - min.x;
26 let height = max.y - min.y;
27 Size { width, height }
28 }
29
30 fn get_corners(&self) -> (Pos, Pos);
32}
33
34pub trait LayerTransform {
35
36 fn transform(&mut self, transform: &Pos);
38}
39
40pub trait LayerScale {
41
42 fn scale(&mut self, x: f64, y: f64);
44}
45
46pub trait LayerMerge {
47
48 fn merge(&mut self, other: &Self);
50}
51
52pub trait LayerStepAndRepeat {
53
54 fn step_and_repeat(&mut self, x_repetitions: u32, y_repetitions: u32, offset: &Pos);
56}
57
58#[derive(Debug, Clone, PartialEq, Display)]
60#[display("x: {x:.2}, y: {y:.2}")]
61#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
62pub struct Pos {
63 pub x: f64,
64 pub y: f64,
65}
66
67#[derive(Debug, Clone, PartialEq, Display)]
69#[display("width: {width:.2}, height: {height:.2}")]
70#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
71pub struct Size {
72 pub width: f64,
73 pub height: f64,
74}
75
76#[macro_export]
80macro_rules! load_layer_data {
81 ($file:expr $(,)?) => {{
82 let data = include_str!($file);
83 let reader = std::io::BufReader::new(std::io::Cursor::new(data));
84 let ty = LayerType::try_from($file.to_string().rsplitn(2, ".").next().unwrap()).unwrap();
85 LayerData::parse(ty, reader).unwrap()
86 }};
87}
88
89#[macro_export]
93macro_rules! load_board_data {
94 ($path:expr, $(($name:literal, $ty:expr)),* $(,)?) => {{
95 let mut board = Board::empty();
96 $(
97 board.add_layer(Layer {
98 ty: $ty,
99 name: $name.to_string(),
100 data: load_layer_data!(concat!($path, $name)).1
101 });
102 )*
103 board
104 }};
105}
106
107#[cfg(test)]
108mod tests {
109 use std::fs;
110 use std::path::Path;
111 use crate::board::Board;
112 use super::*;
113
114 #[test]
115 fn it_works() {
116 let folders = ["mobo"];
117 if Path::new("output").exists() {
118 fs::remove_dir_all("output").unwrap();
119 }
120 for folder in folders {
121 let in_path = Path::new("test").join(folder);
122 let out_path = Path::new("output").join(folder);
123 fs::create_dir_all(&out_path).unwrap();
124 println!("Processing folder: {:?}", in_path);
125 let mut board = Board::from_folder(&in_path).unwrap();
126
127 let (min, max) = board.get_corners();
128 println!(
129 "Transformed Corners: ({}, {}) - ({}, {})",
130 min.x, min.y, max.x, max.y
131 );
132
133 let size = board.get_size();
134
135 board.transform(&Pos {
136 x: 100.0,
137 y: -100.0,
138 });
139
140 board.transform(&Pos {
141 x: -100.0,
142 y: 100.0,
143 });
144
145 let mut copy = board.clone();
146 copy.transform(&Pos {
147 y: size.height + 5.0,
148 x: 0.0,
149 });
150 board.merge(©);
151
152 board.write_to_folder(&out_path).unwrap();
153 }
154 }
155}