Compare commits

..

10 Commits

12 changed files with 5815 additions and 2265 deletions

View File

@@ -1,21 +0,0 @@
class GCodeParser():
def __init__(self, gcode_file):
self.gcode_file = gcode_file
self.lines = []
self._parse_gcode()
def _parse_gcode(self):
from pygcode import Line, Machine
machine = Machine()
positions = []
with open(self.gcode_file, "r") as gcode_file:
for line_text in gcode_file:
line = Line(line_text)
if line.block.gcodes:
machine.process_gcodes(*line.block.gcodes)
positions.append((machine.pos.X, machine.pos.Y, machine.pos.Z))
self.lines = positions
def get_positions(self):
return self.lines

210
gcodeinterpreter.py Normal file
View File

@@ -0,0 +1,210 @@
import math
import re
class GcodeInterpreter:
"""
A basic G-code interpreter that converts G-code commands into a list of coordinates.
Supports G00, G01, G02, and G03 commands.
Attributes:
current_position (list): The current position in 3D space [X, Y, Z].
feed_rate (float): The current feed rate.
coordinates (list): The list of calculated coordinates.
segment_multiplier (float): Multiplier for distance to determine number of segments.
max_segments (int): Maximum number of segments allowed.
"""
def __init__(self, initial_position=[0, 0, 0], initial_feed_rate=0, segment_multiplier=2, max_segments=50):
"""
Initializes the GcodeInterpreter with the initial position, feed rate, segment multiplier, and maximum segments.
Args:
initial_position (list, optional): The initial position [X, Y, Z]. Defaults to [0, 0, 0].
initial_feed_rate (float, optional): The initial feed rate. Defaults to 0.
segment_multiplier (float, optional): Multiplier for distance to determine number of segments. Defaults to 10.0
max_segments (int, optional): Maximum number of segments allowed. Defaults to 100.
"""
self.current_position = initial_position[:] # Use a copy to avoid modifying the original
self.feed_rate = initial_feed_rate
self.coordinates = [initial_position[:]] # Store the initial position
self.segment_multiplier = segment_multiplier # Added segment multiplier
self.max_segments = max_segments # Added max segments
def parse_file(self, filename):
"""
Parses a G-code file and processes each line.
Args:
filename (str): The path to the G-code file.
Returns:
GcodeInterpreter: The instance of the GcodeInterpreter with processed coordinates.
"""
with open(filename, 'r') as file:
for line in file:
self.parse_line(line)
return self
def parse_line(self, line):
"""
Parses a single line of G-code.
Args:
line (str): The G-code line to parse.
"""
line = line.strip()
if not line or line.startswith('%') or line.startswith('('): # Skip empty lines and lines starting with '%'
return
# Use regular expression for more robust parsing
parts = re.findall(r'([A-Za-z])([-+]?\d*\.?\d*)', line) # Find all letter-number pairs
if not parts:
return # Skip lines without any recognized G-code commands
command = parts[0][0].upper() + parts[0][1]
args = {}
for part in parts:
if part[0].upper() != command:
try:
args[part[0].upper()] = float(part[1]) if part[1] else 0.0 # convert the number part to float
except ValueError:
print(f"Warning: Could not convert value '{part[1]}' to float for argument {part[0]}. Skipping.")
args[part[0].upper()] = 0.0
self.process_command(command, args)
def process_command(self, command, args):
"""
Processes a G-code command and calls the appropriate function.
Args:
command (str): The G-code command (e.g., 'G00', 'G01', 'G02', 'G03').
args (dict): A dictionary of arguments for the command (e.g., {'X': 10, 'Y': 20}).
"""
if not command: # Add this check
return
if command in ('G00', 'G01'):
self.process_g00_g01(command, args)
elif command == 'G02':
self.process_g02_g03(command, args, clockwise=True)
elif command == 'G03':
self.process_g02_g03(command, args, clockwise=False)
elif command == 'G04':
self.process_g04(args)
elif command == 'F':
self.feed_rate = args.get('F', self.feed_rate) # Keep the current feed rate if not provided
# Add other G-code commands as needed (e.g., G02, G03, G28, etc.)
else:
print(f"Unsupported G-code command: {command}")
def process_g00_g01(self, command, args):
"""
Processes G00 (Rapid Linear Move) and G01 (Controlled Linear Move) commands.
Args:
command (str): The G-code command ('G00' or 'G01').
args (dict): A dictionary of arguments for the command (e.g., {'X': 10, 'Y': 20, 'Z': 5}).
"""
new_position = [args.get('X', self.current_position[0]),
args.get('Y', self.current_position[1]),
args.get('Z', self.current_position[2])]
# Calculate the distance between the current position and the new position
distance = math.sqrt(
(new_position[0] - self.current_position[0]) ** 2 +
(new_position[1] - self.current_position[1]) ** 2 +
(new_position[2] - self.current_position[2]) ** 2
)
# Number of segments. Increase for smoother lines, but use a reasonable maximum.
segments = int(distance * self.segment_multiplier) + 1
segments = min(segments, self.max_segments) # Limit the maximum number of segments
for i in range(segments + 1):
x = self.current_position[0] + (new_position[0] - self.current_position[0]) * i / segments
y = self.current_position[1] + (new_position[1] - self.current_position[1]) * i / segments
z = self.current_position[2] + (new_position[2] - self.current_position[2]) * i / segments
self.current_position = [x, y, z]
self.coordinates.append([x, y, z])
def process_g02_g03(self, command, args, clockwise=True):
"""
Processes G02 (Clockwise Circular Interpolation) and G03 (Counter-Clockwise Circular Interpolation) commands.
Args:
command (str): The G-code command ('G02' or 'G03').
args (dict): A dictionary of arguments for the command.
clockwise (bool): True for G02 (clockwise), False for G03 (counter-clockwise).
"""
new_position = [args.get('X', self.current_position[0]),
args.get('Y', self.current_position[1]),
args.get('Z', self.current_position[2])]
center = [self.current_position[0] + args.get('I', 0),
self.current_position[1] + args.get('J', 0),
self.current_position[2] + args.get('K', 0)]
radius = math.sqrt((self.current_position[0] - center[0]) ** 2 +
(self.current_position[1] - center[1]) ** 2 +
(self.current_position[2] - center[2]) ** 2)
# Handle the case where the radius is zero
if radius == 0:
print(f"Warning: Radius is zero for {command}. No interpolation performed.")
return
# Calculate the angle between the current point and the target point
start_angle = math.atan2(self.current_position[1] - center[1], self.current_position[0] - center[0])
end_angle = math.atan2(new_position[1] - center[1], new_position[0] - center[0])
# Ensure angles are between 0 and 2*pi
if start_angle < 0:
start_angle += 2 * math.pi
if end_angle < 0:
end_angle += 2 * math.pi
# Calculate the total angle
total_angle = end_angle - start_angle
if clockwise:
if total_angle > 0:
total_angle -= 2 * math.pi
else:
if total_angle < 0:
total_angle += 2 * math.pi
# Number of segments. Increase for smoother curves.
arc_length = radius * abs(total_angle)
segments = int(arc_length * self.segment_multiplier) + 1 # Dynamic segments, at least 1.
segments = min(segments, self.max_segments) # Limit max segments
angle_increment = total_angle / segments
for i in range(segments + 1):
angle = start_angle + i * angle_increment
x = center[0] + radius * math.cos(angle)
y = center[1] + radius * math.sin(angle)
z = (self.current_position[2] + (new_position[2] - self.current_position[2]) * i / segments)
self.current_position = [x, y, z]
self.coordinates.append([x, y, z])
def process_g04(self, args):
"""Processes G04 (Dwell) command. For now, just prints a message.
Args:
args (dict): A dictionary of arguments, containing 'P' for the dwell time in milliseconds
"""
dwell_time = args.get('P', 0)
print(f"G04 Dwell for {dwell_time} milliseconds")
# In a real implementation, you would pause execution here. For this example, we just print.
pass
def get_coordinates(self):
"""
Returns the list of calculated coordinates.
Returns:
list: The list of coordinates.
"""
return self.coordinates
def reset(self):
"""Resets the interpreter to its initial state."""
self.current_position = [0, 0, 0]
self.feed_rate = 0
self.coordinates = [[0,0,0]]

20
main.py
View File

@@ -1,6 +1,7 @@
#! /usr/bin/env python
from argparse import ArgumentParser
from gcode_parser import GCodeParser
from gcodeinterpreter import GcodeInterpreter
from pwm_driver import PWMDriver
from visualizer import Visualizer
# A4
@@ -12,12 +13,19 @@ if __name__ == "__main__":
argparser.add_argument("-f", "--file", type=str)
argparser.add_argument("-W", "--width", type=float, default=WIDTH_MM, required=False)
argparser.add_argument("-H", "--height", type=float, default=HEIGHT_MM, required=False)
argparser.add_argument("-V", "--visualize", action="store_true", default=False, required=False)
argparser.add_argument("-P", "--port", type=str, default=None)
args = argparser.parse_args()
parser = GCodeParser(args.file)
positions = parser.get_positions()
parser = GcodeInterpreter().parse_file(args.file)
positions = parser.get_coordinates()
screen_dimensions = (1024*1.5, 1024*1.5 * HEIGHT_MM/WIDTH_MM)
visualizer = Visualizer(positions, screen_dimensions, (args.width, args.height))
visualizer.visualize()
if args.visualize:
screen_dimensions = (1024*1.5, 1024*1.5 * args.height/args.width)
visualizer = Visualizer(positions, screen_dimensions, (args.width, args.height))
visualizer.visualize()
if args.port:
pwm = PWMDriver(positions, (args.width, args.height), args.port)
pwm.run()

18
port-finder.py Executable file
View File

@@ -0,0 +1,18 @@
#! /usr/bin/env python3
import serial.tools.list_ports
from serial.tools.list_ports_common import ListPortInfo
if __name__ == "__main__":
ports = serial.tools.list_ports.comports()
for port in ports:
if port.interface and port.interface.startswith("CircuitPython CDC2"): # CDC2 is the data-port
print(f"Port: {port.device}")
print(f" Description: {port.description}")
print(f" Manufacturer: {port.manufacturer}")
print(f" VID: {port.vid}")
print(f" PID: {port.pid}")
print(f" Serial Number: {port.serial_number}")
print(f" Location: {port.location}")
print(f" Interface: {port.interface}")
print()

39
pwm_driver.py Normal file
View File

