Merge remote-tracking branch 'upstream/master'

master
Ferdi van der Werf 2012-04-24 20:04:51 +02:00
commit a4ba5afb67
9 changed files with 270 additions and 145 deletions

View File

@ -84,8 +84,10 @@ class mainWindow(configBase.configWindowBase):
menubar.Append(helpMenu, 'Help')
self.SetMenuBar(menubar)
self.lastPath = ""
self.filename = profile.getPreference('lastFile')
if profile.getPreference('lastFile') != '':
self.filelist = profile.getPreference('lastFile').split(';')
else:
self.filelist = []
self.progressPanelList = []
#Preview window
@ -189,6 +191,18 @@ class mainWindow(configBase.configWindowBase):
self.Bind(wx.EVT_BUTTON, self.OnLoadModel, loadButton)
self.Bind(wx.EVT_BUTTON, self.OnSlice, sliceButton)
self.Bind(wx.EVT_BUTTON, self.OnPrint, printButton)
extruderCount = int(profile.getPreference('extruder_amount'))
if extruderCount > 1:
loadButton2 = wx.Button(self, -1, 'Load Dual')
self.Bind(wx.EVT_BUTTON, self.OnLoadModel2, loadButton2)
if extruderCount > 2:
loadButton3 = wx.Button(self, -1, 'Load Tripple')
self.Bind(wx.EVT_BUTTON, self.OnLoadModel3, loadButton3)
if extruderCount > 2:
loadButton4 = wx.Button(self, -1, 'Load Quad')
self.Bind(wx.EVT_BUTTON, self.OnLoadModel4, loadButton4)
#Also bind double clicking the 3D preview to load an STL file.
self.preview3d.glCanvas.Bind(wx.EVT_LEFT_DCLICK, self.OnLoadModel, self.preview3d.glCanvas)
@ -196,17 +210,22 @@ class mainWindow(configBase.configWindowBase):
sizer = wx.GridBagSizer()
self.SetSizer(sizer)
sizer.Add(nb, (0,0), span=(1,1), flag=wx.EXPAND)
sizer.Add(self.preview3d, (0,1), span=(1,3), flag=wx.EXPAND)
sizer.AddGrowableCol(2)
sizer.Add(self.preview3d, (0,1), span=(1,2+extruderCount), flag=wx.EXPAND)
sizer.AddGrowableCol(2 + extruderCount)
sizer.AddGrowableRow(0)
sizer.Add(loadButton, (1,1), flag=wx.RIGHT, border=5)
sizer.Add(sliceButton, (1,2), flag=wx.RIGHT, border=5)
sizer.Add(printButton, (1,3), flag=wx.RIGHT, border=5)
if extruderCount > 1:
sizer.Add(loadButton2, (1,2), flag=wx.RIGHT, border=5)
if extruderCount > 2:
sizer.Add(loadButton3, (1,3), flag=wx.RIGHT, border=5)
if extruderCount > 3:
sizer.Add(loadButton4, (1,4), flag=wx.RIGHT, border=5)
sizer.Add(sliceButton, (1,1+extruderCount), flag=wx.RIGHT, border=5)
sizer.Add(printButton, (1,2+extruderCount), flag=wx.RIGHT, border=5)
self.sizer = sizer
if self.filename != "None":
self.preview3d.loadModelFile(self.filename)
self.lastPath = os.path.split(self.filename)[0]
if len(self.filelist) > 0:
self.preview3d.loadModelFiles(self.filelist)
self.updateProfileToControls()
@ -261,25 +280,48 @@ class mainWindow(configBase.configWindowBase):
configWizard.configWizard()
self.updateProfileToControls()
def OnLoadModel(self, e):
dlg=wx.FileDialog(self, "Open file to print", self.lastPath, style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
dlg.SetWildcard("STL files (*.stl)|*.stl;*.STL")
def _showOpenDialog(self, title, wildcard = "STL files (*.stl)|*.stl;*.STL"):
dlg=wx.FileDialog(self, title, os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
dlg.SetWildcard(wildcard)
if dlg.ShowModal() == wx.ID_OK:
self.filename=dlg.GetPath()
profile.putPreference('lastFile', self.filename)
if not(os.path.exists(self.filename)):
return
self.lastPath = os.path.split(self.filename)[0]
self.preview3d.loadModelFile(self.filename)
self.preview3d.setViewMode("Normal")
filename = dlg.GetPath()
dlg.Destroy()
if not(os.path.exists(filename)):
return False
profile.putPreference('lastFile', filename)
return filename
dlg.Destroy()
return False
def _showModelLoadDialog(self, amount):
filelist = []
for i in xrange(0, amount):
filelist.append(self._showOpenDialog("Open file to print"))
if filelist[-1] == False:
return
self.filelist = filelist
profile.putPreference('lastFile', ';'.join(self.filelist))
self.preview3d.loadModelFiles(self.filelist)
self.preview3d.setViewMode("Normal")
def OnLoadModel(self, e):
self._showModelLoadDialog(1)
def OnLoadModel2(self, e):
self._showModelLoadDialog(2)
def OnLoadModel3(self, e):
self._showModelLoadDialog(3)
def OnLoadModel4(self, e):
self._showModelLoadDialog(4)
def OnSlice(self, e):
if self.filename == None:
if len(self.filelist) < 1:
wx.MessageBox('You need to load a file before you can slice it.', 'Print error', wx.OK | wx.ICON_INFORMATION)
return
#Create a progress panel and add it to the window. The progress panel will start the Skein operation.
spp = sliceProgessPanel.sliceProgessPanel(self, self, self.filename)
spp = sliceProgessPanel.sliceProgessPanel(self, self, self.filelist)
self.sizer.Add(spp, (len(self.progressPanelList)+2,0), span=(1,4), flag=wx.EXPAND)
self.sizer.Layout()
newSize = self.GetSize();
@ -288,13 +330,13 @@ class mainWindow(configBase.configWindowBase):
self.progressPanelList.append(spp)
def OnPrint(self, e):
if self.filename == None:
if len(self.filelist) < 1:
wx.MessageBox('You need to load a file and slice it before you can print it.', 'Print error', wx.OK | wx.ICON_INFORMATION)
return
if not os.path.exists(self.filename[: self.filename.rfind('.')] + "_export.gcode"):
if not os.path.exists(self.filelist[0][: self.filelist[0].rfind('.')] + "_export.gcode"):
wx.MessageBox('You need to slice the file to GCode before you can print it.', 'Print error', wx.OK | wx.ICON_INFORMATION)
return
printWindow.printFile(self.filename[: self.filename.rfind('.')] + "_export.gcode")
printWindow.printFile(self.filelist[0][: self.filelist[0].rfind('.')] + "_export.gcode")
def OnExpertOpen(self, e):
ecw = expertConfig.expertConfigWindow()

View File

@ -24,6 +24,7 @@ class preferencesDialog(configBase.configWindowBase):
validators.validFloat(c, 10.0)
c = configBase.SettingRow(left, 'Machine height (mm)', 'machine_height', '200', 'Size of the machine in mm', type = 'preference')
validators.validFloat(c, 10.0)
c = configBase.SettingRow(left, 'Extruder count', 'extruder_amount', ['1', '2', '3', '4'], 'Amount of extruders in your machine.', type = 'preference')
configBase.TitleRow(left, 'Filament settings')
c = configBase.SettingRow(left, 'Filament density (kg/m3)', 'filament_density', '1300', 'Weight of the filament per m3. Around 1300 for PLA. And around 1040 for ABS. This value is used to estimate the weight if the filament used for the print.', type = 'preference')
@ -38,7 +39,7 @@ class preferencesDialog(configBase.configWindowBase):
c = configBase.SettingRow(left, 'Baudrate', 'serial_baud', '250000', 'Speed of the serial port communication\nNeeds to match your firmware settings\nCommon values are 250000, 115200, 57600', type = 'preference')
configBase.TitleRow(left, 'Slicer settings')
c = configBase.SettingRow(left, 'Slicer selection', 'slicer', ['Cura (Skeinforge based)', 'Slic3r'], 'Which slicer to use to slice objects. Usually the Cura engine produces the best results. But Slic3r is developing fast and is faster with slicing.', type = 'preference')
#c = configBase.SettingRow(left, 'Slicer selection', 'slicer', ['Cura (Skeinforge based)', 'Slic3r'], 'Which slicer to use to slice objects. Usually the Cura engine produces the best results. But Slic3r is developing fast and is faster with slicing.', type = 'preference')
c = configBase.SettingRow(left, 'Save profile on slice', 'save_profile', False, 'When slicing save the profile as [stl_file]_profile.ini next to the model.', type = 'preference')
self.MakeModal(True)

View File

@ -27,6 +27,13 @@ from util import gcodeInterpreter
from util import stl
from util import util3d
class previewObject():
def __init__(self):
self.mesh = None
self.filename = None
self.displayList = None
self.dirty = False
class previewPanel(wx.Panel):
def __init__(self, parent):
super(previewPanel, self).__init__(parent,-1)
@ -35,11 +42,10 @@ class previewPanel(wx.Panel):
self.SetMinSize((440,320))
self.glCanvas = PreviewGLCanvas(self)
self.init = 0
self.triangleMesh = None
self.objectList = []
self.gcode = None
self.modelFilename = None
self.loadingProgressAmount = 0
self.objectsMinV = None
self.objectsMaxV = None
self.loadThread = None
self.machineSize = util3d.Vector3(float(profile.getPreference('machine_width')), float(profile.getPreference('machine_depth')), float(profile.getPreference('machine_height')))
self.machineCenter = util3d.Vector3(float(profile.getProfileSetting('machine_center_x')), float(profile.getProfileSetting('machine_center_y')), 0)
@ -138,10 +144,10 @@ class previewPanel(wx.Panel):
self.glCanvas.Refresh()
def OnScaleMax(self, e):
if self.triangleMesh == None:
if self.objectsMinV == None:
return
vMin = self.triangleMesh.getMinimum()
vMax = self.triangleMesh.getMaximum()
vMin = self.objectsMinV
vMax = self.objectsMaxV
scaleX1 = (self.machineSize.x - self.machineCenter.x) / ((vMax.x - vMin.x) / 2)
scaleY1 = (self.machineSize.y - self.machineCenter.y) / ((vMax.y - vMin.y) / 2)
scaleX2 = (self.machineCenter.x) / ((vMax.x - vMin.x) / 2)
@ -194,15 +200,21 @@ class previewPanel(wx.Panel):
self.glCanvas.viewMode = mode
wx.CallAfter(self.glCanvas.Refresh)
def loadModelFile(self, filename):
if self.modelFilename != filename:
self.modelFileTime = None
self.gcodeFileTime = None
self.logFileTime = None
def loadModelFiles(self, filelist):
while len(filelist) > len(self.objectList):
self.objectList.append(previewObject())
for idx in xrange(len(self.objectList), len(filelist)):
self.objectList[idx].mesh = None
for idx in xrange(0, len(filelist)):
obj = self.objectList[idx]
if obj.filename != filelist[idx]:
obj.fileTime = None
self.gcodeFileTime = None
self.logFileTime = None
obj.filename = filelist[idx]
self.modelFilename = filename
self.gcodeFilename = filename[: filename.rfind('.')] + "_export.gcode"
self.logFilename = filename[: filename.rfind('.')] + "_export.log"
self.gcodeFilename = filelist[0][: filelist[0].rfind('.')] + "_export.gcode"
self.logFilename = filelist[0][: filelist[0].rfind('.')] + "_export.log"
#Do the STL file loading in a background thread so we don't block the UI.
if self.loadThread != None and self.loadThread.isAlive():
self.loadThread.join()
@ -210,35 +222,32 @@ class previewPanel(wx.Panel):
self.loadThread.daemon = True
self.loadThread.start()
def loadReModelFile(self, filename):
def loadReModelFiles(self, filelist):
#Only load this again if the filename matches the file we have already loaded (for auto loading GCode after slicing)
if self.modelFilename != filename:
return False
self.loadModelFile(filename)
for idx in xrange(0, len(filelist)):
if self.objectList[idx].filename != filelist[idx]:
return False
self.loadModelFiles(filelist)
return True
def doFileLoadThread(self):
if os.path.isfile(self.modelFilename) and self.modelFileTime != os.stat(self.modelFilename).st_mtime:
self.modelFileTime = os.stat(self.modelFilename).st_mtime
triangleMesh = stl.stlModel()
triangleMesh.load(self.modelFilename)
triangleMesh.origonalVertexes = list(triangleMesh.vertexes)
for i in xrange(0, len(triangleMesh.origonalVertexes)):
triangleMesh.origonalVertexes[i] = triangleMesh.origonalVertexes[i].copy()
triangleMesh.getMinimumZ()
self.modelDirty = False
self.errorList = []
self.triangleMesh = triangleMesh
self.updateModelTransform()
wx.CallAfter(self.updateToolbar)
wx.CallAfter(self.glCanvas.Refresh)
for obj in self.objectList:
if os.path.isfile(obj.filename) and obj.fileTime != os.stat(obj.filename).st_mtime:
obj.ileTime = os.stat(obj.filename).st_mtime
mesh = stl.stlModel()
mesh.load(obj.filename)
obj.dirty = False
obj.errorList = []
obj.mesh = mesh
self.updateModelTransform()
wx.CallAfter(self.updateToolbar)
wx.CallAfter(self.glCanvas.Refresh)
if os.path.isfile(self.gcodeFilename) and self.gcodeFileTime != os.stat(self.gcodeFilename).st_mtime:
self.gcodeFileTime = os.stat(self.gcodeFilename).st_mtime
gcode = gcodeInterpreter.gcode()
gcode.progressCallback = self.loadProgress
gcode.load(self.gcodeFilename)
self.loadingProgressAmount = 0
self.gcodeDirty = False
self.errorList = []
self.gcode = gcode
@ -260,8 +269,7 @@ class previewPanel(wx.Panel):
wx.CallAfter(self.glCanvas.Refresh)
def loadProgress(self, progress):
self.loadingProgressAmount = progress
wx.CallAfter(self.glCanvas.Refresh)
pass
def updateToolbar(self):
self.layerSpin.Show(self.gcode != None)
@ -283,8 +291,6 @@ class previewPanel(wx.Panel):
self.glCanvas.Refresh()
def updateModelTransform(self, f=0):
if self.triangleMesh == None:
return
rotate = profile.getProfileSettingFloat('model_rotate_base') / 180.0 * math.pi
scaleX = 1.0
scaleY = 1.0
@ -302,34 +308,54 @@ class previewPanel(wx.Panel):
mat10 = math.sin(rotate) * scaleX
mat11 = math.cos(rotate) * scaleY
for i in xrange(0, len(self.triangleMesh.origonalVertexes)):
x = self.triangleMesh.origonalVertexes[i].x
y = self.triangleMesh.origonalVertexes[i].y
z = self.triangleMesh.origonalVertexes[i].z
if swapXZ:
x, z = z, x
if swapYZ:
y, z = z, y
self.triangleMesh.vertexes[i].x = x * mat00 + y * mat01
self.triangleMesh.vertexes[i].y = x * mat10 + y * mat11
self.triangleMesh.vertexes[i].z = z * scaleZ
if len(self.objectList) < 1 or self.objectList[0].mesh == None:
return
for face in self.triangleMesh.faces:
v1 = face.v[0]
v2 = face.v[1]
v3 = face.v[2]
face.normal = (v2 - v1).cross(v3 - v1)
face.normal.normalize()
for obj in self.objectList:
if obj.mesh == None:
continue
for i in xrange(0, len(obj.mesh.origonalVertexes)):
x = obj.mesh.origonalVertexes[i].x
y = obj.mesh.origonalVertexes[i].y
z = obj.mesh.origonalVertexes[i].z
if swapXZ:
x, z = z, x
if swapYZ:
y, z = z, y
obj.mesh.vertexes[i].x = x * mat00 + y * mat01
obj.mesh.vertexes[i].y = x * mat10 + y * mat11
obj.mesh.vertexes[i].z = z * scaleZ
minZ = self.triangleMesh.getMinimumZ()
min = self.triangleMesh.getMinimum()
max = self.triangleMesh.getMaximum()
for v in self.triangleMesh.vertexes:
v.z -= minZ
v.x -= min.x + (max.x - min.x) / 2
v.y -= min.y + (max.y - min.y) / 2
self.triangleMesh.getMinimumZ()
self.modelDirty = True
for face in obj.mesh.faces:
v1 = face.v[0]
v2 = face.v[1]
v3 = face.v[2]
face.normal = (v2 - v1).cross(v3 - v1)
face.normal.normalize()
minV = self.objectList[0].mesh.getMinimum()
maxV = self.objectList[0].mesh.getMaximum()
for obj in self.objectList:
if obj.mesh == None:
continue
obj.mesh.getMinimumZ()
minV = minV.min(obj.mesh.getMinimum())
maxV = maxV.max(obj.mesh.getMaximum())
self.objectsMaxV = maxV
self.objectsMinV = minV
for obj in self.objectList:
if obj.mesh == None:
continue
for v in obj.mesh.vertexes:
v.z -= minV.z
v.x -= minV.x + (maxV.x - minV.x) / 2
v.y -= minV.y + (maxV.y - minV.y) / 2
obj.mesh.getMinimumZ()
obj.dirty = True
self.glCanvas.Refresh()
class PreviewGLCanvas(glcanvas.GLCanvas):
@ -349,8 +375,8 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
self.offsetX = 0
self.offsetY = 0
self.view3D = True
self.modelDisplayList = None
self.gcodeDisplayList = None
self.objColor = [[1.0, 0.8, 0.6, 1.0], [0.2, 1.0, 0.1, 1.0], [1.0, 0.2, 0.1, 1.0], [0.1, 0.2, 1.0, 1.0]]
def OnMouseMotion(self,e):
if e.Dragging() and e.LeftIsDown():
@ -398,8 +424,8 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
glTranslate(0,0,-self.zoom)
glRotate(-self.pitch, 1,0,0)
glRotate(self.yaw, 0,0,1)
if self.parent.triangleMesh != None:
glTranslate(0,0,-self.parent.triangleMesh.getMaximum().z * profile.getProfileSettingFloat('model_scale') / 2)
if self.parent.objectsMaxV != None:
glTranslate(0,0,-self.parent.objectsMaxV.z * profile.getProfileSettingFloat('model_scale') / 2)
else:
glScale(1.0/self.zoom, 1.0/self.zoom, 1.0)
glTranslate(self.offsetX, self.offsetY, 0.0)
@ -505,26 +531,28 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
if self.viewMode == "GCode" or self.viewMode == "Mixed":
glCallList(self.gcodeDisplayList)
if self.parent.triangleMesh != None:
if self.modelDisplayList == None:
self.modelDisplayList = glGenLists(1);
if self.parent.modelDirty:
self.parent.modelDirty = False
glNewList(self.modelDisplayList, GL_COMPILE)
opengl.DrawSTL(self.parent.triangleMesh)
glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, 0)
for obj in self.parent.objectList:
if obj.mesh == None:
continue
if obj.displayList == None:
obj.displayList = glGenLists(1);
if obj.dirty:
obj.dirty = False
glNewList(obj.displayList, GL_COMPILE)
opengl.DrawSTL(obj.mesh)
glEndList()
glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, 0)
glEnable(GL_NORMALIZE)
if self.viewMode == "Transparent" or self.viewMode == "Mixed":
glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.5, 0.4, 0.3, 1.0])
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.1, 0.1, 0.1, 0.0])
glLightfv(GL_LIGHT0, GL_DIFFUSE, map(lambda x: x / 2, self.objColor[self.parent.objectList.index(obj)]))
glLightfv(GL_LIGHT0, GL_AMBIENT, map(lambda x: x / 10, self.objColor[self.parent.objectList.index(obj)]))
#If we want transparent, then first render a solid black model to remove the printer size lines.
if self.viewMode != "Mixed":
glDisable(GL_BLEND)
glDisable(GL_LIGHTING)
glColor3f(0,0,0)
self.drawModel()
self.drawModel(obj)
glColor3f(1,1,1)
#After the black model is rendered, render the model again but now with lighting and no depth testing.
glDisable(GL_DEPTH_TEST)
@ -532,23 +560,23 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
glEnable(GL_BLEND)
glBlendFunc(GL_ONE, GL_ONE)
glEnable(GL_LIGHTING)
self.drawModel()
self.drawModel(obj)
elif self.viewMode == "X-Ray":
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
glDisable(GL_DEPTH_TEST)
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, 1)
glStencilOp(GL_INCR, GL_INCR, GL_INCR)
self.drawModel()
self.drawModel(obj)
glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
glStencilFunc(GL_EQUAL, 0, 1);
glColor(1, 1, 1)
self.drawModel()
self.drawModel(obj)
glStencilFunc(GL_EQUAL, 1, 1);
glColor(1, 0, 0)
self.drawModel()
self.drawModel(obj)
glPushMatrix()
glLoadIdentity()
@ -575,28 +603,29 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
glDisable(GL_STENCIL_TEST);
glEnable(GL_DEPTH_TEST)
elif self.viewMode == "Normal":
glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 0.8, 0.6, 1.0])
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.2, 0.2, 0.2, 0.0])
glLightfv(GL_LIGHT0, GL_DIFFUSE, self.objColor[self.parent.objectList.index(obj)])
glLightfv(GL_LIGHT0, GL_AMBIENT, map(lambda x: x / 5, self.objColor[self.parent.objectList.index(obj)]))
glEnable(GL_LIGHTING)
self.drawModel()
self.drawModel(obj)
if self.viewMode == "Normal" or self.viewMode == "Transparent" or self.viewMode == "X-Ray":
glDisable(GL_LIGHTING)
glDisable(GL_DEPTH_TEST)
glDisable(GL_BLEND)
glColor3f(1,0,0)
glBegin(GL_LINES)
for err in self.parent.errorList:
glVertex3f(err[0].x, err[0].y, err[0].z)
glVertex3f(err[1].x, err[1].y, err[1].z)
glEnd()
#glBegin(GL_LINES)
#for err in self.parent.errorList:
# glVertex3f(err[0].x, err[0].y, err[0].z)
# glVertex3f(err[1].x, err[1].y, err[1].z)
#glEnd()
glEnable(GL_DEPTH_TEST)
glFlush()
def drawModel(self):
def drawModel(self, obj):
multiX = int(profile.getProfileSetting('model_multiply_x'))
multiY = int(profile.getProfileSetting('model_multiply_y'))
modelScale = profile.getProfileSettingFloat('model_scale')
modelSize = (self.parent.triangleMesh.getMaximum() - self.parent.triangleMesh.getMinimum()) * modelScale
modelSize = (obj.mesh.getMaximum() - obj.mesh.getMinimum()) * modelScale
glPushMatrix()
glTranslate(-(modelSize.x+10)*(multiX-1)/2,-(modelSize.y+10)*(multiY-1)/2, 0)
for mx in xrange(0, multiX):
@ -604,7 +633,7 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
glPushMatrix()
glTranslate((modelSize.x+10)*mx,(modelSize.y+10)*my, 0)
glScalef(modelScale, modelScale, modelScale)
glCallList(self.modelDisplayList)
glCallList(obj.displayList)
glPopMatrix()
glPopMatrix()

