Broke the UI somehow, but hooking up some buttons

master
mitchellhansen 6 years ago
parent a8d9efb6bb
commit e165aa673f

@ -0,0 +1,16 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<value>
<list size="3">
<item index="0" class="java.lang.String" itemvalue="decorator" />
<item index="1" class="java.lang.String" itemvalue="six" />
<item index="2" class="java.lang.String" itemvalue="pkg-resources" />
</list>
</value>
</option>
</inspection_tool>
</profile>
</component>

@ -1,4 +1,6 @@
from tkinter import Tk, Label, filedialog, Button #from tkinter import Tk, Label, filedialog, Button, LEFT, RIGHT,
from tkinter import *
from tkinter import filedialog
from PIL import Image, ImageTk from PIL import Image, ImageTk
from svgpathtools import svg2paths, Line, QuadraticBezier, CubicBezier from svgpathtools import svg2paths, Line, QuadraticBezier, CubicBezier
import cairo, subprocess, bezier, os, math, time import cairo, subprocess, bezier, os, math, time
@ -6,12 +8,82 @@ import numpy as np
class GCoder(Tk): class GCoder(Tk):
def clear_screen(self, ):
self.png_context.rectangle(0, 0, self.bed_actual_x, self.bed_actual_y)
self.png_context.set_source_rgba(1, 1, 1, 1.0)
self.png_context.fill()
self.png_context.set_source_rgba(0, 0, 0, 1.0)
self.png_context.stroke()
self.svg_context.rectangle(0, 0, self.bed_actual_x, self.bed_actual_y)
self.svg_context.set_source_rgba(1, 1, 1, 1.0)
self.svg_context.fill()
self.svg_context.set_source_rgba(0, 0, 0, 1.0)
self.svg_context.stroke()
def flip_markers(self):
self.lift_markers = not self.lift_markers
def update_highpass_value(self, value):
self.highpass_filter = value
def re_render(self):
self.clear_screen()
# self.render_gcode()
#
# if self.label is not None:
# self.label.pack_forget()
#
# # Apply the rendered gcode image to the UI
# self.image_ref = ImageTk.PhotoImage(
# Image.frombuffer("RGBA", (self.bed_actual_x, self.bed_actual_y), self.png_surface.get_data().tobytes(), "raw", "BGRA", 0, 1))
# self.label = Label(self, image=self.image_ref)
# self.label.pack(expand=True, fill="both")
def init_surfaces(self):
self.png_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, self.bed_actual_x, self.bed_actual_y)
self.svg_surface = cairo.SVGSurface("tmp/rendered-output-t.svg", self.bed_actual_x, self.bed_actual_y)
self.png_context = cairo.Context(self.png_surface)
self.png_context.scale(1, 1)
self.png_context.set_line_width(0.4)
self.svg_context = cairo.Context(self.svg_surface)
self.svg_context.scale(1, 1)
self.svg_context.set_line_width(0.4)
def save_surfaces(self):
self.png_surface.write_to_png('tmp/rendered-output.png')
# Save the SVG so we can view it, then immediately reopen it so it's ready for a re-render
self.svg_surface.finish()
os.rename("tmp/rendered-output-t.svg", "tmp/rendered-output.svg")
self.svg_surface = cairo.SVGSurface("tmp/rendered-output-t.svg", self.bed_actual_x, self.bed_actual_y)
self.svg_context = cairo.Context(self.svg_surface)
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.png_surface = None
self.svg_surface = None
self.png_context = None
self.svg_context = None
# Setup the file structure # Setup the file structure
if not os.path.exists("output"): if not os.path.exists("output"):
os.makedirs("output") os.makedirs("output")
if not os.path.exists("tmp"):
os.makedirs("tmp")
self.highpass_filter = 15
self.label = None
self.image_ref = None
# Height at which the pen touches and draws on the surface # Height at which the pen touches and draws on the surface
self.touch_height = 20 self.touch_height = 20
@ -22,7 +94,7 @@ class GCoder(Tk):
# XY movement speed # XY movement speed
self.speed = 500 self.speed = 500
# Weather we render lift markers # Weather we render lift markers
self.lift_markers = True self.lift_markers = False
# X and Y offsets to place the image on A11 paper # X and Y offsets to place the image on A11 paper
self.offset_x = 75 + self.head_x_offset self.offset_x = 75 + self.head_x_offset
@ -33,6 +105,10 @@ class GCoder(Tk):
self.bed_min_x = self.offset_x self.bed_min_x = self.offset_x
self.bed_max_y = 280 self.bed_max_y = 280
self.bed_min_y = 20 self.bed_min_y = 20
self.bed_actual_x = 300
self.bed_actual_y = 300
# First cycle base case flag
self.started = False self.started = False
self.gcode_preamble = ''' self.gcode_preamble = '''
@ -54,42 +130,51 @@ class GCoder(Tk):
M84 ; Turn off the motors M84 ; Turn off the motors
'''.format(75) '''.format(75)
w, h = 300, 300 # UI counter for times the pen was lifted
self.lift_counter = 0
self.geometry("{}x{}".format(w, h)) # Initialize TK
self.geometry("{}x{}".format(self.bed_actual_x, self.bed_actual_y))
self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 300, 300) # UI ELEMENTS
self.init_surfaces()
self.context = cairo.Context(self.surface) self.rightframe = Frame(self)
self.context.scale(1, 1) self.rightframe.pack(side=RIGHT)
self.context.set_line_width(0.4)
self.button = Button(self.rightframe, text="Select Image", command=self.file_select_callback)
self.button.pack()
self.button = Button(self, text="Select Image", command=self.file_select_callback) self.button = Button(self.rightframe, text="Re-Render", command=self.re_render)
self.button.pack() self.button.pack()
self.lift_markers_checkbox = Checkbutton(self.rightframe, text="Lift Markers", command=self.flip_markers)
self.lift_markers_checkbox.pack()
self.highpass_slider = Scale(self.rightframe, command=self.update_highpass_value, resolution=0.1, to=15)
self.highpass_slider.set(self.highpass_filter)
self.highpass_slider.pack()
# Start TK
self.mainloop() self.mainloop()
def file_select_callback(self): def file_select_callback(self):
filepath = filedialog.askopenfilename(initialdir=".", title="Select file", filepath = filedialog.askopenfilename(initialdir=".", title="Select file",
filetypes=(("jpeg files", "*.jpg"), ("all files", "*.*"))) filetypes=(("jpeg files", "*.jpg"), ("all files", "*.*")))
# User didn't select a file
if len(filepath) is 0: if len(filepath) is 0:
return return
self.context.rectangle(0, 0, 300, 300)
self.context.set_source_rgba(1, 1, 1, 1.0)
self.context.fill()
self.context.set_source_rgba(0, 0, 0, 1.0)
filename = os.path.basename(filepath) filename = os.path.basename(filepath)
self.convert_image(filename) self.convert_image(filename)
self.convert_gcode() self.convert_gcode()
self.clear_screen()
self.render_gcode() self.render_gcode()
self._image_ref = ImageTk.PhotoImage( self.image_ref = ImageTk.PhotoImage(Image.frombuffer("RGBA", (self.bed_actual_x, self.bed_actual_y), self.png_surface.get_data().tobytes(), "raw", "BGRA", 0, 1))
Image.frombuffer("RGBA", (300, 300), self.surface.get_data().tobytes(), "raw", "BGRA", 0, 1)) self.label = Label(self, image=self.image_ref)
self.label = Label(self, image=self._image_ref)
self.label.pack(expand=True, fill="both") self.label.pack(expand=True, fill="both")
def convert_image(self, file_name): def convert_image(self, file_name):
@ -106,7 +191,7 @@ class GCoder(Tk):
print("Running mkbitmap...") print("Running mkbitmap...")
start = time.time() start = time.time()
subprocess.call(["mkbitmap", "input-images/{}.bmp".format(base_name), "-x", subprocess.call(["mkbitmap", "input-images/{}.bmp".format(base_name), "-x",
"-f", "15", "-f", "{}".format(self.highpass_filter),
# "-b", "0", # "-b", "0",
"-o", "input-images/{}-n.bmp".format(base_name) "-o", "input-images/{}-n.bmp".format(base_name)
]) ])
@ -124,70 +209,6 @@ class GCoder(Tk):
]) ])
print("Run took [{:.2f}] seconds\n".format(time.time() - start)) print("Run took [{:.2f}] seconds\n".format(time.time() - start))
def render_gcode(self):
file = open("output/gcode-output.gcode", "r")
largest_x = 0
largest_y = 0
smallest_x = 300
smallest_y = 300
x = None
y = None
for line in file:
split = line.split(" ")
command = split[0]
operands = split[1:]
prev_x = x
prev_y = y
if command == "G1":
for operand in operands:
if operand.startswith("X"):
x = float(operand[1:])
if x > largest_x: largest_x = x
if x < smallest_x: smallest_x = x
elif operand.startswith("Y"):
y = float(operand[1:])
if y > largest_y: largest_y = y
if y < smallest_y: smallest_y = y
elif operand.startswith("Z{}".format(self.touch_height + self.raise_height)):
# signify a lift
if prev_x is not None and prev_y is not None and self.lift_markers:
self.context.arc(prev_x - self.head_x_offset, prev_y, 0.5, 0, 2*math.pi)
self.context.stroke()
prev_x = None
prev_y = None
x = None
y = None
if (prev_x != x and prev_x is not None) or (prev_y != y and prev_y is not None):
self.context.line_to(prev_x - self.head_x_offset, prev_y)
self.context.line_to(x - self.head_x_offset, y)
self.context.stroke()
print("Largest X : " + str(largest_x))
print("Smallest X : " + str(smallest_x))
print("Largest Y : " + str(largest_y))
print("Smallest Y : " + str(smallest_y))
if largest_x > self.bed_max_x:
print("X OVERFLOW")
if largest_y > self.bed_max_y:
print("Y OVERFLOW")
if smallest_x < self.bed_min_x:
print("X_UNDERFLOW")
if smallest_y < self.bed_min_y:
print("Y_UNDERFLOW")
def convert_gcode(self): def convert_gcode(self):
# read in the svg # read in the svg
@ -212,14 +233,14 @@ class GCoder(Tk):
if bounding_y_min is None or bbox[3] > bounding_y_min: if bounding_y_min is None or bbox[3] > bounding_y_min:
bounding_y_min = bbox[3] bounding_y_min = bbox[3]
print("Maximum X : {}".format(bounding_x_max)) print("Maximum X : {:.2f}".format(bounding_x_max))
print("Minimum Y : {}".format(bounding_x_min)) print("Minimum Y : {:.2f}".format(bounding_x_min))
print("Maximum X : {}".format(bounding_y_max)) print("Maximum X : {:.2f}".format(bounding_y_max))
print("Minimum Y : {}".format(bounding_y_min)) print("Minimum Y : {:.2f}".format(bounding_y_min))
max_dim = max(bounding_x_max, bounding_x_min, bounding_y_max, bounding_y_min) max_dim = max(bounding_x_max, bounding_x_min, bounding_y_max, bounding_y_min)
scale = (300 - self.offset_x) / max_dim scale = (300 - self.offset_x) / max_dim
print("Scaling to : {}\n".format(scale)) print("Scaling to : {:.5f}\n".format(scale))
# Start the gcode # Start the gcode
gcode = "" gcode = ""
@ -254,9 +275,9 @@ class GCoder(Tk):
previous_y = end.imag previous_y = end.imag
if lift: if lift:
gcode += "G1 Z{}\n".format(self.raise_height + self.touch_height) gcode += "G1 Z{:.3f}\n".format(self.raise_height + self.touch_height)
else: else:
gcode += "# NOT LIFTING\n" gcode += "# NOT LIFTING [{}]\n".format(self.lift_counter)
if isinstance(part, CubicBezier): if isinstance(part, CubicBezier):
@ -272,18 +293,18 @@ class GCoder(Tk):
for i in pos: for i in pos:
evals.append(curve.evaluate(i)) evals.append(curve.evaluate(i))
gcode += "G1 X{} Y{}\n".format(start_x, start_y) gcode += "G1 X{:.3f} Y{:.3f}\n".format(start_x, start_y)
gcode += "G1 Z{} \n".format(self.touch_height) gcode += "G1 Z{:.3f} \n".format(self.touch_height)
for i in evals: for i in evals:
x = i[0][0] x = i[0][0]
y = i[1][0] y = i[1][0]
gcode += "G1 X{} Y{}\n".format(x * scale + self.offset_x, y * scale + self.offset_y) gcode += "G1 X{:.3f} Y{:.3f}\n".format(x * scale + self.offset_x, y * scale + self.offset_y)
if isinstance(part, Line): if isinstance(part, Line):
gcode += "G1 X{} Y{}\n".format(start_x, start_y) gcode += "G1 X{:.3f} Y{:.3f}\n".format(start_x, start_y)
gcode += "G1 Z{} \n".format(self.touch_height) gcode += "G1 Z{:.3f} \n".format(self.touch_height)
gcode += "G1 X{} Y{}\n".format(end_x, end_y) gcode += "G1 X{:.3f} Y{:.3f}\n".format(end_x, end_y)
gcode += self.gcode_end gcode += self.gcode_end
@ -291,6 +312,89 @@ class GCoder(Tk):
output_gcode.write(gcode) output_gcode.write(gcode)
output_gcode.close() output_gcode.close()
def render_gcode(self):
file = open("output/gcode-output.gcode", "r")
largest_x = 0
largest_y = 0
smallest_x = 300
smallest_y = 300
x = None
y = None
for line in file:
split = line.split(" ")
command = split[0]
operands = split[1:]
prev_x = x
prev_y = y
if command == "G1":
for operand in operands:
if operand.startswith("X"):
x = float(operand[1:])
if x > largest_x: largest_x = x
if x < smallest_x: smallest_x = x
elif operand.startswith("Y"):
y = float(operand[1:])
if y > largest_y: largest_y = y
if y < smallest_y: smallest_y = y
elif operand.startswith("Z{}".format(self.touch_height + self.raise_height)):
# signify a lift
if prev_x is not None and prev_y is not None and self.lift_markers:
self.png_context.arc(prev_x - self.head_x_offset, prev_y, 0.5, 0, 2 * math.pi)
self.png_context.stroke()
self.svg_context.arc(prev_x - self.head_x_offset, prev_y, 0.5, 0, 2 * math.pi)
self.svg_context.stroke()
self.svg_context.set_source_rgba(1, 1, 1, 1.0)
self.svg_context.select_font_face("Purisa", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
self.svg_context.set_font_size(3)
self.svg_context.move_to(prev_x - self.head_x_offset, prev_y)
self.svg_context.show_text(str(self.lift_counter))
self.lift_counter += 1
self.svg_context.stroke()
self.svg_context.set_source_rgba(0, 0, 0, 1.0)
prev_x = None
prev_y = None
x = None
y = None
if (prev_x != x and prev_x is not None) or (prev_y != y and prev_y is not None):
self.png_context.line_to(prev_x - self.head_x_offset, prev_y)
self.png_context.line_to(x - self.head_x_offset, y)
self.png_context.stroke()
self.svg_context.line_to(prev_x - self.head_x_offset, prev_y)
self.svg_context.line_to(x - self.head_x_offset, y)
self.svg_context.stroke()
print("Largest X : " + str(largest_x))
print("Smallest X : " + str(smallest_x))
print("Largest Y : " + str(largest_y))
print("Smallest Y : " + str(smallest_y))
if largest_x > self.bed_max_x:
print("X OVERFLOW")
if largest_y > self.bed_max_y:
print("Y OVERFLOW")
if smallest_x < self.bed_min_x:
print("X_UNDERFLOW")
if smallest_y < self.bed_min_y:
print("Y_UNDERFLOW")
self.save_surfaces()
#self.init_surfaces()
if __name__ == "__main__": if __name__ == "__main__":
GCoder() GCoder()

Loading…
Cancel
Save