parent
3e6ad50eb0
commit
433c4c7482
@ -0,0 +1,170 @@
|
|||||||
|
use std::borrow::Cow;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use ::g_code::{command, emit::Token};
|
||||||
|
use lyon_geom::Point;
|
||||||
|
use lyon_geom::{CubicBezierSegment, QuadraticBezierSegment, SvgArc};
|
||||||
|
|
||||||
|
use crate::arc::{ArcOrLineSegment, FlattenWithArcs};
|
||||||
|
use crate::machine::Machine;
|
||||||
|
use super::Turtle;
|
||||||
|
|
||||||
|
/// Turtle graphics simulator for mapping path segments into g-code
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GCodeTurtle<'input> {
|
||||||
|
pub machine: Machine<'input>,
|
||||||
|
pub tolerance: f64,
|
||||||
|
pub feedrate: f64,
|
||||||
|
pub program: Vec<Token<'input>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'input> GCodeTurtle<'input> {
|
||||||
|
fn circular_interpolation(&self, svg_arc: SvgArc<f64>) -> Vec<Token<'input>> {
|
||||||
|
debug_assert!((svg_arc.radii.x.abs() - svg_arc.radii.y.abs()).abs() < f64::EPSILON);
|
||||||
|
match (svg_arc.flags.large_arc, svg_arc.flags.sweep) {
|
||||||
|
(false, true) => command!(CounterclockwiseCircularInterpolation {
|
||||||
|
X: svg_arc.to.x,
|
||||||
|
Y: svg_arc.to.y,
|
||||||
|
R: svg_arc.radii.x,
|
||||||
|
F: self.feedrate,
|
||||||
|
})
|
||||||
|
.into_token_vec(),
|
||||||
|
(false, false) => command!(ClockwiseCircularInterpolation {
|
||||||
|
X: svg_arc.to.x,
|
||||||
|
Y: svg_arc.to.y,
|
||||||
|
R: svg_arc.radii.x,
|
||||||
|
F: self.feedrate,
|
||||||
|
})
|
||||||
|
.into_token_vec(),
|
||||||
|
(true, _) => {
|
||||||
|
let (left, right) = svg_arc.to_arc().split(0.5);
|
||||||
|
let mut token_vec = self.circular_interpolation(left.to_svg_arc());
|
||||||
|
token_vec.append(&mut self.circular_interpolation(right.to_svg_arc()));
|
||||||
|
token_vec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tool_on(&mut self) {
|
||||||
|
self.program.extend(
|
||||||
|
self.machine
|
||||||
|
.tool_on()
|
||||||
|
.drain(..)
|
||||||
|
.chain(self.machine.absolute()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tool_off(&mut self) {
|
||||||
|
self.program.extend(
|
||||||
|
self.machine
|
||||||
|
.tool_off()
|
||||||
|
.drain(..)
|
||||||
|
.chain(self.machine.absolute()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'input> Turtle for GCodeTurtle<'input> {
|
||||||
|
fn begin(&mut self) {
|
||||||
|
self.program
|
||||||
|
.append(&mut command!(UnitsMillimeters {}).into_token_vec());
|
||||||
|
self.program.extend(self.machine.absolute());
|
||||||
|
self.program.extend(self.machine.program_begin());
|
||||||
|
self.program.extend(self.machine.absolute());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn end(&mut self) {
|
||||||
|
self.program.extend(self.machine.tool_off());
|
||||||
|
self.program.extend(self.machine.absolute());
|
||||||
|
self.program.extend(self.machine.program_end());
|
||||||
|
self.program
|
||||||
|
.append(&mut command!(ProgramEnd {}).into_token_vec());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn comment(&mut self, comment: String) {
|
||||||
|
self.program.push(Token::Comment {
|
||||||
|
is_inline: false,
|
||||||
|
inner: Cow::Owned(comment),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move_to(&mut self, to: Point<f64>) {
|
||||||
|
self.tool_off();
|
||||||
|
self.program.append(
|
||||||
|
&mut command!(RapidPositioning {
|
||||||
|
X: to.x as f64,
|
||||||
|
Y: to.y as f64,
|
||||||
|
})
|
||||||
|
.into_token_vec(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn line_to(&mut self, to: Point<f64>) {
|
||||||
|
self.tool_on();
|
||||||
|
self.program.append(
|
||||||
|
&mut command!(LinearInterpolation {
|
||||||
|
X: to.x,
|
||||||
|
Y: to.y,
|
||||||
|
F: self.feedrate,
|
||||||
|
})
|
||||||
|
.into_token_vec(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arc(&mut self, svg_arc: SvgArc<f64>) {
|
||||||
|
if svg_arc.is_straight_line() {
|
||||||
|
self.line_to(svg_arc.to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tool_on();
|
||||||
|
|
||||||
|
if self
|
||||||
|
.machine
|
||||||
|
.supported_functionality()
|
||||||
|
.circular_interpolation
|
||||||
|
{
|
||||||
|
FlattenWithArcs::flattened(&svg_arc, self.tolerance)
|
||||||
|
.drain(..)
|
||||||
|
.for_each(|segment| match segment {
|
||||||
|
ArcOrLineSegment::Arc(arc) => {
|
||||||
|
self.program.append(&mut self.circular_interpolation(arc))
|
||||||
|
}
|
||||||
|
ArcOrLineSegment::Line(line) => {
|
||||||
|
self.line_to(line.to);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
svg_arc
|
||||||
|
.to_arc()
|
||||||
|
.flattened(self.tolerance)
|
||||||
|
.for_each(|point| self.line_to(point));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cubic_bezier(&mut self, cbs: CubicBezierSegment<f64>) {
|
||||||
|
self.tool_on();
|
||||||
|
|
||||||
|
if self
|
||||||
|
.machine
|
||||||
|
.supported_functionality()
|
||||||
|
.circular_interpolation
|
||||||
|
{
|
||||||
|
FlattenWithArcs::<f64>::flattened(&cbs, self.tolerance)
|
||||||
|
.drain(..)
|
||||||
|
.for_each(|segment| match segment {
|
||||||
|
ArcOrLineSegment::Arc(arc) => {
|
||||||
|
self.program.append(&mut self.circular_interpolation(arc))
|
||||||
|
}
|
||||||
|
ArcOrLineSegment::Line(line) => self.line_to(line.to),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cbs.flattened(self.tolerance)
|
||||||
|
.for_each(|point| self.line_to(point));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quadratic_bezier(&mut self, qbs: QuadraticBezierSegment<f64>) {
|
||||||
|
self.cubic_bezier(qbs.to_cubic());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue