parser = OptionParser(usage="usage: %prog [options] <filename>.stl")
parser.add_option("-i", "--ini", action="store", type="string", dest="profileini", help="Load settings from a profile ini file")
parser.add_option("-P", "--project", action="store_true", dest="openprojectplanner", help="Open the project planner")
+ parser.add_option("-F", "--flat", action="store_true", dest="openflatslicer", help="Open the 2D SVG slicer")
parser.add_option("-r", "--print", action="store", type="string", dest="printfile", help="Open the printing interface, instead of the normal cura interface.")
parser.add_option("-p", "--profile", action="store", type="string", dest="profile", help="Internal option, do not use!")
(options, args) = parser.parse_args()
from gui import projectPlanner
projectPlanner.main()
return
+ if options.openflatslicer != None:
+ from gui import flatSlicerWindow
+ flatSlicerWindow.main()
+ return
if options.printfile != None:
from gui import printWindow
printWindow.startPrintInterface(options.printfile)
--- /dev/null
+import wx, os, platform, types, webbrowser
+
+from wx import glcanvas
+import wx
+try:
+ import OpenGL
+ OpenGL.ERROR_CHECKING = False
+ from OpenGL.GLU import *
+ from OpenGL.GL import *
+ hasOpenGLlibs = True
+except:
+ print "Failed to find PyOpenGL: http://pyopengl.sourceforge.net/"
+ hasOpenGLlibs = False
+
+from gui import toolbarUtil
+from gui import opengl
+from util import util3d
+from util import svg
+from util import profile
+from util import version
+
+class flatSlicerWindow(wx.Frame):
+ "Cura 2D SVG slicer"
+ def __init__(self):
+ super(flatSlicerWindow, self).__init__(None, title='Cura - ' + version.getVersion())
+
+ self.machineSize = util3d.Vector3(profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height'))
+ self.filename = None
+ self.svg = None
+
+ wx.EVT_CLOSE(self, self.OnClose)
+ self.panel = wx.Panel(self, -1)
+ self.SetSizer(wx.BoxSizer(wx.VERTICAL))
+ self.GetSizer().Add(self.panel, 1, flag=wx.EXPAND)
+ #self.SetIcon(icon.getMainIcon())
+
+ self.toolbar = toolbarUtil.Toolbar(self.panel)
+
+ toolbarUtil.NormalButton(self.toolbar, self.OnOpenSVG, 'open.png', 'Open SVG')
+ self.toolbar.AddSeparator()
+ group = []
+ toolbarUtil.RadioButton(self.toolbar, group, 'object-3d-on.png', 'object-3d-off.png', '3D view', callback=self.On3DClick)
+ toolbarUtil.RadioButton(self.toolbar, group, 'object-top-on.png', 'object-top-off.png', 'Topdown view', callback=self.OnTopClick).SetValue(True)
+ self.toolbar.AddSeparator()
+ toolbarUtil.NormalButton(self.toolbar, self.OnQuit, 'exit.png', 'Close project planner')
+
+ self.toolbar.Realize()
+
+ sizer = wx.GridBagSizer(2,2)
+ self.panel.SetSizer(sizer)
+ self.preview = PreviewGLCanvas(self.panel, self)
+
+ sizer.Add(self.toolbar, (0,0), span=(1,1), flag=wx.EXPAND|wx.LEFT|wx.RIGHT)
+ sizer.Add(self.preview, (1,0), span=(5,1), flag=wx.EXPAND)
+
+ sizer.AddGrowableCol(0)
+ sizer.AddGrowableRow(1)
+
+ self.SetSize((600,400))
+
+ def OnClose(self, e):
+ self.Destroy()
+
+ def OnQuit(self, e):
+ self.Close()
+
+ def On3DClick(self):
+ self.preview.yaw = 30
+ self.preview.pitch = 60
+ self.preview.zoom = 300
+ self.preview.view3D = True
+ self.preview.Refresh()
+
+ def OnTopClick(self):
+ self.preview.view3D = False
+ self.preview.zoom = self.machineSize.x / 2 + 10
+ self.preview.offsetX = 0
+ self.preview.offsetY = 0
+ self.preview.Refresh()
+
+ def OnOpenSVG(self, e):
+ dlg=wx.FileDialog(self, "Open SVG file", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
+ dlg.SetWildcard("SVG files (*.svg)|*.svg;*.SVG")
+ if dlg.ShowModal() == wx.ID_OK:
+ self.filename = dlg.GetPath()
+ self.svg = svg.SVG(self.filename)
+ self.svg.center(complex(profile.getProfileSettingFloat('machine_center_x'), profile.getProfileSettingFloat('machine_center_y')))
+ self.preview.Refresh()
+ dlg.Destroy()
+
+class PreviewGLCanvas(glcanvas.GLCanvas):
+ def __init__(self, parent, realParent):
+ attribList = (glcanvas.WX_GL_RGBA, glcanvas.WX_GL_DOUBLEBUFFER, glcanvas.WX_GL_DEPTH_SIZE, 24, glcanvas.WX_GL_STENCIL_SIZE, 8)
+ glcanvas.GLCanvas.__init__(self, parent, attribList = attribList)
+ self.parent = realParent
+ self.context = glcanvas.GLContext(self)
+ wx.EVT_PAINT(self, self.OnPaint)
+ wx.EVT_SIZE(self, self.OnSize)
+ wx.EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
+ wx.EVT_LEFT_DOWN(self, self.OnMouseLeftDown)
+ wx.EVT_MOTION(self, self.OnMouseMotion)
+ wx.EVT_MOUSEWHEEL(self, self.OnMouseWheel)
+ self.yaw = 30
+ self.pitch = 60
+ self.zoom = self.parent.machineSize.x / 2 + 10
+ self.offsetX = 0
+ self.offsetY = 0
+ self.view3D = False
+ self.allowDrag = False
+
+ def OnMouseLeftDown(self,e):
+ self.allowDrag = True
+
+ def OnMouseMotion(self,e):
+ if self.allowDrag and e.Dragging() and e.LeftIsDown():
+ if self.view3D:
+ self.yaw += e.GetX() - self.oldX
+ self.pitch -= e.GetY() - self.oldY
+ if self.pitch > 170:
+ self.pitch = 170
+ if self.pitch < 10:
+ self.pitch = 10
+ else:
+ self.offsetX += float(e.GetX() - self.oldX) * self.zoom / self.GetSize().GetHeight() * 2
+ self.offsetY -= float(e.GetY() - self.oldY) * self.zoom / self.GetSize().GetHeight() * 2
+ self.Refresh()
+ else:
+ self.allowDrag = False
+ if e.Dragging() and e.RightIsDown():
+ if self.view3D:
+ self.zoom += e.GetY() - self.oldY
+ if self.zoom < 1:
+ self.zoom = 1
+ self.Refresh()
+ self.oldX = e.GetX()
+ self.oldY = e.GetY()
+
+ def OnMouseWheel(self,e):
+ if self.view3D:
+ self.zoom *= 1.0 - float(e.GetWheelRotation() / e.GetWheelDelta()) / 10.0
+ if self.zoom < 1.0:
+ self.zoom = 1.0
+ self.Refresh()
+
+ def OnEraseBackground(self,event):
+ #Workaround for windows background redraw flicker.
+ pass
+
+ def OnSize(self,event):
+ self.Refresh()
+
+ def OnPaint(self,event):
+ dc = wx.PaintDC(self)
+ if not hasOpenGLlibs:
+ dc.Clear()
+ dc.DrawText("No PyOpenGL installation found.\nNo preview window available.", 10, 10)
+ return
+ self.SetCurrent(self.context)
+ opengl.InitGL(self, self.view3D, self.zoom)
+ if self.view3D:
+ glTranslate(0,0,-self.zoom)
+ glRotate(-self.pitch, 1,0,0)
+ glRotate(self.yaw, 0,0,1)
+ if False: #self.parent.triangleMesh != None:
+ glTranslate(0,0,-self.parent.triangleMesh.getMaximum().z / 2)
+ else:
+ glScale(1.0/self.zoom, 1.0/self.zoom, 1.0)
+ glTranslate(self.offsetX, self.offsetY, 0.0)
+ glTranslate(-self.parent.machineSize.x/2, -self.parent.machineSize.y/2, 0)
+
+ self.OnDraw()
+ self.SwapBuffers()
+
+ def OnDraw(self):
+ machineSize = self.parent.machineSize
+ opengl.DrawMachine(machineSize)
+
+ if self.parent.svg != None:
+ for path in self.parent.svg.paths:
+ glColor3f(1.0,0.8,0.6)
+ glBegin(GL_LINE_STRIP)
+ for p in path:
+ glVertex3f(p.real, p.imag, 1)
+ glEnd()
+
+ glFlush()
+
+def main():
+ app = wx.App(False)
+ flatSlicerWindow().Show(True)
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main()
+
from gui import printWindow
from gui import simpleMode
from gui import projectPlanner
+from gui import flatSlicerWindow
from gui import icon
from util import profile
from util import version
expertMenu = wx.Menu()
i = expertMenu.Append(-1, 'Open expert settings...')
self.Bind(wx.EVT_MENU, self.OnExpertOpen, i)
+ i = expertMenu.Append(-1, 'Open SVG (2D) slicer...')
+ self.Bind(wx.EVT_MENU, self.OnSVGSlicerOpen, i)
expertMenu.AppendSeparator()
i = expertMenu.Append(-1, 'Install default Marlin firmware')
self.Bind(wx.EVT_MENU, self.OnDefaultMarlinFirmware, i)
pp.Centre()
pp.Show(True)
+ def OnSVGSlicerOpen(self, e):
+ svgSlicer = flatSlicerWindow.flatSlicerWindow()
+ svgSlicer.Centre()
+ svgSlicer.Show(True)
+
def removeSliceProgress(self, spp):
self.progressPanelList.remove(spp)
newSize = self.GetSize();
--- /dev/null
+import sys, math, re, os, struct, time
+from xml.etree import ElementTree
+
+import profile
+
+def processRect(e):
+ x = float(e.get('x'))
+ y = float(e.get('y'))
+ width = float(e.get('width'))
+ height = float(e.get('height'))
+ return [[complex(x, -y), complex(x+width, -y), complex(x+width, -(y+height)), complex(x, -(y+height)), complex(x, -y)]]
+
+def processPath(e):
+ d = e.get('d').replace(',', ' ')
+ num = ""
+ cmd = None
+ paths = []
+ curPath = None
+
+ p = complex(0, 0)
+ for c in d + "#":
+ if c in "-+.0123456789e":
+ num += c
+ if c in " \t\n\r#":
+ if len(num) > 0:
+ param.append(float(num))
+ num = ""
+ if c in "MmZzLlHhVvCcSsQqTtAa#":
+ if cmd == 'M':
+ p = complex(param[0], -param[1])
+ curPath = None
+ i = 2
+ while i < len(param):
+ if curPath == None:
+ curPath = [p]
+ paths.append(curPath)
+ p = complex(param[i], -param[i+1])
+ curPath.append(p)
+ i += 2
+ elif cmd == 'm':
+ p += complex(param[0], -param[1])
+ curPath = None
+ i = 2
+ while i < len(param):
+ if curPath == None:
+ curPath = [p]
+ paths.append(curPath)
+ p += complex(param[i], -param[i+1])
+ curPath.append(p)
+ i += 2
+ elif cmd == 'L':
+ if curPath == None:
+ curPath = [p]
+ paths.append(curPath)
+ i = 0
+ while i < len(param):
+ p = complex(param[i], -param[i+1])
+ curPath.append(p)
+ i += 2
+ elif cmd == 'l':
+ if curPath == None:
+ curPath = [p]
+ paths.append(curPath)
+ i = 0
+ while i < len(param):
+ p += complex(param[i], -param[i+1])
+ curPath.append(p)
+ i += 2
+ curPath.append(p)
+ elif cmd == 'c':
+ if curPath == None:
+ curPath = [p]
+ paths.append(curPath)
+ i = 0
+ while i < len(param):
+ addCurve(curPath, p, p + complex(param[i], -param[i+1]), p + complex(param[i+2], -param[i+3]), p + complex(param[i+4], -param[i+5]))
+ p += complex(param[i+4], -param[i+5])
+ curPath.append(p)
+ i += 6
+ elif cmd == 'Z' or cmd == 'z':
+ curPath.append(curPath[0])
+ elif cmd != None:
+ print cmd
+ cmd = c
+ param = []
+ return paths
+
+def interpolate(p0, p1, f):
+ return complex(p0.real + (p1.real - p0.real) * f, p0.imag + (p1.imag - p0.imag) * f)
+
+def addCurve(path, p0, q0, q1, p1):
+ oldPoint = p0
+ for n in xrange(0, 100):
+ k = n / 100.0
+ r0 = interpolate(p0, q0, k);
+ r1 = interpolate(q0, q1, k);
+ r2 = interpolate(q1, p1, k);
+ b0 = interpolate(r0, r1, k);
+ b1 = interpolate(r1, r2, k);
+ s = interpolate(b0, b1, k);
+ if abs(s - oldPoint) > 1.0:
+ path.append(s)
+ oldPoint = s
+
+def movePath(p, offset):
+ return map(lambda _p: _p - offset, p)
+
+class SVG(object):
+ def __init__(self, filename):
+ tagProcess = {}
+ tagProcess['rect'] = processRect
+ tagProcess['path'] = processPath
+
+ self.paths = []
+ for e in ElementTree.parse(open(filename, "r")).getiterator():
+ tag = e.tag[e.tag.find('}')+1:]
+ if not tag in tagProcess:
+ #print 'unknown tag: %s' % (tag)
+ continue
+ self.paths.extend(tagProcess[tag](e))
+
+ def center(self, centerPoint):
+ offset = complex(0, 0)
+ n = 0
+ for path in self.paths:
+ for point in path:
+ offset += point
+ n += 1
+ offset /= n
+ offset -= centerPoint
+
+ self.paths = [movePath(p, offset) for p in self.paths]
+
+if __name__ == '__main__':
+ svg = SVG("../logo.svg")
+ f = open("../../test_export.gcode", "w")
+
+ f.write(';TYPE:CUSTOM\n')
+ f.write(profile.getAlterationFileContents('start.gcode'))
+ svg.center(complex(profile.getProfileSettingFloat('machine_center_x'), profile.getProfileSettingFloat('machine_center_y')))
+
+ layerThickness = 0.4
+ filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
+ filamentArea = math.pi * filamentRadius * filamentRadius
+ lineWidth = profile.getProfileSettingFloat('nozzle_size') * 2
+
+ e = 0
+ z = layerThickness
+
+ for n in xrange(0, 20):
+ f.write("G1 Z%f F%f\n" % (z, profile.getProfileSettingFloat('max_z_speed')*60))
+ for path in svg.paths:
+ oldPoint = path[0]
+ extrusionMMperDist = lineWidth * layerThickness / filamentArea
+ f.write("G1 X%f Y%f F%f\n" % (oldPoint.real, oldPoint.imag, profile.getProfileSettingFloat('travel_speed')*60))
+ f.write("G1 F%f\n" % (profile.getProfileSettingFloat('print_speed')*60))
+ for point in path[1:]:
+ dist = abs(oldPoint - point)
+ e += dist * extrusionMMperDist
+ f.write("G1 X%f Y%f E%f\n" % (point.real, point.imag, e))
+ oldPoint = point
+ z += layerThickness
+ f.write(profile.getAlterationFileContents('end.gcode'))
+ f.close()
+