Merge commit 'd0691018c211d1dbd500c0b3d363da8c5bd2f11d'

This commit is contained in:
Lawrence Johnston 2012-04-07 13:17:52 -07:00
commit 53aa2efd71
17 changed files with 303 additions and 209 deletions

View File

@ -64,6 +64,27 @@ def calculateMultiplyDistance(setting):
edgeWidth = calculateEdgeWidth(setting)
return 10.0 / edgeWidth
def calcBottomLayerFlowRateRatio(setting):
bottomThickness = float(profile.getProfileSetting('bottom_thickness'))
layerThickness = float(profile.getProfileSetting('layer_height'))
if bottomThickness < layerThickness:
return 1.0
return bottomThickness / layerThickness
def calcExtraBottomThickness(setting):
bottomThickness = float(profile.getProfileSetting('bottom_thickness'))
layerThickness = float(profile.getProfileSetting('layer_height'))
if bottomThickness < layerThickness:
return 0.0
return bottomThickness - layerThickness
def calcLayerSkip(setting):
bottomThickness = float(profile.getProfileSetting('bottom_thickness'))
layerThickness = float(profile.getProfileSetting('layer_height'))
if bottomThickness < layerThickness:
return 0
return int(math.ceil((bottomThickness - layerThickness) / layerThickness + 0.0001) - 1)
def getProfileInformation():
return {
'carve': {
@ -72,7 +93,7 @@ def getProfileInformation():
'Extra_Decimal_Places_float': DEFSET,
'Import_Coarseness_ratio': DEFSET,
'Layer_Height_mm': storedSetting("layer_height"),
'Layers_From_index': DEFSET,
'Layers_From_index': calcLayerSkip,
'Layers_To_index': DEFSET,
'Correct_Mesh': DEFSET,
'Unproven_Mesh': DEFSET,
@ -80,6 +101,8 @@ def getProfileInformation():
'FlipX': storedSetting("flip_x"),
'FlipY': storedSetting("flip_y"),
'FlipZ': storedSetting("flip_z"),
'SwapXZ': storedSetting("swap_xz"),
'SwapYZ': storedSetting("swap_yz"),
'Scale': storedSetting("model_scale"),
'Rotate': storedSetting("model_rotate_base"),
},'scale': {
@ -90,7 +113,7 @@ def getProfileInformation():
},'bottom': {
'Activate_Bottom': DEFSET,
'Additional_Height_over_Layer_Thickness_ratio': DEFSET,
'Altitude_mm': DEFSET,
'Altitude_mm': calcExtraBottomThickness,
'SVG_Viewer': DEFSET,
},'preface': {
'Meta': DEFSET,
@ -167,6 +190,7 @@ def getProfileInformation():
'Perimeter_Feed_Rate_Multiplier_ratio': DEFSET,
'Perimeter_Flow_Rate_Multiplier_ratio': DEFSET,
'Travel_Feed_Rate_mm/s': storedSetting("travel_speed"),
'Bottom_layer_flow_rate_ratio': calcBottomLayerFlowRateRatio,
},'temperature': {
'Activate_Temperature': DEFSET,#ifSettingAboveZero('print_temperature'),
'Cooling_Rate_Celcius/second': DEFSET,
@ -246,12 +270,12 @@ def getProfileInformation():
'Perimeter_Outside_Stretch_Over_Perimeter_Width_ratio': DEFSET,
'Stretch_From_Distance_Over_Perimeter_Width_ratio': DEFSET,
},'skin': {
'Activate_Skin': "False",
'Horizontal_Infill_Divisions_integer': DEFSET,
'Horizontal_Perimeter_Divisions_integer': DEFSET,
'Vertical_Divisions_integer': DEFSET,
'Hop_When_Extruding_Infill': DEFSET,
'Layers_From_index': DEFSET,
'Activate_Skin': storedSetting("enable_skin"),
'Horizontal_Infill_Divisions_integer': "1",
'Horizontal_Perimeter_Divisions_integer': "1",
'Vertical_Divisions_integer': "2",
'Hop_When_Extruding_Infill': "False",
'Layers_From_index': "1",
},'comb': {
'Activate_Comb': "True",
'Running_Jump_Space_mm': DEFSET,

View File

@ -183,6 +183,8 @@ class CarveRepository:
self.flipX = settings.BooleanSetting().getFromValue('FlipX', self, False)
self.flipY = settings.BooleanSetting().getFromValue('FlipY', self, False)
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.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 )
@ -210,6 +212,8 @@ class CarveSkein:
scaleY = -scaleY
if repository.flipZ.value == True:
scaleZ = -scaleZ
swapXZ = repository.swapXZ.value
swapYZ = repository.swapYZ.value
mat00 = math.cos(rotate) * scaleX
mat01 =-math.sin(rotate) * scaleY
mat10 = math.sin(rotate) * scaleX
@ -226,10 +230,17 @@ class CarveSkein:
#v.y += self.machineCenter.y
for i in xrange(0, len(carving.vertexes)):
x = carving.vertexes[i].x
y = carving.vertexes[i].y
z = carving.vertexes[i].z
if swapXZ:
x, z = z, x
if swapYZ:
y, z = z, y
carving.vertexes[i] = Vector3(
carving.vertexes[i].x * mat00 + carving.vertexes[i].y * mat01,
carving.vertexes[i].x * mat10 + carving.vertexes[i].y * mat11,
carving.vertexes[i].z * scaleZ)
x * mat00 + y * mat01,
x * mat10 + y * mat11,
z * scaleZ)
layerHeight = repository.layerHeight.value
edgeWidth = repository.edgeWidth.value

View File

@ -210,6 +210,8 @@ class SpeedRepository:
settings.LabelSeparator().getFromRepository(self)
self.travelFeedRatePerSecond = settings.FloatSpin().getFromValue( 2.0, 'Travel Feed Rate (mm/s):', self, 350.0, 250.0 )
self.executeTitle = 'Speed'
self.bottomLayerFlowRateMultiplier = settings.FloatSpin().getFromValue(0.0, 'Bottom layer flow rate (ratio):', self, 10.0, 1.0)
def execute(self):
"Speed button has been clicked."
@ -246,6 +248,8 @@ class SpeedSkein:
flowRate *= ((self.repository.objectFirstLayerFlowRatePerimeterMultiplier.value * (self.repository.objectFirstLayersLayerAmount.value - self.layerIndex)) + self.layerIndex) / self.repository.objectFirstLayersLayerAmount.value
else:
flowRate *= ((self.repository.objectFirstLayerFlowRateInfillMultiplier.value * (self.repository.objectFirstLayersLayerAmount.value - self.layerIndex)) + self.layerIndex) / self.repository.objectFirstLayersLayerAmount.value
if self.layerIndex == 0:
flowRate *= self.repository.bottomLayerFlowRateMultiplier.value
if flowRate != self.oldFlowRate:
self.distanceFeedRate.addLine('M108 S' + euclidean.getFourSignificantFigures(flowRate))
self.oldFlowRate = flowRate

View File

@ -10,10 +10,10 @@ from gui import sliceProgessPanel
from gui import alterationPanel
from gui import validators
class advancedConfigWindow(configBase.configWindowBase):
"Advanced configuration window"
class expertConfigWindow(configBase.configWindowBase):
"Expert configuration window"
def __init__(self):
super(advancedConfigWindow, self).__init__(title='Expert config')
super(expertConfigWindow, self).__init__(title='Expert config')
wx.EVT_CLOSE(self, self.OnClose)

View File

@ -106,18 +106,33 @@ class InstallFirmware(wx.Dialog):
class VirtualPrinter():
def __init__(self):
self.readList = ['start\n']
self.temp = 0.0
self.targetTemp = 0.0
def write(self, data):
if self.readList == None:
return
print "Send: %s" % (data.rstrip())
self.readList.append("ok\n")
if 'M104' in data:
try:
self.targetTemp = float(data[data.find('S')+1:])
except:
pass
if 'M105' in data:
self.readList.append("ok T:%f/%f\n" % (self.temp, self.targetTemp))
else:
self.readList.append("ok\n")
def readline(self):
if self.readList == None:
return ''
n = 0
self.temp = (self.temp + self.targetTemp) / 2
while len(self.readList) < 1:
time.sleep(0.1)
n += 1
if n == 20:
return ''
if self.readList == None:
return ''
time.sleep(0.001)
@ -141,7 +156,7 @@ class MachineCom():
programmer.connect(port)
programmer.close()
print "Connecting to: %s %i" % (port, baudrate)
self.serial = Serial(port, baudrate, timeout=5)
self.serial = Serial(port, baudrate, timeout=2)
break
except ispBase.IspError:
pass
@ -152,7 +167,7 @@ class MachineCom():
self.serial = VirtualPrinter()
else:
try:
self.serial = Serial(port, baudrate, timeout=5)
self.serial = Serial(port, baudrate, timeout=2)
except:
print "Unexpected error while connecting to serial port:" + port, sys.exc_info()[0]

View File

