Merge branch 'master' of github.com:daid/Cura

Conflicts:
	Cura/gui/sliceProgessPanel.py
This commit is contained in:
Daid 2012-05-05 00:10:37 +02:00
commit 1b6cb8913c
27 changed files with 726 additions and 374 deletions

View File

@ -824,7 +824,7 @@ class TriangleMesh( group.Group ):
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))

View File

@ -113,6 +113,9 @@ def getProfileInformation():
'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,
@ -171,7 +174,7 @@ def getProfileInformation():
'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'),

View File

@ -185,8 +185,11 @@ class CarveRepository:
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):
@ -219,16 +222,6 @@ class CarveSkein:
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
@ -242,6 +235,34 @@ class CarveSkein:
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)

View File

@ -223,6 +223,8 @@ class CoolSkein:
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)
@ -404,9 +406,10 @@ class CoolSkein:
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.'

View File

@ -171,6 +171,8 @@ class SkirtSkein:
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

View File

@ -1,6 +1,7 @@
import wx
import sys,math,threading,os
from gui import gcodeTextArea
from util import profile
class alterationPanel(wx.Panel):
@ -10,8 +11,9 @@ class alterationPanel(wx.Panel):
self.alterationFileList = ['start.gcode', 'end.gcode', 'support_start.gcode', 'support_end.gcode', 'nextobject.gcode', 'replace.csv']
self.currentFile = None
self.textArea = wx.TextCtrl(self, style=wx.TE_MULTILINE|wx.TE_DONTWRAP|wx.TE_PROCESS_TAB)
self.textArea.SetFont(wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
#self.textArea = wx.TextCtrl(self, style=wx.TE_MULTILINE|wx.TE_DONTWRAP|wx.TE_PROCESS_TAB)
#self.textArea.SetFont(wx.Font(wx.SystemSettings.GetFont(wx.SYS_ANSI_VAR_FONT).GetPointSize(), wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
self.textArea = gcodeTextArea.GcodeTextArea(self)
self.list = wx.ListBox(self, choices=self.alterationFileList, style=wx.LB_SINGLE)
self.list.SetSelection(0)
self.Bind(wx.EVT_LISTBOX, self.OnSelect, self.list)

103
Cura/gui/gcodeTextArea.py Normal file
View File

@ -0,0 +1,103 @@
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)

View File

@ -86,6 +86,7 @@ class mainWindow(configBase.configWindowBase):
if profile.getPreference('lastFile') != '':
self.filelist = profile.getPreference('lastFile').split(';')
self.SetTitle(self.filelist[-1] + ' - Cura - ' + version.getVersion())
else:
self.filelist = []
self.progressPanelList = []
@ -299,6 +300,7 @@ class mainWindow(configBase.configWindowBase):
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)

View File

@ -17,7 +17,9 @@ def InitGL(window, view3D, zoom):
glViewport(0,0, size.GetWidth(), size.GetHeight())
glLightfv(GL_LIGHT0, GL_POSITION, [1.0, 1.0, 1.0, 0.0])
glLightfv(GL_LIGHT1, GL_POSITION, [1.0, 1.0, 1.0, 0.0])
glEnable(GL_NORMALIZE)
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_DEPTH_TEST)
@ -198,6 +200,7 @@ def DrawBox(vMin, vMax):
glEnd()
def DrawSTL(mesh):
glEnable(GL_CULL_FACE)
for face in mesh.faces:
glBegin(GL_TRIANGLES)
v1 = face.v[0]

View File

@ -7,6 +7,7 @@ import ConfigParser
from gui import configBase
from gui import validators
from gui import machineCom
from util import profile
class preferencesDialog(configBase.configWindowBase):
def __init__(self, parent):
@ -14,6 +15,8 @@ class preferencesDialog(configBase.configWindowBase):
wx.EVT_CLOSE(self, self.OnClose)
self.oldExtruderAmount = int(profile.getPreference('extruder_amount'))
left, right, main = self.CreateConfigPanel(self)
configBase.TitleRow(left, 'Machine settings')
c = configBase.SettingRow(left, 'Steps per E', 'steps_per_e', '0', 'Amount of steps per mm filament extrusion', type = 'preference')
@ -25,6 +28,13 @@ class preferencesDialog(configBase.configWindowBase):
c = configBase.SettingRow(left, 'Machine height (mm)', 'machine_height', '200', 'Size of the machine in mm', type = 'preference')
validators.validFloat(c, 10.0)
c = configBase.SettingRow(left, 'Extruder count', 'extruder_amount', ['1', '2', '3', '4'], 'Amount of extruders in your machine.', type = 'preference')
for i in xrange(1, self.oldExtruderAmount):
configBase.TitleRow(left, 'Extruder %d' % (i+1))
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')
validators.validFloat(c)
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')
validators.validFloat(c)
configBase.TitleRow(left, 'Filament settings')
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')
@ -42,10 +52,16 @@ class preferencesDialog(configBase.configWindowBase):
#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')
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')
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):
if self.oldExtruderAmount != int(profile.getPreference('extruder_amount')):
wx.MessageBox('After changing the amount of extruders you need to restart Cura for full effect.', 'Extruder amount warning.', wx.OK | wx.ICON_INFORMATION)
self.MakeModal(False)
self.Destroy()

View File

