1 from __future__ import absolute_import
4 import wx, sys, os, shutil, math, threading, subprocess, time, re
6 from util import profile
7 from util import sliceRun
8 from util import exporer
9 from util import gcodeInterpreter
11 class sliceProgessPanel(wx.Panel):
12 def __init__(self, mainWindow, parent, filelist):
13 wx.Panel.__init__(self, parent, -1)
14 self.mainWindow = mainWindow
15 self.filelist = filelist
18 box = wx.StaticBox(self, -1, filelist[0])
19 self.sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
21 mainSizer = wx.BoxSizer(wx.VERTICAL)
22 mainSizer.Add(self.sizer, 0, flag=wx.EXPAND)
24 self.statusText = wx.StaticText(self, -1, "Starting...")
25 self.progressGauge = wx.Gauge(self, -1)
26 self.progressGauge.SetRange(10000 * len(filelist))
27 self.abortButton = wx.Button(self, -1, "X", style=wx.BU_EXACTFIT)
28 self.sizer.Add(self.statusText, 2, flag=wx.ALIGN_CENTER )
29 self.sizer.Add(self.progressGauge, 2)
30 self.sizer.Add(self.abortButton, 0)
32 self.Bind(wx.EVT_BUTTON, self.OnAbort, self.abortButton)
34 self.SetSizer(mainSizer)
35 self.prevStep = 'start'
36 self.totalDoneFactor = 0.0
37 self.startTime = time.time()
38 if profile.getPreference('save_profile') == 'True':
39 profile.saveGlobalProfile(self.filelist[0][: self.filelist[0].rfind('.')] + "_profile.ini")
41 for filename in self.filelist:
42 idx = self.filelist.index(filename)
45 profile.setTempOverride('fan_enabled', 'False')
46 profile.setTempOverride('skirt_line_count', '0')
47 profile.setTempOverride('machine_center_x', profile.getProfileSettingFloat('machine_center_x') - profile.getPreferenceFloat('extruder_offset_x%d' % (idx)))
48 profile.setTempOverride('machine_center_y', profile.getProfileSettingFloat('machine_center_y') - profile.getPreferenceFloat('extruder_offset_y%d' % (idx)))
49 profile.setTempOverride('alternative_center', self.filelist[0])
50 if len(self.filelist) > 1:
51 profile.setTempOverride('add_start_end_gcode', 'False')
52 profile.setTempOverride('gcode_extension', 'multi_extrude_tmp')
53 cmdList.append(sliceRun.getSliceCommand(filename))
54 profile.resetTempOverride()
55 self.thread = WorkerThread(self, filelist, cmdList)
59 self.mainWindow.removeSliceProgress(self)
63 def OnShowGCode(self, e):
64 self.mainWindow.preview3d.loadModelFiles(self.filelist)
65 self.mainWindow.preview3d.setViewMode("GCode")
67 def OnShowLog(self, e):
68 LogWindow('\n'.join(self.progressLog))
70 def OnOpenFileLocation(self, e):
71 exporer.openExporer(sliceRun.getExportFilename(self.filelist[0]))
73 def OnCopyToSD(self, e):
74 exportFilename = sliceRun.getExportFilename(self.filelist[0])
75 filename = os.path.basename(exportFilename)
76 if profile.getPreference('sdshortnames') == 'True':
77 filename = sliceRun.getShortFilename(filename)
78 shutil.copy(exportFilename, os.path.join(profile.getPreference('sdpath'), filename))
80 def OnSliceDone(self, result):
81 self.progressGauge.Destroy()
82 self.abortButton.Destroy()
83 self.progressLog = result.progressLog
84 self.logButton = wx.Button(self, -1, "Show Log")
85 self.abortButton = wx.Button(self, -1, "X", style=wx.BU_EXACTFIT)
86 self.Bind(wx.EVT_BUTTON, self.OnShowLog, self.logButton)
87 self.Bind(wx.EVT_BUTTON, self.OnAbort, self.abortButton)
88 self.sizer.Add(self.logButton, 0)
89 if result.returnCode == 0:
90 status = "Ready: Filament: %.2fm %.2fg" % (result.gcode.extrusionAmount / 1000, result.gcode.calculateWeight() * 1000)
91 status += " Print time: %02d:%02d" % (int(result.gcode.totalMoveTimeMinute / 60), int(result.gcode.totalMoveTimeMinute % 60))
92 cost = result.gcode.calculateCost()
94 status += " Cost: %s" % (cost)
95 self.statusText.SetLabel(status)
96 if exporer.hasExporer():
97 self.openFileLocationButton = wx.Button(self, -1, "Open file location")
98 self.Bind(wx.EVT_BUTTON, self.OnOpenFileLocation, self.openFileLocationButton)
99 self.sizer.Add(self.openFileLocationButton, 0)
100 if profile.getPreference('sdpath') != '':
101 self.copyToSDButton = wx.Button(self, -1, "To SDCard")
102 self.Bind(wx.EVT_BUTTON, self.OnCopyToSD, self.copyToSDButton)
103 self.sizer.Add(self.copyToSDButton, 0)
104 self.showButton = wx.Button(self, -1, "Show result")
105 self.Bind(wx.EVT_BUTTON, self.OnShowGCode, self.showButton)
106 self.sizer.Add(self.showButton, 0)
108 self.statusText.SetLabel("Something went wrong during slicing!")
109 self.sizer.Add(self.abortButton, 0)
113 if self.mainWindow.preview3d.loadReModelFiles(self.filelist):
114 self.mainWindow.preview3d.setViewMode("GCode")
116 def SetProgress(self, stepName, layer, maxLayer):
117 if self.prevStep != stepName:
118 self.totalDoneFactor += sliceRun.sliceStepTimeFactor[self.prevStep]
119 newTime = time.time()
120 #print "#####" + str(newTime-self.startTime) + " " + self.prevStep + " -> " + stepName
121 self.startTime = newTime
122 self.prevStep = stepName
124 progresValue = ((self.totalDoneFactor + sliceRun.sliceStepTimeFactor[stepName] * layer / maxLayer) / sliceRun.totalRunTimeFactor) * 10000
125 self.progressGauge.SetValue(int(progresValue))
126 self.statusText.SetLabel(stepName + " [" + str(layer) + "/" + str(maxLayer) + "]")
128 class WorkerThread(threading.Thread):
129 def __init__(self, notifyWindow, filelist, cmdList):
130 threading.Thread.__init__(self)
131 self.filelist = filelist
132 self.notifyWindow = notifyWindow
133 self.cmdList = cmdList
139 if subprocess.mswindows:
140 su = subprocess.STARTUPINFO()
141 su.dwFlags |= subprocess.STARTF_USESHOWWINDOW
142 su.wShowWindow = subprocess.SW_HIDE
143 kwargs['startupinfo'] = su
144 print self.cmdList[self.fileIdx]
145 p = subprocess.Popen(self.cmdList[self.fileIdx], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)
146 line = p.stdout.readline()
147 self.progressLog = []
149 while(len(line) > 0):
151 if line[0:9] == "Progress[" and line[-1:] == "]":
152 progress = line[9:-1].split(":")
153 if len(progress) > 2:
154 maxValue = int(progress[2])
155 wx.CallAfter(self.notifyWindow.SetProgress, progress[0], int(progress[1]), maxValue)
157 self.progressLog.append(line)
158 wx.CallAfter(self.notifyWindow.statusText.SetLabel, line)
159 if self.notifyWindow.abort:
161 wx.CallAfter(self.notifyWindow.statusText.SetLabel, "Aborted by user.")
163 line = p.stdout.readline()
164 self.returnCode = p.wait()
166 if self.fileIdx == len(self.cmdList):
167 if len(self.filelist) > 1:
168 self._stitchMultiExtruder()
169 gcodeFilename = sliceRun.getExportFilename(self.filelist[0])
170 gcodefile = open(gcodeFilename, "a")
171 for logLine in self.progressLog:
172 if logLine.startswith('Model error('):
173 gcodefile.write(';%s\n' % (logLine))
175 self.gcode = gcodeInterpreter.gcode()
176 self.gcode.load(gcodeFilename)
177 profile.replaceGCodeTags(gcodeFilename, self.gcode)
178 wx.CallAfter(self.notifyWindow.OnSliceDone, self)
182 def _stitchMultiExtruder(self):
184 resultFile = open(sliceRun.getExportFilename(self.filelist[0]), "w")
185 resultFile.write(';TYPE:CUSTOM\n')
186 resultFile.write(profile.getAlterationFileContents('start.gcode'))
187 for filename in self.filelist:
188 if os.path.isfile(sliceRun.getExportFilename(filename, 'multi_extrude_tmp')):
189 files.append(open(sliceRun.getExportFilename(filename, 'multi_extrude_tmp'), "r"))
194 resultFile.write('T%d\n' % (currentExtruder))
203 if line.startswith(';LAYER:'):
206 lastZ = float(re.search('Z([^\s]+)', line).group(1))
208 nextExtruder = files.index(f)
209 resultFile.write(';LAYER:%d\n' % (layerNr))
210 resultFile.write(';EXTRUDER:%d\n' % (nextExtruder))
211 if nextExtruder != currentExtruder:
212 resultFile.write(';TYPE:CUSTOM\n')
213 profile.setTempOverride('extruder', nextExtruder)
214 resultFile.write(profile.getAlterationFileContents('switchExtruder.gcode'))
215 profile.resetTempOverride()
216 currentExtruder = nextExtruder
218 resultFile.write(line)
222 for filename in self.filelist:
223 os.remove(sliceRun.getExportFilename(filename, 'multi_extrude_tmp'))
224 resultFile.write(';TYPE:CUSTOM\n')
225 resultFile.write(profile.getAlterationFileContents('end.gcode'))
228 class LogWindow(wx.Frame):
229 def __init__(self, logText):
230 super(LogWindow, self).__init__(None, title="Slice log")
231 self.textBox = wx.TextCtrl(self, -1, logText, style=wx.TE_MULTILINE|wx.TE_DONTWRAP|wx.TE_READONLY)
232 self.SetSize((400,300))