halfHeight = 0.5 * self.layerHeight
self.zoneArrangement = ZoneArrangement(self.layerHeight, self.getTransformedVertexes())
layerTop = self.cornerMaximum.z - halfHeight * 0.5
- z = self.cornerMinimum.z + halfHeight
+ z = halfHeight
layerCount = int((layerTop - z) / self.layerHeight) + 1
while z < layerTop:
getLoopLayerAppend(self.loopLayers, layerCount, z).loops = self.getLoopsFromMesh(self.zoneArrangement.getEmptyZ(z))
'SwapYZ': storedSetting("swap_yz"),
'Scale': storedSettingFloat("model_scale"),
'Rotate': storedSettingFloat("model_rotate_base"),
+ 'CenterX': storedSettingFloat("machine_center_x"),
+ 'CenterY': storedSettingFloat("machine_center_y"),
+ 'AlternativeCenterFile': storedSetting("alternative_center"),
},'scale': {
'Activate_Scale': "False",
'XY_Plane_Scale_ratio': DEFSET,
'Surrounding_Angle_degrees': DEFSET,
'Thread_Sequence_Choice': storedSetting('sequence'),
},'multiply': {
- 'Activate_Multiply': "True",
+ 'Activate_Multiply': "False",
'Center_X_mm': storedSettingFloat("machine_center_x"),
'Center_Y_mm': storedSettingFloat("machine_center_y"),
'Number_of_Columns_integer': storedSetting('model_multiply_x'),
self.flipZ = settings.BooleanSetting().getFromValue('FlipZ', self, False)
self.swapXZ = settings.BooleanSetting().getFromValue('SwapXZ', self, False)
self.swapYZ = settings.BooleanSetting().getFromValue('SwapYZ', self, False)
+ self.centerX = settings.FloatSpin().getFromValue(0.0, 'CenterX', self, 1000.0, 0.0)
+ self.centerY = settings.FloatSpin().getFromValue(0.0, 'CenterY', self, 1000.0, 0.0)
self.scale = settings.FloatSpin().getFromValue( 0.1, 'Scale', self, 10.0, 1.0 )
self.rotate = settings.FloatSpin().getFromValue( -180.0, 'Rotate', self, 180.0, 0.0 )
+ self.alternativeCenter = settings.StringSetting().getFromValue('AlternativeCenterFile', self, '')
def execute(self):
mat10 = math.sin(rotate) * scaleX
mat11 = math.cos(rotate) * scaleY
- minZ = carving.getMinimumZ()
- minSize = carving.getCarveCornerMinimum()
- maxSize = carving.getCarveCornerMaximum()
- for v in carving.vertexes:
- v.z -= minZ
- v.x -= minSize.x + (maxSize.x - minSize.x) / 2
- v.y -= minSize.y + (maxSize.y - minSize.y) / 2
- #v.x += self.machineCenter.x
- #v.y += self.machineCenter.y
-
for i in xrange(0, len(carving.vertexes)):
x = carving.vertexes[i].x
y = carving.vertexes[i].y
x * mat10 + y * mat11,
z * scaleZ)
+ if repository.alternativeCenter.value != '':
+ carving2 = svg_writer.getCarving(repository.alternativeCenter.value)
+ for i in xrange(0, len(carving2.vertexes)):
+ x = carving2.vertexes[i].x
+ y = carving2.vertexes[i].y
+ z = carving2.vertexes[i].z
+ if swapXZ:
+ x, z = z, x
+ if swapYZ:
+ y, z = z, y
+ carving2.vertexes[i] = Vector3(
+ x * mat00 + y * mat01,
+ x * mat10 + y * mat11,
+ z * scaleZ)
+ minZ = carving2.getMinimumZ()
+ minSize = carving2.getCarveCornerMinimum()
+ maxSize = carving2.getCarveCornerMaximum()
+ else:
+ minZ = carving.getMinimumZ()
+ minSize = carving.getCarveCornerMinimum()
+ maxSize = carving.getCarveCornerMaximum()
+ for v in carving.vertexes:
+ v.z -= minZ
+ v.x -= minSize.x + (maxSize.x - minSize.x) / 2
+ v.y -= minSize.y + (maxSize.y - minSize.y) / 2
+ v.x += repository.centerX.value
+ v.y += repository.centerY.value
+
layerHeight = repository.layerHeight.value
edgeWidth = repository.edgeWidth.value
carving.setCarveLayerHeight(layerHeight)
def addCoolTemperature(self, remainingOrbitTime):
'Parse a gcode line and add it to the cool skein.'
+ if self.repository.minimumLayerTime.value < 0.0001:
+ return
layerCool = self.repository.maximumCool.value * remainingOrbitTime / self.repository.minimumLayerTime.value
if self.isBridgeLayer:
layerCool = max(self.repository.bridgeCool.value, layerCool)
def setMultiplier(self, remainingOrbitTime):
'Set the feed and flow rate multiplier.'
layerTimeActive = self.getLayerTimeActive()
- self.multiplier = min(1.0, layerTimeActive / (remainingOrbitTime + layerTimeActive))
-
-
+ if remainingOrbitTime + layerTimeActive > 0.00001:
+ self.multiplier = min(1.0, layerTimeActive / (remainingOrbitTime + layerTimeActive))
+ else:
+ self.multiplier = 1.0
def main():
'Display the cool dialog.'
def addSkirt(self, z):
'At skirt at z to gcode output.'
+ if len(self.outsetLoops) < 1 or len(self.outsetLoops[0]) < 1:
+ return
self.setSkirtFeedFlowTemperature()
self.distanceFeedRate.addLine('(<skirt>)')
oldTemperature = self.oldTemperatureInput
import wx\r
import sys,math,threading,os\r
\r
+from gui import gcodeTextArea\r
from util import profile\r
\r
class alterationPanel(wx.Panel):\r
self.alterationFileList = ['start.gcode', 'end.gcode', 'support_start.gcode', 'support_end.gcode', 'nextobject.gcode', 'replace.csv']\r
self.currentFile = None\r
\r
- self.textArea = wx.TextCtrl(self, style=wx.TE_MULTILINE|wx.TE_DONTWRAP|wx.TE_PROCESS_TAB)\r
- self.textArea.SetFont(wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))\r
+ #self.textArea = wx.TextCtrl(self, style=wx.TE_MULTILINE|wx.TE_DONTWRAP|wx.TE_PROCESS_TAB)\r
+ #self.textArea.SetFont(wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))\r
+ self.textArea = gcodeTextArea.GcodeTextArea(self)\r
self.list = wx.ListBox(self, choices=self.alterationFileList, style=wx.LB_SINGLE)\r
self.list.SetSelection(0)\r
self.Bind(wx.EVT_LISTBOX, self.OnSelect, self.list)\r
--- /dev/null
+import wx, wx.stc
+import sys,math,os
+
+from util import profile
+
+class GcodeTextArea(wx.stc.StyledTextCtrl):
+ def __init__(self, parent):
+ super(GcodeTextArea, self).__init__(parent)
+
+ self.SetLexer(wx.stc.STC_LEX_CONTAINER)
+ self.Bind(wx.stc.EVT_STC_STYLENEEDED, self.OnStyle)
+
+ fontSize = wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize()
+ fontName = wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL).GetFaceName()
+ self.SetStyleBits(5)
+ self.StyleSetSpec(0, "face:%s,size:%d" % (fontName, fontSize))
+ self.StyleSetSpec(1, "fore:#006000,face:%s,size:%d" % (fontName, fontSize))
+ self.IndicatorSetStyle(0, wx.stc.STC_INDIC_TT)
+ self.IndicatorSetForeground(0, "#0000FF")
+ self.IndicatorSetStyle(1, wx.stc.STC_INDIC_SQUIGGLE)
+ self.IndicatorSetForeground(1, "#FF0000")
+ self.SetWrapMode(wx.stc.STC_WRAP_NONE)
+ self.SetScrollWidth(1000)
+
+ #GCodes and MCodes as supported by Marlin
+ #GCode 21 is not really supported by Marlin, but we still do not report it as error as it's often used.
+ self.supportedGCodes = [0,1,2,3,4,21,28,90,91,92]
+ self.supportedMCodes = [17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,42,80,81,82,83,84,85,92,104,105,106,107,109,114,115,117,119,140,190,201,202,203,204,205,206,220,221,240,301,302,303,400,500,501,502,503,999]
+
+ def OnStyle(self, e):
+ lineNr = self.LineFromPosition(self.GetEndStyled())
+ while self.PositionFromLine(lineNr) > -1:
+ line = self.GetLine(lineNr)
+ start = self.PositionFromLine(lineNr)
+ length = self.LineLength(lineNr)
+ self.StartStyling(start, 255)
+ self.SetStyling(length, 0)
+ if ';' in line:
+ pos = line.index(';')
+ self.StartStyling(start + pos, 31)
+ self.SetStyling(length - pos, 1)
+ length = pos
+
+ pos = 0
+ while pos < length:
+ if line[pos] in " \t\n\r":
+ while pos < length and line[pos] in " \t\n\r":
+ pos += 1
+ else:
+ end = pos
+ while end < length and not line[end] in " \t\n\r":
+ end += 1
+ if self.checkGCodePart(line[pos:end], start + pos):
+ self.StartStyling(start + pos, 0x20)
+ self.SetStyling(end - pos, 0x20)
+ pos = end
+ lineNr += 1
+
+ def checkGCodePart(self, part, pos):
+ if len(part) < 2:
+ self.StartStyling(pos, 0x40)
+ self.SetStyling(1, 0x40)
+ return True
+ if not part[0] in "GMXYZFESTBPIDCJ":
+ self.StartStyling(pos, 0x40)
+ self.SetStyling(1, 0x40)
+ return True
+ if part[1] == '{':
+ if part[-1] != '}':
+ return True
+ tag = part[2:-1]
+ if not profile.isProfileSetting(tag) and not profile.isPreference(tag):
+ self.StartStyling(pos + 2, 0x40)
+ self.SetStyling(len(tag), 0x40)
+ return True
+ elif part[0] in "GM":
+ try:
+ code = int(part[1:])
+ except (ValueError):
+ self.StartStyling(pos + 1, 0x40)
+ self.SetStyling(len(part) - 1, 0x40)
+ return True
+ if part[0] == 'G':
+ if not code in self.supportedGCodes:
+ return True
+ if part[0] == 'M':
+ if not code in self.supportedMCodes:
+ return True
+ else:
+ try:
+ float(part[1:])
+ except (ValueError):
+ self.StartStyling(pos + 1, 0x40)
+ self.SetStyling(len(part) - 1, 0x40)
+ return True
+ return False
+
+ def GetValue(self):
+ return self.GetText()
+
+ def SetValue(self, s):
+ self.SetText(s)
+
if profile.getPreference('lastFile') != '':
self.filelist = profile.getPreference('lastFile').split(';')
+ self.SetTitle(self.filelist[-1] + ' - Cura - ' + version.getVersion())
else:
self.filelist = []
self.progressPanelList = []
filelist.append(self._showOpenDialog("Open file to print"))
if filelist[-1] == False:
return
+ self.SetTitle(filelist[-1] + ' - Cura - ' + version.getVersion())
self.filelist = filelist
profile.putPreference('lastFile', ';'.join(self.filelist))
self.preview3d.loadModelFiles(self.filelist)
glViewport(0,0, size.GetWidth(), size.GetHeight())\r
\r
glLightfv(GL_LIGHT0, GL_POSITION, [1.0, 1.0, 1.0, 0.0])\r
+ glLightfv(GL_LIGHT1, GL_POSITION, [1.0, 1.0, 1.0, 0.0])\r
\r
+ glEnable(GL_NORMALIZE)\r
glEnable(GL_LIGHTING)\r
glEnable(GL_LIGHT0)\r
glEnable(GL_DEPTH_TEST)\r
glEnd()\r
\r
def DrawSTL(mesh):\r
+ glEnable(GL_CULL_FACE)\r
for face in mesh.faces:\r
glBegin(GL_TRIANGLES)\r
v1 = face.v[0]\r
from gui import configBase\r
from gui import validators\r
from gui import machineCom\r
+from util import profile\r
\r
class preferencesDialog(configBase.configWindowBase):\r
def __init__(self, parent):\r
\r
wx.EVT_CLOSE(self, self.OnClose)\r
\r
+ self.oldExtruderAmount = int(profile.getPreference('extruder_amount'))\r
+ \r
left, right, main = self.CreateConfigPanel(self)\r
configBase.TitleRow(left, 'Machine settings')\r
c = configBase.SettingRow(left, 'Steps per E', 'steps_per_e', '0', 'Amount of steps per mm filament extrusion', type = 'preference')\r
c = configBase.SettingRow(left, 'Machine height (mm)', 'machine_height', '200', 'Size of the machine in mm', type = 'preference')\r
validators.validFloat(c, 10.0)\r
c = configBase.SettingRow(left, 'Extruder count', 'extruder_amount', ['1', '2', '3', '4'], 'Amount of extruders in your machine.', type = 'preference')\r
+ \r
+ for i in xrange(1, self.oldExtruderAmount):\r
+ configBase.TitleRow(left, 'Extruder %d' % (i+1))\r
+ c = configBase.SettingRow(left, 'Offset X', 'extruder_offset_x%d' % (i), '0.0', 'The offset of your secondary extruder compared to the primary.', type = 'preference')\r
+ validators.validFloat(c)\r
+ c = configBase.SettingRow(left, 'Offset Y', 'extruder_offset_y%d' % (i), '0.0', 'The offset of your secondary extruder compared to the primary.', type = 'preference')\r
+ validators.validFloat(c)\r
\r
configBase.TitleRow(left, 'Filament settings')\r
c = configBase.SettingRow(left, 'Filament density (kg/m3)', 'filament_density', '1300', 'Weight of the filament per m3. Around 1300 for PLA. And around 1040 for ABS. This value is used to estimate the weight if the filament used for the print.', type = 'preference')\r
#c = configBase.SettingRow(left, 'Slicer selection', 'slicer', ['Cura (Skeinforge based)', 'Slic3r'], 'Which slicer to use to slice objects. Usually the Cura engine produces the best results. But Slic3r is developing fast and is faster with slicing.', type = 'preference')\r
c = configBase.SettingRow(left, 'Save profile on slice', 'save_profile', False, 'When slicing save the profile as [stl_file]_profile.ini next to the model.', type = 'preference')\r
\r
+ self.okButton = wx.Button(left, -1, 'Ok')\r
+ left.GetSizer().Add(self.okButton, (left.GetSizer().GetRows(), 1))\r
+ self.okButton.Bind(wx.EVT_BUTTON, self.OnClose)\r
+ \r
self.MakeModal(True)\r
main.Fit()\r
self.Fit()\r
\r
def OnClose(self, e):\r
+ if self.oldExtruderAmount != int(profile.getPreference('extruder_amount')):\r
+ wx.MessageBox('After changing the amount of extruders you need to restart Cura for full effect.', 'Extruder amount warning.', wx.OK | wx.ICON_INFORMATION)\r
self.MakeModal(False)\r
self.Destroy()\r
from __future__ import division\r
\r
-import sys\r
-import math\r
-import threading\r
-import re\r
-import time\r
-import os\r
+import sys, math, threading, re, time, os\r
\r
from wx import glcanvas\r
import wx\r
\r
self.glCanvas = PreviewGLCanvas(self)\r
self.objectList = []\r
+ self.errorList = []\r
self.gcode = None\r
self.objectsMinV = None\r
self.objectsMaxV = None\r
self.loadThread = None\r
- self.machineSize = util3d.Vector3(float(profile.getPreference('machine_width')), float(profile.getPreference('machine_depth')), float(profile.getPreference('machine_height')))\r
+ self.machineSize = util3d.Vector3(profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height'))\r
self.machineCenter = util3d.Vector3(float(profile.getProfileSetting('machine_center_x')), float(profile.getProfileSetting('machine_center_y')), 0)\r
\r
self.toolbar = toolbarUtil.Toolbar(self)\r
self.xrayViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-xray-on.png', 'view-xray-off.png', 'X-Ray view', callback=self.OnViewChange)\r
self.gcodeViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-gcode-on.png', 'view-gcode-off.png', 'GCode view', callback=self.OnViewChange)\r
self.mixedViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-mixed-on.png', 'view-mixed-off.png', 'Mixed model/GCode view', callback=self.OnViewChange)\r
- self.OnViewChange()\r
self.toolbar.AddSeparator()\r
\r
self.layerSpin = wx.SpinCtrl(self.toolbar, -1, '', size=(21*4,21), style=wx.SP_ARROW_KEYS)\r
self.toolbar2.AddSeparator()\r
\r
# Multiply\r
- self.mulXadd = toolbarUtil.NormalButton(self.toolbar2, self.OnMulXAddClick, 'object-mul-x-add.png', 'Increase number of models on X axis')\r
- self.mulXsub = toolbarUtil.NormalButton(self.toolbar2, self.OnMulXSubClick, 'object-mul-x-sub.png', 'Decrease number of models on X axis')\r
- self.mulYadd = toolbarUtil.NormalButton(self.toolbar2, self.OnMulYAddClick, 'object-mul-y-add.png', 'Increase number of models on Y axis')\r
- self.mulYsub = toolbarUtil.NormalButton(self.toolbar2, self.OnMulYSubClick, 'object-mul-y-sub.png', 'Decrease number of models on Y axis')\r
-\r
- self.toolbar2.AddSeparator()\r
+ #self.mulXadd = toolbarUtil.NormalButton(self.toolbar2, self.OnMulXAddClick, 'object-mul-x-add.png', 'Increase number of models on X axis')\r
+ #self.mulXsub = toolbarUtil.NormalButton(self.toolbar2, self.OnMulXSubClick, 'object-mul-x-sub.png', 'Decrease number of models on X axis')\r
+ #self.mulYadd = toolbarUtil.NormalButton(self.toolbar2, self.OnMulYAddClick, 'object-mul-y-add.png', 'Increase number of models on Y axis')\r
+ #self.mulYsub = toolbarUtil.NormalButton(self.toolbar2, self.OnMulYSubClick, 'object-mul-y-sub.png', 'Decrease number of models on Y axis')\r
+ #self.toolbar2.AddSeparator()\r
\r
# Rotate\r
self.rotateReset = toolbarUtil.NormalButton(self.toolbar2, self.OnRotateReset, 'object-rotate.png', 'Reset model rotation')\r
self.rotate = wx.SpinCtrl(self.toolbar2, -1, profile.getProfileSetting('model_rotate_base'), size=(21*3,21), style=wx.SP_WRAP|wx.SP_ARROW_KEYS)\r
self.rotate.SetRange(0, 360)\r
- self.Bind(wx.EVT_TEXT, self.OnRotate)\r
+ self.rotate.Bind(wx.EVT_TEXT, self.OnRotate)\r
self.toolbar2.AddControl(self.rotate)\r
\r
self.toolbar2.Realize()\r
- self.updateToolbar()\r
+ self.OnViewChange()\r
\r
sizer = wx.BoxSizer(wx.VERTICAL)\r
sizer.Add(self.toolbar, 0, flag=wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, border=1)\r
self.glCanvas.Refresh()\r
\r
def OnLayerNrChange(self, e):\r
- self.gcodeDirty = True\r
self.glCanvas.Refresh()\r
\r
def updateCenterX(self):\r
def loadModelFiles(self, filelist):\r
while len(filelist) > len(self.objectList):\r
self.objectList.append(previewObject())\r
- for idx in xrange(len(self.objectList), len(filelist)):\r
+ for idx in xrange(len(filelist), len(self.objectList)):\r
self.objectList[idx].mesh = None\r
+ self.objectList[idx].filename = None\r
for idx in xrange(0, len(filelist)):\r
obj = self.objectList[idx]\r
if obj.filename != filelist[idx]:\r
\r
def doFileLoadThread(self):\r
for obj in self.objectList:\r
- if os.path.isfile(obj.filename) and obj.fileTime != os.stat(obj.filename).st_mtime:\r
+ if obj.filename != None and os.path.isfile(obj.filename) and obj.fileTime != os.stat(obj.filename).st_mtime:\r
obj.ileTime = os.stat(obj.filename).st_mtime\r
mesh = stl.stlModel()\r
mesh.load(obj.filename)\r
obj.dirty = False\r
- obj.errorList = []\r
obj.mesh = mesh\r
self.updateModelTransform()\r
wx.CallAfter(self.updateToolbar)\r
pass\r
\r
def updateToolbar(self):\r
- self.layerSpin.Show(self.gcode != None)\r
+ self.gcodeViewButton.Show(self.gcode != None)\r
+ self.mixedViewButton.Show(self.gcode != None)\r
+ self.layerSpin.Show(self.glCanvas.viewMode == "GCode" or self.glCanvas.viewMode == "Mixed")\r
if self.gcode != None:\r
- self.layerSpin.SetRange(1, len(self.gcode.layerList))\r
+ self.layerSpin.SetRange(1, len(self.gcode.layerList) - 1)\r
self.toolbar.Realize()\r
\r
def OnViewChange(self):\r
self.glCanvas.viewMode = "GCode"\r
elif self.mixedViewButton.GetValue():\r
self.glCanvas.viewMode = "Mixed"\r
+ self.updateToolbar()\r
self.glCanvas.Refresh()\r
\r
def updateModelTransform(self, f=0):\r
self.offsetY = 0\r
self.view3D = True\r
self.gcodeDisplayList = None\r
+ self.gcodeDisplayListCount = 0\r
self.objColor = [[1.0, 0.8, 0.6, 1.0], [0.2, 1.0, 0.1, 1.0], [1.0, 0.2, 0.1, 1.0], [0.1, 0.2, 1.0, 1.0]]\r
\r
def OnMouseMotion(self,e):\r
glTranslate(0,0,-self.zoom)\r
glRotate(-self.pitch, 1,0,0)\r
glRotate(self.yaw, 0,0,1)\r
- if self.parent.objectsMaxV != None:\r
- glTranslate(0,0,-self.parent.objectsMaxV.z * profile.getProfileSettingFloat('model_scale') / 2)\r
+ if self.viewMode == "GCode" or self.viewMode == "Mixed":\r
+ if self.parent.gcode != None:\r
+ glTranslate(0,0,-self.parent.gcode.layerList[self.parent.layerSpin.GetValue()][0].list[-1].z)\r
+ else:\r
+ if self.parent.objectsMaxV != None:\r
+ glTranslate(0,0,-self.parent.objectsMaxV.z * profile.getProfileSettingFloat('model_scale') / 2)\r
else:\r
glScale(1.0/self.zoom, 1.0/self.zoom, 1.0)\r
glTranslate(self.offsetX, self.offsetY, 0.0)\r
machineSize = self.parent.machineSize\r
opengl.DrawMachine(machineSize)\r
\r
- if self.parent.gcode != None:\r
- if self.gcodeDisplayList == None:\r
- self.gcodeDisplayList = glGenLists(1);\r
- if self.parent.gcodeDirty:\r
- self.parent.gcodeDirty = False\r
- glNewList(self.gcodeDisplayList, GL_COMPILE)\r
- prevLayerZ = 0.0\r
- curLayerZ = 0.0\r
- \r
- layerThickness = 0.0\r
- filamentRadius = float(profile.getProfileSetting('filament_diameter')) / 2\r
- filamentArea = math.pi * filamentRadius * filamentRadius\r
- lineWidth = float(profile.getProfileSetting('nozzle_size')) / 2 / 10\r
- \r
- curLayerNum = 0\r
- for layer in self.parent.gcode.layerList:\r
- curLayerZ = layer[0].list[1].z\r
- layerThickness = curLayerZ - prevLayerZ\r
- prevLayerZ = layer[-1].list[-1].z\r
- for path in layer:\r
- c = 1.0\r
- if curLayerNum != self.parent.layerSpin.GetValue():\r
- if curLayerNum < self.parent.layerSpin.GetValue():\r
- c = 0.9 - (self.parent.layerSpin.GetValue() - curLayerNum) * 0.1\r
- if c < 0.4:\r
- c = 0.4\r
- else:\r
- break\r
- if path.type == 'move':\r
- glColor3f(0,0,c)\r
- if path.type == 'extrude':\r
- if path.pathType == 'FILL':\r
- glColor3f(c/2,c/2,0)\r
- elif path.pathType == 'WALL-INNER':\r
- glColor3f(0,c,0)\r
- elif path.pathType == 'SUPPORT':\r
- glColor3f(0,c,c)\r
- elif path.pathType == 'SKIRT':\r
- glColor3f(0,c/2,c/2)\r
- else:\r
- glColor3f(c,0,0)\r
- if path.type == 'retract':\r
- glColor3f(0,c,c)\r
- if c > 0.4 and path.type == 'extrude':\r
- for i in xrange(0, len(path.list)-1):\r
- v0 = path.list[i]\r
- v1 = path.list[i+1]\r
-\r
- # Calculate line width from ePerDistance (needs layer thickness and filament diameter)\r
- dist = (v0 - v1).vsize()\r
- if dist > 0 and layerThickness > 0:\r
- extrusionMMperDist = (v1.e - v0.e) / dist\r
- lineWidth = extrusionMMperDist * filamentArea / layerThickness / 2\r
-\r
- normal = (v0 - v1).cross(util3d.Vector3(0,0,1))\r
- normal.normalize()\r
- v2 = v0 + normal * lineWidth\r
- v3 = v1 + normal * lineWidth\r
- v0 = v0 - normal * lineWidth\r
- v1 = v1 - normal * lineWidth\r
-\r
- glBegin(GL_QUADS)\r
- if path.pathType == 'FILL': #Remove depth buffer fighting on infill/wall overlap\r
- glVertex3f(v0.x, v0.y, v0.z - 0.02)\r
- glVertex3f(v1.x, v1.y, v1.z - 0.02)\r
- glVertex3f(v3.x, v3.y, v3.z - 0.02)\r
- glVertex3f(v2.x, v2.y, v2.z - 0.02)\r
- else:\r
- glVertex3f(v0.x, v0.y, v0.z - 0.01)\r
- glVertex3f(v1.x, v1.y, v1.z - 0.01)\r
- glVertex3f(v3.x, v3.y, v3.z - 0.01)\r
- glVertex3f(v2.x, v2.y, v2.z - 0.01)\r
- glEnd()\r
- \r
- #for v in path['list']:\r
- # glBegin(GL_TRIANGLE_FAN)\r
- # glVertex3f(v.x, v.y, v.z - 0.001)\r
- # for i in xrange(0, 16+1):\r
- # if path['pathType'] == 'FILL': #Remove depth buffer fighting on infill/wall overlap\r
- # glVertex3f(v.x + math.cos(math.pi*2/16*i) * lineWidth, v.y + math.sin(math.pi*2/16*i) * lineWidth, v.z - 0.02)\r
- # else:\r
- # glVertex3f(v.x + math.cos(math.pi*2/16*i) * lineWidth, v.y + math.sin(math.pi*2/16*i) * lineWidth, v.z - 0.01)\r
- # glEnd()\r
+ if self.parent.gcode != None and self.parent.gcodeDirty:\r
+ if self.gcodeDisplayListCount < len(self.parent.gcode.layerList) or self.gcodeDisplayList == None:\r
+ if self.gcodeDisplayList != None:\r
+ glDeleteLists(self.gcodeDisplayList, self.gcodeDisplayListCount)\r
+ self.gcodeDisplayList = glGenLists(len(self.parent.gcode.layerList));\r
+ self.gcodeDisplayListCount = len(self.parent.gcode.layerList)\r
+ self.parent.gcodeDirty = False\r
+ prevLayerZ = 0.0\r
+ curLayerZ = 0.0\r
+ \r
+ layerThickness = 0.0\r
+ filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2\r
+ filamentArea = math.pi * filamentRadius * filamentRadius\r
+ lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10\r
+ \r
+ curLayerNum = 0\r
+ for layer in self.parent.gcode.layerList:\r
+ glNewList(self.gcodeDisplayList + curLayerNum, GL_COMPILE)\r
+ glDisable(GL_CULL_FACE)\r
+ curLayerZ = layer[0].list[1].z\r
+ layerThickness = curLayerZ - prevLayerZ\r
+ prevLayerZ = layer[-1].list[-1].z\r
+ for path in layer:\r
+ if path.type == 'move':\r
+ glColor3f(0,0,1)\r
+ if path.type == 'extrude':\r
+ if path.pathType == 'FILL':\r
+ glColor3f(0.5,0.5,0)\r
+ elif path.pathType == 'WALL-INNER':\r
+ glColor3f(0,1,0)\r
+ elif path.pathType == 'SUPPORT':\r
+ glColor3f(0,1,1)\r
+ elif path.pathType == 'SKIRT':\r
+ glColor3f(0,0.5,0.5)\r
else:\r
- glBegin(GL_LINE_STRIP)\r
- for v in path.list:\r
- glVertex3f(v.x, v.y, v.z)\r
+ glColor3f(1,0,0)\r
+ if path.type == 'retract':\r
+ glColor3f(0,1,1)\r
+ if path.type == 'extrude':\r
+ for i in xrange(0, len(path.list)-1):\r
+ v0 = path.list[i]\r
+ v1 = path.list[i+1]\r
+\r
+ # Calculate line width from ePerDistance (needs layer thickness and filament diameter)\r
+ dist = (v0 - v1).vsize()\r
+ if dist > 0 and layerThickness > 0:\r
+ extrusionMMperDist = (v1.e - v0.e) / dist\r
+ lineWidth = extrusionMMperDist * filamentArea / layerThickness / 2\r
+\r
+ normal = (v0 - v1).cross(util3d.Vector3(0,0,1))\r
+ normal.normalize()\r
+ v2 = v0 + normal * lineWidth\r
+ v3 = v1 + normal * lineWidth\r
+ v0 = v0 - normal * lineWidth\r
+ v1 = v1 - normal * lineWidth\r
+\r
+ glBegin(GL_QUADS)\r
+ if path.pathType == 'FILL': #Remove depth buffer fighting on infill/wall overlap\r
+ glVertex3f(v0.x, v0.y, v0.z - 0.02)\r
+ glVertex3f(v1.x, v1.y, v1.z - 0.02)\r
+ glVertex3f(v3.x, v3.y, v3.z - 0.02)\r
+ glVertex3f(v2.x, v2.y, v2.z - 0.02)\r
+ else:\r
+ glVertex3f(v0.x, v0.y, v0.z - 0.01)\r
+ glVertex3f(v1.x, v1.y, v1.z - 0.01)\r
+ glVertex3f(v3.x, v3.y, v3.z - 0.01)\r
+ glVertex3f(v2.x, v2.y, v2.z - 0.01)\r
glEnd()\r
- curLayerNum += 1\r
+ \r
+ #for v in path['list']:\r
+ # glBegin(GL_TRIANGLE_FAN)\r
+ # glVertex3f(v.x, v.y, v.z - 0.001)\r
+ # for i in xrange(0, 16+1):\r
+ # if path['pathType'] == 'FILL': #Remove depth buffer fighting on infill/wall overlap\r
+ # glVertex3f(v.x + math.cos(math.pi*2/16*i) * lineWidth, v.y + math.sin(math.pi*2/16*i) * lineWidth, v.z - 0.02)\r
+ # else:\r
+ # glVertex3f(v.x + math.cos(math.pi*2/16*i) * lineWidth, v.y + math.sin(math.pi*2/16*i) * lineWidth, v.z - 0.01)\r
+ # glEnd()\r
+ else:\r
+ glBegin(GL_LINE_STRIP)\r
+ for v in path.list:\r
+ glVertex3f(v.x, v.y, v.z)\r
+ glEnd()\r
+ curLayerNum += 1\r
+ glEnable(GL_CULL_FACE)\r
glEndList()\r
- if self.viewMode == "GCode" or self.viewMode == "Mixed":\r
- glCallList(self.gcodeDisplayList)\r
\r
+ if self.parent.gcode != None and (self.viewMode == "GCode" or self.viewMode == "Mixed"):\r
+ glEnable(GL_COLOR_MATERIAL)\r
+ glEnable(GL_LIGHTING)\r
+ for i in xrange(0, self.parent.layerSpin.GetValue() + 1):\r
+ c = 1.0\r
+ if i < self.parent.layerSpin.GetValue():\r
+ c = 0.9 - (self.parent.layerSpin.GetValue() - i) * 0.1\r
+ if c < 0.4:\r
+ c = (0.4 + c) / 2\r
+ if c < 0.1:\r
+ c = 0.1\r
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, [0,0,0,0])\r
+ glLightfv(GL_LIGHT0, GL_AMBIENT, [c,c,c,c])\r
+ glCallList(self.gcodeDisplayList + i)\r
+ glDisable(GL_LIGHTING)\r
+ glDisable(GL_COLOR_MATERIAL)\r
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, [0.2, 0.2, 0.2, 1.0]);\r
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, [0.8, 0.8, 0.8, 1.0]);\r
+\r
+ glColor3f(1.0,1.0,1.0)\r
glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, 0)\r
for obj in self.parent.objectList:\r
if obj.mesh == None:\r
opengl.DrawSTL(obj.mesh)\r
glEndList()\r
\r
- glEnable(GL_NORMALIZE)\r
if self.viewMode == "Transparent" or self.viewMode == "Mixed":\r
glLightfv(GL_LIGHT0, GL_DIFFUSE, map(lambda x: x / 2, self.objColor[self.parent.objectList.index(obj)]))\r
glLightfv(GL_LIGHT0, GL_AMBIENT, map(lambda x: x / 10, self.objColor[self.parent.objectList.index(obj)]))\r
#If we want transparent, then first render a solid black model to remove the printer size lines.\r
if self.viewMode != "Mixed":\r
glDisable(GL_BLEND)\r
- glDisable(GL_LIGHTING)\r
- glColor3f(0,0,0)\r
+ glColor3f(0.0,0.0,0.0)\r
self.drawModel(obj)\r
- glColor3f(1,1,1)\r
+ glColor3f(1.0,1.0,1.0)\r
#After the black model is rendered, render the model again but now with lighting and no depth testing.\r
glDisable(GL_DEPTH_TEST)\r
glEnable(GL_LIGHTING)\r
glEnable(GL_LIGHTING)\r
self.drawModel(obj)\r
\r
- if self.viewMode == "Normal" or self.viewMode == "Transparent" or self.viewMode == "X-Ray":\r
- glDisable(GL_LIGHTING)\r
- glDisable(GL_DEPTH_TEST)\r
- glDisable(GL_BLEND)\r
- glColor3f(1,0,0)\r
- #glBegin(GL_LINES)\r
- #for err in self.parent.errorList:\r
- # glVertex3f(err[0].x, err[0].y, err[0].z)\r
- # glVertex3f(err[1].x, err[1].y, err[1].z)\r
- #glEnd()\r
- glEnable(GL_DEPTH_TEST)\r
+ if self.viewMode == "Normal" or self.viewMode == "Transparent" or self.viewMode == "X-Ray":\r
+ glDisable(GL_LIGHTING)\r
+ glDisable(GL_DEPTH_TEST)\r
+ glDisable(GL_BLEND)\r
+ glColor3f(1,0,0)\r
+ glBegin(GL_LINES)\r
+ for err in self.parent.errorList:\r
+ glVertex3f(err[0].x, err[0].y, err[0].z)\r
+ glVertex3f(err[1].x, err[1].y, err[1].z)\r
+ glEnd()\r
+ glEnable(GL_DEPTH_TEST)\r
glFlush()\r
\r
def drawModel(self, obj):\r
- multiX = int(profile.getProfileSetting('model_multiply_x'))\r
- multiY = int(profile.getProfileSetting('model_multiply_y'))\r
+ multiX = 1 #int(profile.getProfileSetting('model_multiply_x'))\r
+ multiY = 1 #int(profile.getProfileSetting('model_multiply_y'))\r
modelScale = profile.getProfileSettingFloat('model_scale')\r
modelSize = (obj.mesh.getMaximum() - obj.mesh.getMinimum()) * modelScale\r
glPushMatrix()\r
status = ""\r
if self.gcode != None:\r
status += "Filament: %.2fm %.2fg\n" % (self.gcode.extrusionAmount / 1000, self.gcode.calculateWeight() * 1000)\r
- cost_kg = float(profile.getPreference('filament_cost_kg'))\r
- cost_meter = float(profile.getPreference('filament_cost_meter'))\r
- if cost_kg > 0.0 and cost_meter > 0.0:\r
- status += "Filament cost: %.2f / %.2f\n" % (self.gcode.calculateWeight() * cost_kg, self.gcode.extrusionAmount / 1000 * cost_meter)\r
- elif cost_kg > 0.0:\r
- status += "Filament cost: %.2f\n" % (self.gcode.calculateWeight() * cost_kg)\r
- elif cost_meter > 0.0:\r
- status += "Filament cost: %.2f\n" % (self.gcode.extrusionAmount / 1000 * cost_meter)\r
+ cost = self.gcode.calculateCost()\r
+ if cost != False:\r
+ status += "Filament cost: %s\n" % (cost)\r
status += "Print time: %02d:%02d\n" % (int(self.gcode.totalMoveTimeMinute / 60), int(self.gcode.totalMoveTimeMinute % 60))\r
if self.printIdx == None:\r
self.progress.SetValue(0)\r
from util import util3d\r
from util import stl\r
from util import sliceRun\r
+from util import gcodeInterpreter\r
\r
-class Action():\r
+class Action(object):\r
pass\r
\r
+class ProjectObject(stl.stlModel):\r
+ def __init__(self, filename):\r
+ super(ProjectObject, self).__init__()\r
+\r
+ self.load(filename)\r
+\r
+ self.filename = filename\r
+ self.scale = 1.0\r
+ self.rotate = 0.0\r
+ self.flipX = False\r
+ self.flipY = False\r
+ self.flipZ = False\r
+ self.swapXZ = False\r
+ self.swapYZ = False\r
+ self.extruder = 0\r
+ \r
+ self.modelDisplayList = None\r
+ self.modelDirty = False\r
+\r
+ self.origonalVertexes = list(self.vertexes)\r
+ for i in xrange(0, len(self.origonalVertexes)):\r
+ self.origonalVertexes[i] = self.origonalVertexes[i].copy()\r
+ self.getMinimumZ()\r
+ \r
+ self.centerX = -self.getMinimum().x + 5\r
+ self.centerY = -self.getMinimum().y + 5\r
+ \r
+ self.updateModelTransform()\r
+\r
+ self.centerX = -self.getMinimum().x + 5\r
+ self.centerY = -self.getMinimum().y + 5\r
+\r
+ def updateModelTransform(self):\r
+ rotate = self.rotate / 180.0 * math.pi\r
+ scaleX = 1.0\r
+ scaleY = 1.0\r
+ scaleZ = 1.0\r
+ if self.flipX:\r
+ scaleX = -scaleX\r
+ if self.flipY:\r
+ scaleY = -scaleY\r
+ if self.flipZ:\r
+ scaleZ = -scaleZ\r
+ swapXZ = self.swapXZ\r
+ swapYZ = self.swapYZ\r
+ mat00 = math.cos(rotate) * scaleX\r
+ mat01 =-math.sin(rotate) * scaleY\r
+ mat10 = math.sin(rotate) * scaleX\r
+ mat11 = math.cos(rotate) * scaleY\r
+ \r
+ for i in xrange(0, len(self.origonalVertexes)):\r
+ x = self.origonalVertexes[i].x\r
+ y = self.origonalVertexes[i].y\r
+ z = self.origonalVertexes[i].z\r
+ if swapXZ:\r
+ x, z = z, x\r
+ if swapYZ:\r
+ y, z = z, y\r
+ self.vertexes[i].x = x * mat00 + y * mat01\r
+ self.vertexes[i].y = x * mat10 + y * mat11\r
+ self.vertexes[i].z = z * scaleZ\r
+\r
+ for face in self.faces:\r
+ v1 = face.v[0]\r
+ v2 = face.v[1]\r
+ v3 = face.v[2]\r
+ face.normal = (v2 - v1).cross(v3 - v1)\r
+ face.normal.normalize()\r
+\r
+ minZ = self.getMinimumZ()\r
+ minV = self.getMinimum()\r
+ maxV = self.getMaximum()\r
+ for v in self.vertexes:\r
+ v.z -= minZ\r
+ v.x -= minV.x + (maxV.x - minV.x) / 2\r
+ v.y -= minV.y + (maxV.y - minV.y) / 2\r
+ self.getMinimumZ()\r
+ self.modelDirty = True\r
+ \r
+ def clone(self):\r
+ p = ProjectObject(self.filename)\r
+\r
+ p.centerX = self.centerX + 5\r
+ p.centerY = self.centerY + 5\r
+ \r
+ p.filename = self.filename\r
+ p.scale = self.scale\r
+ p.rotate = self.rotate\r
+ p.flipX = self.flipX\r
+ p.flipY = self.flipY\r
+ p.flipZ = self.flipZ\r
+ p.swapXZ = self.swapXZ\r
+ p.swapYZ = self.swapYZ\r
+ p.extruder = self.extruder\r
+ \r
+ p.updateModelTransform()\r
+ \r
+ return p\r
+\r
class projectPlanner(wx.Frame):\r
"Main user interface window"\r
def __init__(self):\r
self.list = []\r
self.selection = None\r
\r
- self.machineSize = util3d.Vector3(float(profile.getPreference('machine_width')), float(profile.getPreference('machine_depth')), float(profile.getPreference('machine_height')))\r
- self.headSizeMin = util3d.Vector3(70,16,0)\r
- self.headSizeMax = util3d.Vector3(16,35,0)\r
+ self.machineSize = util3d.Vector3(profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height'))\r
+ self.headSizeMin = util3d.Vector3(profile.getPreferenceFloat('extruder_head_size_min_x'), profile.getPreferenceFloat('extruder_head_size_min_y'),0)\r
+ self.headSizeMax = util3d.Vector3(profile.getPreferenceFloat('extruder_head_size_max_x'), profile.getPreferenceFloat('extruder_head_size_max_y'),0)\r
+\r
+ self.extruderOffset = [\r
+ util3d.Vector3(0,0,0),\r
+ util3d.Vector3(profile.getPreferenceFloat('extruder_offset_x1'), profile.getPreferenceFloat('extruder_offset_y1'), 0),\r
+ util3d.Vector3(profile.getPreferenceFloat('extruder_offset_x2'), profile.getPreferenceFloat('extruder_offset_y2'), 0),\r
+ util3d.Vector3(profile.getPreferenceFloat('extruder_offset_x3'), profile.getPreferenceFloat('extruder_offset_y3'), 0)]\r
\r
self.toolbar = toolbarUtil.Toolbar(self)\r
\r
toolbarUtil.NormalButton(self.toolbar, self.OnQuit, 'exit.png', 'Close project planner')\r
\r
self.toolbar.Realize()\r
+\r
+ self.toolbar2 = toolbarUtil.Toolbar(self)\r
+ toolbarUtil.NormalButton(self.toolbar2, self.OnAddModel, 'object-add.png', 'Add model')\r
+ toolbarUtil.NormalButton(self.toolbar2, self.OnRemModel, 'object-remove.png', 'Remove model')\r
+ toolbarUtil.NormalButton(self.toolbar2, self.OnMoveUp, 'move-up.png', 'Move model up in print list')\r
+ toolbarUtil.NormalButton(self.toolbar2, self.OnMoveDown, 'move-down.png', 'Move model down in print list')\r
+ toolbarUtil.NormalButton(self.toolbar2, self.OnCopy, 'copy.png', 'Make a copy of the current selected object')\r
+ self.toolbar2.Realize()\r
\r
sizer = wx.GridBagSizer(2,2)\r
self.SetSizer(sizer)\r
self.sliceButton = wx.Button(self, -1, "Slice")\r
self.autoPlaceButton = wx.Button(self, -1, "Auto Place")\r
\r
- sizer.Add(self.toolbar, (0,0), span=(1,3), flag=wx.EXPAND)\r
+ sizer.Add(self.toolbar, (0,0), span=(1,1), flag=wx.EXPAND)\r
+ sizer.Add(self.toolbar2, (0,1), span=(1,2), flag=wx.EXPAND)\r
sizer.Add(self.preview, (1,0), span=(4,1), flag=wx.EXPAND)\r
sizer.Add(self.listbox, (1,1), span=(1,2), flag=wx.EXPAND)\r
sizer.Add(self.addButton, (2,1), span=(1,1))\r
sizer.Add(self.scaleCtrl, (0,1), flag=wx.ALIGN_BOTTOM|wx.EXPAND)\r
sizer.Add(wx.StaticText(panel, -1, 'Rotate'), (1,0), flag=wx.ALIGN_CENTER_VERTICAL)\r
sizer.Add(self.rotateCtrl, (1,1), flag=wx.ALIGN_BOTTOM|wx.EXPAND)\r
+ \r
+ if int(profile.getPreference('extruder_amount')) > 1:\r
+ self.extruderCtrl = wx.ComboBox(panel, -1, '1', choices=map(str, range(1, int(profile.getPreference('extruder_amount'))+1)), style=wx.CB_DROPDOWN|wx.CB_READONLY)\r
+ sizer.Add(wx.StaticText(panel, -1, 'Extruder'), (2,0), flag=wx.ALIGN_CENTER_VERTICAL)\r
+ sizer.Add(self.extruderCtrl, (2,1), flag=wx.ALIGN_BOTTOM|wx.EXPAND)\r
+ self.extruderCtrl.Bind(wx.EVT_COMBOBOX, self.OnExtruderChange)\r
\r
self.scaleCtrl.Bind(wx.EVT_TEXT, self.OnScaleChange)\r
self.rotateCtrl.Bind(wx.EVT_SPINCTRL, self.OnRotateChange)\r
cp.set(section, 'flipZ', str(item.flipZ))\r
cp.set(section, 'swapXZ', str(item.swapXZ))\r
cp.set(section, 'swapYZ', str(item.swapYZ))\r
+ cp.set(section, 'extruder', str(item.extruder+1))\r
i += 1\r
cp.write(open(dlg.GetPath(), "w"))\r
dlg.Destroy()\r
while cp.has_section('model_%d' % (i)):\r
section = 'model_%d' % (i)\r
\r
- item = stl.stlModel()\r
- item.filename = unicode(cp.get(section, 'filename'), "utf-8")\r
- self.loadModelFile(item)\r
+ item = ProjectObject(unicode(cp.get(section, 'filename'), "utf-8"))\r
item.centerX = float(cp.get(section, 'centerX'))\r
item.centerY = float(cp.get(section, 'centerY'))\r
item.scale = float(cp.get(section, 'scale'))\r
item.rotate = float(cp.get(section, 'rotate'))\r
- cp.get(section, 'flipX')\r
- cp.get(section, 'flipY')\r
- cp.get(section, 'flipZ')\r
- cp.get(section, 'swapXZ')\r
- cp.get(section, 'swapYZ')\r
+ item.flipX = cp.get(section, 'flipX') == 'True'\r
+ item.flipY = cp.get(section, 'flipY') == 'True'\r
+ item.flipZ = cp.get(section, 'flipZ') == 'True'\r
+ item.swapXZ = cp.get(section, 'swapXZ') == 'True'\r
+ item.swapYZ = cp.get(section, 'swapYZ') == 'True'\r
+ if cp.has_option(section, 'extruder'):\r
+ item.extuder = int(cp.get(section, 'extruder'))-1\r
+ item.updateModelTransform()\r
i += 1\r
\r
self.list.append(item)\r
\r
self.listbox.SetSelection(len(self.list)-1)\r
self.OnListSelect(None)\r
+ self.preview.Refresh()\r
\r
dlg.Destroy()\r
\r
self.selection = self.list[self.listbox.GetSelection()]\r
self.scaleCtrl.SetValue(str(self.selection.scale))\r
self.rotateCtrl.SetValue(int(self.selection.rotate))\r
+ if int(profile.getPreference('extruder_amount')) > 1:\r
+ self.extruderCtrl.SetValue(str(self.selection.extruder+1))\r
self.preview.Refresh()\r
-\r
+ \r
def OnAddModel(self, e):\r
dlg=wx.FileDialog(self, "Open file to print", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST|wx.FD_MULTIPLE)\r
dlg.SetWildcard("STL files (*.stl)|*.stl;*.STL")\r
if dlg.ShowModal() == wx.ID_OK:\r
for filename in dlg.GetPaths():\r
- item = stl.stlModel()\r
- item.filename=filename\r
+ item = ProjectObject(filename)\r
profile.putPreference('lastFile', item.filename)\r
- if not(os.path.exists(item.filename)):\r
- return\r
- self.loadModelFile(item)\r
self.list.append(item)\r
- self.listbox.AppendAndEnsureVisible(os.path.split(item.filename)[1])\r
- self.listbox.SetSelection(len(self.list)-1)\r
- self.OnListSelect(None)\r
+ self.selection = item\r
+ self._updateListbox()\r
+ self.preview.Refresh()\r
dlg.Destroy()\r
\r
def OnRemModel(self, e):\r
if self.selection == None:\r
return\r
self.list.remove(self.selection)\r
+ self._updateListbox()\r
+ self.preview.Refresh()\r
+ \r
+ def OnMoveUp(self, e):\r
+ if self.selection == None:\r
+ return\r
i = self.listbox.GetSelection()\r
- self.listbox.Delete(i)\r
- if len(self.list) > i:\r
- self.listbox.SetSelection(i)\r
- elif len(self.list) > 0:\r
- self.listbox.SetSelection(len(self.list) - 1)\r
- self.selection = None\r
- self.OnListSelect(None)\r
+ if i == 0:\r
+ return\r
+ self.list.remove(self.selection)\r
+ self.list.insert(i-1, self.selection)\r
+ self._updateListbox()\r
+ self.preview.Refresh()\r
+\r
+ def OnMoveDown(self, e):\r
+ if self.selection == None:\r
+ return\r
+ i = self.listbox.GetSelection()\r
+ if i == len(self.list) - 1:\r
+ return\r
+ self.list.remove(self.selection)\r
+ self.list.insert(i+1, self.selection)\r
+ self._updateListbox()\r
+ self.preview.Refresh()\r
+ \r
+ def OnCopy(self, e):\r
+ if self.selection == None:\r
+ return\r
+ \r
+ item = self.selection.clone()\r
+ self.list.append(item)\r
+ self.selection = item\r
+ \r
+ self._updateListbox()\r
self.preview.Refresh()\r
\r
+ def _updateListbox(self):\r
+ self.listbox.Clear()\r
+ for item in self.list:\r
+ self.listbox.AppendAndEnsureVisible(os.path.split(item.filename)[1])\r
+ if self.selection in self.list:\r
+ self.listbox.SetSelection(self.list.index(self.selection))\r
+ elif len(self.list) > 0:\r
+ self.selection = self.list[0]\r
+ self.listbox.SetSelection(0)\r
+ else:\r
+ self.selection = None\r
+ self.listbox.SetSelection(-1)\r
+\r
def OnAutoPlace(self, e):\r
bestAllowedSize = int(self.machineSize.y)\r
bestArea = self._doAutoPlace(bestAllowedSize)\r
extraSizeMax = self.headSizeMax\r
if profile.getProfileSettingFloat('skirt_line_count') > 0:\r
skirtSize = profile.getProfileSettingFloat('skirt_line_count') * profile.calculateEdgeWidth() + profile.getProfileSettingFloat('skirt_gap')\r
- extraSizeMin = extraSizeMin - util3d.Vector3(skirtSize, skirtSize, 0)\r
+ extraSizeMin = extraSizeMin + util3d.Vector3(skirtSize, skirtSize, 0)\r
extraSizeMax = extraSizeMax + util3d.Vector3(skirtSize, skirtSize, 0)\r
\r
posX = self.machineSize.x\r
return (maxX - minX) + (maxY - minY)\r
\r
def OnSlice(self, e):\r
- oldProfile = profile.getGlobalProfileString()\r
- \r
- put = profile.putProfileSetting\r
+ put = profile.setTempOverride\r
\r
put('model_multiply_x', '1')\r
put('model_multiply_y', '1')\r
clearZ = 0\r
actionList = []\r
for item in self.list:\r
- put('machine_center_x', item.centerX)\r
- put('machine_center_y', item.centerY)\r
+ put('machine_center_x', item.centerX - self.extruderOffset[item.extruder].x)\r
+ put('machine_center_y', item.centerY - self.extruderOffset[item.extruder].y)\r
put('model_scale', item.scale)\r
put('flip_x', item.flipX)\r
put('flip_y', item.flipY)\r
action.sliceCmd = sliceRun.getSliceCommand(item.filename)\r
action.centerX = item.centerX\r
action.centerY = item.centerY\r
+ action.extruder = item.extruder\r
action.filename = item.filename\r
clearZ = max(clearZ, item.getMaximum().z * item.scale)\r
action.clearZ = clearZ\r
actionList.append(action)\r
\r
#Restore the old profile.\r
- profile.loadGlobalProfileFromString(oldProfile)\r
+ profile.resetTempOverride()\r
\r
dlg=wx.FileDialog(self, "Save project gcode file", os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_SAVE)\r
dlg.SetWildcard("GCode file (*.gcode)|*.gcode")\r
dlg.Destroy()\r
\r
pspw = ProjectSliceProgressWindow(actionList, resultFilename)\r
+ pspw.extruderOffset = self.extruderOffset\r
pspw.Centre()\r
pspw.Show(True)\r
\r
- def loadModelFile(self, item):\r
- item.load(item.filename)\r
- item.origonalVertexes = list(item.vertexes)\r
- for i in xrange(0, len(item.origonalVertexes)):\r
- item.origonalVertexes[i] = item.origonalVertexes[i].copy()\r
- item.getMinimumZ()\r
- \r
- item.centerX = -item.getMinimum().x + 5\r
- item.centerY = -item.getMinimum().y + 5\r
- item.scale = 1.0\r
- item.rotate = 0.0\r
- item.flipX = False\r
- item.flipY = False\r
- item.flipZ = False\r
- item.swapXZ = False\r
- item.swapYZ = False\r
- \r
- item.modelDisplayList = None\r
- item.modelDirty = False\r
- \r
- self.updateModelTransform(item)\r
-\r
- item.centerX = -item.getMinimum().x + 5\r
- item.centerY = -item.getMinimum().y + 5\r
-\r
def OnScaleChange(self, e):\r
if self.selection == None:\r
return\r
if self.selection == None:\r
return\r
self.selection.rotate = float(self.rotateCtrl.GetValue())\r
- self.updateModelTransform(self.selection)\r
-\r
- def updateModelTransform(self, item):\r
- rotate = item.rotate / 180.0 * math.pi\r
- scaleX = 1.0\r
- scaleY = 1.0\r
- scaleZ = 1.0\r
- if item.flipX:\r
- scaleX = -scaleX\r
- if item.flipY:\r
- scaleY = -scaleY\r
- if item.flipZ:\r
- scaleZ = -scaleZ\r
- swapXZ = item.swapXZ\r
- swapYZ = item.swapYZ\r
- mat00 = math.cos(rotate) * scaleX\r
- mat01 =-math.sin(rotate) * scaleY\r
- mat10 = math.sin(rotate) * scaleX\r
- mat11 = math.cos(rotate) * scaleY\r
- \r
- for i in xrange(0, len(item.origonalVertexes)):\r
- x = item.origonalVertexes[i].x\r
- y = item.origonalVertexes[i].y\r
- z = item.origonalVertexes[i].z\r
- if swapXZ:\r
- x, z = z, x\r
- if swapYZ:\r
- y, z = z, y\r
- item.vertexes[i].x = x * mat00 + y * mat01\r
- item.vertexes[i].y = x * mat10 + y * mat11\r
- item.vertexes[i].z = z * scaleZ\r
-\r
- for face in item.faces:\r
- v1 = face.v[0]\r
- v2 = face.v[1]\r
- v3 = face.v[2]\r
- face.normal = (v2 - v1).cross(v3 - v1)\r
- face.normal.normalize()\r
+ self.selection.updateModelTransform()\r
+ self.preview.Refresh()\r
\r
- self.moveModel(item)\r
- \r
- def moveModel(self, item):\r
- minZ = item.getMinimumZ()\r
- min = item.getMinimum()\r
- max = item.getMaximum()\r
- for v in item.vertexes:\r
- v.z -= minZ\r
- v.x -= min.x + (max.x - min.x) / 2\r
- v.y -= min.y + (max.y - min.y) / 2\r
- item.getMinimumZ()\r
- item.modelDirty = True\r
+ def OnExtruderChange(self, e):\r
+ if self.selection == None:\r
+ return\r
+ self.selection.extruder = int(self.extruderCtrl.GetValue()) - 1\r
self.preview.Refresh()\r
\r
class PreviewGLCanvas(glcanvas.GLCanvas):\r
if item != None:\r
item.centerX += float(e.GetX() - self.oldX) * self.zoom / self.GetSize().GetHeight() * 2\r
item.centerY -= float(e.GetY() - self.oldY) * self.zoom / self.GetSize().GetHeight() * 2\r
- if item.centerX < -item.getMinimum().x * item.scale:\r
- item.centerX = -item.getMinimum().x * item.scale\r
- if item.centerY < -item.getMinimum().y * item.scale:\r
- item.centerY = -item.getMinimum().y * item.scale\r
- if item.centerX > self.parent.machineSize.x - item.getMaximum().x * item.scale:\r
- item.centerX = self.parent.machineSize.x - item.getMaximum().x * item.scale\r
- if item.centerY > self.parent.machineSize.y - item.getMaximum().y * item.scale:\r
- item.centerY = self.parent.machineSize.y - item.getMaximum().y * item.scale\r
+ if item.centerX < -item.getMinimum().x * item.scale + self.parent.extruderOffset[item.extruder].x:\r
+ item.centerX = -item.getMinimum().x * item.scale + self.parent.extruderOffset[item.extruder].x\r
+ if item.centerY < -item.getMinimum().y * item.scale + self.parent.extruderOffset[item.extruder].y:\r
+ item.centerY = -item.getMinimum().y * item.scale + self.parent.extruderOffset[item.extruder].y\r
+ if item.centerX > self.parent.machineSize.x + self.parent.extruderOffset[item.extruder].x - item.getMaximum().x * item.scale:\r
+ item.centerX = self.parent.machineSize.x + self.parent.extruderOffset[item.extruder].x - item.getMaximum().x * item.scale\r
+ if item.centerY > self.parent.machineSize.y + self.parent.extruderOffset[item.extruder].y - item.getMaximum().y * item.scale:\r
+ item.centerY = self.parent.machineSize.y + self.parent.extruderOffset[item.extruder].y - item.getMaximum().y * item.scale\r
self.Refresh()\r
else:\r
self.allowDrag = False\r
extraSizeMax = self.parent.headSizeMax\r
if profile.getProfileSettingFloat('skirt_line_count') > 0:\r
skirtSize = profile.getProfileSettingFloat('skirt_line_count') * profile.calculateEdgeWidth() + profile.getProfileSettingFloat('skirt_gap')\r
- extraSizeMin = extraSizeMin - util3d.Vector3(skirtSize, skirtSize, 0)\r
+ extraSizeMin = extraSizeMin + util3d.Vector3(skirtSize, skirtSize, 0)\r
extraSizeMax = extraSizeMax + util3d.Vector3(skirtSize, skirtSize, 0)\r
\r
for item in self.parent.list:\r
\r
for idx1 in xrange(0, len(self.parent.list)):\r
item = self.parent.list[idx1]\r
- iMin1 = item.getMinimum() * item.scale + util3d.Vector3(item.centerX, item.centerY, 0) - extraSizeMin\r
- iMax1 = item.getMaximum() * item.scale + util3d.Vector3(item.centerX, item.centerY, 0) + extraSizeMax\r
+ iMin1 = item.getMinimum() * item.scale + util3d.Vector3(item.centerX, item.centerY, 0) - extraSizeMin - self.parent.extruderOffset[item.extruder]\r
+ iMax1 = item.getMaximum() * item.scale + util3d.Vector3(item.centerX, item.centerY, 0) + extraSizeMax - self.parent.extruderOffset[item.extruder]\r
for idx2 in xrange(0, idx1):\r
item2 = self.parent.list[idx2]\r
iMin2 = item2.getMinimum() * item2.scale + util3d.Vector3(item2.centerX, item2.centerY, 0)\r
\r
vMin = item.getMinimum() * item.scale\r
vMax = item.getMaximum() * item.scale\r
- vMinHead = vMin - extraSizeMin\r
- vMaxHead = vMax + extraSizeMax\r
+ vMinHead = vMin - extraSizeMin - self.parent.extruderOffset[item.extruder]\r
+ vMaxHead = vMax + extraSizeMax - self.parent.extruderOffset[item.extruder]\r
\r
glDisable(GL_LIGHTING)\r
\r
self.startTime = time.time()\r
self.sliceStartTime = time.time()\r
\r
- #How long does each step take compared to the others. This is used to make a better scaled progress bar, and guess time left.\r
- # TODO: Duplicate with sliceProgressPanel, move to sliceRun.\r
- self.sliceStepTimeFactor = {\r
- 'start': 3.3713991642,\r
- 'slice': 15.4984838963,\r
- 'preface': 5.17178297043,\r
- 'inset': 116.362634182,\r
- 'fill': 215.702672005,\r
- 'multiply': 21.9536788464,\r
- 'speed': 12.759510994,\r
- 'raft': 31.4580039978,\r
- 'skirt': 19.3436040878,\r
- 'skin': 1.0,\r
- 'joris': 1.0,\r
- 'comb': 23.7805759907,\r
- 'cool': 27.148763895,\r
- 'dimension': 90.4914340973\r
- }\r
- self.totalRunTimeFactor = 0\r
- for v in self.sliceStepTimeFactor.itervalues():\r
- self.totalRunTimeFactor += v\r
- \r
self.sizer = wx.GridBagSizer(2, 2) \r
self.statusText = wx.StaticText(self, -1, "Building: %s" % (resultFilename))\r
self.progressGauge = wx.Gauge(self, -1)\r
self.sizer.Add(self.statusText, (0,0), flag=wx.ALIGN_CENTER)\r
self.sizer.Add(self.progressGauge, (1, 0), flag=wx.EXPAND)\r
self.sizer.Add(self.progressGauge2, (2, 0), flag=wx.EXPAND)\r
+\r
self.sizer.Add(self.abortButton, (3,0), flag=wx.ALIGN_CENTER)\r
self.sizer.AddGrowableCol(0)\r
self.sizer.AddGrowableRow(0)\r
\r
def SetProgress(self, stepName, layer, maxLayer):\r
if self.prevStep != stepName:\r
- self.totalDoneFactor += self.sliceStepTimeFactor[self.prevStep]\r
+ self.totalDoneFactor += sliceRun.sliceStepTimeFactor[self.prevStep]\r
newTime = time.time()\r
#print "#####" + str(newTime-self.startTime) + " " + self.prevStep + " -> " + stepName\r
self.startTime = newTime\r
self.prevStep = stepName\r
\r
- progresValue = ((self.totalDoneFactor + self.sliceStepTimeFactor[stepName] * layer / maxLayer) / self.totalRunTimeFactor) * 10000\r
+ progresValue = ((self.totalDoneFactor + sliceRun.sliceStepTimeFactor[stepName] * layer / maxLayer) / sliceRun.totalRunTimeFactor) * 10000\r
self.progressGauge.SetValue(int(progresValue))\r
self.statusText.SetLabel(stepName + " [" + str(layer) + "/" + str(maxLayer) + "]")\r
\r
def OnRun(self):\r
resultFile = open(self.resultFilename, "w")\r
- put = profile.putProfileSetting\r
+ put = profile.setTempOverride\r
for action in self.actionList:\r
p = subprocess.Popen(action.sliceCmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)\r
line = p.stdout.readline()\r
if self.abort:\r
p.terminate()\r
wx.CallAfter(self.statusText.SetLabel, "Aborted by user.")\r
+ resultFile.close()\r
return\r
line = p.stdout.readline()\r
self.returnCode = p.wait()\r
\r
- oldProfile = profile.getGlobalProfileString()\r
- put('machine_center_x', action.centerX)\r
- put('machine_center_y', action.centerY)\r
+ put('machine_center_x', action.centerX - self.extruderOffset[action.extruder].x)\r
+ put('machine_center_y', action.centerY - self.extruderOffset[action.extruder].y)\r
put('clear_z', action.clearZ)\r
+ put('extruder', action.extruder)\r
\r
if action == self.actionList[0]:\r
resultFile.write(';TYPE:CUSTOM\n')\r
+ resultFile.write('T%d\n' % (action.extruder))\r
+ currentExtruder = action.extruder\r
resultFile.write(profile.getAlterationFileContents('start.gcode'))\r
else:\r
#reset the extrusion length, and move to the next object center.\r
resultFile.write(';TYPE:CUSTOM\n')\r
resultFile.write(profile.getAlterationFileContents('nextobject.gcode'))\r
resultFile.write(';PRINTNR:%d\n' % self.actionList.index(action))\r
- profile.loadGlobalProfileFromString(oldProfile)\r
+ profile.resetTempOverride()\r
\r
f = open(action.filename[: action.filename.rfind('.')] + "_export.project_tmp", "r")\r
data = f.read(4096)\r
resultFile.write(';TYPE:CUSTOM\n')\r
resultFile.write(profile.getAlterationFileContents('end.gcode'))\r
resultFile.close()\r
+ \r
+ gcode = gcodeInterpreter.gcode()\r
+ gcode.load(self.resultFilename)\r
+ \r
self.abort = True\r
sliceTime = time.time() - self.sliceStartTime\r
- wx.CallAfter(self.statusText.SetLabel, 'Slicing took: %d:%d' % (sliceTime / 60, sliceTime % 60))\r
+ status = "Slicing took: %02d:%02d\n" % (sliceTime / 60, sliceTime % 60)\r
+ status = "Filament: %.2fm %.2fg\n" % (gcode.extrusionAmount / 1000, gcode.calculateWeight() * 1000)\r
+ status += "Print time: %02d:%02d\n" % (int(gcode.totalMoveTimeMinute / 60), int(gcode.totalMoveTimeMinute % 60))\r
+ cost = gcode.calculateCost()\r
+ if cost != False:\r
+ status += "Cost: %s\n" % (cost)\r
+ wx.CallAfter(self.statusText.SetLabel, status)\r
+ \r
wx.CallAfter(self.abortButton.SetLabel, 'Close')\r
\r
def main():\r
self.sizer = sizer
if self.filename != "None":
- self.preview3d.loadModelFile(self.filename)
+ self.preview3d.loadModelFiles([self.filename])
self.lastPath = os.path.split(self.filename)[0]
self.updateProfileToControls()
if not(os.path.exists(self.filename)):
return
self.lastPath = os.path.split(self.filename)[0]
- self.preview3d.loadModelFile(self.filename)
+ self.preview3d.loadModelFiles([self.filename])
self.preview3d.setViewMode("Normal")
dlg.Destroy()
from __future__ import absolute_import
import __init__
-import wx, sys, os, math, threading, subprocess, time
+import wx, sys, os, math, threading, subprocess, time, re
from util import profile
from util import sliceRun
from util import exporer
+from util import gcodeInterpreter
class sliceProgessPanel(wx.Panel):
def __init__(self, mainWindow, parent, filelist):
self.filelist = filelist
self.abort = False
- #How long does each step take compared to the others. This is used to make a better scaled progress bar, and guess time left.
- self.sliceStepTimeFactor = {
- 'start': 3.3713991642,
- 'slice': 15.4984838963,
- 'preface': 5.17178297043,
- 'inset': 116.362634182,
- 'fill': 215.702672005,
- 'multiply': 21.9536788464,
- 'speed': 12.759510994,
- 'raft': 31.4580039978,
- 'skirt': 19.3436040878,
- 'skin': 1.0,
- 'joris': 1.0,
- 'comb': 23.7805759907,
- 'cool': 27.148763895,
- 'dimension': 90.4914340973
- }
- self.totalRunTimeFactor = 0
- for v in self.sliceStepTimeFactor.itervalues():
- self.totalRunTimeFactor += v
-
box = wx.StaticBox(self, -1, filelist[0])
self.sizer = wx.StaticBoxSizer(box, wx.HORIZONTAL)
if profile.getPreference('save_profile') == 'True':
profile.saveGlobalProfile(self.filelist[0][: self.filelist[0].rfind('.')] + "_profile.ini")
cmdList = []
- oldProfile = profile.getGlobalProfileString()
for filename in self.filelist:
- print filename, self.filelist.index(filename)
- if self.filelist.index(filename) > 0:
- profile.putProfileSetting('fan_enabled', 'False')
- profile.putProfileSetting('skirt_line_count', '0')
- profile.putProfileSetting('machine_center_x', profile.getProfileSettingFloat('machine_center_x') + 22)
+ idx = self.filelist.index(filename)
+ print filename, idx
+ if idx > 0:
+ profile.setTempOverride('fan_enabled', 'False')
+ profile.setTempOverride('skirt_line_count', '0')
+ profile.setTempOverride('machine_center_x', profile.getProfileSettingFloat('machine_center_x') - profile.getPreferenceFloat('extruder_offset_x%d' % (idx)))
+ profile.setTempOverride('machine_center_y', profile.getProfileSettingFloat('machine_center_y') - profile.getPreferenceFloat('extruder_offset_y%d' % (idx)))
+ profile.setTempOverride('alternative_center', self.filelist[0])
if len(self.filelist) > 1:
- profile.putProfileSetting('add_start_end_gcode', 'False')
- profile.putProfileSetting('gcode_extension', 'multi_extrude_tmp')
+ profile.setTempOverride('add_start_end_gcode', 'False')
+ profile.setTempOverride('gcode_extension', 'multi_extrude_tmp')
cmdList.append(sliceRun.getSliceCommand(filename))
- profile.loadGlobalProfileFromString(oldProfile)
+ profile.resetTempOverride()
self.thread = WorkerThread(self, filelist, cmdList)
def OnAbort(self, e):
self.Bind(wx.EVT_BUTTON, self.OnAbort, self.abortButton)
self.sizer.Add(self.logButton, 0)
if result.returnCode == 0:
- self.statusText.SetLabel("Ready.")
+ 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 != False:
+ status += " Cost: %s" % (cost)
+ self.statusText.SetLabel(status)
if exporer.hasExporer():
self.openFileLocationButton = wx.Button(self, -1, "Open file location")
self.Bind(wx.EVT_BUTTON, self.OnOpenFileLocation, self.openFileLocationButton)
def SetProgress(self, stepName, layer, maxLayer):
if self.prevStep != stepName:
- self.totalDoneFactor += self.sliceStepTimeFactor[self.prevStep]
+ 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 + self.sliceStepTimeFactor[stepName] * layer / maxLayer) / self.totalRunTimeFactor) * 10000
+ progresValue = ((self.totalDoneFactor + sliceRun.sliceStepTimeFactor[stepName] * layer / maxLayer) / sliceRun.totalRunTimeFactor) * 10000
self.progressGauge.SetValue(int(progresValue))
self.statusText.SetLabel(stepName + " [" + str(layer) + "/" + str(maxLayer) + "]")
if self.fileIdx == len(self.cmdList):
if len(self.filelist) > 1:
self._stitchMultiExtruder()
+ self.gcode = gcodeInterpreter.gcode()
+ self.gcode.load(self.filelist[0][:self.filelist[0].rfind('.')]+'_export.gcode')
wx.CallAfter(self.notifyWindow.OnSliceDone, self)
else:
self.run()
resultFile.write(';TYPE:CUSTOM\n')
resultFile.write(profile.getAlterationFileContents('start.gcode'))
for filename in self.filelist:
- files.append(open(filename[:filename.rfind('.')]+'_export.multi_extrude_tmp', "r"))
+ if os.path.isfile(filename[:filename.rfind('.')]+'_export.multi_extrude_tmp'):
+ files.append(open(filename[:filename.rfind('.')]+'_export.multi_extrude_tmp', "r"))
+ else:
+ return
currentExtruder = 0
- resultFile.write("T%d\n" % (currentExtruder))
+ resultFile.write('T%d\n' % (currentExtruder))
layerNr = -1
hasLine = True
while hasLine:
hasLine = True
if line.startswith(';LAYER:'):
break
+ if 'Z' in line:
+ lastZ = float(re.search('Z([^\s]+)', line).group(1))
if not layerHasLine:
nextExtruder = files.index(f)
resultFile.write(';LAYER:%d\n' % (layerNr))
resultFile.write(';EXTRUDER:%d\n' % (nextExtruder))
if nextExtruder != currentExtruder:
- resultFile.write("G1 E-2 F3000\n")
+ resultFile.write("G1 E-5 F5000\n")
+ resultFile.write("G92 E0\n")
resultFile.write("T%d\n" % (nextExtruder))
- resultFile.write("G1 E2 F3000\n")
+ resultFile.write("G1 E5 F5000\n")
resultFile.write("G92 E0\n")
currentExtruder = nextExtruder
layerHasLine = True
super(NormalButton, self).__init__(parent, id, self.bitmap, size=size)
self.helpText = helpText
+ self.callback = callback
self.SetBezelWidth(1)
self.SetUseFocusIndicator(False)
self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnter)
self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave)
- self.Bind(wx.EVT_BUTTON, callback)
+ self.Bind(wx.EVT_BUTTON, self.OnButton)
parent.AddControl(self)
+ def OnButton(self, event):
+ self.GetParent().OnPopupHide(event)
+ self.callback(event)
+
def OnMouseEnter(self, event):
self.GetParent().OnPopupDisplay(event)
event.Skip()
WARNING = 1
ERROR = 2
-class validFloat():
+class validFloat(object):
def __init__(self, setting, minValue = None, maxValue = None):
self.setting = setting
self.setting.validators.append(self)
except (ValueError, SyntaxError):
return ERROR, '"' + str(self.setting.GetValue()) + '" is not a valid number or expression'
-class validInt():
+class validInt(object):
def __init__(self, setting, minValue = None, maxValue = None):
self.setting = setting
self.setting.validators.append(self)
except (ValueError, SyntaxError):
return ERROR, '"' + str(self.setting.GetValue()) + '" is not a valid whole number or expression'
-class warningAbove():
+class warningAbove(object):
def __init__(self, setting, minValueForWarning, warningMessage):
self.setting = setting
self.setting.validators.append(self)
#We already have an error by the int/float validator in this case.
return SUCCESS, ''
-class wallThicknessValidator():
+class wallThicknessValidator(object):
def __init__(self, setting):
self.setting = setting
self.setting.validators.append(self)
#We already have an error by the int/float validator in this case.
return SUCCESS, ''
-class printSpeedValidator():
+class printSpeedValidator(object):
def __init__(self, setting):
self.setting = setting
self.setting.validators.append(self)
from util import util3d
from util import profile
-class gcodePath():
+class gcodePath(object):
def __init__(self, newType, pathType, startPoint):
self.type = newType
self.pathType = pathType
self.list = [startPoint]
-class gcode():
+class gcode(object):
def __init__(self):
self.regMatch = {}
self.layerList = []
#Calculates the weight of the filament in kg
radius = float(profile.getProfileSetting('filament_diameter')) / 2
volumeM3 = (self.extrusionAmount * (math.pi * radius * radius)) / (1000*1000*1000)
- return volumeM3 * float(profile.getPreference('filament_density'))
+ return volumeM3 * profile.getPreferenceFloat('filament_density')
+
+ def calculateCost(self):
+ cost_kg = profile.getPreferenceFloat('filament_cost_kg')
+ cost_meter = profile.getPreferenceFloat('filament_cost_meter')
+ if cost_kg > 0.0 and cost_meter > 0.0:
+ return "%.2f / %.2f" % (self.calculateWeight() * cost_kg, self.extrusionAmount / 1000 * cost_meter)
+ elif cost_kg > 0.0:
+ return "%.2f" % (self.calculateWeight() * cost_kg)
+ elif cost_meter > 0.0:
+ return "%.2f" % (self.extrusionAmount / 1000 * cost_meter)
+ return False
def _load(self, gcodeFile):
filePos = 0
currentE = 0.0
totalExtrusion = 0.0
maxExtrusion = 0.0
+ currentExtruder = 0
totalMoveTimeMinute = 0.0
scale = 1.0
posAbs = True
if pathType != "CUSTOM":
startCodeDone = True
line = line[0:line.find(';')]
+ T = self.getCodeInt(line, 'T')
+ if T is not None:
+ if currentExtruder > 0:
+ posOffset.x -= profile.getPreferenceFloat('extruder_offset_x%d' % (currentExtruder))
+ posOffset.y -= profile.getPreferenceFloat('extruder_offset_y%d' % (currentExtruder))
+ currentExtruder = T
+ if currentExtruder > 0:
+ posOffset.x += profile.getPreferenceFloat('extruder_offset_x%d' % (currentExtruder))
+ posOffset.y += profile.getPreferenceFloat('extruder_offset_y%d' % (currentExtruder))
G = self.getCodeInt(line, 'G')
if G is not None:
oldPos = pos.copy()
if x is not None:
if posAbs:
- pos.x = x * scale
+ pos.x = x * scale + posOffset.x
else:
pos.x += x * scale
if y is not None:
if posAbs:
- pos.y = y * scale
+ pos.y = y * scale + posOffset.y
else:
pos.y += y * scale
if z is not None:
if posAbs:
- pos.z = z * scale
+ pos.z = z * scale + posOffset.z
else:
pos.z += z * scale
#Check if we have a new layer.
self.layerList.append(currentLayer)
self.extrusionAmount = maxExtrusion
self.totalMoveTimeMinute = totalMoveTimeMinute
- print "Extruded a total of: %d mm of filament" % (self.extrusionAmount)
- print "Estimated print duration: %.2f minutes" % (self.totalMoveTimeMinute)
+ #print "Extruded a total of: %d mm of filament" % (self.extrusionAmount)
+ #print "Estimated print duration: %.2f minutes" % (self.totalMoveTimeMinute)
def getCodeInt(self, line, code):
if code not in self.regMatch:
'bottom_layer_speed': '20',\r
'cool_min_layer_time': '10',\r
'fan_enabled': 'True',\r
- 'fan_layer': '0',\r
+ 'fan_layer': '1',\r
'fan_speed': '100',\r
'model_scale': '1.0',\r
'flip_x': 'False',\r
\r
'add_start_end_gcode': 'True',\r
'gcode_extension': 'gcode',\r
+ 'alternative_center': '',\r
+ 'clear_z': '0.0',\r
+ 'extruder': '0',\r
}\r
alterationDefault = {\r
#######################################################################################\r
'machine_depth': '205',\r
'machine_height': '200',\r
'extruder_amount': '1',\r
+ 'extruder_offset_x1': '-22.0',\r
+ 'extruder_offset_y1': '0.0',\r
+ 'extruder_offset_x2': '0.0',\r
+ 'extruder_offset_y2': '0.0',\r
+ 'extruder_offset_x3': '0.0',\r
+ 'extruder_offset_y3': '0.0',\r
'filament_density': '1300',\r
'steps_per_e': '0',\r
'serial_port': 'AUTO',\r
'save_profile': 'False',\r
'filament_cost_kg': '0',\r
'filament_cost_meter': '0',\r
+ \r
+ 'extruder_head_size_min_x': '70.0',\r
+ 'extruder_head_size_min_y': '18.0',\r
+ 'extruder_head_size_max_x': '18.0',\r
+ 'extruder_head_size_max_y': '35.0',\r
}\r
\r
#########################################################\r
## Profile and preferences functions\r
#########################################################\r
\r
+## Profile functions\r
def getDefaultProfilePath():\r
return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../current_profile.ini"))\r
\r
\r
p = []\r
alt = []\r
- for key in globalProfileParser.options('profile'):\r
- p.append(key + "=" + globalProfileParser.get('profile', key))\r
- for key in globalProfileParser.options('alterations'):\r
- alt.append(key + "=" + globalProfileParser.get('alterations', key))\r
+ tempDone = []\r
+ if globalProfileParser.has_section('profile'):\r
+ for key in globalProfileParser.options('profile'):\r
+ if key in tempOverride:\r
+ p.append(key + "=" + unicode(tempOverride[key]))\r
+ tempDone.append(key)\r
+ else:\r
+ p.append(key + "=" + globalProfileParser.get('profile', key))\r
+ if globalProfileParser.has_section('alterations'):\r
+ for key in globalProfileParser.options('alterations'):\r
+ if key in tempOverride:\r
+ p.append(key + "=" + tempOverride[key])\r
+ tempDone.append(key)\r
+ else:\r
+ alt.append(key + "=" + globalProfileParser.get('alterations', key))\r
+ for key in tempOverride:\r
+ if key not in tempDone:\r
+ p.append(key + "=" + unicode(tempOverride[key]))\r
ret = '\b'.join(p) + '\f' + '\b'.join(alt)\r
ret = base64.b64encode(zlib.compress(ret, 9))\r
return ret\r
\r
def getProfileSetting(name):\r
+ if name in tempOverride:\r
+ return unicode(tempOverride[name])\r
#Check if we have a configuration file loaded, else load the default.\r
if not globals().has_key('globalProfileParser'):\r
loadGlobalProfile(getDefaultProfilePath())\r
globalProfileParser.add_section('profile')\r
globalProfileParser.set('profile', name, str(value))\r
\r
+def isProfileSetting(name):\r
+ if name in profileDefaultSettings:\r
+ return True\r
+ return False\r
+\r
+## Preferences functions\r
global globalPreferenceParser\r
globalPreferenceParser = None\r
\r
def getPreferencePath():\r
return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../preferences.ini"))\r
\r
+def getPreferenceFloat(name):\r
+ try:\r
+ return float(eval(getPreference(name), {}, {}))\r
+ except (ValueError, SyntaxError):\r
+ return 0.0\r
+\r
def getPreference(name):\r
+ if name in tempOverride:\r
+ return unicode(tempOverride[name])\r
global globalPreferenceParser\r
if globalPreferenceParser == None:\r
globalPreferenceParser = ConfigParser.ConfigParser()\r
globalPreferenceParser.set('preference', name, unicode(value).encode("utf-8"))\r
globalPreferenceParser.write(open(getPreferencePath(), 'w'))\r
\r
+def isPreference(name):\r
+ if name in preferencesDefaultSettings:\r
+ return True\r
+ return False\r
+\r
+## Temp overrides for multi-extruder slicing and the project planner.\r
+tempOverride = {}\r
+def setTempOverride(name, value):\r
+ tempOverride[name] = value\r
+def resetTempOverride():\r
+ tempOverride.clear()\r
+\r
#########################################################\r
## Utility functions to calculate common profile values\r
#########################################################\r
tag = m.group(0)[1:-1]\r
if tag in ['print_speed', 'retraction_speed', 'travel_speed', 'max_z_speed', 'bottom_layer_speed', 'cool_min_feedrate']:\r
return str(getProfileSettingFloat(tag) * 60)\r
- return str(getProfileSettingFloat(tag))\r
+ if isProfileSetting(tag):\r
+ return str(getProfileSettingFloat(tag))\r
+ if isPreference(tag):\r
+ return str(getProfileSettingFloat(tag))\r
+ return tag\r
\r
### Get aleration raw contents. (Used internally in Cura)\r
def getAlterationFile(filename):\r
if filename == 'start.gcode':\r
#For the start code, hack the temperature and the steps per E value into it. So the temperature is reached before the start code extrusion.\r
#We also set our steps per E here, if configured.\r
- eSteps = float(getPreference('steps_per_e'))\r
+ eSteps = getPreferenceFloat('steps_per_e')\r
if eSteps > 0:\r
prefix += 'M92 E%f\n' % (eSteps)\r
temp = getProfileSettingFloat('print_temperature')\r
from cura_sf.skeinforge_application.skeinforge_utilities import skeinforge_craft
from util import profile
+#How long does each step take compared to the others. This is used to make a better scaled progress bar, and guess time left.
+sliceStepTimeFactor = {
+ 'start': 3.3713991642,
+ 'slice': 15.4984838963,
+ 'preface': 5.17178297043,
+ 'inset': 116.362634182,
+ 'fill': 215.702672005,
+ 'multiply': 21.9536788464,
+ 'speed': 12.759510994,
+ 'raft': 31.4580039978,
+ 'skirt': 19.3436040878,
+ 'skin': 1.0,
+ 'joris': 1.0,
+ 'comb': 23.7805759907,
+ 'cool': 27.148763895,
+ 'dimension': 90.4914340973
+}
+
+totalRunTimeFactor = 0
+for v in sliceStepTimeFactor.itervalues():
+ totalRunTimeFactor += v
+
def getPyPyExe():
"Return the path to the pypy executable if we can find it. Else return False"
if platform.system() == "Windows":
from util import util3d
-class stlFace():
+class stlFace(object):
def __init__(self, v0, v1, v2):
self.v = [v0, v1, v2]
-class stlModel():
+class stlModel(object):
def __init__(self):
self.faces = []
self.vertexes = []
import math
-class Vector3():
+class Vector3(object):
def __init__(self, x=0.0, y=0.0, z=0.0):
self.x = x
self.y = y