Commit bbd016dc authored by D1plo1d's avatar D1plo1d

Merge branch 'master' of github.com:kliment/Printrun

parents cebc3212 baa22754
Some cleanup commands : Some cleanup commands:
To add a space after each comma : To add a space after each comma:
sed -e "s/\(\w\),\(\w\)/\1, \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\(\w\),\(\w\)/\1, \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\(\w\),\(\"\)/\1, \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\(\w\),\(\"\)/\1, \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\(\"\),\(\w\)/\1, \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\(\"\),\(\w\)/\1, \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\(\"\),\(\"\)/\1, \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\(\"\),\(\"\)/\1, \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\([)}\]]\),\(\w\)/\1, \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\([)}\]]\),\(\w\)/\1, \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\([)}\]]\),\([\[{(]\)/\1, \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\([)}\]]\),\([\[{(]\)/\1, \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\(\w\),\([\[{(]\)/\1, \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\(\w\),\([\[{(]\)/\1, \2/g" -i *.py printrun/*.py printrun/*/*.py
To add spaces around each = : To add spaces around each =:
sed -e "s/\(\w\)=\(\w\)/\1 = \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\(\w\)=\(\w\)/\1 = \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\(\w\)=\(\"\)/\1 = \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\(\w\)=\(\"\)/\1 = \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\(\w\)=\((\)/\1 = \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\(\w\)=\((\)/\1 = \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\(\w\)=\((\)/\1 = \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\(\w\)=\((\)/\1 = \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\(\w\)=\([\[{(]\)/\1 = \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\(\w\)=\([\[{(]\)/\1 = \2/g" -i *.py printrun/*.py printrun/*/*.py
To add spaces around each == : To add spaces around each ==:
sed -e "s/\(\w\)==\(\w\)/\1 == \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\(\w\)==\(\w\)/\1 == \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\(\w\)==\(\"\)/\1 == \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\(\w\)==\(\"\)/\1 == \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\(\w\)==\((\)/\1 == \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\(\w\)==\((\)/\1 == \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\()\)==\(\w\)/\1 == \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\()\)==\(\w\)/\1 == \2/g" -i *.py printrun/*.py printrun/*/*.py
sed -e "s/\()\)==\((\)/\1 == \2/g" -i *.py printrun/*.py printrun/svg/*.py sed -e "s/\()\)==\((\)/\1 == \2/g" -i *.py printrun/*.py printrun/*/*.py
Obviously this is not a perfect solution, it WILL break the code. Juste check the diff and fix what's wrong before commiting. Obviously this is not a perfect solution, it WILL break the code. Juste check the diff and fix what's wrong before commiting.
Flake8 checking:
Flake8 can be used to check the coding style of the project.
The current source code (as of July 23rd 2013) has been checked using the following command:
flake8 . --statistics --count --ignore=E251,E701,E302,E501 --exclude=.svn,CVS,.bzr,.hg,.git,__pycache__,prontserve.py,./printrun/server,projectlayer.py,./printrun/cairosvg
This call ignores 4 kind of errors (E501: line being greater than 80 chars,
E701: multiple statements on one line (usually this is if ...: ...), E302:
wrong number of blank lines between functions, E251: unexpected spaces around
keywoard/parameter equals), the rest of the errors and warnings should be
killed as much as possible. Long lines should be avoided too.
#!/usr/bin/env python
# This file is part of the Printrun suite.
#
# Printrun is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Printrun is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>.
# Set up Internationalization using gettext
# searching for installed locales on /usr/share; uses relative folder if not found (windows)
from printrun.printrun_utils import install_locale
install_locale('plater')
import wx
import sys
from printrun import gcview
from printrun import gcoder
from printrun.objectplater import Plater
from printrun.gl.libtatlin import actors
class GcodePlater(Plater):
load_wildcard = _("GCODE files (*.gcode;*.GCODE;*.g)")
save_wildcard = _("GCODE files (*.gcode;*.GCODE;*.g)")
def __init__(self, filenames = [], size = (800, 580), callback = None, parent = None, build_dimensions = None):
super(GcodePlater, self).__init__(filenames, size, callback, parent, build_dimensions)
viewer = gcview.GcodeViewPanel(self, build_dimensions = self.build_dimensions)
self.set_viewer(viewer)
self.platform = actors.Platform(self.build_dimensions)
self.platform_object = gcview.GCObject(self.platform)
def get_objects(self):
return [self.platform_object] + self.models.values()
objects = property(get_objects)
def load_file(self, filename):
gcode = gcoder.GCode(open(filename))
model = actors.GcodeModel()
model.load_data(gcode)
obj = gcview.GCObject(model)
obj.gcode = gcode
obj.dims = [gcode.xmin, gcode.xmax,
gcode.ymin, gcode.ymax,
gcode.zmin, gcode.zmax]
obj.centeroffset = [-(obj.dims[1] + obj.dims[0]) / 2,
-(obj.dims[3] + obj.dims[2]) / 2,
0]
self.add_model(filename, obj)
wx.CallAfter(self.Refresh)
# What's hard in there ?
# 1) finding the order in which the objects are printed
# 2) handling layers correctly
# 3) handling E correctly
# 4) handling position shifts: should we either reset absolute 0 using G92
# or should we rewrite all positions ?
# 5) handling the start & end gcode properly ?
# Initial implementation should just print the objects sequentially,
# but the end goal is to have a clean per-layer merge
def export_to(self, name):
with open(name, "w") as f:
models = self.models.values()
last_real_position = None
# Sort models by Z max to print smaller objects first
models.sort(key = lambda x: x.dims[-1])
for model in models:
r = model.rot # no rotation support for now
if r != 0:
print _("Warning: no rotation support for now, "
"object won't be correctly rotated")
o = model.offsets
co = model.centeroffset
offset_pos = last_real_position if last_real_position is not None else [0, 0, 0]
trans = (offset_pos[0] - (o[0] + co[0]),
offset_pos[1] - (o[1] + co[1]),
offset_pos[2] - (o[2] + co[2]))
f.write("G90\n")
f.write("G92 X%.5f Y%.5f Z%.5f E0\n" % trans)
for l in model.gcode:
if l.command != "G28" and (l.command != "92" or not any([l.x, l.y, l.z])):
f.write(l.raw + "\n")
# Find the current real position
for i in xrange(len(model.gcode) - 1, -1, -1):
if model.gcode.lines[i].is_move:
gline = model.gcode.lines[i]
last_real_position = [- trans[0] + gline.current_x,
- trans[1] + gline.current_y,
- trans[2] + gline.current_z]
break
print _("Exported merged G-Codes to %s") % name
if __name__ == '__main__':
app = wx.App(False)
main = GcodePlater(sys.argv[1:])
main.Show()
app.MainLoop()
...@@ -15,23 +15,22 @@ ...@@ -15,23 +15,22 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>. # along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import os
# Set up Internationalization using gettext # Set up Internationalization using gettext
# searching for installed locales on /usr/share; uses relative folder if not found (windows) # searching for installed locales on /usr/share; uses relative folder if not found (windows)
import os, Queue, re
from printrun.printrun_utils import install_locale from printrun.printrun_utils import install_locale
install_locale('plater') install_locale('plater')
import wx import wx
import time import time
import random
import threading import threading
import math import math
import sys import sys
import traceback import traceback
from printrun import stltool from printrun import stltool
from printrun.printrun_utils import pixmapfile from printrun.objectplater import Plater
glview = False glview = False
if "-nogl" not in sys.argv: if "-nogl" not in sys.argv:
...@@ -47,22 +46,9 @@ def evalme(s): ...@@ -47,22 +46,9 @@ def evalme(s):
return eval(s[s.find("(") + 1:s.find(")")]) return eval(s[s.find("(") + 1:s.find(")")])
class stlwrap:
def __init__(self, obj, name = None):
self.obj = obj
self.name = name
if name is None:
self.name = obj.name
def __repr__(self):
return self.name
class showstl(wx.Window): class showstl(wx.Window):
def __init__(self, parent, size, pos): def __init__(self, parent, size, pos):
wx.Window.__init__(self, parent, size = size, pos = pos) wx.Window.__init__(self, parent, size = size, pos = pos)
#self.SetBackgroundColour((0, 0, 0))
#wx.FutureCall(200, self.paint)
self.i = 0 self.i = 0
self.parent = parent self.parent = parent
self.previ = 0 self.previ = 0
...@@ -70,7 +56,6 @@ class showstl(wx.Window): ...@@ -70,7 +56,6 @@ class showstl(wx.Window):
self.Bind(wx.EVT_MOUSE_EVENTS, self.move) self.Bind(wx.EVT_MOUSE_EVENTS, self.move)
self.Bind(wx.EVT_PAINT, self.repaint) self.Bind(wx.EVT_PAINT, self.repaint)
self.Bind(wx.EVT_KEY_DOWN, self.keypress) self.Bind(wx.EVT_KEY_DOWN, self.keypress)
#self.s = stltool.stl("sphere.stl").scale([2, 1, 1])
self.triggered = 0 self.triggered = 0
self.initpos = None self.initpos = None
self.prevsel = -1 self.prevsel = -1
...@@ -81,15 +66,10 @@ class showstl(wx.Window): ...@@ -81,15 +66,10 @@ class showstl(wx.Window):
dc.SelectObject(m.bitmap) dc.SelectObject(m.bitmap)
dc.SetBackground(wx.Brush((0, 0, 0, 0))) dc.SetBackground(wx.Brush((0, 0, 0, 0)))
dc.SetBrush(wx.Brush((0, 0, 0, 255))) dc.SetBrush(wx.Brush((0, 0, 0, 255)))
#dc.DrawRectangle(-1, -1, 10000, 10000)
dc.SetBrush(wx.Brush(wx.Colour(128, 255, 128))) dc.SetBrush(wx.Brush(wx.Colour(128, 255, 128)))
dc.SetPen(wx.Pen(wx.Colour(128, 128, 128))) dc.SetPen(wx.Pen(wx.Colour(128, 128, 128)))
#m.offsets = [10, 10, 0] for i in m.facets:
#print m.offsets, m.dims
for i in m.facets: # random.sample(m.facets, min(100000, len(m.facets))):
dc.DrawPolygon([wx.Point(400 + scale * p[0], (400 - scale * p[1])) for p in i[1]]) dc.DrawPolygon([wx.Point(400 + scale * p[0], (400 - scale * p[1])) for p in i[1]])
#if(time.time()-t)>5:
# break
dc.SelectObject(wx.NullBitmap) dc.SelectObject(wx.NullBitmap)
m.bitmap.SetMask(wx.Mask(m.bitmap, wx.Colour(0, 0, 0, 255))) m.bitmap.SetMask(wx.Mask(m.bitmap, wx.Colour(0, 0, 0, 255)))
...@@ -102,8 +82,7 @@ class showstl(wx.Window): ...@@ -102,8 +82,7 @@ class showstl(wx.Window):
return False return False
name = self.parent.l.GetString(name) name = self.parent.l.GetString(name)
model = self.parent.models[name] model = self.parent.models[name]
model.offsets = [ model.offsets = [model.offsets[0] + delta[0],
model.offsets[0] + delta[0],
model.offsets[1] + delta[1], model.offsets[1] + delta[1],
model.offsets[2] model.offsets[2]
] ]
...@@ -114,9 +93,8 @@ class showstl(wx.Window): ...@@ -114,9 +93,8 @@ class showstl(wx.Window):
if event.ButtonUp(wx.MOUSE_BTN_LEFT): if event.ButtonUp(wx.MOUSE_BTN_LEFT):
if(self.initpos is not None): if(self.initpos is not None):
currentpos = event.GetPositionTuple() currentpos = event.GetPositionTuple()
delta = ( delta = (0.5 * (currentpos[0] - self.initpos[0]),
0.5 * (currentpos[0] - self.initpos[0]), -0.5 * (currentpos[1] - self.initpos[1])
- 0.5 * (currentpos[1] - self.initpos[1])
) )
self.move_shape(delta) self.move_shape(delta)
self.Refresh() self.Refresh()
...@@ -130,8 +108,6 @@ class showstl(wx.Window): ...@@ -130,8 +108,6 @@ class showstl(wx.Window):
dc = wx.ClientDC(self) dc = wx.ClientDC(self)
p = event.GetPositionTuple() p = event.GetPositionTuple()
dc.DrawLine(self.initpos[0], self.initpos[1], p[0], p[1]) dc.DrawLine(self.initpos[0], self.initpos[1], p[0], p[1])
#print math.sqrt((p[0]-self.initpos[0])**2+(p[1]-self.initpos[1])**2)
del dc del dc
else: else:
event.Skip() event.Skip()
...@@ -178,9 +154,7 @@ class showstl(wx.Window): ...@@ -178,9 +154,7 @@ class showstl(wx.Window):
if self.i != self.previ: if self.i != self.previ:
i = self.parent.l.GetSelection() i = self.parent.l.GetSelection()
if i != wx.NOT_FOUND: if i != wx.NOT_FOUND:
#o = self.models[self.l.GetItemText(i)].offsets
self.parent.models[self.parent.l.GetString(i)].rot -= 5 * (self.i - self.previ) self.parent.models[self.parent.l.GetString(i)].rot -= 5 * (self.i - self.previ)
#self.models[self.l.GetItemText(i)].offsets = o
self.previ = self.i self.previ = self.i
self.Refresh() self.Refresh()
...@@ -205,10 +179,8 @@ class showstl(wx.Window): ...@@ -205,10 +179,8 @@ class showstl(wx.Window):
self.paint(dc = dc) self.paint(dc = dc)
def paint(self, coord1 = "x", coord2 = "y", dc = None): def paint(self, coord1 = "x", coord2 = "y", dc = None):
coords = {"x": 0, "y": 1, "z": 2}
if dc is None: if dc is None:
dc = wx.ClientDC(self) dc = wx.ClientDC(self)
offset = [0, 0]
scale = 2 scale = 2
dc.SetPen(wx.Pen(wx.Colour(100, 100, 100))) dc.SetPen(wx.Pen(wx.Colour(100, 100, 100)))
for i in xrange(20): for i in xrange(20):
...@@ -220,7 +192,6 @@ class showstl(wx.Window): ...@@ -220,7 +192,6 @@ class showstl(wx.Window):
dc.DrawLine(i * scale * 50, 0, i * scale * 50, 400) dc.DrawLine(i * scale * 50, 0, i * scale * 50, 400)
dc.SetBrush(wx.Brush(wx.Colour(128, 255, 128))) dc.SetBrush(wx.Brush(wx.Colour(128, 255, 128)))
dc.SetPen(wx.Pen(wx.Colour(128, 128, 128))) dc.SetPen(wx.Pen(wx.Colour(128, 128, 128)))
t = time.time()
dcs = wx.MemoryDC() dcs = wx.MemoryDC()
for m in self.parent.models.values(): for m in self.parent.models.values():
b = m.bitmap b = m.bitmap
...@@ -231,134 +202,20 @@ class showstl(wx.Window): ...@@ -231,134 +202,20 @@ class showstl(wx.Window):
dcs.SelectObject(bm) dcs.SelectObject(bm)
bsz = bm.GetSize() bsz = bm.GetSize()
dc.Blit(scale * m.offsets[0] - bsz[0] / 2, 400 - (scale * m.offsets[1] + bsz[1] / 2), bsz[0], bsz[1], dcs, 0, 0, useMask = 1) dc.Blit(scale * m.offsets[0] - bsz[0] / 2, 400 - (scale * m.offsets[1] + bsz[1] / 2), bsz[0], bsz[1], dcs, 0, 0, useMask = 1)
#for i in m.facets:#random.sample(m.facets, min(100000, len(m.facets))):
# dc.DrawPolygon([wx.Point(offset[0]+scale*m.offsets[0]+scale*p[0], 400-(offset[1]+scale*m.offsets[1]+scale*p[1])) for p in i[1]])
#if(time.time()-t)>5:
# break
del dc del dc
class stlwin(wx.Frame): class StlPlater(Plater):
load_wildcard = _("STL files (*.stl;*.STL)|*.stl;*.STL|OpenSCAD files (*.scad)|*.scad")
save_wildcard = _("STL files (*.stl;*.STL)|*.stl;*.STL")
def __init__(self, filenames = [], size = (800, 580), callback = None, parent = None, build_dimensions = None): def __init__(self, filenames = [], size = (800, 580), callback = None, parent = None, build_dimensions = None):
wx.Frame.__init__(self, parent, title = _("Plate building tool"), size = size) super(StlPlater, self).__init__(filenames, size, callback, parent, build_dimensions)
self.filenames = filenames
if hasattr(sys,"frozen") and sys.frozen=="windows_exe":
self.SetIcon(wx.Icon(sys.executable, wx.BITMAP_TYPE_ICO))
else:
self.SetIcon(wx.Icon(pixmapfile("plater.ico"), wx.BITMAP_TYPE_ICO))
self.mainsizer = wx.BoxSizer(wx.HORIZONTAL)
self.panel = wx.Panel(self, -1, size = (150, 600), pos = (0, 0))
#self.panel.SetBackgroundColour((10, 10, 10))
self.l = wx.ListBox(self.panel, size = (300, 180), pos = (0, 30))
self.cl = wx.Button(self.panel, label = _("Clear"), pos = (0, 205))
self.lb = wx.Button(self.panel, label = _("Load"), pos = (0, 0))
if(callback is None):
self.eb = wx.Button(self.panel, label = _("Export"), pos = (100, 0))
self.eb.Bind(wx.EVT_BUTTON, self.export)
else:
self.eb = wx.Button(self.panel, label = _("Export"), pos = (200, 205))
self.eb.Bind(wx.EVT_BUTTON, self.export)
self.edb = wx.Button(self.panel, label = _("Done"), pos = (100, 0))
self.edb.Bind(wx.EVT_BUTTON, lambda e: self.done(e, callback))
self.eb = wx.Button(self.panel, label = _("Cancel"), pos = (200, 0))
self.eb.Bind(wx.EVT_BUTTON, lambda e: self.Destroy())
self.sb = wx.Button(self.panel, label = _("Snap to Z = 0"), pos = (00, 255))
self.cb = wx.Button(self.panel, label = _("Put at 100, 100"), pos = (0, 280))
self.db = wx.Button(self.panel, label = _("Delete"), pos = (0, 305))
self.ab = wx.Button(self.panel, label = _("Auto"), pos = (0, 330))
self.cl.Bind(wx.EVT_BUTTON, self.clear)
self.lb.Bind(wx.EVT_BUTTON, self.right)
self.sb.Bind(wx.EVT_BUTTON, self.snap)
self.cb.Bind(wx.EVT_BUTTON, self.center)
self.db.Bind(wx.EVT_BUTTON, self.delete)
self.ab.Bind(wx.EVT_BUTTON, self.autoplate)
self.basedir = "."
self.models = {}
#self.SetBackgroundColour((10, 10, 10))
self.mainsizer.Add(self.panel)
#self.mainsizer.AddSpacer(10)
if build_dimensions:
self.build_dimensions = build_dimensions
else:
self.build_dimensions = [200, 200, 100, 0, 0, 0]
if glview: if glview:
self.s = stlview.StlViewPanel(self, (580, 580), build_dimensions = self.build_dimensions) viewer = stlview.StlViewPanel(self, (580, 580), build_dimensions = self.build_dimensions)
else: else:
self.s = showstl(self, (580, 580), (0, 0)) viewer = showstl(self, (580, 580), (0, 0))
self.mainsizer.Add(self.s, 1, wx.EXPAND) self.set_viewer(viewer)
self.SetSizer(self.mainsizer)
#self.mainsizer.Fit(self)
self.Layout()
#self.SetClientSize(size)
def autoplate(self, event):
print _("Autoplating")
separation = 2
bedsize = self.build_dimensions[0:3]
cursor = [0, 0, 0]
newrow = 0
max = [0, 0]
for i in self.models:
self.models[i].offsets[2] = -1.0 * self.models[i].dims[4]
x = abs(self.models[i].dims[0] - self.models[i].dims[1])
y = abs(self.models[i].dims[2] - self.models[i].dims[3])
centre = [x / 2, y / 2]
centreoffset = [self.models[i].dims[0] + centre[0], self.models[i].dims[2] + centre[1]]
if (cursor[0] + x + separation) >= bedsize[0]:
cursor[0] = 0
cursor[1] += newrow + separation
newrow = 0
if (newrow == 0) or (newrow < y):
newrow = y
#To the person who works out why the offsets are applied differently here:
# Good job, it confused the hell out of me.
self.models[i].offsets[0] = cursor[0] + centre[0] - centreoffset[0]
self.models[i].offsets[1] = cursor[1] + centre[1] - centreoffset[1]
if (max[0] == 0) or (max[0] < (cursor[0] + x)):
max[0] = cursor[0] + x
if (max[1] == 0) or (max[1] < (cursor[1] + x)):
max[1] = cursor[1] + x
cursor[0] += x + separation
if (cursor[1] + y) >= bedsize[1]:
print _("Bed full, sorry sir :(")
self.Refresh()
return
centreoffset = [(bedsize[0] - max[0]) / 2, (bedsize[1] - max[1]) / 2]
for i in self.models:
self.models[i].offsets[0] += centreoffset[0]
self.models[i].offsets[1] += centreoffset[1]
self.Refresh()
def clear(self, event):
result = wx.MessageBox(_('Are you sure you want to clear the grid? All unsaved changes will be lost.'), _('Clear the grid?'),
wx.YES_NO | wx.ICON_QUESTION)
if (result == 2):
self.models = {}
self.l.Clear()
self.Refresh()
def center(self, event):
i = self.l.GetSelection()
if i != -1:
m = self.models[self.l.GetString(i)]
m.offsets = [100, 100, m.offsets[2]]
self.Refresh()
def snap(self, event):
i = self.l.GetSelection()
if i != -1:
m = self.models[self.l.GetString(i)]
m.offsets[2] = -1.0 * min(m.facetsminz)[0]
#print m.offsets[2]
self.Refresh()
def delete(self, event):
i = self.l.GetSelection()
if i != -1:
del self.models[self.l.GetString(i)]
self.l.Delete(i)
self.l.Select(self.l.GetCount() - 1)
self.Refresh()
def done(self, event, cb): def done(self, event, cb):
try: try:
...@@ -366,51 +223,18 @@ class stlwin(wx.Frame): ...@@ -366,51 +223,18 @@ class stlwin(wx.Frame):
except: except:
pass pass
name = "tempstl/" + str(int(time.time()) % 10000) + ".stl" name = "tempstl/" + str(int(time.time()) % 10000) + ".stl"
self.writefiles(name) self.export_to(name)
if cb is not None: if cb is not None:
cb(name) cb(name)
self.Destroy() self.Destroy()
def export(self, event): def load_file(self, filename):
dlg = wx.FileDialog(self, _("Pick file to save to"), self.basedir, style = wx.FD_SAVE)
dlg.SetWildcard(_("STL files (*.stl;*.STL)|*.stl;*.STL"))
if(dlg.ShowModal() == wx.ID_OK):
name = dlg.GetPath()
self.writefiles(name)
dlg.Destroy()
def writefiles(self, name):
sf = open(name.replace(".", "_") + ".scad", "w")
facets = []
for i in self.models.values():
r = i.rot
o = i.offsets
sf.write('translate([%s, %s, %s]) rotate([0, 0, %s]) import_stl("%s");\n' % (str(o[0]), str(o[1]), str(o[2]), r, os.path.split(i.filename)[1]))
if r != 0:
i = i.rotate([0, 0, r])
if o != [0, 0, 0]:
i = i.translate([o[0], o[1], o[2]])
facets += i.facets
sf.close()
stltool.emitstl(name, facets, "plater_export")
print _("wrote %s") % name
def right(self, event):
dlg = wx.FileDialog(self, _("Pick file to load"), self.basedir, style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
dlg.SetWildcard(_("STL files (*.stl;*.STL)|*.stl;*.STL|OpenSCAD files (*.scad)|*.scad"))
if dlg.ShowModal() == wx.ID_OK:
name = dlg.GetPath()
self.load_file(event, name)
dlg.Destroy()
def load_file(self, event, filename):
if filename.lower().endswith(".stl"): if filename.lower().endswith(".stl"):
self.load_stl(event, filename) self.load_stl(filename)
elif filename.lower().endswith(".scad"): elif filename.lower().endswith(".scad"):
self.load_scad(event, filename) self.load_scad(filename)
def load_scad(self, event, name): def load_scad(self, name):
lf = open(name) lf = open(name)
s = [i.replace("\n", "").replace("\r", "").replace(";", "") for i in lf if "stl" in i] s = [i.replace("\n", "").replace("\r", "").replace(";", "") for i in lf if "stl" in i]
lf.close() lf.close()
...@@ -437,33 +261,30 @@ class stlwin(wx.Frame): ...@@ -437,33 +261,30 @@ class stlwin(wx.Frame):
stl_full_path = os.path.join(stl_path[0], str(stl_file)) stl_full_path = os.path.join(stl_path[0], str(stl_file))
self.load_stl_into_model(stl_full_path, stl_file, translate_list, rotate_list[2]) self.load_stl_into_model(stl_full_path, stl_file, translate_list, rotate_list[2])
def load_stl(self, event, name): def load_stl(self, name):
if not(os.path.exists(name)): if not os.path.exists(name):
print _("Couldn't load non-existing file %s") % name
return return
path = os.path.split(name)[0] path = os.path.split(name)[0]
self.basedir = path self.basedir = path
t = time.time()
#print name
if name.lower().endswith(".stl"): if name.lower().endswith(".stl"):
#Filter out the path, just show the STL filename. #Filter out the path, just show the STL filename.
self.load_stl_into_model(name, name) self.load_stl_into_model(name, name)
self.Refresh() self.Refresh()
#print time.time()-t
def load_stl_into_model(self, path, name, offset = [0, 0, 0], rotation = 0, scale = [1.0, 1.0, 1.0]): def load_stl_into_model(self, path, name, offset = [0, 0, 0], rotation = 0, scale = [1.0, 1.0, 1.0]):
newname = os.path.split(name.lower())[1] model = stltool.stl(path)
c = 1 model.offsets = list(offset)
while newname in self.models: model.rot = rotation
newname = os.path.split(name.lower())[1] model.scale = list(scale)
newname = newname + "(%d)" % c model.filename = name
c += 1 minx = float("inf")
self.models[newname] = stltool.stl(path) miny = float("inf")
self.models[newname].offsets = offset minz = float("inf")
self.models[newname].rot = rotation maxx = float("-inf")
self.models[newname].scale = scale maxy = float("-inf")
self.models[newname].filename = name maxz = float("-inf")
minx, miny, minz, maxx, maxy, maxz = (10000, 10000, 10000, 0, 0, 0) for i in model.facets:
for i in self.models[newname].facets:
for j in i[1]: for j in i[1]:
if j[0] < minx: if j[0] < minx:
minx = j[0] minx = j[0]
...@@ -477,24 +298,42 @@ class stlwin(wx.Frame): ...@@ -477,24 +298,42 @@ class stlwin(wx.Frame):
maxy = j[1] maxy = j[1]
if j[2] > maxz: if j[2] > maxz:
maxz = j[2] maxz = j[2]
self.models[newname].dims = [minx, maxx, miny, maxy, minz, maxz] model.dims = [minx, maxx, miny, maxy, minz, maxz]
#if minx < 0: self.add_model(name, model)
# self.models[newname].offsets[0] = -minx model.centeroffset = [-(model.dims[1] + model.dims[0]) / 2,
#if miny < 0: -(model.dims[3] + model.dims[2]) / 2,
# self.models[newname].offsets[1] = -miny 0]
self.s.drawmodel(self.models[newname], 2) self.s.drawmodel(model, 2)
#print time.time() - t def export_to(self, name):
self.l.Append(newname) sf = open(name.replace(".", "_") + ".scad", "w")
i = self.l.GetSelection() facets = []
if i == wx.NOT_FOUND: for model in self.models.values():
self.l.Select(0) r = model.rot
rot = [0, 0, r] if r else None
self.l.Select(self.l.GetCount() - 1) o = model.offsets
co = model.centeroffset
sf.write("translate([%s, %s, %s])"
"rotate([0, 0, %s])"
"translate([%s, %s, %s])"
"import(\"%s\");\n" % (o[0], o[1], o[2],
r,
co[0], co[1], co[2],
model.filename))
if any(co):
model = model.translate(co)
if rot:
model = model.rotate(rot)
if any(o):
model = model.translate(o)
facets += model.facets
sf.close()
stltool.emitstl(name, facets, "plater_export")
print _("Wrote plate to %s") % name
if __name__ == '__main__': if __name__ == '__main__':
app = wx.App(False) app = wx.App(False)
main = stlwin(sys.argv[1:]) main = StlPlater(sys.argv[1:])
main.Show() main.Show()
app.MainLoop() app.MainLoop()
...@@ -19,14 +19,21 @@ from serial import Serial, SerialException ...@@ -19,14 +19,21 @@ from serial import Serial, SerialException
from select import error as SelectError from select import error as SelectError
from threading import Thread, Lock from threading import Thread, Lock
from Queue import Queue, Empty as QueueEmpty from Queue import Queue, Empty as QueueEmpty
import time, getopt, sys import time
import platform, os, traceback, errno import getopt
import sys
import platform
import os
import traceback
import errno
import socket import socket
import re import re
from functools import wraps from functools import wraps
from collections import deque from collections import deque
from printrun.GCodeAnalyzer import GCodeAnalyzer from printrun.GCodeAnalyzer import GCodeAnalyzer
from printrun import gcoder from printrun import gcoder
from printrun.printrun_utils import install_locale
install_locale('pronterface')
def locked(f): def locked(f):
@wraps(f) @wraps(f)
...@@ -52,15 +59,18 @@ def disable_hup(port): ...@@ -52,15 +59,18 @@ def disable_hup(port):
class printcore(): class printcore():
def __init__(self, port = None, baud = None): def __init__(self, port = None, baud = None):
"""Initializes a printcore instance. Pass the port and baud rate to connect immediately """Initializes a printcore instance. Pass the port and baud rate to
""" connect immediately"""
self.baud = None self.baud = None
self.port = None self.port = None
self.analyzer = GCodeAnalyzer() self.analyzer = GCodeAnalyzer()
self.printer = None #Serial instance connected to the printer, None when disconnected self.printer = None # Serial instance connected to the printer,
self.clear = 0 #clear to send, enabled after responses # should be None when disconnected
self.online = False #The printer has responded to the initial command and is active self.clear = 0 # clear to send, enabled after responses
self.printing = False #is a print currently running, true if printing, false if paused self.online = False # The printer has responded to the initial command
# and is active
self.printing = False # is a print currently running, true if printing
# , false if paused
self.mainqueue = None self.mainqueue = None
self.priqueue = Queue(0) self.priqueue = Queue(0)
self.queueindex = 0 self.queueindex = 0
...@@ -71,18 +81,18 @@ class printcore(): ...@@ -71,18 +81,18 @@ class printcore():
self.log = deque(maxlen = 10000) self.log = deque(maxlen = 10000)
self.sent = [] self.sent = []
self.writefailures = 0 self.writefailures = 0
self.tempcb = None #impl (wholeline) self.tempcb = None # impl (wholeline)
self.recvcb = None #impl (wholeline) self.recvcb = None # impl (wholeline)
self.sendcb = None #impl (wholeline) self.sendcb = None # impl (wholeline)
self.preprintsendcb = None #impl (wholeline) self.preprintsendcb = None # impl (wholeline)
self.printsendcb = None #impl (wholeline) self.printsendcb = None # impl (wholeline)
self.layerchangecb = None #impl (wholeline) self.layerchangecb = None # impl (wholeline)
self.errorcb = None #impl (wholeline) self.errorcb = None # impl (wholeline)
self.startcb = None #impl () self.startcb = None # impl ()
self.endcb = None #impl () self.endcb = None # impl ()
self.onlinecb = None #impl () self.onlinecb = None # impl ()
self.loud = False #emit sent and received lines to terminal self.loud = False # emit sent and received lines to terminal
self.greetings = ['start','Grbl '] self.greetings = ['start', 'Grbl ']
self.wait = 0 # default wait period for send(), send_now() self.wait = 0 # default wait period for send(), send_now()
self.read_thread = None self.read_thread = None
self.stop_read_thread = False self.stop_read_thread = False
...@@ -144,7 +154,8 @@ class printcore(): ...@@ -144,7 +154,8 @@ class printcore():
pass pass
self.writefailures = 0 self.writefailures = 0
if not is_serial: if not is_serial:
self.printer_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.printer_tcp = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
self.timeout = 0.25 self.timeout = 0.25
self.printer_tcp.settimeout(1.0) self.printer_tcp.settimeout(1.0)
try: try:
...@@ -162,7 +173,9 @@ class printcore(): ...@@ -162,7 +173,9 @@ class printcore():
disable_hup(self.port) disable_hup(self.port)
self.printer_tcp = None self.printer_tcp = None
try: try:
self.printer = Serial(port = self.port, baudrate = self.baud, timeout = 0.25) self.printer = Serial(port = self.port,
baudrate = self.baud,
timeout = 0.25)
except SerialException as e: except SerialException as e:
print _("Could not connect to %s at baudrate %s:") % (self.port, self.baud) print _("Could not connect to %s at baudrate %s:") % (self.port, self.baud)
self.printer = None self.printer = None
...@@ -199,27 +212,29 @@ class printcore(): ...@@ -199,27 +212,29 @@ class printcore():
return line return line
except SelectError as e: except SelectError as e:
if 'Bad file descriptor' in e.args[1]: if 'Bad file descriptor' in e.args[1]:
print "Can't read from printer (disconnected?) (SelectError {0}): {1}".format(e.errno, e.strerror) print _("Can't read from printer (disconnected?) (SelectError {0}): {1}").format(e.errno, e.strerror)
return None return None
else: else:
print "SelectError ({0}): {1}".format(e.errno, e.strerror) print _("SelectError ({0}): {1}").format(e.errno, e.strerror)
raise raise
except SerialException as e: except SerialException as e:
print "Can't read from printer (disconnected?) (SerialException): {0}".format(e) print _("Can't read from printer (disconnected?) (SerialException): {0}").format(e)
return None return None
except socket.error as e: except socket.error as e:
print "Can't read from printer (disconnected?) (Socket error {0}): {1}".format(e.errno, e.strerror) print _("Can't read from printer (disconnected?) (Socket error {0}): {1}").format(e.errno, e.strerror)
return None return None
except OSError as e: except OSError as e:
if e.errno == errno.EAGAIN: # Not a real error, no data was available if e.errno == errno.EAGAIN: # Not a real error, no data was available
return "" return ""
print "Can't read from printer (disconnected?) (OS Error {0}): {1}".format(e.errno, e.strerror) print _("Can't read from printer (disconnected?) (OS Error {0}): {1}").format(e.errno, e.strerror)
return None return None
def _listen_can_continue(self): def _listen_can_continue(self):
if self.printer_tcp: if self.printer_tcp:
return not self.stop_read_thread and self.printer return not self.stop_read_thread and self.printer
return not self.stop_read_thread and self.printer and self.printer.isOpen() return (not self.stop_read_thread
and self.printer
and self.printer.isOpen())
def _listen_until_online(self): def _listen_until_online(self):
while not self.online and self._listen_can_continue(): while not self.online and self._listen_can_continue():
...@@ -227,7 +242,7 @@ class printcore(): ...@@ -227,7 +242,7 @@ class printcore():
empty_lines = 0 empty_lines = 0
while self._listen_can_continue(): while self._listen_can_continue():
line = self._readline() line = self._readline()
if line == None: break # connection problem if line is None: break # connection problem
# workaround cases where M105 was sent before printer Serial # workaround cases where M105 was sent before printer Serial
# was online an empty line means read timeout was reached, # was online an empty line means read timeout was reached,
# meaning no data was received thus we count those empty lines, # meaning no data was received thus we count those empty lines,
...@@ -241,7 +256,8 @@ class printcore(): ...@@ -241,7 +256,8 @@ class printcore():
empty_lines += 1 empty_lines += 1
if empty_lines == 15: break if empty_lines == 15: break
else: empty_lines = 0 else: empty_lines = 0
if line.startswith(tuple(self.greetings)) or line.startswith('ok') or "T:" in line: if line.startswith(tuple(self.greetings)) \
or line.startswith('ok') or "T:" in line:
if self.onlinecb: if self.onlinecb:
try: self.onlinecb() try: self.onlinecb()
except: pass except: pass
...@@ -256,7 +272,7 @@ class printcore(): ...@@ -256,7 +272,7 @@ class printcore():
self._listen_until_online() self._listen_until_online()
while self._listen_can_continue(): while self._listen_can_continue():
line = self._readline() line = self._readline()
if line == None: if line is None:
break break
if line.startswith('DEBUG_'): if line.startswith('DEBUG_'):
continue continue
...@@ -274,7 +290,8 @@ class printcore(): ...@@ -274,7 +290,8 @@ class printcore():
# Teststrings for resend parsing # Firmware exp. result # Teststrings for resend parsing # Firmware exp. result
# line="rs N2 Expected checksum 67" # Teacup 2 # line="rs N2 Expected checksum 67" # Teacup 2
if line.lower().startswith("resend") or line.startswith("rs"): if line.lower().startswith("resend") or line.startswith("rs"):
line = line.replace("N:"," ").replace("N"," ").replace(":"," ") for haystack in ["N:", "N", ":"]:
line = line.replace(haystack, " ")
linewords = line.split() linewords = line.split()
while len(linewords) != 0: while len(linewords) != 0:
try: try:
...@@ -311,13 +328,14 @@ class printcore(): ...@@ -311,13 +328,14 @@ class printcore():
time.sleep(0.001) time.sleep(0.001)
def _checksum(self, command): def _checksum(self, command):
return reduce(lambda x, y:x^y, map(ord, command)) return reduce(lambda x, y: x ^ y, map(ord, command))
def startprint(self, gcode, startindex = 0): def startprint(self, gcode, startindex = 0):
"""Start a print, gcode is an array of gcode commands. """Start a print, gcode is an array of gcode commands.
returns True on success, False if already printing. returns True on success, False if already printing.
The print queue will be replaced with the contents of the data array, the next line will be set to 0 and the firmware notified. The print queue will be replaced with the contents of the data array,
Printing will then start in a parallel thread. the next line will be set to 0 and the firmware notified. Printing
will then start in a parallel thread.
""" """
if self.printing or not self.online or not self.printer: if self.printing or not self.online or not self.printer:
return False return False
...@@ -331,25 +349,23 @@ class printcore(): ...@@ -331,25 +349,23 @@ class printcore():
return True return True
self.clear = False self.clear = False
resuming = (startindex != 0) resuming = (startindex != 0)
self.print_thread = Thread(target = self._print, kwargs = {"resuming": resuming}) self.print_thread = Thread(target = self._print,
kwargs = {"resuming": resuming})
self.print_thread.start() self.print_thread.start()
return True return True
# run a simple script if it exists, no multithreading # run a simple script if it exists, no multithreading
def runSmallScript(self, filename): def runSmallScript(self, filename):
if filename == None: return if filename is None: return
f = None f = None
try: try:
f = open(filename) with open(filename) as f:
except:
pass
if f != None:
for i in f: for i in f:
l = i.replace("\n", "") l = i.replace("\n", "")
l = l[:l.find(";")] #remove comment l = l[:l.find(";")] # remove comments
self.send_now(l) self.send_now(l)
f.close() except:
pass
def pause(self): def pause(self):
"""Pauses the print, saving the current position. """Pauses the print, saving the current position.
...@@ -358,7 +374,8 @@ class printcore(): ...@@ -358,7 +374,8 @@ class printcore():
self.paused = True self.paused = True
self.printing = False self.printing = False
# try joining the print thread: enclose it in try/except because we might be calling it from the thread itself # try joining the print thread: enclose it in try/except because we
# might be calling it from the thread itself
try: try:
self.print_thread.join() self.print_thread.join()
except: except:
...@@ -367,42 +384,47 @@ class printcore(): ...@@ -367,42 +384,47 @@ class printcore():
self.print_thread = None self.print_thread = None
# saves the status # saves the status
self.pauseX = self.analyzer.x-self.analyzer.xOffset; self.pauseX = self.analyzer.x - self.analyzer.xOffset
self.pauseY = self.analyzer.y-self.analyzer.yOffset; self.pauseY = self.analyzer.y - self.analyzer.yOffset
self.pauseZ = self.analyzer.z-self.analyzer.zOffset; self.pauseZ = self.analyzer.z - self.analyzer.zOffset
self.pauseE = self.analyzer.e-self.analyzer.eOffset; self.pauseE = self.analyzer.e - self.analyzer.eOffset
self.pauseF = self.analyzer.f; self.pauseF = self.analyzer.f
self.pauseRelative = self.analyzer.relative; self.pauseRelative = self.analyzer.relative
def resume(self): def resume(self):
"""Resumes a paused print. """Resumes a paused print.
""" """
if not self.paused: return False if not self.paused: return False
if self.paused: if self.paused:
#restores the status # restores the status
self.send_now("G90") # go to absolute coordinates self.send_now("G90") # go to absolute coordinates
xyFeedString = "" xyFeedString = ""
zFeedString = "" zFeedString = ""
if self.xy_feedrate != None: xyFeedString = " F" + str(self.xy_feedrate) if self.xy_feedrate is not None:
if self.z_feedrate != None: zFeedString = " F" + str(self.z_feedrate) xyFeedString = " F" + str(self.xy_feedrate)
if self.z_feedrate is not None:
zFeedString = " F" + str(self.z_feedrate)
self.send_now("G1 X" + str(self.pauseX) + " Y" + str(self.pauseY) + xyFeedString) self.send_now("G1 X%s Y%s%s" % (self.pauseX, self.pauseY,
xyFeedString))
self.send_now("G1 Z" + str(self.pauseZ) + zFeedString) self.send_now("G1 Z" + str(self.pauseZ) + zFeedString)
self.send_now("G92 E" + str(self.pauseE)) self.send_now("G92 E" + str(self.pauseE))
if self.pauseRelative: self.send_now("G91") # go back to relative if needed # go back to relative if needed
#reset old feed rate if self.pauseRelative: self.send_now("G91")
# reset old feed rate
self.send_now("G1 F" + str(self.pauseF)) self.send_now("G1 F" + str(self.pauseF))
self.paused = False self.paused = False
self.printing = True self.printing = True
self.print_thread = Thread(target = self._print, kwargs = {"resuming": True}) self.print_thread = Thread(target = self._print,
kwargs = {"resuming": True})
self.print_thread.start() self.print_thread.start()
def send(self, command, wait = 0): def send(self, command, wait = 0):
"""Adds a command to the checksummed main command queue if printing, or sends the command immediately if not printing """Adds a command to the checksummed main command queue if printing, or
""" sends the command immediately if not printing"""
if self.online: if self.online:
if self.printing: if self.printing:
...@@ -413,8 +435,8 @@ class printcore(): ...@@ -413,8 +435,8 @@ class printcore():
print "Not connected to printer." print "Not connected to printer."
def send_now(self, command, wait = 0): def send_now(self, command, wait = 0):
"""Sends a command to the printer ahead of the command queue, without a checksum """Sends a command to the printer ahead of the command queue, without a
""" checksum"""
if self.online: if self.online:
self.priqueue.put_nowait(command) self.priqueue.put_nowait(command)
else: else:
...@@ -451,7 +473,7 @@ class printcore(): ...@@ -451,7 +473,7 @@ class printcore():
def processHostCommand(self, command): def processHostCommand(self, command):
command = command.lstrip() command = command.lstrip()
if command.startswith(";@pause"): if command.startswith(";@pause"):
if self.pronterface != None: if self.pronterface is not None:
self.pronterface.pause(None) self.pronterface.pause(None)
else: else:
self.pause() self.pause()
...@@ -489,7 +511,7 @@ class printcore(): ...@@ -489,7 +511,7 @@ class printcore():
else: else:
next_gline = None next_gline = None
gline = self.preprintsendcb(gline, next_gline) gline = self.preprintsendcb(gline, next_gline)
if gline == None: if gline is None:
self.queueindex += 1 self.queueindex += 1
self.clear = True self.clear = True
return return
...@@ -526,7 +548,8 @@ class printcore(): ...@@ -526,7 +548,8 @@ class printcore():
self.sentlines[lineno] = command self.sentlines[lineno] = command
if self.printer: if self.printer:
self.sent.append(command) self.sent.append(command)
self.analyzer.Analyze(command) # run the command through the analyzer # run the command through the analyzer
self.analyzer.Analyze(command)
if self.loud: if self.loud:
print "SENT:", command print "SENT:", command
if self.sendcb: if self.sendcb:
...@@ -537,13 +560,13 @@ class printcore(): ...@@ -537,13 +560,13 @@ class printcore():
if self.printer_tcp: self.printer.flush() if self.printer_tcp: self.printer.flush()
self.writefailures = 0 self.writefailures = 0
except socket.error as e: except socket.error as e:
print "Can't write to printer (disconnected?) (Socket error {0}): {1}".format(e.errno, e.strerror) print _("Can't write to printer (disconnected?) (Socket error {0}): {1}").format(e.errno, e.strerror)
self.writefailures += 1 self.writefailures += 1
except SerialException as e: except SerialException as e:
print "Can't write to printer (disconnected?) (SerialException): {0}".format(e) print _("Can't write to printer (disconnected?) (SerialException): {0}").format(e)
self.writefailures += 1 self.writefailures += 1
except RuntimeError as e: except RuntimeError as e:
print "Socket connection broken, disconnected. ({0}): {1}".format(e.errno, e.strerror) print _("Socket connection broken, disconnected. ({0}): {1}").format(e.errno, e.strerror)
self.writefailures += 1 self.writefailures += 1
if __name__ == '__main__': if __name__ == '__main__':
...@@ -559,16 +582,17 @@ if __name__ == '__main__': ...@@ -559,16 +582,17 @@ if __name__ == '__main__':
for o, a in opts: for o, a in opts:
if o in ('-h', '--help'): if o in ('-h', '--help'):
# FIXME: Fix help # FIXME: Fix help
print "Opts are: --help , -b --baud = baudrate, -v --verbose, -s --statusreport" print "Opts are: --help, -b --baud = baudrate, -v --verbose, \
-s --statusreport"
sys.exit(1) sys.exit(1)
if o in ('-b', '--baud'): if o in ('-b', '--baud'):
baud = int(a) baud = int(a)
if o in ('-v','--verbose'): if o in ('-v', '--verbose'):
loud = True loud = True
elif o in ('-s','--statusreport'): elif o in ('-s', '--statusreport'):
statusreport = True statusreport = True
if len (args) > 1: if len(args) > 1:
port = args[-2] port = args[-2]
filename = args[-1] filename = args[-1]
print "Printing: %s on %s with baudrate %d" % (filename, port, baud) print "Printing: %s on %s with baudrate %d" % (filename, port, baud)
...@@ -590,7 +614,9 @@ if __name__ == '__main__': ...@@ -590,7 +614,9 @@ if __name__ == '__main__':
while p.printing: while p.printing:
time.sleep(1) time.sleep(1)
if statusreport: if statusreport:
sys.stdout.write("Progress: %02.1f%%\r" % (100 * float(p.queueindex) / len(p.mainqueue),) ) sys.stdout.write("Progress: %02.1f%%\r"
% (100 * float(p.queueindex)
/ len(p.mainqueue),))
sys.stdout.flush() sys.stdout.flush()
p.disconnect() p.disconnect()
sys.exit(0) sys.exit(0)
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import re
import gcoder import gcoder
class GCodeAnalyzer(): class GCodeAnalyzer():
...@@ -81,9 +80,8 @@ class GCodeAnalyzer(): ...@@ -81,9 +80,8 @@ class GCodeAnalyzer():
self.lastY = self.y self.lastY = self.y
self.lastZ = self.z self.lastZ = self.z
self.lastE = self.e self.lastE = self.e
eChanged = False;
code_f = gline.f code_f = gline.f
if code_f != None: if code_f is not None:
self.f = code_f self.f = code_f
code_x = gline.x code_x = gline.x
...@@ -92,27 +90,24 @@ class GCodeAnalyzer(): ...@@ -92,27 +90,24 @@ class GCodeAnalyzer():
code_e = gline.e code_e = gline.e
if self.relative: if self.relative:
if code_x != None: self.x += code_x if code_x is not None: self.x += code_x
if code_y != None: self.y += code_y if code_y is not None: self.y += code_y
if code_z != None: self.z += code_z if code_z is not None: self.z += code_z
if code_e != None: if code_e is not None:
if code_e != 0: if code_e != 0:
eChanged = True
self.e += code_e self.e += code_e
else: else:
# absolute coordinates # absolute coordinates
if code_x != None: self.x = self.xOffset + code_x if code_x is not None: self.x = self.xOffset + code_x
if code_y != None: self.y = self.yOffset + code_y if code_y is not None: self.y = self.yOffset + code_y
if code_z != None: self.z = self.zOffset + code_z if code_z is not None: self.z = self.zOffset + code_z
if code_e != None: if code_e is not None:
if self.eRelative: if self.eRelative:
if code_e != 0: if code_e != 0:
eChanged = True
self.e += code_e self.e += code_e
else: else:
# e is absolute. Is it changed? # e is absolute. Is it changed?
if self.e != self.eOffset + code_e: if self.e != self.eOffset + code_e:
eChanged = True
self.e = self.eOffset + code_e self.e = self.eOffset + code_e
#limit checking #limit checking
""" """
...@@ -137,20 +132,20 @@ class GCodeAnalyzer(): ...@@ -137,20 +132,20 @@ class GCodeAnalyzer():
code_z = gline.z code_z = gline.z
code_e = gline.e code_e = gline.e
homeAll = False homeAll = False
if code_x == None and code_y == None and code_z == None: homeAll = True if code_x is None and code_y is None and code_z is None: homeAll = True
if code_x != None or homeAll: if code_x is not None or homeAll:
self.hasHomeX = True self.hasHomeX = True
self.xOffset = 0 self.xOffset = 0
self.x = self.homeX self.x = self.homeX
if code_y != None or homeAll: if code_y is not None or homeAll:
self.hasHomeY = True self.hasHomeY = True
self.yOffset = 0 self.yOffset = 0
self.y = self.homeY self.y = self.homeY
if code_z != None or homeAll: if code_z is not None or homeAll:
self.hasHomeZ = True self.hasHomeZ = True
self.zOffset = 0 self.zOffset = 0
self.z = self.homeZ self.z = self.homeZ
if code_e != None: if code_e is not None:
self.eOffset = 0 self.eOffset = 0
self.e = 0 self.e = 0
elif code_g == 162: elif code_g == 162:
...@@ -162,16 +157,16 @@ class GCodeAnalyzer(): ...@@ -162,16 +157,16 @@ class GCodeAnalyzer():
code_y = gline.y code_y = gline.y
code_z = gline.z code_z = gline.z
homeAll = False homeAll = False
if code_x == None and code_y == None and code_z == None: homeAll = True if code_x is None and code_y is None and code_z is None: homeAll = True
if code_x != None or homeAll: if code_x is not None or homeAll:
self.hasHomeX = True self.hasHomeX = True
self.xOffset = 0 self.xOffset = 0
self.x = self.maxX self.x = self.maxX
if code_y != None or homeAll: if code_y is not None or homeAll:
self.hasHomeY = True self.hasHomeY = True
self.yOffset = 0 self.yOffset = 0
self.y = self.maxY self.y = self.maxY
if code_z != None or homeAll: if code_z is not None or homeAll:
self.hasHomeZ = True self.hasHomeZ = True
self.zOffset = 0 self.zOffset = 0
self.z = self.maxZ self.z = self.maxZ
...@@ -182,20 +177,20 @@ class GCodeAnalyzer(): ...@@ -182,20 +177,20 @@ class GCodeAnalyzer():
code_y = gline.y code_y = gline.y
code_z = gline.z code_z = gline.z
code_e = gline.e code_e = gline.e
if code_x != None: if code_x is not None:
self.xOffset = self.x - float(code_x) self.xOffset = self.x - float(code_x)
self.x = self.xOffset self.x = self.xOffset
if code_y != None: if code_y is not None:
self.yOffset = self.y - float(code_y) self.yOffset = self.y - float(code_y)
self.y = self.yOffset self.y = self.yOffset
if code_z != None: if code_z is not None:
self.zOffset = self.z - float(code_z) self.zOffset = self.z - float(code_z)
self.z = self.zOffset self.z = self.zOffset
if code_e != None: if code_e is not None:
self.xOffset = self.e - float(code_e) self.xOffset = self.e - float(code_e)
self.e = self.eOffset self.e = self.eOffset
#End code_g != None #End code_g is not None
if code_m != None: if code_m is not None:
if code_m == 82: self.eRelative = False if code_m == 82: self.eRelative = False
elif code_m == 83: self.eRelative = True elif code_m == 83: self.eRelative = True
......
...@@ -38,15 +38,14 @@ class SkeinforgeQuickEditDialog(wx.Dialog): ...@@ -38,15 +38,14 @@ class SkeinforgeQuickEditDialog(wx.Dialog):
NOTE: Skeinforge is tightly integrated with Tkinter and there appears to be a dependency which stops radio-button values from being saved. NOTE: Skeinforge is tightly integrated with Tkinter and there appears to be a dependency which stops radio-button values from being saved.
Perhaps this can be solved, but at the moment this dialog cannot modify radio button values. One will have to use the main Skeinforge application. Perhaps this can be solved, but at the moment this dialog cannot modify radio button values. One will have to use the main Skeinforge application.
""" """
self.moduleSettingsMap = { self.moduleSettingsMap = {'dimension': ['Filament Diameter (mm):', 'Retraction Distance (millimeters):', 'Retraction Distance (millimeters):', 'Extruder Retraction Speed (mm/s):'],
'dimension':['Filament Diameter (mm):','Retraction Distance (millimeters):', 'Retraction Distance (millimeters):','Extruder Retraction Speed (mm/s):'], 'carve': ['Layer Height = Extrusion Thickness (mm):', 'Extrusion Width (mm):'],
'carve':['Layer Height = Extrusion Thickness (mm):', 'Extrusion Width (mm):'], 'chamber': ['Heated PrintBed Temperature (Celcius):', 'Turn print Bed Heater Off at Shut Down', 'Turn Extruder Heater Off at Shut Down'],
'chamber':['Heated PrintBed Temperature (Celcius):', 'Turn print Bed Heater Off at Shut Down', 'Turn Extruder Heater Off at Shut Down'], 'cool': ['Activate Cool.. but use with a fan!', 'Use Cool if layer takes shorter than(seconds):'],
'cool':['Activate Cool.. but use with a fan!', 'Use Cool if layer takes shorter than(seconds):'], 'fill': ['Activate Fill:', 'Infill Solidity (ratio):', 'Fully filled Layers (each top and bottom):', 'Extra Shells on Sparse Layer (layers):', 'Extra Shells on Alternating Solid Layer (layers):'],
'fill':['Activate Fill:', 'Infill Solidity (ratio):', 'Fully filled Layers (each top and bottom):', 'Extra Shells on Sparse Layer (layers):', 'Extra Shells on Alternating Solid Layer (layers):'], 'multiply': ['Number of Columns (integer):', 'Number of Rows (integer):'],
'multiply':['Number of Columns (integer):', 'Number of Rows (integer):'], 'raft': ['First Layer Main Feedrate (mm/s):', 'First Layer Perimeter Feedrate (mm/s):', 'First Layer Flow Rate Infill(scaler):', 'First Layer Flow Rate Perimeter(scaler):'],
'raft':['First Layer Main Feedrate (mm/s):','First Layer Perimeter Feedrate (mm/s):','First Layer Flow Rate Infill(scaler):','First Layer Flow Rate Perimeter(scaler):',], 'speed': ['Main Feed Rate (mm/s):', 'Main Flow Rate (scaler):', 'Perimeter Feed Rate (mm/s):', 'Perimeter Flow Rate (scaler):', 'Travel Feed Rate (mm/s):']
'speed':['Main Feed Rate (mm/s):','Main Flow Rate (scaler):','Perimeter Feed Rate (mm/s):','Perimeter Flow Rate (scaler):','Travel Feed Rate (mm/s):']
} }
self.scrollbarPanel = wx.ScrolledWindow(self, -1, style = wx.TAB_TRAVERSAL) self.scrollbarPanel = wx.ScrolledWindow(self, -1, style = wx.TAB_TRAVERSAL)
...@@ -140,7 +139,7 @@ class SkeinforgeQuickEditDialog(wx.Dialog): ...@@ -140,7 +139,7 @@ class SkeinforgeQuickEditDialog(wx.Dialog):
isDirty = False isDirty = False
for setting in settings.getReadRepository(repo).preferences: for setting in settings.getReadRepository(repo).preferences:
if setting.name == settingName: if setting.name == settingName:
if setting.value == None or str(x.GetValue()) != str(setting.value): if setting.value is None or str(x.GetValue()) != str(setting.value):
print('Saving ... ' + settingName + ' = ' + str(x.GetValue())) print('Saving ... ' + settingName + ' = ' + str(x.GetValue()))
setting.value = x.GetValue() setting.value = x.GetValue()
isDirty = True isDirty = True
......
...@@ -62,14 +62,14 @@ class BufferedCanvas(wx.Panel): ...@@ -62,14 +62,14 @@ class BufferedCanvas(wx.Panel):
ID=-1, ID=-1,
pos = wx.DefaultPosition, pos = wx.DefaultPosition,
size = wx.DefaultSize, size = wx.DefaultSize,
style = wx.NO_FULL_REPAINT_ON_RESIZE|wx.WANTS_CHARS): style = wx.NO_FULL_REPAINT_ON_RESIZE | wx.WANTS_CHARS):
wx.Panel.__init__(self, parent, ID, pos, size, style) wx.Panel.__init__(self, parent, ID, pos, size, style)
# Bind events # Bind events
self.Bind(wx.EVT_PAINT, self.onPaint) self.Bind(wx.EVT_PAINT, self.onPaint)
# Disable background erasing (flicker-licious) # Disable background erasing (flicker-licious)
def disable_event(*pargs,**kwargs): def disable_event(*pargs, **kwargs):
pass # the sauce, please pass # the sauce, please
self.Bind(wx.EVT_ERASE_BACKGROUND, disable_event) self.Bind(wx.EVT_ERASE_BACKGROUND, disable_event)
......
...@@ -17,27 +17,30 @@ ...@@ -17,27 +17,30 @@
#Interactive RepRap e axis calibration program #Interactive RepRap e axis calibration program
#(C) Nathan Zadoks 2011 #(C) Nathan Zadoks 2011
s = 300 #Extrusion speed (mm/min) s = 300 # Extrusion speed (mm/min)
n = 100 #Default length to extrude n = 100 # Default length to extrude
m= 0 #User-entered measured extrusion length m = 0 # User-entered measured extrusion length
k = 300 #Default amount of steps per mm k = 300 # Default amount of steps per mm
port='/dev/ttyUSB0' #Default serial port to connect to printer port = '/dev/ttyUSB0' # Default serial port to connect to printer
temp = 210 #Default extrusion temperature temp = 210 # Default extrusion temperature
tempmax = 250 #Maximum extrusion temperature tempmax = 250 # Maximum extrusion temperature
t = int(n*60)/s #Time to wait for extrusion t = int(n * 60) / s # Time to wait for extrusion
try: try:
from printdummy import printcore from printdummy import printcore
except ImportError: except ImportError:
from printcore import printcore from printcore import printcore
import time, getopt, sys, os
import time
import getopt
import sys
import os
def float_input(prompt=''): def float_input(prompt=''):
import sys
f = None f = None
while f == None: while f is None:
s = raw_input(prompt) s = raw_input(prompt)
try: try:
f = float(s) f = float(s)
...@@ -46,14 +49,13 @@ def float_input(prompt=''): ...@@ -46,14 +49,13 @@ def float_input(prompt=''):
sys.stderr.flush() sys.stderr.flush()
return f return f
def wait(t, m=''): def wait(t, m=''):
import time, sys sys.stdout.write(m + '[' + (' ' * t) + ']\r' + m + '[')
sys.stdout.write(m+'['+(' '*t)+']\r'+m+'[')
sys.stdout.flush() sys.stdout.flush()
for i in range(t): for i in range(t):
for s in ['|\b','/\b','-\b','\\\b','|']: for s in ['|\b', '/\b', '-\b', '\\\b', '|']:
sys.stdout.write(s) sys.stdout.write(s)
sys.stdout.flush() sys.stdout.flush()
time.sleep(1.0/5) time.sleep(1.0 / 5)
print print
def w(s): def w(s):
sys.stdout.write(s) sys.stdout.write(s)
...@@ -62,31 +64,31 @@ def w(s): ...@@ -62,31 +64,31 @@ def w(s):
def heatup(p, temp, s = 0): def heatup(p, temp, s = 0):
curtemp = gettemp(p) curtemp = gettemp(p)
p.send_now('M109 S%03d'%temp) p.send_now('M109 S%03d' % temp)
p.temp = 0 p.temp = 0
if not s: w("Heating extruder up..") if not s: w("Heating extruder up..")
f = False f = False
while curtemp<=(temp-1): while curtemp <= (temp - 1):
p.send_now('M105') p.send_now('M105')
time.sleep(0.5) time.sleep(0.5)
if not f: if not f:
time.sleep(1.5) time.sleep(1.5)
f = True f = True
curtemp = gettemp(p) curtemp = gettemp(p)
if curtemp: w(u"\rHeating extruder up.. %3d \xb0C"%curtemp) if curtemp: w(u"\rHeating extruder up.. %3d \xb0C" % curtemp)
if s: print if s: print
else: print "\nReady." else: print "\nReady."
def gettemp(p): def gettemp(p):
try: p.logl try: p.logl
except: setattr(p,'logl',0) except: setattr(p, 'logl', 0)
try: p.temp try: p.temp
except: setattr(p,'temp',0) except: setattr(p, 'temp', 0)
for n in range(p.logl, len(p.log)): for n in range(p.logl, len(p.log)):
line = p.log[n] line = p.log[n]
if 'T:' in line: if 'T:' in line:
try: try:
setattr(p,'temp',int(line.split('T:')[1].split()[0])) setattr(p, 'temp', int(line.split('T:')[1].split()[0]))
except: print line except: print line
p.logl = len(p.log) p.logl = len(p.log)
return p.temp return p.temp
...@@ -101,35 +103,35 @@ help = u""" ...@@ -101,35 +103,35 @@ help = u"""
-t --temp Extrusion temperature in degrees Celsius (default: %d \xb0C, max %d \xb0C) -t --temp Extrusion temperature in degrees Celsius (default: %d \xb0C, max %d \xb0C)
-p --port Serial port the printer is connected to (default: %s) -p --port Serial port the printer is connected to (default: %s)
-h --help This cruft. -h --help This cruft.
"""[1:-1].encode('utf-8')%(sys.argv[0], n, k, temp, tempmax, port if port else 'auto') """[1:-1].encode('utf-8') % (sys.argv[0], n, k, temp, tempmax, port if port else 'auto')
try: try:
opts, args = getopt.getopt(sys.argv[1:],"hl:s:t:p:",["help", "length=", "steps=", "temp=", "port="]) opts, args = getopt.getopt(sys.argv[1:], "hl:s:t:p:", ["help", "length=", "steps=", "temp=", "port="])
except getopt.GetoptError, err: except getopt.GetoptError, err:
print str(err) print str(err)
print help print help
sys.exit(2) sys.exit(2)
for o, a in opts: for o, a in opts:
if o in ('-h','--help'): if o in ('-h', '--help'):
print help print help
sys.exit() sys.exit()
elif o in ('-l','--length'): elif o in ('-l', '--length'):
n = float(a) n = float(a)
elif o in ('-s','--steps'): elif o in ('-s', '--steps'):
k = int(a) k = int(a)
elif o in ('-t','--temp'): elif o in ('-t', '--temp'):
temp = int(a) temp = int(a)
if temp>=tempmax: if temp >= tempmax:
print (u'%d \xb0C? Are you insane?'.encode('utf-8')%temp)+(" That's over nine thousand!" if temp>9000 else '') print (u'%d \xb0C? Are you insane?'.encode('utf-8') % temp) + (" That's over nine thousand!" if temp > 9000 else '')
sys.exit(255) sys.exit(255)
elif o in ('-p','--port'): elif o in ('-p', '--port'):
port = a port = a
#Show initial parameters #Show initial parameters
print "Initial parameters" print "Initial parameters"
print "Steps per mm: %3d steps"%k print "Steps per mm: %3d steps" % k
print "Length extruded: %3d mm"%n print "Length extruded: %3d mm" % n
print print
print "Serial port: %s"%(port if port else 'auto') print "Serial port: %s" % (port if port else 'auto')
p = None p = None
try: try:
...@@ -148,18 +150,18 @@ try: ...@@ -148,18 +150,18 @@ try:
heatup(p, temp) heatup(p, temp)
#Calibration loop #Calibration loop
while n!=m: while n != m:
heatup(p, temp, True) heatup(p, temp, True)
p.send_now("G92 E0") #Reset e axis p.send_now("G92 E0") # Reset e axis
p.send_now("G1 E%d F%d"%(n, s)) #Extrude length of filament p.send_now("G1 E%d F%d" % (n, s)) # Extrude length of filament
wait(t,'Extruding.. ') wait(t, 'Extruding.. ')
m = float_input("How many millimeters of filament were extruded? ") m = float_input("How many millimeters of filament were extruded? ")
if m == 0: continue if m == 0: continue
if n!=m: if n != m:
k = (n/m)*k k = (n / m) * k
p.send_now("M92 E%d"%int(round(k))) #Set new step count p.send_now("M92 E%d" % int(round(k))) # Set new step count
print "Steps per mm: %3d steps"%k #Tell user print "Steps per mm: %3d steps" % k # Tell user
print 'Calibration completed.' #Yay! print 'Calibration completed.' # Yay!
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
finally: finally:
......
...@@ -24,7 +24,10 @@ class ExcluderWindow(gviz.GvizWindow): ...@@ -24,7 +24,10 @@ class ExcluderWindow(gviz.GvizWindow):
def __init__(self, excluder, *args, **kwargs): def __init__(self, excluder, *args, **kwargs):
super(ExcluderWindow, self).__init__(*args, **kwargs) super(ExcluderWindow, self).__init__(*args, **kwargs)
self.SetTitle(_("Part excluder: draw rectangles where print instructions should be ignored")) self.SetTitle(_("Part excluder: draw rectangles where print instructions should be ignored"))
self.toolbar.AddLabelTool(128, " " + _("Reset selection"), wx.Image(imagefile('reset.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), shortHelp = _("Reset selection"), longHelp = "") self.toolbar.AddLabelTool(128, " " + _("Reset selection"),
wx.Image(imagefile('reset.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(),
shortHelp = _("Reset selection"),
longHelp = "")
self.Bind(wx.EVT_TOOL, self.reset_selection, id = 128) self.Bind(wx.EVT_TOOL, self.reset_selection, id = 128)
self.parent = excluder self.parent = excluder
self.p.paint_overlay = self.paint_selection self.p.paint_overlay = self.paint_selection
...@@ -39,7 +42,8 @@ class ExcluderWindow(gviz.GvizWindow): ...@@ -39,7 +42,8 @@ class ExcluderWindow(gviz.GvizWindow):
self.p.build_dimensions[1] - (y - self.p.build_dimensions[4])) self.p.build_dimensions[1] - (y - self.p.build_dimensions[4]))
def mouse(self, event): def mouse(self, event):
if event.ButtonUp(wx.MOUSE_BTN_LEFT) or event.ButtonUp(wx.MOUSE_BTN_RIGHT): if event.ButtonUp(wx.MOUSE_BTN_LEFT) \
or event.ButtonUp(wx.MOUSE_BTN_RIGHT):
self.initpos = None self.initpos = None
elif event.Dragging() and event.RightIsDown(): elif event.Dragging() and event.RightIsDown():
e = event.GetPositionTuple() e = event.GetPositionTuple()
...@@ -74,11 +78,11 @@ class ExcluderWindow(gviz.GvizWindow): ...@@ -74,11 +78,11 @@ class ExcluderWindow(gviz.GvizWindow):
def _line_scaler(self, orig): def _line_scaler(self, orig):
x0, y0 = self.gcode_to_real(orig[0], orig[1]) x0, y0 = self.gcode_to_real(orig[0], orig[1])
x0 = self.p.scale[0]*x0 + self.p.translate[0] x0 = self.p.scale[0] * x0 + self.p.translate[0]
y0 = self.p.scale[1]*y0 + self.p.translate[1] y0 = self.p.scale[1] * y0 + self.p.translate[1]
x1, y1 = self.gcode_to_real(orig[2], orig[3]) x1, y1 = self.gcode_to_real(orig[2], orig[3])
x1 = self.p.scale[0]*x1 + self.p.translate[0] x1 = self.p.scale[0] * x1 + self.p.translate[0]
y1 = self.p.scale[1]*y1 + self.p.translate[1] y1 = self.p.scale[1] * y1 + self.p.translate[1]
width = max(x0, x1) - min(x0, x1) + 1 width = max(x0, x1) - min(x0, x1) + 1
height = max(y0, y1) - min(y0, y1) + 1 height = max(y0, y1) - min(y0, y1) + 1
return (min(x0, x1), min(y0, y1), width, height,) return (min(x0, x1), min(y0, y1), width, height,)
...@@ -86,7 +90,8 @@ class ExcluderWindow(gviz.GvizWindow): ...@@ -86,7 +90,8 @@ class ExcluderWindow(gviz.GvizWindow):
def paint_selection(self, dc): def paint_selection(self, dc):
dc = wx.GCDC(dc) dc = wx.GCDC(dc)
dc.SetPen(wx.TRANSPARENT_PEN) dc.SetPen(wx.TRANSPARENT_PEN)
dc.DrawRectangleList([self._line_scaler(rect) for rect in self.parent.rectangles], dc.DrawRectangleList([self._line_scaler(rect)
for rect in self.parent.rectangles],
None, wx.Brush((200, 200, 200, 150))) None, wx.Brush((200, 200, 200, 150)))
def reset_selection(self, event): def reset_selection(self, event):
...@@ -117,6 +122,7 @@ class Excluder(object): ...@@ -117,6 +122,7 @@ class Excluder(object):
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
import gcoder
gcode = gcoder.GCode(open(sys.argv[1])) gcode = gcoder.GCode(open(sys.argv[1]))
app = wx.App(False) app = wx.App(False)
ex = Excluder() ex = Excluder()
......
...@@ -30,10 +30,11 @@ move_gcodes = ["G0", "G1", "G2", "G3"] ...@@ -30,10 +30,11 @@ move_gcodes = ["G0", "G1", "G2", "G3"]
class PyLine(object): class PyLine(object):
__slots__ = ('x','y','z','e','f','i','j', __slots__ = ('x', 'y', 'z', 'e', 'f', 'i', 'j',
'raw', 'command', 'is_move', 'raw', 'command', 'is_move',
'relative','relative_e', 'relative', 'relative_e',
'current_x', 'current_y', 'current_z', 'extruding', 'current_tool', 'current_x', 'current_y', 'current_z', 'extruding',
'current_tool',
'gcview_end_vertex') 'gcview_end_vertex')
def __init__(self, l): def __init__(self, l):
...@@ -75,24 +76,27 @@ def parse_coordinates(line, split_raw, imperial = False, force = False): ...@@ -75,24 +76,27 @@ def parse_coordinates(line, split_raw, imperial = False, force = False):
for bit in split_raw: for bit in split_raw:
code = bit[0] code = bit[0]
if code not in gcode_parsed_nonargs and bit[1]: if code not in gcode_parsed_nonargs and bit[1]:
setattr(line, code, unit_factor*float(bit[1])) setattr(line, code, unit_factor * float(bit[1]))
class Layer(list): class Layer(list):
__slots__ = ("duration") __slots__ = ("duration", "z")
def _preprocess(self, current_x, current_y, current_z): def __init__(self, lines, z = None):
super(Layer, self).__init__(lines)
self.z = z
def _preprocess(self, current_x, current_y, current_z,
offset_x, offset_y, offset_z):
xmin = float("inf") xmin = float("inf")
ymin = float("inf") ymin = float("inf")
zmin = 0 zmin = 0
xmax = float("-inf") xmax = float("-inf")
ymax = float("-inf") ymax = float("-inf")
zmax = float("-inf") zmax = float("-inf")
relative = False
relative_e = False
for line in self: for line in self:
if not line.is_move and line.command != "G92": if not line.is_move and line.command != "G92" and line.command != "G28":
continue continue
if line.is_move: if line.is_move:
x = line.x x = line.x
...@@ -103,6 +107,10 @@ class Layer(list): ...@@ -103,6 +107,10 @@ class Layer(list):
x = current_x + (x or 0) x = current_x + (x or 0)
y = current_y + (y or 0) y = current_y + (y or 0)
z = current_z + (z or 0) z = current_z + (z or 0)
else:
if line.x: x = line.x + offset_x
if line.y: y = line.y + offset_y
if line.z: z = line.z + offset_z
current_x = x or current_x current_x = x or current_x
current_y = y or current_y current_y = y or current_y
...@@ -119,15 +127,25 @@ class Layer(list): ...@@ -119,15 +127,25 @@ class Layer(list):
zmin = min(zmin, current_z) zmin = min(zmin, current_z)
zmax = max(zmax, current_z) zmax = max(zmax, current_z)
elif line.command == "G28":
if not any([line.x, line.y, line.z]):
current_x = current_y = current_z = 0
else: else:
current_x = line.x or current_x if line.x: current_x = 0
current_y = line.y or current_y if line.y: current_y = 0
current_z = line.z or current_z if line.z: current_z = 0
elif line.command == "G92":
if line.x: offset_x = current_x - line.x
if line.y: offset_y = current_y - line.y
if line.z: offset_z = current_z - line.z
line.current_x = current_x line.current_x = current_x
line.current_y = current_y line.current_y = current_y
line.current_z = current_z line.current_z = current_z
return (current_x, current_y, current_z), (xmin, xmax), (ymin, ymax), (zmin, zmax) return ((current_x, current_y, current_z),
(offset_x, offset_y, offset_z),
(xmin, xmax), (ymin, ymax), (zmin, zmax))
class GCode(object): class GCode(object):
...@@ -155,7 +173,9 @@ class GCode(object): ...@@ -155,7 +173,9 @@ class GCode(object):
depth = None depth = None
height = None height = None
def __init__(self,data): est_layer_height = None
def __init__(self, data):
self.lines = [Line(l2) for l2 in self.lines = [Line(l2) for l2 in
(l.strip() for l in data) (l.strip() for l in data)
if l2] if l2]
...@@ -184,7 +204,7 @@ class GCode(object): ...@@ -184,7 +204,7 @@ class GCode(object):
return gline return gline
def _preprocess_lines(self, lines = None): def _preprocess_lines(self, lines = None):
"""Checks for G20, G21, G90 and G91, sets imperial and relative flags""" """Checks for imperial/relativeness settings and tool changes"""
if not lines: if not lines:
lines = self.lines lines = self.lines
imperial = self.imperial imperial = self.imperial
...@@ -230,7 +250,7 @@ class GCode(object): ...@@ -230,7 +250,7 @@ class GCode(object):
max_e = 0 max_e = 0
for line in lines: for line in lines:
if line.e == None: if line.e is None:
continue continue
if line.is_move: if line.is_move:
if line.relative_e: if line.relative_e:
...@@ -256,31 +276,50 @@ class GCode(object): ...@@ -256,31 +276,50 @@ class GCode(object):
layer_id = 0 layer_id = 0
layer_line = 0 layer_line = 0
last_layer_z = None
prev_z = None prev_z = None
cur_z = 0 prev_base_z = (None, None)
cur_z = None
cur_lines = [] cur_lines = []
for line in self.lines: for line in self.lines:
if line.command == "G92" and line.z != None: if line.command == "G92" and line.z is not None:
cur_z = line.z cur_z = line.z
elif line.is_move: elif line.is_move:
if line.z != None: if line.z is not None:
if line.relative: if line.relative:
cur_z += line.z cur_z += line.z
else: else:
cur_z = line.z cur_z = line.z
# FIXME: the logic behind this code seems to work, but it might be
# broken
if cur_z != prev_z: if cur_z != prev_z:
if prev_z is not None: if prev_z is not None and last_layer_z is not None:
base_z = (prev_z - (prev_z % 0.1)) if abs(cur_z - prev_z) < 0.01 else prev_z offset = self.est_layer_height if self.est_layer_height else 0.01
if abs(prev_z - last_layer_z) < offset:
if self.est_layer_height is None:
zs = sorted([l.z for l in all_layers if l.z is not None])
heights = [round(zs[i + 1] - zs[i], 3) for i in range(len(zs) - 1)]
if len(heights) >= 2: self.est_layer_height = heights[1]
elif heights: self.est_layer_height = heights[0]
else: self.est_layer_height = 0.1
base_z = round(prev_z - (prev_z % self.est_layer_height), 2)
else:
base_z = round(prev_z, 2)
else: else:
base_z = None base_z = prev_z
all_layers.append(Layer(cur_lines))
if base_z != prev_base_z:
all_layers.append(Layer(cur_lines, base_z))
old_lines = layers.get(base_z, []) old_lines = layers.get(base_z, [])
old_lines += cur_lines old_lines += cur_lines
layers[base_z] = old_lines layers[base_z] = old_lines
cur_lines = [] cur_lines = []
layer_id += 1 layer_id += 1
layer_line = 0 layer_line = 0
last_layer_z = base_z
prev_base_z = base_z
cur_lines.append(line) cur_lines.append(line)
layer_idxs.append(layer_id) layer_idxs.append(layer_id)
...@@ -289,22 +328,22 @@ class GCode(object): ...@@ -289,22 +328,22 @@ class GCode(object):
prev_z = cur_z prev_z = cur_z
if cur_lines: if cur_lines:
all_layers.append(Layer(cur_lines)) all_layers.append(Layer(cur_lines, prev_z))
old_lines = layers.get(prev_z, []) old_lines = layers.get(prev_z, [])
old_lines += cur_lines old_lines += cur_lines
layers[prev_z] = old_lines layers[prev_z] = old_lines
for idx in layers.keys(): for zindex in layers.keys():
cur_lines = layers[idx] cur_lines = layers[zindex]
has_movement = False has_movement = False
for l in layers[idx]: for l in layers[zindex]:
if l.is_move and l.e != None: if l.is_move and l.e is not None:
has_movement = True has_movement = True
break break
if has_movement: if has_movement:
layers[idx] = Layer(cur_lines) layers[zindex] = Layer(cur_lines, zindex)
else: else:
del layers[idx] del layers[zindex]
self.append_layer_id = len(all_layers) self.append_layer_id = len(all_layers)
self.append_layer = Layer([]) self.append_layer = Layer([])
...@@ -331,9 +370,16 @@ class GCode(object): ...@@ -331,9 +370,16 @@ class GCode(object):
current_x = 0 current_x = 0
current_y = 0 current_y = 0
current_z = 0 current_z = 0
offset_x = 0
offset_y = 0
offset_z = 0
for l in self.all_layers: for l in self.all_layers:
(current_x, current_y, current_z), (xm, xM), (ym, yM), (zm, zM) = l._preprocess(current_x, current_y, current_z) meta = l._preprocess(current_x, current_y, current_z,
offset_x, offset_y, offset_z)
current_x, current_y, current_z = meta[0]
offset_x, offset_y, offset_z = meta[1]
(xm, xM), (ym, yM), (zm, zM) = meta[2:]
xmin = min(xm, xmin) xmin = min(xm, xmin)
xmax = max(xM, xmax) xmax = max(xM, xmax)
ymin = min(ym, ymin) ymin = min(ym, ymin)
...@@ -352,18 +398,16 @@ class GCode(object): ...@@ -352,18 +398,16 @@ class GCode(object):
self.height = self.zmax - self.zmin self.height = self.zmax - self.zmin
def estimate_duration(self): def estimate_duration(self):
lastx = lasty = lastz = laste = lastf = 0.0 lastx = lasty = laste = lastf = 0.0
x = y = z = e = f = 0.0 x = y = e = f = 0.0
currenttravel = 0.0 currenttravel = 0.0
totaltravel = 0.0
moveduration = 0.0 moveduration = 0.0
totalduration = 0.0 totalduration = 0.0
acceleration = 1500.0 #mm/s/s ASSUMING THE DEFAULT FROM SPRINTER !!!! acceleration = 1500.0 # mm/s/s ASSUMING THE DEFAULT FROM SPRINTER !!!
layerduration = 0.0
layerbeginduration = 0.0 layerbeginduration = 0.0
layercount = 0
#TODO: #TODO:
# get device caps from firmware: max speed, acceleration/axis (including extruder) # get device caps from firmware: max speed, acceleration/axis
# (including extruder)
# calculate the maximum move duration accounting for above ;) # calculate the maximum move duration accounting for above ;)
for layer in self.all_layers: for layer in self.all_layers:
for line in layer: for line in layer:
...@@ -376,19 +420,30 @@ class GCode(object): ...@@ -376,19 +420,30 @@ class GCode(object):
else: else:
moveduration /= 1000.0 moveduration /= 1000.0
else: else:
x = line.x if line.x != None else lastx x = line.x if line.x is not None else lastx
y = line.y if line.y != None else lasty y = line.y if line.y is not None else lasty
e = line.e if line.e != None else laste e = line.e if line.e is not None else laste
f = line.f / 60.0 if line.f != None else lastf # mm/s vs mm/m => divide by 60 # mm/s vs mm/m => divide by 60
f = line.f / 60.0 if line.f is not None else lastf
# given last feedrate and current feedrate calculate the distance needed to achieve current feedrate.
# if travel is longer than req'd distance, then subtract distance to achieve full speed, and add the time it took to get there. # given last feedrate and current feedrate calculate the
# then calculate the time taken to complete the remaining distance # distance needed to achieve current feedrate.
# if travel is longer than req'd distance, then subtract
# distance to achieve full speed, and add the time it took
# to get there.
# then calculate the time taken to complete the remaining
# distance
# FIXME: this code has been proven to be super wrong when 2
# subsquent moves are in opposite directions, as requested
# speed is constant but printer has to fully decellerate
# and reaccelerate
currenttravel = math.hypot(x - lastx, y - lasty) currenttravel = math.hypot(x - lastx, y - lasty)
if currenttravel == 0 and line.e != None: if currenttravel == 0 and line.e is not None:
currenttravel = abs(line.e) if line.relative_e else abs(line.e - laste) currenttravel = abs(line.e) if line.relative_e else abs(line.e - laste)
if f == lastf: # Feedrate hasn't changed, no acceleration/decceleration planned # Feedrate hasn't changed, no acceleration/decceleration planned
if f == lastf:
moveduration = currenttravel / f if f != 0 else 0. moveduration = currenttravel / f if f != 0 else 0.
else: else:
# FIXME: review this better # FIXME: review this better
...@@ -413,7 +468,8 @@ class GCode(object): ...@@ -413,7 +468,8 @@ class GCode(object):
layer.duration = totalduration - layerbeginduration layer.duration = totalduration - layerbeginduration
layerbeginduration = totalduration layerbeginduration = totalduration
return "%d layers, %s" % (len(self.layers), str(datetime.timedelta(seconds = int(totalduration)))) totaltime = datetime.timedelta(seconds = int(totalduration))
return "%d layers, %s" % (len(self.layers), str(totaltime))
def main(): def main():
if len(sys.argv) < 2: if len(sys.argv) < 2:
...@@ -424,9 +480,12 @@ def main(): ...@@ -424,9 +480,12 @@ def main():
gcode = GCode(open(sys.argv[1])) gcode = GCode(open(sys.argv[1]))
print "Dimensions:" print "Dimensions:"
print "\tX: %0.02f - %0.02f (%0.02f)" % (gcode.xmin,gcode.xmax,gcode.width) xdims = (gcode.xmin, gcode.xmax, gcode.width)
print "\tY: %0.02f - %0.02f (%0.02f)" % (gcode.ymin,gcode.ymax,gcode.depth) print "\tX: %0.02f - %0.02f (%0.02f)" % xdims
print "\tZ: %0.02f - %0.02f (%0.02f)" % (gcode.zmin,gcode.zmax,gcode.height) ydims = (gcode.ymin, gcode.ymax, gcode.depth)
print "\tY: %0.02f - %0.02f (%0.02f)" % ydims
zdims = (gcode.zmin, gcode.zmax, gcode.height)
print "\tZ: %0.02f - %0.02f (%0.02f)" % zdims
print "Filament used: %0.02fmm" % gcode.filament_length print "Filament used: %0.02fmm" % gcode.filament_length
print "Number of layers: %d" % gcode.num_layers() print "Number of layers: %d" % gcode.num_layers()
print "Estimated duration: %s" % gcode.estimate_duration() print "Estimated duration: %s" % gcode.estimate_duration()
......
...@@ -15,23 +15,17 @@ ...@@ -15,23 +15,17 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>. # along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import os
import math
import wx import wx
from wx import glcanvas
import pyglet
pyglet.options['debug_gl'] = True
from pyglet.gl import *
from pyglet import gl
from . import gcoder from . import gcoder
from .gl.panel import wxGLPanel from .gl.panel import wxGLPanel
from .gl.trackball import trackball, mulquat, build_rotmatrix from .gl.trackball import build_rotmatrix
from .gl.libtatlin import actors from .gl.libtatlin import actors
from pyglet.gl import glPushMatrix, glPopMatrix, \
glTranslatef, glRotatef, glScalef, glMultMatrixd
from .gviz import GvizBaseFrame from .gviz import GvizBaseFrame
from printrun_utils import imagefile, install_locale from printrun_utils import imagefile, install_locale
...@@ -39,9 +33,10 @@ install_locale('pronterface') ...@@ -39,9 +33,10 @@ install_locale('pronterface')
class GcodeViewPanel(wxGLPanel): class GcodeViewPanel(wxGLPanel):
def __init__(self, parent, id = wx.ID_ANY, build_dimensions = None, realparent = None): def __init__(self, parent, id = wx.ID_ANY,
super(GcodeViewPanel, self).__init__(parent, id, wx.DefaultPosition, wx.DefaultSize, 0) build_dimensions = None, realparent = None):
self.batches = [] super(GcodeViewPanel, self).__init__(parent, id, wx.DefaultPosition,
wx.DefaultSize, 0)
self.canvas.Bind(wx.EVT_MOUSE_EVENTS, self.move) self.canvas.Bind(wx.EVT_MOUSE_EVENTS, self.move)
self.canvas.Bind(wx.EVT_LEFT_DCLICK, self.double) self.canvas.Bind(wx.EVT_LEFT_DCLICK, self.double)
self.canvas.Bind(wx.EVT_KEY_DOWN, self.keypress) self.canvas.Bind(wx.EVT_KEY_DOWN, self.keypress)
...@@ -60,6 +55,14 @@ class GcodeViewPanel(wxGLPanel): ...@@ -60,6 +55,14 @@ class GcodeViewPanel(wxGLPanel):
def setlayercb(self, layer): def setlayercb(self, layer):
pass pass
def OnInitGL(self, *args, **kwargs):
super(GcodeViewPanel, self).OnInitGL(*args, **kwargs)
if hasattr(self.parent, "filenames") and self.parent.filenames:
for filename in self.parent.filenames:
self.parent.load_file(filename)
self.parent.autoplate()
self.parent.filenames = None
def create_objects(self): def create_objects(self):
'''create opengl objects when opengl is initialized''' '''create opengl objects when opengl is initialized'''
for obj in self.parent.objects: for obj in self.parent.objects:
...@@ -79,15 +82,21 @@ class GcodeViewPanel(wxGLPanel): ...@@ -79,15 +82,21 @@ class GcodeViewPanel(wxGLPanel):
glTranslatef(0, 0, -3 * self.dist) # Move back glTranslatef(0, 0, -3 * self.dist) # Move back
else: else:
glTranslatef(0, 0, -self.dist) # Move back glTranslatef(0, 0, -self.dist) # Move back
glMultMatrixd(build_rotmatrix(self.basequat)) # Rotate according to trackball # Rotate according to trackball
glTranslatef(- self.build_dimensions[3] - self.parent.platform.width/2, glMultMatrixd(build_rotmatrix(self.basequat))
- self.build_dimensions[4] - self.parent.platform.depth/2, 0) # Move origin to bottom left of platform # Move origin to bottom left of platform
platformx0 = -self.build_dimensions[3] - self.parent.platform.width / 2
platformy0 = -self.build_dimensions[4] - self.parent.platform.depth / 2
glTranslatef(platformx0, platformy0, 0)
for obj in self.parent.objects: for obj in self.parent.objects:
if not obj.model or not obj.model.loaded or not obj.model.initialized: if not obj.model \
or not obj.model.loaded \
or not obj.model.initialized:
continue continue
glPushMatrix() glPushMatrix()
glTranslatef(*(obj.offsets)) glTranslatef(*(obj.offsets))
glTranslatef(*(obj.centeroffset))
glRotatef(obj.rot, 0.0, 0.0, 1.0) glRotatef(obj.rot, 0.0, 0.0, 1.0)
glScalef(*obj.scale) glScalef(*obj.scale)
...@@ -99,35 +108,6 @@ class GcodeViewPanel(wxGLPanel): ...@@ -99,35 +108,6 @@ class GcodeViewPanel(wxGLPanel):
if self.parent.clickcb: if self.parent.clickcb:
self.parent.clickcb(event) self.parent.clickcb(event)
def handle_rotation(self, event):
if self.initpos == None:
self.initpos = event.GetPositionTuple()
else:
p1 = self.initpos
p2 = event.GetPositionTuple()
sz = self.GetClientSize()
p1x = float(p1[0]) / (sz[0] / 2) - 1
p1y = 1 - float(p1[1]) / (sz[1] / 2)
p2x = float(p2[0]) / (sz[0] / 2) - 1
p2y = 1 - float(p2[1]) / (sz[1] / 2)
quat = trackball(p1x, p1y, p2x, p2y, self.dist / 250.0)
self.basequat = mulquat(self.basequat, quat)
self.initpos = p2
def handle_translation(self, event):
if self.initpos is None:
self.initpos = event.GetPositionTuple()
else:
p1 = self.initpos
p2 = event.GetPositionTuple()
if self.orthographic:
x1, y1, _ = self.mouse_to_3d(p1[0], p1[1])
x2, y2, _ = self.mouse_to_3d(p2[0], p2[1])
glTranslatef(x2 - x1, y2 - y1, 0)
else:
glTranslatef(p2[0] - p1[0], -(p2[1] - p1[1]), 0)
self.initpos = p2
def move(self, event): def move(self, event):
"""react to mouse actions: """react to mouse actions:
no mouse: show red mousedrop no mouse: show red mousedrop
...@@ -174,14 +154,10 @@ class GcodeViewPanel(wxGLPanel): ...@@ -174,14 +154,10 @@ class GcodeViewPanel(wxGLPanel):
self.parent.setlayercb(new_layer) self.parent.setlayercb(new_layer)
wx.CallAfter(self.Refresh) wx.CallAfter(self.Refresh)
def wheel(self, event): def handle_wheel(self, event):
"""react to mouse wheel actions:
without shift: set max layer
with shift: zoom viewport
"""
delta = event.GetWheelRotation() delta = event.GetWheelRotation()
factor = 1.05 factor = 1.05
if event.ShiftDown(): if hasattr(self.parent, "model") and event.ShiftDown():
if not self.parent.model: if not self.parent.model:
return return
count = 1 if not event.ControlDown() else 10 count = 1 if not event.ControlDown() else 10
...@@ -194,7 +170,15 @@ class GcodeViewPanel(wxGLPanel): ...@@ -194,7 +170,15 @@ class GcodeViewPanel(wxGLPanel):
if delta > 0: if delta > 0:
self.zoom(factor, (x, y)) self.zoom(factor, (x, y))
else: else:
self.zoom(1/factor, (x, y)) self.zoom(1 / factor, (x, y))
def wheel(self, event):
"""react to mouse wheel actions:
without shift: set max layer
with shift: zoom viewport
"""
self.handle_wheel(event)
wx.CallAfter(self.Refresh)
def fit(self): def fit(self):
if not self.parent.model or not self.parent.model.loaded: if not self.parent.model or not self.parent.model.loaded:
...@@ -254,16 +238,17 @@ class GCObject(object): ...@@ -254,16 +238,17 @@ class GCObject(object):
def __init__(self, model): def __init__(self, model):
self.offsets = [0, 0, 0] self.offsets = [0, 0, 0]
self.centeroffset = [0, 0, 0]
self.rot = 0 self.rot = 0
self.curlayer = 0.0 self.curlayer = 0.0
self.scale = [1.0, 1.0, 1.0] self.scale = [1.0, 1.0, 1.0]
self.batch = pyglet.graphics.Batch()
self.model = model self.model = model
class GcodeViewMainWrapper(object): class GcodeViewMainWrapper(object):
def __init__(self, parent, build_dimensions): def __init__(self, parent, build_dimensions):
self.glpanel = GcodeViewPanel(parent, realparent = self, build_dimensions = build_dimensions) self.glpanel = GcodeViewPanel(parent, realparent = self,
build_dimensions = build_dimensions)
self.glpanel.SetMinSize((150, 150)) self.glpanel.SetMinSize((150, 150))
self.clickcb = None self.clickcb = None
self.widget = self.glpanel self.widget = self.glpanel
...@@ -306,7 +291,8 @@ class GcodeViewFrame(GvizBaseFrame): ...@@ -306,7 +291,8 @@ class GcodeViewFrame(GvizBaseFrame):
def __init__(self, parent, ID, title, build_dimensions, objects = None, def __init__(self, parent, ID, title, build_dimensions, objects = None,
pos = wx.DefaultPosition, size = wx.DefaultSize, pos = wx.DefaultPosition, size = wx.DefaultSize,
style = wx.DEFAULT_FRAME_STYLE): style = wx.DEFAULT_FRAME_STYLE):
super(GcodeViewFrame, self).__init__(parent, ID, title, pos, size, style) super(GcodeViewFrame, self).__init__(parent, ID, title,
pos, size, style)
panel, vbox = self.create_base_ui() panel, vbox = self.create_base_ui()
...@@ -320,14 +306,18 @@ class GcodeViewFrame(GvizBaseFrame): ...@@ -320,14 +306,18 @@ class GcodeViewFrame(GvizBaseFrame):
self.model = None self.model = None
self.objects = [GCObject(self.platform), GCObject(None)] self.objects = [GCObject(self.platform), GCObject(None)]
self.toolbar.AddLabelTool(6, " " + _("Fit to plate"), wx.Image(imagefile('fit.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), shortHelp = _("Fit to plate [F]"), longHelp = '') fit_image = wx.Image(imagefile('fit.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap()
self.toolbar.AddLabelTool(6, " " + _("Fit to plate"), fit_image,
shortHelp = _("Fit to plate [F]"),
longHelp = '')
self.toolbar.Realize() self.toolbar.Realize()
self.glpanel = GcodeViewPanel(panel, build_dimensions = build_dimensions, self.glpanel = GcodeViewPanel(panel,
build_dimensions = build_dimensions,
realparent = self) realparent = self)
vbox.Add(self.glpanel, 1, flag = wx.EXPAND) vbox.Add(self.glpanel, 1, flag = wx.EXPAND)
self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.zoom_to_center(1.2), id = 1) self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.zoom_to_center(1.2), id = 1)
self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.zoom_to_center(1/1.2), id = 2) self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.zoom_to_center(1 / 1.2), id = 2)
self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.layerup(), id = 3) self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.layerup(), id = 3)
self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.layerdown(), id = 4) self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.layerdown(), id = 4)
self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.resetview(), id = 5) self.Bind(wx.EVT_TOOL, lambda x: self.glpanel.resetview(), id = 5)
...@@ -367,7 +357,9 @@ if __name__ == "__main__": ...@@ -367,7 +357,9 @@ if __name__ == "__main__":
import sys import sys
app = wx.App(redirect = False) app = wx.App(redirect = False)
build_dimensions = [200, 200, 100, 0, 0, 0] build_dimensions = [200, 200, 100, 0, 0, 0]
frame = GcodeViewFrame(None, wx.ID_ANY, 'Gcode view, shift to move view, mousewheel to set layer', size = (400, 400), build_dimensions = build_dimensions) title = 'Gcode view, shift to move view, mousewheel to set layer'
frame = GcodeViewFrame(None, wx.ID_ANY, title, size = (400, 400),
build_dimensions = build_dimensions)
gcode = gcoder.GCode(open(sys.argv[1])) gcode = gcoder.GCode(open(sys.argv[1]))
frame.addfile(gcode) frame.addfile(gcode)
...@@ -377,14 +369,15 @@ if __name__ == "__main__": ...@@ -377,14 +369,15 @@ if __name__ == "__main__":
first_move = gcode.lines[i] first_move = gcode.lines[i]
break break
last_move = None last_move = None
for i in range(len(gcode.lines)-1,-1,-1): for i in range(len(gcode.lines) - 1, -1, -1):
if gcode.lines[i].is_move: if gcode.lines[i].is_move:
last_move = gcode.lines[i] last_move = gcode.lines[i]
break break
nsteps = 20 nsteps = 20
steptime = 500 steptime = 500
lines = [first_move] + [gcode.lines[int(float(i)*(len(gcode.lines)-1)/nsteps)] for i in range(1, nsteps)] + [last_move] lines = [first_move] + [gcode.lines[int(float(i) * (len(gcode.lines) - 1) / nsteps)] for i in range(1, nsteps)] + [last_move]
current_line = 0 current_line = 0
def setLine(): def setLine():
global current_line global current_line
frame.set_current_gline(lines[current_line]) frame.set_current_gline(lines[current_line])
......
...@@ -21,8 +21,13 @@ import numpy ...@@ -21,8 +21,13 @@ import numpy
import math import math
import logging import logging
from pyglet.gl import * from pyglet.gl import glPushMatrix, glPopMatrix, glTranslatef, \
from pyglet import gl glGenLists, glNewList, GL_COMPILE, glEndList, glCallList, \
GL_ARRAY_BUFFER, GL_STATIC_DRAW, glColor4f, glVertex3f, glRectf, \
glBegin, glEnd, GL_LINES, glEnable, glDisable, glGetFloatv, \
GL_LINE_SMOOTH, glLineWidth, GL_LINE_WIDTH, GLfloat, GL_FLOAT, \
glVertexPointer, glColorPointer, glDrawArrays, \
glEnableClientState, glDisableClientState, GL_VERTEX_ARRAY, GL_COLOR_ARRAY
from pyglet.graphics.vertexbuffer import create_buffer, VertexBufferObject from pyglet.graphics.vertexbuffer import create_buffer, VertexBufferObject
from printrun.printrun_utils import install_locale from printrun.printrun_utils import install_locale
...@@ -253,14 +258,13 @@ class GcodeModel(Model): ...@@ -253,14 +258,13 @@ class GcodeModel(Model):
def load_data(self, model_data, callback=None): def load_data(self, model_data, callback=None):
t_start = time.time() t_start = time.time()
self.dims = ((model_data.xmin,model_data.xmax,model_data.width), self.dims = ((model_data.xmin, model_data.xmax, model_data.width),
(model_data.ymin,model_data.ymax,model_data.depth), (model_data.ymin, model_data.ymax, model_data.depth),
(model_data.zmin,model_data.zmax,model_data.height)) (model_data.zmin, model_data.zmax, model_data.height))
vertex_list = [] vertex_list = []
color_list = [] color_list = []
self.layer_stops = [0] self.layer_stops = [0]
arrow_list = []
num_layers = len(model_data.all_layers) num_layers = len(model_data.all_layers)
prev_pos = (0, 0, 0) prev_pos = (0, 0, 0)
...@@ -413,4 +417,3 @@ class GcodeModel(Model): ...@@ -413,4 +417,3 @@ class GcodeModel(Model):
self.vertex_buffer.unbind() self.vertex_buffer.unbind()
self.vertex_color_buffer.unbind() self.vertex_color_buffer.unbind()
...@@ -15,9 +15,6 @@ ...@@ -15,9 +15,6 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>. # along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import os
import math
import wx import wx
from wx import glcanvas from wx import glcanvas
...@@ -26,6 +23,7 @@ pyglet.options['debug_gl'] = True ...@@ -26,6 +23,7 @@ pyglet.options['debug_gl'] = True
from pyglet.gl import * from pyglet.gl import *
from pyglet import gl from pyglet import gl
from .trackball import trackball, mulquat
class wxGLPanel(wx.Panel): class wxGLPanel(wx.Panel):
'''A simple class for using OpenGL with wxPython.''' '''A simple class for using OpenGL with wxPython.'''
...@@ -64,7 +62,7 @@ class wxGLPanel(wx.Panel): ...@@ -64,7 +62,7 @@ class wxGLPanel(wx.Panel):
def processSizeEvent(self, event): def processSizeEvent(self, event):
'''Process the resize event.''' '''Process the resize event.'''
if (wx.VERSION > (2,9) and self.canvas.IsShownOnScreen()) or self.canvas.GetContext(): if (wx.VERSION > (2, 9) and self.canvas.IsShownOnScreen()) or self.canvas.GetContext():
# Make sure the frame is shown before calling SetCurrent. # Make sure the frame is shown before calling SetCurrent.
self.canvas.SetCurrent(self.context) self.canvas.SetCurrent(self.context)
self.OnReshape() self.OnReshape()
...@@ -110,7 +108,7 @@ class wxGLPanel(wx.Panel): ...@@ -110,7 +108,7 @@ class wxGLPanel(wx.Panel):
self.OnReshape() self.OnReshape()
def OnReshape(self): def OnReshape(self):
'''Reshape the OpenGL viewport based on the dimensions of the window.''' """Reshape the OpenGL viewport based on the size of the window"""
size = self.GetClientSize() size = self.GetClientSize()
oldwidth, oldheight = self.width, self.height oldwidth, oldheight = self.width, self.height
width, height = size.width, size.height width, height = size.width, size.height
...@@ -174,7 +172,8 @@ class wxGLPanel(wx.Panel): ...@@ -174,7 +172,8 @@ class wxGLPanel(wx.Panel):
def mouse_to_3d(self, x, y, z = 1.0): def mouse_to_3d(self, x, y, z = 1.0):
x = float(x) x = float(x)
y = self.height - float(y) y = self.height - float(y)
# The following could work if we were not initially scaling to zoom on the bed # The following could work if we were not initially scaling to zoom on
# the bed
#if self.orthographic: #if self.orthographic:
# return (x - self.width / 2, y - self.height / 2, 0) # return (x - self.width / 2, y - self.height / 2, 0)
pmat = (GLdouble * 16)() pmat = (GLdouble * 16)()
...@@ -183,7 +182,7 @@ class wxGLPanel(wx.Panel): ...@@ -183,7 +182,7 @@ class wxGLPanel(wx.Panel):
px = (GLdouble)() px = (GLdouble)()
py = (GLdouble)() py = (GLdouble)()
pz = (GLdouble)() pz = (GLdouble)()
glGetIntegerv(GL_VIEWPORT, viewport); glGetIntegerv(GL_VIEWPORT, viewport)
glGetDoublev(GL_PROJECTION_MATRIX, pmat) glGetDoublev(GL_PROJECTION_MATRIX, pmat)
glGetDoublev(GL_MODELVIEW_MATRIX, mvmat) glGetDoublev(GL_MODELVIEW_MATRIX, mvmat)
gluUnProject(x, y, z, mvmat, pmat, viewport, px, py, pz) gluUnProject(x, y, z, mvmat, pmat, viewport, px, py, pz)
...@@ -204,3 +203,32 @@ class wxGLPanel(wx.Panel): ...@@ -204,3 +203,32 @@ class wxGLPanel(wx.Panel):
self.canvas.SetCurrent(self.context) self.canvas.SetCurrent(self.context)
x, y, _ = self.mouse_to_3d(self.width / 2, self.height / 2) x, y, _ = self.mouse_to_3d(self.width / 2, self.height / 2)
self.zoom(factor, (x, y)) self.zoom(factor, (x, y))
def handle_rotation(self, event):
if self.initpos is None:
self.initpos = event.GetPositionTuple()
else:
p1 = self.initpos
p2 = event.GetPositionTuple()
sz = self.GetClientSize()
p1x = float(p1[0]) / (sz[0] / 2) - 1
p1y = 1 - float(p1[1]) / (sz[1] / 2)
p2x = float(p2[0]) / (sz[0] / 2) - 1
p2y = 1 - float(p2[1]) / (sz[1] / 2)
quat = trackball(p1x, p1y, p2x, p2y, self.dist / 250.0)
self.basequat = mulquat(self.basequat, quat)
self.initpos = p2
def handle_translation(self, event):
if self.initpos is None:
self.initpos = event.GetPositionTuple()
else:
p1 = self.initpos
p2 = event.GetPositionTuple()
if self.orthographic:
x1, y1, _ = self.mouse_to_3d(p1[0], p1[1])
x2, y2, _ = self.mouse_to_3d(p2[0], p2[1])
glTranslatef(x2 - x1, y2 - y1, 0)
else:
glTranslatef(p2[0] - p1[0], -(p2[1] - p1[1]), 0)
self.initpos = p2
...@@ -17,10 +17,12 @@ ...@@ -17,10 +17,12 @@
import math import math
from pyglet.gl import * from pyglet.gl import GLdouble
def cross(v1, v2): def cross(v1, v2):
return [v1[1]*v2[2]-v1[2]*v2[1], v1[2]*v2[0]-v1[0]*v2[2], v1[0]*v2[1]-v1[1]*v2[0]] return [v1[1] * v2[2] - v1[2] * v2[1],
v1[2] * v2[0] - v1[0] * v2[2],
v1[0] * v2[1] - v1[1] * v2[0]]
def trackball(p1x, p1y, p2x, p2y, r): def trackball(p1x, p1y, p2x, p2y, r):
TRACKBALLSIZE = r TRACKBALLSIZE = r
......
...@@ -15,14 +15,18 @@ ...@@ -15,14 +15,18 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>. # along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import wx, random import wx
from math import log10, floor, ceil from math import log10, floor, ceil
from bufferedcanvas import * from printrun.printrun_utils import install_locale
install_locale('pronterface')
from bufferedcanvas import BufferedCanvas
class GraphWindow(wx.Frame): class GraphWindow(wx.Frame):
def __init__(self, root, size = (600, 600)): def __init__(self, root, size = (600, 600)):
wx.Frame.__init__(self, None, title = _("Temperature graph"), size = size) super(GraphWindow, self).__init__(None, title = _("Temperature graph"),
size = size)
panel = wx.Panel(self, -1) panel = wx.Panel(self, -1)
vbox = wx.BoxSizer(wx.VERTICAL) vbox = wx.BoxSizer(wx.VERTICAL)
self.graph = Graph(panel, wx.ID_ANY, root) self.graph = Graph(panel, wx.ID_ANY, root)
...@@ -75,10 +79,6 @@ class Graph(BufferedCanvas): ...@@ -75,10 +79,6 @@ class Graph(BufferedCanvas):
def __del__(self): def __del__(self):
if self.window: self.window.Close() if self.window: self.window.Close()
def OnPaint(self, evt):
dc = wx.PaintDC(self)
gc = wx.GraphicsContext.Create(dc)
def updateTemperatures(self, event): def updateTemperatures(self, event):
self.AddBedTemperature(self.bedtemps[-1]) self.AddBedTemperature(self.bedtemps[-1])
self.AddBedTargetTemperature(self.bedtargettemps[-1]) self.AddBedTargetTemperature(self.bedtargettemps[-1])
...@@ -91,7 +91,9 @@ class Graph(BufferedCanvas): ...@@ -91,7 +91,9 @@ class Graph(BufferedCanvas):
self.Refresh() self.Refresh()
def drawgrid(self, dc, gc): def drawgrid(self, dc, gc):
#cold, medium, hot = wx.Colour(0, 167, 223), wx.Colour(239, 233, 119), wx.Colour(210, 50.100) #cold, medium, hot = wx.Colour(0, 167, 223),\
# wx.Colour(239, 233, 119),\
# wx.Colour(210, 50.100)
#col1 = wx.Colour(255, 0, 0, 255) #col1 = wx.Colour(255, 0, 0, 255)
#col2 = wx.Colour(255, 255, 255, 128) #col2 = wx.Colour(255, 255, 255, 128)
...@@ -111,26 +113,32 @@ class Graph(BufferedCanvas): ...@@ -111,26 +113,32 @@ class Graph(BufferedCanvas):
# draw vertical bars # draw vertical bars
dc.SetPen(wx.Pen(wx.Colour(225, 225, 225), 1)) dc.SetPen(wx.Pen(wx.Colour(225, 225, 225), 1))
for x in range(self.xbars+1): for x in range(self.xbars + 1):
dc.DrawLine(x*(float(self.width-1)/(self.xbars-1)), 0, x*(float(self.width-1)/(self.xbars-1)), self.height) dc.DrawLine(x * (float(self.width - 1) / (self.xbars - 1)),
0,
x * (float(self.width - 1) / (self.xbars - 1)),
self.height)
# draw horizontal bars # draw horizontal bars
spacing = self._calculate_spacing() #spacing between bars, in degrees spacing = self._calculate_spacing() # spacing between bars, in degrees
yspan = self.maxyvalue-self.minyvalue yspan = self.maxyvalue - self.minyvalue
ybars = int(yspan/spacing) #Should be close to self.ybars ybars = int(yspan / spacing) # Should be close to self.ybars
firstbar = int(ceil(self.minyvalue/spacing)) #in degrees firstbar = int(ceil(self.minyvalue / spacing)) # in degrees
dc.SetPen(wx.Pen(wx.Colour(225, 225, 225), 1)) dc.SetPen(wx.Pen(wx.Colour(225, 225, 225), 1))
for y in xrange(firstbar,firstbar+ybars+1): for y in range(firstbar, firstbar + ybars + 1):
#y_pos = y*(float(self.height)/self.ybars) #y_pos = y*(float(self.height)/self.ybars)
degrees = y*spacing degrees = y * spacing
y_pos = self._y_pos(degrees) y_pos = self._y_pos(degrees)
dc.DrawLine(0, y_pos, self.width, y_pos) dc.DrawLine(0, y_pos, self.width, y_pos)
gc.DrawText(unicode(y*spacing), 1, y_pos - (font.GetPointSize() / 2)) gc.DrawText(unicode(y * spacing),
1, y_pos - (font.GetPointSize() / 2))
if self.timer.IsRunning() == False: if self.timer.IsRunning() is False:
font = wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD) font = wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD)
gc.SetFont(font, wx.Colour(3, 4, 4)) gc.SetFont(font, wx.Colour(3, 4, 4))
gc.DrawText("Graph offline", self.width/2 - (font.GetPointSize() * 3), self.height/2 - (font.GetPointSize() * 1)) gc.DrawText("Graph offline",
self.width / 2 - (font.GetPointSize() * 3),
self.height / 2 - (font.GetPointSize() * 1))
#dc.DrawCircle(50, 50, 1) #dc.DrawCircle(50, 50, 1)
...@@ -138,40 +146,42 @@ class Graph(BufferedCanvas): ...@@ -138,40 +146,42 @@ class Graph(BufferedCanvas):
#gc.DrawLines([[20, 30], [10, 53]]) #gc.DrawLines([[20, 30], [10, 53]])
#dc.SetPen(wx.Pen(wx.Colour(255, 0, 0, 0), 1)) #dc.SetPen(wx.Pen(wx.Colour(255, 0, 0, 0), 1))
def _y_pos(self,temperature): def _y_pos(self, temperature):
"""Converts a temperature, in degrees, to a pixel position""" """Converts a temperature, in degrees, to a pixel position"""
#fraction of the screen from the bottom #fraction of the screen from the bottom
frac = float(temperature-self.minyvalue)/(self.maxyvalue-self.minyvalue) frac = (float(temperature - self.minyvalue)
return int( (1.0-frac)*(self.height-1) ) / (self.maxyvalue - self.minyvalue))
return int((1.0 - frac) * (self.height - 1))
def _calculate_spacing(self): def _calculate_spacing(self):
# Allow grids of spacings 1,2.5,5,10,25,50,100,etc # Allow grids of spacings 1,2.5,5,10,25,50,100,etc
yspan = float(self.maxyvalue-self.minyvalue) yspan = float(self.maxyvalue - self.minyvalue)
log_yspan = log10( yspan/self.ybars ) log_yspan = log10(yspan / self.ybars)
exponent = int( floor(log_yspan) ) exponent = int(floor(log_yspan))
#calculate boundary points between allowed spacings #calculate boundary points between allowed spacings
log1_25 = log10(2)+log10(1)+log10(2.5)-log10(1+2.5) log1_25 = log10(2) + log10(1) + log10(2.5) - log10(1 + 2.5)
log25_5 = log10(2)+log10(2.5)+log10(5)-log10(2.5+5) log25_5 = log10(2) + log10(2.5) + log10(5) - log10(2.5 + 5)
log5_10 = log10(2)+log10(5)+log10(10)-log10(5+10) log5_10 = log10(2) + log10(5) + log10(10) - log10(5 + 10)
if log_yspan-exponent < log1_25: if log_yspan - exponent < log1_25:
return 10**exponent return 10 ** exponent
elif log1_25 <= log_yspan-exponent < log25_5: elif log1_25 <= log_yspan - exponent < log25_5:
return 25*10**(exponent-1) return 25 * 10 ** (exponent - 1)
elif log25_5 <= log_yspan-exponent < log5_10: elif log25_5 <= log_yspan - exponent < log5_10:
return 5*10**exponent return 5 * 10 ** exponent
else: else:
return 10**(exponent+1) return 10 ** (exponent + 1)
def drawtemperature(self, dc, gc, temperature_list, text, text_xoffset, r, g, b, a): def drawtemperature(self, dc, gc, temperature_list,
if self.timer.IsRunning() == False: text, text_xoffset, r, g, b, a):
if self.timer.IsRunning() is False:
dc.SetPen(wx.Pen(wx.Colour(128, 128, 128, 128), 1)) dc.SetPen(wx.Pen(wx.Colour(128, 128, 128, 128), 1))
else: else:
dc.SetPen(wx.Pen(wx.Colour(r, g, b, a), 1)) dc.SetPen(wx.Pen(wx.Colour(r, g, b, a), 1))
x_add = float(self.width)/self.xsteps x_add = float(self.width) / self.xsteps
x_pos = 0.0 x_pos = 0.0
lastxvalue = 0.0 lastxvalue = 0.0
lastyvalue = temperature_list[-1] lastyvalue = temperature_list[-1]
...@@ -188,34 +198,39 @@ class Graph(BufferedCanvas): ...@@ -188,34 +198,39 @@ class Graph(BufferedCanvas):
if len(text) > 0: if len(text) > 0:
font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD) font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD)
#font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL) #font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL)
if self.timer.IsRunning() == False: if self.timer.IsRunning() is False:
gc.SetFont(font, wx.Colour(128, 128, 128)) gc.SetFont(font, wx.Colour(128, 128, 128))
else: else:
gc.SetFont(font, wx.Colour(r, g, b)) gc.SetFont(font, wx.Colour(r, g, b))
gc.DrawText(text, x_pos - x_add - (font.GetPointSize() * ((len(text) * text_xoffset + 1))), lastyvalue - (font.GetPointSize() / 2)) text_size = len(text) * text_xoffset + 1
gc.DrawText(text,
x_pos - x_add - (font.GetPointSize() * text_size),
lastyvalue - (font.GetPointSize() / 2))
def drawbedtemp(self, dc, gc): def drawbedtemp(self, dc, gc):
self.drawtemperature(dc, gc, self.bedtemps, "Bed", 2, 255, 0, 0, 128) self.drawtemperature(dc, gc, self.bedtemps,
"Bed", 2, 255, 0, 0, 128)
def drawbedtargettemp(self, dc, gc): def drawbedtargettemp(self, dc, gc):
self.drawtemperature(dc, gc, self.bedtargettemps, "Bed Target", 2, 255, 120, 0, 128) self.drawtemperature(dc, gc, self.bedtargettemps,
"Bed Target", 2, 255, 120, 0, 128)
def drawextruder0temp(self, dc, gc): def drawextruder0temp(self, dc, gc):
self.drawtemperature(dc, gc, self.extruder0temps, "Ex0", 1, 0, 155, 255, 128) self.drawtemperature(dc, gc, self.extruder0temps,
"Ex0", 1, 0, 155, 255, 128)
def drawextruder0targettemp(self, dc, gc): def drawextruder0targettemp(self, dc, gc):
self.drawtemperature(dc, gc, self.extruder0targettemps, "Ex0 Target", 2, 0, 5, 255, 128) self.drawtemperature(dc, gc, self.extruder0targettemps,
"Ex0 Target", 2, 0, 5, 255, 128)
def drawextruder1temp(self, dc, gc): def drawextruder1temp(self, dc, gc):
self.drawtemperature(dc, gc, self.extruder1temps, "Ex1", 3, 55, 55, 0, 128) self.drawtemperature(dc, gc, self.extruder1temps,
"Ex1", 3, 55, 55, 0, 128)
def drawextruder1targettemp(self, dc, gc): def drawextruder1targettemp(self, dc, gc):
self.drawtemperature(dc, gc, self.extruder1targettemps, "Ex1 Target", 2, 55, 55, 0, 128) self.drawtemperature(dc, gc, self.extruder1targettemps,
"Ex1 Target", 2, 55, 55, 0, 128)
def SetBedTemperature(self, value): def SetBedTemperature(self, value):
self.bedtemps.pop() self.bedtemps.pop()
...@@ -224,7 +239,7 @@ class Graph(BufferedCanvas): ...@@ -224,7 +239,7 @@ class Graph(BufferedCanvas):
def AddBedTemperature(self, value): def AddBedTemperature(self, value):
self.bedtemps.append(value) self.bedtemps.append(value)
if (len(self.bedtemps)-1) * float(self.width)/self.xsteps > self.width: if float(len(self.bedtemps) - 1) / self.xsteps > 1:
self.bedtemps.pop(0) self.bedtemps.pop(0)
def SetBedTargetTemperature(self, value): def SetBedTargetTemperature(self, value):
...@@ -234,7 +249,7 @@ class Graph(BufferedCanvas): ...@@ -234,7 +249,7 @@ class Graph(BufferedCanvas):
def AddBedTargetTemperature(self, value): def AddBedTargetTemperature(self, value):
self.bedtargettemps.append(value) self.bedtargettemps.append(value)
if (len(self.bedtargettemps)-1) * float(self.width)/self.xsteps > self.width: if float(len(self.bedtargettemps) - 1) / self.xsteps > 1:
self.bedtargettemps.pop(0) self.bedtargettemps.pop(0)
def SetExtruder0Temperature(self, value): def SetExtruder0Temperature(self, value):
...@@ -244,7 +259,7 @@ class Graph(BufferedCanvas): ...@@ -244,7 +259,7 @@ class Graph(BufferedCanvas):
def AddExtruder0Temperature(self, value): def AddExtruder0Temperature(self, value):
self.extruder0temps.append(value) self.extruder0temps.append(value)
if (len(self.extruder0temps)-1) * float(self.width)/self.xsteps > self.width: if float(len(self.extruder0temps) - 1) / self.xsteps > 1:
self.extruder0temps.pop(0) self.extruder0temps.pop(0)
def SetExtruder0TargetTemperature(self, value): def SetExtruder0TargetTemperature(self, value):
...@@ -254,7 +269,7 @@ class Graph(BufferedCanvas): ...@@ -254,7 +269,7 @@ class Graph(BufferedCanvas):
def AddExtruder0TargetTemperature(self, value): def AddExtruder0TargetTemperature(self, value):
self.extruder0targettemps.append(value) self.extruder0targettemps.append(value)
if (len(self.extruder0targettemps)-1) * float(self.width)/self.xsteps > self.width: if float(len(self.extruder0targettemps) - 1) / self.xsteps > 1:
self.extruder0targettemps.pop(0) self.extruder0targettemps.pop(0)
def SetExtruder1Temperature(self, value): def SetExtruder1Temperature(self, value):
...@@ -264,7 +279,7 @@ class Graph(BufferedCanvas): ...@@ -264,7 +279,7 @@ class Graph(BufferedCanvas):
def AddExtruder1Temperature(self, value): def AddExtruder1Temperature(self, value):
self.extruder1temps.append(value) self.extruder1temps.append(value)
if (len(self.extruder1temps)-1) * float(self.width)/self.xsteps > self.width: if float(len(self.extruder1temps) - 1) / self.xsteps > 1:
self.extruder1temps.pop(0) self.extruder1temps.pop(0)
def SetExtruder1TargetTemperature(self, value): def SetExtruder1TargetTemperature(self, value):
...@@ -274,7 +289,7 @@ class Graph(BufferedCanvas): ...@@ -274,7 +289,7 @@ class Graph(BufferedCanvas):
def AddExtruder1TargetTemperature(self, value): def AddExtruder1TargetTemperature(self, value):
self.extruder1targettemps.append(value) self.extruder1targettemps.append(value)
if (len(self.extruder1targettemps)-1) * float(self.width)/self.xsteps > self.width: if float(len(self.extruder1targettemps) - 1) / self.xsteps > 1:
self.extruder1targettemps.pop(0) self.extruder1targettemps.pop(0)
def StartPlotting(self, time): def StartPlotting(self, time):
...@@ -304,7 +319,7 @@ class Graph(BufferedCanvas): ...@@ -304,7 +319,7 @@ class Graph(BufferedCanvas):
class _YBounds(object): class _YBounds(object):
"""Small helper class to claculate y bounds dynamically""" """Small helper class to claculate y bounds dynamically"""
def __init__(self, graph, minimum_scale=5.0,buffer=0.10): def __init__(self, graph, minimum_scale=5.0, buffer=0.10):
"""_YBounds(Graph,float,float) """_YBounds(Graph,float,float)
graph parent object to calculate scales for graph parent object to calculate scales for
...@@ -320,18 +335,21 @@ class Graph(BufferedCanvas): ...@@ -320,18 +335,21 @@ class Graph(BufferedCanvas):
# Frequency to rescale the graph # Frequency to rescale the graph
self.update_freq = 10 self.update_freq = 10
self._last_update = self.update_freq #number of updates since last full refresh #number of updates since last full refresh
self._last_update = self.update_freq
def update(self,forceUpdate=False): def update(self, forceUpdate=False):
"""Updates graph.minyvalue and graph.maxyvalue based on current temperatures """Updates graph.minyvalue and graph.maxyvalue based on current
""" temperatures """
self._last_update += 1 self._last_update += 1
#TODO Smart update. Only do full calculation every 10s. Otherwise, just look at current graph & expand if necessary # TODO Smart update. Only do full calculation every 10s. Otherwise,
# just look at current graph & expand if necessary
if forceUpdate or self._last_update >= self.update_freq: if forceUpdate or self._last_update >= self.update_freq:
self.graph.minyvalue, self.graph.maxyvalue = self.getBounds() self.graph.minyvalue, self.graph.maxyvalue = self.getBounds()
self._last_update = 0 self._last_update = 0
else: else:
self.graph.minyvalue, self.graph.maxyvalue = self.getBoundsQuick() bounds = self.getBoundsQuick()
self.graph.minyvalue, self.graph.maxyvalue = bounds
def getBounds(self): def getBounds(self):
""" """
...@@ -339,7 +357,8 @@ class Graph(BufferedCanvas): ...@@ -339,7 +357,8 @@ class Graph(BufferedCanvas):
Rules: Rules:
* Include the full extruder0 history * Include the full extruder0 history
* Include the current target temp (but not necessarily old settings) * Include the current target temp (but not necessarily old
settings)
* Include the extruder1 and/or bed temp if * Include the extruder1 and/or bed temp if
1) The target temp is >0 1) The target temp is >0
2) The history has ever been above 5 2) The history has ever been above 5
...@@ -358,23 +377,23 @@ class Graph(BufferedCanvas): ...@@ -358,23 +377,23 @@ class Graph(BufferedCanvas):
miny = min(extruder0_min, extruder0_target) miny = min(extruder0_min, extruder0_target)
maxy = max(extruder0_max, extruder0_target) maxy = max(extruder0_max, extruder0_target)
if extruder1_target > 0 or extruder1_max > 5: #use extruder1 if extruder1_target > 0 or extruder1_max > 5: # use extruder1
miny = min(miny, extruder1_min, extruder1_target) miny = min(miny, extruder1_min, extruder1_target)
maxy = max(maxy, extruder1_max, extruder1_target) maxy = max(maxy, extruder1_max, extruder1_target)
if bed_target > 0 or bed_max > 5: #use HBP if bed_target > 0 or bed_max > 5: # use HBP
miny = min(miny, bed_min, bed_target) miny = min(miny, bed_min, bed_target)
maxy = max(maxy, bed_max, bed_target) maxy = max(maxy, bed_max, bed_target)
padding = (maxy-miny)*self.buffer/(1.0-2*self.buffer) padding = (maxy - miny) * self.buffer / (1.0 - 2 * self.buffer)
miny -= padding miny -= padding
maxy += padding maxy += padding
if maxy-miny < self.min_scale: if maxy - miny < self.min_scale:
extrapadding = (self.min_scale-maxy+miny)/2.0 extrapadding = (self.min_scale - maxy + miny) / 2.0
miny -= extrapadding miny -= extrapadding
maxy += extrapadding maxy += extrapadding
return (miny,maxy) return (miny, maxy)
def getBoundsQuick(self): def getBoundsQuick(self):
# Only look at current temps # Only look at current temps
...@@ -390,20 +409,21 @@ class Graph(BufferedCanvas): ...@@ -390,20 +409,21 @@ class Graph(BufferedCanvas):
miny = min(extruder0_min, extruder0_target) miny = min(extruder0_min, extruder0_target)
maxy = max(extruder0_max, extruder0_target) maxy = max(extruder0_max, extruder0_target)
if extruder1_target > 0 or extruder1_max > 5: #use extruder1 if extruder1_target > 0 or extruder1_max > 5: # use extruder1
miny = min(miny, extruder1_min, extruder1_target) miny = min(miny, extruder1_min, extruder1_target)
maxy = max(maxy, extruder1_max, extruder1_target) maxy = max(maxy, extruder1_max, extruder1_target)
if bed_target > 0 or bed_max > 5: #use HBP if bed_target > 0 or bed_max > 5: # use HBP
miny = min(miny, bed_min, bed_target) miny = min(miny, bed_min, bed_target)
maxy = max(maxy, bed_max, bed_target) maxy = max(maxy, bed_max, bed_target)
#We have to rescale, so add padding #We have to rescale, so add padding
bufratio = self.buffer / (1.0 - self.buffer)
if miny < self.graph.minyvalue: if miny < self.graph.minyvalue:
padding = (self.graph.maxyvalue-miny)*self.buffer/(1.0-self.buffer) padding = (self.graph.maxyvalue - miny) * bufratio
miny -= padding miny -= padding
if maxy > self.graph.maxyvalue: if maxy > self.graph.maxyvalue:
padding = (maxy-self.graph.minyvalue)*self.buffer/(1.0-self.buffer) padding = (maxy - self.graph.minyvalue) * bufratio
maxy += padding maxy += padding
return min(miny,self.graph.minyvalue),max(maxy,self.graph.maxyvalue) return (min(miny, self.graph.minyvalue),
max(maxy, self.graph.maxyvalue))
...@@ -67,7 +67,7 @@ class XYZControlsSizer(wx.GridBagSizer): ...@@ -67,7 +67,7 @@ class XYZControlsSizer(wx.GridBagSizer):
def add_extra_controls(self, root, parentpanel, extra_buttons = None): def add_extra_controls(self, root, parentpanel, extra_buttons = None):
standalone_mode = extra_buttons is not None standalone_mode = extra_buttons is not None
base_line = 1 if standalone_mode else 2 base_line = 1 if standalone_mode else 2
root.monitorbox = wx.CheckBox(parentpanel,-1, _("Watch")) root.monitorbox = wx.CheckBox(parentpanel, -1, _("Watch"))
root.monitorbox.SetValue(bool(root.settings.monitor)) root.monitorbox.SetValue(bool(root.settings.monitor))
root.monitorbox.SetToolTip(wx.ToolTip("Monitor Temperatures in Graph")) root.monitorbox.SetToolTip(wx.ToolTip("Monitor Temperatures in Graph"))
if standalone_mode: if standalone_mode:
...@@ -76,17 +76,17 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None): ...@@ -76,17 +76,17 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None):
self.Add(root.monitorbox, pos = (base_line + 1, 5)) self.Add(root.monitorbox, pos = (base_line + 1, 5))
root.monitorbox.Bind(wx.EVT_CHECKBOX, root.setmonitor) root.monitorbox.Bind(wx.EVT_CHECKBOX, root.setmonitor)
self.Add(wx.StaticText(parentpanel,-1, _("Heat:")), pos = (base_line + 0, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT) self.Add(wx.StaticText(parentpanel, -1, _("Heat:")), pos = (base_line + 0, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
htemp_choices = [root.temps[i]+" ("+i+")" for i in sorted(root.temps.keys(), key = lambda x:root.temps[x])] htemp_choices = [root.temps[i] + " (" + i + ")" for i in sorted(root.temps.keys(), key = lambda x:root.temps[x])]
root.settoff = make_button(parentpanel, _("Off"), lambda e: root.do_settemp("off"), _("Switch Hotend Off"), size = (38,-1), style = wx.BU_EXACTFIT) root.settoff = make_button(parentpanel, _("Off"), lambda e: root.do_settemp("off"), _("Switch Hotend Off"), size = (38, -1), style = wx.BU_EXACTFIT)
root.printerControls.append(root.settoff) root.printerControls.append(root.settoff)
self.Add(root.settoff, pos = (base_line + 0, 2), span = (1, 1)) self.Add(root.settoff, pos = (base_line + 0, 2), span = (1, 1))
if root.settings.last_temperature not in map(float, root.temps.values()): if root.settings.last_temperature not in map(float, root.temps.values()):
htemp_choices = [str(root.settings.last_temperature)] + htemp_choices htemp_choices = [str(root.settings.last_temperature)] + htemp_choices
root.htemp = wx.ComboBox(parentpanel, -1, root.htemp = wx.ComboBox(parentpanel, -1, choices = htemp_choices,
choices = htemp_choices, style = wx.CB_DROPDOWN, size = (80,-1)) style = wx.CB_DROPDOWN, size = (80, -1))
root.htemp.SetToolTip(wx.ToolTip("Select Temperature for Hotend")) root.htemp.SetToolTip(wx.ToolTip("Select Temperature for Hotend"))
root.htemp.Bind(wx.EVT_COMBOBOX, root.htemp_change) root.htemp.Bind(wx.EVT_COMBOBOX, root.htemp_change)
...@@ -95,17 +95,17 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None): ...@@ -95,17 +95,17 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None):
root.printerControls.append(root.settbtn) root.printerControls.append(root.settbtn)
self.Add(root.settbtn, pos = (base_line + 0, 4), span = (1, 1)) self.Add(root.settbtn, pos = (base_line + 0, 4), span = (1, 1))
self.Add(wx.StaticText(parentpanel,-1, _("Bed:")), pos = (base_line + 1, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT) self.Add(wx.StaticText(parentpanel, -1, _("Bed:")), pos = (base_line + 1, 0), span = (1, 2), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT)
btemp_choices = [root.bedtemps[i]+" ("+i+")" for i in sorted(root.bedtemps.keys(), key = lambda x:root.temps[x])] btemp_choices = [root.bedtemps[i] + " (" + i + ")" for i in sorted(root.bedtemps.keys(), key = lambda x:root.temps[x])]
root.setboff = make_button(parentpanel, _("Off"), lambda e:root.do_bedtemp("off"), _("Switch Heated Bed Off"), size = (38,-1), style = wx.BU_EXACTFIT) root.setboff = make_button(parentpanel, _("Off"), lambda e: root.do_bedtemp("off"), _("Switch Heated Bed Off"), size = (38, -1), style = wx.BU_EXACTFIT)
root.printerControls.append(root.setboff) root.printerControls.append(root.setboff)
self.Add(root.setboff, pos = (base_line + 1, 2), span = (1, 1)) self.Add(root.setboff, pos = (base_line + 1, 2), span = (1, 1))
if root.settings.last_bed_temperature not in map(float, root.bedtemps.values()): if root.settings.last_bed_temperature not in map(float, root.bedtemps.values()):
btemp_choices = [str(root.settings.last_bed_temperature)] + btemp_choices btemp_choices = [str(root.settings.last_bed_temperature)] + btemp_choices
root.btemp = wx.ComboBox(parentpanel, -1, root.btemp = wx.ComboBox(parentpanel, -1, choices = btemp_choices,
choices = btemp_choices, style = wx.CB_DROPDOWN, size = (80,-1)) style = wx.CB_DROPDOWN, size = (80, -1))
root.btemp.SetToolTip(wx.ToolTip("Select Temperature for Heated Bed")) root.btemp.SetToolTip(wx.ToolTip("Select Temperature for Heated Bed"))
root.btemp.Bind(wx.EVT_COMBOBOX, root.btemp_change) root.btemp.Bind(wx.EVT_COMBOBOX, root.btemp_change)
self.Add(root.btemp, pos = (base_line + 1, 3), span = (1, 1)) self.Add(root.btemp, pos = (base_line + 1, 3), span = (1, 1))
...@@ -125,15 +125,15 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None): ...@@ -125,15 +125,15 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None):
if i.split()[0] == str(root.settings.last_bed_temperature).split('.')[0] or i.split()[0] == str(root.settings.last_bed_temperature): if i.split()[0] == str(root.settings.last_bed_temperature).split('.')[0] or i.split()[0] == str(root.settings.last_bed_temperature):
root.btemp.SetValue(i) root.btemp.SetValue(i)
for i in htemp_choices: for i in htemp_choices:
if i.split()[0] == str(root.settings.last_temperature).split('.')[0] or i.split()[0] == str(root.settings.last_temperature) : if i.split()[0] == str(root.settings.last_temperature).split('.')[0] or i.split()[0] == str(root.settings.last_temperature):
root.htemp.SetValue(i) root.htemp.SetValue(i)
if( '(' not in root.btemp.Value): if '(' not in root.btemp.Value:
root.btemp.SetValue(root.btemp.Value + ' (user)') root.btemp.SetValue(root.btemp.Value + ' (user)')
if( '(' not in root.htemp.Value): if '(' not in root.htemp.Value:
root.htemp.SetValue(root.htemp.Value + ' (user)') root.htemp.SetValue(root.htemp.Value + ' (user)')
root.tempdisp = wx.StaticText(parentpanel,-1, "") root.tempdisp = wx.StaticText(parentpanel, -1, "")
if not extra_buttons: if not extra_buttons:
ebuttonspanel = root.newPanel(parentpanel) ebuttonspanel = root.newPanel(parentpanel)
...@@ -143,13 +143,13 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None): ...@@ -143,13 +143,13 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None):
esettingspanel = root.newPanel(parentpanel) esettingspanel = root.newPanel(parentpanel)
esettingssizer = wx.BoxSizer(wx.HORIZONTAL) esettingssizer = wx.BoxSizer(wx.HORIZONTAL)
root.edist = wx.SpinCtrl(esettingspanel,-1, "5", min = 0, max = 1000, size = (70,-1)) root.edist = wx.SpinCtrl(esettingspanel, -1, "5", min = 0, max = 1000, size = (70, -1))
root.edist.SetBackgroundColour((225, 200, 200)) root.edist.SetBackgroundColour((225, 200, 200))
root.edist.SetForegroundColour("black") root.edist.SetForegroundColour("black")
esettingssizer.Add(root.edist, flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5) esettingssizer.Add(root.edist, flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
esettingssizer.Add(wx.StaticText(esettingspanel, -1, _("mm @")), flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5) esettingssizer.Add(wx.StaticText(esettingspanel, -1, _("mm @")), flag = wx.ALIGN_CENTER | wx.RIGHT, border = 5)
root.edist.SetToolTip(wx.ToolTip("Amount to Extrude or Retract (mm)")) root.edist.SetToolTip(wx.ToolTip("Amount to Extrude or Retract (mm)"))
root.efeedc = wx.SpinCtrl(esettingspanel,-1, str(root.settings.e_feedrate), min = 0, max = 50000, size = (70,-1)) root.efeedc = wx.SpinCtrl(esettingspanel, -1, str(root.settings.e_feedrate), min = 0, max = 50000, size = (70, -1))
root.efeedc.SetToolTip(wx.ToolTip("Extrude / Retract speed (mm/min)")) root.efeedc.SetToolTip(wx.ToolTip("Extrude / Retract speed (mm/min)"))
root.efeedc.SetBackgroundColour((225, 200, 200)) root.efeedc.SetBackgroundColour((225, 200, 200))
root.efeedc.SetForegroundColour("black") root.efeedc.SetForegroundColour("black")
...@@ -166,12 +166,14 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None): ...@@ -166,12 +166,14 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None):
self.Add(root.hottgauge, pos = (gauges_base_line + 0, 0), span = (1, 6), flag = wx.EXPAND) self.Add(root.hottgauge, pos = (gauges_base_line + 0, 0), span = (1, 6), flag = wx.EXPAND)
root.bedtgauge = TempGauge(parentpanel, size = (-1, 24), title = _("Bed:"), maxval = 150) root.bedtgauge = TempGauge(parentpanel, size = (-1, 24), title = _("Bed:"), maxval = 150)
self.Add(root.bedtgauge, pos = (gauges_base_line + 1, 0), span = (1, 6), flag = wx.EXPAND) self.Add(root.bedtgauge, pos = (gauges_base_line + 1, 0), span = (1, 6), flag = wx.EXPAND)
def hotendgauge_scroll_setpoint(e): def hotendgauge_scroll_setpoint(e):
rot = e.GetWheelRotation() rot = e.GetWheelRotation()
if rot > 0: if rot > 0:
root.do_settemp(str(root.hsetpoint + 1)) root.do_settemp(str(root.hsetpoint + 1))
elif rot < 0: elif rot < 0:
root.do_settemp(str(max(0, root.hsetpoint - 1))) root.do_settemp(str(max(0, root.hsetpoint - 1)))
def bedgauge_scroll_setpoint(e): def bedgauge_scroll_setpoint(e):
rot = e.GetWheelRotation() rot = e.GetWheelRotation()
if rot > 0: if rot > 0:
...@@ -193,15 +195,13 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None): ...@@ -193,15 +195,13 @@ def add_extra_controls(self, root, parentpanel, extra_buttons = None):
root.graph.Bind(wx.EVT_LEFT_DOWN, root.graph.showwin) root.graph.Bind(wx.EVT_LEFT_DOWN, root.graph.showwin)
if extra_buttons: if extra_buttons:
pos_mapping = { pos_mapping = {(2, 5): (0, 0),
(2,5):(0,0), (4, 0): (3, 0),
(4,0):(3,0), (4, 2): (3, 2),
(4,2):(3,2),
} }
span_mapping = { span_mapping = {(2, 5): (1, 3),
(2,5):(1,3), (4, 0): (1, 2),
(4,0):(1,2), (4, 2): (1, 3),
(4,2):(1,3),
} }
for i in extra_buttons: for i in extra_buttons:
btn = extra_buttons[i] btn = extra_buttons[i]
...@@ -224,12 +224,11 @@ class LeftPane(wx.GridBagSizer): ...@@ -224,12 +224,11 @@ class LeftPane(wx.GridBagSizer):
self.Add(self.xyzsizer, pos = (1, 0), span = (1, 6), flag = wx.ALIGN_CENTER) self.Add(self.xyzsizer, pos = (1, 0), span = (1, 6), flag = wx.ALIGN_CENTER)
self.extra_buttons = {} self.extra_buttons = {}
ebuttons = []
for i in root.cpbuttons: for i in root.cpbuttons:
if not standalone_mode and i.pos and i.pos[0] == 4: if not standalone_mode and i.pos and i.pos[0] == 4:
continue continue
btn = make_custom_button(root, parentpanel, i) btn = make_custom_button(root, parentpanel, i)
if i.pos == None: if i.pos is None:
if i.span == 0: if i.span == 0:
llts.Add(btn) llts.Add(btn)
elif not standalone_mode: elif not standalone_mode:
...@@ -237,12 +236,12 @@ class LeftPane(wx.GridBagSizer): ...@@ -237,12 +236,12 @@ class LeftPane(wx.GridBagSizer):
else: else:
self.extra_buttons[i] = btn self.extra_buttons[i] = btn
root.xyfeedc = wx.SpinCtrl(parentpanel,-1, str(root.settings.xy_feedrate), min = 0, max = 50000, size = (70,-1)) root.xyfeedc = wx.SpinCtrl(parentpanel, -1, str(root.settings.xy_feedrate), min = 0, max = 50000, size = (70, -1))
root.xyfeedc.SetToolTip(wx.ToolTip("Set Maximum Speed for X & Y axes (mm/min)")) root.xyfeedc.SetToolTip(wx.ToolTip("Set Maximum Speed for X & Y axes (mm/min)"))
llts.Add(wx.StaticText(parentpanel,-1, _("XY:")), flag = wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) llts.Add(wx.StaticText(parentpanel, -1, _("XY:")), flag = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
llts.Add(root.xyfeedc) llts.Add(root.xyfeedc)
llts.Add(wx.StaticText(parentpanel,-1, _("mm/min Z:")), flag = wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) llts.Add(wx.StaticText(parentpanel, -1, _("mm/min Z:")), flag = wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
root.zfeedc = wx.SpinCtrl(parentpanel,-1, str(root.settings.z_feedrate), min = 0, max = 50000, size = (70,-1)) root.zfeedc = wx.SpinCtrl(parentpanel, -1, str(root.settings.z_feedrate), min = 0, max = 50000, size = (70, -1))
root.zfeedc.SetToolTip(wx.ToolTip("Set Maximum Speed for Z axis (mm/min)")) root.zfeedc.SetToolTip(wx.ToolTip("Set Maximum Speed for Z axis (mm/min)"))
llts.Add(root.zfeedc,) llts.Add(root.zfeedc,)
...@@ -262,12 +261,16 @@ class NoViz(object): ...@@ -262,12 +261,16 @@ class NoViz(object):
def clear(self, *a): def clear(self, *a):
pass pass
def addfile(self, *a, **kw): def addfile(self, *a, **kw):
pass pass
def addgcode(self, *a, **kw): def addgcode(self, *a, **kw):
pass pass
def Refresh(self, *a): def Refresh(self, *a):
pass pass
def setlayer(self, *a): def setlayer(self, *a):
pass pass
...@@ -312,8 +315,7 @@ class VizPane(wx.BoxSizer): ...@@ -312,8 +315,7 @@ class VizPane(wx.BoxSizer):
print "Falling back to 2D view, and here is the backtrace:" print "Falling back to 2D view, and here is the backtrace:"
traceback.print_exc() traceback.print_exc()
if not use3dview: if not use3dview:
root.gwindow = gviz.GvizWindow( root.gwindow = gviz.GvizWindow(build_dimensions = root.build_dimensions_list,
build_dimensions = root.build_dimensions_list,
grid = (root.settings.preview_grid_step1, root.settings.preview_grid_step2), grid = (root.settings.preview_grid_step1, root.settings.preview_grid_step2),
extrusion_width = root.settings.preview_extrusion_width, extrusion_width = root.settings.preview_extrusion_width,
bgcolor = root.settings.bgcolor) bgcolor = root.settings.bgcolor)
...@@ -326,8 +328,8 @@ class LogPane(wx.BoxSizer): ...@@ -326,8 +328,8 @@ class LogPane(wx.BoxSizer):
def __init__(self, root, parentpanel = None): def __init__(self, root, parentpanel = None):
super(LogPane, self).__init__(wx.VERTICAL) super(LogPane, self).__init__(wx.VERTICAL)
if not parentpanel: parentpanel = root.panel if not parentpanel: parentpanel = root.panel
root.logbox = wx.TextCtrl(parentpanel, style = wx.TE_MULTILINE, size = (350,-1)) root.logbox = wx.TextCtrl(parentpanel, style = wx.TE_MULTILINE, size = (350, -1))
root.logbox.SetMinSize((100,-1)) root.logbox.SetMinSize((100, -1))
root.logbox.SetEditable(0) root.logbox.SetEditable(0)
self.Add(root.logbox, 1, wx.EXPAND) self.Add(root.logbox, 1, wx.EXPAND)
lbrs = wx.BoxSizer(wx.HORIZONTAL) lbrs = wx.BoxSizer(wx.HORIZONTAL)
...@@ -351,25 +353,24 @@ def MainToolbar(root, parentpanel = None, use_wrapsizer = False): ...@@ -351,25 +353,24 @@ def MainToolbar(root, parentpanel = None, use_wrapsizer = False):
root.locker.Bind(wx.EVT_CHECKBOX, root.lock) root.locker.Bind(wx.EVT_CHECKBOX, root.lock)
root.locker.SetToolTip(wx.ToolTip(_("Lock graphical interface"))) root.locker.SetToolTip(wx.ToolTip(_("Lock graphical interface")))
glob = wx.BoxSizer(wx.HORIZONTAL) glob = wx.BoxSizer(wx.HORIZONTAL)
origpanel = parentpanel
parentpanel = root.newPanel(parentpanel) parentpanel = root.newPanel(parentpanel)
glob.Add(parentpanel, 1, flag = wx.EXPAND) glob.Add(parentpanel, 1, flag = wx.EXPAND)
glob.Add(root.locker, 0) glob.Add(root.locker, 0)
ToolbarSizer = wx.WrapSizer if use_wrapsizer and wx.VERSION > (2, 9) else wx.BoxSizer ToolbarSizer = wx.WrapSizer if use_wrapsizer and wx.VERSION > (2, 9) else wx.BoxSizer
self = ToolbarSizer(wx.HORIZONTAL) self = ToolbarSizer(wx.HORIZONTAL)
root.rescanbtn = make_sized_button(parentpanel, _("Port"), root.rescanports, _("Communication Settings\nClick to rescan ports")) root.rescanbtn = make_sized_button(parentpanel, _("Port"), root.rescanports, _("Communication Settings\nClick to rescan ports"))
self.Add(root.rescanbtn, 0, wx.TOP|wx.LEFT, 0) self.Add(root.rescanbtn, 0, wx.TOP | wx.LEFT, 0)
root.serialport = wx.ComboBox(parentpanel, -1, root.serialport = wx.ComboBox(parentpanel, -1, choices = root.scanserial(),
choices = root.scanserial(),
style = wx.CB_DROPDOWN, size = (-1, 25)) style = wx.CB_DROPDOWN, size = (-1, 25))
root.serialport.SetToolTip(wx.ToolTip("Select Port Printer is connected to")) root.serialport.SetToolTip(wx.ToolTip("Select Port Printer is connected to"))
root.rescanports() root.rescanports()
self.Add(root.serialport) self.Add(root.serialport)
self.Add(wx.StaticText(parentpanel,-1, "@"), 0, wx.RIGHT|wx.ALIGN_CENTER, 0) self.Add(wx.StaticText(parentpanel, -1, "@"), 0, wx.RIGHT | wx.ALIGN_CENTER, 0)
root.baud = wx.ComboBox(parentpanel, -1, root.baud = wx.ComboBox(parentpanel, -1,
choices = ["2400", "9600", "19200", "38400", "57600", "115200", "250000"], choices = ["2400", "9600", "19200", "38400",
"57600", "115200", "250000"],
style = wx.CB_DROPDOWN, size = (100, 25)) style = wx.CB_DROPDOWN, size = (100, 25))
root.baud.SetToolTip(wx.ToolTip("Select Baud rate for printer communication")) root.baud.SetToolTip(wx.ToolTip("Select Baud rate for printer communication"))
try: try:
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
from Queue import Queue from Queue import Queue
from collections import deque from collections import deque
import wx, time import wx
from printrun import gcoder from printrun import gcoder
from printrun_utils import imagefile, install_locale from printrun_utils import imagefile, install_locale
...@@ -76,10 +76,10 @@ class GvizWindow(GvizBaseFrame): ...@@ -76,10 +76,10 @@ class GvizWindow(GvizBaseFrame):
vbox.Add(self.p, 1, wx.EXPAND) vbox.Add(self.p, 1, wx.EXPAND)
self.SetMinSize(self.ClientToWindowSize(vbox.GetMinSize())) self.SetMinSize(self.ClientToWindowSize(vbox.GetMinSize()))
self.Bind(wx.EVT_TOOL, lambda x:self.p.zoom(-1, -1, 1.2), id = 1) self.Bind(wx.EVT_TOOL, lambda x: self.p.zoom(-1, -1, 1.2), id = 1)
self.Bind(wx.EVT_TOOL, lambda x:self.p.zoom(-1, -1, 1/1.2), id = 2) self.Bind(wx.EVT_TOOL, lambda x: self.p.zoom(-1, -1, 1 / 1.2), id = 2)
self.Bind(wx.EVT_TOOL, lambda x:self.p.layerup(), id = 3) self.Bind(wx.EVT_TOOL, lambda x: self.p.layerup(), id = 3)
self.Bind(wx.EVT_TOOL, lambda x:self.p.layerdown(), id = 4) self.Bind(wx.EVT_TOOL, lambda x: self.p.layerdown(), id = 4)
self.Bind(wx.EVT_TOOL, self.resetview, id = 5) self.Bind(wx.EVT_TOOL, self.resetview, id = 5)
#self.Bind(wx.EVT_TOOL, lambda x:self.p.inject(), id = 6) #self.Bind(wx.EVT_TOOL, lambda x:self.p.inject(), id = 6)
...@@ -140,7 +140,7 @@ class GvizWindow(GvizBaseFrame): ...@@ -140,7 +140,7 @@ class GvizWindow(GvizBaseFrame):
if x in kzi: if x in kzi:
self.p.zoom(cx, cy, 1.2) self.p.zoom(cx, cy, 1.2)
if x in kzo: if x in kzo:
self.p.zoom(cx, cy, 1/1.2) self.p.zoom(cx, cy, 1 / 1.2)
def zoom(self, event): def zoom(self, event):
z = event.GetWheelRotation() z = event.GetWheelRotation()
...@@ -149,14 +149,16 @@ class GvizWindow(GvizBaseFrame): ...@@ -149,14 +149,16 @@ class GvizWindow(GvizBaseFrame):
elif z < 0: self.p.layerup() elif z < 0: self.p.layerup()
else: else:
if z > 0: self.p.zoom(event.GetX(), event.GetY(), 1.2) if z > 0: self.p.zoom(event.GetX(), event.GetY(), 1.2)
elif z < 0: self.p.zoom(event.GetX(), event.GetY(), 1/1.2) elif z < 0: self.p.zoom(event.GetX(), event.GetY(), 1 / 1.2)
class Gviz(wx.Panel): class Gviz(wx.Panel):
# Mark canvas as dirty when setting showall # Mark canvas as dirty when setting showall
_showall = 0 _showall = 0
def _get_showall(self): def _get_showall(self):
return self._showall return self._showall
def _set_showall(self, showall): def _set_showall(self, showall):
if showall != self._showall: if showall != self._showall:
self.dirty = 1 self.dirty = 1
...@@ -168,7 +170,7 @@ class Gviz(wx.Panel): ...@@ -168,7 +170,7 @@ class Gviz(wx.Panel):
self.widget = self self.widget = self
size = [max(1.0, x) for x in size] size = [max(1.0, x) for x in size]
ratio = size[0] / size[1] ratio = size[0] / size[1]
self.SetMinSize((150, 150/ratio)) self.SetMinSize((150, 150 / ratio))
self.parent = realparent if realparent else parent self.parent = realparent if realparent else parent
self.size = size self.size = size
self.build_dimensions = build_dimensions self.build_dimensions = build_dimensions
...@@ -186,14 +188,14 @@ class Gviz(wx.Panel): ...@@ -186,14 +188,14 @@ class Gviz(wx.Panel):
self.filament_width = extrusion_width # set it to 0 to disable scaling lines with zoom self.filament_width = extrusion_width # set it to 0 to disable scaling lines with zoom
self.update_basescale() self.update_basescale()
self.scale = self.basescale self.scale = self.basescale
penwidth = max(1.0, self.filament_width*((self.scale[0]+self.scale[1])/2.0)) penwidth = max(1.0, self.filament_width * ((self.scale[0] + self.scale[1]) / 2.0))
self.translate = [0.0, 0.0] self.translate = [0.0, 0.0]
self.mainpen = wx.Pen(wx.Colour(0, 0, 0), penwidth) self.mainpen = wx.Pen(wx.Colour(0, 0, 0), penwidth)
self.arcpen = wx.Pen(wx.Colour(255, 0, 0), penwidth) self.arcpen = wx.Pen(wx.Colour(255, 0, 0), penwidth)
self.travelpen = wx.Pen(wx.Colour(10, 80, 80), penwidth) self.travelpen = wx.Pen(wx.Colour(10, 80, 80), penwidth)
self.hlpen = wx.Pen(wx.Colour(200, 50, 50), penwidth) self.hlpen = wx.Pen(wx.Colour(200, 50, 50), penwidth)
self.fades = [wx.Pen(wx.Colour(250-0.6**i*100, 250-0.6**i*100, 200-0.4**i*50), penwidth) for i in xrange(6)] self.fades = [wx.Pen(wx.Colour(250 - 0.6 ** i * 100, 250 - 0.6 ** i * 100, 200 - 0.4 ** i * 50), penwidth) for i in xrange(6)]
self.penslist = [self.mainpen, self.travelpen, self.hlpen]+self.fades self.penslist = [self.mainpen, self.travelpen, self.hlpen] + self.fades
self.showall = 0 self.showall = 0
self.hilight = deque() self.hilight = deque()
self.hilightarcs = deque() self.hilightarcs = deque()
...@@ -207,8 +209,8 @@ class Gviz(wx.Panel): ...@@ -207,8 +209,8 @@ class Gviz(wx.Panel):
def inject(self): def inject(self):
#import pdb; pdb.set_trace() #import pdb; pdb.set_trace()
print"Inject code here..." print "Inject code here..."
print "Layer "+str(self.layerindex +1)+" - Z = "+str(self.layers[self.layerindex])+" mm" print "Layer " + str(self.layerindex + 1) + " - Z = " + str(self.layers[self.layerindex]) + " mm"
def clearhilights(self): def clearhilights(self):
self.hilight.clear() self.hilight.clear()
...@@ -255,8 +257,8 @@ class Gviz(wx.Panel): ...@@ -255,8 +257,8 @@ class Gviz(wx.Panel):
wx.CallAfter(self.Refresh) wx.CallAfter(self.Refresh)
def update_basescale(self): def update_basescale(self):
self.basescale = 2*[min(float(self.size[0] - 1)/self.build_dimensions[0], self.basescale = 2 * [min(float(self.size[0] - 1) / self.build_dimensions[0],
float(self.size[1] - 1)/self.build_dimensions[1])] float(self.size[1] - 1) / self.build_dimensions[1])]
def resize(self, event): def resize(self, event):
old_basescale = self.basescale old_basescale = self.basescale
...@@ -273,25 +275,25 @@ class Gviz(wx.Panel): ...@@ -273,25 +275,25 @@ class Gviz(wx.Panel):
self.translate = [x - (x - self.translate[0]) * factor, self.translate = [x - (x - self.translate[0]) * factor,
y - (y - self.translate[1]) * factor] y - (y - self.translate[1]) * factor]
penwidth = max(1.0, self.filament_width*((self.scale[0]+self.scale[1])/2.0)) penwidth = max(1.0, self.filament_width * ((self.scale[0] + self.scale[1]) / 2.0))
for pen in self.penslist: for pen in self.penslist:
pen.SetWidth(penwidth) pen.SetWidth(penwidth)
self.dirty = 1 self.dirty = 1
wx.CallAfter(self.Refresh) wx.CallAfter(self.Refresh)
def _line_scaler(self, x): def _line_scaler(self, x):
return (self.scale[0]*x[0], return (self.scale[0] * x[0],
self.scale[1]*x[1], self.scale[1] * x[1],
self.scale[0]*x[2], self.scale[0] * x[2],
self.scale[1]*x[3],) self.scale[1] * x[3],)
def _arc_scaler(self, x): def _arc_scaler(self, x):
return (self.scale[0]*x[0], return (self.scale[0] * x[0],
self.scale[1]*x[1], self.scale[1] * x[1],
self.scale[0]*x[2], self.scale[0] * x[2],
self.scale[1]*x[3], self.scale[1] * x[3],
self.scale[0]*x[4], self.scale[0] * x[4],
self.scale[1]*x[5],) self.scale[1] * x[5],)
def _drawlines(self, dc, lines, pens): def _drawlines(self, dc, lines, pens):
scaled_lines = map(self._line_scaler, lines) scaled_lines = map(self._line_scaler, lines)
...@@ -305,8 +307,8 @@ class Gviz(wx.Panel): ...@@ -305,8 +307,8 @@ class Gviz(wx.Panel):
dc.DrawArc(*scaled_arcs[i]) dc.DrawArc(*scaled_arcs[i])
def repaint_everything(self): def repaint_everything(self):
width = self.scale[0]*self.build_dimensions[0] width = self.scale[0] * self.build_dimensions[0]
height = self.scale[1]*self.build_dimensions[1] height = self.scale[1] * self.build_dimensions[1]
self.blitmap = wx.EmptyBitmap(width + 1, height + 1, -1) self.blitmap = wx.EmptyBitmap(width + 1, height + 1, -1)
dc = wx.MemoryDC() dc = wx.MemoryDC()
dc.SelectObject(self.blitmap) dc.SelectObject(self.blitmap)
...@@ -315,23 +317,23 @@ class Gviz(wx.Panel): ...@@ -315,23 +317,23 @@ class Gviz(wx.Panel):
dc.SetPen(wx.Pen(wx.Colour(180, 180, 150))) dc.SetPen(wx.Pen(wx.Colour(180, 180, 150)))
for grid_unit in self.grid: for grid_unit in self.grid:
if grid_unit > 0: if grid_unit > 0:
for x in xrange(int(self.build_dimensions[0]/grid_unit)+1): for x in xrange(int(self.build_dimensions[0] / grid_unit) + 1):
draw_x = self.scale[0]*x*grid_unit draw_x = self.scale[0] * x * grid_unit
dc.DrawLine(draw_x, 0, draw_x, height) dc.DrawLine(draw_x, 0, draw_x, height)
for y in xrange(int(self.build_dimensions[1]/grid_unit)+1): for y in xrange(int(self.build_dimensions[1] / grid_unit) + 1):
draw_y = self.scale[1]*(self.build_dimensions[1]-y*grid_unit) draw_y = self.scale[1] * (self.build_dimensions[1] - y * grid_unit)
dc.DrawLine(0, draw_y, width, draw_y) dc.DrawLine(0, draw_y, width, draw_y)
dc.SetPen(wx.Pen(wx.Colour(0, 0, 0))) dc.SetPen(wx.Pen(wx.Colour(0, 0, 0)))
if not self.showall: if not self.showall:
# Draw layer gauge
dc.SetBrush(wx.Brush((43, 144, 255))) dc.SetBrush(wx.Brush((43, 144, 255)))
dc.DrawRectangle(self.size[0]-15, 0, 15, self.size[1]) dc.DrawRectangle(width - 15, 0, 15, height)
dc.SetBrush(wx.Brush((0, 255, 0))) dc.SetBrush(wx.Brush((0, 255, 0)))
if len(self.layers): if self.layers:
dc.DrawRectangle(self.size[0]-14, (1.0-(1.0*(self.layerindex+1))/len(self.layers))*self.size[1], 13, self.size[1]-1) dc.DrawRectangle(width - 14, (1.0 - (1.0 * (self.layerindex + 1)) / len(self.layers)) * height, 13, height - 1)
if self.showall: if self.showall:
l = []
for i in self.layers: for i in self.layers:
self._drawlines(dc, self.lines[i], self.pens[i]) self._drawlines(dc, self.lines[i], self.pens[i])
self._drawarcs(dc, self.arcs[i], self.arcpens[i]) self._drawarcs(dc, self.arcs[i], self.arcpens[i])
...@@ -380,7 +382,7 @@ class Gviz(wx.Panel): ...@@ -380,7 +382,7 @@ class Gviz(wx.Panel):
def addfile(self, gcode): def addfile(self, gcode):
self.clear() self.clear()
self.add_parsed_gcodes(gcode.lines) self.add_parsed_gcodes(gcode)
max_layers = len(self.layers) max_layers = len(self.layers)
if hasattr(self.parent, "layerslider"): if hasattr(self.parent, "layerslider"):
self.parent.layerslider.SetRange(0, max_layers - 1) self.parent.layerslider.SetRange(0, max_layers - 1)
...@@ -390,48 +392,50 @@ class Gviz(wx.Panel): ...@@ -390,48 +392,50 @@ class Gviz(wx.Panel):
# the reason addgcode is not factored as a add_parsed_gcodes([gline]) is # the reason addgcode is not factored as a add_parsed_gcodes([gline]) is
# because when loading a file there's no hilight, so it simply lets us not # because when loading a file there's no hilight, so it simply lets us not
# do the if hilight: all the time for nothing when loading a lot of lines # do the if hilight: all the time for nothing when loading a lot of lines
def add_parsed_gcodes(self, lines): def add_parsed_gcodes(self, gcode):
def _y(y): def _y(y):
return self.build_dimensions[1] - (y - self.build_dimensions[4]) return self.build_dimensions[1] - (y - self.build_dimensions[4])
def _x(x): def _x(x):
return x - self.build_dimensions[3] return x - self.build_dimensions[3]
for gline in lines: for layer_idx, layer in enumerate(gcode.all_layers):
if gline.command not in ["G0", "G1", "G2", "G3"]: has_move = False
for gline in layer:
if gline.is_move:
has_move = True
break
if not has_move:
continue
self.lines[layer.z] = []
self.pens[layer.z] = []
self.arcs[layer.z] = []
self.arcpens[layer.z] = []
self.layers.append(layer.z)
for gline in layer:
if not gline.is_move:
continue continue
target = self.lastpos[:] target = self.lastpos[:]
target[0] = gline.current_x
target[1] = gline.current_y
target[2] = gline.current_z
target[5] = 0.0 target[5] = 0.0
target[6] = 0.0 target[6] = 0.0
if gline.relative: if gline.e is not None:
if gline.x != None: target[0] += gline.x
if gline.y != None: target[1] += gline.y
if gline.z != None: target[2] += gline.z
else:
if gline.x != None: target[0] = gline.x
if gline.y != None: target[1] = gline.y
if gline.z != None: target[2] = gline.z
if gline.e != None:
if gline.relative_e: if gline.relative_e:
target[3] += gline.e target[3] += gline.e
else: else:
target[3] = gline.e target[3] = gline.e
if gline.f != None: target[4] = gline.f if gline.f is not None: target[4] = gline.f
if gline.i != None: target[5] = gline.i if gline.i is not None: target[5] = gline.i
if gline.j != None: target[6] = gline.j if gline.j is not None: target[6] = gline.j
z = target[2]
if z not in self.layers:
self.lines[z] = []
self.pens[z] = []
self.arcs[z] = []
self.arcpens[z] = []
self.layers.append(z)
start_pos = self.lastpos[:] start_pos = self.lastpos[:]
if gline.command in ["G0", "G1"]: if gline.command in ["G0", "G1"]:
self.lines[z].append((_x(start_pos[0]), _y(start_pos[1]), _x(target[0]), _y(target[1]))) self.lines[layer.z].append((_x(start_pos[0]), _y(start_pos[1]), _x(target[0]), _y(target[1])))
self.pens[z].append(self.mainpen if target[3] != self.lastpos[3] else self.travelpen) self.pens[layer.z].append(self.mainpen if target[3] != self.lastpos[3] else self.travelpen)
elif gline.command in ["G2", "G3"]: elif gline.command in ["G2", "G3"]:
# startpos, endpos, arc center # startpos, endpos, arc center
arc = [_x(start_pos[0]), _y(start_pos[1]), arc = [_x(start_pos[0]), _y(start_pos[1]),
...@@ -440,8 +444,8 @@ class Gviz(wx.Panel): ...@@ -440,8 +444,8 @@ class Gviz(wx.Panel):
if gline.command == "G2": # clockwise, reverse endpoints if gline.command == "G2": # clockwise, reverse endpoints
arc[0], arc[1], arc[2], arc[3] = arc[2], arc[3], arc[0], arc[1] arc[0], arc[1], arc[2], arc[3] = arc[2], arc[3], arc[0], arc[1]
self.arcs[z].append(arc) self.arcs[layer.z].append(arc)
self.arcpens[z].append(self.arcpen) self.arcpens[layer.z].append(self.arcpen)
self.lastpos = target self.lastpos = target
self.dirty = 1 self.dirty = 1
...@@ -459,6 +463,7 @@ class Gviz(wx.Panel): ...@@ -459,6 +463,7 @@ class Gviz(wx.Panel):
def _y(y): def _y(y):
return self.build_dimensions[1] - (y - self.build_dimensions[4]) return self.build_dimensions[1] - (y - self.build_dimensions[4])
def _x(x): def _x(x):
return x - self.build_dimensions[3] return x - self.build_dimensions[3]
...@@ -470,13 +475,13 @@ class Gviz(wx.Panel): ...@@ -470,13 +475,13 @@ class Gviz(wx.Panel):
target = start_pos[:] target = start_pos[:]
target[5] = 0.0 target[5] = 0.0
target[6] = 0.0 target[6] = 0.0
if gline.x != None: target[0] = gline.x if gline.x is not None: target[0] = gline.x
if gline.y != None: target[1] = gline.y if gline.y is not None: target[1] = gline.y
if gline.z != None: target[2] = gline.z if gline.z is not None: target[2] = gline.z
if gline.e != None: target[3] = gline.e if gline.e is not None: target[3] = gline.e
if gline.f != None: target[4] = gline.f if gline.f is not None: target[4] = gline.f
if gline.i != None: target[5] = gline.i if gline.i is not None: target[5] = gline.i
if gline.j != None: target[6] = gline.j if gline.j is not None: target[6] = gline.j
z = target[2] z = target[2]
if not hilight and z not in self.layers: if not hilight and z not in self.layers:
......
#!/usr/bin/env python
# This file is part of the Printrun suite.
#
# Printrun is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Printrun is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>.
from printrun.printrun_utils import install_locale, iconfile
install_locale('plater')
import os
import types
import wx
def patch_method(obj, method, replacement):
orig_handler = getattr(obj, method)
def wrapped(*a, **kwargs):
kwargs['orig_handler'] = orig_handler
return replacement(*a, **kwargs)
setattr(obj, method, types.MethodType(wrapped, obj))
class Plater(wx.Frame):
def __init__(self, filenames = [], size = (800, 580), callback = None, parent = None, build_dimensions = None):
super(Plater, self).__init__(parent, title = _("Plate building tool"), size = size)
self.filenames = filenames
self.SetIcon(wx.Icon(iconfile("plater.ico"), wx.BITMAP_TYPE_ICO))
self.mainsizer = wx.BoxSizer(wx.HORIZONTAL)
panel = wx.Panel(self, -1)
sizer = wx.GridBagSizer()
self.l = wx.ListBox(panel)
sizer.Add(self.l, pos = (1, 0), span = (1, 2), flag = wx.EXPAND)
sizer.AddGrowableRow(1, 1)
# Clear button
clearbutton = wx.Button(panel, label = _("Clear"))
clearbutton.Bind(wx.EVT_BUTTON, self.clear)
sizer.Add(clearbutton, pos = (2, 0), span = (1, 2), flag = wx.EXPAND)
# Load button
loadbutton = wx.Button(panel, label = _("Load"))
loadbutton.Bind(wx.EVT_BUTTON, self.load)
sizer.Add(loadbutton, pos = (0, 0), span = (1, 1), flag = wx.EXPAND)
# Snap to Z = 0 button
snapbutton = wx.Button(panel, label = _("Snap to Z = 0"))
snapbutton.Bind(wx.EVT_BUTTON, self.snap)
sizer.Add(snapbutton, pos = (3, 0), span = (1, 1), flag = wx.EXPAND)
# Put at center button
centerbutton = wx.Button(panel, label = _("Put at center"))
centerbutton.Bind(wx.EVT_BUTTON, self.center)
sizer.Add(centerbutton, pos = (3, 1), span = (1, 1), flag = wx.EXPAND)
# Delete button
deletebutton = wx.Button(panel, label = _("Delete"))
deletebutton.Bind(wx.EVT_BUTTON, self.delete)
sizer.Add(deletebutton, pos = (4, 0), span = (1, 1), flag = wx.EXPAND)
# Auto arrange button
autobutton = wx.Button(panel, label = _("Auto arrange"))
autobutton.Bind(wx.EVT_BUTTON, self.autoplate)
sizer.Add(autobutton, pos = (5, 0), span = (1, 2), flag = wx.EXPAND)
# Export button
exportbutton = wx.Button(panel, label = _("Export"))
exportbutton.Bind(wx.EVT_BUTTON, self.export)
sizer.Add(exportbutton, pos = (0, 1), span = (1, 1), flag = wx.EXPAND)
if callback is not None:
donebutton = wx.Button(panel, label = _("Done"))
donebutton.Bind(wx.EVT_BUTTON, lambda e: self.done(e, callback))
sizer.Add(donebutton, pos = (6, 0), span = (1, 1), flag = wx.EXPAND)
cancelbutton = wx.Button(panel, label = _("Cancel"))
cancelbutton.Bind(wx.EVT_BUTTON, lambda e: self.Destroy())
sizer.Add(cancelbutton, pos = (6, 1), span = (1, 1), flag = wx.EXPAND)
self.basedir = "."
self.models = {}
panel.SetSizerAndFit(sizer)
self.mainsizer.Add(panel, flag = wx.EXPAND)
self.SetSizer(self.mainsizer)
if build_dimensions:
self.build_dimensions = build_dimensions
else:
self.build_dimensions = [200, 200, 100, 0, 0, 0]
def set_viewer(self, viewer):
# Patch handle_rotation on the fly
if hasattr(viewer, "handle_rotation"):
def handle_rotation(self, event, orig_handler):
if self.initpos is None:
self.initpos = event.GetPositionTuple()
else:
if not event.ShiftDown():
p1 = self.initpos
p2 = event.GetPositionTuple()
x1, y1, _ = self.mouse_to_3d(p1[0], p1[1])
x2, y2, _ = self.mouse_to_3d(p2[0], p2[1])
self.parent.move_shape((x2 - x1, y2 - y1))
self.initpos = p2
else:
orig_handler(event)
patch_method(viewer, "handle_rotation", handle_rotation)
# Patch handle_wheel on the fly
if hasattr(viewer, "handle_wheel"):
def handle_wheel(self, event, orig_handler):
if not event.ShiftDown():
delta = event.GetWheelRotation()
angle = 10
if delta > 0:
self.parent.rotate_shape(angle / 2)
else:
self.parent.rotate_shape(-angle / 2)
else:
orig_handler(event)
patch_method(viewer, "handle_wheel", handle_wheel)
self.s = viewer
self.mainsizer.Add(self.s, 1, wx.EXPAND)
def move_shape(self, delta):
"""moves shape (selected in l, which is list ListBox of shapes)
by an offset specified in tuple delta.
Positive numbers move to (rigt, down)"""
name = self.l.GetSelection()
if name == wx.NOT_FOUND:
return False
name = self.l.GetString(name)
model = self.models[name]
model.offsets = [model.offsets[0] + delta[0],
model.offsets[1] + delta[1],
model.offsets[2]
]
return True
def rotate_shape(self, angle):
"""rotates acive shape
positive angle is clockwise
"""
name = self.l.GetSelection()
if name == wx.NOT_FOUND:
return False
name = self.l.GetString(name)
model = self.models[name]
model.rot += angle
def autoplate(self, event = None):
print _("Autoplating")
separation = 2
try:
from printrun import packer
p = packer.Packer()
for i in self.models:
width = abs(self.models[i].dims[0] - self.models[i].dims[1])
height = abs(self.models[i].dims[2] - self.models[i].dims[3])
p.add_rect(width, height, data = i)
# FIXME: probably wrong, not taking offsets into account
centerx = self.build_dimensions[0] / 2
centery = self.build_dimensions[1] / 2
rects = p.pack(padding = separation,
center = packer.Vector2(centerx, centery))
for rect in rects:
i = rect.data
position = rect.center()
self.models[i].offsets[0] = position.x
self.models[i].offsets[1] = position.y
except ImportError:
bedsize = self.build_dimensions[0:3]
cursor = [0, 0, 0]
newrow = 0
max = [0, 0]
for i in self.models:
self.models[i].offsets[2] = -1.0 * self.models[i].dims[4]
x = abs(self.models[i].dims[0] - self.models[i].dims[1])
y = abs(self.models[i].dims[2] - self.models[i].dims[3])
centre = [x / 2, y / 2]
centreoffset = [self.models[i].dims[0] + centre[0],
self.models[i].dims[2] + centre[1]]
if (cursor[0] + x + separation) >= bedsize[0]:
cursor[0] = 0
cursor[1] += newrow + separation
newrow = 0
if (newrow == 0) or (newrow < y):
newrow = y
# To the person who works out why the offsets are applied
# differently here:
# Good job, it confused the hell out of me.
self.models[i].offsets[0] = cursor[0] + centre[0] - centreoffset[0]
self.models[i].offsets[1] = cursor[1] + centre[1] - centreoffset[1]
if (max[0] == 0) or (max[0] < (cursor[0] + x)):
max[0] = cursor[0] + x
if (max[1] == 0) or (max[1] < (cursor[1] + x)):
max[1] = cursor[1] + x
cursor[0] += x + separation
if (cursor[1] + y) >= bedsize[1]:
print _("Bed full, sorry sir :(")
self.Refresh()
return
centreoffset = [(bedsize[0] - max[0]) / 2, (bedsize[1] - max[1]) / 2]
for i in self.models:
self.models[i].offsets[0] += centreoffset[0]
self.models[i].offsets[1] += centreoffset[1]
self.Refresh()
def clear(self, event):
result = wx.MessageBox(_('Are you sure you want to clear the grid? All unsaved changes will be lost.'),
_('Clear the grid?'),
wx.YES_NO | wx.ICON_QUESTION)
if result == 2:
self.models = {}
self.l.Clear()
self.Refresh()
def center(self, event):
i = self.l.GetSelection()
if i != -1:
m = self.models[self.l.GetString(i)]
m.offsets = [100, 100, m.offsets[2]]
self.Refresh()
def snap(self, event):
i = self.l.GetSelection()
if i != -1:
m = self.models[self.l.GetString(i)]
m.offsets[2] = -1.0 * min(m.facetsminz)[0]
self.Refresh()
def delete(self, event):
i = self.l.GetSelection()
if i != -1:
del self.models[self.l.GetString(i)]
self.l.Delete(i)
self.l.Select(self.l.GetCount() - 1)
self.Refresh()
def add_model(self, name, model):
newname = os.path.split(name.lower())[1]
c = 1
while newname in self.models:
newname = os.path.split(name.lower())[1]
newname = newname + "(%d)" % c
c += 1
self.models[newname] = model
self.l.Append(newname)
i = self.l.GetSelection()
if i == wx.NOT_FOUND:
self.l.Select(0)
self.l.Select(self.l.GetCount() - 1)
def load(self, event):
dlg = wx.FileDialog(self, _("Pick file to load"), self.basedir, style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
dlg.SetWildcard(self.load_wildcard)
if dlg.ShowModal() == wx.ID_OK:
name = dlg.GetPath()
self.load_file(name)
dlg.Destroy()
def load_file(self, filename):
raise NotImplementedError
def export(self, event):
dlg = wx.FileDialog(self, _("Pick file to save to"), self.basedir, style = wx.FD_SAVE)
dlg.SetWildcard(self.save_wildcard)
if(dlg.ShowModal() == wx.ID_OK):
name = dlg.GetPath()
self.export_to(name)
dlg.Destroy()
def export_to(self, name):
raise NotImplementedError
## Imported from python-rectangle-packer commit 32fce1aaba
## https://github.com/maxretter/python-rectangle-packer
##
## Python Rectangle Packer - Packs rectangles around a central point
## Copyright (C) 2013 Max Retter
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/>.
import math
import Polygon
import Polygon.Utils
class Vector2(object):
"""Simple 2d vector / point class."""
def __init__(self, x=0, y=0):
self.x = float(x)
self.y = float(y)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def add(self, other):
return Vector2(self.x + other.x, self.y + other.y)
def sub(self, other):
return Vector2(self.x - other.x, self.y - other.y)
def scale(self, factor):
return Vector2(self.x * factor, self.y * factor)
def magnitude(self):
return math.sqrt(self.dot_product(self))
def unit(self):
"""Build unit vector."""
return self.scale(1 / self.magnitude())
def dot_product(self, other):
return self.x * other.x + self.y * other.y
def distance(self, other):
"""Distance forumla for other point."""
return math.sqrt(
(other.x - self.x) ** 2 +
(other.y - self.y) ** 2
)
class Rect(object):
"""Simple rectangle object."""
def __init__(self, width, height, data={}):
self.width = width
self.height = height
self.data = data
## upper left
self.position = Vector2()
def half(self):
"""Half width and height."""
return Vector2(
self.width / 2,
self.height / 2
)
def expand(self, width, height):
"""Builds a new rectangle based on this one with given offsets."""
expanded = Rect(self.width + width, self.height + height)
expanded.set_center(self.center())
return expanded
def point_list(self):
top = self.position.y
right = self.position.x + self.width
bottom = self.position.y + self.height
left = self.position.x
return PointList([
(left, top),
(right, top),
(right, bottom),
(left, bottom),
])
def center(self):
"""Center of rect calculated from position and dimensions."""
return self.position.add(self.half())
def set_center(self, center):
"""Set the position based on a new center point."""
self.position = center.sub(self.half())
def area(self):
"""Area: length * width."""
return self.width * self.height
class PointList(object):
"""Methods for transforming a list of points."""
def __init__(self, points=[]):
self.points = points
self._polygon = None
def polygon(self):
"""Builds a polygon from the set of points."""
if not self._polygon:
self._polygon = Polygon.Polygon(self.points)
return self._polygon
def segments(self):
"""Returns a list of LineSegment objects."""
segs = []
for i, point in enumerate(self.points[1:]):
index = i + 1
segs.append(LineSegment(
Vector2(self.points[index-1][0], self.points[index-1][1]),
Vector2(self.points[index][0], self.points[index][1])
))
segs.append(LineSegment(
Vector2(self.points[-1][0], self.points[-1][1]),
Vector2(self.points[0][0], self.points[0][1]),
))
return segs
class LineSegment(object):
def __init__(self, start, end):
self.start = start
self.end = end
def length(self):
"""Length of segment vector."""
return self.end.sub(self.start).magnitude()
def closest_point_to_point(self, point):
"""Point along segment that is closest to given point."""
segment_vector = self.end.sub(self.start)
point_vector = point.sub(self.start)
seg_mag = segment_vector.magnitude()
## project point_vector on segment_vector
projection = segment_vector.dot_product(point_vector)
## scalar value used to interpolate new point along segment_vector
scalar = projection / seg_mag ** 2
## clamp on [0,1]
scalar = 1.0 if scalar > 1.0 else scalar
scalar = 0.0 if scalar < 0.0 else scalar
## interpolate scalar along segment and add start point back in
return self.start.add(segment_vector.unit().scale(scalar * seg_mag))
def closest_distance_to_point(self, point):
"""Helper method too automatically return distance."""
closest_point = self.closest_point_to_point(point)
return closest_point.distance(point)
class Packer(object):
def __init__(self):
self._rects = []
def add_rect(self, width, height, data={}):
self._rects.append(Rect(width, height, data))
def pack(self, padding=0, center=Vector2()):
## init everything
placed_rects = []
sorted_rects = sorted(self._rects, key=lambda rect: -rect.area())
## double padding due to halfing later on
padding *= 2
for rect in sorted_rects:
if not placed_rects:
## first rect, right on target.
rect.set_center(center)
else:
## Expand each rectangle based on new rect size and padding
## get a list of points
## build a polygon
point_lists = [
pr.expand(rect.width + padding, rect.height + padding).point_list().polygon()
for pr in placed_rects
]
## take the union of all the polygons (relies on + operator override)
## the [0] at the end returns the first "contour", which is the only one we need
bounding_points = PointList(sum(
point_lists[1:],
point_lists[0]
)[0])
## find the closest segment
closest_segments = sorted(
bounding_points.segments(),
key=lambda segment: segment.closest_distance_to_point(center)
)
## get the closest point
place_point = closest_segments[0].closest_point_to_point(center)
## set the rect position
rect.set_center(place_point)
placed_rects.append(rect)
return placed_rects
...@@ -13,25 +13,36 @@ ...@@ -13,25 +13,36 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>. # along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import os, sys import os
import sys
import gettext import gettext
# Set up Internationalization using gettext # Set up Internationalization using gettext
# searching for installed locales on /usr/share; uses relative folder if not found (windows) # searching for installed locales on /usr/share; uses relative folder if not
# found (windows)
def install_locale(domain): def install_locale(domain):
if os.path.exists('/usr/share/pronterface/locale'): if os.path.exists('/usr/share/pronterface/locale'):
gettext.install(domain, '/usr/share/pronterface/locale', unicode = 1) gettext.install(domain, '/usr/share/pronterface/locale', unicode = 1)
elif os.path.exists('/usr/local/share/pronterface/locale'): elif os.path.exists('/usr/local/share/pronterface/locale'):
gettext.install(domain, '/usr/local/share/pronterface/locale', unicode = 1) gettext.install(domain, '/usr/local/share/pronterface/locale',
unicode = 1)
else: else:
gettext.install(domain, './locale', unicode = 1) gettext.install(domain, './locale', unicode = 1)
def iconfile(filename):
if hasattr(sys, "frozen") and sys.frozen == "windows_exe":
return sys.executable
else:
return pixmapfile("plater.ico")
def imagefile(filename): def imagefile(filename):
for prefix in ['/usr/local/share/pronterface/images', '/usr/share/pronterface/images']: for prefix in ['/usr/local/share/pronterface/images',
'/usr/share/pronterface/images']:
candidate = os.path.join(prefix, filename) candidate = os.path.join(prefix, filename)
if os.path.exists(candidate): if os.path.exists(candidate):
return candidate return candidate
local_candidate = os.path.join(os.path.dirname(sys.argv[0]), "images", filename) local_candidate = os.path.join(os.path.dirname(sys.argv[0]),
"images", filename)
if os.path.exists(local_candidate): if os.path.exists(local_candidate):
return local_candidate return local_candidate
else: else:
...@@ -49,13 +60,15 @@ def lookup_file(filename, prefixes): ...@@ -49,13 +60,15 @@ def lookup_file(filename, prefixes):
return filename return filename
def pixmapfile(filename): def pixmapfile(filename):
return lookup_file(filename, ['/usr/local/share/pixmaps', '/usr/share/pixmaps']) return lookup_file(filename, ['/usr/local/share/pixmaps',
'/usr/share/pixmaps'])
def sharedfile(filename): def sharedfile(filename):
return lookup_file(filename, ['/usr/local/share/pronterface', '/usr/share/pronterface']) return lookup_file(filename, ['/usr/local/share/pronterface',
'/usr/share/pronterface'])
def configfile(filename): def configfile(filename):
return lookup_file(filename, [os.path.expanduser("~/.printrun/"),]) return lookup_file(filename, [os.path.expanduser("~/.printrun/"), ])
class RemainingTimeEstimator(object): class RemainingTimeEstimator(object):
...@@ -88,7 +101,7 @@ class RemainingTimeEstimator(object): ...@@ -88,7 +101,7 @@ class RemainingTimeEstimator(object):
if idx == self.last_idx: if idx == self.last_idx:
return self.last_estimate return self.last_estimate
layer, line = self.gcode.idxs(idx) layer, line = self.gcode.idxs(idx)
layer_progress = (1 - (float(line+1) / self.current_layer_lines)) layer_progress = (1 - (float(line + 1) / self.current_layer_lines))
remaining = layer_progress * self.current_layer_estimate + self.remaining_layers_estimate remaining = layer_progress * self.current_layer_estimate + self.remaining_layers_estimate
estimate = self.drift * remaining estimate = self.drift * remaining
total = estimate + printtime total = estimate + printtime
......
...@@ -25,14 +25,15 @@ class MacroEditor(wx.Dialog): ...@@ -25,14 +25,15 @@ class MacroEditor(wx.Dialog):
if gcode: if gcode:
title = " %s" title = " %s"
self.gcode = gcode self.gcode = gcode
wx.Dialog.__init__(self, None, title = title % macro_name, style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) wx.Dialog.__init__(self, None, title = title % macro_name,
style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
self.callback = callback self.callback = callback
self.panel = wx.Panel(self,-1) self.panel = wx.Panel(self, -1)
titlesizer = wx.BoxSizer(wx.HORIZONTAL) titlesizer = wx.BoxSizer(wx.HORIZONTAL)
titletext = wx.StaticText(self.panel,-1, " _") #title%macro_name) self.titletext = wx.StaticText(self.panel, -1, " _") # title%macro_name)
#title.SetFont(wx.Font(11, wx.NORMAL, wx.NORMAL, wx.BOLD)) #title.SetFont(wx.Font(11, wx.NORMAL, wx.NORMAL, wx.BOLD))
titlesizer.Add(titletext, 1) titlesizer.Add(self.titletext, 1)
self.findb = wx.Button(self.panel, -1, _("Find"), style = wx.BU_EXACTFIT) #New button for "Find" (Jezmy) self.findb = wx.Button(self.panel, -1, _("Find"), style = wx.BU_EXACTFIT) # New button for "Find" (Jezmy)
self.findb.Bind(wx.EVT_BUTTON, self.find) self.findb.Bind(wx.EVT_BUTTON, self.find)
self.okb = wx.Button(self.panel, -1, _("Save"), style = wx.BU_EXACTFIT) self.okb = wx.Button(self.panel, -1, _("Save"), style = wx.BU_EXACTFIT)
self.okb.Bind(wx.EVT_BUTTON, self.save) self.okb.Bind(wx.EVT_BUTTON, self.save)
...@@ -44,12 +45,12 @@ class MacroEditor(wx.Dialog): ...@@ -44,12 +45,12 @@ class MacroEditor(wx.Dialog):
titlesizer.Add(self.cancelb) titlesizer.Add(self.cancelb)
topsizer = wx.BoxSizer(wx.VERTICAL) topsizer = wx.BoxSizer(wx.VERTICAL)
topsizer.Add(titlesizer, 0, wx.EXPAND) topsizer.Add(titlesizer, 0, wx.EXPAND)
self.e = wx.TextCtrl(self.panel, style = wx.HSCROLL|wx.TE_MULTILINE|wx.TE_RICH2, size = (400, 400)) self.e = wx.TextCtrl(self.panel, style = wx.HSCROLL | wx.TE_MULTILINE | wx.TE_RICH2, size = (400, 400))
if not self.gcode: if not self.gcode:
self.e.SetValue(self.unindent(definition)) self.e.SetValue(self.unindent(definition))
else: else:
self.e.SetValue("\n".join(definition)) self.e.SetValue("\n".join(definition))
topsizer.Add(self.e, 1, wx.ALL+wx.EXPAND) topsizer.Add(self.e, 1, wx.ALL | wx.EXPAND)
self.panel.SetSizer(topsizer) self.panel.SetSizer(topsizer)
topsizer.Layout() topsizer.Layout()
topsizer.Fit(self) topsizer.Fit(self)
...@@ -59,19 +60,18 @@ class MacroEditor(wx.Dialog): ...@@ -59,19 +60,18 @@ class MacroEditor(wx.Dialog):
def find(self, ev): def find(self, ev):
# Ask user what to look for, find it and point at it ... (Jezmy) # Ask user what to look for, find it and point at it ... (Jezmy)
S = self.e.GetStringSelection() S = self.e.GetStringSelection()
if not S : if not S:
S = "Z" S = "Z"
FindValue = wx.GetTextFromUser('Please enter a search string:', caption = "Search", default_value = S, parent = None) FindValue = wx.GetTextFromUser('Please enter a search string:', caption = "Search", default_value = S, parent = None)
somecode = self.e.GetValue() somecode = self.e.GetValue()
numLines = len(somecode)
position = somecode.find(FindValue, self.e.GetInsertionPoint()) position = somecode.find(FindValue, self.e.GetInsertionPoint())
if position == -1 : if position == -1:
# ShowMessage(self,-1, "Not found!") # ShowMessage(self,-1, "Not found!")
titletext = wx.TextCtrl(self.panel,-1, "Not Found!") self.titletext.SetLabel(_("Not Found!"))
else: else:
# self.title.SetValue("Position : "+str(position)) # self.title.SetValue("Position : "+str(position))
titletext = wx.TextCtrl(self.panel,-1, str(position)) self.titletext.SetLabel(str(position))
# ananswer = wx.MessageBox(str(numLines)+" Lines detected in file\n"+str(position), "OK") # ananswer = wx.MessageBox(str(numLines)+" Lines detected in file\n"+str(position), "OK")
self.e.SetFocus() self.e.SetFocus()
...@@ -79,9 +79,9 @@ class MacroEditor(wx.Dialog): ...@@ -79,9 +79,9 @@ class MacroEditor(wx.Dialog):
self.e.SetSelection(position, position + len(FindValue)) self.e.SetSelection(position, position + len(FindValue))
self.e.ShowPosition(position) self.e.ShowPosition(position)
def ShowMessage(self, ev , message): def ShowMessage(self, ev, message):
dlg = wxMessageDialog(self, message, dlg = wx.MessageDialog(self, message,
"Info!", wxOK | wxICON_INFORMATION) "Info!", wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal() dlg.ShowModal()
dlg.Destroy() dlg.Destroy()
...@@ -96,7 +96,7 @@ class MacroEditor(wx.Dialog): ...@@ -96,7 +96,7 @@ class MacroEditor(wx.Dialog):
self.Destroy() self.Destroy()
def unindent(self, text): def unindent(self, text):
self.indent_chars = text[:len(text)-len(text.lstrip())] self.indent_chars = text[:len(text) - len(text.lstrip())]
if len(self.indent_chars) == 0: if len(self.indent_chars) == 0:
self.indent_chars = " " self.indent_chars = " "
unindented = "" unindented = ""
...@@ -110,6 +110,7 @@ class MacroEditor(wx.Dialog): ...@@ -110,6 +110,7 @@ class MacroEditor(wx.Dialog):
else: else:
unindented += line + "\n" unindented += line + "\n"
return unindented return unindented
def reindent(self, text): def reindent(self, text):
lines = re.split(r"(?:\r\n?|\n)", text) lines = re.split(r"(?:\r\n?|\n)", text)
if len(lines) <= 1: if len(lines) <= 1:
...@@ -127,7 +128,8 @@ SETTINGS_GROUPS = {"Printer": _("Printer settings"), ...@@ -127,7 +128,8 @@ SETTINGS_GROUPS = {"Printer": _("Printer settings"),
class PronterOptionsDialog(wx.Dialog): class PronterOptionsDialog(wx.Dialog):
"""Options editor""" """Options editor"""
def __init__(self, pronterface): def __init__(self, pronterface):
wx.Dialog.__init__(self, parent = None, title = _("Edit settings"), size = (400, 500), style = wx.DEFAULT_DIALOG_STYLE) wx.Dialog.__init__(self, parent = None, title = _("Edit settings"),
size = (400, 500), style = wx.DEFAULT_DIALOG_STYLE)
panel = wx.Panel(self) panel = wx.Panel(self)
header = wx.StaticBox(panel, label = _("Settings")) header = wx.StaticBox(panel, label = _("Settings"))
sbox = wx.StaticBoxSizer(header, wx.VERTICAL) sbox = wx.StaticBoxSizer(header, wx.VERTICAL)
...@@ -152,12 +154,12 @@ class PronterOptionsDialog(wx.Dialog): ...@@ -152,12 +154,12 @@ class PronterOptionsDialog(wx.Dialog):
grid.AddGrowableCol(1) grid.AddGrowableCol(1)
grid.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED) grid.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
for setting in settings: for setting in settings:
label,widget = setting.get_label(grouppanel),setting.get_widget(grouppanel) label, widget = setting.get_label(grouppanel), setting.get_widget(grouppanel)
grid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.ALIGN_RIGHT) grid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.ALIGN_RIGHT)
grid.Add(widget, 1, wx.ALIGN_CENTER_VERTICAL|wx.ALL|wx.EXPAND) grid.Add(widget, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND)
if hasattr(label,"set_default"): if hasattr(label, "set_default"):
label.Bind(wx.EVT_MOUSE_EVENTS, label.set_default) label.Bind(wx.EVT_MOUSE_EVENTS, label.set_default)
if hasattr(widget,"Bind"): if hasattr(widget, "Bind"):
widget.Bind(wx.EVT_MOUSE_EVENTS, label.set_default) widget.Bind(wx.EVT_MOUSE_EVENTS, label.set_default)
grouppanel.SetSizer(grid) grouppanel.SetSizer(grid)
sbox.Add(notebook, 1, wx.EXPAND) sbox.Add(notebook, 1, wx.EXPAND)
...@@ -181,29 +183,30 @@ def PronterOptions(pronterface): ...@@ -181,29 +183,30 @@ def PronterOptions(pronterface):
class ButtonEdit(wx.Dialog): class ButtonEdit(wx.Dialog):
"""Custom button edit dialog""" """Custom button edit dialog"""
def __init__(self, pronterface): def __init__(self, pronterface):
wx.Dialog.__init__(self, None, title = _("Custom button"), style = wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) wx.Dialog.__init__(self, None, title = _("Custom button"),
style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
self.pronterface = pronterface self.pronterface = pronterface
topsizer = wx.BoxSizer(wx.VERTICAL) topsizer = wx.BoxSizer(wx.VERTICAL)
grid = wx.FlexGridSizer(rows = 0, cols = 2, hgap = 4, vgap = 2) grid = wx.FlexGridSizer(rows = 0, cols = 2, hgap = 4, vgap = 2)
grid.AddGrowableCol(1, 1) grid.AddGrowableCol(1, 1)
grid.Add(wx.StaticText(self,-1, _("Button title")), 0, wx.BOTTOM|wx.RIGHT) grid.Add(wx.StaticText(self, -1, _("Button title")), 0, wx.BOTTOM | wx.RIGHT)
self.name = wx.TextCtrl(self,-1, "") self.name = wx.TextCtrl(self, -1, "")
grid.Add(self.name, 1, wx.EXPAND) grid.Add(self.name, 1, wx.EXPAND)
grid.Add(wx.StaticText(self, -1, _("Command")), 0, wx.BOTTOM|wx.RIGHT) grid.Add(wx.StaticText(self, -1, _("Command")), 0, wx.BOTTOM | wx.RIGHT)
self.command = wx.TextCtrl(self,-1, "") self.command = wx.TextCtrl(self, -1, "")
xbox = wx.BoxSizer(wx.HORIZONTAL) xbox = wx.BoxSizer(wx.HORIZONTAL)
xbox.Add(self.command, 1, wx.EXPAND) xbox.Add(self.command, 1, wx.EXPAND)
self.command.Bind(wx.EVT_TEXT, self.macrob_enabler) self.command.Bind(wx.EVT_TEXT, self.macrob_enabler)
self.macrob = wx.Button(self,-1, "..", style = wx.BU_EXACTFIT) self.macrob = wx.Button(self, -1, "..", style = wx.BU_EXACTFIT)
self.macrob.Bind(wx.EVT_BUTTON, self.macrob_handler) self.macrob.Bind(wx.EVT_BUTTON, self.macrob_handler)
xbox.Add(self.macrob, 0) xbox.Add(self.macrob, 0)
grid.Add(xbox, 1, wx.EXPAND) grid.Add(xbox, 1, wx.EXPAND)
grid.Add(wx.StaticText(self,-1, _("Color")), 0, wx.BOTTOM|wx.RIGHT) grid.Add(wx.StaticText(self, -1, _("Color")), 0, wx.BOTTOM | wx.RIGHT)
self.color = wx.TextCtrl(self,-1, "") self.color = wx.TextCtrl(self, -1, "")
grid.Add(self.color, 1, wx.EXPAND) grid.Add(self.color, 1, wx.EXPAND)
topsizer.Add(grid, 0, wx.EXPAND) topsizer.Add(grid, 0, wx.EXPAND)
topsizer.Add( (0, 0), 1) topsizer.Add((0, 0), 1)
topsizer.Add(self.CreateStdDialogButtonSizer(wx.OK|wx.CANCEL), 0, wx.ALIGN_CENTER) topsizer.Add(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL), 0, wx.ALIGN_CENTER)
self.SetSizer(topsizer) self.SetSizer(topsizer)
def macrob_enabler(self, e): def macrob_enabler(self, e):
...@@ -212,9 +215,9 @@ class ButtonEdit(wx.Dialog): ...@@ -212,9 +215,9 @@ class ButtonEdit(wx.Dialog):
try: try:
if macro == "": if macro == "":
valid = True valid = True
elif self.pronterface.macros.has_key(macro): elif macro in self.pronterface.macros:
valid = True valid = True
elif hasattr(self.pronterface.__class__, u"do_"+macro): elif hasattr(self.pronterface.__class__, u"do_" + macro):
valid = False valid = False
elif len([c for c in macro if not c.isalnum() and c != "_"]): elif len([c for c in macro if not c.isalnum() and c != "_"]):
valid = False valid = False
...@@ -223,7 +226,7 @@ class ButtonEdit(wx.Dialog): ...@@ -223,7 +226,7 @@ class ButtonEdit(wx.Dialog):
except: except:
if macro == "": if macro == "":
valid = True valid = True
elif self.pronterface.macros.has_key(macro): elif macro in self.pronterface.macros:
valid = True valid = True
elif len([c for c in macro if not c.isalnum() and c != "_"]): elif len([c for c in macro if not c.isalnum() and c != "_"]):
valid = False valid = False
...@@ -235,13 +238,14 @@ class ButtonEdit(wx.Dialog): ...@@ -235,13 +238,14 @@ class ButtonEdit(wx.Dialog):
macro = self.command.GetValue() macro = self.command.GetValue()
macro = self.pronterface.edit_macro(macro) macro = self.pronterface.edit_macro(macro)
self.command.SetValue(macro) self.command.SetValue(macro)
if self.name.GetValue()=="": if self.name.GetValue() == "":
self.name.SetValue(macro) self.name.SetValue(macro)
class TempGauge(wx.Panel): class TempGauge(wx.Panel):
def __init__(self, parent, size = (200, 22), title = "", maxval = 240, gaugeColour = None): def __init__(self, parent, size = (200, 22), title = "",
wx.Panel.__init__(self, parent,-1, size = size) maxval = 240, gaugeColour = None):
wx.Panel.__init__(self, parent, -1, size = size)
self.Bind(wx.EVT_PAINT, self.paint) self.Bind(wx.EVT_PAINT, self.paint)
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
self.width, self.height = size self.width, self.height = size
...@@ -253,9 +257,9 @@ class TempGauge(wx.Panel): ...@@ -253,9 +257,9 @@ class TempGauge(wx.Panel):
self.recalc() self.recalc()
def recalc(self): def recalc(self):
mmax = max(int(self.setpoint*1.05), self.max) mmax = max(int(self.setpoint * 1.05), self.max)
self.scale = float(self.width-2)/float(mmax) self.scale = float(self.width - 2) / float(mmax)
self.ypt = max(16, int(self.scale*max(self.setpoint, self.max/6))) self.ypt = max(16, int(self.scale * max(self.setpoint, self.max / 6)))
def SetValue(self, value): def SetValue(self, value):
self.value = value self.value = value
...@@ -269,18 +273,18 @@ class TempGauge(wx.Panel): ...@@ -269,18 +273,18 @@ class TempGauge(wx.Panel):
if val < vmin: return cmin if val < vmin: return cmin
if val > vmax: return cmax if val > vmax: return cmax
if val <= vmid: if val <= vmid:
lo, hi, val, valhi = cmin, cmid, val-vmin, vmid-vmin lo, hi, val, valhi = cmin, cmid, val - vmin, vmid - vmin
else: else:
lo, hi, val, valhi = cmid, cmax, val-vmid, vmax-vmid lo, hi, val, valhi = cmid, cmax, val - vmid, vmax - vmid
vv = float(val)/valhi vv = float(val) / valhi
rgb = lo.Red()+(hi.Red()-lo.Red())*vv, lo.Green()+(hi.Green()-lo.Green())*vv, lo.Blue()+(hi.Blue()-lo.Blue())*vv rgb = lo.Red() + (hi.Red() - lo.Red()) * vv, lo.Green() + (hi.Green() - lo.Green()) * vv, lo.Blue() + (hi.Blue() - lo.Blue()) * vv
rgb = map(lambda x:x*0.8, rgb) rgb = map(lambda x: x * 0.8, rgb)
return wx.Colour(*map(int, rgb)) return wx.Colour(*map(int, rgb))
def paint(self, ev): def paint(self, ev):
self.width, self.height = self.GetClientSizeTuple() self.width, self.height = self.GetClientSizeTuple()
self.recalc() self.recalc()
x0, y0, x1, y1, xE, yE = 1, 1, self.ypt+1, 1, self.width+1-2, 20 x0, y0, x1, y1, xE, yE = 1, 1, self.ypt + 1, 1, self.width + 1 - 2, 20
dc = wx.PaintDC(self) dc = wx.PaintDC(self)
dc.SetBackground(wx.Brush((255, 255, 255))) dc.SetBackground(wx.Brush((255, 255, 255)))
dc.Clear() dc.Clear()
...@@ -290,60 +294,60 @@ class TempGauge(wx.Panel): ...@@ -290,60 +294,60 @@ class TempGauge(wx.Panel):
gc = wx.GraphicsContext.Create(dc) gc = wx.GraphicsContext.Create(dc)
# draw shadow first # draw shadow first
# corners # corners
gc.SetBrush(gc.CreateRadialGradientBrush(xE-7, 9, xE-7, 9, 8, shadow1, shadow2)) gc.SetBrush(gc.CreateRadialGradientBrush(xE - 7, 9, xE - 7, 9, 8, shadow1, shadow2))
gc.DrawRectangle(xE-7, 1, 8, 8) gc.DrawRectangle(xE - 7, 1, 8, 8)
gc.SetBrush(gc.CreateRadialGradientBrush(xE-7, 17, xE-7, 17, 8, shadow1, shadow2)) gc.SetBrush(gc.CreateRadialGradientBrush(xE - 7, 17, xE - 7, 17, 8, shadow1, shadow2))
gc.DrawRectangle(xE-7, 17, 8, 8) gc.DrawRectangle(xE - 7, 17, 8, 8)
gc.SetBrush(gc.CreateRadialGradientBrush(x0+6, 17, x0+6, 17, 8, shadow1, shadow2)) gc.SetBrush(gc.CreateRadialGradientBrush(x0 + 6, 17, x0 + 6, 17, 8, shadow1, shadow2))
gc.DrawRectangle(0, 17, x0+6, 8) gc.DrawRectangle(0, 17, x0 + 6, 8)
# edges # edges
gc.SetBrush(gc.CreateLinearGradientBrush(xE-6, 0, xE+1, 0, shadow1, shadow2)) gc.SetBrush(gc.CreateLinearGradientBrush(xE - 6, 0, xE + 1, 0, shadow1, shadow2))
gc.DrawRectangle(xE-7, 9, 8, 8) gc.DrawRectangle(xE - 7, 9, 8, 8)
gc.SetBrush(gc.CreateLinearGradientBrush(x0, yE-2, x0, yE+5, shadow1, shadow2)) gc.SetBrush(gc.CreateLinearGradientBrush(x0, yE - 2, x0, yE + 5, shadow1, shadow2))
gc.DrawRectangle(x0+6, yE-2, xE-12, 7) gc.DrawRectangle(x0 + 6, yE - 2, xE - 12, 7)
# draw gauge background # draw gauge background
gc.SetBrush(gc.CreateLinearGradientBrush(x0, y0, x1+1, y1, cold, medium)) gc.SetBrush(gc.CreateLinearGradientBrush(x0, y0, x1 + 1, y1, cold, medium))
gc.DrawRoundedRectangle(x0, y0, x1+4, yE, 6) gc.DrawRoundedRectangle(x0, y0, x1 + 4, yE, 6)
gc.SetBrush(gc.CreateLinearGradientBrush(x1-2, y1, xE, y1, medium, hot)) gc.SetBrush(gc.CreateLinearGradientBrush(x1 - 2, y1, xE, y1, medium, hot))
gc.DrawRoundedRectangle(x1-2, y1, xE-x1, yE, 6) gc.DrawRoundedRectangle(x1 - 2, y1, xE - x1, yE, 6)
# draw gauge # draw gauge
width = 12 width = 12
w1 = y0+9-width/2 w1 = y0 + 9 - width / 2
w2 = w1+width w2 = w1 + width
value = x0+max(10, min(self.width+1-2, int(self.value*self.scale))) value = x0 + max(10, min(self.width + 1 - 2, int(self.value * self.scale)))
#gc.SetBrush(gc.CreateLinearGradientBrush(x0, y0+3, x0, y0+15, gauge1, gauge2)) #gc.SetBrush(gc.CreateLinearGradientBrush(x0, y0 + 3, x0, y0 + 15, gauge1, gauge2))
#gc.SetBrush(gc.CreateLinearGradientBrush(0, 3, 0, 15, wx.Colour(255, 255, 255), wx.Colour(255, 90, 32))) #gc.SetBrush(gc.CreateLinearGradientBrush(0, 3, 0, 15, wx.Colour(255, 255, 255), wx.Colour(255, 90, 32)))
gc.SetBrush(gc.CreateLinearGradientBrush(x0, y0+3, x0, y0+15, gauge1, self.interpolatedColour(value, x0, x1, xE, cold, medium, hot))) gc.SetBrush(gc.CreateLinearGradientBrush(x0, y0 + 3, x0, y0 + 15, gauge1, self.interpolatedColour(value, x0, x1, xE, cold, medium, hot)))
val_path = gc.CreatePath() val_path = gc.CreatePath()
val_path.MoveToPoint(x0, w1) val_path.MoveToPoint(x0, w1)
val_path.AddLineToPoint(value, w1) val_path.AddLineToPoint(value, w1)
val_path.AddLineToPoint(value+2, w1+width/4) val_path.AddLineToPoint(value + 2, w1 + width / 4)
val_path.AddLineToPoint(value+2, w2-width/4) val_path.AddLineToPoint(value + 2, w2 - width / 4)
val_path.AddLineToPoint(value, w2) val_path.AddLineToPoint(value, w2)
#val_path.AddLineToPoint(value-4, 10) #val_path.AddLineToPoint(value-4, 10)
val_path.AddLineToPoint(x0, w2) val_path.AddLineToPoint(x0, w2)
gc.DrawPath(val_path) gc.DrawPath(val_path)
# draw setpoint markers # draw setpoint markers
setpoint = x0+max(10, int(self.setpoint*self.scale)) setpoint = x0 + max(10, int(self.setpoint * self.scale))
gc.SetBrush(gc.CreateBrush(wx.Brush(wx.Colour(0, 0, 0)))) gc.SetBrush(gc.CreateBrush(wx.Brush(wx.Colour(0, 0, 0))))
setp_path = gc.CreatePath() setp_path = gc.CreatePath()
setp_path.MoveToPoint(setpoint-4, y0) setp_path.MoveToPoint(setpoint - 4, y0)
setp_path.AddLineToPoint(setpoint+4, y0) setp_path.AddLineToPoint(setpoint + 4, y0)
setp_path.AddLineToPoint(setpoint, y0+5) setp_path.AddLineToPoint(setpoint, y0 + 5)
setp_path.MoveToPoint(setpoint-4, yE) setp_path.MoveToPoint(setpoint - 4, yE)
setp_path.AddLineToPoint(setpoint+4, yE) setp_path.AddLineToPoint(setpoint + 4, yE)
setp_path.AddLineToPoint(setpoint, yE-5) setp_path.AddLineToPoint(setpoint, yE - 5)
gc.DrawPath(setp_path) gc.DrawPath(setp_path)
# draw readout # draw readout
text = u"T\u00B0 %u/%u"%(self.value, self.setpoint) text = u"T\u00B0 %u/%u" % (self.value, self.setpoint)
#gc.SetFont(gc.CreateFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD), wx.WHITE)) #gc.SetFont(gc.CreateFont(wx.Font(12, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD), wx.WHITE))
#gc.DrawText(text, 29,-2) #gc.DrawText(text, 29,-2)
gc.SetFont(gc.CreateFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD), wx.WHITE)) gc.SetFont(gc.CreateFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD), wx.WHITE))
gc.DrawText(self.title, x0+19, y0+4) gc.DrawText(self.title, x0 + 19, y0 + 4)
gc.DrawText(text, x0+119, y0+4) gc.DrawText(text, x0 + 119, y0 + 4)
gc.SetFont(gc.CreateFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD))) gc.SetFont(gc.CreateFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)))
gc.DrawText(self.title, x0+18, y0+3) gc.DrawText(self.title, x0 + 18, y0 + 3)
gc.DrawText(text, x0+118, y0+3) gc.DrawText(text, x0 + 118, y0 + 3)
class SpecialButton(object): class SpecialButton(object):
...@@ -355,7 +359,8 @@ class SpecialButton(object): ...@@ -355,7 +359,8 @@ class SpecialButton(object):
tooltip = None tooltip = None
custom = None custom = None
def __init__(self, label, command, background = None, pos = None, span = None, tooltip = None, custom = False): def __init__(self, label, command, background = None, pos = None,
span = None, tooltip = None, custom = False):
self.label = label self.label = label
self.command = command self.command = command
self.pos = pos self.pos = pos
......
...@@ -13,19 +13,21 @@ ...@@ -13,19 +13,21 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>. # along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import sys, struct, math import sys
import struct
import math
def cross(v1, v2): def cross(v1, v2):
return [v1[1]*v2[2]-v1[2]*v2[1], v1[2]*v2[0]-v1[0]*v2[2], v1[0]*v2[1]-v1[1]*v2[0]] return [v1[1] * v2[2] - v1[2] * v2[1], v1[2] * v2[0] - v1[0] * v2[2], v1[0] * v2[1] - v1[1] * v2[0]]
def genfacet(v): def genfacet(v):
veca = [v[1][0]-v[0][0], v[1][1]-v[0][1], v[1][2]-v[0][2]] veca = [v[1][0] - v[0][0], v[1][1] - v[0][1], v[1][2] - v[0][2]]
vecb = [v[2][0]-v[1][0], v[2][1]-v[1][1], v[2][2]-v[1][2]] vecb = [v[2][0] - v[1][0], v[2][1] - v[1][1], v[2][2] - v[1][2]]
vecx = cross(veca, vecb) vecx = cross(veca, vecb)
vlen = math.sqrt(sum(map(lambda x:x*x, vecx))) vlen = math.sqrt(sum(map(lambda x: x * x, vecx)))
if vlen == 0: if vlen == 0:
vlen = 1 vlen = 1
normal = map(lambda x:x/vlen, vecx) normal = map(lambda x: x / vlen, vecx)
return [normal, v] return [normal, v]
I = [ I = [
...@@ -40,14 +42,14 @@ def transpose(matrix): ...@@ -40,14 +42,14 @@ def transpose(matrix):
#return [[v[i] for v in matrix] for i in xrange(len(matrix[0]))] #return [[v[i] for v in matrix] for i in xrange(len(matrix[0]))]
def multmatrix(vector, matrix): def multmatrix(vector, matrix):
return map(sum, transpose(map(lambda x:[x[0]*p for p in x[1]], zip(vector, transpose(matrix))))) return map(sum, transpose(map(lambda x: [x[0] * p for p in x[1]], zip(vector, transpose(matrix)))))
def applymatrix(facet, matrix = I): def applymatrix(facet, matrix = I):
#return facet #return facet
#return [map(lambda x:-1.0*x, multmatrix(facet[0]+[1], matrix)[:3]), map(lambda x:multmatrix(x+[1], matrix)[:3], facet[1])] #return [map(lambda x:-1.0*x, multmatrix(facet[0]+[1], matrix)[:3]), map(lambda x:multmatrix(x+[1], matrix)[:3], facet[1])]
return genfacet(map(lambda x:multmatrix(x+[1], matrix)[:3], facet[1])) return genfacet(map(lambda x: multmatrix(x + [1], matrix)[:3], facet[1]))
f = [[0, 0, 0],[[-3.022642, 0.642482, -9.510565],[-3.022642, 0.642482, -9.510565],[-3.022642, 0.642482, -9.510565]]] f = [[0, 0, 0], [[-3.022642, 0.642482, -9.510565], [-3.022642, 0.642482, -9.510565], [-3.022642, 0.642482, -9.510565]]]
m = [ m = [
[1, 0, 0, 0], [1, 0, 0, 0],
[0, 1, 0, 0], [0, 1, 0, 0],
...@@ -60,37 +62,35 @@ def emitstl(filename, facets = [], objname = "stltool_export", binary = 1): ...@@ -60,37 +62,35 @@ def emitstl(filename, facets = [], objname = "stltool_export", binary = 1):
return return
if binary: if binary:
f = open(filename, "wb") f = open(filename, "wb")
buf = "".join(["\0"]*80) buf = "".join(["\0"] * 80)
buf+=struct.pack("<I", len(facets)) buf += struct.pack("<I", len(facets))
facetformat = struct.Struct("<ffffffffffffH") facetformat = struct.Struct("<ffffffffffffH")
for i in facets: for i in facets:
l = list(i[0][:]) l = list(i[0][:])
for j in i[1]: for j in i[1]:
l+=j[:] l += j[:]
l+=[0] l += [0]
#print len(l) #print len(l)
buf+=facetformat.pack(*l) buf += facetformat.pack(*l)
f.write(buf) f.write(buf)
f.close() f.close()
return return
f = open(filename, "w") f = open(filename, "w")
f.write("solid "+objname+"\n") f.write("solid " + objname + "\n")
for i in facets: for i in facets:
f.write(" facet normal "+" ".join(map(str, i[0]))+"\n outer loop\n") f.write(" facet normal " + " ".join(map(str, i[0])) + "\n outer loop\n")
for j in i[1]: for j in i[1]:
f.write(" vertex "+" ".join(map(str, j))+"\n") f.write(" vertex " + " ".join(map(str, j)) + "\n")
f.write(" endloop"+"\n") f.write(" endloop" + "\n")
f.write(" endfacet"+"\n") f.write(" endfacet" + "\n")
f.write("endsolid "+objname+"\n") f.write("endsolid " + objname + "\n")
f.close() f.close()
class stl(object): class stl(object):
def __init__(self, filename = None): def __init__(self, filename = None):
self.facet = [[0, 0, 0],[[0, 0, 0],[0, 0, 0],[0, 0, 0]]] self.facet = [[0, 0, 0], [[0, 0, 0], [0, 0, 0], [0, 0, 0]]]
self.facets = [] self.facets = []
self.facetsminz = [] self.facetsminz = []
self.facetsmaxz = [] self.facetsmaxz = []
...@@ -129,16 +129,15 @@ class stl(object): ...@@ -129,16 +129,15 @@ class stl(object):
buf += newdata buf += newdata
fd = list(facetformat.unpack(buf)) fd = list(facetformat.unpack(buf))
self.name = "binary soloid" self.name = "binary soloid"
facet = [fd[:3],[fd[3:6], fd[6:9], fd[9:12]]] facet = [fd[:3], [fd[3:6], fd[6:9], fd[9:12]]]
self.facets.append(facet) self.facets.append(facet)
self.facetsminz.append((min(map(lambda x:x[2], facet[1])), facet)) self.facetsminz.append((min(map(lambda x: x[2], facet[1])), facet))
self.facetsmaxz.append((max(map(lambda x:x[2], facet[1])), facet)) self.facetsmaxz.append((max(map(lambda x: x[2], facet[1])), facet))
f.close() f.close()
return return
def translate(self, v = [0, 0, 0]): def translate(self, v = [0, 0, 0]):
matrix = [ matrix = [[1, 0, 0, v[0]],
[1, 0, 0, v[0]],
[0, 1, 0, v[1]], [0, 1, 0, v[1]],
[0, 0, 1, v[2]], [0, 0, 1, v[2]],
[0, 0, 0, 1] [0, 0, 0, 1]
...@@ -148,22 +147,19 @@ class stl(object): ...@@ -148,22 +147,19 @@ class stl(object):
def rotate(self, v = [0, 0, 0]): def rotate(self, v = [0, 0, 0]):
import math import math
z = v[2] z = v[2]
matrix1 = [ matrix1 = [[math.cos(math.radians(z)), -math.sin(math.radians(z)), 0, 0],
[math.cos(math.radians(z)),-math.sin(math.radians(z)), 0, 0],
[math.sin(math.radians(z)), math.cos(math.radians(z)), 0, 0], [math.sin(math.radians(z)), math.cos(math.radians(z)), 0, 0],
[0, 0, 1, 0], [0, 0, 1, 0],
[0, 0, 0, 1] [0, 0, 0, 1]
] ]
y = v[0] y = v[0]
matrix2 = [ matrix2 = [[1, 0, 0, 0],
[1, 0, 0, 0], [0, math.cos(math.radians(y)), -math.sin(math.radians(y)), 0],
[0, math.cos(math.radians(y)),-math.sin(math.radians(y)), 0],
[0, math.sin(math.radians(y)), math.cos(math.radians(y)), 0], [0, math.sin(math.radians(y)), math.cos(math.radians(y)), 0],
[0, 0, 0, 1] [0, 0, 0, 1]
] ]
x = v[1] x = v[1]
matrix3 = [ matrix3 = [[math.cos(math.radians(x)), 0, -math.sin(math.radians(x)), 0],
[math.cos(math.radians(x)), 0,-math.sin(math.radians(x)), 0],
[0, 1, 0, 0], [0, 1, 0, 0],
[math.sin(math.radians(x)), 0, math.cos(math.radians(x)), 0], [math.sin(math.radians(x)), 0, math.cos(math.radians(x)), 0],
[0, 0, 0, 1] [0, 0, 0, 1]
...@@ -171,15 +167,13 @@ class stl(object): ...@@ -171,15 +167,13 @@ class stl(object):
return self.transform(matrix1).transform(matrix2).transform(matrix3) return self.transform(matrix1).transform(matrix2).transform(matrix3)
def scale(self, v = [0, 0, 0]): def scale(self, v = [0, 0, 0]):
matrix = [ matrix = [[v[0], 0, 0, 0],
[v[0], 0, 0, 0],
[0, v[1], 0, 0], [0, v[1], 0, 0],
[0, 0, v[2], 0], [0, 0, v[2], 0],
[0, 0, 0, 1] [0, 0, 0, 1]
] ]
return self.transform(matrix) return self.transform(matrix)
def transform(self, m = I): def transform(self, m = I):
s = stl() s = stl()
s.facets = [applymatrix(i, m) for i in self.facets] s.facets = [applymatrix(i, m) for i in self.facets]
...@@ -189,20 +183,20 @@ class stl(object): ...@@ -189,20 +183,20 @@ class stl(object):
s.facetloc = 0 s.facetloc = 0
s.name = self.name s.name = self.name
for facet in s.facets: for facet in s.facets:
s.facetsminz+=[(min(map(lambda x:x[2], facet[1])), facet)] s.facetsminz += [(min(map(lambda x:x[2], facet[1])), facet)]
s.facetsmaxz+=[(max(map(lambda x:x[2], facet[1])), facet)] s.facetsmaxz += [(max(map(lambda x:x[2], facet[1])), facet)]
return s return s
def export(self, f = sys.stdout): def export(self, f = sys.stdout):
f.write("solid "+self.name+"\n") f.write("solid " + self.name + "\n")
for i in self.facets: for i in self.facets:
f.write(" facet normal "+" ".join(map(str, i[0]))+"\n") f.write(" facet normal " + " ".join(map(str, i[0])) + "\n")
f.write(" outer loop"+"\n") f.write(" outer loop" + "\n")
for j in i[1]: for j in i[1]:
f.write(" vertex "+" ".join(map(str, j))+"\n") f.write(" vertex " + " ".join(map(str, j)) + "\n")
f.write(" endloop"+"\n") f.write(" endloop" + "\n")
f.write(" endfacet"+"\n") f.write(" endfacet" + "\n")
f.write("endsolid "+self.name+"\n") f.write("endsolid " + self.name + "\n")
f.flush() f.flush()
def parseline(self, l): def parseline(self, l):
...@@ -216,33 +210,34 @@ class stl(object): ...@@ -216,33 +210,34 @@ class stl(object):
self.insolid = 0 self.insolid = 0
return 0 return 0
elif l.startswith("facet normal"): elif l.startswith("facet normal"):
l = l.replace(", ",".") l = l.replace(", ", ".")
self.infacet = 11 self.infacet = 11
self.facetloc = 0 self.facetloc = 0
self.facet = [[0, 0, 0],[[0, 0, 0],[0, 0, 0],[0, 0, 0]]] self.facet = [[0, 0, 0], [[0, 0, 0], [0, 0, 0], [0, 0, 0]]]
self.facet[0]=map(float, l.split()[2:]) self.facet[0] = map(float, l.split()[2:])
elif l.startswith("endfacet"): elif l.startswith("endfacet"):
self.infacet = 0 self.infacet = 0
self.facets+=[self.facet] self.facets += [self.facet]
facet = self.facet facet = self.facet
self.facetsminz+=[(min(map(lambda x:x[2], facet[1])), facet)] self.facetsminz += [(min(map(lambda x:x[2], facet[1])), facet)]
self.facetsmaxz+=[(max(map(lambda x:x[2], facet[1])), facet)] self.facetsmaxz += [(max(map(lambda x:x[2], facet[1])), facet)]
elif l.startswith("vertex"): elif l.startswith("vertex"):
l = l.replace(", ",".") l = l.replace(", ", ".")
self.facet[1][self.facetloc]=map(float, l.split()[1:]) self.facet[1][self.facetloc] = map(float, l.split()[1:])
self.facetloc+=1 self.facetloc += 1
return 1 return 1
if __name__ == "__main__": if __name__ == "__main__":
s = stl("../../Downloads/frame-vertex-neo-foot-x4.stl") s = stl("../../Downloads/frame-vertex-neo-foot-x4.stl")
for i in xrange(11, 11): for i in xrange(11, 11):
working = s.facets[:] working = s.facets[:]
for j in reversed(sorted(s.facetsminz)): for j in reversed(sorted(s.facetsminz)):
if(j[0]>i): if(j[0] > i):
working.remove(j[1]) working.remove(j[1])
else: else:
break break
for j in (sorted(s.facetsmaxz)): for j in (sorted(s.facetsmaxz)):
if(j[0]<i): if(j[0] < i):
working.remove(j[1]) working.remove(j[1])
else: else:
break break
......
...@@ -15,13 +15,8 @@ ...@@ -15,13 +15,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>. # along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import os
import math
import stltool
import wx import wx
from wx import glcanvas
import time import time
import threading
import pyglet import pyglet
pyglet.options['debug_gl'] = True pyglet.options['debug_gl'] = True
...@@ -130,9 +125,11 @@ class StlViewPanel(wxGLPanel): ...@@ -130,9 +125,11 @@ class StlViewPanel(wxGLPanel):
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, vec(0, 0.1, 0, 0.9)) glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, vec(0, 0.1, 0, 0.9))
if call_reshape: if call_reshape:
self.OnReshape() self.OnReshape()
if self.parent.filenames: if hasattr(self.parent, "filenames") and self.parent.filenames:
for filename in self.parent.filenames: for filename in self.parent.filenames:
self.parent.load_file(None, filename) self.parent.load_file(filename)
self.parent.autoplate()
self.parent.filenames = None
def double(self, event): def double(self, event):
p = event.GetPositionTuple() p = event.GetPositionTuple()
...@@ -140,34 +137,14 @@ class StlViewPanel(wxGLPanel): ...@@ -140,34 +137,14 @@ class StlViewPanel(wxGLPanel):
v = map(lambda m, w, b: b * m / w, p, sz, self.build_dimensions[0:2]) v = map(lambda m, w, b: b * m / w, p, sz, self.build_dimensions[0:2])
v[1] = self.build_dimensions[1] - v[1] v[1] = self.build_dimensions[1] - v[1]
v += [300] v += [300]
print "Double-click at "+str(v)+" in " print "Double-click at " + str(v) + " in "
print self print self
def forceresize(self): def forceresize(self):
self.SetClientSize((self.GetClientSize()[0], self.GetClientSize()[1] + 1)) self.SetClientSize((self.GetClientSize()[0], self.GetClientSize()[1] + 1))
self.SetClientSize((self.GetClientSize()[0], self.GetClientSize()[1] - 1)) self.SetClientSize((self.GetClientSize()[0], self.GetClientSize()[1] - 1))
threading.Thread(target = self.update).start()
self.initialized = 0 self.initialized = 0
def move_shape(self, delta):
"""moves shape (selected in l, which is list ListBox of shapes)
by an offset specified in tuple delta.
Positive numbers move to (rigt, down)"""
name = self.parent.l.GetSelection()
if name == wx.NOT_FOUND:
return False
name = self.parent.l.GetString(name)
model = self.parent.models[name]
model.offsets = [
model.offsets[0] + delta[0],
model.offsets[1] + delta[1],
model.offsets[2]
]
self.Refresh()
return True
def move(self, event): def move(self, event):
"""react to mouse actions: """react to mouse actions:
no mouse: show red mousedrop no mouse: show red mousedrop
...@@ -178,80 +155,38 @@ class StlViewPanel(wxGLPanel): ...@@ -178,80 +155,38 @@ class StlViewPanel(wxGLPanel):
""" """
self.mousepos = event.GetPositionTuple() self.mousepos = event.GetPositionTuple()
if event.Dragging() and event.LeftIsDown(): if event.Dragging() and event.LeftIsDown():
if self.initpos == None: self.handle_rotation(event)
self.initpos = event.GetPositionTuple() elif event.Dragging() and event.RightIsDown():
else: self.handle_translation(event)
if not event.ShiftDown():
p1 = self.initpos
p2 = event.GetPositionTuple()
x1, y1, _ = self.mouse_to_3d(p1[0], p1[1])
x2, y2, _ = self.mouse_to_3d(p2[0], p2[1])
self.move_shape((x2 - x1, y2 - y1))
self.initpos = p2
return
p1 = self.initpos
p2 = event.GetPositionTuple()
sz = self.GetClientSize()
p1x = (float(p1[0]) - sz[0] / 2) / (sz[0] / 2)
p1y = -(float(p1[1]) - sz[1] / 2) / (sz[1] / 2)
p2x = (float(p2[0]) - sz[0] / 2) / (sz[0] / 2)
p2y = -(float(p2[1]) - sz[1] / 2) / (sz[1] / 2)
quat = trackball(p1x, p1y, p2x, p2y, 0.8)
self.basequat = mulquat(self.basequat, quat)
self.initpos = p2
elif event.ButtonUp(wx.MOUSE_BTN_LEFT): elif event.ButtonUp(wx.MOUSE_BTN_LEFT):
if self.initpos is not None: if self.initpos is not None:
self.initpos = None self.initpos = None
elif event.ButtonUp(wx.MOUSE_BTN_RIGHT): elif event.ButtonUp(wx.MOUSE_BTN_RIGHT):
if self.initpos is not None: if self.initpos is not None:
self.initpos = None self.initpos = None
elif event.Dragging() and event.RightIsDown():
if self.initpos is None:
self.initpos = event.GetPositionTuple()
else:
p1 = self.initpos
p2 = event.GetPositionTuple()
if self.orthographic:
x1, y1, _ = self.mouse_to_3d(p1[0], p1[1])
x2, y2, _ = self.mouse_to_3d(p2[0], p2[1])
glTranslatef(x2 - x1, y2 - y1, 0)
else: else:
glTranslatef(p2[0] - p1[0], -(p2[1] - p1[1]), 0) event.Skip()
self.initpos = p2 return
event.Skip()
def rotate_shape(self, angle): wx.CallAfter(self.Refresh)
"""rotates acive shape
positive angle is clockwise
"""
name = self.parent.l.GetSelection()
if name == wx.NOT_FOUND:
return False
name = self.parent.l.GetString(name)
model = self.parent.models[name]
model.rot += angle
def wheel(self, event): def handle_wheel(self, event):
"""react to mouse wheel actions:
rotate object
with shift zoom viewport
"""
delta = event.GetWheelRotation() delta = event.GetWheelRotation()
if not event.ShiftDown():
angle = 10
if delta > 0:
self.rotate_shape(angle / 2)
else:
self.rotate_shape(-angle / 2)
else:
factor = 1.05 factor = 1.05
x, y = event.GetPositionTuple() x, y = event.GetPositionTuple()
x, y, _ = self.mouse_to_3d(x, y) x, y, _ = self.mouse_to_3d(x, y)
if delta > 0: if delta > 0:
self.zoom(factor, (x, y)) self.zoom(factor, (x, y))
else: else:
self.zoom(1/factor, (x, y)) self.zoom(1 / factor, (x, y))
def wheel(self, event):
"""react to mouse wheel actions:
rotate object
with shift zoom viewport
"""
self.handle_wheel(event)
wx.CallAfter(self.Refresh)
def keypress(self, event): def keypress(self, event):
"""gets keypress events and moves/rotates acive shape""" """gets keypress events and moves/rotates acive shape"""
...@@ -264,32 +199,24 @@ class StlViewPanel(wxGLPanel): ...@@ -264,32 +199,24 @@ class StlViewPanel(wxGLPanel):
angle = 1 angle = 1
#h #h
if keycode == 72: if keycode == 72:
self.move_shape((-step, 0)) self.parent.move_shape((-step, 0))
#l #l
if keycode == 76: if keycode == 76:
self.move_shape((step, 0)) self.parent.move_shape((step, 0))
#j #j
if keycode == 75: if keycode == 75:
self.move_shape((0, step)) self.parent.move_shape((0, step))
#k #k
if keycode == 74: if keycode == 74:
self.move_shape((0, -step)) self.parent.move_shape((0, -step))
#[ #[
if keycode == 91: if keycode == 91:
self.rotate_shape(-angle) self.parent.rotate_shape(-angle)
#] #]
if keycode == 93: if keycode == 93:
self.rotate_shape(angle) self.parent.rotate_shape(angle)
event.Skip() event.Skip()
def update(self):
while(1):
dt = 0.05
time.sleep(0.05)
try:
wx.CallAfter(self.Refresh) wx.CallAfter(self.Refresh)
except:
return
def anim(self, obj): def anim(self, obj):
g = 50 * 9.8 g = 50 * 9.8
...@@ -321,7 +248,7 @@ class StlViewPanel(wxGLPanel): ...@@ -321,7 +248,7 @@ class StlViewPanel(wxGLPanel):
def drawmodel(self, m, n): def drawmodel(self, m, n):
batch = pyglet.graphics.Batch() batch = pyglet.graphics.Batch()
stl = stlview(m.facets, batch = batch) stlview(m.facets, batch = batch)
m.batch = batch m.batch = batch
m.animoffset = 300 m.animoffset = 300
#print m #print m
...@@ -340,8 +267,8 @@ class StlViewPanel(wxGLPanel): ...@@ -340,8 +267,8 @@ class StlViewPanel(wxGLPanel):
glTranslatef(0, 0, -self.dist) glTranslatef(0, 0, -self.dist)
glMultMatrixd(build_rotmatrix(self.basequat)) # Rotate according to trackball glMultMatrixd(build_rotmatrix(self.basequat)) # Rotate according to trackball
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.2, 0.2, 0.2, 1)) glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec(0.2, 0.2, 0.2, 1))
glTranslatef(- self.build_dimensions[3] - self.platform.width/2, glTranslatef(- self.build_dimensions[3] - self.platform.width / 2,
- self.build_dimensions[4] - self.platform.depth/2, 0) # Move origin to bottom left of platform - self.build_dimensions[4] - self.platform.depth / 2, 0) # Move origin to bottom left of platform
# Draw platform # Draw platform
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
self.platform.draw() self.platform.draw()
...@@ -365,12 +292,14 @@ class StlViewPanel(wxGLPanel): ...@@ -365,12 +292,14 @@ class StlViewPanel(wxGLPanel):
glPushMatrix() glPushMatrix()
# Draw objects # Draw objects
for i in self.parent.models.values(): for i in self.parent.models:
model = self.parent.models[i]
glPushMatrix() glPushMatrix()
glTranslatef(*(i.offsets)) glTranslatef(*(model.offsets))
glRotatef(i.rot, 0.0, 0.0, 1.0) glRotatef(model.rot, 0.0, 0.0, 1.0)
glScalef(*i.scale) glTranslatef(*(model.centeroffset))
i.batch.draw() glScalef(*model.scale)
model.batch.draw()
glPopMatrix() glPopMatrix()
glPopMatrix() glPopMatrix()
glPopMatrix() glPopMatrix()
...@@ -378,7 +307,7 @@ class StlViewPanel(wxGLPanel): ...@@ -378,7 +307,7 @@ class StlViewPanel(wxGLPanel):
def main(): def main():
app = wx.App(redirect = False) app = wx.App(redirect = False)
frame = wx.Frame(None, -1, "GL Window", size = (400, 400)) frame = wx.Frame(None, -1, "GL Window", size = (400, 400))
panel = StlViewPanel(frame) StlViewPanel(frame)
frame.Show(True) frame.Show(True)
app.MainLoop() app.MainLoop()
app.Destroy() app.Destroy()
......
...@@ -13,9 +13,10 @@ ...@@ -13,9 +13,10 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>. # along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import wx, os, math import wx
from bufferedcanvas import * import math
from printrun_utils import * from bufferedcanvas import BufferedCanvas
from printrun_utils import imagefile
def sign(n): def sign(n):
if n < 0: return -1 if n < 0: return -1
...@@ -94,10 +95,10 @@ class XYButtons(BufferedCanvas): ...@@ -94,10 +95,10 @@ class XYButtons(BufferedCanvas):
ylen = y2 - y1 ylen = y2 - y1
pxlen = x1 - pos.x pxlen = x1 - pos.x
pylen = y1 - pos.y pylen = y1 - pos.y
return abs(xlen*pylen-ylen*pxlen)/math.sqrt(xlen**2+ylen**2) return abs(xlen * pylen - ylen * pxlen) / math.sqrt(xlen ** 2 + ylen ** 2)
def distanceToPoint(self, x1, y1, x2, y2): def distanceToPoint(self, x1, y1, x2, y2):
return math.sqrt((x1-x2)**2 + (y1-y2)**2) return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
def cycleKeypadIndex(self): def cycleKeypadIndex(self):
idx = self.keypad_idx + 1 idx = self.keypad_idx + 1
...@@ -110,11 +111,11 @@ class XYButtons(BufferedCanvas): ...@@ -110,11 +111,11 @@ class XYButtons(BufferedCanvas):
def getMovement(self): def getMovement(self):
xdir = [1, 0, -1, 0, 0, 0][self.quadrant] xdir = [1, 0, -1, 0, 0, 0][self.quadrant]
ydir = [0, 1, 0, -1, 0 ,0][self.quadrant] ydir = [0, 1, 0, -1, 0, 0][self.quadrant]
zdir = [0, 0, 0, 0, 1 ,-1][self.quadrant] zdir = [0, 0, 0, 0, 1, -1][self.quadrant]
magnitude = math.pow(10, self.concentric-1) magnitude = math.pow(10, self.concentric - 1)
if not zdir == 0: if not zdir == 0:
magnitude=min(magnitude,10) magnitude = min(magnitude, 10)
return (magnitude * xdir, magnitude * ydir, magnitude * zdir) return (magnitude * xdir, magnitude * ydir, magnitude * zdir)
def lookupConcentric(self, radius): def lookupConcentric(self, radius):
...@@ -128,7 +129,7 @@ class XYButtons(BufferedCanvas): ...@@ -128,7 +129,7 @@ class XYButtons(BufferedCanvas):
def getQuadrantConcentricFromPosition(self, pos): def getQuadrantConcentricFromPosition(self, pos):
rel_x = pos[0] - XYButtons.center[0] rel_x = pos[0] - XYButtons.center[0]
rel_y = pos[1] - XYButtons.center[1] rel_y = pos[1] - XYButtons.center[1]
radius = math.sqrt(rel_x**2 + rel_y**2) radius = math.sqrt(rel_x ** 2 + rel_y ** 2)
if rel_x > rel_y and rel_x > -rel_y: if rel_x > rel_y and rel_x > -rel_y:
quadrant = 0 # Right quadrant = 0 # Right
elif rel_x <= rel_y and rel_x > -rel_y: elif rel_x <= rel_y and rel_x > -rel_y:
...@@ -149,7 +150,7 @@ class XYButtons(BufferedCanvas): ...@@ -149,7 +150,7 @@ class XYButtons(BufferedCanvas):
return None return None
def drawPartialPie(self, gc, center, r1, r2, angle1, angle2): def drawPartialPie(self, gc, center, r1, r2, angle1, angle2):
p1 = wx.Point(center.x + r1*math.cos(angle1), center.y + r1*math.sin(angle1)) p1 = wx.Point(center.x + r1 * math.cos(angle1), center.y + r1 * math.sin(angle1))
path = gc.CreatePath() path = gc.CreatePath()
path.MoveToPoint(p1.x, p1.y) path.MoveToPoint(p1.x, p1.y)
...@@ -167,22 +168,22 @@ class XYButtons(BufferedCanvas): ...@@ -167,22 +168,22 @@ class XYButtons(BufferedCanvas):
fudge = -0.02 fudge = -0.02
center = wx.Point(XYButtons.center[0], XYButtons.center[1]) center = wx.Point(XYButtons.center[0], XYButtons.center[1])
if quadrant == 0: if quadrant == 0:
a1, a2 = (-math.pi*0.25, math.pi*0.25) a1, a2 = (-math.pi * 0.25, math.pi * 0.25)
center.x += inner_ring_radius center.x += inner_ring_radius
elif quadrant == 1: elif quadrant == 1:
a1, a2 = (math.pi*1.25, math.pi*1.75) a1, a2 = (math.pi * 1.25, math.pi * 1.75)
center.y -= inner_ring_radius center.y -= inner_ring_radius
elif quadrant == 2: elif quadrant == 2:
a1, a2 = (math.pi*0.75, math.pi*1.25) a1, a2 = (math.pi * 0.75, math.pi * 1.25)
center.x -= inner_ring_radius center.x -= inner_ring_radius
elif quadrant == 3: elif quadrant == 3:
a1, a2 = (math.pi*0.25, math.pi*0.75) a1, a2 = (math.pi * 0.25, math.pi * 0.75)
center.y += inner_ring_radius center.y += inner_ring_radius
r1 = XYButtons.concentric_circle_radii[concentric] r1 = XYButtons.concentric_circle_radii[concentric]
r2 = XYButtons.concentric_circle_radii[concentric+1] r2 = XYButtons.concentric_circle_radii[concentric + 1]
self.drawPartialPie(gc, center, r1-inner_ring_radius, r2-inner_ring_radius, a1+fudge, a2-fudge) self.drawPartialPie(gc, center, r1 - inner_ring_radius, r2 - inner_ring_radius, a1 + fudge, a2 - fudge)
def drawCorner(self, gc, x, y, angle = 0.0): def drawCorner(self, gc, x, y, angle = 0.0):
w, h = XYButtons.corner_size w, h = XYButtons.corner_size
...@@ -191,12 +192,12 @@ class XYButtons(BufferedCanvas): ...@@ -191,12 +192,12 @@ class XYButtons(BufferedCanvas):
gc.Translate(x, y) gc.Translate(x, y)
gc.Rotate(angle) gc.Rotate(angle)
path = gc.CreatePath() path = gc.CreatePath()
path.MoveToPoint(-w/2, -h/2) path.MoveToPoint(-w / 2, -h / 2)
path.AddLineToPoint(w/2, -h/2) path.AddLineToPoint(w / 2, -h / 2)
path.AddLineToPoint(w/2, -h/2+h/3) path.AddLineToPoint(w / 2, -h / 2 + h / 3)
path.AddLineToPoint(-w/2+w/3, h/2) path.AddLineToPoint(-w / 2 + w / 3, h / 2)
path.AddLineToPoint(-w/2, h/2) path.AddLineToPoint(-w / 2, h / 2)
path.AddLineToPoint(-w/2, -h/2) path.AddLineToPoint(-w / 2, -h / 2)
gc.DrawPath(path) gc.DrawPath(path)
gc.PopState() gc.PopState()
...@@ -207,25 +208,23 @@ class XYButtons(BufferedCanvas): ...@@ -207,25 +208,23 @@ class XYButtons(BufferedCanvas):
inset = 10 inset = 10
if corner == 0: if corner == 0:
x, y = (cx - ww/2 + inset, cy - wh/2 + inset) x, y = (cx - ww / 2 + inset, cy - wh / 2 + inset)
self.drawCorner(gc, x+w/2, y+h/2, 0) self.drawCorner(gc, x + w / 2, y + h / 2, 0)
elif corner == 1: elif corner == 1:
x, y = (cx + ww/2 - inset, cy - wh/2 + inset) x, y = (cx + ww / 2 - inset, cy - wh / 2 + inset)
self.drawCorner(gc, x-w/2, y+h/2, math.pi/2) self.drawCorner(gc, x - w / 2, y + h / 2, math.pi / 2)
elif corner == 2: elif corner == 2:
x, y = (cx + ww/2 - inset, cy + wh/2 - inset) x, y = (cx + ww / 2 - inset, cy + wh / 2 - inset)
self.drawCorner(gc, x-w/2, y-h/2, math.pi) self.drawCorner(gc, x - w / 2, y - h / 2, math.pi)
elif corner == 3: elif corner == 3:
x, y = (cx - ww/2 + inset, cy + wh/2 - inset) x, y = (cx - ww / 2 + inset, cy + wh / 2 - inset)
self.drawCorner(gc, x+w/2, y-h/2, math.pi*3/2) self.drawCorner(gc, x + w / 2, y - h / 2, math.pi * 3 / 2)
def draw(self, dc, w, h): def draw(self, dc, w, h):
dc.SetBackground(wx.Brush(self.bgcolor)) dc.SetBackground(wx.Brush(self.bgcolor))
dc.Clear() dc.Clear()
gc = wx.GraphicsContext.Create(dc) gc = wx.GraphicsContext.Create(dc)
center = wx.Point(XYButtons.center[0], XYButtons.center[1])
if self.bg_bmp: if self.bg_bmp:
w, h = (self.bg_bmp.GetWidth(), self.bg_bmp.GetHeight()) w, h = (self.bg_bmp.GetWidth(), self.bg_bmp.GetHeight())
gc.DrawBitmap(self.bg_bmp, 0, 0, w, h) gc.DrawBitmap(self.bg_bmp, 0, 0, w, h)
...@@ -235,32 +234,30 @@ class XYButtons(BufferedCanvas): ...@@ -235,32 +234,30 @@ class XYButtons(BufferedCanvas):
gc.SetPen(wx.Pen(wx.Colour(100, 100, 100, 172), 4)) gc.SetPen(wx.Pen(wx.Colour(100, 100, 100, 172), 4))
gc.SetBrush(wx.Brush(wx.Colour(0, 0, 0, 128))) gc.SetBrush(wx.Brush(wx.Colour(0, 0, 0, 128)))
if self.concentric != None: if self.concentric is not None:
if self.concentric < len(XYButtons.concentric_circle_radii): if self.concentric < len(XYButtons.concentric_circle_radii):
if self.quadrant != None: if self.quadrant is not None:
self.highlightQuadrant(gc, self.quadrant, self.concentric) self.highlightQuadrant(gc, self.quadrant, self.concentric)
elif self.corner != None: elif self.corner is not None:
self.highlightCorner(gc, self.corner) self.highlightCorner(gc, self.corner)
if self.keypad_idx >= 0: if self.keypad_idx >= 0:
padw, padh = (self.keypad_bmp.GetWidth(), self.keypad_bmp.GetHeight()) padw, padh = (self.keypad_bmp.GetWidth(), self.keypad_bmp.GetHeight())
pos = XYButtons.keypad_positions[self.keypad_idx] pos = XYButtons.keypad_positions[self.keypad_idx]
pos = (pos[0] - padw/2 - 3, pos[1] - padh/2 - 3) pos = (pos[0] - padw / 2 - 3, pos[1] - padh / 2 - 3)
gc.DrawBitmap(self.keypad_bmp, pos[0], pos[1], padw, padh) gc.DrawBitmap(self.keypad_bmp, pos[0], pos[1], padw, padh)
# Draw label overlays # Draw label overlays
gc.SetPen(wx.Pen(wx.Colour(255, 255, 255, 128), 1)) gc.SetPen(wx.Pen(wx.Colour(255, 255, 255, 128), 1))
gc.SetBrush(wx.Brush(wx.Colour(255, 255, 255, 128+64))) gc.SetBrush(wx.Brush(wx.Colour(255, 255, 255, 128 + 64)))
for idx, kpos in XYButtons.label_overlay_positions.items(): for idx, kpos in XYButtons.label_overlay_positions.items():
if idx != self.concentric: if idx != self.concentric:
r = kpos[2] r = kpos[2]
gc.DrawEllipse(kpos[0]-r, kpos[1]-r, r*2, r*2) gc.DrawEllipse(kpos[0] - r, kpos[1] - r, r * 2, r * 2)
else: else:
gc.SetPen(wx.Pen(self.bgcolor, 0)) gc.SetPen(wx.Pen(self.bgcolor, 0))
gc.SetBrush(wx.Brush(self.bgcolormask)) gc.SetBrush(wx.Brush(self.bgcolormask))
gc.DrawRectangle(0, 0, w, h) gc.DrawRectangle(0, 0, w, h)
# Used to check exact position of keypad dots, should we ever resize the bg image # Used to check exact position of keypad dots, should we ever resize the bg image
# for idx, kpos in XYButtons.label_overlay_positions.items(): # for idx, kpos in XYButtons.label_overlay_positions.items():
# dc.DrawCircle(kpos[0], kpos[1], kpos[2]) # dc.DrawCircle(kpos[0], kpos[1], kpos[2])
...@@ -268,7 +265,6 @@ class XYButtons(BufferedCanvas): ...@@ -268,7 +265,6 @@ class XYButtons(BufferedCanvas):
## ------ ## ## ------ ##
## Events ## ## Events ##
## ------ ## ## ------ ##
def OnTopLevelKey(self, evt): def OnTopLevelKey(self, evt):
# Let user press escape on any control, and return focus here # Let user press escape on any control, and return focus here
if evt.GetKeyCode() == wx.WXK_ESCAPE: if evt.GetKeyCode() == wx.WXK_ESCAPE:
...@@ -300,14 +296,13 @@ class XYButtons(BufferedCanvas): ...@@ -300,14 +296,13 @@ class XYButtons(BufferedCanvas):
self.concentric = self.keypad_idx self.concentric = self.keypad_idx
x, y, z = self.getMovement() x, y, z = self.getMovement()
if x!=0 or y!=0 and self.moveCallback: if x != 0 or y != 0 and self.moveCallback:
self.moveCallback(x, y) self.moveCallback(x, y)
if z!=0 and self.zCallback: if z != 0 and self.zCallback:
self.zCallback(z) self.zCallback(z)
elif evt.GetKeyCode() == wx.WXK_SPACE: elif evt.GetKeyCode() == wx.WXK_SPACE:
self.spacebarCallback() self.spacebarCallback()
def OnMotion(self, event): def OnMotion(self, event):
if not self.enabled: if not self.enabled:
return return
...@@ -319,10 +314,10 @@ class XYButtons(BufferedCanvas): ...@@ -319,10 +314,10 @@ class XYButtons(BufferedCanvas):
idx = self.mouseOverKeypad(mpos) idx = self.mouseOverKeypad(mpos)
self.quadrant = None self.quadrant = None
self.concentric = None self.concentric = None
if idx == None: if idx is None:
center = wx.Point(XYButtons.center[0], XYButtons.center[1]) center = wx.Point(XYButtons.center[0], XYButtons.center[1])
riseDist = self.distanceToLine(mpos, center.x-1, center.y-1, center.x+1, center.y+1) riseDist = self.distanceToLine(mpos, center.x - 1, center.y - 1, center.x + 1, center.y + 1)
fallDist = self.distanceToLine(mpos, center.x-1, center.y+1, center.x+1, center.y-1) fallDist = self.distanceToLine(mpos, center.x - 1, center.y + 1, center.x + 1, center.y - 1)
self.quadrant, self.concentric = self.getQuadrantConcentricFromPosition(mpos) self.quadrant, self.concentric = self.getQuadrantConcentricFromPosition(mpos)
# If mouse hovers in space between quadrants, don't commit to a quadrant # If mouse hovers in space between quadrants, don't commit to a quadrant
...@@ -352,17 +347,17 @@ class XYButtons(BufferedCanvas): ...@@ -352,17 +347,17 @@ class XYButtons(BufferedCanvas):
mpos = event.GetPosition() mpos = event.GetPosition()
idx = self.mouseOverKeypad(mpos) idx = self.mouseOverKeypad(mpos)
if idx == None: if idx is None:
self.quadrant, self.concentric = self.getQuadrantConcentricFromPosition(mpos) self.quadrant, self.concentric = self.getQuadrantConcentricFromPosition(mpos)
if self.concentric != None: if self.concentric is not None:
if self.concentric < len(XYButtons.concentric_circle_radii): if self.concentric < len(XYButtons.concentric_circle_radii):
if self.quadrant != None: if self.quadrant is not None:
x, y, z = self.getMovement() x, y, z = self.getMovement()
if self.moveCallback: if self.moveCallback:
self.lastMove = (x, y) self.lastMove = (x, y)
self.lastCorner = None self.lastCorner = None
self.moveCallback(x, y) self.moveCallback(x, y)
elif self.corner != None: elif self.corner is not None:
if self.cornerCallback: if self.cornerCallback:
self.lastCorner = self.corner self.lastCorner = self.corner
self.lastMove = None self.lastMove = None
......
...@@ -13,9 +13,10 @@ ...@@ -13,9 +13,10 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>. # along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import wx, os, math import wx
from bufferedcanvas import * import math
from printrun_utils import * from bufferedcanvas import BufferedCanvas
from printrun_utils import imagefile
def sign(n): def sign(n):
if n < 0: return -1 if n < 0: return -1
...@@ -83,11 +84,11 @@ class ZButtons(BufferedCanvas): ...@@ -83,11 +84,11 @@ class ZButtons(BufferedCanvas):
fudge = 11 fudge = 11
x = 0 + fudge x = 0 + fudge
w = 59 - fudge*2 w = 59 - fudge * 2
if rng >= 0: if rng >= 0:
k = 1 if dir > 0 else 0 k = 1 if dir > 0 else 0
y = ZButtons.center[1] - (dir * ZButtons.button_ydistances[rng+k]) y = ZButtons.center[1] - (dir * ZButtons.button_ydistances[rng + k])
h = ZButtons.button_ydistances[rng+1] - ZButtons.button_ydistances[rng] h = ZButtons.button_ydistances[rng + 1] - ZButtons.button_ydistances[rng]
gc.DrawRoundedRectangle(x, y, w, h, 4) gc.DrawRoundedRectangle(x, y, w, h, 4)
# gc.DrawRectangle(x, y, w, h) # gc.DrawRectangle(x, y, w, h)
# self.drawPartialPie(dc, center, r1-inner_ring_radius, r2-inner_ring_radius, a1+fudge, a2-fudge) # self.drawPartialPie(dc, center, r1-inner_ring_radius, r2-inner_ring_radius, a1+fudge, a2-fudge)
...@@ -107,16 +108,16 @@ class ZButtons(BufferedCanvas): ...@@ -107,16 +108,16 @@ class ZButtons(BufferedCanvas):
if self.enabled: if self.enabled:
# Draw label overlays # Draw label overlays
gc.SetPen(wx.Pen(wx.Colour(255, 255, 255, 128), 1)) gc.SetPen(wx.Pen(wx.Colour(255, 255, 255, 128), 1))
gc.SetBrush(wx.Brush(wx.Colour(255, 255, 255, 128+64))) gc.SetBrush(wx.Brush(wx.Colour(255, 255, 255, 128 + 64)))
for idx, kpos in ZButtons.label_overlay_positions.items(): for idx, kpos in ZButtons.label_overlay_positions.items():
if kpos and idx != self.range: if kpos and idx != self.range:
r = kpos[2] r = kpos[2]
gc.DrawEllipse(ZButtons.center[0]-kpos[0]-r, ZButtons.center[1]-kpos[1]-r, r*2, r*2) gc.DrawEllipse(ZButtons.center[0] - kpos[0] - r, ZButtons.center[1] - kpos[1] - r, r * 2, r * 2)
# Top 'layer' is the mouse-over highlights # Top 'layer' is the mouse-over highlights
gc.SetPen(wx.Pen(wx.Colour(100, 100, 100, 172), 4)) gc.SetPen(wx.Pen(wx.Colour(100, 100, 100, 172), 4))
gc.SetBrush(wx.Brush(wx.Colour(0, 0, 0, 128))) gc.SetBrush(wx.Brush(wx.Colour(0, 0, 0, 128)))
if self.range != None and self.direction != None: if self.range is not None and self.direction is not None:
self.highlight(gc, self.range, self.direction) self.highlight(gc, self.range, self.direction)
else: else:
gc.SetPen(wx.Pen(self.bgcolor, 0)) gc.SetPen(wx.Pen(self.bgcolor, 0))
......
...@@ -13,44 +13,39 @@ ...@@ -13,44 +13,39 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>. # along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import wx, math import wx
from stltool import * from stltool import stl, genfacet, emitstl
a = wx.App() a = wx.App()
def genscape(data = [[0, 1, 0, 0],[1, 0, 2, 0],[1, 0, 0, 0],[0, 1, 0, 1]], pscale = 1.0, bheight = 1.0, zscale = 1.0): def genscape(data = [[0, 1, 0, 0], [1, 0, 2, 0], [1, 0, 0, 0], [0, 1, 0, 1]],
pscale = 1.0, bheight = 1.0, zscale = 1.0):
o = stl(None) o = stl(None)
datal = len(data) datal = len(data)
datah = len(data[0]) datah = len(data[0])
#create bottom: #create bottom:
bmidpoint = (pscale*(datal-1)/2.0, pscale*(datah-1)/2.0) bmidpoint = (pscale * (datal - 1) / 2.0, pscale * (datah - 1) / 2.0)
#print range(datal), bmidpoint #print range(datal), bmidpoint
for i in zip(range(datal+1)[:-1], range(datal+1)[1:])[:-1]: for i in zip(range(datal + 1)[:-1], range(datal + 1)[1:])[:-1]:
#print (pscale*i[0], pscale*i[1]) #print (pscale*i[0], pscale*i[1])
o.facets+=[[[0, 0,-1],[[0.0, pscale*i[0], 0.0],[0.0, pscale*i[1], 0.0],[bmidpoint[0], bmidpoint[1], 0.0]]]] o.facets += [[[0, 0, -1], [[0.0, pscale * i[0], 0.0], [0.0, pscale * i[1], 0.0], [bmidpoint[0], bmidpoint[1], 0.0]]]]
o.facets+=[[[0, 0,-1],[[2.0*bmidpoint[1], pscale*i[1], 0.0],[2.0*bmidpoint[1], pscale*i[0], 0.0],[bmidpoint[0], bmidpoint[1], 0.0]]]] o.facets += [[[0, 0, -1], [[2.0 * bmidpoint[1], pscale * i[1], 0.0], [2.0 * bmidpoint[1], pscale * i[0], 0.0], [bmidpoint[0], bmidpoint[1], 0.0]]]]
o.facets+=[genfacet([[0.0, pscale*i[0], data[i[0]][0]*zscale+bheight],[0.0, pscale*i[1], data[i[1]][0]*zscale+bheight],[0.0, pscale*i[1], 0.0]])] o.facets += [genfacet([[0.0, pscale * i[0], data[i[0]][0] * zscale + bheight], [0.0, pscale * i[1], data[i[1]][0] * zscale + bheight], [0.0, pscale * i[1], 0.0]])]
o.facets+=[genfacet([[2.0*bmidpoint[1], pscale*i[1], data[i[1]][datah-1]*zscale+bheight],[2.0*bmidpoint[1], pscale*i[0], data[i[0]][datah-1]*zscale+bheight],[2.0*bmidpoint[1], pscale*i[1], 0.0]])] o.facets += [genfacet([[2.0 * bmidpoint[1], pscale * i[1], data[i[1]][datah - 1] * zscale + bheight], [2.0 * bmidpoint[1], pscale * i[0], data[i[0]][datah - 1] * zscale + bheight], [2.0 * bmidpoint[1], pscale * i[1], 0.0]])]
o.facets+=[genfacet([[0.0, pscale*i[0], data[i[0]][0]*zscale+bheight],[0.0, pscale*i[1], 0.0],[0.0, pscale*i[0], 0.0]])] o.facets += [genfacet([[0.0, pscale * i[0], data[i[0]][0] * zscale + bheight], [0.0, pscale * i[1], 0.0], [0.0, pscale * i[0], 0.0]])]
o.facets+=[genfacet([[2.0*bmidpoint[1], pscale*i[1], 0.0],[2.0*bmidpoint[1], pscale*i[0], data[i[0]][datah-1]*zscale+bheight],[2.0*bmidpoint[1], pscale*i[0], 0.0]])] o.facets += [genfacet([[2.0 * bmidpoint[1], pscale * i[1], 0.0], [2.0 * bmidpoint[1], pscale * i[0], data[i[0]][datah - 1] * zscale + bheight], [2.0 * bmidpoint[1], pscale * i[0], 0.0]])]
for i in zip(range(datah + 1)[: - 1], range(datah + 1)[1:])[: - 1]:
#print (pscale * i[0], pscale * i[1])
o.facets += [[[0, 0, -1], [[pscale * i[1], 0.0, 0.0], [pscale * i[0], 0.0, 0.0], [bmidpoint[0], bmidpoint[1], 0.0]]]]
o.facets += [[[0, 0, -1], [[pscale * i[0], 2.0 * bmidpoint[0], 0.0], [pscale * i[1], 2.0 * bmidpoint[0], 0.0], [bmidpoint[0], bmidpoint[1], 0.0]]]]
o.facets += [genfacet([[pscale * i[1], 0.0, data[0][i[1]] * zscale + bheight], [pscale * i[0], 0.0, data[0][i[0]] * zscale + bheight], [pscale * i[1], 0.0, 0.0]])]
o.facets += [genfacet([[pscale * i[0], 2.0 * bmidpoint[0], data[datal - 1][i[0]] * zscale + bheight], [pscale * i[1], 2.0 * bmidpoint[0], data[datal - 1][i[1]] * zscale + bheight], [pscale * i[1], 2.0 * bmidpoint[0], 0.0]])]
o.facets += [genfacet([[pscale * i[1], 0.0, 0.0], [pscale * i[0], 0.0, data[0][i[0]] * zscale + bheight], [pscale * i[0], 0.0, 0.0]])]
o.facets += [genfacet([[pscale * i[0], 2.0 * bmidpoint[0], data[datal - 1][i[0]] * zscale + bheight], [pscale * i[1], 2.0 * bmidpoint[0], 0.0], [pscale * i[0], 2.0 * bmidpoint[0], 0.0]])]
for i in xrange(datah - 1):
for j in xrange(datal - 1):
o.facets += [genfacet([[pscale * i, pscale * j, data[j][i] * zscale + bheight], [pscale * (i + 1), pscale * (j), data[j][i + 1] * zscale + bheight], [pscale * (i + 1), pscale * (j + 1), data[j + 1][i + 1] * zscale + bheight]])]
o.facets += [genfacet([[pscale * (i), pscale * (j + 1), data[j + 1][i] * zscale + bheight], [pscale * i, pscale * j, data[j][i] * zscale + bheight], [pscale * (i + 1), pscale * (j + 1), data[j + 1][i + 1] * zscale + bheight]])]
#print o.facets[-1] #print o.facets[-1]
pass
#print o.facets[-4:]
for i in zip(range(datah+1)[:-1], range(datah+1)[1:])[:-1]:
#print (pscale*i[0], pscale*i[1])
o.facets+=[[[0, 0,-1],[[pscale*i[1], 0.0, 0.0],[pscale*i[0], 0.0, 0.0],[bmidpoint[0], bmidpoint[1], 0.0]]]]
o.facets+=[[[0, 0,-1],[[pscale*i[0], 2.0*bmidpoint[0], 0.0],[pscale*i[1], 2.0*bmidpoint[0], 0.0],[bmidpoint[0], bmidpoint[1], 0.0]]]]
o.facets+=[genfacet([[pscale*i[1], 0.0, data[0][i[1]]*zscale+bheight],[pscale*i[0], 0.0, data[0][i[0]]*zscale+bheight],[pscale*i[1], 0.0, 0.0]])]
#break
o.facets+=[genfacet([[pscale*i[0], 2.0*bmidpoint[0], data[datal-1][i[0]]*zscale+bheight],[pscale*i[1], 2.0*bmidpoint[0], data[datal-1][i[1]]*zscale+bheight],[pscale*i[1], 2.0*bmidpoint[0], 0.0]])]
o.facets+=[genfacet([[pscale*i[1], 0.0, 0.0],[pscale*i[0], 0.0, data[0][i[0]]*zscale+bheight],[pscale*i[0], 0.0, 0.0]])]
o.facets+=[genfacet([[pscale*i[0], 2.0*bmidpoint[0], data[datal-1][i[0]]*zscale+bheight],[pscale*i[1], 2.0*bmidpoint[0], 0.0],[pscale*i[0], 2.0*bmidpoint[0], 0.0]])]
pass
for i in xrange(datah-1):
for j in xrange(datal-1):
o.facets+=[genfacet([[pscale*i, pscale*j, data[j][i]*zscale+bheight],[pscale*(i+1), pscale*(j), data[j][i+1]*zscale+bheight],[pscale*(i+1), pscale*(j+1), data[j+1][i+1]*zscale+bheight]])]
o.facets+=[genfacet([[pscale*(i), pscale*(j+1), data[j+1][i]*zscale+bheight],[pscale*i, pscale*j, data[j][i]*zscale+bheight],[pscale*(i+1), pscale*(j+1), data[j+1][i+1]*zscale+bheight]])]
#print o.facets[-1]
facet = [[0, 0, 0],[[0, 0, 0],[0, 0, 0],[0, 0, 0]]]
return o return o
def zimage(name, out): def zimage(name, out):
i = wx.Image(name) i = wx.Image(name)
...@@ -59,14 +54,15 @@ def zimage(name, out): ...@@ -59,14 +54,15 @@ def zimage(name, out):
b = map(ord, i.GetData()[::3]) b = map(ord, i.GetData()[::3])
data = [] data = []
for i in xrange(s[0]): for i in xrange(s[0]):
data+=[b[i*s[1]:(i+1)*s[1]]] data += [b[i * s[1]:(i + 1) * s[1]]]
#data = [i[::5] for i in data[::5]] #data = [i[::5] for i in data[::5]]
emitstl(out, genscape(data, zscale = 0.1).facets, name) emitstl(out, genscape(data, zscale = 0.1).facets, name)
""" """
class scapewin(wx.Frame): class scapewin(wx.Frame):
def __init__(self, size = (400, 530)): def __init__(self, size = (400, 530)):
wx.Frame.__init__(self, None, title = "Right-click to load an image", size = size) wx.Frame.__init__(self, None,
title = "Right-click to load an image", size = size)
self.SetIcon(wx.Icon("plater.ico", wx.BITMAP_TYPE_ICO)) self.SetIcon(wx.Icon("plater.ico", wx.BITMAP_TYPE_ICO))
self.SetClientSize(size) self.SetClientSize(size)
self.panel = wx.Panel(self, size = size) self.panel = wx.Panel(self, size = size)
......
...@@ -15,19 +15,22 @@ ...@@ -15,19 +15,22 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>. # along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import cmd, sys import cmd
import glob, os, time, datetime import glob
import sys, subprocess, traceback import os
import math, codecs import time
import sys
import subprocess
import traceback
import codecs
import shlex import shlex
from math import sqrt
import argparse import argparse
import locale import locale
import printcore import printcore
from printrun.printrun_utils import install_locale from printrun.printrun_utils import install_locale
from printrun import gcoder
install_locale('pronterface') install_locale('pronterface')
from printrun import gcoder
from functools import wraps from functools import wraps
...@@ -40,21 +43,21 @@ READLINE = True ...@@ -40,21 +43,21 @@ READLINE = True
try: try:
import readline import readline
try: try:
readline.rl.mode.show_all_if_ambiguous = "on" #config pyreadline on windows readline.rl.mode.show_all_if_ambiguous = "on" # config pyreadline on windows
except: except:
pass pass
except: except:
READLINE = False #neither readline module is available READLINE = False # neither readline module is available
def dosify(name): def dosify(name):
return os.path.split(name)[1].split(".")[0][:8]+".g" return os.path.split(name)[1].split(".")[0][:8] + ".g"
def setting_add_tooltip(func): def setting_add_tooltip(func):
@wraps(func) @wraps(func)
def decorator(self, *args, **kwargs): def decorator(self, *args, **kwargs):
widget = func(self, *args, **kwargs) widget = func(self, *args, **kwargs)
helptxt = self.help or "" helptxt = self.help or ""
sep,deftxt = "","" sep, deftxt = "", ""
if len(helptxt): if len(helptxt):
sep = "\n" sep = "\n"
if helptxt.find("\n") >= 0: if helptxt.find("\n") >= 0:
...@@ -88,6 +91,7 @@ class Setting(object): ...@@ -88,6 +91,7 @@ class Setting(object):
def _get_value(self): def _get_value(self):
return self._value return self._value
def _set_value(self, value): def _set_value(self, value):
raise NotImplementedError raise NotImplementedError
value = property(_get_value, _set_value) value = property(_get_value, _set_value)
...@@ -95,7 +99,7 @@ class Setting(object): ...@@ -95,7 +99,7 @@ class Setting(object):
def set_default(self, e): def set_default(self, e):
import wx import wx
if e.CmdDown() and e.ButtonDClick() and self.default is not "": if e.CmdDown() and e.ButtonDClick() and self.default is not "":
confirmation = wx.MessageDialog(None,_("Are you sure you want to reset the setting to the default value: {0!r} ?").format(self.default),_("Confirm set default"),wx.ICON_EXCLAMATION|wx.YES_NO|wx.NO_DEFAULT) confirmation = wx.MessageDialog(None, _("Are you sure you want to reset the setting to the default value: {0!r} ?").format(self.default), _("Confirm set default"), wx.ICON_EXCLAMATION | wx.YES_NO | wx.NO_DEFAULT)
if confirmation.ShowModal() == wx.ID_YES: if confirmation.ShowModal() == wx.ID_YES:
self._set_value(self.default) self._set_value(self.default)
else: else:
...@@ -187,6 +191,7 @@ class BooleanSetting(wxSetting): ...@@ -187,6 +191,7 @@ class BooleanSetting(wxSetting):
def _get_value(self): def _get_value(self):
return bool(self._value) return bool(self._value)
def _set_value(self, value): def _set_value(self, value):
self._value = value self._value = value
if self.widget: if self.widget:
...@@ -208,10 +213,13 @@ class StaticTextSetting(wxSetting): ...@@ -208,10 +213,13 @@ class StaticTextSetting(wxSetting):
def update(self): def update(self):
pass pass
def _get_value(self): def _get_value(self):
return "" return ""
def _set_value(self, value): def _set_value(self, value):
pass pass
def get_specific_widget(self, parent): def get_specific_widget(self, parent):
import wx import wx
self.widget = wx.StaticText(parent, -1, self.text) self.widget = wx.StaticText(parent, -1, self.text)
...@@ -223,6 +231,7 @@ class Settings(object): ...@@ -223,6 +231,7 @@ class Settings(object):
# if v < 0: raise ValueError("You cannot set negative temperatures. To turn the hotend off entirely, set its temperature to 0.") # if v < 0: raise ValueError("You cannot set negative temperatures. To turn the hotend off entirely, set its temperature to 0.")
#def _bedtemperature_alias(self): return {"pla":60, "abs":110, "off":0} #def _bedtemperature_alias(self): return {"pla":60, "abs":110, "off":0}
def _baudrate_list(self): return ["2400", "9600", "19200", "38400", "57600", "115200", "250000"] def _baudrate_list(self): return ["2400", "9600", "19200", "38400", "57600", "115200", "250000"]
def __init__(self): def __init__(self):
# defaults here. # defaults here.
# the initial value determines the type # the initial value determines the type
...@@ -256,6 +265,7 @@ class Settings(object): ...@@ -256,6 +265,7 @@ class Settings(object):
self._add(HiddenSetting("pause_between_prints", True)) self._add(HiddenSetting("pause_between_prints", True))
_settings = [] _settings = []
def __setattr__(self, name, value): def __setattr__(self, name, value):
if name.startswith("_"): if name.startswith("_"):
return object.__setattr__(self, name, value) return object.__setattr__(self, name, value)
...@@ -280,31 +290,31 @@ class Settings(object): ...@@ -280,31 +290,31 @@ class Settings(object):
def _set(self, key, value): def _set(self, key, value):
try: try:
value = getattr(self, "_%s_alias"%key)()[value] value = getattr(self, "_%s_alias" % key)()[value]
except KeyError: except KeyError:
pass pass
except AttributeError: except AttributeError:
pass pass
try: try:
getattr(self, "_%s_validate"%key)(value) getattr(self, "_%s_validate" % key)(value)
except AttributeError: except AttributeError:
pass pass
t = type(getattr(self, key)) t = type(getattr(self, key))
if t == bool and value == "False": setattr(self, key, False) if t == bool and value == "False": setattr(self, key, False)
else: setattr(self, key, t(value)) else: setattr(self, key, t(value))
try: try:
getattr(self, "_%s_cb"%key)(key, value) getattr(self, "_%s_cb" % key)(key, value)
except AttributeError: except AttributeError:
pass pass
return value return value
def _tabcomplete(self, key): def _tabcomplete(self, key):
try: try:
return getattr(self, "_%s_list"%key)() return getattr(self, "_%s_list" % key)()
except AttributeError: except AttributeError:
pass pass
try: try:
return getattr(self, "_%s_alias"%key)().keys() return getattr(self, "_%s_alias" % key)().keys()
except AttributeError: except AttributeError:
pass pass
return [] return []
...@@ -340,7 +350,6 @@ class Status: ...@@ -340,7 +350,6 @@ class Status:
return self.extruder_temp != 0 return self.extruder_temp != 0
class pronsole(cmd.Cmd): class pronsole(cmd.Cmd):
def __init__(self): def __init__(self):
cmd.Cmd.__init__(self) cmd.Cmd.__init__(self)
...@@ -358,8 +367,8 @@ class pronsole(cmd.Cmd): ...@@ -358,8 +367,8 @@ class pronsole(cmd.Cmd):
self.sdfiles = [] self.sdfiles = []
self.paused = False self.paused = False
self.sdprinting = 0 self.sdprinting = 0
self.temps = {"pla":"185", "abs":"230", "off":"0"} self.temps = {"pla": "185", "abs": "230", "off": "0"}
self.bedtemps = {"pla":"60", "abs":"110", "off":"0"} self.bedtemps = {"pla": "60", "abs": "110", "off": "0"}
self.percentdone = 0 self.percentdone = 0
self.tempreadings = "" self.tempreadings = ""
self.macros = {} self.macros = {}
...@@ -374,11 +383,11 @@ class pronsole(cmd.Cmd): ...@@ -374,11 +383,11 @@ class pronsole(cmd.Cmd):
self.settings._bedtemp_pla_cb = self.set_temp_preset self.settings._bedtemp_pla_cb = self.set_temp_preset
self.monitoring = 0 self.monitoring = 0
self.silent = False self.silent = False
self.commandprefixes='MGT$' self.commandprefixes = 'MGT$'
self.promptstrs = {"offline" : "%(bold)suninitialized>%(normal)s ", self.promptstrs = {"offline": "%(bold)suninitialized>%(normal)s ",
"fallback" : "%(bold)sPC>%(normal)s ", "fallback": "%(bold)sPC>%(normal)s ",
"macro" : "%(bold)s..>%(normal)s ", "macro": "%(bold)s..>%(normal)s ",
"online" : "%(bold)sT:%(extruder_temp_fancy)s %(progress_fancy)s >%(normal)s "} "online": "%(bold)sT:%(extruder_temp_fancy)s %(progress_fancy)s >%(normal)s "}
def confirm(self): def confirm(self):
y_or_n = raw_input("y/n: ") y_or_n = raw_input("y/n: ")
...@@ -415,14 +424,14 @@ class pronsole(cmd.Cmd): ...@@ -415,14 +424,14 @@ class pronsole(cmd.Cmd):
else: else:
specials["extruder_temp_fancy"] = "%s/%s" % (str(int(self.status.extruder_temp)), str(int(self.status.extruder_temp_target))) specials["extruder_temp_fancy"] = "%s/%s" % (str(int(self.status.extruder_temp)), str(int(self.status.extruder_temp_target)))
if self.p.printing: if self.p.printing:
progress = int(1000*float(self.p.queueindex)/len(self.p.mainqueue)) / 10 progress = int(1000 * float(self.p.queueindex) / len(self.p.mainqueue)) / 10
elif self.sdprinting: elif self.sdprinting:
progress = self.percentdone progress = self.percentdone
else: else:
progress = 0.0 progress = 0.0
specials["progress"] = str(progress) specials["progress"] = str(progress)
if self.p.printing or self.sdprinting: if self.p.printing or self.sdprinting:
specials["progress_fancy"] = str(progress) +"%" specials["progress_fancy"] = str(progress) + "%"
else: else:
specials["progress_fancy"] = "?%" specials["progress_fancy"] = "?%"
specials["bold"] = "\033[01m" specials["bold"] = "\033[01m"
...@@ -457,8 +466,8 @@ class pronsole(cmd.Cmd): ...@@ -457,8 +466,8 @@ class pronsole(cmd.Cmd):
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM") key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM")
i = 0 i = 0
while(1): while(1):
baselist+=[_winreg.EnumValue(key, i)[1]] baselist += [_winreg.EnumValue(key, i)[1]]
i+=1 i += 1
except: except:
pass pass
...@@ -487,9 +496,9 @@ class pronsole(cmd.Cmd): ...@@ -487,9 +496,9 @@ class pronsole(cmd.Cmd):
self.log("Gcodes are passed through to the printer as they are") self.log("Gcodes are passed through to the printer as they are")
def complete_macro(self, text, line, begidx, endidx): def complete_macro(self, text, line, begidx, endidx):
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "): if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1] == " "):
return [i for i in self.macros.keys() if i.startswith(text)] return [i for i in self.macros.keys() if i.startswith(text)]
elif(len(line.split()) == 3 or (len(line.split()) == 2 and line[-1]==" ")): elif(len(line.split()) == 3 or (len(line.split()) == 2 and line[-1] == " ")):
return [i for i in ["/D", "/S"] + self.completenames(text) if i.startswith(text)] return [i for i in ["/D", "/S"] + self.completenames(text) if i.startswith(text)]
else: else:
return [] return []
...@@ -497,7 +506,7 @@ class pronsole(cmd.Cmd): ...@@ -497,7 +506,7 @@ class pronsole(cmd.Cmd):
def hook_macro(self, l): def hook_macro(self, l):
l = l.rstrip() l = l.rstrip()
ls = l.lstrip() ls = l.lstrip()
ws = l[:len(l)-len(ls)] # just leading whitespace ws = l[:len(l) - len(ls)] # just leading whitespace
if len(ws) == 0: if len(ws) == 0:
self.end_macro() self.end_macro()
# pass the unprocessed line to regular command processor to not require empty line in .pronsolerc # pass the unprocessed line to regular command processor to not require empty line in .pronsolerc
...@@ -505,19 +514,19 @@ class pronsole(cmd.Cmd): ...@@ -505,19 +514,19 @@ class pronsole(cmd.Cmd):
self.cur_macro_def += l + "\n" self.cur_macro_def += l + "\n"
def end_macro(self): def end_macro(self):
if self.__dict__.has_key("onecmd"): del self.onecmd # remove override if "onecmd" in self.__dict__: del self.onecmd # remove override
self.in_macro = False self.in_macro = False
self.prompt = self.promptf() self.prompt = self.promptf()
if self.cur_macro_def!="": if self.cur_macro_def != "":
self.macros[self.cur_macro_name] = self.cur_macro_def self.macros[self.cur_macro_name] = self.cur_macro_def
macro = self.compile_macro(self.cur_macro_name, self.cur_macro_def) macro = self.compile_macro(self.cur_macro_name, self.cur_macro_def)
setattr(self.__class__, "do_"+self.cur_macro_name, lambda self, largs, macro = macro:macro(self,*largs.split())) setattr(self.__class__, "do_" + self.cur_macro_name, lambda self, largs, macro = macro: macro(self, *largs.split()))
setattr(self.__class__, "help_"+self.cur_macro_name, lambda self, macro_name = self.cur_macro_name: self.subhelp_macro(macro_name)) setattr(self.__class__, "help_" + self.cur_macro_name, lambda self, macro_name = self.cur_macro_name: self.subhelp_macro(macro_name))
if not self.processing_rc: if not self.processing_rc:
self.log("Macro '"+self.cur_macro_name+"' defined") self.log("Macro '" + self.cur_macro_name + "' defined")
# save it # save it
if not self.processing_args: if not self.processing_args:
macro_key = "macro "+self.cur_macro_name macro_key = "macro " + self.cur_macro_name
macro_def = macro_key macro_def = macro_key
if "\n" in self.cur_macro_def: if "\n" in self.cur_macro_def:
macro_def += "\n" macro_def += "\n"
...@@ -535,14 +544,14 @@ class pronsole(cmd.Cmd): ...@@ -535,14 +544,14 @@ class pronsole(cmd.Cmd):
def compile_macro_line(self, line): def compile_macro_line(self, line):
line = line.rstrip() line = line.rstrip()
ls = line.lstrip() ls = line.lstrip()
ws = line[:len(line)-len(ls)] # just leading whitespace ws = line[:len(line) - len(ls)] # just leading whitespace
if ls == "" or ls.startswith('#'): return "" # no code if ls == "" or ls.startswith('#'): return "" # no code
if ls.startswith('!'): if ls.startswith('!'):
return ws + ls[1:] + "\n" # python mode return ws + ls[1:] + "\n" # python mode
else: else:
ls = ls.replace('"','\\"') # need to escape double quotes ls = ls.replace('"', '\\"') # need to escape double quotes
ret = ws + 'self.parseusercmd("'+ls+'".format(*arg))\n' # parametric command mode ret = ws + 'self.parseusercmd("' + ls + '".format(*arg))\n' # parametric command mode
return ret + ws + 'self.onecmd("'+ls+'".format(*arg))\n' return ret + ws + 'self.onecmd("' + ls + '".format(*arg))\n'
def compile_macro(self, macro_name, macro_def): def compile_macro(self, macro_name, macro_def):
if macro_def.strip() == "": if macro_def.strip() == "":
...@@ -550,7 +559,7 @@ class pronsole(cmd.Cmd): ...@@ -550,7 +559,7 @@ class pronsole(cmd.Cmd):
return return
pycode = "def macro(self,*arg):\n" pycode = "def macro(self,*arg):\n"
if "\n" not in macro_def.strip(): if "\n" not in macro_def.strip():
pycode += self.compile_macro_line(" "+macro_def.strip()) pycode += self.compile_macro_line(" " + macro_def.strip())
else: else:
lines = macro_def.split("\n") lines = macro_def.split("\n")
for l in lines: for l in lines:
...@@ -569,21 +578,22 @@ class pronsole(cmd.Cmd): ...@@ -569,21 +578,22 @@ class pronsole(cmd.Cmd):
def delete_macro(self, macro_name): def delete_macro(self, macro_name):
if macro_name in self.macros.keys(): if macro_name in self.macros.keys():
delattr(self.__class__, "do_"+macro_name) delattr(self.__class__, "do_" + macro_name)
del self.macros[macro_name] del self.macros[macro_name]
self.log("Macro '"+macro_name+"' removed") self.log("Macro '" + macro_name + "' removed")
if not self.processing_rc and not self.processing_args: if not self.processing_rc and not self.processing_args:
self.save_in_rc("macro "+macro_name, "") self.save_in_rc("macro " + macro_name, "")
else: else:
self.logError("Macro '"+macro_name+"' is not defined") self.logError("Macro '" + macro_name + "' is not defined")
def do_macro(self, args): def do_macro(self, args):
if args.strip()=="": if args.strip() == "":
self.print_topics("User-defined macros", map(str,self.macros.keys()), 15, 80) self.print_topics("User-defined macros", map(str, self.macros.keys()), 15, 80)
return return
arglist = args.split(None, 1) arglist = args.split(None, 1)
macro_name = arglist[0] macro_name = arglist[0]
if macro_name not in self.macros and hasattr(self.__class__, "do_"+macro_name): if macro_name not in self.macros and hasattr(self.__class__, "do_" + macro_name):
self.logError("Name '"+macro_name+"' is being used by built-in command") self.logError("Name '" + macro_name + "' is being used by built-in command")
return return
if len(arglist) == 2: if len(arglist) == 2:
macro_def = arglist[1] macro_def = arglist[1]
...@@ -597,7 +607,7 @@ class pronsole(cmd.Cmd): ...@@ -597,7 +607,7 @@ class pronsole(cmd.Cmd):
self.cur_macro_name = macro_name self.cur_macro_name = macro_name
self.end_macro() self.end_macro()
return return
if self.macros.has_key(macro_name): if macro_name in self.macros:
self.start_macro(macro_name, self.macros[macro_name]) self.start_macro(macro_name, self.macros[macro_name])
else: else:
self.start_macro(macro_name) self.start_macro(macro_name)
...@@ -615,19 +625,19 @@ class pronsole(cmd.Cmd): ...@@ -615,19 +625,19 @@ class pronsole(cmd.Cmd):
if macro_name in self.macros.keys(): if macro_name in self.macros.keys():
macro_def = self.macros[macro_name] macro_def = self.macros[macro_name]
if "\n" in macro_def: if "\n" in macro_def:
self.log("Macro '"+macro_name+"' defined as:") self.log("Macro '" + macro_name + "' defined as:")
self.log(self.macros[macro_name]+"----------------") self.log(self.macros[macro_name] + "----------------")
else: else:
self.log("Macro '"+macro_name+"' defined as: '"+macro_def+"'") self.log("Macro '" + macro_name + "' defined as: '" + macro_def + "'")
else: else:
self.logError("Macro '"+macro_name+"' is not defined") self.logError("Macro '" + macro_name + "' is not defined")
def set(self, var, str): def set(self, var, str):
try: try:
t = type(getattr(self.settings, var)) t = type(getattr(self.settings, var))
value = self.settings._set(var, str) value = self.settings._set(var, str)
if not self.processing_rc and not self.processing_args: if not self.processing_rc and not self.processing_args:
self.save_in_rc("set "+var, "set %s %s" % (var, value)) self.save_in_rc("set " + var, "set %s %s" % (var, value))
except AttributeError: except AttributeError:
self.logError("Unknown variable '%s'" % var) self.logError("Unknown variable '%s'" % var)
except ValueError, ve: except ValueError, ve:
...@@ -639,7 +649,6 @@ class pronsole(cmd.Cmd): ...@@ -639,7 +649,6 @@ class pronsole(cmd.Cmd):
for k in [kk for kk in dir(self.settings) if not kk.startswith("_")]: for k in [kk for kk in dir(self.settings) if not kk.startswith("_")]:
self.log("%s = %s" % (k, str(getattr(self.settings, k)))) self.log("%s = %s" % (k, str(getattr(self.settings, k))))
return return
value = getattr(self.settings, args[0])
if len(args) < 2: if len(args) < 2:
try: try:
self.log("%s = %s" % (args[0], getattr(self.settings, args[0]))) self.log("%s = %s" % (args[0], getattr(self.settings, args[0])))
...@@ -654,9 +663,9 @@ class pronsole(cmd.Cmd): ...@@ -654,9 +663,9 @@ class pronsole(cmd.Cmd):
self.log("'set' without arguments displays all variables") self.log("'set' without arguments displays all variables")
def complete_set(self, text, line, begidx, endidx): def complete_set(self, text, line, begidx, endidx):
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "): if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1] == " "):
return [i for i in dir(self.settings) if not i.startswith("_") and i.startswith(text)] return [i for i in dir(self.settings) if not i.startswith("_") and i.startswith(text)]
elif(len(line.split()) == 3 or (len(line.split()) == 2 and line[-1]==" ")): elif(len(line.split()) == 3 or (len(line.split()) == 2 and line[-1] == " ")):
return [i for i in self.settings._tabcomplete(line.split()[1]) if i.startswith(text)] return [i for i in self.settings._tabcomplete(line.split()[1]) if i.startswith(text)]
else: else:
return [] return []
...@@ -681,8 +690,8 @@ class pronsole(cmd.Cmd): ...@@ -681,8 +690,8 @@ class pronsole(cmd.Cmd):
self.processing_rc = False self.processing_rc = False
def load_default_rc(self, rc_filename = ".pronsolerc"): def load_default_rc(self, rc_filename = ".pronsolerc"):
if rc_filename == ".pronsolerc" and hasattr(sys,"frozen") and sys.frozen in ["windows_exe", "console_exe"]: if rc_filename == ".pronsolerc" and hasattr(sys, "frozen") and sys.frozen in ["windows_exe", "console_exe"]:
rc_filename="printrunconf.ini" rc_filename = "printrunconf.ini"
try: try:
try: try:
self.load_rc(os.path.join(os.path.expanduser("~"), rc_filename)) self.load_rc(os.path.join(os.path.expanduser("~"), rc_filename))
...@@ -711,18 +720,18 @@ class pronsole(cmd.Cmd): ...@@ -711,18 +720,18 @@ class pronsole(cmd.Cmd):
written = False written = False
if os.path.exists(self.rc_filename): if os.path.exists(self.rc_filename):
import shutil import shutil
shutil.copy(self.rc_filename, self.rc_filename+"~bak") shutil.copy(self.rc_filename, self.rc_filename + "~bak")
rci = codecs.open(self.rc_filename+"~bak", "r", "utf-8") rci = codecs.open(self.rc_filename + "~bak", "r", "utf-8")
rco = codecs.open(self.rc_filename, "w", "utf-8") rco = codecs.open(self.rc_filename, "w", "utf-8")
if rci is not None: if rci is not None:
overwriting = False overwriting = False
for rc_cmd in rci: for rc_cmd in rci:
l = rc_cmd.rstrip() l = rc_cmd.rstrip()
ls = l.lstrip() ls = l.lstrip()
ws = l[:len(l)-len(ls)] # just leading whitespace ws = l[:len(l) - len(ls)] # just leading whitespace
if overwriting and len(ws) == 0: if overwriting and len(ws) == 0:
overwriting = False overwriting = False
if not written and key != "" and rc_cmd.startswith(key) and (rc_cmd+"\n")[len(key)].isspace(): if not written and key != "" and rc_cmd.startswith(key) and (rc_cmd + "\n")[len(key)].isspace():
overwriting = True overwriting = True
written = True written = True
rco.write(definition) rco.write(definition)
...@@ -739,7 +748,7 @@ class pronsole(cmd.Cmd): ...@@ -739,7 +748,7 @@ class pronsole(cmd.Cmd):
#else: #else:
# self.log("Removed '"+key+"' from '"+self.rc_filename+"'") # self.log("Removed '"+key+"' from '"+self.rc_filename+"'")
except Exception, e: except Exception, e:
self.logError("Saving failed for ", key+":", str(e)) self.logError("Saving failed for ", key + ":", str(e))
finally: finally:
del rci, rco del rci, rco
...@@ -752,16 +761,16 @@ class pronsole(cmd.Cmd): ...@@ -752,16 +761,16 @@ class pronsole(cmd.Cmd):
a = l.split() a = l.split()
p = self.scanserial() p = self.scanserial()
port = self.settings.port port = self.settings.port
if (port == "" or port not in p) and len(p)>0: if (port == "" or port not in p) and len(p) > 0:
port = p[0] port = p[0]
baud = self.settings.baudrate or 115200 baud = self.settings.baudrate or 115200
if(len(a)>0): if len(a) > 0:
port = a[0] port = a[0]
if(len(a)>1): if len(a) > 1:
try: try:
baud = int(a[1]) baud = int(a[1])
except: except:
self.log("Bad baud value '"+a[1]+"' ignored") self.log("Bad baud value '" + a[1] + "' ignored")
if len(p) == 0 and not port: if len(p) == 0 and not port:
self.log("No serial ports detected - please specify a port") self.log("No serial ports detected - please specify a port")
return return
...@@ -786,9 +795,9 @@ class pronsole(cmd.Cmd): ...@@ -786,9 +795,9 @@ class pronsole(cmd.Cmd):
self.log("No serial ports were automatically found.") self.log("No serial ports were automatically found.")
def complete_connect(self, text, line, begidx, endidx): def complete_connect(self, text, line, begidx, endidx):
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "): if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1] == " "):
return [i for i in self.scanserial() if i.startswith(text)] return [i for i in self.scanserial() if i.startswith(text)]
elif(len(line.split()) == 3 or (len(line.split()) == 2 and line[-1]==" ")): elif(len(line.split()) == 3 or (len(line.split()) == 2 and line[-1] == " ")):
return [i for i in ["2400", "9600", "19200", "38400", "57600", "115200"] if i.startswith(text)] return [i for i in ["2400", "9600", "19200", "38400", "57600", "115200"] if i.startswith(text)]
else: else:
return [] return []
...@@ -816,13 +825,13 @@ class pronsole(cmd.Cmd): ...@@ -816,13 +825,13 @@ class pronsole(cmd.Cmd):
def complete_load(self, text, line, begidx, endidx): def complete_load(self, text, line, begidx, endidx):
s = line.split() s = line.split()
if len(s)>2: if len(s) > 2:
return [] return []
if (len(s) == 1 and line[-1]==" ") or (len(s) == 2 and line[-1]!=" "): if (len(s) == 1 and line[-1] == " ") or (len(s) == 2 and line[-1] != " "):
if len(s)>1: if len(s) > 1:
return [i[len(s[1])-len(text):] for i in glob.glob(s[1]+"*/")+glob.glob(s[1]+"*.g*")] return [i[len(s[1]) - len(text):] for i in glob.glob(s[1] + "*/") + glob.glob(s[1] + "*.g*")]
else: else:
return glob.glob("*/")+glob.glob("*.g*") return glob.glob("*/") + glob.glob("*.g*")
def help_load(self): def help_load(self):
self.log("Loads a gcode file (with tab-completion)") self.log("Loads a gcode file (with tab-completion)")
...@@ -850,9 +859,9 @@ class pronsole(cmd.Cmd): ...@@ -850,9 +859,9 @@ class pronsole(cmd.Cmd):
time.sleep(1) time.sleep(1)
while self.p.printing: while self.p.printing:
time.sleep(1) time.sleep(1)
sys.stdout.write("\b\b\b\b\b%04.1f%%" % (100*float(self.p.queueindex)/len(self.p.mainqueue),)) sys.stdout.write("\b\b\b\b\b%04.1f%%" % (100 * float(self.p.queueindex) / len(self.p.mainqueue),))
sys.stdout.flush() sys.stdout.flush()
self.p.send_now("M29 "+tname) self.p.send_now("M29 " + targetname)
self.sleep(0.2) self.sleep(0.2)
self.p.clear = 1 self.p.clear = 1
self._do_ls(False) self._do_ls(False)
...@@ -862,7 +871,7 @@ class pronsole(cmd.Cmd): ...@@ -862,7 +871,7 @@ class pronsole(cmd.Cmd):
except: except:
self.logError(_("...interrupted!")) self.logError(_("...interrupted!"))
self.p.pause() self.p.pause()
self.p.send_now("M29 "+targetname) self.p.send_now("M29 " + targetname)
time.sleep(0.2) time.sleep(0.2)
self.p.clear = 1 self.p.clear = 1
self.p.startprint(None) self.p.startprint(None)
...@@ -870,13 +879,13 @@ class pronsole(cmd.Cmd): ...@@ -870,13 +879,13 @@ class pronsole(cmd.Cmd):
def complete_upload(self, text, line, begidx, endidx): def complete_upload(self, text, line, begidx, endidx):
s = line.split() s = line.split()
if len(s)>2: if len(s) > 2:
return [] return []
if (len(s) == 1 and line[-1]==" ") or (len(s) == 2 and line[-1]!=" "): if (len(s) == 1 and line[-1] == " ") or (len(s) == 2 and line[-1] != " "):
if len(s)>1: if len(s) > 1:
return [i[len(s[1])-len(text):] for i in glob.glob(s[1]+"*/")+glob.glob(s[1]+"*.g*")] return [i[len(s[1]) - len(text):] for i in glob.glob(s[1] + "*/") + glob.glob(s[1] + "*.g*")]
else: else:
return glob.glob("*/")+glob.glob("*.g*") return glob.glob("*/") + glob.glob("*.g*")
def help_upload(self): def help_upload(self):
self.log("Uploads a gcode file to the sd card") self.log("Uploads a gcode file to the sd card")
...@@ -985,7 +994,7 @@ class pronsole(cmd.Cmd): ...@@ -985,7 +994,7 @@ class pronsole(cmd.Cmd):
try: try:
resp = l.split() resp = l.split()
vals = resp[-1].split("/") vals = resp[-1].split("/")
self.percentdone = 100.0*int(vals[0])/int(vals[1]) self.percentdone = 100.0 * int(vals[0]) / int(vals[1])
except: except:
pass pass
...@@ -1020,7 +1029,7 @@ class pronsole(cmd.Cmd): ...@@ -1020,7 +1029,7 @@ class pronsole(cmd.Cmd):
self._do_ls(False) self._do_ls(False)
while self.listfiles in self.recvlisteners: while self.listfiles in self.recvlisteners:
time.sleep(0.1) time.sleep(0.1)
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "): if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1] == " "):
return [i for i in self.sdfiles if i.startswith(text)] return [i for i in self.sdfiles if i.startswith(text)]
def recvcb(self, l): def recvcb(self, l):
...@@ -1031,7 +1040,7 @@ class pronsole(cmd.Cmd): ...@@ -1031,7 +1040,7 @@ class pronsole(cmd.Cmd):
if tstring != "ok" and not self.listing and not self.monitoring: if tstring != "ok" and not self.listing and not self.monitoring:
if tstring[:5] == "echo:": if tstring[:5] == "echo:":
tstring = tstring[5:].lstrip() tstring = tstring[5:].lstrip()
if self.silent == False: print "\r" + tstring.ljust(15) if self.silent is False: print "\r" + tstring.ljust(15)
sys.stdout.write(self.promptf()) sys.stdout.write(self.promptf())
sys.stdout.flush() sys.stdout.flush()
for i in self.recvlisteners: for i in self.recvlisteners:
...@@ -1045,7 +1054,7 @@ class pronsole(cmd.Cmd): ...@@ -1045,7 +1054,7 @@ class pronsole(cmd.Cmd):
if l[0] in self.commandprefixes.upper(): if l[0] in self.commandprefixes.upper():
if self.p and self.p.online: if self.p and self.p.online:
if not self.p.loud: if not self.p.loud:
self.log("SENDING:"+l) self.log("SENDING:" + l)
self.p.send_now(l) self.p.send_now(l)
else: else:
self.logError(_("Printer is not online.")) self.logError(_("Printer is not online."))
...@@ -1053,7 +1062,7 @@ class pronsole(cmd.Cmd): ...@@ -1053,7 +1062,7 @@ class pronsole(cmd.Cmd):
elif l[0] in self.commandprefixes.lower(): elif l[0] in self.commandprefixes.lower():
if self.p and self.p.online: if self.p and self.p.online:
if not self.p.loud: if not self.p.loud:
self.log("SENDING:"+l.upper()) self.log("SENDING:" + l.upper())
self.p.send_now(l.upper()) self.p.send_now(l.upper())
else: else:
self.logError(_("Printer is not online.")) self.logError(_("Printer is not online."))
...@@ -1061,17 +1070,14 @@ class pronsole(cmd.Cmd): ...@@ -1061,17 +1070,14 @@ class pronsole(cmd.Cmd):
elif l[0] == "@": elif l[0] == "@":
if self.p and self.p.online: if self.p and self.p.online:
if not self.p.loud: if not self.p.loud:
self.log("SENDING:"+l[1:]) self.log("SENDING:" + l[1:])
self.p.send_now(l[1:]) self.p.send_now(l[1:])
else: else:
self.logError("printer is not online.") self.logError(_("Printer is not online."))
return return
else: else:
cmd.Cmd.default(self, l) cmd.Cmd.default(self, l)
def help_help(self):
self.do_help("")
def tempcb(self, l): def tempcb(self, l):
if "T:" in l: if "T:" in l:
self.log(l.strip().replace("T", "Hotend").replace("B", "Bed").replace("ok ", "")) self.log(l.strip().replace("T", "Hotend").replace("B", "Bed").replace("ok ", ""))
...@@ -1092,7 +1098,7 @@ class pronsole(cmd.Cmd): ...@@ -1092,7 +1098,7 @@ class pronsole(cmd.Cmd):
self.log(_("Read the extruder and bed temperature.")) self.log(_("Read the extruder and bed temperature."))
def do_settemp(self, l): def do_settemp(self, l):
l = l.lower().replace(", ",".") l = l.lower().replace(", ", ".")
for i in self.temps.keys(): for i in self.temps.keys():
l = l.replace(i, self.temps[i]) l = l.replace(i, self.temps[i])
try: try:
...@@ -1101,13 +1107,13 @@ class pronsole(cmd.Cmd): ...@@ -1101,13 +1107,13 @@ class pronsole(cmd.Cmd):
self.logError(_("You must enter a temperature.")) self.logError(_("You must enter a temperature."))
return return
if f>=0: if f >= 0:
if f > 250: if f > 250:
print _("%s is a high temperature to set your extruder to. Are you sure you want to do that?") % f print _("%s is a high temperature to set your extruder to. Are you sure you want to do that?") % f
if not self.confirm(): if not self.confirm():
return return
if self.p.online: if self.p.online:
self.p.send_now("M104 S"+l) self.p.send_now("M104 S" + l)
self.log(_("Setting hotend temperature to %s degrees Celsius.") % f) self.log(_("Setting hotend temperature to %s degrees Celsius.") % f)
else: else:
self.logError(_("Printer is not online.")) self.logError(_("Printer is not online."))
...@@ -1117,16 +1123,16 @@ class pronsole(cmd.Cmd): ...@@ -1117,16 +1123,16 @@ class pronsole(cmd.Cmd):
def help_settemp(self): def help_settemp(self):
self.log(_("Sets the hotend temperature to the value entered.")) self.log(_("Sets the hotend temperature to the value entered."))
self.log(_("Enter either a temperature in celsius or one of the following keywords")) self.log(_("Enter either a temperature in celsius or one of the following keywords"))
self.log(", ".join([i+"("+self.temps[i]+")" for i in self.temps.keys()])) self.log(", ".join([i + "(" + self.temps[i] + ")" for i in self.temps.keys()]))
def complete_settemp(self, text, line, begidx, endidx): def complete_settemp(self, text, line, begidx, endidx):
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "): if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1] == " "):
return [i for i in self.temps.keys() if i.startswith(text)] return [i for i in self.temps.keys() if i.startswith(text)]
def do_bedtemp(self, l): def do_bedtemp(self, l):
f = None f = None
try: try:
l = l.lower().replace(", ",".") l = l.lower().replace(", ", ".")
for i in self.bedtemps.keys(): for i in self.bedtemps.keys():
l = l.replace(i, self.bedtemps[i]) l = l.replace(i, self.bedtemps[i])
f = float(l) f = float(l)
...@@ -1144,14 +1150,14 @@ class pronsole(cmd.Cmd): ...@@ -1144,14 +1150,14 @@ class pronsole(cmd.Cmd):
def help_bedtemp(self): def help_bedtemp(self):
self.log(_("Sets the bed temperature to the value entered.")) self.log(_("Sets the bed temperature to the value entered."))
self.log(_("Enter either a temperature in celsius or one of the following keywords")) self.log(_("Enter either a temperature in celsius or one of the following keywords"))
self.log(", ".join([i+"("+self.bedtemps[i]+")" for i in self.bedtemps.keys()])) self.log(", ".join([i + "(" + self.bedtemps[i] + ")" for i in self.bedtemps.keys()]))
def complete_bedtemp(self, text, line, begidx, endidx): def complete_bedtemp(self, text, line, begidx, endidx):
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "): if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1] == " "):
return [i for i in self.bedtemps.keys() if i.startswith(text)] return [i for i in self.bedtemps.keys() if i.startswith(text)]
def do_move(self, l): def do_move(self, l):
if(len(l.split())<2): if(len(l.split()) < 2):
self.logError(_("No move specified.")) self.logError(_("No move specified."))
return return
if self.p.printing: if self.p.printing:
...@@ -1161,24 +1167,23 @@ class pronsole(cmd.Cmd): ...@@ -1161,24 +1167,23 @@ class pronsole(cmd.Cmd):
self.logError(_("Printer is not online. Unable to move.")) self.logError(_("Printer is not online. Unable to move."))
return return
l = l.split() l = l.split()
if(l[0].lower()=="x"): if(l[0].lower() == "x"):
feed = self.settings.xy_feedrate feed = self.settings.xy_feedrate
axis = "X" axis = "X"
elif(l[0].lower()=="y"): elif(l[0].lower() == "y"):
feed = self.settings.xy_feedrate feed = self.settings.xy_feedrate
axis = "Y" axis = "Y"
elif(l[0].lower()=="z"): elif(l[0].lower() == "z"):
feed = self.settings.z_feedrate feed = self.settings.z_feedrate
axis = "Z" axis = "Z"
elif(l[0].lower()=="e"): elif(l[0].lower() == "e"):
feed = self.settings.e_feedrate feed = self.settings.e_feedrate
axis = "E" axis = "E"
else: else:
self.logError(_("Unknown axis.")) self.logError(_("Unknown axis."))
return return
dist = 0
try: try:
dist = float(l[1]) float(l[1]) # check if distance can be a float
except: except:
self.logError(_("Invalid distance")) self.logError(_("Invalid distance"))
return return
...@@ -1187,7 +1192,7 @@ class pronsole(cmd.Cmd): ...@@ -1187,7 +1192,7 @@ class pronsole(cmd.Cmd):
except: except:
pass pass
self.p.send_now("G91") self.p.send_now("G91")
self.p.send_now("G1 "+axis+str(l[1])+" F"+str(feed)) self.p.send_now("G1 " + axis + str(l[1]) + " F" + str(feed))
self.p.send_now("G90") self.p.send_now("G90")
def help_move(self): def help_move(self):
...@@ -1198,22 +1203,22 @@ class pronsole(cmd.Cmd): ...@@ -1198,22 +1203,22 @@ class pronsole(cmd.Cmd):
self.log(_("Common amounts are in the tabcomplete list.")) self.log(_("Common amounts are in the tabcomplete list."))
def complete_move(self, text, line, begidx, endidx): def complete_move(self, text, line, begidx, endidx):
if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1]==" "): if (len(line.split()) == 2 and line[-1] != " ") or (len(line.split()) == 1 and line[-1] == " "):
return [i for i in ["X ", "Y ", "Z ", "E "] if i.lower().startswith(text)] return [i for i in ["X ", "Y ", "Z ", "E "] if i.lower().startswith(text)]
elif(len(line.split()) == 3 or (len(line.split()) == 2 and line[-1]==" ")): elif(len(line.split()) == 3 or (len(line.split()) == 2 and line[-1] == " ")):
base = line.split()[-1] base = line.split()[-1]
rlen = 0 rlen = 0
if base.startswith("-"): if base.startswith("-"):
rlen = 1 rlen = 1
if line[-1]==" ": if line[-1] == " ":
base = "" base = ""
return [i[rlen:] for i in ["-100", "-10", "-1", "-0.1", "100", "10", "1", "0.1", "-50", "-5", "-0.5", "50", "5", "0.5", "-200", "-20", "-2", "-0.2", "200", "20", "2", "0.2"] if i.startswith(base)] return [i[rlen:] for i in ["-100", "-10", "-1", "-0.1", "100", "10", "1", "0.1", "-50", "-5", "-0.5", "50", "5", "0.5", "-200", "-20", "-2", "-0.2", "200", "20", "2", "0.2"] if i.startswith(base)]
else: else:
return [] return []
def do_extrude(self, l, override = None, overridefeed = 300): def do_extrude(self, l, override = None, overridefeed = 300):
length = 5#default extrusion length length = 5 # default extrusion length
feed = self.settings.e_feedrate#default speed feed = self.settings.e_feedrate # default speed
if not self.p.online: if not self.p.online:
self.logError("Printer is not online. Unable to extrude.") self.logError("Printer is not online. Unable to extrude.")
return return
...@@ -1226,7 +1231,7 @@ class pronsole(cmd.Cmd): ...@@ -1226,7 +1231,7 @@ class pronsole(cmd.Cmd):
length = float(ls[0]) length = float(ls[0])
except: except:
self.logError(_("Invalid length given.")) self.logError(_("Invalid length given."))
if len(ls)>1: if len(ls) > 1:
try: try:
feed = int(ls[1]) feed = int(ls[1])
except: except:
...@@ -1237,11 +1242,11 @@ class pronsole(cmd.Cmd): ...@@ -1237,11 +1242,11 @@ class pronsole(cmd.Cmd):
if length > 0: if length > 0:
self.log(_("Extruding %fmm of filament.") % (length,)) self.log(_("Extruding %fmm of filament.") % (length,))
elif length < 0: elif length < 0:
self.log(_("Reversing %fmm of filament.") % (-1*length,)) self.log(_("Reversing %fmm of filament.") % (-length,))
else: else:
self.log(_("Length is 0, not doing anything.")) self.log(_("Length is 0, not doing anything."))
self.p.send_now("G91") self.p.send_now("G91")
self.p.send_now("G1 E"+str(length)+" F"+str(feed)) self.p.send_now("G1 E" + str(length) + " F" + str(feed))
self.p.send_now("G90") self.p.send_now("G90")
def help_extrude(self): def help_extrude(self):
...@@ -1252,8 +1257,8 @@ class pronsole(cmd.Cmd): ...@@ -1252,8 +1257,8 @@ class pronsole(cmd.Cmd):
self.log(_("extrude 10 210 - extrudes 10mm of filament at 210mm/min (3.5mm/s)")) self.log(_("extrude 10 210 - extrudes 10mm of filament at 210mm/min (3.5mm/s)"))
def do_reverse(self, l): def do_reverse(self, l):
length = 5#default extrusion length length = 5 # default extrusion length
feed = self.settings.e_feedrate#default speed feed = self.settings.e_feedrate # default speed
if not self.p.online: if not self.p.online:
self.logError(_("Printer is not online. Unable to reverse.")) self.logError(_("Printer is not online. Unable to reverse."))
return return
...@@ -1266,12 +1271,12 @@ class pronsole(cmd.Cmd): ...@@ -1266,12 +1271,12 @@ class pronsole(cmd.Cmd):
length = float(ls[0]) length = float(ls[0])
except: except:
self.logError(_("Invalid length given.")) self.logError(_("Invalid length given."))
if len(ls)>1: if len(ls) > 1:
try: try:
feed = int(ls[1]) feed = int(ls[1])
except: except:
self.logError(_("Invalid speed given.")) self.logError(_("Invalid speed given."))
self.do_extrude("", length*-1.0, feed) self.do_extrude("", -length, feed)
def help_reverse(self): def help_reverse(self):
self.log(_("Reverses the extruder, 5mm by default, or the number of mm given as a parameter")) self.log(_("Reverses the extruder, 5mm by default, or the number of mm given as a parameter"))
...@@ -1327,18 +1332,17 @@ class pronsole(cmd.Cmd): ...@@ -1327,18 +1332,17 @@ class pronsole(cmd.Cmd):
#print (self.tempreadings.replace("\r", "").replace("T", "Hotend").replace("B", "Bed").replace("\n", "").replace("ok ", "")) #print (self.tempreadings.replace("\r", "").replace("T", "Hotend").replace("B", "Bed").replace("\n", "").replace("ok ", ""))
if self.p.printing: if self.p.printing:
preface = _("Print progress: ") preface = _("Print progress: ")
progress = 100*float(self.p.queueindex)/len(self.p.mainqueue) progress = 100 * float(self.p.queueindex) / len(self.p.mainqueue)
elif self.sdprinting: elif self.sdprinting:
preface = _("Print progress: ") preface = _("Print progress: ")
progress = self.percentdone progress = self.percentdone
progress = int(progress*10)/10.0 #limit precision prev_msg = preface + "%.1f%%" % progress
prev_msg = preface + str(progress) + "%" if self.silent is False:
if self.silent == False:
sys.stdout.write("\r" + prev_msg.ljust(prev_msg_len)) sys.stdout.write("\r" + prev_msg.ljust(prev_msg_len))
sys.stdout.flush() sys.stdout.flush()
prev_msg_len = len(prev_msg) prev_msg_len = len(prev_msg)
except KeyboardInterrupt: except KeyboardInterrupt:
if self.silent == False: print _("Done monitoring.") if self.silent is False: print _("Done monitoring.")
self.monitoring = 0 self.monitoring = 0
def help_monitor(self): def help_monitor(self):
...@@ -1355,7 +1359,7 @@ class pronsole(cmd.Cmd): ...@@ -1355,7 +1359,7 @@ class pronsole(cmd.Cmd):
self.logError(_("No file name given.")) self.logError(_("No file name given."))
return return
settings = 0 settings = 0
if(l[0]=="set"): if l[0] == "set":
settings = 1 settings = 1
else: else:
self.log(_("Skeining file: %s") % l[0]) self.log(_("Skeining file: %s") % l[0])
...@@ -1379,13 +1383,13 @@ class pronsole(cmd.Cmd): ...@@ -1379,13 +1383,13 @@ class pronsole(cmd.Cmd):
def complete_skein(self, text, line, begidx, endidx): def complete_skein(self, text, line, begidx, endidx):
s = line.split() s = line.split()
if len(s)>2: if len(s) > 2:
return [] return []
if (len(s) == 1 and line[-1]==" ") or (len(s) == 2 and line[-1]!=" "): if (len(s) == 1 and line[-1] == " ") or (len(s) == 2 and line[-1] != " "):
if len(s)>1: if len(s) > 1:
return [i[len(s[1])-len(text):] for i in glob.glob(s[1]+"*/")+glob.glob(s[1]+"*.stl")] return [i[len(s[1]) - len(text):] for i in glob.glob(s[1] + "*/") + glob.glob(s[1] + "*.stl")]
else: else:
return glob.glob("*/")+glob.glob("*.stl") return glob.glob("*/") + glob.glob("*.stl")
def help_skein(self): def help_skein(self):
self.log(_("Creates a gcode file from an stl model using the slicer (with tab-completion)")) self.log(_("Creates a gcode file from an stl model using the slicer (with tab-completion)"))
...@@ -1443,8 +1447,8 @@ class pronsole(cmd.Cmd): ...@@ -1443,8 +1447,8 @@ class pronsole(cmd.Cmd):
self.log(_("Turns off everything on the printer")) self.log(_("Turns off everything on the printer"))
def add_cmdline_arguments(self, parser): def add_cmdline_arguments(self, parser):
parser.add_argument('-c','--conf','--config', help = _("load this file on startup instead of .pronsolerc ; you may chain config files, if so settings auto-save will use the last specified file"), action = "append", default = []) parser.add_argument('-c', '--conf', '--config', help = _("load this file on startup instead of .pronsolerc ; you may chain config files, if so settings auto-save will use the last specified file"), action = "append", default = [])
parser.add_argument('-e','--execute', help = _("executes command after configuration/.pronsolerc is loaded ; macros/settings from these commands are not autosaved"), action = "append", default = []) parser.add_argument('-e', '--execute', help = _("executes command after configuration/.pronsolerc is loaded ; macros/settings from these commands are not autosaved"), action = "append", default = [])
parser.add_argument('filename', nargs='?', help = _("file to load")) parser.add_argument('filename', nargs='?', help = _("file to load"))
def process_cmdline_arguments(self, args): def process_cmdline_arguments(self, args):
...@@ -1487,14 +1491,14 @@ class pronsole(cmd.Cmd): ...@@ -1487,14 +1491,14 @@ class pronsole(cmd.Cmd):
import readline import readline
self.old_completer = readline.get_completer() self.old_completer = readline.get_completer()
readline.set_completer(self.complete) readline.set_completer(self.complete)
readline.parse_and_bind(self.completekey+": complete") readline.parse_and_bind(self.completekey + ": complete")
except ImportError: except ImportError:
pass pass
try: try:
if intro is not None: if intro is not None:
self.intro = intro self.intro = intro
if self.intro: if self.intro:
self.stdout.write(str(self.intro)+"\n") self.stdout.write(str(self.intro) + "\n")
stop = None stop = None
while not stop: while not stop:
if self.cmdqueue: if self.cmdqueue:
......
...@@ -15,7 +15,18 @@ ...@@ -15,7 +15,18 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>. # along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import os, Queue, re import os
import Queue
import re
import sys
import time
import datetime
import threading
import traceback
import cStringIO as StringIO
import subprocess
import shlex
import glob
from printrun.printrun_utils import install_locale, RemainingTimeEstimator from printrun.printrun_utils import install_locale, RemainingTimeEstimator
install_locale('pronterface') install_locale('pronterface')
...@@ -25,25 +36,17 @@ try: ...@@ -25,25 +36,17 @@ try:
except: except:
print _("WX is not installed. This program requires WX to run.") print _("WX is not installed. This program requires WX to run.")
raise raise
import sys, glob, time, datetime, threading, traceback, cStringIO, subprocess
import shlex
from printrun.pronterface_widgets import * from printrun.pronterface_widgets import SpecialButton, MacroEditor, \
PronterOptions, ButtonEdit
from serial import SerialException from serial import SerialException
StringIO = cStringIO
winsize = (800, 500) winsize = (800, 500)
layerindex = 0 layerindex = 0
if os.name == "nt": if os.name == "nt":
winsize = (800, 530) winsize = (800, 530)
try:
import _winreg
except:
pass
import printcore from printrun.printrun_utils import iconfile, configfile
from printrun.printrun_utils import pixmapfile, configfile
from printrun.gui import MainWindow from printrun.gui import MainWindow
from printrun.excluder import Excluder from printrun.excluder import Excluder
import pronsole import pronsole
...@@ -67,8 +70,10 @@ class Tee(object): ...@@ -67,8 +70,10 @@ class Tee(object):
self.stdout = sys.stdout self.stdout = sys.stdout
sys.stdout = self sys.stdout = self
self.target = target self.target = target
def __del__(self): def __del__(self):
sys.stdout = self.stdout sys.stdout = self.stdout
def write(self, data): def write(self, data):
try: try:
self.target(data) self.target(data)
...@@ -79,6 +84,7 @@ class Tee(object): ...@@ -79,6 +84,7 @@ class Tee(object):
except: except:
pass pass
self.stdout.write(data) self.stdout.write(data)
def flush(self): def flush(self):
self.stdout.flush() self.stdout.flush()
...@@ -157,13 +163,6 @@ class BuildDimensionsSetting(wxSetting): ...@@ -157,13 +163,6 @@ class BuildDimensionsSetting(wxSetting):
values = [float(w.GetValue()) for w in self.widgets] values = [float(w.GetValue()) for w in self.widgets]
self.value = "%.02fx%.02fx%.02f%+.02f%+.02f%+.02f%+.02f%+.02f%+.02f" % tuple(values) self.value = "%.02fx%.02fx%.02f%+.02f%+.02f%+.02f%+.02f%+.02f%+.02f" % tuple(values)
class StringSetting(wxSetting):
def get_specific_widget(self, parent):
import wx
self.widget = wx.TextCtrl(parent, -1, str(self.value))
return self.widget
class ComboSetting(wxSetting): class ComboSetting(wxSetting):
def __init__(self, name, default, choices, label = None, help = None, group = None): def __init__(self, name, default, choices, label = None, help = None, group = None):
...@@ -178,8 +177,10 @@ class ComboSetting(wxSetting): ...@@ -178,8 +177,10 @@ class ComboSetting(wxSetting):
class PronterWindow(MainWindow, pronsole.pronsole): class PronterWindow(MainWindow, pronsole.pronsole):
_fgcode = None _fgcode = None
def _get_fgcode(self): def _get_fgcode(self):
return self._fgcode return self._fgcode
def _set_fgcode(self, value): def _set_fgcode(self, value):
self._fgcode = value self._fgcode = value
self.excluder = None self.excluder = None
...@@ -188,8 +189,9 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -188,8 +189,9 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.excluder_z_rel = None self.excluder_z_rel = None
fgcode = property(_get_fgcode, _set_fgcode) fgcode = property(_get_fgcode, _set_fgcode)
def __init__(self, filename = None, size = winsize): def __init__(self, app, filename = None, size = winsize):
pronsole.pronsole.__init__(self) pronsole.pronsole.__init__(self)
self.app = app
#default build dimensions are 200x200x100 with 0, 0, 0 in the corner of the bed and endstops at 0, 0 and 0 #default build dimensions are 200x200x100 with 0, 0, 0 in the corner of the bed and endstops at 0, 0 and 0
monitorsetting = BooleanSetting("monitor", False) monitorsetting = BooleanSetting("monitor", False)
monitorsetting.hidden = True monitorsetting.hidden = True
...@@ -198,8 +200,9 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -198,8 +200,9 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.settings._add(BooleanSetting("clamp_jogging", False, _("Clamp manual moves"), _("Prevent manual moves from leaving the specified build dimensions"), "Printer")) self.settings._add(BooleanSetting("clamp_jogging", False, _("Clamp manual moves"), _("Prevent manual moves from leaving the specified build dimensions"), "Printer"))
self.settings._add(StringSetting("bgcolor", "#FFFFFF", _("Background color"), _("Pronterface background color"), "UI")) self.settings._add(StringSetting("bgcolor", "#FFFFFF", _("Background color"), _("Pronterface background color"), "UI"))
self.settings._add(ComboSetting("uimode", "Standard", ["Standard", "Compact", "Tabbed"], _("Interface mode"), _("Standard interface is a one-page, three columns layout with controls/visualization/log\nCompact mode is a one-page, two columns layout with controls + log/visualization\nTabbed mode is a two-pages mode, where the first page shows controls and the second one shows visualization and log."), "UI")) self.settings._add(ComboSetting("uimode", "Standard", ["Standard", "Compact", "Tabbed"], _("Interface mode"), _("Standard interface is a one-page, three columns layout with controls/visualization/log\nCompact mode is a one-page, two columns layout with controls + log/visualization\nTabbed mode is a two-pages mode, where the first page shows controls and the second one shows visualization and log."), "UI"))
self.settings._add(BooleanSetting("viz3d", False, _("Enable 3D viewer"), _("Use 3D visualization instead of 2D layered visualization"), "UI")) self.settings._add(BooleanSetting("slic3rintegration", False, _("Enable Slic3r integration"), _("Add a menu to select Slic3r profiles directly from Pronterface"), "UI"))
self.settings._add(ComboSetting("mainviz", "2D", ["2D", "3D", "None"], _("Main visualization"), _("Select visualization for main window."), "UI")) self.settings._add(ComboSetting("mainviz", "2D", ["2D", "3D", "None"], _("Main visualization"), _("Select visualization for main window."), "UI"))
self.settings._add(BooleanSetting("viz3d", False, _("Use 3D in GCode viewer window"), _("Use 3D mode instead of 2D layered mode in the visualization window"), "UI"))
self.settings._add(BooleanSetting("tempgraph", True, _("Display temperature graph"), _("Display time-lapse temperature graph"), "UI")) self.settings._add(BooleanSetting("tempgraph", True, _("Display temperature graph"), _("Display time-lapse temperature graph"), "UI"))
self.settings._add(BooleanSetting("tempgauges", False, _("Display temperature gauges"), _("Display graphical gauges for temperatures visualization"), "UI")) self.settings._add(BooleanSetting("tempgauges", False, _("Display temperature gauges"), _("Display graphical gauges for temperatures visualization"), "UI"))
self.settings._add(BooleanSetting("lockbox", False, _("Display interface lock checkbox"), _("Display a checkbox that, when check, locks most of Pronterface"), "UI")) self.settings._add(BooleanSetting("lockbox", False, _("Display interface lock checkbox"), _("Display a checkbox that, when check, locks most of Pronterface"), "UI"))
...@@ -217,11 +220,8 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -217,11 +220,8 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.filename = filename self.filename = filename
os.putenv("UBUNTU_MENUPROXY", "0") os.putenv("UBUNTU_MENUPROXY", "0")
MainWindow.__init__(self, None, title = _("Pronterface"), size = size); MainWindow.__init__(self, None, title = _("Pronterface"), size = size)
if hasattr(sys,"frozen") and sys.frozen=="windows_exe": self.SetIcon(wx.Icon(iconfile("P-face.ico"), wx.BITMAP_TYPE_ICO))
self.SetIcon(wx.Icon(sys.executable, wx.BITMAP_TYPE_ICO))
else:
self.SetIcon(wx.Icon(pixmapfile("P-face.ico"), wx.BITMAP_TYPE_ICO))
self.statuscheck = False self.statuscheck = False
self.status_thread = None self.status_thread = None
...@@ -332,7 +332,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -332,7 +332,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def add_cmdline_arguments(self, parser): def add_cmdline_arguments(self, parser):
pronsole.pronsole.add_cmdline_arguments(self, parser) pronsole.pronsole.add_cmdline_arguments(self, parser)
parser.add_argument('-a','--autoconnect', help = _("automatically try to connect to printer on startup"), action = "store_true") parser.add_argument('-a', '--autoconnect', help = _("automatically try to connect to printer on startup"), action = "store_true")
def process_cmdline_arguments(self, args): def process_cmdline_arguments(self, args):
pronsole.pronsole.process_cmdline_arguments(self, args) pronsole.pronsole.process_cmdline_arguments(self, args)
...@@ -350,7 +350,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -350,7 +350,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def endcb(self): def endcb(self):
if self.p.queueindex == 0: if self.p.queueindex == 0:
print_duration = int(time.time () - self.starttime + self.extra_print_time) print_duration = int(time.time() - self.starttime + self.extra_print_time)
print _("Print ended at: %(end_time)s and took %(duration)s") % {"end_time": format_time(time.time()), print _("Print ended at: %(end_time)s and took %(duration)s") % {"end_time": format_time(time.time()),
"duration": format_duration(print_duration)} "duration": format_duration(print_duration)}
wx.CallAfter(self.pausebtn.Disable) wx.CallAfter(self.pausebtn.Disable)
...@@ -393,23 +393,23 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -393,23 +393,23 @@ class PronterWindow(MainWindow, pronsole.pronsole):
split_raw = gcoder.split(gline) split_raw = gcoder.split(gline)
gcoder.parse_coordinates(gline, split_raw, imperial = False) gcoder.parse_coordinates(gline, split_raw, imperial = False)
if gline.is_move: if gline.is_move:
if gline.z != None: if gline.z is not None:
layer = gline.z layer = gline.z
if layer != self.curlayer: if layer != self.curlayer:
self.curlayer = layer self.curlayer = layer
self.gviz.clearhilights() wx.CallAfter(self.gviz.clearhilights)
wx.CallAfter(self.gviz.setlayer, layer) wx.CallAfter(self.gviz.setlayer, layer)
elif gline.command in ["M104", "M109"]: elif gline.command in ["M104", "M109"]:
gcoder.parse_coordinates(gline, split_raw, imperial = False, force = True) gcoder.parse_coordinates(gline, split_raw, imperial = False, force = True)
gline_s = gcoder.S(gline) gline_s = gcoder.S(gline)
if gline_s != None: if gline_s is not None:
temp = gline_s temp = gline_s
if self.display_gauges: wx.CallAfter(self.hottgauge.SetTarget, temp) if self.display_gauges: wx.CallAfter(self.hottgauge.SetTarget, temp)
if self.display_graph: wx.CallAfter(self.graph.SetExtruder0TargetTemperature, temp) if self.display_graph: wx.CallAfter(self.graph.SetExtruder0TargetTemperature, temp)
elif gline.command == "M140": elif gline.command == "M140":
gline.parse_coordinates(gline, split_raw, imperial = False, force = True) gline.parse_coordinates(gline, split_raw, imperial = False, force = True)
gline_s = gcoder.S(gline) gline_s = gcoder.S(gline)
if gline_s != None: if gline_s is not None:
temp = gline_s temp = gline_s
if self.display_gauges: wx.CallAfter(self.bedtgauge.SetTarget, temp) if self.display_gauges: wx.CallAfter(self.bedtgauge.SetTarget, temp)
if self.display_graph: wx.CallAfter(self.graph.SetBedTargetTemperature, temp) if self.display_graph: wx.CallAfter(self.graph.SetBedTargetTemperature, temp)
...@@ -429,35 +429,35 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -429,35 +429,35 @@ class PronterWindow(MainWindow, pronsole.pronsole):
if not self.is_excluded_move(gline): if not self.is_excluded_move(gline):
return gline return gline
else: else:
if gline.z != None: if gline.z is not None:
if gline.relative: if gline.relative:
if self.excluder_z_abs != None: if self.excluder_z_abs is not None:
self.excluder_z_abs += gline.z self.excluder_z_abs += gline.z
elif self.excluder_z_rel != None: elif self.excluder_z_rel is not None:
self.excluder_z_rel += gline.z self.excluder_z_rel += gline.z
else: else:
self.excluder_z_rel = gline.z self.excluder_z_rel = gline.z
else: else:
self.excluder_z_rel = None self.excluder_z_rel = None
self.excluder_z_abs = gline.z self.excluder_z_abs = gline.z
if gline.e != None and not gline.relative_e: if gline.e is not None and not gline.relative_e:
self.excluder_e = gline.e self.excluder_e = gline.e
# If next move won't be excluded, push the changes we have to do # If next move won't be excluded, push the changes we have to do
if next_gline != None and not self.is_excluded_move(next_gline): if next_gline is not None and not self.is_excluded_move(next_gline):
if self.excluder_e != None: if self.excluder_e is not None:
self.p.send_now("G92 E%.5f" % self.excluder_e) self.p.send_now("G92 E%.5f" % self.excluder_e)
self.excluder_e = None self.excluder_e = None
if self.excluder_z_abs != None: if self.excluder_z_abs is not None:
if gline.relative: if gline.relative:
self.p.send_now("G90") self.p.send_now("G90")
self.p.send_now("G1 Z.5f" % self.excluder_z_abs) self.p.send_now("G1 Z%.5f" % self.excluder_z_abs)
self.excluder_z_abs = None self.excluder_z_abs = None
if gline.relative: if gline.relative:
self.p.send_now("G91") self.p.send_now("G91")
if self.excluder_z_rel != None: if self.excluder_z_rel is not None:
if not gline.relative: if not gline.relative:
self.p.send_now("G91") self.p.send_now("G91")
self.p.send_now("G1 Z.5f" % self.excluder_z_rel) self.p.send_now("G1 Z%.5f" % self.excluder_z_rel)
self.excluder_z_rel = None self.excluder_z_rel = None
if not gline.relative: if not gline.relative:
self.p.send_now("G90") self.p.send_now("G90")
...@@ -489,7 +489,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -489,7 +489,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.bsetpoint = f self.bsetpoint = f
if self.display_gauges: self.bedtgauge.SetTarget(int(f)) if self.display_gauges: self.bedtgauge.SetTarget(int(f))
if self.display_graph: wx.CallAfter(self.graph.SetBedTargetTemperature, int(f)) if self.display_graph: wx.CallAfter(self.graph.SetBedTargetTemperature, int(f))
if f>0: if f > 0:
wx.CallAfter(self.btemp.SetValue, str(f)) wx.CallAfter(self.btemp.SetValue, str(f))
self.set("last_bed_temperature", str(f)) self.set("last_bed_temperature", str(f))
wx.CallAfter(self.setboff.SetBackgroundColour, None) wx.CallAfter(self.setboff.SetBackgroundColour, None)
...@@ -535,7 +535,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -535,7 +535,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
f = float(l) f = float(l)
if f >= 0: if f >= 0:
if self.p.online: if self.p.online:
self.p.send_now("M104 S"+l) self.p.send_now("M104 S" + l)
print _("Setting hotend temperature to %f degrees Celsius.") % f print _("Setting hotend temperature to %f degrees Celsius.") % f
self.sethotendgui(f) self.sethotendgui(f)
else: else:
...@@ -555,7 +555,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -555,7 +555,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
f = float(l) f = float(l)
if f >= 0: if f >= 0:
if self.p.online: if self.p.online:
self.p.send_now("M140 S"+l) self.p.send_now("M140 S" + l)
print _("Setting bed temperature to %f degrees Celsius.") % f print _("Setting bed temperature to %f degrees Celsius.") % f
self.setbedgui(f) self.setbedgui(f)
else: else:
...@@ -578,7 +578,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -578,7 +578,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def cb(definition): def cb(definition):
if len(definition.strip()) == 0: if len(definition.strip()) == 0:
if old_macro_definition != "": if old_macro_definition != "":
dialog = wx.MessageDialog(self, _("Do you want to erase the macro?"), style = wx.YES_NO|wx.YES_DEFAULT|wx.ICON_QUESTION) dialog = wx.MessageDialog(self, _("Do you want to erase the macro?"), style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
if dialog.ShowModal() == wx.ID_YES: if dialog.ShowModal() == wx.ID_YES:
self.delete_macro(macro_name) self.delete_macro(macro_name)
return return
...@@ -594,7 +594,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -594,7 +594,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def catchprint(self, l): def catchprint(self, l):
wx.CallAfter(self.addtexttolog, l) wx.CallAfter(self.addtexttolog, l)
def project(self,event): def project(self, event):
from printrun import projectlayer from printrun import projectlayer
projectlayer.SettingsFrame(self, self.p).Show() projectlayer.SettingsFrame(self, self.p).Show()
...@@ -628,6 +628,20 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -628,6 +628,20 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.Bind(wx.EVT_MENU, self.recover, self.recoverbtn) self.Bind(wx.EVT_MENU, self.recover, self.recoverbtn)
self.menustrip.Append(m, _("&Advanced")) self.menustrip.Append(m, _("&Advanced"))
if self.settings.slic3rintegration:
m = wx.Menu()
self.menustrip.Append(m, _("&Slic3r"))
print_menu = wx.Menu()
filament_menu = wx.Menu()
printer_menu = wx.Menu()
m.AppendSubMenu(print_menu, _("Print &settings"))
m.AppendSubMenu(filament_menu, _("&Filament"))
m.AppendSubMenu(printer_menu, _("&Printer"))
menus = {"print": print_menu,
"filament": filament_menu,
"printer": printer_menu}
self.load_slic3r_configs(menus)
# Settings menu # Settings menu
m = wx.Menu() m = wx.Menu()
self.macros_menu = wx.Menu() self.macros_menu = wx.Menu()
...@@ -635,7 +649,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -635,7 +649,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.Bind(wx.EVT_MENU, self.new_macro, self.macros_menu.Append(-1, _("<&New...>"))) self.Bind(wx.EVT_MENU, self.new_macro, self.macros_menu.Append(-1, _("<&New...>")))
self.Bind(wx.EVT_MENU, lambda *e: PronterOptions(self), m.Append(-1, _("&Options"), _(" Options dialog"))) self.Bind(wx.EVT_MENU, lambda *e: PronterOptions(self), m.Append(-1, _("&Options"), _(" Options dialog")))
self.Bind(wx.EVT_MENU, lambda x: threading.Thread(target = lambda:self.do_skein("set")).start(), m.Append(-1, _("Slicing Settings"), _(" Adjust slicing settings"))) self.Bind(wx.EVT_MENU, lambda x: threading.Thread(target = lambda: self.do_skein("set")).start(), m.Append(-1, _("Slicing Settings"), _(" Adjust slicing settings")))
mItem = m.AppendCheckItem(-1, _("Debug G-code"), mItem = m.AppendCheckItem(-1, _("Debug G-code"),
_("Print all G-code sent to and received from the printer.")) _("Print all G-code sent to and received from the printer."))
...@@ -652,6 +666,57 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -652,6 +666,57 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.update_macros_menu() self.update_macros_menu()
self.SetMenuBar(self.menustrip) self.SetMenuBar(self.menustrip)
def load_slic3r_configs(self, menus):
# Hack to get correct path for Slic3r config
orig_appname = self.app.GetAppName()
self.app.SetAppName("Slic3r")
configpath = wx.StandardPaths.Get().GetUserDataDir()
self.app.SetAppName(orig_appname)
configfile = os.path.join(configpath, "slic3r.ini")
config = self.read_slic3r_config(configfile)
for cat in menus:
menu = menus[cat]
pattern = os.path.join(configpath, cat, "*.ini")
files = sorted(glob.glob(pattern))
try: preset = config.get("presets", cat)
except: preset = None
for f in files:
name = os.path.splitext(os.path.basename(f))[0]
item = menu.Append(-1, name, f, wx.ITEM_RADIO)
item.Check(os.path.basename(f) == preset)
self.Bind(wx.EVT_MENU,
lambda event, cat = cat, f = f:
self.set_slic3r_config(configfile, cat, f), item)
def read_slic3r_config(self, configfile, parser = None):
import ConfigParser
parser = ConfigParser.RawConfigParser()
class add_header(object):
def __init__(self, f):
self.f = f
self.header = '[dummy]'
def readline(self):
if self.header:
try: return self.header
finally: self.header = None
else:
return self.f.readline()
parser.readfp(add_header(open(configfile)), configfile)
return parser
def set_slic3r_config(self, configfile, cat, file):
config = self.read_slic3r_config(configfile)
config.set("presets", cat, os.path.basename(file))
f = StringIO.StringIO()
config.write(f)
data = f.getvalue()
f.close()
data = data.replace("[dummy]\n", "")
with open(configfile, "w") as f:
f.write(data)
def doneediting(self, gcode): def doneediting(self, gcode):
open(self.filename, "w").write("\n".join(gcode)) open(self.filename, "w").write("\n".join(gcode))
wx.CallAfter(self.loadfile, None, self.filename) wx.CallAfter(self.loadfile, None, self.filename)
...@@ -668,12 +733,12 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -668,12 +733,12 @@ class PronterWindow(MainWindow, pronsole.pronsole):
dialog.namectrl = wx.TextCtrl(panel, -1, '', (110, 8), size = (130, 24), style = wx.TE_PROCESS_ENTER) dialog.namectrl = wx.TextCtrl(panel, -1, '', (110, 8), size = (130, 24), style = wx.TE_PROCESS_ENTER)
hbox = wx.BoxSizer(wx.HORIZONTAL) hbox = wx.BoxSizer(wx.HORIZONTAL)
okb = wx.Button(dialog, wx.ID_OK, _("Ok"), size = (60, 24)) okb = wx.Button(dialog, wx.ID_OK, _("Ok"), size = (60, 24))
dialog.Bind(wx.EVT_TEXT_ENTER, lambda e:dialog.EndModal(wx.ID_OK), dialog.namectrl) dialog.Bind(wx.EVT_TEXT_ENTER, lambda e: dialog.EndModal(wx.ID_OK), dialog.namectrl)
#dialog.Bind(wx.EVT_BUTTON, lambda e:self.new_macro_named(dialog, e), okb) #dialog.Bind(wx.EVT_BUTTON, lambda e:self.new_macro_named(dialog, e), okb)
hbox.Add(okb) hbox.Add(okb)
hbox.Add(wx.Button(dialog, wx.ID_CANCEL, _("Cancel"), size = (60, 24))) hbox.Add(wx.Button(dialog, wx.ID_CANCEL, _("Cancel"), size = (60, 24)))
vbox.Add(panel) vbox.Add(panel)
vbox.Add(hbox, 1, wx.ALIGN_CENTER|wx.TOP|wx.BOTTOM, 10) vbox.Add(hbox, 1, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 10)
dialog.SetSizer(vbox) dialog.SetSizer(vbox)
dialog.Centre() dialog.Centre()
macro = "" macro = ""
...@@ -686,12 +751,12 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -686,12 +751,12 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def edit_macro(self, macro): def edit_macro(self, macro):
if macro == "": return self.new_macro() if macro == "": return self.new_macro()
if self.macros.has_key(macro): if macro in self.macros:
old_def = self.macros[macro] old_def = self.macros[macro]
elif len([c for c in macro.encode("ascii", "replace") if not c.isalnum() and c != "_"]): elif len([c for c in macro.encode("ascii", "replace") if not c.isalnum() and c != "_"]):
print _("Macro name may contain only ASCII alphanumeric symbols and underscores") print _("Macro name may contain only ASCII alphanumeric symbols and underscores")
return return
elif hasattr(self.__class__, "do_"+macro): elif hasattr(self.__class__, "do_" + macro):
print _("Name '%s' is being used by built-in command") % macro print _("Name '%s' is being used by built-in command") % macro
return return
else: else:
...@@ -730,16 +795,16 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -730,16 +795,16 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def cbkey(self, e): def cbkey(self, e):
if e.GetKeyCode() == wx.WXK_UP: if e.GetKeyCode() == wx.WXK_UP:
if self.commandbox.histindex == len(self.commandbox.history): if self.commandbox.histindex == len(self.commandbox.history):
self.commandbox.history+=[self.commandbox.GetValue()] #save current command self.commandbox.history.append(self.commandbox.GetValue()) # save current command
if len(self.commandbox.history): if len(self.commandbox.history):
self.commandbox.histindex = (self.commandbox.histindex-1)%len(self.commandbox.history) self.commandbox.histindex = (self.commandbox.histindex - 1) % len(self.commandbox.history)
self.commandbox.SetValue(self.commandbox.history[self.commandbox.histindex]) self.commandbox.SetValue(self.commandbox.history[self.commandbox.histindex])
self.commandbox.SetSelection(0, len(self.commandbox.history[self.commandbox.histindex])) self.commandbox.SetSelection(0, len(self.commandbox.history[self.commandbox.histindex]))
elif e.GetKeyCode() == wx.WXK_DOWN: elif e.GetKeyCode() == wx.WXK_DOWN:
if self.commandbox.histindex == len(self.commandbox.history): if self.commandbox.histindex == len(self.commandbox.history):
self.commandbox.history+=[self.commandbox.GetValue()] #save current command self.commandbox.history.append(self.commandbox.GetValue()) # save current command
if len(self.commandbox.history): if len(self.commandbox.history):
self.commandbox.histindex = (self.commandbox.histindex+1)%len(self.commandbox.history) self.commandbox.histindex = (self.commandbox.histindex + 1) % len(self.commandbox.history)
self.commandbox.SetValue(self.commandbox.history[self.commandbox.histindex]) self.commandbox.SetValue(self.commandbox.history[self.commandbox.histindex])
self.commandbox.SetSelection(0, len(self.commandbox.history[self.commandbox.histindex])) self.commandbox.SetSelection(0, len(self.commandbox.history[self.commandbox.histindex]))
else: else:
...@@ -748,7 +813,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -748,7 +813,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def plate(self, e): def plate(self, e):
import plater import plater
print _("Plate function activated") print _("Plate function activated")
plater.stlwin(size = (800, 580), callback = self.platecb, parent = self, build_dimensions = self.build_dimensions_list).Show() plater.StlPlater(size = (800, 580), callback = self.platecb, parent = self, build_dimensions = self.build_dimensions_list).Show()
def platecb(self, name): def platecb(self, name):
print _("Plated %s") % name print _("Plated %s") % name
...@@ -784,7 +849,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -784,7 +849,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def update_gviz_params(self, param, value): def update_gviz_params(self, param, value):
params_map = {"preview_extrusion_width": "extrusion_width", params_map = {"preview_extrusion_width": "extrusion_width",
"preview_grid_step1": "grid", "preview_grid_step1": "grid",
"preview_grid_step2": "grid",} "preview_grid_step2": "grid"}
if param not in params_map: if param not in params_map:
return return
trueparam = params_map[param] trueparam = params_map[param]
...@@ -837,11 +902,11 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -837,11 +902,11 @@ class PronterWindow(MainWindow, pronsole.pronsole):
for i, btndef in enumerate(custombuttons): for i, btndef in enumerate(custombuttons):
try: try:
b = wx.Button(self.centerpanel, -1, btndef.label, style = wx.BU_EXACTFIT) b = wx.Button(self.centerpanel, -1, btndef.label, style = wx.BU_EXACTFIT)
b.SetToolTip(wx.ToolTip(_("Execute command: ")+btndef.command)) b.SetToolTip(wx.ToolTip(_("Execute command: ") + btndef.command))
if btndef.background: if btndef.background:
b.SetBackgroundColour(btndef.background) b.SetBackgroundColour(btndef.background)
rr, gg, bb = b.GetBackgroundColour().Get() rr, gg, bb = b.GetBackgroundColour().Get()
if 0.3*rr+0.59*gg+0.11*bb < 60: if 0.3 * rr + 0.59 * gg + 0.11 * bb < 60:
b.SetForegroundColour("#ffffff") b.SetForegroundColour("#ffffff")
except: except:
if i == len(custombuttons) - 1: if i == len(custombuttons) - 1:
...@@ -851,7 +916,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -851,7 +916,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
b.SetToolTip(wx.ToolTip(_("click to add new custom button"))) b.SetToolTip(wx.ToolTip(_("click to add new custom button")))
b.Bind(wx.EVT_BUTTON, self.cbutton_edit) b.Bind(wx.EVT_BUTTON, self.cbutton_edit)
else: else:
b = wx.Button(self.centerpanel,-1, ".", size = (1, 1)) b = wx.Button(self.centerpanel, -1, ".", size = (1, 1))
#b = wx.StaticText(self.panel,-1, "", size = (72, 22), style = wx.ALIGN_CENTRE+wx.ST_NO_AUTORESIZE) #+wx.SIMPLE_BORDER #b = wx.StaticText(self.panel,-1, "", size = (72, 22), style = wx.ALIGN_CENTRE+wx.ST_NO_AUTORESIZE) #+wx.SIMPLE_BORDER
b.Disable() b.Disable()
#continue #continue
...@@ -871,7 +936,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -871,7 +936,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def nextarg(rest): def nextarg(rest):
rest = rest.lstrip() rest = rest.lstrip()
if rest.startswith('"'): if rest.startswith('"'):
return rest[1:].split('"',1) return rest[1:].split('"', 1)
else: else:
return rest.split(None, 1) return rest.split(None, 1)
#try: #try:
...@@ -886,7 +951,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -886,7 +951,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
except: except:
pass pass
command = argstr.strip() command = argstr.strip()
if num<0 or num>=64: if num < 0 or num >= 64:
print _("Custom button number should be between 0 and 63") print _("Custom button number should be between 0 and 63")
return return
while num >= len(self.custombuttons): while num >= len(self.custombuttons):
...@@ -903,19 +968,19 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -903,19 +968,19 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def cbutton_save(self, n, bdef, new_n = None): def cbutton_save(self, n, bdef, new_n = None):
if new_n is None: new_n = n if new_n is None: new_n = n
if bdef is None or bdef == "": if bdef is None or bdef == "":
self.save_in_rc(("button %d" % n),'') self.save_in_rc(("button %d" % n), '')
elif bdef.background: elif bdef.background:
colour = bdef.background colour = bdef.background
if type(colour) not in (str, unicode): if type(colour) not in (str, unicode):
#print type(colour), map(type, colour) #print type(colour), map(type, colour)
if type(colour) == tuple and tuple(map(type, colour)) == (int, int, int): if type(colour) == tuple and tuple(map(type, colour)) == (int, int, int):
colour = map(lambda x:x%256, colour) colour = map(lambda x: x % 256, colour)
colour = wx.Colour(*colour).GetAsString(wx.C2S_NAME|wx.C2S_HTML_SYNTAX) colour = wx.Colour(*colour).GetAsString(wx.C2S_NAME | wx.C2S_HTML_SYNTAX)
else: else:
colour = wx.Colour(colour).GetAsString(wx.C2S_NAME|wx.C2S_HTML_SYNTAX) colour = wx.Colour(colour).GetAsString(wx.C2S_NAME | wx.C2S_HTML_SYNTAX)
self.save_in_rc(("button %d" % n),'button %d "%s" /c "%s" %s' % (new_n, bdef.label, colour, bdef.command)) self.save_in_rc(("button %d" % n), 'button %d "%s" /c "%s" %s' % (new_n, bdef.label, colour, bdef.command))
else: else:
self.save_in_rc(("button %d" % n),'button %d "%s" %s' % (new_n, bdef.label, bdef.command)) self.save_in_rc(("button %d" % n), 'button %d "%s" %s' % (new_n, bdef.label, bdef.command))
def cbutton_edit(self, e, button = None): def cbutton_edit(self, e, button = None):
bedit = ButtonEdit(self) bedit = ButtonEdit(self)
...@@ -928,20 +993,20 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -928,20 +993,20 @@ class PronterWindow(MainWindow, pronsole.pronsole):
if type(colour) not in (str, unicode): if type(colour) not in (str, unicode):
#print type(colour) #print type(colour)
if type(colour) == tuple and tuple(map(type, colour)) == (int, int, int): if type(colour) == tuple and tuple(map(type, colour)) == (int, int, int):
colour = map(lambda x:x%256, colour) colour = map(lambda x: x % 256, colour)
colour = wx.Colour(*colour).GetAsString(wx.C2S_NAME|wx.C2S_HTML_SYNTAX) colour = wx.Colour(*colour).GetAsString(wx.C2S_NAME | wx.C2S_HTML_SYNTAX)
else: else:
colour = wx.Colour(colour).GetAsString(wx.C2S_NAME|wx.C2S_HTML_SYNTAX) colour = wx.Colour(colour).GetAsString(wx.C2S_NAME | wx.C2S_HTML_SYNTAX)
bedit.color.SetValue(colour) bedit.color.SetValue(colour)
else: else:
n = len(self.custombuttons) n = len(self.custombuttons)
while n>0 and self.custombuttons[n-1] is None: while n > 0 and self.custombuttons[n - 1] is None:
n -= 1 n -= 1
if bedit.ShowModal() == wx.ID_OK: if bedit.ShowModal() == wx.ID_OK:
if n == len(self.custombuttons): if n == len(self.custombuttons):
self.custombuttons+=[None] self.custombuttons.append(None)
self.custombuttons[n]=SpecialButton(bedit.name.GetValue().strip(), bedit.command.GetValue().strip(), custom = True) self.custombuttons[n] = SpecialButton(bedit.name.GetValue().strip(), bedit.command.GetValue().strip(), custom = True)
if bedit.color.GetValue().strip()!="": if bedit.color.GetValue().strip() != "":
self.custombuttons[n].background = bedit.color.GetValue() self.custombuttons[n].background = bedit.color.GetValue()
self.cbutton_save(n, self.custombuttons[n]) self.cbutton_save(n, self.custombuttons[n])
wx.CallAfter(bedit.Destroy) wx.CallAfter(bedit.Destroy)
...@@ -957,14 +1022,14 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -957,14 +1022,14 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def cbutton_order(self, e, button, dir): def cbutton_order(self, e, button, dir):
n = button.custombutton n = button.custombutton
if dir<0: if dir < 0:
n = n-1 n = n - 1
if n+1 >= len(self.custombuttons): if n + 1 >= len(self.custombuttons):
self.custombuttons+=[None] # pad self.custombuttons.append(None) # pad
# swap # swap
self.custombuttons[n], self.custombuttons[n+1] = self.custombuttons[n+1], self.custombuttons[n] self.custombuttons[n], self.custombuttons[n + 1] = self.custombuttons[n + 1], self.custombuttons[n]
self.cbutton_save(n, self.custombuttons[n]) self.cbutton_save(n, self.custombuttons[n])
self.cbutton_save(n+1, self.custombuttons[n+1]) self.cbutton_save(n + 1, self.custombuttons[n + 1])
#if self.custombuttons[-1] is None: #if self.custombuttons[-1] is None:
# del self.custombuttons[-1] # del self.custombuttons[-1]
wx.CallAfter(self.cbuttons_reload) wx.CallAfter(self.cbuttons_reload)
...@@ -979,16 +1044,16 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -979,16 +1044,16 @@ class PronterWindow(MainWindow, pronsole.pronsole):
obj = e.GetEventObject() obj = e.GetEventObject()
if hasattr(obj, "custombutton"): if hasattr(obj, "custombutton"):
item = popupmenu.Append(-1, _("Edit custom button '%s'") % e.GetEventObject().GetLabelText()) item = popupmenu.Append(-1, _("Edit custom button '%s'") % e.GetEventObject().GetLabelText())
self.Bind(wx.EVT_MENU, lambda e, button = e.GetEventObject():self.cbutton_edit(e, button), item) self.Bind(wx.EVT_MENU, lambda e, button = e.GetEventObject(): self.cbutton_edit(e, button), item)
item = popupmenu.Append(-1, _("Move left <<")) item = popupmenu.Append(-1, _("Move left <<"))
self.Bind(wx.EVT_MENU, lambda e, button = e.GetEventObject():self.cbutton_order(e, button,-1), item) self.Bind(wx.EVT_MENU, lambda e, button = e.GetEventObject(): self.cbutton_order(e, button, -1), item)
if obj.custombutton == 0: item.Enable(False) if obj.custombutton == 0: item.Enable(False)
item = popupmenu.Append(-1, _("Move right >>")) item = popupmenu.Append(-1, _("Move right >>"))
self.Bind(wx.EVT_MENU, lambda e, button = e.GetEventObject():self.cbutton_order(e, button, 1), item) self.Bind(wx.EVT_MENU, lambda e, button = e.GetEventObject(): self.cbutton_order(e, button, 1), item)
if obj.custombutton == 63: item.Enable(False) if obj.custombutton == 63: item.Enable(False)
pos = self.panel.ScreenToClient(e.GetEventObject().ClientToScreen(pos)) pos = self.panel.ScreenToClient(e.GetEventObject().ClientToScreen(pos))
item = popupmenu.Append(-1, _("Remove custom button '%s'") % e.GetEventObject().GetLabelText()) item = popupmenu.Append(-1, _("Remove custom button '%s'") % e.GetEventObject().GetLabelText())
self.Bind(wx.EVT_MENU, lambda e, button = e.GetEventObject():self.cbutton_remove(e, button), item) self.Bind(wx.EVT_MENU, lambda e, button = e.GetEventObject(): self.cbutton_remove(e, button), item)
else: else:
item = popupmenu.Append(-1, _("Add custom button")) item = popupmenu.Append(-1, _("Add custom button"))
self.Bind(wx.EVT_MENU, self.cbutton_edit, item) self.Bind(wx.EVT_MENU, self.cbutton_edit, item)
...@@ -1001,8 +1066,8 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1001,8 +1066,8 @@ class PronterWindow(MainWindow, pronsole.pronsole):
e.Skip() e.Skip()
return return
else: else:
dx, dy = self.dragpos[0]-scrpos[0], self.dragpos[1]-scrpos[1] dx, dy = self.dragpos[0] - scrpos[0], self.dragpos[1] - scrpos[1]
if dx*dx+dy*dy < 5*5: # threshold to detect dragging for jittery mice if dx * dx + dy * dy < 5 * 5: # threshold to detect dragging for jittery mice
e.Skip() e.Skip()
return return
if not hasattr(self, "dragging"): if not hasattr(self, "dragging"):
...@@ -1027,7 +1092,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1027,7 +1092,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.uppersizer.SetItemMinSize(b, obj.GetSize()) self.uppersizer.SetItemMinSize(b, obj.GetSize())
self.mainsizer.Layout() self.mainsizer.Layout()
# b.SetStyle(wx.ALIGN_CENTRE+wx.ST_NO_AUTORESIZE+wx.SIMPLE_BORDER) # b.SetStyle(wx.ALIGN_CENTRE+wx.ST_NO_AUTORESIZE+wx.SIMPLE_BORDER)
self.dragging = wx.Button(self.panel,-1, obj.GetLabel(), style = wx.BU_EXACTFIT) self.dragging = wx.Button(self.panel, -1, obj.GetLabel(), style = wx.BU_EXACTFIT)
self.dragging.SetBackgroundColour(obj.GetBackgroundColour()) self.dragging.SetBackgroundColour(obj.GetBackgroundColour())
self.dragging.SetForegroundColour(obj.GetForegroundColour()) self.dragging.SetForegroundColour(obj.GetForegroundColour())
self.dragging.sourcebutton = obj self.dragging.sourcebutton = obj
...@@ -1042,7 +1107,6 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1042,7 +1107,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
# dragging in progress # dragging in progress
self.dragging.SetPosition(self.panel.ScreenToClient(scrpos)) self.dragging.SetPosition(self.panel.ScreenToClient(scrpos))
wx.CallAfter(self.dragging.Refresh) wx.CallAfter(self.dragging.Refresh)
btns = self.custombuttonbuttons
dst = None dst = None
src = self.dragging.sourcebutton src = self.dragging.sourcebutton
drg = self.dragging drg = self.dragging
...@@ -1176,7 +1240,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1176,7 +1240,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def procbutton(self, e): def procbutton(self, e):
try: try:
if hasattr(e.GetEventObject(),"custombutton"): if hasattr(e.GetEventObject(), "custombutton"):
if wx.GetKeyState(wx.WXK_CONTROL) or wx.GetKeyState(wx.WXK_ALT): if wx.GetKeyState(wx.WXK_CONTROL) or wx.GetKeyState(wx.WXK_ALT):
return self.editbutton(e) return self.editbutton(e)
self.cur_button = e.GetEventObject().custombutton self.cur_button = e.GetEventObject().custombutton
...@@ -1206,14 +1270,14 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1206,14 +1270,14 @@ class PronterWindow(MainWindow, pronsole.pronsole):
wx.CallAfter(self.Destroy) wx.CallAfter(self.Destroy)
def do_monitor(self, l = ""): def do_monitor(self, l = ""):
if l.strip()=="": if l.strip() == "":
self.monitorbox.SetValue(not self.monitorbox.GetValue()) self.monitorbox.SetValue(not self.monitorbox.GetValue())
elif l.strip()=="off": elif l.strip() == "off":
wx.CallAfter(self.monitorbox.SetValue, False) wx.CallAfter(self.monitorbox.SetValue, False)
else: else:
try: try:
self.monitor_interval = float(l) self.monitor_interval = float(l)
wx.CallAfter(self.monitorbox.SetValue, self.monitor_interval>0) wx.CallAfter(self.monitorbox.SetValue, self.monitor_interval > 0)
except: except:
print _("Invalid period given.") print _("Invalid period given.")
self.setmonitor(None) self.setmonitor(None)
...@@ -1231,20 +1295,20 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1231,20 +1295,20 @@ class PronterWindow(MainWindow, pronsole.pronsole):
else: else:
wx.CallAfter(self.graph.StopPlotting) wx.CallAfter(self.graph.StopPlotting)
def addtexttolog(self,text): def addtexttolog(self, text):
try: try:
self.logbox.AppendText(text) self.logbox.AppendText(text)
except: except:
print _("Attempted to write invalid text to console, which could be due to an invalid baudrate") print _("Attempted to write invalid text to console, which could be due to an invalid baudrate")
def setloud(self,e): def setloud(self, e):
self.p.loud=e.IsChecked() self.p.loud = e.IsChecked()
def sendline(self, e): def sendline(self, e):
command = self.commandbox.GetValue() command = self.commandbox.GetValue()
if not len(command): if not len(command):
return return
wx.CallAfter(self.addtexttolog, ">>>" + command + "\n"); wx.CallAfter(self.addtexttolog, ">>>" + command + "\n")
self.parseusercmd(str(command)) self.parseusercmd(str(command))
self.onecmd(str(command)) self.onecmd(str(command))
self.commandbox.SetSelection(0, len(command)) self.commandbox.SetSelection(0, len(command))
...@@ -1286,7 +1350,6 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1286,7 +1350,6 @@ class PronterWindow(MainWindow, pronsole.pronsole):
setpoint = float(setpoint) setpoint = float(setpoint)
if self.display_graph: wx.CallAfter(self.graph.SetBedTargetTemperature, setpoint) if self.display_graph: wx.CallAfter(self.graph.SetBedTargetTemperature, setpoint)
if self.display_gauges: wx.CallAfter(self.bedtgauge.SetTarget, setpoint) if self.display_gauges: wx.CallAfter(self.bedtgauge.SetTarget, setpoint)
except: except:
traceback.print_exc() traceback.print_exc()
...@@ -1314,8 +1377,8 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1314,8 +1377,8 @@ class PronterWindow(MainWindow, pronsole.pronsole):
if self.sdprinting or self.uploading: if self.sdprinting or self.uploading:
if self.uploading: if self.uploading:
fractioncomplete = float(self.p.queueindex) / len(self.p.mainqueue) fractioncomplete = float(self.p.queueindex) / len(self.p.mainqueue)
string += _("SD upload: %04.2f%% |") % (100*fractioncomplete,) string += _("SD upload: %04.2f%% |") % (100 * fractioncomplete,)
string += _(" Line# %d of %d lines |" ) % (self.p.queueindex, len(self.p.mainqueue)) string += _(" Line# %d of %d lines |") % (self.p.queueindex, len(self.p.mainqueue))
else: else:
fractioncomplete = float(self.percentdone / 100.0) fractioncomplete = float(self.percentdone / 100.0)
string += _("SD printing: %04.2f%% |") % (self.percentdone,) string += _("SD printing: %04.2f%% |") % (self.percentdone,)
...@@ -1328,8 +1391,8 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1328,8 +1391,8 @@ class PronterWindow(MainWindow, pronsole.pronsole):
string += _(" Z: %.3f mm") % self.curlayer string += _(" Z: %.3f mm") % self.curlayer
elif self.p.printing: elif self.p.printing:
fractioncomplete = float(self.p.queueindex) / len(self.p.mainqueue) fractioncomplete = float(self.p.queueindex) / len(self.p.mainqueue)
string += _("Printing: %04.2f%% |") % (100*float(self.p.queueindex)/len(self.p.mainqueue),) string += _("Printing: %04.2f%% |") % (100 * float(self.p.queueindex) / len(self.p.mainqueue),)
string += _(" Line# %d of %d lines |" ) % (self.p.queueindex, len(self.p.mainqueue)) string += _(" Line# %d of %d lines |") % (self.p.queueindex, len(self.p.mainqueue))
if self.p.queueindex > 0: if self.p.queueindex > 0:
secondselapsed = int(time.time() - self.starttime + self.extra_print_time) secondselapsed = int(time.time() - self.starttime + self.extra_print_time)
secondsremain, secondsestimate = self.compute_eta(self.p.queueindex, secondselapsed) secondsremain, secondsestimate = self.compute_eta(self.p.queueindex, secondselapsed)
...@@ -1380,7 +1443,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1380,7 +1443,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.userm114 -= 1 self.userm114 -= 1
else: else:
isreport = True isreport = True
if "ok T:" in l: if "ok T:" in l or ("T:" in l and "E:" in l):
self.tempreport = l self.tempreport = l
wx.CallAfter(self.tempdisp.SetLabel, self.tempreport.strip().replace("ok ", "")) wx.CallAfter(self.tempdisp.SetLabel, self.tempreport.strip().replace("ok ", ""))
self.update_tempdisplay() self.update_tempdisplay()
...@@ -1390,7 +1453,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1390,7 +1453,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
isreport = True isreport = True
tstring = l.rstrip() tstring = l.rstrip()
if not self.p.loud and (tstring not in ["ok", "wait"] and not isreport): if not self.p.loud and (tstring not in ["ok", "wait"] and not isreport):
wx.CallAfter(self.addtexttolog, tstring + "\n"); wx.CallAfter(self.addtexttolog, tstring + "\n")
for listener in self.recvlisteners: for listener in self.recvlisteners:
listener(l) listener(l)
...@@ -1428,7 +1491,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1428,7 +1491,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
try: try:
resp = l.split() resp = l.split()
vals = resp[-1].split("/") vals = resp[-1].split("/")
self.percentdone = 100.0*int(vals[0])/int(vals[1]) self.percentdone = 100.0 * int(vals[0]) / int(vals[1])
except: except:
pass pass
...@@ -1437,8 +1500,8 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1437,8 +1500,8 @@ class PronterWindow(MainWindow, pronsole.pronsole):
if(dlg.ShowModal() == wx.ID_OK): if(dlg.ShowModal() == wx.ID_OK):
target = dlg.GetStringSelection() target = dlg.GetStringSelection()
if len(target): if len(target):
self.recvlisteners+=[self.waitforsdresponse] self.recvlisteners.append(self.waitforsdresponse)
self.p.send_now("M23 "+target.lower()) self.p.send_now("M23 " + target.lower())
dlg.Destroy() dlg.Destroy()
#print self.sdfiles #print self.sdfiles
...@@ -1468,7 +1531,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1468,7 +1531,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.skeinp = subprocess.Popen(pararray, stderr = subprocess.STDOUT, stdout = subprocess.PIPE) self.skeinp = subprocess.Popen(pararray, stderr = subprocess.STDOUT, stdout = subprocess.PIPE)
while True: while True:
o = self.skeinp.stdout.read(1) o = self.skeinp.stdout.read(1)
if o == '' and self.skeinp.poll() != None: break if o == '' and self.skeinp.poll() is not None: break
sys.stdout.write(o) sys.stdout.write(o)
self.skeinp.wait() self.skeinp.wait()
self.stopsf = 1 self.stopsf = 1
...@@ -1480,7 +1543,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1480,7 +1543,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def skein_monitor(self): def skein_monitor(self):
while not self.stopsf: while not self.stopsf:
try: try:
wx.CallAfter(self.statusbar.SetStatusText, _("Slicing..."))#+self.cout.getvalue().split("\n")[-1]) wx.CallAfter(self.statusbar.SetStatusText, _("Slicing...")) # +self.cout.getvalue().split("\n")[-1])
except: except:
pass pass
time.sleep(0.1) time.sleep(0.1)
...@@ -1518,7 +1581,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1518,7 +1581,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
# handle it when everything has been prepared # handle it when everything has been prepared
self.filename = filename self.filename = filename
def do_load(self,l): def do_load(self, l):
if hasattr(self, 'skeining'): if hasattr(self, 'skeining'):
self.loadfile(None, l) self.loadfile(None, l)
else: else:
...@@ -1537,7 +1600,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1537,7 +1600,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
pass pass
dlg = None dlg = None
if filename is None: if filename is None:
dlg = wx.FileDialog(self, _("Open file to print"), basedir, style = wx.FD_OPEN|wx.FD_FILE_MUST_EXIST) dlg = wx.FileDialog(self, _("Open file to print"), basedir, style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
dlg.SetWildcard(_("OBJ, STL, and GCODE files (*.gcode;*.gco;*.g;*.stl;*.STL;*.obj;*.OBJ)|*.gcode;*.gco;*.g;*.stl;*.STL;*.obj;*.OBJ|All Files (*.*)|*.*")) dlg.SetWildcard(_("OBJ, STL, and GCODE files (*.gcode;*.gco;*.g;*.stl;*.STL;*.obj;*.OBJ)|*.gcode;*.gco;*.g;*.stl;*.STL;*.obj;*.OBJ|All Files (*.*)|*.*"))
if filename or dlg.ShowModal() == wx.ID_OK: if filename or dlg.ShowModal() == wx.ID_OK:
if filename: if filename:
...@@ -1631,7 +1694,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1631,7 +1694,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
return return
if not self.p.online: if not self.p.online:
return return
dlg = wx.TextEntryDialog(self, ("Enter a target filename in 8.3 format:"), _("Pick SD filename") ,dosify(self.filename)) dlg = wx.TextEntryDialog(self, ("Enter a target filename in 8.3 format:"), _("Pick SD filename"), dosify(self.filename))
if dlg.ShowModal() == wx.ID_OK: if dlg.ShowModal() == wx.ID_OK:
self.p.send_now("M21") self.p.send_now("M21")
self.p.send_now("M28 " + str(dlg.GetValue())) self.p.send_now("M28 " + str(dlg.GetValue()))
...@@ -1764,7 +1827,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1764,7 +1827,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
def reset(self, event): def reset(self, event):
print _("Reset.") print _("Reset.")
dlg = wx.MessageDialog(self, _("Are you sure you want to reset the printer?"), _("Reset?"), wx.YES|wx.NO) dlg = wx.MessageDialog(self, _("Are you sure you want to reset the printer?"), _("Reset?"), wx.YES | wx.NO)
if dlg.ShowModal() == wx.ID_YES: if dlg.ShowModal() == wx.ID_YES:
self.p.reset() self.p.reset()
self.sethotendgui(0) self.sethotendgui(0)
...@@ -1778,7 +1841,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1778,7 +1841,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
dlg.Destroy() dlg.Destroy()
def lock(self, event = None, force = None): def lock(self, event = None, force = None):
if force != None: if force is not None:
self.locker.SetValue(force) self.locker.SetValue(force)
if self.locker.GetValue(): if self.locker.GetValue():
print _("Locking interface.") print _("Locking interface.")
...@@ -1795,7 +1858,8 @@ class PronterApp(wx.App): ...@@ -1795,7 +1858,8 @@ class PronterApp(wx.App):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PronterApp, self).__init__(*args, **kwargs) super(PronterApp, self).__init__(*args, **kwargs)
self.mainwindow = PronterWindow() self.SetAppName("Pronterface")
self.mainwindow = PronterWindow(self)
self.mainwindow.Show() self.mainwindow.Show()
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>. # along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import sys, os, glob import sys
import subprocess import os
from stat import * from stat import S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH
from distutils.core import setup from distutils.core import setup
from distutils.command.install import install as _install from distutils.command.install import install as _install
from distutils.command.install_data import install_data as _install_data from distutils.command.install_data import install_data as _install_data
...@@ -33,93 +33,93 @@ INSTALLED_FILES = "installed_files" ...@@ -33,93 +33,93 @@ INSTALLED_FILES = "installed_files"
class install (_install): class install (_install):
def run (self): def run(self):
_install.run (self) _install.run(self)
outputs = self.get_outputs () outputs = self.get_outputs()
length = 0 length = 0
if self.root: if self.root:
length += len (self.root) length += len(self.root)
if self.prefix: if self.prefix:
length += len (self.prefix) length += len(self.prefix)
if length: if length:
for counter in xrange (len (outputs)): for counter in xrange(len(outputs)):
outputs[counter] = outputs[counter][length:] outputs[counter] = outputs[counter][length:]
data = "\n".join (outputs) data = "\n".join(outputs)
try: try:
file = open (INSTALLED_FILES, "w") file = open(INSTALLED_FILES, "w")
except: except:
self.warn ("Could not write installed files list %s" % \ self.warn("Could not write installed files list %s" %
INSTALLED_FILES) INSTALLED_FILES)
return return
file.write (data) file.write(data)
file.close () file.close()
class install_data (_install_data): class install_data(_install_data):
def run (self): def run(self):
def chmod_data_file (file): def chmod_data_file(file):
try: try:
os.chmod (file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) os.chmod(file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
except: except:
self.warn ("Could not chmod data file %s" % file) self.warn("Could not chmod data file %s" % file)
_install_data.run (self) _install_data.run(self)
map (chmod_data_file, self.get_outputs ()) map(chmod_data_file, self.get_outputs())
class uninstall (_install): class uninstall(_install):
def run (self): def run(self):
try: try:
file = open (INSTALLED_FILES, "r") file = open(INSTALLED_FILES, "r")
except: except:
self.warn ("Could not read installed files list %s" % \ self.warn("Could not read installed files list %s" %
INSTALLED_FILES) INSTALLED_FILES)
return return
files = file.readlines () files = file.readlines()
file.close () file.close()
prepend = "" prepend = ""
if self.root: if self.root:
prepend += self.root prepend += self.root
if self.prefix: if self.prefix:
prepend += self.prefix prepend += self.prefix
if len (prepend): if len(prepend):
for counter in xrange (len (files)): for counter in xrange(len(files)):
files[counter] = prepend + files[counter].rstrip () files[counter] = prepend + files[counter].rstrip()
for file in files: for file in files:
print "Uninstalling %s" % file print "Uninstalling", file
try: try:
os.unlink (file) os.unlink(file)
except: except:
self.warn ("Could not remove file %s" % file) self.warn("Could not remove file %s" % file)
ops = ("install", "build", "sdist", "uninstall", "clean", "build_ext") ops = ("install", "build", "sdist", "uninstall", "clean", "build_ext")
if len (sys.argv) < 2 or sys.argv[1] not in ops: if len(sys.argv) < 2 or sys.argv[1] not in ops:
print "Please specify operation : %s" % " | ".join (ops) print "Please specify operation : %s" % " | ".join(ops)
raise SystemExit raise SystemExit
prefix = None prefix = None
if len (sys.argv) > 2: if len(sys.argv) > 2:
i = 0 i = 0
for o in sys.argv: for o in sys.argv:
if o.startswith ("--prefix"): if o.startswith("--prefix"):
if o == "--prefix": if o == "--prefix":
if len (sys.argv) >= i: if len(sys.argv) >= i:
prefix = sys.argv[i + 1] prefix = sys.argv[i + 1]
sys.argv.remove (prefix) sys.argv.remove(prefix)
elif o.startswith ("--prefix=") and len (o[9:]): elif o.startswith("--prefix=") and len(o[9:]):
prefix = o[9:] prefix = o[9:]
sys.argv.remove (o) sys.argv.remove(o)
i += 1 i += 1
if not prefix and "PREFIX" in os.environ: if not prefix and "PREFIX" in os.environ:
prefix = os.environ["PREFIX"] prefix = os.environ["PREFIX"]
if not prefix or not len (prefix): if not prefix or not len(prefix):
prefix = sys.prefix prefix = sys.prefix
if sys.argv[1] in ("install", "uninstall") and len (prefix): if sys.argv[1] in("install", "uninstall") and len(prefix):
sys.argv += ["--prefix", prefix] sys.argv += ["--prefix", prefix]
target_images_path = "share/pronterface/images/" target_images_path = "share/pronterface/images/"
data_files = [('share/pixmaps/', ['P-face.ico','plater.ico','pronsole.ico'])] data_files = [('share/pixmaps/', ['P-face.ico', 'plater.ico', 'pronsole.ico'])]
for basedir, subdirs, files in os.walk("images"): for basedir, subdirs, files in os.walk("images"):
images = [] images = []
...@@ -135,23 +135,22 @@ for basedir, subdirs, files in os.walk("locale"): ...@@ -135,23 +135,22 @@ for basedir, subdirs, files in os.walk("locale"):
destpath = os.path.join("share", "pronterface", basedir) destpath = os.path.join("share", "pronterface", basedir)
files = filter(lambda x: x.endswith(".mo"), files) files = filter(lambda x: x.endswith(".mo"), files)
files = map(lambda x: os.path.join(basedir, x), files) files = map(lambda x: os.path.join(basedir, x), files)
data_files.append ((destpath, files)) data_files.append((destpath, files))
extra_data_dirs = ["css"] extra_data_dirs = ["css"]
for extra_data_dir in extra_data_dirs: for extra_data_dir in extra_data_dirs:
for basedir, subdirs, files in os.walk(extra_data_dir): for basedir, subdirs, files in os.walk(extra_data_dir):
files = map(lambda x: os.path.join(basedir, x), files) files = map(lambda x: os.path.join(basedir, x), files)
destpath = os.path.join("share", "pronterface", basedir) destpath = os.path.join("share", "pronterface", basedir)
data_files.append ((destpath, files)) data_files.append((destpath, files))
cmdclass = {"uninstall" : uninstall, cmdclass = {"uninstall": uninstall,
"install" : install, "install": install,
"install_data" : install_data} "install_data": install_data}
if build_ext: if build_ext:
cmdclass['build_ext'] = build_ext cmdclass['build_ext'] = build_ext
setup ( setup(name = "Printrun",
name = "Printrun",
description = "Host software for 3D printers", description = "Host software for 3D printers",
author = "Kliment Yanev", author = "Kliment Yanev",
url = "http://github.com/kliment/Printrun/", url = "http://github.com/kliment/Printrun/",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment