chiark / gitweb /
Multiple extruders, not functional yet. Final GCode has wrong E values. But the idea...
authordaid <daid303@gmail.com>
Tue, 24 Apr 2012 16:46:29 +0000 (18:46 +0200)
committerdaid <daid303@gmail.com>
Tue, 24 Apr 2012 16:46:29 +0000 (18:46 +0200)
Cura/gui/mainWindow.py
Cura/gui/preferencesDialog.py
Cura/gui/preview3d.py
Cura/gui/projectPlanner.py
Cura/gui/sliceProgessPanel.py
Cura/util/profile.py
Cura/util/sliceRun.py
Cura/util/stl.py
Cura/util/util3d.py

index c9ad00db50c6bb411e25bc989e857ef51c3c9511..3cd22ab273cb93c1cfd52a3f08bb11e789d230a2 100644 (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()
index 81734c28cab551ada5694eb545decfc1568f2111..ec3159792ee13b5f36129e125f95b7a79ea6b760 100644 (file)
@@ -24,6 +24,7 @@ class preferencesDialog(configBase.configWindowBase):
                validators.validFloat(c, 10.0)\r
                c = configBase.SettingRow(left, 'Machine height (mm)', 'machine_height', '200', 'Size of the machine in mm', type = 'preference')\r
                validators.validFloat(c, 10.0)\r
+               c = configBase.SettingRow(left, 'Extruder count', 'extruder_amount', ['1', '2', '3', '4'], 'Amount of extruders in your machine.', type = 'preference')\r
 \r
                configBase.TitleRow(left, 'Filament settings')\r
                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')\r
@@ -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')\r
 \r
                configBase.TitleRow(left, 'Slicer settings')\r
-               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')\r
+               #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')\r
                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')\r
                \r
                self.MakeModal(True)\r
index b6eb69c298186818ee292231c24f8f7266059654..ac8eff9728a4891bca1670e0a9f5086b08c6ac1b 100644 (file)
@@ -27,6 +27,13 @@ from util import gcodeInterpreter
 from util import stl\r
 from util import util3d\r
 \r
+class previewObject():\r
+       def __init__(self):\r
+               self.mesh = None\r
+               self.filename = None\r
+               self.displayList = None\r
+               self.dirty = False\r
+\r
 class previewPanel(wx.Panel):\r
        def __init__(self, parent):\r
                super(previewPanel, self).__init__(parent,-1)\r
@@ -35,11 +42,10 @@ class previewPanel(wx.Panel):
                self.SetMinSize((440,320))\r
                \r
                self.glCanvas = PreviewGLCanvas(self)\r
-               self.init = 0\r
-               self.triangleMesh = None\r
+               self.objectList = []\r
                self.gcode = None\r
-               self.modelFilename = None\r
-               self.loadingProgressAmount = 0\r
+               self.objectsMinV = None\r
+               self.objectsMaxV = None\r
                self.loadThread = None\r
                self.machineSize = util3d.Vector3(float(profile.getPreference('machine_width')), float(profile.getPreference('machine_depth')), float(profile.getPreference('machine_height')))\r
                self.machineCenter = util3d.Vector3(float(profile.getProfileSetting('machine_center_x')), float(profile.getProfileSetting('machine_center_y')), 0)\r
@@ -138,10 +144,10 @@ class previewPanel(wx.Panel):
                self.glCanvas.Refresh()\r
        \r
        def OnScaleMax(self, e):\r
-               if self.triangleMesh == None:\r
+               if self.objectsMinV == None:\r
                        return\r
-               vMin = self.triangleMesh.getMinimum()\r
-               vMax = self.triangleMesh.getMaximum()\r
+               vMin = self.objectsMinV\r
+               vMax = self.objectsMaxV\r
                scaleX1 = (self.machineSize.x - self.machineCenter.x) / ((vMax.x - vMin.x) / 2)\r
                scaleY1 = (self.machineSize.y - self.machineCenter.y) / ((vMax.y - vMin.y) / 2)\r
                scaleX2 = (self.machineCenter.x) / ((vMax.x - vMin.x) / 2)\r
@@ -194,15 +200,21 @@ class previewPanel(wx.Panel):
                self.glCanvas.viewMode = mode\r
                wx.CallAfter(self.glCanvas.Refresh)\r
        \r
-       def loadModelFile(self, filename):\r
-               if self.modelFilename != filename:\r
-                       self.modelFileTime = None\r
-                       self.gcodeFileTime = None\r
-                       self.logFileTime = None\r
+       def loadModelFiles(self, filelist):\r
+               while len(filelist) > len(self.objectList):\r
+                       self.objectList.append(previewObject())\r
+               for idx in xrange(len(self.objectList), len(filelist)):\r
+                       self.objectList[idx].mesh = None\r
+               for idx in xrange(0, len(filelist)):\r
+                       obj = self.objectList[idx]\r
+                       if obj.filename != filelist[idx]:\r
+                               obj.fileTime = None\r
+                               self.gcodeFileTime = None\r
+                               self.logFileTime = None\r
+                       obj.filename = filelist[idx]\r
                \r
-               self.modelFilename = filename\r
-               self.gcodeFilename = filename[: filename.rfind('.')] + "_export.gcode"\r
-               self.logFilename = filename[: filename.rfind('.')] + "_export.log"\r
+               self.gcodeFilename = filelist[0][: filelist[0].rfind('.')] + "_export.gcode"\r
+               self.logFilename = filelist[0][: filelist[0].rfind('.')] + "_export.log"\r
                #Do the STL file loading in a background thread so we don't block the UI.\r
                if self.loadThread != None and self.loadThread.isAlive():\r
                        self.loadThread.join()\r
@@ -210,35 +222,32 @@ class previewPanel(wx.Panel):
                self.loadThread.daemon = True\r
                self.loadThread.start()\r
        \r
-       def loadReModelFile(self, filename):\r
+       def loadReModelFiles(self, filelist):\r
                #Only load this again if the filename matches the file we have already loaded (for auto loading GCode after slicing)\r
-               if self.modelFilename != filename:\r
-                       return False\r
-               self.loadModelFile(filename)\r
+               for idx in xrange(0, len(filelist)):\r
+                       if self.objectList[idx].filename != filelist[idx]:\r
+                               return False\r
+               self.loadModelFiles(filelist)\r
                return True\r
        \r
        def doFileLoadThread(self):\r
-               if os.path.isfile(self.modelFilename) and self.modelFileTime != os.stat(self.modelFilename).st_mtime:\r
-                       self.modelFileTime = os.stat(self.modelFilename).st_mtime\r
-                       triangleMesh = stl.stlModel()\r
-                       triangleMesh.load(self.modelFilename)\r
-                       triangleMesh.origonalVertexes = list(triangleMesh.vertexes)\r
-                       for i in xrange(0, len(triangleMesh.origonalVertexes)):\r
-                               triangleMesh.origonalVertexes[i] = triangleMesh.origonalVertexes[i].copy()\r
-                       triangleMesh.getMinimumZ()\r
-                       self.modelDirty = False\r
-                       self.errorList = []\r
-                       self.triangleMesh = triangleMesh\r
-                       self.updateModelTransform()\r
-                       wx.CallAfter(self.updateToolbar)\r
-                       wx.CallAfter(self.glCanvas.Refresh)\r
+               for obj in self.objectList:\r
+                       if os.path.isfile(obj.filename) and obj.fileTime != os.stat(obj.filename).st_mtime:\r
+                               obj.ileTime = os.stat(obj.filename).st_mtime\r
+                               mesh = stl.stlModel()\r
+                               mesh.load(obj.filename)\r
+                               obj.dirty = False\r
+                               obj.errorList = []\r
+                               obj.mesh = mesh\r
+                               self.updateModelTransform()\r
+                               wx.CallAfter(self.updateToolbar)\r
+                               wx.CallAfter(self.glCanvas.Refresh)\r
                \r
                if os.path.isfile(self.gcodeFilename) and self.gcodeFileTime != os.stat(self.gcodeFilename).st_mtime:\r
                        self.gcodeFileTime = os.stat(self.gcodeFilename).st_mtime\r
                        gcode = gcodeInterpreter.gcode()\r
                        gcode.progressCallback = self.loadProgress\r
                        gcode.load(self.gcodeFilename)\r
-                       self.loadingProgressAmount = 0\r
                        self.gcodeDirty = False\r
                        self.errorList = []\r
                        self.gcode = gcode\r
@@ -260,8 +269,7 @@ class previewPanel(wx.Panel):
                        wx.CallAfter(self.glCanvas.Refresh)\r
        \r
        def loadProgress(self, progress):\r
-               self.loadingProgressAmount = progress\r
-               wx.CallAfter(self.glCanvas.Refresh)\r
+               pass\r
        \r
        def updateToolbar(self):\r
                self.layerSpin.Show(self.gcode != None)\r
@@ -283,8 +291,6 @@ class previewPanel(wx.Panel):
                self.glCanvas.Refresh()\r
        \r
        def updateModelTransform(self, f=0):\r
-               if self.triangleMesh == None:\r
-                       return\r
                rotate = profile.getProfileSettingFloat('model_rotate_base') / 180.0 * math.pi\r
                scaleX = 1.0\r
                scaleY = 1.0\r
@@ -302,34 +308,54 @@ class previewPanel(wx.Panel):
                mat10 = math.sin(rotate) * scaleX\r
                mat11 = math.cos(rotate) * scaleY\r
                \r
-               for i in xrange(0, len(self.triangleMesh.origonalVertexes)):\r
-                       x = self.triangleMesh.origonalVertexes[i].x\r
-                       y = self.triangleMesh.origonalVertexes[i].y\r
-                       z = self.triangleMesh.origonalVertexes[i].z\r
-                       if swapXZ:\r
-                               x, z = z, x\r
-                       if swapYZ:\r
-                               y, z = z, y\r
-                       self.triangleMesh.vertexes[i].x = x * mat00 + y * mat01\r
-                       self.triangleMesh.vertexes[i].y = x * mat10 + y * mat11\r
-                       self.triangleMesh.vertexes[i].z = z * scaleZ\r
-\r
-               for face in self.triangleMesh.faces:\r
-                       v1 = face.v[0]\r
-                       v2 = face.v[1]\r
-                       v3 = face.v[2]\r
-                       face.normal = (v2 - v1).cross(v3 - v1)\r
-                       face.normal.normalize()\r
-\r
-               minZ = self.triangleMesh.getMinimumZ()\r
-               min = self.triangleMesh.getMinimum()\r
-               max = self.triangleMesh.getMaximum()\r
-               for v in self.triangleMesh.vertexes:\r
-                       v.z -= minZ\r
-                       v.x -= min.x + (max.x - min.x) / 2\r
-                       v.y -= min.y + (max.y - min.y) / 2\r
-               self.triangleMesh.getMinimumZ()\r
-               self.modelDirty = True\r
+               if len(self.objectList) < 1 or self.objectList[0].mesh == None:\r
+                       return\r
+\r
+               for obj in self.objectList:\r
+                       if obj.mesh == None:\r
+                               continue\r
+               \r
+                       for i in xrange(0, len(obj.mesh.origonalVertexes)):\r
+                               x = obj.mesh.origonalVertexes[i].x\r
+                               y = obj.mesh.origonalVertexes[i].y\r
+                               z = obj.mesh.origonalVertexes[i].z\r
+                               if swapXZ:\r
+                                       x, z = z, x\r
+                               if swapYZ:\r
+                                       y, z = z, y\r
+                               obj.mesh.vertexes[i].x = x * mat00 + y * mat01\r
+                               obj.mesh.vertexes[i].y = x * mat10 + y * mat11\r
+                               obj.mesh.vertexes[i].z = z * scaleZ\r
+\r
+                       for face in obj.mesh.faces:\r
+                               v1 = face.v[0]\r
+                               v2 = face.v[1]\r
+                               v3 = face.v[2]\r
+                               face.normal = (v2 - v1).cross(v3 - v1)\r
+                               face.normal.normalize()\r
+               \r
+               minV = self.objectList[0].mesh.getMinimum()\r
+               maxV = self.objectList[0].mesh.getMaximum()\r
+               for obj in self.objectList:\r
+                       if obj.mesh == None:\r
+                               continue\r
+\r
+                       obj.mesh.getMinimumZ()\r
+                       minV = minV.min(obj.mesh.getMinimum())\r
+                       maxV = maxV.max(obj.mesh.getMaximum())\r
+\r
+               self.objectsMaxV = maxV\r
+               self.objectsMinV = minV\r
+               for obj in self.objectList:\r
+                       if obj.mesh == None:\r
+                               continue\r
+\r
+                       for v in obj.mesh.vertexes:\r
+                               v.z -= minV.z\r
+                               v.x -= minV.x + (maxV.x - minV.x) / 2\r
+                               v.y -= minV.y + (maxV.y - minV.y) / 2\r
+                       obj.mesh.getMinimumZ()\r
+                       obj.dirty = True\r
                self.glCanvas.Refresh()\r
 \r
 class PreviewGLCanvas(glcanvas.GLCanvas):\r
@@ -349,8 +375,8 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
                self.offsetX = 0\r
                self.offsetY = 0\r
                self.view3D = True\r
-               self.modelDisplayList = None\r
                self.gcodeDisplayList = None\r
+               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]]\r
        \r
        def OnMouseMotion(self,e):\r
                if e.Dragging() and e.LeftIsDown():\r
