Merge branch 'dual-motor'

master
mitchellhansen 4 years ago
commit 2c6ab65565

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
</component>
</module>

@ -1,16 +0,0 @@
<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>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (Trac3r)" project-jdk-type="Python SDK" />
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/Trac3r.iml" filepath="$PROJECT_DIR$/.idea/Trac3r.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PySciProjectComponent">
<option name="PY_SCI_VIEW_SUGGESTED" value="true" />
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

@ -1,33 +1,32 @@
import cairo, os, math import cairo, os, math
import Svg2GcodeConverter
# This renderer takes the generated GCODE and turns it into two images
# One is an SVG of the tool paths, the other a png image
class Renderer(): class Renderer():
def __init__(self, settings): def __init__(self, settings):
self.settings = settings self.settings = settings
self.svg_surface = cairo.SVGSurface("tmp/rendered-output-t.svg", self.settings.bed_actual_x, self.settings.bed_actual_y) self.svg_surface = cairo.SVGSurface("tmp/rendered-output-t.svg", self.settings.canvas_x, self.settings.canvas_y)
self.svg_context = cairo.Context(self.svg_surface) self.svg_context = cairo.Context(self.svg_surface)
self.svg_context.scale(1, 1) self.svg_context.scale(1, 1)
self.svg_context.set_line_width(0.1) self.svg_context.set_line_width(0.1)
def clear_screen(self): def clear_screen(self):
self.svg_context.rectangle(0, 0, self.settings.bed_actual_x, self.settings.bed_actual_y) self.svg_surface.finish()
self.svg_context.set_source_rgba(1, 1, 1, 1.0) self.svg_surface = cairo.SVGSurface("tmp/rendered-output-t.svg", self.settings.canvas_x, self.settings.canvas_y)
self.svg_context.fill() self.svg_context = cairo.Context(self.svg_surface)
self.svg_context.set_source_rgba(0, 0, 0, 1.0) self.svg_context.scale(1, 1)
self.svg_context.stroke() self.svg_context.set_line_width(0.1)
self.svg_context.set_source_rgba(1, 0, 0, 1.0) # self.svg_context.rectangle(0, 0, self.settings.canvas_x, self.settings.canvas_y)
self.svg_context.line_to(self.settings.bed_min_x - self.settings.head_x_offset, self.settings.bed_min_y) # self.svg_context.set_source_rgba(1, 1, 1, 1.0)
self.svg_context.line_to(self.settings.bed_max_x - self.settings.head_x_offset, self.settings.bed_min_y) # self.svg_context.fill()
self.svg_context.line_to(self.settings.bed_max_x - self.settings.head_x_offset, self.settings.bed_max_y) # self.svg_context.set_source_rgba(0, 0, 0, 1.0)
self.svg_context.line_to(self.settings.bed_min_x - self.settings.head_x_offset, self.settings.bed_max_y) # self.svg_context.stroke()
self.svg_context.line_to(self.settings.bed_min_x - self.settings.head_x_offset, self.settings.bed_min_y)
self.svg_context.stroke()
self.svg_context.set_source_rgba(0, 0, 0, 1.0)
# Render GCODE from the gcode-output.gcode output file that was generated in convert_gcode # Render GCODE from the gcode-output.gcode output file that was generated in convert_gcode
def render_gcode(self): def render_gcode(self):
@ -36,8 +35,8 @@ class Renderer():
largest_x = 0 largest_x = 0
largest_y = 0 largest_y = 0
smallest_x = 300 smallest_x = 99999999
smallest_y = 300 smallest_y = 99999999
x = None x = None
y = None y = None
@ -60,14 +59,16 @@ class Renderer():
y = float(operand[1:]) y = float(operand[1:])
if y > largest_y: largest_y = y if y > largest_y: largest_y = y
if y < smallest_y: smallest_y = y if y < smallest_y: smallest_y = y
elif operand.startswith("Z{}".format(self.settings.touch_height + self.settings.raise_height)): elif operand.startswith("Z{}".format(1)):
# signify a lift # signify a lift
if prev_x is not None and prev_y is not None and self.settings.lift_markers: if prev_x is not None and prev_y is not None and self.settings.lift_markers:
self.svg_context.arc(prev_x - self.settings.head_x_offset, prev_y, 0.5, 0, 2 * math.pi) # draw a cirlce at the lift
self.svg_context.arc(prev_x, prev_y, 0.5, 0, 2 * math.pi)
self.svg_context.stroke() self.svg_context.stroke()
# And draw the lift number
self.svg_context.set_source_rgba(1, 1, 1, 1.0) self.svg_context.set_source_rgba(1, 1, 1, 1.0)
self.svg_context.select_font_face("Purisa", cairo.FONT_SLANT_NORMAL, self.svg_context.select_font_face("Purisa", cairo.FONT_SLANT_NORMAL,
cairo.FONT_WEIGHT_NORMAL) cairo.FONT_WEIGHT_NORMAL)
@ -84,8 +85,12 @@ class Renderer():
y = None y = None
if (prev_x != x and prev_x is not None) or (prev_y != y and prev_y is not None): if (prev_x != x and prev_x is not None) or (prev_y != y and prev_y is not None):
self.svg_context.line_to(prev_x - self.settings.head_x_offset, prev_y) prev = Svg2GcodeConverter.untriangulate_lengths(self.settings, prev_x, prev_y)
self.svg_context.line_to(x - self.settings.head_x_offset, y) this = Svg2GcodeConverter.untriangulate_lengths(self.settings, x, y)
#self.svg_context.line_to(prev_x, prev_y)
#self.svg_context.line_to(x, y)
self.svg_context.line_to(prev[0], prev[1])
self.svg_context.line_to(this[0], this[1])
self.svg_context.stroke() self.svg_context.stroke()
print("Largest X : " + str(largest_x)) print("Largest X : " + str(largest_x))
@ -94,25 +99,16 @@ class Renderer():
print("Largest Y : " + str(largest_y)) print("Largest Y : " + str(largest_y))
print("Smallest Y : " + str(smallest_y)) print("Smallest Y : " + str(smallest_y))
if largest_x > self.settings.bed_max_x: if largest_x > self.settings.canvas_x:
print("X OVERFLOW") print("X OVERFLOW")
if largest_y > self.settings.bed_max_y: if largest_y > self.settings.canvas_y:
print("Y OVERFLOW") print("Y OVERFLOW")
if smallest_x < self.settings.bed_min_x: if smallest_x < 0:
print("X_UNDERFLOW") print("X_UNDERFLOW")
if smallest_y < self.settings.bed_min_y: if smallest_y < 0:
print("Y_UNDERFLOW") print("Y_UNDERFLOW")
self.svg_context.set_source_rgba(0, 0, 1, 1.0)
self.svg_context.line_to(smallest_x - self.settings.head_x_offset, smallest_y)
self.svg_context.line_to(largest_x - self.settings.head_x_offset, smallest_y)
self.svg_context.line_to(largest_x - self.settings.head_x_offset, largest_y)
self.svg_context.line_to(smallest_x - self.settings.head_x_offset, largest_y)
self.svg_context.line_to(smallest_x - self.settings.head_x_offset, smallest_y)
self.svg_context.stroke()
self.svg_context.set_source_rgba(0, 0, 0, 1.0)
self.save_surfaces() self.save_surfaces()
# self.init_surfaces() # self.init_surfaces()
@ -123,21 +119,8 @@ class Renderer():
# Save the SVG so we can view it, then immediately reopen it so it's ready for a re-render # Save the SVG so we can view it, then immediately reopen it so it's ready for a re-render
self.svg_surface.finish() self.svg_surface.finish()
os.rename("tmp/rendered-output-t.svg", "tmp/rendered-output.svg") os.rename("tmp/rendered-output-t.svg", "tmp/rendered-output.svg")
self.svg_surface = cairo.SVGSurface("tmp/rendered-output-t.svg", self.settings.bed_actual_x, self.settings.bed_actual_y) self.svg_surface = cairo.SVGSurface("tmp/rendered-output-t.svg", self.settings.canvas_x, self.settings.canvas_y)
self.svg_context = cairo.Context(self.svg_surface) self.svg_context = cairo.Context(self.svg_surface)
# def 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 toggle_flip_markers(self): def toggle_flip_markers(self):
self.settings.lift_markers = not self.settings.lift_markers self.settings.lift_markers = not self.settings.lift_markers

@ -0,0 +1,57 @@
import subprocess, os, time
class ImageConverter:
class ConverterSettings:
def __init__(self):
# mkbitmap settings
self.highpass_filter = 0
self.blur = 0
# potrace settings
self.turd = 0
# This function takes a file and runs it through mogrify, mkbitmap, and finally potrace.
# The flow of the intermediate files is
# input_file.extension : The input file
# input_file.bmp : The input file converted to bmp
# input_file-n.bmp : The bmp file after running through some filters
# input_file.svg : The output svg render
def convert_image(self, file_name, settings):
base_name = file_name.split(".")[0]
print("Converting input file [{}]".format(file_name))
print("Running mogrify...")
start = time.time()
subprocess.call(["mogrify", "-format", "bmp", "input-images/{}".format(file_name)])
print("Run took [{:.2f}] seconds".format(time.time() - start))
print("Running mkbitmap...")
start = time.time()
mkbitmap_args = ["mkbitmap", "input-images/{}.bmp".format(base_name),
"-o", "input-images/{}-n.pbm".format(base_name)]
if settings.highpass_filter > 0:
mkbitmap_args.append(["-f", settings.highpass_filter])
if settings.blur > 0:
mkbitmap_args.append(["-b", settings.blur])
subprocess.call(mkbitmap_args)
print("Run took [{:.2f}] seconds".format(time.time() - start))
print("Running potrace...")
start = time.time()
potrace_args = ["potrace",
"-z", "white",
"-b", "svg",
"input-images/{}-n.pbm".format(base_name),
"--rotate", "0",
"-o", "tmp/conversion-output.svg"]
if settings.turd > 0:
potrace_args.append(["-t", settings.turd])
subprocess.call(potrace_args)
print("Run took [{:.2f}] seconds\n".format(time.time() - start))

@ -0,0 +1,45 @@
import sys, pygame
import threading
class EventThread(threading.Thread):
def __init__(self):
super(EventThread, self).__init__()
def run(self):
while True:
for events in pygame.event.get():
if events.type == pygame.QUIT:
pygame.display.quit()
pygame.quit()
class Simulator:
def __init__(self):
pygame.init()
self.size = width, height = 320, 240
self.black = 0, 0, 0
self.red=(255,0,0)
self.screen = pygame.display.set_mode(self.size)
def render(self):
self.screen.fill(self.black)
pygame.draw.line(self.screen, self.red, (60, 80), (130, 100))
pygame.display.flip()
t = EventThread()
t.start()

@ -1,6 +1,40 @@
from svgpathtools import svg2paths, Line, QuadraticBezier, CubicBezier from svgpathtools import svg2paths, Line, QuadraticBezier, CubicBezier
import numpy as np import numpy as np
import bezier import bezier, math
def triangulate_lengths(settings, dest_xy):
left_pulley_position = (settings.left_pulley_x_offset, -settings.pulley_y_droop)
right_pulley_position = (settings.right_pulley_x_offset + settings.canvas_x, -settings.pulley_y_droop)
right_squared_x = pow(right_pulley_position[0] - dest_xy[0], 2)
right_squared_y = pow(right_pulley_position[1] - dest_xy[1], 2)
left_squared_x = pow(left_pulley_position[0] - dest_xy[0], 2)
left_squared_y = pow(left_pulley_position[1] - dest_xy[1], 2)
right_pulley_length = math.sqrt(right_squared_x + right_squared_y)
left_pulley_length = math.sqrt(left_squared_x + left_squared_y)
return left_pulley_length, right_pulley_length
# http://paulbourke.net/geometry/circlesphere/
# https://math.stackexchange.com/questions/187107/calculate-coordinates-of-3rd-point-vertex-of-a-scalene-triangle-if-angles-and
# http://xaktly.com/MathNonRightTrig.html
def untriangulate_lengths(settings, x, y):
r0 = x
r1 = y
r2 = settings.distance_between_centers
a = (pow(r0, 2) - pow(r1, 2) + pow(r2, 2)) / (2 * r2)
h = math.sqrt(pow(r0, 2) - pow(a, 2))
a = a + settings.left_pulley_x_offset
h = h - settings.pulley_y_droop
return a, h
class Svg2GcodeConverter: class Svg2GcodeConverter:
@ -12,24 +46,20 @@ class Svg2GcodeConverter:
# First cycle base case flag # First cycle base case flag
self.started = False self.started = False
starting_xy = triangulate_lengths(self.settings, (self.settings.canvas_x/2, 0))
self.gcode_preamble = ''' self.gcode_preamble = '''
G91 ; Set to relative mode for the initial pen lift G91 ; Set to relative mode for the initial pen lift
G1 Z20 ; Lift head by 20 G1 Z1 ; Lift head by 1
G90 ; Set back to absolute position mode
M107 ; Fan off
M190 S0 ; Set bed temp
M104 S0 ; Set nozzle temp
G28 ; home all axes
G0 F{1} ; Set the feed rate G0 F{1} ; Set the feed rate
G1 Z{0} ; Move the pen to just above the paper G1 Z{0} ; Move the pen to just above the paper
'''.format(self.settings.touch_height + self.settings.raise_height, self.settings.speed) G90
G92 X{2} Y{3}
'''.format(1, self.settings.speed, starting_xy[0], starting_xy[1])
self.gcode_end = ''' self.gcode_end = '''
G1 Z{0} F7000 ; Raise the pen high up so we can fit a cap onto it G1 Z{0} F7000 ; Raise the pen
M104 S0 ; Set the nozzle to 0 '''.format(1)
G28 X0 Y0 ; Home back to (0,0) for (x,y)
M84 ; Turn off the motors
'''.format(75)
# From an input svg file, convert the vector svg paths to gcode tool paths # From an input svg file, convert the vector svg paths to gcode tool paths
def convert_gcode(self): def convert_gcode(self):
@ -70,8 +100,8 @@ class Svg2GcodeConverter:
max_x_dim = max(bounding_x_max, bounding_x_min) max_x_dim = max(bounding_x_max, bounding_x_min)
max_y_dim = max(bounding_y_max, bounding_y_min) max_y_dim = max(bounding_y_max, bounding_y_min)
scale_x = (self.settings.bed_max_x - self.settings.bed_min_x) / max_x_dim scale_x = self.settings.canvas_x / max_x_dim
scale_y = (self.settings.bed_max_y - self.settings.bed_min_y) / max_y_dim scale_y = self.settings.canvas_y / max_y_dim
scale = min(scale_x, scale_y) scale = min(scale_x, scale_y)
print("Scaling to : {:.5f}\n".format(scale)) print("Scaling to : {:.5f}\n".format(scale))
@ -91,11 +121,11 @@ class Svg2GcodeConverter:
start = part.start start = part.start
end = part.end end = part.end
start_x = start.real * scale + self.settings.offset_x start_x = start.real * scale
start_y = start.imag * scale + self.settings.offset_y start_y = start.imag * scale
end_x = end.real * scale + self.settings.offset_x end_x = end.real * scale
end_y = end.imag * scale + self.settings.offset_y end_y = end.imag * scale
# Check to see if the endpoint of the last cycle continues and whether we need to lift the pen or not # Check to see if the endpoint of the last cycle continues and whether we need to lift the pen or not
lift = True lift = True
@ -109,9 +139,9 @@ class Svg2GcodeConverter:
previous_y = end.imag previous_y = end.imag
if lift: if lift:
gcode += "G1 Z{:.3f}\n".format(self.settings.raise_height + self.settings.touch_height) gcode += "G1 Z{:.3f}\n".format(1)
else: else:
gcode += ";# NOT LIFTING [{}]\n".format(self.settings.lift_counter) gcode += "; NOT LIFTING [{}]\n".format(self.settings.lift_counter)
if isinstance(part, CubicBezier): if isinstance(part, CubicBezier):
@ -127,18 +157,27 @@ class Svg2GcodeConverter:
for i in pos: for i in pos:
evals.append(curve.evaluate(i)) evals.append(curve.evaluate(i))
gcode += "G1 X{:.3f} Y{:.3f}\n".format(start_x, start_y) lengths = triangulate_lengths(self.settings, (start_x, start_y))
gcode += "G1 Z{:.3f} \n".format(self.settings.touch_height) # gcode += "; Setting down tip at beginning of line ({}, {})\n".format(start_x, start_y)
gcode += "G1 X{:.3f} Y{:.3f}\n".format(lengths[0], lengths[1])
gcode += "G1 Z{:.3f} \n".format(0)
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{:.3f} Y{:.3f}\n".format(x * scale + self.settings.offset_x, y * scale + self.settings.offset_y) tmp_len = triangulate_lengths(self.settings, (x * scale, y * scale))
# gcode += "; Continuing the line ({}, {})\n".format(x * scale, y * scale)
gcode += "G1 X{:.3f} Y{:.3f}\n".format(tmp_len[0], tmp_len[1])
if isinstance(part, Line): if isinstance(part, Line):
gcode += "G1 X{:.3f} Y{:.3f}\n".format(start_x, start_y) start_len = triangulate_lengths(self.settings, (start_x, start_y))
gcode += "G1 Z{:.3f} \n".format(self.settings.touch_height) end_len = triangulate_lengths(self.settings, (end_x, end_y))
gcode += "G1 X{:.3f} Y{:.3f}\n".format(end_x, end_y)
# gcode += "; Setting down tip at beginning of line ({}, {})\n".format(start_x, start_y)
gcode += "G1 X{:.3f} Y{:.3f}\n".format(start_len[0], start_len[1])
gcode += "G1 Z{:.3f} \n".format(0)
# gcode += "; Moving tip to the end of the line ({}, {})\n".format(end_x, end_y)
gcode += "G1 X{:.3f} Y{:.3f}\n".format(end_len[0], end_len[1])
gcode += self.gcode_end gcode += self.gcode_end

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

@ -3,43 +3,44 @@ from tkinter import filedialog
from tkinter.ttk import Notebook from tkinter.ttk import Notebook
from PIL import Image, ImageTk from PIL import Image, ImageTk
import subprocess, os, time import os
from Renderer import Renderer from GCodeRenderer import Renderer
from Svg2GcodeConverter import Svg2GcodeConverter from Svg2GcodeConverter import Svg2GcodeConverter, triangulate_lengths, untriangulate_lengths
from ImageConverter import ImageConverter
from Simulator import Simulator
class Settings: class Settings:
def __init__(self): def __init__(self):
# Height at which the pen touches and draws on the surface # ============ HARDCODED VALUES ===========
self.touch_height = 12
# How far to raise the pen tip to raise it off the page # Canvas size
self.raise_height = 2 self.canvas_x = 200
# The inherent offset from true 0 we have from the pen bracket self.canvas_y = 200
self.head_x_offset = 50
# XY movement speed
self.speed = 1000
# Whether we render lift markers
self.lift_markers = False
# X and Y offsets to place the image on A11 paper # The position of the pulley centers in relation to the top left and right of the canvas
self.offset_x = 70 + self.head_x_offset self.left_pulley_x_offset = -40
self.offset_y = 20 self.right_pulley_x_offset = 40
self.pulley_y_droop = 60
# Bed dimensions to fit A11 paper # Diameter of the inner portion of the pulley in millimeters
self.bed_max_x = 300 - 70 + self.head_x_offset + 20 # 20 is to adjust for the misalignment of print bed self.pulley_diameter = 45
self.bed_min_x = self.offset_x
self.bed_max_y = 280
self.bed_min_y = 20
self.bed_actual_x = 300 # Feed rates
self.bed_actual_y = 300 self.speed = 1000
# Whether we render lift markers
self.lift_markers = False
self.lift_counter = 0 self.lift_counter = 0
# ============ CALCULATED VALUES ===========
self.distance_between_centers = abs(self.left_pulley_x_offset) + self.canvas_x + self.right_pulley_x_offset
# Main GUI class and program entry point
class Tracer(Tk): class Tracer(Tk):
def update_highpass_value(self, value): def update_highpass_value(self, value):
@ -48,6 +49,9 @@ class Tracer(Tk):
def update_blur_value(self, value): def update_blur_value(self, value):
self.blur = value self.blur = value
def update_turd_value(self, value):
self.turd = value
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -58,15 +62,21 @@ class Tracer(Tk):
if not os.path.exists("tmp"): if not os.path.exists("tmp"):
os.makedirs("tmp") os.makedirs("tmp")
# Settings for the printer are loaded, TODO: Customize for our dual motor printer
self.settings = Settings() self.settings = Settings()
# Image filename which we are converting
self.filename = None self.filename = None
# GCODE -> SVG,PNG renderer
self.cairo_renderer = Renderer(self.settings) self.cairo_renderer = Renderer(self.settings)
# SVG -> GCODE converter
self.gcode_converter = Svg2GcodeConverter(self.settings) self.gcode_converter = Svg2GcodeConverter(self.settings)
self.highpass_filter = 0 # FILE -> SVG converter
self.blur = 0 self.image_converter = ImageConverter()
self.image_converter_settings = ImageConverter.ConverterSettings()
self.label = None self.label = None
self.pix = None self.pix = None
@ -74,38 +84,55 @@ class Tracer(Tk):
self.image_ref = None self.image_ref = None
# Initialize TK # Initialize TK
self.geometry("{}x{}".format(500, 500)) self.geometry("{}x{}".format(800, 800))
self.n = Notebook(self, width= 400, height =400) self.tab_bar = Notebook(self, width= 400, height =400)
self.n.pack(fill=BOTH, expand=1) self.tab_bar.pack(fill=BOTH, expand=1)
self.f1 = Frame(self.n) self.converted_image_tab = Frame(self.tab_bar)
self.f2 = Frame(self.n) self.original_image_tab = Frame(self.tab_bar)
self.rightframe = Frame(self) self.rightframe = Frame(self)
self.rightframe.pack(side=RIGHT) self.rightframe.pack(side=RIGHT)
self.button = Button(self.rightframe, text="Select Image", command=self.file_select_callback) self.centerframe = Frame(self)
self.button.pack() self.centerframe.pack(side=BOTTOM)
self.image_select_button = Button(self.rightframe, text="Select Image", command=self.file_select_callback)
self.image_select_button.pack()
self.rerender_button = Button(self.rightframe, text="Re-Render", command=self.render)
self.rerender_button.pack()
self.button = Button(self.rightframe, text="Re-Render", command=self.render) self.render_simulation_button = Button(self.rightframe, text="Render Simulation", command=self.render_simulation)
self.button.pack() self.render_simulation_button.pack()
self.lift_markers_checkbox = Checkbutton(self.rightframe, text="Lift Markers", command=self.cairo_renderer.toggle_flip_markers) self.lift_markers_checkbox = Checkbutton(self.rightframe, text="Lift Markers", command=self.cairo_renderer.toggle_flip_markers)
self.lift_markers_checkbox.pack() self.lift_markers_checkbox.pack()
self.highpass_slider = Scale(self.rightframe, command=self.update_highpass_value, resolution=0.1, to=15) self.highpass_label = Label(self.centerframe, text="Highpass filter", fg="black")
self.highpass_slider.set(self.highpass_filter) self.highpass_label.pack()
self.highpass_slider = Scale(self.centerframe, command=self.update_highpass_value, resolution=0.0, to=15, orient=HORIZONTAL)
self.highpass_slider.set(self.image_converter_settings.highpass_filter)
self.highpass_slider.pack() self.highpass_slider.pack()
self.blur_slider = Scale(self.rightframe, command=self.update_blur_value, resolution=0.1, to=5) self.blur_label = Label(self.centerframe, text="Blur", fg="black")
self.blur_slider.set(self.blur) self.blur_label.pack()
self.blur_slider = Scale(self.centerframe, command=self.update_blur_value, resolution=0.0, to=5, orient=HORIZONTAL)
self.blur_slider.set(self.image_converter_settings.blur)
self.blur_slider.pack() self.blur_slider.pack()
self.turd_label = Label(self.centerframe, text="Turds", fg="black")
self.turd_label.pack()
self.turd_slider = Scale(self.centerframe, command=self.update_turd_value, resolution=0.0, to=5, orient=HORIZONTAL)
self.turd_slider.set(self.image_converter_settings.turd)
self.turd_slider.pack()
# Start TK # 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", "*.*")))
@ -120,14 +147,14 @@ class Tracer(Tk):
self.render() self.render()
def render(self): def render(self):
self.convert_image(self.filename) self.image_converter.convert_image(self.filename, self.image_converter_settings)
self.gcode_converter.convert_gcode() self.gcode_converter.convert_gcode()
self.cairo_renderer.clear_screen() self.cairo_renderer.clear_screen()
self.cairo_renderer.render_gcode() self.cairo_renderer.render_gcode()
self.f1.pack_forget() self.converted_image_tab.pack_forget()
self.f2.pack_forget() self.original_image_tab.pack_forget()
if self.label is not None: if self.label is not None:
self.label.pack_forget() self.label.pack_forget()
@ -139,59 +166,24 @@ class Tracer(Tk):
# scale = self.winfo_width() / pil_image.width # scale = self.winfo_width() / pil_image.width
# pil_image = pil_image.resize((int(scale * pil_image.width), int(scale * pil_image.height))) # pil_image = pil_image.resize((int(scale * pil_image.width), int(scale * pil_image.height)))
self.image_ref = ImageTk.PhotoImage(pil_image) self.image_ref = ImageTk.PhotoImage(pil_image)
self.label = Label(self.f1, image=self.image_ref) self.label = Label(self.converted_image_tab, image=self.image_ref)
self.n.add(self.f1, text="Converted") self.tab_bar.add(self.converted_image_tab, text="Converted")
self.label.pack(expand=True, fill="both") self.label.pack(expand=True, fill="both")
self.pic = ImageTk.PhotoImage(file="input-images/{}".format(self.filename)) self.pic = ImageTk.PhotoImage(file="input-images/{}".format(self.filename))
self.label1 = Label(self.f2, image=self.pic) self.label1 = Label(self.original_image_tab, image=self.pic)
self.n.add(self.f2, text="Original") self.tab_bar.add(self.original_image_tab, text="Original")
self.label1.pack(expand=True, fill="both") self.label1.pack(expand=True, fill="both")
def render_simulation(self):
simulator = Simulator()
simulator.render()
# This function takes a file and runs it through mogrify, mkbitmap, and finally potrace. settings = Settings()
# The flow of the intermediate files is print(triangulate_lengths(settings, (150, 0)))
# input_file.extension : The input file # print(triangulate_lengths(settings, (300, 300)))
# input_file.bmp : The input file converted to bmp
# input_file-n.bmp : The bmp file after running through some filters
# input_file.svg : The output svg render
def convert_image(self, file_name):
base_name = file_name.split(".")[0]
print("Converting input file [{}]".format(file_name))
print("Running mogrify...")
start = time.time()
subprocess.call(["mogrify", "-format", "bmp", "input-images/{}".format(file_name)])
print("Run took [{:.2f}] seconds".format(time.time() - start))
print("Running mkbitmap...")
start = time.time()
mkbitmap_args = ["mkbitmap", "input-images/{}.bmp".format(base_name),
"-o", "input-images/{}-n.pbm".format(base_name)]
if self.highpass_filter > 0:
mkbitmap_args.append(["-f", self.highpass_filter])
if self.blur > 0:
mkbitmap_args.append(["-b", self.blur])
subprocess.call(mkbitmap_args)
print("Run took [{:.2f}] seconds".format(time.time() - start))
print("Running potrace...")
start = time.time()
subprocess.call(["potrace",
#"-t", "0.1",
"-z", "white",
"-b", "svg",
"input-images/{}-n.pbm".format(base_name),
"--rotate", "0",
"-o", "tmp/conversion-output.svg",
])
print("Run took [{:.2f}] seconds\n".format(time.time() - start))
if __name__ == "__main__": if __name__ == "__main__":

@ -10,7 +10,6 @@ idna==2.8
matplotlib==2.1.1 matplotlib==2.1.1
numpy==1.15.4 numpy==1.15.4
Pillow==5.1.0 Pillow==5.1.0
pkg-resources==0.0.0
pycairo==1.16.2 pycairo==1.16.2
pycparser==2.19 pycparser==2.19
pycrypto==2.6.1 pycrypto==2.6.1

Loading…
Cancel
Save