use std::io::Write;
use crate::cad::svg_reader::{SvgElement, parse_svg_elements};
use crate::error::Result;
pub fn write_svg_to_gcode<W: Write>(svg_content: &str, mut writer: W) -> Result<()> {
let doc = parse_svg_elements(svg_content)?;
let view_height = doc.height;
let mut polylines: Vec<Vec<(f64, f64)>> = Vec::new();
for elem in doc.elements {
match elem {
SvgElement::Line { p1, p2, .. } => {
if p1.x.is_finite() && p1.y.is_finite() && p2.x.is_finite() && p2.y.is_finite() {
polylines.push(vec![(p1.x, view_height - p1.y), (p2.x, view_height - p2.y)]);
}
}
SvgElement::Rect {
x,
y,
width,
height,
..
} => {
if x.is_finite()
&& y.is_finite()
&& width.is_finite()
&& height.is_finite()
&& width > 0.0
&& height > 0.0
{
let y0 = view_height - y;
let y1 = view_height - (y + height);
polylines.push(vec![
(x, y0),
(x + width, y0),
(x + width, y1),
(x, y1),
(x, y0),
]);
}
}
SvgElement::Circle { center, radius, .. } => {
if center.x.is_finite()
&& center.y.is_finite()
&& radius.is_finite()
&& radius > 0.0
{
let dy = view_height - center.y;
let segments = crate::cad::DEFAULT_CIRCLE_SEGMENTS;
let mut circle_pts = Vec::with_capacity(segments + 1);
for i in 0..=segments {
let theta = (i as f64) * std::f64::consts::TAU / (segments as f64);
circle_pts
.push((center.x + radius * theta.cos(), dy + radius * theta.sin()));
}
polylines.push(circle_pts);
}
}
SvgElement::Polyline {
points, is_closed, ..
} => {
let mut pts: Vec<(f64, f64)> = points
.into_iter()
.filter(|p| p.x.is_finite() && p.y.is_finite())
.map(|p| (p.x, view_height - p.y))
.collect();
if pts.len() >= 2 {
if is_closed
&& pts.first() != pts.last()
&& let Some(&first) = pts.first()
{
pts.push(first);
}
polylines.push(pts);
}
}
SvgElement::Text { .. } => {}
}
}
writeln!(writer, "(Generated by document-svg)")?;
writeln!(writer, "G21 (Units in millimeters)")?;
writeln!(writer, "G90 (Absolute distance mode)")?;
writeln!(writer, "G17 (XY plane selection)")?;
writeln!(writer, "G94 (Feedrate per minute)")?;
writeln!(writer, "G00 Z5.000 (Safe clearance height)")?;
for (idx, poly) in polylines.iter().enumerate() {
if poly.len() < 2 {
continue;
}
let start = poly[0];
writeln!(
writer,
"
(--- Toolpath #{idx} ---)"
)?;
writeln!(writer, "G00 X{:.3} Y{:.3}", start.0, start.1)?;
writeln!(writer, "M03 S1000")?;
writeln!(writer, "G01 Z0.000 F300.0 (Engage material)")?;
for pt in &poly[1..] {
writeln!(writer, "G01 X{:.3} Y{:.3} F1200.0", pt.0, pt.1)?;
}
writeln!(writer, "M05")?;
writeln!(writer, "G00 Z5.000")?;
}
writeln!(
writer,
"
(--- End of program ---)"
)?;
writeln!(writer, "M05")?;
writeln!(writer, "G00 Z10.000")?;
writeln!(writer, "G00 X0.000 Y0.000")?;
writeln!(writer, "M02")?;
Ok(())
}