implement origin control (#7), fix bad final G0

master
Sameer Puri 5 years ago
parent 90b83459e3
commit 5b0a96a1b1

@ -16,7 +16,6 @@ pub struct ProgramOptions {
pub feedrate: f64,
/// Dots per inch for pixels, picas, points, etc.
pub dpi: f64,
pub origin: (f64, f64),
}
pub fn svg2program(doc: &svgdom::Document, options: ProgramOptions, mach: Machine) -> Vec<Command> {
@ -215,7 +214,8 @@ pub fn svg2program(doc: &svgdom::Document, options: ProgramOptions, mach: Machin
}
}
}
// Critical step for actually move the machine back to the origin
turtle.pop_all_transforms();
program.append(&mut turtle.machine.tool_off());
program.append(&mut turtle.machine.absolute());
program.append(&mut turtle.move_to(true, 0.0, 0.0));

@ -17,6 +17,15 @@ pub enum Value {
String(Box<String>),
}
impl Into<f64> for &Value {
fn into(self) -> f64 {
match self {
Value::Float(f) => *f,
_ => panic!("Unwrapping a non-float")
}
}
}
impl std::fmt::Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
@ -44,7 +53,7 @@ macro_rules! commands {
/// Commands are the operational unit of GCode
/// They consist of an identifying word followed by arguments
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Debug)]
pub struct Command {
command_word: CommandWord,
arguments: Vec<Word>
@ -77,6 +86,25 @@ macro_rules! commands {
_ => {}
}
}
pub fn word<'a>(&'a self) -> &'a CommandWord {
&self.command_word
}
pub fn get<'a>(&'a self, letter: char) -> Option<&'a Word> {
let letter = letter.to_ascii_uppercase();
self.arguments.iter().find(|arg| arg.letter == letter)
}
pub fn set(&mut self, letter: char, value: Value) {
let letter = letter.to_ascii_uppercase();
for i in 0..self.arguments.len() {
if self.arguments[i].letter == letter {
self.arguments[i].value = value;
break;
}
}
}
}
impl Into<Vec<Word>> for Command {
@ -113,7 +141,7 @@ macro_rules! commands {
}
}
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum CommandWord {
$(
$(#[$outer])*

@ -22,6 +22,9 @@ mod machine;
/// Provides an interface for drawing lines in GCode
/// This concept is referred to as [Turtle graphics](https://en.wikipedia.org/wiki/Turtle_graphics).
mod turtle;
/// Operations that are easier to implement after GCode is generated, or would
/// over-complicate SVG conversion
mod postprocess;
fn main() -> io::Result<()> {
if let Err(_) = env::var("RUST_LOG") {
@ -41,7 +44,7 @@ fn main() -> io::Result<()> {
(@arg begin_sequence: --begin +takes_value "Optional GCode begin sequence (i.e. change to a tool)")
(@arg end_sequence: --end +takes_value "Optional GCode end sequence, prior to program end (i.e. change to a tool)")
(@arg out: --out -o +takes_value "Output file path (overwrites old files), else writes to stdout")
(@arg origin: --origin +takes_value "Set where the bottom left corner of the SVG will be placed (e.g. 0,0)")
(@arg origin: --origin +takes_value "Set where the bottom left corner of the SVG will be placed (default: 0,0)")
)
.get_matches();
@ -74,13 +77,6 @@ fn main() -> io::Result<()> {
.value_of("dpi")
.map(|x| x.parse().expect("could not parse DPI"))
.unwrap_or(96.0),
origin: matches
.value_of("origin")
.map(|coords| coords.split(','))
.map(|coords| coords.map(|point| point.parse().expect("could not parse coordinate")))
.map(|coords| coords.collect::<Vec<f64>>())
.map(|coords| (coords[0], coords[1]))
.unwrap_or((0., 0.)),
};
let machine = machine::Machine::new(
@ -104,7 +100,17 @@ fn main() -> io::Result<()> {
let document = svgdom::Document::from_str(&input).expect("Invalid or unsupported SVG file");
let program = converter::svg2program(&document, options, machine);
let mut program = converter::svg2program(&document, options, machine);
let origin = matches
.value_of("origin")
.map(|coords| coords.split(','))
.map(|coords| coords.map(|point| point.parse().expect("could not parse coordinate")))
.map(|coords| coords.collect::<Vec<f64>>())
.map(|coords| (coords[0], coords[1]))
.unwrap_or((0., 0.));
postprocess::set_origin(&mut program, lyon_geom::math::point(origin.0, origin.1));
if let Some(out_path) = matches.value_of("out") {
gcode::program2gcode(program, File::create(out_path)?)
} else {

@ -0,0 +1,63 @@
use crate::gcode::CommandWord::*;
use crate::gcode::*;
use lyon_geom::math::{point, vector, F64Point};
pub fn set_origin(commands: &mut [Command], origin: F64Point) {
let offset = get_bounding_box(commands).0.to_vector() + origin.to_vector();
let mut is_relative = false;
let mut current_position = point(0f64, 0f64);
for i in 0..commands.len() {
match &commands[i].word() {
RapidPositioning | LinearInterpolation => {
let x: f64 = (&commands[i].get('X').unwrap().value).into();
let y: f64 = (&commands[i].get('Y').unwrap().value).into();
if is_relative {
current_position += vector(x, y);
} else {
current_position = point(x, y);
commands[i].set('X', Value::Float((current_position + offset).x));
commands[i].set('Y', Value::Float((current_position + offset).y));
}
},
AbsoluteDistanceMode => {
is_relative = false;
}
RelativeDistanceMode => {
is_relative = true;
}
_ => {}
}
}
}
fn get_bounding_box(commands: &[Command]) -> (F64Point, F64Point) {
let (mut minimum, mut maximum) = (point(0f64, 0f64), point(0f64, 0f64));
let mut is_relative = false;
let mut current_position = point(0f64, 0f64);
for i in 0..commands.len() {
let command = &commands[i];
match command.word() {
AbsoluteDistanceMode => {
is_relative = false;
}
RelativeDistanceMode => {
is_relative = true;
}
LinearInterpolation | RapidPositioning => {
let x: f64 = (&command.get('x').unwrap().value).into();
let y: f64 = (&command.get('y').unwrap().value).into();
if is_relative {
current_position += vector(x, y)
} else {
current_position = point(x, y);
}
minimum = minimum.min(current_position);
maximum = maximum.max(current_position);
}
_ => (),
}
}
(minimum, maximum)
}

@ -476,6 +476,14 @@ impl Turtle {
.expect("popped when no transforms left");
}
/// Remove all transforms, returning to true absolute coordinates
pub fn pop_all_transforms(&mut self) {
while self.transform_stack.len() != 0 {
self.pop_transform();
}
self.current_transform = Transform2D::identity();
}
/// Reset the position of the turtle to the origin in the current transform stack
pub fn reset(&mut self) {
self.current_position = point(0.0, 0.0);

Loading…
Cancel
Save