@ -4,7 +4,7 @@ import __init__
import wx, os, platform, types, webbrowser
from gui import configBase
from gui import advancedConfig
from gui import expertConfig
from gui import preview3d
from gui import sliceProgessPanel
from gui import alterationPanel
@ -96,7 +96,7 @@ class mainWindow(configBase.configWindowBase):
configBase.TitleRow(left, "Accuracy")
c = configBase.SettingRow(left, "Layer height (mm)", 'layer_height', '0.2', 'Layer height in millimeters.\n0.2 is a good value for quick prints.\n0.1 gives high quality prints.')
validators.validFloat(c, 0.0)
validators.warningAbove(c, lambda : (float(profile.getProfileSetting('nozzle_size')) * 80 / 100), "Thicker layers then %.2fmm (80%% nozzle size) usually give bad results and are not recommended.")
validators.warningAbove(c, lambda : (float(profile.getProfileSetting('nozzle_size')) * 80.0 / 100.0), "Thicker layers then %.2fmm (80%% nozzle size) usually give bad results and are not recommended.")
c = configBase.SettingRow(left, "Wall thickness (mm)", 'wall_thickness', '0.8', 'Thickness of the walls.\nThis is used in combination with the nozzle size to define the number\nof perimeter lines and the thickness of those perimeter lines.')
validators.validFloat(c, 0.0)
validators.wallThicknessValidator(c)
@ -126,7 +126,7 @@ class mainWindow(configBase.configWindowBase):
configBase.TitleRow(right, "Support")
c = configBase.SettingRow(right, "Support type", 'support', ['None', 'Exterior Only', 'Everywhere', 'Empty Layers Only'], 'Type of support structure build.\nNone does not do any support.\nExterior only only creates support on the outside.\nEverywhere creates support even on the insides of the model.\nOnly on empty layers is for stacked objects.')
c = configBase.SettingRow(right, "Add raft", 'enable_raft', False, 'A raft is a few layers of lines below the bottom of the object. It prevents warping. Full raft settings can be found in the advanced settings.\nFor PLA this is usually not required. But if you print with ABS it is almost required.')
c = configBase.SettingRow(right, "Add raft", 'enable_raft', False, 'A raft is a few layers of lines below the bottom of the object. It prevents warping. Full raft settings can be found in the expert settings.\nFor PLA this is usually not required. But if you print with ABS it is almost required.')
configBase.TitleRow(right, "Filament")
c = configBase.SettingRow(right, "Diameter (mm)", 'filament_diameter', '2.89', 'Diameter of your filament, as accurately as possible.\nIf you cannot measure this value you will have to callibrate it, a higher number means less extrusion, a smaller number generates more extrusion.')
@ -171,6 +171,12 @@ class mainWindow(configBase.configWindowBase):
validators.validFloat(c, 0.0)
c = configBase.SettingRow(right, "Enable cooling fan", 'fan_enabled', True, 'Enable the cooling fan during the print. The extra cooling from the cooling fan is essensial during faster prints.')
configBase.TitleRow(right, "Accuracy")
c = configBase.SettingRow(right, "Initial layer thickness (mm)", 'bottom_thickness', '0.0', 'Layer thickness of the bottom layer. A thicker bottom layer makes sticking to the bed easier. Set to 0.0 to have the bottom layer thickness the same as the other layers.')
validators.validFloat(c, 0.0)
validators.warningAbove(c, lambda : (float(profile.getProfileSetting('nozzle_size')) * 3.0 / 4.0), "A bottom layer of more then %.2fmm (3/4 nozzle size) usually give bad results and is not recommended.")
c = configBase.SettingRow(right, "Enable 'skin'", 'enable_skin', False, 'Skin prints the outer lines of the prints twice, each time with half the thickness. This gives the illusion of a higher print quality.')
nb.AddPage(alterationPanel.alterationPanel(nb), "Start/End-GCode")
# load and slice buttons.
@ -287,9 +293,9 @@ class mainWindow(configBase.configWindowBase):
printWindow.printFile(self.filename[: self.filename.rfind('.')] + "_export.gcode")
def OnExpertOpen(self, e):
acw = advancedConfig.advancedConfigWindow()
acw.Centre()
acw.Show(True)
ecw = expertConfig.expertConfigWindow()
ecw.Centre()
ecw.Show(True)
def removeSliceProgress(self, spp):
self.progressPanelList.remove(spp)

94
Cura/gui/opengl.py Normal file
View File

@ -0,0 +1,94 @@
try:
import OpenGL
OpenGL.ERROR_CHECKING = False
from OpenGL.GLU import *
from OpenGL.GL import *
hasOpenGLlibs = True
except:
print "Failed to find PyOpenGL: http://pyopengl.sourceforge.net/"
hasOpenGLlibs = False
def InitGL(window, view3D, zoom):
# set viewing projection
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
size = window.GetSize()
glViewport(0,0, size.GetWidth(), size.GetHeight())
glLightfv(GL_LIGHT0, GL_POSITION, [1.0, 1.0, 1.0, 0.0])
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE)
glDisable(GL_BLEND)
glClearColor(0.0, 0.0, 0.0, 1.0)
glClearStencil(0)
glClearDepth(1.0)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
aspect = float(size.GetWidth()) / float(size.GetHeight())
if view3D:
gluPerspective(90.0, aspect, 1.0, 1000.0)
else:
glOrtho(-aspect, aspect, -1, 1, -1000.0, 1000.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
def DrawMachine(machineSize):
glColor3f(1,1,1)
glLineWidth(4)
glDisable(GL_LIGHTING)
glBegin(GL_LINE_LOOP)
glVertex3f(0, 0, 0)
glVertex3f(machineSize.x, 0, 0)
glVertex3f(machineSize.x, machineSize.y, 0)
glVertex3f(0, machineSize.y, 0)
glEnd()
glLineWidth(2)
glBegin(GL_LINES)
for i in xrange(0, int(machineSize.x), 10):
glVertex3f(i, 0, 0)
glVertex3f(i, machineSize.y, 0)
for i in xrange(0, int(machineSize.y), 10):
glVertex3f(0, i, 0)
glVertex3f(machineSize.x, i, 0)
glEnd()
glLineWidth(1)
glBegin(GL_LINE_LOOP)
glVertex3f(0, 0, machineSize.z)
glVertex3f(machineSize.x, 0, machineSize.z)
glVertex3f(machineSize.x, machineSize.y, machineSize.z)
glVertex3f(0, machineSize.y, machineSize.z)
glEnd()
glBegin(GL_LINES)
glVertex3f(0, 0, 0)
glVertex3f(0, 0, machineSize.z)
glVertex3f(machineSize.x, 0, 0)
glVertex3f(machineSize.x, 0, machineSize.z)
glVertex3f(machineSize.x, machineSize.y, 0)
glVertex3f(machineSize.x, machineSize.y, machineSize.z)
glVertex3f(0, machineSize.y, 0)
glVertex3f(0, machineSize.y, machineSize.z)
glEnd()
def DrawSTL(mesh):
for face in mesh.faces:
glBegin(GL_TRIANGLES)
v1 = face.v[0]
v2 = face.v[1]
v3 = face.v[2]
glNormal3f(face.normal.x, face.normal.y, face.normal.z)
glVertex3f(v1.x, v1.y, v1.z)
glVertex3f(v2.x, v2.y, v2.z)
glVertex3f(v3.x, v3.y, v3.z)
glNormal3f(-face.normal.x, -face.normal.y, -face.normal.z)
glVertex3f(v1.x, v1.y, v1.z)
glVertex3f(v3.x, v3.y, v3.z)
glVertex3f(v2.x, v2.y, v2.z)
glEnd()

View File

@ -17,6 +17,8 @@ except:
print "Failed to find PyOpenGL: http://pyopengl.sourceforge.net/"
hasOpenGLlibs = False
from gui import opengl
from util import profile
from util import gcodeInterpreter
from util import stl
@ -75,6 +77,16 @@ class previewPanel(wx.Panel):
self.flipZ.SetValue(profile.getProfileSetting('flip_z') == 'True')
self.toolbar2.AddControl(self.flipZ)
self.Bind(wx.EVT_CHECKBOX, self.OnFlipZClick, self.flipZ)
self.swapXZ = wx.CheckBox(self.toolbar2, -1, "XZ")
self.swapXZ.SetValue(profile.getProfileSetting('swap_xz') == 'True')
self.toolbar2.AddControl(self.swapXZ)
self.Bind(wx.EVT_CHECKBOX, self.OnSwapXZClick, self.swapXZ)
self.swapYZ = wx.CheckBox(self.toolbar2, -1, "YZ")
self.swapYZ.SetValue(profile.getProfileSetting('swap_yz') == 'True')
self.toolbar2.AddControl(self.swapYZ)
self.Bind(wx.EVT_CHECKBOX, self.OnSwapYZClick, self.swapYZ)
self.toolbar2.InsertSeparator(self.toolbar2.GetToolsCount())
self.toolbar2.AddControl(wx.StaticText(self.toolbar2, -1, 'Scale'))
@ -126,6 +138,14 @@ class previewPanel(wx.Panel):
profile.putProfileSetting('flip_z', str(self.flipZ.GetValue()))
self.updateModelTransform()
def OnSwapXZClick(self, e):
profile.putProfileSetting('swap_xz', str(self.swapXZ.GetValue()))
self.updateModelTransform()
def OnSwapYZClick(self, e):
profile.putProfileSetting('swap_yz', str(self.swapYZ.GetValue()))
self.updateModelTransform()
def OnMulXAddClick(self, e):
profile.putProfileSetting('model_multiply_x', str(max(1, int(profile.getProfileSetting('model_multiply_x'))+1)))
self.updateModelTransform()
@ -285,15 +305,24 @@ class previewPanel(wx.Panel):
scaleY = -scaleY
if profile.getProfileSetting('flip_z') == 'True':
scaleZ = -scaleZ
swapXZ = profile.getProfileSetting('swap_xz') == 'True'
swapYZ = profile.getProfileSetting('swap_yz') == 'True'
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.triangleMesh.origonalVertexes)):
self.triangleMesh.vertexes[i].x = self.triangleMesh.origonalVertexes[i].x * mat00 + self.triangleMesh.origonalVertexes[i].y * mat01
self.triangleMesh.vertexes[i].y = self.triangleMesh.origonalVertexes[i].x * mat10 + self.triangleMesh.origonalVertexes[i].y * mat11
self.triangleMesh.vertexes[i].z = self.triangleMesh.origonalVertexes[i].z * scaleZ
x = self.triangleMesh.origonalVertexes[i].x
y = self.triangleMesh.origonalVertexes[i].y
z = self.triangleMesh.origonalVertexes[i].z
if swapXZ:
x, z = z, x
if swapYZ:
y, z = z, y
self.triangleMesh.vertexes[i].x = x * mat00 + y * mat01
self.triangleMesh.vertexes[i].y = x * mat10 + y * mat11
self.triangleMesh.vertexes[i].z = z * scaleZ
for face in self.triangleMesh.faces:
v1 = face.v[0]
@ -381,51 +410,24 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
dc.DrawText("No PyOpenGL installation found.\nNo preview window available.", 10, 10)
return
self.SetCurrent(self.context)
self.InitGL()
opengl.InitGL(self, self.view3D, self.zoom)
if self.view3D:
glTranslate(0,0,-self.zoom)
glRotate(-self.pitch, 1,0,0)
glRotate(self.yaw, 0,0,1)
if self.parent.triangleMesh != None:
glTranslate(0,0,-self.parent.triangleMesh.getMaximum().z / 2)
else:
glScale(1.0/self.zoom, 1.0/self.zoom, 1.0)
glTranslate(self.offsetX, self.offsetY, 0.0)
glTranslate(-self.parent.machineCenter.x, -self.parent.machineCenter.y, 0)
self.OnDraw()
self.SwapBuffers()
def OnDraw(self):
machineSize = self.parent.machineSize
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
glTranslate(-self.parent.machineCenter.x, -self.parent.machineCenter.y, 0)
glColor3f(1,1,1)
glLineWidth(4)
glDisable(GL_LIGHTING)
glBegin(GL_LINE_LOOP)
glVertex3f(0, 0, 0)
glVertex3f(machineSize.x, 0, 0)
glVertex3f(machineSize.x, machineSize.y, 0)
glVertex3f(0, machineSize.y, 0)
glEnd()
glLineWidth(2)
glBegin(GL_LINES)
for i in xrange(0, int(machineSize.x), 10):
glVertex3f(i, 0, 0)
glVertex3f(i, machineSize.y, 0)
for i in xrange(0, int(machineSize.y), 10):
glVertex3f(0, i, 0)
glVertex3f(machineSize.x, i, 0)
glEnd()
glLineWidth(1)
glBegin(GL_LINE_LOOP)
glVertex3f(0, 0, machineSize.z)
glVertex3f(machineSize.x, 0, machineSize.z)
glVertex3f(machineSize.x, machineSize.y, machineSize.z)
glVertex3f(0, machineSize.y, machineSize.z)
glEnd()
glBegin(GL_LINES)
glVertex3f(0, 0, 0)
glVertex3f(0, 0, machineSize.z)
glVertex3f(machineSize.x, 0, 0)
glVertex3f(machineSize.x, 0, machineSize.z)
glVertex3f(machineSize.x, machineSize.y, 0)
glVertex3f(machineSize.x, machineSize.y, machineSize.z)
glVertex3f(0, machineSize.y, 0)
glVertex3f(0, machineSize.y, machineSize.z)
glEnd()
opengl.DrawMachine(machineSize)
if self.parent.gcode != None:
if self.gcodeDisplayList == None:
@ -439,10 +441,13 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
layerThickness = 0.0
filamentRadius = float(profile.getProfileSetting('filament_diameter')) / 2
filamentArea = math.pi * filamentRadius * filamentRadius
lineWidth = float(profile.getProfileSetting('nozzle_size')) / 2
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():
@ -530,26 +535,16 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
glTranslate(-(modelSize.x+10)*(multiX-1)/2,-(modelSize.y+10)*(multiY-1)/2, 0)
for mx in xrange(0, multiX):
for my in xrange(0, multiY):
for face in self.parent.triangleMesh.faces:
glPushMatrix()
glTranslate((modelSize.x+10)*mx,(modelSize.y+10)*my, 0)
glBegin(GL_TRIANGLES)
v1 = face.v[0]
v2 = face.v[1]
v3 = face.v[2]
glNormal3f(face.normal.x, face.normal.y, face.normal.z)
glVertex3f(v1.x, v1.y, v1.z)
glVertex3f(v2.x, v2.y, v2.z)
glVertex3f(v3.x, v3.y, v3.z)
glNormal3f(-face.normal.x, -face.normal.y, -face.normal.z)
glVertex3f(v1.x, v1.y, v1.z)
glVertex3f(v3.x, v3.y, v3.z)
glVertex3f(v2.x, v2.y, v2.z)
glEnd()
glPopMatrix()
glPushMatrix()
glTranslate((modelSize.x+10)*mx,(modelSize.y+10)*my, 0)
opengl.DrawSTL(self.parent.triangleMesh)
glPopMatrix()
glPopMatrix()
glEndList()
if self.viewMode == "Model - Transparent" or self.viewMode == "Mixed":
glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.5, 0.4, 0.3, 1.0])
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.1, 0.1, 0.1, 0.0])
#If we want transparent, then first render a solid black model to remove the printer size lines.
if self.viewMode != "Mixed":
glDisable(GL_BLEND)
@ -606,6 +601,8 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
glDisable(GL_STENCIL_TEST);
glEnable(GL_DEPTH_TEST)
elif self.viewMode == "Model - Normal":
glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 0.8, 0.6, 1.0])
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.2, 0.2, 0.2, 0.0])
glEnable(GL_LIGHTING)
glCallList(self.modelDisplayList)
@ -622,48 +619,3 @@ class PreviewGLCanvas(glcanvas.GLCanvas):
glEnd()
glFlush()
def InitGL(self):
# set viewing projection
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
size = self.GetSize()
glViewport(0,0, size.GetWidth(), size.GetHeight())
if self.viewMode == "Model - Transparent" or self.viewMode == "Mixed":
glLightfv(GL_LIGHT0, GL_DIFFUSE, [0.5, 0.4, 0.3, 1.0])
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.1, 0.1, 0.1, 0.0])
else:
glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 0.8, 0.6, 1.0])
glLightfv(GL_LIGHT0, GL_AMBIENT, [0.2, 0.2, 0.2, 0.0])
glLightfv(GL_LIGHT0, GL_POSITION, [1.0, 1.0, 1.0, 0.0])
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE)
glDisable(GL_BLEND)
glClearColor(0.0, 0.0, 0.0, 1.0)
glClearStencil(0)
glClearDepth(1.0)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
aspect = float(self.GetSize().GetWidth()) / float(self.GetSize().GetHeight())
if self.view3D:
gluPerspective(90.0, aspect, 1.0, 1000.0)
else:
glOrtho(-self.zoom * aspect, self.zoom * aspect, -self.zoom, self.zoom, -1000.0, 1000.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
if self.view3D:
glTranslate(0,0,-self.zoom)
glRotate(-self.pitch, 1,0,0)
glRotate(self.yaw, 0,0,1)
if self.parent.triangleMesh != None:
glTranslate(0,0,-self.parent.triangleMesh.getMaximum().z / 2)
else:
glTranslate(self.offsetX, self.offsetY, 0)

View File

@ -1,7 +1,7 @@
from __future__ import absolute_import
import __init__
import wx, threading
import wx, threading, re
from gui import machineCom
from gui import icon
@ -27,7 +27,9 @@ class printWindow(wx.Frame):
self.thread = None
self.gcode = None
self.gcodeList = None
self.sendList = []
self.printIdx = None
self.temp = None
self.bufferLineCount = 4
self.sendCnt = 0
@ -51,11 +53,20 @@ class printWindow(wx.Frame):
self.printButton = wx.Button(self.panel, -1, 'Print GCode')
self.cancelButton = wx.Button(self.panel, -1, 'Cancel print')
self.progress = wx.Gauge(self.panel, -1)
h = self.connectButton.GetSize().GetHeight()
self.temperatureSelect = wx.SpinCtrl(self.panel, -1, '0', size=(21*3,21), style=wx.SP_ARROW_KEYS)
self.temperatureSelect.SetRange(0, 400)
self.sizer.Add(self.connectButton, pos=(0,1))
#self.sizer.Add(self.loadButton, pos=(1,1))
self.sizer.Add(self.printButton, pos=(2,1))
self.sizer.Add(self.cancelButton, pos=(3,1))
self.sizer.Add(self.progress, pos=(4,0), span=(1,2), flag=wx.EXPAND)
self.sizer.Add(wx.StaticText(self.panel, -1, "Temp:"), pos=(0,3))
self.sizer.Add(self.temperatureSelect, pos=(0,4))
self.sizer.AddGrowableRow(3)
self.sizer.AddGrowableCol(0)
@ -65,6 +76,8 @@ class printWindow(wx.Frame):
self.printButton.Bind(wx.EVT_BUTTON, self.OnPrint)
self.cancelButton.Bind(wx.EVT_BUTTON, self.OnCancel)
self.Bind(wx.EVT_SPINCTRL, self.OnTempChange, self.temperatureSelect)
self.Layout()
self.Fit()
self.Centre()
@ -90,6 +103,8 @@ class printWindow(wx.Frame):
else:
self.progress.SetValue(self.printIdx)
status += 'Line: %d/%d\n' % (self.printIdx, len(self.gcodeList))
if self.temp != None:
status += 'Temp: %d\n' % (self.temp)
self.statsText.SetLabel(status)
def OnConnect(self, e):
@ -128,9 +143,13 @@ class printWindow(wx.Frame):
self.thread.join()
self.Destroy()
def OnTempChange(self, e):
self.sendCommand("M104 S%d" % (self.temperatureSelect.GetValue()))
def LoadGCodeFile(self, filename):
if self.printIdx != None:
return
#Send an initial M110 to reset the line counter to zero.
gcodeList = ["M110"]
for line in open(filename, 'r'):
if ';' in line:
@ -146,6 +165,13 @@ class printWindow(wx.Frame):
self.gcodeList = gcodeList
self.UpdateButtonStates()
self.UpdateProgress()
def sendCommand(self, cmd):
if self.machineConnected:
if self.printIdx == None:
self.machineCom.sendCommand(cmd)
else:
self.sendList.append(cmd)
def sendLine(self, lineNr):
if lineNr >= len(self.gcodeList):
@ -155,7 +181,6 @@ class printWindow(wx.Frame):
return True
def PrinterMonitor(self):
skipCount = 0
while True:
line = self.machineCom.readline()
if line == None:
@ -170,10 +195,16 @@ class printWindow(wx.Frame):
elif line.startswith("start"):
self.machineConnected = True
wx.CallAfter(self.UpdateButtonStates)
if self.printIdx != None:
if 'T:' in line:
self.temp = float(re.search("[0-9\.]*", line.split('T:')[1]).group(0))
wx.CallAfter(self.UpdateProgress)
if self.printIdx == None:
if line == '': #When we have a communication "timeout" and we're not sending gcode, then read the temperature.
self.machineCom.sendCommand("M105")
else:
if line.startswith("ok"):
if skipCount > 0:
skipCount -= 1
if len(self.sendList) > 0:
self.machineCom.sendCommand(self.sendList.pop(0))
else:
if self.sendLine(self.printIdx):
self.printIdx += 1

View File

@ -205,7 +205,7 @@ class simpleModeWindow(configBase.configWindowBase):
put('infill_type', 'Line')
put('solid_top', 'True')
put('fill_overlap', '15')
put('support_rate', '100')
put('support_rate', '50')
put('support_distance', '0.5')
put('joris', 'False')
put('cool_min_feedrate', '5')
@ -214,6 +214,7 @@ class simpleModeWindow(configBase.configWindowBase):
put('raft_margin', '5')
put('raft_base_material_amount', '100')
put('raft_interface_material_amount', '100')
put('bottom_thickness', '0.0')
if self.printSupport.GetValue():
put('support', 'Exterior Only')
@ -234,6 +235,7 @@ class simpleModeWindow(configBase.configWindowBase):
put('layer_height', '0.1')
put('fill_density', '30')
put('bottom_layer_speed', '15')
put('bottom_thickness', '0.2')
elif self.printTypeJoris.GetValue():
put('wall_thickness', nozzle_size * 1.5)
put('layer_height', '0.2')
@ -255,6 +257,7 @@ class simpleModeWindow(configBase.configWindowBase):
put('enable_raft', 'True')
put('skirt_line_count', '0')
put('fan_layer', '1')
put('bottom_thickness', '0.0')
#Create a progress panel and add it to the window. The progress panel will start the Skein operation.
spp = sliceProgessPanel.sliceProgessPanel(self, self, self.filename)

View File

@ -28,6 +28,7 @@ class sliceProgessPanel(wx.Panel):
'speed': 12.759510994,
'raft': 31.4580039978,
'skirt': 19.3436040878,
'skin': 1.0,
'joris': 1.0,
'comb': 23.7805759907,
'cool': 27.148763895,

View File

@ -105,7 +105,7 @@ class gcode():
else:
pos.z += z * scale
#Check if we have a new layer.
if oldPos.z != pos.z and startCodeDone:
if oldPos.z < pos.z and startCodeDone and len(currentLayer) > 0:
self.layerList.append(currentLayer)
currentLayer = []
if f is not None:

View File

@ -42,6 +42,8 @@ profileDefaultSettings = {
'flip_x': 'False',
'flip_y': 'False',
'flip_z': 'False',
'swap_xz': 'False',
'swap_yz': 'False',
'model_rotate_base': '0',
'model_multiply_x': '1',
'model_multiply_y': '1',
@ -51,9 +53,10 @@ profileDefaultSettings = {
'infill_type': 'Line',
'solid_top': 'True',
'fill_overlap': '15',
'support_rate': '100',
'support_rate': '50',
'support_distance': '0.5',
'joris': 'False',
'enable_skin': 'False',
'enable_raft': 'False',
'cool_min_feedrate': '5',
'bridge_speed': '100',
@ -61,6 +64,7 @@ profileDefaultSettings = {
'raft_margin': '5',
'raft_base_material_amount': '100',
'raft_interface_material_amount': '100',
'bottom_thickness': '0.0',
}
preferencesDefaultSettings = {
'wizardDone': 'False',
@ -158,7 +162,7 @@ def getPreference(name):
globalPreferenceParser.set('preference', name, str(default))
print name + " not found in preferences, so using default: " + str(default)
return default
return globalPreferenceParser.get('preference', name)
return unicode(globalPreferenceParser.get('preference', name), "utf-8")
def putPreference(name, value):
#Check if we have a configuration file loaded, else load the default.
@ -168,7 +172,7 @@ def putPreference(name, value):
globalPreferenceParser.read(getPreferencePath())
if not globalPreferenceParser.has_section('preference'):
globalPreferenceParser.add_section('preference')
globalPreferenceParser.set('preference', name, str(value))
globalPreferenceParser.set('preference', name, str(value).encode("utf-8"))
globalPreferenceParser.write(open(getPreferencePath(), 'w'))
#########################################################

View File

@ -89,7 +89,7 @@ def getSliceCommand(filename):
'--solid-layers', str(profile.calculateSolidLayerCount()),
'--fill-density', str(float(profile.getProfileSetting('fill_density'))/100),
'--fill-angle', '45',
'--fill-pattern', 'rectilinear',
'--fill-pattern', 'rectilinear', #rectilinear line concentric hilbertcurve archimedeanchords octagramspiral
'--solid-fill-pattern', 'rectilinear',
'--start-gcode', profile.getAlterationFilePath('start.gcode'),
'--end-gcode', profile.getAlterationFilePath('end.gcode'),

66
README
View File

@ -1,66 +0,0 @@
For documentation check: https://github.com/daid/Cura/wiki
For downloads check: https://github.com/daid/Cura/downloads
This package includes two programs:
Pronterface:
An application for both manually controlling and automatically feeding gcode to a 3D printer.
Cura:
A easy to use program for slicing STL files using SkeinForge. Cura can also visualize the 3D models in a variety of ways.
On first run, Cura will ask to go through a set of calibration steps that will perform a series of operations on your 3D printer. One of those steps involves extruding a bit of filament where the filament is initially nearly fully extracted. As such, it you will probably need to run Pronterface first, heat up the extruder enough to be able to extract the filament and then use the Pronterface interface to reverse the extruder motor until the filament is at the right position (specifically, until the filament end is even with where the Bowden tube leaves the extuder motor assembly, on an Ultimaker).
========
BUILDING
========
./package.sh
The build script defaults to building for Windows. If you want to build for Mac OS X or Linux, choose one of:
./package.sh osx64
./package.sh linux
Note that Mac OS X currently requires the manual installation of wxPython, PySerial, and PyOpenGL:
sudo easy_install-2.7 pyserial
sudo easy_install-2.7 PyOpenGL
You will need to download the appropriate wxPython Installer package and install it. It is available from:
http://www.wxpython.org/download.php
Specifically, install "wxPython2.9-osx-cocoa-py2.7" as it is the build that supports 64-bit execution.
=======
RUNNING
=======
Windows
-------
Double-click skeinforge.bat and Printrun.bat.
Mac OS X & Linux
----------------
Once built, the two apps -- Pronterface and Cura -- must be started from the command line (for now):
# open a new terminal window and....
cd osx64-Cura-NewUI-Beta4
./pronterface.sh &
./Cura.sh &
This will start both applications with their console logging output directed into the terminal window.
========
FIRMWARE
========
For Ultimaker users, it is highly recommended -- nearly required -- that you upgrade your firmware to the latest Marlin builds. See:
http://wiki.ultimaker.com/Skeinforge_PyPy

17
README.md Normal file
View File

@ -0,0 +1,17 @@
Cura
====
If you are reading this, then you are looking at the *development* version of Cura. If you just want to use Cura look at the following location: https://github.com/daid/Cura/wiki
Development
===========
Cura is developed in Python. Getting Cura up and running for development is not very difficult. If you copy the python and pypy from a release into your Cura development checkout then you can use Cura right away, just like you would with a release.
For development with git, check the help on github. Pull requests is the fastest way to get changes into Cura.
Packaging
---------
Cura development comes with a script "package.sh", this script has been designed to run under unix like OSes (Linux, MacOS). Running it from sygwin is not a priority.
The "package.sh" script generates a final release package. You should not need it during development, unless you are changing the release process. If you want to distribute your own version of Cura, then the package.sh script will allow you to do that.

View File

@ -85,6 +85,7 @@ Section "Cura Installer"
CreateDirectory "$SMPROGRAMS\Cura ${VERSION}"
CreateShortCut "$SMPROGRAMS\Cura ${VERSION}\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0
CreateShortCut "$SMPROGRAMS\Cura ${VERSION}\Cura.lnk" "$INSTDIR\cura.bat" "" "$INSTDIR\cura.icon" 0
CreateShortCut "$SMPROGRAMS\Cura ${VERSION}\PrintRun.lnk" "$INSTDIR\printrun.bat" "" "$INSTDIR\cura.icon" 0
; Set output path to the driver directory.
SetOutPath "$INSTDIR\drivers\"
@ -108,9 +109,6 @@ Section "Uninstall"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cura_${VERSION}"
DeleteRegKey HKLM "SOFTWARE\Cura_${VERSION}"
; Remove shortcuts, if any
Delete "$SMPROGRAMS\Cura ${VERSION}\*.*"
; Remove directories used
RMDir /r "$SMPROGRAMS\Cura ${VERSION}"
RMDir /r "$INSTDIR"