use crate::*;
use std::{
fmt,
io::{BufRead, Error as ioError},
};
use super::{types::*, utils::*};
pub fn load_gcode_points<IP, P, R>(read: &mut R, ip: &mut IP) -> GcodeResult<()>
where
IP: IsPushable<P>,
P: IsBuildable3D,
R: BufRead,
{
let mut line_buffer = Vec::new();
let mut i_line = 0;
let mut start_pushed = false;
let mut ra = RelativeAbsolute::Absolute;
let mut x = 0.0;
let mut y = 0.0;
let mut z = 0.0;
while let Ok(line) = fetch_line(read, &mut line_buffer) {
i_line += 1;
if line.len() >= 4 && line[0] == b'G' {
if line[2] == b' ' && (line[1] == b'1' || line[1] == b'2' || line[1] == b'3') {
let mut any_changed = false;
let [opt_x, opt_y, opt_z] = command(&line[3..])
.ok_or(GcodeError::Command)
.line(i_line, line)?;
if let Some(new_x) = opt_x {
any_changed = true;
match ra {
RelativeAbsolute::Absolute => x = new_x,
RelativeAbsolute::Relative => x += new_x,
}
}
if let Some(new_y) = opt_y {
any_changed = true;
match ra {
RelativeAbsolute::Absolute => y = new_y,
RelativeAbsolute::Relative => y += new_y,
}
}
if let Some(new_z) = opt_z {
any_changed = true;
match ra {
RelativeAbsolute::Absolute => z = new_z,
RelativeAbsolute::Relative => z += new_z,
}
}
if any_changed {
if !start_pushed {
ip.push(P::new(0.0, 0.0, 0.0));
start_pushed = true
}
ip.push(P::new(x, y, z));
}
} else if line[1] == b'9' && line[3] == b' ' {
if line[2] == b'0' {
ra = RelativeAbsolute::Absolute;
} else if line[2] == b'1' {
ra = RelativeAbsolute::Relative;
} else if line[2] == b'2' {
let mut any_changed = false;
let [opt_x, opt_y, opt_z] = command(&line[4..])
.ok_or(GcodeError::Command)
.line(i_line, line)?;
if let Some(new_x) = opt_x {
any_changed = true;
x = new_x
}
if let Some(new_y) = opt_y {
any_changed = true;
y = new_y
}
if let Some(new_z) = opt_z {
any_changed = true;
z = new_z
}
if any_changed {
if !start_pushed {
ip.push(P::new(0.0, 0.0, 0.0));
start_pushed = true
}
ip.push(P::new(x, y, z));
}
}
}
}
}
Ok(())
}
fn command(line: &[u8]) -> Option<[Option<f64>; 3]> {
let mut n_found = 0;
let mut x = None;
let mut y = None;
let mut z = None;
let words = line.split(|x| *x == b' ');
for word in words {
if n_found == 3 {
break;
}
let n = word.len();
if n == 0 {
continue;
}
if word[0] == b';' {
break;
}
if n < 2 {
continue;
}
match word[0] {
b'X' => {
x = Some(from_ascii(&word[1..])?);
n_found += 1
}
b'Y' => {
y = Some(from_ascii(&word[1..])?);
n_found += 1
}
b'Z' => {
z = Some(from_ascii(&word[1..])?);
n_found += 1
}
_ => (),
}
}
Some([x, y, z])
}
enum RelativeAbsolute {
Relative,
Absolute,
}
pub enum GcodeError {
AccessFile,
Command,
}
pub type GcodeResult<T> = IOResult<T, GcodeError>;
impl fmt::Debug for GcodeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Command => write!(f, "Unable to parse command"),
Self::AccessFile => write!(f, "Unable to access file"),
}
}
}
impl fmt::Display for GcodeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl From<ioError> for GcodeError {
fn from(_error: ioError) -> Self {
GcodeError::AccessFile
}
}