--- /dev/null
+from __future__ import absolute_import\r
+import __init__\r
+\r
+import wx, os, platform, types, webbrowser, math, subprocess\r
+import ConfigParser\r
+\r
+from wx import glcanvas\r
+import wx\r
+try:\r
+ import OpenGL\r
+ OpenGL.ERROR_CHECKING = False\r
+ from OpenGL.GLU import *\r
+ from OpenGL.GL import *\r
+ hasOpenGLlibs = True\r
+except:\r
+ print "Failed to find PyOpenGL: http://pyopengl.sourceforge.net/"\r
+ hasOpenGLlibs = False\r
+\r
+from gui import opengl\r
+from gui import icon\r
+from util import profile\r
+from util import util3d\r
+from util import stl\r
+from util import sliceRun\r
+\r
+class projectPlanner(wx.Frame):\r
+ "Main user interface window"\r
+ def __init__(self):\r
+ super(projectPlanner, self).__init__(None, title='Cura')\r
+ \r
+ self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))\r
+ wx.EVT_CLOSE(self, self.OnClose)\r
+ #self.SetIcon(icon.getMainIcon())\r
+ \r
+ menubar = wx.MenuBar()\r
+ fileMenu = wx.Menu()\r
+ i = fileMenu.Append(-1, 'Open Project...')\r
+ self.Bind(wx.EVT_MENU, self.OnLoadProject, i)\r
+ i = fileMenu.Append(-1, 'Save Project...')\r
+ self.Bind(wx.EVT_MENU, self.OnSaveProject, i)\r
+ fileMenu.AppendSeparator()\r
+ i = fileMenu.Append(wx.ID_EXIT, 'Quit')\r
+ self.Bind(wx.EVT_MENU, self.OnQuit, i)\r
+ menubar.Append(fileMenu, '&File')\r
+ self.SetMenuBar(menubar)\r
+ \r
+ self.list = []\r
+ self.selection = None\r
+\r
+ self.machineSize = util3d.Vector3(float(profile.getPreference('machine_width')), float(profile.getPreference('machine_depth')), float(profile.getPreference('machine_height')))\r
+ self.headSizeMin = util3d.Vector3(70,16,0)\r
+ self.headSizeMax = util3d.Vector3(16,35,0)\r
+\r
+ self.toolbar = wx.ToolBar( self, -1 )\r
+ self.toolbar.SetToolBitmapSize( ( 21, 21 ) )\r
+\r
+ button = wx.Button(self.toolbar, -1, "3D", size=(21*2,21))\r
+ self.toolbar.AddControl(button)\r
+ self.Bind(wx.EVT_BUTTON, self.On3DClick, button)\r
+ \r
+ button = wx.Button(self.toolbar, -1, "Top", size=(21*2,21))\r
+ self.toolbar.AddControl(button)\r
+ self.Bind(wx.EVT_BUTTON, self.OnTopClick, button)\r
+ self.toolbar.Realize()\r
+ \r
+ sizer = wx.GridBagSizer(2,2)\r
+ self.SetSizer(sizer)\r
+ self.preview = PreviewGLCanvas(self)\r
+ self.listbox = wx.ListBox(self, -1, choices=[])\r
+ self.addButton = wx.Button(self, -1, "Add")\r
+ self.remButton = wx.Button(self, -1, "Remove")\r
+ self.sliceButton = wx.Button(self, -1, "Slice")\r
+ \r
+ sizer.Add(self.toolbar, (0,0), span=(1,1), flag=wx.EXPAND)\r
+ sizer.Add(self.preview, (1,0), span=(3,1), flag=wx.EXPAND)\r
+ sizer.Add(self.listbox, (0,1), span=(2,2), flag=wx.EXPAND)\r
+ sizer.Add(self.addButton, (2,1), span=(1,1))\r
+ sizer.Add(self.remButton, (2,2), span=(1,1))\r
+ sizer.Add(self.sliceButton, (3,1), span=(1,1))\r
+ sizer.AddGrowableCol(0)\r
+ sizer.AddGrowableRow(1)\r
+ \r
+ self.addButton.Bind(wx.EVT_BUTTON, self.OnAddModel)\r
+ self.remButton.Bind(wx.EVT_BUTTON, self.OnRemModel)\r
+ self.sliceButton.Bind(wx.EVT_BUTTON, self.OnSlice)\r
+ self.listbox.Bind(wx.EVT_LISTBOX, self.OnListSelect)\r
+ \r
+ self.SetSize((800,600))\r
+\r
+ def OnClose(self, e):\r
+ self.Destroy()\r
+\r
+ def OnQuit(self, e):\r
+ self.Close()\r
+ \r
+ def OnSaveProject(self, e):\r
+ dlg=wx.FileDialog(self, "Save project file", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)\r
+ dlg.SetWildcard("Project files (*.curaproject)|*.curaproject")\r
+ if dlg.ShowModal() == wx.ID_OK:\r
+ cp = ConfigParser.ConfigParser()\r
+ i = 0\r
+ for item in self.list:\r
+ section = 'model_%d' % (i)\r
+ cp.add_section(section)\r
+ cp.set(section, 'filename', item.filename.encode("utf-8"))\r
+ cp.set(section, 'centerX', str(item.centerX))\r
+ cp.set(section, 'centerY', str(item.centerY))\r
+ cp.set(section, 'scale', str(item.scale))\r
+ cp.set(section, 'rotate', str(item.rotate))\r
+ cp.set(section, 'flipX', str(item.flipX))\r
+ cp.set(section, 'flipY', str(item.flipY))\r
+ cp.set(section, 'flipZ', str(item.flipZ))\r
+ cp.set(section, 'swapXZ', str(item.swapXZ))\r
+ cp.set(section, 'swapYZ', str(item.swapYZ))\r
+ i += 1\r
+ cp.write(open(dlg.GetPath(), "w"))\r
+ dlg.Destroy()\r
+\r
+ def OnLoadProject(self, e):\r
+ dlg=wx.FileDialog(self, "Open project file", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)\r
+ dlg.SetWildcard("Project files (*.curaproject)|*.curaproject")\r
+ if dlg.ShowModal() == wx.ID_OK:\r
+ cp = ConfigParser.ConfigParser()\r
+ cp.read(dlg.GetPath())\r
+ self.list = []\r
+ self.listbox.Clear()\r
+ i = 0\r
+ while cp.has_section('model_%d' % (i)):\r
+ section = 'model_%d' % (i)\r
+ \r
+ item = stl.stlModel()\r
+ item.filename = unicode(cp.get(section, 'filename'), "utf-8")\r
+ self.loadModelFile(item)\r
+ item.centerX = float(cp.get(section, 'centerX'))\r
+ item.centerY = float(cp.get(section, 'centerY'))\r
+ item.scale = float(cp.get(section, 'scale'))\r
+ item.rotate = float(cp.get(section, 'rotate'))\r
+ cp.get(section, 'flipX')\r
+ cp.get(section, 'flipY')\r
+ cp.get(section, 'flipZ')\r
+ cp.get(section, 'swapXZ')\r
+ cp.get(section, 'swapYZ')\r
+ i += 1\r
+ \r
+ self.list.append(item)\r
+ self.listbox.AppendAndEnsureVisible(os.path.split(item.filename)[1])\r
+ \r
+ self.listbox.SetSelection(len(self.list)-1)\r
+ self.OnListSelect(None)\r
+\r
+ dlg.Destroy()\r
+\r
+ def On3DClick(self, e):\r
+ self.preview.yaw = 30\r
+ self.preview.pitch = 60\r
+ self.preview.zoom = 300\r
+ self.preview.view3D = True\r
+ self.preview.Refresh()\r
+\r
+ def OnTopClick(self, e):\r
+ self.preview.view3D = False\r
+ self.preview.zoom = self.machineSize.x / 2 + 10\r
+ self.preview.offsetX = 0\r
+ self.preview.offsetY = 0\r
+ self.preview.Refresh()\r
+\r
+ def OnListSelect(self, e):\r
+ self.selection = self.list[self.listbox.GetSelection()]\r
+ self.preview.Refresh()\r
+\r
+ def OnAddModel(self, e):\r
+ dlg=wx.FileDialog(self, "Open file to print", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)\r
+ dlg.SetWildcard("STL files (*.stl)|*.stl;*.STL")\r
+ if dlg.ShowModal() == wx.ID_OK:\r
+ item = stl.stlModel()\r
+ item.filename=dlg.GetPath()\r
+ profile.putPreference('lastFile', item.filename)\r
+ if not(os.path.exists(item.filename)):\r
+ return\r
+ self.loadModelFile(item)\r
+ self.list.append(item)\r
+ self.listbox.AppendAndEnsureVisible(os.path.split(item.filename)[1])\r
+ self.listbox.SetSelection(len(self.list)-1)\r
+ self.OnListSelect(None)\r
+ dlg.Destroy()\r
+ \r
+ def OnRemModel(self, e):\r
+ if self.selection == None:\r
+ return\r
+ self.list.remove(self.selection)\r
+ self.listbox.Delete(self.listbox.GetSelection())\r
+ self.selection = None\r
+ self.preview.Refresh()\r
+\r
+ def OnSlice(self, e):\r
+ oldProfile = profile.getGlobalProfileString()\r
+ \r
+ put = profile.putProfileSetting\r
+\r
+ put('model_multiply_x', '1')\r
+ put('model_multiply_y', '1')\r
+ put('skirt_line_count', '0')\r
+ put('enable_raft', 'False')\r
+ put('add_start_end_gcode', 'False')\r
+ put('gcode_extension', 'project_tmp')\r
+ \r
+ for item in self.list:\r
+ put('machine_center_x', item.centerX)\r
+ put('machine_center_y', item.centerY)\r
+ put('model_scale', item.scale)\r
+ put('flip_x', item.flipX)\r
+ put('flip_y', item.flipY)\r
+ put('flip_z', item.flipZ)\r
+ put('model_rotate_base', item.rotate)\r
+ put('swap_xz', item.swapXZ)\r
+ put('swap_yz', item.swapYZ)\r
+ \r
+ item.sliceCmd = sliceRun.getSliceCommand(item.filename)\r
+ \r
+ #Restore the old profile.\r
+ profile.loadGlobalProfileFromString(oldProfile)\r
+ \r
+ resultFile = open("D:/Printing/result_export.gcode", "w")\r
+ resultFile.write(';TYPE:CUSTOM\n')\r
+ resultFile.write(profile.getAlterationFileContents('start.gcode'))\r
+ i = 1\r
+ maxZ = 0\r
+ prevItem = None\r
+ for item in self.list:\r
+ subprocess.call(item.sliceCmd)\r
+ \r
+ if prevItem != None:\r
+ #reset the extrusion length, and move to the next object center.\r
+ resultFile.write(';PRINTNR:%d\n' % (i))\r
+ resultFile.write(';TYPE:CUSTOM\n')\r
+ resultFile.write('G1 Z%f F%f\n' % (maxZ + 5, profile.getProfileSettingFloat('travel_speed') * 60))\r
+ resultFile.write('G92 E0\n')\r
+ resultFile.write('G1 X%f Y%f F%f\n' % (item.centerX, item.centerY, profile.getProfileSettingFloat('travel_speed') * 60))\r
+ resultFile.write('G1 Z0 F%f\n' % (profile.getProfileSettingFloat('max_z_speed') * 60))\r
+ \r
+ f = open(item.filename[: item.filename.rfind('.')] + "_export.project_tmp", "r")\r
+ data = f.read(4096)\r
+ while data != '':\r
+ resultFile.write(data)\r
+ data = f.read(4096)\r
+ f.close()\r
+ os.remove(item.filename[: item.filename.rfind('.')] + "_export.project_tmp")\r
+ i += 1\r
+ \r
+ prevItem = item\r
+ maxZ = max(maxZ, item.getMaximum().z * item.scale)\r
+ \r
+ resultFile.write(';TYPE:CUSTOM\n')\r
+ resultFile.write(profile.getAlterationFileContents('end.gcode'))\r
+ resultFile.close() \r
+ \r
+ def loadModelFile(self, item):\r
+ item.load(item.filename)\r
+ item.origonalVertexes = list(item.vertexes)\r
+ for i in xrange(0, len(item.origonalVertexes)):\r
+ item.origonalVertexes[i] = item.origonalVertexes[i].copy()\r
+ item.getMinimumZ()\r
+ \r
+ item.centerX = -item.getMinimum().x + 5\r
+ item.centerY = -item.getMinimum().y + 5\r
+ item.scale = 1.0\r
+ item.rotate = 0.0\r
+ item.flipX = False\r
+ item.flipY = False\r
+ item.flipZ = False\r
+ item.swapXZ = False\r
+ item.swapYZ = False\r
+ \r
+ item.modelDisplayList = None\r
+ item.modelDirty = False\r
+ \r
+ self.updateModelTransform(item)\r
+\r
+ def updateModelTransform(self, item):\r
+ scale = item.scale\r
+ rotate = item.rotate\r
+ scaleX = scale\r
+ scaleY = scale\r
+ scaleZ = scale\r
+ if item.flipX:\r
+ scaleX = -scaleX\r
+ if item.flipY:\r
+ scaleY = -scaleY\r
+ if item.flipZ:\r
+ scaleZ = -scaleZ\r
+ swapXZ = item.swapXZ\r
+ swapYZ = item.swapYZ\r
+ mat00 = math.cos(rotate) * scaleX\r
+ mat01 =-math.sin(rotate) * scaleY\r
+ mat10 = math.sin(rotate) * scaleX\r
+ mat11 = math.cos(rotate) * scaleY\r
+ \r
+ for i in xrange(0, len(item.origonalVertexes)):\r
+ x = item.origonalVertexes[i].x\r
+ y = item.origonalVertexes[i].y\r
+ z = item.origonalVertexes[i].z\r
+ if swapXZ:\r
+ x, z = z, x\r
+ if swapYZ:\r
+ y, z = z, y\r
+ item.vertexes[i].x = x * mat00 + y * mat01\r
+ item.vertexes[i].y = x * mat10 + y * mat11\r
+ item.vertexes[i].z = z * scaleZ\r
+\r
+ for face in item.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
+ self.moveModel(item)\r
+ \r
+ def moveModel(self, item):\r
+ minZ = item.getMinimumZ()\r
+ min = item.getMinimum()\r
+ max = item.getMaximum()\r
+ for v in item.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
+ item.getMinimumZ()\r
+ item.modelDirty = True\r
+ self.preview.Refresh()\r
+\r
+class PreviewGLCanvas(glcanvas.GLCanvas):\r
+ def __init__(self, parent):\r
+ attribList = (glcanvas.WX_GL_RGBA, glcanvas.WX_GL_DOUBLEBUFFER, glcanvas.WX_GL_DEPTH_SIZE, 24, glcanvas.WX_GL_STENCIL_SIZE, 8)\r
+ glcanvas.GLCanvas.__init__(self, parent, attribList = attribList)\r
+ self.parent = parent\r
+ self.context = glcanvas.GLContext(self)\r
+ wx.EVT_PAINT(self, self.OnPaint)\r
+ wx.EVT_SIZE(self, self.OnSize)\r
+ wx.EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)\r
+ wx.EVT_LEFT_DOWN(self, self.OnMouseLeftDown)\r
+ wx.EVT_MOTION(self, self.OnMouseMotion)\r
+ wx.EVT_MOUSEWHEEL(self, self.OnMouseWheel)\r
+ self.yaw = 30\r
+ self.pitch = 60\r
+ self.zoom = self.parent.machineSize.x / 2 + 10\r
+ self.offsetX = 0\r
+ self.offsetY = 0\r
+ self.view3D = False\r
+ self.allowDrag = False\r
+ \r
+ def OnMouseLeftDown(self,e):\r
+ self.allowDrag = True\r
+ \r
+ def OnMouseMotion(self,e):\r
+ if self.allowDrag and e.Dragging() and e.LeftIsDown():\r
+ if self.view3D:\r
+ self.yaw += e.GetX() - self.oldX\r
+ self.pitch -= e.GetY() - self.oldY\r
+ if self.pitch > 170:\r
+ self.pitch = 170\r
+ if self.pitch < 10:\r
+ self.pitch = 10\r
+ else:\r
+ #self.offsetX += float(e.GetX() - self.oldX) * self.zoom / self.GetSize().GetHeight() * 2\r
+ #self.offsetY -= float(e.GetY() - self.oldY) * self.zoom / self.GetSize().GetHeight() * 2\r
+ item = self.parent.selection\r
+ if item != None:\r
+ item.centerX += float(e.GetX() - self.oldX) * self.zoom / self.GetSize().GetHeight() * 2\r
+ item.centerY -= float(e.GetY() - self.oldY) * self.zoom / self.GetSize().GetHeight() * 2\r
+ if item.centerX < -item.getMinimum().x * item.scale:\r
+ item.centerX = -item.getMinimum().x * item.scale\r
+ if item.centerY < -item.getMinimum().y * item.scale:\r
+ item.centerY = -item.getMinimum().y * item.scale\r
+ if item.centerX > self.parent.machineSize.x - item.getMaximum().x * item.scale:\r
+ item.centerX = self.parent.machineSize.x - item.getMaximum().x * item.scale\r
+ if item.centerY > self.parent.machineSize.y - item.getMaximum().y * item.scale:\r
+ item.centerY = self.parent.machineSize.y - item.getMaximum().y * item.scale\r
+ self.Refresh()\r
+ else:\r
+ self.allowDrag = False\r
+ if e.Dragging() and e.RightIsDown():\r
+ if self.view3D:\r
+ self.zoom += e.GetY() - self.oldY\r
+ if self.zoom < 1:\r
+ self.zoom = 1\r
+ self.Refresh()\r
+ self.oldX = e.GetX()\r
+ self.oldY = e.GetY()\r
+ \r
+ def OnMouseWheel(self,e):\r
+ if self.view3D:\r
+ self.zoom *= 1.0 - float(e.GetWheelRotation() / e.GetWheelDelta()) / 10.0\r
+ if self.zoom < 1.0:\r
+ self.zoom = 1.0\r
+ self.Refresh()\r
+ \r
+ def OnEraseBackground(self,event):\r
+ #Workaround for windows background redraw flicker.\r
+ pass\r
+ \r
+ def OnSize(self,event):\r
+ self.Refresh()\r
+\r
+ def OnPaint(self,event):\r
+ dc = wx.PaintDC(self)\r
+ if not hasOpenGLlibs:\r
+ dc.Clear()\r
+ dc.DrawText("No PyOpenGL installation found.\nNo preview window available.", 10, 10)\r
+ return\r
+ self.SetCurrent(self.context)\r
+ opengl.InitGL(self, self.view3D, self.zoom)\r
+ if self.view3D:\r
+ glTranslate(0,0,-self.zoom)\r
+ glRotate(-self.pitch, 1,0,0)\r
+ glRotate(self.yaw, 0,0,1)\r
+ if False: #self.parent.triangleMesh != None:\r
+ glTranslate(0,0,-self.parent.triangleMesh.getMaximum().z / 2)\r
+ else:\r
+ glScale(1.0/self.zoom, 1.0/self.zoom, 1.0)\r
+ glTranslate(self.offsetX, self.offsetY, 0.0)\r
+ glTranslate(-self.parent.machineSize.x/2, -self.parent.machineSize.y/2, 0)\r
+\r
+ self.OnDraw()\r
+ self.SwapBuffers()\r
+\r
+ def OnDraw(self):\r
+ machineSize = self.parent.machineSize\r
+ opengl.DrawMachine(machineSize)\r
+\r
+ for item in self.parent.list:\r
+ item.validPlacement = True\r
+ item.gotHit = False\r
+ \r
+ for idx1 in xrange(0, len(self.parent.list)):\r
+ item = self.parent.list[idx1]\r
+ iMin1 = item.getMinimum() * item.scale + util3d.Vector3(item.centerX, item.centerY, 0) - self.parent.headSizeMin\r
+ iMax1 = item.getMaximum() * item.scale + util3d.Vector3(item.centerX, item.centerY, 0) + self.parent.headSizeMax\r
+ for idx2 in xrange(0, idx1):\r
+ item2 = self.parent.list[idx2]\r
+ iMin2 = item2.getMinimum() * item2.scale + util3d.Vector3(item2.centerX, item2.centerY, 0)\r
+ iMax2 = item2.getMaximum() * item2.scale + util3d.Vector3(item2.centerX, item2.centerY, 0)\r
+ if item != item2 and iMax1.x >= iMin2.x and iMin1.x <= iMax2.x and iMax1.y >= iMin2.y and iMin1.y <= iMax2.y:\r
+ item.validPlacement = False\r
+ item2.gotHit = True\r
+ \r
+ for item in self.parent.list:\r
+ if item.modelDisplayList == None:\r
+ item.modelDisplayList = glGenLists(1);\r
+ if item.modelDirty:\r
+ item.modelDirty = False\r
+ modelSize = item.getMaximum() - item.getMinimum()\r
+ glNewList(item.modelDisplayList, GL_COMPILE)\r
+ opengl.DrawSTL(item)\r
+ glEndList()\r
+ \r
+ if item.validPlacement:\r
+ if self.parent.selection == item:\r
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 0.9, 0.7, 1.0])\r
+ glLightfv(GL_LIGHT0, GL_AMBIENT, [0.2, 0.3, 0.2, 0.0])\r
+ else:\r
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 0.8, 0.6, 1.0])\r
+ glLightfv(GL_LIGHT0, GL_AMBIENT, [0.2, 0.1, 0.1, 0.0])\r
+ else:\r
+ if self.parent.selection == item:\r
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 0.0, 0.0, 0.0])\r
+ glLightfv(GL_LIGHT0, GL_AMBIENT, [0.2, 0.0, 0.0, 0.0])\r
+ else:\r
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 0.0, 0.0, 0.0])\r
+ glLightfv(GL_LIGHT0, GL_AMBIENT, [0.2, 0.0, 0.0, 0.0])\r
+ glPushMatrix()\r
+ \r
+ glEnable(GL_LIGHTING)\r
+ glTranslate(item.centerX, item.centerY, 0)\r
+ glPushMatrix()\r
+ glEnable(GL_NORMALIZE)\r
+ glScalef(item.scale, item.scale, item.scale)\r
+ glCallList(item.modelDisplayList)\r
+ glPopMatrix()\r
+ \r
+ vMin = item.getMinimum() * item.scale\r
+ vMax = item.getMaximum() * item.scale\r
+ glDisable(GL_LIGHTING)\r
+ if item.gotHit:\r
+ glColor3f(1.0,0.3,0.0)\r
+ else:\r
+ glColor3f(1.0,1.0,0.0)\r
+ opengl.DrawBox(vMin, vMax)\r
+ \r
+ vMin = vMin - self.parent.headSizeMin\r
+ vMax = vMax + self.parent.headSizeMax\r
+ if item.validPlacement:\r
+ glColor3f(1.0,0.0,1.0)\r
+ else:\r
+ glColor3f(1.0,0.0,0.3)\r
+ opengl.DrawBox(vMin, vMax)\r
+ \r
+ glPopMatrix()\r
+ \r
+ glFlush()\r
+\r
+def main():\r
+ app = wx.App(False)\r
+ projectPlanner().Show(True)\r
+ app.MainLoop()\r
+\r
+if __name__ == '__main__':\r
+ main()\r