Fix incorrect smooth curve ctrl point reflection, update README.md with demo, add compensation for same closepath point, add demo in README

master
Sameer Puri 6 years ago
parent 35e77e53f9
commit 2de4ec05de

@ -8,9 +8,29 @@ Convert any SVG 1.1 path to gcode for a pen plotter, laser engraver, etc.
- [ ] Biarc interpolation (G2/G3 instead of many G1) - [ ] Biarc interpolation (G2/G3 instead of many G1)
- [x] Px, pc, in to mm - [x] Px, pc, in to mm
- [x] Configurable DPI for px/pc to mm - [x] Configurable DPI for px/pc to mm
- [ ] Sort paths by distance to reduce G0 distances
## Known bugs & whether fixed ## Known bugs & whether fixed
- [ ] Smooth curves should not use the control point when the previous curve is not of the same type (quadratic -> smooth cubic, cubic -> smooth quadratic) - [ ] Smooth curves should not use the control point when the previous curve is not of the same type (quadratic -> smooth cubic, cubic -> smooth quadratic)
- [x] Image coordinates mirrored in the y-axis because SVGs uses upper left corner as (0,0) while GCode uses lower left as (0,0) - [x] Image coordinates mirrored in the y-axis because SVGs uses upper left corner as (0,0) while GCode uses lower left as (0,0)
- [x] Close path command connects back to (0.0, 0.0) instead of the last move - [x] Close path command connects back to (0.0, 0.0) instead of the last move
- [ ] Ellipse paths are dubious -- large_arc, sweep may need to be inverted - [ ] Ellipse paths are dubious -- large_arc, sweep may need to be inverted
## Demonstration
### Input
```bash
cargo run --release -- examples/Vanderbilt_Commodores_logo.svg
```
![Vanderbilt Commodores Logo](examples/Vanderbilt_Commodores_logo.svg)
### Output, rendered at [https://ncviewer.com]()
```bash
cat output.gcode
```
![Vanderbilt Commodores Logo Gcode](examples/Vanderbilt_Commodores_logo_gcode.png)

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" height="115.11" viewBox="0 0 117.73047 115.11328" width="117.73" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"><g transform="matrix(1.25 0 0 -1.25 0 115.11)"><g transform="translate(.83719 .83719)"><path d="m57.975 0.63672-14.858 41.006-35.568-0.01-7.549-0.002 34.061 25.879-17.524 46.24 41.279-24.838 34.465 20.688 6.912 4.15-17.523-46.24 34.06-25.879l-7.5488 0.002-35.568 0.0098-12.07-33.87-2.568-7.1363z" transform="matrix(.8 0 0 -.8 0 91)" fill="#A8996E"/><path d="m57.971 8.5664-12.932 35.686-37.49-0.01 29.615 22.502-15.236 40.206 35.892-21.595 35.981 21.595-15.237-40.206 29.616-22.502-37.491 0.01-12.718-35.686z" transform="matrix(.8 0 0 -.8 0 91)"/><path d="m42.688 46.742v5.2969h2.6855l8.4277 31.018h7.3594l9.0293-31.018h2.5918v-5.2969h-11.158v5.2969h2.918l-6.623 24.178-6.1094-24.178h2.9629v-5.2969h-12.084z" transform="matrix(.8 0 0 -.8 0 91)" fill="#fff"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

@ -261,7 +261,7 @@ fn svg2program(doc: &svgdom::Document, opts: ProgramOptions, mach: Machine) -> P
} }
} }
_ => { _ => {
info!("Node <{} id=\"{}\" .../> is not supported", id, node.id()); warn!("Node <{} id=\"{}\" .../> is not supported", id, node.id());
} }
} }
} }