@@ -0,0 +1,39 @@
class PWMDriver():
def __init__(self, positions : list[tuple[float, float, float]], gcode_size : tuple[float, float], port : str, baudrate : int = 115200) -> None:
self.positions = positions
self.gcode_size = gcode_size
self.port = port
self.baudrate = baudrate
self._init_pwm()
def _init_pwm(self) -> None:
from serial import Serial
self.serial = Serial(self.port, self.baudrate)
def _send_position(self, pos : tuple[float, float, float]) -> None:
x, y, z = pos
# Convert coordinates to PWM values
precision = ((2 ** 16) - 1)
pwm_x : int = int(x / self.gcode_size[0] * precision)
pwm_y : int = int(y / self.gcode_size[1] * precision)
pen : int = 1 if z < 0 else 0
# Send PWM values to the serial port
print(f"Sending PWM values: X={pwm_x:<5}, Y={pwm_y:<5}, Pen={pen}")
self.serial.write(f"{pwm_x},{pwm_y},{pen}\n".encode())
def _position_reached(self) -> bool:
# Check if the position has been reached
return self.serial.readline().decode().strip() == "OK"
def _wait_for_position(self) -> None:
# Wait until the position is reached
while not self._position_reached():
pass
def run(self) -> None:
for pos in self.positions:
self._send_position(pos)
self._wait_for_position()
print("All positions sent successfully.")

View File

@@ -1,2 +1,3 @@
pygame==2.6.1
pygcode==0.2.1
colorama==0.4.6
pyserial

26
set_pos.py Executable file
View File

@@ -0,0 +1,26 @@
#! /usr/bin/env python3
import serial
import argparse
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Set the position of the PWM driver.")
parser.add_argument("x", type=float, help="X coordinate [0 - 1]")
parser.add_argument("y", type=float, help="Y coordinate [0 - 1]")
parser.add_argument("pen", type=int, help="pen down (True) or pen up (False)")
parser.add_argument("-p", "--port", type=str, required=True, help="Serial port")
args = parser.parse_args()
# Open the serial port
ser = serial.Serial(args.port, 115200)
# Saturate values to [0, 1]
args.x = int(max(0, min(1, args.x)) * 0xFFFF)
args.y = int(max(0, min(1, args.y)) * 0xFFFF)
args.z = int(max(0, min(1, args.pen)))
# Send the position
print(f"{args.x},{args.y},{args.z}\n")
ser.write(f"{args.x},{args.y},{args.z}\n".encode())
# Close the serial port
ser.close()

