1 from __future__ import absolute_import
3 from optparse import OptionParser
13 if not hasattr(sys, 'frozen'):
14 cura_sf_path = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "./cura_sf/"))
15 if cura_sf_path not in sys.path:
16 sys.path.append(cura_sf_path)
18 from Cura.util import profile
19 from Cura.util import version
20 from Cura.slice.cura_sf.skeinforge_application.skeinforge_plugins.craft_plugins import export
23 if input.startswith('#UTF8#'):
24 return input[6:].decode('utf-8')
28 parser = OptionParser(usage="usage: %prog [options] <X,Y> <filename>[, <X,Y> <filename>][, ...]")
29 parser.add_option("-p", "--profile", action="store", type="string", dest="profile",
30 help="Encoded profile to use for the print")
31 parser.add_option("-o", "--output", action="store", type="string", dest="output",
32 help="Output filename")
33 (options, args) = parser.parse_args()
34 if options.output is None:
35 print 'Missing output filename'
37 if options.profile is not None:
38 profile.loadGlobalProfileFromString(options.profile)
39 options.output = fixUTF8(options.output)
41 steamEngineFilename = os.path.join(os.path.dirname(__file__), 'SteamEngine')
42 if platform.system() == "Windows":
43 steamEngineFilename += ".exe"
44 if os.path.isfile("C:\Software\Cura_SteamEngine\_bin\Release\Cura_SteamEngine.exe"):
45 steamEngineFilename = "C:\Software\Cura_SteamEngine\_bin\Release\Cura_SteamEngine.exe"
46 if os.path.isfile(steamEngineFilename):
47 for idx in xrange(0, len(args), 2):
48 position = map(float, args[idx].split(','))
49 if len(position) < 9 + 2:
50 position = position[0:2]
56 settings['layerThickness'] = int(profile.getProfileSettingFloat('layer_height') * 1000)
57 settings['initialLayerThickness'] = int(profile.getProfileSettingFloat('bottom_thickness') * 1000)
58 settings['filamentDiameter'] = int(profile.getProfileSettingFloat('filament_diameter') * 1000)
59 settings['extrusionWidth'] = int(profile.calculateEdgeWidth() * 1000)
60 settings['insetCount'] = int(profile.calculateLineCount())
61 settings['downSkinCount'] = int(profile.calculateSolidLayerCount())
62 settings['upSkinCount'] = int(profile.calculateSolidLayerCount())
63 if profile.getProfileSettingFloat('fill_density') > 0:
64 settings['sparseInfillLineDistance'] = int(100 * 1000 * profile.calculateEdgeWidth() / profile.getProfileSettingFloat('fill_density'))
66 settings['sparseInfillLineDistance'] = 9999999
67 settings['skirtDistance'] = int(profile.getProfileSettingFloat('skirt_gap') * 1000)
68 settings['skirtLineCount'] = int(profile.getProfileSettingFloat('skirt_line_count'))
70 settings['initialSpeedupLayers'] = int(4)
71 settings['initialLayerSpeed'] = int(profile.getProfileSettingFloat('bottom_layer_speed'))
72 settings['printSpeed'] = int(profile.getProfileSettingFloat('print_speed'))
73 settings['moveSpeed'] = int(profile.getProfileSettingFloat('travel_speed'))
74 settings['fanOnLayerNr'] = int(profile.getProfileSettingFloat('fan_layer'))
75 settings['supportAngle'] = int(60) if profile.getProfileSetting('support') != 'None' else int(-1)
76 settings['supportEverywhere'] = int(1) if profile.getProfileSetting('support') == 'Everywhere' else int(0)
77 settings['retractionAmount'] = int(0) if profile.getProfileSetting('retraction_enable') == 'False' else int(profile.getProfileSettingFloat('retraction_amount') * 1000)
78 settings['retractionSpeed'] = int(profile.getProfileSettingFloat('retraction_speed'))
79 settings['objectSink'] = int(profile.getProfileSettingFloat('object_sink') * 1000.0)
81 cmdList = [steamEngineFilename, args[idx+1], '-o', options.output, '-m', ','.join(map(str, position[2:]))]
82 for (key, value) in settings.items():
83 cmdList += ['-s', str(key) + "=" + str(value)]
85 if subprocess.mswindows:
86 su = subprocess.STARTUPINFO()
87 su.dwFlags |= subprocess.STARTF_USESHOWWINDOW
88 su.wShowWindow = subprocess.SW_HIDE
89 kwargs['startupinfo'] = su
90 p = subprocess.Popen(cmdList, **kwargs)
95 resultFile = open(options.output, "w")
96 for idx in xrange(0, len(args), 2):
97 position = map(float, args[idx].split(','))
98 if len(position) < 9 + 2:
99 position = position[0:2]
103 filenames = fixUTF8(args[idx + 1]).split('|')
105 profile.setTempOverride('object_center_x', position[0])
106 profile.setTempOverride('object_center_y', position[1])
108 resultFile.write(';TYPE:CUSTOM\n')
109 resultFile.write(profile.getAlterationFileContents('start.gcode', len(filenames)).replace('?filename?', ' '.join(filenames).encode('ascii', 'replace')))
111 resultFile.write(';TYPE:CUSTOM\n')
112 n = output[-1].rfind('Z')+1
113 zString = output[-1][n:n+20]
114 zString = zString[0:zString.find(' ')]
115 clearZ = max(clearZ, float(zString) + 10)
116 profile.setTempOverride('clear_z', clearZ)
118 print profile.getAlterationFileContents('nextobject.gcode')
119 resultFile.write(profile.getAlterationFileContents('nextobject.gcode').replace('?filename?', ' '.join(filenames).encode('ascii', 'replace')))
122 for filename in filenames:
123 extruderNr = filenames.index(filename)
124 profile.resetTempOverride()
126 profile.setTempOverride('object_center_x', position[0] - profile.getPreferenceFloat('extruder_offset_x%d' % (extruderNr)))
127 profile.setTempOverride('object_center_y', position[1] - profile.getPreferenceFloat('extruder_offset_y%d' % (extruderNr)))
128 profile.setTempOverride('fan_enabled', 'False')
129 profile.setTempOverride('skirt_line_count', '0')
130 profile.setTempOverride('alternative_center', filenames[0])
132 profile.setTempOverride('object_center_x', position[0])
133 profile.setTempOverride('object_center_y', position[1])
134 profile.setTempOverride('object_matrix', ','.join(map(str, position[2:11])))
136 if profile.getProfileSettingFloat('filament_diameter%d' % (extruderNr + 1)) > 0:
137 profile.setTempOverride('filament_diameter', profile.getProfileSetting('filament_diameter%d' % (extruderNr + 1)))
138 output.append(export.getOutput(filename))
139 profile.resetTempOverride()
141 resultFile.write(output[0])
143 stitchMultiExtruder(output, resultFile)
144 resultFile.write(';TYPE:CUSTOM\n')
145 resultFile.write(profile.getAlterationFileContents('end.gcode'))
148 print "Running plugins"
149 ret = profile.runPostProcessingPlugins(options.output)
152 print "Finalizing %s" % (os.path.basename(options.output))
153 if profile.getPreference('submit_slice_information') == 'True':
154 filenames = fixUTF8(args[idx + 1]).split('|')
155 for filename in filenames:
157 f = open(filename, "rb")
165 'processor': platform.processor(),
166 'machine': platform.machine(),
167 'platform': platform.platform(),
168 'profile': profile.getGlobalProfileString(),
169 'preferences': profile.getGlobalPreferencesString(),
170 'modelhash': m.hexdigest(),
171 'version': version.getVersion(),
174 f = urllib2.urlopen("http://platform.ultimaker.com/curastats/", data = urllib.urlencode(data), timeout = 5);
181 def isPrintingLine(line):
182 if line.startswith("G1") and ('X' in line or 'Y' in line) and 'E' in line:
186 def getCodeFloat(line, code, default):
187 n = line.find(code) + 1
190 m = line.find(' ', n)
193 return float(line[n:])
194 return float(line[n:m])
198 def stitchMultiExtruder(outputList, resultFile):
199 print "Stitching %i files for multi-extrusion" % (len(outputList))
201 resultFile.write('T%d\n' % (currentExtruder))
204 outputList = map(lambda o: o.split('\n'), outputList)
205 outputOrder = range(0, len(outputList))
207 for n in xrange(0, len(outputList)):
208 outputSlice.append([0, 0])
214 hasLine = layerNr < 1000
215 for n in xrange(0, len(outputList)):
216 outputSlice[n][0] = outputSlice[n][1] + 1
217 outputSlice[n][1] = outputSlice[n][0]
218 while outputSlice[n][1] < len(outputList[n]) and not outputList[n][outputSlice[n][1]].startswith(';LAYER:'):
219 outputSlice[n][1] += 1
220 outputOrder = range(currentExtruder, len(outputList)) + range(0, currentExtruder)
221 for n in outputOrder:
222 if outputSlice[n][1] > outputSlice[n][0] + 1:
224 resultFile.write(';LAYER:%d\n' % (layerNr))
225 resultFile.write(';EXTRUDER:%d\n' % (nextExtruder))
227 startSlice = outputSlice[n][0]
228 endSlice = outputSlice[n][1]
230 while not isPrintingLine(outputList[n][startSlice]):
231 currentE = getCodeFloat(outputList[n][startSlice], 'E', currentE)
232 currentX = getCodeFloat(outputList[n][startSlice], 'X', currentX)
233 currentY = getCodeFloat(outputList[n][startSlice], 'Y', currentY)
234 currentZ = getCodeFloat(outputList[n][startSlice], 'Z', currentZ)
235 currentF = getCodeFloat(outputList[n][startSlice], 'F', currentF)
237 while not isPrintingLine(outputList[n][endSlice-1]):
240 if nextExtruder != currentExtruder:
241 profile.setTempOverride('extruder', nextExtruder)
242 profile.setTempOverride('new_x', currentX)
243 profile.setTempOverride('new_y', currentY)
244 profile.setTempOverride('new_z', currentZ)
245 resultFile.write(profile.getAlterationFileContents('switchExtruder.gcode') + '\n')
246 profile.resetTempOverride()
247 currentExtruder = nextExtruder
249 for idx in xrange(outputSlice[n][0], startSlice):
250 if not 'G1' in outputList[n][idx]:
251 resultFile.write(outputList[n][idx])
252 resultFile.write('\n')
254 resultFile.write('G1 X%f Y%f Z%f F%f\n' % (currentX, currentY, currentZ, profile.getProfileSettingFloat('travel_speed') * 60))
255 resultFile.write('G1 F%f\n' % (currentF))
256 resultFile.write('G92 E%f\n' % (currentE))
257 for idx in xrange(startSlice, endSlice):
258 resultFile.write(outputList[n][idx])
259 resultFile.write('\n')
260 currentX = getCodeFloat(outputList[n][idx], 'X', currentX)
261 currentY = getCodeFloat(outputList[n][idx], 'Y', currentY)
262 currentZ = getCodeFloat(outputList[n][idx], 'Z', currentZ)
264 resultFile.write('G92 E0\n')
267 if __name__ == '__main__':