chiark / gitweb /
Add back the ultimaker platform, and made the platform mesh simpler.
[cura.git] / Cura / slice / __main__.py
1 from __future__ import absolute_import
2
3 from optparse import OptionParser
4 import sys
5 import re
6 import os
7 import urllib
8 import urllib2
9 import platform
10 import hashlib
11 import subprocess
12
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)
17
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
21
22 def fixUTF8(input):
23         if input.startswith('#UTF8#'):
24                 return input[6:].decode('utf-8')
25         return input
26
27 def main():
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'
36                 sys.exit(1)
37         if options.profile is not None:
38                 profile.loadProfileFromString(options.profile)
39         options.output = fixUTF8(options.output)
40
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]
51                                 position += [1,0,0]
52                                 position += [0,1,0]
53                                 position += [0,0,1]
54
55                         settings = {}
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'))
65                         else:
66                                 settings['sparseInfillLineDistance'] = 9999999
67                         settings['skirtDistance'] = int(profile.getProfileSettingFloat('skirt_gap') * 1000)
68                         settings['skirtLineCount'] = int(profile.getProfileSettingFloat('skirt_line_count'))
69
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)
80
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)]
84                         kwargs = {}
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)
91                         p.communicate()
92                 return
93
94         clearZ = 0
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]
100                         position += [1,0,0]
101                         position += [0,1,0]
102                         position += [0,0,1]
103                 filenames = fixUTF8(args[idx + 1]).split('|')
104
105                 profile.setTempOverride('object_center_x', position[0])
106                 profile.setTempOverride('object_center_y', position[1])
107                 if idx == 0:
108                         resultFile.write(';TYPE:CUSTOM\n')
109                         resultFile.write(profile.getAlterationFileContents('start.gcode', len(filenames)).replace('?filename?', ' '.join(filenames).encode('ascii', 'replace')))
110                 else:
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)
117                         print position
118                         print profile.getAlterationFileContents('nextobject.gcode')
119                         resultFile.write(profile.getAlterationFileContents('nextobject.gcode').replace('?filename?', ' '.join(filenames).encode('ascii', 'replace')))
120
121                 output = []
122                 for filename in filenames:
123                         extruderNr = filenames.index(filename)
124                         profile.resetTempOverride()
125                         if extruderNr > 0:
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])
131                         else:
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])))
135                         if extruderNr > 0:
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()
140                 if len(output) == 1:
141                         resultFile.write(output[0])
142                 else:
143                         stitchMultiExtruder(output, resultFile)
144         resultFile.write(';TYPE:CUSTOM\n')
145         resultFile.write(profile.getAlterationFileContents('end.gcode'))
146         resultFile.close()
147
148         print "Running plugins"
149         ret = profile.runPostProcessingPlugins(options.output)
150         if ret is not None:
151                 print ret
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:
156                         m = hashlib.sha512()
157                         f = open(filename, "rb")
158                         while True:
159                                 chunk = f.read(1024)
160                                 if not chunk:
161                                         break
162                                 m.update(chunk)
163                         f.close()
164                         data = {
165                                 'processor': platform.processor(),
166                                 'machine': platform.machine(),
167                                 'platform': platform.platform(),
168                                 'profile': profile.getProfileString(),
169                                 'preferences': profile.getGlobalPreferencesString(),
170                                 'modelhash': m.hexdigest(),
171                                 'version': version.getVersion(),
172                         }
173                         try:
174                                 f = urllib2.urlopen("http://platform.ultimaker.com/curastats/", data = urllib.urlencode(data), timeout = 5);
175                                 f.read()
176                                 f.close()
177                         except:
178                                 pass
179
180
181 def isPrintingLine(line):
182         if line.startswith("G1") and ('X' in line or 'Y' in line) and 'E' in line:
183                 return True
184         return False
185
186 def getCodeFloat(line, code, default):
187         n = line.find(code) + 1
188         if n < 1:
189                 return default
190         m = line.find(' ', n)
191         try:
192                 if m < 0:
193                         return float(line[n:])
194                 return float(line[n:m])
195         except:
196                 return default
197
198 def stitchMultiExtruder(outputList, resultFile):
199         print "Stitching %i files for multi-extrusion" % (len(outputList))
200         currentExtruder = 0
201         resultFile.write('T%d\n' % (currentExtruder))
202         layerNr = 0
203         hasLine = True
204         outputList = map(lambda o: o.split('\n'), outputList)
205         outputOrder = range(0, len(outputList))
206         outputSlice = []
207         for n in xrange(0, len(outputList)):
208                 outputSlice.append([0, 0])
209         currentX = 0
210         currentY = 0
211         currentZ = 0
212         currentF = 60
213         while hasLine:
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:
223                                 nextExtruder = n
224                                 resultFile.write(';LAYER:%d\n' % (layerNr))
225                                 resultFile.write(';EXTRUDER:%d\n' % (nextExtruder))
226
227                                 startSlice = outputSlice[n][0]
228                                 endSlice = outputSlice[n][1]
229                                 currentE = 0
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)
236                                         startSlice += 1
237                                 while not isPrintingLine(outputList[n][endSlice-1]):
238                                         endSlice -= 1
239
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
248
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')
253
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)
263                                         hasLine = True
264                                 resultFile.write('G92 E0\n')
265                 layerNr += 1
266
267 if __name__ == '__main__':
268         main()