3669
test/gothenburg.gcode Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -6,119 +6,206 @@ M3
(Header end.)
G21 (All units in mm)
(Start cutting path id: path1471)
(Start cutting path id: path686)
(Change tool to Cylindrical cutter)
G00 Z4.000000
G00 X40.792992 Y80.926340
G00 X14.552637 Y93.606430
G01 Z-0.100000 F100.0(Penetrate)
G03 X48.432275 Y88.140738 Z-0.100000 I-204.578799 J224.279063 F400.000000
G03 X53.994514 Y93.810363 Z-0.100000 I-133.160993 J136.202090
G03 X59.272395 Y99.729942 Z-0.100000 I-107.634090 J101.278949
G03 X62.820468 Y104.228711 Z-0.100000 I-65.304081 J55.152310
G03 X65.994164 Y108.976904 Z-0.100000 I-51.047939 J37.555235
G03 X67.828284 Y112.451877 Z-0.100000 I-28.758974 J17.400746
G03 X69.150010 Y116.118517 Z-0.100000 I-21.870192 J9.955166
G03 X69.575390 Y118.750352 Z-0.100000 I-12.328848 J3.342987
G03 X69.368199 Y121.376336 Z-0.100000 I-9.811238 J0.547056
G03 X68.619214 Y123.394630 Z-0.100000 I-7.424736 J-1.607186
G03 X67.328874 Y125.148383 Z-0.100000 I-7.014669 J-3.809540
G03 X65.517184 Y126.655202 Z-0.100000 I-7.995064 J-7.770148
G03 X63.423291 Y127.812114 Z-0.100000 I-7.988995 J-11.985955
G03 X60.826730 Y128.802563 Z-0.100000 I-9.942260 J-22.165825
G03 X58.130482 Y129.528270 Z-0.100000 I-9.541314 J-30.077639
G03 X55.105279 Y130.107203 Z-0.100000 I-11.295310 J-50.829803
G03 X52.049800 Y130.526407 Z-0.100000 I-10.577428 J-65.751531
G03 X48.910261 Y130.839617 Z-0.100000 I-12.954376 J-113.959914
G03 X45.762044 Y131.079031 Z-0.100000 I-13.816738 J-160.866844
G03 X42.799102 Y131.270295 Z-0.100000 I-59.054412 J-891.785707
G02 X39.833939 Y131.464707 Z-0.100000 I34.926137 J555.401921
G02 X37.329233 Y131.669732 Z-0.100000 I6.322592 J92.642654
G02 X34.832837 Y131.966743 Z-0.100000 I5.148114 J53.909978
G02 X33.058081 Y132.308419 Z-0.100000 I2.627877 J18.429995
G02 X31.376807 Y132.877795 Z-0.100000 I2.394198 J9.836617
G02 X30.543074 Y133.456849 Z-0.100000 I1.066724 J2.425631
G02 X30.160248 Y134.253900 Z-0.100000 I0.998202 J0.969902
G02 X30.341642 Y135.385514 Z-0.100000 I2.033035 J0.254456
G02 X31.053355 Y136.462075 Z-0.100000 I4.128165 J-1.955590
G02 X33.011212 Y138.364908 Z-0.100000 I13.851663 J-12.293556
G02 X35.209343 Y140.058106 Z-0.100000 I21.730814 J-25.937792
G02 X39.109213 Y142.665522 Z-0.100000 I52.049120 J-73.628840
G02 X43.215542 Y145.015461 Z-0.100000 I29.025488 J-45.956988
G02 X48.133576 Y147.339948 Z-0.100000 I35.918327 J-69.629317
G02 X53.194572 Y149.346402 Z-0.100000 I36.693592 J-85.168337
G02 X58.948615 Y151.278535 Z-0.100000 I42.902754 J-118.233694
G02 X64.785575 Y152.949199 Z-0.100000 I42.582637 J-137.743082
G02 X71.161336 Y154.508415 Z-0.100000 I46.820418 J-177.637487
G02 X77.586835 Y155.850497 Z-0.100000 I44.960072 J-199.202994
G02 X84.378744 Y157.056719 Z-0.100000 I46.254865 J-240.723707
G02 X98.134017 Y158.945187 Z-0.100000 I44.256544 J-271.317302
G02 X112.255639 Y160.217127 Z-0.100000 I36.838985 J-329.973901
G02 X126.425918 Y160.894096 Z-0.100000 I23.405641 J-341.281719
G02 X139.435338 Y160.976811 Z-0.100000 I8.507921 J-315.023673
G02 X152.452978 Y160.486372 Z-0.100000 I-3.981081 J-278.676949
G02 X162.773882 Y159.552821 Z-0.100000 I-10.832870 J-177.281484
G02 X167.868820 Y158.845212 Z-0.100000 I-16.454201 J-137.170051
G02 X172.020233 Y158.089777 Z-0.100000 I-14.075692 J-89.135966
G02 X176.124440 Y157.112858 Z-0.100000 I-14.065191 J-68.200025
G02 X179.127309 Y156.162209 Z-0.100000 I-9.644364 J-35.682199
G02 X181.999539 Y154.907314 Z-0.100000 I-8.558857 J-23.504143
G02 X183.702116 Y153.797249 Z-0.100000 I-4.509523 J-8.777248
G02 X184.969965 Y152.342594 Z-0.100000 I-3.529109 J-4.355745
G02 X185.351659 Y151.022027 Z-0.100000 I-2.265939 J-1.370388
G02 X185.038181 Y149.681813 Z-0.100000 I-2.796666 J-0.052626
G02 X183.682942 Y147.863676 Z-0.100000 I-6.233159 J3.232032
G02 X181.831384 Y146.382057 Z-0.100000 I-8.852518 J9.165118
G02 X178.302970 Y144.349327 Z-0.100000 I-18.966475 J28.843345
G03 X170.928466 Y140.650922 Z-0.100000 I1526.290230 J-3052.576402
G03 X164.440169 Y137.333509 Z-0.100000 I249.035894 J-495.075649
G03 X158.009538 Y133.906624 Z-0.100000 I161.452019 J-310.715630
G03 X152.642644 Y130.843877 Z-0.100000 I79.851784 J-146.158965
G03 X147.422441 Y127.548628 Z-0.100000 I60.865266 J-102.202823
G03 X143.397120 Y124.617338 Z-0.100000 I34.264407 J-51.282217
G03 X139.691193 Y121.328139 Z-0.100000 I27.429682 J-34.637241
G03 X137.190317 Y118.390799 Z-0.100000 I16.300280 J-16.411494
G03 X136.147741 Y116.762747 Z-0.100000 I15.047170 J-10.783800
G03 X135.378538 Y115.195314 Z-0.100000 I12.419279 J-7.067096
G03 X134.818551 Y113.546449 Z-0.100000 I11.882467 J-4.955048
G03 X134.508961 Y111.901168 Z-0.100000 I10.983562 J-2.918529
G03 X134.446462 Y110.229975 Z-0.100000 I11.105406 J-1.252081
G03 X134.642425 Y108.475476 Z-0.100000 I11.976148 J0.449444
G03 X135.084854 Y106.763614 Z-0.100000 I12.795729 J2.393940
G03 X135.839772 Y104.885352 Z-0.100000 I15.682336 J5.212257
G03 X136.806014 Y103.101413 Z-0.100000 I17.313031 J8.223685
G03 X138.161841 Y101.097907 Z-0.100000 I22.636570 J13.858273
G03 X139.683381 Y99.212258 Z-0.100000 I25.292769 J18.852177
G03 X141.669474 Y97.080257 Z-0.100000 I33.649979 J29.355966
G03 X145.967245 Y93.175631 Z-0.100000 I40.638606 J40.412826
G03 X152.484790 Y88.222790 Z-0.100000 I70.154427 J85.552944
G02 X155.786747 Y85.783852 Z-0.100000 I-50.527300 J-71.861035
G02 X158.272013 Y83.745413 Z-0.100000 I-35.961052 J-46.377969
G02 X160.624685 Y81.561427 Z-0.100000 I-31.023158 J-35.778517
G02 X162.291579 Y79.765445 Z-0.100000 I-21.312713 J-21.452369
G02 X163.783343 Y77.829366 Z-0.100000 I-18.176492 J-15.547879
G02 X164.735875 Y76.254112 Z-0.100000 I-12.308977 J-8.518667
G02 X165.458550 Y74.570007 Z-0.100000 I-10.555749 J-5.526741
G02 X165.797289 Y73.182637 Z-0.100000 I-7.613170 J-2.593859
G02 X165.865693 Y71.761139 Z-0.100000 I-6.876266 J-1.043289
G02 X165.668206 Y70.522244 Z-0.100000 I-6.052550 J0.329623
G02 X165.220071 Y69.344543 Z-0.100000 I-5.985404 J1.603435
G02 X164.541014 Y68.244159 Z-0.100000 I-6.614812 J3.322342
G02 X162.714220 Y66.399179 Z-0.100000 I-7.455324 J5.554954
G02 X160.061850 Y64.719806 Z-0.100000 I-11.086716 J14.575914
G02 X157.151071 Y63.434187 Z-0.100000 I-11.691140 J22.532017
G02 X153.898891 Y62.379372 Z-0.100000 I-14.952321 J40.559713
G02 X150.566625 Y61.558271 Z-0.100000 I-14.300496 J50.863354
G02 X147.591231 Y60.992650 Z-0.100000 I-14.791279 J69.699412
G02 X144.574010 Y60.546979 Z-0.100000 I-12.674394 J75.370292
G02 X142.677966 Y60.329435 Z-0.100000 I-9.678879 J75.986377
G02 X141.579387 Y60.224555 Z-0.100000 I-8.496644 J83.193018
G02 X140.698190 Y60.159520 Z-0.100000 I-2.620904 J29.509849
G01 X40.792992 Y80.926340 Z-0.100000
G02 X20.744531 Y97.132218 Z-0.100000 I58.837019 J-96.128067 F400.000000
G02 X25.716552 Y99.525614 Z-0.100000 I34.485847 J-65.279503
G02 X30.860300 Y101.491015 Z-0.100000 I23.790996 J-54.550899
G02 X34.959887 Y102.600926 Z-0.100000 I12.260142 J-37.158180
G02 X39.150265 Y103.209091 Z-0.100000 I6.697716 J-31.408261
G02 X42.532580 Y103.224539 Z-0.100000 I1.795934 J-22.932442
G02 X45.870181 Y102.713250 Z-0.100000 I-1.404588 J-20.318145
G02 X48.684570 Y101.788627 Z-0.100000 I-4.188822 J-17.495591
G02 X51.317759 Y100.411842 Z-0.100000 I-7.068443 J-16.725319
G02 X53.665796 Y98.685361 Z-0.100000 I-11.078526 J-17.526859
G02 X55.775079 Y96.652958 Z-0.100000 I-15.188138 J-17.873400
G02 X57.726196 Y94.306916 Z-0.100000 I-23.584596 J-21.598798
G02 X59.470711 Y91.791387 Z-0.100000 I-30.810456 J-23.229671
G02 X61.115709 Y89.045465 Z-0.100000 I-50.136040 J-31.900659
G02 X62.630031 Y86.220124 Z-0.100000 I-67.202070 J-37.837378
G02 X64.084273 Y83.293181 Z-0.100000 I-144.036213 J-73.388621
G02 X65.494590 Y80.343272 Z-0.100000 I-291.514429 J-141.180087
G03 X66.881828 Y77.442236 Z-0.100000 I283.572929 J133.817113
G03 X68.313824 Y74.564333 Z-0.100000 I137.241882 J66.494060
G03 X69.758311 Y71.884805 Z-0.100000 I61.141728 J31.231317
G03 X71.336939 Y69.288112 Z-0.100000 I44.576782 J25.321713
G03 X72.963662 Y67.013060 Z-0.100000 I26.152579 J16.980690
G03 X74.802248 Y64.922485 Z-0.100000 I19.649002 J15.426825
G03 X76.747819 Y63.219174 Z-0.100000 I12.369484 J12.165982
G03 X78.923535 Y61.857370 Z-0.100000 I9.054792 J12.047641
G03 X81.360720 Y60.895321 Z-0.100000 I6.109585 J11.909471
G03 X83.931304 Y60.421258 Z-0.100000 I3.758224 J13.172327
G03 X87.052305 Y60.433674 Z-0.100000 I1.492311 J17.147166
G03 X90.141616 Y60.965854 Z-0.100000 I-1.957952 J20.598780
G03 X94.072512 Y62.226406 Z-0.100000 I-7.883990 J31.344689
G03 X97.849430 Y63.933050 Z-0.100000 I-15.102771 J38.456045
G03 X102.671280 Y66.665690 Z-0.100000 I-30.887708 J60.123069
G02 X107.455492 Y69.516107 Z-0.100000 I76.319751 J-122.656834
G02 X111.778145 Y71.864657 Z-0.100000 I59.849304 J-105.004055
G02 X116.195789 Y74.026840 Z-0.100000 I50.953186 J-98.510484
G02 X120.197678 Y75.765423 Z-0.100000 I39.542572 J-85.544426
G02 X124.277762 Y77.309185 Z-0.100000 I32.945222 J-80.908914
G02 X127.992363 Y78.503646 Z-0.100000 I25.153027 J-71.849106
G02 X131.764395 Y79.500062 Z-0.100000 I20.181063 J-68.759565
G02 X135.224685 Y80.214984 Z-0.100000 I14.823846 J-63.017244
G02 X138.719390 Y80.736201 Z-0.100000 I10.923189 J-61.262385
G02 X141.957129 Y81.035094 Z-0.100000 I7.031183 J-58.479198
G02 X145.206983 Y81.153633 Z-0.100000 I3.741895 J-57.979350
G02 X148.252179 Y81.099633 Z-0.100000 I0.492298 J-58.128277
G02 X151.291365 Y80.887398 Z-0.100000 I-2.594382 J-59.017970
G02 X154.172321 Y80.544259 Z-0.100000 I-6.004970 J-62.682596
G02 X157.036011 Y80.071812 Z-0.100000 I-9.343840 J-65.551964
G02 X159.780039 Y79.504629 Z-0.100000 I-14.036409 J-74.829451
G02 X162.503404 Y78.841104 Z-0.100000 I-18.436483 J-81.591141
G02 X165.137818 Y78.116401 Z-0.100000 I-27.191313 J-103.995462
G02 X167.755226 Y77.329975 Z-0.100000 I-35.376756 J-122.491044
G02 X170.308142 Y76.515232 Z-0.100000 I-63.095750 J-202.111153
G02 X172.852727 Y75.673769 Z-0.100000 I-100.985659 J-309.649100
G03 X175.353497 Y74.836779 Z-0.100000 I824.726160 J2459.974416
G03 X177.856967 Y74.008305 Z-0.100000 I145.131966 J434.360678
G03 X180.336368 Y73.216701 Z-0.100000 I52.878481 J161.343222
G03 X182.828867 Y72.469528 Z-0.100000 I38.111423 J122.605193
G03 X185.319239 Y71.790655 Z-0.100000 I23.905804 J82.788507
G03 X187.829219 Y71.193050 Z-0.100000 I18.410824 J71.756814
G03 X190.364594 Y70.694298 Z-0.100000 I12.556310 J57.135618
G03 X192.918913 Y70.313651 Z-0.100000 I9.134546 J52.536396
G03 X195.534920 Y70.063287 Z-0.100000 I5.730078 J46.080297
G03 X198.159586 Y69.965048 Z-0.100000 I2.965597 J44.121682
G03 X200.892700 Y70.033280 Z-0.100000 I0.322653 J41.849195
G03 X203.634685 Y70.214064 Z-0.100000 I-9.642083 J167.128071
G03 X206.734190 Y70.468208 Z-0.100000 I-14.808021 J199.624135
G03 X209.828711 Y70.768943 Z-0.100000 I-19.054664 J212.141427
G03 X213.185728 Y71.144851 Z-0.100000 I-23.944887 J229.015273
G03 X216.536369 Y71.569433 Z-0.100000 I-27.820491 J232.982259
G03 X220.054927 Y72.068144 Z-0.100000 I-31.235128 J233.035128
G03 X223.565116 Y72.620309 Z-0.100000 I-34.247524 J229.149691
G03 X227.149400 Y73.243018 Z-0.100000 I-35.615483 J215.627772
G03 X230.722353 Y73.926542 Z-0.100000 I-37.577673 J206.108108
G03 X234.276760 Y74.674407 Z-0.100000 I-36.862694 J184.019161
G03 X237.815350 Y75.493254 Z-0.100000 I-37.806210 J171.432212
G03 X241.244620 Y76.367245 Z-0.100000 I-35.310162 J145.710840
G03 X244.651119 Y77.325701 Z-0.100000 I-35.390941 J132.317698
G03 X247.860593 Y78.326465 Z-0.100000 I-31.591268 J106.960795
G03 X251.036164 Y79.429240 Z-0.100000 I-31.024541 J94.462390
G03 X253.932293 Y80.556999 Z-0.100000 I-26.474034 J72.268933
G03 X256.775961 Y81.809146 Z-0.100000 I-25.498067 J61.762086
G03 X259.267331 Y83.063781 Z-0.100000 I-20.772732 J44.350028
G03 X261.673924 Y84.469733 Z-0.100000 I-19.631861 J36.366877
G03 X263.673323 Y85.851744 Z-0.100000 I-15.307078 J24.282539
G03 X265.530243 Y87.411006 Z-0.100000 I-14.246357 J18.851271
G03 X266.957880 Y88.925821 Z-0.100000 I-10.886437 J11.690065
G03 X268.146784 Y90.619795 Z-0.100000 I-10.156820 J8.392689
G03 X268.928616 Y92.290945 Z-0.100000 I-8.308777 J4.905647
G03 X269.357297 Y94.072485 Z-0.100000 I-8.181325 J2.910968
G03 X269.393144 Y95.952050 Z-0.100000 I-8.386143 J1.100063
G03 X269.027656 Y97.799340 Z-0.100000 I-9.115328 J-0.843674
G03 X268.159077 Y99.914069 Z-0.100000 I-11.976068 J-3.683172
G03 X266.946743 Y101.867828 Z-0.100000 I-13.731658 J-7.167668
G03 X265.034028 Y104.181934 Z-0.100000 I-19.881289 J-14.485266
G03 X262.873021 Y106.280809 Z-0.100000 I-22.835912 J-21.349997
G03 X259.825610 Y108.760580 Z-0.100000 I-32.852748 J-37.260623
G03 X256.476576 Y110.709846 Z-0.100000 I-10.010231 J-13.346960
G03 X252.773344 Y111.883993 Z-0.100000 I-7.493702 J-17.207922
G03 X248.877241 Y112.327664 Z-0.100000 I-4.407126 J-21.372573
G03 X244.450008 Y112.121603 Z-0.100000 I-0.742684 J-31.706144
G03 X240.060530 Y111.353088 Z-0.100000 I4.553065 J-38.925229
G03 X235.163093 Y109.981508 Z-0.100000 I13.543583 J-57.788781
G03 X230.378159 Y108.229403 Z-0.100000 I22.565424 J-69.035121
G03 X225.220090 Y105.971807 Z-0.100000 I40.057628 J-98.543426
G03 X220.174534 Y103.464869 Z-0.100000 I54.183655 J-115.382898
G03 X214.928487 Y100.600598 Z-0.100000 I84.046615 J-160.171681
G03 X209.770717 Y97.577215 Z-0.100000 I106.036659 J-186.805411
G03 X204.595777 Y94.375981 Z-0.100000 I159.527010 J-263.666062
G03 X199.478162 Y91.081669 Z-0.100000 I201.070883 J-317.979798
G03 X194.529447 Y87.806053 Z-0.100000 I348.426084 J-531.768904
G03 X189.605017 Y84.491293 Z-0.100000 I534.035069 J-798.681601
G02 X185.036990 Y81.398913 Z-0.100000 I-3409.804231 J5032.001950
G02 X180.458155 Y78.318762 Z-0.100000 I-623.481769 J921.900652
G02 X176.425895 Y75.662661 Z-0.100000 I-186.252784 J278.363925
G02 X172.343973 Y73.079173 Z-0.100000 I-119.461839 J184.233742
G02 X169.003652 Y71.105394 Z-0.100000 I-52.095598 J84.350515
G02 X165.571823 Y69.298462 Z-0.100000 I-32.343612 J57.266406
G02 X163.077751 Y68.235212 Z-0.100000 I-11.428252 J23.350514
G02 X160.502116 Y67.547415 Z-0.100000 I-5.104505 J13.948698
G02 X158.955683 Y67.560212 Z-0.100000 I-0.737926 J4.270941
G02 X157.731476 Y68.200123 Z-0.100000 I0.444587 J2.341498
G02 X156.944937 Y69.588495 Z-0.100000 I2.023651 J2.063417
G02 X156.801982 Y71.348238 Z-0.100000 I5.571122 J1.338259
G02 X157.353005 Y74.828158 Z-0.100000 I21.087233 J-1.555446
G02 X158.370785 Y78.264326 Z-0.100000 I36.642233 J-8.984475
G02 X160.487376 Y83.787300 Z-0.100000 I91.589403 J-31.933101
G02 X162.889369 Y89.212416 Z-0.100000 I134.487773 J-56.300725
G02 X166.655540 Y96.974020 Z-0.100000 I267.631027 J-125.068347
G03 X170.453824 Y104.728830 Z-0.100000 I-353.386875 J177.895474
G03 X173.157092 Y110.620878 Z-0.100000 I-203.339069 J96.858011
G03 X175.655698 Y116.592772 Z-0.100000 I-151.906226 J67.065324
G03 X177.230787 Y120.906722 Z-0.100000 I-80.003800 J31.655140
G03 X178.518148 Y125.298438 Z-0.100000 I-56.752677 J19.020677
G03 X179.092855 Y128.259078 Z-0.100000 I-26.514778 J6.683036
G03 X179.249550 Y131.234152 Z-0.100000 I-17.602420 J2.418768
G03 X178.959525 Y133.105472 Z-0.100000 I-7.748214 J-0.242714
G03 X178.164821 Y134.770613 Z-0.100000 I-5.274347 J-1.495021
G03 X177.047028 Y135.873431 Z-0.100000 I-3.627994 J-2.559367
G03 X175.594363 Y136.576383 Z-0.100000 I-3.048814 J-4.447978
G03 X173.571592 Y136.990480 Z-0.100000 I-3.105214 J-10.020832
G03 X171.471477 Y137.068245 Z-0.100000 I-1.635210 J-15.763692
G03 X168.749449 Y136.884146 Z-0.100000 I1.048042 J-35.711634
G03 X166.037085 Y136.527390 Z-0.100000 I5.761018 J-54.289385
G03 X162.796828 Y135.981956 Z-0.100000 I23.329119 J-148.488603
G03 X159.565658 Y135.385276 Z-0.100000 I59.156603 J-329.394985
G02 X155.929958 Y134.711435 Z-0.100000 I-80.995633 J426.866156
G02 X152.288355 Y134.082554 Z-0.100000 I-41.132700 J227.325234
G02 X148.365069 Y133.500111 Z-0.100000 I-20.596158 J125.229171
G02 X144.427460 Y133.053734 Z-0.100000 I-13.792412 J104.075983
G02 X140.318392 Y132.775508 Z-0.100000 I-7.322865 J77.668032
G02 X136.205438 Y132.728765 Z-0.100000 I-2.839383 J68.865364
G02 X132.006156 Y132.965154 Z-0.100000 I1.029488 J55.704941
G02 X127.846119 Y133.531548 Z-0.100000 I4.767945 J50.579969
G02 X123.644591 Y134.496575 Z-0.100000 I7.714789 J43.217395
G02 X119.569924 Y135.877058 Z-0.100000 I11.283147 J40.007304
G02 X115.449927 Y137.797297 Z-0.100000 I14.557774 J36.614621
G02 X111.583891 Y140.175584 Z-0.100000 I18.672319 J34.684253
G02 X107.638393 Y143.294847 Z-0.100000 I24.065426 J34.494836
G02 X104.081169 Y146.849471 Z-0.100000 I29.795594 J33.374617
G02 X100.426220 Y151.416750 Z-0.100000 I39.923690 J35.694859
G03 X96.861751 Y156.067796 Z-0.100000 I-70.859008 J-50.613537
G03 X93.897268 Y159.392445 Z-0.100000 I-42.365964 J-34.792383
G03 X90.647615 Y162.421331 Z-0.100000 I-30.882655 J-29.875911
G03 X87.974250 Y164.392723 Z-0.100000 I-16.928804 J-20.158463
G03 X85.062213 Y165.954787 Z-0.100000 I-11.208750 J-17.400236
G03 X82.631681 Y166.757136 Z-0.100000 I-5.489126 J-12.545506
G03 X80.100449 Y167.054290 Z-0.100000 I-2.630925 J-11.481487
G03 X77.844074 Y166.825240 Z-0.100000 I-0.087721 J-10.364200
G03 X75.677709 Y166.114652 Z-0.100000 I2.251124 J-10.520571
G03 X73.585940 Y164.936589 Z-0.100000 I5.495451 J-12.203832
G03 X71.703619 Y163.417209 Z-0.100000 I8.984648 J-13.056514
G03 X69.831793 Y161.430738 Z-0.100000 I15.706928 J-16.675572
G03 X68.181100 Y159.244563 Z-0.100000 I21.305085 J-17.802887
G03 X66.556147 Y156.647241 Z-0.100000 I33.052975 J-22.485788
G03 X65.116782 Y153.938128 Z-0.100000 I41.144863 J-23.597379
G03 X63.733513 Y150.925653 Z-0.100000 I58.201905 J-28.548995
G03 X62.495117 Y147.849036 Z-0.100000 I68.612114 J-29.405211
G03 X61.338406 Y144.605528 Z-0.100000 I90.031382 J-33.935324
G03 X60.292015 Y141.323793 Z-0.100000 I101.989494 J-34.327319
G03 X59.345337 Y138.026420 Z-0.100000 I125.607517 J-37.846608
G03 X58.481449 Y134.705405 Z-0.100000 I137.732403 J-37.600881
G03 X57.728820 Y131.527885 Z-0.100000 I160.170234 J-39.615880
G03 X57.037175 Y128.335124 Z-0.100000 I170.460702 J-38.598048
G03 X56.463368 Y125.449476 Z-0.100000 I187.118800 J-38.708174
G03 X55.428496 Y119.545207 Z-0.100000 I195.277299 J-37.270122
G03 X54.883711 Y115.911257 Z-0.100000 I188.415983 J-30.104235
G03 X54.641709 Y114.113864 Z-0.100000 I168.111543 J-23.549653
G03 X54.518532 Y113.130555 Z-0.100000 I126.811802 J-16.384825
G03 X54.451092 Y112.564881 Z-0.100000 I135.732881 J-16.469000
G03 X54.402469 Y112.128198 Z-0.100000 I38.359439 J-4.492203
G00 Z4.000000
(End cutting path id: path1471)
(End cutting path id: path686)
(Footer)

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 14 KiB

