2 Slice engine communication.
3 This module handles all communication with the slicing engine.
5 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
22 import cStringIO as StringIO
24 from Cura.util import profile
25 from Cura.util import pluginInfo
26 from Cura.util import version
27 from Cura.util import gcodeInterpreter
29 def getEngineFilename():
31 Finds and returns the path to the current engine executable. This is OS depended.
32 :return: The full path to the engine executable.
34 if platform.system() == 'Windows':
35 if version.isDevVersion() and os.path.exists('C:/Software/Cura_SteamEngine/_bin/Release/Cura_SteamEngine.exe'):
36 return 'C:/Software/Cura_SteamEngine/_bin/Release/Cura_SteamEngine.exe'
37 return os.path.abspath(os.path.join(os.path.dirname(__file__), '../..', 'CuraEngine.exe'))
38 if hasattr(sys, 'frozen'):
39 return os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../../..', 'CuraEngine'))
40 if os.path.isfile('/usr/bin/CuraEngine'):
41 return '/usr/bin/CuraEngine'
42 if os.path.isfile('/usr/local/bin/CuraEngine'):
43 return '/usr/local/bin/CuraEngine'
44 tempPath = os.path.abspath(os.path.join(os.path.dirname(__file__), '../..', 'CuraEngine'))
45 if os.path.isdir(tempPath):
46 tempPath = os.path.join(tempPath,'CuraEngine')
49 class EngineResult(object):
51 Result from running the CuraEngine.
52 Contains the engine log, polygons retrieved from the engine, the GCode and some meta-data.
56 self._gcodeData = StringIO.StringIO()
58 self._replaceInfo = {}
60 self._printTimeSeconds = None
61 self._filamentMM = [0.0] * 4
62 self._modelHash = None
63 self._profileString = profile.getProfileString()
64 self._preferencesString = profile.getPreferencesString()
65 self._gcodeInterpreter = gcodeInterpreter.gcode()
66 self._gcodeLoadThread = None
67 self._finished = False
69 def getFilamentWeight(self, e=0):
70 #Calculates the weight of the filament in kg
71 radius = float(profile.getProfileSetting('filament_diameter')) / 2
72 volumeM3 = (self._filamentMM[e] * (math.pi * radius * radius)) / (1000*1000*1000)
73 return volumeM3 * profile.getPreferenceFloat('filament_physical_density')
75 def getFilamentCost(self, e=0):
76 cost_kg = profile.getPreferenceFloat('filament_cost_kg')
77 cost_meter = profile.getPreferenceFloat('filament_cost_meter')
78 if cost_kg > 0.0 and cost_meter > 0.0:
79 return "%.2f / %.2f" % (self.getFilamentWeight(e) * cost_kg, self._filamentMM[e] / 1000.0 * cost_meter)
81 return "%.2f" % (self.getFilamentWeight(e) * cost_kg)
82 elif cost_meter > 0.0:
83 return "%.2f" % (self._filamentMM[e] / 1000.0 * cost_meter)
86 def getPrintTime(self):
87 if self._printTimeSeconds is None:
89 if int(self._printTimeSeconds / 60 / 60) < 1:
90 return '%d minutes' % (int(self._printTimeSeconds / 60) % 60)
91 if int(self._printTimeSeconds / 60 / 60) == 1:
92 return '%d hour %d minutes' % (int(self._printTimeSeconds / 60 / 60), int(self._printTimeSeconds / 60) % 60)
93 return '%d hours %d minutes' % (int(self._printTimeSeconds / 60 / 60), int(self._printTimeSeconds / 60) % 60)
95 def getFilamentAmount(self, e=0):
96 if self._filamentMM[e] == 0.0:
98 return '%0.2f meter %0.0f gram' % (float(self._filamentMM[e]) / 1000.0, self.getFilamentWeight(e) * 1000.0)
101 return self._engineLog
104 data = self._gcodeData.getvalue()
105 if len(self._replaceInfo) > 0:
106 block0 = data[0:2048]
107 for k, v in self._replaceInfo.items():
108 v = (v + ' ' * len(k))[:len(k)]
109 block0 = block0.replace(k, v)
110 return block0 + data[2048:]
113 def setGCode(self, gcode):
114 self._gcodeData = StringIO.StringIO(gcode)
115 self._replaceInfo = {}
117 def addLog(self, line):
118 self._engineLog.append(line)
120 def setHash(self, hash):
121 self._modelHash = hash
123 def setFinished(self, result):
124 self._finished = result
126 def isFinished(self):
127 return self._finished
129 def getGCodeLayers(self, loadCallback):
130 if not self._finished:
132 if self._gcodeInterpreter.layerList is None and self._gcodeLoadThread is None:
133 self._gcodeInterpreter.progressCallback = self._gcodeInterpreterCallback
134 self._gcodeLoadThread = threading.Thread(target=lambda : self._gcodeInterpreter.load(self._gcodeData))
135 self._gcodeLoadCallback = loadCallback
136 self._gcodeLoadThread.daemon = True
137 self._gcodeLoadThread.start()
138 return self._gcodeInterpreter.layerList
140 def _gcodeInterpreterCallback(self, progress):
141 if len(self._gcodeInterpreter.layerList) % 5 == 0:
143 return self._gcodeLoadCallback(self, progress)
145 def submitInfoOnline(self):
146 if profile.getPreference('submit_slice_information') != 'True':
148 if version.isDevVersion():
151 'processor': platform.processor(),
152 'machine': platform.machine(),
153 'platform': platform.platform(),
154 'profile': self._profileString,
155 'preferences': self._preferencesString,
156 'modelhash': self._modelHash,
157 'version': version.getVersion(),
160 f = urllib2.urlopen("https://www.youmagine.com/curastats/", data = urllib.urlencode(data), timeout = 1)
165 traceback.print_exc()
167 class Engine(object):
169 Class used to communicate with the CuraEngine.
170 The CuraEngine is ran as a 2nd process and reports back information trough stderr.
171 GCode trough stdout and has a socket connection for polygon information and loading the 3D model into the engine.
173 GUI_CMD_REQUEST_MESH = 0x01
174 GUI_CMD_SEND_POLYGONS = 0x02
175 GUI_CMD_FINISH_OBJECT = 0x03
177 def __init__(self, progressCallback):
180 self._callback = progressCallback
181 self._progressSteps = ['inset', 'skin', 'export']
185 self._serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
186 self._serverPortNr = 0xC20A
189 self._serversocket.bind(('127.0.0.1', self._serverPortNr))
191 print "Failed to listen on port: %d" % (self._serverPortNr)
192 self._serverPortNr += 1
193 if self._serverPortNr > 0xFFFF:
194 print "Failed to listen on any port..."
198 thread = threading.Thread(target=self._socketListenThread)
202 def _socketListenThread(self):
203 self._serversocket.listen(1)
204 print 'Listening for engine communications on %d' % (self._serverPortNr)
207 sock, _ = self._serversocket.accept()
208 thread = threading.Thread(target=self._socketConnectionThread, args=(sock,))
211 except socket.error, e:
212 if e.errno != errno.EINTR:
215 def _socketConnectionThread(self, sock):
225 cmd = struct.unpack('@i', data)[0]
226 if cmd == self.GUI_CMD_REQUEST_MESH:
227 meshInfo = self._modelData[0]
228 self._modelData = self._modelData[1:]
229 sock.sendall(struct.pack('@i', meshInfo[0]))
230 sock.sendall(meshInfo[1].tostring())
231 elif cmd == self.GUI_CMD_SEND_POLYGONS:
232 cnt = struct.unpack('@i', sock.recv(4))[0]
233 layerNr = struct.unpack('@i', sock.recv(4))[0]
234 layerNr += layerNrOffset
235 z = struct.unpack('@i', sock.recv(4))[0]
236 z = float(z) / 1000.0
237 typeNameLen = struct.unpack('@i', sock.recv(4))[0]
238 typeName = sock.recv(typeNameLen)
239 while len(self._result._polygons) < layerNr + 1:
240 self._result._polygons.append({})
241 polygons = self._result._polygons[layerNr]
242 if typeName not in polygons:
243 polygons[typeName] = []
244 for n in xrange(0, cnt):
245 length = struct.unpack('@i', sock.recv(4))[0]
247 while len(data) < length * 8 * 2:
248 recvData = sock.recv(length * 8 * 2 - len(data))
249 if len(recvData) < 1:
252 polygon2d = numpy.array(numpy.fromstring(data, numpy.int64), numpy.float32) / 1000.0
253 polygon2d = polygon2d.reshape((len(polygon2d) / 2, 2))
254 polygon = numpy.empty((len(polygon2d), 3), numpy.float32)
255 polygon[:,:-1] = polygon2d
257 polygons[typeName].append(polygon)
258 elif cmd == self.GUI_CMD_FINISH_OBJECT:
259 layerNrOffset = len(self._result._polygons)
261 print "Unknown command on socket: %x" % (cmd)
265 self._serversocket.close()
267 def abortEngine(self):
268 if self._process is not None:
270 self._process.terminate()
273 if self._thread is not None:
278 if self._thread is not None:
284 def runEngine(self, scene):
285 if len(scene.objects()) < 1:
288 for obj in scene.objects():
289 if scene.checkPlatform(obj):
290 extruderCount = max(extruderCount, len(obj._meshList))
292 extruderCount = max(extruderCount, profile.minimalExtruderCount())
294 commandList = [getEngineFilename(), '-v', '-p']
295 for k, v in self._engineSettings(extruderCount).iteritems():
296 commandList += ['-s', '%s=%s' % (k, str(v))]
297 commandList += ['-g', '%d' % (self._serverPortNr)]
300 hash = hashlib.sha512()
301 order = scene.printOrder()
303 pos = numpy.array(profile.getMachineCenterCoords()) * 1000
306 for obj in scene.objects():
307 if scene.checkPlatform(obj):
308 oMin = obj.getMinimum()[0:2] + obj.getPosition()
309 oMax = obj.getMaximum()[0:2] + obj.getPosition()
314 objMin[0] = min(oMin[0], objMin[0])
315 objMin[1] = min(oMin[1], objMin[1])
316 objMax[0] = max(oMax[0], objMax[0])
317 objMax[1] = max(oMax[1], objMax[1])
320 pos += (objMin + objMax) / 2.0 * 1000
321 commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
323 vertexTotal = [0] * 4
325 for obj in scene.objects():
326 if scene.checkPlatform(obj):
327 meshMax = max(meshMax, len(obj._meshList))
328 for n in xrange(0, len(obj._meshList)):
329 vertexTotal[n] += obj._meshList[n].vertexCount
331 for n in xrange(0, meshMax):
332 verts = numpy.zeros((0, 3), numpy.float32)
333 for obj in scene.objects():
334 if scene.checkPlatform(obj):
335 if n < len(obj._meshList):
336 vertexes = (numpy.matrix(obj._meshList[n].vertexes, copy = False) * numpy.matrix(obj._matrix, numpy.float32)).getA()
337 vertexes -= obj._drawOffset
338 vertexes += numpy.array([obj.getPosition()[0], obj.getPosition()[1], 0.0])
339 verts = numpy.concatenate((verts, vertexes))
340 hash.update(obj._meshList[n].vertexes.tostring())
341 engineModelData.append((vertexTotal[n], verts))
343 commandList += ['$' * meshMax]
347 obj = scene.objects()[n]
348 for mesh in obj._meshList:
349 engineModelData.append((mesh.vertexCount, mesh.vertexes))
350 hash.update(mesh.vertexes.tostring())
351 pos = obj.getPosition() * 1000
352 pos += numpy.array(profile.getMachineCenterCoords()) * 1000
353 commandList += ['-m', ','.join(map(str, obj._matrix.getA().flatten()))]
354 commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
355 commandList += ['$' * len(obj._meshList)]
357 modelHash = hash.hexdigest()
358 if self._objCount > 0:
359 self._thread = threading.Thread(target=self._watchProcess, args=(commandList, self._thread, engineModelData, modelHash))
360 self._thread.daemon = True
363 def _watchProcess(self, commandList, oldThread, engineModelData, modelHash):
364 if oldThread is not None:
365 if self._process is not None:
366 self._process.terminate()
369 self._modelData = engineModelData
371 self._process = self._runEngineProcess(commandList)
373 traceback.print_exc()
375 if self._thread != threading.currentThread():
376 self._process.terminate()
378 self._result = EngineResult()
379 self._result.addLog('Running: %s' % (' '.join(commandList)))
380 self._result.setHash(modelHash)
383 logThread = threading.Thread(target=self._watchStderr, args=(self._process.stderr,))
384 logThread.daemon = True
387 data = self._process.stdout.read(4096)
389 self._result._gcodeData.write(data)
390 data = self._process.stdout.read(4096)
392 returnCode = self._process.wait()
395 pluginError = pluginInfo.runPostProcessingPlugins(self._result)
396 if pluginError is not None:
398 self._result.addLog(pluginError)
399 self._result.setFinished(True)
402 for line in self._result.getLog():
407 def _watchStderr(self, stderr):
409 line = stderr.readline()
412 if line.startswith('Progress:'):
413 line = line.split(':')
414 if line[1] == 'process':
416 elif line[1] in self._progressSteps:
417 progressValue = float(line[2]) / float(line[3])
418 progressValue /= len(self._progressSteps)
419 progressValue += 1.0 / len(self._progressSteps) * self._progressSteps.index(line[1])
421 progressValue /= self._objCount
422 progressValue += 1.0 / self._objCount * objectNr
424 self._callback(progressValue)
427 elif line.startswith('Print time:'):
428 self._result._printTimeSeconds = int(line.split(':')[1].strip())
429 elif line.startswith('Filament:'):
430 self._result._filamentMM[0] = int(line.split(':')[1].strip())
431 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
432 radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
433 self._result._filamentMM[0] /= (math.pi * radius * radius)
434 elif line.startswith('Filament2:'):
435 self._result._filamentMM[1] = int(line.split(':')[1].strip())
436 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
437 radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
438 self._result._filamentMM[1] /= (math.pi * radius * radius)
439 elif line.startswith('Replace:'):
440 self._result._replaceInfo[line.split(':')[1].strip()] = line.split(':')[2].strip()
442 self._result.addLog(line)
443 line = stderr.readline()
445 def _engineSettings(self, extruderCount):
447 'layerThickness': int(profile.getProfileSettingFloat('layer_height') * 1000),
448 'initialLayerThickness': int(profile.getProfileSettingFloat('bottom_thickness') * 1000) if profile.getProfileSettingFloat('bottom_thickness') > 0.0 else int(profile.getProfileSettingFloat('layer_height') * 1000),
449 'filamentDiameter': int(profile.getProfileSettingFloat('filament_diameter') * 1000),
450 'filamentFlow': int(profile.getProfileSettingFloat('filament_flow')),
451 'extrusionWidth': int(profile.calculateEdgeWidth() * 1000),
452 'layer0extrusionWidth': int(profile.calculateEdgeWidth() * profile.getProfileSettingFloat('layer0_width_factor') / 100 * 1000),
453 'insetCount': int(profile.calculateLineCount()),
454 'downSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_bottom') == 'True' else 0,
455 'upSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_top') == 'True' else 0,
456 'infillOverlap': int(profile.getProfileSettingFloat('fill_overlap')),
457 'initialSpeedupLayers': int(4),
458 'initialLayerSpeed': int(profile.getProfileSettingFloat('bottom_layer_speed')),
459 'printSpeed': int(profile.getProfileSettingFloat('print_speed')),
460 'infillSpeed': int(profile.getProfileSettingFloat('infill_speed')) if int(profile.getProfileSettingFloat('infill_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
461 'inset0Speed': int(profile.getProfileSettingFloat('inset0_speed')) if int(profile.getProfileSettingFloat('inset0_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
462 'insetXSpeed': int(profile.getProfileSettingFloat('insetx_speed')) if int(profile.getProfileSettingFloat('insetx_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
463 'moveSpeed': int(profile.getProfileSettingFloat('travel_speed')),
464 'fanSpeedMin': int(profile.getProfileSettingFloat('fan_speed')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
465 'fanSpeedMax': int(profile.getProfileSettingFloat('fan_speed_max')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
466 'supportAngle': int(-1) if profile.getProfileSetting('support') == 'None' else int(profile.getProfileSettingFloat('support_angle')),
467 'supportEverywhere': int(1) if profile.getProfileSetting('support') == 'Everywhere' else int(0),
468 'supportLineDistance': int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('support_fill_rate')) if profile.getProfileSettingFloat('support_fill_rate') > 0 else -1,
469 'supportXYDistance': int(1000 * profile.getProfileSettingFloat('support_xy_distance')),
470 'supportZDistance': int(1000 * profile.getProfileSettingFloat('support_z_distance')),
471 'supportExtruder': 0 if profile.getProfileSetting('support_dual_extrusion') == 'First extruder' else (1 if profile.getProfileSetting('support_dual_extrusion') == 'Second extruder' and profile.minimalExtruderCount() > 1 else -1),
472 'retractionAmount': int(profile.getProfileSettingFloat('retraction_amount') * 1000) if profile.getProfileSetting('retraction_enable') == 'True' else 0,
473 'retractionSpeed': int(profile.getProfileSettingFloat('retraction_speed')),
474 'retractionMinimalDistance': int(profile.getProfileSettingFloat('retraction_min_travel') * 1000),
475 'retractionAmountExtruderSwitch': int(profile.getProfileSettingFloat('retraction_dual_amount') * 1000),
476 'retractionZHop': int(profile.getProfileSettingFloat('retraction_hop') * 1000),
477 'minimalExtrusionBeforeRetraction': int(profile.getProfileSettingFloat('retraction_minimal_extrusion') * 1000),
478 'enableCombing': 1 if profile.getProfileSetting('retraction_combing') == 'True' else 0,
479 'multiVolumeOverlap': int(profile.getProfileSettingFloat('overlap_dual') * 1000),
480 'objectSink': max(0, int(profile.getProfileSettingFloat('object_sink') * 1000)),
481 'minimalLayerTime': int(profile.getProfileSettingFloat('cool_min_layer_time')),
482 'minimalFeedrate': int(profile.getProfileSettingFloat('cool_min_feedrate')),
483 'coolHeadLift': 1 if profile.getProfileSetting('cool_head_lift') == 'True' else 0,
484 'startCode': profile.getAlterationFileContents('start.gcode', extruderCount),
485 'endCode': profile.getAlterationFileContents('end.gcode', extruderCount),
486 'preSwitchExtruderCode': profile.getAlterationFileContents('preSwitchExtruder.gcode', extruderCount),
487 'postSwitchExtruderCode': profile.getAlterationFileContents('postSwitchExtruder.gcode', extruderCount),
489 'extruderOffset[1].X': int(profile.getMachineSettingFloat('extruder_offset_x1') * 1000),
490 'extruderOffset[1].Y': int(profile.getMachineSettingFloat('extruder_offset_y1') * 1000),
491 'extruderOffset[2].X': int(profile.getMachineSettingFloat('extruder_offset_x2') * 1000),
492 'extruderOffset[2].Y': int(profile.getMachineSettingFloat('extruder_offset_y2') * 1000),
493 'extruderOffset[3].X': int(profile.getMachineSettingFloat('extruder_offset_x3') * 1000),
494 'extruderOffset[3].Y': int(profile.getMachineSettingFloat('extruder_offset_y3') * 1000),
497 fanFullHeight = int(profile.getProfileSettingFloat('fan_full_height') * 1000)
498 settings['fanFullOnLayerNr'] = (fanFullHeight - settings['initialLayerThickness'] - 1) / settings['layerThickness'] + 1
499 if settings['fanFullOnLayerNr'] < 0:
500 settings['fanFullOnLayerNr'] = 0
501 if profile.getProfileSetting('support_type') == 'Lines':
502 settings['supportType'] = 1
504 if profile.getProfileSettingFloat('fill_density') == 0:
505 settings['sparseInfillLineDistance'] = -1
506 elif profile.getProfileSettingFloat('fill_density') == 100:
507 settings['sparseInfillLineDistance'] = settings['extrusionWidth']
508 #Set the up/down skins height to 10000 if we want a 100% filled object.
509 # This gives better results then normal 100% infill as the sparse and up/down skin have some overlap.
510 settings['downSkinCount'] = 10000
511 settings['upSkinCount'] = 10000
513 settings['sparseInfillLineDistance'] = int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('fill_density'))
514 if profile.getProfileSetting('platform_adhesion') == 'Brim':
515 settings['skirtDistance'] = 0
516 settings['skirtLineCount'] = int(profile.getProfileSettingFloat('brim_line_count'))
517 elif profile.getProfileSetting('platform_adhesion') == 'Raft':
518 settings['skirtDistance'] = 0
519 settings['skirtLineCount'] = 0
520 settings['raftMargin'] = int(profile.getProfileSettingFloat('raft_margin') * 1000)
521 settings['raftLineSpacing'] = int(profile.getProfileSettingFloat('raft_line_spacing') * 1000)
522 settings['raftBaseThickness'] = int(profile.getProfileSettingFloat('raft_base_thickness') * 1000)
523 settings['raftBaseLinewidth'] = int(profile.getProfileSettingFloat('raft_base_linewidth') * 1000)
524 settings['raftInterfaceThickness'] = int(profile.getProfileSettingFloat('raft_interface_thickness') * 1000)
525 settings['raftInterfaceLinewidth'] = int(profile.getProfileSettingFloat('raft_interface_linewidth') * 1000)
526 settings['raftInterfaceLineSpacing'] = int(profile.getProfileSettingFloat('raft_interface_linewidth') * 1000 * 2.0)
527 settings['raftAirGapLayer0'] = int(profile.getProfileSettingFloat('raft_airgap') * 1000)
528 settings['raftBaseSpeed'] = int(profile.getProfileSettingFloat('bottom_layer_speed'))
529 settings['raftFanSpeed'] = 100
530 settings['raftSurfaceThickness'] = settings['raftInterfaceThickness']
531 settings['raftSurfaceLinewidth'] = int(profile.calculateEdgeWidth() * 1000)
532 settings['raftSurfaceLineSpacing'] = int(profile.calculateEdgeWidth() * 1000 * 0.9)
533 settings['raftSurfaceLayers'] = int(profile.getProfileSettingFloat('raft_surface_layers'))
534 settings['raftSurfaceSpeed'] = int(profile.getProfileSettingFloat('bottom_layer_speed'))
536 settings['skirtDistance'] = int(profile.getProfileSettingFloat('skirt_gap') * 1000)
537 settings['skirtLineCount'] = int(profile.getProfileSettingFloat('skirt_line_count'))
538 settings['skirtMinLength'] = int(profile.getProfileSettingFloat('skirt_minimal_length') * 1000)
540 if profile.getProfileSetting('fix_horrible_union_all_type_a') == 'True':
541 settings['fixHorrible'] |= 0x01
542 if profile.getProfileSetting('fix_horrible_union_all_type_b') == 'True':
543 settings['fixHorrible'] |= 0x02
544 if profile.getProfileSetting('fix_horrible_use_open_bits') == 'True':
545 settings['fixHorrible'] |= 0x10
546 if profile.getProfileSetting('fix_horrible_extensive_stitching') == 'True':
547 settings['fixHorrible'] |= 0x04
549 if settings['layerThickness'] <= 0:
550 settings['layerThickness'] = 1000
551 if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
552 settings['gcodeFlavor'] = 1
553 elif profile.getMachineSetting('gcode_flavor') == 'MakerBot':
554 settings['gcodeFlavor'] = 2
555 elif profile.getMachineSetting('gcode_flavor') == 'BFB':
556 settings['gcodeFlavor'] = 3
557 elif profile.getMachineSetting('gcode_flavor') == 'Mach3':
558 settings['gcodeFlavor'] = 4
559 elif profile.getMachineSetting('gcode_flavor') == 'RepRap (Volumetric)':
560 settings['gcodeFlavor'] = 5
561 if profile.getProfileSetting('spiralize') == 'True':
562 settings['spiralizeMode'] = 1
563 if profile.getProfileSetting('simple_mode') == 'True':
564 settings['simpleMode'] = 1
565 if profile.getProfileSetting('wipe_tower') == 'True' and extruderCount > 1:
566 settings['wipeTowerSize'] = int(math.sqrt(profile.getProfileSettingFloat('wipe_tower_volume') * 1000 * 1000 * 1000 / settings['layerThickness']))
567 if profile.getProfileSetting('ooze_shield') == 'True':
568 settings['enableOozeShield'] = 1
571 def _runEngineProcess(self, cmdList):
573 if subprocess.mswindows:
574 su = subprocess.STARTUPINFO()
575 su.dwFlags |= subprocess.STARTF_USESHOWWINDOW
576 su.wShowWindow = subprocess.SW_HIDE
577 kwargs['startupinfo'] = su
578 kwargs['creationflags'] = 0x00004000 #BELOW_NORMAL_PRIORITY_CLASS
579 return subprocess.Popen(cmdList, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs)