Skip to content

Commit

Permalink
feat!: add circle tool compensation, return Result
Browse files Browse the repository at this point in the history
* Adds tool compensation for circle
* Rename Circle::hole to Circle::drill
* Return Result wrapped instructions and gcode

BREAKING CHANGE: Circle::hole was renamed to Circle::drill. Adds
mandatory ToolPathCompensation to Cut::circle (Circle struct) that is
used when calculating cut radius. All to_instructions and
Program::to_gcode now returns Result wrapped values for error handling.
  • Loading branch information
tirithen committed May 23, 2022
1 parent e056490 commit 2036d22
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 65 deletions.
61 changes: 45 additions & 16 deletions src/cuts/circle.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use anyhow::{anyhow, Result};

use crate::instructions::*;
use crate::program::*;
use crate::types::*;
Expand All @@ -9,42 +11,65 @@ pub struct Circle {
pub end_z: f64,
pub radius: f64,
pub max_step_z: f64,
pub compensation: ToolPathCompensation,
}

impl Circle {
#[must_use]
pub fn new(start: Vector3, end_z: f64, radius: f64, max_step_z: f64) -> Self {
pub fn new(
start: Vector3,
end_z: f64,
radius: f64,
max_step_z: f64,
compensation: ToolPathCompensation,
) -> Self {
Self {
start,
end_z,
radius,
max_step_z,
compensation,
}
}

#[must_use]
pub fn hole(start: Vector3, end_z: f64) -> Self {
pub fn drill(start: Vector3, end_z: f64) -> Self {
Self {
start,
end_z,
radius: 0.0,
max_step_z: 0.0,
compensation: ToolPathCompensation::None,
}
}

#[must_use]
pub fn bounds(&self) -> Bounds {
Bounds {
min: Vector3::new(self.start.x - self.radius, self.start.y - self.radius, self.end_z),
max: Vector3::new(self.start.x + self.radius, self.start.y + self.radius, self.start.z),
min: Vector3::new(
self.start.x - self.radius,
self.start.y - self.radius,
self.end_z,
),
max: Vector3::new(
self.start.x + self.radius,
self.start.y + self.radius,
self.start.z,
),
}
}

#[must_use]
pub fn to_instructions(&self, context: Context) -> Vec<Instruction> {
pub fn to_instructions(&self, context: Context) -> Result<Vec<Instruction>> {
let mut instructions = vec![];

if self.radius < 0.001 {
let cut_radius = match self.compensation {
ToolPathCompensation::None => self.radius,
ToolPathCompensation::Inner => self.radius - context.tool().radius(),
ToolPathCompensation::Outer => self.radius + context.tool().radius(),
};

if cut_radius >= 0.0 && cut_radius < 0.001 {
instructions.append(&mut vec![
Instruction::Empty(Empty {}),
Instruction::Comment(Comment {
Expand Down Expand Up @@ -76,7 +101,7 @@ impl Circle {
z: Some(context.z_safe()),
}),
])
} else if self.radius >= 0.0 {
} else if cut_radius > 0.0 {
instructions.append(&mut vec![
Instruction::Empty(Empty {}),
Instruction::Comment(Comment {
Expand All @@ -92,7 +117,7 @@ impl Circle {
z: Some(context.z_safe()),
}),
Instruction::G0(G0 {
x: Some(self.start.x - self.radius),
x: Some(self.start.x - cut_radius),
y: Some(self.start.y),
z: None,
}),
Expand All @@ -112,10 +137,10 @@ impl Circle {
// Cut spiraling down in steps
for index in 0..layers {
instructions.push(Instruction::G2(G2 {
x: Some(self.start.x - self.radius),
x: Some(self.start.x - cut_radius),
y: None,
z: Some((self.start.z - index as f64 * max_step_z).max(self.end_z)),
i: Some(self.radius),
i: Some(cut_radius),
j: None,
k: None,
r: None,
Expand All @@ -126,10 +151,10 @@ impl Circle {

// Extra flat circle
instructions.push(Instruction::G2(G2 {
x: Some(self.start.x - self.radius),
x: Some(self.start.x - cut_radius),
y: None,
z: Some(self.end_z),
i: Some(self.radius),
i: Some(cut_radius),
j: None,
k: None,
r: None,
Expand All @@ -138,10 +163,10 @@ impl Circle {
}));

instructions.push(Instruction::G2(G2 {
x: Some(self.start.x - self.radius),
x: Some(self.start.x - cut_radius),
y: None,
z: Some(self.end_z),
i: Some(self.radius - 0.001),
i: Some(cut_radius - 0.001),
j: None,
k: None,
r: None,
Expand All @@ -155,9 +180,13 @@ impl Circle {
z: Some(context.z_safe()),
}));
} else {
panic!("Unable to make circle, tool is to wide");
return Err(anyhow!(
"Unable to cut circle, tool is {} mm to wide (tool diameter is {} mm).",
cut_radius.abs() * 2.0,
context.tool().diameter()
));
}

instructions
Ok(instructions)
}
}
30 changes: 21 additions & 9 deletions src/cuts/frame.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use anyhow::{anyhow, Result};

use crate::instructions::*;
use crate::program::*;
use crate::types::*;
Expand Down Expand Up @@ -26,13 +28,27 @@ impl Frame {
pub fn bounds(&self) -> Bounds {
Bounds {
min: Vector3::new(self.start.x, self.start.y, self.end_z),
max: Vector3::new(self.start.x + self.size.x, self.start.y + self.size.y, self.start.z),
max: Vector3::new(
self.start.x + self.size.x,
self.start.y + self.size.y,
self.start.z,
),
}
}

#[must_use]
pub fn to_instructions(&self, context: Context) -> Vec<Instruction> {
pub fn to_instructions(&self, context: Context) -> Result<Vec<Instruction>> {
let tool_radius = context.tool().radius();
let tool_diameter = context.tool().diameter();

if self.size.x < tool_diameter {
return Err(anyhow!("Unable to cut frame, tool is {} mm to wider than x dimension (tool diameter is {} mm)", tool_diameter - self.size.x, tool_diameter));
}

if self.size.y < tool_diameter {
return Err(anyhow!("Unable to cut frame, tool is {} mm to wider than y dimension (tool diameter is {} mm)", tool_diameter - self.size.y, tool_diameter));
}

let mut instructions = Vec::new();

instructions.append(&mut vec![
Expand Down Expand Up @@ -70,11 +86,7 @@ impl Frame {

for _layer in 1..=layers {
end_z -= max_step_z;
instructions.append(&mut self.generate_layer_instructions(
start_z,
end_z,
tool_radius,
));
instructions.append(&mut self.generate_layer_instructions(start_z, end_z, tool_radius));
start_z = end_z;
}

Expand Down Expand Up @@ -103,7 +115,7 @@ impl Frame {
z: None,
}));

instructions
Ok(instructions)
}

fn generate_layer_instructions(
Expand Down Expand Up @@ -151,4 +163,4 @@ impl Frame {

instructions
}
}
}
30 changes: 23 additions & 7 deletions src/cuts/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use anyhow::Result;

use crate::instructions::*;
use crate::program::*;
use crate::types::*;
Expand All @@ -24,13 +26,19 @@ pub enum Cut {

impl Cut {
#[must_use]
pub fn circle(start: Vector3, end_z: f64, radius: f64, max_step_z: f64) -> Self {
Self::Circle(Circle::new(start, end_z, radius, max_step_z))
pub fn circle(
start: Vector3,
end_z: f64,
radius: f64,
max_step_z: f64,
compensation: ToolPathCompensation,
) -> Self {
Self::Circle(Circle::new(start, end_z, radius, max_step_z, compensation))
}

#[must_use]
pub fn hole(start: Vector3, end_z: f64) -> Self {
Self::Circle(Circle::hole(start, end_z))
pub fn drill(start: Vector3, end_z: f64) -> Self {
Self::Circle(Circle::drill(start, end_z))
}

#[must_use]
Expand All @@ -49,8 +57,16 @@ impl Cut {
}

#[must_use]
pub fn plane_with_slope(start: Vector3, size: Vector2, end_z: f64, end_z_stop: f64, max_step_z: f64) -> Self {
Self::Plane(Plane::new_with_slope(start, size, end_z, end_z_stop, max_step_z))
pub fn plane_with_slope(
start: Vector3,
size: Vector2,
end_z: f64,
end_z_stop: f64,
max_step_z: f64,
) -> Self {
Self::Plane(Plane::new_with_slope(
start, size, end_z, end_z_stop, max_step_z,
))
}

#[must_use]
Expand All @@ -64,7 +80,7 @@ impl Cut {
}

#[must_use]
pub fn to_instructions(&self, context: Context) -> Vec<Instruction> {
pub fn to_instructions(&self, context: Context) -> Result<Vec<Instruction>> {
match self {
Self::Circle(c) => c.to_instructions(context),
Self::Frame(c) => c.to_instructions(context),
Expand Down
8 changes: 5 additions & 3 deletions src/cuts/path.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use anyhow::Result;

use crate::instructions::*;
use crate::program::*;
use crate::types::*;
Expand Down Expand Up @@ -112,11 +114,11 @@ impl Path {
}

#[must_use]
pub fn to_instructions(&self, context: Context) -> Vec<Instruction> {
pub fn to_instructions(&self, context: Context) -> Result<Vec<Instruction>> {
let mut instructions = vec![];

if self.segments.is_empty() {
return instructions;
return Ok(instructions);
}

let start = match &self.segments[0] {
Expand Down Expand Up @@ -205,7 +207,7 @@ impl Path {
z: Some(context.z_safe()),
}));

instructions
Ok(instructions)
}

fn segments_to_instructions(
Expand Down
40 changes: 33 additions & 7 deletions src/cuts/plane.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use anyhow::{anyhow, Result};

use crate::instructions::*;
use crate::program::*;
use crate::types::*;
Expand Down Expand Up @@ -25,7 +27,13 @@ impl Plane {
}

#[must_use]
pub fn new_with_slope(start: Vector3, size: Vector2, end_z: f64, end_z_stop: f64, max_step_z: f64) -> Self {
pub fn new_with_slope(
start: Vector3,
size: Vector2,
end_z: f64,
end_z_stop: f64,
max_step_z: f64,
) -> Self {
Self {
start,
size,
Expand All @@ -39,13 +47,27 @@ impl Plane {
pub fn bounds(&self) -> Bounds {
Bounds {
min: Vector3::new(self.start.x, self.start.y, self.end_z.min(self.end_z_stop)),
max: Vector3::new(self.start.x + self.size.x, self.start.y + self.size.y, self.start.z),
max: Vector3::new(
self.start.x + self.size.x,
self.start.y + self.size.y,
self.start.z,
),
}
}

#[must_use]
pub fn to_instructions(&self, context: Context) -> Vec<Instruction> {
pub fn to_instructions(&self, context: Context) -> Result<Vec<Instruction>> {
let tool_radius = context.tool().radius();
let tool_diameter = context.tool().diameter();

if self.size.x < tool_diameter {
return Err(anyhow!("Unable to plane area, tool is {} mm to wider than x dimension (tool diameter is {} mm)", tool_diameter - self.size.x, tool_diameter));
}

if self.size.y < tool_diameter {
return Err(anyhow!("Unable to plane area, tool is {} mm to wider than y dimension (tool diameter is {} mm)", tool_diameter - self.size.y, tool_diameter));
}

let mut instructions = Vec::new();

instructions.append(&mut vec![
Expand Down Expand Up @@ -83,7 +105,11 @@ impl Plane {
} else {
(delta_z.abs() / max_step_z).ceil() as u32
};
let start_z = if delta_z < 0.0 {self.start.z - delta_z} else {self.start.z};
let start_z = if delta_z < 0.0 {
self.start.z - delta_z
} else {
self.start.z
};
let mut end_z = start_z;
let mut end_z_stop = start_z + delta_z;

Expand All @@ -109,7 +135,7 @@ impl Plane {
z: Some(context.z_safe()),
}));

instructions
Ok(instructions)
}

fn generate_layer_instructions(
Expand Down Expand Up @@ -186,7 +212,7 @@ impl Plane {
instructions.push(Instruction::G0(G0 {
x: None,
y: None,
z: Some(if end_at_start {end_z} else {end_z_stop} + 0.5),
z: Some(if end_at_start { end_z } else { end_z_stop } + 0.5),
}));

instructions.push(Instruction::G0(G0 {
Expand All @@ -204,4 +230,4 @@ impl Plane {

instructions
}
}
}
Loading

0 comments on commit 2036d22

Please sign in to comment.