pub mod board;
pub mod error;
pub mod excellon_format;
pub mod gerber;
pub mod gerber_ascii;
pub mod layer;
pub mod unit_able;
pub use gerber_parser;
pub use gerber_parser::gerber_types;
use crate::layer::{LayerData, LayerType};
use derive_more::Display;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub type Result<T> = std::result::Result<T, error::Error>;
pub trait LayerCorners {
fn get_corners(&self) -> (Pos, Pos);
fn get_size(&self) -> Size {
let (min, max) = self.get_corners();
let width = max.x - min.x;
let height = max.y - min.y;
Size { width, height }
}
}
pub trait LayerTransform {
fn transform(&mut self, transform: &Pos);
}
pub trait LayerScale {
fn scale(&mut self, x: f64, y: f64);
}
pub trait LayerMerge: Sized {
fn merge(&mut self, other: &Self);
fn merge_from(&mut self, other: impl Into<Self>) {
self.merge(&other.into());
}
}
pub trait LayerRotate {
fn rotate(&mut self, steps: i32);
fn rebase(&mut self, steps: i32, offset: &Pos);
}
pub(crate) fn rotate_90(x: f64, y: f64, steps: i32) -> (f64, f64) {
match steps.rem_euclid(4) {
1 => (y, -x),
2 => (-x, -y),
3 => (-y, x),
_ => (x, y),
}
}
pub trait LayerStepAndRepeat {
fn step_and_repeat(&mut self, x_repetitions: u32, y_repetitions: u32, offset: &Pos);
}
#[derive(Debug, Clone, PartialEq, Display, Default)]
#[display("x: {x:.3}, y: {y:.3}")]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Pos {
pub x: f64,
pub y: f64,
}
#[derive(Debug, Clone, PartialEq, Display, Default)]
#[display("width: {width:.3}, height: {height:.3}")]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Size {
pub width: f64,
pub height: f64,
}
#[macro_export]
macro_rules! load_layer_data {
($file:expr $(,)?) => {{
let data = include_str!($file);
let reader = std::io::BufReader::new(std::io::Cursor::new(data));
let ty = LayerType::try_from($file.to_string().rsplitn(2, ".").next().unwrap()).unwrap();
LayerData::parse(ty, reader).unwrap()
}};
}
#[macro_export]
macro_rules! load_board_data {
($path:expr, $(($name:literal, $ty:expr)),* $(,)?) => {{
let mut board = Board::empty();
$(
board.add_layer(Layer {
ty: $ty,
name: $name.to_string(),
data: load_layer_data!(concat!($path, $name)).1
});
)*
board
}};
}
#[cfg(test)]
mod tests {
use super::*;
use crate::board::Board;
use std::fs;
use std::path::Path;
#[test]
fn it_works() {
let folders = ["mobo"];
if Path::new("output").exists() {
fs::remove_dir_all("output").unwrap();
}
for folder in folders {
let in_path = Path::new("test").join(folder);
let out_path = Path::new("output").join(folder);
fs::create_dir_all(&out_path).unwrap();
println!("Processing folder: {:?}", in_path);
let result = Board::from_folder(&in_path).unwrap();
for (name, err) in &result.errors {
println!("Warning: failed to load '{}': {}", name, err);
}
let mut board = result.board;
let (min, max) = board.get_corners();
println!(
"Transformed Corners: ({}, {}) - ({}, {})",
min.x, min.y, max.x, max.y
);
let size = board.get_size();
board.transform(&Pos {
x: 100.0,
y: -100.0,
});
board.transform(&Pos {
x: -100.0,
y: 100.0,
});
let mut copy = board.clone();
copy.transform(&Pos {
y: size.height + 5.0,
x: 0.0,
});
board.merge(©);
board.write_to_folder(&out_path).unwrap();
}
}
}