From: daid303 Date: Thu, 16 May 2013 09:11:32 +0000 (+0200) Subject: Add an about box. X-Git-Tag: 13.05~11 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=fa0ca3ea3f6c5174855c9d300c67ee6d9ad1cc05;p=cura.git Add an about box. --- diff --git a/Cura/gui/mainWindow.py b/Cura/gui/mainWindow.py index 0523889d..998f4b77 100644 --- a/Cura/gui/mainWindow.py +++ b/Cura/gui/mainWindow.py @@ -145,6 +145,8 @@ class mainWindow(wx.Frame): self.Bind(wx.EVT_MENU, lambda e: webbrowser.open('https://github.com/daid/Cura/issues'), i) i = helpMenu.Append(-1, 'Check for update...') self.Bind(wx.EVT_MENU, self.OnCheckForUpdate, i) + i = helpMenu.Append(-1, 'About Cura...') + self.Bind(wx.EVT_MENU, self.OnAbout, i) self.menubar.Append(helpMenu, 'Help') self.SetMenuBar(self.menubar) @@ -409,6 +411,28 @@ class mainWindow(wx.Frame): else: wx.MessageBox('You are running the latest version of Cura!', 'Awesome!', wx.ICON_INFORMATION) + def OnAbout(self, e): + info = wx.AboutDialogInfo() + info.SetName('Cura') + info.SetDescription('End solution for Open Source Fused Filament Fabrication 3D printing.') + info.SetWebSite('http://software.ultimaker.com/') + info.SetCopyright('Copyright (C) David Braam') + info.SetLicence(""" + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +""") + wx.AboutBox(info) + def OnClose(self, e): profile.saveProfile(profile.getDefaultProfilePath()) diff --git a/Cura/gui/preview3d.py b/Cura/gui/preview3d.py deleted file mode 100644 index 4a25ea31..00000000 --- a/Cura/gui/preview3d.py +++ /dev/null @@ -1,902 +0,0 @@ -from __future__ import absolute_import -from __future__ import division - -import math -import threading -import re -import time -import os -import numpy -import traceback -import sys - -from wx import glcanvas -import wx -import OpenGL -OpenGL.ERROR_CHECKING = False -from OpenGL.GLU import * -from OpenGL.GL import * - -from Cura.util import profile -from Cura.util import gcodeInterpreter -from Cura.util import meshLoader -from Cura.util import util3d -from Cura.util import sliceRun - -from Cura.gui.util import opengl -from Cura.gui.util import previewTools -from Cura.gui.util import openglGui - -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) - - self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DDKSHADOW)) - self.SetMinSize((440,320)) - - self.objectList = [] - self.errorList = [] - self.gcode = None - self.objectsMinV = None - self.objectsMaxV = None - self.objectsBoundaryCircleSize = None - self.loadThread = None - self.machineSize = util3d.Vector3(profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')) - self.machineCenter = util3d.Vector3(self.machineSize.x / 2, self.machineSize.y / 2, 0) - - self.glCanvas = PreviewGLCanvas(self) - #Create the popup window - self.warningPopup = wx.PopupWindow(self, flags=wx.BORDER_SIMPLE) - self.warningPopup.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_INFOBK)) - self.warningPopup.text = wx.StaticText(self.warningPopup, -1, 'Reset scale, rotation and mirror?') - self.warningPopup.yesButton = wx.Button(self.warningPopup, -1, 'yes', style=wx.BU_EXACTFIT) - self.warningPopup.noButton = wx.Button(self.warningPopup, -1, 'no', style=wx.BU_EXACTFIT) - self.warningPopup.sizer = wx.BoxSizer(wx.HORIZONTAL) - self.warningPopup.SetSizer(self.warningPopup.sizer) - self.warningPopup.sizer.Add(self.warningPopup.text, 1, flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL, border=1) - self.warningPopup.sizer.Add(self.warningPopup.yesButton, 0, flag=wx.EXPAND|wx.ALL, border=1) - self.warningPopup.sizer.Add(self.warningPopup.noButton, 0, flag=wx.EXPAND|wx.ALL, border=1) - self.warningPopup.Fit() - self.warningPopup.Layout() - self.warningPopup.timer = wx.Timer(self) - self.Bind(wx.EVT_TIMER, self.OnHideWarning, self.warningPopup.timer) - - self.Bind(wx.EVT_BUTTON, self.OnWarningPopup, self.warningPopup.yesButton) - self.Bind(wx.EVT_BUTTON, self.OnHideWarning, self.warningPopup.noButton) - parent.Bind(wx.EVT_MOVE, self.OnMove) - parent.Bind(wx.EVT_SIZE, self.OnMove) - - sizer = wx.BoxSizer(wx.VERTICAL) - sizer.Add(self.glCanvas, 1, flag=wx.EXPAND) - self.SetSizer(sizer) - - self.checkReloadFileTimer = wx.Timer(self) - self.Bind(wx.EVT_TIMER, self.OnCheckReloadFile, self.checkReloadFileTimer) - self.checkReloadFileTimer.Start(1000) - - group = [] - self.rotateToolButton = openglGui.glRadioButton(self.glCanvas, 8, 'Rotate', (0,-1), group, self.OnToolSelect) - self.scaleToolButton = openglGui.glRadioButton(self.glCanvas, 9, 'Scale', (1,-1), group, self.OnToolSelect) - self.mirrorToolButton = openglGui.glRadioButton(self.glCanvas, 10, 'Mirror', (2,-1), group, self.OnToolSelect) - - self.resetRotationButton = openglGui.glButton(self.glCanvas, 12, 'Reset', (0,-2), self.OnRotateReset) - self.layFlatButton = openglGui.glButton(self.glCanvas, 16, 'Lay flat', (0,-3), self.OnLayFlat) - - self.resetScaleButton = openglGui.glButton(self.glCanvas, 13, 'Reset', (1,-2), self.OnScaleReset) - self.scaleMaxButton = openglGui.glButton(self.glCanvas, 17, 'To max', (1,-3), self.OnScaleMax) - - self.mirrorXButton = openglGui.glButton(self.glCanvas, 14, 'Mirror X', (2,-2), lambda : self.OnMirror(0)) - self.mirrorYButton = openglGui.glButton(self.glCanvas, 18, 'Mirror Y', (2,-3), lambda : self.OnMirror(1)) - self.mirrorZButton = openglGui.glButton(self.glCanvas, 22, 'Mirror Z', (2,-4), lambda : self.OnMirror(2)) - - self.openFileButton = openglGui.glButton(self.glCanvas, 4, 'Load', (0,0), lambda : self.GetParent().GetParent().GetParent()._showModelLoadDialog(1)) - self.sliceButton = openglGui.glButton(self.glCanvas, 5, 'Prepare', (1,0), lambda : self.GetParent().GetParent().GetParent().OnSlice(None)) - self.printButton = openglGui.glButton(self.glCanvas, 6, 'Print', (2,0), lambda : self.GetParent().GetParent().GetParent().OnPrint(None)) - - self.rotateToolButton.setExpandArrow(True) - self.scaleToolButton.setExpandArrow(True) - self.mirrorToolButton.setExpandArrow(True) - - extruderCount = int(profile.getPreference('extruder_amount')) - if extruderCount > 1: - openglGui.glButton(self.glCanvas, 4, 'Load dual', (0,1), lambda : self.GetParent().GetParent().GetParent()._showModelLoadDialog(2)) - if extruderCount > 2: - openglGui.glButton(self.glCanvas, 4, 'Load triple', (0,2), lambda : self.GetParent().GetParent().GetParent()._showModelLoadDialog(3)) - if extruderCount > 3: - openglGui.glButton(self.glCanvas, 4, 'Load quad', (0,3), lambda : self.GetParent().GetParent().GetParent()._showModelLoadDialog(4)) - - self.scaleForm = openglGui.glFrame(self.glCanvas, (2, -2)) - openglGui.glGuiLayoutGrid(self.scaleForm) - openglGui.glLabel(self.scaleForm, 'Scale X', (0,0)) - self.scaleXctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,0), lambda value: self.OnScaleEntry(value, 0)) - openglGui.glLabel(self.scaleForm, 'Scale Y', (0,1)) - self.scaleYctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,1), lambda value: self.OnScaleEntry(value, 1)) - openglGui.glLabel(self.scaleForm, 'Scale Z', (0,2)) - self.scaleZctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,2), lambda value: self.OnScaleEntry(value, 2)) - openglGui.glLabel(self.scaleForm, 'Size X (mm)', (0,4)) - self.scaleXmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,4), lambda value: self.OnScaleEntryMM(value, 0)) - openglGui.glLabel(self.scaleForm, 'Size Y (mm)', (0,5)) - self.scaleYmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,5), lambda value: self.OnScaleEntryMM(value, 1)) - openglGui.glLabel(self.scaleForm, 'Size Z (mm)', (0,6)) - self.scaleZmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,6), lambda value: self.OnScaleEntryMM(value, 2)) - openglGui.glLabel(self.scaleForm, 'Uniform scale', (0,8)) - self.scaleUniform = openglGui.glCheckbox(self.scaleForm, True, (1,8), None) - - self.viewSelection = openglGui.glComboButton(self.glCanvas, 'View mode', [7,11,15,19,23], ['Normal', 'Transparent', 'X-Ray', 'Overhang', 'Layers'], (-1,0), self.OnViewChange) - self.layerSelect = openglGui.glSlider(self.glCanvas, 0, 0, 100, (-1,-2), lambda : self.Refresh()) - - self.OnViewChange() - self.OnToolSelect() - self.updateModelTransform() - - self.matrix = numpy.matrix(numpy.array(profile.getObjectMatrix(), numpy.float64).reshape((3,3,))) - - def OnToolSelect(self): - if self.rotateToolButton.getSelected(): - self.tool = previewTools.toolRotate(self.glCanvas) - elif self.scaleToolButton.getSelected(): - self.tool = previewTools.toolScale(self.glCanvas) - elif self.mirrorToolButton.getSelected(): - self.tool = previewTools.toolNone(self.glCanvas) - else: - self.tool = previewTools.toolNone(self.glCanvas) - self.resetRotationButton.setHidden(not self.rotateToolButton.getSelected()) - self.layFlatButton.setHidden(not self.rotateToolButton.getSelected()) - self.resetScaleButton.setHidden(not self.scaleToolButton.getSelected()) - self.scaleMaxButton.setHidden(not self.scaleToolButton.getSelected()) - self.scaleForm.setHidden(not self.scaleToolButton.getSelected()) - self.mirrorXButton.setHidden(not self.mirrorToolButton.getSelected()) - self.mirrorYButton.setHidden(not self.mirrorToolButton.getSelected()) - self.mirrorZButton.setHidden(not self.mirrorToolButton.getSelected()) - self.updateModelTransform() - - def OnScaleEntry(self, value, axis): - try: - value = float(value) - except: - return - scale = numpy.linalg.norm(self.matrix[::,axis].getA().flatten()) - scale = value / scale - if scale == 0: - return - if self.scaleUniform.getValue(): - matrix = [[scale,0,0], [0, scale, 0], [0, 0, scale]] - else: - matrix = [[1.0,0,0], [0, 1.0, 0], [0, 0, 1.0]] - matrix[axis][axis] = scale - self.matrix *= numpy.matrix(matrix, numpy.float64) - self.updateModelTransform() - - def OnScaleEntryMM(self, value, axis): - try: - value = float(value) - except: - return - scale = self.objectsSize[axis] - scale = value / scale - if scale == 0: - return - if self.scaleUniform.getValue(): - matrix = [[scale,0,0], [0, scale, 0], [0, 0, scale]] - else: - matrix = [[1,0,0], [0, 1, 0], [0, 0, 1]] - matrix[axis][axis] = scale - self.matrix *= numpy.matrix(matrix, numpy.float64) - self.updateModelTransform() - - def OnMirror(self, axis): - matrix = [[1,0,0], [0, 1, 0], [0, 0, 1]] - matrix[axis][axis] = -1 - self.matrix *= numpy.matrix(matrix, numpy.float64) - for obj in self.objectList: - obj.dirty = True - obj.steepDirty = True - self.updateModelTransform() - - def OnMove(self, e = None): - if e is not None: - e.Skip() - x, y = self.glCanvas.ClientToScreenXY(0, 0) - sx, sy = self.glCanvas.GetClientSizeTuple() - self.warningPopup.SetPosition((x, y+sy-self.warningPopup.GetSize().height)) - - def OnScaleMax(self): - if self.objectsMinV is None: - return - vMin = self.objectsMinV - vMax = self.objectsMaxV - skirtSize = 3 - if profile.getProfileSettingFloat('skirt_line_count') > 0: - skirtSize = 3 + profile.getProfileSettingFloat('skirt_line_count') * profile.calculateEdgeWidth() + profile.getProfileSettingFloat('skirt_gap') - scaleX1 = (self.machineSize.x - self.machineCenter.x - skirtSize) / ((vMax[0] - vMin[0]) / 2) - scaleY1 = (self.machineSize.y - self.machineCenter.y - skirtSize) / ((vMax[1] - vMin[1]) / 2) - scaleX2 = (self.machineCenter.x - skirtSize) / ((vMax[0] - vMin[0]) / 2) - scaleY2 = (self.machineCenter.y - skirtSize) / ((vMax[1] - vMin[1]) / 2) - scaleZ = self.machineSize.z / (vMax[2] - vMin[2]) - scale = min(scaleX1, scaleY1, scaleX2, scaleY2, scaleZ) - self.matrix *= numpy.matrix([[scale,0,0],[0,scale,0],[0,0,scale]], numpy.float64) - if self.glCanvas.viewMode == 'GCode' or self.glCanvas.viewMode == 'Mixed': - self.setViewMode('Normal') - self.updateModelTransform() - - def OnRotateReset(self): - x = numpy.linalg.norm(self.matrix[::,0].getA().flatten()) - y = numpy.linalg.norm(self.matrix[::,1].getA().flatten()) - z = numpy.linalg.norm(self.matrix[::,2].getA().flatten()) - self.matrix = numpy.matrix([[x,0,0],[0,y,0],[0,0,z]], numpy.float64) - for obj in self.objectList: - obj.dirty = True - obj.steepDirty = True - self.updateModelTransform() - - def OnScaleReset(self): - x = 1/numpy.linalg.norm(self.matrix[::,0].getA().flatten()) - y = 1/numpy.linalg.norm(self.matrix[::,1].getA().flatten()) - z = 1/numpy.linalg.norm(self.matrix[::,2].getA().flatten()) - self.matrix *= numpy.matrix([[x,0,0],[0,y,0],[0,0,z]], numpy.float64) - for obj in self.objectList: - obj.steepDirty = True - self.updateModelTransform() - - def OnLayFlat(self): - transformedVertexes = (numpy.matrix(self.objectList[0].mesh.vertexes, copy = False) * self.matrix).getA() - minZvertex = transformedVertexes[transformedVertexes.argmin(0)[2]] - dotMin = 1.0 - dotV = None - for v in transformedVertexes: - diff = v - minZvertex - len = math.sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2]) - if len < 5: - continue - dot = (diff[2] / len) - if dotMin > dot: - dotMin = dot - dotV = diff - if dotV is None: - return - rad = -math.atan2(dotV[1], dotV[0]) - self.matrix *= numpy.matrix([[math.cos(rad), math.sin(rad), 0], [-math.sin(rad), math.cos(rad), 0], [0,0,1]], numpy.float64) - rad = -math.asin(dotMin) - self.matrix *= numpy.matrix([[math.cos(rad), 0, math.sin(rad)], [0,1,0], [-math.sin(rad), 0, math.cos(rad)]], numpy.float64) - - - transformedVertexes = (numpy.matrix(self.objectList[0].mesh.vertexes, copy = False) * self.matrix).getA() - minZvertex = transformedVertexes[transformedVertexes.argmin(0)[2]] - dotMin = 1.0 - dotV = None - for v in transformedVertexes: - diff = v - minZvertex - len = math.sqrt(diff[1] * diff[1] + diff[2] * diff[2]) - if len < 5: - continue - dot = (diff[2] / len) - if dotMin > dot: - dotMin = dot - dotV = diff - if dotV is None: - return - if dotV[1] < 0: - rad = math.asin(dotMin) - else: - rad = -math.asin(dotMin) - self.matrix *= numpy.matrix([[1,0,0], [0, math.cos(rad), math.sin(rad)], [0, -math.sin(rad), math.cos(rad)]], numpy.float64) - - for obj in self.objectList: - obj.steepDirty = True - self.updateModelTransform() - - def setViewMode(self, mode): - if mode == "Normal": - self.viewSelection.setValue(0) - if mode == "GCode": - self.viewSelection.setValue(4) - wx.CallAfter(self.glCanvas.Refresh) - - def loadModelFiles(self, filelist, showWarning = False): - while len(filelist) > len(self.objectList): - self.objectList.append(previewObject()) - for idx in xrange(len(filelist), len(self.objectList)): - self.objectList[idx].mesh = None - self.objectList[idx].filename = 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.mesh = None - obj.filename = filelist[idx] - - self.deselectTool() - self.gcodeFilename = sliceRun.getExportFilename(filelist[0]) - self.gcode = None - #Do the STL file loading in a background thread so we don't block the UI. - if self.loadThread is not None and self.loadThread.isAlive(): - self.abortLoading = True - self.loadThread.join() - self.abortLoading = False - self.loadThread = threading.Thread(target=self.doFileLoadThread) - self.loadThread.daemon = True - self.loadThread.start() - - if showWarning: - if (self.matrix - numpy.matrix([[1,0,0],[0,1,0],[0,0,1]], numpy.float64)).any() or len(profile.getPluginConfig()) > 0: - self.ShowWarningPopup('Reset scale, rotation, mirror and plugins?', self.OnResetAll) - - def OnCheckReloadFile(self, e): - #Only show the reload popup when the window has focus, because the popup goes over other programs. - if self.GetParent().FindFocus() is None: - return - for obj in self.objectList: - if obj.filename is not None and os.path.isfile(obj.filename) and obj.fileTime != os.stat(obj.filename).st_mtime: - self.checkReloadFileTimer.Stop() - self.ShowWarningPopup('File changed, reload?', self.reloadModelFiles) - if wx.TheClipboard.Open(): - data = wx.TextDataObject() - if wx.TheClipboard.GetData(data): - data = data.GetText() - if re.match('^http://.*/.*$', data): - if data.endswith(tuple(meshLoader.loadSupportedExtensions())): - #Got an url on the clipboard with a model file. - pass - wx.TheClipboard.Close() - - def reloadModelFiles(self, filelist = None): - if filelist is not None: - #Only load this again if the filename matches the file we have already loaded (for auto loading GCode after slicing) - for idx in xrange(0, len(filelist)): - if self.objectList[idx].filename != filelist[idx]: - return False - else: - filelist = [] - for idx in xrange(0, len(self.objectList)): - filelist.append(self.objectList[idx].filename) - self.loadModelFiles(filelist) - return True - - def doFileLoadThread(self): - for obj in self.objectList: - if obj.filename is not None and os.path.isfile(obj.filename) and obj.fileTime != os.stat(obj.filename).st_mtime: - obj.fileTime = os.stat(obj.filename).st_mtime - try: - mesh = meshLoader.loadMeshes(obj.filename)[0] - except: - traceback.print_exc(file=sys.stdout) - wx.CallAfter(self.ShowWarningPopup, 'Failed to load %s' % (obj.filename)) - obj.mesh = None - obj.filename = None - else: - obj.mesh = mesh - obj.dirty = True - obj.steepDirty = True - self.updateModelTransform() - if self.objectsBoundaryCircleSize is not None: - self.glCanvas.zoom = self.objectsBoundaryCircleSize * 6.0 - self.errorList = [] - wx.CallAfter(self.updateToolbar) - wx.CallAfter(self.glCanvas.Refresh) - elif obj.filename is None or not os.path.isfile(obj.filename): - obj.mesh = None - obj.filename = None - - if os.path.isfile(self.gcodeFilename) and self.gcodeFileTime != os.stat(self.gcodeFilename).st_mtime: - self.gcodeFileTime = os.stat(self.gcodeFilename).st_mtime - self.gcodeDirty = True - self.gcode = gcodeInterpreter.gcode() - self.gcode.progressCallback = self.loadProgress - self.gcode.load(self.gcodeFilename) - - errorList = [] - for line in open(self.gcodeFilename, "rt"): - res = re.search(';Model error\(([a-z ]*)\): \(([0-9\.\-e]*), ([0-9\.\-e]*), ([0-9\.\-e]*)\) \(([0-9\.\-e]*), ([0-9\.\-e]*), ([0-9\.\-e]*)\)', line) - if res is not None: - v1 = util3d.Vector3(float(res.group(2)), float(res.group(3)), float(res.group(4))) - v2 = util3d.Vector3(float(res.group(5)), float(res.group(6)), float(res.group(7))) - errorList.append([v1, v2]) - self.errorList = errorList - - wx.CallAfter(self.updateToolbar) - wx.CallAfter(self.glCanvas.Refresh) - elif not os.path.isfile(self.gcodeFilename): - self.gcode = None - wx.CallAfter(self.checkReloadFileTimer.Start, 1000) - - def loadProgress(self, progress): - if self.gcode is None: - return True - if self.layerSelect.getValue() == self.layerSelect.getMaxValue(): - self.layerSelect.setRange(1, len(self.gcode.layerList) - 1) - self.layerSelect.setValue(self.layerSelect.getMaxValue()) - else: - self.layerSelect.setRange(1, len(self.gcode.layerList) - 1) - return self.abortLoading - - def OnResetAll(self, e = None): - profile.putProfileSetting('model_matrix', '1,0,0,0,1,0,0,0,1') - profile.setPluginConfig([]) - self.updateProfileToControls() - - def ShowWarningPopup(self, text, callback = None): - self.warningPopup.text.SetLabel(text) - self.warningPopup.callback = callback - if callback is None: - self.warningPopup.yesButton.Show(False) - self.warningPopup.noButton.SetLabel('ok') - else: - self.warningPopup.yesButton.Show(True) - self.warningPopup.noButton.SetLabel('no') - self.warningPopup.Fit() - self.warningPopup.Layout() - self.OnMove() - self.warningPopup.Show(True) - self.warningPopup.timer.Start(5000) - - def OnWarningPopup(self, e): - self.warningPopup.Show(False) - self.warningPopup.timer.Stop() - self.warningPopup.callback() - - def OnHideWarning(self, e): - self.warningPopup.Show(False) - self.warningPopup.timer.Stop() - - def updateToolbar(self): - self.sliceButton.setDisabled(len(self.objectList) < 1 or self.objectList[0].mesh is None) - self.printButton.setDisabled(self.gcode is None) - self.rotateToolButton.setHidden(self.glCanvas.viewMode == "GCode") - self.scaleToolButton.setHidden(self.glCanvas.viewMode == "GCode") - self.mirrorToolButton.setHidden(self.glCanvas.viewMode == "GCode") - if self.gcode is not None: - self.layerSelect.setRange(1, len(self.gcode.layerList) - 1) - self.Update() - - def OnViewChange(self): - selection = self.viewSelection.getValue() - self.glCanvas.drawSteepOverhang = False - self.glCanvas.drawBorders = False - if selection == 0: - self.glCanvas.viewMode = "Normal" - elif selection == 1: - self.glCanvas.viewMode = "Transparent" - elif selection == 2: - self.glCanvas.viewMode = "X-Ray" - elif selection == 3: - self.glCanvas.viewMode = "Normal" - self.glCanvas.drawSteepOverhang = True - elif selection == 4: - self.layerSelect.setValue(self.layerSelect.getMaxValue()) - self.glCanvas.viewMode = "GCode" - elif selection == 5: - self.glCanvas.viewMode = "Mixed" - self.layerSelect.setHidden(self.glCanvas.viewMode != "GCode") - self.updateToolbar() - self.deselectTool() - self.glCanvas.Refresh() - - def deselectTool(self): - self.rotateToolButton.setSelected(False) - self.scaleToolButton.setSelected(False) - self.mirrorToolButton.setSelected(False) - self.OnToolSelect() - - def updateModelTransform(self, f=0): - if len(self.objectList) < 1 or self.objectList[0].mesh is None: - return - - profile.putProfileSetting('model_matrix', ','.join(map(str, list(self.matrix.getA().flatten())))) - for obj in self.objectList: - if obj.mesh is None: - continue - obj.mesh.matrix = self.matrix - obj.mesh.processMatrix() - - minV = self.objectList[0].mesh.getMinimum() - maxV = self.objectList[0].mesh.getMaximum() - objectsBoundaryCircleSize = self.objectList[0].mesh.getBoundaryCircle() - for obj in self.objectList: - if obj.mesh is None: - continue - - minV = numpy.minimum(minV, obj.mesh.getMinimum()) - maxV = numpy.maximum(maxV, obj.mesh.getMaximum()) - objectsBoundaryCircleSize = max(objectsBoundaryCircleSize, obj.mesh.getBoundaryCircle()) - - self.objectsMaxV = maxV - self.objectsMinV = minV - self.objectsSize = self.objectsMaxV - self.objectsMinV - self.objectsBoundaryCircleSize = objectsBoundaryCircleSize - - scaleX = numpy.linalg.norm(self.matrix[::,0].getA().flatten()) - scaleY = numpy.linalg.norm(self.matrix[::,1].getA().flatten()) - scaleZ = numpy.linalg.norm(self.matrix[::,2].getA().flatten()) - self.scaleXctrl.setValue(round(scaleX, 2)) - self.scaleYctrl.setValue(round(scaleY, 2)) - self.scaleZctrl.setValue(round(scaleZ, 2)) - self.scaleXmmctrl.setValue(round(self.objectsSize[0], 2)) - self.scaleYmmctrl.setValue(round(self.objectsSize[1], 2)) - self.scaleZmmctrl.setValue(round(self.objectsSize[2], 2)) - - self.glCanvas.Refresh() - - def updateProfileToControls(self): - self.matrix = numpy.matrix(numpy.array(profile.getObjectMatrix(), numpy.float64).reshape((3,3,))) - self.updateModelTransform() - for obj in self.objectList: - obj.steepDirty = True - self.glCanvas.updateProfileToControls() - -class PreviewGLCanvas(openglGui.glGuiPanel): - def __init__(self, parent): - super(PreviewGLCanvas, self).__init__(parent) - wx.EVT_MOUSEWHEEL(self, self.OnMouseWheel) - self.parent = parent - self.yaw = 30 - self.pitch = 60 - self.zoom = 300 - self.viewTarget = [parent.machineCenter.x, parent.machineCenter.y, 0.0] - self.view3D = True - self.gcodeDisplayList = [] - self.gcodeQuickDisplayList = [] - self.gcodeDisplayListMade = 0 - self.gcodeQuickDisplayListMade = 0 - 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]] - self.oldX = 0 - self.oldY = 0 - self.dragType = '' - self.tempMatrix = None - self.viewport = None - - def updateProfileToControls(self): - self.objColor[0] = profile.getPreferenceColour('model_colour') - self.objColor[1] = profile.getPreferenceColour('model_colour2') - self.objColor[2] = profile.getPreferenceColour('model_colour3') - self.objColor[3] = profile.getPreferenceColour('model_colour4') - - def OnMouseMotion(self,e): - if self.parent.objectsMaxV is not None and self.viewport is not None and self.viewMode != 'GCode' and self.viewMode != 'Mixed': - p0 = opengl.unproject(e.GetX(), self.viewport[1] + self.viewport[3] - e.GetY(), 0, self.modelMatrix, self.projMatrix, self.viewport) - p1 = opengl.unproject(e.GetX(), self.viewport[1] + self.viewport[3] - e.GetY(), 1, self.modelMatrix, self.projMatrix, self.viewport) - p0 -= self.viewTarget - p1 -= self.viewTarget - if not e.Dragging() or self.dragType != 'tool': - self.parent.tool.OnMouseMove(p0, p1) - else: - p0 = [0,0,0] - p1 = [1,0,0] - - if e.Dragging() and e.LeftIsDown(): - if self.dragType == '': - #Define the drag type depending on the cursor position. - self.dragType = 'viewRotate' - if self.viewMode != 'GCode' and self.viewMode != 'Mixed': - if self.parent.tool.OnDragStart(p0, p1): - self.dragType = 'tool' - - if self.dragType == 'viewRotate': - 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.viewTarget[0] -= float(e.GetX() - self.oldX) * self.zoom / self.GetSize().GetHeight() * 2 - self.viewTarget[1] += float(e.GetY() - self.oldY) * self.zoom / self.GetSize().GetHeight() * 2 - elif self.dragType == 'tool': - self.parent.tool.OnDrag(p0, p1) - - #Workaround for buggy ATI cards. - size = self.GetSizeTuple() - self.SetSize((size[0]+1, size[1])) - self.SetSize((size[0], size[1])) - self.Refresh() - else: - if self.dragType != '': - if self.tempMatrix is not None: - self.parent.matrix *= self.tempMatrix - self.parent.updateModelTransform() - self.tempMatrix = None - for obj in self.parent.objectList: - obj.steepDirty = True - self.parent.tool.OnDragEnd() - self.dragType = '' - if e.Dragging() and e.RightIsDown(): - self.zoom += e.GetY() - self.oldY - if self.zoom < 1: - self.zoom = 1 - if self.zoom > 500: - self.zoom = 500 - self.oldX = e.GetX() - self.oldY = e.GetY() - - def getObjectBoundaryCircle(self): - return self.parent.objectsBoundaryCircleSize - - def getObjectSize(self): - return self.parent.objectsSize - - def getObjectMatrix(self): - return self.parent.matrix - - def getObjectCenterPos(self): - return [self.parent.machineCenter.x, self.parent.machineCenter.y, self.parent.objectsSize[2] / 2 - profile.getProfileSettingFloat('object_sink')] - - def OnMouseWheel(self,e): - self.zoom *= 1.0 - float(e.GetWheelRotation() / e.GetWheelDelta()) / 10.0 - if self.zoom < 1.0: - self.zoom = 1.0 - if self.zoom > 500: - self.zoom = 500 - self.Refresh() - - def OnKeyChar(self, keycode): - if keycode == wx.WXK_UP: - self.parent.layerSelect.setValue(self.parent.layerSelect.getValue() + 1) - self.Refresh() - elif keycode == wx.WXK_DOWN: - self.parent.layerSelect.setValue(self.parent.layerSelect.getValue() - 1) - self.Refresh() - elif keycode == wx.WXK_PAGEUP: - self.parent.layerSelect.setValue(self.parent.layerSelect.getValue() + 10) - self.Refresh() - elif keycode == wx.WXK_PAGEDOWN: - self.parent.layerSelect.setValue(self.parent.layerSelect.getValue() - 10) - self.Refresh() - - def OnPaint(self,e): - opengl.InitGL(self, self.view3D, self.zoom) - if self.view3D: - glTranslate(0,0,-self.zoom) - glTranslate(self.zoom/20.0,0,0) - glRotate(-self.pitch, 1,0,0) - glRotate(self.yaw, 0,0,1) - - if self.viewMode == "GCode" or self.viewMode == "Mixed": - n = min(self.gcodeQuickDisplayListMade, self.parent.layerSelect.getValue()) - if self.parent.gcode is not None and -1 < n < len(self.parent.gcode.layerList) and len(self.parent.gcode.layerList[n]) > 0: - self.viewTarget[2] = self.parent.gcode.layerList[n][0].list[-1].z - else: - if self.parent.objectsMaxV is not None: - self.viewTarget = self.getObjectCenterPos() - glTranslate(-self.viewTarget[0], -self.viewTarget[1], -self.viewTarget[2]) - - self.viewport = glGetIntegerv(GL_VIEWPORT) - self.modelMatrix = glGetDoublev(GL_MODELVIEW_MATRIX) - self.projMatrix = glGetDoublev(GL_PROJECTION_MATRIX) - - self.OnDraw() - - if len(self.parent.objectList) > 0 and self.parent.objectList[0].mesh is None and self.parent.objectList[0].filename is not None: - glDisable(GL_DEPTH_TEST) - glLoadIdentity() - glColor3ub(255,255,255) - glTranslate(0, -3, -10) - opengl.glDrawStringCenter('Loading %s ...' % (os.path.basename(self.parent.objectList[0].filename))) - - def OnDraw(self): - machineSize = self.parent.machineSize - - if self.parent.gcode is not None and (self.viewMode == "GCode" or self.viewMode == "Mixed"): - if self.parent.gcodeDirty: - self.parent.gcodeDirty = False - self.gcodeDisplayListMade = 0 - self.gcodeQuickDisplayListMade = 0 - - if self.gcodeDisplayListMade < len(self.parent.gcode.layerList): - gcodeGenStartTime = time.time() - while time.time() - gcodeGenStartTime < 0.1 and self.gcodeQuickDisplayListMade < len(self.parent.gcode.layerList): - if len(self.gcodeQuickDisplayList) == self.gcodeQuickDisplayListMade: - self.gcodeQuickDisplayList.append(glGenLists(1)) - glNewList(self.gcodeQuickDisplayList[self.gcodeQuickDisplayListMade], GL_COMPILE) - opengl.DrawGCodeLayer(self.parent.gcode.layerList[self.gcodeQuickDisplayListMade], True) - glEndList() - self.gcodeQuickDisplayListMade += 1 - while time.time() - gcodeGenStartTime < 0.1 and self.gcodeDisplayListMade < len(self.parent.gcode.layerList): - if len(self.gcodeDisplayList) == self.gcodeDisplayListMade: - self.gcodeDisplayList.append(glGenLists(1)) - glNewList(self.gcodeDisplayList[self.gcodeDisplayListMade], GL_COMPILE) - opengl.DrawGCodeLayer(self.parent.gcode.layerList[self.gcodeDisplayListMade], False) - glEndList() - self.gcodeDisplayListMade += 1 - wx.CallAfter(self.Refresh) - - glPushMatrix() - glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, -profile.getProfileSettingFloat('object_sink')) - for obj in self.parent.objectList: - if obj.mesh is None: - continue - if obj.displayList is None: - obj.displayList = glGenLists(1) - obj.steepDisplayList = glGenLists(1) - obj.outlineDisplayList = glGenLists(1) - if obj.dirty: - obj.dirty = False - glNewList(obj.displayList, GL_COMPILE) - opengl.DrawMesh(obj.mesh, numpy.linalg.det(obj.mesh.matrix) < 0) - glEndList() - glNewList(obj.outlineDisplayList, GL_COMPILE) - opengl.DrawMeshOutline(obj.mesh) - glEndList() - - if self.viewMode == "Mixed": - glDisable(GL_BLEND) - glColor3f(0.0,0.0,0.0) - self.drawModel(obj.displayList) - glColor3f(1.0,1.0,1.0) - glClear(GL_DEPTH_BUFFER_BIT) - - glPopMatrix() - - if self.parent.gcode is not None and (self.viewMode == "GCode" or self.viewMode == "Mixed"): - glPushMatrix() - if profile.getPreference('machine_center_is_zero') == 'True': - glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, 0) - glEnable(GL_COLOR_MATERIAL) - glEnable(GL_LIGHTING) - drawQuickUpToLayer = min(self.gcodeQuickDisplayListMade, self.parent.layerSelect.getValue() + 1) - drawUpToLayer = min(self.gcodeDisplayListMade, self.parent.layerSelect.getValue() + 1) - - for i in xrange(drawQuickUpToLayer - 1, -1, -1): - c = 1.0 - if i < self.parent.layerSelect.getValue(): - c = 0.9 - (drawQuickUpToLayer - i) * 0.1 - if c < 0.4: - c = (0.4 + c) / 2 - if c < 0.1: - c = 0.1 - glLightfv(GL_LIGHT0, GL_DIFFUSE, [0,0,0,0]) - glLightfv(GL_LIGHT0, GL_AMBIENT, [c,c,c,c]) - if self.gcodeDisplayListMade > i and drawUpToLayer - i < 15: - glCallList(self.gcodeDisplayList[i]) - else: - glCallList(self.gcodeQuickDisplayList[i]) - - glDisable(GL_LIGHTING) - glDisable(GL_COLOR_MATERIAL) - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, [0.2, 0.2, 0.2, 1.0]); - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, [0.8, 0.8, 0.8, 1.0]); - glPopMatrix() - - glColor3f(1.0,1.0,1.0) - glPushMatrix() - glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, -profile.getProfileSettingFloat('object_sink')) - for obj in self.parent.objectList: - if obj.mesh is None: - continue - - if self.viewMode == "Transparent" or self.viewMode == "Mixed": - 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) - glColor3f(0.0,0.0,0.0) - self.drawModel(obj.displayList) - glColor3f(1.0,1.0,1.0) - #After the black model is rendered, render the model again but now with lighting and no depth testing. - glDisable(GL_DEPTH_TEST) - glEnable(GL_LIGHTING) - glEnable(GL_BLEND) - glBlendFunc(GL_ONE, GL_ONE) - glEnable(GL_LIGHTING) - self.drawModel(obj.displayList) - glEnable(GL_DEPTH_TEST) - elif self.viewMode == "X-Ray": - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) - glDisable(GL_LIGHTING) - glDisable(GL_DEPTH_TEST) - glEnable(GL_STENCIL_TEST) - glStencilFunc(GL_ALWAYS, 1, 1) - glStencilOp(GL_INCR, GL_INCR, GL_INCR) - self.drawModel(obj.displayList) - 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(obj.displayList) - glStencilFunc(GL_EQUAL, 1, 1) - glColor(1, 0, 0) - self.drawModel(obj.displayList) - - glPushMatrix() - glLoadIdentity() - for i in xrange(2, 15, 2): - glStencilFunc(GL_EQUAL, i, 0xFF); - glColor(float(i)/10, float(i)/10, float(i)/5) - glBegin(GL_QUADS) - glVertex3f(-1000,-1000,-1) - glVertex3f( 1000,-1000,-1) - glVertex3f( 1000, 1000,-1) - glVertex3f(-1000, 1000,-1) - glEnd() - for i in xrange(1, 15, 2): - glStencilFunc(GL_EQUAL, i, 0xFF); - glColor(float(i)/10, 0, 0) - glBegin(GL_QUADS) - glVertex3f(-1000,-1000,-1) - glVertex3f( 1000,-1000,-1) - glVertex3f( 1000, 1000,-1) - glVertex3f(-1000, 1000,-1) - glEnd() - glPopMatrix() - - glDisable(GL_STENCIL_TEST) - glEnable(GL_DEPTH_TEST) - - #Fix the depth buffer - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE) - self.drawModel(obj.displayList) - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) - elif self.viewMode == "Normal": - glLightfv(GL_LIGHT0, GL_DIFFUSE, self.objColor[self.parent.objectList.index(obj)]) - glLightfv(GL_LIGHT0, GL_AMBIENT, map(lambda x: x * 0.4, self.objColor[self.parent.objectList.index(obj)])) - glEnable(GL_LIGHTING) - self.drawModel(obj.displayList) - - if self.drawBorders and (self.viewMode == "Normal" or self.viewMode == "Transparent" or self.viewMode == "X-Ray"): - glEnable(GL_DEPTH_TEST) - glDisable(GL_LIGHTING) - glColor3f(1,1,1) - self.drawModel(obj.outlineDisplayList) - - if self.drawSteepOverhang: - if obj.steepDirty: - obj.steepDirty = False - glNewList(obj.steepDisplayList, GL_COMPILE) - opengl.DrawMeshSteep(obj.mesh, self.parent.matrix, 60) - glEndList() - glDisable(GL_LIGHTING) - glColor3f(1,1,1) - self.drawModel(obj.steepDisplayList) - - glPopMatrix() - #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() - # glEnable(GL_DEPTH_TEST) - - opengl.DrawMachine(machineSize) - - #Draw the current selected tool - if self.parent.objectsMaxV is not None and self.viewMode != 'GCode' and self.viewMode != 'Mixed': - glPushMatrix() - pos = self.getObjectCenterPos() - glTranslate(pos[0], pos[1], pos[2]) - self.parent.tool.OnDraw() - glPopMatrix() - - def drawModel(self, displayList): - vMin = self.parent.objectsMinV - vMax = self.parent.objectsMaxV - if vMin is None: - return - offset = - vMin - (vMax - vMin) / 2 - - matrix = opengl.convert3x3MatrixTo4x4(self.parent.matrix) - - glPushMatrix() - glTranslate(0, 0, self.parent.objectsSize[2]/2) - if self.tempMatrix is not None: - tempMatrix = opengl.convert3x3MatrixTo4x4(self.tempMatrix) - glMultMatrixf(tempMatrix) - glTranslate(0, 0, -self.parent.objectsSize[2]/2) - glTranslate(offset[0], offset[1], -vMin[2]) - glMultMatrixf(matrix) - glCallList(displayList) - glPopMatrix() diff --git a/Cura/gui/projectPlanner.py b/Cura/gui/projectPlanner.py deleted file mode 100644 index 626e006d..00000000 --- a/Cura/gui/projectPlanner.py +++ /dev/null @@ -1,1159 +0,0 @@ -from __future__ import absolute_import - -import wx -import os -import threading -import time -import re -import shutil -import ConfigParser -import numpy -import math - -import OpenGL -OpenGL.ERROR_CHECKING = False -from OpenGL.GLU import * -from OpenGL.GL import * - -from Cura.gui.util import opengl -from Cura.gui.util import toolbarUtil -from Cura.gui import configBase -from Cura.gui import printWindow -from Cura.gui.util import dropTarget -from Cura.gui.util import taskbar -from Cura.gui.util import previewTools -from Cura.gui.util import openglGui -from Cura.util import validators -from Cura.util import profile -from Cura.util import util3d -from Cura.util import meshLoader -from Cura.util.meshLoaders import stl -from Cura.util import mesh -from Cura.util import sliceRun -from Cura.util import gcodeInterpreter -from Cura.util import explorer - -class Action(object): - pass - -class ProjectObject(object): - def __init__(self, parent, filename): - super(ProjectObject, self).__init__() - - self.mesh = meshLoader.loadMesh(filename) - - self.parent = parent - self.filename = filename - self.matrix = numpy.matrix([[1,0,0],[0,1,0],[0,0,1]], numpy.float64) - self.profile = None - - self.modelDisplayList = None - self.modelDirty = True - - self.centerX = self.getSize()[0]/2 + 5 - self.centerY = self.getSize()[1]/2 + 5 - - self.updateMatrix() - - def isSameExceptForPosition(self, other): - if self.filename != other.filename: - return False - if self.matrix != other.matrix: - return False - if self.profile != other.profile: - return False - return True - - def updateMatrix(self): - self.mesh.matrix = self.matrix - self.mesh.processMatrix() - - scaleX = numpy.linalg.norm(self.matrix[::,0].getA().flatten()) - scaleY = numpy.linalg.norm(self.matrix[::,1].getA().flatten()) - scaleZ = numpy.linalg.norm(self.matrix[::,2].getA().flatten()) - self.parent.scaleXctrl.setValue(round(scaleX, 2)) - self.parent.scaleYctrl.setValue(round(scaleY, 2)) - self.parent.scaleZctrl.setValue(round(scaleZ, 2)) - self.parent.scaleXmmctrl.setValue(round(self.getSize()[0], 2)) - self.parent.scaleYmmctrl.setValue(round(self.getSize()[1], 2)) - self.parent.scaleZmmctrl.setValue(round(self.getSize()[2], 2)) - - def getMinimum(self): - return self.mesh.getMinimum() - def getMaximum(self): - return self.mesh.getMaximum() - def getSize(self): - return self.mesh.getSize() - def getBoundaryCircle(self): - return self.mesh.boundaryCircleSize - - def clone(self): - p = ProjectObject(self.parent, self.filename) - - p.centerX = self.centerX + 5 - p.centerY = self.centerY + 5 - - p.filename = self.filename - p.matrix = self.matrix.copy() - p.profile = self.profile - - p.updateMatrix() - - return p - - def clampXY(self): - size = self.getSize() - if self.centerX < size[0] / 2: - self.centerX = size[0] / 2 - if self.centerY < size[1] / 2: - self.centerY = size[1] / 2 - if self.centerX > self.parent.machineSize[0] - size[0] / 2: - self.centerX = self.parent.machineSize[0] - size[0] / 2 - if self.centerY > self.parent.machineSize[1] - size[1] / 2: - self.centerY = self.parent.machineSize[1] - size[1] / 2 - -class projectPlanner(wx.Frame): - "Main user interface window" - def __init__(self): - super(projectPlanner, self).__init__(None, title='Cura - Project Planner') - - 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.SetDropTarget(dropTarget.FileDropTarget(self.OnDropFiles, meshLoader.loadSupportedExtensions())) - - self.list = [] - self.selection = None - self.printMode = 0 - self.alwaysAutoPlace = profile.getPreference('planner_always_autoplace') == 'True' - - self.machineSize = numpy.array([profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height')]) - self.headSizeMin = numpy.array([profile.getPreferenceFloat('extruder_head_size_min_x'), profile.getPreferenceFloat('extruder_head_size_min_y'),0]) - self.headSizeMax = numpy.array([profile.getPreferenceFloat('extruder_head_size_max_x'), profile.getPreferenceFloat('extruder_head_size_max_y'),0]) - - self.extruderOffset = [ - numpy.array([0,0,0]), - numpy.array([profile.getPreferenceFloat('extruder_offset_x1'), profile.getPreferenceFloat('extruder_offset_y1'), 0]), - numpy.array([profile.getPreferenceFloat('extruder_offset_x2'), profile.getPreferenceFloat('extruder_offset_y2'), 0]), - numpy.array([profile.getPreferenceFloat('extruder_offset_x3'), profile.getPreferenceFloat('extruder_offset_y3'), 0])] - - self.toolbar = toolbarUtil.Toolbar(self.panel) - - toolbarUtil.NormalButton(self.toolbar, self.OnLoadProject, 'open.png', 'Open project') - toolbarUtil.NormalButton(self.toolbar, self.OnSaveProject, 'save.png', 'Save project') - self.toolbar.AddSeparator() - group = [] - toolbarUtil.RadioButton(self.toolbar, group, 'object-3d-on.png', 'object-3d-off.png', '3D view', callback=self.On3DClick).SetValue(self.alwaysAutoPlace) - toolbarUtil.RadioButton(self.toolbar, group, 'object-top-on.png', 'object-top-off.png', 'Topdown view', callback=self.OnTopClick).SetValue(not self.alwaysAutoPlace) - self.toolbar.AddSeparator() - toolbarUtil.NormalButton(self.toolbar, self.OnPreferences, 'preferences.png', 'Project planner preferences') - self.toolbar.AddSeparator() - toolbarUtil.NormalButton(self.toolbar, self.OnCutMesh, 'cut-mesh.png', 'Cut a plate STL into multiple STL files, and add those files to the project.\nNote: Splitting up plates sometimes takes a few minutes.') - toolbarUtil.NormalButton(self.toolbar, self.OnSaveCombinedSTL, 'save-combination.png', 'Save all the combined STL files into a single STL file as a plate.') - self.toolbar.AddSeparator() - group = [] - self.printOneAtATime = toolbarUtil.RadioButton(self.toolbar, group, 'view-normal-on.png', 'view-normal-off.png', 'Print one object at a time', callback=self.OnPrintTypeChange) - self.printAllAtOnce = toolbarUtil.RadioButton(self.toolbar, group, 'all-at-once-on.png', 'all-at-once-off.png', 'Print all the objects at once', callback=self.OnPrintTypeChange) - self.toolbar.AddSeparator() - toolbarUtil.NormalButton(self.toolbar, self.OnQuit, 'exit.png', 'Close project planner') - - self.toolbar.Realize() - - self.toolbar2 = toolbarUtil.Toolbar(self.panel) - - toolbarUtil.NormalButton(self.toolbar2, self.OnAddModel, 'object-add.png', 'Add model') - toolbarUtil.NormalButton(self.toolbar2, self.OnRemModel, 'object-remove.png', 'Remove model') - self.toolbar2.AddSeparator() - toolbarUtil.NormalButton(self.toolbar2, self.OnMoveUp, 'move-up.png', 'Move model up in print list') - toolbarUtil.NormalButton(self.toolbar2, self.OnMoveDown, 'move-down.png', 'Move model down in print list') - toolbarUtil.NormalButton(self.toolbar2, self.OnCopy, 'copy.png', 'Make a copy of the current selected object') - toolbarUtil.NormalButton(self.toolbar2, self.OnSetCustomProfile, 'set-profile.png', 'Set a custom profile to be used to prepare a specific object.') - self.toolbar2.AddSeparator() - if not self.alwaysAutoPlace: - toolbarUtil.NormalButton(self.toolbar2, self.OnAutoPlace, 'autoplace.png', 'Automaticly organize the objects on the platform.') - toolbarUtil.NormalButton(self.toolbar2, self.OnSlice, 'slice.png', 'Prepare to project into a gcode file.') - self.toolbar2.Realize() - - sizer = wx.GridBagSizer(2,2) - self.panel.SetSizer(sizer) - self.glCanvas = PreviewGLCanvas(self.panel, self) - self.listbox = wx.ListBox(self.panel, -1, choices=[]) - self.addButton = wx.Button(self.panel, -1, "Add") - self.remButton = wx.Button(self.panel, -1, "Remove") - self.sliceButton = wx.Button(self.panel, -1, "Prepare") - if not self.alwaysAutoPlace: - self.autoPlaceButton = wx.Button(self.panel, -1, "Auto Place") - - sizer.Add(self.toolbar, (0,0), span=(1,1), flag=wx.EXPAND|wx.LEFT|wx.RIGHT) - sizer.Add(self.toolbar2, (0,1), span=(1,2), flag=wx.EXPAND|wx.LEFT|wx.RIGHT) - sizer.Add(self.glCanvas, (1,0), span=(5,1), flag=wx.EXPAND) - sizer.Add(self.listbox, (1,1), span=(1,2), flag=wx.EXPAND) - sizer.Add(self.addButton, (2,1), span=(1,1)) - sizer.Add(self.remButton, (2,2), span=(1,1)) - sizer.Add(self.sliceButton, (3,1), span=(1,1)) - if not self.alwaysAutoPlace: - sizer.Add(self.autoPlaceButton, (3,2), span=(1,1)) - sizer.AddGrowableCol(0) - sizer.AddGrowableRow(1) - - self.addButton.Bind(wx.EVT_BUTTON, self.OnAddModel) - self.remButton.Bind(wx.EVT_BUTTON, self.OnRemModel) - self.sliceButton.Bind(wx.EVT_BUTTON, self.OnSlice) - if not self.alwaysAutoPlace: - self.autoPlaceButton.Bind(wx.EVT_BUTTON, self.OnAutoPlace) - self.listbox.Bind(wx.EVT_LISTBOX, self.OnListSelect) - - panel = wx.Panel(self.panel, -1) - sizer.Add(panel, (5,1), span=(1,2)) - - sizer = wx.GridBagSizer(2,2) - panel.SetSizer(sizer) - - group = [] - self.rotateToolButton = openglGui.glRadioButton(self.glCanvas, 8, 'Rotate', (0,-1), group, self.OnToolSelect) - self.scaleToolButton = openglGui.glRadioButton(self.glCanvas, 9, 'Scale', (1,-1), group, self.OnToolSelect) - self.mirrorToolButton = openglGui.glRadioButton(self.glCanvas, 10, 'Mirror', (2,-1), group, self.OnToolSelect) - - self.resetRotationButton = openglGui.glButton(self.glCanvas, 12, 'Reset', (0,-2), self.OnRotateReset) - self.layFlatButton = openglGui.glButton(self.glCanvas, 16, 'Lay flat', (0,-3), self.OnLayFlat) - - self.resetScaleButton = openglGui.glButton(self.glCanvas, 13, 'Reset', (1,-2), self.OnScaleReset) - - self.mirrorXButton = openglGui.glButton(self.glCanvas, 14, 'Mirror X', (2,-2), lambda : self.OnMirror(0)) - self.mirrorYButton = openglGui.glButton(self.glCanvas, 18, 'Mirror Y', (2,-3), lambda : self.OnMirror(1)) - self.mirrorZButton = openglGui.glButton(self.glCanvas, 22, 'Mirror Z', (2,-4), lambda : self.OnMirror(2)) - - self.scaleForm = openglGui.glFrame(self.glCanvas, (2, -2)) - openglGui.glGuiLayoutGrid(self.scaleForm) - openglGui.glLabel(self.scaleForm, 'Scale X', (0,0)) - self.scaleXctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,0), lambda value: self.OnScaleEntry(value, 0)) - openglGui.glLabel(self.scaleForm, 'Scale Y', (0,1)) - self.scaleYctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,1), lambda value: self.OnScaleEntry(value, 1)) - openglGui.glLabel(self.scaleForm, 'Scale Z', (0,2)) - self.scaleZctrl = openglGui.glNumberCtrl(self.scaleForm, '1.0', (1,2), lambda value: self.OnScaleEntry(value, 2)) - openglGui.glLabel(self.scaleForm, 'Size X (mm)', (0,4)) - self.scaleXmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,4), lambda value: self.OnScaleEntryMM(value, 0)) - openglGui.glLabel(self.scaleForm, 'Size Y (mm)', (0,5)) - self.scaleYmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,5), lambda value: self.OnScaleEntryMM(value, 1)) - openglGui.glLabel(self.scaleForm, 'Size Z (mm)', (0,6)) - self.scaleZmmctrl = openglGui.glNumberCtrl(self.scaleForm, '0.0', (1,6), lambda value: self.OnScaleEntryMM(value, 2)) - openglGui.glLabel(self.scaleForm, 'Uniform scale', (0,8)) - self.scaleUniform = openglGui.glCheckbox(self.scaleForm, True, (1,8), None) - - self.SetSize((800,600)) - - self.OnToolSelect() - - def OnToolSelect(self): - if self.rotateToolButton.getSelected(): - self.tool = previewTools.toolRotate(self.glCanvas) - elif self.scaleToolButton.getSelected(): - self.tool = previewTools.toolScale(self.glCanvas) - elif self.mirrorToolButton.getSelected(): - self.tool = previewTools.toolNone(self.glCanvas) - else: - self.tool = previewTools.toolNone(self.glCanvas) - self.resetRotationButton.setHidden(not self.rotateToolButton.getSelected()) - self.layFlatButton.setHidden(not self.rotateToolButton.getSelected()) - self.resetScaleButton.setHidden(not self.scaleToolButton.getSelected()) - self.scaleForm.setHidden(not self.scaleToolButton.getSelected()) - self.mirrorXButton.setHidden(not self.mirrorToolButton.getSelected()) - self.mirrorYButton.setHidden(not self.mirrorToolButton.getSelected()) - self.mirrorZButton.setHidden(not self.mirrorToolButton.getSelected()) - self.glCanvas.Refresh() - - def OnRotateReset(self): - if self.selection is None: - return - x = numpy.linalg.norm(self.selection.matrix[::,0].getA().flatten()) - y = numpy.linalg.norm(self.selection.matrix[::,1].getA().flatten()) - z = numpy.linalg.norm(self.selection.matrix[::,2].getA().flatten()) - self.selection.matrix = numpy.matrix([[x,0,0],[0,y,0],[0,0,z]], numpy.float64) - self.selection.updateMatrix() - - def OnLayFlat(self): - if self.selection is None: - return - transformedVertexes = (numpy.matrix(self.selection.mesh.vertexes, copy = False) * self.selection.matrix).getA() - minZvertex = transformedVertexes[transformedVertexes.argmin(0)[2]] - dotMin = 1.0 - dotV = None - for v in transformedVertexes: - diff = v - minZvertex - len = math.sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2]) - if len < 5: - continue - dot = (diff[2] / len) - if dotMin > dot: - dotMin = dot - dotV = diff - if dotV is None: - return - rad = -math.atan2(dotV[1], dotV[0]) - self.selection.matrix *= numpy.matrix([[math.cos(rad), math.sin(rad), 0], [-math.sin(rad), math.cos(rad), 0], [0,0,1]], numpy.float64) - rad = -math.asin(dotMin) - self.selection.matrix *= numpy.matrix([[math.cos(rad), 0, math.sin(rad)], [0,1,0], [-math.sin(rad), 0, math.cos(rad)]], numpy.float64) - - - transformedVertexes = (numpy.matrix(self.selection.mesh.vertexes, copy = False) * self.selection.matrix).getA() - minZvertex = transformedVertexes[transformedVertexes.argmin(0)[2]] - dotMin = 1.0 - dotV = None - for v in transformedVertexes: - diff = v - minZvertex - len = math.sqrt(diff[1] * diff[1] + diff[2] * diff[2]) - if len < 5: - continue - dot = (diff[2] / len) - if dotMin > dot: - dotMin = dot - dotV = diff - if dotV is None: - return - if dotV[1] < 0: - rad = math.asin(dotMin) - else: - rad = -math.asin(dotMin) - self.selection.matrix *= numpy.matrix([[1,0,0], [0, math.cos(rad), math.sin(rad)], [0, -math.sin(rad), math.cos(rad)]], numpy.float64) - - self.selection.updateMatrix() - - def OnScaleReset(self): - if self.selection is None: - return - x = 1/numpy.linalg.norm(self.selection.matrix[::,0].getA().flatten()) - y = 1/numpy.linalg.norm(self.selection.matrix[::,1].getA().flatten()) - z = 1/numpy.linalg.norm(self.selection.matrix[::,2].getA().flatten()) - self.selection.matrix *= numpy.matrix([[x,0,0],[0,y,0],[0,0,z]], numpy.float64) - self.selection.updateMatrix() - - def OnMirror(self, axis): - if self.selection is None: - return - matrix = [[1,0,0], [0, 1, 0], [0, 0, 1]] - matrix[axis][axis] = -1 - self.selection.matrix *= numpy.matrix(matrix, numpy.float64) - - def OnScaleEntry(self, value, axis): - if self.selection is None: - return - try: - value = float(value) - except: - return - scale = numpy.linalg.norm(self.selection.matrix[::,axis].getA().flatten()) - scale = value / scale - if scale == 0: - return - if self.scaleUniform.getValue(): - matrix = [[scale,0,0], [0, scale, 0], [0, 0, scale]] - else: - matrix = [[1.0,0,0], [0, 1.0, 0], [0, 0, 1.0]] - matrix[axis][axis] = scale - self.selection.matrix *= numpy.matrix(matrix, numpy.float64) - self.selection.updateMatrix() - - def OnScaleEntryMM(self, value, axis): - try: - value = float(value) - except: - return - scale = self.selection.getSize()[axis] - scale = value / scale - if scale == 0: - return - if self.scaleUniform.getValue(): - matrix = [[scale,0,0], [0, scale, 0], [0, 0, scale]] - else: - matrix = [[1,0,0], [0, 1, 0], [0, 0, 1]] - matrix[axis][axis] = scale - self.selection.matrix *= numpy.matrix(matrix, numpy.float64) - self.selection.updateMatrix() - - def OnClose(self, e): - self.Destroy() - - def OnQuit(self, e): - self.Close() - - def OnPreferences(self, e): - prefDialog = preferencesDialog(self) - prefDialog.Centre() - prefDialog.Show(True) - - def OnCutMesh(self, e): - dlg=wx.FileDialog(self, "Open file to cut", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST) - dlg.SetWildcard(meshLoader.wildcardFilter()) - if dlg.ShowModal() == wx.ID_OK: - filename = dlg.GetPath() - model = meshLoader.loadMesh(filename) - pd = wx.ProgressDialog('Splitting model.', 'Splitting model into multiple parts.', model.vertexCount, self, wx.PD_ELAPSED_TIME | wx.PD_REMAINING_TIME | wx.PD_SMOOTH) - parts = model.splitToParts(pd.Update) - for part in parts: - partFilename = filename[:filename.rfind('.')] + "_part%d.stl" % (parts.index(part)) - stl.saveAsSTL(part, partFilename) - item = ProjectObject(self, partFilename) - self.list.append(item) - self.selection = item - self._updateListbox() - self.OnListSelect(None) - pd.Destroy() - self.glCanvas.Refresh() - dlg.Destroy() - - def OnDropFiles(self, filenames): - for filename in filenames: - item = ProjectObject(self, filename) - profile.putPreference('lastFile', item.filename) - self.list.append(item) - self.selection = item - self._updateListbox() - self.OnListSelect(None) - self.glCanvas.Refresh() - - def OnPrintTypeChange(self): - self.printMode = 0 - if self.printAllAtOnce.GetValue(): - self.printMode = 1 - if self.alwaysAutoPlace: - self.OnAutoPlace(None) - self.glCanvas.Refresh() - - def OnSaveCombinedSTL(self, e): - dlg=wx.FileDialog(self, "Save as STL", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE) - dlg.SetWildcard("STL files (*.stl)|*.stl;*.STL") - if dlg.ShowModal() == wx.ID_OK: - self._saveCombinedSTL(dlg.GetPath()) - dlg.Destroy() - - def _saveCombinedSTL(self, filename): - totalCount = 0 - for item in self.list: - totalCount += item.mesh.vertexCount - output = mesh.mesh() - output._prepareVertexCount(totalCount) - for item in self.list: - vMin = item.getMinimum() - vMax = item.getMaximum() - offset = - vMin - (vMax - vMin) / 2 - offset += numpy.array([item.centerX, item.centerY, (vMax[2] - vMin[2]) / 2]) - vertexes = (item.mesh.vertexes * item.matrix).getA() + offset - for v in vertexes: - output.addVertex(v[0], v[1], v[2]) - stl.saveAsSTL(output, filename) - - def OnSaveProject(self, e): - dlg=wx.FileDialog(self, "Save project file", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE) - dlg.SetWildcard("Project files (*.curaproject)|*.curaproject") - if dlg.ShowModal() == wx.ID_OK: - cp = ConfigParser.ConfigParser() - i = 0 - for item in self.list: - section = 'model_%d' % (i) - cp.add_section(section) - cp.set(section, 'filename', item.filename.encode("utf-8")) - cp.set(section, 'centerX', str(item.centerX)) - cp.set(section, 'centerY', str(item.centerY)) - cp.set(section, 'matrix', ','.join(map(str, item.matrix.getA().flatten()))) - if item.profile != None: - cp.set(section, 'profile', item.profile) - i += 1 - cp.write(open(dlg.GetPath(), "w")) - dlg.Destroy() - - def OnLoadProject(self, e): - dlg=wx.FileDialog(self, "Open project file", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST) - dlg.SetWildcard("Project files (*.curaproject)|*.curaproject") - if dlg.ShowModal() == wx.ID_OK: - cp = ConfigParser.ConfigParser() - cp.read(dlg.GetPath()) - self.list = [] - i = 0 - while cp.has_section('model_%d' % (i)): - section = 'model_%d' % (i) - - item = ProjectObject(self, unicode(cp.get(section, 'filename'), "utf-8")) - item.centerX = float(cp.get(section, 'centerX')) - item.centerY = float(cp.get(section, 'centerY')) - item.matrix = numpy.matrix(numpy.array(map(float, cp.get(section, 'matrix').split(',')), numpy.float64).reshape((3,3,))) - if cp.has_option(section, 'extruder'): - item.extuder = int(cp.get(section, 'extruder')) - 1 - if cp.has_option(section, 'profile'): - item.profile = cp.get(section, 'profile') - item.updateMatrix() - i += 1 - - self.list.append(item) - - self.selected = self.list[0] - self._updateListbox() - self.OnListSelect(None) - self.glCanvas.Refresh() - - dlg.Destroy() - - def On3DClick(self): - self.glCanvas.yaw = 30 - self.glCanvas.pitch = 60 - self.glCanvas.zoom = 300 - self.glCanvas.view3D = True - self.glCanvas.Refresh() - - def OnTopClick(self): - self.glCanvas.view3D = False - self.glCanvas.zoom = self.machineSize[0] / 2 + 10 - self.glCanvas.offsetX = 0 - self.glCanvas.offsetY = 0 - self.glCanvas.Refresh() - - def OnListSelect(self, e): - if self.listbox.GetSelection() == -1: - return - self.selection = self.list[self.listbox.GetSelection()] - self.glCanvas.Refresh() - - def OnAddModel(self, e): - dlg=wx.FileDialog(self, "Open file to print", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST|wx.FD_MULTIPLE) - dlg.SetWildcard(meshLoader.wildcardFilter()) - if dlg.ShowModal() == wx.ID_OK: - for filename in dlg.GetPaths(): - item = ProjectObject(self, filename) - profile.putPreference('lastFile', item.filename) - self.list.append(item) - self.selection = item - self._updateListbox() - self.OnListSelect(None) - self.glCanvas.Refresh() - dlg.Destroy() - - def OnRemModel(self, e): - if self.selection is None: - return - self.list.remove(self.selection) - self._updateListbox() - self.glCanvas.Refresh() - - def OnMoveUp(self, e): - if self.selection is None: - return - i = self.listbox.GetSelection() - if i == 0: - return - self.list.remove(self.selection) - self.list.insert(i-1, self.selection) - self._updateListbox() - self.glCanvas.Refresh() - - def OnMoveDown(self, e): - if self.selection is None: - return - i = self.listbox.GetSelection() - if i == len(self.list) - 1: - return - self.list.remove(self.selection) - self.list.insert(i+1, self.selection) - self._updateListbox() - self.glCanvas.Refresh() - - def OnCopy(self, e): - if self.selection is None: - return - - item = self.selection.clone() - self.list.insert(self.list.index(self.selection), item) - self.selection = item - - self._updateListbox() - self.glCanvas.Refresh() - - def OnSetCustomProfile(self, e): - if self.selection is None: - return - - dlg=wx.FileDialog(self, "Select profile", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST) - dlg.SetWildcard("Profile files (*.ini)|*.ini;*.INI") - if dlg.ShowModal() == wx.ID_OK: - self.selection.profile = dlg.GetPath() - else: - self.selection.profile = None - self._updateListbox() - dlg.Destroy() - - def _updateListbox(self): - self.listbox.Clear() - for item in self.list: - if item.profile is not None: - self.listbox.AppendAndEnsureVisible(os.path.split(item.filename)[1] + " *") - else: - self.listbox.AppendAndEnsureVisible(os.path.split(item.filename)[1]) - if self.selection in self.list: - self.listbox.SetSelection(self.list.index(self.selection)) - elif len(self.list) > 0: - self.selection = self.list[0] - self.listbox.SetSelection(0) - else: - self.selection = None - self.listbox.SetSelection(-1) - if self.alwaysAutoPlace: - self.OnAutoPlace(None) - - def OnAutoPlace(self, e): - bestAllowedSize = int(self.machineSize[1]) - bestArea = self._doAutoPlace(bestAllowedSize) - for i in xrange(10, int(self.machineSize[1]), 10): - area = self._doAutoPlace(i) - if area < bestArea: - bestAllowedSize = i - bestArea = area - self._doAutoPlace(bestAllowedSize) - if not self.alwaysAutoPlace: - for item in self.list: - item.clampXY() - self.glCanvas.Refresh() - - def _doAutoPlace(self, allowedSizeY): - extraSizeMin, extraSizeMax = self.getExtraHeadSize() - - if extraSizeMin[0] > extraSizeMax[0]: - posX = self.machineSize[0] - dirX = -1 - else: - posX = 0 - dirX = 1 - posY = 0 - dirY = 1 - - minX = self.machineSize[0] - minY = self.machineSize[1] - maxX = 0 - maxY = 0 - for item in self.list: - item.centerX = posX + item.getSize()[0] / 2 * dirX - item.centerY = posY + item.getSize()[1] / 2 * dirY - if item.centerY + item.getSize()[1] >= allowedSizeY: - if dirX < 0: - posX = minX - extraSizeMax[0] - 1 - else: - posX = maxX + extraSizeMin[0] + 1 - posY = 0 - item.centerX = posX + item.getSize()[0] / 2 * dirX - item.centerY = posY + item.getSize()[1] / 2 * dirY - posY += item.getSize()[1] * dirY + extraSizeMin[1] + 1 - minX = min(minX, item.centerX - item.getSize()[0] / 2) - minY = min(minY, item.centerY - item.getSize()[1] / 2) - maxX = max(maxX, item.centerX + item.getSize()[0] / 2) - maxY = max(maxY, item.centerY + item.getSize()[1] / 2) - - for item in self.list: - if dirX < 0: - item.centerX -= minX / 2 - else: - item.centerX += (self.machineSize[0] - maxX) / 2 - item.centerY += (self.machineSize[1] - maxY) / 2 - - if minX < 0 or maxX > self.machineSize[0]: - return ((maxX - minX) + (maxY - minY)) * 100 - - return (maxX - minX) + (maxY - minY) - - def OnSlice(self, e): - dlg=wx.FileDialog(self, "Save project gcode file", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE) - dlg.SetWildcard("GCode file (*.gcode)|*.gcode") - if dlg.ShowModal() != wx.ID_OK: - dlg.Destroy() - return - resultFilename = dlg.GetPath() - dlg.Destroy() - - put = profile.setTempOverride - oldProfile = profile.getGlobalProfileString() - - if self.printMode == 0: - fileList = [] - positionList = [] - for item in self.list: - fileList.append(item.filename) - if profile.getPreference('machine_center_is_zero') == 'True': - pos = [item.centerX - self.machineSize[0] / 2, item.centerY - self.machineSize[1] / 2] - else: - pos = [item.centerX, item.centerY] - positionList.append(pos + item.matrix.getA().flatten().tolist()) - print positionList - sliceCommand = sliceRun.getSliceCommand(resultFilename, fileList, positionList) - else: - self._saveCombinedSTL(resultFilename + "_temp_.stl") - sliceCommand = sliceRun.getSliceCommand(resultFilename, [resultFilename + "_temp_.stl"], [profile.getMachineCenterCoords()]) - - pspw = ProjectSliceProgressWindow(sliceCommand, resultFilename, len(self.list)) - pspw.Centre() - pspw.Show(True) - - def getExtraHeadSize(self): - extraSizeMin = self.headSizeMin - extraSizeMax = self.headSizeMax - if profile.getProfileSettingFloat('skirt_line_count') > 0: - skirtSize = profile.getProfileSettingFloat('skirt_line_count') * profile.calculateEdgeWidth() + profile.getProfileSettingFloat('skirt_gap') - extraSizeMin = extraSizeMin + numpy.array([skirtSize, skirtSize, 0]) - extraSizeMax = extraSizeMax + numpy.array([skirtSize, skirtSize, 0]) - if profile.getProfileSetting('enable_raft') != 'False': - raftSize = profile.getProfileSettingFloat('raft_margin') * 2 - extraSizeMin = extraSizeMin + numpy.array([raftSize, raftSize, 0]) - extraSizeMax = extraSizeMax + numpy.array([raftSize, raftSize, 0]) - if profile.getProfileSetting('support') != 'None': - extraSizeMin = extraSizeMin + numpy.array([3.0, 0, 0]) - extraSizeMax = extraSizeMax + numpy.array([3.0, 0, 0]) - - if self.printMode == 1: - extraSizeMin = numpy.array([6.0, 6.0, 0]) - extraSizeMax = numpy.array([6.0, 6.0, 0]) - - return extraSizeMin, extraSizeMax - -class PreviewGLCanvas(openglGui.glGuiPanel): - def __init__(self, parent, projectPlannerWindow): - super(PreviewGLCanvas, self).__init__(parent) - self.parent = projectPlannerWindow - wx.EVT_MOUSEWHEEL(self, self.OnMouseWheel) - self.yaw = 30 - self.pitch = 60 - self.offsetX = 0 - self.offsetY = 0 - self.view3D = self.parent.alwaysAutoPlace - if self.view3D: - self.zoom = 300 - else: - self.zoom = self.parent.machineSize[0] / 2 + 10 - self.dragType = '' - self.viewport = None - self.allowDrag = False - self.tempMatrix = None - - self.objColor = profile.getPreferenceColour('model_colour') - - def OnMouseLeftDown(self,e): - self.allowDrag = True - if not self.parent.alwaysAutoPlace and not self.view3D: - p0 = opengl.unproject(e.GetX(), self.viewport[1] + self.viewport[3] - e.GetY(), 0, self.modelMatrix, self.projMatrix, self.viewport) - p1 = opengl.unproject(e.GetX(), self.viewport[1] + self.viewport[3] - e.GetY(), 1, self.modelMatrix, self.projMatrix, self.viewport) - p0 -= self.viewTarget - p1 -= self.viewTarget - p0 -= self.getObjectCenterPos() - self.viewTarget - p1 -= self.getObjectCenterPos() - self.viewTarget - cursorZ0 = p0 - (p1 - p0) * (p0[2] / (p1[2] - p0[2])) - - for item in self.parent.list: - iMin =-item.getSize() / 2 + numpy.array([item.centerX, item.centerY, 0]) - iMax = item.getSize() / 2 + numpy.array([item.centerX, item.centerY, 0]) - if iMin[0] <= cursorZ0[0] <= iMax[0] and iMin[1] <= cursorZ0[1] <= iMax[1]: - self.parent.selection = item - self.parent._updateListbox() - self.parent.OnListSelect(None) - - def OnMouseMotion(self,e): - if self.viewport is not None: - p0 = opengl.unproject(e.GetX(), self.viewport[1] + self.viewport[3] - e.GetY(), 0, self.modelMatrix, self.projMatrix, self.viewport) - p1 = opengl.unproject(e.GetX(), self.viewport[1] + self.viewport[3] - e.GetY(), 1, self.modelMatrix, self.projMatrix, self.viewport) - p0 -= self.viewTarget - p1 -= self.viewTarget - p0 -= self.getObjectCenterPos() - self.viewTarget - p1 -= self.getObjectCenterPos() - self.viewTarget - if not e.Dragging() or self.dragType != 'tool': - self.parent.tool.OnMouseMove(p0, p1) - else: - p0 = [0,0,0] - p1 = [1,0,0] - - if self.allowDrag and e.Dragging() and e.LeftIsDown(): - if self.dragType == '': - #Define the drag type depending on the cursor position. - self.dragType = 'viewRotate' - if self.parent.tool.OnDragStart(p0, p1): - self.dragType = 'tool' - if self.dragType == 'viewRotate': - 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 - elif not self.parent.alwaysAutoPlace: - item = self.parent.selection - if item is not None: - item.centerX += float(e.GetX() - self.oldX) * self.zoom / self.GetSize().GetHeight() * 2 - item.centerY -= float(e.GetY() - self.oldY) * self.zoom / self.GetSize().GetHeight() * 2 - item.clampXY() - elif self.dragType == 'tool': - self.parent.tool.OnDrag(p0, p1) - else: - if self.dragType != '': - if self.tempMatrix is not None: - self.parent.selection.matrix *= self.tempMatrix - self.parent.selection.updateMatrix() - self.tempMatrix = None - self.parent.tool.OnDragEnd() - self.dragType = '' - 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): - 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) - self.viewTarget = self.parent.machineSize / 2 - self.viewTarget[2] = 0 - glTranslate(-self.viewTarget[0], -self.viewTarget[1], -self.viewTarget[2]) - - self.viewport = glGetIntegerv(GL_VIEWPORT) - self.modelMatrix = glGetDoublev(GL_MODELVIEW_MATRIX) - self.projMatrix = glGetDoublev(GL_PROJECTION_MATRIX) - - self.OnDraw() - - def OnDraw(self): - machineSize = self.parent.machineSize - extraSizeMin, extraSizeMax = self.parent.getExtraHeadSize() - - for item in self.parent.list: - item.validPlacement = True - item.gotHit = False - - for idx1 in xrange(0, len(self.parent.list)): - item = self.parent.list[idx1] - iMin1 =-item.getSize() / 2 + numpy.array([item.centerX, item.centerY, 0]) - extraSizeMin #- self.parent.extruderOffset[item.extruder] - iMax1 = item.getSize() / 2 + numpy.array([item.centerX, item.centerY, 0]) + extraSizeMax #- self.parent.extruderOffset[item.extruder] - if iMin1[0] < -self.parent.headSizeMin[0] or iMin1[1] < -self.parent.headSizeMin[1]: - item.validPlacement = False - if iMax1[0] > machineSize[0] + self.parent.headSizeMax[0] or iMax1[1] > machineSize[1] + self.parent.headSizeMax[1]: - item.validPlacement = False - for idx2 in xrange(0, idx1): - item2 = self.parent.list[idx2] - iMin2 =-item2.getSize() / 2 + numpy.array([item2.centerX, item2.centerY, 0]) - iMax2 = item2.getSize() / 2 + numpy.array([item2.centerX, item2.centerY, 0]) - if item != item2 and iMax1[0] >= iMin2[0] and iMin1[0] <= iMax2[0] and iMax1[1] >= iMin2[1] and iMin1[1] <= iMax2[1]: - item.validPlacement = False - item2.gotHit = True - - seenSelected = False - for item in self.parent.list: - if item == self.parent.selection: - seenSelected = True - if item.modelDisplayList is None: - item.modelDisplayList = glGenLists(1); - if item.modelDirty: - item.modelDirty = False - glNewList(item.modelDisplayList, GL_COMPILE) - opengl.DrawMesh(item.mesh) - glEndList() - - if item.validPlacement: - if self.parent.selection == item: - glLightfv(GL_LIGHT0, GL_DIFFUSE, map(lambda x: x + 0.2, self.objColor)) - glLightfv(GL_LIGHT0, GL_AMBIENT, map(lambda x: x / 2, self.objColor)) - else: - glLightfv(GL_LIGHT0, GL_DIFFUSE, self.objColor) - glLightfv(GL_LIGHT0, GL_AMBIENT, map(lambda x: x / 2, self.objColor)) - else: - if self.parent.selection == item: - glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 0.0, 0.0, 0.0]) - glLightfv(GL_LIGHT0, GL_AMBIENT, [0.2, 0.0, 0.0, 0.0]) - else: - glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 0.0, 0.0, 0.0]) - glLightfv(GL_LIGHT0, GL_AMBIENT, [0.2, 0.0, 0.0, 0.0]) - glPushMatrix() - - glEnable(GL_LIGHTING) - glTranslate(item.centerX, item.centerY, 0) - vMin = item.getMinimum() - vMax = item.getMaximum() - offset = - vMin - (vMax - vMin) / 2 - matrix = opengl.convert3x3MatrixTo4x4(item.matrix) - glPushMatrix() - glTranslate(0, 0, item.getSize()[2]/2) - if self.tempMatrix is not None and item == self.parent.selection: - tempMatrix = opengl.convert3x3MatrixTo4x4(self.tempMatrix) - glMultMatrixf(tempMatrix) - glTranslate(0, 0, -item.getSize()[2]/2) - glTranslate(offset[0], offset[1], -vMin[2]) - glMultMatrixf(matrix) - glCallList(item.modelDisplayList) - glPopMatrix() - - vMin =-item.getSize() / 2 - vMax = item.getSize() / 2 - vMax[2] -= vMin[2] - vMin[2] = 0 - vMinHead = vMin - extraSizeMin# - self.parent.extruderOffset[item.extruder] - vMaxHead = vMax + extraSizeMax# - self.parent.extruderOffset[item.extruder] - - glDisable(GL_LIGHTING) - - if not self.parent.alwaysAutoPlace: - glLineWidth(1) - if self.parent.selection == item: - if item.gotHit: - glColor3f(1.0,0.0,0.3) - else: - glColor3f(1.0,0.0,1.0) - opengl.DrawBox(vMin, vMax) - if item.gotHit: - glColor3f(1.0,0.3,0.0) - else: - glColor3f(1.0,1.0,0.0) - opengl.DrawBox(vMinHead, vMaxHead) - elif seenSelected: - if item.gotHit: - glColor3f(0.5,0.0,0.1) - else: - glColor3f(0.5,0.0,0.5) - opengl.DrawBox(vMinHead, vMaxHead) - else: - if item.gotHit: - glColor3f(0.7,0.1,0.0) - else: - glColor3f(0.7,0.7,0.0) - opengl.DrawBox(vMin, vMax) - - glPopMatrix() - - opengl.DrawMachine(util3d.Vector3(machineSize[0], machineSize[1], machineSize[2])) - - if self.parent.selection is not None: - glPushMatrix() - glTranslate(self.parent.selection.centerX, self.parent.selection.centerY, self.parent.selection.getSize()[2]/2) - self.parent.tool.OnDraw() - glPopMatrix() - - def getObjectSize(self): - if self.parent.selection is not None: - return self.parent.selection.getSize() - return [0.0,0.0,0.0] - def getObjectBoundaryCircle(self): - if self.parent.selection is not None: - return self.parent.selection.getBoundaryCircle() - return 0.0 - def getObjectMatrix(self): - return self.parent.selection.matrix - def getObjectCenterPos(self): - if self.parent.selection is None: - return [0,0,0] - return [self.parent.selection.centerX, self.parent.selection.centerY, self.getObjectSize()[2] / 2] - -class ProjectSliceProgressWindow(wx.Frame): - def __init__(self, sliceCommand, resultFilename, fileCount): - super(ProjectSliceProgressWindow, self).__init__(None, title='Cura') - self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE)) - - self.sliceCommand = sliceCommand - self.resultFilename = resultFilename - self.fileCount = fileCount - self.abort = False - self.prevStep = 'start' - self.totalDoneFactor = 0.0 - self.startTime = time.time() - self.sliceStartTime = time.time() - - self.sizer = wx.GridBagSizer(2, 2) - self.statusText = wx.StaticText(self, -1, "Building: %s" % (resultFilename)) - self.progressGauge = wx.Gauge(self, -1) - self.progressGauge.SetRange(10000) - self.progressGauge2 = wx.Gauge(self, -1) - self.progressGauge2.SetRange(self.fileCount) - self.progressGauge2.SetValue(-1) - self.abortButton = wx.Button(self, -1, "Abort") - self.sizer.Add(self.statusText, (0,0), span=(1,5)) - self.sizer.Add(self.progressGauge, (1, 0), span=(1,5), flag=wx.EXPAND) - self.sizer.Add(self.progressGauge2, (2, 0), span=(1,5), flag=wx.EXPAND) - - self.sizer.Add(self.abortButton, (3,0), span=(1,5), flag=wx.ALIGN_CENTER) - self.sizer.AddGrowableCol(0) - self.sizer.AddGrowableRow(0) - - self.Bind(wx.EVT_BUTTON, self.OnAbort, self.abortButton) - self.SetSizer(self.sizer) - self.Layout() - self.Fit() - - threading.Thread(target=self.OnRun).start() - - def OnAbort(self, e): - if self.abort: - self.Close() - else: - self.abort = True - self.abortButton.SetLabel('Close') - - def SetProgress(self, stepName, layer, maxLayer): - if self.prevStep != stepName: - if stepName == 'slice': - self.progressGauge2.SetValue(self.progressGauge2.GetValue() + 1) - self.totalDoneFactor = 0 - self.totalDoneFactor += sliceRun.sliceStepTimeFactor[self.prevStep] - newTime = time.time() - #print "#####" + str(newTime-self.startTime) + " " + self.prevStep + " -> " + stepName - self.startTime = newTime - self.prevStep = stepName - - progresValue = ((self.totalDoneFactor + sliceRun.sliceStepTimeFactor[stepName] * layer / maxLayer) / sliceRun.totalRunTimeFactor) * 10000 - self.progressGauge.SetValue(int(progresValue)) - self.statusText.SetLabel(stepName + " [" + str(layer) + "/" + str(maxLayer) + "]") - taskbar.setProgress(self, 10000 * self.progressGauge2.GetValue() + int(progresValue), 10000 * self.fileCount) - - def OnRun(self): - self.progressLog = [] - p = sliceRun.startSliceCommandProcess(self.sliceCommand) - line = p.stdout.readline() - while(len(line) > 0): - line = line.rstrip() - if line[0:9] == "Progress[" and line[-1:] == "]": - progress = line[9:-1].split(":") - if len(progress) > 2: - maxValue = int(progress[2]) - wx.CallAfter(self.SetProgress, progress[0], int(progress[1]), maxValue) - else: - self.progressLog.append(line) - wx.CallAfter(self.statusText.SetLabel, line) - if self.abort: - p.terminate() - wx.CallAfter(self.statusText.SetLabel, "Aborted by user.") - return - line = p.stdout.readline() - line = p.stderr.readline() - while len(line) > 0: - line = line.rstrip() - self.progressLog.append(line) - line = p.stderr.readline() - self.returnCode = p.wait() - self.progressGauge2.SetValue(self.fileCount) - - gcode = gcodeInterpreter.gcode() - gcode.load(self.resultFilename) - - self.abort = True - sliceTime = time.time() - self.sliceStartTime - status = "Build: %s" % (self.resultFilename) - status += "\nSlicing took: %02d:%02d" % (sliceTime / 60, sliceTime % 60) - status += "\nFilament: %.2fm %.2fg" % (gcode.extrusionAmount / 1000, gcode.calculateWeight() * 1000) - status += "\nPrint time: %02d:%02d" % (int(gcode.totalMoveTimeMinute / 60), int(gcode.totalMoveTimeMinute % 60)) - cost = gcode.calculateCost() - if cost is not None: - status += "\nCost: %s" % (cost) - profile.replaceGCodeTags(self.resultFilename, gcode) - wx.CallAfter(self.statusText.SetLabel, status) - wx.CallAfter(self.OnSliceDone) - - def _adjustNumberInLine(self, line, tag, f): - m = re.search('^(.*'+tag+')([0-9\.]*)(.*)$', line) - return m.group(1) + str(float(m.group(2)) + f) + m.group(3) + '\n' - - def OnSliceDone(self): - self.abortButton.Destroy() - self.closeButton = wx.Button(self, -1, "Close") - self.printButton = wx.Button(self, -1, "Print") - self.logButton = wx.Button(self, -1, "Show log") - self.sizer.Add(self.closeButton, (3,0), span=(1,1)) - self.sizer.Add(self.printButton, (3,1), span=(1,1)) - self.sizer.Add(self.logButton, (3,2), span=(1,1)) - if explorer.hasExplorer(): - self.openFileLocationButton = wx.Button(self, -1, "Open file location") - self.Bind(wx.EVT_BUTTON, self.OnOpenFileLocation, self.openFileLocationButton) - self.sizer.Add(self.openFileLocationButton, (3,3), span=(1,1)) - if profile.getPreference('sdpath') != '': - self.copyToSDButton = wx.Button(self, -1, "To SDCard") - self.Bind(wx.EVT_BUTTON, self.OnCopyToSD, self.copyToSDButton) - self.sizer.Add(self.copyToSDButton, (3,4), span=(1,1)) - self.Bind(wx.EVT_BUTTON, self.OnAbort, self.closeButton) - self.Bind(wx.EVT_BUTTON, self.OnPrint, self.printButton) - self.Bind(wx.EVT_BUTTON, self.OnShowLog, self.logButton) - self.Layout() - self.Fit() - taskbar.setBusy(self, False) - - def OnCopyToSD(self, e): - filename = os.path.basename(self.resultFilename) - if profile.getPreference('sdshortnames') == 'True': - filename = sliceRun.getShortFilename(filename) - shutil.copy(self.resultFilename, os.path.join(profile.getPreference('sdpath'), filename)) - - def OnOpenFileLocation(self, e): - explorer.openExplorer(self.resultFilename) - - def OnPrint(self, e): - printWindow.printFile(self.resultFilename) - - def OnShowLog(self, e): - LogWindow('\n'.join(self.progressLog)) - -class preferencesDialog(wx.Frame): - def __init__(self, parent): - super(preferencesDialog, self).__init__(None, title="Project Planner Preferences", style=wx.DEFAULT_DIALOG_STYLE) - - self.parent = parent - wx.EVT_CLOSE(self, self.OnClose) - - self.panel = configBase.configPanelBase(self) - extruderAmount = int(profile.getPreference('extruder_amount')) - - left, right, main = self.panel.CreateConfigPanel(self) - configBase.TitleRow(left, 'User interface settings') - c = configBase.SettingRow(left, 'Always auto place objects in planner', 'planner_always_autoplace', True, 'Disable this to allow manual placement in the project planner (requires restart).', type = 'preference') - configBase.TitleRow(left, 'Machine head size') - c = configBase.SettingRow(left, 'Head size - X towards home (mm)', 'extruder_head_size_min_x', '0', 'Size of your printer head in the X direction, on the Ultimaker your fan is in this direction.', type = 'preference') - validators.validFloat(c, 0.1) - c = configBase.SettingRow(left, 'Head size - X towards end (mm)', 'extruder_head_size_max_x', '0', 'Size of your printer head in the X direction.', type = 'preference') - validators.validFloat(c, 0.1) - c = configBase.SettingRow(left, 'Head size - Y towards home (mm)', 'extruder_head_size_min_y', '0', 'Size of your printer head in the Y direction.', type = 'preference') - validators.validFloat(c, 0.1) - c = configBase.SettingRow(left, 'Head size - Y towards end (mm)', 'extruder_head_size_max_y', '0', 'Size of your printer head in the Y direction.', type = 'preference') - validators.validFloat(c, 0.1) - c = configBase.SettingRow(left, 'Head gantry height (mm)', 'extruder_head_size_height', '0', 'The tallest object height that will always fit under your printers gantry system when the printer head is at the lowest Z position.', type = 'preference') - validators.validFloat(c) - - self.okButton = wx.Button(left, -1, 'Ok') - left.GetSizer().Add(self.okButton, (left.GetSizer().GetRows(), 1)) - self.okButton.Bind(wx.EVT_BUTTON, self.OnClose) - - self.MakeModal(True) - main.Fit() - self.Fit() - - def OnClose(self, e): - self.parent.headSizeMin = numpy.array([profile.getPreferenceFloat('extruder_head_size_min_x'), profile.getPreferenceFloat('extruder_head_size_min_y'),0]) - self.parent.headSizeMax = numpy.array([profile.getPreferenceFloat('extruder_head_size_max_x'), profile.getPreferenceFloat('extruder_head_size_max_y'),0]) - self.parent.Refresh() - - self.MakeModal(False) - self.Destroy() - -class LogWindow(wx.Frame): - def __init__(self, logText): - super(LogWindow, self).__init__(None, title="Slice log") - self.textBox = wx.TextCtrl(self, -1, logText, style=wx.TE_MULTILINE|wx.TE_DONTWRAP|wx.TE_READONLY) - self.SetSize((400,300)) - self.Centre() - self.Show(True) diff --git a/Cura/gui/sliceProgressPanel.py b/Cura/gui/sliceProgressPanel.py deleted file mode 100644 index c53371fe..00000000 --- a/Cura/gui/sliceProgressPanel.py +++ /dev/null @@ -1,209 +0,0 @@ -from __future__ import absolute_import - -import wx -import os -import shutil -import threading -import time -import re -import platform - -from Cura.gui import preferencesDialog -from Cura.gui.util import taskbar -from Cura.util import profile -from Cura.util import sliceRun -from Cura.util import explorer -from Cura.util import gcodeInterpreter - -class sliceProgressPanel(wx.Panel): - def __init__(self, mainWindow, parent, filelist): - wx.Panel.__init__(self, parent, -1) - self.mainWindow = mainWindow - self.filelist = filelist - self.abort = False - - box = wx.StaticBox(self, -1, filelist[0]) - self.sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL) - - mainSizer = wx.BoxSizer(wx.VERTICAL) - mainSizer.Add(self.sizer, 0, flag=wx.EXPAND) - - self.statusText = wx.StaticText(self, -1, "Starting...") - self.progressGauge = wx.Gauge(self, -1) - self.progressGauge.SetRange(10000 * len(filelist)) - self.abortButton = wx.Button(self, -1, "X", style=wx.BU_EXACTFIT) - self.sizer.Add(self.statusText, 2, flag=wx.ALIGN_CENTER ) - self.sizer.Add(self.progressGauge, 2) - self.sizer.Add(self.abortButton, 0) - - self.Bind(wx.EVT_BUTTON, self.OnAbort, self.abortButton) - - self.SetSizer(mainSizer) - self.prevStep = 'start' - self.totalDoneFactor = 0.0 - self.startTime = time.time() - if profile.getPreference('save_profile') == 'True': - profile.saveProfile(self.filelist[0][: self.filelist[0].rfind('.')] + "_profile.ini") - center = profile.getMachineCenterCoords() + profile.getObjectMatrix() - cmdList = [sliceRun.getSliceCommand(sliceRun.getExportFilename(self.filelist[0]), ['|'.join(self.filelist)], [center])] - self.thread = WorkerThread(self, filelist, cmdList) - - def OnAbort(self, e): - if self.abort: - self.mainWindow.removeSliceProgress(self) - else: - self.abort = True - - def OnShowGCode(self, e): - self.mainWindow.preview3d.loadModelFiles(self.filelist) - self.mainWindow.preview3d.setViewMode("GCode") - - def OnShowLog(self, e): - LogWindow('\n'.join(self.progressLog)) - - def OnOpenFileLocation(self, e): - explorer.openExplorer(sliceRun.getExportFilename(self.filelist[0])) - - def OnCopyToSD(self, e): - if profile.getPreference('sdpath') == '': - wx.MessageBox("You need to configure your SD card drive first before you can copy files to it.\nOpening the preferences now.", 'No SD card drive.', wx.OK | wx.ICON_INFORMATION) - prefDialog = preferencesDialog.preferencesDialog(self.GetParent()) - prefDialog.Centre() - prefDialog.Show(True) - if profile.getPreference('sdpath') == '': - print "No path set" - return - exportFilename = sliceRun.getExportFilename(self.filelist[0]) - filename = os.path.basename(exportFilename) - if profile.getPreference('sdshortnames') == 'True': - filename = sliceRun.getShortFilename(filename) - try: - shutil.copy(exportFilename, os.path.join(profile.getPreference('sdpath'), filename)) - except: - self.GetParent().preview3d.ShowWarningPopup("Failed to copy file to SD card, card out of space or locked?") - return - self.GetParent().preview3d.ShowWarningPopup("Copy finished, safely remove SD card?", self.OnSafeRemove) - - def OnSafeRemove(self): - if platform.system() == "Windows": - cmd = '"%s" %s>NUL' % (os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'EjectMedia.exe')), profile.getPreference('sdpath')) - elif platform.system() == "Darwin": - cmd = "diskutil eject '%s' > /dev/null 2>&1" % (profile.getPreference('sdpath')) - else: - cmd = "umount '%s' > /dev/null 2>&1" % (profile.getPreference('sdpath')) - if os.system(cmd): - self.GetParent().preview3d.ShowWarningPopup("Safe remove failed.") - else: - self.GetParent().preview3d.ShowWarningPopup("You can now eject the card.") - - def OnSliceDone(self, result): - self.progressGauge.Destroy() - self.abortButton.Destroy() - self.progressLog = result.progressLog - self.logButton = wx.Button(self, -1, "Show Log") - self.abortButton = wx.Button(self, -1, "X", style=wx.BU_EXACTFIT) - self.Bind(wx.EVT_BUTTON, self.OnShowLog, self.logButton) - self.Bind(wx.EVT_BUTTON, self.OnAbort, self.abortButton) - self.sizer.Add(self.logButton, 0) - if result.returnCode == 0: - status = "Ready: Filament: %.2fm %.2fg" % (result.gcode.extrusionAmount / 1000, result.gcode.calculateWeight() * 1000) - status += " Print time: %02d:%02d" % (int(result.gcode.totalMoveTimeMinute / 60), int(result.gcode.totalMoveTimeMinute % 60)) - cost = result.gcode.calculateCost() - if cost is not None: - status += " Cost: %s" % (cost) - self.statusText.SetLabel(status) - if explorer.hasExplorer(): - self.openFileLocationButton = wx.Button(self, -1, "Open file location") - self.Bind(wx.EVT_BUTTON, self.OnOpenFileLocation, self.openFileLocationButton) - self.sizer.Add(self.openFileLocationButton, 0) - if len(profile.getSDcardDrives()) > 0: - self.copyToSDButton = wx.Button(self, -1, "Copy to SDCard") - self.Bind(wx.EVT_BUTTON, self.OnCopyToSD, self.copyToSDButton) - self.sizer.Add(self.copyToSDButton, 0) - self.showButton = wx.Button(self, -1, "Show result") - self.Bind(wx.EVT_BUTTON, self.OnShowGCode, self.showButton) - self.sizer.Add(self.showButton, 0) - else: - self.statusText.SetLabel("Something went wrong during slicing!") - self.sizer.Add(self.abortButton, 0) - self.sizer.Layout() - self.Layout() - self.abort = True - if self.mainWindow.preview3d.reloadModelFiles(self.filelist): - self.mainWindow.preview3d.setViewMode("GCode") - self.thread = None - del result.gcode - taskbar.setBusy(self.GetParent(), False) - - def SetProgress(self, stepName, layer, maxLayer): - if self.prevStep != stepName: - self.totalDoneFactor += sliceRun.sliceStepTimeFactor[self.prevStep] - newTime = time.time() - #print "#####" + str(newTime-self.startTime) + " " + self.prevStep + " -> " + stepName - self.startTime = newTime - self.prevStep = stepName - - progresValue = ((self.totalDoneFactor + sliceRun.sliceStepTimeFactor[stepName] * layer / maxLayer) / sliceRun.totalRunTimeFactor) * 10000 - self.progressGauge.SetValue(int(progresValue)) - taskbar.setProgress(self.GetParent(), int(progresValue), self.progressGauge.GetRange()) - self.statusText.SetLabel("Preparing: processing %s [%d/%d]" % (stepName, layer, maxLayer)) - -class WorkerThread(threading.Thread): - def __init__(self, notifyWindow, filelist, cmdList): - threading.Thread.__init__(self) - self.filelist = filelist - self.notifyWindow = notifyWindow - self.cmdList = cmdList - self.fileIdx = 0 - self.start() - - def run(self): - p = sliceRun.startSliceCommandProcess(self.cmdList[self.fileIdx]) - line = p.stdout.readline() - self.progressLog = [] - maxValue = 1 - starttime = time.time() - while len(line) > 0: - line = line.rstrip() - if line[0:9] == "Progress[" and line[-1:] == "]": - progress = line[9:-1].split(":") - if len(progress) > 2: - maxValue = int(progress[2]) - wx.CallAfter(self.notifyWindow.SetProgress, progress[0], int(progress[1]), maxValue) - else: - self.progressLog.append("%0.2f: %s" % (time.time() - starttime, line)) - wx.CallAfter(self.notifyWindow.statusText.SetLabel, line) - if self.notifyWindow.abort: - p.terminate() - wx.CallAfter(self.notifyWindow.mainWindow.removeSliceProgress, self.notifyWindow) - return - line = p.stdout.readline() - line = p.stderr.readline() - while len(line) > 0: - line = line.rstrip() - self.progressLog.append(line) - line = p.stderr.readline() - self.returnCode = p.wait() - self.fileIdx += 1 - if self.fileIdx == len(self.cmdList): - gcodeFilename = sliceRun.getExportFilename(self.filelist[0]) - gcodefile = open(gcodeFilename, "a") - for logLine in self.progressLog: - if logLine.startswith('Model error('): - gcodefile.write(';%s\n' % (logLine)) - gcodefile.close() - self.gcode = gcodeInterpreter.gcode() - self.gcode.load(gcodeFilename) - profile.replaceGCodeTags(gcodeFilename, self.gcode) - wx.CallAfter(self.notifyWindow.OnSliceDone, self) - else: - self.run() - -class LogWindow(wx.Frame): - def __init__(self, logText): - super(LogWindow, self).__init__(None, title="Slice log") - self.textBox = wx.TextCtrl(self, -1, logText, style=wx.TE_MULTILINE|wx.TE_DONTWRAP|wx.TE_READONLY) - self.SetSize((400,300)) - self.Centre() - self.Show(True) - diff --git a/Cura/gui/tools/superformula.py b/Cura/gui/tools/superformula.py index 9517fccb..3d53b4ae 100644 --- a/Cura/gui/tools/superformula.py +++ b/Cura/gui/tools/superformula.py @@ -361,6 +361,7 @@ class superformulaWindow(wx.Frame): m.vertexCount = self._shape._obj._meshList[0].vertexCount obj._postProcessAfterLoad() self.GetParent().scene._scene.add(obj) + self.GetParent().scene.sceneUpdated() def _updateShape(self): if self._shape is not None: