Use EPSILON for feedrate comparison, simplify program appending w/ impl AddAssign, don't turn on tool after path (for laser / others sake)

master
Sameer Puri 6 years ago
parent d82eb8f22b
commit c383a3f2e1

@ -1,4 +1,5 @@
use std::io::{self, Write}; use std::io::{self, Write};
use std::ops::AddAssign;
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]
pub enum Direction { pub enum Direction {
@ -18,7 +19,34 @@ pub enum Distance {
Incremental, Incremental,
} }
pub type Program = Vec<GCode>; #[derive(Default, PartialEq, Clone)]
pub struct Program(Vec<GCode>);
impl std::ops::Deref for Program {
type Target = [GCode];
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
impl AddAssign for Program {
fn add_assign(&mut self, mut other: Program) {
self.0.extend(other.0.drain(..));
}
}
impl From<Vec<GCode>> for Program {
fn from(v: Vec<GCode>) -> Self {
Self(v)
}
}
impl Program {
pub fn push(&mut self, g: GCode) {
self.0.push(g)
}
}
macro_rules! write_if_some { macro_rules! write_if_some {
($w:expr, $s:expr, $v:ident) => { ($w:expr, $s:expr, $v:ident) => {
@ -59,7 +87,7 @@ pub enum GCode {
pub fn program2gcode<W: Write>(p: &Program, mut w: W) -> io::Result<()> { pub fn program2gcode<W: Write>(p: &Program, mut w: W) -> io::Result<()> {
use GCode::*; use GCode::*;
let mut last_feedrate = None; let mut last_feedrate: Option<f64> = None;
for code in p.iter() { for code in p.iter() {
match code { match code {
RapidPositioning { x, y } => { RapidPositioning { x, y } => {
@ -84,15 +112,15 @@ pub fn program2gcode<W: Write>(p: &Program, mut w: W) -> io::Result<()> {
)) ))
} }
(Some(last), Some(new)) => { (Some(last), Some(new)) => {
if last != new { if (last - *new).abs() < std::f64::EPSILON {
last_feedrate = Some(new); last_feedrate = Some(*new);
Some(new) Some(new)
} else { } else {
None None
} }
} }
(None, Some(new)) => { (None, Some(new)) => {
last_feedrate = Some(new); last_feedrate = Some(*new);
Some(new) Some(new)
} }
(Some(_), None) => None, (Some(_), None) => None,

@ -4,8 +4,8 @@ use crate::code::*;
pub struct Machine { pub struct Machine {
tool_state: Option<Tool>, tool_state: Option<Tool>,
distance_mode: Option<Distance>, distance_mode: Option<Distance>,
pub tool_on_action: Program, pub tool_on_action: Vec<GCode>,
pub tool_off_action: Program, pub tool_off_action: Vec<GCode>,
} }
impl Default for Machine { impl Default for Machine {
@ -20,7 +20,7 @@ impl Default for Machine {
} }
impl Machine { impl Machine {
pub fn tool_on(&mut self) -> Program { pub fn tool_on(&mut self) -> Vec<GCode> {
if self.tool_state == Some(Tool::Off) || self.tool_state == None { if self.tool_state == Some(Tool::Off) || self.tool_state == None {
self.tool_state = Some(Tool::On); self.tool_state = Some(Tool::On);
self.tool_on_action.clone() self.tool_on_action.clone()
@ -29,7 +29,7 @@ impl Machine {
} }
} }
pub fn tool_off(&mut self) -> Program { pub fn tool_off(&mut self) -> Vec<GCode> {
if self.tool_state == Some(Tool::On) || self.tool_state == None { if self.tool_state == Some(Tool::On) || self.tool_state == None {
self.tool_state = Some(Tool::Off); self.tool_state = Some(Tool::Off);
self.tool_off_action.clone() self.tool_off_action.clone()
@ -38,7 +38,7 @@ impl Machine {
} }
} }
pub fn distance(&mut self, is_absolute: bool) -> Program { pub fn distance(&mut self, is_absolute: bool) -> Vec<GCode> {
if is_absolute { if is_absolute {
self.absolute() self.absolute()
} else { } else {
@ -46,7 +46,7 @@ impl Machine {
} }
} }
pub fn absolute(&mut self) -> Program { pub fn absolute(&mut self) -> Vec<GCode> {
if self.distance_mode == Some(Distance::Incremental) || self.distance_mode == None { if self.distance_mode == Some(Distance::Incremental) || self.distance_mode == None {
self.distance_mode = Some(Distance::Absolute); self.distance_mode = Some(Distance::Absolute);
vec![GCode::DistanceMode(Distance::Absolute)] vec![GCode::DistanceMode(Distance::Absolute)]
@ -55,7 +55,7 @@ impl Machine {
} }
} }
pub fn incremental(&mut self) -> Program { pub fn incremental(&mut self) -> Vec<GCode> {
if self.distance_mode == Some(Distance::Absolute) || self.distance_mode == None { if self.distance_mode == Some(Distance::Absolute) || self.distance_mode == None {
self.distance_mode = Some(Distance::Incremental); self.distance_mode = Some(Distance::Incremental);
vec![GCode::DistanceMode(Distance::Incremental)] vec![GCode::DistanceMode(Distance::Incremental)]

@ -108,14 +108,13 @@ impl Default for ProgramOptions {
} }
fn svg2program(doc: &svgdom::Document, opts: ProgramOptions, mach: Machine) -> Program { fn svg2program(doc: &svgdom::Document, opts: ProgramOptions, mach: Machine) -> Program {
let mut p = Program::new(); let mut p = Program::default();
let mut t = Turtle::default(); let mut t = Turtle::default();
t.mach = mach; t.mach = mach;
p.push(GCode::UnitsMillimeters); p.push(GCode::UnitsMillimeters);
p.extend(t.mach.tool_off()); p += t.mach.tool_off().into();
p.extend(t.move_to(true, 0.0, 0.0)); p += t.move_to(true, 0.0, 0.0).into();
p.extend(t.mach.tool_on());
for edge in doc.root().traverse() { for edge in doc.root().traverse() {
let (node, is_start) = match edge { let (node, is_start) = match edge {
@ -147,8 +146,10 @@ fn svg2program(doc: &svgdom::Document, opts: ProgramOptions, mach: Machine) -> P
); );
} }
} }
if let (ElementId::G, true) = (id, is_start) { if let ElementId::G = id {
p.push(GCode::Named(Box::new(node.id().to_string()))); if is_start {
p.push(GCode::Named(Box::new(node.id().to_string())));
}
} }
if let Some(&AttributeValue::Transform(ref trans)) = attrs.get_value(AttributeId::Transform) if let Some(&AttributeValue::Transform(ref trans)) = attrs.get_value(AttributeId::Transform)
{ {
@ -167,22 +168,20 @@ fn svg2program(doc: &svgdom::Document, opts: ProgramOptions, mach: Machine) -> P
p.push(GCode::Named(Box::new(node.id().to_string()))); p.push(GCode::Named(Box::new(node.id().to_string())));
t.reset(); t.reset();
for segment in path.iter() { for segment in path.iter() {
match segment { let segment_gcode = match segment {
PathSegment::MoveTo { abs, x, y } => { PathSegment::MoveTo { abs, x, y } => t.move_to(*abs, *x, *y),
p.extend(t.move_to(*abs, *x, *y))
}
PathSegment::ClosePath { abs } => { PathSegment::ClosePath { abs } => {
// Ignore abs, should have identical effect: https://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand // Ignore abs, should have identical effect: https://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand
p.extend(t.close(None, opts.feedrate)) t.close(None, opts.feedrate)
} }
PathSegment::LineTo { abs, x, y } => { PathSegment::LineTo { abs, x, y } => {
p.extend(t.line(*abs, *x, *y, None, opts.feedrate)); t.line(*abs, *x, *y, None, opts.feedrate)
} }
PathSegment::HorizontalLineTo { abs, x } => { PathSegment::HorizontalLineTo { abs, x } => {
p.extend(t.line(*abs, *x, None, None, opts.feedrate)); t.line(*abs, *x, None, None, opts.feedrate)
} }
PathSegment::VerticalLineTo { abs, y } => { PathSegment::VerticalLineTo { abs, y } => {
p.extend(t.line(*abs, None, *y, None, opts.feedrate)); t.line(*abs, None, *y, None, opts.feedrate)
} }
PathSegment::CurveTo { PathSegment::CurveTo {
abs, abs,
@ -192,22 +191,20 @@ fn svg2program(doc: &svgdom::Document, opts: ProgramOptions, mach: Machine) -> P
y2, y2,
x, x,
y, y,
} => { } => t.cubic_bezier(
p.extend(t.cubic_bezier( *abs,
*abs, *x1,
*x1, *y1,
*y1, *x2,
*x2, *y2,
*y2, *x,
*x, *y,
*y, opts.tolerance,
opts.tolerance, None,
None, opts.feedrate,
opts.feedrate, ),
)); PathSegment::SmoothCurveTo { abs, x2, y2, x, y } => t
} .smooth_cubic_bezier(
PathSegment::SmoothCurveTo { abs, x2, y2, x, y } => {
p.extend(t.smooth_cubic_bezier(
*abs, *abs,
*x2, *x2,
*y2, *y2,
@ -216,30 +213,26 @@ fn svg2program(doc: &svgdom::Document, opts: ProgramOptions, mach: Machine) -> P
opts.tolerance, opts.tolerance,
None, None,
opts.feedrate, opts.feedrate,
)); ),
} PathSegment::Quadratic { abs, x1, y1, x, y } => t.quadratic_bezier(
PathSegment::Quadratic { abs, x1, y1, x, y } => { *abs,
p.extend(t.quadratic_bezier( *x1,
*abs, *y1,
*x1, *x,
*y1, *y,
*x, opts.tolerance,
*y, None,
opts.tolerance, opts.feedrate,
None, ),
opts.feedrate, PathSegment::SmoothQuadratic { abs, x, y } => t
)); .smooth_quadratic_bezier(
}
PathSegment::SmoothQuadratic { abs, x, y } => {
p.extend(t.smooth_quadratic_bezier(
*abs, *abs,
*x, *x,
*y, *y,
opts.tolerance, opts.tolerance,
None, None,
opts.feedrate, opts.feedrate,
)); ),
}
PathSegment::EllipticalArc { PathSegment::EllipticalArc {
abs, abs,
rx, rx,
@ -249,22 +242,21 @@ fn svg2program(doc: &svgdom::Document, opts: ProgramOptions, mach: Machine) -> P
sweep, sweep,
x, x,
y, y,
} => { } => t.elliptical(
p.extend(t.elliptical( *abs,
*abs, *rx,
*rx, *ry,
*ry, *x_axis_rotation,
*x_axis_rotation, *large_arc,
*large_arc, *sweep,
*sweep, *x,
*x, *y,
*y, None,
None, opts.feedrate,
opts.feedrate, opts.tolerance,
opts.tolerance, ),
)); };
} p += segment_gcode.into();
}
} }
} }
} }
@ -275,13 +267,12 @@ fn svg2program(doc: &svgdom::Document, opts: ProgramOptions, mach: Machine) -> P
} }
} }
p.extend(t.mach.tool_off()); p += t.mach.tool_off().into();
p.extend(t.mach.absolute()); p += t.mach.absolute().into();
p.push(GCode::RapidPositioning { p.push(GCode::RapidPositioning {
x: 0.0.into(), x: 0.0.into(),
y: 0.0.into(), y: 0.0.into(),
}); });
p.extend(t.mach.tool_on());
p.push(GCode::ProgramEnd); p.push(GCode::ProgramEnd);
p p

@ -1,4 +1,4 @@
use crate::code::{GCode, Program}; use crate::code::{GCode};
use crate::machine::Machine; use crate::machine::Machine;
use lyon_geom::euclid::{Angle, Transform2D}; use lyon_geom::euclid::{Angle, Transform2D};
use lyon_geom::math::{point, vector, F64Point}; use lyon_geom::math::{point, vector, F64Point};
@ -29,7 +29,7 @@ impl Default for Turtle {
} }
impl Turtle { impl Turtle {
pub fn move_to<X, Y>(&mut self, abs: bool, x: X, y: Y) -> Program pub fn move_to<X, Y>(&mut self, abs: bool, x: X, y: Y) -> Vec<GCode>
where where
X: Into<Option<f64>>, X: Into<Option<f64>>,
Y: Into<Option<f64>>, Y: Into<Option<f64>>,
@ -64,7 +64,7 @@ impl Turtle {
.collect() .collect()
} }
pub fn close<Z, F>(&mut self, z: Z, f: F) -> Program pub fn close<Z, F>(&mut self, z: Z, f: F) -> Vec<GCode>
where where
Z: Into<Option<f64>>, Z: Into<Option<f64>>,
F: Into<Option<f64>>, F: Into<Option<f64>>,
@ -85,7 +85,7 @@ impl Turtle {
.collect() .collect()
} }
pub fn line<X, Y, Z, F>(&mut self, abs: bool, x: X, y: Y, z: Z, f: F) -> Program pub fn line<X, Y, Z, F>(&mut self, abs: bool, x: X, y: Y, z: Z, f: F) -> Vec<GCode>
where where
X: Into<Option<f64>>, X: Into<Option<f64>>,
Y: Into<Option<f64>>, Y: Into<Option<f64>>,
@ -129,7 +129,7 @@ impl Turtle {
tolerance: f64, tolerance: f64,
z: Z, z: Z,
f: F, f: F,
) -> Program { ) -> Vec<GCode> {
let z = z.into(); let z = z.into();
let f = f.into(); let f = f.into();
let last_point = std::cell::Cell::new(self.curpos); let last_point = std::cell::Cell::new(self.curpos);
@ -164,7 +164,7 @@ impl Turtle {
tolerance: f64, tolerance: f64,
z: Z, z: Z,
f: F, f: F,
) -> Program ) -> Vec<GCode>
where where
Z: Into<Option<f64>>, Z: Into<Option<f64>>,
F: Into<Option<f64>>, F: Into<Option<f64>>,
@ -203,7 +203,7 @@ impl Turtle {
tolerance: f64, tolerance: f64,
z: Z, z: Z,
f: F, f: F,
) -> Program ) -> Vec<GCode>
where where
Z: Into<Option<f64>>, Z: Into<Option<f64>>,
F: Into<Option<f64>>, F: Into<Option<f64>>,
@ -238,7 +238,7 @@ impl Turtle {
tolerance: f64, tolerance: f64,
z: Z, z: Z,
f: F, f: F,
) -> Program ) -> Vec<GCode>
where where
Z: Into<Option<f64>>, Z: Into<Option<f64>>,
F: Into<Option<f64>>, F: Into<Option<f64>>,
@ -267,7 +267,7 @@ impl Turtle {
tolerance: f64, tolerance: f64,
z: Z, z: Z,
f: F, f: F,
) -> Program ) -> Vec<GCode>
where where
Z: Into<Option<f64>>, Z: Into<Option<f64>>,
F: Into<Option<f64>>, F: Into<Option<f64>>,
@ -301,7 +301,7 @@ impl Turtle {
z: Z, z: Z,
f: F, f: F,
tolerance: f64, tolerance: f64,
) -> Program ) -> Vec<GCode>
where where
Z: Into<Option<f64>>, Z: Into<Option<f64>>,
F: Into<Option<f64>>, F: Into<Option<f64>>,

Loading…
Cancel
Save