Skip to content

Commit

Permalink
Make kicad_parser pure of any opencascade types, integrate into the v…
Browse files Browse the repository at this point in the history
…iewer app
  • Loading branch information
bschwind committed Dec 25, 2023
1 parent 0c65c39 commit 45c68a4
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 131 deletions.
4 changes: 1 addition & 3 deletions crates/kicad-parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,5 @@ version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = "1"
thiserror = "1"
sexp = "1.1.4"
opencascade = { version = "0.2", path = "../opencascade" }
glam = { version = "0.23", features = ["bytemuck"] }
56 changes: 23 additions & 33 deletions crates/kicad-parser/src/board.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use anyhow::{anyhow, Context, Result};
use opencascade::primitives::{Edge, EdgeConnection, Face, Wire};
use crate::Error;
use sexp::{Atom, Sexp};
use std::path::Path;

Expand Down Expand Up @@ -115,29 +114,44 @@ pub struct KicadBoard {
}

impl KicadBoard {
pub fn from_file<P: AsRef<Path>>(file: P) -> Result<Self> {
let kicad_board_str = std::fs::read_to_string(&file)
.context(format!("Reading {:?}", file.as_ref().to_string_lossy()))?;
pub fn from_file<P: AsRef<Path>>(file: P) -> Result<Self, Error> {
let kicad_board_str = std::fs::read_to_string(&file)?;
let sexp = sexp::parse(&kicad_board_str)?;

let Sexp::List(list) = sexp else {
return Err(anyhow!("Top level file wasn't a list"));
return Err(Error::TopLevelObjectNotList);
};

let Sexp::Atom(Atom::S(head)) = &list[0] else {
return Err(anyhow!("First element in the top level list should be a string"));
return Err(Error::FirstElementInListNotString);
};

match head.as_str() {
"kicad_pcb" => {
let board_fields = &list[1..];
Ok(Self::handle_board_fields(board_fields)?)
},
_ => Err(anyhow!("Invalid top-level file type - expected 'kicad_pcb'")),
_ => Err(Error::NotKicadPcbFile),
}
}

fn handle_board_fields(fields: &[Sexp]) -> Result<Self> {
pub fn lines(&self) -> impl Iterator<Item = &GraphicLine> {
self.graphic_lines.iter()
}

pub fn arcs(&self) -> impl Iterator<Item = &GraphicArc> {
self.graphic_arcs.iter()
}

pub fn circles(&self) -> impl Iterator<Item = &GraphicCircle> {
self.graphic_circles.iter()
}

pub fn rects(&self) -> impl Iterator<Item = &GraphicRect> {
self.graphic_rects.iter()
}

fn handle_board_fields(fields: &[Sexp]) -> Result<Self, Error> {
let mut board = Self::default();

for field in fields {
Expand Down Expand Up @@ -180,28 +194,4 @@ impl KicadBoard {

Ok(board)
}

pub fn layer_edges(&self, layer: BoardLayer) -> Vec<Edge> {
self.graphic_lines
.iter()
.filter(|line| line.layer() == layer)
.map(Into::<Edge>::into)
.chain(
self.graphic_arcs.iter().filter(|arc| arc.layer() == layer).map(Into::<Edge>::into),
)
.collect()
}

pub fn layer_wire(&self, layer: BoardLayer) -> Wire {
Wire::from_unordered_edges(&self.layer_edges(layer), EdgeConnection::default())
}

pub fn layer_face(&self, layer: BoardLayer) -> Face {
Face::from_wire(&self.layer_wire(layer))
}

pub fn outline(&self, _offset: f64) -> Face {
// TODO apply offset around the face
self.layer_face(BoardLayer::EdgeCuts)
}
}
89 changes: 22 additions & 67 deletions crates/kicad-parser/src/graphics.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
use anyhow::{anyhow, Result};
use glam::{dvec3, DVec3};
use opencascade::{
primitives::{Edge, Face},
workplane::Workplane,
};
use crate::Error;
use sexp::{Atom, Sexp};

use crate::board::BoardLayer;
Expand All @@ -16,7 +11,7 @@ pub struct GraphicLine {
}

impl GraphicLine {
pub fn from_list(list: &[Sexp]) -> Result<Self> {
pub fn from_list(list: &[Sexp]) -> Result<Self, Error> {
let mut line = Self::default();

for field in list {
Expand Down Expand Up @@ -51,25 +46,19 @@ impl GraphicLine {
Ok(line)
}

pub fn start_point(&self) -> DVec3 {
dvec3(self.start.0, self.start.1, 0.0)
pub fn start_point(&self) -> (f64, f64) {
self.start
}

pub fn end_point(&self) -> DVec3 {
dvec3(self.end.0, self.end.1, 0.0)
pub fn end_point(&self) -> (f64, f64) {
self.end
}

pub fn layer(&self) -> BoardLayer {
BoardLayer::from(self.layer.as_str())
}
}

impl Into<Edge> for &GraphicLine {
fn into(self) -> Edge {
Edge::segment(self.start_point(), self.end_point())
}
}

#[derive(Debug, Clone, Default, PartialEq)]
pub struct GraphicArc {
start: (f64, f64),
Expand All @@ -79,7 +68,7 @@ pub struct GraphicArc {
}

impl GraphicArc {
pub fn from_list(list: &[Sexp]) -> Result<Self> {
pub fn from_list(list: &[Sexp]) -> Result<Self, Error> {
let mut line = Self::default();

for field in list {
Expand Down Expand Up @@ -118,29 +107,23 @@ impl GraphicArc {
Ok(line)
}

pub fn start_point(&self) -> DVec3 {
dvec3(self.start.0, self.start.1, 0.0)
pub fn start_point(&self) -> (f64, f64) {
self.start
}

pub fn mid_point(&self) -> DVec3 {
dvec3(self.mid.0, self.mid.1, 0.0)
pub fn mid_point(&self) -> (f64, f64) {
self.mid
}

pub fn end_point(&self) -> DVec3 {
dvec3(self.end.0, self.end.1, 0.0)
pub fn end_point(&self) -> (f64, f64) {
self.end
}

pub fn layer(&self) -> BoardLayer {
BoardLayer::from(self.layer.as_str())
}
}

impl Into<Edge> for &GraphicArc {
fn into(self) -> Edge {
Edge::arc(self.start_point(), self.mid_point(), self.end_point())
}
}

#[derive(Debug, Clone, Default, PartialEq)]
pub struct GraphicCircle {
center: (f64, f64),
Expand All @@ -149,7 +132,7 @@ pub struct GraphicCircle {
}

impl GraphicCircle {
pub fn from_list(list: &[Sexp]) -> Result<Self> {
pub fn from_list(list: &[Sexp]) -> Result<Self, Error> {
let mut line = Self::default();

for field in list {
Expand Down Expand Up @@ -184,31 +167,19 @@ impl GraphicCircle {
Ok(line)
}

pub fn center_point(&self) -> DVec3 {
dvec3(self.center.0, self.center.1, 0.0)
pub fn center_point(&self) -> (f64, f64) {
self.center
}

pub fn end_point(&self) -> DVec3 {
dvec3(self.end.0, self.end.1, 0.0)
pub fn end_point(&self) -> (f64, f64) {
self.end
}

pub fn layer(&self) -> BoardLayer {
BoardLayer::from(self.layer.as_str())
}
}

impl Into<Face> for &GraphicCircle {
fn into(self) -> Face {
let delta_x = (self.center.0 - self.end.0).abs();
let delta_y = (self.center.1 - self.end.1).abs();
let radius = (delta_x * delta_x + delta_y * delta_y).sqrt();
Workplane::xy()
.translated(self.center_point())
.circle(self.center.0, self.center.1, radius)
.to_face()
}
}

#[derive(Debug, Clone, Default, PartialEq)]
pub struct GraphicRect {
start: (f64, f64),
Expand All @@ -217,7 +188,7 @@ pub struct GraphicRect {
}

impl GraphicRect {
pub fn from_list(list: &[Sexp]) -> Result<Self> {
pub fn from_list(list: &[Sexp]) -> Result<Self, Error> {
let mut line = Self::default();

for field in list {
Expand Down Expand Up @@ -252,35 +223,19 @@ impl GraphicRect {
Ok(line)
}

pub fn start_point(&self) -> DVec3 {
dvec3(self.start.0, self.start.1, 0.0)
}

pub fn end_point(&self) -> DVec3 {
dvec3(self.end.0, self.end.1, 0.0)
}

pub fn layer(&self) -> BoardLayer {
BoardLayer::from(self.layer.as_str())
}
}

impl Into<Face> for &GraphicRect {
fn into(self) -> Face {
let height = (self.end.1 - self.start.1).abs();
let width = (self.end.0 - self.start.0).abs();
Workplane::xy().translated(self.start_point()).rect(height, width).to_face()
}
}

fn extract_coords(x: &Sexp, y: &Sexp) -> Result<(f64, f64)> {
fn extract_coords(x: &Sexp, y: &Sexp) -> Result<(f64, f64), Error> {
Ok((extract_number(x)?, extract_number(y)?))
}

fn extract_number(num: &Sexp) -> Result<f64> {
fn extract_number(num: &Sexp) -> Result<f64, Error> {
match num {
Sexp::Atom(Atom::F(float)) => Ok(*float),
Sexp::Atom(Atom::I(int)) => Ok(*int as f64),
_ => Err(anyhow!("Expected a number to be a float or integer")),
_ => Err(Error::NumberShouldBeFloatOrInt),
}
}
23 changes: 0 additions & 23 deletions crates/kicad-parser/src/main.rs

This file was deleted.

1 change: 1 addition & 0 deletions crates/opencascade/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ repository = "https://github.com/bschwind/opencascade-rs"
cxx = "1"
opencascade-sys = { version = "0.2", path = "../opencascade-sys" }
glam = { version = "0.24", features = ["bytemuck"] }
kicad-parser = { path = "../kicad-parser" }
thiserror = "1"

[features]
Expand Down
Loading

0 comments on commit 45c68a4

Please sign in to comment.