1561
test/test_hatch_fill.gcode Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,6 @@
import pygame
import sys
from colorama import Fore, Style
class Visualizer:
def __init__(self, positions : list[tuple[float, float, float]], screen_dimensions : tuple[int, int], gcode_size : tuple[float, float]):
@@ -30,6 +32,26 @@ class Visualizer:
self.screen = pygame.display.set_mode(self.screen_dimensions)
self.clock = pygame.time.Clock()
def _print_status(self) -> None:
normalized_x = self.prev_x / self.screen.get_width()
normalized_y = self.prev_y / self.screen.get_height()
pen_active = self.prev_z < 0
# Clear the terminal with ANSI code
print("\033c", end="")
# X-axis bar
x_bar = f"{Fore.GREEN}{'#'*int(normalized_x*100)}{Style.RESET_ALL}{' '*int((1.0-normalized_x)*100)}"
print(f"X: |{x_bar}| {(normalized_x*100):.2f}%")
# Y-axis bar
y_bar = f"{Fore.BLUE}{'#'*int(normalized_y*100)}{Style.RESET_ALL}{' '*int((1.0-normalized_y)*100)}"
print(f"Y: |{y_bar}| {(normalized_y*100):.2f}%")
# Pen status
pen_status = f"{Fore.GREEN}Active{Style.RESET_ALL}" if pen_active else f"{Fore.RED}Inactive{Style.RESET_ALL}"
print(f"Pen: {pen_status}")
def visualize(self) -> None:
running = True
while running:
@@ -61,5 +83,7 @@ class Visualizer:
x1, y1, x2, y2 = drawn_line
pygame.draw.line(self.screen, (255, 255, 255), (int(x1), int(y1)), (int(x2), int(y2)), 2)
self._print_status()
pygame.display.flip()
self.clock.tick(60)
self.clock.tick(10)