@@ -398,8 +424,8 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
                        glTranslate(0,0,-self.zoom)\r
                        glRotate(-self.pitch, 1,0,0)\r
                        glRotate(self.yaw, 0,0,1)\r
-                       if self.parent.triangleMesh != None:\r
-                               glTranslate(0,0,-self.parent.triangleMesh.getMaximum().z * profile.getProfileSettingFloat('model_scale') / 2)\r
+                       if self.parent.objectsMaxV != None:\r
+                               glTranslate(0,0,-self.parent.objectsMaxV.z * profile.getProfileSettingFloat('model_scale') / 2)\r
                else:\r
                        glScale(1.0/self.zoom, 1.0/self.zoom, 1.0)\r
                        glTranslate(self.offsetX, self.offsetY, 0.0)\r
@@ -505,26 +531,28 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
                        if self.viewMode == "GCode" or self.viewMode == "Mixed":\r
                                glCallList(self.gcodeDisplayList)\r
                \r
-               if self.parent.triangleMesh != None:\r
-                       if self.modelDisplayList == None:\r
-                               self.modelDisplayList = glGenLists(1);\r
-                       if self.parent.modelDirty:\r
-                               self.parent.modelDirty = False\r
-                               glNewList(self.modelDisplayList, GL_COMPILE)\r
-                               opengl.DrawSTL(self.parent.triangleMesh)\r
+               glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, 0)\r
+               for obj in self.parent.objectList:\r
+                       if obj.mesh == None:\r
+                               continue\r
+                       if obj.displayList == None:\r
+                               obj.displayList = glGenLists(1);\r
+                       if obj.dirty:\r
+                               obj.dirty = False\r
+                               glNewList(obj.displayList, GL_COMPILE)\r
+                               opengl.DrawSTL(obj.mesh)\r
                                glEndList()\r
                        \r
-                       glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, 0)\r
                        glEnable(GL_NORMALIZE)\r
                        if self.viewMode == "Transparent" or self.viewMode == "Mixed":\r
-                               glLightfv(GL_LIGHT0, GL_DIFFUSE,  [0.5, 0.4, 0.3, 1.0])\r
-                               glLightfv(GL_LIGHT0, GL_AMBIENT,  [0.1, 0.1, 0.1, 0.0])\r
+                               glLightfv(GL_LIGHT0, GL_DIFFUSE, map(lambda x: x / 2, self.objColor[self.parent.objectList.index(obj)]))\r
+                               glLightfv(GL_LIGHT0, GL_AMBIENT, map(lambda x: x / 10, self.objColor[self.parent.objectList.index(obj)]))\r
                                #If we want transparent, then first render a solid black model to remove the printer size lines.\r
                                if self.viewMode != "Mixed":\r
                                        glDisable(GL_BLEND)\r
                                        glDisable(GL_LIGHTING)\r
                                        glColor3f(0,0,0)\r
-                                       self.drawModel()\r
+                                       self.drawModel(obj)\r
                                        glColor3f(1,1,1)\r
                                #After the black model is rendered, render the model again but now with lighting and no depth testing.\r
                                glDisable(GL_DEPTH_TEST)\r
