1 from __future__ import absolute_import
\r
2 #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.
\r
10 #########################################################
\r
11 ## Profile and preferences functions
\r
12 #########################################################
\r
14 #Single place to store the defaults, so we have a consistent set of default settings.
\r
15 profileDefaultSettings = {
\r
16 'nozzle_size': '0.4',
\r
17 'layer_height': '0.2',
\r
18 'wall_thickness': '0.8',
\r
19 'solid_layer_thickness': '0.6',
\r
20 'fill_density': '20',
\r
21 'skirt_line_count': '1',
\r
23 'print_speed': '50',
\r
24 'print_temperature': '0',
\r
26 'filament_diameter': '2.89',
\r
27 'filament_density': '1.00',
\r
28 'machine_center_x': '100',
\r
29 'machine_center_y': '100',
\r
30 'retraction_min_travel': '5.0',
\r
31 'retraction_speed': '13.5',
\r
32 'retraction_amount': '0.0',
\r
33 'retraction_extra': '0.0',
\r
34 'travel_speed': '150',
\r
35 'max_z_speed': '1.0',
\r
36 'bottom_layer_speed': '25',
\r
37 'cool_min_layer_time': '10',
\r
38 'fan_enabled': 'True',
\r
41 'model_scale': '1.0',
\r
45 'model_rotate_base': '0',
\r
46 'model_multiply_x': '1',
\r
47 'model_multiply_y': '1',
\r
48 'extra_base_wall_thickness': '0.0',
\r
49 'sequence': 'Loops > Perimeter > Infill',
\r
50 'force_first_layer_sequence': 'True',
\r
51 'infill_type': 'Line',
\r
52 'solid_top': 'True',
\r
53 'fill_overlap': '15',
\r
54 'support_rate': '100',
\r
55 'support_distance': '0.5',
\r
57 'enable_raft': 'False',
\r
58 'cool_min_feedrate': '5',
\r
59 'bridge_speed': '100',
\r
60 'bridge_material_amount': '100',
\r
62 'raft_base_material_amount': '100',
\r
63 'raft_interface_material_amount': '100',
\r
65 preferencesDefaultSettings = {
\r
66 'wizardDone': 'False',
\r
67 'startMode': 'Simple',
\r
69 'machine_width': '205',
\r
70 'machine_depth': '205',
\r
71 'machine_height': '200',
\r
73 'serial_port': 'AUTO',
\r
74 'serial_baud': '250000',
\r
75 'slicer': 'Cura (Skeinforge based)',
\r
78 def getDefaultProfilePath():
\r
79 return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../current_profile.ini"))
\r
81 def loadGlobalProfile(filename):
\r
82 #Read a configuration file as global config
\r
83 global globalProfileParser
\r
84 globalProfileParser = ConfigParser.ConfigParser()
\r
85 globalProfileParser.read(filename)
\r
87 def saveGlobalProfile(filename):
\r
88 #Save the current profile to an ini file
\r
89 globalProfileParser.write(open(filename, 'w'))
\r
91 def loadGlobalProfileFromString(options):
\r
92 global globalProfileParser
\r
93 globalProfileParser = ConfigParser.ConfigParser()
\r
94 globalProfileParser.add_section('profile')
\r
95 for option in options.split('#'):
\r
96 (key, value) = option.split('=', 1)
\r
97 globalProfileParser.set('profile', key, value)
\r
99 def getGlobalProfileString():
\r
100 global globalProfileParser
\r
101 if not globals().has_key('globalProfileParser'):
\r
102 loadGlobalProfile(getDefaultProfilePath())
\r
105 for key in globalProfileParser.options('profile'):
\r
106 ret.append(key + "=" + globalProfileParser.get('profile', key))
\r
107 return '#'.join(ret)
\r
109 def getProfileSetting(name):
\r
110 if name in profileDefaultSettings:
\r
111 default = profileDefaultSettings[name]
\r
113 print "Missing default setting for: '" + name + "'"
\r
114 profileDefaultSettings[name] = ''
\r
117 #Check if we have a configuration file loaded, else load the default.
\r
118 if not globals().has_key('globalProfileParser'):
\r
119 loadGlobalProfile(getDefaultProfilePath())
\r
120 if not globalProfileParser.has_option('profile', name):
\r
121 if not globalProfileParser.has_section('profile'):
\r
122 globalProfileParser.add_section('profile')
\r
123 globalProfileParser.set('profile', name, str(default))
\r
124 print name + " not found in profile, so using default: " + str(default)
\r
126 return globalProfileParser.get('profile', name)
\r
128 def putProfileSetting(name, value):
\r
129 #Check if we have a configuration file loaded, else load the default.
\r
130 if not globals().has_key('globalProfileParser'):
\r
131 loadGlobalProfile(getDefaultProfilePath())
\r
132 if not globalProfileParser.has_section('profile'):
\r
133 globalProfileParser.add_section('profile')
\r
134 globalProfileParser.set('profile', name, str(value))
\r
136 global globalPreferenceParser
\r
137 globalPreferenceParser = None
\r
139 def getPreferencePath():
\r
140 return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../preferences.ini"))
\r
142 def getPreference(name):
\r
143 if name in preferencesDefaultSettings:
\r
144 default = preferencesDefaultSettings[name]
\r
146 print "Missing default setting for: '" + name + "'"
\r
147 preferencesDefaultSettings[name] = ''
\r
150 global globalPreferenceParser
\r
151 if globalPreferenceParser == None:
\r
152 globalPreferenceParser = ConfigParser.ConfigParser()
\r
153 globalPreferenceParser.read(getPreferencePath())
\r
154 if not globalPreferenceParser.has_option('preference', name):
\r
155 if not globalPreferenceParser.has_section('preference'):
\r
156 globalPreferenceParser.add_section('preference')
\r
157 globalPreferenceParser.set('preference', name, str(default))
\r
158 print name + " not found in preferences, so using default: " + str(default)
\r
160 return globalPreferenceParser.get('preference', name)
\r
162 def putPreference(name, value):
\r
163 #Check if we have a configuration file loaded, else load the default.
\r
164 global globalPreferenceParser
\r
165 if globalPreferenceParser == None:
\r
166 globalPreferenceParser = ConfigParser.ConfigParser()
\r
167 globalPreferenceParser.read(getPreferencePath())
\r
168 if not globalPreferenceParser.has_section('preference'):
\r
169 globalPreferenceParser.add_section('preference')
\r
170 globalPreferenceParser.set('preference', name, str(value))
\r
171 globalPreferenceParser.write(open(getPreferencePath(), 'w'))
\r
173 #########################################################
\r
174 ## Utility functions to calculate common profile values
\r
175 #########################################################
\r
176 def calculateEdgeWidth():
\r
177 wallThickness = float(getProfileSetting('wall_thickness'))
\r
178 nozzleSize = float(getProfileSetting('nozzle_size'))
\r
180 if wallThickness < nozzleSize:
\r
181 return wallThickness
\r
183 lineCount = int(wallThickness / nozzleSize)
\r
184 lineWidth = wallThickness / lineCount
\r
185 lineWidthAlt = wallThickness / (lineCount + 1)
\r
186 if lineWidth > nozzleSize * 1.5:
\r
187 return lineWidthAlt
\r
190 def calculateLineCount():
\r
191 wallThickness = float(getProfileSetting('wall_thickness'))
\r
192 nozzleSize = float(getProfileSetting('nozzle_size'))
\r
194 if wallThickness < nozzleSize:
\r
197 lineCount = int(wallThickness / nozzleSize + 0.0001)
\r
198 lineWidth = wallThickness / lineCount
\r
199 lineWidthAlt = wallThickness / (lineCount + 1)
\r
200 if lineWidth > nozzleSize * 1.5:
\r
201 return lineCount + 1
\r
204 def calculateSolidLayerCount():
\r
205 layerHeight = float(getProfileSetting('layer_height'))
\r
206 solidThickness = float(getProfileSetting('solid_layer_thickness'))
\r
207 return int(math.ceil(solidThickness / layerHeight - 0.0001))
\r
209 #########################################################
\r
210 ## Alteration file functions
\r
211 #########################################################
\r
212 def getCuraBasePath():
\r
213 return os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
\r
215 def getAlterationFilePath(filename):
\r
216 return os.path.join(getCuraBasePath(), "alterations", filename)
\r
218 def getAlterationFileContents(filename, allowMagicPrefix = True):
\r
219 "Get the file from the fileName or the lowercase fileName in the alterations directories."
\r
221 if allowMagicPrefix:
\r
222 if filename == 'start.gcode':
\r
223 #For the start code, hack the temperature and the steps per E value into it. So the temperature is reached before the start code extrusion.
\r
224 #We also set our steps per E here, if configured.
\r
225 eSteps = float(getPreference('steps_per_e'))
\r
227 prefix += 'M92 E'+str(eSteps)+'\n'
\r
228 temp = float(getProfileSetting('print_temperature'))
\r
230 prefix += 'M109 S'+str(temp)+'\n'
\r
231 elif filename == 'replace.csv':
\r
232 prefix = 'M101\nM103\n'
\r
233 fullFilename = getAlterationFilePath(filename)
\r
234 if os.path.isfile(fullFilename):
\r
235 file = open(fullFilename, "r")
\r
236 fileText = file.read()
\r
238 return prefix + fileText
\r