@ -1,9 +1,12 @@
use crate::code::{GCode}; 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};
use lyon_geom::{ArcFlags, CubicBezierSegment, QuadraticBezierSegment, SvgArc}; use lyon_geom::{ArcFlags, CubicBezierSegment, QuadraticBezierSegment, SvgArc};
/// Turtle graphics simulator for paths that outputs the GCode enum representation for each operation.
/// Handles trasforms, scaling, position offsets, etc.
/// See https://www.w3.org/TR/SVG/paths.html
pub struct Turtle { pub struct Turtle {
curpos: F64Point, curpos: F64Point,
initpos: F64Point, initpos: F64Point,
@ -11,7 +14,7 @@ pub struct Turtle {
scaling: Option<Transform2D<f64>>, scaling: Option<Transform2D<f64>>,
transtack: Vec<Transform2D<f64>>, transtack: Vec<Transform2D<f64>>,
pub mach: Machine, pub mach: Machine,
prev_ctrl: F64Point, prev_ctrl: Option<F64Point>,
} }
impl Default for Turtle { impl Default for Turtle {
@ -23,7 +26,7 @@ impl Default for Turtle {
scaling: None, scaling: None,
transtack: vec![], transtack: vec![],
mach: Machine::default(), mach: Machine::default(),
prev_ctrl: point(0.0, 0.0), prev_ctrl: None,
} }
} }
} }
@ -49,7 +52,7 @@ impl Turtle {
to = self.curtran.transform_point(&to); to = self.curtran.transform_point(&to);
self.curpos = to; self.curpos = to;
self.initpos = to; self.initpos = to;
self.prev_ctrl = to; self.prev_ctrl = None;
vec![ vec![
self.mach.tool_off(), self.mach.tool_off(),
@ -69,6 +72,14 @@ impl Turtle {
Z: Into<Option<f64>>, Z: Into<Option<f64>>,
F: Into<Option<f64>>, F: Into<Option<f64>>,
{ {
// See https://www.w3.org/TR/SVG/paths.html#Segment-CompletingClosePath which could result in a G91 G1 X0 Y0
if (self.curpos - self.initpos)
.abs()
.lower_than(&vector(std::f64::EPSILON, std::f64::EPSILON))
.all()
{
return vec![];
}
self.curpos = self.initpos; self.curpos = self.initpos;
vec![ vec![
self.mach.tool_on(), self.mach.tool_on(),
@ -106,7 +117,7 @@ impl Turtle {
let mut to = point(x, y); let mut to = point(x, y);
to = self.curtran.transform_point(&to); to = self.curtran.transform_point(&to);
self.curpos = to; self.curpos = to;
self.prev_ctrl = self.curpos; self.prev_ctrl = None;
vec![ vec![
self.mach.tool_on(), self.mach.tool_on(),
@ -144,7 +155,12 @@ impl Turtle {
last_point.set(point); last_point.set(point);
}); });
self.curpos = last_point.get(); self.curpos = last_point.get();
self.prev_ctrl = cbs.ctrl1; // See https://www.w3.org/TR/SVG/paths.html#ReflectedControlPoints
self.prev_ctrl = point(
2.0 * self.curpos.x - cbs.ctrl2.x,
2.0 * self.curpos.y - cbs.ctrl2.y,
)
.into();
vec![self.mach.tool_on(), self.mach.absolute(), cubic] vec![self.mach.tool_on(), self.mach.absolute(), cubic]
.drain(..) .drain(..)
@ -209,7 +225,7 @@ impl Turtle {
F: Into<Option<f64>>, F: Into<Option<f64>>,
{ {
let from = self.curpos; let from = self.curpos;
let ctrl1 = self.prev_ctrl; let ctrl1 = self.prev_ctrl.unwrap_or(self.curpos);
let mut ctrl2 = point(x2, y2); let mut ctrl2 = point(x2, y2);
let mut to = point(x, y); let mut to = point(x, y);
if !abs { if !abs {
@ -244,7 +260,7 @@ impl Turtle {
F: Into<Option<f64>>, F: Into<Option<f64>>,
{ {
let from = self.curpos; let from = self.curpos;
let ctrl = self.prev_ctrl; let ctrl = self.prev_ctrl.unwrap_or(self.curpos);
let mut to = point(x, y); let mut to = point(x, y);
if !abs { if !abs {
let invtran = self.curtran.inverse().unwrap(); let invtran = self.curtran.inverse().unwrap();
@ -345,7 +361,7 @@ impl Turtle {
last_point.set(point); last_point.set(point);
}); });
self.curpos = last_point.get(); self.curpos = last_point.get();
self.prev_ctrl = self.curpos; self.prev_ctrl = None;
vec![self.mach.tool_on(), self.mach.absolute(), ellipse] vec![self.mach.tool_on(), self.mach.absolute(), ellipse]
.drain(..) .drain(..)
@ -385,7 +401,7 @@ impl Turtle {
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.curpos = point(0.0, 0.0); self.curpos = point(0.0, 0.0);
self.curpos = self.curtran.transform_point(&self.curpos); self.curpos = self.curtran.transform_point(&self.curpos);
self.prev_ctrl = self.curpos; self.prev_ctrl = None;
self.initpos = self.curpos; self.initpos = self.curpos;
} }
} }

Loading…
Cancel
Save