@@ -532,23 +560,23 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
                                glEnable(GL_BLEND)\r
                                glBlendFunc(GL_ONE, GL_ONE)\r
                                glEnable(GL_LIGHTING)\r
-                               self.drawModel()\r
+                               self.drawModel(obj)\r
                        elif self.viewMode == "X-Ray":\r
                                glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)\r
                                glDisable(GL_DEPTH_TEST)\r
                                glEnable(GL_STENCIL_TEST);\r
                                glStencilFunc(GL_ALWAYS, 1, 1)\r
                                glStencilOp(GL_INCR, GL_INCR, GL_INCR)\r
-                               self.drawModel()\r
+                               self.drawModel(obj)\r
                                glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);\r
                                \r
                                glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)\r
                                glStencilFunc(GL_EQUAL, 0, 1);\r
                                glColor(1, 1, 1)\r
-                               self.drawModel()\r
+                               self.drawModel(obj)\r
                                glStencilFunc(GL_EQUAL, 1, 1);\r
                                glColor(1, 0, 0)\r
-                               self.drawModel()\r
+                               self.drawModel(obj)\r
 \r
                                glPushMatrix()\r
                                glLoadIdentity()\r
@@ -575,28 +603,29 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
                                glDisable(GL_STENCIL_TEST);\r
                                glEnable(GL_DEPTH_TEST)\r
                        elif self.viewMode == "Normal":\r
