chiark / gitweb /
Add instant slicing.
[cura.git] / Cura / util / sliceEngine.py
1 import subprocess
2 import time
3 import numpy
4 import os
5 import warnings
6 import threading
7
8 from Cura.util import profile
9
10 def getEngineFilename():
11         return 'C:/Software/Cura_SteamEngine/_bin/Release/Cura_SteamEngine.exe'
12
13 def getTempFilename():
14         warnings.simplefilter('ignore')
15         ret = os.tempnam(None, "Cura_Tmp")
16         warnings.simplefilter('default')
17         return ret
18
19 class Slicer(object):
20         def __init__(self, progressCallback):
21                 self._process = None
22                 self._thread = None
23                 self._callback = progressCallback
24                 self._binaryStorageFilename = getTempFilename()
25                 self._exportFilename = getTempFilename()
26                 self._progressSteps = ['inset', 'skin', 'export']
27
28         def abortSlicer(self):
29                 if self._process is not None:
30                         self._process.terminate()
31                         self._thread.join()
32
33         def runSlicer(self, scene):
34                 self.abortSlicer()
35                 self._callback(0.0, False)
36
37                 commandList = [getEngineFilename(), '-vv']
38                 for k, v in self._engineSettings().iteritems():
39                         commandList += ['-s', '%s=%s' % (k, str(v))]
40                 commandList += ['-o', self._exportFilename]
41                 commandList += ['-b', self._binaryStorageFilename]
42                 self._objCount = 0
43                 with open(self._binaryStorageFilename, "wb") as f:
44                         for obj in scene._objectList:
45                                 if not scene.checkPlatform(obj):
46                                         continue
47                                 for mesh in obj._meshList:
48                                         n = numpy.array(mesh.vertexCount, numpy.int32)
49                                         f.write(n.tostring())
50                                         f.write(mesh.vertexes.tostring())
51                                 pos = obj.getPosition() * 1000
52                                 pos += numpy.array([profile.getPreferenceFloat('machine_width') * 1000 / 2, profile.getPreferenceFloat('machine_depth') * 1000 / 2])
53                                 commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1]), '#']
54                                 self._objCount += 1
55                 if self._objCount > 0:
56                         print ' '.join(commandList)
57                         self._process = self._runSliceProcess(commandList)
58                         self._thread = threading.Thread(target=self._watchProcess)
59                         self._thread.daemon = True
60                         self._thread.start()
61
62         def _watchProcess(self):
63                 self._callback(0.0, False)
64                 line = self._process.stdout.readline()
65                 while len(line):
66                         line = line.strip()
67                         if line.startswith('Progress:'):
68                                 line = line.split(':')
69                                 progressValue = float(line[2]) / float(line[3])
70                                 progressValue /= len(self._progressSteps)
71                                 progressValue += 1.0 / len(self._progressSteps) * self._progressSteps.index(line[1])
72                                 self._callback(progressValue, False)
73                         else:
74                                 print '#', line.strip()
75                         line = self._process.stdout.readline()
76                 for line in self._process.stderr:
77                         print line.strip()
78                 returnCode = self._process.wait()
79                 print returnCode
80                 if returnCode == 0:
81                         self._callback(1.0, True)
82                 else:
83                         self._callback(0.0, False)
84                 self._process = None
85
86         def _engineSettings(self):
87                 return {
88                         'layerThickness': int(profile.getProfileSettingFloat('layer_height') * 1000),
89                         'initialLayerThickness': int(profile.getProfileSettingFloat('bottom_thickness') * 1000),
90                         'filamentDiameter': int(profile.getProfileSettingFloat('filament_diameter') * 1000),
91                         'extrusionWidth': int(profile.calculateEdgeWidth() * 1000),
92                         'insetCount': int(profile.calculateLineCount()),
93                         'downSkinCount': int(profile.calculateSolidLayerCount()),
94                         'upSkinCount': int(profile.calculateSolidLayerCount()),
95                         'sparseInfillLineDistance': int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('fill_density')),
96                         'skirtDistance': int(profile.getProfileSettingFloat('skirt_gap') * 1000),
97                         'skirtLineCount': int(profile.getProfileSettingFloat('skirt_line_count')),
98                         'initialSpeedupLayers': int(4),
99                         'initialLayerSpeed': int(profile.getProfileSettingFloat('bottom_layer_speed')),
100                         'printSpeed': int(profile.getProfileSettingFloat('print_speed')),
101                         'moveSpeed': int(profile.getProfileSettingFloat('travel_speed')),
102                         'fanOnLayerNr': int(profile.getProfileSettingFloat('fan_layer')),
103                         'supportAngle': int(-1) if profile.getProfileSetting('support') == 'None' else int(60),
104                         'supportEverywhere': int(1) if profile.getProfileSetting('support') == 'Everywhere' else int(0),
105                         'retractionAmount': int(profile.getProfileSettingFloat('retraction_amount') * 1000),
106                         'retractionSpeed': int(profile.getProfileSettingFloat('retraction_speed')),
107                         'objectSink': int(profile.getProfileSettingFloat('object_sink') * 1000),
108                 }
109
110         def _runSliceProcess(self, cmdList):
111                 kwargs = {}
112                 if subprocess.mswindows:
113                         su = subprocess.STARTUPINFO()
114                         su.dwFlags |= subprocess.STARTF_USESHOWWINDOW
115                         su.wShowWindow = subprocess.SW_HIDE
116                         kwargs['startupinfo'] = su
117                 return subprocess.Popen(cmdList, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)