245 lines
8.4 KiB
Python
245 lines
8.4 KiB
Python
from __future__ import absolute_import
|
|
#Init has to be imported first because it has code to workaround the python bug where relative imports don't work if the module is imported as a main module.
|
|
import __init__
|
|
|
|
import ConfigParser
|
|
import os
|
|
import traceback
|
|
import math
|
|
|
|
#########################################################
|
|
## Profile and preferences functions
|
|
#########################################################
|
|
|
|
#Single place to store the defaults, so we have a consistent set of default settings.
|
|
profileDefaultSettings = {
|
|
'nozzle_size': '0.4',
|
|
'layer_height': '0.2',
|
|
'wall_thickness': '0.8',
|
|
'solid_layer_thickness': '0.6',
|
|
'fill_density': '20',
|
|
'skirt_line_count': '1',
|
|
'skirt_gap': '6.0',
|
|
'print_speed': '50',
|
|
'print_temperature': '0',
|
|
'support': 'None',
|
|
'filament_diameter': '2.89',
|
|
'filament_density': '1.00',
|
|
'machine_center_x': '100',
|
|
'machine_center_y': '100',
|
|
'retraction_min_travel': '5.0',
|
|
'retraction_speed': '13.5',
|
|
'retraction_amount': '0.0',
|
|
'retraction_extra': '0.0',
|
|
'travel_speed': '150',
|
|
'max_z_speed': '1.0',
|
|
'bottom_layer_speed': '25',
|
|
'cool_min_layer_time': '10',
|
|
'fan_enabled': 'True',
|
|
'fan_layer': '0',
|
|
'fan_speed': '100',
|
|
'model_scale': '1.0',
|
|
'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',
|
|
'extra_base_wall_thickness': '0.0',
|
|
'sequence': 'Loops > Perimeter > Infill',
|
|
'force_first_layer_sequence': 'True',
|
|
'infill_type': 'Line',
|
|
'solid_top': 'True',
|
|
'fill_overlap': '15',
|
|
'support_rate': '50',
|
|
'support_distance': '0.5',
|
|
'joris': 'False',
|
|
'enable_skin': 'False',
|
|
'enable_raft': 'False',
|
|
'cool_min_feedrate': '5',
|
|
'bridge_speed': '100',
|
|
'bridge_material_amount': '100',
|
|
'raft_margin': '5',
|
|
'raft_base_material_amount': '100',
|
|
'raft_interface_material_amount': '100',
|
|
'bottom_thickness': '0.0',
|
|
}
|
|
preferencesDefaultSettings = {
|
|
'wizardDone': 'False',
|
|
'startMode': 'Simple',
|
|
'lastFile': 'None',
|
|
'machine_width': '205',
|
|
'machine_depth': '205',
|
|
'machine_height': '200',
|
|
'filament_density': '1300',
|
|
'steps_per_e': '0',
|
|
'serial_port': 'AUTO',
|
|
'serial_baud': '250000',
|
|
'slicer': 'Cura (Skeinforge based)',
|
|
}
|
|
|
|
def getDefaultProfilePath():
|
|
return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../current_profile.ini"))
|
|
|
|
def loadGlobalProfile(filename):
|
|
#Read a configuration file as global config
|
|
global globalProfileParser
|
|
globalProfileParser = ConfigParser.ConfigParser()
|
|
globalProfileParser.read(filename)
|
|
|
|
def saveGlobalProfile(filename):
|
|
#Save the current profile to an ini file
|
|
globalProfileParser.write(open(filename, 'w'))
|
|
|
|
def loadGlobalProfileFromString(options):
|
|
global globalProfileParser
|
|
globalProfileParser = ConfigParser.ConfigParser()
|
|
globalProfileParser.add_section('profile')
|
|
for option in options.split('#'):
|
|
(key, value) = option.split('=', 1)
|
|
globalProfileParser.set('profile', key, value)
|
|
|
|
def getGlobalProfileString():
|
|
global globalProfileParser
|
|
if not globals().has_key('globalProfileParser'):
|
|
loadGlobalProfile(getDefaultProfilePath())
|
|
|
|
ret = []
|
|
for key in globalProfileParser.options('profile'):
|
|
ret.append(key + "=" + globalProfileParser.get('profile', key))
|
|
return '#'.join(ret)
|
|
|
|
def getProfileSetting(name):
|
|
if name in profileDefaultSettings:
|
|
default = profileDefaultSettings[name]
|
|
else:
|
|
print "Missing default setting for: '" + name + "'"
|
|
profileDefaultSettings[name] = ''
|
|
default = ''
|
|
|
|
#Check if we have a configuration file loaded, else load the default.
|
|
if not globals().has_key('globalProfileParser'):
|
|
loadGlobalProfile(getDefaultProfilePath())
|
|
if not globalProfileParser.has_option('profile', name):
|
|
if not globalProfileParser.has_section('profile'):
|
|
globalProfileParser.add_section('profile')
|
|
globalProfileParser.set('profile', name, str(default))
|
|
print name + " not found in profile, so using default: " + str(default)
|
|
return default
|
|
return globalProfileParser.get('profile', name)
|
|
|
|
def putProfileSetting(name, value):
|
|
#Check if we have a configuration file loaded, else load the default.
|
|
if not globals().has_key('globalProfileParser'):
|
|
loadGlobalProfile(getDefaultProfilePath())
|
|
if not globalProfileParser.has_section('profile'):
|
|
globalProfileParser.add_section('profile')
|
|
globalProfileParser.set('profile', name, str(value))
|
|
|
|
global globalPreferenceParser
|
|
globalPreferenceParser = None
|
|
|
|
def getPreferencePath():
|
|
return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../preferences.ini"))
|
|
|
|
def getPreference(name):
|
|
if name in preferencesDefaultSettings:
|
|
default = preferencesDefaultSettings[name]
|
|
else:
|
|
print "Missing default setting for: '" + name + "'"
|
|
preferencesDefaultSettings[name] = ''
|
|
default = ''
|
|
|
|
global globalPreferenceParser
|
|
if globalPreferenceParser == None:
|
|
globalPreferenceParser = ConfigParser.ConfigParser()
|
|
globalPreferenceParser.read(getPreferencePath())
|
|
if not globalPreferenceParser.has_option('preference', name):
|
|
if not globalPreferenceParser.has_section('preference'):
|
|
globalPreferenceParser.add_section('preference')
|
|
globalPreferenceParser.set('preference', name, str(default))
|
|
print name + " not found in preferences, so using default: " + str(default)
|
|
return default
|
|
return unicode(globalPreferenceParser.get('preference', name), "utf-8")
|
|
|
|
def putPreference(name, value):
|
|
#Check if we have a configuration file loaded, else load the default.
|
|
global globalPreferenceParser
|
|
if globalPreferenceParser == None:
|
|
globalPreferenceParser = ConfigParser.ConfigParser()
|
|
globalPreferenceParser.read(getPreferencePath())
|
|
if not globalPreferenceParser.has_section('preference'):
|
|
globalPreferenceParser.add_section('preference')
|
|
globalPreferenceParser.set('preference', name, str(value).encode("utf-8"))
|
|
globalPreferenceParser.write(open(getPreferencePath(), 'w'))
|
|
|
|
#########################################################
|
|
## Utility functions to calculate common profile values
|
|
#########################################################
|
|
def calculateEdgeWidth():
|
|
wallThickness = float(getProfileSetting('wall_thickness'))
|
|
nozzleSize = float(getProfileSetting('nozzle_size'))
|
|
|
|
if wallThickness < nozzleSize:
|
|
return wallThickness
|
|
|
|
lineCount = int(wallThickness / nozzleSize)
|
|
lineWidth = wallThickness / lineCount
|
|
lineWidthAlt = wallThickness / (lineCount + 1)
|
|
if lineWidth > nozzleSize * 1.5:
|
|
return lineWidthAlt
|
|
return lineWidth
|
|
|
|
def calculateLineCount():
|
|
wallThickness = float(getProfileSetting('wall_thickness'))
|
|
nozzleSize = float(getProfileSetting('nozzle_size'))
|
|
|
|
if wallThickness < nozzleSize:
|
|
return 1
|
|
|
|
lineCount = int(wallThickness / nozzleSize + 0.0001)
|
|
lineWidth = wallThickness / lineCount
|
|
lineWidthAlt = wallThickness / (lineCount + 1)
|
|
if lineWidth > nozzleSize * 1.5:
|
|
return lineCount + 1
|
|
return lineCount
|
|
|
|
def calculateSolidLayerCount():
|
|
layerHeight = float(getProfileSetting('layer_height'))
|
|
solidThickness = float(getProfileSetting('solid_layer_thickness'))
|
|
return int(math.ceil(solidThickness / layerHeight - 0.0001))
|
|
|
|
#########################################################
|
|
## Alteration file functions
|
|
#########################################################
|
|
def getCuraBasePath():
|
|
return os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
|
|
|
|
def getAlterationFilePath(filename):
|
|
return os.path.join(getCuraBasePath(), "alterations", filename)
|
|
|
|
def getAlterationFileContents(filename, allowMagicPrefix = True):
|
|
"Get the file from the fileName or the lowercase fileName in the alterations directories."
|
|
prefix = ''
|
|
if allowMagicPrefix:
|
|
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'))
|
|
if eSteps > 0:
|
|
prefix += 'M92 E'+str(eSteps)+'\n'
|
|
temp = float(getProfileSetting('print_temperature'))
|
|
if temp > 0:
|
|
prefix += 'M109 S'+str(temp)+'\n'
|
|
elif filename == 'replace.csv':
|
|
prefix = 'M101\nM103\n'
|
|
fullFilename = getAlterationFilePath(filename)
|
|
if os.path.isfile(fullFilename):
|
|
file = open(fullFilename, "r")
|
|
fileText = file.read()
|
|
file.close()
|
|
return prefix + fileText
|
|
return prefix
|
|
|