-                               glLightfv(GL_LIGHT0, GL_DIFFUSE,  [1.0, 0.8, 0.6, 1.0])\r
-                               glLightfv(GL_LIGHT0, GL_AMBIENT,  [0.2, 0.2, 0.2, 0.0])\r
+                               glLightfv(GL_LIGHT0, GL_DIFFUSE, self.objColor[self.parent.objectList.index(obj)])\r
+                               glLightfv(GL_LIGHT0, GL_AMBIENT, map(lambda x: x / 5, self.objColor[self.parent.objectList.index(obj)]))\r
                                glEnable(GL_LIGHTING)\r
-                               self.drawModel()\r
+                               self.drawModel(obj)\r
                        \r
                        if self.viewMode == "Normal" or self.viewMode == "Transparent" or self.viewMode == "X-Ray":\r
                                glDisable(GL_LIGHTING)\r
                                glDisable(GL_DEPTH_TEST)\r
                                glDisable(GL_BLEND)\r
                                glColor3f(1,0,0)\r
-                               glBegin(GL_LINES)\r
-                               for err in self.parent.errorList:\r
-                                       glVertex3f(err[0].x, err[0].y, err[0].z)\r
-                                       glVertex3f(err[1].x, err[1].y, err[1].z)\r
-                               glEnd()\r
+                               #glBegin(GL_LINES)\r
+                               #for err in self.parent.errorList:\r
+                               #       glVertex3f(err[0].x, err[0].y, err[0].z)\r
+                               #       glVertex3f(err[1].x, err[1].y, err[1].z)\r
+                               #glEnd()\r
+                               glEnable(GL_DEPTH_TEST)\r
                glFlush()\r
        \r