View File

@ -707,11 +707,11 @@ class ProjectSliceProgressWindow(wx.Frame):
if action == self.actionList[0]:
resultFile.write(';TYPE:CUSTOM\n')
resultFile.write(profile.getAlterationFileContents('start.gcode'))
resultFile.write(profile.getAlterationFileContents('start.gcode').encode('utf-8')
else:
#reset the extrusion length, and move to the next object center.
resultFile.write(';TYPE:CUSTOM\n')
resultFile.write(profile.getAlterationFileContents('nextobject.gcode'))
resultFile.write(profile.getAlterationFileContents('nextobject.gcode').encode('utf-8')
resultFile.write(';PRINTNR:%d\n' % self.actionList.index(action))
profile.loadGlobalProfileFromString(oldProfile)
@ -727,7 +727,7 @@ class ProjectSliceProgressWindow(wx.Frame):
wx.CallAfter(self.progressGauge2.SetValue, self.actionList.index(action) + 1)
resultFile.write(';TYPE:CUSTOM\n')
resultFile.write(profile.getAlterationFileContents('end.gcode'))
resultFile.write(profile.getAlterationFileContents('end.gcode').encode('utf-8')
resultFile.close()
self.abort = True
wx.CallAfter(self.abortButton.SetLabel, 'Close')

View File

@ -1,22 +1,17 @@
from __future__ import absolute_import
import __init__
import wx
import sys
import math
import threading
import subprocess
import time
import wx, sys, os, math, threading, subprocess, time
from util import profile
from util import sliceRun
from util import exporer
class sliceProgessPanel(wx.Panel):
def __init__(self, mainWindow, parent, filename):
def __init__(self, mainWindow, parent, filelist):
wx.Panel.__init__(self, parent, -1)
self.mainWindow = mainWindow
self.filename = filename
self.filelist = filelist
self.abort = False
#How long does each step take compared to the others. This is used to make a better scaled progress bar, and guess time left.
@ -40,7 +35,7 @@ class sliceProgessPanel(wx.Panel):
for v in self.sliceStepTimeFactor.itervalues():
self.totalRunTimeFactor += v
box = wx.StaticBox(self, -1, filename)
box = wx.StaticBox(self, -1, filelist[0])
self.sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
mainSizer = wx.BoxSizer(wx.VERTICAL)
@ -61,9 +56,18 @@ class sliceProgessPanel(wx.Panel):
self.totalDoneFactor = 0.0
self.startTime = time.time()
if profile.getPreference('save_profile') == 'True':
profile.saveGlobalProfile(self.filename[: self.filename.rfind('.')] + "_profile.ini")
p = subprocess.Popen(sliceRun.getSliceCommand(self.filename), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
self.thread = WorkerThread(self, filename, p)
profile.saveGlobalProfile(self.filelist[0][: self.filelist[0].rfind('.')] + "_profile.ini")
cmdList = []
oldProfile = profile.getGlobalProfileString()
for filename in self.filelist:
if self.filelist.index(filename) > 0:
profile.putProfileSetting('fan_enabled', 'False')
if len(self.filelist) > 1:
profile.putProfileSetting('add_start_end_gcode', 'False')
profile.putProfileSetting('gcode_extension', 'multi_extrude_tmp')
cmdList.append(sliceRun.getSliceCommand(filename))
profile.loadGlobalProfileFromString(oldProfile)
self.thread = WorkerThread(self, filelist, cmdList)
def OnAbort(self, e):
if self.abort:
@ -72,14 +76,14 @@ class sliceProgessPanel(wx.Panel):
self.abort = True
def OnShowGCode(self, e):
self.mainWindow.preview3d.loadModelFile(self.filename)
self.mainWindow.preview3d.loadModelFiles(self.filelist)
self.mainWindow.preview3d.setViewMode("GCode")
def OnShowLog(self, e):
LogWindow('\n'.join(self.progressLog))
def OnOpenFileLocation(self, e):
exporer.openExporer(self.filename[: self.filename.rfind('.')] + "_export.gcode")
exporer.openExporer(self.filelist[0][: self.filelist[0].rfind('.')] + "_export.gcode")
def OnSliceDone(self, result):
self.progressGauge.Destroy()
@ -105,7 +109,7 @@ class sliceProgessPanel(wx.Panel):
self.sizer.Layout()
self.Layout()
self.abort = True
if self.mainWindow.preview3d.loadReModelFile(self.filename):
if self.mainWindow.preview3d.loadReModelFiles(self.filelist):
self.mainWindow.preview3d.setViewMode("GCode")
def SetProgress(self, stepName, layer, maxLayer):
@ -121,18 +125,19 @@ class sliceProgessPanel(wx.Panel):
self.statusText.SetLabel(stepName + " [" + str(layer) + "/" + str(maxLayer) + "]")
class WorkerThread(threading.Thread):
def __init__(self, notifyWindow, filename, process):
def __init__(self, notifyWindow, filelist, cmdList):
threading.Thread.__init__(self)
self.filename = filename
self.filelist = filelist
self.notifyWindow = notifyWindow
self.process = process
self.cmdList = cmdList
self.fileIdx = 0
self.start()
def run(self):
p = self.process
p = subprocess.Popen(self.cmdList[self.fileIdx], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
line = p.stdout.readline()
maxValue = 1
self.progressLog = []
maxValue = 1
while(len(line) > 0):
line = line.rstrip()
if line[0:9] == "Progress[" and line[-1:] == "]":
@ -150,12 +155,43 @@ class WorkerThread(threading.Thread):
return
line = p.stdout.readline()
self.returnCode = p.wait()
logfile = open(self.filename[: self.filename.rfind('.')] + "_export.log", "w")
logfile = open(self.filelist[self.fileIdx][: self.filelist[self.fileIdx].rfind('.')] + "_export.log", "w")
for logLine in self.progressLog:
logfile.write(logLine)
logfile.write('\n')
logfile.close()
wx.CallAfter(self.notifyWindow.OnSliceDone, self)
self.fileIdx += 1
if self.fileIdx == len(self.cmdList):
if len(self.filelist) > 1:
self._stitchMultiExtruder()
wx.CallAfter(self.notifyWindow.OnSliceDone, self)
else:
self.run()
def _stitchMultiExtruder(self):
files = []
resultFile = open(self.filelist[0][:self.filelist[0].rfind('.')]+'_export.gcode', "w")
resultFile.write(';TYPE:CUSTOM\n')
resultFile.write(unicode(profile.getAlterationFileContents('start.gcode')).encode('utf-8'))
for filename in self.filelist:
files.append(open(filename[:filename.rfind('.')]+'_export.multi_extrude_tmp', "r"))
hasLine = True
while hasLine:
hasLine = False
for f in files:
for line in f:
resultFile.write(line)
hasLine = True
if line.startswith(';LAYER:'):
break
for f in files:
f.close()
for filename in self.filelist:
os.remove(filename[:filename.rfind('.')]+'_export.multi_extrude_tmp')
resultFile.write(';TYPE:CUSTOM\n')
resultFile.write(unicode(profile.getAlterationFileContents('end.gcode')).encode('utf-8'))
resultFile.close()
class LogWindow(wx.Frame):
def __init__(self, logText):

View File

@ -123,10 +123,11 @@ G1 Z0 F{max_z_speed}
preferencesDefaultSettings = {
'wizardDone': 'False',
'startMode': 'Simple',
'lastFile': 'None',
'lastFile': '',
'machine_width': '205',
'machine_depth': '205',
'machine_height': '200',
'extruder_amount': '1',
'filament_density': '1300',
'steps_per_e': '0',
'serial_port': 'AUTO',

View File

@ -116,5 +116,7 @@ def getSliceCommand(filename):
pypyExe = getPyPyExe()
if pypyExe == False:
pypyExe = sys.executable
return [pypyExe, os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", os.path.split(sys.argv[0])[1])), '-p', profile.getGlobalProfileString(), filename]
cmd = [pypyExe, os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", os.path.split(sys.argv[0])[1])), '-p', profile.getGlobalProfileString()]
cmd.append(filename)
return cmd

View File

@ -28,6 +28,8 @@ class stlModel():
else:
self._loadBinary(f)
f.close()
self._createOrigonalVertexCopy()
def _loadAscii(self, f):
cnt = 0
@ -62,6 +64,12 @@ class stlModel():
self.vertexes.append(v1)
self.vertexes.append(v2)
def _createOrigonalVertexCopy(self):
self.origonalVertexes = list(self.vertexes)
for i in xrange(0, len(self.origonalVertexes)):
self.origonalVertexes[i] = self.origonalVertexes[i].copy()
self.getMinimumZ()
def getMinimumZ(self):
minv = self.vertexes[0].copy()
maxv = self.vertexes[0].copy()

View File

@ -69,3 +69,9 @@ class Vector3():
self.y /= f
self.z /= f
def min(self, v):
return Vector3(min(self.x, v.x), min(self.y, v.y), min(self.z, v.z))
def max(self, v):
return Vector3(max(self.x, v.x), max(self.y, v.y), max(self.z, v.z))