@ -1,11 +1,6 @@
from __future__ import division
import sys
import math
import threading
import re
import time
import os
import sys, math, threading, re, time, os
from wx import glcanvas
import wx
@ -43,11 +38,12 @@ class previewPanel(wx.Panel):
self.glCanvas = PreviewGLCanvas(self)
self.objectList = []
self.errorList = []
self.gcode = None
self.objectsMinV = None
self.objectsMaxV = None
self.loadThread = None
self.machineSize = util3d.Vector3(float(profile.getPreference('machine_width')), float(profile.getPreference('machine_depth')), float(profile.getPreference('machine_height')))
self.machineSize = util3d.Vector3(profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height'))
self.machineCenter = util3d.Vector3(float(profile.getProfileSetting('machine_center_x')), float(profile.getProfileSetting('machine_center_y')), 0)
self.toolbar = toolbarUtil.Toolbar(self)
@ -63,7 +59,6 @@ class previewPanel(wx.Panel):
self.xrayViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-xray-on.png', 'view-xray-off.png', 'X-Ray view', callback=self.OnViewChange)
self.gcodeViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-gcode-on.png', 'view-gcode-off.png', 'GCode view', callback=self.OnViewChange)
self.mixedViewButton = toolbarUtil.RadioButton(self.toolbar, group, 'view-mixed-on.png', 'view-mixed-off.png', 'Mixed model/GCode view', callback=self.OnViewChange)
self.OnViewChange()
self.toolbar.AddSeparator()
self.layerSpin = wx.SpinCtrl(self.toolbar, -1, '', size=(21*4,21), style=wx.SP_ARROW_KEYS)
@ -93,22 +88,21 @@ class previewPanel(wx.Panel):
self.toolbar2.AddSeparator()
# Multiply
self.mulXadd = toolbarUtil.NormalButton(self.toolbar2, self.OnMulXAddClick, 'object-mul-x-add.png', 'Increase number of models on X axis')
self.mulXsub = toolbarUtil.NormalButton(self.toolbar2, self.OnMulXSubClick, 'object-mul-x-sub.png', 'Decrease number of models on X axis')
self.mulYadd = toolbarUtil.NormalButton(self.toolbar2, self.OnMulYAddClick, 'object-mul-y-add.png', 'Increase number of models on Y axis')
self.mulYsub = toolbarUtil.NormalButton(self.toolbar2, self.OnMulYSubClick, 'object-mul-y-sub.png', 'Decrease number of models on Y axis')
self.toolbar2.AddSeparator()
#self.mulXadd = toolbarUtil.NormalButton(self.toolbar2, self.OnMulXAddClick, 'object-mul-x-add.png', 'Increase number of models on X axis')
#self.mulXsub = toolbarUtil.NormalButton(self.toolbar2, self.OnMulXSubClick, 'object-mul-x-sub.png', 'Decrease number of models on X axis')
#self.mulYadd = toolbarUtil.NormalButton(self.toolbar2, self.OnMulYAddClick, 'object-mul-y-add.png', 'Increase number of models on Y axis')
#self.mulYsub = toolbarUtil.NormalButton(self.toolbar2, self.OnMulYSubClick, 'object-mul-y-sub.png', 'Decrease number of models on Y axis')
#self.toolbar2.AddSeparator()
# Rotate
self.rotateReset = toolbarUtil.NormalButton(self.toolbar2, self.OnRotateReset, 'object-rotate.png', 'Reset model rotation')
self.rotate = wx.SpinCtrl(self.toolbar2, -1, profile.getProfileSetting('model_rotate_base'), size=(21*3,21), style=wx.SP_WRAP|wx.SP_ARROW_KEYS)
self.rotate.SetRange(0, 360)
self.Bind(wx.EVT_TEXT, self.OnRotate)
self.rotate.Bind(wx.EVT_TEXT, self.OnRotate)
self.toolbar2.AddControl(self.rotate)
self.toolbar2.Realize()
self.updateToolbar()
self.OnViewChange()
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.toolbar, 0, flag=wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, border=1)
@ -181,7 +175,6 @@ class previewPanel(wx.Panel):
self.glCanvas.Refresh()
def OnLayerNrChange(self, e):
self.gcodeDirty = True
self.glCanvas.Refresh()
def updateCenterX(self):
@ -203,8 +196,9 @@ class previewPanel(wx.Panel):
def loadModelFiles(self, filelist):
while len(filelist) > len(self.objectList):
self.objectList.append(previewObject())
for idx in xrange(len(self.objectList), len(filelist)):
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]:
@ -232,12 +226,11 @@ class previewPanel(wx.Panel):
def doFileLoadThread(self):
for obj in self.objectList:
if os.path.isfile(obj.filename) and obj.fileTime != os.stat(obj.filename).st_mtime:
if obj.filename != None and os.path.isfile(obj.filename) and obj.fileTime != os.stat(obj.filename).st_mtime:
obj.ileTime = os.stat(obj.filename).st_mtime
mesh = stl.stlModel()
mesh.load(obj.filename)
obj.dirty = False
obj.errorList = []
obj.mesh = mesh
self.updateModelTransform()
wx.CallAfter(self.updateToolbar)
@ -272,9 +265,11 @@ class previewPanel(wx.Panel):
pass
def updateToolbar(self):
self.layerSpin.Show(self.gcode != None)
self.gcodeViewButton.Show(self.gcode != None)
self.mixedViewButton.Show(self.gcode != None)
self.layerSpin.Show(self.glCanvas.viewMode == "GCode" or self.glCanvas.viewMode == "Mixed")
if self.gcode != None:
self.layerSpin.SetRange(1, len(self.gcode.layerList))
self.layerSpin.SetRange(1, len(self.gcode.layerList) - 1)
self.toolbar.Realize()
def OnViewChange(self):
@ -288,6 +283,7 @@ class previewPanel(wx.Panel):
self.glCanvas.viewMode = "GCode"
elif self.mixedViewButton.GetValue():
self.glCanvas.viewMode = "Mixed"
self.updateToolbar()
self.glCanvas.Refresh()
def updateModelTransform(self, f=0):
@ -376,6 +372,7 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
self.offsetY = 0
self.view3D = True
self.gcodeDisplayList = None
self.gcodeDisplayListCount = 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]]
def OnMouseMotion(self,e):
@ -424,8 +421,12 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
glTranslate(0,0,-self.zoom)
glRotate(-self.pitch, 1,0,0)
glRotate(self.yaw, 0,0,1)
if self.parent.objectsMaxV != None:
glTranslate(0,0,-self.parent.objectsMaxV.z * profile.getProfileSettingFloat('model_scale') / 2)
if self.viewMode == "GCode" or self.viewMode == "Mixed":
if self.parent.gcode != None:
glTranslate(0,0,-self.parent.gcode.layerList[self.parent.layerSpin.GetValue()][0].list[-1].z)
else:
if self.parent.objectsMaxV != None:
glTranslate(0,0,-self.parent.objectsMaxV.z * profile.getProfileSettingFloat('model_scale') / 2)
else:
glScale(1.0/self.zoom, 1.0/self.zoom, 1.0)
glTranslate(self.offsetX, self.offsetY, 0.0)
@ -438,99 +439,113 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
machineSize = self.parent.machineSize
opengl.DrawMachine(machineSize)
if self.parent.gcode != None:
if self.gcodeDisplayList == None:
self.gcodeDisplayList = glGenLists(1);
if self.parent.gcodeDirty:
self.parent.gcodeDirty = False
glNewList(self.gcodeDisplayList, GL_COMPILE)
prevLayerZ = 0.0
curLayerZ = 0.0
layerThickness = 0.0
filamentRadius = float(profile.getProfileSetting('filament_diameter')) / 2
filamentArea = math.pi * filamentRadius * filamentRadius
lineWidth = float(profile.getProfileSetting('nozzle_size')) / 2 / 10
curLayerNum = 0
for layer in self.parent.gcode.layerList:
curLayerZ = layer[0].list[1].z
layerThickness = curLayerZ - prevLayerZ
prevLayerZ = layer[-1].list[-1].z
for path in layer:
c = 1.0
if curLayerNum != self.parent.layerSpin.GetValue():
if curLayerNum < self.parent.layerSpin.GetValue():
c = 0.9 - (self.parent.layerSpin.GetValue() - curLayerNum) * 0.1
if c < 0.4:
c = 0.4
else:
break
if path.type == 'move':
glColor3f(0,0,c)
if path.type == 'extrude':
if path.pathType == 'FILL':
glColor3f(c/2,c/2,0)
elif path.pathType == 'WALL-INNER':
glColor3f(0,c,0)
elif path.pathType == 'SUPPORT':
glColor3f(0,c,c)
elif path.pathType == 'SKIRT':
glColor3f(0,c/2,c/2)
else:
glColor3f(c,0,0)
if path.type == 'retract':
glColor3f(0,c,c)
if c > 0.4 and path.type == 'extrude':
for i in xrange(0, len(path.list)-1):
v0 = path.list[i]
v1 = path.list[i+1]
# Calculate line width from ePerDistance (needs layer thickness and filament diameter)
dist = (v0 - v1).vsize()
if dist > 0 and layerThickness > 0:
extrusionMMperDist = (v1.e - v0.e) / dist
lineWidth = extrusionMMperDist * filamentArea / layerThickness / 2
normal = (v0 - v1).cross(util3d.Vector3(0,0,1))
normal.normalize()
v2 = v0 + normal * lineWidth
v3 = v1 + normal * lineWidth
v0 = v0 - normal * lineWidth
v1 = v1 - normal * lineWidth
glBegin(GL_QUADS)
if path.pathType == 'FILL': #Remove depth buffer fighting on infill/wall overlap
glVertex3f(v0.x, v0.y, v0.z - 0.02)
glVertex3f(v1.x, v1.y, v1.z - 0.02)
glVertex3f(v3.x, v3.y, v3.z - 0.02)
glVertex3f(v2.x, v2.y, v2.z - 0.02)
else:
glVertex3f(v0.x, v0.y, v0.z - 0.01)
glVertex3f(v1.x, v1.y, v1.z - 0.01)
glVertex3f(v3.x, v3.y, v3.z - 0.01)
glVertex3f(v2.x, v2.y, v2.z - 0.01)
glEnd()
#for v in path['list']:
# glBegin(GL_TRIANGLE_FAN)
# glVertex3f(v.x, v.y, v.z - 0.001)
# for i in xrange(0, 16+1):
# if path['pathType'] == 'FILL': #Remove depth buffer fighting on infill/wall overlap
# 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)
# else:
# 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)
# glEnd()
if self.parent.gcode != None and self.parent.gcodeDirty:
if self.gcodeDisplayListCount < len(self.parent.gcode.layerList) or self.gcodeDisplayList == None:
if self.gcodeDisplayList != None:
glDeleteLists(self.gcodeDisplayList, self.gcodeDisplayListCount)
self.gcodeDisplayList = glGenLists(len(self.parent.gcode.layerList));
self.gcodeDisplayListCount = len(self.parent.gcode.layerList)
self.parent.gcodeDirty = False
prevLayerZ = 0.0
curLayerZ = 0.0
layerThickness = 0.0
filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
filamentArea = math.pi * filamentRadius * filamentRadius
lineWidth = profile.getProfileSettingFloat('nozzle_size') / 2 / 10
curLayerNum = 0
for layer in self.parent.gcode.layerList:
glNewList(self.gcodeDisplayList + curLayerNum, GL_COMPILE)
glDisable(GL_CULL_FACE)
curLayerZ = layer[0].list[1].z
layerThickness = curLayerZ - prevLayerZ
prevLayerZ = layer[-1].list[-1].z
for path in layer:
if path.type == 'move':
glColor3f(0,0,1)
if path.type == 'extrude':
if path.pathType == 'FILL':
glColor3f(0.5,0.5,0)
elif path.pathType == 'WALL-INNER':
glColor3f(0,1,0)
elif path.pathType == 'SUPPORT':
glColor3f(0,1,1)
elif path.pathType == 'SKIRT':
glColor3f(0,0.5,0.5)
else:
glBegin(GL_LINE_STRIP)
for v in path.list:
glVertex3f(v.x, v.y, v.z)
glColor3f(1,0,0)
if path.type == 'retract':
glColor3f(0,1,1)
if path.type == 'extrude':
for i in xrange(0, len(path.list)-1):
v0 = path.list[i]
v1 = path.list[i+1]
# Calculate line width from ePerDistance (needs layer thickness and filament diameter)
dist = (v0 - v1).vsize()
if dist > 0 and layerThickness > 0:
extrusionMMperDist = (v1.e - v0.e) / dist
lineWidth = extrusionMMperDist * filamentArea / layerThickness / 2
normal = (v0 - v1).cross(util3d.Vector3(0,0,1))
normal.normalize()
v2 = v0 + normal * lineWidth
v3 = v1 + normal * lineWidth
v0 = v0 - normal * lineWidth
v1 = v1 - normal * lineWidth
glBegin(GL_QUADS)
if path.pathType == 'FILL': #Remove depth buffer fighting on infill/wall overlap
glVertex3f(v0.x, v0.y, v0.z - 0.02)
glVertex3f(v1.x, v1.y, v1.z - 0.02)
glVertex3f(v3.x, v3.y, v3.z - 0.02)
glVertex3f(v2.x, v2.y, v2.z - 0.02)
else:
glVertex3f(v0.x, v0.y, v0.z - 0.01)
glVertex3f(v1.x, v1.y, v1.z - 0.01)
glVertex3f(v3.x, v3.y, v3.z - 0.01)
glVertex3f(v2.x, v2.y, v2.z - 0.01)
glEnd()
curLayerNum += 1
#for v in path['list']:
# glBegin(GL_TRIANGLE_FAN)
# glVertex3f(v.x, v.y, v.z - 0.001)
# for i in xrange(0, 16+1):
# if path['pathType'] == 'FILL': #Remove depth buffer fighting on infill/wall overlap
# 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)
# else:
# 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)
# glEnd()
else:
glBegin(GL_LINE_STRIP)
for v in path.list:
glVertex3f(v.x, v.y, v.z)
glEnd()
curLayerNum += 1
glEnable(GL_CULL_FACE)
glEndList()
if self.viewMode == "GCode" or self.viewMode == "Mixed":
glCallList(self.gcodeDisplayList)
if self.parent.gcode != None and (self.viewMode == "GCode" or self.viewMode == "Mixed"):
glEnable(GL_COLOR_MATERIAL)
glEnable(GL_LIGHTING)
for i in xrange(0, self.parent.layerSpin.GetValue() + 1):
c = 1.0
if i < self.parent.layerSpin.GetValue():
c = 0.9 - (self.parent.layerSpin.GetValue() - 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])
glCallList(self.gcodeDisplayList + 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]);
glColor3f(1.0,1.0,1.0)
glTranslate(self.parent.machineCenter.x, self.parent.machineCenter.y, 0)
for obj in self.parent.objectList:
if obj.mesh == None:
@ -543,17 +558,15 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
opengl.DrawSTL(obj.mesh)
glEndList()
glEnable(GL_NORMALIZE)
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)
glDisable(GL_LIGHTING)
glColor3f(0,0,0)
glColor3f(0.0,0.0,0.0)
self.drawModel(obj)
glColor3f(1,1,1)
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)
@ -608,22 +621,22 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
glEnable(GL_LIGHTING)
self.drawModel(obj)
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)
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)
glFlush()
def drawModel(self, obj):
multiX = int(profile.getProfileSetting('model_multiply_x'))
multiY = int(profile.getProfileSetting('model_multiply_y'))
multiX = 1 #int(profile.getProfileSetting('model_multiply_x'))
multiY = 1 #int(profile.getProfileSetting('model_multiply_y'))
modelScale = profile.getProfileSettingFloat('model_scale')
modelSize = (obj.mesh.getMaximum() - obj.mesh.getMinimum()) * modelScale
glPushMatrix()

View File

@ -176,14 +176,9 @@ class printWindow(wx.Frame):
status = ""
if self.gcode != None:
status += "Filament: %.2fm %.2fg\n" % (self.gcode.extrusionAmount / 1000, self.gcode.calculateWeight() * 1000)
cost_kg = float(profile.getPreference('filament_cost_kg'))
cost_meter = float(profile.getPreference('filament_cost_meter'))
if cost_kg > 0.0 and cost_meter > 0.0:
status += "Filament cost: %.2f / %.2f\n" % (self.gcode.calculateWeight() * cost_kg, self.gcode.extrusionAmount / 1000 * cost_meter)
elif cost_kg > 0.0:
status += "Filament cost: %.2f\n" % (self.gcode.calculateWeight() * cost_kg)
elif cost_meter > 0.0:
status += "Filament cost: %.2f\n" % (self.gcode.extrusionAmount / 1000 * cost_meter)
cost = self.gcode.calculateCost()
if cost != False:
status += "Filament cost: %s\n" % (cost)
status += "Print time: %02d:%02d\n" % (int(self.gcode.totalMoveTimeMinute / 60), int(self.gcode.totalMoveTimeMinute % 60))
if self.printIdx == None:
self.progress.SetValue(0)

View File

@ -23,10 +23,110 @@ from util import profile
from util import util3d
from util import stl
from util import sliceRun
from util import gcodeInterpreter
class Action():
class Action(object):
pass
class ProjectObject(stl.stlModel):
def __init__(self, filename):
super(ProjectObject, self).__init__()
self.load(filename)
self.filename = filename
self.scale = 1.0
self.rotate = 0.0
self.flipX = False
self.flipY = False
self.flipZ = False
self.swapXZ = False
self.swapYZ = False
self.extruder = 0
self.modelDisplayList = None
self.modelDirty = False
self.origonalVertexes = list(self.vertexes)
for i in xrange(0, len(self.origonalVertexes)):
self.origonalVertexes[i] = self.origonalVertexes[i].copy()
self.getMinimumZ()
self.centerX = -self.getMinimum().x + 5
self.centerY = -self.getMinimum().y + 5
self.updateModelTransform()
self.centerX = -self.getMinimum().x + 5
self.centerY = -self.getMinimum().y + 5
def updateModelTransform(self):
rotate = self.rotate / 180.0 * math.pi
scaleX = 1.0
scaleY = 1.0
scaleZ = 1.0
if self.flipX:
scaleX = -scaleX
if self.flipY:
scaleY = -scaleY
if self.flipZ:
scaleZ = -scaleZ
swapXZ = self.swapXZ
swapYZ = self.swapYZ
mat00 = math.cos(rotate) * scaleX
mat01 =-math.sin(rotate) * scaleY
mat10 = math.sin(rotate) * scaleX
mat11 = math.cos(rotate) * scaleY
for i in xrange(0, len(self.origonalVertexes)):
x = self.origonalVertexes[i].x
y = self.origonalVertexes[i].y
z = self.origonalVertexes[i].z
if swapXZ:
x, z = z, x
if swapYZ:
y, z = z, y
self.vertexes[i].x = x * mat00 + y * mat01
self.vertexes[i].y = x * mat10 + y * mat11
self.vertexes[i].z = z * scaleZ
for face in self.faces:
v1 = face.v[0]
v2 = face.v[1]
v3 = face.v[2]
face.normal = (v2 - v1).cross(v3 - v1)
face.normal.normalize()
minZ = self.getMinimumZ()
minV = self.getMinimum()
maxV = self.getMaximum()
for v in self.vertexes:
v.z -= minZ
v.x -= minV.x + (maxV.x - minV.x) / 2
v.y -= minV.y + (maxV.y - minV.y) / 2
self.getMinimumZ()
self.modelDirty = True
def clone(self):
p = ProjectObject(self.filename)
p.centerX = self.centerX + 5
p.centerY = self.centerY + 5
p.filename = self.filename
p.scale = self.scale
p.rotate = self.rotate
p.flipX = self.flipX
p.flipY = self.flipY
p.flipZ = self.flipZ
p.swapXZ = self.swapXZ
p.swapYZ = self.swapYZ
p.extruder = self.extruder
p.updateModelTransform()
return p
class projectPlanner(wx.Frame):
"Main user interface window"
def __init__(self):
@ -39,9 +139,15 @@ class projectPlanner(wx.Frame):
self.list = []
self.selection = None
self.machineSize = util3d.Vector3(float(profile.getPreference('machine_width')), float(profile.getPreference('machine_depth')), float(profile.getPreference('machine_height')))
self.headSizeMin = util3d.Vector3(70,16,0)
self.headSizeMax = util3d.Vector3(16,35,0)
self.machineSize = util3d.Vector3(profile.getPreferenceFloat('machine_width'), profile.getPreferenceFloat('machine_depth'), profile.getPreferenceFloat('machine_height'))
self.headSizeMin = util3d.Vector3(profile.getPreferenceFloat('extruder_head_size_min_x'), profile.getPreferenceFloat('extruder_head_size_min_y'),0)
self.headSizeMax = util3d.Vector3(profile.getPreferenceFloat('extruder_head_size_max_x'), profile.getPreferenceFloat('extruder_head_size_max_y'),0)
self.extruderOffset = [
util3d.Vector3(0,0,0),
util3d.Vector3(profile.getPreferenceFloat('extruder_offset_x1'), profile.getPreferenceFloat('extruder_offset_y1'), 0),
util3d.Vector3(profile.getPreferenceFloat('extruder_offset_x2'), profile.getPreferenceFloat('extruder_offset_y2'), 0),
util3d.Vector3(profile.getPreferenceFloat('extruder_offset_x3'), profile.getPreferenceFloat('extruder_offset_y3'), 0)]
self.toolbar = toolbarUtil.Toolbar(self)
@ -55,6 +161,14 @@ class projectPlanner(wx.Frame):
toolbarUtil.NormalButton(self.toolbar, self.OnQuit, 'exit.png', 'Close project planner')
self.toolbar.Realize()
self.toolbar2 = toolbarUtil.Toolbar(self)
toolbarUtil.NormalButton(self.toolbar2, self.OnAddModel, 'object-add.png', 'Add model')
toolbarUtil.NormalButton(self.toolbar2, self.OnRemModel, 'object-remove.png', 'Remove model')
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')
self.toolbar2.Realize()
sizer = wx.GridBagSizer(2,2)
self.SetSizer(sizer)
@ -65,7 +179,8 @@ class projectPlanner(wx.Frame):
self.sliceButton = wx.Button(self, -1, "Slice")
self.autoPlaceButton = wx.Button(self, -1, "Auto Place")
sizer.Add(self.toolbar, (0,0), span=(1,3), flag=wx.EXPAND)
sizer.Add(self.toolbar, (0,0), span=(1,1), flag=wx.EXPAND)
sizer.Add(self.toolbar2, (0,1), span=(1,2), flag=wx.EXPAND)
sizer.Add(self.preview, (1,0), span=(4,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))
@ -95,6 +210,12 @@ class projectPlanner(wx.Frame):
sizer.Add(self.scaleCtrl, (0,1), flag=wx.ALIGN_BOTTOM|wx.EXPAND)
sizer.Add(wx.StaticText(panel, -1, 'Rotate'), (1,0), flag=wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.rotateCtrl, (1,1), flag=wx.ALIGN_BOTTOM|wx.EXPAND)
if int(profile.getPreference('extruder_amount')) > 1:
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)
sizer.Add(wx.StaticText(panel, -1, 'Extruder'), (2,0), flag=wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.extruderCtrl, (2,1), flag=wx.ALIGN_BOTTOM|wx.EXPAND)
self.extruderCtrl.Bind(wx.EVT_COMBOBOX, self.OnExtruderChange)
self.scaleCtrl.Bind(wx.EVT_TEXT, self.OnScaleChange)
self.rotateCtrl.Bind(wx.EVT_SPINCTRL, self.OnRotateChange)
@ -126,6 +247,7 @@ class projectPlanner(wx.Frame):
cp.set(section, 'flipZ', str(item.flipZ))
cp.set(section, 'swapXZ', str(item.swapXZ))
cp.set(section, 'swapYZ', str(item.swapYZ))
cp.set(section, 'extruder', str(item.extruder+1))
i += 1
cp.write(open(dlg.GetPath(), "w"))
dlg.Destroy()
@ -142,18 +264,19 @@ class projectPlanner(wx.Frame):
while cp.has_section('model_%d' % (i)):
section = 'model_%d' % (i)
item = stl.stlModel()
item.filename = unicode(cp.get(section, 'filename'), "utf-8")
self.loadModelFile(item)
item = ProjectObject(unicode(cp.get(section, 'filename'), "utf-8"))
item.centerX = float(cp.get(section, 'centerX'))
item.centerY = float(cp.get(section, 'centerY'))
item.scale = float(cp.get(section, 'scale'))
item.rotate = float(cp.get(section, 'rotate'))
cp.get(section, 'flipX')
cp.get(section, 'flipY')
cp.get(section, 'flipZ')
cp.get(section, 'swapXZ')
cp.get(section, 'swapYZ')
item.flipX = cp.get(section, 'flipX') == 'True'
item.flipY = cp.get(section, 'flipY') == 'True'
item.flipZ = cp.get(section, 'flipZ') == 'True'
item.swapXZ = cp.get(section, 'swapXZ') == 'True'
item.swapYZ = cp.get(section, 'swapYZ') == 'True'
if cp.has_option(section, 'extruder'):
item.extuder = int(cp.get(section, 'extruder'))-1
item.updateModelTransform()
i += 1
self.list.append(item)
@ -161,6 +284,7 @@ class projectPlanner(wx.Frame):
self.listbox.SetSelection(len(self.list)-1)
self.OnListSelect(None)
self.preview.Refresh()
dlg.Destroy()
@ -184,39 +308,76 @@ class projectPlanner(wx.Frame):
self.selection = self.list[self.listbox.GetSelection()]
self.scaleCtrl.SetValue(str(self.selection.scale))
self.rotateCtrl.SetValue(int(self.selection.rotate))
if int(profile.getPreference('extruder_amount')) > 1:
self.extruderCtrl.SetValue(str(self.selection.extruder+1))
self.preview.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("STL files (*.stl)|*.stl;*.STL")
if dlg.ShowModal() == wx.ID_OK:
for filename in dlg.GetPaths():
item = stl.stlModel()
item.filename=filename
item = ProjectObject(filename)
profile.putPreference('lastFile', item.filename)
if not(os.path.exists(item.filename)):
return
self.loadModelFile(item)
self.list.append(item)
self.listbox.AppendAndEnsureVisible(os.path.split(item.filename)[1])
self.listbox.SetSelection(len(self.list)-1)
self.OnListSelect(None)
self.selection = item
self._updateListbox()
self.preview.Refresh()
dlg.Destroy()
def OnRemModel(self, e):
if self.selection == None:
return
self.list.remove(self.selection)
i = self.listbox.GetSelection()
self.listbox.Delete(i)
if len(self.list) > i:
self.listbox.SetSelection(i)
elif len(self.list) > 0:
self.listbox.SetSelection(len(self.list) - 1)
self.selection = None
self.OnListSelect(None)
self._updateListbox()
self.preview.Refresh()
def OnMoveUp(self, e):
if self.selection == 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.preview.Refresh()
def OnMoveDown(self, e):
if self.selection == 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.preview.Refresh()
def OnCopy(self, e):
if self.selection == None:
return
item = self.selection.clone()
self.list.append(item)
self.selection = item
self._updateListbox()
self.preview.Refresh()
def _updateListbox(self):
self.listbox.Clear()
for item in self.list:
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)
def OnAutoPlace(self, e):
bestAllowedSize = int(self.machineSize.y)
bestArea = self._doAutoPlace(bestAllowedSize)
@ -233,7 +394,7 @@ class projectPlanner(wx.Frame):
extraSizeMax = self.headSizeMax
if profile.getProfileSettingFloat('skirt_line_count') > 0:
skirtSize = profile.getProfileSettingFloat('skirt_line_count') * profile.calculateEdgeWidth() + profile.getProfileSettingFloat('skirt_gap')
extraSizeMin = extraSizeMin - util3d.Vector3(skirtSize, skirtSize, 0)
extraSizeMin = extraSizeMin + util3d.Vector3(skirtSize, skirtSize, 0)
extraSizeMax = extraSizeMax + util3d.Vector3(skirtSize, skirtSize, 0)
posX = self.machineSize.x
@ -268,9 +429,7 @@ class projectPlanner(wx.Frame):
return (maxX - minX) + (maxY - minY)
def OnSlice(self, e):
oldProfile = profile.getGlobalProfileString()
put = profile.putProfileSetting
put = profile.setTempOverride
put('model_multiply_x', '1')
put('model_multiply_y', '1')
@ -281,8 +440,8 @@ class projectPlanner(wx.Frame):
clearZ = 0
actionList = []
for item in self.list:
put('machine_center_x', item.centerX)
put('machine_center_y', item.centerY)
put('machine_center_x', item.centerX - self.extruderOffset[item.extruder].x)
put('machine_center_y', item.centerY - self.extruderOffset[item.extruder].y)
put('model_scale', item.scale)
put('flip_x', item.flipX)
put('flip_y', item.flipY)
@ -295,13 +454,14 @@ class projectPlanner(wx.Frame):
action.sliceCmd = sliceRun.getSliceCommand(item.filename)
action.centerX = item.centerX
action.centerY = item.centerY
action.extruder = item.extruder
action.filename = item.filename
clearZ = max(clearZ, item.getMaximum().z * item.scale)
action.clearZ = clearZ
actionList.append(action)
#Restore the old profile.
profile.loadGlobalProfileFromString(oldProfile)
profile.resetTempOverride()
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")
@ -312,34 +472,10 @@ class projectPlanner(wx.Frame):
dlg.Destroy()
pspw = ProjectSliceProgressWindow(actionList, resultFilename)
pspw.extruderOffset = self.extruderOffset
pspw.Centre()
pspw.Show(True)
def loadModelFile(self, item):
item.load(item.filename)
item.origonalVertexes = list(item.vertexes)
for i in xrange(0, len(item.origonalVertexes)):
item.origonalVertexes[i] = item.origonalVertexes[i].copy()
item.getMinimumZ()
item.centerX = -item.getMinimum().x + 5
item.centerY = -item.getMinimum().y + 5
item.scale = 1.0
item.rotate = 0.0
item.flipX = False
item.flipY = False
item.flipZ = False
item.swapXZ = False
item.swapYZ = False
item.modelDisplayList = None
item.modelDirty = False
self.updateModelTransform(item)
item.centerX = -item.getMinimum().x + 5
item.centerY = -item.getMinimum().y + 5
def OnScaleChange(self, e):
if self.selection == None:
return
@ -353,57 +489,13 @@ class projectPlanner(wx.Frame):
if self.selection == None:
return
self.selection.rotate = float(self.rotateCtrl.GetValue())
self.updateModelTransform(self.selection)
self.selection.updateModelTransform()
self.preview.Refresh()
def updateModelTransform(self, item):
rotate = item.rotate / 180.0 * math.pi
scaleX = 1.0
scaleY = 1.0
scaleZ = 1.0
if item.flipX:
scaleX = -scaleX
if item.flipY:
scaleY = -scaleY
if item.flipZ:
scaleZ = -scaleZ
swapXZ = item.swapXZ
swapYZ = item.swapYZ
mat00 = math.cos(rotate) * scaleX
mat01 =-math.sin(rotate) * scaleY
mat10 = math.sin(rotate) * scaleX
mat11 = math.cos(rotate) * scaleY
for i in xrange(0, len(item.origonalVertexes)):
x = item.origonalVertexes[i].x
y = item.origonalVertexes[i].y
z = item.origonalVertexes[i].z
if swapXZ:
x, z = z, x
if swapYZ:
y, z = z, y
item.vertexes[i].x = x * mat00 + y * mat01
item.vertexes[i].y = x * mat10 + y * mat11
item.vertexes[i].z = z * scaleZ
for face in item.faces:
v1 = face.v[0]
v2 = face.v[1]
v3 = face.v[2]
face.normal = (v2 - v1).cross(v3 - v1)
face.normal.normalize()
self.moveModel(item)
def moveModel(self, item):
minZ = item.getMinimumZ()
min = item.getMinimum()
max = item.getMaximum()
for v in item.vertexes:
v.z -= minZ
v.x -= min.x + (max.x - min.x) / 2
v.y -= min.y + (max.y - min.y) / 2
item.getMinimumZ()
item.modelDirty = True
def OnExtruderChange(self, e):
if self.selection == None:
return
self.selection.extruder = int(self.extruderCtrl.GetValue()) - 1
self.preview.Refresh()
class PreviewGLCanvas(glcanvas.GLCanvas):
@ -445,14 +537,14 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
if item != 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
if item.centerX < -item.getMinimum().x * item.scale:
item.centerX = -item.getMinimum().x * item.scale
if item.centerY < -item.getMinimum().y * item.scale:
item.centerY = -item.getMinimum().y * item.scale
if item.centerX > self.parent.machineSize.x - item.getMaximum().x * item.scale:
item.centerX = self.parent.machineSize.x - item.getMaximum().x * item.scale
if item.centerY > self.parent.machineSize.y - item.getMaximum().y * item.scale:
item.centerY = self.parent.machineSize.y - item.getMaximum().y * item.scale
if item.centerX < -item.getMinimum().x * item.scale + self.parent.extruderOffset[item.extruder].x:
item.centerX = -item.getMinimum().x * item.scale + self.parent.extruderOffset[item.extruder].x
if item.centerY < -item.getMinimum().y * item.scale + self.parent.extruderOffset[item.extruder].y:
item.centerY = -item.getMinimum().y * item.scale + self.parent.extruderOffset[item.extruder].y
if item.centerX > self.parent.machineSize.x + self.parent.extruderOffset[item.extruder].x - item.getMaximum().x * item.scale:
item.centerX = self.parent.machineSize.x + self.parent.extruderOffset[item.extruder].x - item.getMaximum().x * item.scale
if item.centerY > self.parent.machineSize.y + self.parent.extruderOffset[item.extruder].y - item.getMaximum().y * item.scale:
item.centerY = self.parent.machineSize.y + self.parent.extruderOffset[item.extruder].y - item.getMaximum().y * item.scale
self.Refresh()
else:
self.allowDrag = False
@ -508,7 +600,7 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
extraSizeMax = self.parent.headSizeMax
if profile.getProfileSettingFloat('skirt_line_count') > 0:
skirtSize = profile.getProfileSettingFloat('skirt_line_count') * profile.calculateEdgeWidth() + profile.getProfileSettingFloat('skirt_gap')
extraSizeMin = extraSizeMin - util3d.Vector3(skirtSize, skirtSize, 0)
extraSizeMin = extraSizeMin + util3d.Vector3(skirtSize, skirtSize, 0)
extraSizeMax = extraSizeMax + util3d.Vector3(skirtSize, skirtSize, 0)
for item in self.parent.list:
@ -517,8 +609,8 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
for idx1 in xrange(0, len(self.parent.list)):
item = self.parent.list[idx1]
iMin1 = item.getMinimum() * item.scale + util3d.Vector3(item.centerX, item.centerY, 0) - extraSizeMin
iMax1 = item.getMaximum() * item.scale + util3d.Vector3(item.centerX, item.centerY, 0) + extraSizeMax
iMin1 = item.getMinimum() * item.scale + util3d.Vector3(item.centerX, item.centerY, 0) - extraSizeMin - self.parent.extruderOffset[item.extruder]
iMax1 = item.getMaximum() * item.scale + util3d.Vector3(item.centerX, item.centerY, 0) + extraSizeMax - self.parent.extruderOffset[item.extruder]
for idx2 in xrange(0, idx1):
item2 = self.parent.list[idx2]
iMin2 = item2.getMinimum() * item2.scale + util3d.Vector3(item2.centerX, item2.centerY, 0)
@ -566,8 +658,8 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
vMin = item.getMinimum() * item.scale
vMax = item.getMaximum() * item.scale
vMinHead = vMin - extraSizeMin
vMaxHead = vMax + extraSizeMax
vMinHead = vMin - extraSizeMin - self.parent.extruderOffset[item.extruder]
vMaxHead = vMax + extraSizeMax - self.parent.extruderOffset[item.extruder]
glDisable(GL_LIGHTING)
@ -612,28 +704,6 @@ class ProjectSliceProgressWindow(wx.Frame):
self.startTime = time.time()
self.sliceStartTime = time.time()
#How long does each step take compared to the others. This is used to make a better scaled progress bar, and guess time left.
# TODO: Duplicate with sliceProgressPanel, move to sliceRun.
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
self.sizer = wx.GridBagSizer(2, 2)
self.statusText = wx.StaticText(self, -1, "Building: %s" % (resultFilename))
self.progressGauge = wx.Gauge(self, -1)
@ -644,6 +714,7 @@ class ProjectSliceProgressWindow(wx.Frame):
self.sizer.Add(self.statusText, (0,0), flag=wx.ALIGN_CENTER)
self.sizer.Add(self.progressGauge, (1, 0), flag=wx.EXPAND)
self.sizer.Add(self.progressGauge2, (2, 0), flag=wx.EXPAND)
self.sizer.Add(self.abortButton, (3,0), flag=wx.ALIGN_CENTER)
self.sizer.AddGrowableCol(0)
self.sizer.AddGrowableRow(0)
@ -664,19 +735,19 @@ class ProjectSliceProgressWindow(wx.Frame):
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) + "]")
def OnRun(self):
resultFile = open(self.resultFilename, "w")
put = profile.putProfileSetting
put = profile.setTempOverride
for action in self.actionList:
p = subprocess.Popen(action.sliceCmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
line = p.stdout.readline()
@ -697,24 +768,27 @@ class ProjectSliceProgressWindow(wx.Frame):
if self.abort:
p.terminate()
wx.CallAfter(self.statusText.SetLabel, "Aborted by user.")
resultFile.close()
return
line = p.stdout.readline()
self.returnCode = p.wait()
oldProfile = profile.getGlobalProfileString()
put('machine_center_x', action.centerX)
put('machine_center_y', action.centerY)
put('machine_center_x', action.centerX - self.extruderOffset[action.extruder].x)
put('machine_center_y', action.centerY - self.extruderOffset[action.extruder].y)
put('clear_z', action.clearZ)
put('extruder', action.extruder)
if action == self.actionList[0]:
resultFile.write(';TYPE:CUSTOM\n')
resultFile.write('T%d\n' % (action.extruder))
currentExtruder = action.extruder
resultFile.write(profile.getAlterationFileContents('start.gcode'))
else:
#reset the extrusion length, and move to the next object center.
resultFile.write(';TYPE:CUSTOM\n')
resultFile.write(profile.getAlterationFileContents('nextobject.gcode'))
resultFile.write(';PRINTNR:%d\n' % self.actionList.index(action))
profile.loadGlobalProfileFromString(oldProfile)
profile.resetTempOverride()
f = open(action.filename[: action.filename.rfind('.')] + "_export.project_tmp", "r")
data = f.read(4096)
@ -731,9 +805,20 @@ class ProjectSliceProgressWindow(wx.Frame):
resultFile.write(';TYPE:CUSTOM\n')
resultFile.write(profile.getAlterationFileContents('end.gcode'))
resultFile.close()
gcode = gcodeInterpreter.gcode()
gcode.load(self.resultFilename)
self.abort = True
sliceTime = time.time() - self.sliceStartTime
wx.CallAfter(self.statusText.SetLabel, 'Slicing took: %d:%d' % (sliceTime / 60, sliceTime % 60))
status = "Slicing took: %02d:%02d\n" % (sliceTime / 60, sliceTime % 60)
status = "Filament: %.2fm %.2fg\n" % (gcode.extrusionAmount / 1000, gcode.calculateWeight() * 1000)
status += "Print time: %02d:%02d\n" % (int(gcode.totalMoveTimeMinute / 60), int(gcode.totalMoveTimeMinute % 60))
cost = gcode.calculateCost()
if cost != False:
status += "Cost: %s\n" % (cost)
wx.CallAfter(self.statusText.SetLabel, status)
wx.CallAfter(self.abortButton.SetLabel, 'Close')
def main():

View File

@ -117,7 +117,7 @@ class simpleModeWindow(configBase.configWindowBase):
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()
@ -158,7 +158,7 @@ class simpleModeWindow(configBase.configWindowBase):
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()

View File

@ -1,11 +1,12 @@
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):
@ -14,27 +15,6 @@ class sliceProgessPanel(wx.Panel):
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)
@ -58,18 +38,20 @@ class sliceProgessPanel(wx.Panel):
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):
@ -98,7 +80,12 @@ class sliceProgessPanel(wx.Panel):
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)
@ -117,13 +104,13 @@ class sliceProgessPanel(wx.Panel):
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) + "]")
@ -167,6 +154,8 @@ class WorkerThread(threading.Thread):
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()
@ -177,10 +166,13 @@ class WorkerThread(threading.Thread):
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:
@ -191,14 +183,17 @@ class WorkerThread(threading.Thread):
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

View File

@ -180,6 +180,7 @@ class NormalButton(buttons.GenBitmapButton):
super(NormalButton, self).__init__(parent, id, self.bitmap, size=size)
self.helpText = helpText
self.callback = callback
self.SetBezelWidth(1)
self.SetUseFocusIndicator(False)
@ -187,10 +188,14 @@ class NormalButton(buttons.GenBitmapButton):
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()

View File

@ -11,7 +11,7 @@ SUCCESS = 0
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)
@ -29,7 +29,7 @@ class validFloat():
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)
@ -47,7 +47,7 @@ class validInt():
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)
@ -68,7 +68,7 @@ class warningAbove():
#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)
@ -94,7 +94,7 @@ class wallThicknessValidator():
#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)

BIN
Cura/images/copy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

BIN
Cura/images/move-down.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

BIN
Cura/images/move-up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

BIN
Cura/images/object-add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 B

View File

@ -9,13 +9,13 @@ import os
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 = []
@ -36,7 +36,18 @@ class gcode():
#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
@ -45,6 +56,7 @@ class gcode():
currentE = 0.0
totalExtrusion = 0.0
maxExtrusion = 0.0
currentExtruder = 0
totalMoveTimeMinute = 0.0
scale = 1.0
posAbs = True
@ -79,6 +91,15 @@ class gcode():
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:
@ -91,17 +112,17 @@ class gcode():
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.
@ -200,8 +221,8 @@ class gcode():
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:

View File

@ -34,7 +34,7 @@ profileDefaultSettings = {
'bottom_layer_speed': '20',
'cool_min_layer_time': '10',
'fan_enabled': 'True',
'fan_layer': '0',
'fan_layer': '1',
'fan_speed': '100',
'model_scale': '1.0',
'flip_x': 'False',
@ -67,6 +67,9 @@ profileDefaultSettings = {
'add_start_end_gcode': 'True',
'gcode_extension': 'gcode',
'alternative_center': '',
'clear_z': '0.0',
'extruder': '0',
}
alterationDefault = {
#######################################################################################
@ -128,6 +131,12 @@ preferencesDefaultSettings = {
'machine_depth': '205',
'machine_height': '200',
'extruder_amount': '1',
'extruder_offset_x1': '-22.0',
'extruder_offset_y1': '0.0',
'extruder_offset_x2': '0.0',
'extruder_offset_y2': '0.0',
'extruder_offset_x3': '0.0',
'extruder_offset_y3': '0.0',
'filament_density': '1300',
'steps_per_e': '0',
'serial_port': 'AUTO',
@ -136,12 +145,18 @@ preferencesDefaultSettings = {
'save_profile': 'False',
'filament_cost_kg': '0',
'filament_cost_meter': '0',
'extruder_head_size_min_x': '70.0',
'extruder_head_size_min_y': '18.0',
'extruder_head_size_max_x': '18.0',
'extruder_head_size_max_y': '35.0',
}
#########################################################
## Profile and preferences functions
#########################################################
## Profile functions
def getDefaultProfilePath():
return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../current_profile.ini"))
@ -177,15 +192,31 @@ def getGlobalProfileString():
p = []
alt = []
for key in globalProfileParser.options('profile'):
p.append(key + "=" + globalProfileParser.get('profile', key))
for key in globalProfileParser.options('alterations'):
alt.append(key + "=" + globalProfileParser.get('alterations', key))
tempDone = []
if globalProfileParser.has_section('profile'):
for key in globalProfileParser.options('profile'):
if key in tempOverride:
p.append(key + "=" + unicode(tempOverride[key]))
tempDone.append(key)
else:
p.append(key + "=" + globalProfileParser.get('profile', key))
if globalProfileParser.has_section('alterations'):
for key in globalProfileParser.options('alterations'):
if key in tempOverride:
p.append(key + "=" + tempOverride[key])
tempDone.append(key)
else:
alt.append(key + "=" + globalProfileParser.get('alterations', key))
for key in tempOverride:
if key not in tempDone:
p.append(key + "=" + unicode(tempOverride[key]))
ret = '\b'.join(p) + '\f' + '\b'.join(alt)
ret = base64.b64encode(zlib.compress(ret, 9))
return ret
def getProfileSetting(name):
if name in tempOverride:
return unicode(tempOverride[name])
#Check if we have a configuration file loaded, else load the default.
if not globals().has_key('globalProfileParser'):
loadGlobalProfile(getDefaultProfilePath())
@ -217,13 +248,27 @@ def putProfileSetting(name, value):
globalProfileParser.add_section('profile')
globalProfileParser.set('profile', name, str(value))
def isProfileSetting(name):
if name in profileDefaultSettings:
return True
return False
## Preferences functions
global globalPreferenceParser
globalPreferenceParser = None
def getPreferencePath():
return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../preferences.ini"))
def getPreferenceFloat(name):
try:
return float(eval(getPreference(name), {}, {}))
except (ValueError, SyntaxError):
return 0.0
def getPreference(name):
if name in tempOverride:
return unicode(tempOverride[name])
global globalPreferenceParser
if globalPreferenceParser == None:
globalPreferenceParser = ConfigParser.ConfigParser()
@ -253,6 +298,18 @@ def putPreference(name, value):
globalPreferenceParser.set('preference', name, unicode(value).encode("utf-8"))
globalPreferenceParser.write(open(getPreferencePath(), 'w'))
def isPreference(name):
if name in preferencesDefaultSettings:
return True
return False
## Temp overrides for multi-extruder slicing and the project planner.
tempOverride = {}
def setTempOverride(name, value):
tempOverride[name] = value
def resetTempOverride():
tempOverride.clear()
#########################################################
## Utility functions to calculate common profile values
#########################################################
@ -296,7 +353,11 @@ def replaceTagMatch(m):
tag = m.group(0)[1:-1]
if tag in ['print_speed', 'retraction_speed', 'travel_speed', 'max_z_speed', 'bottom_layer_speed', 'cool_min_feedrate']:
return str(getProfileSettingFloat(tag) * 60)
return str(getProfileSettingFloat(tag))
if isProfileSetting(tag):
return str(getProfileSettingFloat(tag))
if isPreference(tag):
return str(getProfileSettingFloat(tag))
return tag
### Get aleration raw contents. (Used internally in Cura)
def getAlterationFile(filename):
@ -333,7 +394,7 @@ def getAlterationFileContents(filename):
if filename == 'start.gcode':
#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.
#We also set our steps per E here, if configured.
eSteps = float(getPreference('steps_per_e'))
eSteps = getPreferenceFloat('steps_per_e')
if eSteps > 0:
prefix += 'M92 E%f\n' % (eSteps)
temp = getProfileSettingFloat('print_temperature')

View File

@ -5,6 +5,28 @@ import platform, os, subprocess, sys
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":

View File

@ -9,11 +9,11 @@ import struct
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 = []

View File

@ -1,7 +1,7 @@
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