-       def drawModel(self):\r
+       def drawModel(self, obj):\r
                multiX = int(profile.getProfileSetting('model_multiply_x'))\r
                multiY = int(profile.getProfileSetting('model_multiply_y'))\r
                modelScale = profile.getProfileSettingFloat('model_scale')\r
-               modelSize = (self.parent.triangleMesh.getMaximum() - self.parent.triangleMesh.getMinimum()) * modelScale\r
+               modelSize = (obj.mesh.getMaximum() - obj.mesh.getMinimum()) * modelScale\r
                glPushMatrix()\r
                glTranslate(-(modelSize.x+10)*(multiX-1)/2,-(modelSize.y+10)*(multiY-1)/2, 0)\r
                for mx in xrange(0, multiX):\r
@@ -604,7 +633,7 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
                                glPushMatrix()\r
                                glTranslate((modelSize.x+10)*mx,(modelSize.y+10)*my, 0)\r
                                glScalef(modelScale, modelScale, modelScale)\r
-                               glCallList(self.modelDisplayList)\r
+                               glCallList(obj.displayList)\r
                                glPopMatrix()\r
                glPopMatrix()\r
 \r
index 18027f67f1f70ca653814063777f3c7a4d0349a8..19000aac6bfd012dd1df8d577402414bd0e4cc2a 100644 (file)
@@ -707,11 +707,11 @@ class ProjectSliceProgressWindow(wx.Frame):
                        \r
                        if action == self.actionList[0]:\r
                                resultFile.write(';TYPE:CUSTOM\n')\r
-                               resultFile.write(profile.getAlterationFileContents('start.gcode'))\r
+                               resultFile.write(profile.getAlterationFileContents('start.gcode').encode('utf-8')\r
                        else:\r
                                #reset the extrusion length, and move to the next object center.\r
                                resultFile.write(';TYPE:CUSTOM\n')\r
-                               resultFile.write(profile.getAlterationFileContents('nextobject.gcode'))\r
+                               resultFile.write(profile.getAlterationFileContents('nextobject.gcode').encode('utf-8')\r
                        resultFile.write(';PRINTNR:%d\n' % self.actionList.index(action))\r
                        profile.loadGlobalProfileFromString(oldProfile)\r
                        \r
@@ -727,7 +727,7 @@ class ProjectSliceProgressWindow(wx.Frame):
                        wx.CallAfter(self.progressGauge2.SetValue, self.actionList.index(action) + 1)\r
                \r
                resultFile.write(';TYPE:CUSTOM\n')\r
-               resultFile.write(profile.getAlterationFileContents('end.gcode'))\r
+               resultFile.write(profile.getAlterationFileContents('end.gcode').encode('utf-8')\r
                resultFile.close()\r
                self.abort = True\r
                wx.CallAfter(self.abortButton.SetLabel, 'Close')\r
index a89a209c6e54126abe3765e93f508f755c363ddf..465dc2590214188e3185d01476eec75e771ee752 100644 (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):
index 5fa85b7ff208847f6be75b044fea639dbbe86ddb..eb6c4ec6bcba490228dbda0fba3c6172b2d22686 100644 (file)
@@ -123,10 +123,11 @@ G1 Z0 F{max_z_speed}
 preferencesDefaultSettings = {\r
        'wizardDone': 'False',\r
        'startMode': 'Simple',\r
-       'lastFile': 'None',\r
+       'lastFile': '',\r
        'machine_width': '205',\r
        'machine_depth': '205',\r
        'machine_height': '200',\r
+       'extruder_amount': '1',\r
        'filament_density': '1300',\r
        'steps_per_e': '0',\r
        'serial_port': 'AUTO',\r
index e4ddf2f66581c059e283c64b7d4e524ff2723605..edc304d317c553c0dbbfe58f86fb53ef84319982 100644 (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
 
index 2a01adec878a2d0308cad7d2368031790dcb129b..9b1323a294237880f6e61ca31d1f95b4d2ba76ea 100644 (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()
index 146906a767081ad4123dc99d5c802381eed8d33b..30b25159d6221d1bfd3770d25c69855cc948179a 100644 (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))
+