Skip to content

Commit c386a17

Browse files
committed
auto extrusion for arcs too
1 parent 43aef3c commit c386a17

File tree

5 files changed

+60
-14
lines changed

5 files changed

+60
-14
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,5 @@ G-code generator for Marlin printers.
33
Inspired by [Full Control GCODE](http://fullcontrolgcode.com/).
44

55
## Planned features
6-
- create g-code based on mathematical functions/generators
76
- cleaner interfacing for absolute movements
87

examples/circlegrid.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
g.travel((0, 20, 0))
1616
for j in range(3):
1717
g.travel((20, 0, 0))
18-
g.draw_arc(0, -10, e=5)
18+
g.draw_arc(0, -10)
1919
g.travel((-60, 0, 0))
2020

2121
g.set_tool_temp(0)

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = gcodepy
3-
version = 0.0.1
3+
version = 0.1.0
44
author = Rahul Menon
55
author_email = [email protected]
66
description = Tool to generate g-code for Marlin based printers

src/gcodepy/gcode.py

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from typing import Callable, Tuple, Union
2+
import math
23
from . import util
34

4-
# circumference calcs for arcs
5+
# TODO:
56
# minimize feedrate output
67
# draw absolute
8+
# catch more invalid inputs
79
class Gcode:
810
def __init__(
911
self,
@@ -92,9 +94,14 @@ def travel(self, delta: Tuple[float, float, float], feedrate: int = 2400):
9294
self.pos[0] += delta[0]
9395
self.pos[1] += delta[1]
9496
self.pos[2] += delta[2]
95-
self.file.write(
96-
f"G0 F{feedrate} X{self.pos[0]} Y{self.pos[1]} Z{self.pos[2]}\n"
97-
)
97+
out = f"G0 F{feedrate}"
98+
if delta[0] != 0.0:
99+
out += f" X{self.pos[0]}"
100+
if delta[1] != 0.0:
101+
out += f" Y{self.pos[1]}"
102+
if delta[2] != 0.0:
103+
out += f" Z{self.pos[2]}"
104+
self.file.write(out + "\n")
98105

99106
def travel_arc(
100107
self,
@@ -139,9 +146,15 @@ def draw(
139146
self.pos[1] += delta[1]
140147
self.pos[2] += delta[2]
141148
self.e += e
142-
self.file.write(
143-
f"G1 F{feedrate} X{self.pos[0]} Y{self.pos[1]} Z{self.pos[2]} E{self.e}\n"
144-
)
149+
out = f"G1 F{feedrate}"
150+
if delta[0] != 0.0:
151+
out += f" X{self.pos[0]}"
152+
if delta[1] != 0.0:
153+
out += f" Y{self.pos[1]}"
154+
if delta[2] != 0.0:
155+
out += f" Z{self.pos[2]}"
156+
out += f" E{e}"
157+
self.file.write(out + "\n")
145158

146159
def draw_arc(
147160
self,
@@ -154,7 +167,7 @@ def draw_arc(
154167
):
155168
if e is None:
156169
e = self.extrusion_length_calculator(
157-
util.dist(delta), # REPLACE
170+
util.arclen((i, j), delta[:2], clockwise),
158171
self.line_width,
159172
self.layer_height,
160173
self.filament_width,
@@ -182,9 +195,19 @@ def draw_arc_r(
182195
clockwise: bool = True,
183196
feedrate: int = 2400,
184197
):
198+
if r == 0 or r is None:
199+
raise ValueError("Radius r cannot be 0 or None.")
185200
if e is None:
201+
d2 = (delta[0] / 2, delta[1] / 2)
202+
m = -1 if clockwise ^ (r < 0) else 1
203+
l = util.dist(d2)
204+
h2 = (r - l) * (r + l)
205+
h = 0 if h2 < 0 else math.sqrt(h2)
206+
s = (-d2[1], d2[0])
207+
s = [s[i] / l * m * h for i in range(2)]
208+
center = tuple(d2[i] + s[i] for i in range(2))
186209
e = self.extrusion_length_calculator(
187-
util.dist(delta), # REPLACE
210+
util.arclen(center, delta[:2], clockwise),
188211
self.line_width,
189212
self.layer_height,
190213
self.filament_width,

src/gcodepy/util.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,35 @@
11
import math
2-
from typing import Tuple
2+
from typing import Iterable, Tuple
33

44

5-
def dist(delta: Tuple[float, float, float]) -> float:
5+
def dist(delta: Iterable[float]) -> float:
66
return math.sqrt(sum(i ** 2 for i in delta))
77

88

9+
def arclen(
10+
center: Tuple[float, float], other: Tuple[float, float], clockwise: bool
11+
) -> float:
12+
radius = dist(center)
13+
if other == (0.0, 0.0):
14+
return math.pi * radius ** 2
15+
16+
# using formula theta = atan2(||u x v||, u . v)
17+
rvec = tuple(-i for i in center)
18+
rt = tuple(other[i] - center[i] for i in range(2))
19+
uxv = rvec[0] * rt[1] - rvec[1] * rt[0]
20+
udv = rvec[0] * rt[0] + rvec[1] * rt[1]
21+
angle = math.atan2(uxv, udv)
22+
if abs(angle) < 1e-6:
23+
return 0
24+
25+
if clockwise and angle > 0:
26+
angle = 2 * math.pi - angle
27+
elif not clockwise and angle < 0:
28+
angle += 2 * math.pi
29+
30+
return angle * radius
31+
32+
933
def calculate_extrusion_length(
1034
path_length: float,
1135
line_width: float,

0 commit comments

Comments
 (0)